@framers/agentos 0.9.26 → 0.9.28

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 (33) hide show
  1. package/dist/api/generateText.d.ts +18 -0
  2. package/dist/api/generateText.d.ts.map +1 -1
  3. package/dist/api/generateText.js +280 -207
  4. package/dist/api/generateText.js.map +1 -1
  5. package/dist/api/runtime/tool-emulation/activation.d.ts +7 -0
  6. package/dist/api/runtime/tool-emulation/activation.d.ts.map +1 -0
  7. package/dist/api/runtime/tool-emulation/activation.js +17 -0
  8. package/dist/api/runtime/tool-emulation/activation.js.map +1 -0
  9. package/dist/api/runtime/tool-emulation/index.d.ts +5 -0
  10. package/dist/api/runtime/tool-emulation/index.d.ts.map +1 -0
  11. package/dist/api/runtime/tool-emulation/index.js +5 -0
  12. package/dist/api/runtime/tool-emulation/index.js.map +1 -0
  13. package/dist/api/runtime/tool-emulation/loop.d.ts +38 -0
  14. package/dist/api/runtime/tool-emulation/loop.d.ts.map +1 -0
  15. package/dist/api/runtime/tool-emulation/loop.js +53 -0
  16. package/dist/api/runtime/tool-emulation/loop.js.map +1 -0
  17. package/dist/api/runtime/tool-emulation/parser.d.ts +23 -0
  18. package/dist/api/runtime/tool-emulation/parser.d.ts.map +1 -0
  19. package/dist/api/runtime/tool-emulation/parser.js +38 -0
  20. package/dist/api/runtime/tool-emulation/parser.js.map +1 -0
  21. package/dist/api/runtime/tool-emulation/renderer.d.ts +8 -0
  22. package/dist/api/runtime/tool-emulation/renderer.d.ts.map +1 -0
  23. package/dist/api/runtime/tool-emulation/renderer.js +26 -0
  24. package/dist/api/runtime/tool-emulation/renderer.js.map +1 -0
  25. package/dist/api/streamText.d.ts.map +1 -1
  26. package/dist/api/streamText.js +324 -256
  27. package/dist/api/streamText.js.map +1 -1
  28. package/dist/cognition/rag/vector_stores/PostgresVectorStore.js +3 -3
  29. package/dist/cognition/rag/vector_stores/PostgresVectorStore.js.map +1 -1
  30. package/dist/core/llm/providers/implementations/AnthropicProvider.d.ts.map +1 -1
  31. package/dist/core/llm/providers/implementations/AnthropicProvider.js +18 -4
  32. package/dist/core/llm/providers/implementations/AnthropicProvider.js.map +1 -1
  33. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  import { type HostLLMPolicy } from './runtime/hostPolicy.js';
2
2
  import { type AdaptableToolInput } from './runtime/toolAdapter.js';
3
+ import { type ToolMode } from './runtime/tool-emulation/index.js';
3
4
  import type { AgentOSUsageLedgerOptions } from './runtime/usageLedger.js';
4
5
  import type { ITool } from '../core/tools/ITool.js';
5
6
  import type { AgentCallRecord, AgencyTraceEvent } from './types.js';
