@p-sw/brainbox 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/dist/index.js +5312 -0
  2. package/package.json +7 -4
  3. package/scripts/smoke_providers.ts +0 -176
  4. package/src/brain/index.ts +0 -936
  5. package/src/brain/manager.ts +0 -144
  6. package/src/brain/memory.ts +0 -99
  7. package/src/brain/messageHistory.ts +0 -26
  8. package/src/brain/schedule.ts +0 -11
  9. package/src/brain/types.ts +0 -26
  10. package/src/channel/base.ts +0 -527
  11. package/src/channel/discord.ts +0 -227
  12. package/src/channel/telegram.ts +0 -150
  13. package/src/commands/auth.tsx +0 -306
  14. package/src/commands/brain.ts +0 -119
  15. package/src/commands/daemon/commands.ts +0 -56
  16. package/src/commands/daemon/pairingCommand.ts +0 -15
  17. package/src/commands/daemon/restartCommand.ts +0 -17
  18. package/src/commands/daemon.ts +0 -168
  19. package/src/commands/index.ts +0 -16
  20. package/src/commands/model.tsx +0 -138
  21. package/src/commands/onboard.tsx +0 -473
  22. package/src/commands/pairing.ts +0 -32
  23. package/src/commands/restart.ts +0 -24
  24. package/src/config/file/auth.ts +0 -105
  25. package/src/config/file/root.ts +0 -37
  26. package/src/config/index.ts +0 -21
  27. package/src/config/loader.ts +0 -115
  28. package/src/index.ts +0 -61
  29. package/src/provider/index.ts +0 -122
  30. package/src/provider/llm.ts +0 -191
  31. package/src/provider/promptLoader.ts +0 -36
  32. package/src/provider/providers/302ai.ts +0 -17
  33. package/src/provider/providers/MiniMax.ts +0 -17
  34. package/src/provider/providers/anthropic.ts +0 -257
  35. package/src/provider/providers/azure_cognitive.ts +0 -40
  36. package/src/provider/providers/azure_openai.ts +0 -49
  37. package/src/provider/providers/baseten.ts +0 -17
  38. package/src/provider/providers/bedrock.ts +0 -312
  39. package/src/provider/providers/cerebras.ts +0 -17
  40. package/src/provider/providers/cloudflare_gateway.ts +0 -34
  41. package/src/provider/providers/cloudflare_workers.ts +0 -178
  42. package/src/provider/providers/copilot.ts +0 -22
  43. package/src/provider/providers/cortecs.ts +0 -17
  44. package/src/provider/providers/deepinfra.ts +0 -17
  45. package/src/provider/providers/deepseek.ts +0 -17
  46. package/src/provider/providers/digitalocean.ts +0 -17
  47. package/src/provider/providers/fireworks.ts +0 -17
  48. package/src/provider/providers/gitlab_duo.ts +0 -184
  49. package/src/provider/providers/gmi.ts +0 -17
  50. package/src/provider/providers/groq.ts +0 -17
  51. package/src/provider/providers/helicone.ts +0 -17
  52. package/src/provider/providers/huggingface.ts +0 -17
  53. package/src/provider/providers/ionet.ts +0 -17
  54. package/src/provider/providers/llamacpp.ts +0 -17
  55. package/src/provider/providers/llmgateway.ts +0 -17
  56. package/src/provider/providers/lmstudio.ts +0 -17
  57. package/src/provider/providers/mistral.ts +0 -17
  58. package/src/provider/providers/moonshot.ts +0 -17
  59. package/src/provider/providers/nebius.ts +0 -17
  60. package/src/provider/providers/nvidia.ts +0 -17
  61. package/src/provider/providers/ollama.ts +0 -17
  62. package/src/provider/providers/ollama_cloud.ts +0 -17
  63. package/src/provider/providers/openai.ts +0 -17
  64. package/src/provider/providers/openai_compatible.ts +0 -293
  65. package/src/provider/providers/openrouter.ts +0 -175
  66. package/src/provider/providers/ovhcloud.ts +0 -17
  67. package/src/provider/providers/sap_aicore.ts +0 -22
  68. package/src/provider/providers/scaleway.ts +0 -17
  69. package/src/provider/providers/snowflake_cortex.ts +0 -207
  70. package/src/provider/providers/stackit.ts +0 -17
  71. package/src/provider/providers/together.ts +0 -17
  72. package/src/provider/providers/venice.ts +0 -17
  73. package/src/provider/providers/vercel.ts +0 -17
  74. package/src/provider/providers/vertex.ts +0 -229
  75. package/src/provider/providers/xai.ts +0 -17
  76. package/src/provider/providers/zai.ts +0 -17
  77. package/src/provider/providers/zenmux.ts +0 -17
  78. package/src/provider/schema.ts +0 -143
  79. package/src/ui/TextInput.tsx +0 -114
  80. package/src/utils/daemonClient.ts +0 -85
  81. package/src/utils/logger.ts +0 -204
  82. package/tsconfig.json +0 -34
  83. /package/{prompts → dist/prompts}/daily_schedule.md +0 -0
  84. /package/{prompts → dist/prompts}/memoir.md +0 -0
  85. /package/{prompts → dist/prompts}/monthly_schedule.md +0 -0
  86. /package/{prompts → dist/prompts}/objectifier.md +0 -0
  87. /package/{prompts → dist/prompts}/persona_base_system_prompt.md +0 -0
  88. /package/{prompts → dist/prompts}/persona_base_system_prompt_fixed.md +0 -0
  89. /package/{prompts → dist/prompts}/persona_init.md +0 -0
  90. /package/{prompts → dist/prompts}/schedule_availability.md +0 -0
  91. /package/{prompts → dist/prompts}/send_message.md +0 -0
  92. /package/{prompts → dist/prompts}/start_conversation.md +0 -0
