@jussmor/sdk-ai 0.2.0

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 (111) hide show
  1. package/dist/conversation-kIkMQdYK.d.cts +105 -0
  2. package/dist/conversation-kIkMQdYK.d.ts +105 -0
  3. package/dist/conversation-store-CAyPuBjk.d.ts +10 -0
  4. package/dist/conversation-store-Cl42jpsA.d.cts +10 -0
  5. package/dist/index.cjs +1630 -0
  6. package/dist/index.cjs.map +1 -0
  7. package/dist/index.d.cts +251 -0
  8. package/dist/index.d.ts +251 -0
  9. package/dist/index.js +1536 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/memory-uBLqrQRY.d.cts +28 -0
  12. package/dist/memory-uBLqrQRY.d.ts +28 -0
  13. package/dist/providers/llm/anthropic.cjs +275 -0
  14. package/dist/providers/llm/anthropic.cjs.map +1 -0
  15. package/dist/providers/llm/anthropic.d.cts +22 -0
  16. package/dist/providers/llm/anthropic.d.ts +22 -0
  17. package/dist/providers/llm/anthropic.js +240 -0
  18. package/dist/providers/llm/anthropic.js.map +1 -0
  19. package/dist/providers/llm/ollama.cjs +195 -0
  20. package/dist/providers/llm/ollama.cjs.map +1 -0
  21. package/dist/providers/llm/ollama.d.cts +23 -0
  22. package/dist/providers/llm/ollama.d.ts +23 -0
  23. package/dist/providers/llm/ollama.js +170 -0
  24. package/dist/providers/llm/ollama.js.map +1 -0
  25. package/dist/providers/llm/openai.cjs +213 -0
  26. package/dist/providers/llm/openai.cjs.map +1 -0
  27. package/dist/providers/llm/openai.d.cts +22 -0
  28. package/dist/providers/llm/openai.d.ts +22 -0
  29. package/dist/providers/llm/openai.js +178 -0
  30. package/dist/providers/llm/openai.js.map +1 -0
  31. package/dist/providers/memory/filesystem.cjs +112 -0
  32. package/dist/providers/memory/filesystem.cjs.map +1 -0
  33. package/dist/providers/memory/filesystem.d.cts +17 -0
  34. package/dist/providers/memory/filesystem.d.ts +17 -0
  35. package/dist/providers/memory/filesystem.js +87 -0
  36. package/dist/providers/memory/filesystem.js.map +1 -0
  37. package/dist/providers/store/filesystem.cjs +87 -0
  38. package/dist/providers/store/filesystem.cjs.map +1 -0
  39. package/dist/providers/store/filesystem.d.cts +14 -0
  40. package/dist/providers/store/filesystem.d.ts +14 -0
  41. package/dist/providers/store/filesystem.js +62 -0
  42. package/dist/providers/store/filesystem.js.map +1 -0
  43. package/dist/providers/thread/memory.cjs +81 -0
  44. package/dist/providers/thread/memory.cjs.map +1 -0
  45. package/dist/providers/thread/memory.d.cts +14 -0
  46. package/dist/providers/thread/memory.d.ts +14 -0
  47. package/dist/providers/thread/memory.js +56 -0
  48. package/dist/providers/thread/memory.js.map +1 -0
  49. package/dist/providers/thread/sqlite.cjs +917 -0
  50. package/dist/providers/thread/sqlite.cjs.map +1 -0
  51. package/dist/providers/thread/sqlite.d.cts +17 -0
  52. package/dist/providers/thread/sqlite.d.ts +17 -0
  53. package/dist/providers/thread/sqlite.js +911 -0
  54. package/dist/providers/thread/sqlite.js.map +1 -0
  55. package/dist/providers/tokenizers/auto.cjs +136 -0
  56. package/dist/providers/tokenizers/auto.cjs.map +1 -0
  57. package/dist/providers/tokenizers/auto.d.cts +24 -0
  58. package/dist/providers/tokenizers/auto.d.ts +24 -0
  59. package/dist/providers/tokenizers/auto.js +107 -0
  60. package/dist/providers/tokenizers/auto.js.map +1 -0
  61. package/dist/streaming-B-P6Fw_k.d.cts +372 -0
  62. package/dist/streaming-BtD23BE0.d.ts +372 -0
  63. package/dist/thread-C2b9xRMJ.d.cts +30 -0
  64. package/dist/thread-C2b9xRMJ.d.ts +30 -0
  65. package/dist/tokenizer-BhG_RGUk.d.cts +13 -0
  66. package/dist/tokenizer-BhG_RGUk.d.ts +13 -0
  67. package/package.json +84 -0
  68. package/src/agent-loop.ts +311 -0
  69. package/src/agent-source.ts +12 -0
  70. package/src/artifact.ts +31 -0
  71. package/src/compaction.ts +75 -0
  72. package/src/context-budget.ts +65 -0
  73. package/src/conversation-store.ts +8 -0
  74. package/src/conversation.ts +42 -0
  75. package/src/dispatch.ts +207 -0
  76. package/src/engine.ts +53 -0
  77. package/src/execution-context.ts +31 -0
  78. package/src/index.ts +37 -0
  79. package/src/interrupt-store.ts +25 -0
  80. package/src/interrupt.ts +55 -0
  81. package/src/llm-router.ts +34 -0
  82. package/src/llm.ts +100 -0
  83. package/src/memory-selector.ts +38 -0
  84. package/src/memory.ts +34 -0
  85. package/src/mode.ts +81 -0
  86. package/src/permissions.ts +104 -0
  87. package/src/protocol.ts +1 -0
  88. package/src/providers/llm/anthropic.ts +298 -0
  89. package/src/providers/llm/ollama.ts +219 -0
  90. package/src/providers/llm/openai.ts +215 -0
  91. package/src/providers/memory/filesystem.ts +99 -0
  92. package/src/providers/store/filesystem.ts +64 -0
  93. package/src/providers/thread/memory.ts +67 -0
  94. package/src/providers/thread/sqlite.ts +147 -0
  95. package/src/providers/tokenizers/auto.ts +26 -0
  96. package/src/providers/tokenizers/byte.ts +27 -0
  97. package/src/providers/tokenizers/tiktoken.ts +91 -0
  98. package/src/reasoning.ts +7 -0
  99. package/src/rule-matcher.ts +32 -0
  100. package/src/runtime.ts +416 -0
  101. package/src/safety.ts +56 -0
  102. package/src/sandbox.ts +23 -0
  103. package/src/session-context.ts +33 -0
  104. package/src/skill-source.ts +21 -0
  105. package/src/streaming.ts +124 -0
  106. package/src/system-prompt.ts +71 -0
  107. package/src/system-reminder.ts +9 -0
  108. package/src/thread.ts +33 -0
  109. package/src/tokenizer.ts +31 -0
  110. package/src/tool.ts +175 -0
  111. package/src/tracing.ts +63 -0
