@bolt-foundry/gambit 0.8.6 → 1.0.0-rc.2

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 +54 -2
  2. package/README.md +165 -50
  3. package/esm/mod.d.ts +11 -3
  4. package/esm/mod.d.ts.map +1 -1
  5. package/esm/mod.js +7 -1
  6. package/esm/src/codex_app_server_debug.d.ts +1 -1
  7. package/esm/src/codex_app_server_debug.d.ts.map +1 -1
  8. package/esm/src/codex_app_server_debug.js +1 -1
  9. package/esm/src/codex_auth.d.ts +1 -1
  10. package/esm/src/codex_auth.d.ts.map +1 -1
  11. package/esm/src/codex_auth.js +1 -1
  12. package/esm/src/default_runtime.d.ts +5 -1
  13. package/esm/src/default_runtime.d.ts.map +1 -1
  14. package/esm/src/default_runtime.js +48 -29
  15. package/esm/src/openai_compat.d.ts.map +1 -1
  16. package/esm/src/openai_compat.js +111 -11
  17. package/esm/src/providers/claude_code.d.ts.map +1 -1
  18. package/esm/src/providers/claude_code.js +3 -3
  19. package/esm/src/providers/codex.d.ts +12 -1
  20. package/esm/src/providers/codex.d.ts.map +1 -1
  21. package/esm/src/providers/codex.js +94 -30
  22. package/esm/src/providers/google.d.ts.map +1 -1
  23. package/esm/src/providers/google.js +7 -114
  24. package/esm/src/providers/manifest.d.ts +2 -2
  25. package/esm/src/providers/manifest.d.ts.map +1 -1
  26. package/esm/src/providers/manifest.js +5 -5
  27. package/esm/src/providers/ollama.d.ts.map +1 -1
  28. package/esm/src/providers/ollama.js +0 -112
  29. package/esm/src/providers/openrouter.d.ts.map +1 -1
  30. package/esm/src/providers/openrouter.js +0 -264
  31. package/esm/src/providers/requirements.js +1 -1
  32. package/package.json +1 -1
  33. package/script/mod.d.ts +11 -3
  34. package/script/mod.d.ts.map +1 -1
  35. package/script/mod.js +15 -6
  36. package/script/src/codex_app_server_debug.d.ts +1 -1
  37. package/script/src/codex_app_server_debug.d.ts.map +1 -1
  38. package/script/src/codex_app_server_debug.js +1 -1
  39. package/script/src/codex_auth.d.ts +1 -1
  40. package/script/src/codex_auth.d.ts.map +1 -1
  41. package/script/src/codex_auth.js +1 -1
  42. package/script/src/default_runtime.d.ts +5 -1
  43. package/script/src/default_runtime.d.ts.map +1 -1
  44. package/script/src/default_runtime.js +48 -28
  45. package/script/src/openai_compat.d.ts.map +1 -1
  46. package/script/src/openai_compat.js +110 -10
  47. package/script/src/providers/claude_code.d.ts.map +1 -1
  48. package/script/src/providers/claude_code.js +3 -3
  49. package/script/src/providers/codex.d.ts +12 -1
  50. package/script/src/providers/codex.d.ts.map +1 -1
  51. package/script/src/providers/codex.js +94 -29
  52. package/script/src/providers/google.d.ts.map +1 -1
  53. package/script/src/providers/google.js +7 -114
  54. package/script/src/providers/manifest.d.ts +2 -2
  55. package/script/src/providers/manifest.d.ts.map +1 -1
  56. package/script/src/providers/manifest.js +5 -5
  57. package/script/src/providers/ollama.d.ts.map +1 -1
  58. package/script/src/providers/ollama.js +0 -112
  59. package/script/src/providers/openrouter.d.ts.map +1 -1
  60. package/script/src/providers/openrouter.js +0 -264
  61. package/script/src/providers/requirements.js +1 -1
@@ -1,6 +1,6 @@
1
1
  import * as dntShim from "../../_dnt.shims.js";
2
2
  import * as path from "../../deps/jsr.io/@std/path/1.1.4/mod.js";
3
- import { loadDeck } from "@bolt-foundry/gambit-core";
3
+ import { joinTextParts, loadDeck } from "@bolt-foundry/gambit-core";
4
4
  import { logCodexAppServerDebug } from "../codex_app_server_debug.js";
5
5
  import { ensureTempMcpDenoConfigSync } from "../mcp_deno_config.js";
6
6
  export const CODEX_PREFIX = "codex-cli/";
@@ -13,13 +13,14 @@ const CODEX_REASONING_SUMMARY_ENV = "GAMBIT_CODEX_REASONING_SUMMARY";
13
13
  const CODEX_VERBOSITY_ENV = "GAMBIT_CODEX_VERBOSITY";
14
14
  const CODEX_BIN_ENV = "GAMBIT_CODEX_BIN";
