Skip to content
This repository was archived by the owner on Jul 4, 2025. It is now read-only.

Commit d7e4cd3

Browse files
committed
feat: add assistants
1 parent 4d2d236 commit d7e4cd3

File tree

10 files changed

+526
-4
lines changed

10 files changed

+526
-4
lines changed

engine/common/assistant.h

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include "common/assistant_tool.h"
5+
#include "common/thread_tool_resources.h"
6+
#include "common/variant_map.h"
7+
#include "utils/result.hpp"
8+
9+
namespace OpenAi {
10+
// Deprecated. After jan's migration, we should remove this struct
11+
struct JanAssistant : JsonSerializable {
12+
std::string id;
13+
14+
std::string name;
15+
16+
std::string object = "assistant";
17+
18+
uint32_t created_at;
19+
20+
Json::Value tools;
21+
22+
Json::Value model;
23+
24+
std::string instructions;
25+
26+
~JanAssistant() = default;
27+
28+
cpp::result<Json::Value, std::string> ToJson() override {
29+
try {
30+
Json::Value json;
31+
32+
json["id"] = id;
33+
json["name"] = name;
34+
json["object"] = object;
35+
json["created_at"] = created_at;
36+
37+
json["tools"] = tools;
38+
json["model"] = model;
39+
json["instructions"] = instructions;
40+
41+
return json;
42+
} catch (const std::exception& e) {
43+
return cpp::fail(std::string("ToJson failed: ") + e.what());
44+
}
45+
}
46+
47+
static cpp::result<JanAssistant, std::string> FromJson(Json::Value&& json) {
48+
if (json.empty()) {
49+
return cpp::fail("Empty JSON");
50+
}
51+
52+
JanAssistant assistant;
53+
if (json.isMember("assistant_id")) {
54+
assistant.id = json["assistant_id"].asString();
55+
} else {
56+
assistant.id = json["id"].asString();
57+
}
58+
59+
if (json.isMember("assistant_name")) {
60+
assistant.name = json["assistant_name"].asString();
61+
} else {
62+
assistant.name = json["name"].asString();
63+
}
64+
assistant.object = "assistant";
65+
assistant.created_at = 0; // Jan does not have this
66+
if (json.isMember("tools")) {
67+
assistant.tools = json["tools"];
68+
}
69+
if (json.isMember("model")) {
70+
assistant.model = json["model"];
71+
}
72+
assistant.instructions = json["instructions"].asString();
73+
74+
return assistant;
75+
}
76+
};
77+
78+
struct Assistant {
79+
/**
80+
* The identifier, which can be referenced in API endpoints.
81+
*/
82+
std::string id;
83+
84+
/**
85+
* The object type, which is always assistant.
86+
*/
87+
std::string object = "assistant";
88+
89+
/**
90+
* The Unix timestamp (in seconds) for when the assistant was created.
91+
*/
92+
uint64_t created_at;
93+
94+
/**
95+
* The name of the assistant. The maximum length is 256 characters.
96+
*/
97+
std::optional<std::string> name;
98+
99+
/**
100+
* The description of the assistant. The maximum length is 512 characters.
101+
*/
102+
std::optional<std::string> description;
103+
104+
/**
105+
* ID of the model to use. You can use the List models API to see all of
106+
* your available models, or see our Model overview for descriptions of them.
107+
*/
108+
std::string model;
109+
110+
/**
111+
* The system instructions that the assistant uses. The maximum length is
112+
* 256,000 characters.
113+
*/
114+
std::optional<std::string> instructions;
115+
116+
/**
117+
* A list of tool enabled on the assistant. There can be a maximum of 128
118+
* tools per assistant. Tools can be of types code_interpreter, file_search,
119+
* or function.
120+
*/
121+
std::vector<std::unique_ptr<AssistantTool>> tools;
122+
123+
/**
124+
* A set of resources that are used by the assistant's tools. The resources
125+
* are specific to the type of tool. For example, the code_interpreter tool
126+
* requires a list of file IDs, while the file_search tool requires a list
127+
* of vector store IDs.
128+
*/
129+
std::optional<std::variant<ThreadCodeInterpreter, ThreadFileSearch>>
130+
tool_resources;
131+
132+
/**
133+
* Set of 16 key-value pairs that can be attached to an object. This can be
134+
* useful for storing additional information about the object in a structured
135+
* format. Keys can be a maximum of 64 characters long and values can be a
136+
* maximum of 512 characters long.
137+
*/
138+
Cortex::VariantMap metadata;
139+
140+
/**
141+
* What sampling temperature to use, between 0 and 2. Higher values like
142+
* 0.8 will make the output more random, while lower values like 0.2 will
143+
* make it more focused and deterministic.
144+
*/
145+
std::optional<float> temperature;
146+
147+
/**
148+
* An alternative to sampling with temperature, called nucleus sampling,
149+
* where the model considers the results of the tokens with top_p
150+
* probability mass. So 0.1 means only the tokens comprising the top 10%
151+
* probability mass are considered.
152+
*
153+
* We generally recommend altering this or temperature but not both.
154+
*/
155+
std::optional<float> top_p;
156+
};
157+
} // namespace OpenAi

