@jambonz/llm 0.6.9 → 0.6.10

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.
package/dist/index.cjs CHANGED
@@ -1315,6 +1315,21 @@ var ANTHROPIC_KNOWN_MODELS = [
1315
1315
  maxContextTokens: 2e5
1316
1316
  }
1317
1317
  },
1318
+ {
1319
+ // Thinks by default (effort `medium`), and the thinking counts toward
1320
+ // max_tokens. For voice, send `providerParams: {output_config: {effort:
1321
+ // 'low'}}`. Rejects non-default sampling parameters, so the adapter
1322
+ // leaves `temperature` out of its requests.
1323
+ id: "claude-haiku-5-5",
1324
+ displayName: "Claude Haiku 5.5",
1325
+ capabilities: {
1326
+ streaming: true,
1327
+ tools: true,
1328
+ vision: true,
1329
+ systemPrompt: true,
1330
+ maxContextTokens: 1e6
1331
+ }
1332
+ },
1318
1333
  {
1319
1334
  id: "claude-haiku-4-5-20251001",
1320
1335
  displayName: "Claude Haiku 4.5",
@@ -1398,6 +1413,7 @@ var ANTHROPIC_METADATA_EXTRACTOR = makeMetadataExtractor([
1398
1413
  { header: "anthropic-ratelimit-input-tokens-remaining", key: "input_tokens_remaining", numeric: true },
1399
1414
  { header: "anthropic-ratelimit-output-tokens-remaining", key: "output_tokens_remaining", numeric: true }
1400
1415
  ]);
1416
+ var REJECTS_SAMPLING_PARAMS = /^claude-(opus-4-[7-9]|opus-5|sonnet-5|haiku-5|fable|mythos)/;
1401
1417
  var AnthropicAdapter = class {
1402
1418
  vendor = anthropicManifest.vendor;
1403
1419
  acceptedAuth = ["apiKey"];
@@ -1430,7 +1446,14 @@ var AnthropicAdapter = class {
1430
1446
  };
1431
1447
  if (req.system) body.system = req.system;
1432
1448
  if (tools) body.tools = tools;
1433
- if (req.temperature !== void 0) body.temperature = req.temperature;
1449
+ if (req.temperature !== void 0 && !REJECTS_SAMPLING_PARAMS.test(req.model)) {
1450
+ body.temperature = req.temperature;
1451
+ }
1452
+ if (req.providerParams) {
1453
+ for (const [key, value] of Object.entries(req.providerParams)) {
1454
+ if (!(key in body)) body[key] = value;
1455
+ }
1456
+ }
1434
1457
  if (req.cacheKey) {
1435
1458
  if (req.system) {
1436
1459
  body.system = [{ type: "text", text: req.system, cache_control: { type: "ephemeral" } }];
@@ -1441,21 +1464,31 @@ var AnthropicAdapter = class {
1441
1464
  }
1442
1465
  markLastMessageForCaching(messages);
1443
1466
  }
1444
- let stream;
1445
- let responseHeaders;
1446
- try {
1467
+ const open = async (b) => {
1447
1468
  const apiPromise = client.messages.create(
1448
- body,
1469
+ b,
1449
1470
  { signal: req.signal }
1450
1471
  );
1451
1472
  const maybeWithResponse = apiPromise.withResponse;
1452
1473
  if (typeof maybeWithResponse === "function") {
1453
1474
  const result = await maybeWithResponse.call(apiPromise);
1454
- stream = result.data;
1455
- responseHeaders = result.response?.headers;
1456
- } else {
1457
- stream = await apiPromise;
1475
+ return { stream: result.data, headers: result.response?.headers };
1476
+ }
1477
+ return { stream: await apiPromise, headers: void 0 };
1478
+ };
1479
+ let stream;
1480
+ let responseHeaders;
1481
+ try {
1482
+ let opened;
1483
+ try {
1484
+ opened = await open(body);
1485
+ } catch (err) {
1486
+ const stripped = isThinkingBlockRejection(err) ? withoutThinking(messages) : void 0;
1487
+ if (!stripped) throw err;
1488
+ opened = await open({ ...body, messages: stripped });
1458
1489
  }
1490
+ stream = opened.stream;
1491
+ responseHeaders = opened.headers;
1459
1492
  } catch (err) {
1460
1493
  if (isAbortError2(err)) {
1461
1494
  yield { type: "end", finishReason: "aborted" };
@@ -1464,7 +1497,10 @@ var AnthropicAdapter = class {
1464
1497
  throw err;
1465
1498
  }
1466
1499
  let currentToolUse = null;
1500
+ let currentThinking = null;
1501
+ let currentText = null;
1467
1502
  const completedToolCalls = [];
1503
+ const turnContent = [];
1468
1504
  let stopReason;
1469
1505
  let inputTokens;
1470
1506
  let outputTokens;
@@ -1497,19 +1533,42 @@ var AnthropicAdapter = class {
1497
1533
  name: currentToolUse.name
1498
1534
  };
1499
1535
  }
1536
+ } else if (block?.type === "text") {
1537
+ currentText = block.text ?? "";
1538
+ } else if (block?.type === "thinking") {
1539
+ currentThinking = {
1540
+ type: "thinking",
1541
+ thinking: block.thinking ?? "",
1542
+ signature: block.signature ?? ""
1543
+ };
1544
+ } else if (block?.type === "redacted_thinking" && block.data) {
1545
+ turnContent.push({ type: "redacted_thinking", data: block.data });
1500
1546
  }
1501
1547
  break;
1502
1548
  }
1503
1549
  case "content_block_delta": {
1504
1550
  const delta = event.delta;
1505
1551
  if (delta?.type === "text_delta" && delta.text) {
1552
+ if (currentText !== null) currentText += delta.text;
1506
1553
  yield { type: "token", text: delta.text };
1507
1554
  } else if (delta?.type === "input_json_delta" && currentToolUse && delta.partial_json) {
1508
1555
  currentToolUse.argumentsText += delta.partial_json;
1556
+ } else if (delta?.type === "thinking_delta" && currentThinking && delta.thinking) {
1557
+ currentThinking.thinking += delta.thinking;
1558
+ } else if (delta?.type === "signature_delta" && currentThinking && delta.signature) {
1559
+ currentThinking.signature += delta.signature;
1509
1560
  }
1510
1561
  break;
1511
1562
  }
1512
1563
  case "content_block_stop":
1564
+ if (currentThinking) {
1565
+ if (currentThinking.signature) turnContent.push(currentThinking);
1566
+ currentThinking = null;
1567
+ }
1568
+ if (currentText !== null) {
1569
+ if (currentText) turnContent.push({ type: "text", text: currentText });
1570
+ currentText = null;
1571
+ }
1513
1572
  if (currentToolUse && currentToolUse.id && currentToolUse.name) {
1514
1573
  let parsed = {};
1515
1574
  try {
@@ -1522,6 +1581,12 @@ var AnthropicAdapter = class {
1522
1581
  name: currentToolUse.name,
1523
1582
  arguments: parsed
1524
1583
  });
1584
+ turnContent.push({
1585
+ type: "tool_use",
1586
+ id: currentToolUse.id,
1587
+ name: currentToolUse.name,
1588
+ input: parsed
1589
+ });
1525
1590
  }
1526
1591
  currentToolUse = null;
1527
1592
  break;
@@ -1550,12 +1615,14 @@ var AnthropicAdapter = class {
1550
1615
  yield { type: "end", finishReason: "aborted" };
1551
1616
  return;
1552
1617
  }
1618
+ const toolCallRaw = { content: turnContent };
1553
1619
  for (const tc of completedToolCalls) {
1554
1620
  yield {
1555
1621
  type: "toolCall",
1556
1622
  id: tc.id,
1557
1623
  name: tc.name,
1558
- arguments: tc.arguments
1624
+ arguments: tc.arguments,
1625
+ vendorRaw: toolCallRaw
1559
1626
  };
1560
1627
  }
1561
1628
  const finishReason = mapStopReason(stopReason, completedToolCalls.length > 0);
@@ -1586,15 +1653,7 @@ var AnthropicAdapter = class {
1586
1653
  const text = assistantText?.trim() ? assistantText : null;
1587
1654
  const wireMessage = {
1588
1655
  role: "assistant",
1589
- content: [
1590
- ...text ? [{ type: "text", text }] : [],
1591
- ...toolCalls.map((tc) => ({
1592
- type: "tool_use",
1593
- id: tc.id,
1594
- name: tc.name,
1595
- input: tc.arguments ?? {}
1596
- }))
1597
- ]
1656
+ content: assistantTurnContent(toolCalls, text)
1598
1657
  };
1599
1658
  return [
1600
1659
  ...history,
@@ -1686,6 +1745,62 @@ function markLastMessageForCaching(messages) {
1686
1745
  };
1687
1746
  }
1688
1747
  }
1748
+ function isThinkingBlockRejection(err) {
1749
+ const e = err;
1750
+ return e?.status === 400 && /`thinking` block/.test(String(e.message ?? ""));
1751
+ }
1752
+ function withoutThinking(messages) {
1753
+ let removed = false;
1754
+ const out = messages.map((m) => {
1755
+ const content = m.content;
1756
+ if (!Array.isArray(content)) return m;
1757
+ const kept = content.filter((b) => {
1758
+ const thinking = b?.type === "thinking" || b?.type === "redacted_thinking";
1759
+ if (thinking) removed = true;
1760
+ return !thinking;
1761
+ });
1762
+ return kept.length === content.length ? m : { ...m, content: kept };
1763
+ });
1764
+ return removed ? out : void 0;
1765
+ }
1766
+ function assistantTurnContent(toolCalls, text) {
1767
+ const recorded = recordedTurnOf(toolCalls);
1768
+ if (!recorded) {
1769
+ return [
1770
+ ...text ? [{ type: "text", text }] : [],
1771
+ ...toolCalls.map((tc) => ({
1772
+ type: "tool_use",
1773
+ id: tc.id,
1774
+ name: tc.name,
1775
+ input: tc.arguments ?? {}
1776
+ }))
1777
+ ];
1778
+ }
1779
+ const ids = new Set(toolCalls.map((tc) => tc.id));
1780
+ const content = recorded.filter(
1781
+ (b) => b.type !== "tool_use" || ids.has(b.id)
1782
+ );
1783
+ if (text && !content.some((b) => b.type === "text")) {
1784
+ const at = content.findIndex((b) => b.type === "tool_use");
1785
+ content.splice(at === -1 ? content.length : at, 0, { type: "text", text });
1786
+ }
1787
+ const known = new Set(
1788
+ content.flatMap((b) => b.type === "tool_use" ? [b.id] : [])
1789
+ );
1790
+ for (const tc of toolCalls) {
1791
+ if (!known.has(tc.id)) {
1792
+ content.push({ type: "tool_use", id: tc.id, name: tc.name, input: tc.arguments ?? {} });
1793
+ }
1794
+ }
1795
+ return content;
1796
+ }
1797
+ function recordedTurnOf(toolCalls) {
1798
+ for (const tc of toolCalls) {
1799
+ const raw = tc.vendorRaw;
1800
+ if (raw && Array.isArray(raw.content)) return raw.content;
1801
+ }
1802
+ return void 0;
1803
+ }
1689
1804
  function formatTools2(tools) {
1690
1805
  return tools.map((t) => ({
1691
1806
  name: t.name,
@@ -1703,6 +1818,8 @@ function mapStopReason(r, hadToolCalls) {
1703
1818
  return "tool";
1704
1819
  case "max_tokens":
1705
1820
  return "length";
1821
+ case "refusal":
1822
+ return "filtered";
1706
1823
  default:
1707
1824
  return "stop";
1708
1825
  }