eve 0.72.0 → 0.73.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 +35 -0
- package/dist/src/channel/agent-description.d.ts +49 -9
- package/dist/src/channel/agent-description.js +1 -1
- package/dist/src/channel/invoke-tool.d.ts +26 -4
- package/dist/src/channel/invoke-tool.js +1 -1
- package/dist/src/channel/principal-identity.d.ts +9 -0
- package/dist/src/channel/principal-identity.js +1 -0
- package/dist/src/channel/prompt-queue.d.ts +31 -0
- package/dist/src/channel/prompt-queue.js +1 -0
- package/dist/src/channel/routes.d.ts +19 -4
- package/dist/src/channel/schedule.js +1 -1
- package/dist/src/channel/skill-files.d.ts +114 -0
- package/dist/src/channel/skill-files.js +1 -0
- package/dist/src/cli/commands/agent-instructions.js +1 -1
- package/dist/src/cli/commands/extension-init.js +1 -1
- package/dist/src/cli/commands/init-agent-workspace.js +1 -1
- package/dist/src/cli/commands/init-project.js +1 -1
- package/dist/src/cli/commands/init.js +1 -1
- package/dist/src/cli/dev/diagnostic-dump.js +1 -1
- package/dist/src/cli/dev/tui/blocks.d.ts +6 -0
- package/dist/src/cli/dev/tui/blocks.js +2 -2
- package/dist/src/cli/dev/tui/markdown.d.ts +5 -0
- package/dist/src/cli/dev/tui/markdown.js +2 -2
- package/dist/src/cli/dev/tui/transcript-parts.d.ts +4 -1
- package/dist/src/cli/dev/tui/transcript-parts.js +2 -2
- package/dist/src/cli/dev/tui/transcript.js +1 -1
- package/dist/src/compiled/.vendor-stamp.json +8 -8
- package/dist/src/compiled/@eve/catalog/index.js +1 -1
- package/dist/src/compiled/@modelcontextprotocol/server/index.d.ts +68 -7
- package/dist/src/compiled/@workflow/core/capabilities.d.ts +33 -6
- package/dist/src/compiled/@workflow/core/flushable-stream.d.ts +2 -0
- package/dist/src/compiled/@workflow/core/index.d.ts +1 -0
- package/dist/src/compiled/@workflow/core/index.js +2 -2
- package/dist/src/compiled/@workflow/core/private.js +1 -1
- package/dist/src/compiled/@workflow/core/runtime/helpers.d.ts +6 -0
- package/dist/src/compiled/@workflow/core/runtime/helpers.js +1 -1
- package/dist/src/compiled/@workflow/core/runtime.js +3 -3
- package/dist/src/compiled/@workflow/core/serialization/codec.d.ts +8 -8
- package/dist/src/compiled/@workflow/core/serialization/compression.d.ts +13 -5
- package/dist/src/compiled/@workflow/core/serialization.d.ts +9 -9
- package/dist/src/compiled/@workflow/core/serialization.js +1 -1
- package/dist/src/compiled/@workflow/core/symbols.d.ts +2 -0
- package/dist/src/compiled/@workflow/core/telemetry/semantic-conventions.d.ts +2 -2
- package/dist/src/compiled/@workflow/core/version.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/workflow/index.d.ts +1 -0
- package/dist/src/compiled/@workflow/core/workflow.js +1 -1
- package/dist/src/compiled/@workflow/errors/index.js +1 -1
- package/dist/src/compiled/@workflow/world/events.d.ts +11 -0
- package/dist/src/compiled/@workflow/world/hooks.d.ts +2 -0
- package/dist/src/compiled/@workflow/world/interfaces.d.ts +6 -0
- package/dist/src/compiled/@workflow/world-local/index.js +3 -3
- package/dist/src/compiled/@workflow/world-vercel/index.js +13 -13
- package/dist/src/compiled/_chunks/workflow/{attribute-changes-VaTKT4K8.js → attribute-changes-CSqvJx6j.js} +2 -2
- package/dist/src/compiled/_chunks/workflow/{dist-B7NC1c9-.js → dist-DmXynLVH.js} +1 -1
- package/dist/src/compiled/_chunks/workflow/dist-T5NnW-0k.js +3 -0
- package/dist/src/compiled/_chunks/workflow/helpers-BXCuoPUb.js +1 -0
- package/dist/src/compiled/_chunks/workflow/private-Dlf90Zvn.js +1 -0
- package/dist/src/compiled/_chunks/workflow/resume-hook-CvENCrxc.js +1 -0
- package/dist/src/compiled/_chunks/workflow/{run-DYKeqbob.js → run-8pLWuR2U.js} +6 -6
- package/dist/src/compiled/_chunks/workflow/serialization-vDozzDhh.js +16 -0
- package/dist/src/compiled/_chunks/workflow/sleep-BMqbraZM.js +1 -0
- package/dist/src/compiled/_chunks/workflow/wait-until-A344L2AG.js +1 -0
- package/dist/src/compiled/shadcn-registry/index.js +3408 -35163
- package/dist/src/compiler/artifacts.js +1 -1
- package/dist/src/compiler/compile-agent.js +1 -1
- package/dist/src/compiler/development-extensions.js +1 -1
- package/dist/src/compiler/extension-compatibility.d.ts +6 -6
- package/dist/src/compiler/extension-compatibility.js +1 -1
- package/dist/src/context/providers/session.js +1 -1
- package/dist/src/context/turn-principals.d.ts +12 -0
- package/dist/src/context/turn-principals.js +1 -0
- package/dist/src/evals/cli/eval-client.js +1 -1
- package/dist/src/evals/cli/eval.js +1 -1
- package/dist/src/evals/mock-model.js +1 -1
- package/dist/src/execution/cancelled-model-call-batch.js +1 -1
- package/dist/src/execution/dynamic-workflow/tool.js +1 -1
- package/dist/src/execution/invoke-tool.d.ts +6 -2
- package/dist/src/execution/invoke-tool.js +1 -1
- package/dist/src/execution/legacy-session/turn-workflow.js +1 -1
- package/dist/src/execution/node-step.d.ts +1 -0
- package/dist/src/execution/node-step.js +1 -1
- package/dist/src/execution/publish-session-events.js +1 -1
- package/dist/src/execution/sandbox/bindings/just-bash.js +1 -1
- package/dist/src/execution/sandbox/bindings/vercel-errors.d.ts +11 -0
- package/dist/src/execution/sandbox/bindings/vercel-errors.js +2 -1
- package/dist/src/execution/sandbox/bindings/vercel-tool-sessions.d.ts +7 -0
- package/dist/src/execution/sandbox/bindings/vercel-tool-sessions.js +1 -0
- package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
- package/dist/src/execution/sandbox/development-lazy-prewarm.js +1 -1
- package/dist/src/execution/sandbox/ensure.d.ts +14 -1
- package/dist/src/execution/sandbox/ensure.js +1 -1
- package/dist/src/execution/sandbox/prewarm.js +1 -1
- package/dist/src/execution/session/active-turn.d.ts +2 -1
- package/dist/src/execution/session/active-turn.js +1 -1
- package/dist/src/execution/session/entry.d.ts +10 -1
- package/dist/src/execution/session/entry.js +1 -1
- package/dist/src/execution/session/program.d.ts +4 -0
- package/dist/src/execution/session/program.js +1 -1
- package/dist/src/execution/session/timeout-control.d.ts +1 -2
- package/dist/src/execution/session/timeout-control.js +1 -1
- package/dist/src/execution/session/turn-control.d.ts +7 -0
- package/dist/src/execution/session/turn-control.js +1 -0
- package/dist/src/execution/session/turn-step.js +1 -1
- package/dist/src/execution/session/turn.d.ts +2 -0
- package/dist/src/execution/session/turn.js +1 -1
- package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
- package/dist/src/execution/tool-session/id.d.ts +22 -0
- package/dist/src/execution/tool-session/id.js +1 -0
- package/dist/src/execution/tool-session/sandbox.d.ts +22 -0
- package/dist/src/execution/tool-session/sandbox.js +1 -0
- package/dist/src/execution/tools/agent-router-workflow.js +1 -1
- package/dist/src/execution/tools/connection-tools.js +1 -1
- package/dist/src/harness/hitl/approvals.d.ts +1 -1
- package/dist/src/harness/hitl/approvals.js +1 -1
- package/dist/src/harness/hitl/delivery.d.ts +9 -2
- package/dist/src/harness/hitl/delivery.js +1 -1
- package/dist/src/harness/hitl/intake.js +1 -1
- package/dist/src/harness/model-call/usage.js +1 -1
- package/dist/src/harness/open-input-request.d.ts +8 -0
- package/dist/src/harness/open-input-request.js +1 -0
- package/dist/src/harness/session-machine/current.js +1 -1
- package/dist/src/harness/session-machine/transitions.js +1 -1
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/harness/types.d.ts +2 -0
- package/dist/src/internal/application/cache-metadata.js +1 -1
- package/dist/src/internal/application/compiled-artifacts.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/application/paths.js +1 -1
- package/dist/src/internal/application/runtime-compiled-artifacts-source.js +1 -1
- package/dist/src/internal/authored-definition/connection.js +1 -1
- package/dist/src/internal/authored-module-loader.js +1 -1
- package/dist/src/internal/authored-package-boundary.js +1 -1
- package/dist/src/internal/invocation/metadata.js +1 -1
- package/dist/src/internal/mcp/forwarded-principal-header.d.ts +31 -0
- package/dist/src/internal/mcp/forwarded-principal-header.js +1 -0
- package/dist/src/internal/mcp/published-tools.d.ts +9 -2
- package/dist/src/internal/mcp/published-tools.js +1 -1
- package/dist/src/internal/mcp/skills.d.ts +57 -0
- package/dist/src/internal/mcp/skills.js +1 -0
- package/dist/src/internal/mcp/streamable-http-server.d.ts +38 -6
- package/dist/src/internal/mcp/streamable-http-server.js +1 -1
- package/dist/src/internal/nitro/dev-runtime-artifacts.js +1 -1
- package/dist/src/internal/nitro/host/artifacts-config.js +1 -1
- package/dist/src/internal/nitro/host/build-application.js +1 -1
- package/dist/src/internal/nitro/host/build-extension.js +1 -1
- package/dist/src/internal/nitro/host/build-vercel-agent-summary.js +1 -1
- package/dist/src/internal/nitro/host/configure-nitro-routes.js +1 -1
- package/dist/src/internal/nitro/host/create-application-nitro.js +1 -1
- package/dist/src/internal/nitro/host/dev-authored-source-watcher.js +1 -1
- package/dist/src/internal/nitro/host/dev-runner.js +1 -1
- package/dist/src/internal/nitro/host/local-tracing-runtime-plugin.js +1 -1
- package/dist/src/internal/nitro/host/skill-server-assets.d.ts +29 -0
- package/dist/src/internal/nitro/host/skill-server-assets.js +1 -0
- package/dist/src/internal/nitro/host/start-production-server.js +1 -1
- package/dist/src/internal/nitro/host/workspace-extensions.js +1 -1
- package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
- package/dist/src/internal/nitro/routes/channel-route-context.d.ts +4 -0
- package/dist/src/internal/nitro/routes/channel-route-context.js +1 -1
- package/dist/src/internal/vercel/build-agent-workspace.js +1 -1
- package/dist/src/internal/workflow/development-world-client.js +1 -1
- package/dist/src/internal/workflow/validate-world.js +1 -1
- package/dist/src/internal/workflow/vercel-world-defaults.js +1 -1
- package/dist/src/internal/workflow-bundle/builder-support.js +1 -1
- package/dist/src/internal/workflow-bundle/builder.js +1 -1
- package/dist/src/public/channels/chat-sdk/authorization.js +1 -1
- package/dist/src/public/channels/chat-sdk/chatSdkChannel.d.ts +7 -1
- package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +2 -2
- package/dist/src/public/channels/discord/defaults.d.ts +8 -7
- package/dist/src/public/channels/discord/discordChannel.d.ts +21 -1
- package/dist/src/public/channels/discord/discordChannel.js +1 -1
- package/dist/src/public/channels/discord/index.d.ts +1 -1
- package/dist/src/public/channels/github/defaults.js +3 -3
- package/dist/src/public/channels/github/githubChannel.d.ts +4 -1
- package/dist/src/public/channels/github/state.d.ts +2 -1
- package/dist/src/public/channels/index.d.ts +1 -1
- package/dist/src/public/channels/linear/defaults.js +1 -1
- package/dist/src/public/channels/linear/linearChannel.d.ts +4 -1
- package/dist/src/public/channels/mcp.d.ts +26 -5
- package/dist/src/public/channels/mcp.js +1 -1
- package/dist/src/public/channels/slack/interactions.js +1 -1
- package/dist/src/public/channels/slack/slackChannel.d.ts +6 -0
- package/dist/src/public/channels/twilio/defaults.js +2 -4
- package/dist/src/public/channels/twilio/twilioChannel.d.ts +4 -1
- package/dist/src/public/definitions/channel.d.ts +1 -1
- package/dist/src/public/definitions/connections/mcp.d.ts +11 -0
- package/dist/src/public/sveltekit/dev-server.js +1 -1
- package/dist/src/runtime/cache-key.js +1 -1
- package/dist/src/runtime/connections/mcp-client.d.ts +18 -1
- package/dist/src/runtime/connections/mcp-client.js +1 -1
- package/dist/src/runtime/loaders/compile-metadata.js +1 -1
- package/dist/src/runtime/loaders/manifest.js +1 -1
- package/dist/src/runtime/loaders/module-map.js +1 -1
- package/dist/src/runtime/resolve-connection.js +1 -1
- package/dist/src/runtime/sandbox/prepared-artifacts.js +1 -1
- package/dist/src/runtime/sessions/compiled-agent-cache.js +1 -1
- package/dist/src/runtime/sessions/runtime-session.d.ts +10 -0
- package/dist/src/runtime/sessions/runtime-session.js +1 -1
- package/dist/src/runtime/types.d.ts +2 -0
- package/dist/src/self-modification/config.d.ts +4 -63
- package/dist/src/self-modification/config.js +1 -1
- package/dist/src/self-modification/credentials.d.ts +1 -1
- package/dist/src/self-modification/deployed-sandbox.d.ts +14 -0
- package/dist/src/self-modification/deployed-sandbox.js +1 -0
- package/dist/src/self-modification/extension/config-schema.d.ts +2 -17
- package/dist/src/self-modification/extension/config-schema.js +1 -1
- package/dist/src/self-modification/extension/local-only.d.ts +1 -1
- package/dist/src/self-modification/extension/local-only.js +1 -1
- package/dist/src/self-modification/extension/subagents/agent/agent.d.ts +1 -1
- package/dist/src/self-modification/extension/subagents/agent/agent.js +1 -1
- package/dist/src/self-modification/extension/subagents/agent/instructions.js +3 -35
- package/dist/src/self-modification/extension/subagents/agent/tools/registry_add.d.ts +3 -31
- package/dist/src/self-modification/extension/subagents/agent/tools/registry_add.js +1 -1
- package/dist/src/self-modification/git-workspace.d.ts +1 -2
- package/dist/src/self-modification/git-workspace.js +1 -1
- package/dist/src/self-modification/github-publisher.d.ts +1 -1
- package/dist/src/self-modification/mode.d.ts +4 -4
- package/dist/src/self-modification/mode.js +1 -1
- package/dist/src/self-modification/proposal.js +1 -1
- package/dist/src/self-modification/remote/config-schema.d.ts +20 -0
- package/dist/src/self-modification/remote/config-schema.js +1 -0
- package/dist/src/self-modification/remote/config.d.ts +66 -0
- package/dist/src/self-modification/remote/config.js +1 -0
- package/dist/src/self-modification/remote/extension.d.ts +5 -0
- package/dist/src/self-modification/remote/extension.js +1 -0
- package/dist/src/self-modification/remote/production-registry-add.js +1 -0
- package/dist/src/self-modification/remote/subagents/agent/agent.d.ts +4 -0
- package/dist/src/self-modification/remote/subagents/agent/agent.js +1 -0
- package/dist/src/self-modification/remote/subagents/agent/instructions.d.ts +2 -0
- package/dist/src/self-modification/remote/subagents/agent/instructions.js +5 -0
- package/dist/src/self-modification/remote/subagents/agent/sandbox.d.ts +2 -0
- package/dist/src/self-modification/remote/subagents/agent/sandbox.js +1 -0
- package/dist/src/self-modification/remote/subagents/agent/tools/edit_file.d.ts +1 -0
- package/dist/src/self-modification/remote/subagents/agent/tools/edit_file.js +1 -0
- package/dist/src/self-modification/remote/subagents/agent/tools/publish.js +1 -0
- package/dist/src/self-modification/remote/subagents/agent/tools/registry_add.d.ts +32 -0
- package/dist/src/self-modification/remote/subagents/agent/tools/registry_add.js +1 -0
- package/dist/src/self-modification/remote/subagents/agent/tools/search_models.d.ts +1 -0
- package/dist/src/self-modification/remote/subagents/agent/tools/search_models.js +1 -0
- package/dist/src/self-modification/remote/subagents/agent/tools/search_registry.d.ts +1 -0
- package/dist/src/self-modification/remote/subagents/agent/tools/search_registry.js +1 -0
- package/dist/src/self-modification/sandbox.d.ts +1 -6
- package/dist/src/self-modification/sandbox.js +1 -1
- package/dist/src/self-modification/scaffold.js +1 -1
- package/dist/src/self-modification/setup.d.ts +6 -0
- package/dist/src/self-modification/setup.js +46 -48
- package/dist/src/self-modification/subagent-guidance.d.ts +15 -0
- package/dist/src/self-modification/subagent-guidance.js +29 -0
- package/dist/src/services/dev-client/request-headers.js +1 -1
- package/dist/src/setup/flows/model-source-change.js +1 -1
- package/dist/src/setup/integrations/self-modification/setup.js +1 -1
- package/dist/src/setup/project-resolution.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/setup/verified-remote-client.d.ts +3 -0
- package/dist/src/setup/verified-remote-client.js +1 -1
- package/dist/src/shared/framework-eve-server.js +1 -1
- package/dist/src/subagents/hitl-proxy.js +1 -1
- package/dist/src/tools/provided/ask-question-workflow.js +1 -1
- package/dist/src/tools/provided/sleep-workflow.js +1 -1
- package/dist/src/tracing/invoke-tool-span.d.ts +1 -0
- package/docs/channels/chat-sdk.mdx +27 -0
- package/docs/channels/custom.mdx +5 -2
- package/docs/channels/discord.mdx +22 -0
- package/docs/channels/mcp.mdx +102 -4
- package/docs/channels/slack.mdx +1 -1
- package/docs/concepts/built-in-tools.md +2 -2
- package/docs/connections/mcp.mdx +30 -0
- package/docs/connections/overview.mdx +1 -1
- package/docs/evals/targets.mdx +5 -1
- package/docs/guides/self-modification.md +50 -3
- package/docs/tools/human-in-the-loop.md +14 -2
- package/docs/tutorial/guard-the-spend.mdx +1 -1
- package/package.json +25 -7
- package/dist/src/compiled/@workflow/core/runtime/vm-serde-bundle.generated.d.ts +0 -14
- package/dist/src/compiled/_chunks/workflow/dist-CaNNONeg.js +0 -3
- package/dist/src/compiled/_chunks/workflow/global-DKbOgrts.js +0 -1
- package/dist/src/compiled/_chunks/workflow/helpers-CP9TjeO8.js +0 -1
- package/dist/src/compiled/_chunks/workflow/logger-oqfblE3p.js +0 -14
- package/dist/src/compiled/_chunks/workflow/resume-hook-yq-NAdBu.js +0 -1
- package/dist/src/compiled/_chunks/workflow/serialization-APSKphN5.js +0 -3
- package/dist/src/compiled/_chunks/workflow/sleep-Ba8SExMt.js +0 -1
- package/dist/src/compiled/_chunks/workflow/wait-until-Dc9s3yyP.js +0 -1
- package/dist/src/self-modification/extension/production-registry-add.js +0 -1
- package/dist/src/self-modification/extension/subagents/agent/tools/publish.js +0 -1
- /package/dist/src/self-modification/{extension → remote}/production-registry-add.d.ts +0 -0
- /package/dist/src/self-modification/{extension → remote}/subagents/agent/tools/publish.d.ts +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Channel } from "#public/definitions/channel.js";
|
|
2
|
+
import type { TrustedForwarders } from "#channel/forwarded-principal.js";
|
|
2
3
|
import { type AuthFn } from "#public/channels/auth.js";
|
|
3
4
|
export interface McpChannelInput {
|
|
4
5
|
/** Existing eve route-auth policy. Use `none()` for explicit public access. */
|
|
@@ -7,26 +8,46 @@ export interface McpChannelInput {
|
|
|
7
8
|
readonly route?: string;
|
|
8
9
|
/**
|
|
9
10
|
* Serve the `agent_*` tools, which start and follow a durable agent task.
|
|
10
|
-
* With `false`, the channel serves only
|
|
11
|
+
* With `false`, the channel serves only what `tools` and `skills` publish.
|
|
11
12
|
* @default true
|
|
12
13
|
*/
|
|
13
14
|
readonly agent?: boolean;
|
|
14
15
|
/**
|
|
15
16
|
* Also publish the agent's invocable tools, each `tools/call` running the
|
|
16
17
|
* tool as the route-authenticated caller. While `agent` is on, an agent
|
|
17
|
-
* tool named like an `agent_*` tool is not published.
|
|
18
|
+
* tool named like an `agent_*` tool is not published. Also advertises the
|
|
19
|
+
* `dev.eve/tool-sessions` extension: a client that declares it joins a tool
|
|
20
|
+
* session by sending `_meta["dev.eve/tool-session"]` on `tools/call`.
|
|
18
21
|
* @default false
|
|
19
22
|
*/
|
|
20
23
|
readonly tools?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Lets a route-authenticated forwarder, such as another eve agent's
|
|
26
|
+
* `forwardPrincipal` connection, run the published tools as a user it names
|
|
27
|
+
* in the `eve-forwarded-principal` header. Receives the verified forwarder
|
|
28
|
+
* and what it asserts, as eveChannel's `trustedForwarders` does; match the
|
|
29
|
+
* forwarder precisely. Accepted principals carry the forwarder's id as the
|
|
30
|
+
* `eve:forwarded-by` attribute. `agent_*` tools still act as the route
|
|
31
|
+
* caller. Omit to refuse any request carrying the header with 403.
|
|
32
|
+
*/
|
|
33
|
+
readonly trustedForwarders?: TrustedForwarders;
|
|
34
|
+
/**
|
|
35
|
+
* Also serve the agent's skills as SEP-2640 skills under `skill://`
|
|
36
|
+
* (`skills/list`, `skills/get`, and the `resources/*` methods), readable
|
|
37
|
+
* by every route-authenticated caller.
|
|
38
|
+
* @default false
|
|
39
|
+
*/
|
|
40
|
+
readonly skills?: boolean;
|
|
21
41
|
}
|
|
22
|
-
/** Public MCP channel publishing this agent's `agent_*` tools and, optionally, its
|
|
42
|
+
/** Public MCP channel publishing this agent's `agent_*` tools and, optionally, its tools and skills. */
|
|
23
43
|
export type McpChannel = Channel;
|
|
24
44
|
/**
|
|
25
45
|
* Publishes this agent as a stateless Streamable HTTP MCP server.
|
|
26
46
|
*
|
|
27
47
|
* This channel owns MCP transport, durable eve invocation through the
|
|
28
|
-
* `agent_*` tools (unless `agent: false`),
|
|
29
|
-
*
|
|
48
|
+
* `agent_*` tools (unless `agent: false`), with `tools: true` the agent's
|
|
49
|
+
* invocable tools, each call run through `invokeTool`, and with
|
|
50
|
+
* `skills: true` the agent's skills and their files. It reuses
|
|
30
51
|
* eve's inbound auth strategies and recognizes `oauthResource(...)` metadata
|
|
31
52
|
* when OAuth discovery is needed.
|
|
32
53
|
* The file containing this channel must be `agent/channels/mcp.ts`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z}from"#compiled/zod/index.js";import{inputRequestSchema,inputResponseSchema}from"#shared/input.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{parseJsonObject}from"#shared/json.js";import{DELETE,GET,HEAD,OPTIONS,POST,defineChannel}from"#public/definitions/channel.js";import{readAgentInfoRouteResponse,readRouteChannelName,readRouteSessionCreator}from"#internal/nitro/routes/channel-route-context.js";import{escapeAuthChallengeParameter,readOAuthResourceOptions,routeAuth}from"#public/channels/auth.js";import{McpToolOperationError,createMcpStreamableHttpServer,defineMcpTool}from"#internal/mcp/streamable-http-server.js";import{WorkflowAgentInvocationExecution}from"#internal/invocation/workflow-execution.js";import{createPublishedTools}from"#internal/mcp/published-tools.js";import{validateMcpHttpRequest,validateMcpMetadataRequest}from"#internal/mcp/http-security.js";import{createMcpProtectedResourceMetadata,createMcpResourceChallenge}from"#internal/mcp/protected-resource.js";function mcpChannel(e){if(e?.auth===void 0)throw Error(`mcpChannel requires auth. Use none() for explicit public access.`);let t={agent:e.agent??!0,tools:e.tools??!1};if(!t.agent&&!t.tools)throw Error(`mcpChannel publishes nothing with agent and tools both false. Enable one.`);let n=e.route??`/eve/v1/mcp`,r=readOAuthResourceOptions(e.auth),i=[GET(n,async(n,i)=>await authenticateMcpRequest(n,i,e.auth,r,t)),POST(n,async(n,i)=>await authenticateMcpRequest(n,i,e.auth,r,t)),DELETE(n,async(n,i)=>await authenticateMcpRequest(n,i,e.auth,r,t))];return r!==void 0&&i.unshift(...protectedResourceMetadataRoutes(r,n)),defineChannel({routes:i})}function protectedResourceMetadataRoutes(e,t){let n=protectedResourceMetadataPath(e,t);return[GET(n,async n=>protectedResourceMetadataResponse(n,e,t,!1)),HEAD(n,async n=>protectedResourceMetadataResponse(n,e,t,!0)),OPTIONS(n,async e=>protectedResourceMetadataOptionsResponse(e))]}function protectedResourceMetadataPath(e,t){if(e.metadataPath!==void 0)return e.metadataPath;let n=e.resource===void 0?t:new URL(e.resource).pathname;return n===`/`?`/.well-known/oauth-protected-resource`:`/.well-known/oauth-protected-resource${n}`}function protectedResourceMetadataResponse(e,t,n,r){let i=validateMcpMetadataRequest(e);if(i!==void 0)return i;let a=t.resource??new URL(n,new URL(e.url).origin).toString(),o=t.issuer===void 0?t.authorizationServers:[t.issuer],s=Response.json(createMcpProtectedResourceMetadata({authorizationServers:o,resource:a,scopesSupported:t.scopes}),{headers:{"access-control-allow-origin":`*`,"cache-control":`no-store`}});return r?new Response(null,{headers:s.headers,status:s.status}):s}function protectedResourceMetadataOptionsResponse(e){let t=validateMcpMetadataRequest(e);if(t!==void 0)return t;let n=new Headers({"access-control-allow-methods":`GET, HEAD, OPTIONS`,"access-control-allow-origin":`*`,"cache-control":`no-store`}),r=e.headers.get(`access-control-request-headers`);return r!==null&&(n.set(`access-control-allow-headers`,r),n.set(`vary`,`Access-Control-Request-Headers`)),new Response(null,{headers:n,status:204})}function addResourceChallenge(e,t,n){if(e.status!==401&&e.status!==403)return e;let r=protectedResourceMetadataPath(n,new URL(t.url).pathname),i=n.resource??new URL(t.url).origin,a=new URL(r,i).toString(),o=new Headers(e.headers),s=o.get(`www-authenticate`);if(e.status===401)o.set(`www-authenticate`,mergeMcpBearerChallenge(s,a,n.scopes));else{let t=augmentInsufficientScopeChallenge(s,a);if(t===void 0)return e;o.set(`www-authenticate`,t)}return new Response(e.body,{headers:o,status:e.status,statusText:e.statusText})}function mergeMcpBearerChallenge(e,t,n){let r=parseAuthChallenges(e),i=r.find(e=>e.scheme.toLowerCase()===`bearer`&&hasAuthParameter(e.value,`error`))??r.find(e=>e.scheme.toLowerCase()===`bearer`);return replaceBearerChallenges(r,i,i===void 0?createMcpResourceChallenge(t,n):augmentBearerChallenge(i.value,t,n))}function augmentInsufficientScopeChallenge(e,t){let n=parseAuthChallenges(e),r=n.find(e=>e.scheme.toLowerCase()===`bearer`&&hasAuthParameter(e.value,`error`,`insufficient_scope`));if(r!==void 0)return replaceBearerChallenges(n,r,augmentBearerChallenge(r.value,t))}function replaceBearerChallenges(e,t,n){let r=[],i=!1;for(let a of e){if(a.scheme.toLowerCase()!==`bearer`){r.push(a.value);continue}!i&&a===t&&(r.push(n),i=!0)}return i||r.push(n),r.join(`, `)}function augmentBearerChallenge(e,t,n){let r=e;return hasAuthParameter(r,`resource_metadata`)||(r=appendAuthParameter(r,`resource_metadata`,t)),n?.length&&!hasAuthParameter(r,`scope`)&&(r=appendAuthParameter(r,`scope`,n.join(` `))),r}function appendAuthParameter(e,t,n){return`${e}${e.trim().toLowerCase()===`bearer`?` `:`, `}${t}="${escapeAuthChallengeParameter(n)}"`}function hasAuthParameter(e,t,n){let r=t.replaceAll(/[.*+?^${}()|[\]\\]/g,`\\$&`);if(n===void 0)return RegExp(`(?:^|[\\s,])${r}\\s*=`,`i`).test(e);let i=n.replaceAll(/[.*+?^${}()|[\]\\]/g,`\\$&`);return RegExp(`(?:^|[\\s,])${r}\\s*=\\s*(?:"${i}"|${i})(?=$|[\\s,])`,`i`).test(e)}function parseAuthChallenges(e){if(e===null)return[];let t=[];for(let n of splitQuotedHeaderList(e)){let e=readChallengeScheme(n);if(e!==void 0){t.push({scheme:e,value:n});continue}let r=t.at(-1);r!==void 0&&(r.value+=`, ${n}`)}return t}function splitQuotedHeaderList(e){let t=[],n=!1,r=!1,i=0;for(let a=0;a<e.length;a++){let o=e[a];if(n)n=!1;else if(o===`\\`)n=!0;else if(o===`"`)r=!r;else if(o===`,`&&!r){let n=e.slice(i,a).trim();n.length>0&&t.push(n),i=a+1}}let a=e.slice(i).trim();return a.length>0&&t.push(a),t}function readChallengeScheme(e){let t=/^([!#$%&'*+\-.^_`|~0-9A-Za-z]+)(?:\s+|$)/.exec(e);if(t===null)return;let n=t[1];if(n!==void 0)return e.slice(n.length).trimStart().startsWith(`=`)?void 0:n}async function authenticateMcpRequest(e,t,n,r,i){let a=validateMcpHttpRequest(e);if(a!==void 0)return a;let o=await routeAuth(e,n);return o instanceof Response?r===void 0?o:addResourceChallenge(o,e,r):await handleMcpRequest(e,t,o,i)}async function handleMcpRequest(e,t,n,r){let i=readRouteSessionCreator(t),a=readRouteChannelName(t),o=readAgentInfoRouteResponse(t);if(a===void 0||i===void 0||o===void 0)return Response.json({error:`MCP requires agent route context.`},{status:500});let s=await o();if(!s.ok)return s;let c=await s.json();if(typeof c.agent?.name!=`string`)return Response.json({error:`MCP requires compiled agent metadata.`},{status:500});let l=typeof c.agent.description==`string`?c.agent.description:void 0,u=new WorkflowAgentInvocationExecution({createSession:i,from:t.from}),d=r.agent?createInvocationTools(u,l,n.authenticator===`none`&&n.principalType===`anonymous`):[],f=r.tools?createPublishedTools({invokeTool:t.invokeTool,reserved:new Set(d.map(e=>e.name)),tools:(await t.describe()).tools}):[];return await createMcpStreamableHttpServer({authenticate:async()=>n,instructions:r.agent?MCP_SERVER_INSTRUCTIONS:void 0,name:c.agent.name,tools:[...d,...f],version:resolveInstalledPackageInfo().version})(e)}const MCP_SERVER_INSTRUCTIONS=[`Each invocation is one durable agent task.`,`Call agent_start once per task and keep the returned invocationId.`,`Poll agent_get, waiting at least pollAfterMs between calls, until status is completed, failed, or cancelled.`,`If status is input_required, answer every entry in inputRequests in one agent_update call; repeating accepted answers is safe.`,`If status is authorization_required, show the user the authorization url or instructions and keep polling.`,`isError on a tool result means your call was rejected; a failed status means the task failed.`,`agent_start is not idempotent and a lost response leaves no invocationId, so ask the user before starting again.`,`Work continues after your connection drops; agent_cancel stops it, then poll until any terminal status.`].join(` `);function createInvocationTools(e,t,n){let r=n?` On this public channel, the invocation ID is a bearer capability until workflow retention expires.`:``,i=`Starts durable work and returns an invocation handle immediately. Call once per task; keep invocationId and poll agent_get. Not idempotent: if the response is lost, ask the user before starting again rather than retrying.${r}`;return[defineMcpTool({definition:{annotations:{destructiveHint:!0,idempotentHint:!1,openWorldHint:!0,readOnlyHint:!1},description:t===void 0?i:`${t} ${i}`,inputSchema:z.strictObject({message:utf8Bounded(MAX_MESSAGE_BYTES).min(1)}),name:`agent_start`,outputSchema:AGENT_INVOCATION_OUTPUT_SCHEMA},async call(t,n){return invocationResult(await e.create({auth:n.auth,message:t.message}))}}),defineMcpTool({definition:{annotations:{destructiveHint:!1,idempotentHint:!0,openWorldHint:!1,readOnlyHint:!0},description:`Reads complete durable invocation state. Wait at least pollAfterMs between calls. Terminal statuses are completed, failed, and cancelled. input_required needs agent_update; authorization_required needs the user to follow the returned authorization.${r}`,inputSchema:z.strictObject({invocationId:z.string().min(1).max(MAX_ID_CHARS)}),name:`agent_get`,outputSchema:AGENT_INVOCATION_OUTPUT_SCHEMA},async call(t,n){return invocationResult(requiredInvocation(await e.read({auth:n.auth,invocationId:t.invocationId})))}}),defineMcpTool({definition:{annotations:{destructiveHint:!0,idempotentHint:!1,openWorldHint:!0,readOnlyHint:!1},description:`Answers the pending input batch on an input_required invocation. Include one response per entry in inputRequests, each keyed by its requestId, in a single call; partial batches are rejected. Returns the current invocation state; repeating the same accepted answers is safe.`,inputSchema:z.strictObject({invocationId:z.string().min(1).max(MAX_ID_CHARS),responses:z.array(MCP_INPUT_RESPONSE_SCHEMA).min(1).max(MAX_RESPONSES_PER_UPDATE)}),name:`agent_update`,outputSchema:AGENT_INVOCATION_OUTPUT_SCHEMA},async call(t,n){return invocationResult(requiredMutation(await e.update({auth:n.auth,invocationId:t.invocationId,responses:t.responses})))}}),defineMcpTool({definition:{annotations:{destructiveHint:!0,idempotentHint:!0,openWorldHint:!1,readOnlyHint:!1},description:`Requests cooperative cancellation of a non-terminal invocation. Cancellation is asynchronous and can race with completion: poll agent_get until status is terminal (cancelled, completed, or failed). Safe to call repeatedly.`,inputSchema:z.strictObject({invocationId:z.string().min(1).max(MAX_ID_CHARS)}),name:`agent_cancel`,outputSchema:AGENT_INVOCATION_OUTPUT_SCHEMA},async call(t,n){return invocationResult(requiredInvocation(await e.cancel({auth:n.auth,invocationId:t.invocationId})))}})]}const INVOCATION_NOT_FOUND=`Invocation not found. It may have expired or belong to another caller.`;function requiredInvocation(e){if(e===void 0)throw new McpToolOperationError(`not_found`,INVOCATION_NOT_FOUND);return e}function requiredMutation(e){switch(e.type){case`success`:return e.invocation;case`conflict`:throw new McpToolOperationError(`conflict`,`${e.message} Call agent_get to read the current state before answering again.`);case`not_found`:throw new McpToolOperationError(`not_found`,INVOCATION_NOT_FOUND)}}function invocationResult(e){let t=parseJsonObject(e);return{content:[{text:JSON.stringify(t),type:`text`}],structuredContent:t}}const AUTHORIZATION_CHALLENGE_SCHEMA=z.strictObject({displayName:z.string().optional(),expiresAt:z.iso.datetime().optional(),instructions:z.string().optional(),url:z.url().optional(),userCode:z.string().optional()}),AUTHORIZATION_REQUEST_SCHEMA=z.strictObject({authorization:AUTHORIZATION_CHALLENGE_SCHEMA.optional(),description:z.string(),name:z.string(),webhookUrl:z.url().optional()}),MAX_MESSAGE_BYTES=65536,MAX_ID_CHARS=256,MAX_RESPONSES_PER_UPDATE=64;function utf8Bounded(e){let t=new TextEncoder;return z.string().refine(n=>t.encode(n).byteLength<=e,{message:`must be at most ${String(e)} bytes when UTF-8 encoded`})}const MCP_INPUT_RESPONSE_SCHEMA=inputResponseSchema.safeExtend({optionId:z.string().max(256).optional(),requestId:z.string().min(1).max(256),text:utf8Bounded(16384).optional()}),MCP_INPUT_REQUEST_SCHEMA=inputRequestSchema.safeExtend({action:z.strictObject({callId:z.string(),input:z.record(z.string(),z.json()),kind:z.literal(`tool-call`),toolName:z.string()})}),AGENT_INVOCATION_BASE_SCHEMA=z.strictObject({createdAt:z.iso.datetime(),expiresAt:z.iso.datetime().optional(),invocationId:z.string()}),AGENT_INVOCATION_OUTPUT_SCHEMA=z.discriminatedUnion(`status`,[AGENT_INVOCATION_BASE_SCHEMA.extend({pollAfterMs:z.number().int().nonnegative(),result:z.json().optional(),status:z.literal(`working`)}),AGENT_INVOCATION_BASE_SCHEMA.extend({inputRequests:z.record(z.string(),MCP_INPUT_REQUEST_SCHEMA),result:z.json().optional(),status:z.literal(`input_required`)}),AGENT_INVOCATION_BASE_SCHEMA.extend({authorizations:z.array(AUTHORIZATION_REQUEST_SCHEMA).min(1),pollAfterMs:z.number().int().nonnegative(),result:z.json().optional(),status:z.literal(`authorization_required`)}),AGENT_INVOCATION_BASE_SCHEMA.extend({result:z.json().optional(),status:z.literal(`completed`)}),AGENT_INVOCATION_BASE_SCHEMA.extend({error:z.strictObject({code:z.number().int(),data:z.json().optional(),message:z.string()}),status:z.literal(`failed`)}),AGENT_INVOCATION_BASE_SCHEMA.extend({status:z.literal(`cancelled`)})]);export{mcpChannel};
|
|
1
|
+
import{z}from"#compiled/zod/index.js";import{inputRequestSchema,inputResponseSchema}from"#shared/input.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{parseJsonObject}from"#shared/json.js";import{DELETE,GET,HEAD,OPTIONS,POST,defineChannel}from"#public/definitions/channel.js";import{readAgentInfoRouteResponse,readRouteChannelName,readRouteSessionCreator,readSkillFileSource}from"#internal/nitro/routes/channel-route-context.js";import{escapeAuthChallengeParameter,readOAuthResourceOptions,routeAuth}from"#public/channels/auth.js";import{McpToolOperationError,createMcpStreamableHttpServer,defineMcpTool}from"#internal/mcp/streamable-http-server.js";import{WorkflowAgentInvocationExecution}from"#internal/invocation/workflow-execution.js";import{MCP_TOOL_SESSIONS_EXTENSION,createPublishedTools}from"#internal/mcp/published-tools.js";import{resolveMcpRequestPrincipals}from"#internal/mcp/forwarded-principal-header.js";import{createMcpSkillsFeature}from"#internal/mcp/skills.js";import{validateMcpHttpRequest,validateMcpMetadataRequest}from"#internal/mcp/http-security.js";import{createMcpProtectedResourceMetadata,createMcpResourceChallenge}from"#internal/mcp/protected-resource.js";function mcpChannel(e){if(e?.auth===void 0)throw Error(`mcpChannel requires auth. Use none() for explicit public access.`);let t={agent:e.agent??!0,skills:e.skills??!1,tools:e.tools??!1};if(!t.agent&&!t.tools&&!t.skills)throw Error(`mcpChannel publishes nothing with agent, tools, and skills all false. Enable one.`);let n=e.route??`/eve/v1/mcp`,r=readOAuthResourceOptions(e.auth),handle=async(n,i)=>await authenticateMcpRequest(n,i,e,r,t),i=[GET(n,handle),POST(n,handle),DELETE(n,handle)];return r!==void 0&&i.unshift(...protectedResourceMetadataRoutes(r,n)),defineChannel({routes:i})}function protectedResourceMetadataRoutes(e,t){let n=protectedResourceMetadataPath(e,t);return[GET(n,async n=>protectedResourceMetadataResponse(n,e,t,!1)),HEAD(n,async n=>protectedResourceMetadataResponse(n,e,t,!0)),OPTIONS(n,async e=>protectedResourceMetadataOptionsResponse(e))]}function protectedResourceMetadataPath(e,t){if(e.metadataPath!==void 0)return e.metadataPath;let n=e.resource===void 0?t:new URL(e.resource).pathname;return n===`/`?`/.well-known/oauth-protected-resource`:`/.well-known/oauth-protected-resource${n}`}function protectedResourceMetadataResponse(e,t,n,r){let i=validateMcpMetadataRequest(e);if(i!==void 0)return i;let a=t.resource??new URL(n,new URL(e.url).origin).toString(),o=t.issuer===void 0?t.authorizationServers:[t.issuer],s=Response.json(createMcpProtectedResourceMetadata({authorizationServers:o,resource:a,scopesSupported:t.scopes}),{headers:{"access-control-allow-origin":`*`,"cache-control":`no-store`}});return r?new Response(null,{headers:s.headers,status:s.status}):s}function protectedResourceMetadataOptionsResponse(e){let t=validateMcpMetadataRequest(e);if(t!==void 0)return t;let n=new Headers({"access-control-allow-methods":`GET, HEAD, OPTIONS`,"access-control-allow-origin":`*`,"cache-control":`no-store`}),r=e.headers.get(`access-control-request-headers`);return r!==null&&(n.set(`access-control-allow-headers`,r),n.set(`vary`,`Access-Control-Request-Headers`)),new Response(null,{headers:n,status:204})}function addResourceChallenge(e,t,n){if(e.status!==401&&e.status!==403)return e;let r=protectedResourceMetadataPath(n,new URL(t.url).pathname),i=n.resource??new URL(t.url).origin,a=new URL(r,i).toString(),o=new Headers(e.headers),s=o.get(`www-authenticate`);if(e.status===401)o.set(`www-authenticate`,mergeMcpBearerChallenge(s,a,n.scopes));else{let t=augmentInsufficientScopeChallenge(s,a);if(t===void 0)return e;o.set(`www-authenticate`,t)}return new Response(e.body,{headers:o,status:e.status,statusText:e.statusText})}function mergeMcpBearerChallenge(e,t,n){let r=parseAuthChallenges(e),i=r.find(e=>e.scheme.toLowerCase()===`bearer`&&hasAuthParameter(e.value,`error`))??r.find(e=>e.scheme.toLowerCase()===`bearer`);return replaceBearerChallenges(r,i,i===void 0?createMcpResourceChallenge(t,n):augmentBearerChallenge(i.value,t,n))}function augmentInsufficientScopeChallenge(e,t){let n=parseAuthChallenges(e),r=n.find(e=>e.scheme.toLowerCase()===`bearer`&&hasAuthParameter(e.value,`error`,`insufficient_scope`));if(r!==void 0)return replaceBearerChallenges(n,r,augmentBearerChallenge(r.value,t))}function replaceBearerChallenges(e,t,n){let r=[],i=!1;for(let a of e){if(a.scheme.toLowerCase()!==`bearer`){r.push(a.value);continue}!i&&a===t&&(r.push(n),i=!0)}return i||r.push(n),r.join(`, `)}function augmentBearerChallenge(e,t,n){let r=e;return hasAuthParameter(r,`resource_metadata`)||(r=appendAuthParameter(r,`resource_metadata`,t)),n?.length&&!hasAuthParameter(r,`scope`)&&(r=appendAuthParameter(r,`scope`,n.join(` `))),r}function appendAuthParameter(e,t,n){return`${e}${e.trim().toLowerCase()===`bearer`?` `:`, `}${t}="${escapeAuthChallengeParameter(n)}"`}function hasAuthParameter(e,t,n){let r=t.replaceAll(/[.*+?^${}()|[\]\\]/g,`\\$&`);if(n===void 0)return RegExp(`(?:^|[\\s,])${r}\\s*=`,`i`).test(e);let i=n.replaceAll(/[.*+?^${}()|[\]\\]/g,`\\$&`);return RegExp(`(?:^|[\\s,])${r}\\s*=\\s*(?:"${i}"|${i})(?=$|[\\s,])`,`i`).test(e)}function parseAuthChallenges(e){if(e===null)return[];let t=[];for(let n of splitQuotedHeaderList(e)){let e=readChallengeScheme(n);if(e!==void 0){t.push({scheme:e,value:n});continue}let r=t.at(-1);r!==void 0&&(r.value+=`, ${n}`)}return t}function splitQuotedHeaderList(e){let t=[],n=!1,r=!1,i=0;for(let a=0;a<e.length;a++){let o=e[a];if(n)n=!1;else if(o===`\\`)n=!0;else if(o===`"`)r=!r;else if(o===`,`&&!r){let n=e.slice(i,a).trim();n.length>0&&t.push(n),i=a+1}}let a=e.slice(i).trim();return a.length>0&&t.push(a),t}function readChallengeScheme(e){let t=/^([!#$%&'*+\-.^_`|~0-9A-Za-z]+)(?:\s+|$)/.exec(e);if(t===null)return;let n=t[1];if(n!==void 0)return e.slice(n.length).trimStart().startsWith(`=`)?void 0:n}async function authenticateMcpRequest(e,t,n,r,i){let a=validateMcpHttpRequest(e);if(a!==void 0)return a;let o=await routeAuth(e,n.auth);if(o instanceof Response)return r===void 0?o:addResourceChallenge(o,e,r);let s=await resolveMcpRequestPrincipals(e,o,n.trustedForwarders);return s instanceof Response?s:await handleMcpRequest(e,t,o,s,i)}async function handleMcpRequest(e,t,n,r,i){let a=readRouteSessionCreator(t),o=readRouteChannelName(t),s=readAgentInfoRouteResponse(t);if(o===void 0||a===void 0||s===void 0)return Response.json({error:`MCP requires agent route context.`},{status:500});let c=await s();if(!c.ok)return c;let l=await c.json();if(typeof l.agent?.name!=`string`)return Response.json({error:`MCP requires compiled agent metadata.`},{status:500});let u=typeof l.agent.description==`string`?l.agent.description:void 0,d=new WorkflowAgentInvocationExecution({createSession:a,from:t.from}),f=i.agent?createInvocationTools(d,u,n.authenticator===`none`&&n.principalType===`anonymous`):[],p=i.tools||i.skills?await t.describe():void 0,m=i.tools&&p!==void 0?createPublishedTools({invokeTool:t.invokeTool,principals:r,reserved:new Set(f.map(e=>e.name)),tools:p.tools}):[],h=[];if(i.tools&&h.push({capabilities:{extensions:{[MCP_TOOL_SESSIONS_EXTENSION]:{}}},register(){}}),i.skills&&p!==void 0){let e=readSkillFileSource(t);if(e===void 0)return Response.json({error:`MCP requires agent route context.`},{status:500});h.push(createMcpSkillsFeature({files:e,skills:p.skills}))}return await createMcpStreamableHttpServer({authenticate:async()=>n,features:h,instructions:i.agent?MCP_SERVER_INSTRUCTIONS:void 0,name:l.agent.name,tools:i.agent||i.tools?[...f,...m]:void 0,version:resolveInstalledPackageInfo().version})(e)}const MCP_SERVER_INSTRUCTIONS=[`Each invocation is one durable agent task.`,`Call agent_start once per task and keep the returned invocationId.`,`Poll agent_get, waiting at least pollAfterMs between calls, until status is completed, failed, or cancelled.`,`If status is input_required, answer every entry in inputRequests in one agent_update call; repeating accepted answers is safe.`,`If status is authorization_required, show the user the authorization url or instructions and keep polling.`,`isError on a tool result means your call was rejected; a failed status means the task failed.`,`agent_start is not idempotent and a lost response leaves no invocationId, so ask the user before starting again.`,`Work continues after your connection drops; agent_cancel stops it, then poll until any terminal status.`].join(` `);function createInvocationTools(e,t,n){let r=n?` On this public channel, the invocation ID is a bearer capability until workflow retention expires.`:``,i=`Starts durable work and returns an invocation handle immediately. Call once per task; keep invocationId and poll agent_get. Not idempotent: if the response is lost, ask the user before starting again rather than retrying.${r}`;return[defineMcpTool({definition:{annotations:{destructiveHint:!0,idempotentHint:!1,openWorldHint:!0,readOnlyHint:!1},description:t===void 0?i:`${t} ${i}`,inputSchema:z.strictObject({message:utf8Bounded(MAX_MESSAGE_BYTES).min(1)}),name:`agent_start`,outputSchema:AGENT_INVOCATION_OUTPUT_SCHEMA},async call(t,n){return invocationResult(await e.create({auth:n.auth,message:t.message}))}}),defineMcpTool({definition:{annotations:{destructiveHint:!1,idempotentHint:!0,openWorldHint:!1,readOnlyHint:!0},description:`Reads complete durable invocation state. Wait at least pollAfterMs between calls. Terminal statuses are completed, failed, and cancelled. input_required needs agent_update; authorization_required needs the user to follow the returned authorization.${r}`,inputSchema:z.strictObject({invocationId:z.string().min(1).max(MAX_ID_CHARS)}),name:`agent_get`,outputSchema:AGENT_INVOCATION_OUTPUT_SCHEMA},async call(t,n){return invocationResult(requiredInvocation(await e.read({auth:n.auth,invocationId:t.invocationId})))}}),defineMcpTool({definition:{annotations:{destructiveHint:!0,idempotentHint:!1,openWorldHint:!0,readOnlyHint:!1},description:`Answers the pending input batch on an input_required invocation. Include one response per entry in inputRequests, each keyed by its requestId, in a single call; partial batches are rejected. Returns the current invocation state; repeating the same accepted answers is safe.`,inputSchema:z.strictObject({invocationId:z.string().min(1).max(MAX_ID_CHARS),responses:z.array(MCP_INPUT_RESPONSE_SCHEMA).min(1).max(MAX_RESPONSES_PER_UPDATE)}),name:`agent_update`,outputSchema:AGENT_INVOCATION_OUTPUT_SCHEMA},async call(t,n){return invocationResult(requiredMutation(await e.update({auth:n.auth,invocationId:t.invocationId,responses:t.responses})))}}),defineMcpTool({definition:{annotations:{destructiveHint:!0,idempotentHint:!0,openWorldHint:!1,readOnlyHint:!1},description:`Requests cooperative cancellation of a non-terminal invocation. Cancellation is asynchronous and can race with completion: poll agent_get until status is terminal (cancelled, completed, or failed). Safe to call repeatedly.`,inputSchema:z.strictObject({invocationId:z.string().min(1).max(MAX_ID_CHARS)}),name:`agent_cancel`,outputSchema:AGENT_INVOCATION_OUTPUT_SCHEMA},async call(t,n){return invocationResult(requiredInvocation(await e.cancel({auth:n.auth,invocationId:t.invocationId})))}})]}const INVOCATION_NOT_FOUND=`Invocation not found. It may have expired or belong to another caller.`;function requiredInvocation(e){if(e===void 0)throw new McpToolOperationError(`not_found`,INVOCATION_NOT_FOUND);return e}function requiredMutation(e){switch(e.type){case`success`:return e.invocation;case`conflict`:throw new McpToolOperationError(`conflict`,`${e.message} Call agent_get to read the current state before answering again.`);case`not_found`:throw new McpToolOperationError(`not_found`,INVOCATION_NOT_FOUND)}}function invocationResult(e){let t=parseJsonObject(e);return{content:[{text:JSON.stringify(t),type:`text`}],structuredContent:t}}const AUTHORIZATION_CHALLENGE_SCHEMA=z.strictObject({displayName:z.string().optional(),expiresAt:z.iso.datetime().optional(),instructions:z.string().optional(),url:z.url().optional(),userCode:z.string().optional()}),AUTHORIZATION_REQUEST_SCHEMA=z.strictObject({authorization:AUTHORIZATION_CHALLENGE_SCHEMA.optional(),description:z.string(),name:z.string(),webhookUrl:z.url().optional()}),MAX_MESSAGE_BYTES=65536,MAX_ID_CHARS=256,MAX_RESPONSES_PER_UPDATE=64;function utf8Bounded(e){let t=new TextEncoder;return z.string().refine(n=>t.encode(n).byteLength<=e,{message:`must be at most ${String(e)} bytes when UTF-8 encoded`})}const MCP_INPUT_RESPONSE_SCHEMA=inputResponseSchema.safeExtend({optionId:z.string().max(256).optional(),requestId:z.string().min(1).max(256),text:utf8Bounded(16384).optional()}),MCP_INPUT_REQUEST_SCHEMA=inputRequestSchema.safeExtend({action:z.strictObject({callId:z.string(),input:z.record(z.string(),z.json()),kind:z.literal(`tool-call`),toolName:z.string()})}),AGENT_INVOCATION_BASE_SCHEMA=z.strictObject({createdAt:z.iso.datetime(),expiresAt:z.iso.datetime().optional(),invocationId:z.string()}),AGENT_INVOCATION_OUTPUT_SCHEMA=z.discriminatedUnion(`status`,[AGENT_INVOCATION_BASE_SCHEMA.extend({pollAfterMs:z.number().int().nonnegative(),result:z.json().optional(),status:z.literal(`working`)}),AGENT_INVOCATION_BASE_SCHEMA.extend({inputRequests:z.record(z.string(),MCP_INPUT_REQUEST_SCHEMA),result:z.json().optional(),status:z.literal(`input_required`)}),AGENT_INVOCATION_BASE_SCHEMA.extend({authorizations:z.array(AUTHORIZATION_REQUEST_SCHEMA).min(1),pollAfterMs:z.number().int().nonnegative(),result:z.json().optional(),status:z.literal(`authorization_required`)}),AGENT_INVOCATION_BASE_SCHEMA.extend({result:z.json().optional(),status:z.literal(`completed`)}),AGENT_INVOCATION_BASE_SCHEMA.extend({error:z.strictObject({code:z.number().int(),data:z.json().optional(),message:z.string()}),status:z.literal(`failed`)}),AGENT_INVOCATION_BASE_SCHEMA.extend({status:z.literal(`cancelled`)})]);export{mcpChannel};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger}from"#internal/logging.js";import{parseInputResponse}from"#shared/input.js";import{readSlackTextObject}from"#public/channels/slack/inbound-content.js";import{isSlackResponseError}from"#public/channels/slack/transport.js";import{buildSlackAuthContext}from"#public/channels/slack/auth.js";import{HITL_FREEFORM_MODAL_ACTION_ID,HITL_FREEFORM_MODAL_BLOCK_ID,HITL_FREEFORM_MODAL_CALLBACK_ID,buildFreeformModalView,decodeFreeformHitlActionId,decodeHitlResponse,isFreeformAction,isHitlAction}from"#public/channels/slack/hitl.js";import{buildSlackBinding,buildSlackWorkspaceHandle,callSlackApi,resolveSlackBotToken,slackContinuationToken}from"#public/channels/slack/api.js";import{dispatchSignInCancel}from"#public/channels/slack/sign-in-cancel.js";import{parseSlackWebhookBody}from"#compiled/@chat-adapter/slack/webhook.js";import{updateAnsweredFreeformCard,updateAnsweredHitlCard}from"#public/channels/slack/interaction-cards.js";import{authorizeInputResponse}from"#public/channels/slack/input-response.js";import{bindSlackSessionOperations,withSlackResponder}from"#public/channels/slack/session-operations.js";import{dispatchSlashCommand}from"#public/channels/slack/slash-command.js";const log=createLogger(`slack.interactions`);function parseBlockActionsPayload(e){if(isSharedBlockActionsPayload(e))return parseSharedBlockActionsPayload(e);let t=e,n=t.actions;if(!Array.isArray(n))return null;let r=t.channel?.id,i=t.message,a=i?.thread_ts??i?.ts;if(!r||!a)return null;let o=t.team,s=t.user,c=s.team_id??o?.id,l={id:s.id,username:s.username,name:s.name},u=i?.blocks??[];return{actions:n.map(e=>({actionId:String(e.action_id??``),value:e.value==null?void 0:String(e.value),blockId:e.block_id==null?void 0:String(e.block_id),selectedOptionValue:extractSelectedOptionValue(e),messageTs:i?.ts,label:extractActionLabel(e),user:l})),channelId:r,installationTeamId:readInstallationTeamId(t),threadTs:a,teamId:c,messageBlocks:u}}function isSharedBlockActionsPayload(e){return e.kind===`block_actions`&&Array.isArray(e.actions)}function parseSharedBlockActionsPayload(e){return!e.channelId||!e.threadTs?null:{actions:e.actions.map(t=>({actionId:t.actionId,value:t.value,blockId:t.blockId,selectedOptionValue:t.selectedOptionValue,messageTs:e.messageTs,label:t.label,user:{id:t.user?.id??e.userId,username:t.user?.username,name:t.user?.name}})),channelId:e.channelId,installationTeamId:readInstallationTeamId(e.raw),threadTs:e.threadTs,teamId:e.user?.teamId??e.teamId,messageBlocks:e.messageBlocks??[]}}function extractSelectedOptionValue(e){let t=e.selected_option;return typeof t?.value==`string`?t.value:void 0}function extractActionLabel(e){let t=e.selected_option?.text?.text;if(typeof t==`string`&&t.length>0)return t;let n=e.text?.text;if(typeof n==`string`&&n.length>0)return n}function findPromptBlocks(e){let t=[];for(let n of e){if(typeof n!=`object`||!n)continue;let e=n.type;if(e===`actions`)break;(e===`section`||e===`context`||e===`divider`||e===`image`)&&t.push(n)}return t}function readPromptTextFromBlocks(e){let t=findPromptBlocks(e)[0],n=readSlackTextObject(t?.text);return n.length>0?n:void 0}function isObjectRecord(e){return typeof e==`object`&&!!e}function readInstallationTeamId(e){if(!isObjectRecord(e))return;let t=isObjectRecord(e.view)?e.view:void 0,n=isObjectRecord(e.team)?e.team:void 0,r=isObjectRecord(e.user)?e.user:void 0;return[t?.app_installed_team_id,e.app_installed_team_id,n?.id,r?.team_id,t?.team_id].find(e=>typeof e==`string`&&e.length>0)}async function handleInteractionPost(e,t,n){let r=new Response(`ok`,{status:200}),i;try{i=parseSlackWebhookBody(e,{contentType:`application/x-www-form-urlencoded`})}catch{return log.warn(`failed to parse Slack interaction payload`),r}if(i.kind===`view_submission`)return handleViewSubmission(i,t,n);if(i.kind===`slash_command`)return dispatchSlashCommand(i,t,n),new Response(null,{status:200});if(i.kind===`unsupported`){let e=parseShortcutPayload(i.raw);return e===null?(log.warn(`unsupported Slack interaction payload ignored`,{type:i.type}),r):(dispatchShortcut(e,readInstallationTeamId(i.raw),t,n),new Response(null,{status:200}))}if(i.kind!==`block_actions`)return log.warn(`unsupported Slack interaction payload ignored`,{type:i.kind}),r;if(dispatchSignInCancel(i.raw,t))return r;let a=parseBlockActionsPayload(i);if(!a)return r;let o=a.actions.find(e=>isFreeformAction(e.actionId));if(o)return await openFreeformModal({payload:i.raw,interaction:a,freeformAction:o,deps:n}),r;let s=a.actions.flatMap(e=>{let t=decodeHitlResponse(e);return t===null?[]:[{action:e,derived:t}]});if(s.length>0){let e=s[0].action.user,r=s[0].derived.route;t.waitUntil(dispatchBlockInputResponses({ctx:t,deps:n,interaction:a,route:r,submission:{type:`block_actions`,actions:s.map(({action:e})=>e),inputResponses:s.map(({derived:e})=>e.response),messageTs:s[0].action.messageTs,user:e}}))}let c=n.config.onInteraction;if(c){let e=a.actions.filter(e=>!isHitlAction(e.actionId));if(e.length>0){let r=e[0].user,{thread:i,slack:o}=buildSlackBinding({api:n.api,botToken:n.config.credentials?.botToken,channelId:a.channelId,threadTs:a.threadTs,installationTeamId:a.installationTeamId,teamId:a.teamId}),s={...bindSlackSessionOperations({address:slackContinuationToken(a.channelId,a.threadTs),defaultAuth:buildSlackAuthContext({channelId:a.channelId,installationTeamId:a.installationTeamId,teamId:a.teamId,threadTs:a.threadTs,userId:r.id,userName:r.username??r.name}),from:t.from,resolveSession:t.resolveSession,state:{channelId:a.channelId,installationTeamId:a.installationTeamId??null,teamId:a.teamId??null,threadTs:a.threadTs,triggeringUserId:r.id}}),thread:i,slack:o};for(let n of e)t.waitUntil(Promise.resolve(c(n,s)).catch(e=>{log.error(`custom interaction handler failed`,{error:e})}))}}return r}function parseShortcutPayload(e){if(!isObjectRecord(e))return null;let t=e.type;if(t!==`message_action`&&t!==`shortcut`)return null;let n=readRequiredString(e.callback_id),r=readRequiredString(e.trigger_id),i=isObjectRecord(e.user)?e.user:void 0,a=readRequiredString(i?.id);if(n===null||r===null||a===null)return null;let o=isObjectRecord(e.team)?e.team:void 0,s=readOptionalString(i?.team_id)??readOptionalString(o?.id),c={id:a,username:readOptionalString(i?.username),name:readOptionalString(i?.name)};if(t===`shortcut`)return{type:t,callbackId:n,triggerId:r,user:c,teamId:s};let l=isObjectRecord(e.channel)?e.channel:void 0,u=isObjectRecord(e.message)?e.message:void 0,d=readRequiredString(l?.id),f=readRequiredString(u?.ts);return d===null||f===null||u===void 0?null:{type:t,callbackId:n,triggerId:r,user:c,teamId:s,channelId:d,message:{text:typeof u.text==`string`?u.text:``,ts:f,threadTs:readOptionalString(u.thread_ts),userId:readOptionalString(u.user)},responseUrl:readOptionalString(e.response_url)}}function readRequiredString(e){return typeof e==`string`&&e.length>0?e:null}function readOptionalString(e){return typeof e==`string`&&e.length>0?e:void 0}function dispatchShortcut(e,t,n,r){let i=r.config.onShortcut;if(i===void 0){log.warn(`Slack shortcut ignored because onShortcut is not configured`,{type:e.type});return}let a={slack:buildSlackWorkspaceHandle({api:r.api,botToken:r.config.credentials?.botToken,installationTeamId:t,teamId:e.teamId})};dispatchInteractionHook(()=>i(e,a),n,`shortcut handler failed`)}function dispatchInteractionHook(e,t,n){t.waitUntil(Promise.resolve().then(e).catch(e=>{log.error(n,{error:e})}))}async function dispatchBlockInputResponses(e){let t=e.route?.channelId??e.interaction.channelId,n=e.route?.threadTs??e.interaction.threadTs,r=await authorizeInputResponse({channelId:t,deps:e.deps,installationTeamId:e.interaction.installationTeamId,submission:e.submission,teamId:e.interaction.teamId,threadTs:n});if(r!==null){try{await e.ctx.from(slackContinuationToken(t,n)).respond(e.submission.inputResponses,{auth:r.auth,state:withSlackResponder(void 0,e.submission.user.id)})}catch(e){log.error(`HITL interaction delivery failed`,{error:e});return}if(!e.submission.actions.some(e=>decodeHitlResponse(e)?.kind===`tool-approval`))try{await updateAnsweredHitlCard(e.interaction,e.deps)}catch(e){log.error(`HITL answered-card update failed`,{error:e})}}}async function openFreeformModal(e){let t=e.payload.trigger_id;if(typeof t!=`string`||t.length===0){log.warn(`freeform button click missing trigger_id — cannot open modal`);return}let n=decodeFreeformHitlActionId(e.freeformAction.actionId);if(n===null){log.warn(`freeform button click carries invalid metadata`);return}let r=n.requestId;if(!r){log.warn(`freeform button click missing requestId`);return}let i=e.freeformAction.messageTs;if(!i){log.warn(`freeform button click missing messageTs`);return}let a=n?.route?.channelId??e.interaction.channelId,o=n?.route?.threadTs??e.interaction.threadTs,s={continuationToken:slackContinuationToken(a,o),channelId:a,installationTeamId:e.interaction.installationTeamId,messageChannelId:e.interaction.channelId,threadTs:o,messageTs:i,requestId:r},c=readPromptTextFromBlocks(e.interaction.messageBlocks),l=buildFreeformModalView({metadata:s,prompt:c}),u=await resolveSlackBotToken(e.deps.config.credentials?.botToken,{teamId:e.interaction.installationTeamId});try{await callSlackApi({api:e.deps.api,botToken:u,operation:`views.open`,body:{trigger_id:t,view:l}})}catch(e){if(!isSlackResponseError(e))throw e;log.error(`Slack views.open failed`,{error:e})}}async function handleViewSubmission(e,t,n){let r=new Response(null,{status:200});if(e.callbackId!==HITL_FREEFORM_MODAL_CALLBACK_ID)return r;let i;try{i=JSON.parse(e.privateMetadata??``)}catch{return log.warn(`freeform view_submission carries invalid private_metadata`),r}if(!i.continuationToken||!i.requestId||!i.messageTs||!i.channelId||!i.threadTs)return r;let a=e.values?.find(e=>e.blockId===HITL_FREEFORM_MODAL_BLOCK_ID&&e.actionId===HITL_FREEFORM_MODAL_ACTION_ID)?.value??``;if(a.length===0)return r;let o=e.user,s=e.userId,c=o?.teamId??e.teamId??null,l=i.installationTeamId??readInstallationTeamId(e.raw),u={type:`view_submission`,inputResponses:[parseInputResponse({requestId:i.requestId,text:a})],messageTs:i.messageTs,user:{id:s,username:o?.username,name:o?.name}};return t.waitUntil(dispatchViewInputResponse({ctx:t,deps:n,installationTeamId:l,metadata:i,submission:u,teamId:c,text:a})),r}async function dispatchViewInputResponse(e){let t=await authorizeInputResponse({channelId:e.metadata.channelId,deps:e.deps,installationTeamId:e.installationTeamId,submission:e.submission,teamId:e.teamId,threadTs:e.metadata.threadTs});if(t!==null){try{await e.ctx.from(e.metadata.continuationToken).respond(e.submission.inputResponses,{auth:t.auth,state:withSlackResponder(void 0,e.submission.user.id)})}catch(e){log.error(`freeform answer delivery failed`,{error:e});return}try{await updateAnsweredFreeformCard({channelId:e.metadata.messageChannelId??e.metadata.channelId,messageTs:e.metadata.messageTs,answerLabel:e.text,userId:e.submission.user.id,installationTeamId:e.installationTeamId,deps:e.deps})}catch(e){log.error(`freeform answered-card update failed`,{error:e})}}}export{handleInteractionPost,parseBlockActionsPayload,parseShortcutPayload};
|
|
1
|
+
import{createLogger}from"#internal/logging.js";import{parseInputResponse}from"#shared/input.js";import{readSlackTextObject}from"#public/channels/slack/inbound-content.js";import{isSlackResponseError}from"#public/channels/slack/transport.js";import{buildSlackAuthContext}from"#public/channels/slack/auth.js";import{HITL_FREEFORM_MODAL_ACTION_ID,HITL_FREEFORM_MODAL_BLOCK_ID,HITL_FREEFORM_MODAL_CALLBACK_ID,buildFreeformModalView,decodeFreeformHitlActionId,decodeHitlResponse,isFreeformAction,isHitlAction}from"#public/channels/slack/hitl.js";import{buildSlackBinding,buildSlackWorkspaceHandle,callSlackApi,resolveSlackBotToken,slackContinuationToken}from"#public/channels/slack/api.js";import{dispatchSignInCancel}from"#public/channels/slack/sign-in-cancel.js";import{parseSlackWebhookBody}from"#compiled/@chat-adapter/slack/webhook.js";import{updateAnsweredFreeformCard,updateAnsweredHitlCard}from"#public/channels/slack/interaction-cards.js";import{authorizeInputResponse}from"#public/channels/slack/input-response.js";import{bindSlackSessionOperations,withSlackResponder}from"#public/channels/slack/session-operations.js";import{dispatchSlashCommand}from"#public/channels/slack/slash-command.js";const log=createLogger(`slack.interactions`);function parseBlockActionsPayload(e){if(isSharedBlockActionsPayload(e))return parseSharedBlockActionsPayload(e);let t=e,n=t.actions;if(!Array.isArray(n))return null;let r=t.channel?.id,i=t.message,a=i?.thread_ts??i?.ts;if(!r||!a)return null;let o=t.team,s=t.user,c=s.team_id??o?.id,l={id:s.id,username:s.username,name:s.name},u=i?.blocks??[];return{actions:n.map(e=>({actionId:String(e.action_id??``),value:e.value==null?void 0:String(e.value),blockId:e.block_id==null?void 0:String(e.block_id),selectedOptionValue:extractSelectedOptionValue(e),messageTs:i?.ts,triggerId:typeof t.trigger_id==`string`?t.trigger_id:void 0,label:extractActionLabel(e),user:l})),channelId:r,installationTeamId:readInstallationTeamId(t),threadTs:a,teamId:c,messageBlocks:u}}function isSharedBlockActionsPayload(e){return e.kind===`block_actions`&&Array.isArray(e.actions)}function parseSharedBlockActionsPayload(e){return!e.channelId||!e.threadTs?null:{actions:e.actions.map(t=>({actionId:t.actionId,value:t.value,blockId:t.blockId,selectedOptionValue:t.selectedOptionValue,messageTs:e.messageTs,triggerId:e.triggerId,label:t.label,user:{id:t.user?.id??e.userId,username:t.user?.username,name:t.user?.name}})),channelId:e.channelId,installationTeamId:readInstallationTeamId(e.raw),threadTs:e.threadTs,teamId:e.user?.teamId??e.teamId,messageBlocks:e.messageBlocks??[]}}function extractSelectedOptionValue(e){let t=e.selected_option;return typeof t?.value==`string`?t.value:void 0}function extractActionLabel(e){let t=e.selected_option?.text?.text;if(typeof t==`string`&&t.length>0)return t;let n=e.text?.text;if(typeof n==`string`&&n.length>0)return n}function findPromptBlocks(e){let t=[];for(let n of e){if(typeof n!=`object`||!n)continue;let e=n.type;if(e===`actions`)break;(e===`section`||e===`context`||e===`divider`||e===`image`)&&t.push(n)}return t}function readPromptTextFromBlocks(e){let t=findPromptBlocks(e)[0],n=readSlackTextObject(t?.text);return n.length>0?n:void 0}function isObjectRecord(e){return typeof e==`object`&&!!e}function readInstallationTeamId(e){if(!isObjectRecord(e))return;let t=isObjectRecord(e.view)?e.view:void 0,n=isObjectRecord(e.team)?e.team:void 0,r=isObjectRecord(e.user)?e.user:void 0;return[t?.app_installed_team_id,e.app_installed_team_id,n?.id,r?.team_id,t?.team_id].find(e=>typeof e==`string`&&e.length>0)}async function handleInteractionPost(e,t,n){let r=new Response(`ok`,{status:200}),i;try{i=parseSlackWebhookBody(e,{contentType:`application/x-www-form-urlencoded`})}catch{return log.warn(`failed to parse Slack interaction payload`),r}if(i.kind===`view_submission`)return handleViewSubmission(i,t,n);if(i.kind===`slash_command`)return dispatchSlashCommand(i,t,n),new Response(null,{status:200});if(i.kind===`unsupported`){let e=parseShortcutPayload(i.raw);return e===null?(log.warn(`unsupported Slack interaction payload ignored`,{type:i.type}),r):(dispatchShortcut(e,readInstallationTeamId(i.raw),t,n),new Response(null,{status:200}))}if(i.kind!==`block_actions`)return log.warn(`unsupported Slack interaction payload ignored`,{type:i.kind}),r;if(dispatchSignInCancel(i.raw,t))return r;let a=parseBlockActionsPayload(i);if(!a)return r;let o=a.actions.find(e=>isFreeformAction(e.actionId));if(o)return await openFreeformModal({payload:i.raw,interaction:a,freeformAction:o,deps:n}),r;let s=a.actions.flatMap(e=>{let t=decodeHitlResponse(e);return t===null?[]:[{action:e,derived:t}]});if(s.length>0){let e=s[0].action.user,r=s[0].derived.route;t.waitUntil(dispatchBlockInputResponses({ctx:t,deps:n,interaction:a,route:r,submission:{type:`block_actions`,actions:s.map(({action:e})=>e),inputResponses:s.map(({derived:e})=>e.response),messageTs:s[0].action.messageTs,user:e}}))}let c=n.config.onInteraction;if(c){let e=a.actions.filter(e=>!isHitlAction(e.actionId));if(e.length>0){let r=e[0].user,{thread:i,slack:o}=buildSlackBinding({api:n.api,botToken:n.config.credentials?.botToken,channelId:a.channelId,threadTs:a.threadTs,installationTeamId:a.installationTeamId,teamId:a.teamId}),s={...bindSlackSessionOperations({address:slackContinuationToken(a.channelId,a.threadTs),defaultAuth:buildSlackAuthContext({channelId:a.channelId,installationTeamId:a.installationTeamId,teamId:a.teamId,threadTs:a.threadTs,userId:r.id,userName:r.username??r.name}),from:t.from,resolveSession:t.resolveSession,state:{channelId:a.channelId,installationTeamId:a.installationTeamId??null,teamId:a.teamId??null,threadTs:a.threadTs,triggeringUserId:r.id}}),thread:i,slack:o};for(let n of e)t.waitUntil(Promise.resolve(c(n,s)).catch(e=>{log.error(`custom interaction handler failed`,{error:e})}))}}return r}function parseShortcutPayload(e){if(!isObjectRecord(e))return null;let t=e.type;if(t!==`message_action`&&t!==`shortcut`)return null;let n=readRequiredString(e.callback_id),r=readRequiredString(e.trigger_id),i=isObjectRecord(e.user)?e.user:void 0,a=readRequiredString(i?.id);if(n===null||r===null||a===null)return null;let o=isObjectRecord(e.team)?e.team:void 0,s=readOptionalString(i?.team_id)??readOptionalString(o?.id),c={id:a,username:readOptionalString(i?.username),name:readOptionalString(i?.name)};if(t===`shortcut`)return{type:t,callbackId:n,triggerId:r,user:c,teamId:s};let l=isObjectRecord(e.channel)?e.channel:void 0,u=isObjectRecord(e.message)?e.message:void 0,d=readRequiredString(l?.id),f=readRequiredString(u?.ts);return d===null||f===null||u===void 0?null:{type:t,callbackId:n,triggerId:r,user:c,teamId:s,channelId:d,message:{text:typeof u.text==`string`?u.text:``,ts:f,threadTs:readOptionalString(u.thread_ts),userId:readOptionalString(u.user)},responseUrl:readOptionalString(e.response_url)}}function readRequiredString(e){return typeof e==`string`&&e.length>0?e:null}function readOptionalString(e){return typeof e==`string`&&e.length>0?e:void 0}function dispatchShortcut(e,t,n,r){let i=r.config.onShortcut;if(i===void 0){log.warn(`Slack shortcut ignored because onShortcut is not configured`,{type:e.type});return}let a={slack:buildSlackWorkspaceHandle({api:r.api,botToken:r.config.credentials?.botToken,installationTeamId:t,teamId:e.teamId})};dispatchInteractionHook(()=>i(e,a),n,`shortcut handler failed`)}function dispatchInteractionHook(e,t,n){t.waitUntil(Promise.resolve().then(e).catch(e=>{log.error(n,{error:e})}))}async function dispatchBlockInputResponses(e){let t=e.route?.channelId??e.interaction.channelId,n=e.route?.threadTs??e.interaction.threadTs,r=await authorizeInputResponse({channelId:t,deps:e.deps,installationTeamId:e.interaction.installationTeamId,submission:e.submission,teamId:e.interaction.teamId,threadTs:n});if(r!==null){try{await e.ctx.from(slackContinuationToken(t,n)).respond(e.submission.inputResponses,{auth:r.auth,state:withSlackResponder(void 0,e.submission.user.id)})}catch(e){log.error(`HITL interaction delivery failed`,{error:e});return}if(!e.submission.actions.some(e=>decodeHitlResponse(e)?.kind===`tool-approval`))try{await updateAnsweredHitlCard(e.interaction,e.deps)}catch(e){log.error(`HITL answered-card update failed`,{error:e})}}}async function openFreeformModal(e){let t=e.payload.trigger_id;if(typeof t!=`string`||t.length===0){log.warn(`freeform button click missing trigger_id — cannot open modal`);return}let n=decodeFreeformHitlActionId(e.freeformAction.actionId);if(n===null){log.warn(`freeform button click carries invalid metadata`);return}let r=n.requestId;if(!r){log.warn(`freeform button click missing requestId`);return}let i=e.freeformAction.messageTs;if(!i){log.warn(`freeform button click missing messageTs`);return}let a=n?.route?.channelId??e.interaction.channelId,o=n?.route?.threadTs??e.interaction.threadTs,s={continuationToken:slackContinuationToken(a,o),channelId:a,installationTeamId:e.interaction.installationTeamId,messageChannelId:e.interaction.channelId,threadTs:o,messageTs:i,requestId:r},c=readPromptTextFromBlocks(e.interaction.messageBlocks),l=buildFreeformModalView({metadata:s,prompt:c}),u=await resolveSlackBotToken(e.deps.config.credentials?.botToken,{teamId:e.interaction.installationTeamId});try{await callSlackApi({api:e.deps.api,botToken:u,operation:`views.open`,body:{trigger_id:t,view:l}})}catch(e){if(!isSlackResponseError(e))throw e;log.error(`Slack views.open failed`,{error:e})}}async function handleViewSubmission(e,t,n){let r=new Response(null,{status:200});if(e.callbackId!==HITL_FREEFORM_MODAL_CALLBACK_ID)return r;let i;try{i=JSON.parse(e.privateMetadata??``)}catch{return log.warn(`freeform view_submission carries invalid private_metadata`),r}if(!i.continuationToken||!i.requestId||!i.messageTs||!i.channelId||!i.threadTs)return r;let a=e.values?.find(e=>e.blockId===HITL_FREEFORM_MODAL_BLOCK_ID&&e.actionId===HITL_FREEFORM_MODAL_ACTION_ID)?.value??``;if(a.length===0)return r;let o=e.user,s=e.userId,c=o?.teamId??e.teamId??null,l=i.installationTeamId??readInstallationTeamId(e.raw),u={type:`view_submission`,inputResponses:[parseInputResponse({requestId:i.requestId,text:a})],messageTs:i.messageTs,user:{id:s,username:o?.username,name:o?.name}};return t.waitUntil(dispatchViewInputResponse({ctx:t,deps:n,installationTeamId:l,metadata:i,submission:u,teamId:c,text:a})),r}async function dispatchViewInputResponse(e){let t=await authorizeInputResponse({channelId:e.metadata.channelId,deps:e.deps,installationTeamId:e.installationTeamId,submission:e.submission,teamId:e.teamId,threadTs:e.metadata.threadTs});if(t!==null){try{await e.ctx.from(e.metadata.continuationToken).respond(e.submission.inputResponses,{auth:t.auth,state:withSlackResponder(void 0,e.submission.user.id)})}catch(e){log.error(`freeform answer delivery failed`,{error:e});return}try{await updateAnsweredFreeformCard({channelId:e.metadata.messageChannelId??e.metadata.channelId,messageTs:e.metadata.messageTs,answerLabel:e.text,userId:e.submission.user.id,installationTeamId:e.installationTeamId,deps:e.deps})}catch(e){log.error(`freeform answered-card update failed`,{error:e})}}}export{handleInteractionPost,parseBlockActionsPayload,parseShortcutPayload};
|
|
@@ -353,6 +353,12 @@ export interface SlackInteractionAction {
|
|
|
353
353
|
* inside thread replies.
|
|
354
354
|
*/
|
|
355
355
|
readonly messageTs?: string;
|
|
356
|
+
/**
|
|
357
|
+
* Slack `trigger_id` of the click. Pass it to `views.open` (for example
|
|
358
|
+
* through `ctx.slack.request`) to open a modal from a message button. Slack
|
|
359
|
+
* accepts it for about 3 seconds, so call `views.open` first in the handler.
|
|
360
|
+
*/
|
|
361
|
+
readonly triggerId?: string;
|
|
356
362
|
/**
|
|
357
363
|
* Display label of the clicked widget: `text.text` for buttons,
|
|
358
364
|
* `selected_option.text.text` for radio/static_select. Renders the
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import{extractErrorId,formatErrorHint}from"#internal/logging.js";import{displayProperName}from"#shared/display-name.js";import{renderTextInputRequest}from"#channel/resolve-text.js";function defaultTwilioAuth(e){let t={channel:e.channel,from:e.from};return e.to!==void 0&&(t.to=e.to),{attributes:t,authenticator:`twilio-webhook`,issuer:`twilio`,principalId:`twilio:${e.from}`,principalType:`user`}}function defaultOnText(e,t){return{auth:defaultTwilioAuth({channel:`text`,from:t.from,to:t.to})}}function defaultOnVoice(e,t){return{}}function defaultOnVoiceTranscription(e,t){return{auth:defaultTwilioAuth({channel:`voice`,from:t.from,to:t.to})}}const defaultEvents={async"message.completed"(e,t,n){e.finishReason!==`tool-calls`&&e.message&&await t.twilio.sendMessage(e.message)}
|
|
1
|
+
import{extractErrorId,formatErrorHint}from"#internal/logging.js";import{displayProperName}from"#shared/display-name.js";import{renderTextInputRequest}from"#channel/resolve-text.js";import{promptQueueEvents}from"#channel/prompt-queue.js";function defaultTwilioAuth(e){let t={channel:e.channel,from:e.from};return e.to!==void 0&&(t.to=e.to),{attributes:t,authenticator:`twilio-webhook`,issuer:`twilio`,principalId:`twilio:${e.from}`,principalType:`user`}}function defaultOnText(e,t){return{auth:defaultTwilioAuth({channel:`text`,from:t.from,to:t.to})}}function defaultOnVoice(e,t){return{}}function defaultOnVoiceTranscription(e,t){return{auth:defaultTwilioAuth({channel:`voice`,from:t.from,to:t.to})}}const defaultEvents={async"message.completed"(e,t,n){e.finishReason!==`tool-calls`&&e.message&&await t.twilio.sendMessage(e.message)},...promptQueueEvents(showPrompt),async"authorization.required"(e,t,n){if(e.candidateId!==void 0)return;let r=e.authorization;await t.twilio.sendMessage([`Sign in to ${r?.displayName??displayProperName(e.name)} to continue.`,r?.instructions,r?.userCode?`Code: ${r.userCode}`:void 0,r?.url].filter(e=>e!==void 0&&e.length>0).join(`
|
|
2
2
|
|
|
3
3
|
`))},async"authorization.completed"(e,t,n){e.candidateId===void 0&&await t.twilio.sendMessage(renderAuthorizationOutcome({displayName:e.authorization?.displayName??displayProperName(e.name),outcome:e.outcome,reason:e.reason}))},async"turn.failed"(e,t,n){let r=formatErrorHint(e),i=extractErrorId(e.details);await t.twilio.sendMessage([`I hit an error while handling your request${r}.`,``,`Please try again, rephrase, or reach out if it keeps failing.`,...i?[``,`Error id: ${i}`]:[]].join(`
|
|
4
4
|
`))},async"session.failed"(e,t){let n=formatErrorHint(e),r=extractErrorId(e.details);await t.twilio.sendMessage([`This session could not recover from an error${n}.`,``,`Start a new message to continue.`,...r?[``,`Error id: ${r}`]:[]].join(`
|
|
5
|
-
`))}};function
|
|
6
|
-
|
|
7
|
-
`)}function renderAuthorizationOutcome(e){if(e.outcome===`authorized`)return`${e.displayName} connected.`;if(e.outcome===`declined`)return`${e.displayName} sign-in cancelled.`;let t=e.outcome===`timed-out`?`timed out`:e.outcome,n=e.reason===void 0?``:` (${e.reason})`;return`${e.displayName} sign-in ${t}${n}.`}export{defaultEvents,defaultOnText,defaultOnVoice,defaultOnVoiceTranscription};
|
|
5
|
+
`))}};async function showPrompt(e,t){let n=renderTextInputRequest(t);if((t.options??[]).length===0){await e.twilio.sendMessage(n);return}let r=t.allowFreeform===!0?`Reply with a number, or with your own answer.`:`Reply with a number to choose.`;await e.twilio.sendMessage(`${n}\n\n${r}`)}function renderAuthorizationOutcome(e){if(e.outcome===`authorized`)return`${e.displayName} connected.`;if(e.outcome===`declined`)return`${e.displayName} sign-in cancelled.`;let t=e.outcome===`timed-out`?`timed out`:e.outcome,n=e.reason===void 0?``:` (${e.reason})`;return`${e.displayName} sign-in ${t}${n}.`}export{defaultEvents,defaultOnText,defaultOnVoice,defaultOnVoiceTranscription};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PromptQueueState } from "#channel/prompt-queue.js";
|
|
1
2
|
import type { SessionAuthContext, TurnPolicy } from "#channel/types.js";
|
|
2
3
|
import type { SessionContext } from "#public/definitions/callback-context.js";
|
|
3
4
|
import type { ChannelContinuationOps } from "#public/definitions/channel.js";
|
|
@@ -23,7 +24,7 @@ interface TwilioChannelContext extends TwilioContext {
|
|
|
23
24
|
export interface TwilioEventContext extends TwilioChannelContext, ChannelContinuationOps {
|
|
24
25
|
}
|
|
25
26
|
/** JSON-serializable state for the phone-number conversation. */
|
|
26
|
-
export interface TwilioChannelState {
|
|
27
|
+
export interface TwilioChannelState extends PromptQueueState {
|
|
27
28
|
/** Caller / sender phone number. */
|
|
28
29
|
from: string | null;
|
|
29
30
|
/** Twilio number or sender that received the latest session-starting webhook. */
|
|
@@ -95,6 +96,8 @@ export interface TwilioChannelEvents {
|
|
|
95
96
|
readonly "message.completed"?: TwilioEventHandler<"message.completed">;
|
|
96
97
|
readonly "message.appended"?: TwilioEventHandler<"message.appended">;
|
|
97
98
|
readonly "input.requested"?: TwilioEventHandler<"input.requested">;
|
|
99
|
+
readonly "input.resolved"?: TwilioEventHandler<"input.resolved">;
|
|
100
|
+
readonly "approval.settled"?: TwilioEventHandler<"approval.settled">;
|
|
98
101
|
readonly "turn.failed"?: TwilioEventHandler<"turn.failed">;
|
|
99
102
|
readonly "turn.completed"?: TwilioEventHandler<"turn.completed">;
|
|
100
103
|
readonly "turn.cancelled"?: TwilioEventHandler<"turn.cancelled">;
|
|
@@ -15,7 +15,7 @@ export type { AudienceCaller, AudienceContext, AudienceInput, AudiencePrincipal,
|
|
|
15
15
|
export type { SessionRespondOptions, SessionSendOptions } from "#channel/session.js";
|
|
16
16
|
export type { ChannelFrom, ChannelReceiveContext, ChannelResolveSession, ChannelRespondOptions, ChannelSendOptions, ChannelSource, };
|
|
17
17
|
export type { ChannelCors, ChannelCorsOptions } from "#channel/cors.js";
|
|
18
|
-
export type { AgentDescription, AgentToolDescription } from "#channel/agent-description.js";
|
|
18
|
+
export type { AgentDescription, AgentSkillDescription, AgentSkillFileDescription, AgentToolDescription, } from "#channel/agent-description.js";
|
|
19
19
|
export type { InvokeToolFn, InvokeToolOptions, InvokeToolResult } from "#channel/invoke-tool.js";
|
|
20
20
|
export { DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT, WS } from "#channel/routes.js";
|
|
21
21
|
export type { AttachSessionFn, HttpRouteDefinition, RouteDefinition, RouteHandlerArgs, WebSocketMessage, WebSocketPeer, WebSocketRouteDefinition, WebSocketRouteHandler, WebSocketRouteHooks, WebSocketUpgradeRequest, WebSocketUpgradeResult, } from "#channel/routes.js";
|
|
@@ -26,6 +26,17 @@ export interface McpClientConnectionDefinition {
|
|
|
26
26
|
* initialize handshake; that handshake still negotiates a supported version.
|
|
27
27
|
*/
|
|
28
28
|
readonly protocolVersionDiscovery?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Whether to forward the calling turn's user and initiator to the server in
|
|
31
|
+
* the `eve-forwarded-principal` header, so an eve agent's `mcpChannel` can
|
|
32
|
+
* run its published tools as that user. The server must set
|
|
33
|
+
* `trustedForwarders` and trust this connection's route-authenticated
|
|
34
|
+
* identity; otherwise it refuses the request with 403. Anonymous callers
|
|
35
|
+
* are not forwarded. Requests carrying the header fail rather than follow
|
|
36
|
+
* a redirect.
|
|
37
|
+
* @default false
|
|
38
|
+
*/
|
|
39
|
+
readonly forwardPrincipal?: boolean;
|
|
29
40
|
/**
|
|
30
41
|
* Human-readable summary of the connection and its tools.
|
|
31
42
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{normalizeOrigin}from"./routing.js";import{mkdir,open,readFile,rm,stat,writeFile}from"node:fs/promises";import{resolvePackageRoot}from"#internal/application/package.js";import{
|
|
1
|
+
import{normalizeOrigin}from"./routing.js";import{mkdir,open,readFile,rm,stat,writeFile}from"node:fs/promises";import{join}from"node:path";import{resolvePackageRoot}from"#internal/application/package.js";import{spawn}from"node:child_process";import{readDevelopmentRuntimeArtifactsRevision}from"#services/dev-client/runtime-artifacts.js";const EVE_BASE_URL_ENV=`EVE_BASE_URL`,DEFAULT_SERVER_READY_TIMEOUT_MS=3e4,DEV_SERVER_REGISTRY_TIMEOUT_MS=3e4,LOCAL_SERVER_URL_PATTERN=/https?:\/\/(?:\[[^\]\s]+\]|[^\s/:[\]]+)(?::\d+)?/;function isNodeErrorWithCode(e,t){return e instanceof Error&&`code`in e&&e.code===t}function delay(e){return new Promise(t=>setTimeout(t,e))}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function resolveEveCacheDirectory(e){return join(e,`.eve`)}function resolveEveDevServerRegistryPath(e){return join(resolveEveCacheDirectory(e),`sveltekit-dev-server.json`)}function resolveEveDevServerLockPath(e){return join(resolveEveCacheDirectory(e),`sveltekit-dev-server.lock`)}function normalizeDevServerRegistry(e){if(isRecord(e)&&typeof e.appRoot==`string`&&typeof e.origin==`string`&&typeof e.updatedAt==`string`&&(e.pid===null||typeof e.pid==`number`))try{return{appRoot:e.appRoot,origin:normalizeOrigin(e.origin),pid:e.pid,updatedAt:e.updatedAt}}catch{return}}async function readUsableEveDevServerRegistry(e){try{let t=normalizeDevServerRegistry(JSON.parse(await readFile(resolveEveDevServerRegistryPath(e),`utf8`)));return t===void 0||t.appRoot!==e||await readDevelopmentRuntimeArtifactsRevision({serverUrl:t.origin,timeoutMs:1e3})===void 0?void 0:t.origin}catch(e){if(isNodeErrorWithCode(e,`ENOENT`))return;throw e}}async function writeEveDevServerRegistry(e,t){await mkdir(resolveEveCacheDirectory(e),{recursive:!0}),await writeFile(resolveEveDevServerRegistryPath(e),`${JSON.stringify({appRoot:e,origin:t.origin,pid:t.process?.pid??null,updatedAt:new Date().toISOString()},null,2)}\n`)}async function removeStaleEveDevServerLock(e){try{let t=await stat(e);Date.now()-t.mtimeMs>3e4&&await rm(e,{force:!0})}catch(e){if(!isNodeErrorWithCode(e,`ENOENT`))throw e}}async function acquireEveDevServerLock(e){let t=resolveEveCacheDirectory(e),n=resolveEveDevServerLockPath(e),r=Date.now()+DEV_SERVER_REGISTRY_TIMEOUT_MS;for(await mkdir(t,{recursive:!0});;)try{let e=await open(n,`wx`);return await e.writeFile(`${String(process.pid)}\n`),await e.close(),async()=>{await rm(n,{force:!0})}}catch(t){if(!isNodeErrorWithCode(t,`EEXIST`))throw t;if(await readUsableEveDevServerRegistry(e)!==void 0)return async()=>{};if(await removeStaleEveDevServerLock(n),Date.now()>r)throw Error(`Timed out after ${DEV_SERVER_REGISTRY_TIMEOUT_MS}ms waiting for another SvelteKit process to start eve.`);await delay(100)}}function createEveBinaryPath(){return join(resolvePackageRoot(),`bin`,`eve.js`)}function startServerProcess(e){return new Promise((t,n)=>{let r=spawn(e.command,e.args,{cwd:e.cwd,env:{...process.env,...e.env},stdio:[`ignore`,`pipe`,`pipe`]}),i=setTimeout(()=>{r.kill(),n(Error(`Timed out after ${DEFAULT_SERVER_READY_TIMEOUT_MS}ms waiting for eve to print its server URL.`))},DEFAULT_SERVER_READY_TIMEOUT_MS),cleanup=()=>{clearTimeout(i),r.off(`error`,handleError),r.off(`exit`,handleEarlyExit)},handleError=e=>{cleanup(),n(e)},handleEarlyExit=(e,t)=>{cleanup(),n(Error(`eve server process exited before printing its server URL (code ${String(e)}, signal ${String(t)}).`))},a=!1,handleOutput=e=>{if(a)return;let n=LOCAL_SERVER_URL_PATTERN.exec(e.toString(`utf8`));n!==null&&(a=!0,cleanup(),t({origin:normalizeOrigin(n[0]),process:r}))};r.once(`error`,handleError),r.once(`exit`,handleEarlyExit),r.stdout.on(`data`,e=>{process.stdout.write(e),handleOutput(e)}),r.stderr.on(`data`,e=>{process.stderr.write(e),handleOutput(e)})})}function installProcessShutdown(e){let t=e.process;if(t===void 0)return e;let close=()=>{process.off(`beforeExit`,close),process.off(`exit`,close),t.killed||t.kill()};return process.once(`beforeExit`,close),process.once(`exit`,close),e}function startEveDevServer(e){return startServerProcess({args:[createEveBinaryPath(),`dev`,`--no-ui`,`--port`,`0`],command:process.execPath,cwd:e}).then(e=>(process.env[EVE_BASE_URL_ENV]=e.origin,installProcessShutdown(e)))}async function resolveSharedEveDevServer(e){let t=await readUsableEveDevServerRegistry(e);if(t!==void 0)return process.env[EVE_BASE_URL_ENV]=t,{origin:t};let n=await acquireEveDevServerLock(e);try{let t=await readUsableEveDevServerRegistry(e);if(t!==void 0)return process.env[EVE_BASE_URL_ENV]=t,{origin:t};let n=await startEveDevServer(e);return await writeEveDevServerRegistry(e,n),n}finally{await n()}}export{EVE_BASE_URL_ENV,normalizeDevServerRegistry,resolveSharedEveDevServer};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{getRuntimeCompiledArtifactsCacheKey}from"#runtime/compiled-artifacts-source.js";import{resolveRuntimeCompilerArtifactPaths}from"#runtime/loaders/artifact-paths.js";import{loadCompileMetadata}from"#runtime/loaders/compile-metadata.js";async function resolveRuntimeCompiledArtifactsVersionedCacheKey(e){let t=getRuntimeCompiledArtifactsCacheKey(e),n=await resolveCompileMetadataMtimeMs(e);try{let r=(await loadCompileMetadata({compiledArtifactsSource:e}))?.discovery.sourceGraphHash;return r===void 0||r.length===0?n===void 0?t:`${t}:mtime-${formatMtimeMsForCacheKey(n)}`:n===void 0?`${t}:${r}`:`${t}:${r}:mtime-${formatMtimeMsForCacheKey(n)}`}catch{return n===void 0?t:`${t}:mtime-${formatMtimeMsForCacheKey(n)}`}}async function resolveCompileMetadataMtimeMs(e){if(e.kind!==`disk`)return;let{stat:t}=await import(`node:fs/promises`),{compileMetadataPath:n}=resolveRuntimeCompilerArtifactPaths(e.appRoot);try{return(await t(n)).mtimeMs}catch{return}}function formatMtimeMsForCacheKey(e){return Math.floor(e).toString(36)}export{resolveRuntimeCompiledArtifactsVersionedCacheKey};
|
|
@@ -6,6 +6,12 @@ import type { ConnectionClient, ConnectionToolExecuteOptions, ConnectionToolMeta
|
|
|
6
6
|
*
|
|
7
7
|
* Created lazily per-connection per-session. Caches tool metadata after
|
|
8
8
|
* the first `getToolMetadata()` call.
|
|
9
|
+
*
|
|
10
|
+
* When the connection declares `authorization` but no token is available
|
|
11
|
+
* yet (`getToken` throws {@link ConnectionAuthorizationRequiredError}), the
|
|
12
|
+
* client connects anonymously instead of failing. Sign-in is only requested
|
|
13
|
+
* once the server asks for it: an HTTP `401` on any request, or a tool
|
|
14
|
+
* result that carries an `mcp/www_authenticate` challenge.
|
|
9
15
|
*/
|
|
10
16
|
export declare class McpConnectionClient implements ConnectionClient {
|
|
11
17
|
#private;
|
|
@@ -35,7 +41,8 @@ export declare class McpConnectionClient implements ConnectionClient {
|
|
|
35
41
|
* A `401`/`invalid_token` from the remote server is translated into
|
|
36
42
|
* {@link ConnectionAuthorizationRequiredError} via {@link #rethrowClassified}
|
|
37
43
|
* so callers re-enter the authorization flow instead of surfacing an
|
|
38
|
-
* opaque transport error.
|
|
44
|
+
* opaque transport error. A tool error result carrying an
|
|
45
|
+
* `_meta["mcp/www_authenticate"]` challenge is treated the same way.
|
|
39
46
|
*/
|
|
40
47
|
executeTool(toolName: string, args: unknown, options: ConnectionToolExecuteOptions): Promise<unknown>;
|
|
41
48
|
close(): Promise<void>;
|
|
@@ -49,6 +56,16 @@ export declare class McpConnectionClient implements ConnectionClient {
|
|
|
49
56
|
* left to propagate, since re-running the same grant would not help.)
|
|
50
57
|
*/
|
|
51
58
|
export declare function isMcpAuthRequiredError(error: unknown): boolean;
|
|
59
|
+
/** `_meta` key a tool result uses to ask for sign-in (OpenAI Apps SDK convention). */
|
|
60
|
+
export declare const MCP_WWW_AUTHENTICATE_META_KEY = "mcp/www_authenticate";
|
|
61
|
+
/**
|
|
62
|
+
* Returns `true` for a `tools/call` error result that asks the client to
|
|
63
|
+
* sign in: `isError: true` plus a non-empty `_meta["mcp/www_authenticate"]`
|
|
64
|
+
* (a `WWW-Authenticate` challenge string or list of them). Servers that
|
|
65
|
+
* accept anonymous `initialize`/`tools/list` use this to protect individual
|
|
66
|
+
* tools without failing the whole HTTP request.
|
|
67
|
+
*/
|
|
68
|
+
export declare function isMcpAuthChallengeResult(result: unknown): boolean;
|
|
52
69
|
/**
|
|
53
70
|
* Returns `true` when a tool name passes the configured filter.
|
|
54
71
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isObject}from"#shared/guards.js";import{buildCallbackContext}from"#context/build-callback-context.js";import{ConnectionAuthorizationRequiredError}from"#connections/errors.js";import{evictScopedToken,resolveScopedToken}from"#runtime/connections/scoped-authorization.js";import{resolveConnectionAuthorization}from"#runtime/connections/resolve-authorization.js";import{createMCPClient}from"#compiled/@ai-sdk/mcp/index.js";import{omitProvidedArgumentsFromSchema,resolveProvidedArguments}from"#runtime/connections/provided-arguments.js";import{createMcpTraceFetch,withMcpToolCallSpan,withMcpToolsListSpan}from"#runtime/connections/mcp-tracing.js";var McpConnectionClient=class{#e;#t;#n;#r;#i;constructor(e){this.#i=e}async connect(){if(this.#t!==void 0)return this.#t;if(this.#e!==void 0)return this.#e;this.#e=this.#
|
|
1
|
+
import{isObject}from"#shared/guards.js";import{buildCallbackContext}from"#context/build-callback-context.js";import{ConnectionAuthorizationRequiredError,isConnectionAuthorizationRequiredError}from"#connections/errors.js";import{evictScopedToken,resolveScopedToken}from"#runtime/connections/scoped-authorization.js";import{resolveConnectionAuthorization}from"#runtime/connections/resolve-authorization.js";import{FORWARDED_PRINCIPAL_HEADER,encodeForwardedPrincipalHeader}from"#internal/mcp/forwarded-principal-header.js";import{createMCPClient}from"#compiled/@ai-sdk/mcp/index.js";import{readTurnPrincipals}from"#context/turn-principals.js";import{omitProvidedArgumentsFromSchema,resolveProvidedArguments}from"#runtime/connections/provided-arguments.js";import{createMcpTraceFetch,withMcpToolCallSpan,withMcpToolsListSpan}from"#runtime/connections/mcp-tracing.js";var McpConnectionClient=class{#e;#t;#n;#r;#i;#a=!1;constructor(e){this.#i=e}async connect(){if(this.#t!==void 0)return this.#t;if(this.#e!==void 0)return this.#e;this.#e=this.#o();try{return this.#t=await this.#e,this.#t}catch(e){throw this.#e=void 0,e}}async#o(){let{anonymous:e,headers:t}=await resolveConnectionHeaders(this.#i,{anonymousWhenAuthorizationRequired:!0});this.#a=e;let n=this.#i.url,r=createMcpTraceFetch({connectionName:this.#i.connectionName,fetcher:this.#s(),getProtocolVersion:()=>this.#t?.initializeResult?.protocolVersion});try{return await createMCPClient({protocolVersionDiscovery:this.#i.protocolVersionDiscovery,transport:{fetch:r,headers:t,type:`http`,url:n}})}catch(e){if(!isMcpHttpFallbackRetryableError(e))throw e;return await createMCPClient({protocolVersionDiscovery:this.#i.protocolVersionDiscovery,transport:{fetch:r,headers:t,type:`sse`,url:n}})}}#s(){if(this.#i.forwardPrincipal!==!0)return;let e=this.#i.connectionName;return async(t,n)=>{let r=readTurnPrincipals();if(r===void 0)return await globalThis.fetch(t,n);let i=new Headers(n?.headers);return i.set(FORWARDED_PRINCIPAL_HEADER,encodeForwardedPrincipalHeader(r,e)),await globalThis.fetch(t,{...n,headers:i,redirect:`error`})}}async getToolMetadata(){return(await this.#c()).metadata}async executeTool(e,t,n){let r;try{let{tools:i}=await this.#c(),a=i[e];if(a?.execute===void 0)throw Error(`Tool "${e}" not found in connection "${this.#i.connectionName}".`);let o=a.execute,s=await resolveProvidedArguments({args:t,callId:n.callId,connection:this.#i,toolName:e});r=await withMcpToolCallSpan({arguments:t,connectionName:this.#i.connectionName,execute:async()=>await o(s,{abortSignal:n.abortSignal}),protocolVersion:this.#t?.initializeResult?.protocolVersion,toolName:e})}catch(e){return await this.#d(e)}return isMcpAuthChallengeResult(r)?await this.#f(`the server asked for sign-in to call "${e}"`):r}async#c(){if(this.#r!==void 0)return this.#r;if(this.#n!==void 0)return this.#n;this.#n=this.#l();try{return this.#r=await this.#n,this.#r}catch(e){throw this.#n=void 0,e}}async#l(){try{return await this.#u()}catch(e){return await this.#d(e)}}async#u(){let e=await this.connect(),t=await withMcpToolsListSpan({connectionName:this.#i.connectionName,execute:()=>e.listTools(),protocolVersion:e.initializeResult?.protocolVersion}),n=this.#i.tools,r=n===void 0?t.tools:t.tools.filter(e=>passesToolFilter(e.name,n)),i=Object.keys(this.#i.toolCall?.providedArguments??{}),a=r.map(e=>({...e,inputSchema:omitProvidedArgumentsFromSchema(e.inputSchema,i)})),o=e.toolsFromDefinitions({tools:a});return{metadata:a.map(e=>({annotations:e.annotations,description:e.description??``,inputSchema:e.inputSchema??{},name:e.name,outputSchema:`outputSchema`in e&&e.outputSchema!==void 0?e.outputSchema:void 0})),tools:o}}async close(){this.#t!==void 0&&(await this.#t.close(),this.#t=void 0),this.#e=void 0,this.#n=void 0,this.#r=void 0,this.#a=!1}async#d(e){if(!isMcpAuthRequiredError(e))throw e;return await this.#f(this.#a?`the server requires sign-in`:`the server rejected the token`)}async#f(e){throw this.#a||await this.#p(),await this.close(),new ConnectionAuthorizationRequiredError(this.#i.connectionName,{message:`Connection "${this.#i.connectionName}" requires authorization (${e}).`})}async#p(){let e=await resolveConnectionAuthorization(this.#i);e!==void 0&&await evictScopedToken({authorization:e,connection:{url:this.#i.url},instanceId:this.#i.instanceId,scope:this.#i.connectionName})}};function isMcpAuthRequiredError(e){return readHttpStatus(e)===401}const MCP_WWW_AUTHENTICATE_META_KEY=`mcp/www_authenticate`;function isMcpAuthChallengeResult(e){if(!isObject(e)||e.isError!==!0||!isObject(e._meta))return!1;let t=e._meta[MCP_WWW_AUTHENTICATE_META_KEY];return(typeof t==`string`||Array.isArray(t))&&t.length>0}function isMcpHttpFallbackRetryableError(e){let t=readHttpStatus(e);return t===400||t===404||t===405}function readHttpStatus(e){for(let t of walkErrorChain(e)){if(!isObject(t))continue;let e=readStatusField(t);if(e!==void 0)return e;let n=t.response;if(isObject(n)){let e=readStatusField(n);if(e!==void 0)return e}if(typeof t.message==`string`){let e=/\bHTTP\s+(\d{3})\b/u.exec(t.message);if(e?.[1]!==void 0)return Number(e[1])}}}function readStatusField(e){if(typeof e.status==`number`)return e.status;if(typeof e.statusCode==`number`)return e.statusCode}function*walkErrorChain(e){let t=e,n=new Set;for(;t!=null&&!n.has(t);){if(n.add(t),yield t,!isObject(t)||!(`cause`in t))return;t=t.cause}}function passesToolFilter(e,t){return t===void 0?!0:`allow`in t?t.allow.includes(e):!t.block.includes(e)}async function resolveHeaders(e){let{headers:t}=await resolveConnectionHeaders(e,{anonymousWhenAuthorizationRequired:!1});return t}async function resolveConnectionHeaders(e,t){let n={},r=!1,i,getCallbackContext=()=>i??=buildCallbackContext(),a=await resolveConnectionAuthorization(e,typeof e.authorization==`function`?getCallbackContext():void 0);if(a!==void 0)try{n.Authorization=`Bearer ${(await resolveToken(e,a)).token}`}catch(e){if(!t.anonymousWhenAuthorizationRequired||!isConnectionAuthorizationRequiredError(e))throw e;r=!0}if(e.headers!==void 0){let t=await resolveHeadersDefinition(e.headers,getCallbackContext);for(let[r,i]of Object.entries(t)){if(a!==void 0&&r.toLowerCase()===`authorization`)throw Error(`Connection "${e.connectionName}" headers must not include an "Authorization" key when "authorization" is also provided.`);n[r]=i}}return{anonymous:r,headers:n}}async function resolveToken(e,t){return await resolveScopedToken({authorization:t,connection:{url:e.url},instanceId:e.instanceId,scope:e.connectionName})}async function resolveHeadersDefinition(e,t){if(typeof e==`function`)return{...await e(t())};let n={},r=Object.entries(e);for(let[e,i]of r)n[e]=await resolveHeaderValue(i,t);return n}async function resolveHeaderValue(e,t){return typeof e==`function`?await e(t()):await e}export{MCP_WWW_AUTHENTICATE_META_KEY,McpConnectionClient,isMcpAuthChallengeResult,isMcpAuthRequiredError,passesToolFilter,resolveHeaders};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z}from"#compiled/zod/index.js";import{
|
|
1
|
+
import{z}from"#compiled/zod/index.js";import{resolveRuntimeCompilerArtifactPaths}from"#runtime/loaders/artifact-paths.js";import{COMPILE_METADATA_KIND,COMPILE_METADATA_VERSION}from"#compiler/artifacts.js";import{formatValidationError}from"#runtime/validation.js";import{readBundledCompiledArtifacts}from"#runtime/loaders/bundled-artifacts.js";const compileArtifactDigestSchema=z.object({path:z.string(),sha256:z.string()}).strict(),compileMetadataSchema=z.object({compile:z.object({manifest:compileArtifactDigestSchema,moduleMap:compileArtifactDigestSchema}).strict(),discovery:z.object({diagnostics:compileArtifactDigestSchema,manifest:compileArtifactDigestSchema,sourceGraphHash:z.string(),summary:z.object({errors:z.number().finite(),warnings:z.number().finite()}).strict()}).strict(),generator:z.object({name:z.string(),version:z.string()}).strict(),kind:z.literal(COMPILE_METADATA_KIND),status:z.union([z.literal(`failed`),z.literal(`ready`)]),version:z.literal(COMPILE_METADATA_VERSION)}).strict();var LoadCompileMetadataError=class extends Error{metadataPath;constructor(e,t){super(e),this.name=`LoadCompileMetadataError`,t!==void 0&&(this.metadataPath=t)}};async function loadCompileMetadata(e){let t=e.compiledArtifactsSource.kind===`disk`?resolveRuntimeCompilerArtifactPaths(e.compiledArtifactsSource.appRoot).compileMetadataPath:void 0;if(t!==void 0){let{readFile:e}=await import(`node:fs/promises`),n;try{n=JSON.parse(await e(t,`utf8`))}catch(e){throw new LoadCompileMetadataError(formatLoadErrorMessage(e),t)}return parseCompileMetadata(n,t)}let n=readBundledCompiledArtifacts()?.metadata;return n===void 0?null:parseCompileMetadata(n,`bundled compile metadata`)}function parseCompileMetadata(e,t){let n=compileMetadataSchema.safeParse(e);if(!n.success)throw new LoadCompileMetadataError(`Expected "${t}" to contain valid eve compile metadata. ${formatValidationError(n.error)}`,t);return n.data}function formatLoadErrorMessage(e){return e instanceof Error?e.message:`Unknown compile metadata load failure.`}export{loadCompileMetadata};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{resolveRuntimeCompilerArtifactPaths}from"#runtime/loaders/artifact-paths.js";import{compiledAgentManifestSchema}from"#compiler/manifest.js";import{formatValidationError}from"#runtime/validation.js";import{validateCompiledAgentManifest}from"#compiler/validate-artifact.js";import{readBundledCompiledArtifacts}from"#runtime/loaders/bundled-artifacts.js";const BUNDLED_MANIFEST_SOURCE=`bundled compiled manifest`;var LoadCompiledManifestError=class extends Error{manifestPath;constructor(e,t){super(e),this.name=`LoadCompiledManifestError`,t!==void 0&&(this.manifestPath=t)}};async function loadCompiledManifest(e){let t=e.compiledArtifactsSource.kind===`disk`?resolveRuntimeCompilerArtifactPaths(e.compiledArtifactsSource.appRoot).compiledManifestPath:void 0;if(t!==void 0){let{readFile:e}=await import(`node:fs/promises`),n;try{n=JSON.parse(await e(t,`utf8`))}catch(e){throw new LoadCompiledManifestError(formatLoadErrorMessage(e),t)}return parseCompiledManifest(n,t)}let n=readBundledCompiledArtifacts();if(n!==null)return parseCompiledManifest(n.manifest,BUNDLED_MANIFEST_SOURCE);throw new LoadCompiledManifestError(`Compiled manifest is unavailable without an app root or bundled compiled artifacts.`,BUNDLED_MANIFEST_SOURCE)}function parseCompiledManifest(e,t){let n=compiledAgentManifestSchema.safeParse(e);if(!n.success)throw new LoadCompiledManifestError(`Expected "${t}" to contain a valid compiled eve agent manifest. ${formatValidationError(n.error)}`,t);try{validateCompiledAgentManifest(n.data)}catch(e){throw new LoadCompiledManifestError(`Expected "${t}" to contain a semantically valid compiled eve agent manifest. ${formatLoadErrorMessage(e)}`,t)}return n.data}function formatLoadErrorMessage(e){return e instanceof Error?e.message:`Unknown manifest load failure.`}export{LoadCompiledManifestError,loadCompiledManifest};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{resolveRuntimeCompilerArtifactPaths}from"#runtime/loaders/artifact-paths.js";import{compiledModuleMapSchema}from"#compiler/module-map.js";import{formatValidationError}from"#runtime/validation.js";import{readBundledCompiledArtifacts}from"#runtime/loaders/bundled-artifacts.js";const BUNDLED_MODULE_MAP_SOURCE=`bundled compiled module map`;var LoadCompiledModuleMapError=class extends Error{moduleMapPath;constructor(e,t){super(e),this.name=`LoadCompiledModuleMapError`,t!==void 0&&(this.moduleMapPath=t)}};async function loadCompiledModuleMap(e){let t=e.compiledArtifactsSource.kind===`disk`?resolveRuntimeCompilerArtifactPaths(e.compiledArtifactsSource.appRoot).moduleMapPath:void 0;if(t!==void 0){let e=createFileImportSpecifier(t);try{let n=await import(e);return parseCompiledModuleMap(n.moduleMap??n.default,t)}catch(e){throw new LoadCompiledModuleMapError(formatLoadErrorMessage(e),t)}}let n=readBundledCompiledArtifacts();if(n!==null)return parseCompiledModuleMap(n.moduleMap,BUNDLED_MODULE_MAP_SOURCE);throw new LoadCompiledModuleMapError(`Compiled module map is unavailable without an app root or bundled compiled artifacts.`,BUNDLED_MODULE_MAP_SOURCE)}function parseCompiledModuleMap(e,t){let n=compiledModuleMapSchema.safeParse(e);if(!n.success)throw new LoadCompiledModuleMapError(`Expected "${t}" to export a valid compiled eve module map. ${formatValidationError(n.error)}`,t);return n.data}function formatLoadErrorMessage(e){return e instanceof Error?e.message:`Unknown module-map load failure.`}function createFileImportSpecifier(e){let t=e.replaceAll(`\\`,`/`);return/^[A-Za-z]:\//.test(t)?`file:///${encodeURI(t)}`:t.startsWith(`/`)?`file://${encodeURI(t)}`:t}export{LoadCompiledModuleMapError,loadCompiledModuleMap};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{expectObjectRecord}from"#internal/authored-module.js";import{toErrorMessage}from"#shared/errors.js";import{normalizeMcpClientConnectionDefinition,normalizeOpenApiConnectionDefinition}from"#internal/authored-definition/connection.js";import{readStampedConnectionProtocol}from"#public/definitions/connections/protocol.js";import{registerDefinitionSource}from"#internal/authored-definition/source-identity.js";import{normalizeAuthorizationSpec}from"#shared/validate-authorization.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";import{createConnectionInstanceId}from"#runtime/connections/instance-identity.js";async function resolveConnectionDefinition(e,t,n){try{let r=await loadResolvedModuleExport({definition:e,kindLabel:`connection`,moduleMap:t,nodeId:n}),i=expectObjectRecord(r,`Expected the connection export "${e.exportName??`default`}" from "${e.logicalPath}" to return an object.`);registerDefinitionSource(i,{kind:`connection`,logicalPath:e.logicalPath,name:e.connectionName},`connection:${e.url}`);let a=i.auth!==void 0,o=i.headers!==void 0,s=e.protocol===`openapi`?i.operations:i.tools,c={connectionName:e.connectionName,description:e.description,exportName:e.exportName,logicalPath:e.logicalPath,instanceId:createConnectionInstanceId({connectionName:e.connectionName,instanceKey:typeof i.instanceKey==`string`?i.instanceKey:void 0,protocol:e.protocol,sourceId:e.sourceId,url:e.url}),protocol:e.protocol,sourceId:e.sourceId,sourceKind:`module`,url:e.url};if(a){if(typeof i.auth==`function`)c.authorization=i.auth;else try{c.authorization=normalizeAuthorizationSpec(i.auth,`Connection "${e.connectionName}" at "${e.logicalPath}":`)}catch(t){throw new ResolveAgentError(toErrorMessage(t),{logicalPath:e.logicalPath,sourceId:e.sourceId})}}if(e.protocol===`mcp`&&i.protocolVersionDiscovery!==void 0){if(typeof i.protocolVersionDiscovery!=`boolean`)throw Error(`"protocolVersionDiscovery" must be a boolean.`);c.protocolVersionDiscovery=i.protocolVersionDiscovery}return o&&(c.headers=i.headers),i.toolCall!==void 0&&(c.toolCall=i.toolCall),s!==void 0&&(c.tools=s),e.protocol===`openapi`&&i.spec!==void 0&&(c.spec=i.spec),typeof i.approval==`function`&&(c.approval=i.approval),c}catch(t){throw t instanceof ResolveAgentError?t:new ResolveAgentError(`Failed to resolve connection "${e.connectionName}" from "${e.logicalPath}": ${toErrorMessage(t)}`,{logicalPath:e.logicalPath,sourceId:e.sourceId})}}function resolveDynamicConnectionValue(e,t){let n=readStampedConnectionProtocol(e),r=`Dynamic connection "${t.connectionName}" from "${t.logicalPath}" must be created by defineMcpClientConnection() or defineOpenAPIConnection().`;if(n===void 0)throw Error(r);if(registerDefinitionSource(e,{kind:`connection`,logicalPath:t.logicalPath,name:t.connectionName}),n===`openapi`){let i=normalizeOpenApiConnectionDefinition(e,r);return assertAuthenticatedDynamicInstanceKey(i.auth,i.instanceKey,r),omitUndefined({approval:i.approval,authorization:i.auth,connectionName:t.connectionName,description:i.description,exportName:t.exportName,headers:i.headers,instanceId:createConnectionInstanceId({connectionName:t.connectionName,instanceKey:i.instanceKey,protocol:n,sourceId:t.sourceId,url:i.baseUrl??``}),logicalPath:t.logicalPath,protocol:n,sourceId:t.sourceId,sourceKind:`module`,spec:i.spec,toolCall:i.toolCall,tools:i.operations,url:i.baseUrl??``})}let i=normalizeMcpClientConnectionDefinition(e,r);return assertAuthenticatedDynamicInstanceKey(i.auth,i.instanceKey,r),omitUndefined({approval:i.approval,authorization:i.auth,connectionName:t.connectionName,description:i.description,exportName:t.exportName,headers:i.headers,instanceId:createConnectionInstanceId({connectionName:t.connectionName,instanceKey:i.instanceKey,protocol:n,sourceId:t.sourceId,url:i.url}),logicalPath:t.logicalPath,protocol:n,sourceId:t.sourceId,sourceKind:`module`,toolCall:i.toolCall,protocolVersionDiscovery:i.protocolVersionDiscovery,tools:i.tools,url:i.url})}function assertAuthenticatedDynamicInstanceKey(e,t,n){if(e!==void 0&&t===void 0)throw Error(`${n} Authenticated dynamic connections must set "instanceKey" to a stable, non-secret account or tenant identifier.`)}function omitUndefined(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>e!==void 0))}export{resolveConnectionDefinition,resolveDynamicConnectionValue};
|
|
1
|
+
import{expectObjectRecord}from"#internal/authored-module.js";import{toErrorMessage}from"#shared/errors.js";import{normalizeMcpClientConnectionDefinition,normalizeOpenApiConnectionDefinition}from"#internal/authored-definition/connection.js";import{readStampedConnectionProtocol}from"#public/definitions/connections/protocol.js";import{registerDefinitionSource}from"#internal/authored-definition/source-identity.js";import{normalizeAuthorizationSpec}from"#shared/validate-authorization.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";import{createConnectionInstanceId}from"#runtime/connections/instance-identity.js";async function resolveConnectionDefinition(e,t,n){try{let r=await loadResolvedModuleExport({definition:e,kindLabel:`connection`,moduleMap:t,nodeId:n}),i=expectObjectRecord(r,`Expected the connection export "${e.exportName??`default`}" from "${e.logicalPath}" to return an object.`);registerDefinitionSource(i,{kind:`connection`,logicalPath:e.logicalPath,name:e.connectionName},`connection:${e.url}`);let a=i.auth!==void 0,o=i.headers!==void 0,s=e.protocol===`openapi`?i.operations:i.tools,c={connectionName:e.connectionName,description:e.description,exportName:e.exportName,logicalPath:e.logicalPath,instanceId:createConnectionInstanceId({connectionName:e.connectionName,instanceKey:typeof i.instanceKey==`string`?i.instanceKey:void 0,protocol:e.protocol,sourceId:e.sourceId,url:e.url}),protocol:e.protocol,sourceId:e.sourceId,sourceKind:`module`,url:e.url};if(a){if(typeof i.auth==`function`)c.authorization=i.auth;else try{c.authorization=normalizeAuthorizationSpec(i.auth,`Connection "${e.connectionName}" at "${e.logicalPath}":`)}catch(t){throw new ResolveAgentError(toErrorMessage(t),{logicalPath:e.logicalPath,sourceId:e.sourceId})}}if(e.protocol===`mcp`&&i.protocolVersionDiscovery!==void 0){if(typeof i.protocolVersionDiscovery!=`boolean`)throw Error(`"protocolVersionDiscovery" must be a boolean.`);c.protocolVersionDiscovery=i.protocolVersionDiscovery}if(e.protocol===`mcp`&&i.forwardPrincipal!==void 0){if(typeof i.forwardPrincipal!=`boolean`)throw Error(`"forwardPrincipal" must be a boolean.`);c.forwardPrincipal=i.forwardPrincipal}return o&&(c.headers=i.headers),i.toolCall!==void 0&&(c.toolCall=i.toolCall),s!==void 0&&(c.tools=s),e.protocol===`openapi`&&i.spec!==void 0&&(c.spec=i.spec),typeof i.approval==`function`&&(c.approval=i.approval),c}catch(t){throw t instanceof ResolveAgentError?t:new ResolveAgentError(`Failed to resolve connection "${e.connectionName}" from "${e.logicalPath}": ${toErrorMessage(t)}`,{logicalPath:e.logicalPath,sourceId:e.sourceId})}}function resolveDynamicConnectionValue(e,t){let n=readStampedConnectionProtocol(e),r=`Dynamic connection "${t.connectionName}" from "${t.logicalPath}" must be created by defineMcpClientConnection() or defineOpenAPIConnection().`;if(n===void 0)throw Error(r);if(registerDefinitionSource(e,{kind:`connection`,logicalPath:t.logicalPath,name:t.connectionName}),n===`openapi`){let i=normalizeOpenApiConnectionDefinition(e,r);return assertAuthenticatedDynamicInstanceKey(i.auth,i.instanceKey,r),omitUndefined({approval:i.approval,authorization:i.auth,connectionName:t.connectionName,description:i.description,exportName:t.exportName,headers:i.headers,instanceId:createConnectionInstanceId({connectionName:t.connectionName,instanceKey:i.instanceKey,protocol:n,sourceId:t.sourceId,url:i.baseUrl??``}),logicalPath:t.logicalPath,protocol:n,sourceId:t.sourceId,sourceKind:`module`,spec:i.spec,toolCall:i.toolCall,tools:i.operations,url:i.baseUrl??``})}let i=normalizeMcpClientConnectionDefinition(e,r);return assertAuthenticatedDynamicInstanceKey(i.auth,i.instanceKey,r),omitUndefined({approval:i.approval,authorization:i.auth,connectionName:t.connectionName,description:i.description,exportName:t.exportName,headers:i.headers,instanceId:createConnectionInstanceId({connectionName:t.connectionName,instanceKey:i.instanceKey,protocol:n,sourceId:t.sourceId,url:i.url}),logicalPath:t.logicalPath,protocol:n,sourceId:t.sourceId,sourceKind:`module`,toolCall:i.toolCall,protocolVersionDiscovery:i.protocolVersionDiscovery,forwardPrincipal:i.forwardPrincipal,tools:i.tools,url:i.url})}function assertAuthenticatedDynamicInstanceKey(e,t,n){if(e!==void 0&&t===void 0)throw Error(`${n} Authenticated dynamic connections must set "instanceKey" to a stable, non-secret account or tenant identifier.`)}function omitUndefined(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>e!==void 0))}export{resolveConnectionDefinition,resolveDynamicConnectionValue};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomUUID}from"node:crypto";import{readFile,rename,rm,writeFile}from"node:fs/promises";import{
|
|
1
|
+
import{randomUUID}from"node:crypto";import{readFile,rename,rm,writeFile}from"node:fs/promises";import{resolveRuntimeCompilerArtifactPaths}from"#runtime/loaders/artifact-paths.js";import{createSandboxPreparedArtifactsManifest,sandboxPreparedArtifactsManifestSchema}from"#shared/sandbox-prepared-artifacts.js";import{readBundledCompiledArtifacts}from"#runtime/loaders/bundled-artifacts.js";async function writeSandboxPreparedArtifactsManifest(e){if(e.entries.length===0)return;let t=`${e.compileDirectoryPath}/sandbox-prepared-artifacts.json`,n=null;try{n=sandboxPreparedArtifactsManifestSchema.parse(JSON.parse(await readFile(t,`utf8`)))}catch(e){if(!(e instanceof Error&&`code`in e&&e.code===`ENOENT`))throw e}let r=new Map(n?.entries.map(e=>[e.nodeId,e]));for(let t of e.entries)r.set(t.nodeId,t);let i=`${t}.${randomUUID()}.tmp`;try{await writeFile(i,`${JSON.stringify(createSandboxPreparedArtifactsManifest([...r.values()]),null,2)}\n`),await rename(i,t)}finally{await rm(i,{force:!0})}}async function loadSandboxPreparedArtifact(e){let t=(await loadSandboxPreparedArtifactsManifest(e.compiledArtifactsSource))?.entries.find(t=>t.nodeId===e.nodeId);if(t!==void 0&&t.providerName!==e.providerName)throw Error(`Prepared sandbox artifact for node "${e.nodeId}" belongs to provider "${t.providerName}", not "${e.providerName}".`);return t?.artifact}async function loadSandboxPreparedArtifactsManifest(e){if(e.kind===`bundled`)return readBundledCompiledArtifacts()?.sandboxPreparedArtifacts??null;let t=resolveRuntimeCompilerArtifactPaths(e.appRoot).sandboxPreparedArtifactsPath;try{return sandboxPreparedArtifactsManifestSchema.parse(JSON.parse(await readFile(t,`utf8`)))}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return null;throw e}}export{loadSandboxPreparedArtifact,writeSandboxPreparedArtifactsManifest};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{resolveRuntimeCompiledArtifactsVersionedCacheKey}from"#runtime/cache-key.js";import{getRuntimeCompiledArtifactsCacheKey}from"#runtime/compiled-artifacts-source.js";import{loadCompiledManifest}from"#runtime/loaders/manifest.js";import{getActiveRuntimeSession}from"#runtime/sessions/runtime-session.js";import{resolvePackageSourceFilePath}from"#internal/application/package.js";import{pathToFileURL}from"node:url";import{getResolvedRuntimeAgentNode}from"#runtime/graph.js";import{resolveRuntimeAgentGraph}from"#runtime/resolve-agent-graph.js";import{createRuntimeAdapterRegistry}from"#runtime/channels/registry.js";import{loadCompiledModuleMap}from"#runtime/loaders/module-map.js";const isCacheDisabled=process.env.EVE_DISABLE_AGENT_CACHE===`1`;function isDevelopmentRuntimeSnapshotRoot(e){return e.replaceAll(`\\`,`/`).includes(`/.eve/dev-runtime/snapshots/`)}function normalizeCompiledArtifactsSource(e){return e.kind!==`disk`||e.moduleMapLoaderPath!==void 0||!isDevelopmentRuntimeSnapshotRoot(e.appRoot)?e:{...e,moduleMapLoaderPath:resolvePackageSourceFilePath(`src/internal/authored-module-map-loader.ts`)}}async function loadFullBundle(e){let t=normalizeCompiledArtifactsSource(e),[n,r]=await Promise.all([loadCompiledManifest({compiledArtifactsSource:t}),loadRuntimeCompiledModuleMap(t)]),i=await resolveRuntimeAgentGraph({manifest:n,moduleMap:r}),a=i.root;return{adapterRegistry:createRuntimeAdapterRegistry({channels:collectResolvedChannels(i)}),compiledArtifactsSource:t,graph:i,hookRegistry:a.hookRegistry,moduleMap:r,resolvedAgent:a.agent,subagentRegistry:a.subagentRegistry,toolRegistry:a.toolRegistry,turnAgent:a.turnAgent}}async function loadRuntimeCompiledModuleMap(e){return e.kind===`disk`&&e.moduleMapLoaderPath!==void 0?await loadAuthoredSourceCompiledModuleMap(e):await loadCompiledModuleMap({compiledArtifactsSource:e})}async function loadAuthoredSourceCompiledModuleMap(e){if(e.moduleMapLoaderPath===void 0)throw Error(`Authored-source module map loading requires "moduleMapLoaderPath" in the compiled artifacts source.`);return await(await import(pathToFileURL(e.moduleMapLoaderPath).href)).loadCompiledModuleMapFromAuthoredSource({compiledArtifactsSource:e})}async function getOrLoadFullBundle(e){let t=normalizeCompiledArtifactsSource(e);if(isCacheDisabled)return loadFullBundle(t);let n=getActiveRuntimeSession(),r=getRuntimeCompiledArtifactsCacheKey(t),i=await resolveRuntimeCompiledArtifactsVersionedCacheKey(t),a=n.bundleCacheKeyBySourceKey.get(r);a!==void 0&&a!==i&&n.bundleCache.delete(a),n.bundleCacheKeyBySourceKey.set(r,i);let o=n.bundleCache.get(i);if(o!==void 0)return o;let s=loadFullBundle(t).catch(e=>{throw n.bundleCache.delete(i),n.bundleCacheKeyBySourceKey.get(r)===i&&n.bundleCacheKeyBySourceKey.delete(r),e});return n.bundleCache.set(i,s),s}async function getCompiledRuntimeAgentBundle(e){let t=await getOrLoadFullBundle(e.compiledArtifactsSource);if(e.nodeId===void 0)return t;let n=getResolvedRuntimeAgentNode(t.graph,e.nodeId);return{adapterRegistry:t.adapterRegistry,compiledArtifactsSource:t.compiledArtifactsSource,graph:{nodesByNodeId:t.graph.nodesByNodeId,root:n},hookRegistry:n.hookRegistry,moduleMap:t.moduleMap,nodeId:e.nodeId,resolvedAgent:n.agent,subagentRegistry:n.subagentRegistry,toolRegistry:n.toolRegistry,turnAgent:n.turnAgent}}function clearCompiledRuntimeAgentBundleCache(){let e=getActiveRuntimeSession();e.bundleCache.clear(),e.bundleCacheKeyBySourceKey.clear()}function collectResolvedChannels(e){let t=new Map;for(let n of e.nodesByNodeId.values())for(let e of n.channels)t.set(`${e.sourceId}:${e.name}`,e);return[...t.values()]}export{clearCompiledRuntimeAgentBundleCache,getCompiledRuntimeAgentBundle};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DescribedAgent } from "#channel/agent-description.js";
|
|
1
2
|
import type { BundledCompiledArtifacts } from "#runtime/loaders/bundled-artifacts.js";
|
|
2
3
|
import type { CompiledRuntimeAgentBundle } from "#runtime/sessions/compiled-agent-cache.js";
|
|
3
4
|
/**
|
|
@@ -30,6 +31,15 @@ export interface RuntimeSession {
|
|
|
30
31
|
* changes.
|
|
31
32
|
*/
|
|
32
33
|
readonly bundleCacheKeyBySourceKey: Map<string, string>;
|
|
34
|
+
/**
|
|
35
|
+
* Agents as channel routes describe them, keyed by the stable source key
|
|
36
|
+
* and tagged with the versioned cache key they were loaded under, so a
|
|
37
|
+
* recompile under the same app root replaces the entry.
|
|
38
|
+
*/
|
|
39
|
+
readonly describedAgents: Map<string, {
|
|
40
|
+
readonly agent: Promise<DescribedAgent>;
|
|
41
|
+
readonly version: string;
|
|
42
|
+
}>;
|
|
33
43
|
}
|
|
34
44
|
/**
|
|
35
45
|
* Creates a fresh, empty runtime session.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AsyncLocalStorage}from"node:async_hooks";function createRuntimeSession(e=`test-session`){return{bundleCache:new Map,bundleCacheKeyBySourceKey:new Map,compiledArtifacts:null,id:e}}function setRuntimeSessionCompiledArtifacts(e,t){let n=e.compiledArtifacts;(n===null||!isSameCompiledArtifactSnapshot(n,t))&&(e.bundleCache.clear(),e.bundleCacheKeyBySourceKey.clear()),e.compiledArtifacts=t}function isSameCompiledArtifactSnapshot(e,t){let n=e.metadata?.discovery.sourceGraphHash,r=t.metadata?.discovery.sourceGraphHash;return n&&r?n===r&&JSON.stringify(e.sandboxPreparedArtifacts)===JSON.stringify(t.sandboxPreparedArtifacts):e.manifest===t.manifest&&e.moduleMap===t.moduleMap&&e.metadata===t.metadata}const RUNTIME_SESSION_STORAGE_GLOBAL_KEY=Symbol.for(`eve.runtime-session-storage`),RUNTIME_SESSION_DEFAULT_GLOBAL_KEY=Symbol.for(`eve.runtime-session-default`),globalContainer=globalThis;globalContainer[RUNTIME_SESSION_STORAGE_GLOBAL_KEY]===void 0&&(globalContainer[RUNTIME_SESSION_STORAGE_GLOBAL_KEY]=new AsyncLocalStorage);const runtimeSessionStorage=globalContainer[RUNTIME_SESSION_STORAGE_GLOBAL_KEY];function resolveProcessDefaultSession(){return globalContainer[RUNTIME_SESSION_DEFAULT_GLOBAL_KEY]===void 0&&(globalContainer[RUNTIME_SESSION_DEFAULT_GLOBAL_KEY]=createRuntimeSession(`process-default`)),globalContainer[RUNTIME_SESSION_DEFAULT_GLOBAL_KEY]}function getActiveRuntimeSession(){return runtimeSessionStorage.getStore()??resolveProcessDefaultSession()}async function withRuntimeSession(e,t){return await runtimeSessionStorage.run(e,async()=>await t())}export{createRuntimeSession,getActiveRuntimeSession,setRuntimeSessionCompiledArtifacts,withRuntimeSession};
|
|
1
|
+
import{AsyncLocalStorage}from"node:async_hooks";function createRuntimeSession(e=`test-session`){return{bundleCache:new Map,bundleCacheKeyBySourceKey:new Map,compiledArtifacts:null,describedAgents:new Map,id:e}}function setRuntimeSessionCompiledArtifacts(e,t){let n=e.compiledArtifacts;(n===null||!isSameCompiledArtifactSnapshot(n,t))&&(e.bundleCache.clear(),e.bundleCacheKeyBySourceKey.clear(),e.describedAgents.clear()),e.compiledArtifacts=t}function isSameCompiledArtifactSnapshot(e,t){let n=e.metadata?.discovery.sourceGraphHash,r=t.metadata?.discovery.sourceGraphHash;return n&&r?n===r&&JSON.stringify(e.sandboxPreparedArtifacts)===JSON.stringify(t.sandboxPreparedArtifacts):e.manifest===t.manifest&&e.moduleMap===t.moduleMap&&e.metadata===t.metadata}const RUNTIME_SESSION_STORAGE_GLOBAL_KEY=Symbol.for(`eve.runtime-session-storage`),RUNTIME_SESSION_DEFAULT_GLOBAL_KEY=Symbol.for(`eve.runtime-session-default`),globalContainer=globalThis;globalContainer[RUNTIME_SESSION_STORAGE_GLOBAL_KEY]===void 0&&(globalContainer[RUNTIME_SESSION_STORAGE_GLOBAL_KEY]=new AsyncLocalStorage);const runtimeSessionStorage=globalContainer[RUNTIME_SESSION_STORAGE_GLOBAL_KEY];function resolveProcessDefaultSession(){return globalContainer[RUNTIME_SESSION_DEFAULT_GLOBAL_KEY]===void 0&&(globalContainer[RUNTIME_SESSION_DEFAULT_GLOBAL_KEY]=createRuntimeSession(`process-default`)),globalContainer[RUNTIME_SESSION_DEFAULT_GLOBAL_KEY]}function getActiveRuntimeSession(){return runtimeSessionStorage.getStore()??resolveProcessDefaultSession()}async function withRuntimeSession(e,t){return await runtimeSessionStorage.run(e,async()=>await t())}export{createRuntimeSession,getActiveRuntimeSession,setRuntimeSessionCompiledArtifacts,withRuntimeSession};
|
|
@@ -78,6 +78,8 @@ export type ResolvedScheduleDefinition = Readonly<SourceRef & {
|
|
|
78
78
|
*/
|
|
79
79
|
export interface ResolvedConnectionDefinition extends ResolvedModuleSourceRef {
|
|
80
80
|
readonly protocolVersionDiscovery?: boolean;
|
|
81
|
+
/** MCP only: send the turn's principals in `eve-forwarded-principal`. */
|
|
82
|
+
readonly forwardPrincipal?: boolean;
|
|
81
83
|
readonly approval?: Approval;
|
|
82
84
|
readonly authorization?: Readonly<AuthorizationDefinition> | ConnectionAuthResolver;
|
|
83
85
|
readonly connectionName: string;
|