@warlock.js/ai 5.1.0 → 5.2.3
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/CHANGELOG.md +10 -0
- package/README.md +4 -0
- package/cjs/index.cjs +1 -1
- package/cjs/index.cjs.map +1 -1
- package/cjs/{magic-string.es-BoSa5xIt.cjs → magic-string.es-BQeqHJ-a.cjs} +22 -17
- package/cjs/magic-string.es-BQeqHJ-a.cjs.map +1 -0
- package/cjs/matcher-logic-07fFOz7r.cjs.map +1 -1
- package/cjs/{matchers-DnV47KR_.cjs → matchers-CINm4ojZ.cjs} +27 -27
- package/cjs/matchers-CINm4ojZ.cjs.map +1 -0
- package/esm/agent/agent-input-builder.mjs.map +1 -1
- package/esm/agent/agent-stream.d.mts.map +1 -1
- package/esm/agent/agent-stream.mjs.map +1 -1
- package/esm/agent/agent.d.mts.map +1 -1
- package/esm/agent/agent.mjs.map +1 -1
- package/esm/agent/json-stream-guard.mjs.map +1 -1
- package/esm/agent/signature.mjs.map +1 -1
- package/esm/agent/snapshot.mjs.map +1 -1
- package/esm/agent/spawn-sub-agent.d.mts.map +1 -1
- package/esm/batch/batch.d.mts.map +1 -1
- package/esm/batch/batch.mjs.map +1 -1
- package/esm/checkpoint/memory.d.mts.map +1 -1
- package/esm/checkpoint/pg.mjs.map +1 -1
- package/esm/checkpoint/redis.mjs.map +1 -1
- package/esm/config.d.mts.map +1 -1
- package/esm/eval/dataset.d.mts.map +1 -1
- package/esm/eval/dataset.mjs.map +1 -1
- package/esm/eval/eval-runner.d.mts.map +1 -1
- package/esm/eval/eval-runner.mjs.map +1 -1
- package/esm/eval/judge-scorer.d.mts.map +1 -1
- package/esm/eval/regression.d.mts.map +1 -1
- package/esm/eval/regression.mjs.map +1 -1
- package/esm/eval/report-json.d.mts.map +1 -1
- package/esm/eval/report-junit.mjs.map +1 -1
- package/esm/eval/scorers.d.mts.map +1 -1
- package/esm/eval/scorers.mjs.map +1 -1
- package/esm/guard/detectors/injection.mjs.map +1 -1
- package/esm/guard/detectors/moderation.mjs.map +1 -1
- package/esm/guard/detectors/pii.mjs.map +1 -1
- package/esm/guard/detectors/topic.mjs.map +1 -1
- package/esm/human/human-approval.mjs.map +1 -1
- package/esm/human/resume.d.mts.map +1 -1
- package/esm/human/stores/memory.d.mts.map +1 -1
- package/esm/human/stores/pg.mjs.map +1 -1
- package/esm/human/stores/redis.mjs.map +1 -1
- package/esm/image/image.mjs.map +1 -1
- package/esm/memory/derive-id.mjs.map +1 -1
- package/esm/memory/episodic-memory.mjs.map +1 -1
- package/esm/memory/memory.mjs.map +1 -1
- package/esm/memory/procedural-memory.mjs.map +1 -1
- package/esm/memory/semantic-memory.mjs.map +1 -1
- package/esm/memory/working-memory.mjs.map +1 -1
- package/esm/middleware/builtins/budget.mjs.map +1 -1
- package/esm/middleware/builtins/semantic-cache.mjs.map +1 -1
- package/esm/middleware/helpers/compose.d.mts.map +1 -1
- package/esm/middleware/helpers/for-tool.mjs.map +1 -1
- package/esm/middleware/pipeline.d.mts.map +1 -1
- package/esm/middleware/utils/extract-user-text.mjs.map +1 -1
- package/esm/middleware/utils/namespaced-state.d.mts.map +1 -1
- package/esm/mock/mock-agent.d.mts.map +1 -1
- package/esm/mock/mock-agent.mjs.map +1 -1
- package/esm/mock/mock-model.d.mts.map +1 -1
- package/esm/mock/mock-model.mjs.map +1 -1
- package/esm/mock/mock-router.d.mts.map +1 -1
- package/esm/model/fallback-model.mjs.map +1 -1
- package/esm/node_modules/{@jridgewell → .pnpm/@jridgewell_sourcemap-codec@1.6.0/node_modules/@jridgewell}/sourcemap-codec/dist/sourcemap-codec.mjs +19 -14
- package/esm/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.6.0/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs.map +1 -0
- package/esm/node_modules/{@vitest → .pnpm/@vitest_expect@4.1.10/node_modules/@vitest}/expect/dist/index.mjs +8 -8
- package/esm/node_modules/.pnpm/@vitest_expect@4.1.10/node_modules/@vitest/expect/dist/index.mjs.map +1 -0
- package/esm/node_modules/{@vitest → .pnpm/@vitest_pretty-format@4.1.10/node_modules/@vitest}/pretty-format/dist/index.mjs +4 -4
- package/esm/node_modules/.pnpm/@vitest_pretty-format@4.1.10/node_modules/@vitest/pretty-format/dist/index.mjs.map +1 -0
- package/esm/node_modules/{@vitest → .pnpm/@vitest_runner@4.1.10/node_modules/@vitest}/runner/dist/chunk-artifact.mjs +5 -5
- package/esm/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/chunk-artifact.mjs.map +1 -0
- package/esm/node_modules/{@vitest → .pnpm/@vitest_snapshot@4.1.10/node_modules/@vitest}/snapshot/dist/index.mjs +7 -7
- package/esm/node_modules/.pnpm/@vitest_snapshot@4.1.10/node_modules/@vitest/snapshot/dist/index.mjs.map +1 -0
- package/esm/node_modules/{@vitest → .pnpm/@vitest_spy@4.1.10/node_modules/@vitest}/spy/dist/index.mjs +1 -1
- package/esm/node_modules/.pnpm/@vitest_spy@4.1.10/node_modules/@vitest/spy/dist/index.mjs.map +1 -0
- package/esm/node_modules/{@vitest → .pnpm/@vitest_utils@4.1.10/node_modules/@vitest}/utils/dist/chunk-pathe.M-eThtNZ.mjs +1 -1
- package/esm/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/chunk-pathe.M-eThtNZ.mjs.map +1 -0
- package/esm/node_modules/{@vitest → .pnpm/@vitest_utils@4.1.10/node_modules/@vitest}/utils/dist/diff.mjs +4 -4
- package/esm/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/diff.mjs.map +1 -0
- package/esm/node_modules/{@vitest → .pnpm/@vitest_utils@4.1.10/node_modules/@vitest}/utils/dist/display.mjs +3 -3
- package/esm/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/display.mjs.map +1 -0
- package/esm/node_modules/{@vitest → .pnpm/@vitest_utils@4.1.10/node_modules/@vitest}/utils/dist/error.mjs +2 -2
- package/esm/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/error.mjs.map +1 -0
- package/esm/node_modules/{@vitest → .pnpm/@vitest_utils@4.1.10/node_modules/@vitest}/utils/dist/helpers.mjs +1 -1
- package/esm/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/helpers.mjs.map +1 -0
- package/esm/node_modules/{@vitest → .pnpm/@vitest_utils@4.1.10/node_modules/@vitest}/utils/dist/offset.mjs +1 -1
- package/esm/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/offset.mjs.map +1 -0
- package/esm/node_modules/{@vitest → .pnpm/@vitest_utils@4.1.10/node_modules/@vitest}/utils/dist/serialize.mjs +1 -1
- package/esm/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/serialize.mjs.map +1 -0
- package/esm/node_modules/{@vitest → .pnpm/@vitest_utils@4.1.10/node_modules/@vitest}/utils/dist/source-map.mjs +1 -1
- package/esm/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/source-map.mjs.map +1 -0
- package/esm/node_modules/{@vitest → .pnpm/@vitest_utils@4.1.10/node_modules/@vitest}/utils/dist/timers.mjs +1 -1
- package/esm/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/timers.mjs.map +1 -0
- package/esm/node_modules/{chai → .pnpm/chai@6.2.2/node_modules/chai}/index.mjs +1 -1
- package/esm/node_modules/.pnpm/chai@6.2.2/node_modules/chai/index.mjs.map +1 -0
- package/esm/node_modules/{magic-string → .pnpm/magic-string@0.30.21/node_modules/magic-string}/dist/magic-string.es.mjs +3 -3
- package/esm/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.mjs.map +1 -0
- package/esm/node_modules/{tinyrainbow → .pnpm/tinyrainbow@3.1.1/node_modules/tinyrainbow}/dist/index.mjs +1 -1
- package/esm/node_modules/.pnpm/tinyrainbow@3.1.1/node_modules/tinyrainbow/dist/index.mjs.map +1 -0
- package/esm/node_modules/{vitest → .pnpm/vitest@4.1.10_@opentelemetr_3b60e89b8b51a25e87011ae54ec49250/node_modules/vitest}/dist/chunks/_commonjsHelpers.D26ty3Ew.mjs +1 -1
- package/esm/node_modules/.pnpm/vitest@4.1.10_@opentelemetr_3b60e89b8b51a25e87011ae54ec49250/node_modules/vitest/dist/chunks/_commonjsHelpers.D26ty3Ew.mjs.map +1 -0
- package/esm/node_modules/{vitest → .pnpm/vitest@4.1.10_@opentelemetr_3b60e89b8b51a25e87011ae54ec49250/node_modules/vitest}/dist/chunks/rpc.MzXet3jl.mjs +1 -1
- package/esm/node_modules/.pnpm/vitest@4.1.10_@opentelemetr_3b60e89b8b51a25e87011ae54ec49250/node_modules/vitest/dist/chunks/rpc.MzXet3jl.mjs.map +1 -0
- package/esm/node_modules/{vitest → .pnpm/vitest@4.1.10_@opentelemetr_3b60e89b8b51a25e87011ae54ec49250/node_modules/vitest}/dist/chunks/test.DNmyFkvJ.mjs +11 -11
- package/esm/node_modules/.pnpm/vitest@4.1.10_@opentelemetr_3b60e89b8b51a25e87011ae54ec49250/node_modules/vitest/dist/chunks/test.DNmyFkvJ.mjs.map +1 -0
- package/esm/node_modules/{vitest → .pnpm/vitest@4.1.10_@opentelemetr_3b60e89b8b51a25e87011ae54ec49250/node_modules/vitest}/dist/chunks/utils.BX5Fg8C4.mjs +2 -2
- package/esm/node_modules/.pnpm/vitest@4.1.10_@opentelemetr_3b60e89b8b51a25e87011ae54ec49250/node_modules/vitest/dist/chunks/utils.BX5Fg8C4.mjs.map +1 -0
- package/esm/object-stream/parse-partial-json.mjs.map +1 -1
- package/esm/object-stream/stream-object.d.mts.map +1 -1
- package/esm/object-stream/stream-object.mjs.map +1 -1
- package/esm/observe/observer-registry.d.mts.map +1 -1
- package/esm/orchestrator/as-tool.d.mts.map +1 -1
- package/esm/orchestrator/checkpoint.mjs.map +1 -1
- package/esm/orchestrator/compaction.mjs.map +1 -1
- package/esm/orchestrator/emitter.d.mts.map +1 -1
- package/esm/orchestrator/emitter.mjs.map +1 -1
- package/esm/orchestrator/execution.d.mts.map +1 -1
- package/esm/orchestrator/execution.mjs.map +1 -1
- package/esm/orchestrator/memory.mjs.map +1 -1
- package/esm/orchestrator/orchestrator-stream.d.mts.map +1 -1
- package/esm/orchestrator/orchestrator-stream.mjs.map +1 -1
- package/esm/orchestrator/orchestrator.d.mts.map +1 -1
- package/esm/orchestrator/orchestrator.mjs.map +1 -1
- package/esm/orchestrator/session-lock.d.mts.map +1 -1
- package/esm/orchestrator/signature.mjs.map +1 -1
- package/esm/planner/dag-scheduler.mjs.map +1 -1
- package/esm/planner/plan-prompt.mjs.map +1 -1
- package/esm/planner/planner-run.mjs.map +1 -1
- package/esm/planner/planner.d.mts.map +1 -1
- package/esm/planner/planner.mjs.map +1 -1
- package/esm/planner/signature.mjs.map +1 -1
- package/esm/planner/snapshot.mjs.map +1 -1
- package/esm/prompt/prompt-langfuse-sync.mjs.map +1 -1
- package/esm/prompt/prompt-validate.mjs.map +1 -1
- package/esm/prompt/prompt.mjs.map +1 -1
- package/esm/prompts/prompts-manager.d.mts.map +1 -1
- package/esm/prompts/prompts-manager.mjs.map +1 -1
- package/esm/prompts/prompts-validate.mjs.map +1 -1
- package/esm/rag/chunk/chunk.mjs.map +1 -1
- package/esm/rag/chunk/markdown.mjs.map +1 -1
- package/esm/rag/chunk/sentence.mjs.map +1 -1
- package/esm/rag/hybrid/bm25.mjs.map +1 -1
- package/esm/rag/hybrid/hybrid-rank.mjs.map +1 -1
- package/esm/rag/hybrid/rrf.mjs.map +1 -1
- package/esm/rag/loaders/load-html.mjs.map +1 -1
- package/esm/rag/loaders/load-pdf.d.mts.map +1 -1
- package/esm/rag/loaders/load-pdf.mjs.map +1 -1
- package/esm/rag/loaders/load-text.mjs.map +1 -1
- package/esm/rag/rerank/keyword-reranker.mjs.map +1 -1
- package/esm/rag/rerank/llm-reranker.mjs.map +1 -1
- package/esm/rag/retrieve.mjs.map +1 -1
- package/esm/rag/store/cache-vector-store.mjs.map +1 -1
- package/esm/rag/store/pg-vector-store.mjs.map +1 -1
- package/esm/rag/transforms/multi-query.mjs.map +1 -1
- package/esm/security/outbound-policy.mjs.map +1 -1
- package/esm/security/private-ip.mjs.map +1 -1
- package/esm/security/redact.d.mts.map +1 -1
- package/esm/security/redact.mjs.map +1 -1
- package/esm/serve/serve.d.mts.map +1 -1
- package/esm/serve/serve.mjs.map +1 -1
- package/esm/serve/stream-to-sse.d.mts.map +1 -1
- package/esm/skills/catalog.mjs.map +1 -1
- package/esm/skills/skills.mjs.map +1 -1
- package/esm/skills/sources/directory-source.mjs.map +1 -1
- package/esm/skills/sources/parse-frontmatter.mjs.map +1 -1
- package/esm/skills/sources/url-source.mjs.map +1 -1
- package/esm/skills/store/mock-skills-store.mjs.map +1 -1
- package/esm/skills/store/procedural-skill-store.mjs.map +1 -1
- package/esm/snapshot/memory.d.mts.map +1 -1
- package/esm/snapshot/pg.mjs.map +1 -1
- package/esm/speech/speech.mjs.map +1 -1
- package/esm/supervisor/as-tool.d.mts.map +1 -1
- package/esm/supervisor/cancellation.mjs.map +1 -1
- package/esm/supervisor/emitter.d.mts.map +1 -1
- package/esm/supervisor/emitter.mjs.map +1 -1
- package/esm/supervisor/entries.mjs.map +1 -1
- package/esm/supervisor/execution.d.mts.map +1 -1
- package/esm/supervisor/execution.mjs.map +1 -1
- package/esm/supervisor/fan-out.mjs.map +1 -1
- package/esm/supervisor/router-factory.mjs.map +1 -1
- package/esm/supervisor/router-prompt.mjs.map +1 -1
- package/esm/supervisor/signature.mjs.map +1 -1
- package/esm/supervisor/snapshot.mjs.map +1 -1
- package/esm/supervisor/supervisor-stream.d.mts.map +1 -1
- package/esm/supervisor/supervisor-stream.mjs.map +1 -1
- package/esm/supervisor/supervisor.d.mts.map +1 -1
- package/esm/supervisor/supervisor.mjs.map +1 -1
- package/esm/system-prompt/refined-system-prompt.d.mts.map +1 -1
- package/esm/system-prompt/refined-system-prompt.mjs.map +1 -1
- package/esm/system-prompt/system-prompt.d.mts.map +1 -1
- package/esm/system-prompt/system-prompt.mjs.map +1 -1
- package/esm/team/team.d.mts.map +1 -1
- package/esm/testing/matcher-logic.mjs.map +1 -1
- package/esm/testing/matchers.mjs +1 -1
- package/esm/testing/register-lazy.d.mts.map +1 -1
- package/esm/tool/executable-as-tool.d.mts.map +1 -1
- package/esm/tool/tool.d.mts.map +1 -1
- package/esm/tool/tool.mjs.map +1 -1
- package/esm/transcribe/audio-input.mjs.map +1 -1
- package/esm/transcribe/transcribe.mjs.map +1 -1
- package/esm/utils/extract-json-payload.mjs.map +1 -1
- package/esm/utils/generate-run-id.mjs.map +1 -1
- package/esm/utils/prepare-attachment-part.mjs.map +1 -1
- package/esm/utils/run-context.d.mts.map +1 -1
- package/esm/utils/safe-json-parse.d.mts.map +1 -1
- package/esm/vcr/cassette-io.mjs.map +1 -1
- package/esm/vcr/hash-request.mjs.map +1 -1
- package/esm/vcr/vcr.mjs.map +1 -1
- package/esm/workflow/cancellation.mjs.map +1 -1
- package/esm/workflow/emitter.mjs.map +1 -1
- package/esm/workflow/engine.mjs.map +1 -1
- package/esm/workflow/retry.mjs.map +1 -1
- package/esm/workflow/router.mjs.map +1 -1
- package/esm/workflow/signature.d.mts.map +1 -1
- package/esm/workflow/signature.mjs.map +1 -1
- package/esm/workflow/snapshot.mjs.map +1 -1
- package/esm/workflow/step-runner.mjs.map +1 -1
- package/esm/workflow/step.d.mts.map +1 -1
- package/esm/workflow/step.mjs.map +1 -1
- package/esm/workflow/workflow.d.mts.map +1 -1
- package/esm/workflow/workflow.mjs.map +1 -1
- package/llms-full.txt +2 -0
- package/package.json +7 -4
- package/skills/ai-basics/SKILL.md +2 -0
- package/cjs/magic-string.es-BoSa5xIt.cjs.map +0 -1
- package/cjs/matchers-DnV47KR_.cjs.map +0 -1
- package/esm/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs.map +0 -1
- package/esm/node_modules/@vitest/expect/dist/index.mjs.map +0 -1
- package/esm/node_modules/@vitest/pretty-format/dist/index.mjs.map +0 -1
- package/esm/node_modules/@vitest/runner/dist/chunk-artifact.mjs.map +0 -1
- package/esm/node_modules/@vitest/snapshot/dist/index.mjs.map +0 -1
- package/esm/node_modules/@vitest/spy/dist/index.mjs.map +0 -1
- package/esm/node_modules/@vitest/utils/dist/chunk-pathe.M-eThtNZ.mjs.map +0 -1
- package/esm/node_modules/@vitest/utils/dist/diff.mjs.map +0 -1
- package/esm/node_modules/@vitest/utils/dist/display.mjs.map +0 -1
- package/esm/node_modules/@vitest/utils/dist/error.mjs.map +0 -1
- package/esm/node_modules/@vitest/utils/dist/helpers.mjs.map +0 -1
- package/esm/node_modules/@vitest/utils/dist/offset.mjs.map +0 -1
- package/esm/node_modules/@vitest/utils/dist/serialize.mjs.map +0 -1
- package/esm/node_modules/@vitest/utils/dist/source-map.mjs.map +0 -1
- package/esm/node_modules/@vitest/utils/dist/timers.mjs.map +0 -1
- package/esm/node_modules/chai/index.mjs.map +0 -1
- package/esm/node_modules/magic-string/dist/magic-string.es.mjs.map +0 -1
- package/esm/node_modules/tinyrainbow/dist/index.mjs.map +0 -1
- package/esm/node_modules/vitest/dist/chunks/_commonjsHelpers.D26ty3Ew.mjs.map +0 -1
- package/esm/node_modules/vitest/dist/chunks/rpc.MzXet3jl.mjs.map +0 -1
- package/esm/node_modules/vitest/dist/chunks/test.DNmyFkvJ.mjs.map +0 -1
- package/esm/node_modules/vitest/dist/chunks/utils.BX5Fg8C4.mjs.map +0 -1
- /package/esm/node_modules/{@vitest → .pnpm/@vitest_runner@4.1.10/node_modules/@vitest}/runner/dist/index.mjs +0 -0
- /package/esm/node_modules/{@vitest → .pnpm/@vitest_runner@4.1.10/node_modules/@vitest}/runner/dist/utils.mjs +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-input-builder.mjs","names":[],"sources":["../../../../../../../ai/src/agent/agent-input-builder.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { AgentExecuteOptions } from \"../contracts/agent/agent-options.type\";\nimport type { AttachmentPolicy } from \"../contracts/attachment-policy.type\";\nimport type { Attachment } from \"../contracts/attachment.type\";\nimport type { ContentPart } from \"../contracts/content-part.type\";\nimport type { Message } from \"../contracts/conversation-message.type\";\nimport type { Placeholders } from \"../contracts/placeholders.type\";\nimport { InvalidRequestError } from \"../errors\";\nimport { extractJsonSchema, prepareAttachmentPart } from \"../utils\";\nimport type { AgentConfig } from \"./agent-config.type\";\n\n/**\n * Outcome of `buildAgentInputMessages` — the seeded message list and\n * the JSON Schema cached for every trip's\n * `ModelCallOptions.responseSchema`. `responseSchema` is `undefined`\n * when the caller didn't ask for structured output.\n */\nexport type AgentInputBuildResult = {\n messages: Message[];\n responseSchema?: Record<string, unknown>;\n /**\n * The resolved system-prompt text actually sent as the `role: \"system\"`\n * message (persona + instructions + any auto-appended structured-output\n * instruction). Captured for observability; absent when the agent ran\n * without a system prompt.\n */\n systemPrompt?: string;\n /**\n * Registry name of the `SystemPromptContract` the agent resolved, read from\n * its `meta().name`. Present only when the agent ran against a *named*\n * prompt (one registered in `ai.prompts`); absent for a raw-string prompt,\n * an anonymous contract, or no prompt at all. Lets observers attribute a run\n * to a specific prompt in the registry.\n */\n promptName?: string;\n /**\n * Registry version label of the named prompt the agent resolved, read from\n * its `meta().version` (defaulting to `\"1\"` when the prompt carries a name\n * but no explicit version, mirroring the registry's default). Present only\n * alongside {@link AgentInputBuildResult.promptName}.\n */\n promptVersion?: string;\n};\n\n/**\n * Assemble the seed conversation for an agent execution. Runs exactly\n * once per run — subsequent trips append to the same message list.\n *\n * Responsibilities (previously three methods on `Execution`):\n * 1. Merge factory + per-call placeholders.\n * 2. Resolve the system prompt (string, contract, or absent).\n * 3. When an output schema is supplied:\n * - cache its JSON Schema form for `ModelCallOptions.responseSchema`\n * so native-structured-output providers enforce it at the token\n * level;\n * - fall back to a soft system-prompt instruction for providers\n * that don't advertise `structuredOutput` capability.\n * 4. Append caller-supplied `history` (e.g. session-level prior turns).\n * 5. Shape the user message — plain string in the common case,\n * multipart `ContentPart[]` when `attachments` are present. Image\n * attachments require model vision capability; mismatch throws\n * `InvalidRequestError` here rather than failing opaquely at the\n * provider.\n *\n * Extracted from the `Execution` class to isolate the declarative\n * input-shaping phase from the stateful trip loop.\n */\nexport async function buildAgentInputMessages<TOutput>(params: {\n config: AgentConfig<TOutput>;\n input: string;\n options?: AgentExecuteOptions<TOutput>;\n}): Promise<AgentInputBuildResult> {\n const { config, input, options } = params;\n\n const placeholders: Placeholders = {\n ...config.placeholders,\n ...options?.placeholders,\n };\n\n const systemPrompt = options?.systemPrompt ?? config.systemPrompt;\n let systemContent = \"\";\n let promptName: string | undefined;\n let promptVersion: string | undefined;\n\n if (typeof systemPrompt === \"string\") {\n systemContent = systemPrompt;\n } else if (systemPrompt) {\n // A lazily-compiled prompt (`systemPrompt.refined(...)`) finishes its\n // async work here, before the synchronous `resolve()` below — a no-op for\n // plain builders, and never throws (a failed refinement falls back to the\n // original text).\n if (typeof systemPrompt.materialize === \"function\") {\n await systemPrompt.materialize();\n }\n\n systemContent = systemPrompt.resolve(placeholders);\n\n // Capture prompt-version linkage from the contract's metadata: a *named*\n // prompt (one addressable in `ai.prompts`) stamps `promptName@version`\n // onto the run's report so observers can group runs by the exact prompt\n // version that produced them. Anonymous prompts carry no name and are\n // left unlinked.\n const meta = systemPrompt.meta();\n\n if (meta?.name) {\n promptName = meta.name;\n promptVersion = meta.version ?? \"1\";\n }\n }\n\n const { responseSchema, instruction } = resolveStructuredOutput({\n outputSchema: options?.output ?? config.output,\n overrideResponseSchema: options?.responseSchema,\n modelSupportsStructuredOutput: Boolean(config.model.capabilities?.structuredOutput),\n });\n\n if (instruction) {\n systemContent = systemContent ? `${systemContent}\\n\\n${instruction}` : instruction;\n }\n\n const messages: Message[] = [];\n\n if (systemContent) {\n messages.push({ role: \"system\", content: systemContent });\n }\n\n if (options?.history) {\n messages.push(...options.history);\n }\n\n const userContent = await buildUserMessageContent({\n input,\n attachments: options?.attachments,\n attachmentPolicy: options?.attachmentPolicy ?? config.attachmentPolicy,\n modelName: config.model.name,\n modelSupportsVision: Boolean(config.model.capabilities?.vision),\n modelSupportsPdf: Boolean(config.model.capabilities?.pdf),\n modelSupportsAudio: Boolean(config.model.capabilities?.audio),\n });\n\n messages.push({ role: \"user\", content: userContent });\n\n return {\n messages,\n responseSchema,\n systemPrompt: systemContent || undefined,\n promptName,\n promptVersion,\n };\n}\n\n/**\n * Build the user message `content` field. Plain string when no\n * attachments (the hot path) — keeps wire payloads small. Multipart\n * `ContentPart[]` when attachments exist: input text first, resolved\n * parts in declaration order.\n */\nasync function buildUserMessageContent(params: {\n input: string;\n attachments?: Attachment[];\n attachmentPolicy?: AttachmentPolicy;\n modelName: string;\n modelSupportsVision: boolean;\n modelSupportsPdf: boolean;\n modelSupportsAudio: boolean;\n}): Promise<string | ContentPart[]> {\n const {\n input,\n attachments,\n attachmentPolicy,\n modelName,\n modelSupportsVision,\n modelSupportsPdf,\n modelSupportsAudio,\n } = params;\n\n if (!attachments || attachments.length === 0) {\n return input;\n }\n\n const parts: ContentPart[] = await Promise.all(\n attachments.map((attachment) => prepareAttachmentPart(attachment, attachmentPolicy)),\n );\n\n // Capability gate per modality (A2) — reject an attachment the model\n // can't consume here, with a clear message, rather than failing opaquely\n // at the provider.\n assertModality(parts, \"image\", modelSupportsVision, \"vision\", modelName);\n assertModality(parts, \"pdf\", modelSupportsPdf, \"pdf\", modelName);\n assertModality(parts, \"audio\", modelSupportsAudio, \"audio\", modelName);\n\n return [{ type: \"text\", text: input }, ...parts];\n}\n\n/** Throw when a modality is present but the model doesn't declare it. */\nfunction assertModality(\n parts: ContentPart[],\n partType: ContentPart[\"type\"],\n supported: boolean,\n capability: string,\n modelName: string,\n): void {\n if (!supported && parts.some((part) => part.type === partType)) {\n throw new InvalidRequestError(\n `Model \"${modelName}\" does not declare ${capability} capability — ${partType} attachments are not supported`,\n { context: { modelName } },\n );\n }\n}\n\n/**\n * When the caller supplied an `output` schema, resolve two artifacts:\n *\n * - `responseSchema` — extracted JSON Schema to attach on every trip.\n * Adapters that natively support structured output (OpenAI's\n * `response_format: json_schema`) consume it; others ignore it.\n * - `instruction` — a soft fallback appended to the system prompt\n * **only** for models without native structured-output capability.\n * Capable adapters skip it to save tokens and avoid redundancy.\n */\nfunction resolveStructuredOutput(params: {\n outputSchema?: StandardSchemaV1<unknown>;\n overrideResponseSchema?: Record<string, unknown>;\n modelSupportsStructuredOutput: boolean;\n}): {\n responseSchema?: Record<string, unknown>;\n instruction?: string;\n} {\n const { outputSchema, overrideResponseSchema, modelSupportsStructuredOutput } = params;\n\n if (!outputSchema) {\n return {};\n }\n\n const responseSchema = overrideResponseSchema ?? extractJsonSchema(outputSchema);\n\n if (modelSupportsStructuredOutput) {\n return { responseSchema };\n }\n\n const schemaHint = responseSchema\n ? `\\n\\nThe response MUST match this JSON Schema:\\n${JSON.stringify(responseSchema, null, 2)}`\n : \"\";\n\n const instruction = [\n \"You MUST respond with a single valid JSON value only.\",\n \"Do not wrap it in markdown code fences. Do not include prose, commentary, or explanation — JSON only.\",\n schemaHint,\n ]\n .join(\"\")\n .trim();\n\n return { responseSchema, instruction };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmEA,eAAsB,wBAAiC,QAIpB;CACjC,MAAM,EAAE,QAAQ,OAAO,YAAY;CAEnC,MAAM,eAA6B;EACjC,GAAG,OAAO;EACV,GAAG,SAAS;CACd;CAEA,MAAM,eAAe,SAAS,gBAAgB,OAAO;CACrD,IAAI,gBAAgB;CACpB,IAAI;CACJ,IAAI;CAEJ,IAAI,OAAO,iBAAiB,UAC1B,gBAAgB;MACX,IAAI,cAAc;EAKvB,IAAI,OAAO,aAAa,gBAAgB,YACtC,MAAM,aAAa,YAAY;EAGjC,gBAAgB,aAAa,QAAQ,YAAY;EAOjD,MAAM,OAAO,aAAa,KAAK;EAE/B,IAAI,MAAM,MAAM;GACd,aAAa,KAAK;GAClB,gBAAgB,KAAK,WAAW;EAClC;CACF;CAEA,MAAM,EAAE,gBAAgB,gBAAgB,wBAAwB;EAC9D,cAAc,SAAS,UAAU,OAAO;EACxC,wBAAwB,SAAS;EACjC,+BAA+B,QAAQ,OAAO,MAAM,cAAc,gBAAgB;CACpF,CAAC;CAED,IAAI,aACF,gBAAgB,gBAAgB,GAAG,cAAc,MAAM,gBAAgB;CAGzE,MAAM,WAAsB,CAAC;CAE7B,IAAI,eACF,SAAS,KAAK;EAAE,MAAM;EAAU,SAAS;CAAc,CAAC;CAG1D,IAAI,SAAS,SACX,SAAS,KAAK,GAAG,QAAQ,OAAO;CAGlC,MAAM,cAAc,MAAM,wBAAwB;EAChD;EACA,aAAa,SAAS;EACtB,kBAAkB,SAAS,oBAAoB,OAAO;EACtD,WAAW,OAAO,MAAM;EACxB,qBAAqB,QAAQ,OAAO,MAAM,cAAc,MAAM;EAC9D,kBAAkB,QAAQ,OAAO,MAAM,cAAc,GAAG;EACxD,oBAAoB,QAAQ,OAAO,MAAM,cAAc,KAAK;CAC9D,CAAC;CAED,SAAS,KAAK;EAAE,MAAM;EAAQ,SAAS;CAAY,CAAC;CAEpD,OAAO;EACL;EACA;EACA,cAAc,iBAAiB;EAC/B;EACA;CACF;AACF;;;;;;;AAQA,eAAe,wBAAwB,QAQH;CAClC,MAAM,EACJ,OACA,aACA,kBACA,WACA,qBACA,kBACA,uBACE;CAEJ,IAAI,CAAC,eAAe,YAAY,WAAW,GACzC,OAAO;CAGT,MAAM,QAAuB,MAAM,QAAQ,IACzC,YAAY,KAAK,eAAe,sBAAsB,YAAY,gBAAgB,CAAC,CACrF;CAKA,eAAe,OAAO,SAAS,qBAAqB,UAAU,SAAS;CACvE,eAAe,OAAO,OAAO,kBAAkB,OAAO,SAAS;CAC/D,eAAe,OAAO,SAAS,oBAAoB,SAAS,SAAS;CAErE,OAAO,CAAC;EAAE,MAAM;EAAQ,MAAM;CAAM,GAAG,GAAG,KAAK;AACjD;;AAGA,SAAS,eACP,OACA,UACA,WACA,YACA,WACM;CACN,IAAI,CAAC,aAAa,MAAM,MAAM,SAAS,KAAK,SAAS,QAAQ,GAC3D,MAAM,IAAI,oBACR,UAAU,UAAU,qBAAqB,WAAW,gBAAgB,SAAS,iCAC7E,EAAE,SAAS,EAAE,UAAU,EAAE,CAC3B;AAEJ;;;;;;;;;;;AAYA,SAAS,wBAAwB,QAO/B;CACA,MAAM,EAAE,cAAc,wBAAwB,kCAAkC;CAEhF,IAAI,CAAC,cACH,OAAO,CAAC;CAGV,MAAM,iBAAiB,0BAA0B,kBAAkB,YAAY;CAE/E,IAAI,+BACF,OAAO,EAAE,eAAe;CAe1B,OAAO;EAAE;EAAgB,aARL;GAClB;GACA;GANiB,iBACf,kDAAkD,KAAK,UAAU,gBAAgB,MAAM,CAAC,MACxF;EAMJ,CAAC,CACE,KAAK,EAAE,CAAC,CACR,KAEgC;CAAE;AACvC"}
|
|
1
|
+
{"version":3,"file":"agent-input-builder.mjs","names":[],"sources":["../../../../../../../ai/src/agent/agent-input-builder.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { AgentExecuteOptions } from \"../contracts/agent/agent-options.type\";\nimport type { AttachmentPolicy } from \"../contracts/attachment-policy.type\";\nimport type { Attachment } from \"../contracts/attachment.type\";\nimport type { ContentPart } from \"../contracts/content-part.type\";\nimport type { Message } from \"../contracts/conversation-message.type\";\nimport type { Placeholders } from \"../contracts/placeholders.type\";\nimport { InvalidRequestError } from \"../errors\";\nimport { extractJsonSchema, prepareAttachmentPart } from \"../utils\";\nimport type { AgentConfig } from \"./agent-config.type\";\n\n/**\n * Outcome of `buildAgentInputMessages` — the seeded message list and\n * the JSON Schema cached for every trip's\n * `ModelCallOptions.responseSchema`. `responseSchema` is `undefined`\n * when the caller didn't ask for structured output.\n */\nexport type AgentInputBuildResult = {\n messages: Message[];\n responseSchema?: Record<string, unknown>;\n /**\n * The resolved system-prompt text actually sent as the `role: \"system\"`\n * message (persona + instructions + any auto-appended structured-output\n * instruction). Captured for observability; absent when the agent ran\n * without a system prompt.\n */\n systemPrompt?: string;\n /**\n * Registry name of the `SystemPromptContract` the agent resolved, read from\n * its `meta().name`. Present only when the agent ran against a *named*\n * prompt (one registered in `ai.prompts`); absent for a raw-string prompt,\n * an anonymous contract, or no prompt at all. Lets observers attribute a run\n * to a specific prompt in the registry.\n */\n promptName?: string;\n /**\n * Registry version label of the named prompt the agent resolved, read from\n * its `meta().version` (defaulting to `\"1\"` when the prompt carries a name\n * but no explicit version, mirroring the registry's default). Present only\n * alongside {@link AgentInputBuildResult.promptName}.\n */\n promptVersion?: string;\n};\n\n/**\n * Assemble the seed conversation for an agent execution. Runs exactly\n * once per run — subsequent trips append to the same message list.\n *\n * Responsibilities (previously three methods on `Execution`):\n * 1. Merge factory + per-call placeholders.\n * 2. Resolve the system prompt (string, contract, or absent).\n * 3. When an output schema is supplied:\n * - cache its JSON Schema form for `ModelCallOptions.responseSchema`\n * so native-structured-output providers enforce it at the token\n * level;\n * - fall back to a soft system-prompt instruction for providers\n * that don't advertise `structuredOutput` capability.\n * 4. Append caller-supplied `history` (e.g. session-level prior turns).\n * 5. Shape the user message — plain string in the common case,\n * multipart `ContentPart[]` when `attachments` are present. Image\n * attachments require model vision capability; mismatch throws\n * `InvalidRequestError` here rather than failing opaquely at the\n * provider.\n *\n * Extracted from the `Execution` class to isolate the declarative\n * input-shaping phase from the stateful trip loop.\n */\nexport async function buildAgentInputMessages<TOutput>(params: {\n config: AgentConfig<TOutput>;\n input: string;\n options?: AgentExecuteOptions<TOutput>;\n}): Promise<AgentInputBuildResult> {\n const { config, input, options } = params;\n\n const placeholders: Placeholders = {\n ...config.placeholders,\n ...options?.placeholders,\n };\n\n const systemPrompt = options?.systemPrompt ?? config.systemPrompt;\n let systemContent = \"\";\n let promptName: string | undefined;\n let promptVersion: string | undefined;\n\n if (typeof systemPrompt === \"string\") {\n systemContent = systemPrompt;\n } else if (systemPrompt) {\n // A lazily-compiled prompt (`systemPrompt.refined(...)`) finishes its\n // async work here, before the synchronous `resolve()` below — a no-op for\n // plain builders, and never throws (a failed refinement falls back to the\n // original text).\n if (typeof systemPrompt.materialize === \"function\") {\n await systemPrompt.materialize();\n }\n\n systemContent = systemPrompt.resolve(placeholders);\n\n // Capture prompt-version linkage from the contract's metadata: a *named*\n // prompt (one addressable in `ai.prompts`) stamps `promptName@version`\n // onto the run's report so observers can group runs by the exact prompt\n // version that produced them. Anonymous prompts carry no name and are\n // left unlinked.\n const meta = systemPrompt.meta();\n\n if (meta?.name) {\n promptName = meta.name;\n promptVersion = meta.version ?? \"1\";\n }\n }\n\n const { responseSchema, instruction } = resolveStructuredOutput({\n outputSchema: options?.output ?? config.output,\n overrideResponseSchema: options?.responseSchema,\n modelSupportsStructuredOutput: Boolean(config.model.capabilities?.structuredOutput),\n });\n\n if (instruction) {\n systemContent = systemContent ? `${systemContent}\\n\\n${instruction}` : instruction;\n }\n\n const messages: Message[] = [];\n\n if (systemContent) {\n messages.push({ role: \"system\", content: systemContent });\n }\n\n if (options?.history) {\n messages.push(...options.history);\n }\n\n const userContent = await buildUserMessageContent({\n input,\n attachments: options?.attachments,\n attachmentPolicy: options?.attachmentPolicy ?? config.attachmentPolicy,\n modelName: config.model.name,\n modelSupportsVision: Boolean(config.model.capabilities?.vision),\n modelSupportsPdf: Boolean(config.model.capabilities?.pdf),\n modelSupportsAudio: Boolean(config.model.capabilities?.audio),\n });\n\n messages.push({ role: \"user\", content: userContent });\n\n return {\n messages,\n responseSchema,\n systemPrompt: systemContent || undefined,\n promptName,\n promptVersion,\n };\n}\n\n/**\n * Build the user message `content` field. Plain string when no\n * attachments (the hot path) — keeps wire payloads small. Multipart\n * `ContentPart[]` when attachments exist: input text first, resolved\n * parts in declaration order.\n */\nasync function buildUserMessageContent(params: {\n input: string;\n attachments?: Attachment[];\n attachmentPolicy?: AttachmentPolicy;\n modelName: string;\n modelSupportsVision: boolean;\n modelSupportsPdf: boolean;\n modelSupportsAudio: boolean;\n}): Promise<string | ContentPart[]> {\n const {\n input,\n attachments,\n attachmentPolicy,\n modelName,\n modelSupportsVision,\n modelSupportsPdf,\n modelSupportsAudio,\n } = params;\n\n if (!attachments || attachments.length === 0) {\n return input;\n }\n\n const parts: ContentPart[] = await Promise.all(\n attachments.map((attachment) => prepareAttachmentPart(attachment, attachmentPolicy)),\n );\n\n // Capability gate per modality (A2) — reject an attachment the model\n // can't consume here, with a clear message, rather than failing opaquely\n // at the provider.\n assertModality(parts, \"image\", modelSupportsVision, \"vision\", modelName);\n assertModality(parts, \"pdf\", modelSupportsPdf, \"pdf\", modelName);\n assertModality(parts, \"audio\", modelSupportsAudio, \"audio\", modelName);\n\n return [{ type: \"text\", text: input }, ...parts];\n}\n\n/** Throw when a modality is present but the model doesn't declare it. */\nfunction assertModality(\n parts: ContentPart[],\n partType: ContentPart[\"type\"],\n supported: boolean,\n capability: string,\n modelName: string,\n): void {\n if (!supported && parts.some((part) => part.type === partType)) {\n throw new InvalidRequestError(\n `Model \"${modelName}\" does not declare ${capability} capability — ${partType} attachments are not supported`,\n { context: { modelName } },\n );\n }\n}\n\n/**\n * When the caller supplied an `output` schema, resolve two artifacts:\n *\n * - `responseSchema` — extracted JSON Schema to attach on every trip.\n * Adapters that natively support structured output (OpenAI's\n * `response_format: json_schema`) consume it; others ignore it.\n * - `instruction` — a soft fallback appended to the system prompt\n * **only** for models without native structured-output capability.\n * Capable adapters skip it to save tokens and avoid redundancy.\n */\nfunction resolveStructuredOutput(params: {\n outputSchema?: StandardSchemaV1<unknown>;\n overrideResponseSchema?: Record<string, unknown>;\n modelSupportsStructuredOutput: boolean;\n}): {\n responseSchema?: Record<string, unknown>;\n instruction?: string;\n} {\n const { outputSchema, overrideResponseSchema, modelSupportsStructuredOutput } = params;\n\n if (!outputSchema) {\n return {};\n }\n\n const responseSchema = overrideResponseSchema ?? extractJsonSchema(outputSchema);\n\n if (modelSupportsStructuredOutput) {\n return { responseSchema };\n }\n\n const schemaHint = responseSchema\n ? `\\n\\nThe response MUST match this JSON Schema:\\n${JSON.stringify(responseSchema, null, 2)}`\n : \"\";\n\n const instruction = [\n \"You MUST respond with a single valid JSON value only.\",\n \"Do not wrap it in markdown code fences. Do not include prose, commentary, or explanation — JSON only.\",\n schemaHint,\n ]\n .join(\"\")\n .trim();\n\n return { responseSchema, instruction };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmEA,eAAsB,wBAAiC,QAIpB;CACjC,MAAM,EAAE,QAAQ,OAAO,YAAY;CAEnC,MAAM,eAA6B;EACjC,GAAG,OAAO;EACV,GAAG,SAAS;CACd;CAEA,MAAM,eAAe,SAAS,gBAAgB,OAAO;CACrD,IAAI,gBAAgB;CACpB,IAAI;CACJ,IAAI;CAEJ,IAAI,OAAO,iBAAiB,UAC1B,gBAAgB;MACX,IAAI,cAAc;EAKvB,IAAI,OAAO,aAAa,gBAAgB,YACtC,MAAM,aAAa,YAAY;EAGjC,gBAAgB,aAAa,QAAQ,YAAY;EAOjD,MAAM,OAAO,aAAa,KAAK;EAE/B,IAAI,MAAM,MAAM;GACd,aAAa,KAAK;GAClB,gBAAgB,KAAK,WAAW;EAClC;CACF;CAEA,MAAM,EAAE,gBAAgB,gBAAgB,wBAAwB;EAC9D,cAAc,SAAS,UAAU,OAAO;EACxC,wBAAwB,SAAS;EACjC,+BAA+B,QAAQ,OAAO,MAAM,cAAc,gBAAgB;CACpF,CAAC;CAED,IAAI,aACF,gBAAgB,gBAAgB,GAAG,cAAc,MAAM,gBAAgB;CAGzE,MAAM,WAAsB,CAAC;CAE7B,IAAI,eACF,SAAS,KAAK;EAAE,MAAM;EAAU,SAAS;CAAc,CAAC;CAG1D,IAAI,SAAS,SACX,SAAS,KAAK,GAAG,QAAQ,OAAO;CAGlC,MAAM,cAAc,MAAM,wBAAwB;EAChD;EACA,aAAa,SAAS;EACtB,kBAAkB,SAAS,oBAAoB,OAAO;EACtD,WAAW,OAAO,MAAM;EACxB,qBAAqB,QAAQ,OAAO,MAAM,cAAc,MAAM;EAC9D,kBAAkB,QAAQ,OAAO,MAAM,cAAc,GAAG;EACxD,oBAAoB,QAAQ,OAAO,MAAM,cAAc,KAAK;CAC9D,CAAC;CAED,SAAS,KAAK;EAAE,MAAM;EAAQ,SAAS;CAAY,CAAC;CAEpD,OAAO;EACL;EACA;EACA,cAAc,iBAAiB;EAC/B;EACA;CACF;AACF;;;;;;;AAQA,eAAe,wBAAwB,QAQH;CAClC,MAAM,EACJ,OACA,aACA,kBACA,WACA,qBACA,kBACA,uBACE;CAEJ,IAAI,CAAC,eAAe,YAAY,WAAW,GACzC,OAAO;CAGT,MAAM,QAAuB,MAAM,QAAQ,IACzC,YAAY,KAAK,eAAe,sBAAsB,YAAY,gBAAgB,CAAC,CACrF;CAKA,eAAe,OAAO,SAAS,qBAAqB,UAAU,SAAS;CACvE,eAAe,OAAO,OAAO,kBAAkB,OAAO,SAAS;CAC/D,eAAe,OAAO,SAAS,oBAAoB,SAAS,SAAS;CAErE,OAAO,CAAC;EAAE,MAAM;EAAQ,MAAM;CAAM,GAAG,GAAG,KAAK;AACjD;;AAGA,SAAS,eACP,OACA,UACA,WACA,YACA,WACM;CACN,IAAI,CAAC,aAAa,MAAM,MAAM,SAAS,KAAK,SAAS,QAAQ,GAC3D,MAAM,IAAI,oBACR,UAAU,UAAU,qBAAqB,WAAW,gBAAgB,SAAS,iCAC7E,EAAE,SAAS,EAAE,UAAU,EAAE,CAC3B;AAEJ;;;;;;;;;;;AAYA,SAAS,wBAAwB,QAO/B;CACA,MAAM,EAAE,cAAc,wBAAwB,kCAAkC;CAEhF,IAAI,CAAC,cACH,OAAO,CAAC;CAGV,MAAM,iBAAiB,0BAA0B,kBAAkB,YAAY;CAE/E,IAAI,+BACF,OAAO,EAAE,eAAe;CAe1B,OAAO;EAAE;EAAgB,aARL;GAClB;GACA;GANiB,iBACf,kDAAkD,KAAK,UAAU,gBAAgB,MAAM,CAAC,MACxF;EAMJ,EACG,KAAK,EAAE,EACP,KAEgC;CAAE;AACvC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-stream.d.mts","names":[],"sources":["../../../../../../../ai/src/agent/agent-stream.ts"],"mappings":";;;;;;;AAkCA;;;;;;;;;;;;;;;;;;;AAGmB;AAQnB;;;;;;;;KAXY,gBAAA;EACV,IAAA,CAAK,KAAA,EAAO,WAAA;EACZ,GAAA,CAAI,MAAA,EAAQ,OAAA;EACZ,IAAA,CAAK,KAAA,EAAO,KAAA;AAAA;AAAA,iBAQE,iBAAA;EACd,UAAA,EAAY,gBAAA,CAAiB,OAAA;EAC7B,MAAA,EAAQ,cAAA,CAAe,OAAA;AAAA"}
|
|
1
|
+
{"version":3,"file":"agent-stream.d.mts","names":[],"sources":["../../../../../../../ai/src/agent/agent-stream.ts"],"mappings":";;;;;;;AAkCA;;;;;;;;;;;;;;;;;;;AAGmB;AAQnB;;;;;;;;KAXY,gBAAA;EACV,IAAA,CAAK,KAAA,EAAO,WAAA;EACZ,GAAA,CAAI,MAAA,EAAQ,OAAA;EACZ,IAAA,CAAK,KAAA,EAAO,KAAA;AAAA;AAAA,iBAQE,iBAAA,SAAA,CAAA;EACd,UAAA,EAAY,gBAAA,CAAiB,OAAA;EAC7B,MAAA,EAAQ,cAAA,CAAe,OAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-stream.mjs","names":[],"sources":["../../../../../../../ai/src/agent/agent-stream.ts"],"sourcesContent":["import type { StreamContract, StreamEvent } from \"../contracts\";\n\n/**\n * Internal async-queue `StreamContract` used by `agent().stream()`.\n *\n * **Role.** The bridge between a streaming `Execution` (which runs in the\n * background, pushing events as they happen) and a consumer that reads\n * those events with `for await` or an `on(...)` handler map.\n *\n * **Responsibility.**\n * - Owns: the event queue, the pending-read promise chain, the terminal\n * `result` promise, and any user-registered event handlers.\n * - Does NOT own: any knowledge of agents, models, or tool calls — it is a\n * generic producer/consumer pipe parameterized by `TResult`. The streaming\n * execution writes via `push()` / `end()` / `fail()`; the consumer reads\n * via the AsyncIterable surface.\n *\n * Events are coalesced into a queue so that a consumer that starts\n * iterating late still sees every event in order — nothing is dropped. The\n * `on()` handlers fire the moment an event is pushed, independent of\n * whether anyone is iterating.\n *\n * @example\n * // Inside agent.stream():\n * const { controller, stream } = createAgentStream<AgentResult<TOutput>>();\n * new Execution(config, input, options, controller).run();\n * return stream;\n *\n * // Consumer:\n * for await (const event of stream) {\n * if (event.type === \"streaming\") process.stdout.write(event.delta);\n * }\n * const result = await stream.result;\n */\nexport type StreamController<TResult> = {\n push(event: StreamEvent): void;\n end(result: TResult): void;\n fail(error: Error): void;\n};\n\ntype PendingRead = {\n resolve(value: IteratorResult<StreamEvent>): void;\n reject(error: Error): void;\n};\n\nexport function createAgentStream<TResult>(): {\n controller: StreamController<TResult>;\n stream: StreamContract<TResult>;\n} {\n const queue: StreamEvent[] = [];\n const pending: PendingRead[] = [];\n const handlers = new Map<StreamEvent[\"type\"], (event: StreamEvent) => void>();\n\n let closed = false;\n let failure: Error | undefined;\n let resolveResult!: (value: TResult) => void;\n let rejectResult!: (error: Error) => void;\n\n const result = new Promise<TResult>((resolve, reject) => {\n resolveResult = resolve;\n rejectResult = reject;\n });\n\n const controller: StreamController<TResult> = {\n push(event) {\n const handler = handlers.get(event.type);\n\n if (handler) {\n try {\n handler(event);\n } catch {\n // User-provided stream handlers must never crash the agent.\n // Swallow — structured logging attaches here in Phase 0.5.\n }\n }\n\n const reader = pending.shift();\n\n if (reader) {\n reader.resolve({ value: event, done: false });\n return;\n }\n\n queue.push(event);\n },\n\n end(finalResult) {\n closed = true;\n resolveResult(finalResult);\n\n while (pending.length > 0) {\n const reader = pending.shift();\n\n reader?.resolve({ value: undefined, done: true });\n }\n },\n\n fail(error) {\n closed = true;\n failure = error;\n rejectResult(error);\n\n while (pending.length > 0) {\n const reader = pending.shift();\n\n reader?.reject(error);\n }\n },\n };\n\n const iterator: AsyncIterator<StreamEvent> = {\n next() {\n if (queue.length > 0) {\n return Promise.resolve({ value: queue.shift()!, done: false });\n }\n\n if (closed) {\n if (failure) {\n return Promise.reject(failure);\n }\n\n return Promise.resolve({ value: undefined, done: true });\n }\n\n return new Promise<IteratorResult<StreamEvent>>((resolve, reject) => {\n pending.push({ resolve, reject });\n });\n },\n };\n\n const stream: StreamContract<TResult> = {\n result,\n on(handlerMap) {\n for (const [key, handler] of Object.entries(handlerMap)) {\n if (handler) {\n handlers.set(\n key as StreamEvent[\"type\"],\n handler as (event: StreamEvent) => void,\n );\n }\n }\n\n return stream;\n },\n [Symbol.asyncIterator]() {\n return iterator;\n },\n };\n\n return { controller, stream };\n}\n"],"mappings":";AA6CA,SAAgB,oBAGd;CACA,MAAM,QAAuB,CAAC;CAC9B,MAAM,UAAyB,CAAC;CAChC,MAAM,2BAAW,IAAI,IAAuD;CAE5E,IAAI,SAAS;CACb,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,MAAM,SAAS,IAAI,SAAkB,SAAS,WAAW;EACvD,gBAAgB;EAChB,eAAe;CACjB,CAAC;CAED,MAAM,aAAwC;EAC5C,KAAK,OAAO;GACV,MAAM,UAAU,SAAS,IAAI,MAAM,IAAI;GAEvC,IAAI,SACF,IAAI;IACF,QAAQ,KAAK;GACf,QAAQ,CAGR;GAGF,MAAM,SAAS,QAAQ,MAAM;GAE7B,IAAI,QAAQ;IACV,OAAO,QAAQ;KAAE,OAAO;KAAO,MAAM;IAAM,CAAC;IAC5C;GACF;GAEA,MAAM,KAAK,KAAK;EAClB;EAEA,IAAI,aAAa;GACf,SAAS;GACT,cAAc,WAAW;GAEzB,OAAO,QAAQ,SAAS,GAGtB,AAFe,QAAQ,MAElB,
|
|
1
|
+
{"version":3,"file":"agent-stream.mjs","names":[],"sources":["../../../../../../../ai/src/agent/agent-stream.ts"],"sourcesContent":["import type { StreamContract, StreamEvent } from \"../contracts\";\n\n/**\n * Internal async-queue `StreamContract` used by `agent().stream()`.\n *\n * **Role.** The bridge between a streaming `Execution` (which runs in the\n * background, pushing events as they happen) and a consumer that reads\n * those events with `for await` or an `on(...)` handler map.\n *\n * **Responsibility.**\n * - Owns: the event queue, the pending-read promise chain, the terminal\n * `result` promise, and any user-registered event handlers.\n * - Does NOT own: any knowledge of agents, models, or tool calls — it is a\n * generic producer/consumer pipe parameterized by `TResult`. The streaming\n * execution writes via `push()` / `end()` / `fail()`; the consumer reads\n * via the AsyncIterable surface.\n *\n * Events are coalesced into a queue so that a consumer that starts\n * iterating late still sees every event in order — nothing is dropped. The\n * `on()` handlers fire the moment an event is pushed, independent of\n * whether anyone is iterating.\n *\n * @example\n * // Inside agent.stream():\n * const { controller, stream } = createAgentStream<AgentResult<TOutput>>();\n * new Execution(config, input, options, controller).run();\n * return stream;\n *\n * // Consumer:\n * for await (const event of stream) {\n * if (event.type === \"streaming\") process.stdout.write(event.delta);\n * }\n * const result = await stream.result;\n */\nexport type StreamController<TResult> = {\n push(event: StreamEvent): void;\n end(result: TResult): void;\n fail(error: Error): void;\n};\n\ntype PendingRead = {\n resolve(value: IteratorResult<StreamEvent>): void;\n reject(error: Error): void;\n};\n\nexport function createAgentStream<TResult>(): {\n controller: StreamController<TResult>;\n stream: StreamContract<TResult>;\n} {\n const queue: StreamEvent[] = [];\n const pending: PendingRead[] = [];\n const handlers = new Map<StreamEvent[\"type\"], (event: StreamEvent) => void>();\n\n let closed = false;\n let failure: Error | undefined;\n let resolveResult!: (value: TResult) => void;\n let rejectResult!: (error: Error) => void;\n\n const result = new Promise<TResult>((resolve, reject) => {\n resolveResult = resolve;\n rejectResult = reject;\n });\n\n const controller: StreamController<TResult> = {\n push(event) {\n const handler = handlers.get(event.type);\n\n if (handler) {\n try {\n handler(event);\n } catch {\n // User-provided stream handlers must never crash the agent.\n // Swallow — structured logging attaches here in Phase 0.5.\n }\n }\n\n const reader = pending.shift();\n\n if (reader) {\n reader.resolve({ value: event, done: false });\n return;\n }\n\n queue.push(event);\n },\n\n end(finalResult) {\n closed = true;\n resolveResult(finalResult);\n\n while (pending.length > 0) {\n const reader = pending.shift();\n\n reader?.resolve({ value: undefined, done: true });\n }\n },\n\n fail(error) {\n closed = true;\n failure = error;\n rejectResult(error);\n\n while (pending.length > 0) {\n const reader = pending.shift();\n\n reader?.reject(error);\n }\n },\n };\n\n const iterator: AsyncIterator<StreamEvent> = {\n next() {\n if (queue.length > 0) {\n return Promise.resolve({ value: queue.shift()!, done: false });\n }\n\n if (closed) {\n if (failure) {\n return Promise.reject(failure);\n }\n\n return Promise.resolve({ value: undefined, done: true });\n }\n\n return new Promise<IteratorResult<StreamEvent>>((resolve, reject) => {\n pending.push({ resolve, reject });\n });\n },\n };\n\n const stream: StreamContract<TResult> = {\n result,\n on(handlerMap) {\n for (const [key, handler] of Object.entries(handlerMap)) {\n if (handler) {\n handlers.set(\n key as StreamEvent[\"type\"],\n handler as (event: StreamEvent) => void,\n );\n }\n }\n\n return stream;\n },\n [Symbol.asyncIterator]() {\n return iterator;\n },\n };\n\n return { controller, stream };\n}\n"],"mappings":";AA6CA,SAAgB,oBAGd;CACA,MAAM,QAAuB,CAAC;CAC9B,MAAM,UAAyB,CAAC;CAChC,MAAM,2BAAW,IAAI,IAAuD;CAE5E,IAAI,SAAS;CACb,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,MAAM,SAAS,IAAI,SAAkB,SAAS,WAAW;EACvD,gBAAgB;EAChB,eAAe;CACjB,CAAC;CAED,MAAM,aAAwC;EAC5C,KAAK,OAAO;GACV,MAAM,UAAU,SAAS,IAAI,MAAM,IAAI;GAEvC,IAAI,SACF,IAAI;IACF,QAAQ,KAAK;GACf,QAAQ,CAGR;GAGF,MAAM,SAAS,QAAQ,MAAM;GAE7B,IAAI,QAAQ;IACV,OAAO,QAAQ;KAAE,OAAO;KAAO,MAAM;IAAM,CAAC;IAC5C;GACF;GAEA,MAAM,KAAK,KAAK;EAClB;EAEA,IAAI,aAAa;GACf,SAAS;GACT,cAAc,WAAW;GAEzB,OAAO,QAAQ,SAAS,GAGtB,AAFe,QAAQ,MAElB,GAAG,QAAQ;IAAE,OAAO;IAAW,MAAM;GAAK,CAAC;EAEpD;EAEA,KAAK,OAAO;GACV,SAAS;GACT,UAAU;GACV,aAAa,KAAK;GAElB,OAAO,QAAQ,SAAS,GAGtB,AAFe,QAAQ,MAElB,GAAG,OAAO,KAAK;EAExB;CACF;CAEA,MAAM,WAAuC,EAC3C,OAAO;EACL,IAAI,MAAM,SAAS,GACjB,OAAO,QAAQ,QAAQ;GAAE,OAAO,MAAM,MAAM;GAAI,MAAM;EAAM,CAAC;EAG/D,IAAI,QAAQ;GACV,IAAI,SACF,OAAO,QAAQ,OAAO,OAAO;GAG/B,OAAO,QAAQ,QAAQ;IAAE,OAAO;IAAW,MAAM;GAAK,CAAC;EACzD;EAEA,OAAO,IAAI,SAAsC,SAAS,WAAW;GACnE,QAAQ,KAAK;IAAE;IAAS;GAAO,CAAC;EAClC,CAAC;CACH,EACF;CAEA,MAAM,SAAkC;EACtC;EACA,GAAG,YAAY;GACb,KAAK,MAAM,CAAC,KAAK,YAAY,OAAO,QAAQ,UAAU,GACpD,IAAI,SACF,SAAS,IACP,KACA,OACF;GAIJ,OAAO;EACT;EACA,CAAC,OAAO,iBAAiB;GACvB,OAAO;EACT;CACF;CAEA,OAAO;EAAE;EAAY;CAAO;AAC9B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.mts","names":[],"sources":["../../../../../../../ai/src/agent/agent.ts"],"mappings":";;;;;;;;AA6PA;;;;;;;;;;;;;;;;AAA6F;;;;;;AAqL7F;;;;;iBArLgB,KAAA,
|
|
1
|
+
{"version":3,"file":"agent.d.mts","names":[],"sources":["../../../../../../../ai/src/agent/agent.ts"],"mappings":";;;;;;;;AA6PA;;;;;;;;;;;;;;;;AAA6F;;;;;;AAqL7F;;;;;iBArLgB,KAAA,mBAAA,CAAyB,MAAA,EAAQ,WAAA,CAAY,OAAA,IAAW,aAAA,CAAc,OAAA;AAAA,kBAAtE,KAAA;EAAA,kBAAK,UAAA;AAAA;;;;;AAqLqD;KAA9D,gBAAA,sBAAsC,IAAA,CAAK,WAAA,CAAY,OAAA;;;;;;;;;;;;;;;;;;;AAiC3C;;;;;;;;;;iBAHf,UAAA,mBAAA,CACP,MAAA,EAAQ,gBAAA,CAAiB,OAAA,GACzB,KAAA,GAAO,WAAA,aACN,aAAA,CAAc,OAAA"}
|
package/esm/agent/agent.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.mjs","names":[],"sources":["../../../../../../../ai/src/agent/agent.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { log, type Logger } from \"@warlock.js/logger\";\nimport type {\n AgentContract,\n AgentEventHandler,\n AgentEventMap,\n AgentExecuteOptions,\n AgentResult,\n BaseReport,\n CapturedMessage,\n CompleteEvent,\n FinishReason,\n LLMTrip,\n Message,\n MiddlewareExecuteContext,\n MiddlewareState,\n MiddlewareToolContext,\n MiddlewareTripContext,\n ModelResponse,\n ModelToolCallRequest,\n StreamContract,\n StreamEventBody,\n StreamingToolGuardConfig,\n ToolCall,\n ToolContext,\n ToolEventMeta,\n Usage,\n UsageEvent,\n WithoutIdentity,\n} from \"../contracts\";\nimport {\n AgentCancelledError,\n AgentExecutionError,\n AgentMaxTripsError,\n AIError,\n SchemaValidationError,\n} from \"../errors\";\nimport type { AgentContract as AgentContractType } from \"../contracts/agent/agent.contract\";\nimport type { AgentResumeOptions } from \"../contracts/agent/agent-options.type\";\nimport type { AgentSnapshot, AgentSnapshotStatus } from \"../contracts/agent/agent-snapshot.type\";\nimport type { EvalOptions, EvalReport } from \"../contracts/agent/eval.type\";\nimport { runEval } from \"../eval/eval-runner\";\nimport { runPipeline } from \"../middleware\";\nimport { notifyObservers } from \"../observe/resolve-observers\";\nimport { skills } from \"../skills\";\nimport type { SkillsContract } from \"../skills/contracts/skills.contract\";\nimport { normalizeAgentTools } from \"../tool/executable-as-tool\";\nimport type { ToolContract, ToolInvokeResult } from \"../tool/tool\";\nimport {\n captureChildReport,\n computeCost,\n extractJsonLenient,\n extractJsonPayload,\n generateRunId,\n mergeUsage,\n safeJsonParse,\n stampReportLineage,\n} from \"../utils\";\nimport type { AgentConfig } from \"./agent-config.type\";\nimport { JUDGE_DEFAULT_REPAIR_ATTEMPTS, type JudgeConfig } from \"./judge-config.type\";\nimport { buildAgentInputMessages } from \"./agent-input-builder\";\nimport { logAgentEvent } from \"./agent-log-event\";\nimport { createAgentStream, type StreamController } from \"./agent-stream\";\nimport { agentEventToStreamEvent } from \"./agent-to-stream-event\";\nimport { JsonStreamGuard } from \"./json-stream-guard\";\nimport { computeAgentSignature } from \"./signature\";\nimport {\n deleteAgentSnapshot,\n loadAgentSnapshotForResume,\n persistAgentSnapshot,\n} from \"./snapshot\";\n\nconst LOG_MODULE = \"ai.agent\";\n\n/**\n * Internal post-normalization view of an `AgentConfig`. The public\n * `tools` field accepts both built `ToolContract`s and raw executables\n * (`AgentToolEntry[]`); by the time the runtime sees the config every\n * entry has been adapted to a `ToolContract`, so `Execution` works\n * against this narrowed shape and never has to re-discriminate.\n */\ntype ResolvedAgentConfig<TOutput> = Omit<AgentConfig<TOutput>, \"tools\" | \"skills\"> & {\n tools?: ToolContract<unknown, unknown>[];\n /**\n * The skills library resolved once at factory time from the public\n * `skills` option (a {@link SkillsContract} or a raw `SkillsConfig`).\n * `undefined` when the agent has no skills attached — the execute path\n * then behaves byte-for-byte as today.\n */\n skillsLib?: SkillsContract;\n /**\n * Structural drift fingerprint computed once at factory time from the\n * agent's identity-defining fields (model + provider + sorted tool\n * names + maxTrips + output + version). Stamped on every durable\n * snapshot and compared on `resume()`. Always present so the resume\n * path never re-derives it.\n */\n signature: string;\n};\n\n/**\n * Duck-type a value as a {@link SkillsContract} (vs a raw `SkillsConfig`).\n * A contract exposes the agent-facing methods; a config is a plain spec.\n * Checking `catalogPrompt` is sufficient to discriminate the two shapes.\n */\nfunction isSkillsContract(value: unknown): value is SkillsContract {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as SkillsContract).catalogPrompt === \"function\"\n );\n}\n\n/**\n * Detect abort-flavored errors surfaced by SDK HTTP layers — the\n * DOM `AbortError`, axios `ERR_CANCELED`, node-fetch's own\n * `AbortError`. Used to classify them as cancellation rather than\n * generic agent-execution failures.\n */\nfunction isAbortLike(err: unknown): boolean {\n if (!err || typeof err !== \"object\") return false;\n\n const e = err as { name?: unknown; code?: unknown };\n\n return e.name === \"AbortError\" || e.code === \"ERR_CANCELED\" || e.code === \"ABORT_ERR\";\n}\n\n/**\n * Readable synthetic name for agents constructed without an explicit\n * `name`. Format: `anon_<provider>_<model>[_<tool1>+<tool2>+...]` —\n * deterministic (same config → same name across restarts) and\n * human-readable in logs / workflow snapshots.\n *\n * Keeps drift detection honest for the `ai.agent({ model })`\n * one-liner without punishing it with a hashed id nobody can read.\n */\nfunction synthesizeAgentName<T>(config: AgentConfig<T>): string {\n const provider = (config.model as unknown as { provider?: string })?.provider ?? \"unknown\";\n const model = config.model?.name ?? \"unknown\";\n const tools = (config.tools ?? [])\n .map((tool) => tool.name)\n .sort()\n .join(\"+\");\n\n const base = `anon_${sanitize(provider)}_${sanitize(model)}`;\n return tools ? `${base}_${sanitize(tools, { keepPlus: true })}` : base;\n}\n\nfunction sanitize(value: string, opts: { keepPlus?: boolean } = {}): string {\n const allowed = opts.keepPlus ? /[^a-zA-Z0-9._+-]/g : /[^a-zA-Z0-9._-]/g;\n return value.replace(allowed, \"-\");\n}\n\n/**\n * Authoring-time check on the middleware array. Throws an\n * `AgentExecutionError` with `context: { authoring: true }` the\n * moment an invalid entry is found — the agent factory surface is\n * where config bugs should surface, not ten trips into a run.\n *\n * Validates:\n * - Every entry is a non-null object with a non-empty string `name`.\n * - No two entries share the same `name` (would silently collide on\n * `ctx.state` keys and produce impossible-to-debug behavior).\n *\n * Does NOT validate that hook maps contain callable functions —\n * that would catch late-binding bugs but also reject legitimate\n * patterns like `before` being conditionally `undefined`. Runtime\n * dispatch handles missing hooks safely.\n */\nfunction validateMiddleware(middleware: ReadonlyArray<unknown> | undefined): void {\n if (!middleware || middleware.length === 0) {\n return;\n }\n\n const seen = new Set<string>();\n\n for (let index = 0; index < middleware.length; index++) {\n const entry = middleware[index];\n\n if (!entry || typeof entry !== \"object\") {\n throw new AgentExecutionError(\n `middleware[${index}] must be an object; received ${entry === null ? \"null\" : typeof entry}`,\n { context: { authoring: true, index } },\n );\n }\n\n const name = (entry as { name?: unknown }).name;\n\n if (typeof name !== \"string\" || name.length === 0) {\n throw new AgentExecutionError(`middleware[${index}] must have a non-empty string \"name\"`, {\n context: { authoring: true, index },\n });\n }\n\n if (seen.has(name)) {\n throw new AgentExecutionError(\n `duplicate middleware name \"${name}\" — each middleware needs a unique name so ctx.state keys do not collide`,\n { context: { authoring: true, index, name } },\n );\n }\n\n seen.add(name);\n }\n}\n\n/**\n * Normalize the public `judge` flag (`boolean | JudgeConfig | undefined`)\n * into a resolved {@link JudgeConfig} or `undefined` when the preset is\n * off. `true` ⇒ all defaults (`{}`); a partial config fills missing fields\n * from the defaults; `false` / absent ⇒ `undefined` (judge mode off).\n */\nfunction resolveJudgeConfig(judge: boolean | JudgeConfig | undefined): JudgeConfig | undefined {\n if (!judge) {\n return undefined;\n }\n\n const base = judge === true ? {} : judge;\n\n return {\n repairAttempts: base.repairAttempts ?? JUDGE_DEFAULT_REPAIR_ATTEMPTS,\n };\n}\n\n/**\n * Creates an executable AI agent from the given configuration.\n *\n * The agent runs a bounded trip loop: each trip calls the model, dispatches\n * any requested tool calls, then loops until the model stops or `maxTrips`\n * is reached. Each `execute()` / `stream()` call spawns a fresh internal\n * `Execution` instance — the factory itself holds no state across calls.\n *\n * `execute()` never throws — any error is attached to the returned result\n * under `result.error`. `stream()` surfaces errors both on the terminal\n * `error` stream event and via the `stream.result` promise.\n *\n * @example\n * const myAgent = agent({\n * model: openai.model({ name: \"gpt-4o\" }),\n * systemPrompt: \"You are a helpful assistant.\",\n * tools: [searchTool],\n * });\n *\n * const result = await myAgent.execute(\"What is the capital of Egypt?\");\n *\n * @example\n * const stream = myAgent.stream(\"Write a haiku about Cairo.\");\n *\n * for await (const event of stream) {\n * if (event.type === \"streaming\") process.stdout.write(event.delta);\n * }\n *\n * const result = await stream.result;\n */\nexport function agent<TOutput = unknown>(config: AgentConfig<TOutput>): AgentContract<TOutput> {\n // Authoring-time validation of the middleware array. Rejects two\n // classes of bug that would otherwise surface as opaque failures\n // mid-execution: (a) entries that aren't proper middleware\n // objects (null, undefined, missing `name`), and (b) two\n // middlewares sharing the same `name`, which would silently\n // collide on `ctx.state` keys. Fail fast, fail loud — per the\n // authoring-time rules in `domains/ai/conventions/errors.md`.\n validateMiddleware(config.middleware);\n\n // Resolve the agent's identity. Explicit `name` wins; otherwise we\n // synthesize a DETERMINISTIC fingerprint from the config's\n // identity-defining fields (model + provider + tool names). Same\n // config across process restarts produces the same synthetic name,\n // so workflow signature drift detection stays honest for agents\n // composed into workflows without explicit names.\n const isAnonymous = !config.name || typeof config.name !== \"string\";\n\n // Auto-adapt any raw executable (agent/workflow/supervisor) dropped\n // into `tools: []` into a `ToolContract` before the name is\n // synthesized — `synthesizeAgentName` reads `config.tools[].name`,\n // so the fingerprint must see the normalized entries. Built\n // `ToolContract`s (from `.asTool()` / `ai.tool()`) pass through\n // untouched, so this is a no-op for the existing surface.\n const tools = normalizeAgentTools(config.tools);\n const name = isAnonymous\n ? synthesizeAgentName({ ...config, tools })\n : (config.name as string);\n\n // Resolve the `skills` option to a `SkillsContract` ONCE, here, so every\n // `execute()` / `stream()` call reuses the same library (and its\n // `review`-gated saveSkill exposure). A raw `SkillsConfig` is handed to\n // `skills()`; an already-built contract passes through. Absent ⇒ no skills.\n const skillsLib = config.skills\n ? isSkillsContract(config.skills)\n ? config.skills\n : skills(config.skills)\n : undefined;\n\n // Drift fingerprint for durable resume — computed once over the\n // resolved identity (model + provider + sorted tool names + maxTrips +\n // output + version). Cheap FNV-1a; stamped on every snapshot and\n // compared on `resume()`. Computed unconditionally (whether or not\n // `durable` is set) so the value is stable and the resume path is free.\n const signature = computeAgentSignature({\n name: isAnonymous ? undefined : name,\n version: config.version,\n model: { name: config.model?.name, provider: config.model?.provider },\n tools,\n maxTrips: config.maxTrips,\n output: config.output,\n });\n\n const resolvedConfig: ResolvedAgentConfig<TOutput> = {\n ...config,\n name,\n tools,\n skillsLib,\n signature,\n };\n\n // Instance-level handlers registered via `.on()`. Stored here\n // (factory-scope) so every `execute()` / `stream()` call on this\n // agent sees the same set. Each event name gets its own Set so\n // `off()` can remove a specific handler without disturbing others.\n const instanceHandlers = new Map<\n keyof AgentEventMap,\n Set<AgentEventHandler<keyof AgentEventMap>>\n >();\n\n function on<K extends keyof AgentEventMap>(event: K, handler: AgentEventHandler<K>): () => void {\n const existing = instanceHandlers.get(event);\n const bucket = existing ?? new Set<AgentEventHandler<keyof AgentEventMap>>();\n\n if (!existing) {\n instanceHandlers.set(event, bucket);\n }\n\n bucket.add(handler as AgentEventHandler<keyof AgentEventMap>);\n\n return () => off(event, handler);\n }\n\n function off<K extends keyof AgentEventMap>(event: K, handler: AgentEventHandler<K>): void {\n const bucket = instanceHandlers.get(event);\n\n if (!bucket) {\n return;\n }\n\n bucket.delete(handler as AgentEventHandler<keyof AgentEventMap>);\n\n if (bucket.size === 0) {\n instanceHandlers.delete(event);\n }\n }\n\n const agentContract: AgentContractType<TOutput> = {\n name,\n isAnonymous,\n description: config.description,\n signature,\n async execute(\n input: string,\n options?: AgentExecuteOptions<TOutput>,\n ): Promise<AgentResult<TOutput>> {\n return new Execution<TOutput>(\n resolvedConfig,\n input,\n options,\n undefined,\n instanceHandlers,\n ).run();\n },\n\n stream(\n input: string,\n options?: AgentExecuteOptions<TOutput>,\n ): StreamContract<AgentResult<TOutput>> {\n const { controller, stream } = createAgentStream<AgentResult<TOutput>>();\n\n const execution = new Execution<TOutput>(\n resolvedConfig,\n input,\n options,\n controller,\n instanceHandlers,\n );\n\n void execution.run();\n\n return stream;\n },\n\n async resume(\n runId: string,\n options?: AgentResumeOptions<TOutput>,\n ): Promise<AgentResult<TOutput>> {\n // Load the persisted snapshot and run the drift check (throws\n // AgentDriftError on a structural mismatch unless `{ force: true }`).\n const snapshot = await loadAgentSnapshotForResume({\n durable: resolvedConfig.durable,\n agentName: name,\n signature,\n runId,\n options: options as AgentResumeOptions<unknown> | undefined,\n });\n\n // A completed / cancelled / failed snapshot already settled — there\n // is nothing left to run. Rebuild the final result from the stored\n // state and short-circuit so resume is idempotent (mirrors the\n // supervisor \"resume is a no-op and returns the final state\").\n // `running` is the only status the trip loop re-enters.\n const execution = new Execution<TOutput>(\n resolvedConfig,\n snapshot.input,\n { ...options, runId } as AgentExecuteOptions<TOutput>,\n undefined,\n instanceHandlers,\n snapshot,\n );\n\n return execution.run();\n },\n\n on,\n off,\n\n eval<TEval = TOutput>(options: EvalOptions<TEval>): Promise<EvalReport<TEval>> {\n return runEval<TEval>(agentContract as unknown as AgentContract<TEval>, options);\n },\n };\n\n return agentContract;\n}\n\n/**\n * Config for the `ai.agent.judge(...)` helper — every `AgentConfig` field\n * except `judge` itself (the helper sets it). Callers tune resilience by\n * passing a {@link JudgeConfig} as the second argument instead.\n */\nexport type JudgeAgentConfig<TOutput = unknown> = Omit<AgentConfig<TOutput>, \"judge\">;\n\n/**\n * Build a judge-safe agent — sugar for `agent({ ...config, judge })`.\n *\n * Use this for LLM-as-judge graders and verdict classifiers running on\n * models that may emit corrupted structured output (e.g. the Amazon Nova\n * family). The returned agent parses verdicts leniently (tolerates fenced\n * ` ```json ` blocks + surrounding prose), auto-enables a couple of repair\n * re-asks, and never throws on a parse miss — surfacing `result.error` with\n * `result.data` left undefined so a flaky judge degrades gracefully.\n *\n * See {@link AgentConfig.judge} for the full behavior + the resilience-over-\n * strictness trade-off.\n *\n * @param config - Any agent config (model, system prompt, output schema, …).\n * @param judge - Optional fine-tuning ({@link JudgeConfig}); defaults to `true`.\n *\n * @example\n * const grader = ai.agent.judge({\n * model: nova.model({ name: \"amazon.nova-pro-v1:0\" }),\n * systemPrompt: \"Grade the answer. Respond with JSON only.\",\n * output: verdictSchema,\n * });\n *\n * const result = await grader.execute(prompt);\n * if (result.error) {\n * // graceful default — the judge couldn't produce a clean verdict\n * }\n */\nfunction judgeAgent<TOutput = unknown>(\n config: JudgeAgentConfig<TOutput>,\n judge: JudgeConfig | boolean = true,\n): AgentContract<TOutput> {\n return agent<TOutput>({ ...config, judge });\n}\n\n// Attach the judge helper to the `agent` factory so it surfaces as\n// `ai.agent.judge(...)` (the `Ai` namespace exposes `agent` as\n// `typeof agent`, which now carries this property). Done as a typed\n// property assignment rather than `Object.assign` so the generic\n// signature is preserved for callers.\nagent.judge = judgeAgent;\n\n/**\n * Name → handler-set map shared between the `agent()` factory and its\n * per-call `Execution`. Each `.on()` registration mutates this map;\n * every `Execution` reads from the same reference so additions and\n * removals take effect mid-flight.\n */\ntype InstanceHandlerMap = Map<keyof AgentEventMap, Set<AgentEventHandler<keyof AgentEventMap>>>;\n\n/**\n * Per-call driver that owns the full lifecycle of a single\n * `agent.execute()` or `agent.stream()` invocation.\n *\n * **Role.** An `Execution` is the short-lived state container and phase\n * orchestrator for one agent run. The public `agent()` factory stays purely\n * functional — all mutable bookkeeping (trips, tool calls, usage totals,\n * message history, terminal error, parsed output) lives here so each call\n * gets a fresh, isolated instance.\n *\n * **Responsibility.**\n * - Owns: building the initial message list, driving the bounded trip loop,\n * dispatching tool calls safely, parsing the final output against the\n * caller's schema, emitting lifecycle events (to both the user handler\n * and, in stream mode, the `StreamController`), and producing the\n * `AgentResult`.\n * - Does NOT own: how the model produces responses (delegated to\n * `ModelContract.complete` / `ModelContract.stream`), how tools execute\n * (delegated to `ToolContract.invoke`), the async-queue plumbing for\n * streaming (delegated to `createAgentStream`), or any cross-call state\n * (factory-level concerns live in `agent()`).\n *\n * Streaming mode is opt-in via the fourth constructor argument: pass a\n * `StreamController` and every event is mirrored into it while model calls\n * are driven via `model.stream()` instead of `model.complete()`. The public\n * contract of `execute()` says it never throws — `Execution` enforces that\n * by funneling every unexpected error into `this.error` and returning a\n * well-formed result regardless of what went wrong.\n *\n * Not exported — consumers interact only with the `agent()` factory (see\n * §4.2 of code-style.md — \"per-call execution state across phases\").\n *\n * @example\n * // Non-streaming — inside agent.execute():\n * const result = await new Execution(config, input, options).run();\n *\n * @example\n * // Streaming — inside agent.stream():\n * const { controller, stream } = createAgentStream();\n * void new Execution(config, input, options, controller).run();\n * return stream;\n */\nclass Execution<TOutput> {\n private readonly trips: LLMTrip[] = [];\n private readonly toolCalls: ToolCall[] = [];\n private readonly usage: Usage = { input: 0, output: 0, total: 0 };\n private readonly messages: Message[] = [];\n /** Resolved system-prompt text sent to the model, captured for the report. */\n private systemPrompt?: string;\n /**\n * Registry name of the named `SystemPromptContract` this run resolved, when\n * the prompt carried a `meta.name`. Stamped onto the report so observers can\n * attribute the run to a specific registered prompt. Absent for raw-string,\n * anonymous-contract, or absent prompts.\n */\n private promptName?: string;\n /** Registry version label paired with {@link Execution.promptName}. */\n private promptVersion?: string;\n private readonly maxTrips: number;\n private readonly startedAt: Date;\n private readonly start = performance.now();\n /**\n * Stable run id. A caller-supplied `options.runId` wins (load-bearing\n * for durable resume — the snapshot key must stay constant across the\n * crash); otherwise a fresh id is generated. When `resumeFrom` is set\n * its `runId` is authoritative so the resumed run writes back to the\n * same key.\n */\n private readonly runId: string;\n private readonly logger: Logger = log;\n /**\n * Event names whose handler already threw once this run — so the\n * isolate-but-surface warning for a broken handler fires at most once\n * per event type, never spamming the log on a hot event (token\n * deltas, tool calls). See {@link surfaceHandlerError} (C5).\n */\n private readonly warnedHandlerEvents = new Set<string>();\n private readonly middleware: ReadonlyArray<\n NonNullable<AgentConfig<TOutput>[\"middleware\"]>[number]\n >;\n private readonly middlewareState: MiddlewareState = new Map();\n /**\n * The agent's own tools plus this run's skill tools (`loadSkill`, and\n * `saveSkill` when a review gate is configured). Built once per execution\n * because `loadSkillTool` closes over a per-run counter enforcing\n * `maxLoadsPerRun` — one tool instance per run = one budget per run. When\n * no skills library is attached this is just `config.tools`.\n */\n private readonly effectiveTools: ToolContract<unknown, unknown>[];\n\n private error?: AIError;\n private data?: TOutput;\n private responseSchema?: Record<string, unknown>;\n /**\n * Resolved judge-safe preset for this run, or `undefined` when the\n * `judge` flag is off. When set, output parsing is lenient (tolerates\n * fenced blocks + surrounding prose) and repair auto-defaults to the\n * configured attempt count.\n */\n private readonly judgeConfig?: JudgeConfig;\n\n public constructor(\n private readonly config: ResolvedAgentConfig<TOutput>,\n private readonly input: string,\n private readonly options?: AgentExecuteOptions<TOutput>,\n private readonly streamController?: StreamController<AgentResult<TOutput>>,\n private readonly instanceHandlers?: InstanceHandlerMap,\n private readonly resumeFrom?: AgentSnapshot,\n ) {\n this.maxTrips = config.maxTrips ?? 10;\n this.middleware = config.middleware ?? [];\n this.judgeConfig = resolveJudgeConfig(config.judge);\n\n // Resolve the run id: a resumed run reuses the snapshot's key so it\n // writes back to the same record; otherwise a caller-supplied\n // `options.runId` wins (durable callers pass a stable key), else a\n // fresh id is generated. `startedAt` likewise restores from the\n // snapshot so the resumed report spans the whole run, not just the tail.\n this.runId = resumeFrom?.runId ?? options?.runId ?? generateRunId(\"agent\");\n this.startedAt = resumeFrom ? new Date(resumeFrom.startedAt) : new Date();\n\n // Seed the accumulators from the snapshot on resume — re-hydrate the\n // assembled conversation, the completed trips, the dispatched tool\n // records, the running usage, and the resolved prompt/schema metadata.\n // Pushing directly into `this.trips` (rather than re-running `runTrip`)\n // is what keeps a resume from re-emitting completed trips' lifecycle\n // events or re-invoking their tools — the loop later starts at\n // `this.trips.length`. When `resumeFrom` is absent every accumulator\n // stays empty, so the non-durable path is byte-for-byte unchanged.\n if (resumeFrom) {\n this.messages.push(...resumeFrom.messages);\n this.trips.push(...resumeFrom.trips);\n this.toolCalls.push(...resumeFrom.toolCalls);\n mergeUsage(this.usage, resumeFrom.usage);\n this.systemPrompt = resumeFrom.systemPrompt;\n this.responseSchema = resumeFrom.responseSchema;\n this.promptName = resumeFrom.promptName;\n this.promptVersion = resumeFrom.promptVersion;\n }\n\n // Build this run's skill tools once with this run's id so the\n // per-run `maxLoadsPerRun` counter (closed over inside `loadSkillTool`)\n // is scoped to exactly this execution. `tools(runId)` already returns\n // `loadSkill` always and `saveSkill` only when a review gate is wired,\n // so no special-casing is needed here. `normalizeAgentTools` is a\n // passthrough for already-built `ToolContract`s — called for uniformity.\n const skillTools = config.skillsLib\n ? normalizeAgentTools(config.skillsLib.tools(this.runId)) ?? []\n : [];\n\n this.effectiveTools = [...(config.tools ?? []), ...skillTools];\n }\n\n /**\n * Base middleware context shared by every level. `state` is the\n * single mutable bag threaded through `execute`, `trip`, and `tool`\n * hooks for the lifetime of this execution — fresh per `execute()`\n * call, never reused across runs.\n */\n private buildExecuteContext(): MiddlewareExecuteContext {\n return {\n agent: {\n name: this.config.name ?? this.config.model.name,\n isAnonymous: !this.config.name,\n },\n model: {\n name: this.config.model.name,\n provider: this.config.model.provider,\n },\n input: this.input,\n options: this.options as AgentExecuteOptions<unknown> | undefined,\n state: this.middlewareState,\n signal: this.options?.signal,\n };\n }\n\n /**\n * Entry point for a single agent execution. Wraps the real work\n * (`runCore`) in the `execute`-level middleware pipeline, then\n * emits the terminal `agent.completed` / `agent.error` events and\n * closes the stream (if any) with the post-pipeline result — so\n * middleware that short-circuits or transforms the final result\n * still produces a well-formed public outcome.\n *\n * Must never throw: any error that escapes the pipeline is\n * converted into an `AgentResult` with `error` populated before\n * returning, preserving the `agent.execute()` public contract.\n */\n public async run(): Promise<AgentResult<TOutput>> {\n const context = this.buildExecuteContext();\n\n let result: AgentResult<TOutput>;\n\n try {\n result = (await runPipeline(\n this.middleware,\n \"execute\",\n context,\n () => this.runCore(),\n this.logger,\n )) as AgentResult<TOutput>;\n } catch (thrown) {\n this.error = this.toAIError(thrown);\n result = this.buildResult();\n }\n\n if (result.error) {\n this.emit(\"agent.error\", { error: result.error });\n }\n\n this.emit(\"agent.completed\", { result });\n\n // Fire the `onComplete` hook with a flat payload (runId +\n // durationMs pre-extracted) for audit-log consumers. Awaited but\n // errors swallowed so consumer bugs cannot crash the agent or\n // interfere with the result returned to the caller.\n await this.fireCompleteHook(result);\n\n // Route the finished report to any resolved observers (F1/F3).\n // Gated by `config.observe` + the global observe-all flag; a no-op\n // when nothing resolves. Observer errors are swallowed inside\n // `notifyObservers`, so they never break the run — mirroring the\n // onUsage / onComplete hook policy.\n await notifyObservers(this.config.observe, result.report);\n\n // Auto-nest into the enclosing orchestration run when this agent\n // executed inside a supervisor/orchestrator/team intent callback\n // (an ambient `RunFrame` is installed). Captures this report onto\n // the callback's `children[]` and relinks its lineage — so an\n // `agent.execute(...)` called directly inside a `run()` callback\n // shows up nested with its tools, instead of being lost as a\n // separate top-level execution. No-op for standalone runs.\n captureChildReport(result.report);\n\n this.streamController?.end(result);\n\n return result;\n }\n\n /**\n * Inner body wrapped by the `execute`-level pipeline. Drives the\n * full lifecycle — build messages → emit starting → run trip loop\n * → parse output → build result. Catches any unexpected throw and\n * funnels it into `this.error` so the returned result is always\n * well-formed; `execute`-level `after` hooks receive the result,\n * with `error` populated when things went wrong.\n */\n private async runCore(): Promise<AgentResult<TOutput>> {\n // Completed-run short-circuit. A resume of a snapshot whose run\n // already COMPLETED re-runs nothing — the stored trips ARE the\n // result. Rebuild the final result from the re-hydrated accumulators\n // and return, so resume is idempotent (mirrors the supervisor\n // \"resume is a no-op and returns the final state\"). A `failed` or\n // `cancelled` snapshot is intentionally NOT short-circuited — those\n // are exactly the runs a caller resumes to retry the remaining work\n // after fixing the cause, so they re-enter the trip loop below.\n if (this.resumeFrom && this.resumeFrom.status === \"completed\") {\n return this.rebuildResumedResult(this.resumeFrom);\n }\n\n try {\n // On resume the conversation is already hydrated from the snapshot,\n // so skip the (re)build of the initial messages AND the\n // `agent.starting` emit — those belong to the original run. A fresh\n // run (resumeFrom absent) takes the normal path unchanged.\n if (!this.resumeFrom) {\n await this.buildInitialMessages();\n\n this.emit(\"agent.starting\", { input: this.input });\n }\n\n await this.runTripLoop();\n\n const parseOutcome = await this.parseOutput();\n\n if (parseOutcome === \"failed\" && this.resolveRepairAttempts() > 0) {\n await this.runRepairLoop();\n }\n } catch (thrown) {\n this.error = this.toAIError(thrown);\n }\n\n // Terminal checkpoint — persist the final state so a completed-run\n // resume short-circuits to the stored result, then optionally drop\n // the snapshot when `deleteOnComplete` is set and the run succeeded.\n // No-op when `durable` is absent.\n await this.checkpoint(this.resolveSnapshotStatus());\n\n if (!this.error && this.config.durable?.deleteOnComplete) {\n const outcome = await deleteAgentSnapshot({\n durable: this.config.durable,\n runId: this.runId,\n });\n\n if (!outcome.ok) {\n this.logger.warn(LOG_MODULE, \"snapshot.delete.failed\", \"durable snapshot delete failed\", {\n runId: this.runId,\n error: outcome.error instanceof Error ? outcome.error.message : String(outcome.error),\n });\n }\n }\n\n return this.buildResult();\n }\n\n /**\n * Resolve the system prompt (string or `SystemPromptContract`), merge\n * placeholders from config + execute options, inject a structured-output\n * instruction when the caller wants typed output but the model can't\n * enforce it natively, prepend any conversation history, and append the\n * user input. Produces the initial `messages` array the first trip sends\n * to the model. Runs exactly once per execution.\n */\n private async buildInitialMessages(): Promise<void> {\n const { messages, responseSchema, systemPrompt, promptName, promptVersion } =\n await buildAgentInputMessages({\n config: this.config,\n input: this.input,\n options: this.options,\n });\n this.messages.push(...messages);\n this.responseSchema = responseSchema;\n this.systemPrompt = systemPrompt;\n this.promptName = promptName;\n this.promptVersion = promptVersion;\n\n await this.injectSkills();\n }\n\n /**\n * Prepend the skills library's contribution to the system prompt — the\n * always-injected metadata catalog first, then (only under `inject`) the\n * preloaded skill bodies, then the developer's resolved system prompt.\n * Never replaces the developer prompt.\n *\n * No-op when no skills library is attached. `catalogPrompt` returns `\"\"`\n * when nothing is in scope and `preload` returns `[]` when `inject` is\n * omitted (the default), so the prepend is a no-op in those cases too.\n *\n * Awaited inside `buildInitialMessages`, which runs inside `runCore`'s\n * try/catch — a source/embedder failure funnels into `this.error` like\n * any other build failure, no new error handling needed.\n */\n private async injectSkills(): Promise<void> {\n const lib = this.config.skillsLib;\n\n if (!lib) {\n return;\n }\n\n const catalogBlock = await lib.catalogPrompt(this.input);\n const preloaded = await lib.preload(this.input);\n\n const blocks: string[] = [];\n\n if (catalogBlock) {\n blocks.push(catalogBlock);\n }\n\n for (const record of preloaded) {\n if (record.body) {\n blocks.push(record.body);\n }\n }\n\n if (blocks.length === 0) {\n return;\n }\n\n const prefix = blocks.join(\"\\n\\n\");\n\n // Merge in front of the developer's resolved system prompt (captured in\n // `this.systemPrompt` and mirrored as the leading `role: \"system\"`\n // message). When the agent had no system prompt, the skills prefix\n // becomes the system message.\n const merged = this.systemPrompt ? `${prefix}\\n\\n${this.systemPrompt}` : prefix;\n\n this.systemPrompt = merged;\n\n const firstMessage = this.messages[0];\n\n if (firstMessage?.role === \"system\") {\n firstMessage.content = merged;\n } else {\n this.messages.unshift({ role: \"system\", content: merged });\n }\n }\n\n /**\n * Drive sequential trips up to `maxTrips`. Each trip may stop the loop\n * naturally (model returned a non-tool-call finish), abort it (model\n * threw), or continue it (model requested tools). When the loop exits\n * after the cap without a natural stop, records a \"Max trips exceeded\"\n * error so the caller can distinguish runaway tool loops from a real result.\n */\n private async runTripLoop(): Promise<void> {\n // Start at the resumed offset, not 0. On a fresh run `this.trips`\n // is empty so this is `0` and the loop behaves exactly as before; on\n // a resume the already-settled trips are skipped entirely — their\n // model calls and tool dispatches are never re-issued.\n for (let tripIndex = this.trips.length; tripIndex < this.maxTrips; tripIndex++) {\n if (this.options?.signal?.aborted) {\n this.error = this.makeCancelledError();\n return;\n }\n\n const tripInput = tripIndex === 0 ? this.input : \"[tool results]\";\n const outcome = await this.runTrip(tripIndex, tripInput);\n\n if (outcome === \"error\" || outcome === \"stop\") {\n return;\n }\n }\n\n const lastTrip = this.trips[this.trips.length - 1];\n\n if (lastTrip?.finishReason === \"tool_calls\") {\n this.error = new AgentMaxTripsError(\"Max trips exceeded\", {\n maxTrips: this.maxTrips,\n });\n }\n }\n\n /**\n * Execute one round-trip to the model. Aggregates usage into the running\n * total, dispatches any requested tool calls, appends the assistant +\n * tool-result messages for the next trip, and records an `LLMTrip`.\n * Returns an outcome that tells `runTripLoop` whether to continue, stop,\n * or abort.\n */\n private async runTrip(\n tripIndex: number,\n tripInput: string,\n ): Promise<\"continue\" | \"stop\" | \"error\"> {\n this.emit(\"agent.trip.started\", { tripIndex, input: tripInput });\n\n const tripStartedAt = new Date();\n const tripStart = performance.now();\n\n let response: ModelResponse;\n\n try {\n response = await this.runTripThroughPipeline(tripIndex);\n } catch (thrown) {\n this.error = this.toAIError(thrown);\n\n const failedTrip: LLMTrip = {\n index: tripIndex,\n input: tripInput,\n output: \"\",\n finishReason: \"error\",\n startedAt: tripStartedAt.toISOString(),\n endedAt: new Date().toISOString(),\n duration: performance.now() - tripStart,\n usage: { input: 0, output: 0, total: 0 },\n error: this.error,\n };\n\n this.trips.push(failedTrip);\n\n this.emit(\"agent.trip.completed\", { trip: failedTrip });\n this.emit(\"agent.error\", { error: this.error });\n\n // Persist the failed trip too, so a resume sees it in the ledger\n // and the terminal checkpoint records the run as `failed`. The\n // trip's model call already threw — there is no tool side effect to\n // double-count here. No-op when `durable` is absent.\n await this.checkpoint(\"failed\");\n\n return \"error\";\n }\n\n // Attach per-trip cost breakdown using the model's pricing table\n // (when configured). Done at the framework boundary so stored trip\n // records carry historical cost — Panoptic and other archive\n // consumers never re-derive against today's pricing, and the\n // input/output/cached split stays queryable without joining to a\n // pricing table at all.\n if (response.usage.cost === undefined) {\n response.usage.cost = computeCost(response.usage, this.config.model.pricing);\n }\n\n // Roll the trip into the agent total via the shared all-channel merge\n // (was missing reasoningTokens / cacheWriteTokens). `response.usage.cost`\n // is computed just above, so the cost lane merges identically.\n mergeUsage(this.usage, response.usage);\n\n // Fire the `onUsage` hook with a flat, pre-packaged payload so\n // cost-ledger code receives stable identity (runId, model+provider)\n // without joining from elsewhere. Awaited but errors swallowed.\n await this.fireUsageHook(tripIndex, response.usage);\n\n const isToolCallTrip =\n response.finishReason === \"tool_calls\" &&\n response.toolCalls !== undefined &&\n response.toolCalls.length > 0;\n\n const tripToolCalls: ToolCall[] = [];\n\n if (isToolCallTrip) {\n this.messages.push({\n role: \"assistant\",\n content: response.content,\n toolCalls: response.toolCalls,\n });\n\n for (const toolCallRequest of response.toolCalls!) {\n const record = await this.dispatchToolCall(toolCallRequest, tripIndex);\n\n tripToolCalls.push(record);\n }\n }\n\n const trip: LLMTrip = {\n index: tripIndex,\n input: tripInput,\n output: response.content,\n finishReason: response.finishReason,\n startedAt: tripStartedAt.toISOString(),\n endedAt: new Date().toISOString(),\n duration: performance.now() - tripStart,\n usage: response.usage,\n toolCalls: tripToolCalls.length > 0 ? tripToolCalls : undefined,\n };\n\n this.trips.push(trip);\n\n this.emit(\"agent.trip.completed\", { trip });\n\n // Per-trip durable checkpoint. Sits AFTER the trip push + the\n // `agent.trip.completed` emit and AFTER every tool this trip\n // requested has been dispatched (the block above) — the only point\n // where `messages`, `trips`, `toolCalls`, and `usage` are mutually\n // consistent. Swallow-and-log: a failed checkpoint never aborts the\n // run, it only loses resume-ability from here. No-op when `durable`\n // is absent.\n await this.checkpoint(\"running\");\n\n if (!isToolCallTrip) {\n return \"stop\";\n }\n\n // Terminate the trip loop when EVERY tool call this trip is\n // `mode: \"silent\"`. Silent tools don't feed their result back\n // to the model — the prose the model streamed alongside the\n // tool call IS the final reply. The \"all\" rule is load-bearing:\n // if any feedback tool was called too, its result still needs\n // to round-trip, so we must continue.\n //\n // Composite (`asTool`-wrapped) tools never set `mode: \"silent\"`\n // in v1 — silent-composite mechanics are deferred per plan\n // 2026-05-07-silent-tools.md (Q4). They behave as feedback.\n const allSilent = response.toolCalls!.every((request) => {\n const registered = this.effectiveTools.find((tool) => tool.name === request.name);\n return registered?.mode === \"silent\";\n });\n\n return allSilent ? \"stop\" : \"continue\";\n }\n\n /**\n * Route `getModelResponse` through the `trip`-level middleware\n * pipeline. `trip.before` hooks can short-circuit the trip by\n * returning a synthetic `ModelResponse` (semantic cache hit).\n * `trip.after` hooks can transform the response before the trip\n * record is built or any tool calls are dispatched. `trip.onError`\n * hooks can recover from provider failures (fallback chain).\n */\n private async runTripThroughPipeline(tripIndex: number): Promise<ModelResponse> {\n const context: MiddlewareTripContext = {\n ...this.buildExecuteContext(),\n tripIndex,\n messages: this.messages,\n };\n\n return (await runPipeline(\n this.middleware,\n \"trip\",\n context,\n () => this.getModelResponse(tripIndex),\n this.logger,\n )) as ModelResponse;\n }\n\n /**\n * Produce the `ModelResponse` for the current trip. In non-streaming\n * mode, delegates straight to `model.complete()`. In streaming mode,\n * drains `model.stream()` while emitting `streaming` events per delta\n * and accumulates the chunks into the same `ModelResponse` shape, so the\n * rest of the trip pipeline (tool dispatch, trip record, usage\n * aggregation) stays identical between the two modes.\n */\n private async getModelResponse(tripIndex: number): Promise<ModelResponse> {\n const callOptions = {\n ...this.config.modelOptions,\n tools: this.effectiveTools,\n ...(this.responseSchema ? { responseSchema: this.responseSchema } : {}),\n ...(this.options?.signal ? { signal: this.options.signal } : {}),\n };\n\n if (!this.streamController) {\n return this.config.model.complete(this.messages, callOptions);\n }\n\n let content = \"\";\n let finishReason: FinishReason = \"stop\";\n let usage: Usage = { input: 0, output: 0, total: 0 };\n const toolCalls: ModelToolCallRequest[] = [];\n const recoveredCalls: ModelToolCallRequest[] = [];\n\n const guardConfig = this.resolveStreamingToolGuard();\n const guard = guardConfig\n ? new JsonStreamGuard({\n tools: this.effectiveTools as ReadonlyArray<ToolContract<unknown, unknown>>,\n maxBufferBytes: guardConfig.maxBufferBytes,\n onSafeDelta: (delta) => {\n content += delta;\n\n this.emit(\"agent.trip.streaming\", { delta, tripIndex });\n },\n onRecoveredCall: (request) => {\n recoveredCalls.push(request);\n },\n })\n : undefined;\n\n for await (const chunk of this.config.model.stream(this.messages, callOptions)) {\n // Mid-stream abort — break out cleanly instead of continuing to\n // consume the iterator. The underlying fetch is already\n // cancelled via `signal` forwarded in callOptions; this covers\n // adapters that don't honor signal natively and keeps mock\n // models consistent under cancellation tests.\n if (this.options?.signal?.aborted) {\n throw this.makeCancelledError();\n }\n\n if (chunk.type === \"delta\") {\n if (guard) {\n await guard.feed(chunk.content);\n } else {\n content += chunk.content;\n\n this.emit(\"agent.trip.streaming\", { delta: chunk.content, tripIndex });\n }\n\n continue;\n }\n\n if (chunk.type === \"tool-call\") {\n toolCalls.push({\n id: chunk.id,\n name: chunk.name,\n input: chunk.input,\n ...(chunk.providerMetadata ? { providerMetadata: chunk.providerMetadata } : {}),\n });\n\n continue;\n }\n\n finishReason = chunk.finishReason;\n usage = chunk.usage;\n }\n\n if (guard) {\n await guard.finalize();\n }\n\n // Dedupe synthesized calls against real ones the provider streamed\n // structurally — the model occasionally emits BOTH channels for\n // the same call (real tool-call chunk + narrated JSON envelope).\n // Real wins; the synthesized duplicate is dropped so dispatch\n // doesn't run twice. See plan 2026-05-22 §Q5.\n const dedupedRecovered = recoveredCalls.filter(\n (recovered) => !isDuplicateToolCall(recovered, toolCalls),\n );\n\n const mergedToolCalls = [...toolCalls, ...dedupedRecovered];\n\n // When the guard recovered any calls but the model reported a\n // natural `\"stop\"`, override to `\"tool_calls\"` so the agent's\n // dispatch loop (`runTrip` → `isToolCallTrip`) actually fires.\n // Without this the guard silently suppresses the leaked JSON but\n // never dispatches the real action — chips never render.\n const resolvedFinishReason: FinishReason =\n dedupedRecovered.length > 0 && finishReason === \"stop\" ? \"tool_calls\" : finishReason;\n\n return {\n content,\n finishReason: resolvedFinishReason,\n usage,\n toolCalls: mergedToolCalls.length > 0 ? mergedToolCalls : undefined,\n };\n }\n\n /**\n * Resolve the effective `streamingToolGuard` for this trip.\n * Per-call options win over the agent-level config when the key is\n * explicitly present on options (including the explicit `undefined`\n * \"disable for this call\" form). Returns `undefined` when no guard\n * should run.\n */\n private resolveStreamingToolGuard(): StreamingToolGuardConfig | undefined {\n if (\n this.options !== undefined &&\n Object.prototype.hasOwnProperty.call(this.options, \"streamingToolGuard\")\n ) {\n return this.options.streamingToolGuard;\n }\n\n return this.config.streamingToolGuard;\n }\n\n /**\n * Dispatch a single tool call requested by the model. Looks up the tool\n * by name, invokes it via the safe `ToolContract.invoke` entry, pushes a\n * matching tool-result message into `this.messages` so the next trip can\n * see it, and emits the right lifecycle event (`tool-called` on success,\n * `tool-calling-failed` when the tool is unregistered or invoke returned\n * an error). Never throws — always returns a `ToolCall` record.\n */\n private async dispatchToolCall(\n toolCallRequest: ModelToolCallRequest,\n tripIndex: number,\n ): Promise<ToolCall> {\n const registeredTool = this.effectiveTools.find((tool) => tool.name === toolCallRequest.name);\n\n if (!registeredTool) {\n const error = new AgentExecutionError(`Tool not registered: ${toolCallRequest.name}`, {\n context: { toolName: toolCallRequest.name, tripIndex },\n });\n\n const nowIso = new Date().toISOString();\n\n const record: ToolCall = {\n runId: generateRunId(\"tool\"),\n rootRunId: this.runId,\n name: toolCallRequest.name,\n type: \"tool\",\n status: \"failed\",\n startedAt: nowIso,\n endedAt: nowIso,\n duration: 0,\n usage: { input: 0, output: 0, total: 0 },\n children: [],\n tripIndex,\n input: toolCallRequest.input,\n error,\n ...(toolCallRequest.recoveredFrom ? { recoveredFrom: toolCallRequest.recoveredFrom } : {}),\n };\n\n this.toolCalls.push(record);\n\n this.messages.push({\n role: \"tool\",\n toolCallId: toolCallRequest.id,\n content: JSON.stringify({ error: error.message }),\n });\n\n // Stub meta — there's no real tool to describe. Carries the\n // requested name for log correlation and an explanatory\n // description so consumers don't see an empty string.\n this.emit(\"agent.tool.failed\", {\n tool: {\n name: toolCallRequest.name,\n description: \"(unregistered tool — no description available)\",\n },\n input: toolCallRequest.input,\n error,\n tripIndex,\n });\n\n return record;\n }\n\n // Build the lightweight event meta once. Resolves `action` to a\n // string here so consumers receive plain data rather than having\n // to re-evaluate a callback on every event.\n const toolMeta: ToolEventMeta = {\n name: registeredTool.name,\n description: registeredTool.description,\n action: resolveToolAction(registeredTool, toolCallRequest.input),\n };\n\n this.emit(\"agent.tool.calling\", {\n tool: toolMeta,\n input: toolCallRequest.input,\n tripIndex,\n });\n\n const toolContext: MiddlewareToolContext = {\n ...this.buildExecuteContext(),\n tripIndex,\n messages: this.messages,\n tool: {\n name: registeredTool.name,\n description: registeredTool.description,\n mode: registeredTool.mode,\n },\n request: toolCallRequest,\n };\n\n // Thread the run's cancellation signal into the ctx handed to the\n // tool's `invoke`, so composite tools (asTool-wrapped agent/workflow/\n // supervisor) abort their nested run when the outer agent is cancelled\n // (C2). The caller's `toolCtx` (artifacts bag, etc.) is preserved — we\n // only add/override `signal`. With no signal configured we pass\n // `toolCtx` through unchanged so behavior stays byte-identical.\n const runSignal = this.options?.signal;\n const dispatchToolCtx: ToolContext | undefined = runSignal\n ? {\n artifacts: this.options?.toolCtx?.artifacts ?? {},\n ...this.options?.toolCtx,\n signal: runSignal,\n }\n : this.options?.toolCtx;\n\n let invokeResult: ToolInvokeResult<unknown>;\n\n try {\n invokeResult = (await runPipeline(\n this.middleware,\n \"tool\",\n toolContext,\n () => registeredTool.invoke(toolCallRequest.input, dispatchToolCtx),\n this.logger,\n )) as ToolInvokeResult<unknown>;\n } catch (thrown) {\n // A `tool`-level middleware hook threw. The real invoke never\n // throws (it funnels errors into `result.error`), so only a\n // middleware abort or a bug reaches this branch. Synthesize a\n // failed-invoke record so the tool-call trace stays consistent.\n const error = this.toAIError(thrown);\n const nowIso = new Date().toISOString();\n const emptyUsage: Usage = { input: 0, output: 0, total: 0 };\n\n const failedRunId = generateRunId(\"tool\");\n invokeResult = {\n error,\n usage: emptyUsage,\n report: {\n runId: failedRunId,\n rootRunId: failedRunId,\n name: registeredTool.name,\n version: registeredTool.version,\n type: \"tool\",\n status: \"failed\",\n startedAt: nowIso,\n endedAt: nowIso,\n duration: 0,\n usage: emptyUsage,\n children: [],\n },\n };\n }\n\n // The agent-level ToolCall record merges the tool's own invocation\n // report with agent-side enrichments (tripIndex, input, output,\n // error). When the underlying tool was an `asTool`-wrapped\n // composite, its inner report becomes the sole child of this\n // ToolCall — preserving the full nested tree while keeping this\n // node's own `type` as `\"tool\"` (from the agent's POV it *was* a\n // tool dispatch).\n const innerReport = invokeResult.report;\n const isComposite = innerReport.type !== \"tool\";\n\n const record: ToolCall = {\n runId: innerReport.runId,\n rootRunId: this.runId,\n name: toolCallRequest.name,\n version: registeredTool.version,\n type: \"tool\",\n status: innerReport.status,\n startedAt: innerReport.startedAt,\n endedAt: innerReport.endedAt,\n duration: innerReport.duration,\n usage: invokeResult.usage,\n children: isComposite ? [innerReport] : innerReport.children,\n tripIndex,\n input: toolCallRequest.input,\n output: invokeResult.data,\n error: invokeResult.error,\n ...(toolCallRequest.recoveredFrom ? { recoveredFrom: toolCallRequest.recoveredFrom } : {}),\n };\n\n this.toolCalls.push(record);\n\n // Roll child usage into the agent's accumulator. Leaf tools\n // contribute zero; `asTool`-wrapped composites contribute the\n // full cost of the inner agent/workflow/supervisor run.\n // All-channel merge so an asTool-wrapped composite that used prompt-cache\n // or reasoning tokens carries those counts into the parent total too.\n mergeUsage(this.usage, invokeResult.usage);\n\n this.messages.push({\n role: \"tool\",\n toolCallId: toolCallRequest.id,\n content: invokeResult.error\n ? JSON.stringify({ error: invokeResult.error.message })\n : JSON.stringify(invokeResult.data ?? null),\n });\n\n if (invokeResult.error) {\n this.emit(\"agent.tool.failed\", {\n tool: toolMeta,\n input: toolCallRequest.input,\n error: invokeResult.error,\n tripIndex,\n });\n } else {\n this.emit(\"agent.tool.called\", { ...record, tool: toolMeta });\n }\n\n return record;\n }\n\n /**\n * Parse the final trip output against the user-supplied schema (if any).\n * Failures populate `this.error` but never throw. Returns an outcome the\n * caller uses to decide whether self-repair is worth attempting:\n *\n * - `\"skipped\"` — no schema, or a prior trip-level error already set\n * `this.error` (model crash, max trips). Not repairable; the failure\n * isn't a parse problem the model can fix by re-asking.\n * - `\"failed\"` — schema present, output text either failed JSON.parse\n * or failed `~standard.validate`. Repairable via `runRepairLoop`.\n * - `\"success\"` — parsed and validated; `this.data` populated.\n *\n * Under the judge-safe preset (`judge: true`) the JSON extraction is\n * lenient — it tolerates fenced ` ```json ` blocks plus leading /\n * trailing prose by slicing the first balanced object / array out of the\n * response. Never throws regardless of preset: a parse / validation miss\n * sets `this.error` and returns `\"failed\"`, leaving `this.data`\n * undefined for the graceful-default path.\n */\n private async parseOutput(): Promise<\"success\" | \"failed\" | \"skipped\"> {\n const schema = this.options?.output ?? this.config.output;\n\n if (!schema || this.error) {\n return \"skipped\";\n }\n\n const finalTrip = this.trips[this.trips.length - 1];\n const text = finalTrip?.output ?? \"\";\n\n if (!text) {\n return \"skipped\";\n }\n\n // Under the judge-safe preset, parse leniently: tolerate fenced blocks\n // AND surrounding prose by slicing the first balanced JSON object /\n // array out of the response. Normal agents keep the strict\n // `extractJsonPayload` (fence-only) so genuine malformations still fail\n // loudly rather than being papered over.\n const payload = this.judgeConfig ? extractJsonLenient(text) : extractJsonPayload(text);\n const sentinel = Symbol(\"parse-failed\");\n const parsed = safeJsonParse<unknown>(payload, sentinel);\n\n if (parsed === sentinel) {\n this.error = new SchemaValidationError(\"Failed to parse model output as JSON\", {\n context: { text },\n });\n return \"failed\";\n }\n\n const validation = await (schema as StandardSchemaV1<TOutput>)[\"~standard\"].validate(parsed);\n\n if (validation.issues) {\n const summary = validation.issues.map((issue) => issue.message).join(\"; \");\n this.error = new SchemaValidationError(summary, {\n issues: validation.issues,\n });\n return \"failed\";\n }\n\n this.data = validation.value;\n return \"success\";\n }\n\n /**\n * Resolve how many repair re-asks this run should perform after a parse\n * failure. Per-call `options.repair` wins when explicitly set (preserving\n * the existing surface). Otherwise the judge-safe preset supplies its\n * default attempt count — so `judge: true` enables repair without the\n * caller also having to pass `repair`. Returns `0` when neither applies,\n * which leaves the historical \"no repair unless asked\" behavior intact.\n */\n private resolveRepairAttempts(): number {\n if (this.options?.repair) {\n return this.options.repair.maxAttempts ?? 1;\n }\n\n if (this.judgeConfig) {\n return this.judgeConfig.repairAttempts ?? JUDGE_DEFAULT_REPAIR_ATTEMPTS;\n }\n\n return 0;\n }\n\n /**\n * Opt-in self-repair loop for `output` schema failures. Triggered only\n * when repair attempts remain (`resolveRepairAttempts() > 0`) and\n * `parseOutput()` returned `\"failed\"`.\n *\n * Each attempt:\n * 1. Pushes the bad assistant response into `this.messages` (so the\n * model can see what it just produced).\n * 2. Pushes a corrective user message naming the validation/parse error.\n * 3. Runs another trip — counted against the same `maxTrips` cap as\n * normal trips so a stuck model can't loop forever.\n * 4. Re-parses. Stops on success, on a trip-level error, or when\n * either `maxAttempts` or `maxTrips` is exhausted.\n *\n * Resets `this.error` and `this.data` before each attempt so the final\n * outcome (success or last failure) is what surfaces to the caller.\n */\n private async runRepairLoop(): Promise<void> {\n const maxAttempts = this.resolveRepairAttempts();\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (this.trips.length >= this.maxTrips) {\n return;\n }\n\n const lastTrip = this.trips[this.trips.length - 1];\n const badResponse = lastTrip?.output ?? \"\";\n const failureReason = this.error?.message ?? \"unknown validation failure\";\n\n this.error = undefined;\n this.data = undefined;\n\n this.messages.push({ role: \"assistant\", content: badResponse });\n\n this.messages.push({\n role: \"user\",\n content: [\n `Your previous response failed validation: ${failureReason}.`,\n \"Respond again with valid JSON only — no prose, no markdown fences, no commentary.\",\n ].join(\" \"),\n });\n\n const tripIndex = this.trips.length;\n\n this.logger.warn(LOG_MODULE, \"repair.attempting\", \"retrying after validation failure\", {\n attempt: attempt + 1,\n maxAttempts,\n reason: failureReason,\n });\n\n const outcome = await this.runTrip(tripIndex, \"[repair attempt]\");\n\n if (outcome === \"error\") {\n return;\n }\n\n const parseOutcome = await this.parseOutput();\n\n if (parseOutcome === \"success\") {\n return;\n }\n }\n }\n\n /**\n * Build the final `AgentResult` snapshot from accumulated state\n * (trips, tool calls, data/error, usage, timing).\n *\n * Pure — no side effects. `run()` owns terminal event emission and\n * stream closure so the post-pipeline result (possibly transformed\n * or short-circuited by an `execute`-level middleware) is what\n * flows out to consumers and listeners.\n *\n * Trips, tool calls, status, and timing live under `report` so the\n * root stays focused on the four things callers reach for most:\n * `data`, `text`, `usage`, `error`.\n */\n private buildResult(): AgentResult<TOutput> {\n const finalTrip = this.trips[this.trips.length - 1];\n const endedAt = new Date();\n\n const agentName = this.config.name ?? this.config.model.name;\n const status: BaseReport[\"status\"] = this.error\n ? this.error instanceof AgentCancelledError\n ? \"cancelled\"\n : \"failed\"\n : \"completed\";\n\n const report = {\n runId: this.runId,\n rootRunId: this.runId,\n name: agentName,\n version: this.config.version,\n type: \"agent\" as const,\n status,\n // Stamp the terminal error onto the report so the observe path — which\n // sees only the report, never the result envelope — surfaces WHY a\n // failed/cancelled run ended. Spread conditionally so a completed run\n // stays byte-for-byte as before.\n ...(this.error ? { error: this.error } : {}),\n startedAt: this.startedAt.toISOString(),\n endedAt: endedAt.toISOString(),\n duration: performance.now() - this.start,\n usage: this.usage,\n children: this.toolCalls,\n model: {\n name: this.config.model.name,\n provider: this.config.model.provider,\n },\n trips: this.trips,\n systemPrompt: this.systemPrompt,\n // Prompt-version linkage. When the agent resolved a *named* prompt (one\n // registered in `ai.prompts`), stamp its `name` / `version` so observers\n // (e.g. Panoptic) can group/filter runs by the exact prompt version that\n // produced them. Spread conditionally so unnamed / raw-string prompts\n // leave the report byte-for-byte as before.\n ...(this.promptName\n ? { promptName: this.promptName, promptVersion: this.promptVersion }\n : {}),\n // Opt-in full-history capture (F2). When `captureMessages` is set,\n // normalize the real assembled turn array (assistant turns with\n // toolCalls + tool-result turns) onto the report. Off ⇒ field\n // absent, so the report is byte-for-byte as before.\n ...(this.config.captureMessages\n ? { messages: this.captureMessages() }\n : {}),\n };\n\n // Stamp lineage on the assembled tree exactly once per run.\n // Rewrites any inner self-roots from composite children to this\n // run's id, stamps `reportSchemaVersion` on the root, and\n // propagates `sessionId` to every node.\n stampReportLineage(report, {\n rootRunId: this.runId,\n sessionId: this.options?.sessionId,\n });\n\n return {\n type: \"agent\",\n data: this.data,\n text: finalTrip?.output,\n report,\n usage: this.usage,\n error: this.error,\n };\n }\n\n /**\n * Map the run's terminal outcome to the persisted snapshot status.\n * A cancelled error reads as `\"cancelled\"`, any other error as\n * `\"failed\"`, otherwise `\"completed\"`. Mirrors the report-status\n * mapping in {@link buildResult}.\n */\n private resolveSnapshotStatus(): AgentSnapshotStatus {\n if (!this.error) {\n return \"completed\";\n }\n\n return this.error instanceof AgentCancelledError ? \"cancelled\" : \"failed\";\n }\n\n /**\n * Build and persist an {@link AgentSnapshot} from the current\n * accumulators. The per-trip and terminal checkpoints both route\n * through here. Reuses {@link captureMessages} to normalize the live\n * `Message[]` into JSON-safe form so the snapshot round-trips through\n * any store backend.\n *\n * No-op (returns immediately) when `durable` is absent — the common\n * non-durable path stays free. A failed persist is logged and\n * swallowed (never aborts the run), matching the supervisor / workflow\n * checkpoint policy.\n */\n private async checkpoint(status: AgentSnapshotStatus): Promise<void> {\n if (!this.config.durable) {\n return;\n }\n\n const outcome = await persistAgentSnapshot({\n durable: this.config.durable,\n runId: this.runId,\n agentName: this.config.name ?? this.config.model.name,\n signature: this.config.signature,\n version: this.config.version,\n input: this.input,\n systemPrompt: this.systemPrompt,\n responseSchema: this.responseSchema,\n promptName: this.promptName,\n promptVersion: this.promptVersion,\n messages: this.captureMessages() as unknown as Message[],\n trips: this.trips,\n toolCalls: this.toolCalls,\n usage: this.usage,\n status,\n startedAt: this.startedAt.toISOString(),\n });\n\n if (!outcome.ok) {\n this.logger.warn(LOG_MODULE, \"snapshot.persist.failed\", \"durable snapshot persist failed\", {\n runId: this.runId,\n status,\n error: outcome.error instanceof Error ? outcome.error.message : String(outcome.error),\n });\n }\n }\n\n /**\n * Rebuild the final {@link AgentResult} from a COMPLETED snapshot\n * WITHOUT re-running anything. Used by the completed-run resume\n * short-circuit: the persisted trips / tool calls / usage are the\n * authoritative outcome, so a resume of a settled run re-returns that\n * outcome idempotently. Re-derives `this.data` from the final trip\n * output against the schema (cheap, no model call) so the rebuilt\n * result carries the same structured payload the original produced.\n *\n * Only reached for a `completed` snapshot — `failed` / `cancelled`\n * snapshots re-enter the trip loop to retry the remaining work instead.\n */\n private async rebuildResumedResult(_snapshot: AgentSnapshot): Promise<AgentResult<TOutput>> {\n await this.parseOutput();\n\n return this.buildResult();\n }\n\n /**\n * Normalize the accumulated runtime `Message[]` into the JSON-safe\n * {@link CapturedMessage}[] persisted on `AgentReport.messages` (F2).\n * Flattens `ContentPart[]` content to a string, and forwards\n * `toolCalls` (assistant turns) / `toolCallId` (tool-result turns)\n * only when present so the captured shape stays lean. Called only when\n * `captureMessages` is enabled.\n */\n private captureMessages(): CapturedMessage[] {\n return this.messages.map((message) => {\n const captured: CapturedMessage = {\n role: message.role,\n content:\n typeof message.content === \"string\"\n ? message.content\n : JSON.stringify(message.content),\n };\n\n if (message.toolCalls !== undefined) {\n captured.toolCalls = message.toolCalls;\n }\n\n if (message.toolCallId !== undefined) {\n captured.toolCallId = message.toolCallId;\n }\n\n return captured;\n });\n }\n\n /**\n * Normalize any thrown value into an `AIError`. `AIError` instances\n * pass through untouched; provider-adapter SDK errors are caught by\n * the adapter and already arrive typed, so this branch mainly\n * handles runtime crashes (TypeError, ReferenceError) inside\n * model.complete / model.stream and non-Error values (`throw \"bad\"`).\n */\n private toAIError(thrown: unknown): AIError {\n if (thrown instanceof AIError) {\n return thrown;\n }\n\n // Classify abort-flavored errors (DOMException \"AbortError\",\n // node-fetch's `FetchError` with name \"AbortError\", `ERR_CANCELED`\n // from the OpenAI SDK's axios-ish layer) as cancelled instead of\n // a generic exec failure so callers can route retries correctly.\n if (isAbortLike(thrown)) {\n return this.makeCancelledError();\n }\n\n const message = thrown instanceof Error ? thrown.message : String(thrown);\n\n return new AgentExecutionError(message, { cause: thrown });\n }\n\n /**\n * Build the typed cancelled error that both the trip-loop guard\n * and the mid-stream guard emit. Captures the abort reason when\n * one was supplied to `controller.abort(reason)` so logs and\n * telemetry can see what cancelled the run.\n */\n private makeCancelledError(): AgentCancelledError {\n const reason = this.options?.signal?.reason;\n const reasonText = reason === undefined ? \"\" : String(reason);\n\n return new AgentCancelledError(\"agent execution cancelled\", {\n cause: reason,\n cancelledAt: new Date().toISOString(),\n reason: reasonText,\n });\n }\n\n /**\n * Fire a single event through all three subscription tiers in order\n * — factory → instance → per-call — and mirror it into the\n * `StreamController` when streaming is active. A throwing user\n * handler must never crash the agent, so every dispatch is wrapped\n * in `safeCall`. Stream events are converted from the internal\n * `AgentEventMap` payload to the public `StreamEvent` shape because\n * some of them differ (e.g. the tool-called payload vs stream\n * event).\n */\n private emit<K extends keyof AgentEventMap>(\n event: K,\n payload: WithoutIdentity<AgentEventMap[K]>,\n ): void {\n // Inject run identity once, here, so every subscription tier and\n // the stream see it. `rootRunId === runId` for a standalone run;\n // nested propagation lands in a follow-up.\n const fullPayload = {\n ...payload,\n runId: this.runId,\n rootRunId: this.runId,\n } as AgentEventMap[K];\n\n this.logEvent(event, fullPayload);\n\n const onError = (error: unknown) => this.surfaceHandlerError(event, error);\n\n const factoryHandler = this.config.on?.[event] as AgentEventHandler<K> | undefined;\n\n if (factoryHandler) {\n safeCall(factoryHandler, fullPayload, onError);\n }\n\n const bucket = this.instanceHandlers?.get(event);\n\n if (bucket) {\n for (const handler of bucket) {\n safeCall(handler as AgentEventHandler<K>, fullPayload, onError);\n }\n }\n\n const perCallHandler = this.options?.on?.[event] as AgentEventHandler<K> | undefined;\n\n if (perCallHandler) {\n safeCall(perCallHandler, fullPayload, onError);\n }\n\n if (this.streamController) {\n const body = this.toStreamEvent(event, fullPayload);\n\n if (body) {\n this.streamController.push({\n runId: this.runId,\n rootRunId: this.runId,\n ...body,\n });\n }\n }\n }\n\n /**\n * Surface an isolated event-handler failure (C5). A throwing user\n * handler never crashes the agent — that isolation is preserved — but\n * total silence is the wrong default: a broken `on` handler would\n * otherwise disappear from production with no signal. Routed to the\n * structured logger (matching the `onUsage` / `onComplete` policy) and\n * warned at most once per event type so a hot event can't spam the log.\n */\n private surfaceHandlerError(event: keyof AgentEventMap, error: unknown): void {\n if (this.warnedHandlerEvents.has(event as string)) return;\n this.warnedHandlerEvents.add(event as string);\n\n this.logger.warn(LOG_MODULE, \"event.handler.error\", \"an event handler threw and was isolated\", {\n runId: this.runId,\n event: event as string,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n\n /**\n * Emit a structured log line for a lifecycle event. The action\n * string mirrors the event name with the `agent.` prefix stripped\n * (`agent.trip.started` → `trip.started`) so log grep filters and\n * event handlers read the same vocabulary. Level mapping follows\n * the convention documented on `@warlock.js/logger`'s `Logger`.\n */\n private logEvent<K extends keyof AgentEventMap>(event: K, payload: AgentEventMap[K]): void {\n const agentName = this.config.name || this.config.model.name;\n logAgentEvent(\n this.logger,\n {\n module: `${LOG_MODULE}.${agentName}`,\n maxTrips: this.maxTrips,\n modelName: this.config.model.name,\n totalUsage: this.usage,\n totalDurationMs: performance.now() - this.start,\n trips: this.trips,\n toolCalls: this.toolCalls,\n },\n event,\n payload,\n );\n }\n\n private toStreamEvent<K extends keyof AgentEventMap>(\n event: K,\n payload: AgentEventMap[K],\n ): StreamEventBody | undefined {\n return agentEventToStreamEvent(event, payload);\n }\n\n /**\n * Invoke the `onUsage` hook (when configured) with a flat payload\n * carrying stable identity. Awaits the handler so async ledger\n * writes complete before the next trip starts; swallows any throw\n * so consumer bugs cannot crash the agent. Sync handlers wrapped\n * via `Promise.resolve()` so the await is safe in either case.\n */\n private async fireUsageHook(tripIndex: number, tripUsage: Usage): Promise<void> {\n const handler = this.config.onUsage;\n if (!handler) return;\n\n const event: UsageEvent = {\n runId: this.runId,\n tripIndex,\n model: {\n name: this.config.model.name,\n provider: this.config.model.provider,\n },\n usage: { ...tripUsage },\n timestamp: new Date().toISOString(),\n };\n\n try {\n await Promise.resolve(handler(event));\n } catch (err) {\n this.logger.warn(LOG_MODULE, \"onUsage.hook.error\", \"onUsage handler threw\", {\n runId: this.runId,\n tripIndex,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n /**\n * Invoke the `onComplete` hook (when configured) once at the end\n * of every run. Receives the full `AgentResult` plus pre-extracted\n * `runId` and `durationMs`. Same swallow-and-log error policy as\n * `fireUsageHook`.\n */\n private async fireCompleteHook(result: AgentResult<TOutput>): Promise<void> {\n const handler = this.config.onComplete;\n if (!handler) return;\n\n const event: CompleteEvent<TOutput> = {\n result,\n runId: this.runId,\n durationMs: performance.now() - this.start,\n };\n\n try {\n await Promise.resolve(handler(event));\n } catch (err) {\n this.logger.warn(LOG_MODULE, \"onComplete.hook.error\", \"onComplete handler threw\", {\n runId: this.runId,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n}\n\n/**\n * Decide whether a guard-synthesized tool call duplicates a real one\n * the provider already streamed structurally. Match key is\n * `name + key-sorted JSON of input` so identical calls (regardless of\n * argument key order) collapse, but two legitimate calls to the same\n * tool with different inputs still both dispatch.\n */\nfunction isDuplicateToolCall(\n recovered: ModelToolCallRequest,\n realCalls: ReadonlyArray<ModelToolCallRequest>,\n): boolean {\n const recoveredKey = `${recovered.name}|${stableStringify(recovered.input)}`;\n\n for (const real of realCalls) {\n const realKey = `${real.name}|${stableStringify(real.input)}`;\n\n if (realKey === recoveredKey) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * `JSON.stringify` variant that sorts object keys at every nesting\n * level so structurally-equal inputs serialize to identical strings.\n * Used only for dedupe-key comparison; never surfaces to consumers.\n */\nfunction stableStringify(value: unknown): string {\n return JSON.stringify(value, (_key, val) => {\n if (val !== null && typeof val === \"object\" && !Array.isArray(val)) {\n const source = val as Record<string, unknown>;\n const sorted: Record<string, unknown> = {};\n\n for (const key of Object.keys(source).sort()) {\n sorted[key] = source[key];\n }\n\n return sorted;\n }\n\n return val;\n });\n}\n\n/**\n * Invoke a user-supplied event handler without letting exceptions\n * escape the agent. A throw is isolated (it never crashes the agent)\n * but no longer silent: the optional `onError` surfaces it — the agent\n * routes it to its structured logger, matching the swallow-and-log\n * policy of the `onUsage` / `onComplete` hooks (C5).\n */\nfunction safeCall<T>(\n handler: (payload: T) => void,\n payload: T,\n onError?: (error: unknown) => void,\n): void {\n try {\n handler(payload);\n } catch (error) {\n onError?.(error);\n }\n}\n\n/**\n * Resolve a tool's `action` declaration into a plain string for\n * inclusion in `ToolEventMeta`. Static strings pass through;\n * function-shaped actions are invoked with the model's raw,\n * pre-validation input (before `execute`'s schema validation runs).\n *\n * Defensive: if the user's callback throws, swallow and return\n * `undefined` rather than crashing the agent — UI strings are not\n * worth aborting an LLM dispatch over.\n */\nfunction resolveToolAction(\n tool: ToolContract<unknown, unknown>,\n input: unknown,\n): string | undefined {\n if (tool.action === undefined) return undefined;\n if (typeof tool.action === \"string\") return tool.action;\n try {\n return tool.action(input);\n } catch {\n return undefined;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"agent.mjs","names":[],"sources":["../../../../../../../ai/src/agent/agent.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { log, type Logger } from \"@warlock.js/logger\";\nimport type {\n AgentContract,\n AgentEventHandler,\n AgentEventMap,\n AgentExecuteOptions,\n AgentResult,\n BaseReport,\n CapturedMessage,\n CompleteEvent,\n FinishReason,\n LLMTrip,\n Message,\n MiddlewareExecuteContext,\n MiddlewareState,\n MiddlewareToolContext,\n MiddlewareTripContext,\n ModelResponse,\n ModelToolCallRequest,\n StreamContract,\n StreamEventBody,\n StreamingToolGuardConfig,\n ToolCall,\n ToolContext,\n ToolEventMeta,\n Usage,\n UsageEvent,\n WithoutIdentity,\n} from \"../contracts\";\nimport {\n AgentCancelledError,\n AgentExecutionError,\n AgentMaxTripsError,\n AIError,\n SchemaValidationError,\n} from \"../errors\";\nimport type { AgentContract as AgentContractType } from \"../contracts/agent/agent.contract\";\nimport type { AgentResumeOptions } from \"../contracts/agent/agent-options.type\";\nimport type { AgentSnapshot, AgentSnapshotStatus } from \"../contracts/agent/agent-snapshot.type\";\nimport type { EvalOptions, EvalReport } from \"../contracts/agent/eval.type\";\nimport { runEval } from \"../eval/eval-runner\";\nimport { runPipeline } from \"../middleware\";\nimport { notifyObservers } from \"../observe/resolve-observers\";\nimport { skills } from \"../skills\";\nimport type { SkillsContract } from \"../skills/contracts/skills.contract\";\nimport { normalizeAgentTools } from \"../tool/executable-as-tool\";\nimport type { ToolContract, ToolInvokeResult } from \"../tool/tool\";\nimport {\n captureChildReport,\n computeCost,\n extractJsonLenient,\n extractJsonPayload,\n generateRunId,\n mergeUsage,\n safeJsonParse,\n stampReportLineage,\n} from \"../utils\";\nimport type { AgentConfig } from \"./agent-config.type\";\nimport { JUDGE_DEFAULT_REPAIR_ATTEMPTS, type JudgeConfig } from \"./judge-config.type\";\nimport { buildAgentInputMessages } from \"./agent-input-builder\";\nimport { logAgentEvent } from \"./agent-log-event\";\nimport { createAgentStream, type StreamController } from \"./agent-stream\";\nimport { agentEventToStreamEvent } from \"./agent-to-stream-event\";\nimport { JsonStreamGuard } from \"./json-stream-guard\";\nimport { computeAgentSignature } from \"./signature\";\nimport {\n deleteAgentSnapshot,\n loadAgentSnapshotForResume,\n persistAgentSnapshot,\n} from \"./snapshot\";\n\nconst LOG_MODULE = \"ai.agent\";\n\n/**\n * Internal post-normalization view of an `AgentConfig`. The public\n * `tools` field accepts both built `ToolContract`s and raw executables\n * (`AgentToolEntry[]`); by the time the runtime sees the config every\n * entry has been adapted to a `ToolContract`, so `Execution` works\n * against this narrowed shape and never has to re-discriminate.\n */\ntype ResolvedAgentConfig<TOutput> = Omit<AgentConfig<TOutput>, \"tools\" | \"skills\"> & {\n tools?: ToolContract<unknown, unknown>[];\n /**\n * The skills library resolved once at factory time from the public\n * `skills` option (a {@link SkillsContract} or a raw `SkillsConfig`).\n * `undefined` when the agent has no skills attached — the execute path\n * then behaves byte-for-byte as today.\n */\n skillsLib?: SkillsContract;\n /**\n * Structural drift fingerprint computed once at factory time from the\n * agent's identity-defining fields (model + provider + sorted tool\n * names + maxTrips + output + version). Stamped on every durable\n * snapshot and compared on `resume()`. Always present so the resume\n * path never re-derives it.\n */\n signature: string;\n};\n\n/**\n * Duck-type a value as a {@link SkillsContract} (vs a raw `SkillsConfig`).\n * A contract exposes the agent-facing methods; a config is a plain spec.\n * Checking `catalogPrompt` is sufficient to discriminate the two shapes.\n */\nfunction isSkillsContract(value: unknown): value is SkillsContract {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as SkillsContract).catalogPrompt === \"function\"\n );\n}\n\n/**\n * Detect abort-flavored errors surfaced by SDK HTTP layers — the\n * DOM `AbortError`, axios `ERR_CANCELED`, node-fetch's own\n * `AbortError`. Used to classify them as cancellation rather than\n * generic agent-execution failures.\n */\nfunction isAbortLike(err: unknown): boolean {\n if (!err || typeof err !== \"object\") return false;\n\n const e = err as { name?: unknown; code?: unknown };\n\n return e.name === \"AbortError\" || e.code === \"ERR_CANCELED\" || e.code === \"ABORT_ERR\";\n}\n\n/**\n * Readable synthetic name for agents constructed without an explicit\n * `name`. Format: `anon_<provider>_<model>[_<tool1>+<tool2>+...]` —\n * deterministic (same config → same name across restarts) and\n * human-readable in logs / workflow snapshots.\n *\n * Keeps drift detection honest for the `ai.agent({ model })`\n * one-liner without punishing it with a hashed id nobody can read.\n */\nfunction synthesizeAgentName<T>(config: AgentConfig<T>): string {\n const provider = (config.model as unknown as { provider?: string })?.provider ?? \"unknown\";\n const model = config.model?.name ?? \"unknown\";\n const tools = (config.tools ?? [])\n .map((tool) => tool.name)\n .sort()\n .join(\"+\");\n\n const base = `anon_${sanitize(provider)}_${sanitize(model)}`;\n return tools ? `${base}_${sanitize(tools, { keepPlus: true })}` : base;\n}\n\nfunction sanitize(value: string, opts: { keepPlus?: boolean } = {}): string {\n const allowed = opts.keepPlus ? /[^a-zA-Z0-9._+-]/g : /[^a-zA-Z0-9._-]/g;\n return value.replace(allowed, \"-\");\n}\n\n/**\n * Authoring-time check on the middleware array. Throws an\n * `AgentExecutionError` with `context: { authoring: true }` the\n * moment an invalid entry is found — the agent factory surface is\n * where config bugs should surface, not ten trips into a run.\n *\n * Validates:\n * - Every entry is a non-null object with a non-empty string `name`.\n * - No two entries share the same `name` (would silently collide on\n * `ctx.state` keys and produce impossible-to-debug behavior).\n *\n * Does NOT validate that hook maps contain callable functions —\n * that would catch late-binding bugs but also reject legitimate\n * patterns like `before` being conditionally `undefined`. Runtime\n * dispatch handles missing hooks safely.\n */\nfunction validateMiddleware(middleware: ReadonlyArray<unknown> | undefined): void {\n if (!middleware || middleware.length === 0) {\n return;\n }\n\n const seen = new Set<string>();\n\n for (let index = 0; index < middleware.length; index++) {\n const entry = middleware[index];\n\n if (!entry || typeof entry !== \"object\") {\n throw new AgentExecutionError(\n `middleware[${index}] must be an object; received ${entry === null ? \"null\" : typeof entry}`,\n { context: { authoring: true, index } },\n );\n }\n\n const name = (entry as { name?: unknown }).name;\n\n if (typeof name !== \"string\" || name.length === 0) {\n throw new AgentExecutionError(`middleware[${index}] must have a non-empty string \"name\"`, {\n context: { authoring: true, index },\n });\n }\n\n if (seen.has(name)) {\n throw new AgentExecutionError(\n `duplicate middleware name \"${name}\" — each middleware needs a unique name so ctx.state keys do not collide`,\n { context: { authoring: true, index, name } },\n );\n }\n\n seen.add(name);\n }\n}\n\n/**\n * Normalize the public `judge` flag (`boolean | JudgeConfig | undefined`)\n * into a resolved {@link JudgeConfig} or `undefined` when the preset is\n * off. `true` ⇒ all defaults (`{}`); a partial config fills missing fields\n * from the defaults; `false` / absent ⇒ `undefined` (judge mode off).\n */\nfunction resolveJudgeConfig(judge: boolean | JudgeConfig | undefined): JudgeConfig | undefined {\n if (!judge) {\n return undefined;\n }\n\n const base = judge === true ? {} : judge;\n\n return {\n repairAttempts: base.repairAttempts ?? JUDGE_DEFAULT_REPAIR_ATTEMPTS,\n };\n}\n\n/**\n * Creates an executable AI agent from the given configuration.\n *\n * The agent runs a bounded trip loop: each trip calls the model, dispatches\n * any requested tool calls, then loops until the model stops or `maxTrips`\n * is reached. Each `execute()` / `stream()` call spawns a fresh internal\n * `Execution` instance — the factory itself holds no state across calls.\n *\n * `execute()` never throws — any error is attached to the returned result\n * under `result.error`. `stream()` surfaces errors both on the terminal\n * `error` stream event and via the `stream.result` promise.\n *\n * @example\n * const myAgent = agent({\n * model: openai.model({ name: \"gpt-4o\" }),\n * systemPrompt: \"You are a helpful assistant.\",\n * tools: [searchTool],\n * });\n *\n * const result = await myAgent.execute(\"What is the capital of Egypt?\");\n *\n * @example\n * const stream = myAgent.stream(\"Write a haiku about Cairo.\");\n *\n * for await (const event of stream) {\n * if (event.type === \"streaming\") process.stdout.write(event.delta);\n * }\n *\n * const result = await stream.result;\n */\nexport function agent<TOutput = unknown>(config: AgentConfig<TOutput>): AgentContract<TOutput> {\n // Authoring-time validation of the middleware array. Rejects two\n // classes of bug that would otherwise surface as opaque failures\n // mid-execution: (a) entries that aren't proper middleware\n // objects (null, undefined, missing `name`), and (b) two\n // middlewares sharing the same `name`, which would silently\n // collide on `ctx.state` keys. Fail fast, fail loud — per the\n // authoring-time rules in `domains/ai/conventions/errors.md`.\n validateMiddleware(config.middleware);\n\n // Resolve the agent's identity. Explicit `name` wins; otherwise we\n // synthesize a DETERMINISTIC fingerprint from the config's\n // identity-defining fields (model + provider + tool names). Same\n // config across process restarts produces the same synthetic name,\n // so workflow signature drift detection stays honest for agents\n // composed into workflows without explicit names.\n const isAnonymous = !config.name || typeof config.name !== \"string\";\n\n // Auto-adapt any raw executable (agent/workflow/supervisor) dropped\n // into `tools: []` into a `ToolContract` before the name is\n // synthesized — `synthesizeAgentName` reads `config.tools[].name`,\n // so the fingerprint must see the normalized entries. Built\n // `ToolContract`s (from `.asTool()` / `ai.tool()`) pass through\n // untouched, so this is a no-op for the existing surface.\n const tools = normalizeAgentTools(config.tools);\n const name = isAnonymous\n ? synthesizeAgentName({ ...config, tools })\n : (config.name as string);\n\n // Resolve the `skills` option to a `SkillsContract` ONCE, here, so every\n // `execute()` / `stream()` call reuses the same library (and its\n // `review`-gated saveSkill exposure). A raw `SkillsConfig` is handed to\n // `skills()`; an already-built contract passes through. Absent ⇒ no skills.\n const skillsLib = config.skills\n ? isSkillsContract(config.skills)\n ? config.skills\n : skills(config.skills)\n : undefined;\n\n // Drift fingerprint for durable resume — computed once over the\n // resolved identity (model + provider + sorted tool names + maxTrips +\n // output + version). Cheap FNV-1a; stamped on every snapshot and\n // compared on `resume()`. Computed unconditionally (whether or not\n // `durable` is set) so the value is stable and the resume path is free.\n const signature = computeAgentSignature({\n name: isAnonymous ? undefined : name,\n version: config.version,\n model: { name: config.model?.name, provider: config.model?.provider },\n tools,\n maxTrips: config.maxTrips,\n output: config.output,\n });\n\n const resolvedConfig: ResolvedAgentConfig<TOutput> = {\n ...config,\n name,\n tools,\n skillsLib,\n signature,\n };\n\n // Instance-level handlers registered via `.on()`. Stored here\n // (factory-scope) so every `execute()` / `stream()` call on this\n // agent sees the same set. Each event name gets its own Set so\n // `off()` can remove a specific handler without disturbing others.\n const instanceHandlers = new Map<\n keyof AgentEventMap,\n Set<AgentEventHandler<keyof AgentEventMap>>\n >();\n\n function on<K extends keyof AgentEventMap>(event: K, handler: AgentEventHandler<K>): () => void {\n const existing = instanceHandlers.get(event);\n const bucket = existing ?? new Set<AgentEventHandler<keyof AgentEventMap>>();\n\n if (!existing) {\n instanceHandlers.set(event, bucket);\n }\n\n bucket.add(handler as AgentEventHandler<keyof AgentEventMap>);\n\n return () => off(event, handler);\n }\n\n function off<K extends keyof AgentEventMap>(event: K, handler: AgentEventHandler<K>): void {\n const bucket = instanceHandlers.get(event);\n\n if (!bucket) {\n return;\n }\n\n bucket.delete(handler as AgentEventHandler<keyof AgentEventMap>);\n\n if (bucket.size === 0) {\n instanceHandlers.delete(event);\n }\n }\n\n const agentContract: AgentContractType<TOutput> = {\n name,\n isAnonymous,\n description: config.description,\n signature,\n async execute(\n input: string,\n options?: AgentExecuteOptions<TOutput>,\n ): Promise<AgentResult<TOutput>> {\n return new Execution<TOutput>(\n resolvedConfig,\n input,\n options,\n undefined,\n instanceHandlers,\n ).run();\n },\n\n stream(\n input: string,\n options?: AgentExecuteOptions<TOutput>,\n ): StreamContract<AgentResult<TOutput>> {\n const { controller, stream } = createAgentStream<AgentResult<TOutput>>();\n\n const execution = new Execution<TOutput>(\n resolvedConfig,\n input,\n options,\n controller,\n instanceHandlers,\n );\n\n void execution.run();\n\n return stream;\n },\n\n async resume(\n runId: string,\n options?: AgentResumeOptions<TOutput>,\n ): Promise<AgentResult<TOutput>> {\n // Load the persisted snapshot and run the drift check (throws\n // AgentDriftError on a structural mismatch unless `{ force: true }`).\n const snapshot = await loadAgentSnapshotForResume({\n durable: resolvedConfig.durable,\n agentName: name,\n signature,\n runId,\n options: options as AgentResumeOptions<unknown> | undefined,\n });\n\n // A completed / cancelled / failed snapshot already settled — there\n // is nothing left to run. Rebuild the final result from the stored\n // state and short-circuit so resume is idempotent (mirrors the\n // supervisor \"resume is a no-op and returns the final state\").\n // `running` is the only status the trip loop re-enters.\n const execution = new Execution<TOutput>(\n resolvedConfig,\n snapshot.input,\n { ...options, runId } as AgentExecuteOptions<TOutput>,\n undefined,\n instanceHandlers,\n snapshot,\n );\n\n return execution.run();\n },\n\n on,\n off,\n\n eval<TEval = TOutput>(options: EvalOptions<TEval>): Promise<EvalReport<TEval>> {\n return runEval<TEval>(agentContract as unknown as AgentContract<TEval>, options);\n },\n };\n\n return agentContract;\n}\n\n/**\n * Config for the `ai.agent.judge(...)` helper — every `AgentConfig` field\n * except `judge` itself (the helper sets it). Callers tune resilience by\n * passing a {@link JudgeConfig} as the second argument instead.\n */\nexport type JudgeAgentConfig<TOutput = unknown> = Omit<AgentConfig<TOutput>, \"judge\">;\n\n/**\n * Build a judge-safe agent — sugar for `agent({ ...config, judge })`.\n *\n * Use this for LLM-as-judge graders and verdict classifiers running on\n * models that may emit corrupted structured output (e.g. the Amazon Nova\n * family). The returned agent parses verdicts leniently (tolerates fenced\n * ` ```json ` blocks + surrounding prose), auto-enables a couple of repair\n * re-asks, and never throws on a parse miss — surfacing `result.error` with\n * `result.data` left undefined so a flaky judge degrades gracefully.\n *\n * See {@link AgentConfig.judge} for the full behavior + the resilience-over-\n * strictness trade-off.\n *\n * @param config - Any agent config (model, system prompt, output schema, …).\n * @param judge - Optional fine-tuning ({@link JudgeConfig}); defaults to `true`.\n *\n * @example\n * const grader = ai.agent.judge({\n * model: nova.model({ name: \"amazon.nova-pro-v1:0\" }),\n * systemPrompt: \"Grade the answer. Respond with JSON only.\",\n * output: verdictSchema,\n * });\n *\n * const result = await grader.execute(prompt);\n * if (result.error) {\n * // graceful default — the judge couldn't produce a clean verdict\n * }\n */\nfunction judgeAgent<TOutput = unknown>(\n config: JudgeAgentConfig<TOutput>,\n judge: JudgeConfig | boolean = true,\n): AgentContract<TOutput> {\n return agent<TOutput>({ ...config, judge });\n}\n\n// Attach the judge helper to the `agent` factory so it surfaces as\n// `ai.agent.judge(...)` (the `Ai` namespace exposes `agent` as\n// `typeof agent`, which now carries this property). Done as a typed\n// property assignment rather than `Object.assign` so the generic\n// signature is preserved for callers.\nagent.judge = judgeAgent;\n\n/**\n * Name → handler-set map shared between the `agent()` factory and its\n * per-call `Execution`. Each `.on()` registration mutates this map;\n * every `Execution` reads from the same reference so additions and\n * removals take effect mid-flight.\n */\ntype InstanceHandlerMap = Map<keyof AgentEventMap, Set<AgentEventHandler<keyof AgentEventMap>>>;\n\n/**\n * Per-call driver that owns the full lifecycle of a single\n * `agent.execute()` or `agent.stream()` invocation.\n *\n * **Role.** An `Execution` is the short-lived state container and phase\n * orchestrator for one agent run. The public `agent()` factory stays purely\n * functional — all mutable bookkeeping (trips, tool calls, usage totals,\n * message history, terminal error, parsed output) lives here so each call\n * gets a fresh, isolated instance.\n *\n * **Responsibility.**\n * - Owns: building the initial message list, driving the bounded trip loop,\n * dispatching tool calls safely, parsing the final output against the\n * caller's schema, emitting lifecycle events (to both the user handler\n * and, in stream mode, the `StreamController`), and producing the\n * `AgentResult`.\n * - Does NOT own: how the model produces responses (delegated to\n * `ModelContract.complete` / `ModelContract.stream`), how tools execute\n * (delegated to `ToolContract.invoke`), the async-queue plumbing for\n * streaming (delegated to `createAgentStream`), or any cross-call state\n * (factory-level concerns live in `agent()`).\n *\n * Streaming mode is opt-in via the fourth constructor argument: pass a\n * `StreamController` and every event is mirrored into it while model calls\n * are driven via `model.stream()` instead of `model.complete()`. The public\n * contract of `execute()` says it never throws — `Execution` enforces that\n * by funneling every unexpected error into `this.error` and returning a\n * well-formed result regardless of what went wrong.\n *\n * Not exported — consumers interact only with the `agent()` factory (see\n * §4.2 of code-style.md — \"per-call execution state across phases\").\n *\n * @example\n * // Non-streaming — inside agent.execute():\n * const result = await new Execution(config, input, options).run();\n *\n * @example\n * // Streaming — inside agent.stream():\n * const { controller, stream } = createAgentStream();\n * void new Execution(config, input, options, controller).run();\n * return stream;\n */\nclass Execution<TOutput> {\n private readonly trips: LLMTrip[] = [];\n private readonly toolCalls: ToolCall[] = [];\n private readonly usage: Usage = { input: 0, output: 0, total: 0 };\n private readonly messages: Message[] = [];\n /** Resolved system-prompt text sent to the model, captured for the report. */\n private systemPrompt?: string;\n /**\n * Registry name of the named `SystemPromptContract` this run resolved, when\n * the prompt carried a `meta.name`. Stamped onto the report so observers can\n * attribute the run to a specific registered prompt. Absent for raw-string,\n * anonymous-contract, or absent prompts.\n */\n private promptName?: string;\n /** Registry version label paired with {@link Execution.promptName}. */\n private promptVersion?: string;\n private readonly maxTrips: number;\n private readonly startedAt: Date;\n private readonly start = performance.now();\n /**\n * Stable run id. A caller-supplied `options.runId` wins (load-bearing\n * for durable resume — the snapshot key must stay constant across the\n * crash); otherwise a fresh id is generated. When `resumeFrom` is set\n * its `runId` is authoritative so the resumed run writes back to the\n * same key.\n */\n private readonly runId: string;\n private readonly logger: Logger = log;\n /**\n * Event names whose handler already threw once this run — so the\n * isolate-but-surface warning for a broken handler fires at most once\n * per event type, never spamming the log on a hot event (token\n * deltas, tool calls). See {@link surfaceHandlerError} (C5).\n */\n private readonly warnedHandlerEvents = new Set<string>();\n private readonly middleware: ReadonlyArray<\n NonNullable<AgentConfig<TOutput>[\"middleware\"]>[number]\n >;\n private readonly middlewareState: MiddlewareState = new Map();\n /**\n * The agent's own tools plus this run's skill tools (`loadSkill`, and\n * `saveSkill` when a review gate is configured). Built once per execution\n * because `loadSkillTool` closes over a per-run counter enforcing\n * `maxLoadsPerRun` — one tool instance per run = one budget per run. When\n * no skills library is attached this is just `config.tools`.\n */\n private readonly effectiveTools: ToolContract<unknown, unknown>[];\n\n private error?: AIError;\n private data?: TOutput;\n private responseSchema?: Record<string, unknown>;\n /**\n * Resolved judge-safe preset for this run, or `undefined` when the\n * `judge` flag is off. When set, output parsing is lenient (tolerates\n * fenced blocks + surrounding prose) and repair auto-defaults to the\n * configured attempt count.\n */\n private readonly judgeConfig?: JudgeConfig;\n\n public constructor(\n private readonly config: ResolvedAgentConfig<TOutput>,\n private readonly input: string,\n private readonly options?: AgentExecuteOptions<TOutput>,\n private readonly streamController?: StreamController<AgentResult<TOutput>>,\n private readonly instanceHandlers?: InstanceHandlerMap,\n private readonly resumeFrom?: AgentSnapshot,\n ) {\n this.maxTrips = config.maxTrips ?? 10;\n this.middleware = config.middleware ?? [];\n this.judgeConfig = resolveJudgeConfig(config.judge);\n\n // Resolve the run id: a resumed run reuses the snapshot's key so it\n // writes back to the same record; otherwise a caller-supplied\n // `options.runId` wins (durable callers pass a stable key), else a\n // fresh id is generated. `startedAt` likewise restores from the\n // snapshot so the resumed report spans the whole run, not just the tail.\n this.runId = resumeFrom?.runId ?? options?.runId ?? generateRunId(\"agent\");\n this.startedAt = resumeFrom ? new Date(resumeFrom.startedAt) : new Date();\n\n // Seed the accumulators from the snapshot on resume — re-hydrate the\n // assembled conversation, the completed trips, the dispatched tool\n // records, the running usage, and the resolved prompt/schema metadata.\n // Pushing directly into `this.trips` (rather than re-running `runTrip`)\n // is what keeps a resume from re-emitting completed trips' lifecycle\n // events or re-invoking their tools — the loop later starts at\n // `this.trips.length`. When `resumeFrom` is absent every accumulator\n // stays empty, so the non-durable path is byte-for-byte unchanged.\n if (resumeFrom) {\n this.messages.push(...resumeFrom.messages);\n this.trips.push(...resumeFrom.trips);\n this.toolCalls.push(...resumeFrom.toolCalls);\n mergeUsage(this.usage, resumeFrom.usage);\n this.systemPrompt = resumeFrom.systemPrompt;\n this.responseSchema = resumeFrom.responseSchema;\n this.promptName = resumeFrom.promptName;\n this.promptVersion = resumeFrom.promptVersion;\n }\n\n // Build this run's skill tools once with this run's id so the\n // per-run `maxLoadsPerRun` counter (closed over inside `loadSkillTool`)\n // is scoped to exactly this execution. `tools(runId)` already returns\n // `loadSkill` always and `saveSkill` only when a review gate is wired,\n // so no special-casing is needed here. `normalizeAgentTools` is a\n // passthrough for already-built `ToolContract`s — called for uniformity.\n const skillTools = config.skillsLib\n ? normalizeAgentTools(config.skillsLib.tools(this.runId)) ?? []\n : [];\n\n this.effectiveTools = [...(config.tools ?? []), ...skillTools];\n }\n\n /**\n * Base middleware context shared by every level. `state` is the\n * single mutable bag threaded through `execute`, `trip`, and `tool`\n * hooks for the lifetime of this execution — fresh per `execute()`\n * call, never reused across runs.\n */\n private buildExecuteContext(): MiddlewareExecuteContext {\n return {\n agent: {\n name: this.config.name ?? this.config.model.name,\n isAnonymous: !this.config.name,\n },\n model: {\n name: this.config.model.name,\n provider: this.config.model.provider,\n },\n input: this.input,\n options: this.options as AgentExecuteOptions<unknown> | undefined,\n state: this.middlewareState,\n signal: this.options?.signal,\n };\n }\n\n /**\n * Entry point for a single agent execution. Wraps the real work\n * (`runCore`) in the `execute`-level middleware pipeline, then\n * emits the terminal `agent.completed` / `agent.error` events and\n * closes the stream (if any) with the post-pipeline result — so\n * middleware that short-circuits or transforms the final result\n * still produces a well-formed public outcome.\n *\n * Must never throw: any error that escapes the pipeline is\n * converted into an `AgentResult` with `error` populated before\n * returning, preserving the `agent.execute()` public contract.\n */\n public async run(): Promise<AgentResult<TOutput>> {\n const context = this.buildExecuteContext();\n\n let result: AgentResult<TOutput>;\n\n try {\n result = (await runPipeline(\n this.middleware,\n \"execute\",\n context,\n () => this.runCore(),\n this.logger,\n )) as AgentResult<TOutput>;\n } catch (thrown) {\n this.error = this.toAIError(thrown);\n result = this.buildResult();\n }\n\n if (result.error) {\n this.emit(\"agent.error\", { error: result.error });\n }\n\n this.emit(\"agent.completed\", { result });\n\n // Fire the `onComplete` hook with a flat payload (runId +\n // durationMs pre-extracted) for audit-log consumers. Awaited but\n // errors swallowed so consumer bugs cannot crash the agent or\n // interfere with the result returned to the caller.\n await this.fireCompleteHook(result);\n\n // Route the finished report to any resolved observers (F1/F3).\n // Gated by `config.observe` + the global observe-all flag; a no-op\n // when nothing resolves. Observer errors are swallowed inside\n // `notifyObservers`, so they never break the run — mirroring the\n // onUsage / onComplete hook policy.\n await notifyObservers(this.config.observe, result.report);\n\n // Auto-nest into the enclosing orchestration run when this agent\n // executed inside a supervisor/orchestrator/team intent callback\n // (an ambient `RunFrame` is installed). Captures this report onto\n // the callback's `children[]` and relinks its lineage — so an\n // `agent.execute(...)` called directly inside a `run()` callback\n // shows up nested with its tools, instead of being lost as a\n // separate top-level execution. No-op for standalone runs.\n captureChildReport(result.report);\n\n this.streamController?.end(result);\n\n return result;\n }\n\n /**\n * Inner body wrapped by the `execute`-level pipeline. Drives the\n * full lifecycle — build messages → emit starting → run trip loop\n * → parse output → build result. Catches any unexpected throw and\n * funnels it into `this.error` so the returned result is always\n * well-formed; `execute`-level `after` hooks receive the result,\n * with `error` populated when things went wrong.\n */\n private async runCore(): Promise<AgentResult<TOutput>> {\n // Completed-run short-circuit. A resume of a snapshot whose run\n // already COMPLETED re-runs nothing — the stored trips ARE the\n // result. Rebuild the final result from the re-hydrated accumulators\n // and return, so resume is idempotent (mirrors the supervisor\n // \"resume is a no-op and returns the final state\"). A `failed` or\n // `cancelled` snapshot is intentionally NOT short-circuited — those\n // are exactly the runs a caller resumes to retry the remaining work\n // after fixing the cause, so they re-enter the trip loop below.\n if (this.resumeFrom && this.resumeFrom.status === \"completed\") {\n return this.rebuildResumedResult(this.resumeFrom);\n }\n\n try {\n // On resume the conversation is already hydrated from the snapshot,\n // so skip the (re)build of the initial messages AND the\n // `agent.starting` emit — those belong to the original run. A fresh\n // run (resumeFrom absent) takes the normal path unchanged.\n if (!this.resumeFrom) {\n await this.buildInitialMessages();\n\n this.emit(\"agent.starting\", { input: this.input });\n }\n\n await this.runTripLoop();\n\n const parseOutcome = await this.parseOutput();\n\n if (parseOutcome === \"failed\" && this.resolveRepairAttempts() > 0) {\n await this.runRepairLoop();\n }\n } catch (thrown) {\n this.error = this.toAIError(thrown);\n }\n\n // Terminal checkpoint — persist the final state so a completed-run\n // resume short-circuits to the stored result, then optionally drop\n // the snapshot when `deleteOnComplete` is set and the run succeeded.\n // No-op when `durable` is absent.\n await this.checkpoint(this.resolveSnapshotStatus());\n\n if (!this.error && this.config.durable?.deleteOnComplete) {\n const outcome = await deleteAgentSnapshot({\n durable: this.config.durable,\n runId: this.runId,\n });\n\n if (!outcome.ok) {\n this.logger.warn(LOG_MODULE, \"snapshot.delete.failed\", \"durable snapshot delete failed\", {\n runId: this.runId,\n error: outcome.error instanceof Error ? outcome.error.message : String(outcome.error),\n });\n }\n }\n\n return this.buildResult();\n }\n\n /**\n * Resolve the system prompt (string or `SystemPromptContract`), merge\n * placeholders from config + execute options, inject a structured-output\n * instruction when the caller wants typed output but the model can't\n * enforce it natively, prepend any conversation history, and append the\n * user input. Produces the initial `messages` array the first trip sends\n * to the model. Runs exactly once per execution.\n */\n private async buildInitialMessages(): Promise<void> {\n const { messages, responseSchema, systemPrompt, promptName, promptVersion } =\n await buildAgentInputMessages({\n config: this.config,\n input: this.input,\n options: this.options,\n });\n this.messages.push(...messages);\n this.responseSchema = responseSchema;\n this.systemPrompt = systemPrompt;\n this.promptName = promptName;\n this.promptVersion = promptVersion;\n\n await this.injectSkills();\n }\n\n /**\n * Prepend the skills library's contribution to the system prompt — the\n * always-injected metadata catalog first, then (only under `inject`) the\n * preloaded skill bodies, then the developer's resolved system prompt.\n * Never replaces the developer prompt.\n *\n * No-op when no skills library is attached. `catalogPrompt` returns `\"\"`\n * when nothing is in scope and `preload` returns `[]` when `inject` is\n * omitted (the default), so the prepend is a no-op in those cases too.\n *\n * Awaited inside `buildInitialMessages`, which runs inside `runCore`'s\n * try/catch — a source/embedder failure funnels into `this.error` like\n * any other build failure, no new error handling needed.\n */\n private async injectSkills(): Promise<void> {\n const lib = this.config.skillsLib;\n\n if (!lib) {\n return;\n }\n\n const catalogBlock = await lib.catalogPrompt(this.input);\n const preloaded = await lib.preload(this.input);\n\n const blocks: string[] = [];\n\n if (catalogBlock) {\n blocks.push(catalogBlock);\n }\n\n for (const record of preloaded) {\n if (record.body) {\n blocks.push(record.body);\n }\n }\n\n if (blocks.length === 0) {\n return;\n }\n\n const prefix = blocks.join(\"\\n\\n\");\n\n // Merge in front of the developer's resolved system prompt (captured in\n // `this.systemPrompt` and mirrored as the leading `role: \"system\"`\n // message). When the agent had no system prompt, the skills prefix\n // becomes the system message.\n const merged = this.systemPrompt ? `${prefix}\\n\\n${this.systemPrompt}` : prefix;\n\n this.systemPrompt = merged;\n\n const firstMessage = this.messages[0];\n\n if (firstMessage?.role === \"system\") {\n firstMessage.content = merged;\n } else {\n this.messages.unshift({ role: \"system\", content: merged });\n }\n }\n\n /**\n * Drive sequential trips up to `maxTrips`. Each trip may stop the loop\n * naturally (model returned a non-tool-call finish), abort it (model\n * threw), or continue it (model requested tools). When the loop exits\n * after the cap without a natural stop, records a \"Max trips exceeded\"\n * error so the caller can distinguish runaway tool loops from a real result.\n */\n private async runTripLoop(): Promise<void> {\n // Start at the resumed offset, not 0. On a fresh run `this.trips`\n // is empty so this is `0` and the loop behaves exactly as before; on\n // a resume the already-settled trips are skipped entirely — their\n // model calls and tool dispatches are never re-issued.\n for (let tripIndex = this.trips.length; tripIndex < this.maxTrips; tripIndex++) {\n if (this.options?.signal?.aborted) {\n this.error = this.makeCancelledError();\n return;\n }\n\n const tripInput = tripIndex === 0 ? this.input : \"[tool results]\";\n const outcome = await this.runTrip(tripIndex, tripInput);\n\n if (outcome === \"error\" || outcome === \"stop\") {\n return;\n }\n }\n\n const lastTrip = this.trips[this.trips.length - 1];\n\n if (lastTrip?.finishReason === \"tool_calls\") {\n this.error = new AgentMaxTripsError(\"Max trips exceeded\", {\n maxTrips: this.maxTrips,\n });\n }\n }\n\n /**\n * Execute one round-trip to the model. Aggregates usage into the running\n * total, dispatches any requested tool calls, appends the assistant +\n * tool-result messages for the next trip, and records an `LLMTrip`.\n * Returns an outcome that tells `runTripLoop` whether to continue, stop,\n * or abort.\n */\n private async runTrip(\n tripIndex: number,\n tripInput: string,\n ): Promise<\"continue\" | \"stop\" | \"error\"> {\n this.emit(\"agent.trip.started\", { tripIndex, input: tripInput });\n\n const tripStartedAt = new Date();\n const tripStart = performance.now();\n\n let response: ModelResponse;\n\n try {\n response = await this.runTripThroughPipeline(tripIndex);\n } catch (thrown) {\n this.error = this.toAIError(thrown);\n\n const failedTrip: LLMTrip = {\n index: tripIndex,\n input: tripInput,\n output: \"\",\n finishReason: \"error\",\n startedAt: tripStartedAt.toISOString(),\n endedAt: new Date().toISOString(),\n duration: performance.now() - tripStart,\n usage: { input: 0, output: 0, total: 0 },\n error: this.error,\n };\n\n this.trips.push(failedTrip);\n\n this.emit(\"agent.trip.completed\", { trip: failedTrip });\n this.emit(\"agent.error\", { error: this.error });\n\n // Persist the failed trip too, so a resume sees it in the ledger\n // and the terminal checkpoint records the run as `failed`. The\n // trip's model call already threw — there is no tool side effect to\n // double-count here. No-op when `durable` is absent.\n await this.checkpoint(\"failed\");\n\n return \"error\";\n }\n\n // Attach per-trip cost breakdown using the model's pricing table\n // (when configured). Done at the framework boundary so stored trip\n // records carry historical cost — Panoptic and other archive\n // consumers never re-derive against today's pricing, and the\n // input/output/cached split stays queryable without joining to a\n // pricing table at all.\n if (response.usage.cost === undefined) {\n response.usage.cost = computeCost(response.usage, this.config.model.pricing);\n }\n\n // Roll the trip into the agent total via the shared all-channel merge\n // (was missing reasoningTokens / cacheWriteTokens). `response.usage.cost`\n // is computed just above, so the cost lane merges identically.\n mergeUsage(this.usage, response.usage);\n\n // Fire the `onUsage` hook with a flat, pre-packaged payload so\n // cost-ledger code receives stable identity (runId, model+provider)\n // without joining from elsewhere. Awaited but errors swallowed.\n await this.fireUsageHook(tripIndex, response.usage);\n\n const isToolCallTrip =\n response.finishReason === \"tool_calls\" &&\n response.toolCalls !== undefined &&\n response.toolCalls.length > 0;\n\n const tripToolCalls: ToolCall[] = [];\n\n if (isToolCallTrip) {\n this.messages.push({\n role: \"assistant\",\n content: response.content,\n toolCalls: response.toolCalls,\n });\n\n for (const toolCallRequest of response.toolCalls!) {\n const record = await this.dispatchToolCall(toolCallRequest, tripIndex);\n\n tripToolCalls.push(record);\n }\n }\n\n const trip: LLMTrip = {\n index: tripIndex,\n input: tripInput,\n output: response.content,\n finishReason: response.finishReason,\n startedAt: tripStartedAt.toISOString(),\n endedAt: new Date().toISOString(),\n duration: performance.now() - tripStart,\n usage: response.usage,\n toolCalls: tripToolCalls.length > 0 ? tripToolCalls : undefined,\n };\n\n this.trips.push(trip);\n\n this.emit(\"agent.trip.completed\", { trip });\n\n // Per-trip durable checkpoint. Sits AFTER the trip push + the\n // `agent.trip.completed` emit and AFTER every tool this trip\n // requested has been dispatched (the block above) — the only point\n // where `messages`, `trips`, `toolCalls`, and `usage` are mutually\n // consistent. Swallow-and-log: a failed checkpoint never aborts the\n // run, it only loses resume-ability from here. No-op when `durable`\n // is absent.\n await this.checkpoint(\"running\");\n\n if (!isToolCallTrip) {\n return \"stop\";\n }\n\n // Terminate the trip loop when EVERY tool call this trip is\n // `mode: \"silent\"`. Silent tools don't feed their result back\n // to the model — the prose the model streamed alongside the\n // tool call IS the final reply. The \"all\" rule is load-bearing:\n // if any feedback tool was called too, its result still needs\n // to round-trip, so we must continue.\n //\n // Composite (`asTool`-wrapped) tools never set `mode: \"silent\"`\n // in v1 — silent-composite mechanics are deferred per plan\n // 2026-05-07-silent-tools.md (Q4). They behave as feedback.\n const allSilent = response.toolCalls!.every((request) => {\n const registered = this.effectiveTools.find((tool) => tool.name === request.name);\n return registered?.mode === \"silent\";\n });\n\n return allSilent ? \"stop\" : \"continue\";\n }\n\n /**\n * Route `getModelResponse` through the `trip`-level middleware\n * pipeline. `trip.before` hooks can short-circuit the trip by\n * returning a synthetic `ModelResponse` (semantic cache hit).\n * `trip.after` hooks can transform the response before the trip\n * record is built or any tool calls are dispatched. `trip.onError`\n * hooks can recover from provider failures (fallback chain).\n */\n private async runTripThroughPipeline(tripIndex: number): Promise<ModelResponse> {\n const context: MiddlewareTripContext = {\n ...this.buildExecuteContext(),\n tripIndex,\n messages: this.messages,\n };\n\n return (await runPipeline(\n this.middleware,\n \"trip\",\n context,\n () => this.getModelResponse(tripIndex),\n this.logger,\n )) as ModelResponse;\n }\n\n /**\n * Produce the `ModelResponse` for the current trip. In non-streaming\n * mode, delegates straight to `model.complete()`. In streaming mode,\n * drains `model.stream()` while emitting `streaming` events per delta\n * and accumulates the chunks into the same `ModelResponse` shape, so the\n * rest of the trip pipeline (tool dispatch, trip record, usage\n * aggregation) stays identical between the two modes.\n */\n private async getModelResponse(tripIndex: number): Promise<ModelResponse> {\n const callOptions = {\n ...this.config.modelOptions,\n tools: this.effectiveTools,\n ...(this.responseSchema ? { responseSchema: this.responseSchema } : {}),\n ...(this.options?.signal ? { signal: this.options.signal } : {}),\n };\n\n if (!this.streamController) {\n return this.config.model.complete(this.messages, callOptions);\n }\n\n let content = \"\";\n let finishReason: FinishReason = \"stop\";\n let usage: Usage = { input: 0, output: 0, total: 0 };\n const toolCalls: ModelToolCallRequest[] = [];\n const recoveredCalls: ModelToolCallRequest[] = [];\n\n const guardConfig = this.resolveStreamingToolGuard();\n const guard = guardConfig\n ? new JsonStreamGuard({\n tools: this.effectiveTools as ReadonlyArray<ToolContract<unknown, unknown>>,\n maxBufferBytes: guardConfig.maxBufferBytes,\n onSafeDelta: (delta) => {\n content += delta;\n\n this.emit(\"agent.trip.streaming\", { delta, tripIndex });\n },\n onRecoveredCall: (request) => {\n recoveredCalls.push(request);\n },\n })\n : undefined;\n\n for await (const chunk of this.config.model.stream(this.messages, callOptions)) {\n // Mid-stream abort — break out cleanly instead of continuing to\n // consume the iterator. The underlying fetch is already\n // cancelled via `signal` forwarded in callOptions; this covers\n // adapters that don't honor signal natively and keeps mock\n // models consistent under cancellation tests.\n if (this.options?.signal?.aborted) {\n throw this.makeCancelledError();\n }\n\n if (chunk.type === \"delta\") {\n if (guard) {\n await guard.feed(chunk.content);\n } else {\n content += chunk.content;\n\n this.emit(\"agent.trip.streaming\", { delta: chunk.content, tripIndex });\n }\n\n continue;\n }\n\n if (chunk.type === \"tool-call\") {\n toolCalls.push({\n id: chunk.id,\n name: chunk.name,\n input: chunk.input,\n ...(chunk.providerMetadata ? { providerMetadata: chunk.providerMetadata } : {}),\n });\n\n continue;\n }\n\n finishReason = chunk.finishReason;\n usage = chunk.usage;\n }\n\n if (guard) {\n await guard.finalize();\n }\n\n // Dedupe synthesized calls against real ones the provider streamed\n // structurally — the model occasionally emits BOTH channels for\n // the same call (real tool-call chunk + narrated JSON envelope).\n // Real wins; the synthesized duplicate is dropped so dispatch\n // doesn't run twice. See plan 2026-05-22 §Q5.\n const dedupedRecovered = recoveredCalls.filter(\n (recovered) => !isDuplicateToolCall(recovered, toolCalls),\n );\n\n const mergedToolCalls = [...toolCalls, ...dedupedRecovered];\n\n // When the guard recovered any calls but the model reported a\n // natural `\"stop\"`, override to `\"tool_calls\"` so the agent's\n // dispatch loop (`runTrip` → `isToolCallTrip`) actually fires.\n // Without this the guard silently suppresses the leaked JSON but\n // never dispatches the real action — chips never render.\n const resolvedFinishReason: FinishReason =\n dedupedRecovered.length > 0 && finishReason === \"stop\" ? \"tool_calls\" : finishReason;\n\n return {\n content,\n finishReason: resolvedFinishReason,\n usage,\n toolCalls: mergedToolCalls.length > 0 ? mergedToolCalls : undefined,\n };\n }\n\n /**\n * Resolve the effective `streamingToolGuard` for this trip.\n * Per-call options win over the agent-level config when the key is\n * explicitly present on options (including the explicit `undefined`\n * \"disable for this call\" form). Returns `undefined` when no guard\n * should run.\n */\n private resolveStreamingToolGuard(): StreamingToolGuardConfig | undefined {\n if (\n this.options !== undefined &&\n Object.prototype.hasOwnProperty.call(this.options, \"streamingToolGuard\")\n ) {\n return this.options.streamingToolGuard;\n }\n\n return this.config.streamingToolGuard;\n }\n\n /**\n * Dispatch a single tool call requested by the model. Looks up the tool\n * by name, invokes it via the safe `ToolContract.invoke` entry, pushes a\n * matching tool-result message into `this.messages` so the next trip can\n * see it, and emits the right lifecycle event (`tool-called` on success,\n * `tool-calling-failed` when the tool is unregistered or invoke returned\n * an error). Never throws — always returns a `ToolCall` record.\n */\n private async dispatchToolCall(\n toolCallRequest: ModelToolCallRequest,\n tripIndex: number,\n ): Promise<ToolCall> {\n const registeredTool = this.effectiveTools.find((tool) => tool.name === toolCallRequest.name);\n\n if (!registeredTool) {\n const error = new AgentExecutionError(`Tool not registered: ${toolCallRequest.name}`, {\n context: { toolName: toolCallRequest.name, tripIndex },\n });\n\n const nowIso = new Date().toISOString();\n\n const record: ToolCall = {\n runId: generateRunId(\"tool\"),\n rootRunId: this.runId,\n name: toolCallRequest.name,\n type: \"tool\",\n status: \"failed\",\n startedAt: nowIso,\n endedAt: nowIso,\n duration: 0,\n usage: { input: 0, output: 0, total: 0 },\n children: [],\n tripIndex,\n input: toolCallRequest.input,\n error,\n ...(toolCallRequest.recoveredFrom ? { recoveredFrom: toolCallRequest.recoveredFrom } : {}),\n };\n\n this.toolCalls.push(record);\n\n this.messages.push({\n role: \"tool\",\n toolCallId: toolCallRequest.id,\n content: JSON.stringify({ error: error.message }),\n });\n\n // Stub meta — there's no real tool to describe. Carries the\n // requested name for log correlation and an explanatory\n // description so consumers don't see an empty string.\n this.emit(\"agent.tool.failed\", {\n tool: {\n name: toolCallRequest.name,\n description: \"(unregistered tool — no description available)\",\n },\n input: toolCallRequest.input,\n error,\n tripIndex,\n });\n\n return record;\n }\n\n // Build the lightweight event meta once. Resolves `action` to a\n // string here so consumers receive plain data rather than having\n // to re-evaluate a callback on every event.\n const toolMeta: ToolEventMeta = {\n name: registeredTool.name,\n description: registeredTool.description,\n action: resolveToolAction(registeredTool, toolCallRequest.input),\n };\n\n this.emit(\"agent.tool.calling\", {\n tool: toolMeta,\n input: toolCallRequest.input,\n tripIndex,\n });\n\n const toolContext: MiddlewareToolContext = {\n ...this.buildExecuteContext(),\n tripIndex,\n messages: this.messages,\n tool: {\n name: registeredTool.name,\n description: registeredTool.description,\n mode: registeredTool.mode,\n },\n request: toolCallRequest,\n };\n\n // Thread the run's cancellation signal into the ctx handed to the\n // tool's `invoke`, so composite tools (asTool-wrapped agent/workflow/\n // supervisor) abort their nested run when the outer agent is cancelled\n // (C2). The caller's `toolCtx` (artifacts bag, etc.) is preserved — we\n // only add/override `signal`. With no signal configured we pass\n // `toolCtx` through unchanged so behavior stays byte-identical.\n const runSignal = this.options?.signal;\n const dispatchToolCtx: ToolContext | undefined = runSignal\n ? {\n artifacts: this.options?.toolCtx?.artifacts ?? {},\n ...this.options?.toolCtx,\n signal: runSignal,\n }\n : this.options?.toolCtx;\n\n let invokeResult: ToolInvokeResult<unknown>;\n\n try {\n invokeResult = (await runPipeline(\n this.middleware,\n \"tool\",\n toolContext,\n () => registeredTool.invoke(toolCallRequest.input, dispatchToolCtx),\n this.logger,\n )) as ToolInvokeResult<unknown>;\n } catch (thrown) {\n // A `tool`-level middleware hook threw. The real invoke never\n // throws (it funnels errors into `result.error`), so only a\n // middleware abort or a bug reaches this branch. Synthesize a\n // failed-invoke record so the tool-call trace stays consistent.\n const error = this.toAIError(thrown);\n const nowIso = new Date().toISOString();\n const emptyUsage: Usage = { input: 0, output: 0, total: 0 };\n\n const failedRunId = generateRunId(\"tool\");\n invokeResult = {\n error,\n usage: emptyUsage,\n report: {\n runId: failedRunId,\n rootRunId: failedRunId,\n name: registeredTool.name,\n version: registeredTool.version,\n type: \"tool\",\n status: \"failed\",\n startedAt: nowIso,\n endedAt: nowIso,\n duration: 0,\n usage: emptyUsage,\n children: [],\n },\n };\n }\n\n // The agent-level ToolCall record merges the tool's own invocation\n // report with agent-side enrichments (tripIndex, input, output,\n // error). When the underlying tool was an `asTool`-wrapped\n // composite, its inner report becomes the sole child of this\n // ToolCall — preserving the full nested tree while keeping this\n // node's own `type` as `\"tool\"` (from the agent's POV it *was* a\n // tool dispatch).\n const innerReport = invokeResult.report;\n const isComposite = innerReport.type !== \"tool\";\n\n const record: ToolCall = {\n runId: innerReport.runId,\n rootRunId: this.runId,\n name: toolCallRequest.name,\n version: registeredTool.version,\n type: \"tool\",\n status: innerReport.status,\n startedAt: innerReport.startedAt,\n endedAt: innerReport.endedAt,\n duration: innerReport.duration,\n usage: invokeResult.usage,\n children: isComposite ? [innerReport] : innerReport.children,\n tripIndex,\n input: toolCallRequest.input,\n output: invokeResult.data,\n error: invokeResult.error,\n ...(toolCallRequest.recoveredFrom ? { recoveredFrom: toolCallRequest.recoveredFrom } : {}),\n };\n\n this.toolCalls.push(record);\n\n // Roll child usage into the agent's accumulator. Leaf tools\n // contribute zero; `asTool`-wrapped composites contribute the\n // full cost of the inner agent/workflow/supervisor run.\n // All-channel merge so an asTool-wrapped composite that used prompt-cache\n // or reasoning tokens carries those counts into the parent total too.\n mergeUsage(this.usage, invokeResult.usage);\n\n this.messages.push({\n role: \"tool\",\n toolCallId: toolCallRequest.id,\n content: invokeResult.error\n ? JSON.stringify({ error: invokeResult.error.message })\n : JSON.stringify(invokeResult.data ?? null),\n });\n\n if (invokeResult.error) {\n this.emit(\"agent.tool.failed\", {\n tool: toolMeta,\n input: toolCallRequest.input,\n error: invokeResult.error,\n tripIndex,\n });\n } else {\n this.emit(\"agent.tool.called\", { ...record, tool: toolMeta });\n }\n\n return record;\n }\n\n /**\n * Parse the final trip output against the user-supplied schema (if any).\n * Failures populate `this.error` but never throw. Returns an outcome the\n * caller uses to decide whether self-repair is worth attempting:\n *\n * - `\"skipped\"` — no schema, or a prior trip-level error already set\n * `this.error` (model crash, max trips). Not repairable; the failure\n * isn't a parse problem the model can fix by re-asking.\n * - `\"failed\"` — schema present, output text either failed JSON.parse\n * or failed `~standard.validate`. Repairable via `runRepairLoop`.\n * - `\"success\"` — parsed and validated; `this.data` populated.\n *\n * Under the judge-safe preset (`judge: true`) the JSON extraction is\n * lenient — it tolerates fenced ` ```json ` blocks plus leading /\n * trailing prose by slicing the first balanced object / array out of the\n * response. Never throws regardless of preset: a parse / validation miss\n * sets `this.error` and returns `\"failed\"`, leaving `this.data`\n * undefined for the graceful-default path.\n */\n private async parseOutput(): Promise<\"success\" | \"failed\" | \"skipped\"> {\n const schema = this.options?.output ?? this.config.output;\n\n if (!schema || this.error) {\n return \"skipped\";\n }\n\n const finalTrip = this.trips[this.trips.length - 1];\n const text = finalTrip?.output ?? \"\";\n\n if (!text) {\n return \"skipped\";\n }\n\n // Under the judge-safe preset, parse leniently: tolerate fenced blocks\n // AND surrounding prose by slicing the first balanced JSON object /\n // array out of the response. Normal agents keep the strict\n // `extractJsonPayload` (fence-only) so genuine malformations still fail\n // loudly rather than being papered over.\n const payload = this.judgeConfig ? extractJsonLenient(text) : extractJsonPayload(text);\n const sentinel = Symbol(\"parse-failed\");\n const parsed = safeJsonParse<unknown>(payload, sentinel);\n\n if (parsed === sentinel) {\n this.error = new SchemaValidationError(\"Failed to parse model output as JSON\", {\n context: { text },\n });\n return \"failed\";\n }\n\n const validation = await (schema as StandardSchemaV1<TOutput>)[\"~standard\"].validate(parsed);\n\n if (validation.issues) {\n const summary = validation.issues.map((issue) => issue.message).join(\"; \");\n this.error = new SchemaValidationError(summary, {\n issues: validation.issues,\n });\n return \"failed\";\n }\n\n this.data = validation.value;\n return \"success\";\n }\n\n /**\n * Resolve how many repair re-asks this run should perform after a parse\n * failure. Per-call `options.repair` wins when explicitly set (preserving\n * the existing surface). Otherwise the judge-safe preset supplies its\n * default attempt count — so `judge: true` enables repair without the\n * caller also having to pass `repair`. Returns `0` when neither applies,\n * which leaves the historical \"no repair unless asked\" behavior intact.\n */\n private resolveRepairAttempts(): number {\n if (this.options?.repair) {\n return this.options.repair.maxAttempts ?? 1;\n }\n\n if (this.judgeConfig) {\n return this.judgeConfig.repairAttempts ?? JUDGE_DEFAULT_REPAIR_ATTEMPTS;\n }\n\n return 0;\n }\n\n /**\n * Opt-in self-repair loop for `output` schema failures. Triggered only\n * when repair attempts remain (`resolveRepairAttempts() > 0`) and\n * `parseOutput()` returned `\"failed\"`.\n *\n * Each attempt:\n * 1. Pushes the bad assistant response into `this.messages` (so the\n * model can see what it just produced).\n * 2. Pushes a corrective user message naming the validation/parse error.\n * 3. Runs another trip — counted against the same `maxTrips` cap as\n * normal trips so a stuck model can't loop forever.\n * 4. Re-parses. Stops on success, on a trip-level error, or when\n * either `maxAttempts` or `maxTrips` is exhausted.\n *\n * Resets `this.error` and `this.data` before each attempt so the final\n * outcome (success or last failure) is what surfaces to the caller.\n */\n private async runRepairLoop(): Promise<void> {\n const maxAttempts = this.resolveRepairAttempts();\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (this.trips.length >= this.maxTrips) {\n return;\n }\n\n const lastTrip = this.trips[this.trips.length - 1];\n const badResponse = lastTrip?.output ?? \"\";\n const failureReason = this.error?.message ?? \"unknown validation failure\";\n\n this.error = undefined;\n this.data = undefined;\n\n this.messages.push({ role: \"assistant\", content: badResponse });\n\n this.messages.push({\n role: \"user\",\n content: [\n `Your previous response failed validation: ${failureReason}.`,\n \"Respond again with valid JSON only — no prose, no markdown fences, no commentary.\",\n ].join(\" \"),\n });\n\n const tripIndex = this.trips.length;\n\n this.logger.warn(LOG_MODULE, \"repair.attempting\", \"retrying after validation failure\", {\n attempt: attempt + 1,\n maxAttempts,\n reason: failureReason,\n });\n\n const outcome = await this.runTrip(tripIndex, \"[repair attempt]\");\n\n if (outcome === \"error\") {\n return;\n }\n\n const parseOutcome = await this.parseOutput();\n\n if (parseOutcome === \"success\") {\n return;\n }\n }\n }\n\n /**\n * Build the final `AgentResult` snapshot from accumulated state\n * (trips, tool calls, data/error, usage, timing).\n *\n * Pure — no side effects. `run()` owns terminal event emission and\n * stream closure so the post-pipeline result (possibly transformed\n * or short-circuited by an `execute`-level middleware) is what\n * flows out to consumers and listeners.\n *\n * Trips, tool calls, status, and timing live under `report` so the\n * root stays focused on the four things callers reach for most:\n * `data`, `text`, `usage`, `error`.\n */\n private buildResult(): AgentResult<TOutput> {\n const finalTrip = this.trips[this.trips.length - 1];\n const endedAt = new Date();\n\n const agentName = this.config.name ?? this.config.model.name;\n const status: BaseReport[\"status\"] = this.error\n ? this.error instanceof AgentCancelledError\n ? \"cancelled\"\n : \"failed\"\n : \"completed\";\n\n const report = {\n runId: this.runId,\n rootRunId: this.runId,\n name: agentName,\n version: this.config.version,\n type: \"agent\" as const,\n status,\n // Stamp the terminal error onto the report so the observe path — which\n // sees only the report, never the result envelope — surfaces WHY a\n // failed/cancelled run ended. Spread conditionally so a completed run\n // stays byte-for-byte as before.\n ...(this.error ? { error: this.error } : {}),\n startedAt: this.startedAt.toISOString(),\n endedAt: endedAt.toISOString(),\n duration: performance.now() - this.start,\n usage: this.usage,\n children: this.toolCalls,\n model: {\n name: this.config.model.name,\n provider: this.config.model.provider,\n },\n trips: this.trips,\n systemPrompt: this.systemPrompt,\n // Prompt-version linkage. When the agent resolved a *named* prompt (one\n // registered in `ai.prompts`), stamp its `name` / `version` so observers\n // (e.g. Panoptic) can group/filter runs by the exact prompt version that\n // produced them. Spread conditionally so unnamed / raw-string prompts\n // leave the report byte-for-byte as before.\n ...(this.promptName\n ? { promptName: this.promptName, promptVersion: this.promptVersion }\n : {}),\n // Opt-in full-history capture (F2). When `captureMessages` is set,\n // normalize the real assembled turn array (assistant turns with\n // toolCalls + tool-result turns) onto the report. Off ⇒ field\n // absent, so the report is byte-for-byte as before.\n ...(this.config.captureMessages\n ? { messages: this.captureMessages() }\n : {}),\n };\n\n // Stamp lineage on the assembled tree exactly once per run.\n // Rewrites any inner self-roots from composite children to this\n // run's id, stamps `reportSchemaVersion` on the root, and\n // propagates `sessionId` to every node.\n stampReportLineage(report, {\n rootRunId: this.runId,\n sessionId: this.options?.sessionId,\n });\n\n return {\n type: \"agent\",\n data: this.data,\n text: finalTrip?.output,\n report,\n usage: this.usage,\n error: this.error,\n };\n }\n\n /**\n * Map the run's terminal outcome to the persisted snapshot status.\n * A cancelled error reads as `\"cancelled\"`, any other error as\n * `\"failed\"`, otherwise `\"completed\"`. Mirrors the report-status\n * mapping in {@link buildResult}.\n */\n private resolveSnapshotStatus(): AgentSnapshotStatus {\n if (!this.error) {\n return \"completed\";\n }\n\n return this.error instanceof AgentCancelledError ? \"cancelled\" : \"failed\";\n }\n\n /**\n * Build and persist an {@link AgentSnapshot} from the current\n * accumulators. The per-trip and terminal checkpoints both route\n * through here. Reuses {@link captureMessages} to normalize the live\n * `Message[]` into JSON-safe form so the snapshot round-trips through\n * any store backend.\n *\n * No-op (returns immediately) when `durable` is absent — the common\n * non-durable path stays free. A failed persist is logged and\n * swallowed (never aborts the run), matching the supervisor / workflow\n * checkpoint policy.\n */\n private async checkpoint(status: AgentSnapshotStatus): Promise<void> {\n if (!this.config.durable) {\n return;\n }\n\n const outcome = await persistAgentSnapshot({\n durable: this.config.durable,\n runId: this.runId,\n agentName: this.config.name ?? this.config.model.name,\n signature: this.config.signature,\n version: this.config.version,\n input: this.input,\n systemPrompt: this.systemPrompt,\n responseSchema: this.responseSchema,\n promptName: this.promptName,\n promptVersion: this.promptVersion,\n messages: this.captureMessages() as unknown as Message[],\n trips: this.trips,\n toolCalls: this.toolCalls,\n usage: this.usage,\n status,\n startedAt: this.startedAt.toISOString(),\n });\n\n if (!outcome.ok) {\n this.logger.warn(LOG_MODULE, \"snapshot.persist.failed\", \"durable snapshot persist failed\", {\n runId: this.runId,\n status,\n error: outcome.error instanceof Error ? outcome.error.message : String(outcome.error),\n });\n }\n }\n\n /**\n * Rebuild the final {@link AgentResult} from a COMPLETED snapshot\n * WITHOUT re-running anything. Used by the completed-run resume\n * short-circuit: the persisted trips / tool calls / usage are the\n * authoritative outcome, so a resume of a settled run re-returns that\n * outcome idempotently. Re-derives `this.data` from the final trip\n * output against the schema (cheap, no model call) so the rebuilt\n * result carries the same structured payload the original produced.\n *\n * Only reached for a `completed` snapshot — `failed` / `cancelled`\n * snapshots re-enter the trip loop to retry the remaining work instead.\n */\n private async rebuildResumedResult(_snapshot: AgentSnapshot): Promise<AgentResult<TOutput>> {\n await this.parseOutput();\n\n return this.buildResult();\n }\n\n /**\n * Normalize the accumulated runtime `Message[]` into the JSON-safe\n * {@link CapturedMessage}[] persisted on `AgentReport.messages` (F2).\n * Flattens `ContentPart[]` content to a string, and forwards\n * `toolCalls` (assistant turns) / `toolCallId` (tool-result turns)\n * only when present so the captured shape stays lean. Called only when\n * `captureMessages` is enabled.\n */\n private captureMessages(): CapturedMessage[] {\n return this.messages.map((message) => {\n const captured: CapturedMessage = {\n role: message.role,\n content:\n typeof message.content === \"string\"\n ? message.content\n : JSON.stringify(message.content),\n };\n\n if (message.toolCalls !== undefined) {\n captured.toolCalls = message.toolCalls;\n }\n\n if (message.toolCallId !== undefined) {\n captured.toolCallId = message.toolCallId;\n }\n\n return captured;\n });\n }\n\n /**\n * Normalize any thrown value into an `AIError`. `AIError` instances\n * pass through untouched; provider-adapter SDK errors are caught by\n * the adapter and already arrive typed, so this branch mainly\n * handles runtime crashes (TypeError, ReferenceError) inside\n * model.complete / model.stream and non-Error values (`throw \"bad\"`).\n */\n private toAIError(thrown: unknown): AIError {\n if (thrown instanceof AIError) {\n return thrown;\n }\n\n // Classify abort-flavored errors (DOMException \"AbortError\",\n // node-fetch's `FetchError` with name \"AbortError\", `ERR_CANCELED`\n // from the OpenAI SDK's axios-ish layer) as cancelled instead of\n // a generic exec failure so callers can route retries correctly.\n if (isAbortLike(thrown)) {\n return this.makeCancelledError();\n }\n\n const message = thrown instanceof Error ? thrown.message : String(thrown);\n\n return new AgentExecutionError(message, { cause: thrown });\n }\n\n /**\n * Build the typed cancelled error that both the trip-loop guard\n * and the mid-stream guard emit. Captures the abort reason when\n * one was supplied to `controller.abort(reason)` so logs and\n * telemetry can see what cancelled the run.\n */\n private makeCancelledError(): AgentCancelledError {\n const reason = this.options?.signal?.reason;\n const reasonText = reason === undefined ? \"\" : String(reason);\n\n return new AgentCancelledError(\"agent execution cancelled\", {\n cause: reason,\n cancelledAt: new Date().toISOString(),\n reason: reasonText,\n });\n }\n\n /**\n * Fire a single event through all three subscription tiers in order\n * — factory → instance → per-call — and mirror it into the\n * `StreamController` when streaming is active. A throwing user\n * handler must never crash the agent, so every dispatch is wrapped\n * in `safeCall`. Stream events are converted from the internal\n * `AgentEventMap` payload to the public `StreamEvent` shape because\n * some of them differ (e.g. the tool-called payload vs stream\n * event).\n */\n private emit<K extends keyof AgentEventMap>(\n event: K,\n payload: WithoutIdentity<AgentEventMap[K]>,\n ): void {\n // Inject run identity once, here, so every subscription tier and\n // the stream see it. `rootRunId === runId` for a standalone run;\n // nested propagation lands in a follow-up.\n const fullPayload = {\n ...payload,\n runId: this.runId,\n rootRunId: this.runId,\n } as AgentEventMap[K];\n\n this.logEvent(event, fullPayload);\n\n const onError = (error: unknown) => this.surfaceHandlerError(event, error);\n\n const factoryHandler = this.config.on?.[event] as AgentEventHandler<K> | undefined;\n\n if (factoryHandler) {\n safeCall(factoryHandler, fullPayload, onError);\n }\n\n const bucket = this.instanceHandlers?.get(event);\n\n if (bucket) {\n for (const handler of bucket) {\n safeCall(handler as AgentEventHandler<K>, fullPayload, onError);\n }\n }\n\n const perCallHandler = this.options?.on?.[event] as AgentEventHandler<K> | undefined;\n\n if (perCallHandler) {\n safeCall(perCallHandler, fullPayload, onError);\n }\n\n if (this.streamController) {\n const body = this.toStreamEvent(event, fullPayload);\n\n if (body) {\n this.streamController.push({\n runId: this.runId,\n rootRunId: this.runId,\n ...body,\n });\n }\n }\n }\n\n /**\n * Surface an isolated event-handler failure (C5). A throwing user\n * handler never crashes the agent — that isolation is preserved — but\n * total silence is the wrong default: a broken `on` handler would\n * otherwise disappear from production with no signal. Routed to the\n * structured logger (matching the `onUsage` / `onComplete` policy) and\n * warned at most once per event type so a hot event can't spam the log.\n */\n private surfaceHandlerError(event: keyof AgentEventMap, error: unknown): void {\n if (this.warnedHandlerEvents.has(event as string)) return;\n this.warnedHandlerEvents.add(event as string);\n\n this.logger.warn(LOG_MODULE, \"event.handler.error\", \"an event handler threw and was isolated\", {\n runId: this.runId,\n event: event as string,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n\n /**\n * Emit a structured log line for a lifecycle event. The action\n * string mirrors the event name with the `agent.` prefix stripped\n * (`agent.trip.started` → `trip.started`) so log grep filters and\n * event handlers read the same vocabulary. Level mapping follows\n * the convention documented on `@warlock.js/logger`'s `Logger`.\n */\n private logEvent<K extends keyof AgentEventMap>(event: K, payload: AgentEventMap[K]): void {\n const agentName = this.config.name || this.config.model.name;\n logAgentEvent(\n this.logger,\n {\n module: `${LOG_MODULE}.${agentName}`,\n maxTrips: this.maxTrips,\n modelName: this.config.model.name,\n totalUsage: this.usage,\n totalDurationMs: performance.now() - this.start,\n trips: this.trips,\n toolCalls: this.toolCalls,\n },\n event,\n payload,\n );\n }\n\n private toStreamEvent<K extends keyof AgentEventMap>(\n event: K,\n payload: AgentEventMap[K],\n ): StreamEventBody | undefined {\n return agentEventToStreamEvent(event, payload);\n }\n\n /**\n * Invoke the `onUsage` hook (when configured) with a flat payload\n * carrying stable identity. Awaits the handler so async ledger\n * writes complete before the next trip starts; swallows any throw\n * so consumer bugs cannot crash the agent. Sync handlers wrapped\n * via `Promise.resolve()` so the await is safe in either case.\n */\n private async fireUsageHook(tripIndex: number, tripUsage: Usage): Promise<void> {\n const handler = this.config.onUsage;\n if (!handler) return;\n\n const event: UsageEvent = {\n runId: this.runId,\n tripIndex,\n model: {\n name: this.config.model.name,\n provider: this.config.model.provider,\n },\n usage: { ...tripUsage },\n timestamp: new Date().toISOString(),\n };\n\n try {\n await Promise.resolve(handler(event));\n } catch (err) {\n this.logger.warn(LOG_MODULE, \"onUsage.hook.error\", \"onUsage handler threw\", {\n runId: this.runId,\n tripIndex,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n /**\n * Invoke the `onComplete` hook (when configured) once at the end\n * of every run. Receives the full `AgentResult` plus pre-extracted\n * `runId` and `durationMs`. Same swallow-and-log error policy as\n * `fireUsageHook`.\n */\n private async fireCompleteHook(result: AgentResult<TOutput>): Promise<void> {\n const handler = this.config.onComplete;\n if (!handler) return;\n\n const event: CompleteEvent<TOutput> = {\n result,\n runId: this.runId,\n durationMs: performance.now() - this.start,\n };\n\n try {\n await Promise.resolve(handler(event));\n } catch (err) {\n this.logger.warn(LOG_MODULE, \"onComplete.hook.error\", \"onComplete handler threw\", {\n runId: this.runId,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n}\n\n/**\n * Decide whether a guard-synthesized tool call duplicates a real one\n * the provider already streamed structurally. Match key is\n * `name + key-sorted JSON of input` so identical calls (regardless of\n * argument key order) collapse, but two legitimate calls to the same\n * tool with different inputs still both dispatch.\n */\nfunction isDuplicateToolCall(\n recovered: ModelToolCallRequest,\n realCalls: ReadonlyArray<ModelToolCallRequest>,\n): boolean {\n const recoveredKey = `${recovered.name}|${stableStringify(recovered.input)}`;\n\n for (const real of realCalls) {\n const realKey = `${real.name}|${stableStringify(real.input)}`;\n\n if (realKey === recoveredKey) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * `JSON.stringify` variant that sorts object keys at every nesting\n * level so structurally-equal inputs serialize to identical strings.\n * Used only for dedupe-key comparison; never surfaces to consumers.\n */\nfunction stableStringify(value: unknown): string {\n return JSON.stringify(value, (_key, val) => {\n if (val !== null && typeof val === \"object\" && !Array.isArray(val)) {\n const source = val as Record<string, unknown>;\n const sorted: Record<string, unknown> = {};\n\n for (const key of Object.keys(source).sort()) {\n sorted[key] = source[key];\n }\n\n return sorted;\n }\n\n return val;\n });\n}\n\n/**\n * Invoke a user-supplied event handler without letting exceptions\n * escape the agent. A throw is isolated (it never crashes the agent)\n * but no longer silent: the optional `onError` surfaces it — the agent\n * routes it to its structured logger, matching the swallow-and-log\n * policy of the `onUsage` / `onComplete` hooks (C5).\n */\nfunction safeCall<T>(\n handler: (payload: T) => void,\n payload: T,\n onError?: (error: unknown) => void,\n): void {\n try {\n handler(payload);\n } catch (error) {\n onError?.(error);\n }\n}\n\n/**\n * Resolve a tool's `action` declaration into a plain string for\n * inclusion in `ToolEventMeta`. Static strings pass through;\n * function-shaped actions are invoked with the model's raw,\n * pre-validation input (before `execute`'s schema validation runs).\n *\n * Defensive: if the user's callback throws, swallow and return\n * `undefined` rather than crashing the agent — UI strings are not\n * worth aborting an LLM dispatch over.\n */\nfunction resolveToolAction(\n tool: ToolContract<unknown, unknown>,\n input: unknown,\n): string | undefined {\n if (tool.action === undefined) return undefined;\n if (typeof tool.action === \"string\") return tool.action;\n try {\n return tool.action(input);\n } catch {\n return undefined;\n }\n}\n"],"mappings":"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"}
|