@kortyx/hooks 0.14.0 → 0.16.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.
package/dist/index.js CHANGED
@@ -373,6 +373,7 @@ async function runReasonEngine(args) {
373
373
  const reasoning = args.reasoning ?? args.model.options?.reasoning;
374
374
  const responseFormat = args.responseFormat ?? args.model.options?.responseFormat;
375
375
  const providerOptions = args.providerOptions ?? args.model.options?.providerOptions;
376
+ const tools = args.tools ?? args.model.options?.tools;
376
377
  const model = args.model.provider.getModel(args.model.modelId, {
377
378
  ...temperature !== void 0 ? { temperature } : {},
378
379
  streaming: stream,
@@ -381,13 +382,13 @@ async function runReasonEngine(args) {
381
382
  ...abortSignal !== void 0 ? { abortSignal } : {},
382
383
  ...reasoning !== void 0 ? { reasoning } : {},
383
384
  ...responseFormat !== void 0 ? { responseFormat } : {},
385
+ ...tools !== void 0 ? { tools } : {},
384
386
  ...providerOptions !== void 0 ? { providerOptions } : {}
385
387
  });
386
- const messages = [];
387
- if (typeof args.system === "string" && args.system.length > 0) {
388
- messages.push({ role: "system", content: args.system });
389
- }
390
- messages.push({ role: "user", content: String(args.input ?? "") });
388
+ const messages = args.messages !== void 0 ? args.messages : [
389
+ ...typeof args.system === "string" && args.system.length > 0 ? [{ role: "system", content: args.system }] : [],
390
+ { role: "user", content: String(args.input ?? "") }
391
+ ];
391
392
  const opId = typeof args.opId === "string" && args.opId.length > 0 ? args.opId : createRuntimeId();
392
393
  const segmentId = typeof args.segmentId === "string" && args.segmentId.length > 0 ? args.segmentId : createRuntimeId();
393
394
  const commonMeta = {
@@ -403,7 +404,15 @@ async function runReasonEngine(args) {
403
404
  modelId: args.model.modelId,
404
405
  stream,
405
406
  emit,
407
+ ...args.telemetry?.operation ? { operation: args.telemetry.operation } : {},
408
+ ...args.telemetry?.prompt?.name ? { promptName: args.telemetry.prompt.name } : {},
409
+ ...args.telemetry?.prompt?.version !== void 0 ? { promptVersion: args.telemetry.prompt.version } : {},
410
+ ...args.telemetry?.prompt?.type ? { promptType: args.telemetry.prompt.type } : {},
406
411
  ...typeof args.nodeId === "string" && args.nodeId.length > 0 ? { nodeId: args.nodeId } : {}
412
+ },
413
+ telemetry: {
414
+ ...args.telemetry ?? {},
415
+ input: args.telemetry?.input ?? messages
407
416
  }
408
417
  });
409
418
  const endTrace = (span, result) => {
@@ -414,6 +423,10 @@ async function runReasonEngine(args) {
414
423
  ...result.warnings !== void 0 ? { warnings: result.warnings } : {},
415
424
  attributes: {
416
425
  textLength: result.text.length
426
+ },
427
+ telemetry: {
428
+ ...args.telemetry ?? {},
429
+ output: args.telemetry?.output ?? result.text
417
430
  }
418
431
  });
419
432
  };