@@ -1,17 +0,0 @@
1
- import { OpenAICompatibleExecutor } from "./openai_compatible";
2
-
3
- export class MoonshotExecutor extends OpenAICompatibleExecutor {
4
- constructor(opts: {
5
- apiKey: string;
6
- conversationModel: string;
7
- identityModel: string;
8
- }) {
9
- super({
10
- providerName: "moonshot",
11
- baseURL: "https://api.moonshot.ai/v1",
12
- apiKey: opts.apiKey,
13
- conversationModel: opts.conversationModel,
14
- identityModel: opts.identityModel,
15
- });
16
- }
17
- }
@@ -1,17 +0,0 @@
1
- import { OpenAICompatibleExecutor } from "./openai_compatible";
2
-
3
- export class NebiusExecutor extends OpenAICompatibleExecutor {
4
- constructor(opts: {
5
- apiKey: string;
6
- conversationModel: string;
7
- identityModel: string;
8
- }) {
9
- super({
10
- providerName: "nebius",
11
- baseURL: "https://api.tokenfactory.nebius.com/v1",
12
- apiKey: opts.apiKey,
13
- conversationModel: opts.conversationModel,
14
- identityModel: opts.identityModel,
15
- });
16
- }
17
- }
@@ -1,17 +0,0 @@
1
- import { OpenAICompatibleExecutor } from "./openai_compatible";
2
-
3
- export class NvidiaExecutor extends OpenAICompatibleExecutor {
4
- constructor(opts: {
5
- apiKey: string;
6
- conversationModel: string;
7
- identityModel: string;
8
- }) {
9
- super({
10
- providerName: "nvidia",
11
- baseURL: "https://integrate.api.nvidia.com/v1",
12
- apiKey: opts.apiKey,
13
- conversationModel: opts.conversationModel,
14
- identityModel: opts.identityModel,
15
- });
16
- }
17
- }
@@ -1,17 +0,0 @@
1
- import { OpenAICompatibleExecutor } from "./openai_compatible";
2
-
3
- export class OllamaExecutor extends OpenAICompatibleExecutor {
4
- constructor(opts: {
5
- apiKey: string;
6
- conversationModel: string;
7
- identityModel: string;
8
- }) {
9
- super({
10
- providerName: "ollama",
11
- baseURL: "http://127.0.0.1:11434/v1",
12
- apiKey: opts.apiKey || "ollama",
13
- conversationModel: opts.conversationModel,
14
- identityModel: opts.identityModel,
15
- });
16
- }
17
- }
@@ -1,17 +0,0 @@
1
- import { OpenAICompatibleExecutor } from "./openai_compatible";
2
-
3
- export class OllamaCloudExecutor extends OpenAICompatibleExecutor {
4
- constructor(opts: {
5
- apiKey: string;
6
- conversationModel: string;
7
- identityModel: string;
8
- }) {
9
- super({
10
- providerName: "ollama-cloud",
11
- baseURL: "https://api.ollama.cloud/v1",
12
- apiKey: opts.apiKey,
13
- conversationModel: opts.conversationModel,
14
- identityModel: opts.identityModel,
15
- });
16
- }
17
- }
@@ -1,17 +0,0 @@
1
- import { OpenAICompatibleExecutor } from "./openai_compatible";
2
-
3
- export class OpenAIExecutor extends OpenAICompatibleExecutor {
4
- constructor(opts: {
5
- apiKey: string;
6
- conversationModel: string;
7
- identityModel: string;
8
- }) {
9
- super({
10
- providerName: "openai",
11
- baseURL: "https://api.openai.com/v1",
12
- apiKey: opts.apiKey,
13
- conversationModel: opts.conversationModel,
14
- identityModel: opts.identityModel,
15
- });
16
- }
17
- }
@@ -1,293 +0,0 @@
1
- import { logger } from "@/utils/logger";
2
- import {
3
- LLMExecutor,
4
- defaultReasoningEffort,
5
- type CallOptions,
6
- type ChatChoice,
7
- type ChatFunctionTool,
8
- type ChatMessages,
9
- type ChatWithToolsOptions,
10
- type ReasoningEffort,
11
- type ToolCall,
12
- } from "../llm";
13
-
14
- const log = logger.child("llm:openai-compatible");
15
-
16
- // ponytail: Most LLM providers expose an OpenAI-compatible /v1/chat/completions endpoint.
17
- // One executor, parameterized by baseURL + auth headers, covers the majority of the list.
18
- // Per-provider tweaks live in subclass overrides; default behavior needs none.
19
-
20
- export type OpenAICompatibleOptions = {
21
- baseURL: string;
22
- apiKey: string;
23
- conversationModel: string;
24
- identityModel: string;
25
- defaultHeaders?: Record<string, string>;
26
- chatPath?: string;
27
- noBearerPrefix?: boolean;
28
- reasoningEffortInQuery?: boolean;
29
- providerName: string;
30
- };
31
-
32
- type ChatMessageWire =
33
- | { role: "system" | "user"; content: string }
34
- | {
35
- role: "assistant";
36
- content: string | null;
37
- tool_calls?: Array<{
38
- id: string;
39
- type: "function";
40
- function: { name: string; arguments: string };
41
- }>;
42
- }
43
- | { role: "tool"; content: string; tool_call_id: string };
44
-
45
- type ChatResponse = {
46
- choices?: Array<{
47
- message?: {
48
- content?: string | null;
49
- tool_calls?: Array<{
50
- id: string;
51
- type: "function";
52
- function: { name: string; arguments: string };
53
- }>;
54
- };
55
- }>;
56
- error?: { message?: string; type?: string };
57
- };
58
-
59
- function toWireMessage(m: ChatMessages): ChatMessageWire {
60
- if (m.role === "assistant") {
61
- return {
62
- role: "assistant",
63
- content: m.content ?? null,
64
- tool_calls: m.toolCalls?.map((c) => ({
65
- id: c.id,
66
- type: "function",
67
- function: { name: c.function.name, arguments: c.function.arguments },
68
- })),
69
- };
70
- }
71
- if (m.role === "tool") {
72
- return { role: "tool", content: m.content, tool_call_id: m.toolCallId };
73
- }
74
- return { role: m.role, content: m.content };
75
- }
76
-
77
- function fromChoice(
78
- choice: NonNullable<ChatResponse["choices"]>[number],
79
- ): ChatChoice {
80
- const msg = choice.message ?? {};
81
- const toolCalls: ToolCall[] | undefined = msg.tool_calls?.map((c) => ({
82
- id: c.id,
83
- function: { name: c.function.name, arguments: c.function.arguments },
84
- }));
85
- return {
86
- message: {
87
- content: typeof msg.content === "string" ? msg.content : undefined,
88
- toolCalls,
89
- },
90
- };
91
- }
92
-
93
- function toWireTool(t: ChatFunctionTool) {
94
- return {
95
- type: "function" as const,
96
- function: {
97
- name: t.name,
98
- description: t.description ?? "",
99
- parameters: t.parameters ?? {},
100
- },
101
- };
102
- }
103
-
104
- function buildResponseFormat(
105
- jsonSchemaName: string,
106
- jsonSchema: Record<string, unknown> | undefined,
107
- ): Record<string, unknown> {
108
- return {
109
- type: "json_schema",
110
- json_schema: {
111
- name: jsonSchemaName,
112
- schema: jsonSchema ?? {},
113
- strict: true,
114
- },
115
- };
116
- }
117
-
118
- export class OpenAICompatibleExecutor extends LLMExecutor {
119
- readonly providerName: string;
120
- readonly models: { conversation: string; identity: string };
121
-
122
- protected readonly baseURL: string;
123
- protected readonly apiKey: string;
124
- protected readonly defaultHeaders: Record<string, string>;
125
- protected readonly chatPath: string;
126
- protected readonly noBearerPrefix: boolean;
127
- protected readonly reasoningEffortInQuery: boolean;
128
-
129
- constructor(opts: OpenAICompatibleOptions) {
130
- super();
131
- this.providerName = opts.providerName;
132
- this.baseURL = opts.baseURL.replace(/\/+$/, "");
133
- this.apiKey = opts.apiKey;
134
- this.defaultHeaders = opts.defaultHeaders ?? {};
135
- this.chatPath = opts.chatPath ?? "/chat/completions";
136
- this.noBearerPrefix = opts.noBearerPrefix ?? false;
137
- this.reasoningEffortInQuery = opts.reasoningEffortInQuery ?? false;
138
- this.models = {
139
- conversation: opts.conversationModel,
140
- identity: opts.identityModel,
141
- };
142
- }
143
-
144
- protected buildBody(opts: {
145
- model: string;
146
- messages: ChatMessageWire[];
147
- responseFormat?: Record<string, unknown>;
148
- tools?: unknown[];
149
- parallelToolCalls?: boolean;
150
- reasoningEffort?: ReasoningEffort;
151
- }): Record<string, unknown> {
152
- const body: Record<string, unknown> = {
153
- model: opts.model,
154
- messages: opts.messages,
155
- stream: false,
156
- };
157
- if (opts.responseFormat) body["response_format"] = opts.responseFormat;
158
- if (opts.tools) body["tools"] = opts.tools;
159
- if (opts.parallelToolCalls !== undefined) {
160
- body["parallel_tool_calls"] = opts.parallelToolCalls;
161
- }
162
- if (opts.reasoningEffort && opts.reasoningEffort !== "none") {
163
- body["reasoning_effort"] = opts.reasoningEffort;
164
- }
165
- return body;
166
- }
167
-
168
- protected buildRequestUrl(
169
- _model: string,
170
- reasoningEffort: ReasoningEffort | undefined,
171
- ): string {
172
- const url = new URL(this.baseURL + this.chatPath);
173
- if (
174
- this.reasoningEffortInQuery &&
175
- reasoningEffort &&
176
- reasoningEffort !== "none"
177
- ) {
178
- url.searchParams.set("reasoning_effort", reasoningEffort);
179
- }
180
- return url.toString();
181
- }
182
-
183
- private async sendRequest(
184
- body: Record<string, unknown>,
185
- reasoningEffort: ReasoningEffort | undefined,
186
- ): Promise<ChatResponse> {
187
- const modelName = body["model"];
188
- const modelStr = typeof modelName === "string" ? modelName : "";
189
- const url = this.buildRequestUrl(modelStr, reasoningEffort);
190
- const authHeader: Record<string, string> = this.apiKey
191
- ? this.noBearerPrefix
192
- ? { Authorization: this.apiKey }
193
- : { Authorization: `Bearer ${this.apiKey}` }
194
- : {};
195
- const headers: Record<string, string> = {
196
- "Content-Type": "application/json",
197
- ...authHeader,
198
- ...this.defaultHeaders,
199
- };
200
- const res = await fetch(url, {
201
- method: "POST",
202
- headers,
203
- body: JSON.stringify(body),
204
- });
205
- if (!res.ok) {
206
- const text = await res.text().catch(() => "");
207
- log.error(
208
- `${this.providerName}: HTTP ${res.status} ${res.statusText} body=${text.slice(0, 500)}`,
209
- );
210
- throw new Error(
211
- `${this.providerName} request failed: ${res.status} ${res.statusText}`,
212
- );
213
- }
214
- const data = (await res.json()) as ChatResponse;
215
- if (data.error) {
216
- log.error(
217
- `${this.providerName}: API error ${data.error.type ?? ""} ${data.error.message ?? ""}`,
218
- );
219
- throw new Error(
220
- `${this.providerName} API error: ${data.error.message ?? "unknown"}`,
221
- );
222
- }
223
- return data;
224
- }
225
-
226
- async call<T>(model: string, options: CallOptions): Promise<T> {
227
- const jsonMode = "jsonSchemaName" in options;
228
- const reasoning = defaultReasoningEffort(
229
- options.reasoningEffort,
230
- model,
231
- this.models.identity,
232
- );
233
- log.debug(
234
- `call: provider=${this.providerName} model=${model} jsonSchema=${jsonMode ? options.jsonSchemaName : "-"} msgLen=${options.message.length}`,
235
- );
236
- const body = this.buildBody({
237
- model,
238
- messages: [
239
- { role: "system", content: options.instruction },
240
- { role: "user", content: options.message },
241
- ],
242
- responseFormat: jsonMode
243
- ? buildResponseFormat(options.jsonSchemaName, options.jsonSchema)
244
- : undefined,
245
- reasoningEffort: reasoning,
246
- });
247
- const data = await this.sendRequest(body, options.reasoningEffort);
248
- const content = data.choices?.[0]?.message?.content;
249
- if (!content) {
250
- log.debug(`call: empty content in choice 0`);
251
- throw new Error("Empty response from model");
252
- }
253
- log.debug(`call: response ${content.length} chars`);
254
- return (jsonMode ? JSON.parse(content) : content) as T;
255
- }
256
-
257
- async chatWithTools(
258
- model: string,
259
- options: ChatWithToolsOptions,
260
- ): Promise<ChatChoice> {
261
- const reasoning = defaultReasoningEffort(
262
- options.reasoningEffort,
263
- model,
264
- this.models.identity,
265
- );
266
- log.debug(
267
- `chatWithTools: provider=${this.providerName} model=${model} msgs=${options.messages.length} tools=${options.tools.length}`,
268
- );
269
- const body = this.buildBody({
270
- model,
271
- messages: [
272
- { role: "system", content: options.instruction },
273
- ...options.messages.map(toWireMessage),
274
- ],
275
- tools: options.tools.map(toWireTool),
276
- parallelToolCalls: options.parallelToolCalls ?? false,
277
- reasoningEffort: reasoning,
278
- });
279
- const data = await this.sendRequest(body, options.reasoningEffort);
280
- const choice = data.choices?.[0];
281
- if (!choice) {
282
- log.debug(`chatWithTools: no choice in response`);
283
- throw new Error("LLM returned no choice");
284
- }
285
- const calls = choice.message?.tool_calls?.length ?? 0;
286
- const textLen =
287
- typeof choice.message?.content === "string"
288
- ? choice.message.content.length
289
- : 0;
290
- log.debug(`chatWithTools: choice toolCalls=${calls} text=${textLen}`);
291
- return fromChoice(choice);
292
- }
293
- }
@@ -1,175 +0,0 @@
1
- import { OpenRouter } from "@openrouter/sdk";
2
- import { logger } from "@/utils/logger";
3
- import type {
4
- ChatChoice as OrChoice,
5
- ChatFunctionTool as OrTool,
6
- ChatMessages as OrMessage,
7
- ChatRequestEffort,
8
- } from "@openrouter/sdk/models";
9
- import {
10
- LLMExecutor,
11
- type CallOptions,
12
- type ChatChoice,
13
- type ChatFunctionTool,
14
- type ChatMessages,
15
- type ChatWithToolsOptions,
16
- type ReasoningEffort,
17
- type ToolCall,
18
- } from "../llm";
19
-
20
- const log = logger.child("llm:openrouter");
21
-
22
- const REASONING_EFFORT_MAP: Record<ReasoningEffort, ChatRequestEffort> = {
23
- none: "none",
24
- low: "low",
25
- medium: "medium",
26
- high: "high",
27
- };
28
-
29
- function toOrMessage(m: ChatMessages): OrMessage {
30
- if (m.role === "assistant") {
31
- return {
32
- role: "assistant",
33
- content: m.content ?? "",
34
- toolCalls: m.toolCalls?.map((c) => ({
35
- id: c.id,
36
- type: "function" as const,
37
- function: { name: c.function.name, arguments: c.function.arguments },
38
- })),
39
- };
40
- }
41
- if (m.role === "tool") {
42
- return { role: "tool", content: m.content, toolCallId: m.toolCallId };
43
- }
44
- return { role: m.role, content: m.content };
45
- }
46
-
47
- function fromOrChoice(choice: OrChoice): ChatChoice {
48
- const msg = choice.message;
49
- const toolCalls: ToolCall[] | undefined = msg.toolCalls?.map((c) => ({
50
- id: c.id,
51
- function: { name: c.function.name, arguments: c.function.arguments },
52
- }));
53
- return {
54
- message: {
55
- content: typeof msg.content === "string" ? msg.content : undefined,
56
- toolCalls,
57
- },
58
- };
59
- }
60
-
61
- function toOrTool(t: ChatFunctionTool): OrTool {
62
- return {
63
- type: "function",
64
- function: {
65
- name: t.name,
66
- description: t.description ?? "",
67
- parameters: t.parameters ?? {},
68
- },
69
- };
70
- }
71
-
72
- export class OpenRouterExecutor extends LLMExecutor {
73
- readonly providerName = "openrouter";
74
- readonly models: { conversation: string; identity: string };
75
-
76
- private client: OpenRouter;
77
-
78
- constructor(opts: {
79
- apiKey: string;
80
- conversationModel: string;
81
- identityModel: string;
82
- }) {
83
- super();
84
- this.client = new OpenRouter({ apiKey: opts.apiKey, appTitle: "boxbrain" });
85
- this.models = {
86
- conversation: opts.conversationModel,
87
- identity: opts.identityModel,
88
- };
89
- }
90
-
91
- async call<T>(model: string, options: CallOptions): Promise<T> {
92
- const jsonMode = "jsonSchemaName" in options;
93
- log.debug(
94
- `call: model=${model} jsonSchema=${jsonMode ? options.jsonSchemaName : "-"} msgLen=${options.message.length}`,
95
- );
96
- const result = await this.client.chat.send({
97
- chatRequest: {
98
- model,
99
- messages: [
100
- { role: "system", content: options.instruction },
101
- { role: "user", content: options.message },
102
- ],
103
- reasoning: {
104
- effort:
105
- options.reasoningEffort ??
106
- (model === this.models.identity
107
- ? REASONING_EFFORT_MAP.medium
108
- : REASONING_EFFORT_MAP.none),
109
- },
110
- responseFormat: jsonMode
111
- ? {
112
- type: "json_schema",
113
- jsonSchema: {
114
- name: options.jsonSchemaName,
115
- schema: options.jsonSchema,
116
- strict: true,
117
- },
118
- }
119
- : { type: "text" },
120
- stream: false,
121
- },
122
- });
123
-
124
- const content = result.choices[0]?.message?.content;
125
- if (!content) {
126
- log.debug(`call: empty content in choice 0`);
127
- throw new Error("Empty response from model");
128
- }
129
- log.debug(`call: response ${content.length} chars`);
130
-
131
- return (jsonMode ? JSON.parse(content) : content) as T;
132
- }
133
-
134
- async chatWithTools(
135
- model: string,
136
- options: ChatWithToolsOptions,
137
- ): Promise<ChatChoice> {
138
- log.debug(
139
- `chatWithTools: model=${model} msgs=${options.messages.length} tools=${options.tools.length}`,
140
- );
141
- const result = await this.client.chat.send({
142
- chatRequest: {
143
- model,
144
- messages: [
145
- { role: "system", content: options.instruction },
146
- ...options.messages.map(toOrMessage),
147
- ],
148
- reasoning: {
149
- effort:
150
- options.reasoningEffort ??
151
- (model === this.models.identity
152
- ? REASONING_EFFORT_MAP.medium
153
- : REASONING_EFFORT_MAP.none),
154
- },
155
- responseFormat: { type: "text" },
156
- tools: options.tools.map(toOrTool),
157
- parallelToolCalls: options.parallelToolCalls ?? false,
158
- stream: false,
159
- },
160
- });
161
-
162
- const choice = result.choices[0];
163
- if (!choice) {
164
- log.debug(`chatWithTools: no choice in response`);
165
- throw new Error("LLM returned no choice");
166
- }
167
- const calls = choice.message.toolCalls?.length ?? 0;
168
- const textLen =
169
- typeof choice.message.content === "string"
170
- ? choice.message.content.length
171
- : 0;
172
- log.debug(`chatWithTools: choice toolCalls=${calls} text=${textLen}`);
173
- return fromOrChoice(choice);
174
- }
175
- }
@@ -1,17 +0,0 @@
1
- import { OpenAICompatibleExecutor } from "./openai_compatible";
2
-
3
- export class OvhCloudExecutor extends OpenAICompatibleExecutor {
4
- constructor(opts: {
5
- apiKey: string;
6
- conversationModel: string;
7
- identityModel: string;
8
- }) {
9
- super({
10
- providerName: "ovhcloud",
11
- baseURL: "https://oai.endpoints.kepler.ai.cloud.ovh.net/v1",
12
- apiKey: opts.apiKey,
13
- conversationModel: opts.conversationModel,
14
- identityModel: opts.identityModel,
15
- });
16
- }
17
- }
@@ -1,22 +0,0 @@
1
- import { OpenAICompatibleExecutor } from "./openai_compatible";
2
- import { readAuthString } from "../llm";
3
-
4
- export class SapAiCoreExecutor extends OpenAICompatibleExecutor {
5
- constructor(opts: {
6
- apiKey: string;
7
- conversationModel: string;
8
- identityModel: string;
9
- auth?: Record<string, unknown>;
10
- }) {
11
- const baseURL =
12
- readAuthString(opts.auth, "baseURL", "SAP_AI_CORE_BASE_URL") ||
13
- "https://api.ai.prod.eu-central-1.aws.ml.hana.ondemand.com/v2";
14
- super({
15
- providerName: "sap-aicore",
16
- baseURL,
17
- apiKey: opts.apiKey,
18
- conversationModel: opts.conversationModel,
19
- identityModel: opts.identityModel,
20
- });
21
- }
22
- }
@@ -1,17 +0,0 @@
1
- import { OpenAICompatibleExecutor } from "./openai_compatible";
2
-
3
- export class ScalewayExecutor extends OpenAICompatibleExecutor {
4
- constructor(opts: {
5
- apiKey: string;
6
- conversationModel: string;
7
- identityModel: string;
8
- }) {
9
- super({
10
- providerName: "scaleway",
11
- baseURL: "https://api.scaleway.ai/v1",
12
- apiKey: opts.apiKey,
13
- conversationModel: opts.conversationModel,
14
- identityModel: opts.identityModel,
15
- });
16
- }
17
- }