@jambonz/llm 0.1.0 → 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.
@@ -212,6 +212,28 @@ async function* streamFromOpenAI(client, req, options) {
212
212
  };
213
213
  yield endEvent;
214
214
  }
215
+ function appendOpenAIAssistantToolCall(history, toolCalls) {
216
+ const wireMessage = {
217
+ role: "assistant",
218
+ content: null,
219
+ tool_calls: toolCalls.map((tc) => ({
220
+ id: tc.id,
221
+ type: "function",
222
+ function: {
223
+ name: tc.name,
224
+ arguments: typeof tc.arguments === "string" ? tc.arguments : JSON.stringify(tc.arguments ?? {})
225
+ }
226
+ }))
227
+ };
228
+ return [
229
+ ...history,
230
+ {
231
+ role: "assistant",
232
+ content: "",
233
+ vendorRaw: wireMessage
234
+ }
235
+ ];
236
+ }
215
237
  function appendOpenAIToolResult(history, toolCallId, result) {
216
238
  const content = typeof result === "string" ? result : JSON.stringify(result);
217
239
  const wireMessage = {
@@ -433,6 +455,9 @@ var OpenAIAdapter = class {
433
455
  knownModels: openAIManifest.knownModels
434
456
  });
435
457
  }
458
+ appendAssistantToolCall(history, toolCalls) {
459
+ return appendOpenAIAssistantToolCall(history, toolCalls);
460
+ }
436
461
  appendToolResult(history, toolCallId, result) {
437
462
  return appendOpenAIToolResult(history, toolCallId, result);
438
463
  }
@@ -783,6 +808,25 @@ var AnthropicAdapter = class {
783
808
  };
784
809
  yield endEvent;
785
810
  }