@@ -0,0 +1,170 @@
1
+ // src/providers/llm/ollama.ts
2
+ function toOllamaMessages(messages) {
3
+ const out = [];
4
+ for (const msg of messages) {
5
+ if (msg.role === "system") {
6
+ out.push({ role: "system", content: msg.content });
7
+ continue;
8
+ }
9
+ if (msg.role === "tool") {
10
+ out.push({ role: "tool", content: msg.content });
11
+ continue;
12
+ }
13
+ const om = { role: msg.role, content: msg.content };
14
+ if (msg.images?.length) {
15
+ om.images = msg.images.filter((i) => i.source).map((i) => i.source);
16
+ }
17
+ if (msg.toolCalls?.length) {
18
+ om.tool_calls = msg.toolCalls.map((tc) => ({
19
+ function: {
20
+ name: tc.name,
21
+ arguments: JSON.parse(tc.arguments)
22
+ }
23
+ }));
24
+ }
25
+ out.push(om);
26
+ }
27
+ return out;
28
+ }
29
+ var OllamaProvider = class {
30
+ baseURL;
31
+ defaultModel;
32
+ nativeToolCalls;
33
+ temperature;
34
+ constructor(opts = {}) {
35
+ this.baseURL = (opts.baseURL ?? process.env["OLLAMA_BASE_URL"] ?? "http://localhost:11434").replace(/\/$/, "");
36
+ this.defaultModel = opts.defaultModel ?? "llama3.1";
37
+ this.nativeToolCalls = opts.nativeToolCalls ?? false;
38
+ this.temperature = opts.temperature;
39
+ }
40
+ async chat(req, signal) {
41
+ const body = {
42
+ model: req.model ?? this.defaultModel,
43
+ messages: toOllamaMessages(req.messages),
44
+ stream: false,
45
+ options: this.temperature != null ? { temperature: this.temperature } : void 0
46
+ };
47
+ if (this.nativeToolCalls && req.tools?.length) {
48
+ body["tools"] = req.tools.map((t) => ({
49
+ type: "function",
50
+ function: {
51
+ name: t.function.name,
52
+ description: t.function.description,
53
+ parameters: t.function.parameters
54
+ }
55
+ }));
56
+ }
57
+ const resp = await fetch(`${this.baseURL}/api/chat`, {
58
+ method: "POST",
59
+ headers: { "Content-Type": "application/json" },
60
+ body: JSON.stringify(body),
61
+ signal
62
+ });
63
+ if (!resp.ok) {
64
+ throw new Error(`Ollama error: ${resp.status} ${await resp.text()}`);
65
+ }
66
+ const data = await resp.json();
67
+ const toolCalls = [];
68
+ if (data.message.tool_calls?.length) {
69
+ for (let i = 0; i < data.message.tool_calls.length; i++) {
70
+ const tc = data.message.tool_calls[i];
71
+ toolCalls.push({
72
+ id: `ollama-${i}`,
73
+ name: tc.function.name,
74
+ arguments: JSON.stringify(tc.function.arguments)
75
+ });
76
+ }
77
+ }
78
+ const promptTokens = data.prompt_eval_count ?? 0;
79
+ const completionTokens = data.eval_count ?? 0;
80
+ return {
81
+ content: data.message.content,
82
+ toolCalls: toolCalls.length ? toolCalls : void 0,
83
+ finishReason: data.done_reason ?? "stop",
84
+ usage: {
85
+ promptTokens,
86
+ completionTokens,
87
+ totalTokens: promptTokens + completionTokens
88
+ },
89
+ model: data.model
90
+ };
91
+ }
92
+ async *chatStream(req, signal) {
93
+ const body = {
94
+ model: req.model ?? this.defaultModel,
95
+ messages: toOllamaMessages(req.messages),
96
+ stream: true,
97
+ options: this.temperature != null ? { temperature: this.temperature } : void 0
98
+ };
99
+ if (this.nativeToolCalls && req.tools?.length) {
100
+ body["tools"] = req.tools.map((t) => ({
101
+ type: "function",
102
+ function: {
103
+ name: t.function.name,
104
+ description: t.function.description,
105
+ parameters: t.function.parameters
106
+ }
107
+ }));
108
+ }
109
+ const resp = await fetch(`${this.baseURL}/api/chat`, {
110
+ method: "POST",
111
+ headers: { "Content-Type": "application/json" },
112
+ body: JSON.stringify(body),
113
+ signal
114
+ });
115
+ if (!resp.ok) {
116
+ throw new Error(`Ollama error: ${resp.status} ${await resp.text()}`);
117
+ }
118
+ const reader = resp.body?.getReader();
119
+ if (!reader) throw new Error("Ollama: no response body");
120
+ const decoder = new TextDecoder();
121
+ let buf = "";
122
+ let promptTokens = 0;
123
+ let completionTokens = 0;
124
+ let fullContent = "";
125
+ while (true) {
126
+ const { done, value } = await reader.read();
127
+ if (done) break;
128
+ if (signal?.aborted) {
129
+ reader.cancel();
130
+ break;
131
+ }
132
+ buf += decoder.decode(value, { stream: true });
133
+ const lines = buf.split("\n");
134
+ buf = lines.pop() ?? "";
135
+ for (const line of lines) {
136
+ const trimmed = line.trim();
137
+ if (!trimmed) continue;
138
+ const data = JSON.parse(trimmed);
139
+ if (data.message?.content) {
140
+ fullContent += data.message.content;
141
+ yield { type: "delta", delta: data.message.content };
142
+ }
143
+ if (data.done) {
144
+ promptTokens = data.prompt_eval_count ?? 0;
145
+ completionTokens = data.eval_count ?? 0;
146
+ yield {
147
+ type: "done",
148
+ final: {
149
+ finalContent: fullContent,
150
+ providerReasoning: "",
151
+ totalTurns: 1,
152
+ totalUsage: {
153
+ promptTokens,
154
+ completionTokens,
155
+ totalTokens: promptTokens + completionTokens
156
+ },
157
+ messages: [],
158
+ reasoningTrace: [],
159
+ stopReason: "complete"
160
+ }
161
+ };
162
+ }
163
+ }
164
+ }
165
+ }
166
+ };
167
+ export {
168
+ OllamaProvider
169
+ };
170
+ //# sourceMappingURL=ollama.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/providers/llm/ollama.ts"],"sourcesContent":["import type {\n LLMProvider,\n ChatRequest,\n ChatResponse,\n ChatMessage,\n ToolCallEntry,\n} from \"../../llm.js\";\nimport type { StreamingLLMProvider, StreamEvent } from \"../../streaming.js\";\n\ninterface OllamaMessage {\n role: string;\n content: string;\n images?: string[];\n tool_calls?: Array<{\n function: { name: string; arguments: Record<string, unknown> };\n }>;\n}\n\ninterface OllamaChatResponse {\n model: string;\n message: OllamaMessage;\n done: boolean;\n done_reason?: string;\n prompt_eval_count?: number;\n eval_count?: number;\n}\n\nfunction toOllamaMessages(messages: ChatMessage[]): OllamaMessage[] {\n const out: OllamaMessage[] = [];\n for (const msg of messages) {\n if (msg.role === \"system\") {\n out.push({ role: \"system\", content: msg.content });\n continue;\n }\n if (msg.role === \"tool\") {\n out.push({ role: \"tool\", content: msg.content });\n continue;\n }\n const om: OllamaMessage = { role: msg.role, content: msg.content };\n if (msg.images?.length) {\n om.images = msg.images\n .filter((i) => i.source)\n .map((i) => i.source!);\n }\n if (msg.toolCalls?.length) {\n om.tool_calls = msg.toolCalls.map((tc) => ({\n function: {\n name: tc.name,\n arguments: JSON.parse(tc.arguments) as Record<string, unknown>,\n },\n }));\n }\n out.push(om);\n }\n return out;\n}\n\nexport interface OllamaProviderOptions {\n baseURL?: string;\n defaultModel?: string;\n nativeToolCalls?: boolean;\n temperature?: number;\n}\n\nexport class OllamaProvider implements StreamingLLMProvider {\n private baseURL: string;\n private defaultModel: string;\n private nativeToolCalls: boolean;\n private temperature?: number;\n\n constructor(opts: OllamaProviderOptions = {}) {\n this.baseURL =\n (opts.baseURL ?? process.env[\"OLLAMA_BASE_URL\"] ?? \"http://localhost:11434\").replace(/\\/$/, \"\");\n this.defaultModel = opts.defaultModel ?? \"llama3.1\";\n this.nativeToolCalls = opts.nativeToolCalls ?? false;\n this.temperature = opts.temperature;\n }\n\n async chat(req: ChatRequest, signal?: AbortSignal): Promise<ChatResponse> {\n const body: Record<string, unknown> = {\n model: req.model ?? this.defaultModel,\n messages: toOllamaMessages(req.messages),\n stream: false,\n options: this.temperature != null ? { temperature: this.temperature } : undefined,\n };\n\n if (this.nativeToolCalls && req.tools?.length) {\n body[\"tools\"] = req.tools.map((t) => ({\n type: \"function\",\n function: {\n name: t.function.name,\n description: t.function.description,\n parameters: t.function.parameters,\n },\n }));\n }\n\n const resp = await fetch(`${this.baseURL}/api/chat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n signal,\n });\n\n if (!resp.ok) {\n throw new Error(`Ollama error: ${resp.status} ${await resp.text()}`);\n }\n\n const data = (await resp.json()) as OllamaChatResponse;\n const toolCalls: ToolCallEntry[] = [];\n\n if (data.message.tool_calls?.length) {\n for (let i = 0; i < data.message.tool_calls.length; i++) {\n const tc = data.message.tool_calls[i]!;\n toolCalls.push({\n id: `ollama-${i}`,\n name: tc.function.name,\n arguments: JSON.stringify(tc.function.arguments),\n });\n }\n }\n\n const promptTokens = data.prompt_eval_count ?? 0;\n const completionTokens = data.eval_count ?? 0;\n\n return {\n content: data.message.content,\n toolCalls: toolCalls.length ? toolCalls : undefined,\n finishReason: data.done_reason ?? \"stop\",\n usage: {\n promptTokens,\n completionTokens,\n totalTokens: promptTokens + completionTokens,\n },\n model: data.model,\n };\n }\n\n async *chatStream(\n req: ChatRequest,\n signal?: AbortSignal,\n ): AsyncGenerator<StreamEvent> {\n const body: Record<string, unknown> = {\n model: req.model ?? this.defaultModel,\n messages: toOllamaMessages(req.messages),\n stream: true,\n options: this.temperature != null ? { temperature: this.temperature } : undefined,\n };\n\n if (this.nativeToolCalls && req.tools?.length) {\n body[\"tools\"] = req.tools.map((t) => ({\n type: \"function\",\n function: {\n name: t.function.name,\n description: t.function.description,\n parameters: t.function.parameters,\n },\n }));\n }\n\n const resp = await fetch(`${this.baseURL}/api/chat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n signal,\n });\n\n if (!resp.ok) {\n throw new Error(`Ollama error: ${resp.status} ${await resp.text()}`);\n }\n\n const reader = resp.body?.getReader();\n if (!reader) throw new Error(\"Ollama: no response body\");\n\n const decoder = new TextDecoder();\n let buf = \"\";\n let promptTokens = 0;\n let completionTokens = 0;\n let fullContent = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (signal?.aborted) { reader.cancel(); break; }\n buf += decoder.decode(value, { stream: true });\n const lines = buf.split(\"\\n\");\n buf = lines.pop() ?? \"\";\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n const data = JSON.parse(trimmed) as OllamaChatResponse;\n if (data.message?.content) {\n fullContent += data.message.content;\n yield { type: \"delta\", delta: data.message.content };\n }\n if (data.done) {\n promptTokens = data.prompt_eval_count ?? 0;\n completionTokens = data.eval_count ?? 0;\n yield {\n type: \"done\",\n final: {\n finalContent: fullContent,\n providerReasoning: \"\",\n totalTurns: 1,\n totalUsage: {\n promptTokens,\n completionTokens,\n totalTokens: promptTokens + completionTokens,\n },\n messages: [],\n reasoningTrace: [],\n stopReason: \"complete\",\n },\n };\n }\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/providers/llm/openai.ts
31
+ var openai_exports = {};
32
+ __export(openai_exports, {
33
+ OpenAIProvider: () => OpenAIProvider
34
+ });
35
+ module.exports = __toCommonJS(openai_exports);
36
+ var import_openai = __toESM(require("openai"), 1);
37
+ function toOpenAIMessages(messages) {
38
+ return messages.map((msg) => {
39
+ if (msg.role === "system") {
40
+ return { role: "system", content: msg.content };
41
+ }
42
+ if (msg.role === "tool") {
43
+ return {
44
+ role: "tool",
45
+ tool_call_id: msg.toolCallId ?? "",
46
+ content: msg.content
47
+ };
48
+ }
49
+ if (msg.role === "assistant") {
50
+ const out = {
51
+ role: "assistant",
52
+ content: msg.content || null
53
+ };
54
+ if (msg.toolCalls?.length) {
55
+ out.tool_calls = msg.toolCalls.map((tc) => ({
56
+ id: tc.id,
57
+ type: "function",
58
+ function: { name: tc.name, arguments: tc.arguments }
59
+ }));
60
+ }
61
+ return out;
62
+ }
63
+ if (msg.images?.length) {
64
+ const content = msg.images.map(
65
+ (img) => img.url ? { type: "image_url", image_url: { url: img.url } } : {
66
+ type: "image_url",
67
+ image_url: {
68
+ url: `data:${img.mediaType};base64,${img.source}`
69
+ }
70
+ }
71
+ );
72
+ if (msg.content) content.push({ type: "text", text: msg.content });
73
+ return { role: "user", content };
74
+ }
75
+ return { role: "user", content: msg.content };
76
+ });
77
+ }
78
+ var OpenAIProvider = class {
79
+ client;
80
+ defaultModel;
81
+ defaultMaxTokens;
82
+ constructor(opts = {}) {
83
+ this.client = new import_openai.default({
84
+ apiKey: opts.apiKey ?? process.env["OPENAI_API_KEY"],
85
+ baseURL: opts.baseURL ?? process.env["OPENAI_BASE_URL"]
86
+ });
87
+ this.defaultModel = opts.defaultModel ?? "gpt-4o";
88
+ this.defaultMaxTokens = opts.defaultMaxTokens ?? 4096;
89
+ }
90
+ async chat(req, signal) {
91
+ const messages = toOpenAIMessages(req.messages);
92
+ const tools = req.tools?.map((t) => ({
93
+ type: "function",
94
+ function: {
95
+ name: t.function.name,
96
+ description: t.function.description,
97
+ parameters: t.function.parameters
98
+ }
99
+ }));
100
+ const resp = await this.client.chat.completions.create(
101
+ {
102
+ model: req.model ?? this.defaultModel,
103
+ messages,
104
+ max_tokens: req.maxTokens ?? this.defaultMaxTokens,
105
+ ...tools?.length ? { tools } : {},
106
+ ...req.temperature != null ? { temperature: req.temperature } : {},
107
+ ...req.topP != null ? { top_p: req.topP } : {},
108
+ ...req.stop?.length ? { stop: req.stop } : {}
109
+ },
110
+ { signal }
111
+ );
112
+ const choice = resp.choices[0];
113
+ const msg = choice?.message;
114
+ return {
115
+ content: msg?.content ?? "",
116
+ toolCalls: msg?.tool_calls?.map((tc) => ({
117
+ id: tc.id,
118
+ name: tc.function.name,
119
+ arguments: tc.function.arguments
120
+ })),
121
+ finishReason: choice?.finish_reason ?? "stop",
122
+ usage: {
123
+ promptTokens: resp.usage?.prompt_tokens ?? 0,
124
+ completionTokens: resp.usage?.completion_tokens ?? 0,
125
+ totalTokens: resp.usage?.total_tokens ?? 0
126
+ },
127
+ model: resp.model
128
+ };
129
+ }
130
+ async *chatStream(req, signal) {
131
+ const messages = toOpenAIMessages(req.messages);
132
+ const tools = req.tools?.map((t) => ({
133
+ type: "function",
134
+ function: {
135
+ name: t.function.name,
136
+ description: t.function.description,
137
+ parameters: t.function.parameters
138
+ }
139
+ }));
140
+ const stream = await this.client.chat.completions.create(
141
+ {
142
+ model: req.model ?? this.defaultModel,
143
+ messages,
144
+ max_tokens: req.maxTokens ?? this.defaultMaxTokens,
145
+ stream: true,
146
+ stream_options: { include_usage: true },
147
+ ...tools?.length ? { tools } : {},
148
+ ...req.temperature != null ? { temperature: req.temperature } : {},
149
+ ...req.topP != null ? { top_p: req.topP } : {},
150
+ ...req.stop?.length ? { stop: req.stop } : {}
151
+ },
152
+ { signal }
153
+ );
154
+ const toolCallBufs = /* @__PURE__ */ new Map();
155
+ let promptTokens = 0;
156
+ let completionTokens = 0;
157
+ for await (const chunk of stream) {
158
+ if (signal?.aborted) break;
159
+ if (chunk.usage) {
160
+ promptTokens = chunk.usage.prompt_tokens;
161
+ completionTokens = chunk.usage.completion_tokens;
162
+ }
163
+ const delta = chunk.choices[0]?.delta;
164
+ if (!delta) continue;
165
+ if (delta.content) {
166
+ yield { type: "delta", delta: delta.content };
167
+ }
168
+ if (delta.tool_calls) {
169
+ for (const tc of delta.tool_calls) {
170
+ const idx = tc.index;
171
+ if (!toolCallBufs.has(idx)) {
172
+ toolCallBufs.set(idx, { id: tc.id ?? "", name: tc.function?.name ?? "", argsBuf: "" });
173
+ }
174
+ const buf = toolCallBufs.get(idx);
175
+ if (tc.id) buf.id = tc.id;
176
+ if (tc.function?.name) buf.name = tc.function.name;
177
+ if (tc.function?.arguments) buf.argsBuf += tc.function.arguments;
178
+ }
179
+ }
180
+ const finishReason = chunk.choices[0]?.finish_reason;
181
+ if (finishReason) {
182
+ for (const [, tc] of toolCallBufs) {
183
+ yield {
184
+ type: "tool_call",
185
+ toolCall: { id: tc.id, name: tc.name, arguments: tc.argsBuf }
186
+ };
187
+ }
188
+ toolCallBufs.clear();
189
+ yield {
190
+ type: "done",
191
+ final: {
192
+ finalContent: "",
193
+ providerReasoning: "",
194
+ totalTurns: 1,
195
+ totalUsage: {
196
+ promptTokens,
197
+ completionTokens,
198
+ totalTokens: promptTokens + completionTokens
199
+ },
200
+ messages: [],
201
+ reasoningTrace: [],
202
+ stopReason: "complete"
203
+ }
204
+ };
205
+ }
206
+ }
207
+ }
208
+ };
209
+ // Annotate the CommonJS export names for ESM import in node:
210
+ 0 && (module.exports = {
211
+ OpenAIProvider
212
+ });
213
+ //# sourceMappingURL=openai.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/providers/llm/openai.ts"],"sourcesContent":["import OpenAI from \"openai\";\nimport type {\n LLMProvider,\n ChatRequest,\n ChatResponse,\n ChatMessage,\n} from \"../../llm.js\";\nimport type { StreamingLLMProvider, StreamEvent } from \"../../streaming.js\";\n\nfunction toOpenAIMessages(\n messages: ChatMessage[],\n): OpenAI.ChatCompletionMessageParam[] {\n return messages.map((msg): OpenAI.ChatCompletionMessageParam => {\n if (msg.role === \"system\") {\n return { role: \"system\", content: msg.content };\n }\n if (msg.role === \"tool\") {\n return {\n role: \"tool\",\n tool_call_id: msg.toolCallId ?? \"\",\n content: msg.content,\n };\n }\n if (msg.role === \"assistant\") {\n const out: OpenAI.ChatCompletionAssistantMessageParam = {\n role: \"assistant\",\n content: msg.content || null,\n };\n if (msg.toolCalls?.length) {\n out.tool_calls = msg.toolCalls.map((tc) => ({\n id: tc.id,\n type: \"function\" as const,\n function: { name: tc.name, arguments: tc.arguments },\n }));\n }\n return out;\n }\n if (msg.images?.length) {\n const content: OpenAI.ChatCompletionContentPart[] = msg.images.map(\n (img) =>\n img.url\n ? ({ type: \"image_url\", image_url: { url: img.url } } as const)\n : ({\n type: \"image_url\",\n image_url: {\n url: `data:${img.mediaType};base64,${img.source}`,\n },\n } as const),\n );\n if (msg.content) content.push({ type: \"text\", text: msg.content });\n return { role: \"user\", content };\n }\n return { role: \"user\", content: msg.content };\n });\n}\n\nexport interface OpenAIProviderOptions {\n apiKey?: string;\n baseURL?: string;\n defaultModel?: string;\n defaultMaxTokens?: number;\n}\n\nexport class OpenAIProvider implements StreamingLLMProvider {\n private client: OpenAI;\n private defaultModel: string;\n private defaultMaxTokens: number;\n\n constructor(opts: OpenAIProviderOptions = {}) {\n this.client = new OpenAI({\n apiKey: opts.apiKey ?? process.env[\"OPENAI_API_KEY\"],\n baseURL: opts.baseURL ?? process.env[\"OPENAI_BASE_URL\"],\n });\n this.defaultModel = opts.defaultModel ?? \"gpt-4o\";\n this.defaultMaxTokens = opts.defaultMaxTokens ?? 4096;\n }\n\n async chat(req: ChatRequest, signal?: AbortSignal): Promise<ChatResponse> {\n const messages = toOpenAIMessages(req.messages);\n const tools = req.tools?.map((t) => ({\n type: \"function\" as const,\n function: {\n name: t.function.name,\n description: t.function.description,\n parameters: t.function.parameters as unknown as Record<string, unknown>,\n },\n }));\n\n const resp = await this.client.chat.completions.create(\n {\n model: req.model ?? this.defaultModel,\n messages,\n max_tokens: req.maxTokens ?? this.defaultMaxTokens,\n ...(tools?.length ? { tools } : {}),\n ...(req.temperature != null ? { temperature: req.temperature } : {}),\n ...(req.topP != null ? { top_p: req.topP } : {}),\n ...(req.stop?.length ? { stop: req.stop } : {}),\n },\n { signal },\n );\n\n const choice = resp.choices[0];\n const msg = choice?.message;\n\n return {\n content: msg?.content ?? \"\",\n toolCalls: msg?.tool_calls?.map((tc) => ({\n id: tc.id,\n name: tc.function.name,\n arguments: tc.function.arguments,\n })),\n finishReason: choice?.finish_reason ?? \"stop\",\n usage: {\n promptTokens: resp.usage?.prompt_tokens ?? 0,\n completionTokens: resp.usage?.completion_tokens ?? 0,\n totalTokens: resp.usage?.total_tokens ?? 0,\n },\n model: resp.model,\n };\n }\n\n async *chatStream(\n req: ChatRequest,\n signal?: AbortSignal,\n ): AsyncGenerator<StreamEvent> {\n const messages = toOpenAIMessages(req.messages);\n const tools = req.tools?.map((t) => ({\n type: \"function\" as const,\n function: {\n name: t.function.name,\n description: t.function.description,\n parameters: t.function.parameters as unknown as Record<string, unknown>,\n },\n }));\n\n const stream = await this.client.chat.completions.create(\n {\n model: req.model ?? this.defaultModel,\n messages,\n max_tokens: req.maxTokens ?? this.defaultMaxTokens,\n stream: true,\n stream_options: { include_usage: true },\n ...(tools?.length ? { tools } : {}),\n ...(req.temperature != null ? { temperature: req.temperature } : {}),\n ...(req.topP != null ? { top_p: req.topP } : {}),\n ...(req.stop?.length ? { stop: req.stop } : {}),\n },\n { signal },\n );\n\n const toolCallBufs = new Map<\n number,\n { id: string; name: string; argsBuf: string }\n >();\n let promptTokens = 0;\n let completionTokens = 0;\n\n for await (const chunk of stream) {\n if (signal?.aborted) break;\n\n if (chunk.usage) {\n promptTokens = chunk.usage.prompt_tokens;\n completionTokens = chunk.usage.completion_tokens;\n }\n\n const delta = chunk.choices[0]?.delta;\n if (!delta) continue;\n\n if (delta.content) {\n yield { type: \"delta\", delta: delta.content };\n }\n\n if (delta.tool_calls) {\n for (const tc of delta.tool_calls) {\n const idx = tc.index;\n if (!toolCallBufs.has(idx)) {\n toolCallBufs.set(idx, { id: tc.id ?? \"\", name: tc.function?.name ?? \"\", argsBuf: \"\" });\n }\n const buf = toolCallBufs.get(idx)!;\n if (tc.id) buf.id = tc.id;\n if (tc.function?.name) buf.name = tc.function.name;\n if (tc.function?.arguments) buf.argsBuf += tc.function.arguments;\n }\n }\n\n const finishReason = chunk.choices[0]?.finish_reason;\n if (finishReason) {\n for (const [, tc] of toolCallBufs) {\n yield {\n type: \"tool_call\",\n toolCall: { id: tc.id, name: tc.name, arguments: tc.argsBuf },\n };\n }\n toolCallBufs.clear();\n\n yield {\n type: \"done\",\n final: {\n finalContent: \"\",\n providerReasoning: \"\",\n totalTurns: 1,\n totalUsage: {\n promptTokens,\n completionTokens,\n totalTokens: promptTokens + completionTokens,\n },\n messages: [],\n reasoningTrace: [],\n stopReason: \"complete\",\n },\n };\n }\n }\n }\n}\n"],"mappings":"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","names":["OpenAI"]}
@@ -0,0 +1,22 @@
1
+ import { b as ChatRequest, c as ChatResponse } from '../../conversation-kIkMQdYK.cjs';
2
+ import { G as StreamingLLMProvider, S as StreamEvent } from '../../streaming-B-P6Fw_k.cjs';
3
+ import '../../memory-uBLqrQRY.cjs';
4
+ import '../../thread-C2b9xRMJ.cjs';
5
+ import '../../tokenizer-BhG_RGUk.cjs';
6
+
7
+ interface OpenAIProviderOptions {
8
+ apiKey?: string;
9
+ baseURL?: string;
10
+ defaultModel?: string;
11
+ defaultMaxTokens?: number;
12
+ }
13
+ declare class OpenAIProvider implements StreamingLLMProvider {
14
+ private client;
15
+ private defaultModel;
16
+ private defaultMaxTokens;
17
+ constructor(opts?: OpenAIProviderOptions);
18
+ chat(req: ChatRequest, signal?: AbortSignal): Promise<ChatResponse>;
19
+ chatStream(req: ChatRequest, signal?: AbortSignal): AsyncGenerator<StreamEvent>;
20
+ }
21
+
22
+ export { OpenAIProvider, type OpenAIProviderOptions };
@@ -0,0 +1,22 @@
1
+ import { b as ChatRequest, c as ChatResponse } from '../../conversation-kIkMQdYK.js';
2
+ import { G as StreamingLLMProvider, S as StreamEvent } from '../../streaming-BtD23BE0.js';
3
+ import '../../memory-uBLqrQRY.js';
4
+ import '../../thread-C2b9xRMJ.js';
5
+ import '../../tokenizer-BhG_RGUk.js';
6
+
7
+ interface OpenAIProviderOptions {
8
+ apiKey?: string;
9
+ baseURL?: string;
10
+ defaultModel?: string;
11
+ defaultMaxTokens?: number;
12
+ }
13
+ declare class OpenAIProvider implements StreamingLLMProvider {
14
+ private client;
15
+ private defaultModel;
16
+ private defaultMaxTokens;
17
+ constructor(opts?: OpenAIProviderOptions);
18
+ chat(req: ChatRequest, signal?: AbortSignal): Promise<ChatResponse>;
19
+ chatStream(req: ChatRequest, signal?: AbortSignal): AsyncGenerator<StreamEvent>;
20
+ }
21
+
22
+ export { OpenAIProvider, type OpenAIProviderOptions };
@@ -0,0 +1,178 @@
1
+ // src/providers/llm/openai.ts
2
+ import OpenAI from "openai";
3
+ function toOpenAIMessages(messages) {
4
+ return messages.map((msg) => {
5
+ if (msg.role === "system") {
6
+ return { role: "system", content: msg.content };
7
+ }
8
+ if (msg.role === "tool") {
9
+ return {
10
+ role: "tool",
11
+ tool_call_id: msg.toolCallId ?? "",
12
+ content: msg.content
13
+ };
14
+ }
15
+ if (msg.role === "assistant") {
16
+ const out = {
17
+ role: "assistant",
18
+ content: msg.content || null
19
+ };
20
+ if (msg.toolCalls?.length) {
21
+ out.tool_calls = msg.toolCalls.map((tc) => ({
22
+ id: tc.id,
23
+ type: "function",
24
+ function: { name: tc.name, arguments: tc.arguments }
25
+ }));
26
+ }
27
+ return out;
28
+ }
29
+ if (msg.images?.length) {
30
+ const content = msg.images.map(
31
+ (img) => img.url ? { type: "image_url", image_url: { url: img.url } } : {
32
+ type: "image_url",
33
+ image_url: {
34
+ url: `data:${img.mediaType};base64,${img.source}`
35
+ }
36
+ }
37
+ );
38
+ if (msg.content) content.push({ type: "text", text: msg.content });
39
+ return { role: "user", content };
40
+ }
41
+ return { role: "user", content: msg.content };
42
+ });
43
+ }
44
+ var OpenAIProvider = class {
45
+ client;
46
+ defaultModel;
47
+ defaultMaxTokens;
48
+ constructor(opts = {}) {
49
+ this.client = new OpenAI({
50
+ apiKey: opts.apiKey ?? process.env["OPENAI_API_KEY"],
51
+ baseURL: opts.baseURL ?? process.env["OPENAI_BASE_URL"]
52
+ });
53
+ this.defaultModel = opts.defaultModel ?? "gpt-4o";
54
+ this.defaultMaxTokens = opts.defaultMaxTokens ?? 4096;
55
+ }
56
+ async chat(req, signal) {
57
+ const messages = toOpenAIMessages(req.messages);
58
+ const tools = req.tools?.map((t) => ({
59
+ type: "function",
60
+ function: {
61
+ name: t.function.name,
62
+ description: t.function.description,
63
+ parameters: t.function.parameters
64
+ }
65
+ }));
66
+ const resp = await this.client.chat.completions.create(
67
+ {
68
+ model: req.model ?? this.defaultModel,
69
+ messages,
70
+ max_tokens: req.maxTokens ?? this.defaultMaxTokens,
71
+ ...tools?.length ? { tools } : {},
72
+ ...req.temperature != null ? { temperature: req.temperature } : {},
73
+ ...req.topP != null ? { top_p: req.topP } : {},
74
+ ...req.stop?.length ? { stop: req.stop } : {}
75
+ },
76
+ { signal }
77
+ );
78
+ const choice = resp.choices[0];
79
+ const msg = choice?.message;
80
+ return {
81
+ content: msg?.content ?? "",
82
+ toolCalls: msg?.tool_calls?.map((tc) => ({
83
+ id: tc.id,
84
+ name: tc.function.name,
85
+ arguments: tc.function.arguments
86
+ })),
87
+ finishReason: choice?.finish_reason ?? "stop",
88
+ usage: {
89
+ promptTokens: resp.usage?.prompt_tokens ?? 0,
90
+ completionTokens: resp.usage?.completion_tokens ?? 0,
91
+ totalTokens: resp.usage?.total_tokens ?? 0
92
+ },
93
+ model: resp.model
94
+ };
95
+ }
96
+ async *chatStream(req, signal) {
97
+ const messages = toOpenAIMessages(req.messages);
98
+ const tools = req.tools?.map((t) => ({
99
+ type: "function",
100
+ function: {
101
+ name: t.function.name,
102
+ description: t.function.description,
103
+ parameters: t.function.parameters
104
+ }
105
+ }));
106
+ const stream = await this.client.chat.completions.create(
107
+ {
108
+ model: req.model ?? this.defaultModel,
109
+ messages,
110
+ max_tokens: req.maxTokens ?? this.defaultMaxTokens,
111
+ stream: true,
112
+ stream_options: { include_usage: true },
113
+ ...tools?.length ? { tools } : {},
114
+ ...req.temperature != null ? { temperature: req.temperature } : {},
115
+ ...req.topP != null ? { top_p: req.topP } : {},
116
+ ...req.stop?.length ? { stop: req.stop } : {}
117
+ },
118
+ { signal }
119
+ );
120
+ const toolCallBufs = /* @__PURE__ */ new Map();
121
+ let promptTokens = 0;
122
+ let completionTokens = 0;
123
+ for await (const chunk of stream) {
124
+ if (signal?.aborted) break;
125
+ if (chunk.usage) {
126
+ promptTokens = chunk.usage.prompt_tokens;
127
+ completionTokens = chunk.usage.completion_tokens;
128
+ }
129
+ const delta = chunk.choices[0]?.delta;
130
+ if (!delta) continue;
131
+ if (delta.content) {
132
+ yield { type: "delta", delta: delta.content };
133
+ }
134
+ if (delta.tool_calls) {
135
+ for (const tc of delta.tool_calls) {
136
+ const idx = tc.index;
137
+ if (!toolCallBufs.has(idx)) {
138
+ toolCallBufs.set(idx, { id: tc.id ?? "", name: tc.function?.name ?? "", argsBuf: "" });
139
+ }
140
+ const buf = toolCallBufs.get(idx);
141
+ if (tc.id) buf.id = tc.id;
142
+ if (tc.function?.name) buf.name = tc.function.name;
143
+ if (tc.function?.arguments) buf.argsBuf += tc.function.arguments;
144
+ }
145
+ }
146
+ const finishReason = chunk.choices[0]?.finish_reason;
147
+ if (finishReason) {
148
+ for (const [, tc] of toolCallBufs) {
149
+ yield {
150
+ type: "tool_call",
151
+ toolCall: { id: tc.id, name: tc.name, arguments: tc.argsBuf }
152
+ };
153
+ }
154
+ toolCallBufs.clear();
155
+ yield {
156
+ type: "done",
157
+ final: {
158
+ finalContent: "",
159
+ providerReasoning: "",
160
+ totalTurns: 1,
161
+ totalUsage: {
162
+ promptTokens,
163
+ completionTokens,
164
+ totalTokens: promptTokens + completionTokens
165
+ },
166
+ messages: [],
167
+ reasoningTrace: [],
168
+ stopReason: "complete"
169
+ }
170
+ };
171
+ }
172
+ }
173
+ }
174
+ };
175
+ export {
176
+ OpenAIProvider
177
+ };
178
+ //# sourceMappingURL=openai.js.map