@@ -431,6 +444,7 @@ async function runReasonEngine(args) {
431
444
  let raw;
432
445
  let usage;
433
446
  let finishReason;
447
+ let toolCalls;
434
448
  let providerMetadata;
435
449
  let warnings;
436
450
  if (emit) {
@@ -469,6 +483,9 @@ async function runReasonEngine(args) {
469
483
  if (chunk.finishReason !== void 0) {
470
484
  finishReason = chunk.finishReason;
471
485
  }
486
+ if (chunk.toolCalls !== void 0) {
487
+ toolCalls = chunk.toolCalls;
488
+ }
472
489
  if (chunk.providerMetadata !== void 0) {
473
490
  providerMetadata = chunk.providerMetadata;
474
491
  }
@@ -508,6 +525,7 @@ async function runReasonEngine(args) {
508
525
  ...raw !== void 0 ? { raw } : {},
509
526
  ...usage !== void 0 ? { usage } : {},
510
527
  ...finishReason !== void 0 ? { finishReason } : {},
528
+ ...toolCalls !== void 0 ? { toolCalls } : {},
511
529
  ...providerMetadata !== void 0 ? { providerMetadata } : {},
512
530
  ...warnings !== void 0 ? { warnings } : {}
513
531
  };
@@ -534,6 +552,7 @@ async function runReasonEngine(args) {
534
552
  ...response.raw !== void 0 ? { raw: response.raw } : {},
535
553
  ...response.usage !== void 0 ? { usage: response.usage } : {},
536
554
  ...response.finishReason !== void 0 ? { finishReason: response.finishReason } : {},
555
+ ...response.toolCalls !== void 0 ? { toolCalls: response.toolCalls } : {},
537
556
  ...response.providerMetadata !== void 0 ? { providerMetadata: response.providerMetadata } : {},
538
557
  ...response.warnings !== void 0 ? { warnings: response.warnings } : {}
539
558
  };
@@ -566,10 +585,13 @@ async function reasonEngine(args, meta, inputOverride) {
566
585
  reasoning: args.reasoning,
567
586
  responseFormat: args.responseFormat,
568
587
  providerOptions: args.providerOptions,
588
+ tools: args.tools,
589
+ messages: args.messages,
569
590
  defaultTemperature: ctx.node.config?.model?.temperature,
570
591
  stream: args.stream,
571
592
  emit: args.emit,
572
593
  onTextChunk: args.onTextChunk,
594
+ telemetry: args.telemetry,
573
595
  nodeId: ctx.node.graph.node,
574
596
  emitEvent: ctx.node.emit,
575
597
  reasonTrace: ctx.reasonTrace,
@@ -890,6 +912,65 @@ var withStructuredStreamHints = (input, args) => {
890
912
  ].join("\n\n");
891
913
  };
892
914
 
915
+ // src/reason/result.ts
916
+ var mergeUsage = (left, right) => {
917
+ if (!left) return right;
918
+ if (!right) return left;
919
+ const sum = (a, b) => a === void 0 && b === void 0 ? void 0 : (a ?? 0) + (b ?? 0);
920
+ const raw = left.raw || right.raw ? {
921
+ ...left.raw ?? {},
922
+ ...right.raw ?? {}
923
+ } : void 0;
924
+ const input = sum(left.input, right.input);
925
+ const output = sum(left.output, right.output);
926
+ const total = sum(left.total, right.total);
927
+ const reasoning = sum(left.reasoning, right.reasoning);
928
+ const cacheRead = sum(left.cacheRead, right.cacheRead);
929
+ const cacheWrite = sum(left.cacheWrite, right.cacheWrite);
930
+ const merged = {};
931
+ if (input !== void 0) merged.input = input;
932
+ if (output !== void 0) merged.output = output;
933
+ if (total !== void 0) merged.total = total;
934
+ if (reasoning !== void 0) merged.reasoning = reasoning;
935
+ if (cacheRead !== void 0) merged.cacheRead = cacheRead;
936
+ if (cacheWrite !== void 0) merged.cacheWrite = cacheWrite;
937
+ if (raw) merged.raw = raw;
938
+ return merged;
939
+ };
940
+ var mergeWarnings = (left, right) => {
941
+ if (!left?.length) return right;
942
+ if (!right?.length) return left;
943
+ const seen = /* @__PURE__ */ new Set();
944
+ const merged = [];
945
+ for (const warning of [...left, ...right]) {
946
+ const key = JSON.stringify(warning);
947
+ if (seen.has(key)) continue;
948
+ seen.add(key);
949
+ merged.push(warning);
950
+ }
951
+ return merged;
952
+ };
953
+ var mergeProviderMetadata = (left, right) => {
954
+ if (!left) return right;
955
+ if (!right) return left;
956
+ return {
957
+ ...left,
958
+ ...right
959
+ };
960
+ };
961
+ var emitReasonStructuredOutput = (args) => {
962
+ if (!args.emit || !shouldEmitStructured(args.structured)) return;
963
+ emitStructuredData({
964
+ dataType: args.structured?.dataType ?? "reason-output",
965
+ data: args.output,
966
+ kind: "final",
967
+ ...args.structured?.schemaId ? { schemaId: args.structured.schemaId } : {},
968
+ ...args.structured?.schemaVersion ? { schemaVersion: args.structured.schemaVersion } : {},
969
+ ...args.id ? { id: args.id } : {},
970
+ streamId: args.opId
971
+ });
972
+ };
973
+
893
974
  // src/reason/structured-stream.ts
894
975
  var resolveAppendFieldPaths = (cfg) => {
895
976
  const fields = cfg?.fields;
@@ -1450,64 +1531,353 @@ var extractStreamingStringValues = (args) => {
1450
1531
  });
1451
1532
  };
1452
1533
 
1453
- // src/reason/use-reason.ts
1454
- var mergeUsage = (left, right) => {
1455
- if (!left) return right;
1456
- if (!right) return left;
1457
- const sum = (a, b) => a === void 0 && b === void 0 ? void 0 : (a ?? 0) + (b ?? 0);
1458
- const raw = left.raw || right.raw ? {
1459
- ...left.raw ?? {},
1460
- ...right.raw ?? {}
1461
- } : void 0;
1462
- const input = sum(left.input, right.input);
1463
- const output = sum(left.output, right.output);
1464
- const total = sum(left.total, right.total);
1465
- const reasoning = sum(left.reasoning, right.reasoning);
1466
- const cacheRead = sum(left.cacheRead, right.cacheRead);
1467
- const cacheWrite = sum(left.cacheWrite, right.cacheWrite);
1468
- const merged = {};
1469
- if (input !== void 0) merged.input = input;
1470
- if (output !== void 0) merged.output = output;
1471
- if (total !== void 0) merged.total = total;
1472
- if (reasoning !== void 0) merged.reasoning = reasoning;
1473
- if (cacheRead !== void 0) merged.cacheRead = cacheRead;
1474
- if (cacheWrite !== void 0) merged.cacheWrite = cacheWrite;
1475
- if (raw) merged.raw = raw;
1476
- return merged;
1534
+ // src/reason/tools.ts
1535
+ var toErrorMessage = (error) => error instanceof Error ? error.message : String(error);
1536
+ var toToolDefinitions = (tools) => tools.map((tool) => ({
1537
+ name: tool.name,
1538
+ ...tool.title ? { title: tool.title } : {},
1539
+ ...tool.description ? { description: tool.description } : {},
1540
+ inputSchema: tool.inputSchema,
1541
+ ...tool.outputSchema !== void 0 ? { outputSchema: tool.outputSchema } : {},
1542
+ ...tool.annotations !== void 0 ? { annotations: tool.annotations } : {},
1543
+ ...tool.metadata !== void 0 ? { metadata: tool.metadata } : {}
1544
+ }));
1545
+ var resolveToolExecutionBoolean = (value, toolName, fallback) => {
1546
+ if (typeof value === "boolean") return value;
1547
+ if (value && typeof value === "object" && !Array.isArray(value)) {
1548
+ return value[toolName] ?? fallback;
1549
+ }
1550
+ return fallback;
1477
1551
  };
1478
- var mergeWarnings = (left, right) => {
1479
- if (!left?.length) return right;
1480
- if (!right?.length) return left;
1481
- const seen = /* @__PURE__ */ new Set();
1482
- const merged = [];
1483
- for (const warning of [...left, ...right]) {
1484
- const key = JSON.stringify(warning);
1485
- if (seen.has(key)) continue;
1486
- seen.add(key);
1487
- merged.push(warning);
1552
+ var normalizeToolResult = (toolCall, value) => {
1553
+ if (value && typeof value === "object" && !Array.isArray(value) && "toolCallId" in value && "name" in value && "content" in value) {
1554
+ return value;
1555
+ }
1556
+ let content;
1557
+ try {
1558
+ content = typeof value === "string" ? value : JSON.stringify(value);
1559
+ } catch {
1560
+ content = String(value);
1488
1561
  }
1489
- return merged;
1490
- };
1491
- var mergeProviderMetadata = (left, right) => {
1492
- if (!left) return right;
1493
- if (!right) return left;
1494
1562
  return {
1495
- ...left,
1496
- ...right
1563
+ toolCallId: toolCall.id,
1564
+ name: toolCall.name,
1565
+ content,
1566
+ ...value !== void 0 && value !== null && typeof value === "object" && !Array.isArray(value) ? { structuredContent: value } : {}
1497
1567
  };
1498
1568
  };
1499
- var emitReasonStructuredOutput = (args) => {
1500
- if (!args.emit || !shouldEmitStructured(args.structured)) return;
1501
- emitStructuredData({
1502
- dataType: args.structured?.dataType ?? "reason-output",
1503
- data: args.output,
1504
- kind: "final",
1505
- ...args.structured?.schemaId ? { schemaId: args.structured.schemaId } : {},
1506
- ...args.structured?.schemaVersion ? { schemaVersion: args.structured.schemaVersion } : {},
1507
- ...args.id ? { id: args.id } : {},
1508
- streamId: args.opId
1569
+ var closeOwnedTools = async (tools) => {
1570
+ const closeFns = /* @__PURE__ */ new Set();
1571
+ for (const tool of tools) {
1572
+ if (tool.closeAfterUse === false || !tool.close) continue;
1573
+ closeFns.add(tool.close);
1574
+ }
1575
+ await Promise.all(
1576
+ [...closeFns].map(async (close) => {
1577
+ await close();
1578
+ })
1579
+ );
1580
+ };
1581
+ var createInitialMessages = (args) => [
1582
+ ...typeof args.system === "string" && args.system.length > 0 ? [{ role: "system", content: args.system }] : [],
1583
+ { role: "user", content: String(args.input ?? "") }
1584
+ ];
1585
+ var runReasonToolLoop = async (args) => {
1586
+ const { useReasonArgs, id, opId, traceSpan } = args;
1587
+ const ctx = getHookContext();
1588
+ const tools = useReasonArgs.tools ?? [];
1589
+ const toolByName = /* @__PURE__ */ new Map();
1590
+ let validationCompleted = false;
1591
+ try {
1592
+ for (const tool of tools) {
1593
+ if (toolByName.has(tool.name)) {
1594
+ throw new Error(
1595
+ `useReason received duplicate tool name "${tool.name}".`
1596
+ );
1597
+ }
1598
+ toolByName.set(tool.name, tool);
1599
+ }
1600
+ if (useReasonArgs.interrupt) {
1601
+ throw new Error(
1602
+ "useReason tools cannot be combined with useReason interrupt mode yet. Use toolExecution.approval for tool approval."
1603
+ );
1604
+ }
1605
+ validationCompleted = true;
1606
+ } finally {
1607
+ if (!validationCompleted) {
1608
+ await closeOwnedTools(tools);
1609
+ }
1610
+ }
1611
+ const toolDefinitions = toToolDefinitions(tools);
1612
+ const maxSteps = Math.max(1, useReasonArgs.toolExecution?.maxSteps ?? 3);
1613
+ const messages = createInitialMessages({
1614
+ system: useReasonArgs.system,
1615
+ input: useReasonArgs.input
1509
1616
  });
1617
+ const steps = [];
1618
+ const allToolCalls = [];
1619
+ const allToolResults = [];
1620
+ let finalText = "";
1621
+ let finalRaw;
1622
+ let finalOutput;
1623
+ let aggregatedUsage;
1624
+ let finalFinishReason;
1625
+ let aggregatedProviderMetadata;
1626
+ let aggregatedWarnings;
1627
+ const emitToolEvent = (event, payload) => {
1628
+ ctx.node.emit(event, {
1629
+ ...payload,
1630
+ node: ctx.node.graph.node,
1631
+ ...id ? { id } : {},
1632
+ opId
1633
+ });
1634
+ };
1635
+ try {
1636
+ for (let stepIndex = 0; stepIndex < maxSteps; stepIndex += 1) {
1637
+ traceSpan?.addEvent?.("useReason.tool-step.start", {
1638
+ stepIndex,
1639
+ toolCount: toolDefinitions.length
1640
+ });
1641
+ const step = await reasonEngine(
1642
+ {
1643
+ ...useReasonArgs,
1644
+ tools: toolDefinitions,
1645
+ messages,
1646
+ emit: false,
1647
+ stream: false
1648
+ },
1649
+ { ...id ? { id } : {}, opId }
1650
+ );
1651
+ finalText = step.text;
1652
+ finalRaw = step.raw;
1653
+ aggregatedUsage = mergeUsage(aggregatedUsage, step.usage);
1654
+ finalFinishReason = step.finishReason;
1655
+ aggregatedProviderMetadata = mergeProviderMetadata(
1656
+ aggregatedProviderMetadata,
1657
+ step.providerMetadata
1658
+ );
1659
+ aggregatedWarnings = mergeWarnings(aggregatedWarnings, step.warnings);
1660
+ const toolCalls = step.toolCalls ?? [];
1661
+ const toolResults = [];
1662
+ steps.push({
1663
+ stepIndex,
1664
+ text: step.text,
1665
+ toolCalls,
1666
+ toolResults,
1667
+ ...step.usage ? { usage: step.usage } : {},
1668
+ ...step.finishReason ? { finishReason: step.finishReason } : {},
1669
+ ...step.providerMetadata ? { providerMetadata: step.providerMetadata } : {},
1670
+ ...step.warnings ? { warnings: step.warnings } : {}
1671
+ });
1672
+ if (toolCalls.length === 0) {
1673
+ if ((useReasonArgs.emit ?? true) && step.text.length > 0) {
1674
+ emitToolEvent("text-start", {});
1675
+ emitToolEvent("text-delta", { delta: step.text });
1676
+ emitToolEvent("text-end", {});
1677
+ }
1678
+ break;
1679
+ }
1680
+ allToolCalls.push(...toolCalls);
1681
+ messages.push({
1682
+ role: "assistant",
1683
+ content: step.text,
1684
+ toolCalls
1685
+ });
1686
+ for (const toolCall of toolCalls) {
1687
+ const tool = toolByName.get(toolCall.name);
1688
+ if (!tool) {
1689
+ throw new Error(
1690
+ `Model requested unknown tool "${toolCall.name}" from useReason.`
1691
+ );
1692
+ }
1693
+ const shouldEmitTool = resolveToolExecutionBoolean(
1694
+ useReasonArgs.toolExecution?.emit,
1695
+ tool.name,
1696
+ false
1697
+ );
1698
+ const shouldApproveTool = resolveToolExecutionBoolean(
1699
+ useReasonArgs.toolExecution?.approval,
1700
+ tool.name,
1701
+ false
1702
+ );
1703
+ if (shouldEmitTool) {
1704
+ emitToolEvent("tool-call-start", {
1705
+ tool: tool.name,
1706
+ toolCallId: toolCall.id,
1707
+ input: toolCall.input
1708
+ });
1709
+ }
1710
+ if (shouldApproveTool) {
1711
+ const approval = await awaitInterruptInternal({
1712
+ id: `tool:${toolCall.id}`,
1713
+ request: {
1714
+ kind: "choice",
1715
+ question: `Approve ${tool.name}?`,
1716
+ options: [
1717
+ { id: "approve", label: "Approve" },
1718
+ { id: "deny", label: "Deny" }
1719
+ ],
1720
+ meta: {
1721
+ tool: tool.name,
1722
+ toolCallId: toolCall.id,
1723
+ input: toolCall.input
1724
+ }
1725
+ }
1726
+ });
1727
+ const approved = Array.isArray(approval) ? approval.includes("approve") : approval === "approve";
1728
+ if (!approved) {
1729
+ const denied = {
1730
+ toolCallId: toolCall.id,
1731
+ name: tool.name,
1732
+ content: "Tool call denied by user.",
1733
+ isError: true
1734
+ };
1735
+ toolResults.push(denied);
1736
+ allToolResults.push(denied);
1737
+ if (shouldEmitTool) {
1738
+ emitToolEvent("tool-call-result", {
1739
+ tool: tool.name,
1740
+ toolCallId: toolCall.id,
1741
+ content: denied.content,
1742
+ isError: true
1743
+ });
1744
+ }
1745
+ continue;
1746
+ }
1747
+ }
1748
+ try {
1749
+ const rawResult = await tool.execute(toolCall.input, {
1750
+ toolCallId: toolCall.id,
1751
+ ...useReasonArgs.abortSignal ? { abortSignal: useReasonArgs.abortSignal } : {}
1752
+ });
1753
+ const result2 = normalizeToolResult(toolCall, rawResult);
1754
+ toolResults.push(result2);
1755
+ allToolResults.push(result2);
1756
+ if (shouldEmitTool) {
1757
+ emitToolEvent("tool-call-result", {
1758
+ tool: result2.name,
1759
+ toolCallId: result2.toolCallId,
1760
+ content: result2.content,
1761
+ ...result2.structuredContent !== void 0 ? { structuredContent: result2.structuredContent } : {},
1762
+ ...result2.isError !== void 0 ? { isError: result2.isError } : {}
1763
+ });
1764
+ }
1765
+ traceSpan?.addEvent?.("useReason.tool-call.complete", {
1766
+ stepIndex,
1767
+ tool: result2.name,
1768
+ toolCallId: result2.toolCallId,
1769
+ isError: Boolean(result2.isError)
1770
+ });
1771
+ } catch (error) {
1772
+ const result2 = {
1773
+ toolCallId: toolCall.id,
1774
+ name: tool.name,
1775
+ content: toErrorMessage(error),
1776
+ isError: true
1777
+ };
1778
+ toolResults.push(result2);
1779
+ allToolResults.push(result2);
1780
+ if (shouldEmitTool) {
1781
+ emitToolEvent("tool-call-error", {
1782
+ tool: tool.name,
1783
+ toolCallId: toolCall.id,
1784
+ message: result2.content
1785
+ });
1786
+ }
1787
+ traceSpan?.addEvent?.("useReason.tool-call.error", {
1788
+ stepIndex,
1789
+ tool: tool.name,
1790
+ toolCallId: toolCall.id,
1791
+ message: result2.content
1792
+ });
1793
+ }
1794
+ }
1795
+ const currentStep = steps[steps.length - 1];
1796
+ if (currentStep) {
1797
+ steps[steps.length - 1] = {
1798
+ ...currentStep,
1799
+ toolResults
1800
+ };
1801
+ }
1802
+ for (const result2 of toolResults) {
1803
+ messages.push({
1804
+ role: "tool",
1805
+ content: result2.content,
1806
+ toolCallId: result2.toolCallId,
1807
+ name: result2.name,
1808
+ ...result2.structuredContent !== void 0 ? { structuredContent: result2.structuredContent } : {},
1809
+ ...result2.isError !== void 0 ? { isError: result2.isError } : {},
1810
+ ...result2.raw !== void 0 ? { raw: result2.raw } : {}
1811
+ });
1812
+ }
1813
+ }
1814
+ if (steps.length >= maxSteps && steps.at(-1)?.toolCalls.length) {
1815
+ throw new Error(
1816
+ `useReason tool loop reached maxSteps (${maxSteps}) before producing a final response.`
1817
+ );
1818
+ }
1819
+ if (useReasonArgs.outputSchema) {
1820
+ finalOutput = parseReasonOutputWithSchema({
1821
+ text: finalText,
1822
+ schema: useReasonArgs.outputSchema,
1823
+ ...finalFinishReason ? { finishReason: finalFinishReason } : {},
1824
+ label: "useReason output"
1825
+ });
1826
+ }
1827
+ if (finalOutput !== void 0) {
1828
+ emitReasonStructuredOutput({
1829
+ ...id ? { id } : {},
1830
+ opId,
1831
+ output: finalOutput,
1832
+ structured: useReasonArgs.structured,
1833
+ emit: useReasonArgs.emit ?? true
1834
+ });
1835
+ }
1836
+ const result = {
1837
+ ...id ? { id } : {},
1838
+ opId,
1839
+ text: finalText,
1840
+ ...finalRaw !== void 0 ? { raw: finalRaw } : {},
1841
+ ...aggregatedUsage !== void 0 ? { usage: aggregatedUsage } : {},
1842
+ ...finalFinishReason !== void 0 ? { finishReason: finalFinishReason } : {},
1843
+ ...aggregatedProviderMetadata !== void 0 ? { providerMetadata: aggregatedProviderMetadata } : {},
1844
+ ...aggregatedWarnings !== void 0 ? { warnings: aggregatedWarnings } : {},
1845
+ ...finalOutput !== void 0 ? { output: finalOutput } : {},
1846
+ toolCalls: allToolCalls,
1847
+ toolResults: allToolResults,
1848
+ steps
1849
+ };
1850
+ traceSpan?.end?.({
1851
+ ...aggregatedUsage !== void 0 ? { usage: aggregatedUsage } : {},
1852
+ ...finalFinishReason !== void 0 ? { finishReason: finalFinishReason } : {},
1853
+ ...aggregatedProviderMetadata !== void 0 ? { providerMetadata: aggregatedProviderMetadata } : {},
1854
+ ...aggregatedWarnings !== void 0 ? { warnings: aggregatedWarnings } : {},
1855
+ attributes: {
1856
+ textLength: finalText.length,
1857
+ toolCallCount: allToolCalls.length,
1858
+ toolResultCount: allToolResults.length,
1859
+ toolStepCount: steps.length
1860
+ },
1861
+ telemetry: {
1862
+ ...useReasonArgs.telemetry ?? {},
1863
+ output: useReasonArgs.telemetry?.output ?? finalOutput ?? finalText
1864
+ }
1865
+ });
1866
+ return result;
1867
+ } catch (error) {
1868
+ traceSpan?.fail?.(error, {
1869
+ attributes: {
1870
+ toolStepCount: steps.length,
1871
+ toolCallCount: allToolCalls.length
1872
+ }
1873
+ });
1874
+ throw error;
1875
+ } finally {
1876
+ await closeOwnedTools(tools);
1877
+ }
1510
1878
  };
1879
+
1880
+ // src/reason/use-reason.ts
1511
1881
  var shouldStreamReasonStructured = (args) => (args.emit ?? true) && shouldStreamStructured(args.structured);
1512
1882
  var resolveEffectiveReasoningIncludeThoughts = (args) => args.reasoning?.includeThoughts ?? args.model.options?.reasoning?.includeThoughts ?? false;
1513
1883
  var resolveEffectiveResponseFormatType = (args) => args.responseFormat?.type ?? args.model.options?.responseFormat?.type;
@@ -1548,11 +1918,28 @@ async function useReason(args) {
1548
1918
  modelId: args.model.modelId,
1549
1919
  stream: args.stream ?? args.model.options?.streaming ?? true,
1550
1920
  emit: args.emit ?? true,
1921
+ ...args.telemetry?.operation ? { operation: args.telemetry.operation } : {},
1922
+ ...args.telemetry?.prompt?.name ? { promptName: args.telemetry.prompt.name } : {},
1923
+ ...args.telemetry?.prompt?.version !== void 0 ? { promptVersion: args.telemetry.prompt.version } : {},
1924
+ ...args.telemetry?.prompt?.type ? { promptType: args.telemetry.prompt.type } : {},
1551
1925
  hasOutputSchema: Boolean(args.outputSchema),
1552
1926
  hasInterrupt: Boolean(args.interrupt),
1553
- hasStructured: Boolean(args.structured)
1927
+ hasStructured: Boolean(args.structured),
1928
+ hasTools: Boolean(args.tools?.length)
1929
+ },
1930
+ telemetry: {
1931
+ ...args.telemetry ?? {},
1932
+ input: args.telemetry?.input ?? args.input
1554
1933
  }
1555
1934
  });
1935
+ if (args.tools?.length) {
1936
+ return runReasonToolLoop({
1937
+ useReasonArgs: args,
1938
+ ...id ? { id } : {},
1939
+ opId,
1940
+ ...traceSpan ? { traceSpan } : {}
1941
+ });
1942
+ }
1556
1943
  const suppressTextStream = Boolean(args.outputSchema || args.interrupt);
1557
1944
  const setFieldPaths = resolveSetFieldPaths(args.structured);
1558
1945
  const appendFieldPaths = resolveAppendFieldPaths(args.structured);
@@ -1855,6 +2242,10 @@ async function useReason(args) {
1855
2242
  textLength: finalText.length,
1856
2243
  resumedFromCheckpoint: Boolean(existingCheckpoint),
1857
2244
  interrupted: Boolean(interruptResponse !== void 0)
2245
+ },
2246
+ telemetry: {
2247
+ ...args.telemetry ?? {},
2248
+ output: args.telemetry?.output ?? finalOutput ?? finalText
1858
2249
  }
1859
2250
  });
1860
2251
  return result;