811
+ appendAssistantToolCall(history, toolCalls) {
812
+ const wireMessage = {
813
+ role: "assistant",
814
+ content: toolCalls.map((tc) => ({
815
+ type: "tool_use",
816
+ id: tc.id,
817
+ name: tc.name,
818
+ input: tc.arguments ?? {}
819
+ }))
820
+ };
821
+ return [
822
+ ...history,
823
+ {
824
+ role: "assistant",
825
+ content: "",
826
+ vendorRaw: wireMessage
827
+ }
828
+ ];
829
+ }
786
830
  appendToolResult(history, toolCallId, result) {
787
831
  const content = typeof result === "string" ? result : JSON.stringify(result);
788
832
  const wireMessage = {
@@ -998,6 +1042,25 @@ async function* streamFromGemini(client, req) {
998
1042
  };
999
1043
  yield endEvent;
1000
1044
  }
1045
+ function appendGeminiAssistantToolCall(history, toolCalls) {
1046
+ const wireMessage = {
1047
+ role: "model",
1048
+ parts: toolCalls.map((tc) => ({
1049
+ functionCall: {
1050
+ name: parseToolName(tc.id),
1051
+ args: tc.arguments ?? {}
1052
+ }
1053
+ }))
1054
+ };
1055
+ return [
1056
+ ...history,
1057
+ {
1058
+ role: "assistant",
1059
+ content: "",
1060
+ vendorRaw: wireMessage
1061
+ }
1062
+ ];
1063
+ }
1001
1064
  function appendGeminiToolResult(history, toolCallId, result) {
1002
1065
  const name = parseToolName(toolCallId);
1003
1066
  const content = typeof result === "string" ? result : JSON.stringify(result);
@@ -1220,6 +1283,9 @@ var GoogleAdapter = class {
1220
1283
  stream(req) {
1221
1284
  return streamFromGemini(this.ensureClient(), req);
1222
1285
  }
1286
+ appendAssistantToolCall(history, toolCalls) {
1287
+ return appendGeminiAssistantToolCall(history, toolCalls);
1288
+ }
1223
1289
  appendToolResult(history, toolCallId, result) {
1224
1290
  return appendGeminiToolResult(history, toolCallId, result);
1225
1291
  }
@@ -1387,6 +1453,9 @@ var VertexGeminiAdapter = class {
1387
1453
  stream(req) {
1388
1454
  return streamFromGemini(this.ensureClient(), req);
1389
1455
  }
1456
+ appendAssistantToolCall(history, toolCalls) {
1457
+ return appendGeminiAssistantToolCall(history, toolCalls);
1458
+ }
1390
1459
  appendToolResult(history, toolCallId, result) {
1391
1460
  return appendGeminiToolResult(history, toolCallId, result);
1392
1461
  }
@@ -1553,6 +1622,9 @@ var VertexOpenAIAdapter = class {
1553
1622
  knownModels: vertexOpenAIManifest.knownModels
1554
1623
  });
1555
1624
  }
1625
+ appendAssistantToolCall(history, toolCalls) {
1626
+ return appendOpenAIAssistantToolCall(history, toolCalls);
1627
+ }
1556
1628
  appendToolResult(history, toolCallId, result) {
1557
1629
  return appendOpenAIToolResult(history, toolCallId, result);
1558
1630
  }
@@ -1942,6 +2014,26 @@ var BedrockAdapter = class {
1942
2014
  };
1943
2015
  yield endEvent;
1944
2016
  }
2017
+ appendAssistantToolCall(history, toolCalls) {
2018
+ const wireMessage = {
2019
+ role: "assistant",
2020
+ content: toolCalls.map((tc) => ({
2021
+ toolUse: {
2022
+ toolUseId: tc.id,
2023
+ name: tc.name,
2024
+ input: tc.arguments ?? {}
2025
+ }
2026
+ }))
2027
+ };
2028
+ return [
2029
+ ...history,
2030
+ {
2031
+ role: "assistant",
2032
+ content: "",
2033
+ vendorRaw: wireMessage
2034
+ }
2035
+ ];
2036
+ }
1945
2037
  appendToolResult(history, toolCallId, result) {
1946
2038
  const text = typeof result === "string" ? result : JSON.stringify(result);
1947
2039
  const wireMessage = {
@@ -2269,12 +2361,11 @@ function runContractTests(harness) {
2269
2361
  (e) => e.type === "toolCall"
2270
2362
  );
2271
2363
  (0, import_vitest.expect)(tc).toBeDefined();
2272
- const history = [
2273
- { role: "user", content: "call it" },
2274
- harness.buildAssistantWithToolCall(tc)
2275
- ];
2276
- const withResult = adapter.appendToolResult(history, tc.id, { ok: true });
2277
- (0, import_vitest.expect)(withResult.length).toBe(history.length + 1);
2364
+ const baseHistory = [{ role: "user", content: "call it" }];
2365
+ const afterAssistant = adapter.appendAssistantToolCall(baseHistory, [tc]);
2366
+ (0, import_vitest.expect)(afterAssistant.length).toBe(baseHistory.length + 1);
2367
+ const withResult = adapter.appendToolResult(afterAssistant, tc.id, { ok: true });
2368
+ (0, import_vitest.expect)(withResult.length).toBe(afterAssistant.length + 1);
2278
2369
  await harness.mockScenario("simple-stream");
2279
2370
  await (0, import_vitest.expect)(
2280
2371
  drainStream(adapter, {
@@ -2362,11 +2453,11 @@ function runContractTests(harness) {
2362
2453
  (e) => e.type === "toolCall"
2363
2454
  );
2364
2455
  (0, import_vitest.expect)(tc).toBeDefined();
2365
- const history = [
2366
- { role: "user", content: "go" },
2367
- harness.buildAssistantWithToolCall(tc)
2368
- ];
2369
- const withResult = adapter.appendToolResult(history, tc.id, { ok: true });
2456
+ const afterAssistant = adapter.appendAssistantToolCall(
2457
+ [{ role: "user", content: "go" }],
2458
+ [tc]
2459
+ );
2460
+ const withResult = adapter.appendToolResult(afterAssistant, tc.id, { ok: true });
2370
2461
  await harness.mockScenario("simple-stream");
2371
2462
  await drainStream(adapter, {
2372
2463
  model: harness.toolCapableModel,
@@ -2376,6 +2467,28 @@ function runContractTests(harness) {
2376
2467
  (0, import_vitest.expect)(captured).not.toBeNull();
2377
2468
  (0, import_vitest.expect)(captured.vendorRawHonored).toBe(true);
2378
2469
  });
2470
+ (0, import_vitest.it)("[21] appendAssistantToolCall output + appendToolResult re-stream preserves tool-call id on wire", async () => {
2471
+ await harness.mockScenario("tool-call");
2472
+ const adapter = await init(harness);
2473
+ const first = await drainStream(adapter, {
2474
+ model: harness.toolCapableModel,
2475
+ messages: [{ role: "user", content: "go" }],
2476
+ tools: [
2477
+ { name: "test_tool", description: "x", parameters: { type: "object" } }
2478
+ ]
2479
+ });
2480
+ const tc = first.find(
2481
+ (e) => e.type === "toolCall"
2482
+ );
2483
+ (0, import_vitest.expect)(tc).toBeDefined();
2484
+ const history = adapter.appendAssistantToolCall(
2485
+ [{ role: "user", content: "go" }],
2486
+ [tc]
2487
+ );
2488
+ const appended = history[history.length - 1];
2489
+ (0, import_vitest.expect)(appended.role).toBe("assistant");
2490
+ (0, import_vitest.expect)(appended.vendorRaw).toBeDefined();
2491
+ });
2379
2492
  });
2380
2493
  }
2381
2494
  async function init(harness) {
@@ -2440,6 +2553,23 @@ var FakeAdapter = class {
2440
2553
  throw new Error(`FakeAdapter: unknown scenario '${scenario}'`);
2441
2554
  }
2442
2555
  }
2556
+ appendAssistantToolCall(history, toolCalls) {
2557
+ return [
2558
+ ...history,
2559
+ {
2560
+ role: "assistant",
2561
+ content: "",
2562
+ vendorRaw: {
2563
+ role: "assistant",
2564
+ toolCalls: toolCalls.map((tc) => ({
2565
+ id: tc.id,
2566
+ name: tc.name,
2567
+ arguments: tc.arguments
2568
+ }))
2569
+ }
2570
+ }
2571
+ ];
2572
+ }
2443
2573
  appendToolResult(history, toolCallId, result) {
2444
2574
  const content = typeof result === "string" ? result : JSON.stringify(result);
2445
2575
  return [
@@ -2622,17 +2752,7 @@ function createFakeHarness() {
2622
2752
  },
2623
2753
  toolCapableModel: "fake-tool-model",
2624
2754
  nonToolCapableModel: "fake-plain-model",
2625
- emitsToolCallStart: true,
2626
- buildAssistantWithToolCall(tc) {
2627
- return {
2628
- role: "assistant",
2629
- content: "",
2630
- vendorRaw: {
2631
- role: "assistant",
2632
- toolCall: { id: tc.id, name: tc.name, arguments: tc.arguments }
2633
- }
2634
- };
2635
- }
2755
+ emitsToolCallStart: true
2636
2756
  };
2637
2757
  }
2638
2758
  // Annotate the CommonJS export names for ESM import in node: