@warlock.js/ai 4.1.1
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/README.md +72 -0
- package/cjs/index.cjs +8625 -0
- package/cjs/index.cjs.map +1 -0
- package/esm/agent/agent-config.type.d.mts +160 -0
- package/esm/agent/agent-config.type.d.mts.map +1 -0
- package/esm/agent/agent-input-builder.mjs +111 -0
- package/esm/agent/agent-input-builder.mjs.map +1 -0
- package/esm/agent/agent-log-event.mjs +101 -0
- package/esm/agent/agent-log-event.mjs.map +1 -0
- package/esm/agent/agent-stream.d.mts +47 -0
- package/esm/agent/agent-stream.d.mts.map +1 -0
- package/esm/agent/agent-stream.mjs +82 -0
- package/esm/agent/agent-stream.mjs.map +1 -0
- package/esm/agent/agent-to-stream-event.mjs +86 -0
- package/esm/agent/agent-to-stream-event.mjs.map +1 -0
- package/esm/agent/agent.d.mts +38 -0
- package/esm/agent/agent.d.mts.map +1 -0
- package/esm/agent/agent.mjs +974 -0
- package/esm/agent/agent.mjs.map +1 -0
- package/esm/agent/index.d.mts +3 -0
- package/esm/agent/index.mjs +4 -0
- package/esm/agent/json-stream-guard.mjs +400 -0
- package/esm/agent/json-stream-guard.mjs.map +1 -0
- package/esm/ai.d.mts +64 -0
- package/esm/ai.d.mts.map +1 -0
- package/esm/ai.mjs +65 -0
- package/esm/ai.mjs.map +1 -0
- package/esm/config.d.mts +79 -0
- package/esm/config.d.mts.map +1 -0
- package/esm/config.mjs +43 -0
- package/esm/config.mjs.map +1 -0
- package/esm/contracts/agent/agent-options.type.d.mts +132 -0
- package/esm/contracts/agent/agent-options.type.d.mts.map +1 -0
- package/esm/contracts/agent/agent.contract.d.mts +92 -0
- package/esm/contracts/agent/agent.contract.d.mts.map +1 -0
- package/esm/contracts/agent/index.d.mts +2 -0
- package/esm/contracts/attachment.type.d.mts +100 -0
- package/esm/contracts/attachment.type.d.mts.map +1 -0
- package/esm/contracts/content-part.type.d.mts +55 -0
- package/esm/contracts/content-part.type.d.mts.map +1 -0
- package/esm/contracts/conversation-message.type.d.mts +51 -0
- package/esm/contracts/conversation-message.type.d.mts.map +1 -0
- package/esm/contracts/embedder.contract.d.mts +69 -0
- package/esm/contracts/embedder.contract.d.mts.map +1 -0
- package/esm/contracts/end.type.d.mts +53 -0
- package/esm/contracts/end.type.d.mts.map +1 -0
- package/esm/contracts/end.type.mjs +47 -0
- package/esm/contracts/end.type.mjs.map +1 -0
- package/esm/contracts/events/agent-events.type.d.mts +71 -0
- package/esm/contracts/events/agent-events.type.d.mts.map +1 -0
- package/esm/contracts/events/complete-event.type.d.mts +33 -0
- package/esm/contracts/events/complete-event.type.d.mts.map +1 -0
- package/esm/contracts/events/event-identity.type.d.mts +30 -0
- package/esm/contracts/events/event-identity.type.d.mts.map +1 -0
- package/esm/contracts/events/event-map.type.d.mts +80 -0
- package/esm/contracts/events/event-map.type.d.mts.map +1 -0
- package/esm/contracts/events/index.d.mts +7 -0
- package/esm/contracts/events/supervisor-events.type.d.mts +162 -0
- package/esm/contracts/events/supervisor-events.type.d.mts.map +1 -0
- package/esm/contracts/events/usage-event.type.d.mts +39 -0
- package/esm/contracts/events/usage-event.type.d.mts.map +1 -0
- package/esm/contracts/events/workflow-events.type.d.mts +51 -0
- package/esm/contracts/events/workflow-events.type.d.mts.map +1 -0
- package/esm/contracts/executable.contract.d.mts +25 -0
- package/esm/contracts/executable.contract.d.mts.map +1 -0
- package/esm/contracts/finish-reason.type.d.mts +17 -0
- package/esm/contracts/finish-reason.type.d.mts.map +1 -0
- package/esm/contracts/index.d.mts +63 -0
- package/esm/contracts/middleware/index.d.mts +3 -0
- package/esm/contracts/middleware/middleware-context.type.d.mts +99 -0
- package/esm/contracts/middleware/middleware-context.type.d.mts.map +1 -0
- package/esm/contracts/middleware/middleware-state.type.d.mts +34 -0
- package/esm/contracts/middleware/middleware-state.type.d.mts.map +1 -0
- package/esm/contracts/middleware/middleware.contract.d.mts +140 -0
- package/esm/contracts/middleware/middleware.contract.d.mts.map +1 -0
- package/esm/contracts/model-tool-call-request.type.d.mts +58 -0
- package/esm/contracts/model-tool-call-request.type.d.mts.map +1 -0
- package/esm/contracts/model.contract.d.mts +164 -0
- package/esm/contracts/model.contract.d.mts.map +1 -0
- package/esm/contracts/placeholders.type.d.mts +23 -0
- package/esm/contracts/placeholders.type.d.mts.map +1 -0
- package/esm/contracts/result/agent-result.type.d.mts +33 -0
- package/esm/contracts/result/agent-result.type.d.mts.map +1 -0
- package/esm/contracts/result/attempt-entry.type.d.mts +40 -0
- package/esm/contracts/result/attempt-entry.type.d.mts.map +1 -0
- package/esm/contracts/result/base-report.type.d.mts +137 -0
- package/esm/contracts/result/base-report.type.d.mts.map +1 -0
- package/esm/contracts/result/base-report.type.mjs +17 -0
- package/esm/contracts/result/base-report.type.mjs.map +1 -0
- package/esm/contracts/result/base-result.type.d.mts +26 -0
- package/esm/contracts/result/base-result.type.d.mts.map +1 -0
- package/esm/contracts/result/execute-result.type.d.mts +40 -0
- package/esm/contracts/result/execute-result.type.d.mts.map +1 -0
- package/esm/contracts/result/execution-report.type.d.mts +50 -0
- package/esm/contracts/result/execution-report.type.d.mts.map +1 -0
- package/esm/contracts/result/index.d.mts +14 -0
- package/esm/contracts/result/llm-trip.type.d.mts +36 -0
- package/esm/contracts/result/llm-trip.type.d.mts.map +1 -0
- package/esm/contracts/result/model-pricing.type.d.mts +51 -0
- package/esm/contracts/result/model-pricing.type.d.mts.map +1 -0
- package/esm/contracts/result/session-send-result.type.d.mts +29 -0
- package/esm/contracts/result/session-send-result.type.d.mts.map +1 -0
- package/esm/contracts/result/step-result.type.d.mts +43 -0
- package/esm/contracts/result/step-result.type.d.mts.map +1 -0
- package/esm/contracts/result/supervisor-result.type.d.mts +86 -0
- package/esm/contracts/result/supervisor-result.type.d.mts.map +1 -0
- package/esm/contracts/result/tool-call.type.d.mts +44 -0
- package/esm/contracts/result/tool-call.type.d.mts.map +1 -0
- package/esm/contracts/result/usage.type.d.mts +57 -0
- package/esm/contracts/result/usage.type.d.mts.map +1 -0
- package/esm/contracts/result/workflow-result.type.d.mts +45 -0
- package/esm/contracts/result/workflow-result.type.d.mts.map +1 -0
- package/esm/contracts/sdk-adapter.contract.d.mts +77 -0
- package/esm/contracts/sdk-adapter.contract.d.mts.map +1 -0
- package/esm/contracts/stream/stream-event.type.d.mts +68 -0
- package/esm/contracts/stream/stream-event.type.d.mts.map +1 -0
- package/esm/contracts/stream/stream.contract.d.mts +61 -0
- package/esm/contracts/stream/stream.contract.d.mts.map +1 -0
- package/esm/contracts/streaming-tool-guard-config.type.d.mts +78 -0
- package/esm/contracts/streaming-tool-guard-config.type.d.mts.map +1 -0
- package/esm/contracts/supervisor/ack-entry.type.d.mts +97 -0
- package/esm/contracts/supervisor/ack-entry.type.d.mts.map +1 -0
- package/esm/contracts/supervisor/classifier-context.type.d.mts +189 -0
- package/esm/contracts/supervisor/classifier-context.type.d.mts.map +1 -0
- package/esm/contracts/supervisor/dispatch-context.type.d.mts +235 -0
- package/esm/contracts/supervisor/dispatch-context.type.d.mts.map +1 -0
- package/esm/contracts/supervisor/evaluate-context.type.d.mts +124 -0
- package/esm/contracts/supervisor/evaluate-context.type.d.mts.map +1 -0
- package/esm/contracts/supervisor/index.d.mts +16 -0
- package/esm/contracts/supervisor/intent-entry.type.d.mts +254 -0
- package/esm/contracts/supervisor/intent-entry.type.d.mts.map +1 -0
- package/esm/contracts/supervisor/iteration-snapshot.type.d.mts +117 -0
- package/esm/contracts/supervisor/iteration-snapshot.type.d.mts.map +1 -0
- package/esm/contracts/supervisor/next.type.d.mts +25 -0
- package/esm/contracts/supervisor/next.type.d.mts.map +1 -0
- package/esm/contracts/supervisor/route-context.type.d.mts +91 -0
- package/esm/contracts/supervisor/route-context.type.d.mts.map +1 -0
- package/esm/contracts/supervisor/router-entry.type.d.mts +67 -0
- package/esm/contracts/supervisor/router-entry.type.d.mts.map +1 -0
- package/esm/contracts/supervisor/supervisor-config.type.d.mts +356 -0
- package/esm/contracts/supervisor/supervisor-config.type.d.mts.map +1 -0
- package/esm/contracts/supervisor/supervisor-execute-options.type.d.mts +90 -0
- package/esm/contracts/supervisor/supervisor-execute-options.type.d.mts.map +1 -0
- package/esm/contracts/supervisor/supervisor-input.type.d.mts +24 -0
- package/esm/contracts/supervisor/supervisor-input.type.d.mts.map +1 -0
- package/esm/contracts/supervisor/supervisor-snapshot.type.d.mts +49 -0
- package/esm/contracts/supervisor/supervisor-snapshot.type.d.mts.map +1 -0
- package/esm/contracts/supervisor/supervisor-stream-event.type.d.mts +16 -0
- package/esm/contracts/supervisor/supervisor-stream-event.type.d.mts.map +1 -0
- package/esm/contracts/supervisor/supervisor.contract.d.mts +126 -0
- package/esm/contracts/supervisor/supervisor.contract.d.mts.map +1 -0
- package/esm/contracts/system-prompt.contract.d.mts +118 -0
- package/esm/contracts/system-prompt.contract.d.mts.map +1 -0
- package/esm/contracts/tool.contract.d.mts +161 -0
- package/esm/contracts/tool.contract.d.mts.map +1 -0
- package/esm/contracts/workflow/index.d.mts +6 -0
- package/esm/contracts/workflow/next-step-result.type.d.mts +17 -0
- package/esm/contracts/workflow/next-step-result.type.d.mts.map +1 -0
- package/esm/contracts/workflow/retry-config.type.d.mts +19 -0
- package/esm/contracts/workflow/retry-config.type.d.mts.map +1 -0
- package/esm/contracts/workflow/step.contract.d.mts +189 -0
- package/esm/contracts/workflow/step.contract.d.mts.map +1 -0
- package/esm/contracts/workflow/workflow-context.type.d.mts +45 -0
- package/esm/contracts/workflow/workflow-context.type.d.mts.map +1 -0
- package/esm/contracts/workflow/workflow-snapshot.type.d.mts +24 -0
- package/esm/contracts/workflow/workflow-snapshot.type.d.mts.map +1 -0
- package/esm/contracts/workflow/workflow.contract.d.mts +142 -0
- package/esm/contracts/workflow/workflow.contract.d.mts.map +1 -0
- package/esm/errors/agent-cancelled-error.d.mts +49 -0
- package/esm/errors/agent-cancelled-error.d.mts.map +1 -0
- package/esm/errors/agent-cancelled-error.mjs +43 -0
- package/esm/errors/agent-cancelled-error.mjs.map +1 -0
- package/esm/errors/agent-execution-error.d.mts +32 -0
- package/esm/errors/agent-execution-error.d.mts.map +1 -0
- package/esm/errors/agent-execution-error.mjs +35 -0
- package/esm/errors/agent-execution-error.mjs.map +1 -0
- package/esm/errors/agent-max-trips-error.d.mts +45 -0
- package/esm/errors/agent-max-trips-error.d.mts.map +1 -0
- package/esm/errors/agent-max-trips-error.mjs +41 -0
- package/esm/errors/agent-max-trips-error.mjs.map +1 -0
- package/esm/errors/ai-error.d.mts +94 -0
- package/esm/errors/ai-error.d.mts.map +1 -0
- package/esm/errors/ai-error.mjs +68 -0
- package/esm/errors/ai-error.mjs.map +1 -0
- package/esm/errors/budget-exceeded-error.d.mts +41 -0
- package/esm/errors/budget-exceeded-error.d.mts.map +1 -0
- package/esm/errors/budget-exceeded-error.mjs +31 -0
- package/esm/errors/budget-exceeded-error.mjs.map +1 -0
- package/esm/errors/content-filter-error.d.mts +33 -0
- package/esm/errors/content-filter-error.d.mts.map +1 -0
- package/esm/errors/content-filter-error.mjs +28 -0
- package/esm/errors/content-filter-error.mjs.map +1 -0
- package/esm/errors/context-length-exceeded-error.d.mts +38 -0
- package/esm/errors/context-length-exceeded-error.d.mts.map +1 -0
- package/esm/errors/context-length-exceeded-error.mjs +31 -0
- package/esm/errors/context-length-exceeded-error.mjs.map +1 -0
- package/esm/errors/error-category.type.d.mts +30 -0
- package/esm/errors/error-category.type.d.mts.map +1 -0
- package/esm/errors/error-code.type.d.mts +19 -0
- package/esm/errors/error-code.type.d.mts.map +1 -0
- package/esm/errors/guardrail-violation-error.d.mts +55 -0
- package/esm/errors/guardrail-violation-error.d.mts.map +1 -0
- package/esm/errors/guardrail-violation-error.mjs +41 -0
- package/esm/errors/guardrail-violation-error.mjs.map +1 -0
- package/esm/errors/index.d.mts +29 -0
- package/esm/errors/index.mjs +29 -0
- package/esm/errors/invalid-request-error.d.mts +27 -0
- package/esm/errors/invalid-request-error.d.mts.map +1 -0
- package/esm/errors/invalid-request-error.mjs +31 -0
- package/esm/errors/invalid-request-error.mjs.map +1 -0
- package/esm/errors/max-iterations-error.d.mts +31 -0
- package/esm/errors/max-iterations-error.d.mts.map +1 -0
- package/esm/errors/max-iterations-error.mjs +32 -0
- package/esm/errors/max-iterations-error.mjs.map +1 -0
- package/esm/errors/max-steps-exceeded-error.d.mts +20 -0
- package/esm/errors/max-steps-exceeded-error.d.mts.map +1 -0
- package/esm/errors/max-steps-exceeded-error.mjs +21 -0
- package/esm/errors/max-steps-exceeded-error.mjs.map +1 -0
- package/esm/errors/provider-auth-error.d.mts +22 -0
- package/esm/errors/provider-auth-error.d.mts.map +1 -0
- package/esm/errors/provider-auth-error.mjs +26 -0
- package/esm/errors/provider-auth-error.mjs.map +1 -0
- package/esm/errors/provider-error.d.mts +38 -0
- package/esm/errors/provider-error.d.mts.map +1 -0
- package/esm/errors/provider-error.mjs +42 -0
- package/esm/errors/provider-error.mjs.map +1 -0
- package/esm/errors/provider-rate-limit-error.d.mts +34 -0
- package/esm/errors/provider-rate-limit-error.d.mts.map +1 -0
- package/esm/errors/provider-rate-limit-error.mjs +31 -0
- package/esm/errors/provider-rate-limit-error.mjs.map +1 -0
- package/esm/errors/provider-timeout-error.d.mts +22 -0
- package/esm/errors/provider-timeout-error.d.mts.map +1 -0
- package/esm/errors/provider-timeout-error.mjs +26 -0
- package/esm/errors/provider-timeout-error.mjs.map +1 -0
- package/esm/errors/quota-exceeded-error.d.mts +36 -0
- package/esm/errors/quota-exceeded-error.d.mts.map +1 -0
- package/esm/errors/quota-exceeded-error.mjs +40 -0
- package/esm/errors/quota-exceeded-error.mjs.map +1 -0
- package/esm/errors/routing-error.d.mts +23 -0
- package/esm/errors/routing-error.d.mts.map +1 -0
- package/esm/errors/routing-error.mjs +23 -0
- package/esm/errors/routing-error.mjs.map +1 -0
- package/esm/errors/schema-validation-error.d.mts +40 -0
- package/esm/errors/schema-validation-error.d.mts.map +1 -0
- package/esm/errors/schema-validation-error.mjs +37 -0
- package/esm/errors/schema-validation-error.mjs.map +1 -0
- package/esm/errors/step-failed-error.d.mts +20 -0
- package/esm/errors/step-failed-error.d.mts.map +1 -0
- package/esm/errors/step-failed-error.mjs +19 -0
- package/esm/errors/step-failed-error.mjs.map +1 -0
- package/esm/errors/supervisor-cancelled-error.d.mts +29 -0
- package/esm/errors/supervisor-cancelled-error.d.mts.map +1 -0
- package/esm/errors/supervisor-cancelled-error.mjs +29 -0
- package/esm/errors/supervisor-cancelled-error.mjs.map +1 -0
- package/esm/errors/supervisor-drift-error.d.mts +31 -0
- package/esm/errors/supervisor-drift-error.d.mts.map +1 -0
- package/esm/errors/supervisor-drift-error.mjs +30 -0
- package/esm/errors/supervisor-drift-error.mjs.map +1 -0
- package/esm/errors/supervisor-failed-error.d.mts +40 -0
- package/esm/errors/supervisor-failed-error.d.mts.map +1 -0
- package/esm/errors/supervisor-failed-error.mjs +43 -0
- package/esm/errors/supervisor-failed-error.mjs.map +1 -0
- package/esm/errors/supervisor-routing-error.d.mts +44 -0
- package/esm/errors/supervisor-routing-error.d.mts.map +1 -0
- package/esm/errors/supervisor-routing-error.mjs +39 -0
- package/esm/errors/supervisor-routing-error.mjs.map +1 -0
- package/esm/errors/tool-execution-error.d.mts +35 -0
- package/esm/errors/tool-execution-error.d.mts.map +1 -0
- package/esm/errors/tool-execution-error.mjs +32 -0
- package/esm/errors/tool-execution-error.mjs.map +1 -0
- package/esm/errors/workflow-cancelled-error.d.mts +23 -0
- package/esm/errors/workflow-cancelled-error.d.mts.map +1 -0
- package/esm/errors/workflow-cancelled-error.mjs +23 -0
- package/esm/errors/workflow-cancelled-error.mjs.map +1 -0
- package/esm/errors/workflow-drift-error.d.mts +25 -0
- package/esm/errors/workflow-drift-error.d.mts.map +1 -0
- package/esm/errors/workflow-drift-error.mjs +24 -0
- package/esm/errors/workflow-drift-error.mjs.map +1 -0
- package/esm/errors/workflow-error.d.mts +15 -0
- package/esm/errors/workflow-error.d.mts.map +1 -0
- package/esm/errors/workflow-error.mjs +18 -0
- package/esm/errors/workflow-error.mjs.map +1 -0
- package/esm/index.d.mts +137 -0
- package/esm/index.mjs +81 -0
- package/esm/middleware/builtins/budget.d.mts +103 -0
- package/esm/middleware/builtins/budget.d.mts.map +1 -0
- package/esm/middleware/builtins/budget.mjs +100 -0
- package/esm/middleware/builtins/budget.mjs.map +1 -0
- package/esm/middleware/builtins/guardrail.d.mts +92 -0
- package/esm/middleware/builtins/guardrail.d.mts.map +1 -0
- package/esm/middleware/builtins/guardrail.mjs +76 -0
- package/esm/middleware/builtins/guardrail.mjs.map +1 -0
- package/esm/middleware/builtins/semantic-cache.d.mts +106 -0
- package/esm/middleware/builtins/semantic-cache.d.mts.map +1 -0
- package/esm/middleware/builtins/semantic-cache.mjs +149 -0
- package/esm/middleware/builtins/semantic-cache.mjs.map +1 -0
- package/esm/middleware/helpers/compose.d.mts +42 -0
- package/esm/middleware/helpers/compose.d.mts.map +1 -0
- package/esm/middleware/helpers/compose.mjs +52 -0
- package/esm/middleware/helpers/compose.mjs.map +1 -0
- package/esm/middleware/helpers/for-tool.d.mts +55 -0
- package/esm/middleware/helpers/for-tool.d.mts.map +1 -0
- package/esm/middleware/helpers/for-tool.mjs +80 -0
- package/esm/middleware/helpers/for-tool.mjs.map +1 -0
- package/esm/middleware/helpers/index.d.mts +2 -0
- package/esm/middleware/index.d.mts +8 -0
- package/esm/middleware/index.mjs +10 -0
- package/esm/middleware/pipeline.d.mts +70 -0
- package/esm/middleware/pipeline.d.mts.map +1 -0
- package/esm/middleware/pipeline.mjs +100 -0
- package/esm/middleware/pipeline.mjs.map +1 -0
- package/esm/middleware/utils/extract-user-text.d.mts +33 -0
- package/esm/middleware/utils/extract-user-text.d.mts.map +1 -0
- package/esm/middleware/utils/extract-user-text.mjs +40 -0
- package/esm/middleware/utils/extract-user-text.mjs.map +1 -0
- package/esm/middleware/utils/index.d.mts +2 -0
- package/esm/middleware/utils/namespaced-state.d.mts +60 -0
- package/esm/middleware/utils/namespaced-state.d.mts.map +1 -0
- package/esm/middleware/utils/namespaced-state.mjs +60 -0
- package/esm/middleware/utils/namespaced-state.mjs.map +1 -0
- package/esm/mock/index.d.mts +4 -0
- package/esm/mock/index.mjs +5 -0
- package/esm/mock/mock-agent.d.mts +41 -0
- package/esm/mock/mock-agent.d.mts.map +1 -0
- package/esm/mock/mock-agent.mjs +39 -0
- package/esm/mock/mock-agent.mjs.map +1 -0
- package/esm/mock/mock-config.type.d.mts +31 -0
- package/esm/mock/mock-config.type.d.mts.map +1 -0
- package/esm/mock/mock-model.d.mts +94 -0
- package/esm/mock/mock-model.d.mts.map +1 -0
- package/esm/mock/mock-model.mjs +150 -0
- package/esm/mock/mock-model.mjs.map +1 -0
- package/esm/mock/mock-sdk.d.mts +25 -0
- package/esm/mock/mock-sdk.d.mts.map +1 -0
- package/esm/mock/mock-sdk.mjs +37 -0
- package/esm/mock/mock-sdk.mjs.map +1 -0
- package/esm/supervisor/as-tool.d.mts +45 -0
- package/esm/supervisor/as-tool.d.mts.map +1 -0
- package/esm/supervisor/as-tool.mjs +80 -0
- package/esm/supervisor/as-tool.mjs.map +1 -0
- package/esm/supervisor/cancellation.d.mts +12 -0
- package/esm/supervisor/cancellation.d.mts.map +1 -0
- package/esm/supervisor/cancellation.mjs +22 -0
- package/esm/supervisor/cancellation.mjs.map +1 -0
- package/esm/supervisor/decide.mjs +272 -0
- package/esm/supervisor/decide.mjs.map +1 -0
- package/esm/supervisor/emitter.d.mts +27 -0
- package/esm/supervisor/emitter.d.mts.map +1 -0
- package/esm/supervisor/emitter.mjs +47 -0
- package/esm/supervisor/emitter.mjs.map +1 -0
- package/esm/supervisor/entries.d.mts +141 -0
- package/esm/supervisor/entries.d.mts.map +1 -0
- package/esm/supervisor/entries.mjs +206 -0
- package/esm/supervisor/entries.mjs.map +1 -0
- package/esm/supervisor/execution.d.mts +637 -0
- package/esm/supervisor/execution.d.mts.map +1 -0
- package/esm/supervisor/execution.mjs +1868 -0
- package/esm/supervisor/execution.mjs.map +1 -0
- package/esm/supervisor/index.d.mts +11 -0
- package/esm/supervisor/index.mjs +12 -0
- package/esm/supervisor/router-prompt.d.mts +56 -0
- package/esm/supervisor/router-prompt.d.mts.map +1 -0
- package/esm/supervisor/router-prompt.mjs +52 -0
- package/esm/supervisor/router-prompt.mjs.map +1 -0
- package/esm/supervisor/signature.d.mts +28 -0
- package/esm/supervisor/signature.d.mts.map +1 -0
- package/esm/supervisor/signature.mjs +89 -0
- package/esm/supervisor/signature.mjs.map +1 -0
- package/esm/supervisor/snapshot.d.mts +54 -0
- package/esm/supervisor/snapshot.d.mts.map +1 -0
- package/esm/supervisor/snapshot.mjs +77 -0
- package/esm/supervisor/snapshot.mjs.map +1 -0
- package/esm/supervisor/supervisor-stream.d.mts +29 -0
- package/esm/supervisor/supervisor-stream.d.mts.map +1 -0
- package/esm/supervisor/supervisor-stream.mjs +89 -0
- package/esm/supervisor/supervisor-stream.mjs.map +1 -0
- package/esm/supervisor/supervisor.d.mts +27 -0
- package/esm/supervisor/supervisor.d.mts.map +1 -0
- package/esm/supervisor/supervisor.mjs +138 -0
- package/esm/supervisor/supervisor.mjs.map +1 -0
- package/esm/system-prompt/instruction.d.mts +52 -0
- package/esm/system-prompt/instruction.d.mts.map +1 -0
- package/esm/system-prompt/instruction.mjs +57 -0
- package/esm/system-prompt/instruction.mjs.map +1 -0
- package/esm/system-prompt/persona.d.mts +52 -0
- package/esm/system-prompt/persona.d.mts.map +1 -0
- package/esm/system-prompt/persona.mjs +57 -0
- package/esm/system-prompt/persona.mjs.map +1 -0
- package/esm/system-prompt/render-placeholders.d.mts +31 -0
- package/esm/system-prompt/render-placeholders.d.mts.map +1 -0
- package/esm/system-prompt/render-placeholders.mjs +58 -0
- package/esm/system-prompt/render-placeholders.mjs.map +1 -0
- package/esm/system-prompt/system-prompt.d.mts +117 -0
- package/esm/system-prompt/system-prompt.d.mts.map +1 -0
- package/esm/system-prompt/system-prompt.mjs +137 -0
- package/esm/system-prompt/system-prompt.mjs.map +1 -0
- package/esm/tool/index.d.mts +1 -0
- package/esm/tool/index.mjs +3 -0
- package/esm/tool/tool.d.mts +64 -0
- package/esm/tool/tool.d.mts.map +1 -0
- package/esm/tool/tool.mjs +184 -0
- package/esm/tool/tool.mjs.map +1 -0
- package/esm/utils/compute-cost.d.mts +58 -0
- package/esm/utils/compute-cost.d.mts.map +1 -0
- package/esm/utils/compute-cost.mjs +87 -0
- package/esm/utils/compute-cost.mjs.map +1 -0
- package/esm/utils/extract-json-payload.d.mts +33 -0
- package/esm/utils/extract-json-payload.d.mts.map +1 -0
- package/esm/utils/extract-json-payload.mjs +39 -0
- package/esm/utils/extract-json-payload.mjs.map +1 -0
- package/esm/utils/generate-run-id.d.mts +20 -0
- package/esm/utils/generate-run-id.d.mts.map +1 -0
- package/esm/utils/generate-run-id.mjs +23 -0
- package/esm/utils/generate-run-id.mjs.map +1 -0
- package/esm/utils/index.d.mts +9 -0
- package/esm/utils/index.mjs +11 -0
- package/esm/utils/json-schema.d.mts +57 -0
- package/esm/utils/json-schema.d.mts.map +1 -0
- package/esm/utils/json-schema.mjs +89 -0
- package/esm/utils/json-schema.mjs.map +1 -0
- package/esm/utils/prepare-attachment-part.d.mts +36 -0
- package/esm/utils/prepare-attachment-part.d.mts.map +1 -0
- package/esm/utils/prepare-attachment-part.mjs +140 -0
- package/esm/utils/prepare-attachment-part.mjs.map +1 -0
- package/esm/utils/resolve-attachment.d.mts +33 -0
- package/esm/utils/resolve-attachment.d.mts.map +1 -0
- package/esm/utils/resolve-attachment.mjs +73 -0
- package/esm/utils/resolve-attachment.mjs.map +1 -0
- package/esm/utils/safe-json-parse.d.mts +14 -0
- package/esm/utils/safe-json-parse.d.mts.map +1 -0
- package/esm/utils/safe-json-parse.mjs +22 -0
- package/esm/utils/safe-json-parse.mjs.map +1 -0
- package/esm/utils/stamp-report-lineage.d.mts +61 -0
- package/esm/utils/stamp-report-lineage.d.mts.map +1 -0
- package/esm/utils/stamp-report-lineage.mjs +47 -0
- package/esm/utils/stamp-report-lineage.mjs.map +1 -0
- package/esm/utils/token-count.d.mts +15 -0
- package/esm/utils/token-count.d.mts.map +1 -0
- package/esm/utils/token-count.mjs +18 -0
- package/esm/utils/token-count.mjs.map +1 -0
- package/esm/workflow/as-tool.mjs +55 -0
- package/esm/workflow/as-tool.mjs.map +1 -0
- package/esm/workflow/cancellation.mjs +44 -0
- package/esm/workflow/cancellation.mjs.map +1 -0
- package/esm/workflow/emitter.mjs +40 -0
- package/esm/workflow/emitter.mjs.map +1 -0
- package/esm/workflow/engine.mjs +362 -0
- package/esm/workflow/engine.mjs.map +1 -0
- package/esm/workflow/index.d.mts +3 -0
- package/esm/workflow/index.mjs +5 -0
- package/esm/workflow/retry.mjs +32 -0
- package/esm/workflow/retry.mjs.map +1 -0
- package/esm/workflow/router.mjs +56 -0
- package/esm/workflow/router.mjs.map +1 -0
- package/esm/workflow/run-scoped-emitter.mjs +32 -0
- package/esm/workflow/run-scoped-emitter.mjs.map +1 -0
- package/esm/workflow/signature.d.mts +7 -0
- package/esm/workflow/signature.d.mts.map +1 -0
- package/esm/workflow/signature.mjs +34 -0
- package/esm/workflow/signature.mjs.map +1 -0
- package/esm/workflow/snapshot.mjs +71 -0
- package/esm/workflow/snapshot.mjs.map +1 -0
- package/esm/workflow/state.mjs +37 -0
- package/esm/workflow/state.mjs.map +1 -0
- package/esm/workflow/step-runner.mjs +371 -0
- package/esm/workflow/step-runner.mjs.map +1 -0
- package/esm/workflow/step.d.mts +19 -0
- package/esm/workflow/step.d.mts.map +1 -0
- package/esm/workflow/step.mjs +37 -0
- package/esm/workflow/step.mjs.map +1 -0
- package/esm/workflow/workflow.d.mts +12 -0
- package/esm/workflow/workflow.d.mts.map +1 -0
- package/esm/workflow/workflow.mjs +116 -0
- package/esm/workflow/workflow.mjs.map +1 -0
- package/llms-full.txt +2293 -0
- package/llms.txt +20 -0
- package/package.json +37 -0
- package/skills/README.md +53 -0
- package/skills/ai-basics/SKILL.md +95 -0
- package/skills/attach-ai-middleware/SKILL.md +184 -0
- package/skills/define-ai-tool/SKILL.md +186 -0
- package/skills/embed-text/SKILL.md +105 -0
- package/skills/handle-ai-errors/SKILL.md +194 -0
- package/skills/log-ai-calls/SKILL.md +141 -0
- package/skills/persist-ai-data/SKILL.md +207 -0
- package/skills/pick-ai-provider/SKILL.md +164 -0
- package/skills/run-ai-agent/SKILL.md +267 -0
- package/skills/run-ai-workflow/SKILL.md +258 -0
- package/skills/run-supervisor/SKILL.md +309 -0
- package/skills/write-system-prompt/SKILL.md +129 -0
|
@@ -0,0 +1,974 @@
|
|
|
1
|
+
import { AIError } from "../errors/ai-error.mjs";
|
|
2
|
+
import { AgentExecutionError } from "../errors/agent-execution-error.mjs";
|
|
3
|
+
import { AgentCancelledError } from "../errors/agent-cancelled-error.mjs";
|
|
4
|
+
import { AgentMaxTripsError } from "../errors/agent-max-trips-error.mjs";
|
|
5
|
+
import { SchemaValidationError } from "../errors/schema-validation-error.mjs";
|
|
6
|
+
import "../errors/index.mjs";
|
|
7
|
+
import { runPipeline } from "../middleware/pipeline.mjs";
|
|
8
|
+
import "../middleware/index.mjs";
|
|
9
|
+
import { accumulateCost, computeCost } from "../utils/compute-cost.mjs";
|
|
10
|
+
import { extractJsonPayload } from "../utils/extract-json-payload.mjs";
|
|
11
|
+
import { generateRunId } from "../utils/generate-run-id.mjs";
|
|
12
|
+
import { safeJsonParse } from "../utils/safe-json-parse.mjs";
|
|
13
|
+
import { stampReportLineage } from "../utils/stamp-report-lineage.mjs";
|
|
14
|
+
import "../utils/index.mjs";
|
|
15
|
+
import { buildAgentInputMessages } from "./agent-input-builder.mjs";
|
|
16
|
+
import { logAgentEvent } from "./agent-log-event.mjs";
|
|
17
|
+
import { createAgentStream } from "./agent-stream.mjs";
|
|
18
|
+
import { agentEventToStreamEvent } from "./agent-to-stream-event.mjs";
|
|
19
|
+
import { JsonStreamGuard } from "./json-stream-guard.mjs";
|
|
20
|
+
import { log } from "@warlock.js/logger";
|
|
21
|
+
|
|
22
|
+
//#region ../../@warlock.js/ai/src/agent/agent.ts
|
|
23
|
+
const LOG_MODULE = "ai.agent";
|
|
24
|
+
/**
|
|
25
|
+
* Detect abort-flavored errors surfaced by SDK HTTP layers — the
|
|
26
|
+
* DOM `AbortError`, axios `ERR_CANCELED`, node-fetch's own
|
|
27
|
+
* `AbortError`. Used to classify them as cancellation rather than
|
|
28
|
+
* generic agent-execution failures.
|
|
29
|
+
*/
|
|
30
|
+
function isAbortLike(err) {
|
|
31
|
+
if (!err || typeof err !== "object") return false;
|
|
32
|
+
const e = err;
|
|
33
|
+
return e.name === "AbortError" || e.code === "ERR_CANCELED" || e.code === "ABORT_ERR";
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Readable synthetic name for agents constructed without an explicit
|
|
37
|
+
* `name`. Format: `anon_<provider>_<model>[_<tool1>+<tool2>+...]` —
|
|
38
|
+
* deterministic (same config → same name across restarts) and
|
|
39
|
+
* human-readable in logs / workflow snapshots.
|
|
40
|
+
*
|
|
41
|
+
* Keeps drift detection honest for the `ai.agent({ model })`
|
|
42
|
+
* one-liner without punishing it with a hashed id nobody can read.
|
|
43
|
+
*/
|
|
44
|
+
function synthesizeAgentName(config) {
|
|
45
|
+
const provider = config.model?.provider ?? "unknown";
|
|
46
|
+
const model = config.model?.name ?? "unknown";
|
|
47
|
+
const tools = (config.tools ?? []).map((tool) => tool.name).sort().join("+");
|
|
48
|
+
const base = `anon_${sanitize(provider)}_${sanitize(model)}`;
|
|
49
|
+
return tools ? `${base}_${sanitize(tools, { keepPlus: true })}` : base;
|
|
50
|
+
}
|
|
51
|
+
function sanitize(value, opts = {}) {
|
|
52
|
+
const allowed = opts.keepPlus ? /[^a-zA-Z0-9._+-]/g : /[^a-zA-Z0-9._-]/g;
|
|
53
|
+
return value.replace(allowed, "-");
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Authoring-time check on the middleware array. Throws an
|
|
57
|
+
* `AgentExecutionError` with `context: { authoring: true }` the
|
|
58
|
+
* moment an invalid entry is found — the agent factory surface is
|
|
59
|
+
* where config bugs should surface, not ten trips into a run.
|
|
60
|
+
*
|
|
61
|
+
* Validates:
|
|
62
|
+
* - Every entry is a non-null object with a non-empty string `name`.
|
|
63
|
+
* - No two entries share the same `name` (would silently collide on
|
|
64
|
+
* `ctx.state` keys and produce impossible-to-debug behavior).
|
|
65
|
+
*
|
|
66
|
+
* Does NOT validate that hook maps contain callable functions —
|
|
67
|
+
* that would catch late-binding bugs but also reject legitimate
|
|
68
|
+
* patterns like `before` being conditionally `undefined`. Runtime
|
|
69
|
+
* dispatch handles missing hooks safely.
|
|
70
|
+
*/
|
|
71
|
+
function validateMiddleware(middleware) {
|
|
72
|
+
if (!middleware || middleware.length === 0) return;
|
|
73
|
+
const seen = /* @__PURE__ */ new Set();
|
|
74
|
+
for (let index = 0; index < middleware.length; index++) {
|
|
75
|
+
const entry = middleware[index];
|
|
76
|
+
if (!entry || typeof entry !== "object") throw new AgentExecutionError(`middleware[${index}] must be an object; received ${entry === null ? "null" : typeof entry}`, { context: {
|
|
77
|
+
authoring: true,
|
|
78
|
+
index
|
|
79
|
+
} });
|
|
80
|
+
const name = entry.name;
|
|
81
|
+
if (typeof name !== "string" || name.length === 0) throw new AgentExecutionError(`middleware[${index}] must have a non-empty string "name"`, { context: {
|
|
82
|
+
authoring: true,
|
|
83
|
+
index
|
|
84
|
+
} });
|
|
85
|
+
if (seen.has(name)) throw new AgentExecutionError(`duplicate middleware name "${name}" — each middleware needs a unique name so ctx.state keys do not collide`, { context: {
|
|
86
|
+
authoring: true,
|
|
87
|
+
index,
|
|
88
|
+
name
|
|
89
|
+
} });
|
|
90
|
+
seen.add(name);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Creates an executable AI agent from the given configuration.
|
|
95
|
+
*
|
|
96
|
+
* The agent runs a bounded trip loop: each trip calls the model, dispatches
|
|
97
|
+
* any requested tool calls, then loops until the model stops or `maxTrips`
|
|
98
|
+
* is reached. Each `execute()` / `stream()` call spawns a fresh internal
|
|
99
|
+
* `Execution` instance — the factory itself holds no state across calls.
|
|
100
|
+
*
|
|
101
|
+
* `execute()` never throws — any error is attached to the returned result
|
|
102
|
+
* under `result.error`. `stream()` surfaces errors both on the terminal
|
|
103
|
+
* `error` stream event and via the `stream.result` promise.
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* const myAgent = agent({
|
|
107
|
+
* model: openai.model({ name: "gpt-4o" }),
|
|
108
|
+
* systemPrompt: "You are a helpful assistant.",
|
|
109
|
+
* tools: [searchTool],
|
|
110
|
+
* });
|
|
111
|
+
*
|
|
112
|
+
* const result = await myAgent.execute("What is the capital of Egypt?");
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* const stream = myAgent.stream("Write a haiku about Cairo.");
|
|
116
|
+
*
|
|
117
|
+
* for await (const event of stream) {
|
|
118
|
+
* if (event.type === "streaming") process.stdout.write(event.delta);
|
|
119
|
+
* }
|
|
120
|
+
*
|
|
121
|
+
* const result = await stream.result;
|
|
122
|
+
*/
|
|
123
|
+
function agent(config) {
|
|
124
|
+
validateMiddleware(config.middleware);
|
|
125
|
+
const isAnonymous = !config.name || typeof config.name !== "string";
|
|
126
|
+
const name = isAnonymous ? synthesizeAgentName(config) : config.name;
|
|
127
|
+
const resolvedConfig = {
|
|
128
|
+
...config,
|
|
129
|
+
name
|
|
130
|
+
};
|
|
131
|
+
const instanceHandlers = /* @__PURE__ */ new Map();
|
|
132
|
+
function on(event, handler) {
|
|
133
|
+
const existing = instanceHandlers.get(event);
|
|
134
|
+
const bucket = existing ?? /* @__PURE__ */ new Set();
|
|
135
|
+
if (!existing) instanceHandlers.set(event, bucket);
|
|
136
|
+
bucket.add(handler);
|
|
137
|
+
return () => off(event, handler);
|
|
138
|
+
}
|
|
139
|
+
function off(event, handler) {
|
|
140
|
+
const bucket = instanceHandlers.get(event);
|
|
141
|
+
if (!bucket) return;
|
|
142
|
+
bucket.delete(handler);
|
|
143
|
+
if (bucket.size === 0) instanceHandlers.delete(event);
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
name,
|
|
147
|
+
isAnonymous,
|
|
148
|
+
description: config.description,
|
|
149
|
+
async execute(input, options) {
|
|
150
|
+
return new Execution(resolvedConfig, input, options, void 0, instanceHandlers).run();
|
|
151
|
+
},
|
|
152
|
+
stream(input, options) {
|
|
153
|
+
const { controller, stream } = createAgentStream();
|
|
154
|
+
new Execution(resolvedConfig, input, options, controller, instanceHandlers).run();
|
|
155
|
+
return stream;
|
|
156
|
+
},
|
|
157
|
+
on,
|
|
158
|
+
off
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Per-call driver that owns the full lifecycle of a single
|
|
163
|
+
* `agent.execute()` or `agent.stream()` invocation.
|
|
164
|
+
*
|
|
165
|
+
* **Role.** An `Execution` is the short-lived state container and phase
|
|
166
|
+
* orchestrator for one agent run. The public `agent()` factory stays purely
|
|
167
|
+
* functional — all mutable bookkeeping (trips, tool calls, usage totals,
|
|
168
|
+
* message history, terminal error, parsed output) lives here so each call
|
|
169
|
+
* gets a fresh, isolated instance.
|
|
170
|
+
*
|
|
171
|
+
* **Responsibility.**
|
|
172
|
+
* - Owns: building the initial message list, driving the bounded trip loop,
|
|
173
|
+
* dispatching tool calls safely, parsing the final output against the
|
|
174
|
+
* caller's schema, emitting lifecycle events (to both the user handler
|
|
175
|
+
* and, in stream mode, the `StreamController`), and producing the
|
|
176
|
+
* `AgentResult`.
|
|
177
|
+
* - Does NOT own: how the model produces responses (delegated to
|
|
178
|
+
* `ModelContract.complete` / `ModelContract.stream`), how tools execute
|
|
179
|
+
* (delegated to `ToolContract.invoke`), the async-queue plumbing for
|
|
180
|
+
* streaming (delegated to `createAgentStream`), or any cross-call state
|
|
181
|
+
* (factory-level concerns live in `agent()`).
|
|
182
|
+
*
|
|
183
|
+
* Streaming mode is opt-in via the fourth constructor argument: pass a
|
|
184
|
+
* `StreamController` and every event is mirrored into it while model calls
|
|
185
|
+
* are driven via `model.stream()` instead of `model.complete()`. The public
|
|
186
|
+
* contract of `execute()` says it never throws — `Execution` enforces that
|
|
187
|
+
* by funneling every unexpected error into `this.error` and returning a
|
|
188
|
+
* well-formed result regardless of what went wrong.
|
|
189
|
+
*
|
|
190
|
+
* Not exported — consumers interact only with the `agent()` factory (see
|
|
191
|
+
* §4.2 of code-style.md — "per-call execution state across phases").
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* // Non-streaming — inside agent.execute():
|
|
195
|
+
* const result = await new Execution(config, input, options).run();
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* // Streaming — inside agent.stream():
|
|
199
|
+
* const { controller, stream } = createAgentStream();
|
|
200
|
+
* void new Execution(config, input, options, controller).run();
|
|
201
|
+
* return stream;
|
|
202
|
+
*/
|
|
203
|
+
var Execution = class {
|
|
204
|
+
constructor(config, input, options, streamController, instanceHandlers) {
|
|
205
|
+
this.config = config;
|
|
206
|
+
this.input = input;
|
|
207
|
+
this.options = options;
|
|
208
|
+
this.streamController = streamController;
|
|
209
|
+
this.instanceHandlers = instanceHandlers;
|
|
210
|
+
this.trips = [];
|
|
211
|
+
this.toolCalls = [];
|
|
212
|
+
this.usage = {
|
|
213
|
+
input: 0,
|
|
214
|
+
output: 0,
|
|
215
|
+
total: 0
|
|
216
|
+
};
|
|
217
|
+
this.messages = [];
|
|
218
|
+
this.startedAt = /* @__PURE__ */ new Date();
|
|
219
|
+
this.start = performance.now();
|
|
220
|
+
this.runId = generateRunId("agent");
|
|
221
|
+
this.logger = log;
|
|
222
|
+
this.middlewareState = /* @__PURE__ */ new Map();
|
|
223
|
+
this.maxTrips = config.maxTrips ?? 10;
|
|
224
|
+
this.middleware = config.middleware ?? [];
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Base middleware context shared by every level. `state` is the
|
|
228
|
+
* single mutable bag threaded through `execute`, `trip`, and `tool`
|
|
229
|
+
* hooks for the lifetime of this execution — fresh per `execute()`
|
|
230
|
+
* call, never reused across runs.
|
|
231
|
+
*/
|
|
232
|
+
buildExecuteContext() {
|
|
233
|
+
return {
|
|
234
|
+
agent: {
|
|
235
|
+
name: this.config.name ?? this.config.model.name,
|
|
236
|
+
isAnonymous: !this.config.name
|
|
237
|
+
},
|
|
238
|
+
model: {
|
|
239
|
+
name: this.config.model.name,
|
|
240
|
+
provider: this.config.model.provider
|
|
241
|
+
},
|
|
242
|
+
input: this.input,
|
|
243
|
+
options: this.options,
|
|
244
|
+
state: this.middlewareState,
|
|
245
|
+
signal: this.options?.signal
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Entry point for a single agent execution. Wraps the real work
|
|
250
|
+
* (`runCore`) in the `execute`-level middleware pipeline, then
|
|
251
|
+
* emits the terminal `agent.completed` / `agent.error` events and
|
|
252
|
+
* closes the stream (if any) with the post-pipeline result — so
|
|
253
|
+
* middleware that short-circuits or transforms the final result
|
|
254
|
+
* still produces a well-formed public outcome.
|
|
255
|
+
*
|
|
256
|
+
* Must never throw: any error that escapes the pipeline is
|
|
257
|
+
* converted into an `AgentResult` with `error` populated before
|
|
258
|
+
* returning, preserving the `agent.execute()` public contract.
|
|
259
|
+
*/
|
|
260
|
+
async run() {
|
|
261
|
+
const context = this.buildExecuteContext();
|
|
262
|
+
let result;
|
|
263
|
+
try {
|
|
264
|
+
result = await runPipeline(this.middleware, "execute", context, () => this.runCore(), this.logger);
|
|
265
|
+
} catch (thrown) {
|
|
266
|
+
this.error = this.toAIError(thrown);
|
|
267
|
+
result = this.buildResult();
|
|
268
|
+
}
|
|
269
|
+
if (result.error) this.emit("agent.error", { error: result.error });
|
|
270
|
+
this.emit("agent.completed", { result });
|
|
271
|
+
await this.fireCompleteHook(result);
|
|
272
|
+
this.streamController?.end(result);
|
|
273
|
+
return result;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Inner body wrapped by the `execute`-level pipeline. Drives the
|
|
277
|
+
* full lifecycle — build messages → emit starting → run trip loop
|
|
278
|
+
* → parse output → build result. Catches any unexpected throw and
|
|
279
|
+
* funnels it into `this.error` so the returned result is always
|
|
280
|
+
* well-formed; `execute`-level `after` hooks receive the result,
|
|
281
|
+
* with `error` populated when things went wrong.
|
|
282
|
+
*/
|
|
283
|
+
async runCore() {
|
|
284
|
+
try {
|
|
285
|
+
await this.buildInitialMessages();
|
|
286
|
+
this.emit("agent.starting", { input: this.input });
|
|
287
|
+
await this.runTripLoop();
|
|
288
|
+
if (await this.parseOutput() === "failed" && this.options?.repair) await this.runRepairLoop();
|
|
289
|
+
} catch (thrown) {
|
|
290
|
+
this.error = this.toAIError(thrown);
|
|
291
|
+
}
|
|
292
|
+
return this.buildResult();
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Resolve the system prompt (string or `SystemPromptContract`), merge
|
|
296
|
+
* placeholders from config + execute options, inject a structured-output
|
|
297
|
+
* instruction when the caller wants typed output but the model can't
|
|
298
|
+
* enforce it natively, prepend any conversation history, and append the
|
|
299
|
+
* user input. Produces the initial `messages` array the first trip sends
|
|
300
|
+
* to the model. Runs exactly once per execution.
|
|
301
|
+
*/
|
|
302
|
+
async buildInitialMessages() {
|
|
303
|
+
const { messages, responseSchema } = await buildAgentInputMessages({
|
|
304
|
+
config: this.config,
|
|
305
|
+
input: this.input,
|
|
306
|
+
options: this.options
|
|
307
|
+
});
|
|
308
|
+
this.messages.push(...messages);
|
|
309
|
+
this.responseSchema = responseSchema;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Drive sequential trips up to `maxTrips`. Each trip may stop the loop
|
|
313
|
+
* naturally (model returned a non-tool-call finish), abort it (model
|
|
314
|
+
* threw), or continue it (model requested tools). When the loop exits
|
|
315
|
+
* after the cap without a natural stop, records a "Max trips exceeded"
|
|
316
|
+
* error so the caller can distinguish runaway tool loops from a real result.
|
|
317
|
+
*/
|
|
318
|
+
async runTripLoop() {
|
|
319
|
+
for (let tripIndex = 0; tripIndex < this.maxTrips; tripIndex++) {
|
|
320
|
+
if (this.options?.signal?.aborted) {
|
|
321
|
+
this.error = this.makeCancelledError();
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const tripInput = tripIndex === 0 ? this.input : "[tool results]";
|
|
325
|
+
const outcome = await this.runTrip(tripIndex, tripInput);
|
|
326
|
+
if (outcome === "error" || outcome === "stop") return;
|
|
327
|
+
}
|
|
328
|
+
if (this.trips[this.trips.length - 1]?.finishReason === "tool_calls") this.error = new AgentMaxTripsError("Max trips exceeded", { maxTrips: this.maxTrips });
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Execute one round-trip to the model. Aggregates usage into the running
|
|
332
|
+
* total, dispatches any requested tool calls, appends the assistant +
|
|
333
|
+
* tool-result messages for the next trip, and records an `LLMTrip`.
|
|
334
|
+
* Returns an outcome that tells `runTripLoop` whether to continue, stop,
|
|
335
|
+
* or abort.
|
|
336
|
+
*/
|
|
337
|
+
async runTrip(tripIndex, tripInput) {
|
|
338
|
+
this.emit("agent.trip.started", {
|
|
339
|
+
tripIndex,
|
|
340
|
+
input: tripInput
|
|
341
|
+
});
|
|
342
|
+
const tripStartedAt = /* @__PURE__ */ new Date();
|
|
343
|
+
const tripStart = performance.now();
|
|
344
|
+
let response;
|
|
345
|
+
try {
|
|
346
|
+
response = await this.runTripThroughPipeline(tripIndex);
|
|
347
|
+
} catch (thrown) {
|
|
348
|
+
this.error = this.toAIError(thrown);
|
|
349
|
+
const failedTrip = {
|
|
350
|
+
index: tripIndex,
|
|
351
|
+
input: tripInput,
|
|
352
|
+
output: "",
|
|
353
|
+
finishReason: "error",
|
|
354
|
+
startedAt: tripStartedAt.toISOString(),
|
|
355
|
+
endedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
356
|
+
duration: performance.now() - tripStart,
|
|
357
|
+
usage: {
|
|
358
|
+
input: 0,
|
|
359
|
+
output: 0,
|
|
360
|
+
total: 0
|
|
361
|
+
},
|
|
362
|
+
error: this.error
|
|
363
|
+
};
|
|
364
|
+
this.trips.push(failedTrip);
|
|
365
|
+
this.emit("agent.trip.completed", { trip: failedTrip });
|
|
366
|
+
this.emit("agent.error", { error: this.error });
|
|
367
|
+
return "error";
|
|
368
|
+
}
|
|
369
|
+
if (response.usage.cost === void 0) response.usage.cost = computeCost(response.usage, this.config.model.pricing);
|
|
370
|
+
this.usage.input += response.usage.input;
|
|
371
|
+
this.usage.output += response.usage.output;
|
|
372
|
+
this.usage.total += response.usage.total;
|
|
373
|
+
if (response.usage.cachedTokens !== void 0) this.usage.cachedTokens = (this.usage.cachedTokens ?? 0) + response.usage.cachedTokens;
|
|
374
|
+
this.usage.cost = accumulateCost(this.usage.cost, response.usage.cost);
|
|
375
|
+
await this.fireUsageHook(tripIndex, response.usage);
|
|
376
|
+
const isToolCallTrip = response.finishReason === "tool_calls" && response.toolCalls !== void 0 && response.toolCalls.length > 0;
|
|
377
|
+
const tripToolCalls = [];
|
|
378
|
+
if (isToolCallTrip) {
|
|
379
|
+
this.messages.push({
|
|
380
|
+
role: "assistant",
|
|
381
|
+
content: response.content,
|
|
382
|
+
toolCalls: response.toolCalls
|
|
383
|
+
});
|
|
384
|
+
for (const toolCallRequest of response.toolCalls) {
|
|
385
|
+
const record = await this.dispatchToolCall(toolCallRequest, tripIndex);
|
|
386
|
+
tripToolCalls.push(record);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
const trip = {
|
|
390
|
+
index: tripIndex,
|
|
391
|
+
input: tripInput,
|
|
392
|
+
output: response.content,
|
|
393
|
+
finishReason: response.finishReason,
|
|
394
|
+
startedAt: tripStartedAt.toISOString(),
|
|
395
|
+
endedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
396
|
+
duration: performance.now() - tripStart,
|
|
397
|
+
usage: response.usage,
|
|
398
|
+
toolCalls: tripToolCalls.length > 0 ? tripToolCalls : void 0
|
|
399
|
+
};
|
|
400
|
+
this.trips.push(trip);
|
|
401
|
+
this.emit("agent.trip.completed", { trip });
|
|
402
|
+
if (!isToolCallTrip) return "stop";
|
|
403
|
+
return response.toolCalls.every((request) => {
|
|
404
|
+
return (this.config.tools?.find((tool) => tool.name === request.name))?.mode === "silent";
|
|
405
|
+
}) ? "stop" : "continue";
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Route `getModelResponse` through the `trip`-level middleware
|
|
409
|
+
* pipeline. `trip.before` hooks can short-circuit the trip by
|
|
410
|
+
* returning a synthetic `ModelResponse` (semantic cache hit).
|
|
411
|
+
* `trip.after` hooks can transform the response before the trip
|
|
412
|
+
* record is built or any tool calls are dispatched. `trip.onError`
|
|
413
|
+
* hooks can recover from provider failures (fallback chain).
|
|
414
|
+
*/
|
|
415
|
+
async runTripThroughPipeline(tripIndex) {
|
|
416
|
+
const context = {
|
|
417
|
+
...this.buildExecuteContext(),
|
|
418
|
+
tripIndex,
|
|
419
|
+
messages: this.messages
|
|
420
|
+
};
|
|
421
|
+
return await runPipeline(this.middleware, "trip", context, () => this.getModelResponse(tripIndex), this.logger);
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Produce the `ModelResponse` for the current trip. In non-streaming
|
|
425
|
+
* mode, delegates straight to `model.complete()`. In streaming mode,
|
|
426
|
+
* drains `model.stream()` while emitting `streaming` events per delta
|
|
427
|
+
* and accumulates the chunks into the same `ModelResponse` shape, so the
|
|
428
|
+
* rest of the trip pipeline (tool dispatch, trip record, usage
|
|
429
|
+
* aggregation) stays identical between the two modes.
|
|
430
|
+
*/
|
|
431
|
+
async getModelResponse(tripIndex) {
|
|
432
|
+
const callOptions = {
|
|
433
|
+
...this.config.modelOptions,
|
|
434
|
+
tools: this.config.tools ?? [],
|
|
435
|
+
...this.responseSchema ? { responseSchema: this.responseSchema } : {},
|
|
436
|
+
...this.options?.signal ? { signal: this.options.signal } : {}
|
|
437
|
+
};
|
|
438
|
+
if (!this.streamController) return this.config.model.complete(this.messages, callOptions);
|
|
439
|
+
let content = "";
|
|
440
|
+
let finishReason = "stop";
|
|
441
|
+
let usage = {
|
|
442
|
+
input: 0,
|
|
443
|
+
output: 0,
|
|
444
|
+
total: 0
|
|
445
|
+
};
|
|
446
|
+
const toolCalls = [];
|
|
447
|
+
const recoveredCalls = [];
|
|
448
|
+
const guardConfig = this.resolveStreamingToolGuard();
|
|
449
|
+
const guard = guardConfig ? new JsonStreamGuard({
|
|
450
|
+
tools: this.config.tools ?? [],
|
|
451
|
+
maxBufferBytes: guardConfig.maxBufferBytes,
|
|
452
|
+
onSafeDelta: (delta) => {
|
|
453
|
+
content += delta;
|
|
454
|
+
this.emit("agent.trip.streaming", {
|
|
455
|
+
delta,
|
|
456
|
+
tripIndex
|
|
457
|
+
});
|
|
458
|
+
},
|
|
459
|
+
onRecoveredCall: (request) => {
|
|
460
|
+
recoveredCalls.push(request);
|
|
461
|
+
}
|
|
462
|
+
}) : void 0;
|
|
463
|
+
for await (const chunk of this.config.model.stream(this.messages, callOptions)) {
|
|
464
|
+
if (this.options?.signal?.aborted) throw this.makeCancelledError();
|
|
465
|
+
if (chunk.type === "delta") {
|
|
466
|
+
if (guard) await guard.feed(chunk.content);
|
|
467
|
+
else {
|
|
468
|
+
content += chunk.content;
|
|
469
|
+
this.emit("agent.trip.streaming", {
|
|
470
|
+
delta: chunk.content,
|
|
471
|
+
tripIndex
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
if (chunk.type === "tool-call") {
|
|
477
|
+
toolCalls.push({
|
|
478
|
+
id: chunk.id,
|
|
479
|
+
name: chunk.name,
|
|
480
|
+
input: chunk.input,
|
|
481
|
+
...chunk.providerMetadata ? { providerMetadata: chunk.providerMetadata } : {}
|
|
482
|
+
});
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
finishReason = chunk.finishReason;
|
|
486
|
+
usage = chunk.usage;
|
|
487
|
+
}
|
|
488
|
+
if (guard) await guard.finalize();
|
|
489
|
+
const dedupedRecovered = recoveredCalls.filter((recovered) => !isDuplicateToolCall(recovered, toolCalls));
|
|
490
|
+
const mergedToolCalls = [...toolCalls, ...dedupedRecovered];
|
|
491
|
+
const resolvedFinishReason = dedupedRecovered.length > 0 && finishReason === "stop" ? "tool_calls" : finishReason;
|
|
492
|
+
return {
|
|
493
|
+
content,
|
|
494
|
+
finishReason: resolvedFinishReason,
|
|
495
|
+
usage,
|
|
496
|
+
toolCalls: mergedToolCalls.length > 0 ? mergedToolCalls : void 0
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Resolve the effective `streamingToolGuard` for this trip.
|
|
501
|
+
* Per-call options win over the agent-level config when the key is
|
|
502
|
+
* explicitly present on options (including the explicit `undefined`
|
|
503
|
+
* "disable for this call" form). Returns `undefined` when no guard
|
|
504
|
+
* should run.
|
|
505
|
+
*/
|
|
506
|
+
resolveStreamingToolGuard() {
|
|
507
|
+
if (this.options !== void 0 && Object.prototype.hasOwnProperty.call(this.options, "streamingToolGuard")) return this.options.streamingToolGuard;
|
|
508
|
+
return this.config.streamingToolGuard;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Dispatch a single tool call requested by the model. Looks up the tool
|
|
512
|
+
* by name, invokes it via the safe `ToolContract.invoke` entry, pushes a
|
|
513
|
+
* matching tool-result message into `this.messages` so the next trip can
|
|
514
|
+
* see it, and emits the right lifecycle event (`tool-called` on success,
|
|
515
|
+
* `tool-calling-failed` when the tool is unregistered or invoke returned
|
|
516
|
+
* an error). Never throws — always returns a `ToolCall` record.
|
|
517
|
+
*/
|
|
518
|
+
async dispatchToolCall(toolCallRequest, tripIndex) {
|
|
519
|
+
const registeredTool = this.config.tools?.find((tool) => tool.name === toolCallRequest.name);
|
|
520
|
+
if (!registeredTool) {
|
|
521
|
+
const error = new AgentExecutionError(`Tool not registered: ${toolCallRequest.name}`, { context: {
|
|
522
|
+
toolName: toolCallRequest.name,
|
|
523
|
+
tripIndex
|
|
524
|
+
} });
|
|
525
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
526
|
+
const record = {
|
|
527
|
+
runId: generateRunId("tool"),
|
|
528
|
+
rootRunId: this.runId,
|
|
529
|
+
name: toolCallRequest.name,
|
|
530
|
+
type: "tool",
|
|
531
|
+
status: "failed",
|
|
532
|
+
startedAt: nowIso,
|
|
533
|
+
endedAt: nowIso,
|
|
534
|
+
duration: 0,
|
|
535
|
+
usage: {
|
|
536
|
+
input: 0,
|
|
537
|
+
output: 0,
|
|
538
|
+
total: 0
|
|
539
|
+
},
|
|
540
|
+
children: [],
|
|
541
|
+
tripIndex,
|
|
542
|
+
input: toolCallRequest.input,
|
|
543
|
+
error,
|
|
544
|
+
...toolCallRequest.recoveredFrom ? { recoveredFrom: toolCallRequest.recoveredFrom } : {}
|
|
545
|
+
};
|
|
546
|
+
this.toolCalls.push(record);
|
|
547
|
+
this.messages.push({
|
|
548
|
+
role: "tool",
|
|
549
|
+
toolCallId: toolCallRequest.id,
|
|
550
|
+
content: JSON.stringify({ error: error.message })
|
|
551
|
+
});
|
|
552
|
+
this.emit("agent.tool.failed", {
|
|
553
|
+
tool: {
|
|
554
|
+
name: toolCallRequest.name,
|
|
555
|
+
description: "(unregistered tool — no description available)"
|
|
556
|
+
},
|
|
557
|
+
input: toolCallRequest.input,
|
|
558
|
+
error,
|
|
559
|
+
tripIndex
|
|
560
|
+
});
|
|
561
|
+
return record;
|
|
562
|
+
}
|
|
563
|
+
const toolMeta = {
|
|
564
|
+
name: registeredTool.name,
|
|
565
|
+
description: registeredTool.description,
|
|
566
|
+
action: resolveToolAction(registeredTool, toolCallRequest.input)
|
|
567
|
+
};
|
|
568
|
+
this.emit("agent.tool.calling", {
|
|
569
|
+
tool: toolMeta,
|
|
570
|
+
input: toolCallRequest.input,
|
|
571
|
+
tripIndex
|
|
572
|
+
});
|
|
573
|
+
const toolContext = {
|
|
574
|
+
...this.buildExecuteContext(),
|
|
575
|
+
tripIndex,
|
|
576
|
+
messages: this.messages,
|
|
577
|
+
tool: {
|
|
578
|
+
name: registeredTool.name,
|
|
579
|
+
description: registeredTool.description,
|
|
580
|
+
mode: registeredTool.mode
|
|
581
|
+
},
|
|
582
|
+
request: toolCallRequest
|
|
583
|
+
};
|
|
584
|
+
let invokeResult;
|
|
585
|
+
try {
|
|
586
|
+
invokeResult = await runPipeline(this.middleware, "tool", toolContext, () => registeredTool.invoke(toolCallRequest.input, this.options?.toolCtx), this.logger);
|
|
587
|
+
} catch (thrown) {
|
|
588
|
+
const error = this.toAIError(thrown);
|
|
589
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
590
|
+
const emptyUsage = {
|
|
591
|
+
input: 0,
|
|
592
|
+
output: 0,
|
|
593
|
+
total: 0
|
|
594
|
+
};
|
|
595
|
+
const failedRunId = generateRunId("tool");
|
|
596
|
+
invokeResult = {
|
|
597
|
+
error,
|
|
598
|
+
usage: emptyUsage,
|
|
599
|
+
report: {
|
|
600
|
+
runId: failedRunId,
|
|
601
|
+
rootRunId: failedRunId,
|
|
602
|
+
name: registeredTool.name,
|
|
603
|
+
version: registeredTool.version,
|
|
604
|
+
type: "tool",
|
|
605
|
+
status: "failed",
|
|
606
|
+
startedAt: nowIso,
|
|
607
|
+
endedAt: nowIso,
|
|
608
|
+
duration: 0,
|
|
609
|
+
usage: emptyUsage,
|
|
610
|
+
children: []
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
const innerReport = invokeResult.report;
|
|
615
|
+
const isComposite = innerReport.type !== "tool";
|
|
616
|
+
const record = {
|
|
617
|
+
runId: innerReport.runId,
|
|
618
|
+
rootRunId: this.runId,
|
|
619
|
+
name: toolCallRequest.name,
|
|
620
|
+
version: registeredTool.version,
|
|
621
|
+
type: "tool",
|
|
622
|
+
status: innerReport.status,
|
|
623
|
+
startedAt: innerReport.startedAt,
|
|
624
|
+
endedAt: innerReport.endedAt,
|
|
625
|
+
duration: innerReport.duration,
|
|
626
|
+
usage: invokeResult.usage,
|
|
627
|
+
children: isComposite ? [innerReport] : innerReport.children,
|
|
628
|
+
tripIndex,
|
|
629
|
+
input: toolCallRequest.input,
|
|
630
|
+
output: invokeResult.data,
|
|
631
|
+
error: invokeResult.error,
|
|
632
|
+
...toolCallRequest.recoveredFrom ? { recoveredFrom: toolCallRequest.recoveredFrom } : {}
|
|
633
|
+
};
|
|
634
|
+
this.toolCalls.push(record);
|
|
635
|
+
this.usage.input += invokeResult.usage.input;
|
|
636
|
+
this.usage.output += invokeResult.usage.output;
|
|
637
|
+
this.usage.total += invokeResult.usage.total;
|
|
638
|
+
this.usage.cost = accumulateCost(this.usage.cost, invokeResult.usage.cost);
|
|
639
|
+
this.messages.push({
|
|
640
|
+
role: "tool",
|
|
641
|
+
toolCallId: toolCallRequest.id,
|
|
642
|
+
content: invokeResult.error ? JSON.stringify({ error: invokeResult.error.message }) : JSON.stringify(invokeResult.data ?? null)
|
|
643
|
+
});
|
|
644
|
+
if (invokeResult.error) this.emit("agent.tool.failed", {
|
|
645
|
+
tool: toolMeta,
|
|
646
|
+
input: toolCallRequest.input,
|
|
647
|
+
error: invokeResult.error,
|
|
648
|
+
tripIndex
|
|
649
|
+
});
|
|
650
|
+
else this.emit("agent.tool.called", {
|
|
651
|
+
...record,
|
|
652
|
+
tool: toolMeta
|
|
653
|
+
});
|
|
654
|
+
return record;
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Parse the final trip output against the user-supplied schema (if any).
|
|
658
|
+
* Failures populate `this.error` but never throw. Returns an outcome the
|
|
659
|
+
* caller uses to decide whether self-repair is worth attempting:
|
|
660
|
+
*
|
|
661
|
+
* - `"skipped"` — no schema, or a prior trip-level error already set
|
|
662
|
+
* `this.error` (model crash, max trips). Not repairable; the failure
|
|
663
|
+
* isn't a parse problem the model can fix by re-asking.
|
|
664
|
+
* - `"failed"` — schema present, output text either failed JSON.parse
|
|
665
|
+
* or failed `~standard.validate`. Repairable via `runRepairLoop`.
|
|
666
|
+
* - `"success"` — parsed and validated; `this.data` populated.
|
|
667
|
+
*/
|
|
668
|
+
async parseOutput() {
|
|
669
|
+
const schema = this.options?.output ?? this.config.output;
|
|
670
|
+
if (!schema || this.error) return "skipped";
|
|
671
|
+
const text = this.trips[this.trips.length - 1]?.output ?? "";
|
|
672
|
+
if (!text) return "skipped";
|
|
673
|
+
const payload = extractJsonPayload(text);
|
|
674
|
+
const sentinel = Symbol("parse-failed");
|
|
675
|
+
const parsed = safeJsonParse(payload, sentinel);
|
|
676
|
+
if (parsed === sentinel) {
|
|
677
|
+
this.error = new SchemaValidationError("Failed to parse model output as JSON", { context: { text } });
|
|
678
|
+
return "failed";
|
|
679
|
+
}
|
|
680
|
+
const validation = await schema["~standard"].validate(parsed);
|
|
681
|
+
if (validation.issues) {
|
|
682
|
+
const summary = validation.issues.map((issue) => issue.message).join("; ");
|
|
683
|
+
this.error = new SchemaValidationError(summary, { issues: validation.issues });
|
|
684
|
+
return "failed";
|
|
685
|
+
}
|
|
686
|
+
this.data = validation.value;
|
|
687
|
+
return "success";
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Opt-in self-repair loop for `output` schema failures. Triggered only
|
|
691
|
+
* when `options.repair` is set and `parseOutput()` returned `"failed"`.
|
|
692
|
+
*
|
|
693
|
+
* Each attempt:
|
|
694
|
+
* 1. Pushes the bad assistant response into `this.messages` (so the
|
|
695
|
+
* model can see what it just produced).
|
|
696
|
+
* 2. Pushes a corrective user message naming the validation/parse error.
|
|
697
|
+
* 3. Runs another trip — counted against the same `maxTrips` cap as
|
|
698
|
+
* normal trips so a stuck model can't loop forever.
|
|
699
|
+
* 4. Re-parses. Stops on success, on a trip-level error, or when
|
|
700
|
+
* either `maxAttempts` or `maxTrips` is exhausted.
|
|
701
|
+
*
|
|
702
|
+
* Resets `this.error` and `this.data` before each attempt so the final
|
|
703
|
+
* outcome (success or last failure) is what surfaces to the caller.
|
|
704
|
+
*/
|
|
705
|
+
async runRepairLoop() {
|
|
706
|
+
const maxAttempts = this.options?.repair?.maxAttempts ?? 1;
|
|
707
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
708
|
+
if (this.trips.length >= this.maxTrips) return;
|
|
709
|
+
const badResponse = this.trips[this.trips.length - 1]?.output ?? "";
|
|
710
|
+
const failureReason = this.error?.message ?? "unknown validation failure";
|
|
711
|
+
this.error = void 0;
|
|
712
|
+
this.data = void 0;
|
|
713
|
+
this.messages.push({
|
|
714
|
+
role: "assistant",
|
|
715
|
+
content: badResponse
|
|
716
|
+
});
|
|
717
|
+
this.messages.push({
|
|
718
|
+
role: "user",
|
|
719
|
+
content: [`Your previous response failed validation: ${failureReason}.`, "Respond again with valid JSON only — no prose, no markdown fences, no commentary."].join(" ")
|
|
720
|
+
});
|
|
721
|
+
const tripIndex = this.trips.length;
|
|
722
|
+
this.logger.warn(LOG_MODULE, "repair.attempting", "retrying after validation failure", {
|
|
723
|
+
attempt: attempt + 1,
|
|
724
|
+
maxAttempts,
|
|
725
|
+
reason: failureReason
|
|
726
|
+
});
|
|
727
|
+
if (await this.runTrip(tripIndex, "[repair attempt]") === "error") return;
|
|
728
|
+
if (await this.parseOutput() === "success") return;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
/**
|
|
732
|
+
* Build the final `AgentResult` snapshot from accumulated state
|
|
733
|
+
* (trips, tool calls, data/error, usage, timing).
|
|
734
|
+
*
|
|
735
|
+
* Pure — no side effects. `run()` owns terminal event emission and
|
|
736
|
+
* stream closure so the post-pipeline result (possibly transformed
|
|
737
|
+
* or short-circuited by an `execute`-level middleware) is what
|
|
738
|
+
* flows out to consumers and listeners.
|
|
739
|
+
*
|
|
740
|
+
* Trips, tool calls, status, and timing live under `report` so the
|
|
741
|
+
* root stays focused on the four things callers reach for most:
|
|
742
|
+
* `data`, `text`, `usage`, `error`.
|
|
743
|
+
*/
|
|
744
|
+
buildResult() {
|
|
745
|
+
const finalTrip = this.trips[this.trips.length - 1];
|
|
746
|
+
const endedAt = /* @__PURE__ */ new Date();
|
|
747
|
+
const agentName = this.config.name ?? this.config.model.name;
|
|
748
|
+
const status = this.error ? this.error instanceof AgentCancelledError ? "cancelled" : "failed" : "completed";
|
|
749
|
+
const report = {
|
|
750
|
+
runId: this.runId,
|
|
751
|
+
rootRunId: this.runId,
|
|
752
|
+
name: agentName,
|
|
753
|
+
version: this.config.version,
|
|
754
|
+
type: "agent",
|
|
755
|
+
status,
|
|
756
|
+
startedAt: this.startedAt.toISOString(),
|
|
757
|
+
endedAt: endedAt.toISOString(),
|
|
758
|
+
duration: performance.now() - this.start,
|
|
759
|
+
usage: this.usage,
|
|
760
|
+
children: this.toolCalls,
|
|
761
|
+
model: {
|
|
762
|
+
name: this.config.model.name,
|
|
763
|
+
provider: this.config.model.provider
|
|
764
|
+
},
|
|
765
|
+
trips: this.trips
|
|
766
|
+
};
|
|
767
|
+
stampReportLineage(report, {
|
|
768
|
+
rootRunId: this.runId,
|
|
769
|
+
sessionId: this.options?.sessionId
|
|
770
|
+
});
|
|
771
|
+
return {
|
|
772
|
+
type: "agent",
|
|
773
|
+
data: this.data,
|
|
774
|
+
text: finalTrip?.output,
|
|
775
|
+
report,
|
|
776
|
+
usage: this.usage,
|
|
777
|
+
error: this.error
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Normalize any thrown value into an `AIError`. `AIError` instances
|
|
782
|
+
* pass through untouched; provider-adapter SDK errors are caught by
|
|
783
|
+
* the adapter and already arrive typed, so this branch mainly
|
|
784
|
+
* handles runtime crashes (TypeError, ReferenceError) inside
|
|
785
|
+
* model.complete / model.stream and non-Error values (`throw "bad"`).
|
|
786
|
+
*/
|
|
787
|
+
toAIError(thrown) {
|
|
788
|
+
if (thrown instanceof AIError) return thrown;
|
|
789
|
+
if (isAbortLike(thrown)) return this.makeCancelledError();
|
|
790
|
+
return new AgentExecutionError(thrown instanceof Error ? thrown.message : String(thrown), { cause: thrown });
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* Build the typed cancelled error that both the trip-loop guard
|
|
794
|
+
* and the mid-stream guard emit. Captures the abort reason when
|
|
795
|
+
* one was supplied to `controller.abort(reason)` so logs and
|
|
796
|
+
* telemetry can see what cancelled the run.
|
|
797
|
+
*/
|
|
798
|
+
makeCancelledError() {
|
|
799
|
+
const reason = this.options?.signal?.reason;
|
|
800
|
+
const reasonText = reason === void 0 ? "" : String(reason);
|
|
801
|
+
return new AgentCancelledError("agent execution cancelled", {
|
|
802
|
+
cause: reason,
|
|
803
|
+
cancelledAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
804
|
+
reason: reasonText
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Fire a single event through all three subscription tiers in order
|
|
809
|
+
* — factory → instance → per-call — and mirror it into the
|
|
810
|
+
* `StreamController` when streaming is active. A throwing user
|
|
811
|
+
* handler must never crash the agent, so every dispatch is wrapped
|
|
812
|
+
* in `safeCall`. Stream events are converted from the internal
|
|
813
|
+
* `AgentEventMap` payload to the public `StreamEvent` shape because
|
|
814
|
+
* some of them differ (e.g. the tool-called payload vs stream
|
|
815
|
+
* event).
|
|
816
|
+
*/
|
|
817
|
+
emit(event, payload) {
|
|
818
|
+
const fullPayload = {
|
|
819
|
+
...payload,
|
|
820
|
+
runId: this.runId,
|
|
821
|
+
rootRunId: this.runId
|
|
822
|
+
};
|
|
823
|
+
this.logEvent(event, fullPayload);
|
|
824
|
+
const factoryHandler = this.config.on?.[event];
|
|
825
|
+
if (factoryHandler) safeCall(factoryHandler, fullPayload);
|
|
826
|
+
const bucket = this.instanceHandlers?.get(event);
|
|
827
|
+
if (bucket) for (const handler of bucket) safeCall(handler, fullPayload);
|
|
828
|
+
const perCallHandler = this.options?.on?.[event];
|
|
829
|
+
if (perCallHandler) safeCall(perCallHandler, fullPayload);
|
|
830
|
+
if (this.streamController) {
|
|
831
|
+
const body = this.toStreamEvent(event, fullPayload);
|
|
832
|
+
if (body) this.streamController.push({
|
|
833
|
+
runId: this.runId,
|
|
834
|
+
rootRunId: this.runId,
|
|
835
|
+
...body
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Emit a structured log line for a lifecycle event. The action
|
|
841
|
+
* string mirrors the event name with the `agent.` prefix stripped
|
|
842
|
+
* (`agent.trip.started` → `trip.started`) so log grep filters and
|
|
843
|
+
* event handlers read the same vocabulary. Level mapping follows
|
|
844
|
+
* the convention documented on `@warlock.js/logger`'s `Logger`.
|
|
845
|
+
*/
|
|
846
|
+
logEvent(event, payload) {
|
|
847
|
+
const agentName = this.config.name || this.config.model.name;
|
|
848
|
+
logAgentEvent(this.logger, {
|
|
849
|
+
module: `${LOG_MODULE}.${agentName}`,
|
|
850
|
+
maxTrips: this.maxTrips,
|
|
851
|
+
modelName: this.config.model.name,
|
|
852
|
+
totalUsage: this.usage,
|
|
853
|
+
totalDurationMs: performance.now() - this.start,
|
|
854
|
+
trips: this.trips,
|
|
855
|
+
toolCalls: this.toolCalls
|
|
856
|
+
}, event, payload);
|
|
857
|
+
}
|
|
858
|
+
toStreamEvent(event, payload) {
|
|
859
|
+
return agentEventToStreamEvent(event, payload);
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Invoke the `onUsage` hook (when configured) with a flat payload
|
|
863
|
+
* carrying stable identity. Awaits the handler so async ledger
|
|
864
|
+
* writes complete before the next trip starts; swallows any throw
|
|
865
|
+
* so consumer bugs cannot crash the agent. Sync handlers wrapped
|
|
866
|
+
* via `Promise.resolve()` so the await is safe in either case.
|
|
867
|
+
*/
|
|
868
|
+
async fireUsageHook(tripIndex, tripUsage) {
|
|
869
|
+
const handler = this.config.onUsage;
|
|
870
|
+
if (!handler) return;
|
|
871
|
+
const event = {
|
|
872
|
+
runId: this.runId,
|
|
873
|
+
tripIndex,
|
|
874
|
+
model: {
|
|
875
|
+
name: this.config.model.name,
|
|
876
|
+
provider: this.config.model.provider
|
|
877
|
+
},
|
|
878
|
+
usage: { ...tripUsage },
|
|
879
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
880
|
+
};
|
|
881
|
+
try {
|
|
882
|
+
await Promise.resolve(handler(event));
|
|
883
|
+
} catch (err) {
|
|
884
|
+
this.logger.warn(LOG_MODULE, "onUsage.hook.error", "onUsage handler threw", {
|
|
885
|
+
runId: this.runId,
|
|
886
|
+
tripIndex,
|
|
887
|
+
error: err instanceof Error ? err.message : String(err)
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Invoke the `onComplete` hook (when configured) once at the end
|
|
893
|
+
* of every run. Receives the full `AgentResult` plus pre-extracted
|
|
894
|
+
* `runId` and `durationMs`. Same swallow-and-log error policy as
|
|
895
|
+
* `fireUsageHook`.
|
|
896
|
+
*/
|
|
897
|
+
async fireCompleteHook(result) {
|
|
898
|
+
const handler = this.config.onComplete;
|
|
899
|
+
if (!handler) return;
|
|
900
|
+
const event = {
|
|
901
|
+
result,
|
|
902
|
+
runId: this.runId,
|
|
903
|
+
durationMs: performance.now() - this.start
|
|
904
|
+
};
|
|
905
|
+
try {
|
|
906
|
+
await Promise.resolve(handler(event));
|
|
907
|
+
} catch (err) {
|
|
908
|
+
this.logger.warn(LOG_MODULE, "onComplete.hook.error", "onComplete handler threw", {
|
|
909
|
+
runId: this.runId,
|
|
910
|
+
error: err instanceof Error ? err.message : String(err)
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
};
|
|
915
|
+
/**
|
|
916
|
+
* Decide whether a guard-synthesized tool call duplicates a real one
|
|
917
|
+
* the provider already streamed structurally. Match key is
|
|
918
|
+
* `name + key-sorted JSON of input` so identical calls (regardless of
|
|
919
|
+
* argument key order) collapse, but two legitimate calls to the same
|
|
920
|
+
* tool with different inputs still both dispatch.
|
|
921
|
+
*/
|
|
922
|
+
function isDuplicateToolCall(recovered, realCalls) {
|
|
923
|
+
const recoveredKey = `${recovered.name}|${stableStringify(recovered.input)}`;
|
|
924
|
+
for (const real of realCalls) if (`${real.name}|${stableStringify(real.input)}` === recoveredKey) return true;
|
|
925
|
+
return false;
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* `JSON.stringify` variant that sorts object keys at every nesting
|
|
929
|
+
* level so structurally-equal inputs serialize to identical strings.
|
|
930
|
+
* Used only for dedupe-key comparison; never surfaces to consumers.
|
|
931
|
+
*/
|
|
932
|
+
function stableStringify(value) {
|
|
933
|
+
return JSON.stringify(value, (_key, val) => {
|
|
934
|
+
if (val !== null && typeof val === "object" && !Array.isArray(val)) {
|
|
935
|
+
const source = val;
|
|
936
|
+
const sorted = {};
|
|
937
|
+
for (const key of Object.keys(source).sort()) sorted[key] = source[key];
|
|
938
|
+
return sorted;
|
|
939
|
+
}
|
|
940
|
+
return val;
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Invoke a user-supplied event handler without letting exceptions
|
|
945
|
+
* escape the agent. Thrown errors are swallowed — structured logging
|
|
946
|
+
* attaches here in Phase 0.5 so operators still see the failure.
|
|
947
|
+
*/
|
|
948
|
+
function safeCall(handler, payload) {
|
|
949
|
+
try {
|
|
950
|
+
handler(payload);
|
|
951
|
+
} catch {}
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* Resolve a tool's `action` declaration into a plain string for
|
|
955
|
+
* inclusion in `ToolEventMeta`. Static strings pass through;
|
|
956
|
+
* function-shaped actions are invoked with the validated input.
|
|
957
|
+
*
|
|
958
|
+
* Defensive: if the user's callback throws, swallow and return
|
|
959
|
+
* `undefined` rather than crashing the agent — UI strings are not
|
|
960
|
+
* worth aborting an LLM dispatch over.
|
|
961
|
+
*/
|
|
962
|
+
function resolveToolAction(tool, input) {
|
|
963
|
+
if (tool.action === void 0) return void 0;
|
|
964
|
+
if (typeof tool.action === "string") return tool.action;
|
|
965
|
+
try {
|
|
966
|
+
return tool.action(input);
|
|
967
|
+
} catch {
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
//#endregion
|
|
973
|
+
export { agent };
|
|
974
|
+
//# sourceMappingURL=agent.mjs.map
|