engine/common/assistant_tool.h

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#pragma once
2+
3+
#include <string>
4+
5+
namespace OpenAi {
6+
struct AssistantTool {
7+
std::string type;
8+
9+
AssistantTool(const std::string& type) : type{type} {}
10+
11+
virtual ~AssistantTool() = default;
12+
};
13+
14+
struct AssistantCodeInterpreterTool : public AssistantTool {
15+
AssistantCodeInterpreterTool() : AssistantTool{"code_interpreter"} {}
16+
17+
~AssistantCodeInterpreterTool() = default;
18+
};
19+
20+
struct AssistantFileSearchTool : public AssistantTool {
21+
AssistantFileSearchTool() : AssistantTool("file_search") {}
22+
23+
~AssistantFileSearchTool() = default;
24+
25+
/**
26+
* The ranking options for the file search. If not specified,
27+
* the file search tool will use the auto ranker and a score_threshold of 0.
28+
*
29+
* See the file search tool documentation for more information.
30+
*/
31+
struct RankingOption {
32+
/**
33+
* The ranker to use for the file search. If not specified will use the auto ranker.
34+
*/
35+
std::string ranker;
36+
37+
/**
38+
* The score threshold for the file search. All values must be a
39+
* floating point number between 0 and 1.
40+
*/
41+
float score_threshold;
42+
};
43+
44+
/**
45+
* Overrides for the file search tool.
46+
*/
47+
struct FileSearch {
48+
/**
49+
* The maximum number of results the file search tool should output.
50+
* The default is 20 for gpt-4* models and 5 for gpt-3.5-turbo.
51+
* This number should be between 1 and 50 inclusive.
52+
*
53+
* Note that the file search tool may output fewer than max_num_results results.
54+
* See the file search tool documentation for more information.
55+
*/
56+
int max_num_result;
57+
};
58+
};
59+
60+
struct AssistantFunctionTool : public AssistantTool {
61+
AssistantFunctionTool() : AssistantTool("function") {}
62+
63+
~AssistantFunctionTool() = default;
64+
65+
struct Function {
66+
/**
67+
* A description of what the function does, used by the model to choose
68+
* when and how to call the function.
69+
*/
70+
std::string description;
71+
72+
/**
73+
* The name of the function to be called. Must be a-z, A-Z, 0-9, or contain
74+
* underscores and dashes, with a maximum length of 64.
75+
*/
76+
std::string name;
77+
78+
// TODO: namh handle parameters
79+
80+
/**
81+
* Whether to enable strict schema adherence when generating the function call.
82+
* If set to true, the model will follow the exact schema defined in the parameters
83+
* field. Only a subset of JSON Schema is supported when strict is true.
84+
*
85+
* Learn more about Structured Outputs in the function calling guide.
86+
*/
87+
std::optional<bool> strict;
88+
};
89+
};
90+
} // namespace OpenAi

engine/config/model_config.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
#pragma once
22

33
#include <json/json.h>
4-
#include <cmath>
54
#include <ctime>
65
#include <fstream>
7-
#include <iomanip>
86
#include <limits>
97
#include <sstream>
108
#include <stdexcept>
119
#include <string>
1210
#include <vector>
1311
#include "utils/format_utils.h"
1412
#include "utils/remote_models_utils.h"
15-
#include "yaml-cpp/yaml.h"
1613

1714
namespace config {
1815

engine/controllers/assistants.cc

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#include "assistants.h"
2+
#include "utils/cortex_utils.h"
3+
#include "utils/logging_utils.h"
4+
5+
void Assistants::RetrieveAssistant(
6+
const HttpRequestPtr& req,
7+
std::function<void(const HttpResponsePtr&)>&& callback,
8+
const std::string& assistant_id) const {
9+
CTL_INF("RetrieveAssistant: " + assistant_id);
10+
auto res = assistant_service_->RetrieveAssistant(assistant_id);
11+
if (res.has_error()) {
12+
Json::Value ret;
13+
ret["message"] = res.error();
14+
auto resp = cortex_utils::CreateCortexHttpJsonResponse(ret);
15+
resp->setStatusCode(k400BadRequest);
16+
callback(resp);
17+
} else {
18+
auto to_json_res = res->ToJson();
19+
if (to_json_res.has_error()) {
20+
CTL_ERR("Failed to convert assistant to json: " + to_json_res.error());
21+
Json::Value ret;
22+
ret["message"] = to_json_res.error();
23+
auto resp = cortex_utils::CreateCortexHttpJsonResponse(ret);
24+
resp->setStatusCode(k400BadRequest);
25+
callback(resp);
26+
} else {
27+
// TODO: namh need to use the text response because it contains model config
28+
auto resp =
29+
cortex_utils::CreateCortexHttpJsonResponse(res->ToJson().value());
30+
resp->setStatusCode(k200OK);
31+
callback(resp);
32+
}
33+
}
34+
}
35+
36+
void Assistants::ModifyAssistant(
37+
const HttpRequestPtr& req,
38+
std::function<void(const HttpResponsePtr&)>&& callback,
39+
const std::string& assistant_id) {
40+
auto json_body = req->getJsonObject();
41+
if (json_body == nullptr) {
42+
Json::Value ret;
43+
ret["message"] = "Request body can't be empty";
44+
auto resp = cortex_utils::CreateCortexHttpJsonResponse(ret);
45+
resp->setStatusCode(k400BadRequest);
46+
callback(resp);
47+
return;
48+
}
49+
50+
// auto res =
51+
// assistant_service_->ModifyAssistant(thread_id, nullptr, metadata.value());
52+
// if (res.has_error()) {
53+
// Json::Value ret;
54+
// ret["message"] = res.error();
55+
// auto resp = cortex_utils::CreateCortexHttpJsonResponse(ret);
56+
// resp->setStatusCode(k400BadRequest);
57+
// callback(resp);
58+
// } else {
59+
// auto message_to_json = res->ToJson();
60+
// if (message_to_json.has_error()) {
61+
// CTL_ERR("Failed to convert message to json: " + message_to_json.error());
62+
// Json::Value ret;
63+
// ret["message"] = message_to_json.error();
64+
// auto resp = cortex_utils::CreateCortexHttpJsonResponse(ret);
65+
// resp->setStatusCode(k400BadRequest);
66+
// callback(resp);
67+
// } else {
68+
// auto resp =
69+
// cortex_utils::CreateCortexHttpJsonResponse(res->ToJson().value());
70+
// resp->setStatusCode(k200OK);
71+
// callback(resp);
72+
// }
73+
// }
74+
}

engine/controllers/assistants.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#pragma once
2+
3+
#include <drogon/HttpController.h>
4+
#include <trantor/utils/Logger.h>
5+
#include "services/assistant_service.h"
6+
7+
using namespace drogon;
8+
9+
class Assistants : public drogon::HttpController<Assistants, false> {
10+
public:
11+
METHOD_LIST_BEGIN
12+
ADD_METHOD_TO(Assistants::RetrieveAssistant, "/v1/assistants/{assistant_id}",
13+
Get);
14+
ADD_METHOD_TO(Assistants::ModifyAssistant, "/v1/assistants/{assistant_id}",
15+
Options, Post, Patch);
16+
METHOD_LIST_END
17+
18+
explicit Assistants(std::shared_ptr<AssistantService> assistant_srv)
19+
: assistant_service_{assistant_srv} {};
20+
21+
void RetrieveAssistant(const HttpRequestPtr& req,
22+
std::function<void(const HttpResponsePtr&)>&& callback,
23+
const std::string& assistant_id) const;
24+
25+
void ModifyAssistant(const HttpRequestPtr& req,
26+
std::function<void(const HttpResponsePtr&)>&& callback,
27+
const std::string& assistant_id);
28+
29+
private:
30+
std::shared_ptr<AssistantService> assistant_service_;
31+
};

0 commit comments

Comments
 (0)