@bolt-foundry/gambit 0.8.0 → 0.8.3

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 (61) hide show
  1. package/CHANGELOG.md +82 -2
  2. package/README.md +31 -9
  3. package/esm/gambit/simulator-ui/dist/bundle.js +4744 -4360
  4. package/esm/gambit/simulator-ui/dist/bundle.js.map +4 -4
  5. package/esm/gambit/simulator-ui/dist/favicon.ico +0 -0
  6. package/esm/mod.d.ts +7 -3
  7. package/esm/mod.d.ts.map +1 -1
  8. package/esm/mod.js +5 -1
  9. package/esm/src/cli_utils.d.ts +3 -2
  10. package/esm/src/cli_utils.d.ts.map +1 -1
  11. package/esm/src/cli_utils.js +43 -27
  12. package/esm/src/openai_compat.d.ts +63 -0
  13. package/esm/src/openai_compat.d.ts.map +1 -0
  14. package/esm/src/openai_compat.js +277 -0
  15. package/esm/src/providers/google.d.ts +16 -0
  16. package/esm/src/providers/google.d.ts.map +1 -0
  17. package/esm/src/providers/google.js +352 -0
  18. package/esm/src/providers/ollama.d.ts +17 -0
  19. package/esm/src/providers/ollama.d.ts.map +1 -0
  20. package/esm/src/providers/ollama.js +509 -0
  21. package/esm/src/providers/openrouter.d.ts +14 -1
  22. package/esm/src/providers/openrouter.d.ts.map +1 -1
  23. package/esm/src/providers/openrouter.js +460 -463
  24. package/esm/src/server.d.ts +4 -0
  25. package/esm/src/server.d.ts.map +1 -1
  26. package/esm/src/server.js +623 -164
  27. package/esm/src/trace.d.ts.map +1 -1
  28. package/esm/src/trace.js +3 -6
  29. package/package.json +2 -2
  30. package/script/gambit/simulator-ui/dist/bundle.js +4744 -4360
  31. package/script/gambit/simulator-ui/dist/bundle.js.map +4 -4
  32. package/script/gambit/simulator-ui/dist/favicon.ico +0 -0
  33. package/script/mod.d.ts +7 -3
  34. package/script/mod.d.ts.map +1 -1
  35. package/script/mod.js +9 -3
  36. package/script/src/cli_utils.d.ts +3 -2
  37. package/script/src/cli_utils.d.ts.map +1 -1
  38. package/script/src/cli_utils.js +42 -26
  39. package/script/src/openai_compat.d.ts +63 -0
  40. package/script/src/openai_compat.d.ts.map +1 -0
  41. package/script/src/openai_compat.js +281 -0
  42. package/script/src/providers/google.d.ts +16 -0
  43. package/script/src/providers/google.d.ts.map +1 -0
  44. package/script/src/providers/google.js +359 -0
  45. package/script/src/providers/ollama.d.ts +17 -0
  46. package/script/src/providers/ollama.d.ts.map +1 -0
  47. package/script/src/providers/ollama.js +551 -0
  48. package/script/src/providers/openrouter.d.ts +14 -1
  49. package/script/src/providers/openrouter.d.ts.map +1 -1
  50. package/script/src/providers/openrouter.js +461 -463
  51. package/script/src/server.d.ts +4 -0
  52. package/script/src/server.d.ts.map +1 -1
  53. package/script/src/server.js +623 -164
  54. package/script/src/trace.d.ts.map +1 -1
  55. package/script/src/trace.js +3 -6
  56. package/esm/src/compat/openai.d.ts +0 -2
  57. package/esm/src/compat/openai.d.ts.map +0 -1
  58. package/esm/src/compat/openai.js +0 -1
  59. package/script/src/compat/openai.d.ts +0 -2
  60. package/script/src/compat/openai.d.ts.map +0 -1
  61. package/script/src/compat/openai.js +0 -5