@@ -175,11 +176,28 @@ export interface GenerateTextOptions {
175
176
  * tool error if the model invokes them without an executor.
176
177
  */
177
178
  tools?: AdaptableToolInput;
179
+ /**
180
+ * Provider `tool_choice` passthrough. Forwarded verbatim to the provider so
181
+ * callers can force a specific tool, force tool use, or set `'auto'`. Provider
182
+ * support varies; Anthropic + OpenAI honor it. Native path only (ignored on
183
+ * the prompt-emulation shim).
184
+ */
185
+ toolChoice?: string | Record<string, unknown>;
178
186
  /**
179
187
  * Maximum number of agentic steps (LLM calls) to execute before returning.
180
188
  * Each tool-call round trip counts as one step. Defaults to `1`.
181
189
  */
182
190
  maxSteps?: number;
191
+ /**
192
+ * Tool-calling strategy. `'auto'` (default) uses native provider tool-calling,
193
+ * and on a tool-unsupported provider error falls back to a prompt-based shim
194
+ * (tool schemas rendered into the prompt, `<tool_call>` blocks parsed from the
195
+ * model's text). `'native'` forces native only. `'prompt'` forces the shim.
196
+ * The shim makes AgentOS tools work on models without native tool-use (e.g.
197
+ * the uncensored OpenRouter catalog). Shim roundtrips are capped by `maxSteps`
198
+ * (default 5 when unset on the shim path).
199
+ */
200
+ toolMode?: ToolMode;
183
201
  /** Sampling temperature forwarded to the provider (0-2 for most providers). */
184
202
  temperature?: number;
185
203
  /** Hard cap on output tokens. Provider-dependent default applies when omitted. */
@@ -1 +1 @@
1
- {"version":3,"file":"generateText.d.ts","sourceRoot":"","sources":["../../src/api/generateText.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generateText.d.ts","sourceRoot":"","sources":["../../src/api/generateText.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,7 @@ import { attachUsageAttributes, toTurnMetricUsage } from './observability.js';
17
17
  import { fireLlmUsageObserver } from './observers.js';
18
18
  import { hostPolicyToRouteParams, mergeRequiredCapabilities, } from './runtime/hostPolicy.js';
19
19
  import { adaptTools } from './runtime/toolAdapter.js';
20
+ import { runEmulatedToolLoop } from './runtime/tool-emulation/index.js';
20
21
  import { resolveDynamicToolCalls } from './runtime/dynamicToolCalling.js';
21
22
  import { recordAgentOSTurnMetrics, withAgentOSSpan } from '../safety/evaluation/observability/otel.js';
22
23
  import { createLogger } from '../core/logging/loggerFactory.js';
@@ -633,119 +634,293 @@ export async function generateText(opts) {
633
634
  span?.setAttribute('agentos.api.plan_steps', resolvedPlan.steps.length);
634
635
  }
635
636
  }
636
- for (let step = 0; step < maxSteps; step++) {
637
- // --- onBeforeGeneration hook ---
638
- let effectiveMessages = messages;
639
- if (opts.onBeforeGeneration) {
640
- try {
641
- const hookCtx = {
642
- messages: [...messages],
643
- system: opts.system,
644
- tools: Array.from(toolMap.values()),
645
- model: resolved.modelId,
646
- provider: resolved.providerId,
647
- step,
648
- prompt: opts.prompt,
637
+ // --- Prompt-based tool-calling shim (toolMode) ---
638
+ // For models without native tool-use, render tool schemas into the
639
+ // prompt and parse <tool_call> blocks out of the model's text. 'prompt'
640
+ // forces it up front; 'auto' tries native first and falls back on the
641
+ // provider's tool-unsupported error (see the catch after the loop).
642
+ const toolMode = opts.toolMode ?? 'auto';
643
+ const shimMaxRoundtrips = opts.maxSteps ?? 5;
644
+ const runShim = async () => {
645
+ const loopResult = await runEmulatedToolLoop({
646
+ tools: Array.from(toolMap.values()),
647
+ messages: messages.map((m) => ({
648
+ role: String(m.role),
649
+ content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content ?? ''),
650
+ })),
651
+ maxRoundtrips: shimMaxRoundtrips,
652
+ callModel: async (msgs) => {
653
+ const r = await provider.generateCompletion(resolved.modelId, msgs, {
654
+ temperature: opts.temperature,
655
+ maxTokens: opts.maxTokens,
656
+ });
657
+ const cc = r.choices?.[0]?.message?.content;
658
+ return {
659
+ text: typeof cc === 'string' ? cc : (cc?.text ?? ''),
660
+ usage: { totalTokens: r.usage?.totalTokens ?? 0 },
649
661
  };
650
- const modified = await opts.onBeforeGeneration(hookCtx);
651
- if (modified) {
652
- effectiveMessages = modified.messages;
662
+ },
663
+ });
664
+ const shimUsage = {
665
+ ...totalUsage,
666
+ totalTokens: (totalUsage.totalTokens ?? 0) + loopResult.totalTokens,
667
+ };
668
+ metricUsage = shimUsage;
669
+ fireLlmUsageObserver({
670
+ provider: resolved.providerId,
671
+ model: resolved.modelId,
672
+ usage: shimUsage,
673
+ source: opts.source,
674
+ finishReason: loopResult.finishReason,
675
+ surface: 'generateText',
676
+ });
677
+ return {
678
+ provider: resolved.providerId,
679
+ model: resolved.modelId,
680
+ text: loopResult.text,
681
+ usage: shimUsage,
682
+ toolCalls: loopResult.toolCalls.map((c) => ({
683
+ name: c.name,
684
+ args: c.args,
685
+ ...(c.error ? { error: c.error } : {}),
686
+ })),
687
+ finishReason: loopResult.finishReason,
688
+ plan: resolvedPlan,
689
+ };
690
+ };
691
+ const toolUnsupportedErr = (e) => e instanceof Error &&
692
+ /support tool use|does not support (tools|function)|no endpoints found that support/i.test(e.message);
693
+ if (tools.length > 0 && toolMode === 'prompt') {
694
+ return await runShim();
695
+ }
696
+ try {
697
+ for (let step = 0; step < maxSteps; step++) {
698
+ // --- onBeforeGeneration hook ---
699
+ let effectiveMessages = messages;
700
+ if (opts.onBeforeGeneration) {
701
+ try {
702
+ const hookCtx = {
703
+ messages: [...messages],
704
+ system: opts.system,
705
+ tools: Array.from(toolMap.values()),
706
+ model: resolved.modelId,
707
+ provider: resolved.providerId,
708
+ step,
709
+ prompt: opts.prompt,
710
+ };
711
+ const modified = await opts.onBeforeGeneration(hookCtx);
712
+ if (modified) {
713
+ effectiveMessages = modified.messages;
714
+ }
715
+ }
716
+ catch (hookErr) {
717
+ console.warn('[agentos] onBeforeGeneration hook error:', hookErr);
653
718
  }
654
719
  }
655
- catch (hookErr) {
656
- console.warn('[agentos] onBeforeGeneration hook error:', hookErr);
657
- }
658
- }
659
- const response = await withAgentOSSpan('agentos.api.generate_text.step', async (stepSpan) => {
660
- stepSpan?.setAttribute('llm.provider', resolved.providerId);
661
- stepSpan?.setAttribute('llm.model', resolved.modelId);
662
- stepSpan?.setAttribute('agentos.api.step', step + 1);
663
- stepSpan?.setAttribute('agentos.api.tool_count', tools.length);
664
- const stepResponse = await provider.generateCompletion(resolved.modelId, effectiveMessages, {
665
- tools: toolSchemas,
666
- temperature: opts.temperature,
667
- maxTokens: opts.maxTokens,
668
- ...(opts._responseFormat ? { responseFormat: opts._responseFormat } : {}),
720
+ const response = await withAgentOSSpan('agentos.api.generate_text.step', async (stepSpan) => {
721
+ stepSpan?.setAttribute('llm.provider', resolved.providerId);
722
+ stepSpan?.setAttribute('llm.model', resolved.modelId);
723
+ stepSpan?.setAttribute('agentos.api.step', step + 1);
724
+ stepSpan?.setAttribute('agentos.api.tool_count', tools.length);
725
+ const stepResponse = await provider.generateCompletion(resolved.modelId, effectiveMessages, {
726
+ tools: toolSchemas,
727
+ temperature: opts.temperature,
728
+ maxTokens: opts.maxTokens,
729
+ // Forward caller toolChoice so orchestrators can force tool_use
730
+ // (e.g. ai-codegen); models narrate under tool_choice: 'auto'.
731
+ ...(opts.toolChoice !== undefined ? { toolChoice: opts.toolChoice } : {}),
732
+ ...(opts._responseFormat ? { responseFormat: opts._responseFormat } : {}),
733
+ });
734
+ attachUsageAttributes(stepSpan, {
735
+ promptTokens: stepResponse.usage?.promptTokens,
736
+ completionTokens: stepResponse.usage?.completionTokens,
737
+ totalTokens: stepResponse.usage?.totalTokens,
738
+ costUSD: stepResponse.usage?.costUSD,
739
+ });
740
+ return stepResponse;
669
741
  });
670
- attachUsageAttributes(stepSpan, {
671
- promptTokens: stepResponse.usage?.promptTokens,
672
- completionTokens: stepResponse.usage?.completionTokens,
673
- totalTokens: stepResponse.usage?.totalTokens,
674
- costUSD: stepResponse.usage?.costUSD,
675
- });
676
- return stepResponse;
677
- });
678
- if (response.usage) {
679
- totalUsage.promptTokens += response.usage.promptTokens ?? 0;
680
- totalUsage.completionTokens += response.usage.completionTokens ?? 0;
681
- totalUsage.totalTokens += response.usage.totalTokens ?? 0;
682
- if (typeof response.usage.costUSD === 'number') {
683
- totalUsage.costUSD = (totalUsage.costUSD ?? 0) + response.usage.costUSD;
684
- }
685
- // Plumb prompt-cache metrics through so generateText() callers
686
- // can measure cache hit rate. Provider-layer ModelUsage carries
687
- // these fields; TokenUsage was dropping them.
688
- const cacheRead = response.usage.cacheReadInputTokens;
689
- const cacheCreate = response.usage.cacheCreationInputTokens;
690
- if (typeof cacheRead === 'number' && cacheRead > 0) {
691
- totalUsage.cacheReadTokens = (totalUsage.cacheReadTokens ?? 0) + cacheRead;
742
+ if (response.usage) {
743
+ totalUsage.promptTokens += response.usage.promptTokens ?? 0;
744
+ totalUsage.completionTokens += response.usage.completionTokens ?? 0;
745
+ totalUsage.totalTokens += response.usage.totalTokens ?? 0;
746
+ if (typeof response.usage.costUSD === 'number') {
747
+ totalUsage.costUSD = (totalUsage.costUSD ?? 0) + response.usage.costUSD;
748
+ }
749
+ // Plumb prompt-cache metrics through so generateText() callers
750
+ // can measure cache hit rate. Provider-layer ModelUsage carries
751
+ // these fields; TokenUsage was dropping them.
752
+ const cacheRead = response.usage.cacheReadInputTokens;
753
+ const cacheCreate = response.usage.cacheCreationInputTokens;
754
+ if (typeof cacheRead === 'number' && cacheRead > 0) {
755
+ totalUsage.cacheReadTokens = (totalUsage.cacheReadTokens ?? 0) + cacheRead;
756
+ }
757
+ if (typeof cacheCreate === 'number' && cacheCreate > 0) {
758
+ totalUsage.cacheCreationTokens = (totalUsage.cacheCreationTokens ?? 0) + cacheCreate;
759
+ }
692
760
  }
693
- if (typeof cacheCreate === 'number' && cacheCreate > 0) {
694
- totalUsage.cacheCreationTokens = (totalUsage.cacheCreationTokens ?? 0) + cacheCreate;
761
+ const choice = response.choices?.[0];
762
+ if (!choice)
763
+ break;
764
+ const content = choice.message?.content;
765
+ let textContent = typeof content === 'string' ? content : (content?.text ?? '');
766
+ let toolCallsInChoice = resolveDynamicToolCalls(choice.message?.tool_calls, {
767
+ text: textContent,
768
+ step,
769
+ toolsAvailable: tools.length > 0,
770
+ });
771
+ // --- onAfterGeneration hook ---
772
+ if (opts.onAfterGeneration) {
773
+ try {
774
+ const stepUsage = {
775
+ promptTokens: response.usage?.promptTokens ?? 0,
776
+ completionTokens: response.usage?.completionTokens ?? 0,
777
+ totalTokens: response.usage?.totalTokens ?? 0,
778
+ costUSD: response.usage?.costUSD,
779
+ cacheReadTokens: response.usage?.cacheReadInputTokens,
780
+ cacheCreationTokens: response.usage?.cacheCreationInputTokens,
781
+ };
782
+ const toolCallRecords = toolCallsInChoice.map((tc) => ({
783
+ name: tc.function?.name ?? tc.name ?? '',
784
+ args: tc.function?.arguments ?? '{}',
785
+ }));
786
+ const hookResult = {
787
+ text: textContent,
788
+ toolCalls: toolCallRecords,
789
+ usage: stepUsage,
790
+ step,
791
+ };
792
+ const modified = await opts.onAfterGeneration(hookResult);
793
+ if (modified) {
794
+ textContent = modified.text;
795
+ if (modified.toolCalls.length === 0 && toolCallsInChoice.length > 0) {
796
+ toolCallsInChoice = [];
797
+ }
798
+ }
799
+ }
800
+ catch (hookErr) {
801
+ console.warn('[agentos] onAfterGeneration hook error:', hookErr);
802
+ }
695
803
  }
696
- }
697
- const choice = response.choices?.[0];
698
- if (!choice)
699
- break;
700
- const content = choice.message?.content;
701
- let textContent = typeof content === 'string' ? content : (content?.text ?? '');
702
- let toolCallsInChoice = resolveDynamicToolCalls(choice.message?.tool_calls, {
703
- text: textContent,
704
- step,
705
- toolsAvailable: tools.length > 0,
706
- });
707
- // --- onAfterGeneration hook ---
708
- if (opts.onAfterGeneration) {
709
- try {
710
- const stepUsage = {
711
- promptTokens: response.usage?.promptTokens ?? 0,
712
- completionTokens: response.usage?.completionTokens ?? 0,
713
- totalTokens: response.usage?.totalTokens ?? 0,
714
- costUSD: response.usage?.costUSD,
715
- cacheReadTokens: response.usage?.cacheReadInputTokens,
716
- cacheCreationTokens: response.usage?.cacheCreationInputTokens,
717
- };
718
- const toolCallRecords = toolCallsInChoice.map((tc) => ({
719
- name: tc.function?.name ?? tc.name ?? '',
720
- args: tc.function?.arguments ?? '{}',
721
- }));
722
- const hookResult = {
804
+ if (textContent && toolCallsInChoice.length === 0) {
805
+ metricUsage = totalUsage;
806
+ span?.setAttribute('agentos.api.finish_reason', choice.finishReason ?? 'stop');
807
+ span?.setAttribute('agentos.api.tool_calls', allToolCalls.length);
808
+ attachUsageAttributes(span, totalUsage);
809
+ // 2026-05-29 fire the global LLM usage observer so hosts
810
+ // (wilds-ai foundation_usage_events, billing dashboards) get
811
+ // the resolved provider + model + cost without wrapping every
812
+ // callsite. No-op when no observer is registered.
813
+ fireLlmUsageObserver({
814
+ provider: resolved.providerId,
815
+ model: resolved.modelId,
816
+ usage: totalUsage,
817
+ source: opts.source,
818
+ finishReason: choice.finishReason ?? 'stop',
819
+ surface: 'generateText',
820
+ });
821
+ return {
822
+ provider: resolved.providerId,
823
+ model: resolved.modelId,
723
824
  text: textContent,
724
- toolCalls: toolCallRecords,
725
- usage: stepUsage,
726
- step,
825
+ usage: totalUsage,
826
+ toolCalls: allToolCalls,
827
+ finishReason: (choice.finishReason ?? 'stop'),
828
+ plan: resolvedPlan,
727
829
  };
728
- const modified = await opts.onAfterGeneration(hookResult);
729
- if (modified) {
730
- textContent = modified.text;
731
- if (modified.toolCalls.length === 0 && toolCallsInChoice.length > 0) {
732
- toolCallsInChoice = [];
830
+ }
831
+ if (toolCallsInChoice.length > 0) {
832
+ messages.push({
833
+ role: 'assistant',
834
+ content: textContent || null,
835
+ tool_calls: toolCallsInChoice,
836
+ });
837
+ for (const tc of toolCallsInChoice) {
838
+ const fnName = tc.function?.name ?? tc.name ?? '';
839
+ const fnArgs = tc.function?.arguments ?? '{}';
840
+ const tcId = tc.id ?? '';
841
+ const tool = toolMap.get(fnName);
842
+ const record = {
843
+ name: fnName,
844
+ args: fnArgs,
845
+ };
846
+ let parsedArgs;
847
+ try {
848
+ parsedArgs =
849
+ typeof fnArgs === 'string' ? JSON.parse(fnArgs) : fnArgs;
850
+ record.args = parsedArgs;
851
+ }
852
+ catch {
853
+ record.error = `Tool "${fnName}" arguments were not valid JSON.`;
854
+ messages.push({
855
+ role: 'tool',
856
+ tool_call_id: tcId,
857
+ content: JSON.stringify({ error: record.error }),
858
+ });
859
+ allToolCalls.push(record);
860
+ continue;
861
+ }
862
+ // --- onBeforeToolExecution hook ---
863
+ if (opts.onBeforeToolExecution) {
864
+ try {
865
+ const hookInfo = {
866
+ name: fnName,
867
+ args: parsedArgs,
868
+ id: tcId || '',
869
+ step,
870
+ };
871
+ const hookResult = await opts.onBeforeToolExecution(hookInfo);
872
+ if (hookResult === null) {
873
+ record.error = 'Skipped by onBeforeToolExecution hook';
874
+ messages.push({
875
+ role: 'tool',
876
+ tool_call_id: tcId,
877
+ content: JSON.stringify({ skipped: true }),
878
+ });
879
+ allToolCalls.push(record);
880
+ continue;
881
+ }
882
+ parsedArgs = hookResult.args;
883
+ }
884
+ catch (hookErr) {
885
+ console.warn('[agentos] onBeforeToolExecution hook error:', hookErr);
886
+ }
733
887
  }
888
+ if (tool) {
889
+ try {
890
+ const result = await tool.execute(parsedArgs, buildHelperToolExecutionContext('generateText', helperToolRunId, step, tcId || undefined));
891
+ record.result = result.output;
892
+ record.error = result.success ? undefined : result.error;
893
+ messages.push({
894
+ role: 'tool',
895
+ tool_call_id: tcId,
896
+ content: JSON.stringify(result.output ?? result.error ?? ''),
897
+ });
898
+ }
899
+ catch (err) {
900
+ record.error = err?.message;
901
+ messages.push({
902
+ role: 'tool',
903
+ tool_call_id: tcId,
904
+ content: JSON.stringify({ error: err?.message }),
905
+ });
906
+ }
907
+ }
908
+ else {
909
+ record.error = `Tool "${fnName}" not found.`;
910
+ messages.push({
911
+ role: 'tool',
912
+ tool_call_id: tcId,
913
+ content: JSON.stringify({ error: record.error }),
914
+ });
915
+ }
916
+ allToolCalls.push(record);
734
917
  }
918
+ continue;
735
919
  }
736
- catch (hookErr) {
737
- console.warn('[agentos] onAfterGeneration hook error:', hookErr);
738
- }
739
- }
740
- if (textContent && toolCallsInChoice.length === 0) {
741
920
  metricUsage = totalUsage;
742
921
  span?.setAttribute('agentos.api.finish_reason', choice.finishReason ?? 'stop');
743
922
  span?.setAttribute('agentos.api.tool_calls', allToolCalls.length);
744
923
  attachUsageAttributes(span, totalUsage);
745
- // 2026-05-29 — fire the global LLM usage observer so hosts
746
- // (wilds-ai foundation_usage_events, billing dashboards) get
747
- // the resolved provider + model + cost without wrapping every
748
- // callsite. No-op when no observer is registered.
749
924
  fireLlmUsageObserver({
750
925
  provider: resolved.providerId,
751
926
  model: resolved.modelId,
@@ -764,116 +939,14 @@ export async function generateText(opts) {
764
939
  plan: resolvedPlan,
765
940
  };
766
941
  }
767
- if (toolCallsInChoice.length > 0) {
768
- messages.push({
769
- role: 'assistant',
770
- content: textContent || null,
771
- tool_calls: toolCallsInChoice,
772
- });
773
- for (const tc of toolCallsInChoice) {
774
- const fnName = tc.function?.name ?? tc.name ?? '';
775
- const fnArgs = tc.function?.arguments ?? '{}';
776
- const tcId = tc.id ?? '';
777
- const tool = toolMap.get(fnName);
778
- const record = {
779
- name: fnName,
780
- args: fnArgs,
781
- };
782
- let parsedArgs;
783
- try {
784
- parsedArgs =
785
- typeof fnArgs === 'string' ? JSON.parse(fnArgs) : fnArgs;
786
- record.args = parsedArgs;
787
- }
788
- catch {
789
- record.error = `Tool "${fnName}" arguments were not valid JSON.`;
790
- messages.push({
791
- role: 'tool',
792
- tool_call_id: tcId,
793
- content: JSON.stringify({ error: record.error }),
794
- });
795
- allToolCalls.push(record);
796
- continue;
797
- }
798
- // --- onBeforeToolExecution hook ---
799
- if (opts.onBeforeToolExecution) {
800
- try {
801
- const hookInfo = {
802
- name: fnName,
803
- args: parsedArgs,
804
- id: tcId || '',
805
- step,
806
- };
807
- const hookResult = await opts.onBeforeToolExecution(hookInfo);
808
- if (hookResult === null) {
809
- record.error = 'Skipped by onBeforeToolExecution hook';
810
- messages.push({
811
- role: 'tool',
812
- tool_call_id: tcId,
813
- content: JSON.stringify({ skipped: true }),
814
- });
815
- allToolCalls.push(record);
816
- continue;
817
- }
818
- parsedArgs = hookResult.args;
819
- }
820
- catch (hookErr) {
821
- console.warn('[agentos] onBeforeToolExecution hook error:', hookErr);
822
- }
823
- }
824
- if (tool) {
825
- try {
826
- const result = await tool.execute(parsedArgs, buildHelperToolExecutionContext('generateText', helperToolRunId, step, tcId || undefined));
827
- record.result = result.output;
828
- record.error = result.success ? undefined : result.error;
829
- messages.push({
830
- role: 'tool',
831
- tool_call_id: tcId,
832
- content: JSON.stringify(result.output ?? result.error ?? ''),
833
- });
834
- }
835
- catch (err) {
836
- record.error = err?.message;
837
- messages.push({
838
- role: 'tool',
839
- tool_call_id: tcId,
840
- content: JSON.stringify({ error: err?.message }),
841
- });
842
- }
843
- }
844
- else {
845
- record.error = `Tool "${fnName}" not found.`;
846
- messages.push({
847
- role: 'tool',
848
- tool_call_id: tcId,
849
- content: JSON.stringify({ error: record.error }),
850
- });
851
- }
852
- allToolCalls.push(record);
853
- }
854
- continue;
942
+ }
943
+ catch (loopErr) {
944
+ // 'auto' reactive fallback: when the provider rejects native tool-use,
945
+ // re-run the turn through the prompt-based shim.
946
+ if (tools.length > 0 && toolMode === 'auto' && toolUnsupportedErr(loopErr)) {
947
+ return await runShim();
855
948
  }
856
- metricUsage = totalUsage;
857
- span?.setAttribute('agentos.api.finish_reason', choice.finishReason ?? 'stop');
858
- span?.setAttribute('agentos.api.tool_calls', allToolCalls.length);
859
- attachUsageAttributes(span, totalUsage);
860
- fireLlmUsageObserver({
861
- provider: resolved.providerId,
862
- model: resolved.modelId,
863
- usage: totalUsage,
864
- source: opts.source,
865
- finishReason: choice.finishReason ?? 'stop',
866
- surface: 'generateText',
867
- });
868
- return {
869
- provider: resolved.providerId,
870
- model: resolved.modelId,
871
- text: textContent,
872
- usage: totalUsage,
873
- toolCalls: allToolCalls,
874
- finishReason: (choice.finishReason ?? 'stop'),
875
- plan: resolvedPlan,
876
- };
949
+ throw loopErr;
877
950
  }
878
951
  const lastAssistant = messages.filter((m) => m.role === 'assistant').pop();
879
952
  metricUsage = totalUsage;