15
15
  const CODEX_SKIP_SANDBOX_CONFIG_ENV = "GAMBIT_CODEX_SKIP_SANDBOX_CONFIG";
16
+ const CODEX_DISABLE_WEBSOCKETS_ENV = "GAMBIT_CODEX_DISABLE_WEBSOCKETS";
16
17
  const CODEX_DANGEROUS_BYPASS_ENV = "GAMBIT_CODEX_DANGEROUSLY_BYPASS_APPROVALS_AND_SANDBOX";
17
18
  const MCP_DENO_BIN_ENV = "GAMBIT_MCP_DENO_BIN";
18
19
  const MCP_ROOT_DECK_PATH_ENV = "GAMBIT_MCP_ROOT_DECK_PATH";
19
20
  const EXTERNAL_TOOL_BRIDGE_ENV = "GAMBIT_EXTERNAL_TOOL_BRIDGE";
20
21
  const MCP_DEBUG_LOG_PATH_ENV = "GAMBIT_MCP_DEBUG_LOG_PATH";
21
22
  const DENO_DIR_ENV = "DENO_DIR";
22
- const DEBUG_MCP_ENV = "BOLT_FOUNDRY_DESKTOP_CHIEF_RUNTIME_DEBUG_MCP";
23
+ const DEBUG_MCP_ENV = "GAMBIT_MCP_DEBUG";
23
24
  const MCP_SERVER_PATH = (() => {
24
25
  try {
25
26
  const moduleUrl = new URL(globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).url);
@@ -113,13 +114,24 @@ function shouldDebugMcpBridge() {
113
114
  const raw = dntShim.Deno.env.get(DEBUG_MCP_ENV)?.trim().toLowerCase();
114
115
  return raw === "1" || raw === "true" || raw === "yes";
115
116
  }
117
+ function isCodexNativeOrGambitBuiltinTool(name) {
118
+ return new Set([
119
+ "apply_patch",
120
+ "exec",
121
+ "gambit_consume_async_action",
122
+ "gambit_emit_output_item",
123
+ "grep_files",
124
+ "list_dir",
125
+ "read_file",
126
+ ]).has(name);
127
+ }
116
128
  function logCodexMcpDebug(event, details) {
117
129
  if (!shouldDebugMcpBridge())
118
130
  return;
119
131
  globalThis.console.error("[gambit-codex-mcp]", event, details ?? {});
120
132
  }
121
133
  function codexMcpDebugLogPath(cwd) {
122
- return path.join(cwd, ".boltfoundry", "runtime", "chief-runtime", "gambit-mcp-debug.log");
134
+ return path.join(cwd, ".workloop", "runtime", "chief-runtime", "gambit-mcp-debug.log");
123
135
  }
124
136
  function mcpServerDenoBin() {
125
137
  return dntShim.Deno.env.get(MCP_DENO_BIN_ENV)?.trim() || "deno";
@@ -157,6 +169,14 @@ function shouldSkipCodexSandboxConfig(params) {
157
169
  const envRaw = dntShim.Deno.env.get(CODEX_SKIP_SANDBOX_CONFIG_ENV);
158
170
  return Boolean(envRaw && parseTruthy(envRaw));
159
171
  }
172
+ function shouldDisableCodexWebsockets() {
173
+ // Newer Codex releases reserve built-in provider IDs, so overriding
174
+ // `model_providers.openai.supports_websockets` now prevents app-server
175
+ // startup. Keep the env var harmless while the old transport workaround ages
176
+ // out.
177
+ dntShim.Deno.env.get(CODEX_DISABLE_WEBSOCKETS_ENV);
178
+ return false;
179
+ }
160
180
  function tomlString(value) {
161
181
  return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
162
182
  }
@@ -244,6 +264,9 @@ function codexAdditionalConfigArgs(params) {
244
264
  function codexConfigArgs(input) {
245
265
  const args = [];
246
266
  args.push(...codexAdditionalConfigArgs(input.params));
267
+ if (shouldDisableCodexWebsockets()) {
268
+ args.push("-c", "model_providers.openai.supports_websockets=false");
269
+ }
247
270
  args.push("-c", `approval_policy=${tomlString("never")}`);
248
271
  const pathEnv = dntShim.Deno.env.get("PATH")?.trim();
249
272
  if (pathEnv) {
@@ -352,7 +375,15 @@ async function prepareCodexMcpRootDeck(input) {
352
375
  return {};
353
376
  }
354
377
  const deck = await loadDeck(rootDeckPath);
355
- if (deck.actionDecks.length === 0) {
378
+ const deckActionNames = new Set(deck.actionDecks.map((action) => action.name));
379
+ const deckToolNames = new Set(deck.tools.map((tool) => tool.name));
380
+ const extraExternalTools = (input.tools ?? [])
381
+ .map((tool) => tool.function)
382
+ .filter((tool) => tool &&
383
+ !isCodexNativeOrGambitBuiltinTool(tool.name) &&
384
+ !deckActionNames.has(tool.name) &&
385
+ !deckToolNames.has(tool.name));
386
+ if (deck.actionDecks.length === 0 && extraExternalTools.length === 0) {
356
387
  logCodexMcpDebug("prepareRootDeck:reuseOriginal", {
357
388
  actionCount: 0,
358
389
  deckPath: rootDeckPath,
@@ -386,15 +417,28 @@ async function prepareCodexMcpRootDeck(input) {
386
417
  }
387
418
  frontmatter.push("");
388
419
  }
420
+ for (const externalTool of extraExternalTools) {
421
+ frontmatter.push("[[tools]]");
422
+ frontmatter.push(`name = ${tomlString(externalTool.name)}`);
423
+ if (typeof externalTool.description === "string" &&
424
+ externalTool.description.trim()) {
425
+ frontmatter.push(`description = ${tomlString(externalTool.description.trim())}`);
426
+ }
427
+ frontmatter.push("");
428
+ }
389
429
  frontmatter.push("+++", "", "Codex MCP tool surface.");
390
430
  await dntShim.Deno.writeTextFile(tempDeckPath, frontmatter.join("\n"));
391
431
  logCodexMcpDebug("prepareRootDeck:synthesized", {
392
432
  actionCount: deck.actionDecks.length,
393
433
  actionNames: deck.actionDecks.map((action) => action.name),
434
+ extraToolNames: extraExternalTools.map((tool) => tool.name),
394
435
  rootDeckPath,
395
436
  synthesizedDeckPath: tempDeckPath,
396
- toolCount: deck.tools.length,
397
- toolNames: deck.tools.map((tool) => tool.name),
437
+ toolCount: deck.tools.length + extraExternalTools.length,
438
+ toolNames: [
439
+ ...deck.tools.map((tool) => tool.name),
440
+ ...extraExternalTools.map((tool) => tool.name),
441
+ ],
398
442
  });
399
443
  return {
400
444
  deckPath: tempDeckPath,
@@ -443,14 +487,22 @@ async function appServerRequestResult(input) {
443
487
  }
444
488
  if (input.method === "account/chatgptAuthTokens/refresh") {
445
489
  const bridge = requireCodexHostAuthBridge();
446
- const refreshed = await bridge.refreshAuthTokens({
447
- previousAccountId: typeof input.params.previousAccountId === "string"
448
- ? input.params.previousAccountId
449
- : null,
450
- reason: typeof input.params.reason === "string" && input.params.reason
451
- ? input.params.reason
452
- : "account/chatgptAuthTokens/refresh",
453
- });
490
+ let refreshed;
491
+ try {
492
+ refreshed = await bridge.refreshAuthTokens({
493
+ previousAccountId: typeof input.params.previousAccountId === "string"
494
+ ? input.params.previousAccountId
495
+ : null,
496
+ reason: typeof input.params.reason === "string" && input.params.reason
497
+ ? input.params.reason
498
+ : "account/chatgptAuthTokens/refresh",
499
+ });
500
+ }
501
+ catch (error) {
502
+ return {
503
+ error: appServerHostRequestFailure(error),
504
+ };
505
+ }
454
506
  return {
455
507
  result: {
456
508
  accessToken: refreshed.accessToken,
@@ -467,6 +519,14 @@ async function appServerRequestResult(input) {
467
519
  },
468
520
  };
469
521
  }
522
+ function appServerHostRequestFailure(error) {
523
+ return {
524
+ code: -32000,
525
+ message: error instanceof Error && error.message
526
+ ? error.message
527
+ : String(error),
528
+ };
529
+ }
470
530
  async function bootstrapCodexExternalAuth(input) {
471
531
  if (!codexHostAuthBridge) {
472
532
  return;
@@ -949,7 +1009,15 @@ async function defaultAppServerTurnRunner(input) {
949
1009
  method,
950
1010
  params: safeJsonObjectFromRecord(params),
951
1011
  });
952
- const response = await appServerRequestResult({ method, params });
1012
+ let response;
1013
+ try {
1014
+ response = await appServerRequestResult({ method, params });
1015
+ }
1016
+ catch (error) {
1017
+ response = {
1018
+ error: appServerHostRequestFailure(error),
1019
+ };
1020
+ }
953
1021
  logCodexAppServerDebug("message:host_response", {
954
1022
  method,
955
1023
  requestId,
@@ -1350,7 +1418,7 @@ function extractTextParts(value) {
1350
1418
  function extractCodexItemText(record) {
1351
1419
  return typeof record.text === "string"
1352
1420
  ? record.text
1353
- : extractTextParts(record.content).join("");
1421
+ : joinTextParts(extractTextParts(record.content));
1354
1422
  }
1355
1423
  function requireCodexAssistantItemId(input) {
1356
1424
  const itemId = typeof input.record.id === "string"
@@ -1459,7 +1527,7 @@ function emitCodexReasoningEvents(input) {
1459
1527
  if (payloadType === "item.delta") {
1460
1528
  const deltaText = typeof record.text === "string"
1461
1529
  ? record.text
1462
- : extractTextParts(record.content).join("");
1530
+ : joinTextParts(extractTextParts(record.content));
1463
1531
  if (deltaText) {
1464
1532
  input.emit({
1465
1533
  type: "response.reasoning.delta",
@@ -1473,7 +1541,7 @@ function emitCodexReasoningEvents(input) {
1473
1541
  if (payloadType === "item.completed" || payloadType === "item.done") {
1474
1542
  const doneText = typeof record.text === "string"
1475
1543
  ? record.text
1476
- : extractTextParts(record.content).join("");
1544
+ : joinTextParts(extractTextParts(record.content));
1477
1545
  input.emit({
1478
1546
  type: "response.reasoning.done",
1479
1547
  output_index: outputIndex,
@@ -1567,7 +1635,7 @@ function responseItemsToChatMessages(items, instructions) {
1567
1635
  }
1568
1636
  for (const item of items) {
1569
1637
  if (item.type === "message") {
1570
- const content = item.content.map((part) => part.text).join("");
1638
+ const content = joinTextParts(item.content.map((part) => part.text));
1571
1639
  messages.push({ role: item.role, content });
1572
1640
  continue;
1573
1641
  }
@@ -1855,11 +1923,13 @@ export function createCodexProvider(opts) {
1855
1923
  const cwd = codexRunCwd({ deckPath: input.deckPath });
1856
1924
  const preparedMcpRoot = await prepareCodexMcpRootDeck({
1857
1925
  deckPath: input.deckPath,
1926
+ tools: input.tools,
1858
1927
  });
1859
1928
  try {
1860
1929
  const result = await runAppServerTurn({
1861
1930
  model: input.model,
1862
1931
  messages: input.messages,
1932
+ tools: input.tools,
1863
1933
  state: input.state,
1864
1934
  params: input.params,
1865
1935
  deckPath: preparedMcpRoot.deckPath ?? input.deckPath,
@@ -1871,7 +1941,7 @@ export function createCodexProvider(opts) {
1871
1941
  cwd,
1872
1942
  priorThreadId,
1873
1943
  });
1874
- const assistantText = result.assistantMessages.map((message) => message.text).join("");
1944
+ const assistantText = joinTextParts(result.assistantMessages.map((message) => message.text));
1875
1945
  if (input.stream && input.onStreamText && assistantText &&
1876
1946
  !assistantState.sawAssistantTextStream) {
1877
1947
  input.onStreamText(assistantText);
@@ -1896,15 +1966,6 @@ export function createCodexProvider(opts) {
1896
1966
  await preparedMcpRoot.cleanup?.();
1897
1967
  }
1898
1968
  };
1899
- const runChat = async (input) => {
1900
- const result = await runCodexTurn(input);
1901
- return {
1902
- message: result.message,
1903
- finishReason: result.finishReason,
1904
- updatedState: result.updatedState,
1905
- usage: result.usage,
1906
- };
1907
- };
1908
1969
  return {
1909
1970
  async responses(input) {
1910
1971
  const streamHandler = input.onStreamEvent
@@ -1937,6 +1998,7 @@ export function createCodexProvider(opts) {
1937
1998
  const result = await runCodexTurn({
1938
1999
  model: input.request.model,
1939
2000
  messages: responseItemsToChatMessages(input.request.input, input.request.instructions),
2001
+ tools: input.request.tools,
1940
2002
  stream: input.request.stream,
1941
2003
  params: input.request.params,
1942
2004
  state: input.state,
@@ -2052,7 +2114,6 @@ export function createCodexProvider(opts) {
2052
2114
  }
2053
2115
  return response;
2054
2116
  },
2055
- chat: runChat,
2056
2117
  };
2057
2118
  }
2058
2119
  export function normalizeCodexModelForTest(model) {
@@ -2070,6 +2131,9 @@ export function codexConfigArgsForTest(input) {
2070
2131
  export function safeJsonForTest(text) {
2071
2132
  return safeJsonObject(text);
2072
2133
  }
2134
+ export async function appServerRequestResultForTest(input) {
2135
+ return await appServerRequestResult(input);
2136
+ }
2073
2137
  export function sanitizeCodexSpawnArgsForTest(args) {
2074
2138
  return sanitizeCodexSpawnArgsForDebug(args);
2075
2139
  }
@@ -1 +1 @@
1
- {"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../../src/src/providers/google.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAIV,aAAa,EAId,MAAM,2BAA2B,CAAC;AAEnC,eAAO,MAAM,aAAa,YAAY,CAAC;AAIvC,KAAK,YAAY,GAAG;IAClB,IAAI,EAAE;QACJ,WAAW,EAAE;YACX,MAAM,EAAE,CACN,MAAM,EAAE,OAAO,EACf,OAAO,CAAC,EAAE;gBAAE,MAAM,CAAC,EAAE,WAAW,CAAA;aAAE,KAC/B,OAAO,CAAC,OAAO,CAAC,CAAC;SACvB,CAAC;KACH,CAAC;CACH,CAAC;AA8IF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,GAAG,aAAa,CA6XhB"}
1
+ {"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../../src/src/providers/google.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAIV,aAAa,EAId,MAAM,2BAA2B,CAAC;AAGnC,eAAO,MAAM,aAAa,YAAY,CAAC;AAIvC,KAAK,YAAY,GAAG;IAClB,IAAI,EAAE;QACJ,WAAW,EAAE;YACX,MAAM,EAAE,CACN,MAAM,EAAE,OAAO,EACf,OAAO,CAAC,EAAE;gBAAE,MAAM,CAAC,EAAE,WAAW,CAAA;aAAE,KAC/B,OAAO,CAAC,OAAO,CAAC,CAAC;SACvB,CAAC;KACH,CAAC;CACH,CAAC;AA8IF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,GAAG,aAAa,CA+OhB"}
@@ -1,4 +1,5 @@
1
1
  import OpenAI from "openai";
2
+ import { joinTextParts } from "@bolt-foundry/gambit-core";
2
3
  export const GOOGLE_PREFIX = "google/";
3
4
  const DEFAULT_GOOGLE_BASE_URL = "https://generativelanguage.googleapis.com/v1beta/openai/";
4
5
  function safeJson(input) {
@@ -17,9 +18,9 @@ function extractContent(content) {
17
18
  if (typeof content === "string")
18
19
  return content;
19
20
  if (Array.isArray(content)) {
20
- return content
21
+ return joinTextParts(content
21
22
  .map((part) => (typeof part === "string" ? part : part.text ?? ""))
22
- .join("");
23
+ .filter(Boolean));
23
24
  }
24
25
  return "";
25
26
  }
@@ -53,9 +54,7 @@ function responseItemsToChatMessages(items, instructions) {
53
54
  }
54
55
  for (const item of items) {
55
56
  if (item.type === "message") {
56
- const content = item.content
57
- .map((part) => part.text)
58
- .join("");
57
+ const content = joinTextParts(item.content.map((part) => part.text));
59
58
  messages.push({ role: item.role, content });
60
59
  continue;
61
60
  }
@@ -198,9 +197,9 @@ export function createGoogleProvider(opts) {
198
197
  });
199
198
  }
200
199
  else if (Array.isArray(delta.content)) {
201
- const text = delta.content
200
+ const text = joinTextParts(delta.content
202
201
  .map((part) => (typeof part === "string" ? part : part.text ?? ""))
203
- .join("");
202
+ .filter(Boolean));
204
203
  if (text) {
205
204
  contentParts.push(text);
206
205
  input.onStreamEvent?.({
@@ -238,7 +237,7 @@ export function createGoogleProvider(opts) {
238
237
  }));
239
238
  const message = normalizeMessage({
240
239
  role: "assistant",
241
- content: contentParts.length ? contentParts.join("") : null,
240
+ content: contentParts.length ? joinTextParts(contentParts) : null,
242
241
  tool_calls,
243
242
  });
244
243
  const toolCalls = tool_calls.length > 0
@@ -321,111 +320,5 @@ export function createGoogleProvider(opts) {
321
320
  usage: mapChatUsage(response.usage),
322
321
  };
323
322
  },
324
- async chat(input) {
325
- const params = input.params ?? {};
326
- if (input.stream) {
327
- const stream = await client.chat.completions.create({
328
- model: input.model,
329
- messages: input.messages,
330
- tools: input
331
- // this predates the lint rule
332
- .tools,
333
- tool_choice: "auto",
334
- stream: true,
335
- ...params,
336
- }, input.signal ? { signal: input.signal } : undefined);
337
- let finishReason = null;
338
- const contentParts = [];
339
- const toolCallMap = new Map();
340
- for await (const chunk of stream) {
341
- const choice = chunk.choices[0];
342
- const fr = choice.finish_reason;
343
- if (fr === "stop" || fr === "tool_calls" || fr === "length" ||
344
- fr === null) {
345
- finishReason = fr ?? finishReason;
346
- }
347
- const delta = choice.delta;
348
- if (typeof delta.content === "string") {
349
- contentParts.push(delta.content);
350
- input.onStreamText?.(delta.content);
351
- }
352
- else if (Array.isArray(delta.content)) {
353
- const chunkStr = delta.content
354
- .map((c) => (typeof c === "string" ? c : c.text ?? ""))
355
- .join("");
356
- if (chunkStr) {
357
- contentParts.push(chunkStr);
358
- input.onStreamText?.(chunkStr);
359
- }
360
- }
361
- for (const tc of delta.tool_calls ?? []) {
362
- const idx = tc.index ?? 0;
363
- const existing = toolCallMap.get(idx) ??
364
- {
365
- id: tc.id,
366
- function: { name: tc.function?.name, arguments: "" },
367
- };
368
- if (tc.id)
369
- existing.id = tc.id;
370
- if (tc.function?.name)
371
- existing.function.name = tc.function.name;
372
- if (tc.function?.arguments) {
373
- existing.function.arguments += tc.function.arguments;
374
- }
375
- toolCallMap.set(idx, existing);
376
- }
377
- }
378
- const tool_calls = Array.from(toolCallMap.values()).map((tc) => ({
379
- id: tc.id ?? crypto.randomUUID().replace(/-/g, "").slice(0, 24),
380
- type: "function",
381
- function: {
382
- name: tc.function.name ?? "",
383
- arguments: tc.function.arguments,
384
- },
385
- }));
386
- const message = normalizeMessage({
387
- role: "assistant",
388
- content: contentParts.length ? contentParts.join("") : null,
389
- tool_calls,
390
- });
391
- const toolCalls = tool_calls.length > 0
392
- ? tool_calls.map((tc) => ({
393
- id: tc.id,
394
- name: tc.function.name,
395
- args: safeJson(tc.function.arguments),
396
- }))
397
- : undefined;
398
- return {
399
- message,
400
- finishReason: finishReason ?? "stop",
401
- toolCalls,
402
- };
403
- }
404
- const response = await client.chat.completions.create({
405
- model: input.model,
406
- messages: input
407
- // this predates the lint rule
408
- .messages,
409
- tools: input
410
- // this predates the lint rule
411
- .tools,
412
- tool_choice: "auto",
413
- stream: false,
414
- ...params,
415
- }, input.signal ? { signal: input.signal } : undefined);
416
- const choice = response.choices[0];
417
- const message = normalizeMessage(choice.message);
418
- const toolCalls = choice.message.tool_calls?.map((tc) => ({
419
- id: tc.id,
420
- name: tc.function.name,
421
- args: safeJson(tc.function.arguments),
422
- }));
423
- return {
424
- message,
425
- finishReason: (choice.finish_reason ?? "stop"),
426
- toolCalls,
427
- usage: mapChatUsage(response.usage),
428
- };
429
- },
430
323
  };
431
324
  }
@@ -18,8 +18,8 @@ export type ProviderRuntimeAuthStateSource = {
18
18
  kind: "json-file";
19
19
  path: string;
20
20
  };
21
- export type ProviderStorageAuthority = "bfdesktop";
22
- export type ProviderAttachmentAuthority = "bfdesktop-mitm" | "runtime-env-placeholder";
21
+ export type ProviderStorageAuthority = "workloop";
22
+ export type ProviderAttachmentAuthority = "workloop-mitm" | "runtime-env-placeholder";
23
23
  export type ProviderDestinationScope = "declared-destinations";
24
24
  type BaseProviderAuthRequirements = {
25
25
  attachmentAuthority: ProviderAttachmentAuthority;
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/src/providers/manifest.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,WAAW,CAAC;AAEnD,MAAM,MAAM,2BAA2B,GACnC,gBAAgB,GAChB,yBAAyB,CAAC;AAE9B,MAAM,MAAM,wBAAwB,GAAG,uBAAuB,CAAC;AAE/D,KAAK,4BAA4B,GAAG;IAClC,mBAAmB,EAAE,2BAA2B,CAAC;IACjD,gBAAgB,EAAE,wBAAwB,CAAC;IAC3C,gBAAgB,EAAE,wBAAwB,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG,4BAA4B,GAAG;IAC1E,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,KAAK,CAAC,yBAAyB,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,yCAAyC,GACjD,4BAA4B,GAC5B;IACA,IAAI,EAAE,qBAAqB,CAAC;CAC7B,CAAC;AAEJ,MAAM,MAAM,wBAAwB,GAChC,8BAA8B,GAC9B,yCAAyC,CAAC;AAE9C,MAAM,MAAM,qBAAqB,GAAG;IAClC,GAAG,EAAE,WAAW,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,qBAAqB,CAAC;IAChC,IAAI,CAAC,EAAE,wBAAwB,CAAC;IAChC,YAAY,EAAE,KAAK,CAAC,8BAA8B,CAAC,CAAC;CACrD,CAAC;AAgRF,wBAAgB,oBAAoB,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAE9D;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,WAAW,GACpB,gBAAgB,GAAG,IAAI,CAEzB;AAED,wBAAgB,0BAA0B,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAEzE"}
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/src/providers/manifest.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,UAAU,CAAC;AAElD,MAAM,MAAM,2BAA2B,GACnC,eAAe,GACf,yBAAyB,CAAC;AAE9B,MAAM,MAAM,wBAAwB,GAAG,uBAAuB,CAAC;AAE/D,KAAK,4BAA4B,GAAG;IAClC,mBAAmB,EAAE,2BAA2B,CAAC;IACjD,gBAAgB,EAAE,wBAAwB,CAAC;IAC3C,gBAAgB,EAAE,wBAAwB,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG,4BAA4B,GAAG;IAC1E,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,KAAK,CAAC,yBAAyB,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,yCAAyC,GACjD,4BAA4B,GAC5B;IACA,IAAI,EAAE,qBAAqB,CAAC;CAC7B,CAAC;AAEJ,MAAM,MAAM,wBAAwB,GAChC,8BAA8B,GAC9B,yCAAyC,CAAC;AAE9C,MAAM,MAAM,qBAAqB,GAAG;IAClC,GAAG,EAAE,WAAW,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,qBAAqB,CAAC;IAChC,IAAI,CAAC,EAAE,wBAAwB,CAAC;IAChC,YAAY,EAAE,KAAK,CAAC,8BAA8B,CAAC,CAAC;CACrD,CAAC;AAgRF,wBAAgB,oBAAoB,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAE9D;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,WAAW,GACpB,gBAAgB,GAAG,IAAI,CAEzB;AAED,wBAAgB,0BAA0B,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAEzE"}
@@ -18,8 +18,8 @@ bareAlias = "codex-cli"
18
18
 
19
19
  [auth]
20
20
  mode = "chatgpt-auth-tokens"
21
- storageAuthority = "bfdesktop"
22
- attachmentAuthority = "bfdesktop-mitm"
21
+ storageAuthority = "workloop"
22
+ attachmentAuthority = "workloop-mitm"
23
23
  destinationScope = "declared-destinations"
24
24
 
25
25
  [[destinations]]
@@ -54,7 +54,7 @@ routingPrefix = "openrouter/"
54
54
 
55
55
  [auth]
56
56
  mode = "secret"
57
- storageAuthority = "bfdesktop"
57
+ storageAuthority = "workloop"
58
58
  attachmentAuthority = "runtime-env-placeholder"
59
59
  destinationScope = "declared-destinations"
60
60
 
@@ -71,10 +71,10 @@ function isSupportedProviderKey(value) {
71
71
  value === "codex-cli" || value === "claude-code-cli";
72
72
  }
73
73
  function isSupportedStorageAuthority(value) {
74
- return value === "bfdesktop";
74
+ return value === "workloop";
75
75
  }
76
76
  function isSupportedAttachmentAuthority(value) {
77
- return value === "bfdesktop-mitm" || value === "runtime-env-placeholder";
77
+ return value === "workloop-mitm" || value === "runtime-env-placeholder";
78
78
  }
79
79
  function isSupportedDestinationScope(value) {
80
80
  return value === "declared-destinations";
@@ -1 +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,CACN,MAAM,EAAE,OAAO,EACf,OAAO,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,WAAW,CAAA;SAAE,KAC/B,OAAO,CAAC,OAAO,CAAC,CAAC;KACvB,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;AA6wBD,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,CA0ChB"}
1
+ {"version":3,"file":"ollama.d.ts","sourceRoot":"","sources":["../../../src/src/providers/ollama.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAIV,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,CACN,MAAM,EAAE,OAAO,EACf,OAAO,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,WAAW,CAAA;SAAE,KAC/B,OAAO,CAAC,OAAO,CAAC,CAAC;KACvB,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;AA+pBD,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,CAiBhB"}
@@ -69,18 +69,6 @@ export async function ensureOllamaModel(model, baseURL) {
69
69
  }
70
70
  }
71
71
  }
72
- function safeJson(input) {
73
- try {
74
- const parsed = JSON.parse(input);
75
- if (parsed && typeof parsed === "object") {
76
- return parsed;
77
- }
78
- }
79
- catch {
80
- // fall through
81
- }
82
- return {};
83
- }
84
72
  function toJsonValue(value) {
85
73
  if (value === null || typeof value === "string" || typeof value === "boolean") {
86
74
  return value;
@@ -446,86 +434,6 @@ function toOpenAIInputItems(items) {
446
434
  }
447
435
  return mapped;
448
436
  }
449
- function chatMessagesToResponseItems(messages) {
450
- const items = [];
451
- for (const message of messages) {
452
- if (message.role === "tool") {
453
- if (message.tool_call_id &&
454
- typeof message.content === "string") {
455
- items.push({
456
- type: "function_call_output",
457
- call_id: message.tool_call_id,
458
- output: message.content,
459
- });
460
- }
461
- continue;
462
- }
463
- if (message.role === "system" || message.role === "user" ||
464
- message.role === "assistant") {
465
- const content = [];
466
- if (typeof message.content === "string" && message.content.length > 0) {
467
- content.push({
468
- type: message.role === "assistant" ? "output_text" : "input_text",
469
- text: message.content,
470
- });
471
- }
472
- if (content.length > 0) {
473
- items.push({
474
- type: "message",
475
- role: message.role,
476
- content,
477
- });
478
- }
479
- }
480
- if (message.role === "assistant" && message.tool_calls) {
481
- for (const call of message.tool_calls) {
482
- items.push({
483
- type: "function_call",
484
- call_id: call.id,
485
- name: call.function.name,
486
- arguments: call.function.arguments,
487
- });
488
- }
489
- }
490
- }
491
- return items;
492
- }
493
- function responseItemsToChat(items) {
494
- const textParts = [];
495
- const toolCalls = [];
496
- const messageToolCalls = [];
497
- for (const item of items) {
498
- if (item.type === "message" && item.role === "assistant") {
499
- for (const part of item.content) {
500
- if (part.type === "output_text") {
501
- textParts.push(part.text);
502
- }
503
- }
504
- }
505
- if (item.type === "function_call") {
506
- toolCalls.push({
507
- id: item.call_id,
508
- name: item.name,
509
- args: safeJson(item.arguments),
510
- });
511
- messageToolCalls.push({
512
- id: item.call_id,
513
- type: "function",
514
- function: { name: item.name, arguments: item.arguments },
515
- });
516
- }
517
- }
518
- const content = textParts.length > 0 ? textParts.join("") : null;
519
- const message = {
520
- role: "assistant",
521
- content,
522
- tool_calls: messageToolCalls.length > 0 ? messageToolCalls : undefined,
523
- };
524
- return {
525
- message,
526
- toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
527
- };
528
- }
529
437
  async function createResponse(client, request, signal, onStreamEvent) {
530
438
  const baseParams = {
531
439
  model: request.model,
@@ -769,25 +677,5 @@ export function createOllamaProvider(opts) {
769
677
  async responses(input) {
770
678
  return await createResponse(client, input.request, input.signal, input.onStreamEvent);
771
679
  },
772
- async chat(input) {
773
- const response = await createResponse(client, {
774
- model: input.model,
775
- input: chatMessagesToResponseItems(input.messages),
776
- tools: input.tools,
777
- stream: input.stream,
778
- params: input.params ?? {},
779
- }, input.signal, (event) => {
780
- if (event.type === "response.output_text.delta") {
781
- input.onStreamText?.(event.delta);
782
- }
783
- });
784
- const mapped = responseItemsToChat(response.output);
785
- return {
786
- message: mapped.message,
787
- finishReason: mapped.toolCalls ? "tool_calls" : "stop",
788
- toolCalls: mapped.toolCalls,
789
- usage: response.usage,
790
- };
791
- },
792
680
  };
793
681
  }
@@ -1 +1 @@
1
- {"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../../../src/src/providers/openrouter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAKV,aAAa,EAOd,MAAM,2BAA2B,CAAC;AAOnC,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAE/C,KAAK,YAAY,GAAG;IAClB,IAAI,EAAE;QACJ,WAAW,EAAE;YACX,MAAM,EAAE,CACN,MAAM,EAAE,OAAO,EACf,OAAO,CAAC,EAAE;gBAAE,MAAM,CAAC,EAAE,WAAW,CAAA;aAAE,KAC/B,OAAO,CAAC,OAAO,CAAC,CAAC;SACvB,CAAC;KACH,CAAC;IACF,SAAS,EAAE;QACT,MAAM,EAAE,CACN,MAAM,EAAE,OAAO,EACf,OAAO,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,WAAW,CAAA;SAAE,KAC/B,OAAO,CAAC,OAAO,CAAC,CAAC;KACvB,CAAC;CACH,CAAC;AAg0BF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,GAAG,aAAa,CA2OhB"}
1
+ {"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../../../src/src/providers/openrouter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAIV,aAAa,EAOd,MAAM,2BAA2B,CAAC;AAOnC,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAE/C,KAAK,YAAY,GAAG;IAClB,IAAI,EAAE;QACJ,WAAW,EAAE;YACX,MAAM,EAAE,CACN,MAAM,EAAE,OAAO,EACf,OAAO,CAAC,EAAE;gBAAE,MAAM,CAAC,EAAE,WAAW,CAAA;aAAE,KAC/B,OAAO,CAAC,OAAO,CAAC,CAAC;SACvB,CAAC;KACH,CAAC;IACF,SAAS,EAAE;QACT,MAAM,EAAE,CACN,MAAM,EAAE,OAAO,EACf,OAAO,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,WAAW,CAAA;SAAE,KAC/B,OAAO,CAAC,OAAO,CAAC,CAAC;KACvB,CAAC;CACH,CAAC;AA8rBF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,GAAG,aAAa,CAqBhB"}