@@ -0,0 +1,359 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.GOOGLE_PREFIX = void 0;
7
+ exports.createGoogleProvider = createGoogleProvider;
8
+ const openai_1 = __importDefault(require("openai"));
9
+ exports.GOOGLE_PREFIX = "google/";
10
+ const DEFAULT_GOOGLE_BASE_URL = "https://generativelanguage.googleapis.com/v1beta/openai/";
11
+ function safeJson(input) {
12
+ try {
13
+ const parsed = JSON.parse(input);
14
+ if (parsed && typeof parsed === "object") {
15
+ return parsed;
16
+ }
17
+ }
18
+ catch {
19
+ // fall through
20
+ }
21
+ return {};
22
+ }
23
+ function extractContent(content) {
24
+ if (typeof content === "string")
25
+ return content;
26
+ if (Array.isArray(content)) {
27
+ return content
28
+ .map((part) => (typeof part === "string" ? part : part.text ?? ""))
29
+ .join("");
30
+ }
31
+ return "";
32
+ }
33
+ function normalizeMessage(content) {
34
+ const toolCalls = content.tool_calls ??
35
+ undefined;
36
+ return {
37
+ role: content.role,
38
+ content: extractContent(content.content),
39
+ name: content.name,
40
+ tool_call_id: content.tool_call_id,
41
+ tool_calls: toolCalls && toolCalls.length > 0 ? toolCalls : undefined,
42
+ };
43
+ }
44
+ function toToolChoice(choice) {
45
+ if (!choice)
46
+ return undefined;
47
+ if (choice === "auto" || choice === "required")
48
+ return choice;
49
+ return { type: "function", function: { name: choice.function.name } };
50
+ }
51
+ function responseItemsToChatMessages(items, instructions) {
52
+ const messages = [];
53
+ if (instructions) {
54
+ messages.push({ role: "system", content: instructions });
55
+ }
56
+ for (const item of items) {
57
+ if (item.type === "message") {
58
+ const content = item.content
59
+ .map((part) => part.text)
60
+ .join("");
61
+ messages.push({ role: item.role, content });
62
+ continue;
63
+ }
64
+ if (item.type === "function_call") {
65
+ messages.push({
66
+ role: "assistant",
67
+ content: null,
68
+ tool_calls: [{
69
+ id: item.call_id,
70
+ type: "function",
71
+ function: { name: item.name, arguments: item.arguments },
72
+ }],
73
+ });
74
+ continue;
75
+ }
76
+ if (item.type === "function_call_output") {
77
+ messages.push({
78
+ role: "tool",
79
+ content: item.output,
80
+ tool_call_id: item.call_id,
81
+ });
82
+ }
83
+ }
84
+ return messages;
85
+ }
86
+ function responseItemsFromChatMessage(message, toolCalls) {
87
+ const output = [];
88
+ if (typeof message.content === "string" && message.content.length > 0) {
89
+ output.push({
90
+ type: "message",
91
+ role: "assistant",
92
+ content: [{ type: "output_text", text: message.content }],
93
+ });
94
+ }
95
+ if (toolCalls) {
96
+ for (const call of toolCalls) {
97
+ output.push({
98
+ type: "function_call",
99
+ call_id: call.id,
100
+ name: call.name,
101
+ arguments: JSON.stringify(call.args),
102
+ });
103
+ }
104
+ }
105
+ else if (message.tool_calls) {
106
+ for (const call of message.tool_calls) {
107
+ output.push({
108
+ type: "function_call",
109
+ call_id: call.id,
110
+ name: call.function.name,
111
+ arguments: call.function.arguments,
112
+ });
113
+ }
114
+ }
115
+ return output;
116
+ }
117
+ function mapChatUsage(usage) {
118
+ if (!usage)
119
+ return undefined;
120
+ return {
121
+ promptTokens: usage.prompt_tokens ?? 0,
122
+ completionTokens: usage.completion_tokens ?? 0,
123
+ totalTokens: usage.total_tokens ?? 0,
124
+ };
125
+ }
126
+ function createGoogleProvider(opts) {
127
+ const client = (opts.client ??
128
+ new openai_1.default({
129
+ apiKey: opts.apiKey,
130
+ baseURL: opts.baseURL ?? DEFAULT_GOOGLE_BASE_URL,
131
+ }));
132
+ return {
133
+ async responses(input) {
134
+ const request = input.request;
135
+ const params = { ...(request.params ?? {}) };
136
+ if (request.max_output_tokens !== undefined &&
137
+ params.max_tokens === undefined) {
138
+ params.max_tokens = request.max_output_tokens;
139
+ }
140
+ const messages = responseItemsToChatMessages(request.input, request.instructions);
141
+ const toolChoice = toToolChoice(request.tool_choice);
142
+ if (request.stream) {
143
+ const stream = await client.chat.completions.create({
144
+ model: request.model,
145
+ messages: messages,
146
+ tools: request.tools,
147
+ tool_choice: toolChoice ?? "auto",
148
+ stream: true,
149
+ ...params,
150
+ });
151
+ const contentParts = [];
152
+ const toolCallMap = new Map();
153
+ let responseId;
154
+ let created;
155
+ for await (const chunk of stream) {
156
+ responseId = responseId ?? chunk.id;
157
+ created = created ?? chunk.created;
158
+ const choice = chunk.choices[0];
159
+ const delta = choice.delta;
160
+ if (typeof delta.content === "string") {
161
+ contentParts.push(delta.content);
162
+ input.onStreamEvent?.({
163
+ type: "response.output_text.delta",
164
+ output_index: 0,
165
+ delta: delta.content,
166
+ });
167
+ }
168
+ else if (Array.isArray(delta.content)) {
169
+ const text = delta.content
170
+ .map((part) => (typeof part === "string" ? part : part.text ?? ""))
171
+ .join("");
172
+ if (text) {
173
+ contentParts.push(text);
174
+ input.onStreamEvent?.({
175
+ type: "response.output_text.delta",
176
+ output_index: 0,
177
+ delta: text,
178
+ });
179
+ }
180
+ }
181
+ for (const tc of delta.tool_calls ?? []) {
182
+ const idx = tc.index ?? 0;
183
+ const existing = toolCallMap.get(idx) ??
184
+ {
185
+ id: tc.id,
186
+ function: { name: tc.function?.name, arguments: "" },
187
+ };
188
+ if (tc.id)
189
+ existing.id = tc.id;
190
+ if (tc.function?.name)
191
+ existing.function.name = tc.function.name;
192
+ if (tc.function?.arguments) {
193
+ existing.function.arguments += tc.function.arguments;
194
+ }
195
+ toolCallMap.set(idx, existing);
196
+ }
197
+ }
198
+ const tool_calls = Array.from(toolCallMap.values()).map((tc) => ({
199
+ id: tc.id ?? crypto.randomUUID().replace(/-/g, "").slice(0, 24),
200
+ type: "function",
201
+ function: {
202
+ name: tc.function.name ?? "",
203
+ arguments: tc.function.arguments,
204
+ },
205
+ }));
206
+ const message = normalizeMessage({
207
+ role: "assistant",
208
+ content: contentParts.length ? contentParts.join("") : null,
209
+ tool_calls,
210
+ });
211
+ const toolCalls = tool_calls.length > 0
212
+ ? tool_calls.map((tc) => ({
213
+ id: tc.id,
214
+ name: tc.function.name,
215
+ args: safeJson(tc.function.arguments),
216
+ }))
217
+ : undefined;
218
+ const output = responseItemsFromChatMessage(message, toolCalls);
219
+ const response = {
220
+ id: responseId ?? crypto.randomUUID(),
221
+ object: "response",
222
+ model: request.model,
223
+ created,
224
+ status: "completed",
225
+ output,
226
+ };
227
+ input.onStreamEvent?.({ type: "response.completed", response });
228
+ return response;
229
+ }
230
+ const response = await client.chat.completions.create({
231
+ model: request.model,
232
+ messages: messages,
233
+ tools: request.tools,
234
+ tool_choice: toolChoice ?? "auto",
235
+ stream: false,
236
+ ...params,
237
+ });
238
+ const choice = response.choices[0];
239
+ const normalizedMessage = normalizeMessage(choice.message);
240
+ const toolCalls = choice.message.tool_calls?.map((tc) => ({
241
+ id: tc.id,
242
+ name: tc.function.name,
243
+ args: safeJson(tc.function.arguments),
244
+ }));
245
+ return {
246
+ id: response.id,
247
+ object: "response",
248
+ model: response.model,
249
+ created: response.created,
250
+ status: "completed",
251
+ output: responseItemsFromChatMessage(normalizedMessage, toolCalls),
252
+ usage: mapChatUsage(response.usage),
253
+ };
254
+ },
255
+ async chat(input) {
256
+ const params = input.params ?? {};
257
+ if (input.stream) {
258
+ const stream = await client.chat.completions.create({
259
+ model: input.model,
260
+ messages: input.messages,
261
+ tools: input
262
+ .tools,
263
+ tool_choice: "auto",
264
+ stream: true,
265
+ ...params,
266
+ });
267
+ let finishReason = null;
268
+ const contentParts = [];
269
+ const toolCallMap = new Map();
270
+ for await (const chunk of stream) {
271
+ const choice = chunk.choices[0];
272
+ const fr = choice.finish_reason;
273
+ if (fr === "stop" || fr === "tool_calls" || fr === "length" ||
274
+ fr === null) {
275
+ finishReason = fr ?? finishReason;
276
+ }
277
+ const delta = choice.delta;
278
+ if (typeof delta.content === "string") {
279
+ contentParts.push(delta.content);
280
+ input.onStreamText?.(delta.content);
281
+ }
282
+ else if (Array.isArray(delta.content)) {
283
+ const chunkStr = delta.content
284
+ .map((c) => (typeof c === "string" ? c : c.text ?? ""))
285
+ .join("");
286
+ if (chunkStr) {
287
+ contentParts.push(chunkStr);
288
+ input.onStreamText?.(chunkStr);
289
+ }
290
+ }
291
+ for (const tc of delta.tool_calls ?? []) {
292
+ const idx = tc.index ?? 0;
293
+ const existing = toolCallMap.get(idx) ??
294
+ {
295
+ id: tc.id,
296
+ function: { name: tc.function?.name, arguments: "" },
297
+ };
298
+ if (tc.id)
299
+ existing.id = tc.id;
300
+ if (tc.function?.name)
301
+ existing.function.name = tc.function.name;
302
+ if (tc.function?.arguments) {
303
+ existing.function.arguments += tc.function.arguments;
304
+ }
305
+ toolCallMap.set(idx, existing);
306
+ }
307
+ }
308
+ const tool_calls = Array.from(toolCallMap.values()).map((tc) => ({
309
+ id: tc.id ?? crypto.randomUUID().replace(/-/g, "").slice(0, 24),
310
+ type: "function",
311
+ function: {
312
+ name: tc.function.name ?? "",
313
+ arguments: tc.function.arguments,
314
+ },
315
+ }));
316
+ const message = normalizeMessage({
317
+ role: "assistant",
318
+ content: contentParts.length ? contentParts.join("") : null,
319
+ tool_calls,
320
+ });
321
+ const toolCalls = tool_calls.length > 0
322
+ ? tool_calls.map((tc) => ({
323
+ id: tc.id,
324
+ name: tc.function.name,
325
+ args: safeJson(tc.function.arguments),
326
+ }))
327
+ : undefined;
328
+ return {
329
+ message,
330
+ finishReason: finishReason ?? "stop",
331
+ toolCalls,
332
+ };
333
+ }
334
+ const response = await client.chat.completions.create({
335
+ model: input.model,
336
+ messages: input
337
+ .messages,
338
+ tools: input
339
+ .tools,
340
+ tool_choice: "auto",
341
+ stream: false,
342
+ ...params,
343
+ });
344
+ const choice = response.choices[0];
345
+ const message = normalizeMessage(choice.message);
346
+ const toolCalls = choice.message.tool_calls?.map((tc) => ({
347
+ id: tc.id,
348
+ name: tc.function.name,
349
+ args: safeJson(tc.function.arguments),
350
+ }));
351
+ return {
352
+ message,
353
+ finishReason: (choice.finish_reason ?? "stop"),
354
+ toolCalls,
355
+ usage: mapChatUsage(response.usage),
356
+ };
357
+ },
358
+ };
359
+ }
@@ -0,0 +1,17 @@
1
+ import type { ModelProvider } from "@bolt-foundry/gambit-core";
2
+ export declare const OLLAMA_PREFIX = "ollama/";
3
+ export declare const DEFAULT_OLLAMA_BASE_URL = "http://localhost:11434/v1";
4
+ type OpenAIClient = {
5
+ responses: {
6
+ create: (params: unknown) => Promise<unknown>;
7
+ };
8
+ };
9
+ export declare function fetchOllamaTags(baseURL: string | undefined): Promise<Set<string>>;
10
+ export declare function ensureOllamaModel(model: string, baseURL: string | undefined): Promise<void>;
11
+ export declare function createOllamaProvider(opts: {
12
+ apiKey?: string;
13
+ baseURL?: string;
14
+ client?: OpenAIClient;
15
+ }): ModelProvider;
16
+ export {};
17
+ //# sourceMappingURL=ollama.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama.d.ts","sourceRoot":"","sources":["../../../src/src/providers/ollama.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAKV,aAAa,EAOd,MAAM,2BAA2B,CAAC;AAOnC,eAAO,MAAM,aAAa,YAAY,CAAC;AACvC,eAAO,MAAM,uBAAuB,8BAA8B,CAAC;AAEnE,KAAK,YAAY,GAAG;IAClB,SAAS,EAAE;QACT,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;KAC/C,CAAC;CACH,CAAC;AAeF,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,GAAG,SAAS,GAC1B,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAgBtB;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GAAG,SAAS,GAC1B,OAAO,CAAC,IAAI,CAAC,CA8Cf;AAodD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,GAAG,aAAa,CAoChB"}