eve 0.71.2 → 0.72.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/README.md +22 -6
- package/dist/src/acp/adapter.js +1 -1
- package/dist/src/ai/decide.d.ts +7 -0
- package/dist/src/ai/decide.js +1 -0
- package/dist/src/channel/conversation-context.d.ts +4 -1
- package/dist/src/channel/invoke-tool.d.ts +41 -0
- package/dist/src/channel/invoke-tool.js +1 -0
- package/dist/src/channel/routes.d.ts +3 -0
- package/dist/src/chunks/{use-eve-agent-CFCaYnrI.js → use-eve-agent-C1GYGCtb.js} +698 -388
- package/dist/src/chunks/{use-eve-agent-DcDhXNv1.js → use-eve-agent-hZJ7CB8t.js} +698 -388
- package/dist/src/cli/commands/integration-setup.js +1 -1
- package/dist/src/cli/commands/registry.js +1 -1
- package/dist/src/cli/commands/trace-detail.d.ts +1 -1
- package/dist/src/cli/commands/trace-detail.js +1 -1
- package/dist/src/cli/dev/tui/runner.js +1 -1
- package/dist/src/cli/dev/tui/setup-flow.d.ts +1 -0
- package/dist/src/cli/dev/tui/setup-panel.d.ts +1 -0
- package/dist/src/cli/dev/tui/setup-panel.js +2 -1
- package/dist/src/cli/dev/tui/traces/trace-conversation.d.ts +2 -2
- package/dist/src/cli/dev/tui/traces/trace-conversation.js +2 -2
- package/dist/src/cli/dev/tui/transcript-parts.d.ts +2 -1
- package/dist/src/cli/dev/tui/transcript-parts.js +1 -1
- package/dist/src/cli/dev/tui/transcript.js +1 -1
- package/dist/src/cli/dev/tui/tui-prompter.js +1 -1
- package/dist/src/client/conversation-projection.d.ts +4 -0
- package/dist/src/client/conversation-projection.js +1 -0
- package/dist/src/client/conversation-reducer.js +1 -1
- package/dist/src/client/conversation-state.d.ts +5 -26
- package/dist/src/client/conversation-state.js +1 -1
- package/dist/src/client/index.d.ts +1 -0
- package/dist/src/client/index.js +1 -1
- package/dist/src/client/message-action-parts.d.ts +1 -11
- package/dist/src/client/message-action-parts.js +1 -1
- package/dist/src/client/message-reducer.d.ts +3 -1
- package/dist/src/client/message-reducer.js +1 -1
- package/dist/src/client/session-utils.js +1 -1
- package/dist/src/client/session.js +1 -1
- package/dist/src/client/tool-call-state.d.ts +23 -0
- package/dist/src/client/tool-call-state.js +1 -0
- package/dist/src/client/tool-part-state.d.ts +7 -0
- package/dist/src/client/tool-part-state.js +1 -0
- package/dist/src/compiled/.vendor-stamp.json +10 -10
- package/dist/src/compiled/@ai-sdk/anthropic/index.d.ts +1453 -1358
- package/dist/src/compiled/@ai-sdk/anthropic/index.js +1 -2
- package/dist/src/compiled/@ai-sdk/code-mode/index.d.ts +172 -163
- package/dist/src/compiled/@ai-sdk/code-mode/index.js +15 -20
- package/dist/src/compiled/@ai-sdk/google/index.d.ts +772 -733
- package/dist/src/compiled/@ai-sdk/google/index.js +6 -8
- package/dist/src/compiled/@ai-sdk/mcp/index.d.ts +887 -790
- package/dist/src/compiled/@ai-sdk/mcp/index.js +1 -1
- package/dist/src/compiled/@ai-sdk/openai/index.d.ts +1722 -1691
- package/dist/src/compiled/@ai-sdk/openai/index.js +3 -14
- package/dist/src/compiled/@ai-sdk/otel/index.d.ts +216 -159
- package/dist/src/compiled/@ai-sdk/otel/index.js +3 -3
- package/dist/src/compiled/@ai-sdk/provider/index.d.ts +7542 -7271
- package/dist/src/compiled/@ai-sdk/provider/index.js +1 -3
- package/dist/src/compiled/@ai-sdk/provider-utils/index.d.ts +1799 -1600
- package/dist/src/compiled/@eve/catalog/index.js +1 -1
- package/dist/src/compiled/_chunks/workflow/dist-DXLdlucM.js +15 -0
- package/dist/src/compiled/_chunks/workflow/experimental-decision-BrfWf6-n.js +3 -0
- package/dist/src/compiler/extension-compatibility.d.ts +36 -20
- package/dist/src/compiler/extension-compatibility.js +1 -1
- package/dist/src/compiler/manifest.js +1 -1
- package/dist/src/context/build-dynamic-tools.js +1 -1
- package/dist/src/context/caller-scope.d.ts +7 -0
- package/dist/src/context/caller-scope.js +1 -0
- package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
- package/dist/src/context/dynamic-tool-metadata.d.ts +1 -0
- package/dist/src/context/providers/session.js +1 -1
- package/dist/src/evals/define-eval.d.ts +1 -1
- package/dist/src/evals/judge.d.ts +1 -1
- package/dist/src/evals/judge.js +2 -2
- package/dist/src/evals/types.d.ts +8 -8
- package/dist/src/execution/cancel-descendant-turns-step.d.ts +1 -0
- package/dist/src/execution/cancel-descendant-turns-step.js +1 -1
- package/dist/src/execution/cancelled-model-call-batch.js +1 -1
- package/dist/src/execution/coordination-dispatch-shared.d.ts +2 -1
- package/dist/src/execution/coordination-dispatch-shared.js +1 -1
- package/dist/src/execution/coordination-dispatch-step.js +1 -1
- package/dist/src/execution/durable-session-read.d.ts +5 -0
- package/dist/src/execution/durable-session-read.js +1 -0
- package/dist/src/execution/durable-session-store.d.ts +4 -10
- package/dist/src/execution/durable-session-store.js +1 -1
- package/dist/src/execution/dynamic-connections.d.ts +3 -3
- package/dist/src/execution/dynamic-connections.js +1 -1
- package/dist/src/execution/dynamic-workflow/tool.js +1 -1
- package/dist/src/execution/invoke-tool.d.ts +35 -0
- package/dist/src/execution/invoke-tool.js +1 -0
- package/dist/src/execution/legacy-session/interrupt-step.js +1 -1
- package/dist/src/execution/legacy-session/snapshot.d.ts +3 -0
- package/dist/src/execution/legacy-session/snapshot.js +1 -1
- package/dist/src/execution/model-call-batching.js +1 -1
- package/dist/src/execution/node-step.d.ts +2 -0
- package/dist/src/execution/node-step.js +1 -1
- package/dist/src/execution/proxied-deliver-step.js +1 -1
- package/dist/src/execution/publish-session-events.d.ts +8 -0
- package/dist/src/execution/publish-session-events.js +1 -1
- package/dist/src/execution/sandbox/active-handles.d.ts +6 -0
- package/dist/src/execution/sandbox/active-handles.js +1 -1
- package/dist/src/execution/sandbox/ensure.js +1 -1
- package/dist/src/execution/session/active-turn.js +1 -1
- package/dist/src/execution/session/answer-caller.d.ts +15 -0
- package/dist/src/execution/session/answer-caller.js +1 -0
- package/dist/src/execution/session/checkpoint-migrations.js +1 -1
- package/dist/src/execution/session/finalization.js +1 -1
- package/dist/src/execution/session/handoff-steps.d.ts +3 -1
- package/dist/src/execution/session/handoff-steps.js +1 -1
- package/dist/src/execution/session/handoff.d.ts +1 -1
- package/dist/src/execution/session/handoff.js +1 -1
- package/dist/src/execution/session/pending-turn-state.d.ts +8 -3
- package/dist/src/execution/session/pending-turn-state.js +1 -1
- package/dist/src/execution/session/task-tool-tracing-step.d.ts +5 -0
- package/dist/src/execution/session/task-tool-tracing-step.js +1 -0
- package/dist/src/execution/session/turn-step-result.js +1 -1
- package/dist/src/execution/session/turn-step.js +1 -1
- package/dist/src/execution/session/turn-waiting-step.js +1 -1
- package/dist/src/execution/session/turn.d.ts +1 -0
- package/dist/src/execution/session/turn.js +1 -1
- package/dist/src/execution/settle-cancelled-turn-step.d.ts +4 -6
- package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
- package/dist/src/execution/tasks/start.d.ts +3 -3
- package/dist/src/execution/tasks/start.js +1 -1
- package/dist/src/execution/tasks/steps.d.ts +1 -1
- package/dist/src/execution/tasks/steps.js +1 -1
- package/dist/src/execution/terminal-session-completion-step.d.ts +7 -0
- package/dist/src/execution/terminal-session-completion-step.js +1 -1
- package/dist/src/execution/terminal-session-failure-step.js +1 -1
- package/dist/src/execution/tools/agent-router-workflow.js +1 -1
- package/dist/src/execution/tools/connection-tools.js +1 -1
- package/dist/src/execution/tools/workflow/authorization-completion.js +1 -1
- package/dist/src/execution/tools/workflow/harness-definition.js +1 -1
- package/dist/src/execution/tools/workflow/step-execution.js +1 -1
- package/dist/src/execution/tools/workflow/step.js +1 -1
- package/dist/src/execution/tools/workflow/withdraw-step.d.ts +7 -9
- package/dist/src/execution/tools/workflow/withdraw-step.js +1 -1
- package/dist/src/execution/workflow-runtime.js +1 -1
- package/dist/src/execution/workflow-trace-context.d.ts +2 -2
- package/dist/src/harness/authorization.d.ts +4 -2
- package/dist/src/harness/authorization.js +1 -1
- package/dist/src/harness/{compaction.js → compaction/engine.js} +1 -1
- package/dist/src/harness/compaction/step.d.ts +46 -0
- package/dist/src/harness/compaction/step.js +1 -0
- package/dist/src/harness/coordination.d.ts +32 -64
- package/dist/src/harness/coordination.js +1 -1
- package/dist/src/harness/current-messages.d.ts +1 -3
- package/dist/src/harness/current-messages.js +1 -1
- package/dist/src/harness/emission.d.ts +4 -52
- package/dist/src/harness/emission.js +1 -1
- package/dist/src/harness/execute-tool.d.ts +1 -0
- package/dist/src/harness/final-output.d.ts +5 -0
- package/dist/src/harness/final-output.js +1 -1
- package/dist/src/harness/hitl/approvals.d.ts +115 -0
- package/dist/src/harness/hitl/approvals.js +1 -0
- package/dist/src/harness/hitl/approved-call-callers.d.ts +14 -0
- package/dist/src/harness/hitl/approved-call-callers.js +1 -0
- package/dist/src/harness/hitl/approved-calls.d.ts +37 -0
- package/dist/src/harness/hitl/approved-calls.js +1 -0
- package/dist/src/harness/{session-limit-continuation.d.ts → hitl/budget-request.d.ts} +3 -1
- package/dist/src/harness/hitl/budget-request.js +1 -0
- package/dist/src/harness/hitl/budget.d.ts +21 -0
- package/dist/src/harness/hitl/budget.js +1 -0
- package/dist/src/harness/{approval-candidates.d.ts → hitl/candidates.d.ts} +13 -18
- package/dist/src/harness/hitl/candidates.js +1 -0
- package/dist/src/harness/hitl/coordinator.js +1 -0
- package/dist/src/harness/hitl/delivery.d.ts +37 -0
- package/dist/src/harness/hitl/delivery.js +1 -0
- package/dist/src/harness/hitl/index.d.ts +49 -0
- package/dist/src/harness/hitl/index.js +1 -0
- package/dist/src/harness/hitl/intake.d.ts +67 -0
- package/dist/src/harness/hitl/intake.js +1 -0
- package/dist/src/harness/{stale-input-responses.d.ts → hitl/stale-responses.d.ts} +5 -3
- package/dist/src/harness/hitl/stale-responses.js +3 -0
- package/dist/src/harness/inline-tool-authorization.d.ts +4 -0
- package/dist/src/harness/inline-tool-authorization.js +1 -1
- package/dist/src/harness/input-extraction.d.ts +1 -10
- package/dist/src/harness/input-extraction.js +1 -1
- package/dist/src/harness/input-request-resolution.d.ts +1 -5
- package/dist/src/harness/input-request-resolution.js +1 -1
- package/dist/src/harness/messages.js +1 -1
- package/dist/src/harness/model-call/call.d.ts +78 -0
- package/dist/src/harness/model-call/call.js +1 -0
- package/dist/src/harness/{model-call-error.d.ts → model-call/errors.d.ts} +1 -1
- package/dist/src/harness/model-call/failure.d.ts +52 -0
- package/dist/src/harness/model-call/failure.js +1 -0
- package/dist/src/harness/model-call/model.d.ts +18 -0
- package/dist/src/harness/model-call/model.js +1 -0
- package/dist/src/harness/model-call/recovery.d.ts +52 -0
- package/dist/src/harness/model-call/recovery.js +1 -0
- package/dist/src/harness/model-call/request.d.ts +30 -0
- package/dist/src/harness/model-call/request.js +3 -0
- package/dist/src/harness/model-call/response.d.ts +39 -0
- package/dist/src/harness/model-call/response.js +1 -0
- package/dist/src/harness/model-call/retry.d.ts +11 -0
- package/dist/src/harness/model-call/retry.js +1 -0
- package/dist/src/harness/model-call/run.d.ts +38 -0
- package/dist/src/harness/model-call/run.js +1 -0
- package/dist/src/harness/model-call/tools.d.ts +48 -0
- package/dist/src/harness/model-call/tools.js +1 -0
- package/dist/src/harness/model-call/usage.d.ts +23 -0
- package/dist/src/harness/model-call/usage.js +1 -0
- package/dist/src/harness/nested-actions.d.ts +2 -2
- package/dist/src/harness/provider-tools.d.ts +7 -3
- package/dist/src/harness/provider-tools.js +1 -1
- package/dist/src/harness/proxy-input-requests.d.ts +4 -12
- package/dist/src/harness/proxy-input-requests.js +1 -1
- package/dist/src/harness/session-machine/commit.d.ts +28 -0
- package/dist/src/harness/session-machine/commit.js +1 -0
- package/dist/src/harness/session-machine/current.d.ts +29 -0
- package/dist/src/harness/session-machine/current.js +1 -0
- package/dist/src/harness/session-machine/events.d.ts +6 -0
- package/dist/src/harness/session-machine/events.js +1 -0
- package/dist/src/harness/session-machine/resolver-events.d.ts +12 -0
- package/dist/src/harness/session-machine/resolver-events.js +1 -0
- package/dist/src/harness/session-machine/state.d.ts +47 -0
- package/dist/src/harness/session-machine/state.js +1 -0
- package/dist/src/harness/session-machine/transitions.d.ts +188 -0
- package/dist/src/harness/session-machine/transitions.js +1 -0
- package/dist/src/harness/session-machine/view.d.ts +58 -0
- package/dist/src/harness/session-machine/view.js +1 -0
- package/dist/src/harness/step/after-model.d.ts +7 -0
- package/dist/src/harness/step/after-model.js +1 -0
- package/dist/src/harness/step/context.d.ts +59 -0
- package/dist/src/harness/step/context.js +1 -0
- package/dist/src/harness/step/intake.d.ts +34 -0
- package/dist/src/harness/step/intake.js +1 -0
- package/dist/src/harness/step/prompt.d.ts +37 -0
- package/dist/src/harness/step/prompt.js +1 -0
- package/dist/src/harness/step-hooks.d.ts +8 -13
- package/dist/src/harness/step-hooks.js +1 -1
- package/dist/src/harness/tool-call-io.d.ts +25 -0
- package/dist/src/harness/tool-call-io.js +1 -0
- package/dist/src/harness/tool-loop.d.ts +7 -22
- package/dist/src/harness/tool-loop.js +1 -3
- package/dist/src/harness/tool-model-output.d.ts +1 -2
- package/dist/src/harness/tools.d.ts +14 -0
- package/dist/src/harness/tools.js +1 -1
- package/dist/src/harness/turn-tag-state.d.ts +1 -1
- package/dist/src/harness/types.d.ts +6 -0
- package/dist/src/instrumentation/ai-sdk-hook-bridge.d.ts +1 -1
- package/dist/src/instrumentation/ai-sdk-hook-bridge.js +1 -1
- package/dist/src/instrumentation/content.js +1 -1
- package/dist/src/instrumentation/dispatch.js +1 -1
- package/dist/src/instrumentation/lifecycle.d.ts +28 -52
- package/dist/src/instrumentation/native-events.d.ts +2 -1
- package/dist/src/instrumentation/native-events.js +1 -1
- package/dist/src/instrumentation/provider.d.ts +1 -1
- package/dist/src/instrumentation/runtime-context.d.ts +2 -3
- package/dist/src/instrumentation/runtime-context.js +1 -1
- package/dist/src/instrumentation/runtime.d.ts +11 -1
- package/dist/src/instrumentation/runtime.js +1 -1
- package/dist/src/instrumentation/state.d.ts +6 -1
- package/dist/src/instrumentation/state.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/attachments/limited-read.d.ts +16 -0
- package/dist/src/internal/attachments/limited-read.js +1 -0
- package/dist/src/internal/authored-definition/schema-backed.d.ts +2 -1
- package/dist/src/internal/authored-definition/schema-backed.js +1 -1
- package/dist/src/internal/gateway.d.ts +2 -0
- package/dist/src/internal/gateway.js +1 -1
- package/dist/src/internal/mcp/published-tools.d.ts +13 -0
- package/dist/src/internal/mcp/published-tools.js +1 -0
- package/dist/src/internal/mcp/request-trace-context.d.ts +12 -0
- package/dist/src/internal/mcp/request-trace-context.js +1 -0
- package/dist/src/internal/mcp/streamable-http-server.d.ts +7 -3
- package/dist/src/internal/mcp/streamable-http-server.js +1 -1
- package/dist/src/internal/model-auth/transport.d.ts +3 -3
- package/dist/src/internal/model-auth/transport.js +1 -1
- package/dist/src/internal/nitro/host/instrumentation-entry.js +2 -2
- package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
- package/dist/src/internal/nitro/routes/channel-request-instrumentation.js +1 -1
- package/dist/src/internal/nitro/routes/route-invoke-tool.d.ts +24 -0
- package/dist/src/internal/nitro/routes/route-invoke-tool.js +1 -0
- package/dist/src/models/auto.d.ts +5 -5
- package/dist/src/models/auto.js +2 -2
- package/dist/src/protocol/message.d.ts +7 -0
- package/dist/src/protocol/message.js +1 -1
- package/dist/src/protocol/session-projection.d.ts +159 -0
- package/dist/src/protocol/session-projection.js +1 -0
- package/dist/src/public/ai/index.d.ts +1 -1
- package/dist/src/public/ai/index.js +1 -1
- package/dist/src/public/channels/chat-sdk/attachment-refs.d.ts +15 -0
- package/dist/src/public/channels/chat-sdk/attachment-refs.js +1 -0
- package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +2 -2
- package/dist/src/public/channels/chat-sdk/messageToUserContent.d.ts +11 -5
- package/dist/src/public/channels/chat-sdk/messageToUserContent.js +1 -1
- package/dist/src/public/channels/discord/attachments.d.ts +15 -0
- package/dist/src/public/channels/discord/attachments.js +1 -0
- package/dist/src/public/channels/discord/discordChannel.js +1 -1
- package/dist/src/public/channels/discord/inbound.d.ts +13 -0
- package/dist/src/public/channels/discord/inbound.js +1 -1
- package/dist/src/public/channels/index.d.ts +1 -1
- package/dist/src/public/channels/linear/inbound-uploads.d.ts +21 -0
- package/dist/src/public/channels/linear/inbound-uploads.js +1 -0
- package/dist/src/public/channels/linear/linearChannel.js +1 -1
- package/dist/src/public/channels/linq/inboundContent.d.ts +7 -1
- package/dist/src/public/channels/linq/inboundContent.js +1 -1
- package/dist/src/public/channels/linq/linqChannel.js +1 -1
- package/dist/src/public/channels/mcp.d.ts +17 -2
- package/dist/src/public/channels/mcp.js +1 -1
- package/dist/src/public/channels/photon/attachments.d.ts +21 -0
- package/dist/src/public/channels/photon/attachments.js +1 -0
- package/dist/src/public/channels/photon/photonIMessageChannel.js +1 -1
- package/dist/src/public/channels/slack/attachments.d.ts +3 -1
- package/dist/src/public/channels/slack/attachments.js +1 -1
- package/dist/src/public/channels/slack/slackChannel.js +1 -1
- package/dist/src/public/channels/teams/attachments.d.ts +4 -4
- package/dist/src/public/channels/teams/attachments.js +1 -1
- package/dist/src/public/channels/telegram/attachments.js +1 -1
- package/dist/src/public/channels/twilio/api.d.ts +7 -0
- package/dist/src/public/channels/twilio/api.js +1 -1
- package/dist/src/public/channels/twilio/inbound.d.ts +7 -0
- package/dist/src/public/channels/twilio/inbound.js +2 -2
- package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
- package/dist/src/public/definitions/channel.d.ts +1 -0
- package/dist/src/public/definitions/connections/mcp.d.ts +1 -1
- package/dist/src/public/definitions/connections/openapi.d.ts +1 -1
- package/dist/src/public/models/openai/chatgpt/model.js +1 -1
- package/dist/src/react/index.d.ts +1 -0
- package/dist/src/react/index.js +1 -1
- package/dist/src/runtime/agent/mock-model-adapter.js +2 -2
- package/dist/src/runtime/connections/mcp-client.js +1 -1
- package/dist/src/runtime/connections/scoped-authorization.js +1 -1
- package/dist/src/runtime/resolve-tool.js +1 -1
- package/dist/src/setup/boxes/resolve-provisioning.d.ts +2 -0
- package/dist/src/setup/boxes/resolve-provisioning.js +1 -1
- package/dist/src/setup/cli/prompt-ui.d.ts +3 -0
- package/dist/src/setup/cli/prompt-ui.js +3 -1
- package/dist/src/setup/cli/select-component.d.ts +1 -0
- package/dist/src/setup/cli/select-component.js +1 -1
- package/dist/src/setup/flows/ensure-vercel-project.d.ts +2 -0
- package/dist/src/setup/flows/ensure-vercel-project.js +1 -1
- package/dist/src/setup/integrations/discord/api.js +1 -1
- package/dist/src/setup/integrations/web/auth-options.d.ts +4 -0
- package/dist/src/setup/integrations/web/auth-options.js +1 -0
- package/dist/src/setup/integrations/web/auth-scaffold.d.ts +7 -0
- package/dist/src/setup/integrations/web/auth-scaffold.js +1 -0
- package/dist/src/setup/integrations/web/provision-auth.d.ts +3 -0
- package/dist/src/setup/integrations/web/provision-auth.js +1 -0
- package/dist/src/setup/integrations/web/setup.d.ts +11 -6
- package/dist/src/setup/integrations/web/setup.js +3 -3
- package/dist/src/setup/prompter.d.ts +2 -0
- package/dist/src/setup/prompter.js +1 -1
- package/dist/src/setup/scaffold/create/add-to-project.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +2 -2
- package/dist/src/setup/scaffold/create/web-template.d.ts +3 -3
- package/dist/src/setup/scaffold/create/web-template.js +26 -8
- package/dist/src/setup/scaffold/update/web-options.js +1 -1
- package/dist/src/setup/vercel-project-api.d.ts +9 -0
- package/dist/src/setup/vercel-project-api.js +1 -1
- package/dist/src/setup/vercel-project.d.ts +4 -2
- package/dist/src/setup/vercel-project.js +0 -0
- package/dist/src/shared/web-search.d.ts +1 -1
- package/dist/src/subagents/adapter.js +1 -1
- package/dist/src/subagents/event-proxy-step.js +1 -1
- package/dist/src/subagents/hitl-proxy.d.ts +4 -28
- package/dist/src/subagents/hitl-proxy.js +1 -1
- package/dist/src/svelte/index.d.ts +2 -0
- package/dist/src/svelte/index.js +39 -2
- package/dist/src/svelte/use-eve-agent.js +1 -1
- package/dist/src/tools/approval/policies.d.ts +5 -5
- package/dist/src/tools/approval/policies.js +1 -1
- package/dist/src/tools/framework/agent.js +1 -1
- package/dist/src/tools/provided/agent-router.js +1 -1
- package/dist/src/tools/provided/ask-question-workflow.js +1 -1
- package/dist/src/tools/provided/ask-question.js +2 -2
- package/dist/src/tools/provided/bash.js +1 -1
- package/dist/src/tools/provided/framework-tool.d.ts +3 -0
- package/dist/src/tools/provided/framework-tool.js +1 -0
- package/dist/src/tools/provided/glob.js +2 -2
- package/dist/src/tools/provided/grep.js +2 -2
- package/dist/src/tools/provided/load-skill.js +1 -1
- package/dist/src/tools/provided/no-reply.js +1 -1
- package/dist/src/tools/provided/read-file.js +2 -2
- package/dist/src/tools/provided/sleep-workflow.js +1 -1
- package/dist/src/tools/provided/sleep.js +1 -1
- package/dist/src/tools/provided/task-cancel.js +1 -1
- package/dist/src/tools/provided/task-wait.js +1 -1
- package/dist/src/tools/provided/web-fetch.js +2 -2
- package/dist/src/tools/provided/web-search.js +1 -1
- package/dist/src/tools/provided/workflow.js +1 -1
- package/dist/src/tools/provided/write-file.js +2 -2
- package/dist/src/tracing/agent-approval-instrumentation.d.ts +2 -2
- package/dist/src/tracing/agent-approval-instrumentation.js +1 -1
- package/dist/src/tracing/agent-otel-provider.js +2 -2
- package/dist/src/tracing/agent-otel-usage.d.ts +1 -1
- package/dist/src/tracing/agent-otel-usage.js +1 -1
- package/dist/src/tracing/agent-span-contract.d.ts +8 -1
- package/dist/src/tracing/agent-span-contract.js +1 -1
- package/dist/src/tracing/agent-tool-instrumentation.d.ts +16 -5
- package/dist/src/tracing/agent-tool-instrumentation.js +1 -1
- package/dist/src/tracing/agent-trace-context-codec.js +1 -1
- package/dist/src/tracing/agent-trace-span-processor.js +1 -1
- package/dist/src/tracing/agent-trace-state.d.ts +8 -3
- package/dist/src/tracing/install-instrumentation-runtime.js +1 -1
- package/dist/src/tracing/invoke-tool-span.d.ts +61 -0
- package/dist/src/tracing/invoke-tool-span.js +1 -0
- package/dist/src/tracing/local-trace-analysis.js +1 -1
- package/dist/src/vue/index.d.ts +2 -0
- package/dist/src/vue/index.js +39 -2
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/agent-config.md +2 -2
- package/docs/channels/chat-sdk.mdx +3 -1
- package/docs/channels/custom.mdx +3 -0
- package/docs/channels/discord.mdx +5 -4
- package/docs/channels/eve.mdx +65 -0
- package/docs/channels/linear.mdx +1 -1
- package/docs/channels/linq.mdx +2 -0
- package/docs/channels/mcp.mdx +39 -1
- package/docs/channels/photon.mdx +5 -0
- package/docs/channels/teams.mdx +4 -7
- package/docs/channels/twilio.mdx +1 -1
- package/docs/concepts/built-in-tools.md +12 -0
- package/docs/concepts/sessions-runs-and-streaming.md +3 -3
- package/docs/connections/overview.mdx +1 -1
- package/docs/dynamic-configuration/meta.json +1 -1
- package/docs/evals/judge.mdx +16 -16
- package/docs/evals/overview.mdx +1 -1
- package/docs/guides/{evaluate.md → decide.md} +35 -35
- package/docs/guides/dynamic-capabilities.md +1 -1
- package/docs/guides/frontend/overview.mdx +3 -1
- package/docs/guides/hooks.md +1 -1
- package/docs/guides/instrumentation/instrumentation.mdx +23 -22
- package/docs/guides/instrumentation/otel.mdx +13 -2
- package/docs/reference/cli.md +4 -2
- package/docs/reference/typescript-api.md +4 -2
- package/docs/tools/human-in-the-loop.md +8 -4
- package/docs/tools/workflows.mdx +4 -4
- package/package.json +13 -11
- package/dist/src/ai/evaluate.d.ts +0 -7
- package/dist/src/ai/evaluate.js +0 -1
- package/dist/src/client/message-task-parts.d.ts +0 -8
- package/dist/src/client/message-task-parts.js +0 -1
- package/dist/src/compiled/_chunks/workflow/dist-C3ZE62yI.js +0 -25
- package/dist/src/compiled/_chunks/workflow/experimental-evaluation-Dm32egEG.js +0 -5
- package/dist/src/harness/active-turn-id.d.ts +0 -11
- package/dist/src/harness/active-turn-id.js +0 -1
- package/dist/src/harness/approval-candidates.js +0 -1
- package/dist/src/harness/approval-delivery-coordinator.js +0 -1
- package/dist/src/harness/cancelled-turn-emission.d.ts +0 -12
- package/dist/src/harness/cancelled-turn-emission.js +0 -1
- package/dist/src/harness/emission-state.d.ts +0 -26
- package/dist/src/harness/emission-state.js +0 -1
- package/dist/src/harness/held-requests.d.ts +0 -18
- package/dist/src/harness/held-requests.js +0 -1
- package/dist/src/harness/hitl/approval-input-requests.d.ts +0 -27
- package/dist/src/harness/hitl/approval-input-requests.js +0 -1
- package/dist/src/harness/hitl/pending-input-resolution.d.ts +0 -54
- package/dist/src/harness/hitl/pending-input-resolution.js +0 -1
- package/dist/src/harness/hitl/session-limit-input-requests.d.ts +0 -12
- package/dist/src/harness/hitl/session-limit-input-requests.js +0 -1
- package/dist/src/harness/input-requests.d.ts +0 -31
- package/dist/src/harness/input-requests.js +0 -1
- package/dist/src/harness/pending-input-batches.d.ts +0 -81
- package/dist/src/harness/pending-input-batches.js +0 -1
- package/dist/src/harness/session-limit-continuation.js +0 -1
- package/dist/src/harness/session-limit-enforcement.d.ts +0 -45
- package/dist/src/harness/session-limit-enforcement.js +0 -1
- package/dist/src/harness/stale-input-responses.js +0 -3
- package/dist/src/harness/workflow-dispatch.d.ts +0 -30
- package/dist/src/harness/workflow-dispatch.js +0 -1
- package/dist/src/public/channels/linear/inbound-images.d.ts +0 -19
- package/dist/src/public/channels/linear/inbound-images.js +0 -1
- package/dist/src/tracing/agent-action-instrumentation.d.ts +0 -25
- package/dist/src/tracing/agent-action-instrumentation.js +0 -1
- /package/dist/src/harness/{compaction.d.ts → compaction/engine.d.ts} +0 -0
- /package/dist/src/harness/{compaction-prompt.d.ts → compaction/prompt.d.ts} +0 -0
- /package/dist/src/harness/{compaction-prompt.js → compaction/prompt.js} +0 -0
- /package/dist/src/harness/{approval-delivery-coordinator.d.ts → hitl/coordinator.d.ts} +0 -0
- /package/dist/src/harness/{model-call-error.js → model-call/errors.js} +0 -0
|
@@ -12,7 +12,6 @@ interface ApprovalCandidateAuditRecord {
|
|
|
12
12
|
readonly status: ApprovalCandidateStatus;
|
|
13
13
|
readonly createdAt: number;
|
|
14
14
|
readonly completedAt?: number;
|
|
15
|
-
readonly eventEmitted?: boolean;
|
|
16
15
|
readonly expiresAt?: number;
|
|
17
16
|
readonly reason?: string;
|
|
18
17
|
}
|
|
@@ -24,11 +23,12 @@ export interface ApprovalResponderIdentity {
|
|
|
24
23
|
}
|
|
25
24
|
export interface ApprovalSettlementAuditRecord {
|
|
26
25
|
readonly actor: ApprovalResponderIdentity;
|
|
26
|
+
/** The approver's full auth, which the approved call runs as. Absent for cancellations. */
|
|
27
|
+
readonly approver?: SessionAuthContext;
|
|
27
28
|
readonly outcome: "allowed" | "cancelled";
|
|
28
29
|
readonly requestId: string;
|
|
29
30
|
readonly settledAt: number;
|
|
30
31
|
readonly candidateId?: string;
|
|
31
|
-
readonly eventEmitted?: boolean;
|
|
32
32
|
}
|
|
33
33
|
export interface ActiveApprovalCandidate {
|
|
34
34
|
readonly candidateId: string;
|
|
@@ -39,7 +39,6 @@ export interface ActiveApprovalCandidate {
|
|
|
39
39
|
readonly createdAt: number;
|
|
40
40
|
readonly expiresAt: number;
|
|
41
41
|
readonly authorizationChallenges?: readonly AuthorizationChallenge[];
|
|
42
|
-
readonly pendingEventEmitted?: boolean;
|
|
43
42
|
}
|
|
44
43
|
interface ApprovalStateTransition {
|
|
45
44
|
readonly changed: boolean;
|
|
@@ -55,21 +54,6 @@ export declare function createApprovalCandidate(input: {
|
|
|
55
54
|
readonly responder: SessionAuthContext;
|
|
56
55
|
readonly state: SessionStateMap | undefined;
|
|
57
56
|
}): ApprovalStateTransition;
|
|
58
|
-
/** Marks the pending candidate event as emitted. */
|
|
59
|
-
export declare function markApprovalCandidatePendingEventEmitted(input: {
|
|
60
|
-
readonly candidateId: string;
|
|
61
|
-
readonly state: SessionStateMap | undefined;
|
|
62
|
-
}): SessionStateMap | undefined;
|
|
63
|
-
/** Marks a terminal candidate history event as emitted. */
|
|
64
|
-
export declare function markApprovalCandidateHistoryEventEmitted(input: {
|
|
65
|
-
readonly candidateId: string;
|
|
66
|
-
readonly state: SessionStateMap | undefined;
|
|
67
|
-
}): SessionStateMap | undefined;
|
|
68
|
-
/** Marks a terminal settlement event as emitted. */
|
|
69
|
-
export declare function markApprovalSettlementEventEmitted(input: {
|
|
70
|
-
readonly requestId: string;
|
|
71
|
-
readonly state: SessionStateMap | undefined;
|
|
72
|
-
}): SessionStateMap | undefined;
|
|
73
57
|
/** Marks a candidate as waiting on a private authorization challenge. */
|
|
74
58
|
export declare function markApprovalCandidateAuthorizationRequired(input: {
|
|
75
59
|
readonly authorizationChallenges: readonly AuthorizationChallenge[];
|
|
@@ -115,4 +99,15 @@ export declare function getApprovalAuditState(state: SessionStateMap | undefined
|
|
|
115
99
|
readonly candidateHistory: readonly ApprovalCandidateAuditRecord[];
|
|
116
100
|
readonly settlements: readonly ApprovalSettlementAuditRecord[];
|
|
117
101
|
};
|
|
102
|
+
export declare function sameResponder(a: Pick<SessionAuthContext, "authenticator" | "issuer" | "principalId" | "principalType">, b: Pick<SessionAuthContext, "authenticator" | "issuer" | "principalId" | "principalType">): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* The held turn moved on, steered or cancelled: the responders still checking one of its
|
|
105
|
+
* approvals stop, their candidates stale.
|
|
106
|
+
*/
|
|
107
|
+
export declare function retireActiveCandidates(state: SessionStateMap | undefined, input: {
|
|
108
|
+
readonly completedAt: number;
|
|
109
|
+
readonly reason: string;
|
|
110
|
+
}): SessionStateMap | undefined;
|
|
111
|
+
/** The full auth of whoever approved `requestId`, when it was allowed. */
|
|
112
|
+
export declare function approverOfRequest(state: SessionStateMap | undefined, requestId: string): SessionAuthContext | undefined;
|
|
118
113
|
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const APPROVAL_STATE_KEY=`eve.runtime.hitl.approvalState`;function createApprovalCandidate(e){let t=expireApprovalCandidates({now:e.createdAt,state:e.state}),n=readApprovalState(t);if(n.settlements[e.requestId]!==void 0)return{changed:!1,state:t};let r=e.responder;if(Object.values(n.activeCandidates).find(t=>t.requestId===e.requestId&&t.decision===e.decision&&sameResponder(t.responder,r))!==void 0)return{changed:!1,state:t};let i=n.activeCandidates[e.candidateIdPrefix]!==void 0||n.candidateHistory.some(t=>t.candidateId===e.candidateIdPrefix)?`${e.candidateIdPrefix}.${n.nextCandidateSequence.toString(36)}`:e.candidateIdPrefix;if(n.activeCandidates[i]!==void 0||n.candidateHistory.some(e=>e.candidateId===i))throw Error(`Approval candidate id collision: "${i}".`);let a={candidateId:i,createdAt:e.createdAt,decision:e.decision,expiresAt:e.expiresAt,requestId:e.requestId,responder:r,status:`pending`};return{changed:!0,state:writeApprovalState(t,{...n,activeCandidates:{...n.activeCandidates,[a.candidateId]:a},nextCandidateSequence:n.nextCandidateSequence+1})}}function markApprovalCandidateAuthorizationRequired(e){let t=readApprovalState(e.state),n=t.activeCandidates[e.candidateId];if(n===void 0)return e.state;let r={...n,authorizationChallenges:e.authorizationChallenges,expiresAt:e.expiresAt??n.expiresAt,status:`authorization-required`};return writeApprovalState(e.state,{...t,activeCandidates:{...t.activeCandidates,[e.candidateId]:r}})}function finishApprovalCandidate(e){let t=readApprovalState(e.state),n=t.activeCandidates[e.candidateId];if(n===void 0)return e.state;let r={...t.activeCandidates};return delete r[e.candidateId],writeApprovalState(e.state,{...t,activeCandidates:r,candidateHistory:[...t.candidateHistory,toCandidateAuditRecord({candidate:n,completedAt:e.completedAt,reason:e.reason,status:e.status})]})}function expireApprovalCandidates(e){let t=e.state,n=Object.values(readApprovalState(t).activeCandidates);for(let r of n)r.expiresAt>e.now||(t=finishApprovalCandidate({candidateId:r.candidateId,completedAt:e.now,state:t,status:`timed-out`}));return t}function settleAllowedCandidate(e){let t=expireApprovalCandidates({now:e.settledAt,state:e.state}),n=readApprovalState(t),r=n.activeCandidates[e.candidateId];if(r===void 0){let r=n.candidateHistory.find(t=>t.candidateId===e.candidateId);if((r&&n.settlements[r.requestId])!==void 0)return{changed:!1,state:t};throw Error(`Unknown approval candidate "${e.candidateId}".`)}return settleRequest({candidateId:r.candidateId,outcome:r.decision===`cancel`?`cancelled`:`allowed`,requestId:r.requestId,responder:r.responder,settledAt:e.settledAt,state:t})}function settleDirectApprovalResponse(e){let t=expireApprovalCandidates({now:e.settledAt,state:e.state});return settleRequest({outcome:e.outcome,requestId:e.requestId,responder:e.actor,settledAt:e.settledAt,state:t})}function getActiveApprovalCandidate(e,t){return readApprovalState(e).activeCandidates[t]}function getApprovalAuditState(e){let t=readApprovalState(e);return{activeCandidates:Object.values(t.activeCandidates),candidateHistory:t.candidateHistory,settlements:Object.values(t.settlements)}}function settleRequest(e){let t=readApprovalState(e.state);if(t.settlements[e.requestId]!==void 0)return{changed:!1,state:e.state};let n={actor:projectResponder(e.responder),...e.outcome===`allowed`&&{approver:e.responder},candidateId:e.candidateId,outcome:e.outcome,requestId:e.requestId,settledAt:e.settledAt},r={},i=[...t.candidateHistory];for(let n of Object.values(t.activeCandidates)){if(n.requestId!==e.requestId){r[n.candidateId]=n;continue}i.push(toCandidateAuditRecord({candidate:n,completedAt:e.settledAt,status:n.candidateId===e.candidateId?`allowed`:`stale`}))}let a={activeCandidates:r,candidateHistory:i,nextCandidateSequence:t.nextCandidateSequence,settlements:{...t.settlements,[e.requestId]:n}};return{changed:!0,state:writeApprovalState(e.state,a)}}function toCandidateAuditRecord(e){let{authorizationChallenges:t,responder:n,...r}=e.candidate;return{...r,completedAt:e.completedAt,responder:projectResponder(n),reason:e.reason,status:e.status}}function projectResponder(e){return{authenticator:e.authenticator,issuer:e.issuer,principalId:e.principalId,principalType:e.principalType}}function sameResponder(e,t){return e.authenticator===t.authenticator&&e.issuer===t.issuer&&e.principalId===t.principalId&&e.principalType===t.principalType}function readActiveCandidates(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,{...t,decision:t.decision===`cancel`?`cancel`:`approve`}]))}function readApprovalState(e){let t=e?.[APPROVAL_STATE_KEY];if(typeof t!=`object`||!t)return{activeCandidates:{},candidateHistory:[],nextCandidateSequence:0,settlements:{}};let n=t;return{activeCandidates:typeof n.activeCandidates==`object`&&n.activeCandidates!==null?readActiveCandidates(n.activeCandidates):{},candidateHistory:Array.isArray(n.candidateHistory)?n.candidateHistory:[],nextCandidateSequence:typeof n.nextCandidateSequence==`number`&&Number.isSafeInteger(n.nextCandidateSequence)&&n.nextCandidateSequence>=0?n.nextCandidateSequence:deriveNextCandidateSequence(n),settlements:typeof n.settlements==`object`&&n.settlements!==null?n.settlements:{}}}function deriveNextCandidateSequence(e){return Object.keys(e.activeCandidates??{}).length+(Array.isArray(e.candidateHistory)?e.candidateHistory.length:0)}function writeApprovalState(e,t){return{...e,[APPROVAL_STATE_KEY]:t}}function retireActiveCandidates(e,t){let n=e;for(let e of getApprovalAuditState(n).activeCandidates)n=finishApprovalCandidate({candidateId:e.candidateId,completedAt:t.completedAt,reason:t.reason,state:n,status:`stale`});return n}function approverOfRequest(e,t){return readApprovalState(e).settlements[t]?.approver}export{approverOfRequest,createApprovalCandidate,expireApprovalCandidates,finishApprovalCandidate,getActiveApprovalCandidate,getApprovalAuditState,markApprovalCandidateAuthorizationRequired,retireActiveCandidates,sameResponder,settleAllowedCandidate,settleDirectApprovalResponse};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{contextStorage}from"#context/container.js";import{AuthKey,SessionKey}from"#context/keys.js";import{buildCallbackContext}from"#context/build-callback-context.js";import{buildApprovalResponseAuth,handleApprovalResponsePolicyError}from"#execution/tool-auth.js";import{suspendedSteps}from"#harness/session-machine/view.js";import{clearPendingAuthorization,getAuthorizationResult,getPendingAuthorization,isAuthorizationSignal}from"#harness/authorization.js";import{isApprovalRequest}from"#harness/input-request-class.js";import{createApprovalCandidate,expireApprovalCandidates,finishApprovalCandidate,getActiveApprovalCandidate,getApprovalAuditState,markApprovalCandidateAuthorizationRequired,sameResponder,settleAllowedCandidate,settleDirectApprovalResponse}from"#harness/hitl/candidates.js";async function coordinateApprovalDelivery(e){let t=e.now??Date.now(),n=getApprovalAuditState(e.session.state).activeCandidates.filter(e=>e.expiresAt<=t),r=n.flatMap(e=>e.authorizationChallenges?.map(e=>e.attemptId??e.candidateId??e.name)??[]),i=expireApprovalCandidates({now:t,state:e.session.state}),a={...e.session,state:clearPendingAuthorization(i,r)},o=getApprovalAuditState(a.state),s=suspendedSteps(a.state).filter(e=>e.requests.length>0),c=new Set(s.flatMap(e=>e.requests.map(e=>e.requestId))),l=o.settlements.filter(e=>c.has(e.requestId)),u=new Set(o.settlements.map(e=>e.requestId)),d=new Set([...u].filter(e=>!c.has(e))),f=hasResponseForRequest(e.stepInput,d),p=f?removeConsumedResponses(e.stepInput,d):e.stepInput;if(f&&l.length===0&&!hasMeaningfulInput(p))return deliveryResult(a,p,`park`);if(s.length===0)return deliveryResult(a,p);let m=p,h=new Set(s.flatMap(e=>e.responseAuthRequiredRequestIds??[])),g=s.flatMap(e=>e.requests),_=new Map(g.map(e=>[e.requestId,e])),v=[],y=[],b=new Set,x=!1,S=getApprovalAuditState(a.state).activeCandidates,C=[...m?.attributedInputResponses??[],...(m?.inputResponses??[]).map(e=>({auth:void 0,response:e}))];for(let{auth:e,response:n}of C){let r=_.get(n.requestId);if(r===void 0||!isApprovalRequest(r))continue;if(!h.has(n.requestId)){let r=contextStorage.getStore(),i=e===void 0?r?.get(AuthKey)??r?.get(SessionKey)?.auth.current??null:e,o=toCandidateDecision(n.optionId),s=suspendedSteps(a.state).find(e=>e.requests.some(e=>e.requestId===n.requestId))?.requester??null;if(i!==null&&o!==void 0&&s!==null&&!sameResponder(s,i)){b.add(n.requestId),y.push(`Only the person who requested this action can respond to this approval.`);continue}if(i!==null&&o!==void 0){let e=settleDirectApprovalResponse({actor:i,outcome:o===`approve`?`allowed`:`cancelled`,requestId:n.requestId,settledAt:t,state:a.state});a={...a,state:e.state},x||=e.changed}continue}b.add(n.requestId);let i=toCandidateDecision(n.optionId);if(i===void 0)continue;let o=e===void 0?buildCallbackContext().session.auth.current:e;if(o===null){y.push(`Authentication is required to respond to this approval.`);continue}let s=createApprovalCandidate({candidateIdPrefix:approvalCandidateIdPrefix(r.requestId,o,i),createdAt:t,decision:i,expiresAt:t+6e5,requestId:r.requestId,responder:o,state:a.state});a={...a,state:s.state},x||=s.changed}let w=removeConsumedResponses(m,b);if(b.size>0)return deliveryResult(a,w,x?`continue-coordination`:`continue`,[],y);if(x)return deliveryResult(a,w,`continue`,[],y);let T=new Set(getPendingAuthorization(a.state)?.challenges.map(e=>e.name)??[]);for(let n of S){if(n.status===`authorization-required`){let e=n.authorizationChallenges??[];if(!e.some(e=>getAuthorizationResult(e.name)!==void 0)){v.push(...e.filter(e=>!T.has(e.name)));continue}}let r=_.get(n.requestId);if(r===void 0||getActiveApprovalCandidate(a.state,n.candidateId)===void 0)continue;let i=await authorizeCandidate({candidateId:n.candidateId,decision:n.decision,now:t,request:r,responder:n.responder,session:a,tools:await e.prepareTools?.(r)??e.tools});a=i.session,x||=i.didCommit,v.push(...i.challenges);let o=getApprovalAuditState(a.state).settlements.find(e=>e.requestId===n.requestId);o!==void 0&&l.push(o)}let E=appendSettledResponses(w,l);return(x||n.length>0)&&getApprovalAuditState(a.state).activeCandidates.length===0?deliveryResult(a,E,`responses-completed`):l.length>0?deliveryResult(a,E,`continue`):x?deliveryResult(a,E,`continue-coordination`):deliveryResult(a,E,v.length>0?`authorization-required`:`continue`,v)}async function authorizeCandidate(e){let t={...e.session,state:expireApprovalCandidates({now:e.now,state:e.session.state})};if(getActiveApprovalCandidate(t.state,e.candidateId)===void 0)return{challenges:[],didCommit:!1,session:t};let n=e.tools.get(e.request.action.toolName)?.approval,r=n!==void 0&&typeof n!=`function`?n.response:void 0;if(r===void 0)return failCandidate({...e,reason:`Approval authorization is temporarily unavailable. Please try again.`,session:t});try{let n=buildCallbackContext(),i=await withAuthorizerTimeout(r({auth:buildApprovalResponseAuth({responder:e.responder,scope:e.candidateId}),request:{callId:e.request.action.callId,requestId:e.request.requestId,principal:suspendedSteps(t.state).find(t=>t.requests.some(t=>t.requestId===e.request.requestId))?.requester??null,toolInput:e.request.action.input,toolName:e.request.action.toolName},response:{decision:e.decision,principal:e.responder},session:{id:n.session.id,initiator:n.session.auth.initiator,parent:n.session.parent,turn:n.session.turn}}));if(i.status===`rejected`)return t={...t,state:finishApprovalCandidate({candidateId:e.candidateId,completedAt:e.now,reason:i.reason,state:t.state,status:`rejected`})},{challenges:[],didCommit:!0,session:t};if(i.status!==`allowed`)return failCandidate({...e,session:t});let a=settleAllowedCandidate({candidateId:e.candidateId,settledAt:e.now,state:t.state});return{challenges:[],didCommit:a.changed,session:{...t,state:a.state}}}catch(n){let r=await handleApprovalResponsePolicyError(n).catch(()=>void 0);if(isAuthorizationSignal(r)){let n=r.challenges.map(e=>Date.parse(e.challenge.expiresAt??``)).filter(Number.isFinite).sort((e,t)=>e-t)[0];return t={...t,state:markApprovalCandidateAuthorizationRequired({authorizationChallenges:r.challenges.map(t=>({...t,candidateId:e.candidateId})),candidateId:e.candidateId,expiresAt:n,state:t.state})},{challenges:r.challenges.map(t=>({...t,candidateId:e.candidateId})),didCommit:!0,session:t}}return failCandidate({...e,session:t})}}function failCandidate(e){let t=e.reason??`We couldn’t verify your response. Please try again.`;return{challenges:[],didCommit:!0,session:{...e.session,state:finishApprovalCandidate({candidateId:e.candidateId,completedAt:e.now,reason:t,state:e.session.state,status:`failed`})}}}function hasResponseForRequest(e,t){return e?.attributedInputResponses?.some(({response:e})=>t.has(e.requestId))===!0||e?.inputResponses?.some(e=>t.has(e.requestId))===!0}function hasMeaningfulInput(e){return e?.message!==void 0||(e?.attributedInputResponses?.length??0)>0||(e?.inputResponses?.length??0)>0||(e?.runtimeActionResults?.length??0)>0}function appendSettledResponses(e,t){if(t.length===0)return e;let n=new Set([...(e?.inputResponses??[]).map(e=>e.requestId),...(e?.attributedInputResponses??[]).map(({response:e})=>e.requestId)]),r=t.filter(e=>!n.has(e.requestId));return r.length===0?e:{...e,inputResponses:[...e?.inputResponses??[],...r.map(e=>({optionId:e.outcome===`allowed`?`approve`:`cancel`,requestId:e.requestId}))]}}function removeConsumedResponses(e,t){if(e===void 0)return;let n=(e.attributedInputResponses??[]).filter(({response:e})=>!t.has(e.requestId)),r=[...(e.inputResponses??[]).filter(e=>!t.has(e.requestId)),...n.map(({response:e})=>e)];return{...e,attributedInputResponses:void 0,inputResponses:r}}function deliveryResult(e,t,n=`continue`,r=[],i=[]){return{challenges:r,feedback:i,kind:n,session:e,stepInput:t}}function toCandidateDecision(e){if(e===`approve`)return`approve`;if(e===`cancel`||e===`deny`)return`cancel`}function approvalCandidateIdPrefix(e,t,n){let r=[t.authenticator,t.issuer??``,t.principalType,t.principalId].join(`:`),i=`${encodeCandidateIdPart(e)}.${encodeCandidateIdPart(r)}`;return n===`approve`?i:`${i}.${encodeCandidateIdPart(n)}`}function encodeCandidateIdPart(e){return Array.from(e,e=>e.codePointAt(0).toString(36)).join(`-`)}async function withAuthorizerTimeout(e){let t;try{return await Promise.race([Promise.resolve(e),new Promise((e,n)=>{t=setTimeout(()=>n(Error(`Approval response authorizer timed out.`)),1e4)})])}finally{t!==void 0&&clearTimeout(t)}}export{coordinateApprovalDelivery};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { UserContent } from "ai";
|
|
2
|
+
import type { StepInput } from "#harness/types.js";
|
|
3
|
+
import type { InputResponse } from "#shared/input.js";
|
|
4
|
+
import type { SuspendedStep } from "#harness/session-machine/state.js";
|
|
5
|
+
import type { SessionView } from "#harness/session-machine/view.js";
|
|
6
|
+
/**
|
|
7
|
+
* The delivery a step answers with: input queued behind earlier work joins it, unless the
|
|
8
|
+
* runtime still runs calls (queued input waits for them). A stale answer, to a request that
|
|
9
|
+
* already closed, never authorizes anything: a stale session-limit answer is dropped, and
|
|
10
|
+
* any other becomes plain text the model reads.
|
|
11
|
+
*/
|
|
12
|
+
export declare function deliver(view: SessionView, input: StepInput | undefined, options: {
|
|
13
|
+
readonly takeQueued: boolean;
|
|
14
|
+
}): {
|
|
15
|
+
readonly input?: StepInput;
|
|
16
|
+
readonly displayMessage?: string | UserContent;
|
|
17
|
+
readonly takeQueued: boolean;
|
|
18
|
+
};
|
|
19
|
+
export type ResolvedStepInput = StepInput & {
|
|
20
|
+
readonly messageConsumed?: boolean;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Plain text answers the only pending batch, unless a response policy must decide it. A channel
|
|
24
|
+
* that wraps the typed text in an envelope for the model attaches the text itself to answer with.
|
|
25
|
+
* The answer consumes the message and the context the channel sent about it: the model reads
|
|
26
|
+
* neither.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveTextInput(batch: Pick<SuspendedStep, "requests" | "responseAuthRequiredRequestIds">, stepInput: StepInput | undefined): ResolvedStepInput | undefined;
|
|
29
|
+
export declare function canonicalize(responses: readonly InputResponse[]): readonly InputResponse[];
|
|
30
|
+
export declare function hasInput(input: StepInput | undefined): boolean;
|
|
31
|
+
export declare function isEmptyInput(input: StepInput): boolean;
|
|
32
|
+
export declare function withoutResponses(input: ResolvedStepInput | undefined): StepInput | undefined;
|
|
33
|
+
/** The turn's own input: the message a plain-text answer didn't consume, and its context. */
|
|
34
|
+
export declare function turnInputOnly(input: ResolvedStepInput | undefined): StepInput | undefined;
|
|
35
|
+
/** What of the input isn't the turn's: answers, and the output the session asks for. */
|
|
36
|
+
export declare function withoutTurnInput(input: ResolvedStepInput | undefined): ResolvedStepInput;
|
|
37
|
+
export declare function compactInput(input: ResolvedStepInput | undefined): ResolvedStepInput;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{attachClientContext,readClientContext}from"#internal/client-context.js";import{readAnswerText}from"#internal/input-text.js";import{resolveTextToResponses}from"#channel/resolve-text.js";import{coalesceTurnInputs}from"#harness/messages.js";import{ownOpenRequestIds}from"#harness/session-machine/transitions.js";import{convertStaleResponsesToUserMessage,dropStaleSessionLimitContinuationResponses}from"#harness/hitl/stale-responses.js";function deliver(e,t,n){let r=n.takeQueued?e.turn.queued:void 0,i=r===void 0?t:t===void 0?r:coalesceTurnInputs(r,t),a=new Set([...ownOpenRequestIds(e),...e.turn.suspended.flatMap(e=>e.requests.map(e=>e.requestId))]),o=new Map(Object.values(e.projection.inputs).map(e=>[e.request.requestId,e.request])),s=convertStaleResponsesToUserMessage({pendingRequestIds:a,requests:o,stepInput:dropStaleSessionLimitContinuationResponses({pendingRequestIds:a,stepInput:i})});return s.kind===`converted`?{displayMessage:s.displayMessage,input:s.stepInput,takeQueued:n.takeQueued}:{input:s.stepInput,takeQueued:n.takeQueued}}function resolveTextInput(e,t){let n=readAnswerText(t);if(t===void 0||n===void 0)return t;let r=new Set(e.requests.map(e=>e.requestId));if(t.inputResponses?.some(e=>r.has(e.requestId)))return t;let i=new Set(e.responseAuthRequiredRequestIds??[]),a=resolveTextToResponses(n,e.requests.filter(e=>!i.has(e.requestId)));return a.length===0?t:compactInput({...t,context:void 0,inputResponses:[...t.inputResponses??[],...a],message:void 0,messageConsumed:!0})}function canonicalize(e){let t=new Map;for(let n of e)t.set(n.requestId,n);return[...t.values()]}function hasInput(e){return e?.message!==void 0||(e?.inputResponses?.length??0)>0}function isEmptyInput(e){return Object.keys(compactInput(e)).length===0}function withoutResponses(e){if(e===void 0)return;let{attributedInputResponses:t,inputResponses:n,messageConsumed:r,...i}=e;return i}function turnInputOnly(e){if(e===void 0)return;let t={};(e.context?.length??0)>0&&(t.context=e.context),e.message!==void 0&&e.messageConsumed!==!0&&(t.message=e.message);let n=attachClientContext(t,readClientContext(e));return isEmptyInput(n)?void 0:n}function withoutTurnInput(e){let t={};return(e?.inputResponses?.length??0)>0&&(t.inputResponses=e.inputResponses),e?.outputSchema!==void 0&&(t.outputSchema=e.outputSchema),t}function compactInput(e){if(e===void 0)return{};let t={};return(e.context?.length??0)>0&&(t.context=e.context),(e.inputResponses?.length??0)>0&&(t.inputResponses=e.inputResponses),e.message!==void 0&&(t.message=e.message),e.messageConsumed===!0&&(t.messageConsumed=!0),e.outputSchema!==void 0&&(t.outputSchema=e.outputSchema),attachClientContext(t,readClientContext(e))}export{canonicalize,compactInput,deliver,hasInput,isEmptyInput,resolveTextInput,turnInputOnly,withoutResponses,withoutTurnInput};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { ModelMessage } from "ai";
|
|
2
|
+
import type { resolveInlineAuthorizationInterrupt } from "#harness/inline-tool-authorization.js";
|
|
3
|
+
import type { StepCoordinates } from "#harness/session-machine/view.js";
|
|
4
|
+
import type { Step } from "#harness/step/context.js";
|
|
5
|
+
import type { HarnessSessionBase, StepResult } from "#harness/types.js";
|
|
6
|
+
import type { RuntimeWorkflowTaskRequest } from "#shared/action-types.js";
|
|
7
|
+
import type { InputRequest } from "#shared/input.js";
|
|
8
|
+
export { acceptHumanInput, admitApprovedWork, dispatchApprovedWorkflows, hasApprovedWork, runApprovedLocalCalls, type ApprovedWork, type HumanInputIntake, } from "./intake.js";
|
|
9
|
+
export { extractToolApprovalInputRequests } from "#harness/input-extraction.js";
|
|
10
|
+
export { hasRunnableQueue } from "./approvals.js";
|
|
11
|
+
/**
|
|
12
|
+
* A model step made calls that need a person's approval: the step parks on them beside any
|
|
13
|
+
* runtime calls it made. The turn holds for the answers, unless the runtime runs calls for it
|
|
14
|
+
* meanwhile, or queued input can already run.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parkOnApprovals(step: Step, input: {
|
|
17
|
+
readonly event: StepCoordinates;
|
|
18
|
+
readonly messages: readonly ModelMessage[];
|
|
19
|
+
readonly requests: readonly InputRequest[];
|
|
20
|
+
readonly tasks: readonly RuntimeWorkflowTaskRequest[];
|
|
21
|
+
/** The step made calls the runtime runs, so the turn waits on them instead. */
|
|
22
|
+
readonly waitsOnRuntime: boolean;
|
|
23
|
+
}): Promise<StepResult>;
|
|
24
|
+
/**
|
|
25
|
+
* A call the model step ran needs a sign-in: the calls that need it stop, and the model calls
|
|
26
|
+
* them again once it completes.
|
|
27
|
+
*/
|
|
28
|
+
export declare function stopForToolSignIn(step: Step, interrupt: NonNullable<ReturnType<typeof resolveInlineAuthorizationInterrupt>>): Promise<StepResult>;
|
|
29
|
+
/**
|
|
30
|
+
* The gate before each model call. A spent budget asks whether to continue when someone can
|
|
31
|
+
* answer, and fails the session otherwise. `messages` are the step's: they park with the prompt,
|
|
32
|
+
* so the input that triggered it survives into the turn that resumes.
|
|
33
|
+
*/
|
|
34
|
+
export declare function enforceBudget(step: Step, messages: readonly ModelMessage[]): Promise<StepResult | undefined>;
|
|
35
|
+
/**
|
|
36
|
+
* What a model call needs from the approvals: the keys `once()` approvals granted, and a note on
|
|
37
|
+
* the calls still awaiting approval, which a message may revise.
|
|
38
|
+
*/
|
|
39
|
+
export declare function humanInputContext(step: Step): {
|
|
40
|
+
readonly approvedTools: ReadonlySet<string>;
|
|
41
|
+
readonly pendingApprovalsNote?: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Drops what a cleared context owned: sign-in attempts and responders' approval progress. `clear`
|
|
45
|
+
* reported each close; relay routes for live tasks stay.
|
|
46
|
+
*/
|
|
47
|
+
export declare function discardClearedHumanInput<T extends HarnessSessionBase>(session: T): T;
|
|
48
|
+
/** The cancelled turn's responders stop checking its approvals: their candidates stale. */
|
|
49
|
+
export declare function retireCancelledCandidates<T extends HarnessSessionBase>(session: T): T;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{renderPendingApprovalsInstruction}from"./approval-prompt.js";import{grantedApprovalKeys,hasRunnableQueue,parkOnApprovals as parkOnApprovals$1,requestLimit,requireSignIn}from"./approvals.js";import{retireActiveCandidates}from"./candidates.js";import{checkSessionUsageLimit}from"./budget.js";import{acceptHumanInput,admitApprovedWork,dispatchApprovedWorkflows,hasApprovedWork,holdForInput,runApprovedLocalCalls}from"./intake.js";import{AuthKey,SessionKey}from"#context/keys.js";import{validateHarnessModelMessages}from"#harness/messages.js";import{fail}from"#harness/session-machine/transitions.js";import{clearPendingAuthorization}from"#harness/authorization.js";import{buildResponseAuthorizationTools}from"#context/build-dynamic-tools.js";import{extractToolApprovalInputRequests}from"#harness/input-extraction.js";async function parkOnApprovals(e,t){let n=parkOnApprovals$1(e.view(),{event:t.event,messages:t.messages,requests:t.requests,tasks:t.tasks,requester:currentRequester(e),responseAuthRequiredRequestIds:responsePolicyRequestIds(e,t.requests)});return await e.apply(n,[...e.session.history,...n.commit??[]]),t.waitsOnRuntime?{next:null,session:e.session}:hasRunnableQueue(e.view())?{next:e.runStep,session:e.session}:holdForInput(e)}async function stopForToolSignIn(e,t){return e.session={...e.session,history:validateHarnessModelMessages(t.history)},await e.apply(requireSignIn(e.view(),{callIdsByName:t.callIdsByName,challenges:t.challenges}),e.session.history),{held:{kind:`request`},next:null,session:e.session}}async function enforceBudget(e,t){let n=checkSessionUsageLimit({canAsk:e.emit!==void 0&&e.config.capabilities?.requestInput===!0,session:e.session,turnSequence:e.position().sequence});if(n.kind!==`within`)return n.kind===`ask`?(e.session={...e.session,history:validateHarnessModelMessages([...t])},await e.apply(requestLimit(e.view(),{request:n.request}),e.session.history),{next:null,session:e.session}):(await e.apply(fail(e.view(),{code:n.code,details:n.details,message:n.message,terminal:{sessionId:e.session.sessionId}})),{next:{done:!0,output:``},session:e.session})}function humanInputContext(e){let t=e.view(),n=responseTools(e);return{approvedTools:grantedApprovalKeys(t,e=>n.get(e.action.toolName)?.approvalKey?.(e.action.input)),pendingApprovalsNote:renderPendingApprovalsInstruction(t.turn.suspended.flatMap(e=>e.requests))}}function discardClearedHumanInput(e){let{"eve.runtime.hitl.approvalState":t,...n}=clearPendingAuthorization(e.state)??{};return{...e,state:Object.keys(n).length>0?n:void 0}}function responseTools(e){return buildResponseAuthorizationTools({authoredTools:e.config.tools,context:e.ctx})}function responsePolicyRequestIds(e,t){let n=responseTools(e);return t.filter(e=>{let t=n.get(e.action.toolName)?.approval;return t!==void 0&&typeof t!=`function`&&t.response!==void 0}).map(e=>e.requestId)}function currentRequester(e){return e.ctx?.get(AuthKey)??e.ctx?.get(SessionKey)?.auth.current??null}function retireCancelledCandidates(e){return{...e,state:retireActiveCandidates(e.state,{completedAt:Date.now(),reason:`Cancelled.`})}}export{acceptHumanInput,admitApprovedWork,discardClearedHumanInput,dispatchApprovedWorkflows,enforceBudget,extractToolApprovalInputRequests,hasApprovedWork,hasRunnableQueue,humanInputContext,parkOnApprovals,retireCancelledCandidates,runApprovedLocalCalls,stopForToolSignIn};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { SuspendedStep } from "#harness/session-machine/view.js";
|
|
2
|
+
import { type Step } from "#harness/step/context.js";
|
|
3
|
+
import type { HarnessToolMap, StepInput, StepResult } from "#harness/types.js";
|
|
4
|
+
import type { InstrumentationAttempt } from "#instrumentation/runtime.js";
|
|
5
|
+
/**
|
|
6
|
+
* What a delivery does before its turn runs. `stop` ends the step: the answers left nothing to
|
|
7
|
+
* run yet, so the turn holds, or a responder must sign in first. `run` carries the turn's input,
|
|
8
|
+
* without the answers the session took, and the approved work that runs once the turn opens.
|
|
9
|
+
*/
|
|
10
|
+
export type HumanInputIntake = {
|
|
11
|
+
readonly kind: "stop";
|
|
12
|
+
readonly result: StepResult;
|
|
13
|
+
} | {
|
|
14
|
+
readonly kind: "run";
|
|
15
|
+
readonly input: StepInput | undefined;
|
|
16
|
+
/** The message the turn receives, as the stream shows it. */
|
|
17
|
+
readonly message?: StepInput["message"];
|
|
18
|
+
/** A plain-text answer consumed the message, so the model never reads it. */
|
|
19
|
+
readonly consumedMessage: boolean;
|
|
20
|
+
/** The delivery carries input for a turn. */
|
|
21
|
+
readonly opensTurn: boolean;
|
|
22
|
+
readonly approved: ApprovedWork;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* What the delivery decided: the session-limit answer, and the tools approved calls run with.
|
|
26
|
+
* The calls themselves wait in their suspended steps until the turn's next model step.
|
|
27
|
+
*/
|
|
28
|
+
export interface ApprovedWork {
|
|
29
|
+
readonly limit?: {
|
|
30
|
+
readonly granted: boolean;
|
|
31
|
+
};
|
|
32
|
+
/** The tools a parked step's calls run with: those of the step that asked. */
|
|
33
|
+
readonly toolsOf: (step: SuspendedStep | undefined) => HarnessToolMap;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Answers what the session asked: approval answers pass the response policies, and the session
|
|
37
|
+
* decides which parked steps they resolve. Runs before the delivery joins its turn, so approved
|
|
38
|
+
* calls get the tools of the step that asked.
|
|
39
|
+
*/
|
|
40
|
+
export declare function acceptHumanInput(step: Step, input: StepInput | undefined, options: {
|
|
41
|
+
readonly takeQueued: boolean;
|
|
42
|
+
}): Promise<HumanInputIntake>;
|
|
43
|
+
/**
|
|
44
|
+
* Admits what a delivery decided before its turn calls the model: a session-limit answer grants a
|
|
45
|
+
* fresh budget or ends the turn tree, and a step its answers completed, as denials do, commits.
|
|
46
|
+
*/
|
|
47
|
+
export declare function admitApprovedWork(step: Step, work: ApprovedWork): Promise<void>;
|
|
48
|
+
/** Whether a suspended step holds approved calls that haven't run. */
|
|
49
|
+
export declare function hasApprovedWork(step: Step): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Approved workflow and agent calls join the runs their steps wait on, once the step has started
|
|
52
|
+
* and before its budget check. Returns whether any did: the turn then waits on the runtime, and
|
|
53
|
+
* approved local calls run after their results arrive.
|
|
54
|
+
*/
|
|
55
|
+
export declare function dispatchApprovedWorkflows(step: Step, work: ApprovedWork): Promise<boolean>;
|
|
56
|
+
/**
|
|
57
|
+
* Runs approved local calls once the step has started and its budget allows it, as the AI SDK ran
|
|
58
|
+
* them before the model read their results: each with the tools of the step that asked, as
|
|
59
|
+
* whoever approved it, and in the step's first attempt. A call that needs a sign-in holds the
|
|
60
|
+
* turn.
|
|
61
|
+
*/
|
|
62
|
+
export declare function runApprovedLocalCalls(step: Step, work: ApprovedWork, setAttemptScope: (scope: InstrumentationAttempt | undefined) => void): Promise<StepResult | undefined>;
|
|
63
|
+
/**
|
|
64
|
+
* The held turn holds on, for a person to act on its sign-in, approval, or the session-limit
|
|
65
|
+
* prompt; the session resumes it when they do.
|
|
66
|
+
*/
|
|
67
|
+
export declare function holdForInput(step: Step): Promise<StepResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{deliver,turnInputOnly,withoutTurnInput}from"./delivery.js";import{answer,approvingSteps,deferInput,dispatch,grantedApprovalKeys,requireSignIn,stepForRequest,withdrawSignIns}from"./approvals.js";import{getApprovalAuditState,retireActiveCandidates}from"./candidates.js";import{approversOf,setApprovedCallCallers}from"./approved-call-callers.js";import{runApprovedCalls}from"./approved-calls.js";import{coordinateApprovalDelivery}from"./coordinator.js";import{validateHarnessModelMessages}from"#harness/messages.js";import{activeTurnId}from"#harness/session-machine/view.js";import{bumpSessionRuntimeUsageLimits}from"#harness/turn-tag-state.js";import{collectDeferredCalls}from"#harness/coordination.js";import{approvedCalls,completeSignIn,hold,settle}from"#harness/session-machine/transitions.js";import{stepStartedForResolvers}from"#harness/session-machine/resolver-events.js";import{SessionLimitDeclinedError}from"#harness/turn-cancellation.js";import{resolveInlineAuthorizationInterrupt}from"#harness/inline-tool-authorization.js";import{buildResponseAuthorizationTools}from"#context/build-dynamic-tools.js";import{openTurn}from"#harness/step/context.js";import{prepareTurnInput}from"#harness/step/intake.js";import{placeTurnInput}from"#harness/step/prompt.js";async function acceptHumanInput(e,t,n){let{config:r,ctx:i}=e,a=r.signInCompletions??[];a.length>0&&await e.apply(completeSignIn(e.view(),{completions:a}));let o=deliver(e.view(),t,n),s=t?.message!==void 0||o.displayMessage!==void 0?await withdrawSteeredSignIns(e,o.input):o.input,c=new Map,l,restoreTools=async t=>{let n=t?.event??e.position(),a=`${n.turnId}:${n.stepIndex}`,o=c.get(a);if(o!==void 0&&l===a)return o;t!==void 0&&await r.prepareApprovalTurn?.(t.event),i!==void 0&&await r.resolveStepDynamicTools?.({ctx:i,event:stepStartedForResolvers({modelId:e.session.agent.modelReference?.id??`dynamic`,sequence:n.sequence,stepIndex:n.stepIndex,turnId:n.turnId}),messages:e.projectHistory(e.session.history)});let s=buildResponseAuthorizationTools({authoredTools:r.tools,context:i});return c.set(a,s),l=a,s},toolsOf=e=>(e&&c.get(`${e.event.turnId}:${e.event.stepIndex}`))??r.tools,u=e.view().signIns,d=await coordinateApprovalDelivery({session:e.session,stepInput:s,tools:r.tools,prepareTools:t=>restoreTools(stepForRequest(e.view(),t.requestId))});e.session=d.session;for(let t of approvingSteps(e.view(),d.stepInput))await restoreTools(t);let f=answer(e.view(),{approvalKey:t=>toolsOf(stepForRequest(e.view(),t.requestId)).get(t.action.toolName)?.approvalKey?.(t.action.input),delivery:d.stepInput,policy:{...d,audit:getApprovalAuditState(e.session.state),challengesAtStart:u},takeQueued:o.takeQueued});for(let t of f.resolved)await e.instrumentation?.publishInputResolutions({batch:t,sessionId:e.session.sessionId});await e.apply(f);let stop=e=>({kind:`stop`,result:e});switch(f.next){case`park`:return e.view().projection.activeTurnId===void 0?stop({next:null,session:e.session}):stop(await holdForInput(e));case`repeat`:return stop({next:e.runStep,session:e.session});case`sign-in`:return await e.apply(requireSignIn(e.view(),{challenges:d.challenges,queued:d.stepInput})),stop(held(e));case`defer-message`:{if(approvedCalls(e.view().turn).length>0){let t=turnInputOnly(f.input);return t!==void 0&&await e.apply(deferInput(e.view(),t)),stop({next:null,session:e.session})}let t=await prepareTurnInput(e,f.input,{consumedMessage:!1}),n=await openTurn(e,{input:[...t.ephemeral,...t.messages],message:o.displayMessage??f.input?.message});return n===void 0?(e.session={...e.session,history:validateHarnessModelMessages(placeTurnInput(e,e.session.history,t))},stop(await holdForInput(e))):stop(n)}}for(let t of e.view().turn.suspended)(t.approved?.length??0)>0&&await restoreTools(t);let p=f.resolved.some(e=>e.inputs.some(e=>e.request.kind===`tool-approval`)&&e.inputs.every(e=>e.response!==void 0))||approvedCalls(e.view().turn).length>0?turnInputOnly(f.input):void 0;return p!==void 0&&await e.apply(deferInput(e.view(),p)),{approved:{limit:f.limit,toolsOf},consumedMessage:f.consumedMessage===!0,input:p===void 0?f.input:withoutTurnInput(f.input),message:f.consumedMessage===!0||p!==void 0?void 0:o.displayMessage??o.input?.message,kind:`run`,opensTurn:hasTurnInput(o.input)||hasTurnInput(d.stepInput)}}async function admitApprovedWork(e,t){if(t.limit!==void 0){if(!t.limit.granted)throw new SessionLimitDeclinedError;e.session=bumpSessionRuntimeUsageLimits(e.session)}await e.apply(settle(e.view(),{results:[]}))}function hasApprovedWork(e){return approvedCalls(e.view().turn).length>0}async function dispatchApprovedWorkflows(e,t){let n=[],r=[];for(let i of e.view().turn.suspended){let a=t.toolsOf(i),o=(i.approved??[]).filter(e=>a.get(e.action.toolName)?.workflowId!==void 0);if(o.length===0)continue;r.push(...o);let s=collectDeferredCalls({session:e.session,toolCalls:o.map(({action:e})=>({input:e.input,toolCallId:e.callId,toolName:e.toolName})),tools:a,turnId:i.event.turnId});e.session=s.session,n.push(...s.workflowRequests)}return n.length!==0&&(await e.apply(dispatch(e.view(),{approvers:approversOf(r,e.session.state),tasks:n})),!0)}async function runApprovedLocalCalls(e,t,n){let r=e.view().turn.suspended.map(e=>{let n=t.toolsOf(e);return{requests:(e.approved??[]).filter(e=>n.get(e.action.toolName)?.workflowId===void 0),tools:n}}),i=r.flatMap(({requests:e})=>e);e.frameworkToolNames=new Set(r.flatMap(({tools:e})=>[...e].filter(([,e])=>e.frameworkTool===!0).map(([e])=>e))),setApprovedCallCallers(i,e.session.state);let a=e.position(),o=i.length===0?void 0:e.instrumentation?.prepareAttempt({isFrameworkTool:t=>e.frameworkToolNames.has(t),attemptIndex:0,stepIndex:a.stepIndex,turnId:activeTurnId(a)});o!==void 0&&n(o.scope);let s=await Promise.all(r.map(async({requests:t,tools:n})=>t.length===0?{settled:[],toolResults:[]}:await runApprovedCalls({abortSignal:e.config.abortSignal,approvedTools:grantedApprovalKeys(e.view(),e=>n.get(e.action.toolName)?.approvalKey?.(e.action.input)),messages:e.projectHistory(e.session.history),position:e.position(),publish:e.publish,requests:t,telemetry:o?.telemetry,tools:n})));await e.apply(settle(e.view(),{results:s.flatMap(e=>e.settled)}));let c=resolveInlineAuthorizationInterrupt({messages:[],toolResults:s.flatMap(e=>e.toolResults)});if(c!==void 0)return await e.apply(requireSignIn(e.view(),{callIdsByName:c.callIdsByName,challenges:c.challenges}),e.session.history),held(e)}const STEERED_SIGN_IN_REASON=`Cancelled because a new message arrived.`;async function holdForInput(e){return await e.apply(hold(e.view(),{on:`input`})),held(e)}function held(e){return{held:{kind:`request`},next:null,session:e.session}}async function withdrawSteeredSignIns(e,t){let n=[...new Set(e.view().signIns.map(e=>e.name))];return e.session={...e.session,state:retireActiveCandidates(e.session.state,{completedAt:Date.now(),reason:STEERED_SIGN_IN_REASON})},n.length===0?t:(await e.apply(withdrawSignIns(e.view(),STEERED_SIGN_IN_REASON)),{...t,context:[...t?.context??[],`Sign-in to ${n.join(`, `)} was cancelled because the user sent a new message instead. Ask to sign in again only if the new message still needs it.`]})}function hasTurnInput(e){return e===void 0?!1:e.message!==void 0||(e.inputResponses?.length??0)>0}export{acceptHumanInput,admitApprovedWork,dispatchApprovedWorkflows,hasApprovedWork,holdForInput,runApprovedLocalCalls};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { UserContent } from "ai";
|
|
2
2
|
import type { StepInput } from "#harness/types.js";
|
|
3
|
+
import type { InputRequest } from "#shared/input.js";
|
|
3
4
|
type StaleResponseConversion = {
|
|
4
5
|
readonly kind: "unchanged";
|
|
5
6
|
readonly stepInput?: StepInput;
|
|
@@ -31,14 +32,15 @@ export declare function dropStaleSessionLimitContinuationResponses(input: {
|
|
|
31
32
|
* Responses for pending requests stay structured; stale responses become
|
|
32
33
|
* plain user-message text. A stale response never reaches structured HITL
|
|
33
34
|
* processing, so a stale approval cannot authorize an earlier tool call.
|
|
34
|
-
* Request details
|
|
35
|
+
* Request details the session still knows are best-effort model context.
|
|
35
36
|
*
|
|
36
37
|
* Assumes {@link dropStaleSessionLimitContinuationResponses} already ran:
|
|
37
38
|
* stale continuation answers must never reach this conversion.
|
|
38
39
|
*/
|
|
39
40
|
export declare function convertStaleResponsesToUserMessage(input: {
|
|
40
|
-
readonly history: readonly ModelMessage[];
|
|
41
41
|
readonly pendingRequestIds: ReadonlySet<string>;
|
|
42
|
+
/** Requests the session still knows, by id, closed ones included. */
|
|
43
|
+
readonly requests: ReadonlyMap<string, InputRequest>;
|
|
42
44
|
readonly stepInput?: StepInput;
|
|
43
45
|
}): StaleResponseConversion;
|
|
44
46
|
export {};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{appendUserContent,normalizeUserContent}from"#harness/messages.js";import{isSessionLimitContinuationRequestId}from"#harness/hitl/budget-request.js";function dropStaleSessionLimitContinuationResponses(e){if(e.stepInput===void 0)return;let t=e.stepInput.inputResponses??[],n=e.stepInput.attributedInputResponses??[],keep=t=>e.pendingRequestIds.has(t)||!isSessionLimitContinuationRequestId(t),r=t.filter(e=>keep(e.requestId)),i=n.filter(({response:e})=>keep(e.requestId));if(r.length===t.length&&i.length===n.length)return e.stepInput;let{attributedInputResponses:a,inputResponses:o,...s}=e.stepInput,c=s;return r.length>0&&(c.inputResponses=r),i.length>0&&(c.attributedInputResponses=i),c}function convertStaleResponsesToUserMessage(e){if(e.stepInput===void 0)return{kind:`unchanged`};let t=e.stepInput.inputResponses??[],n=e.stepInput.attributedInputResponses??[];if(t.length===0&&n.length===0)return{kind:`unchanged`,stepInput:e.stepInput};let r=[],i=[],a=[];for(let n of t)(e.pendingRequestIds.has(n.requestId)?r:a).push(n);for(let t of n)e.pendingRequestIds.has(t.response.requestId)?i.push(t):a.push(t.response);if(a.length===0)return{kind:`unchanged`,stepInput:e.stepInput};let{requests:o}=e,s=appendOptionalUserContent(e.stepInput.message,formatModelMessage(a,o)),c=appendOptionalUserContent(e.stepInput.message,formatDisplayMessage(a,o)),{attributedInputResponses:l,inputResponses:u,...d}=e.stepInput,f={...d,message:s};return r.length>0&&(f.inputResponses=r),i.length>0&&(f.attributedInputResponses=i),{displayMessage:c,kind:`converted`,stepInput:f}}function formatModelMessage(e,t){let n=e.map(e=>{let n=t.get(e.requestId),r=n?.options?.find(t=>t.id===e.optionId),i={};if(e.optionId!==void 0&&(i.optionId=e.optionId),r!==void 0){let e={id:r.id,label:r.label};r.description!==void 0&&(e.description=r.description),i.selectedOption=e}e.text!==void 0&&(i.text=e.text);let a={requestId:e.requestId,response:i};return n?.kind===`tool-approval`&&(a.prompt=n.prompt,a.requestType=`approval`,a.toolName=n.action.toolName),a});return[`The user submitted the following response to an earlier interactive prompt.`,`Treat it as new input at the current point in the conversation and decide whether it is still relevant. This does not authorize an earlier action; request approval again if that action is still needed.`,JSON.stringify(n,null,2)].join(`
|
|
2
|
+
`)}function formatDisplayMessage(e,t){return e.map(e=>e.text!==void 0&&e.text.length>0?e.text:t.get(e.requestId)?.options?.find(t=>t.id===e.optionId)?.label??e.optionId??`Response to an earlier interactive prompt`).join(`
|
|
3
|
+
`)}function appendOptionalUserContent(e,t){let n=normalizeUserContent(e);return n===void 0?t:appendUserContent({appended:t,existing:n})}export{convertStaleResponsesToUserMessage,dropStaleSessionLimitContinuationResponses};
|
|
@@ -11,5 +11,9 @@ export declare function resolveInlineAuthorizationInterrupt(input: {
|
|
|
11
11
|
readonly toolResults: readonly TypedToolResult<ToolSet>[] | undefined;
|
|
12
12
|
}): {
|
|
13
13
|
readonly challenges: AuthorizationSignal["challenges"];
|
|
14
|
+
/** The calls each sign-in stopped, by the challenge's connection name. */
|
|
15
|
+
readonly callIdsByName: ReadonlyMap<string, readonly string[]>;
|
|
14
16
|
readonly history: ModelMessage[];
|
|
15
17
|
} | undefined;
|
|
18
|
+
/** Drops the given calls and their results, keeping protocol-complete sibling calls. */
|
|
19
|
+
export declare function withoutCalls(messages: readonly ModelMessage[], interruptedCallIds: ReadonlySet<string>): ModelMessage[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{contextStorage}from"#context/container.js";import{isAuthorizationSignal,isPendingAuthorizationToolOutput,resolveActiveAuthorizationChallenges}from"#harness/authorization.js";import{readToolInterrupt}from"#harness/tool-interrupts.js";function isInlineAuthorizationToolResult(e){return isPendingAuthorizationToolOutput(e.output)||readAuthorizationSignal(e)!==void 0}function resolveInlineAuthorizationInterrupt(e){let t=[],n=new Set;for(let
|
|
1
|
+
import{contextStorage}from"#context/container.js";import{isAuthorizationSignal,isPendingAuthorizationToolOutput,resolveActiveAuthorizationChallenges}from"#harness/authorization.js";import{readToolInterrupt}from"#harness/tool-interrupts.js";function isInlineAuthorizationToolResult(e){return isPendingAuthorizationToolOutput(e.output)||readAuthorizationSignal(e)!==void 0}function resolveInlineAuthorizationInterrupt(e){let t=[],n=new Set,r=new Map;for(let i of e.toolResults??[]){let e=readAuthorizationSignal(i);if(e!==void 0){t.push(e),n.add(i.toolCallId);for(let t of e.challenges){let e=r.get(t.name)??[];r.set(t.name,[...e,i.toolCallId])}}}if(t.length!==0)return{callIdsByName:r,challenges:resolveActiveAuthorizationChallenges(t.flatMap(e=>e.challenges)),history:withoutCalls(e.messages,n)}}function readAuthorizationSignal(e){let t=contextStorage.getStore(),n=t===void 0?void 0:readToolInterrupt(t,e.toolCallId);return n!==void 0&&isAuthorizationSignal(n)?n:isAuthorizationSignal(e.output)?e.output:void 0}function withoutCalls(e,t){return e.flatMap(e=>{if(e.role===`assistant`&&Array.isArray(e.content)){let n=e.content.some(e=>e.type===`tool-call`&&t.has(e.toolCallId)),r=e.content.filter(e=>e.type!==`tool-call`||!t.has(e.toolCallId)),i=r.some(e=>e.type===`tool-call`);return r.length===0||n&&!i?[]:[{...e,content:r}]}if(e.role===`tool`){let n=e.content.filter(e=>e.type!==`tool-result`||!t.has(e.toolCallId));return n.length===0?[]:[{...e,content:n}]}return[e]})}export{isInlineAuthorizationToolResult,resolveInlineAuthorizationInterrupt,withoutCalls};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ContentPart,
|
|
1
|
+
import type { ContentPart, ToolSet } from "ai";
|
|
2
2
|
import type { InputRequest } from "#shared/input.js";
|
|
3
3
|
/**
|
|
4
4
|
* Extracts tool approval input requests from AI SDK content parts that
|
|
@@ -8,12 +8,3 @@ export declare function extractToolApprovalInputRequests(input: {
|
|
|
8
8
|
readonly content: readonly ContentPart<ToolSet>[];
|
|
9
9
|
readonly excludedCallIds?: ReadonlySet<string>;
|
|
10
10
|
}): InputRequest[];
|
|
11
|
-
/**
|
|
12
|
-
* Recovers approval request metadata for submitted input response IDs from
|
|
13
|
-
* model history. The newest occurrence wins so compacted or repeated history
|
|
14
|
-
* does not replace the request that is closest to the current turn.
|
|
15
|
-
*/
|
|
16
|
-
export declare function extractHistoricalInputRequests(input: {
|
|
17
|
-
readonly history: readonly ModelMessage[];
|
|
18
|
-
readonly requestIds: ReadonlySet<string>;
|
|
19
|
-
}): ReadonlyMap<string, InputRequest>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z}from"#compiled/zod/index.js";import{toolCallDisplayName}from"#execution/tools/connection-target.js";import{createRuntimeToolCallActionFromToolCall}from"#harness/tool-call-action.js";const ToolCallDescriptorSchema=z.object({input:z.unknown(),toolCallId:z.string(),toolName:z.string()}),PersistedToolCallSchema=ToolCallDescriptorSchema.extend({type:z.literal(`tool-call`)}),ToolApprovalRequestSchema=z.object({approvalId:z.string(),isAutomatic:z.boolean().optional().catch(void 0),toolCall:ToolCallDescriptorSchema.optional().catch(void 0),toolCallId:z.string().optional().catch(void 0),type:z.literal(`tool-approval-request`)});function extractToolApprovalInputRequests(e){return extractApprovalRequests(e)}function extractApprovalRequests(e){let t=[],n=new Map;for(let t of e.content){let e=PersistedToolCallSchema.safeParse(t);e.success&&n.set(e.data.toolCallId,e.data)}for(let r of e.content){let i=ToolApprovalRequestSchema.safeParse(r);if(!i.success)continue;let a=i.data;if(
|
|
1
|
+
import{z}from"#compiled/zod/index.js";import{toolCallDisplayName}from"#execution/tools/connection-target.js";import{createRuntimeToolCallActionFromToolCall}from"#harness/tool-call-action.js";const ToolCallDescriptorSchema=z.object({input:z.unknown(),toolCallId:z.string(),toolName:z.string()}),PersistedToolCallSchema=ToolCallDescriptorSchema.extend({type:z.literal(`tool-call`)}),ToolApprovalRequestSchema=z.object({approvalId:z.string(),isAutomatic:z.boolean().optional().catch(void 0),toolCall:ToolCallDescriptorSchema.optional().catch(void 0),toolCallId:z.string().optional().catch(void 0),type:z.literal(`tool-approval-request`)});function extractToolApprovalInputRequests(e){return extractApprovalRequests(e)}function extractApprovalRequests(e){let t=[],n=new Map;for(let t of e.content){let e=PersistedToolCallSchema.safeParse(t);e.success&&n.set(e.data.toolCallId,e.data)}for(let r of e.content){let i=ToolApprovalRequestSchema.safeParse(r);if(!i.success)continue;let a=i.data;if(a.isAutomatic===!0)continue;let o=a.toolCall??(a.toolCallId===void 0?void 0:n.get(a.toolCallId));o!==void 0&&(e.excludedCallIds?.has(o.toolCallId)||t.push({action:createRuntimeToolCallActionFromToolCall({toolCall:o}),allowFreeform:!1,display:`confirmation`,kind:`tool-approval`,options:[{id:`approve`,label:`Approve`},{id:`cancel`,label:`Cancel`}],prompt:`Approve ${toolCallDisplayName(o.toolName,o.input)}?`,requestId:a.approvalId}))}return t}export{extractToolApprovalInputRequests};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PendingInputBatchEvent } from "#harness/
|
|
1
|
+
import type { StepCoordinates as PendingInputBatchEvent } from "#harness/session-machine/view.js";
|
|
2
2
|
import type { InputRequest, InputResponse } from "#shared/input.js";
|
|
3
3
|
export declare const TOOL_EXECUTION_DENIED_MESSAGE = "Tool execution was denied.";
|
|
4
4
|
type ApprovalTerminalStatus = "approved" | "denied" | "ignored" | "invalid";
|
|
@@ -10,10 +10,6 @@ export interface ResolvedInputBatch {
|
|
|
10
10
|
readonly response?: InputResponse;
|
|
11
11
|
}[];
|
|
12
12
|
}
|
|
13
|
-
export declare function buildResolvedInputBatch(batch: {
|
|
14
|
-
readonly event?: PendingInputBatchEvent;
|
|
15
|
-
readonly requests: readonly InputRequest[];
|
|
16
|
-
}, responses: readonly InputResponse[]): ResolvedInputBatch | undefined;
|
|
17
13
|
/**
|
|
18
14
|
* One request's terminal outcome once its batch resolves: an approval's
|
|
19
15
|
* decision, or whether a question received a response.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const TOOL_EXECUTION_DENIED_MESSAGE=`Tool execution was denied.`;function
|
|
1
|
+
const TOOL_EXECUTION_DENIED_MESSAGE=`Tool execution was denied.`;function resolveInputOutcome(e,t){return e===`tool-approval`?resolveApprovalOutcome(t).status:t===void 0?`ignored`:`answered`}function resolveApprovalOutcome(e){return e===void 0?{approved:!1,reason:`Ignored because the user continued without responding.`,status:`ignored`}:e.optionId===`approve`?{approved:!0,reason:void 0,status:`approved`}:e.optionId===`cancel`||e.optionId===`deny`?{approved:!1,reason:TOOL_EXECUTION_DENIED_MESSAGE,status:`denied`}:{approved:!1,reason:`Invalid approval response.`,status:`invalid`}}export{TOOL_EXECUTION_DENIED_MESSAGE,resolveApprovalOutcome,resolveInputOutcome};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{attachClientContext,readClientContext}from"#internal/client-context.js";import{attachInputText,readInputText}from"#internal/input-text.js";function createUserMessage(e,t,n){let r={content:t,kind:e,role:`user`};return n===void 0?r:{...r,metadata:n}}function createFrameworkUserMessage(e,t,n){return createUserMessage(e,t,n)}function isUserMessageKind(e){return e===`user`||isFrameworkMessageKind(e)}function isUserModelMessage(e){if(e.role!==`user`)return!1;let{kind:t}=e;return isUserMessageKind(t)}function isFrameworkUserMessage(e){return isUserModelMessage(e)&&e.kind!==`user`}function validateHarnessModelMessages(e){let t=[];for(let n of e){if(n.role!==`user`){t.push(n);continue}if(!isUserModelMessage(n))throw TypeError(`Expected every user-role model message to have a kind.`);t.push(n)}return t}function isFrameworkMessageKind(e){return e===`context.instruction`||e===`context.state`||e===`context.compaction`||e===`memory.load`||e===`execution.continuation`||e===`execution.retry`||e===`task.result`}function markFrameworkStepInput(e,t){return{...e,frameworkMessageKind:t}}function frameworkMessageKindForStepInput(e){if(e===void 0)return;let{frameworkMessageKind:t}=e;return isFrameworkMessageKind(t)?t:void 0}function coalesceTurnInputs(e,t){let n=coalesceInputResponses({a:e.inputResponses,b:t.inputResponses}),r=coalesceMessage({a:e.message,b:t.message}),i=coalesceContext({a:e.context,b:t.context}),a=coalesceFrameworkMessageKind({a:e,b:t}),o=coalesceContext({a:readClientContext(e),b:readClientContext(t)}),s=t.outputSchema??e.outputSchema,c={};n!==void 0&&(
|
|
1
|
+
import{attachClientContext,readClientContext}from"#internal/client-context.js";import{attachInputText,readInputText}from"#internal/input-text.js";function createUserMessage(e,t,n){let r={content:t,kind:e,role:`user`};return n===void 0?r:{...r,metadata:n}}function createFrameworkUserMessage(e,t,n){return createUserMessage(e,t,n)}function isUserMessageKind(e){return e===`user`||isFrameworkMessageKind(e)}function isUserModelMessage(e){if(e.role!==`user`)return!1;let{kind:t}=e;return isUserMessageKind(t)}function isFrameworkUserMessage(e){return isUserModelMessage(e)&&e.kind!==`user`}function validateHarnessModelMessages(e){let t=[];for(let n of e){if(n.role!==`user`){t.push(n);continue}if(!isUserModelMessage(n))throw TypeError(`Expected every user-role model message to have a kind.`);t.push(n)}return t}function isFrameworkMessageKind(e){return e===`context.instruction`||e===`context.state`||e===`context.compaction`||e===`memory.load`||e===`execution.continuation`||e===`execution.retry`||e===`task.result`}function markFrameworkStepInput(e,t){return{...e,frameworkMessageKind:t}}function frameworkMessageKindForStepInput(e){if(e===void 0)return;let{frameworkMessageKind:t}=e;return isFrameworkMessageKind(t)?t:void 0}function coalesceTurnInputs(e,t){let n=coalesceInputResponses({a:e.inputResponses,b:t.inputResponses}),r=coalesceMessage({a:e.message,b:t.message}),i=coalesceContext({a:e.context,b:t.context}),a=coalesceFrameworkMessageKind({a:e,b:t}),o=coalesceContext({a:readClientContext(e),b:readClientContext(t)}),s=t.outputSchema??e.outputSchema,c=[...e.attributedInputResponses??[],...t.attributedInputResponses??[]],l={};n!==void 0&&(l.inputResponses=n),c.length>0&&(l.attributedInputResponses=c),r!==void 0&&(l.message=r),i!==void 0&&(l.context=i),s!==void 0&&(l.outputSchema=s);let u=normalizeUserContent(e.message)===void 0?readInputText(t):normalizeUserContent(t.message)===void 0?readInputText(e):void 0;return attachClientContext(attachInputText(a===void 0?l:markFrameworkStepInput(l,a),u),o)}function normalizeUserContent(e){if(e===void 0)return;if(typeof e==`string`)return e.trim().length>0?e:void 0;let t=e.filter(e=>e.type!==`text`||e.text.trim().length>0);if(t.length!==0)return t.length===e.length?e:t}const TOOL_RESULT_BOUNDARY=`…`;function followsToolResults(e){return e.findLast(e=>e.role!==`user`)?.role===`tool`}function createTurnInputMessages(e){let t=[...readClientContext(e)??[],...e?.context??[]].map(e=>createFrameworkUserMessage(`context.instruction`,e)),n=normalizeUserContent(e?.message);if(n===void 0)return t;let r=frameworkMessageKindForStepInput(e);return[...t,r===void 0?createUserMessage(`user`,n):createFrameworkUserMessage(r,n)]}function normalizeModelMessages(e){return e.flatMap(e=>{if(typeof e.content==`string`)return e.content.trim().length>0?[e]:[];let t=e.content.filter(e=>e.type!==`text`||e.text.trim().length>0);return t.length===0?[]:t.length===e.content.length?[e]:[{...e,content:t}]})}function resolveAssistantStepText(e,t){for(let t=e.length-1;t>=0;--t){let n=e[t];if(n?.role!==`assistant`)continue;let r=extractMessageText(n);if(r.trim().length>0)return r}return t!==void 0&&t.trim().length>0?t:null}function extractMessageText(e){return typeof e.content==`string`?e.content:Array.isArray(e.content)?e.content.flatMap(e=>typeof e==`string`?[e]:`type`in e&&e.type===`text`&&typeof e.text==`string`?[e.text]:[]).join(``):``}function coalesceInputResponses(e){let t=e.a??[],n=e.b??[];if(t.length!==0||n.length!==0)return[...t,...n]}function coalesceContext(e){let t=e.a??[],n=e.b??[];if(t.length!==0||n.length!==0)return[...t,...n]}function coalesceFrameworkMessageKind(e){let t=frameworkMessageKindForStepInput(e.a),n=frameworkMessageKindForStepInput(e.b);return e.a.message===void 0?n:e.b.message===void 0||t===n?t:void 0}function coalesceMessage(e){let t=normalizeUserContent(e.a),n=normalizeUserContent(e.b);return t===void 0?n:n===void 0?t:appendUserContent({appended:n,existing:t})}function appendUserContent(e){return typeof e.existing==`string`&&typeof e.appended==`string`?`${e.existing}\n\n${e.appended}`:[...toUserContentArray(e.existing),...toUserContentArray(e.appended)]}function toUserContentArray(e){return typeof e==`string`?e.length>0?[{type:`text`,text:e}]:[]:Array.isArray(e)?[...e]:[]}function coalesceDeliveries(e){let[t,...n]=e;if(t===void 0)throw Error(`Cannot coalesce an empty delivery batch.`);let r=t.auth,i=t.caller,a=[...t.payloads],o=[...t.deliveryMetadata??[]];for(let e of n){let t=a.length;if(e.auth!==void 0&&(r=e.auth),e.caller!==void 0){if(i!==void 0&&i.callId!==e.caller.callId)throw Error(`Cannot coalesce deliveries from different turns.`);i=e.caller}a.push(...e.payloads),o.push(...(e.deliveryMetadata??[]).map(e=>({...e,payloadIndex:e.payloadIndex+t})))}return{...t,auth:r,caller:i,deliveryMetadata:o.length===0?void 0:o,payloads:a}}export{TOOL_RESULT_BOUNDARY,appendUserContent,coalesceDeliveries,coalesceTurnInputs,createFrameworkUserMessage,createTurnInputMessages,createUserMessage,followsToolResults,frameworkMessageKindForStepInput,isFrameworkMessageKind,isFrameworkUserMessage,isUserMessageKind,isUserModelMessage,markFrameworkStepInput,normalizeModelMessages,normalizeUserContent,resolveAssistantStepText,validateHarnessModelMessages};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type LanguageModel, type ModelMessage } from "ai";
|
|
2
|
+
import type { GenerationSteering } from "#harness/generation-steering.js";
|
|
3
|
+
import type { HarnessModelMessage, UserModelMessage } from "#harness/messages.js";
|
|
4
|
+
import { type AnthropicCacheMarker, type PromptCachePath } from "#harness/prompt-cache.js";
|
|
5
|
+
import type { Step } from "#harness/step/context.js";
|
|
6
|
+
import { type Prompt } from "#harness/step/prompt.js";
|
|
7
|
+
import { type HarnessStepResult } from "#harness/step-hooks.js";
|
|
8
|
+
import type { StepResult } from "#harness/types.js";
|
|
9
|
+
import type { InstrumentationAttempt } from "#instrumentation/runtime.js";
|
|
10
|
+
import { type RequestMessages } from "./request.js";
|
|
11
|
+
import { type ModelTools } from "./tools.js";
|
|
12
|
+
/** How one attempt differs from the step's first: what recovery and retries change. */
|
|
13
|
+
export interface ModelCallOptions {
|
|
14
|
+
readonly disabledProviderTools?: ReadonlySet<string>;
|
|
15
|
+
readonly extraSystemNote?: string;
|
|
16
|
+
readonly retryReason?: "empty-response";
|
|
17
|
+
readonly suppressStepStartedEmission?: boolean;
|
|
18
|
+
readonly trailingUserNote?: string;
|
|
19
|
+
}
|
|
20
|
+
/** What a model step's caller needs from the step. */
|
|
21
|
+
interface ModelCallerInput {
|
|
22
|
+
readonly model: LanguageModel;
|
|
23
|
+
readonly generation: GenerationSteering;
|
|
24
|
+
readonly hidesHeldText: boolean;
|
|
25
|
+
readonly turnMessages: readonly UserModelMessage[];
|
|
26
|
+
readonly approvedTools: ReadonlySet<string>;
|
|
27
|
+
readonly pendingApprovalsNote: string | undefined;
|
|
28
|
+
/** The prompt as the step started it, projected for the model. */
|
|
29
|
+
readonly projectedMessages: HarnessModelMessage[];
|
|
30
|
+
readonly startStep: (messages: readonly ModelMessage[]) => Promise<void>;
|
|
31
|
+
readonly setAttemptScope: (scope: InstrumentationAttempt | undefined) => void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Calls the model for one step. Each attempt rebuilds the tools, the request, and the agent, so an
|
|
35
|
+
* earlier stream can't resolve a retry's one-shot step hooks with stale partial output. An attempt
|
|
36
|
+
* may first compact the prompt, which rewrites the durable messages the step later commits.
|
|
37
|
+
*/
|
|
38
|
+
export declare class ModelCaller {
|
|
39
|
+
readonly cachePath: PromptCachePath;
|
|
40
|
+
readonly marker: AnthropicCacheMarker | undefined;
|
|
41
|
+
private readonly attributionHeaders;
|
|
42
|
+
/** The prompt as the model reads it, projected for its history view. */
|
|
43
|
+
private projectedMessages;
|
|
44
|
+
/** The latest attempt's request; its history is what the step commits. */
|
|
45
|
+
request: RequestMessages;
|
|
46
|
+
/** The latest attempt's tools, which decide how the step's calls defer and end the turn. */
|
|
47
|
+
tools: ModelTools | undefined;
|
|
48
|
+
/** The messages the latest attempt sent, after attachments were hydrated. */
|
|
49
|
+
modelMessages: ModelMessage[];
|
|
50
|
+
requestEnvelopeTokens: number;
|
|
51
|
+
/** Usage of a call steering interrupted, which the steered step still counts. */
|
|
52
|
+
private interruptedUsage;
|
|
53
|
+
private compactionFailure;
|
|
54
|
+
private attemptIndex;
|
|
55
|
+
private readonly step;
|
|
56
|
+
private readonly prompt;
|
|
57
|
+
private readonly input;
|
|
58
|
+
constructor(step: Step, prompt: Prompt, input: ModelCallerInput);
|
|
59
|
+
/** Calls the model, retrying transient failures. */
|
|
60
|
+
call(options: ModelCallOptions): Promise<HarnessStepResult>;
|
|
61
|
+
/** A failed compaction fails the step, whatever recovery the call attempted. */
|
|
62
|
+
throwIfCompactionFailed(): void;
|
|
63
|
+
/** Steering interrupted the call: the step ends with what it committed, and runs again. */
|
|
64
|
+
steered(): Promise<StepResult>;
|
|
65
|
+
/** The step's result counted its usage, so an interrupted call's usage no longer applies. */
|
|
66
|
+
clearInterruptedUsage(): void;
|
|
67
|
+
private buildRequest;
|
|
68
|
+
private instructions;
|
|
69
|
+
private prepare;
|
|
70
|
+
/** Compacts the prompt when it's over the threshold, then rebuilds what depends on it. */
|
|
71
|
+
private compact;
|
|
72
|
+
private attempt;
|
|
73
|
+
/** Streams the call, publishing its content as it arrives. */
|
|
74
|
+
private stream;
|
|
75
|
+
/** Runs the call without a listener: nothing streams. */
|
|
76
|
+
private generate;
|
|
77
|
+
}
|
|
78
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{buildGatewayAttributionHeaders}from"./model.js";import{isEmptyModelResponse,rethrowNoOutputAsEmptyResponse}from"./recovery.js";import{modelInstructions,requestMessages,withTrailingUserNote}from"./request.js";import{answerSkippedToolCalls,appendMissingToolResultMessages,extractToolResultCallIds,withAccumulatedResponseMessages}from"./response.js";import{runModelCallWithRetries}from"./retry.js";import{logToolExecutionError,prepareModelTools}from"./tools.js";import{extractGatewayCostUsd,extractTokenUsageDelta}from"./usage.js";import{ToolLoopAgent,isStepCount}from"ai";import{createLogger,logError}from"#internal/logging.js";import{AuthKey,HistoryStateKey}from"#context/keys.js";import{createStepCompletedEvent}from"#protocol/message.js";import{activeTurnId}from"#harness/session-machine/view.js";import{accumulateTurnUsage,getTurnUsageState,setTurnUsageState}from"#harness/turn-tag-state.js";import{hydrateSandboxAttachments,moveToolResultFilesToUserMessages}from"#harness/attachment-staging.js";import{throwIfTurnAborted}from"#harness/turn-cancellation.js";import{summarizeKnownError}from"#harness/semantic-errors/index.js";import{estimateTokens}from"#harness/token-estimate.js";import{estimateRequestEnvelope}from"#harness/request-envelope.js";import{workingTaskIds}from"#execution/tasks/model-step.js";import{ContentFilteredModelResponseError,EmptyModelResponseError}from"#harness/model-call/errors.js";import{interruptStreamOnFailure}from"#harness/interruptible-stream.js";import{buildToolApproval}from"#harness/tools.js";import{compactPrompt,projectPrompt,withClientContext}from"#harness/step/prompt.js";import{emitStreamContent}from"#harness/emission.js";import{FINAL_OUTPUT_TOOL_NAME}from"#harness/final-output.js";import{detectPromptCachePath,getAnthropicCacheMarker}from"#harness/prompt-cache.js";import{buildStepHooks,emitStepActions,readGatewayGenerationId}from"#harness/step-hooks.js";import{maybeCompact}from"#harness/compaction/step.js";const environment=process.env.NODE_ENV??`unknown`,log=createLogger(`harness.tool-loop`);var ModelCaller=class{cachePath;marker;attributionHeaders;projectedMessages;request;tools;modelMessages=[];requestEnvelopeTokens=0;interruptedUsage;compactionFailure;attemptIndex=0;step;prompt;input;constructor(e,t,n){this.step=e,this.prompt=t,this.input=n,this.cachePath=detectPromptCachePath(n.model),this.marker=this.cachePath.kind===`anthropic-direct`?getAnthropicCacheMarker():void 0,this.attributionHeaders=buildGatewayAttributionHeaders(n.model,e.config.runtimeIdentity),this.projectedMessages=n.projectedMessages,this.request=this.buildRequest(e.config.tools)}async call(e){return await runModelCallWithRetries(t=>this.attempt({...e,suppressStepStartedEmission:t!==1||e.suppressStepStartedEmission}),{canRetry:()=>this.compactionFailure===void 0,sessionId:this.step.session.sessionId,turnId:this.step.position().turnId},this.input.generation.signal)}throwIfCompactionFailed(){if(this.compactionFailure!==void 0)throw this.compactionFailure.error}async steered(){let{step:e}=this;return throwIfTurnAborted(e.config.abortSignal),e.ctx?.set(HistoryStateKey,this.request.historyState),this.interruptedUsage!==void 0&&(e.session=setTurnUsageState(e.session,accumulateTurnUsage({previous:getTurnUsageState(e.session.state),turnId:e.position().turnId,usage:this.interruptedUsage}))),await e.emit?.(createStepCompletedEvent({...e.position(),finishReason:`other`,usage:this.interruptedUsage})),{next:e.runStep,session:{...e.session,history:[...this.request.history]},steered:!0}}clearInterruptedUsage(){this.interruptedUsage=void 0}buildRequest(e){return requestMessages(this.step,{coordinationTools:e,hidesHeldText:this.input.hidesHeldText,messages:this.prompt.messages,pendingApprovalsNote:this.input.pendingApprovalsNote,projectedMessages:this.projectedMessages,turnMessages:this.input.turnMessages})}instructions(e){return modelInstructions({extraSystemNote:e,marker:this.marker,session:this.step.session,systemMessages:this.request.systemMessages})}async prepare(e){let t=await prepareModelTools(this.step,{model:this.input.model,approvedTools:this.input.approvedTools,disabledProviderTools:e.disabledProviderTools,generation:this.input.generation,marker:this.marker});return this.tools=t,this.request=this.buildRequest(t.coordinationTools),this.requestEnvelopeTokens=await estimateRequestEnvelope({history:this.projectedMessages,instructions:this.instructions(e.extraSystemNote),messages:withTrailingUserNote(this.request.nonSystemMessages,e.trailingUserNote),tools:t.effectiveTools}),t}async compact(e,t){let{step:n,prompt:r}=this,{config:i}=n,a;try{a=await maybeCompact({abortSignal:i.abortSignal,auth:n.ctx?.get(AuthKey)??null,emissionState:n.position(),historyProjector:i.historyProjector,messages:[...r.messages],model:this.input.model,promptMessages:withClientContext(r),publish:n.publish,requestEnvelopeTokens:this.requestEnvelopeTokens,resolveModel:i.resolveModel,runtimeIdentity:i.runtimeIdentity,session:n.session,telemetry:n.instrumentation?.telemetry()})}catch(e){throw this.compactionFailure={error:e},e}if(n.session=a.session,!a.compacted)return t;compactPrompt(n,r,a.messages);let{compaction:o}=n.session;return n.session={...n.session,compaction:{recentWindowSize:o.recentWindowSize,threshold:o.threshold,thresholdPercent:o.thresholdPercent}},this.projectedMessages=projectPrompt(n,r),await this.prepare(e)}async attempt(e){let{step:t}=this,{generation:n,model:r}=this.input,i=await this.compact(e,await this.prepare(e));this.requestEnvelopeTokens=Math.max(0,this.requestEnvelopeTokens-(estimateTokens(this.request.history)-estimateTokens(this.prompt.messages))),n.begin(),this.modelMessages=await hydrateSandboxAttachments(this.request.nonSystemMessages),typeof this.input.model!=`string`&&typeof this.input.model.provider==`string`&&this.input.model.provider.endsWith(`.chat`)&&(this.modelMessages=moveToolResultFilesToUserMessages(this.modelMessages));let a=this.instructions(e.extraSystemNote),o=t.instrumentation?.resolveRuntimeContext({emissionState:t.position(),environment,modelInput:{instructions:a,messages:this.modelMessages},session:t.session})??{};e.retryReason&&(o[`eve.retry.reason`]=e.retryReason);let s=withTrailingUserNote(this.modelMessages,e.trailingUserNote),c=t.position(),l=t.instrumentation?.prepareAttempt({isFrameworkTool:e=>t.frameworkToolNames.has(e),attemptIndex:this.attemptIndex++,runtimeContext:o,stepIndex:c.stepIndex,turnId:activeTurnId(c)});this.input.setAttemptScope(l?.scope);let u=buildStepHooks({auth:t.ctx?.get(AuthKey)??null,cachePath:this.cachePath,marker:this.marker,session:t.session,startStep:e.suppressStepStartedEmission===!0?void 0:this.input.startStep}),d={headers:this.attributionHeaders,instructions:a,model:r,onLanguageModelCallEnd:e=>{n.interrupted||(this.interruptedUsage=extractTokenUsageDelta({costUsd:extractGatewayCostUsd(e.providerMetadata),usage:e.usage}))},onToolExecutionEnd:logToolExecutionError,onError(e){n.interrupted||summarizeKnownError(e.error)?.tags.includes(`config`)!==!0&&logError(log,`tool-loop stream error`,e.error)},onStepEnd:u.onStepEnd,onStepStart:u.onStepStart,prepareStep:u.prepareStep,reasoning:t.session.agent.modelReference?.reasoning??t.session.agent.reasoning,runtimeContext:o,stopWhen:isStepCount(1),telemetry:l?.telemetry,toolApproval:buildToolApproval(i.modelTools,n.signal),tools:i.effectiveTools},f=new ToolLoopAgent(d);try{let e=t.emit===void 0?await this.generate(f,s,u.stepResult):await this.stream(f,s,u.stepResult,i);return await l?.complete(),e}catch(e){return n.interrupted?await l?.complete():await l?.fail(e),n.check(),rethrowNoOutputAsEmptyResponse(e)}}async stream(e,t,n,r){let{step:i}=this,{generation:a}=this.input,o=new Set([FINAL_OUTPUT_TOOL_NAME]),s=await e.stream({abortSignal:a.signal,messages:t}),{emittedActionCallIds:c,handledInlineToolResultCallIds:l,invalidInputToolCallIds:u,inlineAuthorizationResults:d,trailingInlineToolResultParts:f}=await emitStreamContent(i.publish,i.position(),interruptStreamOnFailure(s.fullStream,a.signal),{excludedActionToolNames:o,hidesHeldText:this.input.hidesHeldText&&workingTaskIds(i.session).length>0,tools:r.presentationTools});throwIfTurnAborted(i.config.abortSignal),a.check();let[p,m]=await Promise.all([n,s.responseMessages]);assertUsableResponse(p,m,d.length>0||f.length>0);let h=answerSkippedToolCalls(p,r.effectiveTools);await emitStepActions(i.publish,i.position(),h.length===0?p:withAccumulatedResponseMessages({stepResult:p,responseMessages:appendMissingToolResultMessages({append:h,responseMessages:p.response.messages})}),{emittedActionCallIds:c,excludedActionCallIds:u,excludedActionToolNames:o,handledInlineToolResultCallIds:l,tools:r.presentationTools});let g=new Map(p.toolResults.map(e=>[e.toolCallId,e]));for(let e of d)g.set(e.toolCallId,e);return withAccumulatedResponseMessages({invalidInputToolCallIds:u,responseMessages:appendMissingToolResultMessages({append:[...f,...answerSkippedToolCalls(p,r.effectiveTools)],responseMessages:m}),stepResult:p,toolResults:[...g.values()]})}async generate(e,t,n){let{generation:r}=this.input,i=await e.generate({abortSignal:r.signal,messages:t});throwIfTurnAborted(this.step.config.abortSignal),r.check();let a=await n;return assertUsableResponse(a,i.responseMessages,!1),withAccumulatedResponseMessages({responseMessages:appendMissingToolResultMessages({append:answerSkippedToolCalls(a,this.tools.effectiveTools),responseMessages:i.responseMessages}),stepResult:a})}};function assertUsableResponse(e,t,n){if(e.finishReason===`content-filter`)throw new ContentFilteredModelResponseError(readGatewayGenerationId(e.providerMetadata));if(isEmptyModelResponse(e)&&extractToolResultCallIds(t).size===0&&!n)throw new EmptyModelResponseError}export{ModelCaller};
|
|
@@ -41,7 +41,7 @@ export declare function extractUnsupportedProviderToolTypes(error: unknown): rea
|
|
|
41
41
|
*/
|
|
42
42
|
export declare function extractModelCallErrorDetails(error: unknown): JsonObject;
|
|
43
43
|
/**
|
|
44
|
-
* A model call that produced no content. Raised by
|
|
44
|
+
* A model call that produced no content. Raised by the model caller from
|
|
45
45
|
* either of its two triggers: `isEmptyModelResponse` (a completed step
|
|
46
46
|
* with finishReason 'other' and no output — AI Gateway HTTP 200 whose
|
|
47
47
|
* stream carries no content, no usage, and no error) or
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { JsonObject } from "#shared/json.js";
|
|
2
|
+
import type { SemanticErrorSummary } from "#harness/semantic-errors/rule.js";
|
|
3
|
+
import { type UpstreamRejectionSummary } from "#harness/model-call/errors.js";
|
|
4
|
+
import type { Step } from "#harness/step/context.js";
|
|
5
|
+
import type { StepResult } from "#harness/types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Projects a model-call failure into the `step.failed` / `turn.failed`
|
|
8
|
+
* `details` payload. Three mutually exclusive branches:
|
|
9
|
+
*
|
|
10
|
+
* 1. Catalog match → the rule's curated `name`/`message`/`hint` plus its
|
|
11
|
+
* registered `semanticErrorId`, no SDK inspector dump.
|
|
12
|
+
* 2. Upstream rejection → raw error `message` with the extracted upstream
|
|
13
|
+
* identity, no inspector dump. No `semanticErrorId`: the message is
|
|
14
|
+
* arbitrary provider prose, not a registered failure shape.
|
|
15
|
+
* 3. Fallback → full {@link formatError} projection (cause chain via
|
|
16
|
+
* `util.inspect`) so unrecognized failures still carry the upstream
|
|
17
|
+
* stack to log aggregators.
|
|
18
|
+
*
|
|
19
|
+
* All branches merge {@link extractModelCallErrorDetails} on top so the
|
|
20
|
+
* compact gateway diagnostics (`statusCode`, `upstreamMessage`,
|
|
21
|
+
* `responseBodySnippet`, ...) always show up next to the message.
|
|
22
|
+
*/
|
|
23
|
+
export declare function buildModelCallFailureDetails(input: {
|
|
24
|
+
readonly catalogSummary: SemanticErrorSummary | null;
|
|
25
|
+
readonly error: unknown;
|
|
26
|
+
readonly errorId: string;
|
|
27
|
+
readonly modelCallDetails: JsonObject;
|
|
28
|
+
readonly upstreamRejection: UpstreamRejectionSummary | null;
|
|
29
|
+
}): JsonObject;
|
|
30
|
+
/**
|
|
31
|
+
* Builds the structured log fields for a model-call failure. When the
|
|
32
|
+
* failure was recognized (catalog match or extracted upstream rejection),
|
|
33
|
+
* attach the compact `details` payload and *omit* the raw `error` so the
|
|
34
|
+
* logger's `util.inspect` of the cause chain (which would render
|
|
35
|
+
* `[object Object]` for upstream `APICallError` shapes) is bypassed.
|
|
36
|
+
* Otherwise fall back to the raw error so unrecognized failures keep
|
|
37
|
+
* their full stack in logs.
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildModelCallFailureLogFields(input: {
|
|
40
|
+
readonly error: unknown;
|
|
41
|
+
readonly errorId: string;
|
|
42
|
+
readonly modelCallDetails: JsonObject;
|
|
43
|
+
readonly recognized: boolean;
|
|
44
|
+
readonly sessionId: string;
|
|
45
|
+
readonly turnId: string;
|
|
46
|
+
}): Record<string, unknown>;
|
|
47
|
+
/**
|
|
48
|
+
* The model call failed past its retries and recoveries. A failed write to the session's stream is
|
|
49
|
+
* the workflow's failure, not the model's: the session parks for the user to retry. A terminal
|
|
50
|
+
* failure ends the session; any other fails the turn recoverably.
|
|
51
|
+
*/
|
|
52
|
+
export declare function reportModelCallFailure(step: Step, error: unknown): Promise<StepResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createErrorId,createLogger,formatError}from"#internal/logging.js";import{toErrorMessage}from"#shared/errors.js";import{fail}from"#harness/session-machine/transitions.js";import{summarizeKnownError}from"#harness/semantic-errors/index.js";import{classifyModelCallError,extractModelCallErrorDetails,extractUpstreamRejectionMessage}from"#harness/model-call/errors.js";import{extractWorkflowStreamWriteErrorDetails}from"#harness/workflow-stream-error.js";const log=createLogger(`harness.tool-loop`);function buildModelCallFailureDetails(e){let{catalogSummary:t,error:n,errorId:r,modelCallDetails:i,upstreamRejection:a}=e;if(t!==null){let e={errorId:r,message:t.message,name:t.name,semanticErrorId:t.id,...i};return t.hint!==void 0&&(e.hint=t.hint),e}return a===null?{...formatError(n,r),...i}:{errorId:r,message:toErrorMessage(n),name:a.name,...i}}function buildModelCallFailureLogFields(e){let t={errorId:e.errorId,sessionId:e.sessionId,turnId:e.turnId};return e.recognized?{...t,details:e.modelCallDetails}:{...t,error:e.error}}async function reportModelCallFailure(e,t){if(e.instrumentation?.recordError(t),e.emit===void 0)throw t;let{sessionId:n}=e.session,{turnId:r}=e.position(),i=extractWorkflowStreamWriteErrorDetails(t);if(i!==null){let a=createErrorId();return log.error(`workflow stream write failed — parking session for retry by the user`,{...i,errorId:a,error:t,sessionId:n,turnId:r}),await e.apply(fail(e.view(),{code:`WORKFLOW_STREAM_WRITE_FAILED`,details:{...i,errorId:a},message:toErrorMessage(t)})),{next:null,session:e.session}}let a=createErrorId(),o=summarizeKnownError(t),s=o===null?extractUpstreamRejectionMessage(t):null,c=o?.message??s?.message??toErrorMessage(t),l=o?.hint===void 0?c:`${c} ${o.hint}`,u=extractModelCallErrorDetails(t),d=buildModelCallFailureDetails({catalogSummary:o,error:t,errorId:a,modelCallDetails:u,upstreamRejection:s}),f=buildModelCallFailureLogFields({error:t,errorId:a,modelCallDetails:u,recognized:o!==null||s!==null,sessionId:n,turnId:r});return classifyModelCallError(t)===`terminal`?(o===null?log.error(s?.message??`model call failed terminally`,f):log.error(`${o.name}: ${o.message}`,{errorId:a,hint:o.hint,sessionId:n,turnId:r}),await e.apply(fail(e.view(),{code:`MODEL_CALL_FAILED`,details:d,message:c,terminal:{sessionId:n}})),{next:e.hasDelegatedCaller?{done:!0,isError:!0,output:l}:{done:!0,output:``},session:e.session}):(log.error(s?.message??`model call failed — parking session for retry by the user`,f),await e.apply(fail(e.view(),{code:`MODEL_CALL_FAILED`,details:d,message:c})),e.session={...e.session,outputSchema:void 0},{next:null,session:e.session,settledTurn:{isError:!0,output:l}})}export{buildModelCallFailureDetails,buildModelCallFailureLogFields,reportModelCallFailure};
|