eve 0.47.2 → 0.47.5
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 +36 -0
- package/bin/eve.js +4 -0
- package/dist/src/channel/activity-renderer.d.ts +21 -0
- package/dist/src/channel/activity-renderer.js +1 -0
- package/dist/src/channel/activity-sink.d.ts +2 -0
- package/dist/src/channel/activity-sink.js +1 -0
- package/dist/src/channel/auth/oidc.js +1 -1
- package/dist/src/channel/channel-address.js +1 -1
- package/dist/src/channel/compiled-channel.d.ts +2 -0
- package/dist/src/channel/compiled-channel.js +2 -2
- package/dist/src/channel/forwarded-principal.js +1 -1
- package/dist/src/channel/session.d.ts +3 -2
- package/dist/src/channel/session.js +1 -1
- package/dist/src/channel/types.d.ts +11 -0
- package/dist/src/chunks/{use-eve-agent-CacMaX4P.js → use-eve-agent-DjYwFJF7.js} +1 -0
- package/dist/src/chunks/{use-eve-agent-kmlFdOBB.js → use-eve-agent-DkUB0Ok4.js} +1 -0
- package/dist/src/cli/dev/tui/status-line.d.ts +6 -0
- package/dist/src/cli/dev/tui/status-line.js +1 -1
- package/dist/src/cli/dev/tui/terminal-renderer.js +12 -12
- package/dist/src/cli/dev/tui/traces/trace-conversation.js +1 -1
- package/dist/src/cli/dev/tui/tui.js +1 -1
- package/dist/src/compiled/.vendor-stamp.json +1 -1
- package/dist/src/compiled/@opentelemetry/api/index.d.ts +37 -0
- package/dist/src/compiled/@vercel/otel/index.d.ts +11 -0
- package/dist/src/compiler/extension-compatibility.d.ts +11 -9
- package/dist/src/compiler/extension-compatibility.js +1 -1
- package/dist/src/compiler/manifest.d.ts +14 -2
- package/dist/src/compiler/manifest.js +1 -1
- package/dist/src/compiler/normalize-connection.d.ts +9 -2
- package/dist/src/compiler/normalize-connection.js +1 -1
- package/dist/src/compiler/normalize-manifest.js +1 -1
- package/dist/src/compiler/normalize-subagent.js +1 -1
- package/dist/src/compiler/validate-artifact.js +1 -1
- package/dist/src/context/dynamic-connection-lifecycle.d.ts +9 -0
- package/dist/src/context/dynamic-connection-lifecycle.js +1 -0
- package/dist/src/context/keys.d.ts +5 -2
- package/dist/src/context/keys.js +1 -1
- package/dist/src/context/memory-tools.js +1 -1
- package/dist/src/context/providers/connection.js +1 -1
- package/dist/src/dynamic/definition.d.ts +6 -3
- package/dist/src/dynamic/definition.js +1 -1
- package/dist/src/eve-channel/activity-observer-request.d.ts +7 -0
- package/dist/src/eve-channel/activity-observer-request.js +1 -0
- package/dist/src/eve-channel/index.js +1 -1
- package/dist/src/eve-channel/request.d.ts +3 -1
- package/dist/src/eve-channel/request.js +1 -1
- package/dist/src/execution/activity-collector.d.ts +12 -0
- package/dist/src/execution/activity-collector.js +1 -0
- package/dist/src/execution/activity-events.d.ts +7 -0
- package/dist/src/execution/activity-events.js +1 -0
- package/dist/src/execution/activity-route.d.ts +2 -0
- package/dist/src/execution/activity-route.js +1 -0
- package/dist/src/execution/activity-text.d.ts +3 -0
- package/dist/src/execution/activity-text.js +1 -0
- package/dist/src/execution/activity-work-id.d.ts +9 -0
- package/dist/src/execution/activity-work-id.js +1 -0
- package/dist/src/execution/activity-work.d.ts +20 -0
- package/dist/src/execution/activity-work.js +1 -0
- package/dist/src/execution/agent-handle-dispatch.d.ts +3 -1
- package/dist/src/execution/agent-handle-dispatch.js +1 -1
- package/dist/src/execution/authorization-callback-match.js +1 -1
- package/dist/src/execution/cancelled-turn-message.d.ts +2 -0
- package/dist/src/execution/cancelled-turn-message.js +1 -0
- package/dist/src/execution/delegated-parent-notification.js +1 -1
- package/dist/src/execution/dispatch-runtime-actions-shared.d.ts +8 -0
- package/dist/src/execution/dispatch-runtime-actions-shared.js +1 -1
- package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
- package/dist/src/execution/dynamic-connections.d.ts +9 -0
- package/dist/src/execution/dynamic-connections.js +1 -0
- package/dist/src/execution/eve-workflow-attributes.js +1 -1
- package/dist/src/execution/node-step.d.ts +2 -0
- package/dist/src/execution/node-step.js +1 -1
- package/dist/src/execution/remote-agent-dispatch.d.ts +3 -1
- package/dist/src/execution/remote-agent-dispatch.js +1 -1
- package/dist/src/execution/runtime-context.js +1 -1
- package/dist/src/execution/sandbox/bindings/vercel-credentials.js +1 -1
- package/dist/src/execution/session-activity-projection.d.ts +14 -0
- package/dist/src/execution/session-activity-projection.js +1 -0
- package/dist/src/execution/session-activity-renderer-step.d.ts +15 -0
- package/dist/src/execution/session-activity-renderer-step.js +1 -0
- package/dist/src/execution/session-activity.d.ts +6 -0
- package/dist/src/execution/session-activity.js +1 -0
- package/dist/src/execution/session-callback-request.d.ts +1 -0
- package/dist/src/execution/session-callback-request.js +1 -1
- package/dist/src/execution/session-callback-route.js +1 -1
- package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
- package/dist/src/execution/subagent-start-local.d.ts +1 -0
- package/dist/src/execution/subagent-start-local.js +1 -1
- package/dist/src/execution/subagent-start-remote.d.ts +1 -0
- package/dist/src/execution/subagent-start-remote.js +1 -1
- package/dist/src/execution/subagent-tool.d.ts +2 -1
- package/dist/src/execution/subagent-tool.js +1 -1
- package/dist/src/execution/submit-activity.d.ts +7 -0
- package/dist/src/execution/submit-activity.js +1 -0
- package/dist/src/execution/tasks/child/steps.d.ts +8 -0
- package/dist/src/execution/tasks/child/steps.js +1 -1
- package/dist/src/execution/tasks/child/update.js +1 -1
- package/dist/src/execution/tasks/child/workflow.d.ts +3 -0
- package/dist/src/execution/tasks/child/workflow.js +1 -1
- package/dist/src/execution/tasks/parent/delegate.d.ts +3 -0
- package/dist/src/execution/tasks/parent/delegate.js +1 -1
- package/dist/src/execution/tasks/parent/dispatch-task-step.js +1 -1
- package/dist/src/execution/tasks/parent/hitl-proxy-steps.js +1 -1
- package/dist/src/execution/tasks/parent/tool-execution.js +1 -1
- package/dist/src/execution/terminate-child-sessions-step.js +1 -1
- package/dist/src/execution/tools/connection-search.js +2 -2
- package/dist/src/execution/tools/load-skill.js +1 -1
- package/dist/src/execution/tools/subagent/local.js +1 -1
- package/dist/src/execution/turn-control-receiver.js +1 -1
- package/dist/src/execution/turn-workflow.js +1 -1
- package/dist/src/execution/web-fetch/request.js +1 -1
- package/dist/src/execution/wire/session-inbox-contract.d.ts +2 -2
- package/dist/src/execution/wire/session-inbox-contract.js +1 -1
- package/dist/src/execution/wire/session-inbox-encoder.d.ts +6 -2
- package/dist/src/execution/wire/session-inbox-encoder.js +1 -1
- package/dist/src/execution/wire/session-inbox-wire.js +1 -1
- package/dist/src/execution/wire/session-inbox-wire.v2-migration.d.ts +4 -0
- package/dist/src/execution/wire/session-inbox-wire.v2-migration.js +1 -0
- package/dist/src/execution/wire/session-inbox-wire.v2.d.ts +478 -0
- package/dist/src/execution/wire/session-inbox-wire.v2.js +1 -0
- package/dist/src/execution/workflow-entry.js +1 -1
- package/dist/src/execution/workflow-runtime.d.ts +4 -0
- package/dist/src/execution/workflow-runtime.js +1 -1
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/execution/workflow-trace-context.d.ts +3 -6
- package/dist/src/execution/workflow-trace-context.js +1 -1
- package/dist/src/harness/approval-delivery-coordinator.js +1 -1
- package/dist/src/harness/authorization.d.ts +11 -4
- package/dist/src/harness/authorization.js +1 -1
- package/dist/src/harness/inline-tool-authorization.d.ts +13 -1
- package/dist/src/harness/inline-tool-authorization.js +1 -1
- package/dist/src/harness/model-call-error.js +1 -1
- package/dist/src/harness/semantic-errors/rule.d.ts +5 -2
- package/dist/src/harness/semantic-errors/rules/gateway.js +1 -1
- package/dist/src/harness/tool-loop.js +2 -2
- package/dist/src/harness/tool-model-output.js +1 -1
- package/dist/src/harness/turn-tag-state.d.ts +1 -1
- package/dist/src/harness/types.d.ts +2 -2
- package/dist/src/{harness → instrumentation}/ai-sdk-hook-bridge.d.ts +1 -1
- package/dist/src/instrumentation/ai-sdk-hook-bridge.js +1 -0
- package/dist/src/{harness → instrumentation}/ai-sdk-telemetry.d.ts +5 -1
- package/dist/src/instrumentation/ai-sdk-telemetry.js +1 -0
- package/dist/src/{harness/channel-delivery-instrumentation.d.ts → instrumentation/channel-delivery.d.ts} +5 -7
- package/dist/src/instrumentation/channel-delivery.js +1 -0
- package/dist/src/{harness/instrumentation → instrumentation}/config.d.ts +0 -10
- package/dist/src/instrumentation/config.js +1 -0
- package/dist/src/instrumentation/content-policy.d.ts +5 -0
- package/dist/src/instrumentation/content-policy.js +1 -0
- package/dist/src/{harness/instrumentation → instrumentation}/content.d.ts +1 -1
- package/dist/src/{harness/instrumentation → instrumentation}/dispatch.d.ts +1 -1
- package/dist/src/instrumentation/dispatch.js +1 -0
- package/dist/src/{harness/instrumentation → instrumentation}/lifecycle.d.ts +34 -35
- package/dist/src/instrumentation/lifecycle.js +1 -0
- package/dist/src/{harness/instrumentation → instrumentation}/native-events.d.ts +1 -1
- package/dist/src/instrumentation/native-events.js +1 -0
- package/dist/src/{harness → instrumentation}/parent-lineage.d.ts +1 -1
- package/dist/src/instrumentation/prepare-trace-context.d.ts +24 -0
- package/dist/src/instrumentation/prepare-trace-context.js +1 -0
- package/dist/src/instrumentation/provider.d.ts +13 -9
- package/dist/src/{harness/instrumentation → instrumentation}/providers.d.ts +1 -1
- package/dist/src/instrumentation/providers.js +1 -0
- package/dist/src/{harness/instrumentation → instrumentation}/runtime-context.d.ts +13 -2
- package/dist/src/instrumentation/runtime-context.js +1 -0
- package/dist/src/instrumentation/runtime.d.ts +100 -0
- package/dist/src/instrumentation/runtime.js +1 -0
- package/dist/src/{harness/instrumentation → instrumentation}/state.d.ts +2 -11
- package/dist/src/internal/application/compiled-artifacts.js +4 -4
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-definition/connection.js +1 -1
- package/dist/src/internal/instrumentation.d.ts +1 -1
- package/dist/src/internal/nitro/routes/channel-request-instrumentation.d.ts +4 -6
- package/dist/src/internal/nitro/routes/channel-request-instrumentation.js +1 -1
- package/dist/src/internal/user-agent.d.ts +2 -0
- package/dist/src/internal/user-agent.js +1 -1
- package/dist/src/packages/eve-catalog/src/index.js +1 -1
- package/dist/src/protocol/activity.d.ts +105 -0
- package/dist/src/protocol/activity.js +1 -0
- package/dist/src/protocol/message.js +2 -2
- package/dist/src/protocol/routes.d.ts +4 -0
- package/dist/src/protocol/routes.js +1 -1
- package/dist/src/public/channels/auth.js +1 -1
- package/dist/src/public/channels/slack/defaults.js +6 -3
- package/dist/src/public/channels/slack/index.d.ts +1 -1
- package/dist/src/public/channels/slack/interactions.d.ts +8 -5
- package/dist/src/public/channels/slack/interactions.js +1 -1
- package/dist/src/public/channels/slack/slackChannel.d.ts +66 -1
- package/dist/src/public/channels/slack/slash-command.d.ts +9 -0
- package/dist/src/public/channels/slack/slash-command.js +1 -0
- package/dist/src/public/connections/index.d.ts +2 -0
- package/dist/src/public/connections/index.js +1 -1
- package/dist/src/public/definitions/connections/dynamic.d.ts +23 -0
- package/dist/src/public/definitions/connections/dynamic.js +1 -0
- package/dist/src/public/definitions/connections/mcp.d.ts +8 -0
- package/dist/src/public/definitions/connections/openapi.d.ts +8 -0
- package/dist/src/public/definitions/connections/protocol.d.ts +6 -0
- package/dist/src/public/definitions/connections/protocol.js +1 -1
- package/dist/src/runtime/channels/registry.js +1 -1
- package/dist/src/runtime/connections/authorization-tokens.d.ts +11 -10
- package/dist/src/runtime/connections/instance-identity.d.ts +12 -0
- package/dist/src/runtime/connections/instance-identity.js +1 -0
- package/dist/src/runtime/connections/mcp-client.js +1 -1
- package/dist/src/runtime/connections/openapi-client.js +1 -1
- package/dist/src/runtime/connections/registry.d.ts +2 -0
- package/dist/src/runtime/connections/registry.js +1 -1
- package/dist/src/runtime/connections/scoped-authorization.d.ts +10 -6
- package/dist/src/runtime/connections/scoped-authorization.js +1 -1
- package/dist/src/runtime/resolve-agent.js +1 -1
- package/dist/src/runtime/resolve-connection.d.ts +5 -0
- package/dist/src/runtime/resolve-connection.js +1 -1
- package/dist/src/runtime/resolve-dynamic-connection.d.ts +5 -0
- package/dist/src/runtime/resolve-dynamic-connection.js +1 -0
- package/dist/src/runtime/subagents/dynamic-remote-agent-config.js +1 -1
- package/dist/src/runtime/types.d.ts +11 -0
- package/dist/src/setup/flows/registry.js +1 -1
- package/dist/src/setup/gateway-models.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/setup/scaffold/create/web-template.d.ts +1 -1
- package/dist/src/setup/scaffold/create/web-template.js +9 -5
- package/dist/src/shared/trace-policy.d.ts +20 -0
- package/dist/src/shared/trace-policy.js +1 -0
- package/dist/src/svelte/index.js +1 -1
- package/dist/src/svelte/use-eve-agent.js +1 -1
- package/dist/src/tracing/agent-action-instrumentation.d.ts +1 -1
- package/dist/src/tracing/agent-action-instrumentation.js +1 -1
- package/dist/src/tracing/agent-approval-instrumentation.d.ts +1 -3
- package/dist/src/tracing/agent-approval-instrumentation.js +1 -1
- package/dist/src/tracing/agent-channel-delivery-instrumentation.d.ts +1 -1
- package/dist/src/tracing/agent-channel-delivery-instrumentation.js +1 -1
- package/dist/src/tracing/agent-otel-provider.d.ts +4 -4
- package/dist/src/tracing/agent-otel-provider.js +2 -2
- package/dist/src/tracing/agent-otel-runtime-context.d.ts +5 -0
- package/dist/src/tracing/agent-otel-runtime-context.js +1 -0
- package/dist/src/tracing/agent-otel-session-context.d.ts +3 -3
- package/dist/src/tracing/agent-otel-session-context.js +1 -1
- package/dist/src/tracing/agent-otel-usage.d.ts +4 -2
- package/dist/src/tracing/agent-otel-usage.js +1 -1
- package/dist/src/tracing/agent-span-id-generator.d.ts +1 -1
- package/dist/src/tracing/agent-tool-instrumentation.d.ts +1 -1
- package/dist/src/tracing/agent-tool-instrumentation.js +1 -1
- package/dist/src/tracing/agent-trace-context-store.d.ts +6 -0
- package/dist/src/tracing/agent-trace-context-store.js +1 -1
- package/dist/src/tracing/agent-trace-context.d.ts +3 -0
- package/dist/src/tracing/agent-trace-context.js +1 -0
- package/dist/src/tracing/agent-trace-state.d.ts +10 -1
- package/dist/src/tracing/agent-trace-state.js +1 -1
- package/dist/src/tracing/install-instrumentation-runtime.d.ts +3 -2
- package/dist/src/tracing/install-instrumentation-runtime.js +1 -1
- package/dist/src/tracing/local-instrumentation-runtime.d.ts +1 -1
- package/dist/src/tracing/local-instrumentation-runtime.js +1 -1
- package/dist/src/tracing/local-trace-reader.d.ts +1 -0
- package/dist/src/tracing/local-trace-reader.js +1 -1
- package/dist/src/tracing/otel-declaration.d.ts +20 -19
- package/dist/src/tracing/otel-declaration.js +1 -1
- package/dist/src/tracing/otel-registration.js +1 -1
- package/dist/src/tracing/sampled-trace.d.ts +1 -14
- package/dist/src/tracing/sampled-trace.js +1 -1
- package/dist/src/vue/index.js +1 -1
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/channels/slack.mdx +25 -5
- package/docs/connections/overview.mdx +46 -2
- package/docs/extensions.md +2 -2
- package/docs/getting-started.mdx +1 -1
- package/docs/guides/dynamic-capabilities.md +91 -5
- package/docs/memory.md +7 -4
- package/docs/reference/cli.md +8 -8
- package/docs/reference/typescript-api.md +32 -23
- package/package.json +1 -1
- package/dist/src/execution/subagent-usage-span.d.ts +0 -9
- package/dist/src/execution/subagent-usage-span.js +0 -1
- package/dist/src/harness/ai-sdk-hook-bridge.js +0 -1
- package/dist/src/harness/ai-sdk-telemetry.js +0 -1
- package/dist/src/harness/channel-delivery-instrumentation.js +0 -1
- package/dist/src/harness/instrumentation/config.js +0 -1
- package/dist/src/harness/instrumentation/content-policy.d.ts +0 -7
- package/dist/src/harness/instrumentation/content-policy.js +0 -1
- package/dist/src/harness/instrumentation/dispatch.js +0 -1
- package/dist/src/harness/instrumentation/lifecycle.js +0 -1
- package/dist/src/harness/instrumentation/native-events.js +0 -1
- package/dist/src/harness/instrumentation/providers.js +0 -1
- package/dist/src/harness/instrumentation/runtime-context.js +0 -1
- package/dist/src/harness/instrumentation/runtime.d.ts +0 -21
- package/dist/src/harness/instrumentation/runtime.js +0 -1
- package/dist/src/harness/prepare-trace-context.d.ts +0 -21
- package/dist/src/harness/prepare-trace-context.js +0 -1
- /package/dist/src/{harness/instrumentation → instrumentation}/content.js +0 -0
- /package/dist/src/{harness → instrumentation}/parent-lineage.js +0 -0
- /package/dist/src/{harness/instrumentation → instrumentation}/setup-context.d.ts +0 -0
- /package/dist/src/{harness/instrumentation → instrumentation}/setup-context.js +0 -0
- /package/dist/src/{harness/instrumentation → instrumentation}/state.js +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Slack
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Slack interactivity wire handling. It decodes and authorizes framework HITL
|
|
3
|
+
* responses, opens freeform modals inline before Slack's trigger expires, and
|
|
4
|
+
* forwards user-owned actions, shortcuts, and slash commands to their authored hooks.
|
|
5
5
|
*/
|
|
6
6
|
import { type SlackBlockActionsPayload } from "#compiled/@chat-adapter/slack/webhook.js";
|
|
7
|
-
import type { SlackChannelConfig, SlackChannelState, SlackInteractionAction } from "#public/channels/slack/slackChannel.js";
|
|
7
|
+
import type { SlackChannelConfig, SlackChannelState, SlackInteractionAction, SlackShortcut } from "#public/channels/slack/slackChannel.js";
|
|
8
8
|
import type { ChannelFrom, ChannelResolveSession } from "#channel/channel-operations.js";
|
|
9
9
|
/**
|
|
10
10
|
* Decoded view of a Slack `block_actions` payload. Returned by
|
|
@@ -39,11 +39,14 @@ export interface InteractionHandlerDeps {
|
|
|
39
39
|
* `view_submission` payloads to the freeform-answer flow, intercepts
|
|
40
40
|
* "Type your answer" button clicks to open a modal, resolves
|
|
41
41
|
* framework HITL clicks through `onInputResponse` to the parked session,
|
|
42
|
-
*
|
|
42
|
+
* forwards other block actions to `config.onInteraction`, shortcuts to
|
|
43
|
+
* `config.onShortcut`, and slash commands to `config.onSlashCommand`.
|
|
43
44
|
*/
|
|
44
45
|
export declare function handleInteractionPost(rawBody: string, ctx: {
|
|
45
46
|
from: ChannelFrom<SlackChannelState>;
|
|
46
47
|
resolveSession: ChannelResolveSession;
|
|
47
48
|
waitUntil: (task: Promise<unknown>) => void;
|
|
48
49
|
}, deps: InteractionHandlerDeps): Promise<Response>;
|
|
50
|
+
/** Normalizes Slack's two shortcut payload variants. */
|
|
51
|
+
export declare function parseShortcutPayload(raw: unknown): SlackShortcut | null;
|
|
49
52
|
export type { ParsedBlockActionsPayload };
|
|
@@ -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{buildSlackBinding,resolveSlackBotToken,slackContinuationToken}from"#public/channels/slack/api.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,deriveHitlResponse,freeformRequestIdFromActionId,isFreeformAction,isHitlAction}from"#public/channels/slack/hitl.js";import{parseSlackWebhookBody}from"#compiled/@chat-adapter/slack/webhook.js";import{updateAnsweredFreeformCard,updateAnsweredHitlCard}from"#public/channels/slack/interaction-cards.js";import{approvalResponderStatePatch,authorizeInputResponse}from"#public/channels/slack/input-response.js";import{bindSlackSessionOperations}from"#public/channels/slack/session-operations.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 findPromptBlock(e){return findPromptBlocks(e)[0]}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=readSlackTextObject(findPromptBlock(e)?.text);return t.length>0?t: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 i=new Response(`ok`,{status:200}),s;try{s=parseSlackWebhookBody(e,{contentType:`application/x-www-form-urlencoded`})}catch{return log.warn(`failed to parse Slack interaction payload`),i}if(s.kind===`view_submission`)return handleViewSubmission(s,t,n);if(s.kind!==`block_actions`)return i;let c=parseBlockActionsPayload(s);if(!c)return i;let l=c.actions.find(e=>isFreeformAction(e.actionId));if(l)return await openFreeformModal({payload:s.raw,interaction:c,freeformAction:l,deps:n}),i;let u=slackContinuationToken(c.channelId,c.threadTs),f=c.actions.flatMap(e=>{let t=deriveHitlResponse(e);return t===null?[]:[{action:e,derived:t}]});if(f.length>0){let e=f[0].action.user;t.waitUntil(dispatchBlockInputResponses({ctx:t,deps:n,interaction:c,submission:{type:`block_actions`,actions:f.map(({action:e})=>e),inputResponses:f.map(({derived:e})=>e.response),messageTs:f[0].action.messageTs,user:e}}))}let h=n.config.onInteraction;if(h){let e=c.actions.filter(e=>!isHitlAction(e.actionId));if(e.length>0){let i=e[0].user,{thread:a,slack:s}=buildSlackBinding({botToken:n.config.credentials?.botToken,channelId:c.channelId,threadTs:c.threadTs,installationTeamId:c.installationTeamId,teamId:c.teamId}),l={...bindSlackSessionOperations({address:u,defaultAuth:buildSlackAuthContext({channelId:c.channelId,teamId:c.teamId,threadTs:c.threadTs,userId:i.id,userName:i.username??i.name}),from:t.from,resolveSession:t.resolveSession,state:{channelId:c.channelId,installationTeamId:c.installationTeamId??null,teamId:c.teamId??null,threadTs:c.threadTs,triggeringUserId:i.id}}),thread:a,slack:s};for(let n of e)t.waitUntil(Promise.resolve(h(n,l)).catch(e=>{log.error(`custom interaction handler failed`,{error:e})}))}}return i}async function dispatchBlockInputResponses(e){let t=await authorizeInputResponse({channelId:e.interaction.channelId,deps:e.deps,installationTeamId:e.interaction.installationTeamId,submission:e.submission,teamId:e.interaction.teamId,threadTs:e.interaction.threadTs});if(t!==null){try{await e.ctx.from(slackContinuationToken(e.interaction.channelId,e.interaction.threadTs)).respond(e.submission.inputResponses,{auth:t.auth,state:approvalResponderStatePatch(e.submission,t.auth)})}catch(e){log.error(`HITL interaction delivery failed`,{error:e});return}if(!e.submission.actions.some(e=>deriveHitlResponse(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=freeformRequestIdFromActionId(e.freeformAction.actionId)??e.freeformAction.value;if(!n){log.warn(`freeform button click missing requestId`);return}let r=e.freeformAction.messageTs;if(!r){log.warn(`freeform button click missing messageTs`);return}let o=buildFreeformModalView({metadata:{continuationToken:slackContinuationToken(e.interaction.channelId,e.interaction.threadTs),channelId:e.interaction.channelId,installationTeamId:e.interaction.installationTeamId,threadTs:e.interaction.threadTs,messageTs:r,requestId:n},prompt:readPromptTextFromBlocks(e.interaction.messageBlocks)}),s=await resolveSlackBotToken(e.deps.config.credentials?.botToken,{teamId:e.interaction.installationTeamId}),c=await fetch(`https://slack.com/api/views.open`,{method:`POST`,headers:{authorization:`Bearer ${s}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({trigger_id:t,view:o})});c.ok||log.error(`Slack views.open returned non-2xx`,{status:c.status})}async function handleViewSubmission(e,n,r){let i=new Response(null,{status:200});if(e.callbackId!==HITL_FREEFORM_MODAL_CALLBACK_ID)return i;let a;try{a=JSON.parse(e.privateMetadata??``)}catch{return log.warn(`freeform view_submission carries invalid private_metadata`),i}if(!a.continuationToken||!a.requestId||!a.messageTs||!a.channelId||!a.threadTs)return i;let o=e.values?.find(e=>e.blockId===HITL_FREEFORM_MODAL_BLOCK_ID&&e.actionId===HITL_FREEFORM_MODAL_ACTION_ID)?.value??``;if(o.length===0)return i;let u=e.user,d=e.userId,f=u?.teamId??e.teamId??null,p=a.installationTeamId??readInstallationTeamId(e.raw),m={type:`view_submission`,inputResponses:[parseInputResponse({requestId:a.requestId,text:o})],messageTs:a.messageTs,user:{id:d,username:u?.username,name:u?.name}};return n.waitUntil(dispatchViewInputResponse({ctx:n,deps:r,installationTeamId:p,metadata:a,submission:m,teamId:f,text:o})),i}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})}catch(e){log.error(`freeform answer delivery failed`,{error:e});return}try{await updateAnsweredFreeformCard({channelId: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};
|
|
1
|
+
import{createLogger}from"#internal/logging.js";import{parseInputResponse}from"#shared/input.js";import{readSlackTextObject}from"#public/channels/slack/inbound-content.js";import{buildSlackBinding,buildSlackWorkspaceHandle,resolveSlackBotToken,slackContinuationToken}from"#public/channels/slack/api.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,deriveHitlResponse,freeformRequestIdFromActionId,isFreeformAction,isHitlAction}from"#public/channels/slack/hitl.js";import{parseSlackWebhookBody}from"#compiled/@chat-adapter/slack/webhook.js";import{updateAnsweredFreeformCard,updateAnsweredHitlCard}from"#public/channels/slack/interaction-cards.js";import{approvalResponderStatePatch,authorizeInputResponse}from"#public/channels/slack/input-response.js";import{bindSlackSessionOperations}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 findPromptBlock(e){return findPromptBlocks(e)[0]}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=readSlackTextObject(findPromptBlock(e)?.text);return t.length>0?t: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 i=new Response(`ok`,{status:200}),a;try{a=parseSlackWebhookBody(e,{contentType:`application/x-www-form-urlencoded`})}catch{return log.warn(`failed to parse Slack interaction payload`),i}if(a.kind===`view_submission`)return handleViewSubmission(a,t,n);if(a.kind===`slash_command`)return dispatchSlashCommand(a,t,n.config),new Response(null,{status:200});if(a.kind===`unsupported`){let e=parseShortcutPayload(a.raw);return e===null?(log.warn(`unsupported Slack interaction payload ignored`,{type:a.type}),i):(dispatchShortcut(e,readInstallationTeamId(a.raw),t,n),new Response(null,{status:200}))}if(a.kind!==`block_actions`)return log.warn(`unsupported Slack interaction payload ignored`,{type:a.kind}),i;let c=parseBlockActionsPayload(a);if(!c)return i;let l=c.actions.find(e=>isFreeformAction(e.actionId));if(l)return await openFreeformModal({payload:a.raw,interaction:c,freeformAction:l,deps:n}),i;let u=slackContinuationToken(c.channelId,c.threadTs),d=c.actions.flatMap(e=>{let t=deriveHitlResponse(e);return t===null?[]:[{action:e,derived:t}]});if(d.length>0){let e=d[0].action.user;t.waitUntil(dispatchBlockInputResponses({ctx:t,deps:n,interaction:c,submission:{type:`block_actions`,actions:d.map(({action:e})=>e),inputResponses:d.map(({derived:e})=>e.response),messageTs:d[0].action.messageTs,user:e}}))}let p=n.config.onInteraction;if(p){let e=c.actions.filter(e=>!isHitlAction(e.actionId));if(e.length>0){let i=e[0].user,{thread:a,slack:o}=buildSlackBinding({botToken:n.config.credentials?.botToken,channelId:c.channelId,threadTs:c.threadTs,installationTeamId:c.installationTeamId,teamId:c.teamId}),l={...bindSlackSessionOperations({address:u,defaultAuth:buildSlackAuthContext({channelId:c.channelId,teamId:c.teamId,threadTs:c.threadTs,userId:i.id,userName:i.username??i.name}),from:t.from,resolveSession:t.resolveSession,state:{channelId:c.channelId,installationTeamId:c.installationTeamId??null,teamId:c.teamId??null,threadTs:c.threadTs,triggeringUserId:i.id}}),thread:a,slack:o};for(let n of e)t.waitUntil(Promise.resolve(p(n,l)).catch(e=>{log.error(`custom interaction handler failed`,{error:e})}))}}return i}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=buildShortcutContext({config:r.config,installationTeamId:t,teamId:e.teamId});dispatchInteractionHook(()=>i(e,a),n,`shortcut handler failed`)}function buildShortcutContext(e){return{slack:buildSlackWorkspaceHandle({botToken:e.config.credentials?.botToken,installationTeamId:e.installationTeamId,teamId:e.teamId})}}function dispatchInteractionHook(e,t,n){t.waitUntil(Promise.resolve().then(e).catch(e=>{log.error(n,{error:e})}))}async function dispatchBlockInputResponses(e){let t=await authorizeInputResponse({channelId:e.interaction.channelId,deps:e.deps,installationTeamId:e.interaction.installationTeamId,submission:e.submission,teamId:e.interaction.teamId,threadTs:e.interaction.threadTs});if(t!==null){try{await e.ctx.from(slackContinuationToken(e.interaction.channelId,e.interaction.threadTs)).respond(e.submission.inputResponses,{auth:t.auth,state:approvalResponderStatePatch(e.submission,t.auth)})}catch(e){log.error(`HITL interaction delivery failed`,{error:e});return}if(!e.submission.actions.some(e=>deriveHitlResponse(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=freeformRequestIdFromActionId(e.freeformAction.actionId)??e.freeformAction.value;if(!n){log.warn(`freeform button click missing requestId`);return}let r=e.freeformAction.messageTs;if(!r){log.warn(`freeform button click missing messageTs`);return}let i=buildFreeformModalView({metadata:{continuationToken:slackContinuationToken(e.interaction.channelId,e.interaction.threadTs),channelId:e.interaction.channelId,installationTeamId:e.interaction.installationTeamId,threadTs:e.interaction.threadTs,messageTs:r,requestId:n},prompt:readPromptTextFromBlocks(e.interaction.messageBlocks)}),s=await resolveSlackBotToken(e.deps.config.credentials?.botToken,{teamId:e.interaction.installationTeamId}),c=await fetch(`https://slack.com/api/views.open`,{method:`POST`,headers:{authorization:`Bearer ${s}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({trigger_id:t,view:i})});c.ok||log.error(`Slack views.open returned non-2xx`,{status:c.status})}async function handleViewSubmission(e,n,r){let i=new Response(null,{status:200});if(e.callbackId!==HITL_FREEFORM_MODAL_CALLBACK_ID)return i;let a;try{a=JSON.parse(e.privateMetadata??``)}catch{return log.warn(`freeform view_submission carries invalid private_metadata`),i}if(!a.continuationToken||!a.requestId||!a.messageTs||!a.channelId||!a.threadTs)return i;let o=e.values?.find(e=>e.blockId===HITL_FREEFORM_MODAL_BLOCK_ID&&e.actionId===HITL_FREEFORM_MODAL_ACTION_ID)?.value??``;if(o.length===0)return i;let s=e.user,d=e.userId,f=s?.teamId??e.teamId??null,p=a.installationTeamId??readInstallationTeamId(e.raw),m={type:`view_submission`,inputResponses:[parseInputResponse({requestId:a.requestId,text:o})],messageTs:a.messageTs,user:{id:d,username:s?.username,name:s?.name}};return n.waitUntil(dispatchViewInputResponse({ctx:n,deps:r,installationTeamId:p,metadata:a,submission:m,teamId:f,text:o})),i}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})}catch(e){log.error(`freeform answer delivery failed`,{error:e});return}try{await updateAnsweredFreeformCard({channelId: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};
|
|
@@ -289,6 +289,16 @@ export interface SlackInboundMessageContext extends SlackContext, SlackSessionOp
|
|
|
289
289
|
/** Interaction-scoped context handed to `slackChannel({ onInteraction })`. */
|
|
290
290
|
export interface SlackInteractionContext extends SlackContext, SlackSessionOperations {
|
|
291
291
|
}
|
|
292
|
+
/** Workspace-scoped context handed to `slackChannel({ onShortcut })`. */
|
|
293
|
+
export interface SlackShortcutContext {
|
|
294
|
+
/** Slack workspace identity and raw Web API escape hatch. */
|
|
295
|
+
readonly slack: SlackWorkspaceHandle;
|
|
296
|
+
}
|
|
297
|
+
/** Workspace-scoped context handed to `slackChannel({ onSlashCommand })`. */
|
|
298
|
+
export interface SlackSlashCommandContext {
|
|
299
|
+
/** Slack workspace identity and raw Web API escape hatch. */
|
|
300
|
+
readonly slack: SlackWorkspaceHandle;
|
|
301
|
+
}
|
|
292
302
|
/** Context handed to `slackChannel({ onInputResponse })` before eve resumes HITL. */
|
|
293
303
|
export interface SlackInputResponseContext extends SlackContext {
|
|
294
304
|
/** Auth derived from the Slack user who submitted the signed interaction. */
|
|
@@ -324,7 +334,7 @@ export interface SlackInteractionAction {
|
|
|
324
334
|
*/
|
|
325
335
|
readonly user: SlackInteractionUser;
|
|
326
336
|
}
|
|
327
|
-
/** Slack actor on
|
|
337
|
+
/** Slack actor on an interactive payload, mirroring `body.user`. */
|
|
328
338
|
export interface SlackInteractionUser {
|
|
329
339
|
readonly id: string;
|
|
330
340
|
/** Modern canonical display handle. */
|
|
@@ -332,6 +342,44 @@ export interface SlackInteractionUser {
|
|
|
332
342
|
/** Legacy display handle, kept for older workspaces. */
|
|
333
343
|
readonly name?: string;
|
|
334
344
|
}
|
|
345
|
+
/** Decoded Slack slash command invocation. */
|
|
346
|
+
export interface SlackSlashCommand {
|
|
347
|
+
/** Configured command name, including its leading slash. */
|
|
348
|
+
readonly command: string;
|
|
349
|
+
readonly text: string;
|
|
350
|
+
readonly user: SlackInteractionUser;
|
|
351
|
+
readonly teamId?: string;
|
|
352
|
+
readonly channelId: string;
|
|
353
|
+
readonly channelName?: string;
|
|
354
|
+
readonly enterpriseId?: string;
|
|
355
|
+
readonly isEnterpriseInstall: boolean;
|
|
356
|
+
readonly triggerId?: string;
|
|
357
|
+
readonly responseUrl?: string;
|
|
358
|
+
}
|
|
359
|
+
/** Message selected through a Slack message shortcut. */
|
|
360
|
+
export interface SlackShortcutMessage {
|
|
361
|
+
readonly text: string;
|
|
362
|
+
readonly ts: string;
|
|
363
|
+
readonly threadTs?: string;
|
|
364
|
+
readonly userId?: string;
|
|
365
|
+
}
|
|
366
|
+
/** Decoded Slack message shortcut or global shortcut. */
|
|
367
|
+
export type SlackShortcut = {
|
|
368
|
+
readonly type: "message_action";
|
|
369
|
+
readonly callbackId: string;
|
|
370
|
+
readonly triggerId: string;
|
|
371
|
+
readonly user: SlackInteractionUser;
|
|
372
|
+
readonly teamId?: string;
|
|
373
|
+
readonly channelId: string;
|
|
374
|
+
readonly message: SlackShortcutMessage;
|
|
375
|
+
readonly responseUrl?: string;
|
|
376
|
+
} | {
|
|
377
|
+
readonly type: "shortcut";
|
|
378
|
+
readonly callbackId: string;
|
|
379
|
+
readonly triggerId: string;
|
|
380
|
+
readonly user: SlackInteractionUser;
|
|
381
|
+
readonly teamId?: string;
|
|
382
|
+
};
|
|
335
383
|
/** Decoded eve-owned HITL response submitted through Slack interactivity. */
|
|
336
384
|
export type SlackInputResponseSubmission = {
|
|
337
385
|
readonly type: "block_actions";
|
|
@@ -512,6 +560,23 @@ export interface SlackChannelConfig {
|
|
|
512
560
|
* Slack Web API calls and `action.messageTs` to target `chat.update`.
|
|
513
561
|
*/
|
|
514
562
|
onInteraction?(action: SlackInteractionAction, ctx: SlackInteractionContext): void | Promise<void>;
|
|
563
|
+
/**
|
|
564
|
+
* Handles Slack message shortcuts (`message_action`) and global shortcuts
|
|
565
|
+
* (`shortcut`) with workspace-scoped Slack Web API access.
|
|
566
|
+
*
|
|
567
|
+
* eve returns `200 OK` immediately and keeps the handler alive through
|
|
568
|
+
* `waitUntil()`. Errors are caught and logged.
|
|
569
|
+
*/
|
|
570
|
+
onShortcut?(shortcut: SlackShortcut, ctx: SlackShortcutContext): void | Promise<void>;
|
|
571
|
+
/**
|
|
572
|
+
* Handles Slack slash commands configured with this channel's webhook route.
|
|
573
|
+
* The command includes the configured command name, arguments, invoking user,
|
|
574
|
+
* channel, workspace, trigger ID, and response URL.
|
|
575
|
+
*
|
|
576
|
+
* eve returns an empty `200 OK` immediately and keeps the handler alive
|
|
577
|
+
* through `waitUntil()`. Errors are caught and logged.
|
|
578
|
+
*/
|
|
579
|
+
onSlashCommand?(command: SlackSlashCommand, ctx: SlackSlashCommandContext): void | Promise<void>;
|
|
515
580
|
/**
|
|
516
581
|
* Authorizes an eve-owned HITL answer before the pending input resolves.
|
|
517
582
|
* Return `{ auth }` to accept the response, or `null` to reject it and keep
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type parseSlackWebhookBody } from "#compiled/@chat-adapter/slack/webhook.js";
|
|
2
|
+
import type { SlackChannelConfig } from "#public/channels/slack/slackChannel.js";
|
|
3
|
+
type SlashCommandPayload = Extract<ReturnType<typeof parseSlackWebhookBody>, {
|
|
4
|
+
kind: "slash_command";
|
|
5
|
+
}>;
|
|
6
|
+
export declare function dispatchSlashCommand(payload: SlashCommandPayload, ctx: {
|
|
7
|
+
readonly waitUntil: (task: Promise<unknown>) => void;
|
|
8
|
+
}, config: SlackChannelConfig): void;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createLogger}from"#internal/logging.js";import{buildSlackWorkspaceHandle}from"#public/channels/slack/api.js";import"#compiled/@chat-adapter/slack/webhook.js";const log=createLogger(`slack.slash-command`);function dispatchSlashCommand(e,t,n){let r=parseSlashCommandPayload(e),i=n.onSlashCommand;if(i===void 0){log.warn(`Slack slash command ignored because onSlashCommand is not configured`,{command:r.command});return}let a={slack:buildSlackWorkspaceHandle({botToken:n.credentials?.botToken,installationTeamId:r.teamId,teamId:r.teamId})};t.waitUntil(Promise.resolve().then(()=>i(r,a)).catch(e=>{log.error(`slash command handler failed`,{error:e})}))}function parseSlashCommandPayload(e){return{command:e.command,text:e.text,user:{id:e.userId,username:e.userName},teamId:e.teamId,channelId:e.channelId,channelName:e.channelName,enterpriseId:e.enterpriseId,isEnterpriseInstall:e.isEnterpriseInstall,triggerId:e.triggerId,responseUrl:e.responseUrl}}export{dispatchSlashCommand};
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
export type { AuthorizationCallback, AuthorizationDefinition, ConnectionAuthDefinition, ConnectionAuthProvider, ConnectionAuthResolver, ConnectionPrincipal, HeadersDefinition, InteractiveAuthorizationDefinition, NonInteractiveAuthorizationDefinition, TokenResult, ToolFilterDefinition, } from "#shared/connection-types.js";
|
|
5
5
|
export { defineInteractiveAuthorization } from "#shared/connection-types.js";
|
|
6
6
|
export type { JsonValue } from "#public/types/json.js";
|
|
7
|
+
export { defineDynamic, type DynamicConnectionDefinition, type DynamicConnectionEvents, type DynamicConnectionResolveContext, type DynamicConnectionResult, type DynamicConnectionSet, } from "#public/definitions/connections/dynamic.js";
|
|
8
|
+
export type { DynamicResolveContext, DynamicSentinel } from "#dynamic/definition.js";
|
|
7
9
|
export { defineMcpClientConnection, type McpClientConnectionDefinition, } from "#public/definitions/connections/mcp.js";
|
|
8
10
|
export type { ConnectionToolCallDefinition, ProvidedArgumentContext, ProvidedArgumentsDefinition, ProvidedArgumentValue, } from "#public/definitions/connections/tool-call.js";
|
|
9
11
|
export { defineOpenAPIConnection, type OpenAPIConnectionDefinition, type OpenAPISpecSource, } from "#public/definitions/connections/openapi.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{defineInteractiveAuthorization}from"#shared/connection-types.js";import{defineMcpClientConnection}from"#public/definitions/connections/mcp.js";import{defineOpenAPIConnection}from"#public/definitions/connections/openapi.js";import{ConnectionAuthorizationFailedError,ConnectionAuthorizationRequiredError,isConnectionAuthorizationFailedError,isConnectionAuthorizationRequiredError}from"#public/connections/errors.js";export{ConnectionAuthorizationFailedError,ConnectionAuthorizationRequiredError,defineInteractiveAuthorization,defineMcpClientConnection,defineOpenAPIConnection,isConnectionAuthorizationFailedError,isConnectionAuthorizationRequiredError};
|
|
1
|
+
import{defineInteractiveAuthorization}from"#shared/connection-types.js";import{defineDynamic}from"#public/definitions/connections/dynamic.js";import{defineMcpClientConnection}from"#public/definitions/connections/mcp.js";import{defineOpenAPIConnection}from"#public/definitions/connections/openapi.js";import{ConnectionAuthorizationFailedError,ConnectionAuthorizationRequiredError,isConnectionAuthorizationFailedError,isConnectionAuthorizationRequiredError}from"#public/connections/errors.js";export{ConnectionAuthorizationFailedError,ConnectionAuthorizationRequiredError,defineDynamic,defineInteractiveAuthorization,defineMcpClientConnection,defineOpenAPIConnection,isConnectionAuthorizationFailedError,isConnectionAuthorizationRequiredError};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { McpClientConnectionDefinition } from "#public/definitions/connections/mcp.js";
|
|
2
|
+
import type { OpenAPIConnectionDefinition } from "#public/definitions/connections/openapi.js";
|
|
3
|
+
import { type DynamicResolveContext, type DynamicSentinel } from "#dynamic/definition.js";
|
|
4
|
+
import type { ExactDefinition } from "#public/definitions/exact.js";
|
|
5
|
+
/** One connection returned by a dynamic connection resolver. */
|
|
6
|
+
export type DynamicConnectionDefinition = McpClientConnectionDefinition | OpenAPIConnectionDefinition;
|
|
7
|
+
/** A runtime connection set whose keys become connection names. */
|
|
8
|
+
export type DynamicConnectionSet = Readonly<Record<string, DynamicConnectionDefinition>>;
|
|
9
|
+
/** Supported return value for a dynamic connection resolver. */
|
|
10
|
+
export type DynamicConnectionResult = DynamicConnectionDefinition | DynamicConnectionSet | null;
|
|
11
|
+
/** Trusted session identity and minimal channel metadata available to connection resolvers. */
|
|
12
|
+
export interface DynamicConnectionResolveContext {
|
|
13
|
+
readonly session: DynamicResolveContext["session"];
|
|
14
|
+
readonly channel: Pick<DynamicResolveContext["channel"], "kind">;
|
|
15
|
+
}
|
|
16
|
+
/** Session and turn handlers supported by dynamic connections. */
|
|
17
|
+
export type DynamicConnectionEvents = {
|
|
18
|
+
readonly [K in "session.started" | "turn.started"]?: (event: unknown, ctx: DynamicConnectionResolveContext) => DynamicConnectionResult | Promise<DynamicConnectionResult>;
|
|
19
|
+
};
|
|
20
|
+
/** Defines a runtime connection resolver for session and turn boundaries. */
|
|
21
|
+
export declare function defineDynamic<const TEvents extends DynamicConnectionEvents>(definition: {
|
|
22
|
+
readonly events: ExactDefinition<TEvents, DynamicConnectionEvents>;
|
|
23
|
+
}): DynamicSentinel<DynamicConnectionResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{DYNAMIC_SENTINEL_KIND}from"#dynamic/definition.js";import{stampDefinitionKey}from"#internal/authored-definition/source-identity.js";function defineDynamic(e){let t={kind:DYNAMIC_SENTINEL_KIND,events:e.events};return stampDefinitionKey(t,`dynamic-connections:${Object.keys(e.events).join(`,`)}`),t}export{defineDynamic};
|
|
@@ -44,6 +44,14 @@ export interface McpClientConnectionDefinition {
|
|
|
44
44
|
* Optional when `headers` is provided for non-Bearer auth schemes.
|
|
45
45
|
*/
|
|
46
46
|
auth?: ConnectionAuthDefinition;
|
|
47
|
+
/**
|
|
48
|
+
* Stable, non-secret identity for the resolved connection instance.
|
|
49
|
+
*
|
|
50
|
+
* Authenticated dynamic connections must set this to an account or tenant
|
|
51
|
+
* identifier that changes whenever the endpoint or auth provider changes.
|
|
52
|
+
* eve hashes the value before storing it in durable authorization state.
|
|
53
|
+
*/
|
|
54
|
+
readonly instanceKey?: string;
|
|
47
55
|
/**
|
|
48
56
|
* Optional per-connection approval gate for connection tool calls.
|
|
49
57
|
*
|
|
@@ -66,6 +66,14 @@ export interface OpenAPIConnectionDefinition {
|
|
|
66
66
|
* Optional when `headers` is provided for non-Bearer auth schemes.
|
|
67
67
|
*/
|
|
68
68
|
auth?: ConnectionAuthDefinition;
|
|
69
|
+
/**
|
|
70
|
+
* Stable, non-secret identity for the resolved connection instance.
|
|
71
|
+
*
|
|
72
|
+
* Authenticated dynamic connections must set this to an account or tenant
|
|
73
|
+
* identifier that changes whenever the endpoint or auth provider changes.
|
|
74
|
+
* eve hashes the value before storing it in durable authorization state.
|
|
75
|
+
*/
|
|
76
|
+
readonly instanceKey?: string;
|
|
69
77
|
/**
|
|
70
78
|
* Optional per-connection approval gate for connection tool calls.
|
|
71
79
|
*
|
|
@@ -10,3 +10,9 @@ export declare function stampConnectionProtocol(definition: object, protocol: Co
|
|
|
10
10
|
* marker existed continue to compile as MCP connections.
|
|
11
11
|
*/
|
|
12
12
|
export declare function readConnectionProtocol(definition: unknown): ConnectionProtocol;
|
|
13
|
+
/**
|
|
14
|
+
* Reads the protocol marker without applying the legacy MCP fallback.
|
|
15
|
+
* Dynamic connection resolvers use this to distinguish one branded
|
|
16
|
+
* connection definition from a map of branded definitions.
|
|
17
|
+
*/
|
|
18
|
+
export declare function readStampedConnectionProtocol(definition: unknown): ConnectionProtocol | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const PROTOCOL_KEY=Symbol.for(`eve.connection-protocol`);function stampConnectionProtocol(
|
|
1
|
+
const PROTOCOL_KEY=Symbol.for(`eve.connection-protocol`);function stampConnectionProtocol(t,n){Object.defineProperty(t,PROTOCOL_KEY,{configurable:!0,value:n})}function readConnectionProtocol(e){return readStampedConnectionProtocol(e)??`mcp`}function readStampedConnectionProtocol(t){if(!(typeof t!=`object`||!t||!(PROTOCOL_KEY in t)))return t[PROTOCOL_KEY]}export{readConnectionProtocol,readStampedConnectionProtocol,stampConnectionProtocol};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getAdapterKind}from"#channel/adapter.js";import{SCHEDULE_ADAPTER}from"#channel/schedule.js";import{HTTP_ADAPTER}from"#channel/http.js";import{SUBAGENT_ADAPTER}from"#execution/subagent-adapter.js";import{RuntimeRegistryError}from"#internal/runtime-registry.js";const FRAMEWORK_ADAPTERS=[HTTP_ADAPTER,SUBAGENT_ADAPTER,SCHEDULE_ADAPTER],ADAPTER_NON_EVENT_FIELDS=new Set([`kind`,`state`,`deliver`,`createAdapterContext`,`fetchFile`,`instrumentation`]);function createRuntimeAdapterRegistry(e){let t=new Map,n=new Set;for(let e of FRAMEWORK_ADAPTERS){let r=requireAdapterKind(e);n.add(r),t.set(r,e)}for(let r of e.channels){if(r.adapter===void 0)continue;let e={logicalPath:r.logicalPath,sourceId:r.sourceId},i=r.adapter,a=requireAdapterKind(i,e);if(n.has(a)){if(carriesAdapterBehavior(i))throw new RuntimeRegistryError(`adapter`,`Channel adapter kind "${a}" is reserved by the framework. A route-declared adapter may share a framework kind only as a pass-through with no \`deliver\` hook, event handlers, \`attachments\` resolver, or \`createAdapterContext\` factory. Use a custom \`kind\` to add channel-specific behavior.`,{...e,entryName:a});continue}t.set(a,i)}return{adaptersByKind:t}}function deserializeRuntimeAdapter(
|
|
1
|
+
import{copyChannelActivityPresentation,getChannelActivityPresentation}from"#channel/activity-renderer.js";import{getAdapterKind}from"#channel/adapter.js";import{SCHEDULE_ADAPTER}from"#channel/schedule.js";import{HTTP_ADAPTER}from"#channel/http.js";import{SUBAGENT_ADAPTER}from"#execution/subagent-adapter.js";import{RuntimeRegistryError}from"#internal/runtime-registry.js";const FRAMEWORK_ADAPTERS=[HTTP_ADAPTER,SUBAGENT_ADAPTER,SCHEDULE_ADAPTER],ADAPTER_NON_EVENT_FIELDS=new Set([`kind`,`state`,`deliver`,`createAdapterContext`,`fetchFile`,`instrumentation`]);function createRuntimeAdapterRegistry(e){let t=new Map,n=new Set;for(let e of FRAMEWORK_ADAPTERS){let r=requireAdapterKind(e);n.add(r),t.set(r,e)}for(let r of e.channels){if(r.adapter===void 0)continue;let e={logicalPath:r.logicalPath,sourceId:r.sourceId},i=r.adapter,a=requireAdapterKind(i,e);if(n.has(a)){if(carriesAdapterBehavior(i))throw new RuntimeRegistryError(`adapter`,`Channel adapter kind "${a}" is reserved by the framework. A route-declared adapter may share a framework kind only as a pass-through with no \`deliver\` hook, event handlers, \`attachments\` resolver, or \`createAdapterContext\` factory. Use a custom \`kind\` to add channel-specific behavior.`,{...e,entryName:a});continue}t.set(a,i)}return{adaptersByKind:t}}function deserializeRuntimeAdapter(t,n){let r=n,i=t.adaptersByKind.get(r.kind);if(i===void 0)throw Error(`Unknown adapter kind: "${r.kind}". Declare the adapter on the route that starts this session so the runtime can rehydrate it.`);let a={...i,state:r.state};return copyChannelActivityPresentation(i,a),a}function requireAdapterKind(e,t){let r=getAdapterKind(e);if(typeof r!=`string`||r.length===0)throw new RuntimeRegistryError(`adapter`,"Adapters must declare a non-empty `kind` field.",{entryName:`unknown`,logicalPath:t?.logicalPath,sourceId:t?.sourceId});return r}function carriesAdapterBehavior(e){if(getChannelActivityPresentation(e)!==void 0||e.deliver!==void 0||e.fetchFile!==void 0||e.createAdapterContext!==void 0)return!0;for(let[t,n]of Object.entries(e))if(!ADAPTER_NON_EVENT_FIELDS.has(t)&&typeof n==`function`)return!0;return!1}export{createRuntimeAdapterRegistry,deserializeRuntimeAdapter};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Per-step cache of resolved connection authorization tokens.
|
|
3
3
|
*
|
|
4
|
-
* Keyed by `(
|
|
5
|
-
* session never share a user-scoped token
|
|
4
|
+
* Keyed by `(authorizationScope, principalKey)` so two users on the same
|
|
5
|
+
* session never share a user-scoped token and two resolved connection
|
|
6
|
+
* instances never share credentials. Stored as a virtual
|
|
6
7
|
* context value and wiped between workflow steps, so bearer tokens
|
|
7
8
|
* are never serialized into the durable step payload. Cross-step
|
|
8
9
|
* reuse is delegated to the upstream authorization provider (for
|
|
@@ -16,7 +17,7 @@ import type { AlsContext } from "#context/container.js";
|
|
|
16
17
|
import { ContextKey } from "#context/key.js";
|
|
17
18
|
import type { TokenResult } from "#shared/connection-types.js";
|
|
18
19
|
/**
|
|
19
|
-
* Virtual context key mapping
|
|
20
|
+
* Virtual context key mapping authorization scope to a per-principal
|
|
20
21
|
* {@link TokenResult} cache.
|
|
21
22
|
*
|
|
22
23
|
* The principal sub-key is produced by
|
|
@@ -27,25 +28,25 @@ import type { TokenResult } from "#shared/connection-types.js";
|
|
|
27
28
|
export declare const ConnectionAuthorizationTokensKey: ContextKey<Readonly<Record<string, Readonly<Record<string, TokenResult>>>>>;
|
|
28
29
|
/**
|
|
29
30
|
* Returns the cached {@link TokenResult} for
|
|
30
|
-
* `(
|
|
31
|
+
* `(authorizationScope, principalKey)` when the entry is still valid
|
|
31
32
|
* (not expired). Expired entries are treated as a cache miss so
|
|
32
33
|
* callers re-run the authorization flow.
|
|
33
34
|
*/
|
|
34
|
-
export declare function readCachedToken(ctx: AlsContext,
|
|
35
|
+
export declare function readCachedToken(ctx: AlsContext, authorizationScope: string, principalKey: string): TokenResult | undefined;
|
|
35
36
|
/**
|
|
36
37
|
* Persists a freshly resolved {@link TokenResult} on the cache under
|
|
37
|
-
* `(
|
|
38
|
-
* principals
|
|
38
|
+
* `(authorizationScope, principalKey)`. Existing entries for other
|
|
39
|
+
* principals in the same scope are left in place.
|
|
39
40
|
*
|
|
40
41
|
* Writes to the virtual context slot so the bearer is never serialized
|
|
41
42
|
* into the durable step payload. See the module docblock.
|
|
42
43
|
*/
|
|
43
|
-
export declare function writeCachedToken(ctx: AlsContext,
|
|
44
|
+
export declare function writeCachedToken(ctx: AlsContext, authorizationScope: string, principalKey: string, token: TokenResult): void;
|
|
44
45
|
/**
|
|
45
|
-
* Drops the cached {@link TokenResult} for `(
|
|
46
|
+
* Drops the cached {@link TokenResult} for `(authorizationScope, principalKey)`,
|
|
46
47
|
* if present. Used when the remote server rejects an already-resolved
|
|
47
48
|
* bearer (HTTP 401) so the subsequent re-authorization attempt does not
|
|
48
49
|
* re-read the stale token from the per-step cache. No-op when nothing is
|
|
49
50
|
* cached for the principal.
|
|
50
51
|
*/
|
|
51
|
-
export declare function evictCachedToken(ctx: AlsContext,
|
|
52
|
+
export declare function evictCachedToken(ctx: AlsContext, authorizationScope: string, principalKey: string): void;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ConnectionProtocol } from "#shared/connection-types.js";
|
|
2
|
+
import type { ResolvedConnectionDefinition } from "#runtime/types.js";
|
|
3
|
+
/** Builds the opaque, reconstruction-stable identity for one resolved connection instance. */
|
|
4
|
+
export declare function createConnectionInstanceId(input: {
|
|
5
|
+
readonly connectionName: string;
|
|
6
|
+
readonly instanceKey?: string;
|
|
7
|
+
readonly protocol: ConnectionProtocol;
|
|
8
|
+
readonly sourceId: string;
|
|
9
|
+
readonly url: string;
|
|
10
|
+
}): string;
|
|
11
|
+
/** Returns the cache and callback scope for one resolved connection. */
|
|
12
|
+
export declare function connectionAuthorizationScope(connection: ResolvedConnectionDefinition): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createHash}from"node:crypto";function createConnectionInstanceId(t){return`connection:${createHash(`sha256`).update(JSON.stringify([t.sourceId,t.connectionName,t.protocol,t.url,t.instanceKey??``])).digest(`base64url`)}`}function connectionAuthorizationScope(e){return e.instanceId??e.connectionName}export{connectionAuthorizationScope,createConnectionInstanceId};
|
|
@@ -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";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.#a();try{return this.#t=await this.#e,this.#t}catch(e){throw this.#e=void 0,e}}async#a(){let e=await resolveHeaders(this.#i),t=this.#i.url;try{return await createMCPClient({transport:{type:`http`,url:t,headers:e}})}catch(n){if(!isMcpHttpFallbackRetryableError(n))throw n;return await createMCPClient({transport:{type:`sse`,url:t,headers:e}})}}async getToolMetadata(){return(await this.#o()).metadata}async getTools(){return(await this.#o()).tools}async executeTool(e,t,n){try{let{tools:r}=await this.#o(),i=r[e];if(i?.execute===void 0)throw Error(`Tool "${e}" not found in connection "${this.#i.connectionName}".`);let a=await resolveProvidedArguments({args:t,callId:n.callId,connection:this.#i,toolName:e});return await i.execute(a,{abortSignal:n.abortSignal})}catch(e){return await this.#l(e)}}async#o(){if(this.#r!==void 0)return this.#r;if(this.#n!==void 0)return this.#n;this.#n=this.#s();try{return this.#r=await this.#n,this.#r}catch(e){throw this.#n=void 0,e}}async#s(){try{return await this.#c()}catch(e){return await this.#l(e)}}async#c(){let e=await this.connect(),t=await e.listTools(),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}async#l(e){throw isMcpAuthRequiredError(e)?(await this.#u(),await this.close(),new ConnectionAuthorizationRequiredError(this.#i.connectionName,{message:`Connection "${this.#i.connectionName}" requires authorization (the server rejected the token).`})):e}async#u(){let e=await resolveConnectionAuthorization(this.#i);e!==void 0&&await evictScopedToken({authorization:e,connection:{url:this.#i.url},scope:this.#i.connectionName})}};function isMcpAuthRequiredError(e){return readHttpStatus(e)===401}function isMcpHttpFallbackRetryableError(e){let t=readHttpStatus(e);return t===400||t===404||t===405}function readHttpStatus(t){for(let n of walkErrorChain(t)){if(!isObject(n))continue;let t=readStatusField(n);if(t!==void 0)return t;let r=n.response;if(isObject(r)){let e=readStatusField(r);if(e!==void 0)return e}if(typeof n.message==`string`){let e=/\bHTTP\s+(\d{3})\b/u.exec(n.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(t){let n=t,r=new Set;for(;n!=null&&!r.has(n);){if(r.add(n),yield n,!isObject(n)||!(`cause`in n))return;n=n.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 n={},r,getCallbackContext=()=>r??=buildCallbackContext(),i=await resolveConnectionAuthorization(e,typeof e.authorization==`function`?getCallbackContext():void 0);if(i!==void 0&&(n.Authorization=`Bearer ${(await resolveToken(e,i)).token}`),e.headers!==void 0){let t=await resolveHeadersDefinition(e.headers,getCallbackContext);for(let[r,a]of Object.entries(t)){if(i!==void 0&&r.toLowerCase()===`authorization`)throw Error(`Connection "${e.connectionName}" headers must not include an "Authorization" key when "authorization" is also provided.`);n[r]=a}}return n}async function resolveToken(e,t){return await resolveScopedToken({authorization:t,connection:{url:e.url},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{McpConnectionClient,isMcpAuthRequiredError,passesToolFilter,resolveHeaders};
|
|
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";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.#a();try{return this.#t=await this.#e,this.#t}catch(e){throw this.#e=void 0,e}}async#a(){let e=await resolveHeaders(this.#i),t=this.#i.url;try{return await createMCPClient({transport:{type:`http`,url:t,headers:e}})}catch(n){if(!isMcpHttpFallbackRetryableError(n))throw n;return await createMCPClient({transport:{type:`sse`,url:t,headers:e}})}}async getToolMetadata(){return(await this.#o()).metadata}async getTools(){return(await this.#o()).tools}async executeTool(e,t,n){try{let{tools:r}=await this.#o(),i=r[e];if(i?.execute===void 0)throw Error(`Tool "${e}" not found in connection "${this.#i.connectionName}".`);let a=await resolveProvidedArguments({args:t,callId:n.callId,connection:this.#i,toolName:e});return await i.execute(a,{abortSignal:n.abortSignal})}catch(e){return await this.#l(e)}}async#o(){if(this.#r!==void 0)return this.#r;if(this.#n!==void 0)return this.#n;this.#n=this.#s();try{return this.#r=await this.#n,this.#r}catch(e){throw this.#n=void 0,e}}async#s(){try{return await this.#c()}catch(e){return await this.#l(e)}}async#c(){let e=await this.connect(),t=await e.listTools(),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}async#l(e){throw isMcpAuthRequiredError(e)?(await this.#u(),await this.close(),new ConnectionAuthorizationRequiredError(this.#i.connectionName,{message:`Connection "${this.#i.connectionName}" requires authorization (the server rejected the token).`})):e}async#u(){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}function isMcpHttpFallbackRetryableError(e){let t=readHttpStatus(e);return t===400||t===404||t===405}function readHttpStatus(t){for(let n of walkErrorChain(t)){if(!isObject(n))continue;let t=readStatusField(n);if(t!==void 0)return t;let r=n.response;if(isObject(r)){let e=readStatusField(r);if(e!==void 0)return e}if(typeof n.message==`string`){let e=/\bHTTP\s+(\d{3})\b/u.exec(n.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(t){let n=t,r=new Set;for(;n!=null&&!r.has(n);){if(r.add(n),yield n,!isObject(n)||!(`cause`in n))return;n=n.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 n={},r,getCallbackContext=()=>r??=buildCallbackContext(),i=await resolveConnectionAuthorization(e,typeof e.authorization==`function`?getCallbackContext():void 0);if(i!==void 0&&(n.Authorization=`Bearer ${(await resolveToken(e,i)).token}`),e.headers!==void 0){let t=await resolveHeadersDefinition(e.headers,getCallbackContext);for(let[r,a]of Object.entries(t)){if(i!==void 0&&r.toLowerCase()===`authorization`)throw Error(`Connection "${e.connectionName}" headers must not include an "Authorization" key when "authorization" is also provided.`);n[r]=a}}return 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{McpConnectionClient,isMcpAuthRequiredError,passesToolFilter,resolveHeaders};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{isLoopbackHostname}from"#shared/network-address.js";import{createLogger}from"#internal/logging.js";import{isObject}from"#shared/guards.js";import{toInputSchema}from"#tools/schema.js";import{tool}from"ai";import{omitProvidedArgumentsFromSchema,resolveProvidedArguments}from"#runtime/connections/provided-arguments.js";import{passesToolFilter,resolveHeaders}from"#runtime/connections/mcp-client.js";import{HTTP_METHODS,operationDescription,operationName,uniqueName}from"#runtime/connections/openapi-operations.js";import{buildInputSchema,deref,derefSchema,isArray}from"#runtime/connections/openapi-schema.js";import{applySecurity,resolveSecurity}from"#runtime/connections/openapi-security.js";import{extractServerUrl,parseSpecDocument}from"#runtime/connections/openapi-spec.js";const log=createLogger(`runtime.connections.openapi-client`),SWAGGER_PARAMETER_SCHEMA_KEYS=[`default`,`enum`,`exclusiveMaximum`,`exclusiveMinimum`,`format`,`items`,`maximum`,`maxItems`,`maxLength`,`minimum`,`minItems`,`minLength`,`multipleOf`,`pattern`,`type`,`uniqueItems`];var OpenApiConnectionClient=class{#e;#t;#n;constructor(e){this.#n=e}async connect(){return this.#r()}async getToolMetadata(){return(await this.#r()).metadata}async getTools(){return(await this.#r()).tools}async executeTool(e,t,r){let i=await this.#r(),a=i.operations.get(e);if(a===void 0)throw Error(`Tool "${e}" not found in connection "${this.#n.connectionName}".`);return this.#f(a,i.baseUrl,isObject(t)?t:{},{abortSignal:r.abortSignal,callId:r.callId})}async close(){this.#e=void 0,this.#t=void 0}async#r(){if(this.#t!==void 0)return this.#t;if(this.#e!==void 0)return this.#e;this.#e=this.#i();try{return this.#t=await this.#e,this.#t}catch(e){throw this.#e=void 0,e}}async#i(){let e=await this.#o(),t=this.#a(e),o=this.#s(e),c=this.#n.tools,l=c===void 0?o:o.filter(e=>passesToolFilter(e.toolName,c)),u=[],d=new Map,f={},p=Object.keys(this.#n.toolCall?.providedArguments??{});for(let e of l){let o=omitProvidedArgumentsFromSchema(e.inputSchema,p),s;try{s=toInputSchema(o)}catch(t){log.warn(`omitting OpenAPI operation with an invalid input schema`,{connectionName:this.#n.connectionName,error:t,toolName:e.toolName});continue}d.set(e.toolName,e),u.push({description:e.description,inputSchema:o,name:e.toolName}),f[e.toolName]=tool({description:e.description,inputSchema:s,execute:async(r,i)=>this.#f(e,t,isObject(r)?r:{},{abortSignal:i?.abortSignal,callId:i.toolCallId})})}return{metadata:u,operations:d,tools:f,baseUrl:t}}#a(e){let t=this.#n.url,n=typeof t==`string`&&t.trim().length>0?t:extractServerUrl(e,this.#n.spec);if(n===void 0)throw Error(`OpenAPI connection "${this.#n.connectionName}" has no base URL: set "baseUrl" or ensure the document declares an absolute "servers" entry or Swagger "host".`);return assertSecureUrl(n,this.#n.connectionName,`base`),n}async#o(){let e=this.#n.spec;if(e===void 0)throw Error(`OpenAPI connection "${this.#n.connectionName}" is missing its "spec" source.`);if(typeof e!=`string`)return e;assertSecureUrl(e,this.#n.connectionName,`spec`);let t;try{t=await fetch(e,{headers:{accept:`application/json, application/yaml, text/yaml, */*`}})}catch(t){throw Error(`OpenAPI connection "${this.#n.connectionName}" failed to fetch its spec from "${e}": ${String(t)}`)}if(t.redirected&&assertSecureUrl(t.url,this.#n.connectionName,`spec`),!t.ok)throw Error(`OpenAPI connection "${this.#n.connectionName}" failed to fetch its spec from "${e}": HTTP ${t.status}.`);let r=await t.text(),i;try{i=parseSpecDocument(r)}catch(t){throw Error(`OpenAPI connection "${this.#n.connectionName}" spec at "${e}" could not be parsed as JSON or YAML: ${String(t)}`)}if(!isObject(i))throw Error(`OpenAPI connection "${this.#n.connectionName}" spec at "${e}" is not an OpenAPI document object.`);return i}#s(e){let t=e.paths;if(!isObject(t))return[];let r=[],i=new Set;for(let[a,o]of Object.entries(t)){if(!isObject(o))continue;let t=isArray(o.parameters)?o.parameters:[];for(let s of HTTP_METHODS){let c=o[s];if(!isObject(c))continue;let l=uniqueName(operationName(c,s,a),i),m=isArray(c.parameters)?c.parameters:[],h=[...t,...m],g=this.#c(e,h),_=this.#l(e,c.requestBody,h);r.push({toolName:l,method:s,pathTemplate:a,description:operationDescription(c),parameters:g,requestBody:_,inputSchema:buildInputSchema(g,_),security:resolveSecurity(e,c)})}}return r}#c(e,t){let r=[];for(let i of t){let t=isObject(i)?deref(e,i):i;if(!isObject(t))continue;let a=t.in;if(a!==`path`&&a!==`query`&&a!==`header`&&a!==`cookie`||typeof t.name!=`string`)continue;let o=this.#u(e,t);r.push({name:t.name,location:a,required:t.required===!0||a===`path`,schema:o,description:typeof t.description==`string`?t.description:void 0})}return r}#l(e,t,r=[]){if(isObject(t)){let r=deref(e,t);if(isObject(r)&&isObject(r.content)){let t=r.content,i=`application/json`in t?`application/json`:Object.keys(t)[0];if(i!==void 0){let a=t[i],o=isObject(a)&&isObject(a.schema)?derefSchema(e,a.schema):{};return{required:r.required===!0,contentType:i,schema:o}}}}return this.#d(e,r)}#u(e,t){if(isObject(t.schema))return derefSchema(e,t.schema);let r={};for(let e of SWAGGER_PARAMETER_SCHEMA_KEYS)t[e]!==void 0&&(r[e]=t[e]);return derefSchema(e,r)}#d(e,t){for(let r of t){let t=isObject(r)?deref(e,r):r;if(!isObject(t)||t.in!==`body`)continue;let i=isObject(t.schema)?derefSchema(e,t.schema):{};return{required:t.required===!0,contentType:`application/json`,schema:i}}}async#f(e,t,n,r){let i=await resolveProvidedArguments({args:n,callId:r.callId,connection:this.#n,toolName:e.toolName}),a=await resolveHeaders(this.#n),s=e.pathTemplate,l=new URLSearchParams,u=[];for(let t of e.parameters){let e=i[t.name];e!=null&&(t.location===`path`?s=s.replace(`{${t.name}}`,encodeURIComponent(String(e))):t.location===`query`?appendQuery(l,t.name,e):t.location===`cookie`?u.push(`${t.name}=${encodeURIComponent(String(e))}`):a[t.name]=String(e))}if(applySecurity(e.security,this.#n,a,l,u),u.length>0){let e=a.cookie??a.Cookie;delete a.Cookie,a.cookie=[e,...u].filter(e=>!!e).join(`; `)}let d=new URL(joinPath(t,s));d.search=l.toString();let f;e.requestBody!==void 0&&i.body!==void 0&&(f=JSON.stringify(i.body),a[`content-type`]=e.requestBody.contentType);let p=await fetch(d,{method:e.method.toUpperCase(),headers:a,body:f,signal:r?.abortSignal});return{status:p.status,statusText:p.statusText,body:await readResponseBody(p)}}};function appendQuery(e,t,n){if(isArray(n)){for(let r of n)e.append(t,String(r));return}e.append(t,String(n))}function joinPath(e,t){return`${e.endsWith(`/`)?e.slice(0,-1):e}${t.startsWith(`/`)?t:`/${t}`}`}function assertSecureUrl(t,n,r){let i;try{i=new URL(t)}catch{throw Error(`OpenAPI connection "${n}" has an invalid ${r} URL "${t}".`)}if(i.protocol!==`https:`&&!(i.protocol===`http:`&&isLoopbackHostname(i.hostname)))throw Error(`OpenAPI connection "${n}" must use https for its ${r} (got "${i.protocol}//${i.host}").`)}async function readResponseBody(e){let t=await e.text();if(t.length===0)return null;if((e.headers.get(`content-type`)??``).includes(`application/json`))try{return JSON.parse(t)}catch{return t}return t}export{OpenApiConnectionClient};
|
|
@@ -12,6 +12,8 @@ import type { ConnectionRegistry } from "#runtime/connections/registry-types.js"
|
|
|
12
12
|
export declare class ConnectionRegistryImpl implements ConnectionRegistry {
|
|
13
13
|
#private;
|
|
14
14
|
constructor(connections: readonly ResolvedConnectionDefinition[]);
|
|
15
|
+
/** Replaces one complete dynamic scope and closes clients whose definition changed. */
|
|
16
|
+
replaceDynamicConnections(scope: "session" | "turn", connectionsByResolver: ReadonlyMap<string, readonly ResolvedConnectionDefinition[]>): Promise<void>;
|
|
15
17
|
/**
|
|
16
18
|
* Returns the client for the named connection, creating it on first
|
|
17
19
|
* access. The connection's `protocol` selects the client type.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{McpConnectionClient}from"#runtime/connections/mcp-client.js";import{OpenApiConnectionClient}from"#runtime/connections/openapi-client.js";var ConnectionRegistryImpl=class{#e=new Map;#t;constructor(e){this.#t=e}getClient(n){let r=this.#e.get(n);if(r!==void 0)return r;let i=this.#t.find(e=>e.connectionName===n);if(i===void 0)throw Error(`Connection "${n}" is not registered.`);let a=i.protocol===`openapi`?new OpenApiConnectionClient(i):new McpConnectionClient(i);return this.#e.set(n,a),a}getConnectionApproval(e){return this.#t.find(t=>t.connectionName===e)?.approval}getConnectionNames(){return this.#t.map(e=>e.connectionName)}getConnections(){return this.#t}async dispose(){let e=[...this.#e.values()].map(e=>e.close());await Promise.allSettled(e),this.#e.clear()}};export{ConnectionRegistryImpl};
|
|
1
|
+
import{McpConnectionClient}from"#runtime/connections/mcp-client.js";import{OpenApiConnectionClient}from"#runtime/connections/openapi-client.js";var ConnectionRegistryImpl=class{#e=new Map;#t;#n;#r=new Map;#i=new Map;constructor(e){this.#n=e,this.#t=e}async replaceDynamicConnections(e,t){let n=e===`session`?new Map(t):this.#r,r=e===`turn`?new Map(t):this.#i,i=this.#a(n,r),a=new Map(this.#t.map(e=>[e.connectionName,e])),o=new Map(i.map(e=>[e.connectionName,e])),s=[];for(let[e,t]of this.#e)a.get(e)!==o.get(e)&&(this.#e.delete(e),s.push(t));this.#r=n,this.#i=r,this.#t=i,await Promise.allSettled(s.map(e=>e.close()))}#a(e,t){let n=new Map(e);for(let[e,r]of t)n.set(e,r);let r=new Map,i=new Map(this.#n.map(e=>[e.connectionName,e]));for(let[e,t]of n)for(let n of t){let t=r.get(n.connectionName);if(t!==void 0&&t!==e)throw Error(`Dynamic connection "${n.connectionName}" from resolver "${e}" collides with dynamic resolver "${t}". Namespace the map key manually.`);r.set(n.connectionName,e),i.set(n.connectionName,n)}return[...i.values()]}getClient(n){let r=this.#e.get(n);if(r!==void 0)return r;let i=this.#t.find(e=>e.connectionName===n);if(i===void 0)throw Error(`Connection "${n}" is not registered.`);let a=i.protocol===`openapi`?new OpenApiConnectionClient(i):new McpConnectionClient(i);return this.#e.set(n,a),a}getConnectionApproval(e){return this.#t.find(t=>t.connectionName===e)?.approval}getConnectionNames(){return this.#t.map(e=>e.connectionName)}getConnections(){return this.#t}async dispose(){let e=[...this.#e.values()].map(e=>e.close());await Promise.allSettled(e),this.#e.clear()}};export{ConnectionRegistryImpl};
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Scope-parameterized authorization flow shared by MCP connections and
|
|
3
3
|
* authored tools that declare `auth`.
|
|
4
4
|
*
|
|
5
|
-
* A *scope*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* A *scope* names the framework-owned callback URL — a connection name for
|
|
6
|
+
* an MCP connection, a tool name for tool-hosted auth. Connection-hosted
|
|
7
|
+
* authorization also carries an opaque instance ID that keys its token cache
|
|
8
|
+
* and pins callback completion to the exact resolved connection. Everything else
|
|
8
9
|
* (principal resolution, the park/resume webhook dance, the loop guard)
|
|
9
10
|
* is identical across both, so it lives here once instead of being
|
|
10
11
|
* duplicated per caller.
|
|
@@ -21,6 +22,8 @@ import { type AuthorizationDefinition, type ConnectionAuthorizationContext, type
|
|
|
21
22
|
*/
|
|
22
23
|
export interface ScopedAuthorization {
|
|
23
24
|
readonly boundResponder?: SessionAuthContext;
|
|
25
|
+
/** Opaque resolved instance identity for connection-hosted authorization. */
|
|
26
|
+
readonly instanceId?: string;
|
|
24
27
|
readonly scope: string;
|
|
25
28
|
readonly authorization: Readonly<AuthorizationDefinition>;
|
|
26
29
|
readonly connection: ConnectionAuthorizationContext;
|
|
@@ -29,9 +32,10 @@ export interface ScopedAuthorization {
|
|
|
29
32
|
* Resolves a bearer token for one scope, consulting the per-step token
|
|
30
33
|
* cache before invoking the authored `getToken`.
|
|
31
34
|
*
|
|
32
|
-
* The cache is keyed by `(scope, principalKey(principal))` so
|
|
33
|
-
* users
|
|
34
|
-
* runtime scope the cache is unavailable, but
|
|
35
|
+
* The cache is keyed by `(instanceId ?? scope, principalKey(principal))` so
|
|
36
|
+
* concurrent users and resolved connection instances never alias onto each
|
|
37
|
+
* other's bearer. Outside a runtime scope the cache is unavailable, but
|
|
38
|
+
* `getToken` still runs with
|
|
35
39
|
* a framework-resolved principal so ad-hoc `"app"`-scoped use keeps
|
|
36
40
|
* working; `"user"`-scoped strategies without a context fail fast inside
|
|
37
41
|
* {@link resolveConnectionPrincipal}.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{contextStorage,loadContext}from"#context/container.js";import{consumeAuthorizationResult,createAuthorizationAttempt,requestAuthorization}from"#harness/authorization.js";import{supportsInteractiveAuthorization}from"#shared/connection-types.js";import{evictCachedToken,readCachedToken,writeCachedToken}from"#runtime/connections/authorization-tokens.js";import{principalKey,resolveConnectionPrincipal,resolveConnectionPrincipalFromAuth}from"#runtime/connections/principal.js";const LOCAL_HTTP_VERCEL_CONNECT_HOSTNAMES=new Set([`127.0.0.1`,`[::1]`]);async function resolveScopedToken(t){let{scope:n,authorization:r,connection:i}=t,a=contextStorage.getStore(),
|
|
1
|
+
import{contextStorage,loadContext}from"#context/container.js";import{consumeAuthorizationResult,createAuthorizationAttempt,requestAuthorization}from"#harness/authorization.js";import{supportsInteractiveAuthorization}from"#shared/connection-types.js";import{evictCachedToken,readCachedToken,writeCachedToken}from"#runtime/connections/authorization-tokens.js";import{principalKey,resolveConnectionPrincipal,resolveConnectionPrincipalFromAuth}from"#runtime/connections/principal.js";const LOCAL_HTTP_VERCEL_CONNECT_HOSTNAMES=new Set([`127.0.0.1`,`[::1]`]);async function resolveScopedToken(t){let{scope:n,authorization:r,connection:i}=t,a=t.instanceId??n,o=contextStorage.getStore(),u=resolveScopedPrincipal(t,o);if(o===void 0)return await r.getToken({connection:i,principal:u});let d=principalKey(u),f=readCachedToken(o,a,d);if(f!==void 0)return f;let p=await r.getToken({connection:i,principal:u});return writeCachedToken(o,a,d,p),p}async function evictScopedToken(t){let{scope:n,authorization:r,connection:i}=t,a=t.instanceId??n,s=contextStorage.getStore();if(s===void 0)return;let c;try{c=resolveScopedPrincipal(t,s),evictCachedToken(s,a,principalKey(c))}catch{return}try{await r.evict?.({connection:i,principal:c})}catch{}}async function completeScopedAuthorization(e){let{scope:r,authorization:i,connection:o}=e;if(!supportsInteractiveAuthorization(i))return!1;let s=consumeAuthorizationResult(r,e.instanceId);if(s===void 0)return!1;let u=i,d=loadContext(),f=s.principal??resolveScopedPrincipal(e,d),p=await u.completeAuthorization({callbackUrl:s.hookUrl,connection:o,principal:f,resume:s.resume,callback:s.callback});return writeCachedToken(d,e.instanceId??r,principalKey(f),p),!0}async function startScopedAuthorization(e){let{scope:t,authorization:n,connection:o}=e;if(!supportsInteractiveAuthorization(n))return;let s=createAuthorizationAttempt(t);if(s===void 0)return;let c=n,l=resolveScopedPrincipal(e),u=resolveAuthorizationCallbackUrl({authorization:n,callbackUrl:s.hookUrl}),{challenge:d,resume:f}=await c.startAuthorization({callbackUrl:u,connection:o,principal:l});return requestAuthorization([{attemptId:s.attemptId,challenge:stampChallengeDisplayName(d,n),hookUrl:u,instanceId:e.instanceId,name:t,principal:l,resume:f}])}function resolveScopedPrincipal(e,t){return e.boundResponder===void 0?resolveConnectionPrincipal(e.scope,e.authorization,t):resolveConnectionPrincipalFromAuth(e.scope,e.authorization,e.boundResponder,t)}function resolveAuthorizationCallbackUrl(e){if(e.authorization.vercelConnect===void 0)return e.callbackUrl;let t;try{t=new URL(e.callbackUrl)}catch{return e.callbackUrl}return t.protocol!==`http:`||!LOCAL_HTTP_VERCEL_CONNECT_HOSTNAMES.has(t.hostname)?e.callbackUrl:(t.hostname=`localhost`,t.toString())}function stampChallengeDisplayName(e,t){let n=t.displayName??e.displayName;return n===e.displayName?e:{...e,displayName:n}}export{completeScopedAuthorization,evictScopedToken,resolveAuthorizationCallbackUrl,resolveScopedToken,stampChallengeDisplayName,startScopedAuthorization};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ResolveAgentError,createResolvedModuleSourceRef}from"#runtime/resolve-helpers.js";import{resolveChannelDefinition}from"#runtime/resolve-channel.js";import{
|
|
1
|
+
import{resolveConnectionDefinition}from"#runtime/resolve-connection.js";import{ResolveAgentError,createResolvedModuleSourceRef}from"#runtime/resolve-helpers.js";import{resolveChannelDefinition}from"#runtime/resolve-channel.js";import{resolveDynamicConnectionDefinition}from"#runtime/resolve-dynamic-connection.js";import{resolveHookDefinition}from"#runtime/resolve-hook.js";import{resolveSandboxDefinition}from"#runtime/resolve-sandbox.js";import{resolveDynamicInstructionsDefinition}from"#runtime/resolve-dynamic-instructions.js";import{resolveDynamicSkillDefinition}from"#runtime/resolve-dynamic-skill.js";import{resolveDynamicToolDefinition}from"#runtime/resolve-dynamic-tool.js";import{resolveToolDefinition}from"#runtime/resolve-tool.js";import{resolveMemoryDefinition}from"#runtime/resolve-memory.js";async function resolveAgent(t){let n=t.manifest.skills.map(e=>({...e,owner:requireCompiledSourceOwner(t.manifest,e),metadata:e.metadata===void 0?void 0:{...e.metadata}})),i=await Promise.all(t.manifest.channelRoutes.effective.map(e=>resolveChannelDefinition(e,t.moduleMap,t.nodeId))),a=await Promise.all(t.manifest.tools.map(e=>resolveToolDefinition(e,t.moduleMap,t.nodeId,requireBindingOwner(t.manifest,e.sourceId)))),o=await Promise.all(t.manifest.dynamicConnections.map(e=>resolveDynamicConnectionDefinition(e,t.moduleMap,t.nodeId))),s=await Promise.all((t.manifest.dynamicInstructions??[]).map(e=>resolveDynamicInstructionsDefinition(e,t.moduleMap,t.nodeId))),c=await Promise.all((t.manifest.dynamicSkills??[]).map(e=>resolveDynamicSkillDefinition(e,t.moduleMap,t.nodeId))),l=await Promise.all(t.manifest.dynamicTools.map(e=>resolveDynamicToolDefinition(e,t.moduleMap,t.nodeId))),u=await Promise.all(t.manifest.hooks.map(e=>resolveHookDefinition(e,t.moduleMap,t.nodeId))),d=await Promise.all(t.manifest.connections.map(n=>resolveConnectionDefinition(n,t.moduleMap,t.nodeId))),f=await Promise.all(t.manifest.memories.map(e=>resolveMemoryDefinition(e,t.moduleMap,t.nodeId))),p=await resolveSandboxDefinition(t.manifest.sandbox,t.moduleMap,t.nodeId),m=t.manifest.instructions.map(e=>createResolvedInstructionsDefinition(t.manifest,e)),h=t.manifest.workspaceResourceRoot,g={channels:i,connections:d,dynamicConnectionResolvers:o,workflowTool:t.manifest.workflowTool===void 0?void 0:{maxSubagents:t.manifest.workflowTool.maxSubagents},webSearchProvider:t.manifest.webSearchProvider,dynamicInstructionsResolvers:s,dynamicSkillResolvers:c,dynamicToolResolvers:l,hooks:u,instructions:m,metadata:{agentRoot:t.manifest.agentRoot,appRoot:t.manifest.appRoot,diagnosticsSummary:t.manifest.diagnosticsSummary},memories:f,sandbox:p,workspaceResourceRoot:h,skills:n,tools:a,workspaceSpec:{rootEntries:[...h.rootEntries]}};return`config`in t.manifest?{...g,config:createResolvedAgentConfig(t.manifest)}:g}function requireBindingOwner(e,t){let n=e.bindings[t];if(n===void 0)throw Error(`Compiled source "${t}" has no binding.`);return n.owner}function createResolvedInstructionsDefinition(e,t){return{content:t.content,name:t.name,owner:requireCompiledSourceOwner(e,t),logicalPath:t.logicalPath,role:t.role,sourceId:t.sourceId,sourceKind:t.sourceKind}}function requireCompiledSourceOwner(e,t){let n=e.bindings[t.sourceId]?.owner??t.owner;if(n===void 0)throw Error(`Compiled source "${t.sourceId}" has no owner.`);return n}function createResolvedAgentConfig(e){let t={name:e.config.name};if(e.config.compaction!==void 0){let n={};e.config.compaction.model!==void 0&&(n.model=e.config.compaction.model.source===void 0?{contextWindowTokens:e.config.compaction.model.contextWindowTokens,id:e.config.compaction.model.id,maxOutputTokens:e.config.compaction.model.maxOutputTokens,providerOptions:e.config.compaction.model.providerOptions}:{contextWindowTokens:e.config.compaction.model.contextWindowTokens,id:e.config.compaction.model.id,maxOutputTokens:e.config.compaction.model.maxOutputTokens,providerOptions:e.config.compaction.model.providerOptions,source:{exportName:e.config.compaction.model.source.exportName,sourceKind:`module`,logicalPath:e.config.compaction.model.source.logicalPath,sourceId:e.config.compaction.model.source.sourceId}}),e.config.compaction.thresholdPercent!==void 0&&(n.thresholdPercent=e.config.compaction.thresholdPercent),t.compaction=n}if(e.config.experimental!==void 0&&(t.experimental={instrumentationProviders:e.config.experimental.instrumentationProviders,tasks:e.config.experimental.tasks,workflow:e.config.experimental.workflow===void 0?void 0:{world:e.config.experimental.workflow.world}}),e.config.outputSchema!==void 0&&(t.outputSchema=e.config.outputSchema),e.config.reasoning!==void 0&&(t.reasoning=e.config.reasoning),e.config.source!==void 0&&(t.source=createResolvedModuleSourceRef(e.config.source)),e.config.limits!==void 0&&(t.limits={maxInputTokensPerSession:e.config.limits.maxInputTokensPerSession,maxOutputTokensPerSession:e.config.limits.maxOutputTokensPerSession,sessionTimeoutMs:e.config.limits.sessionTimeoutMs}),e.config.dynamicModel!==void 0)return{...t,dynamicModel:{...createResolvedModuleSourceRef(e.config.dynamicModel),eventNames:[...e.config.dynamicModel.eventNames]}};let r=e.config.model;return{...t,model:r.source===void 0?{id:r.id,contextWindowTokens:r.contextWindowTokens,maxOutputTokens:r.maxOutputTokens,providerOptions:r.providerOptions}:{contextWindowTokens:r.contextWindowTokens,id:r.id,maxOutputTokens:r.maxOutputTokens,providerOptions:r.providerOptions,source:{exportName:r.source.exportName,sourceKind:`module`,logicalPath:r.source.logicalPath,sourceId:r.source.sourceId}}}}export{ResolveAgentError,resolveAgent};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CompiledConnectionDefinition } from "#compiler/manifest.js";
|
|
2
2
|
import type { CompiledModuleMap } from "#compiler/module-map.js";
|
|
3
3
|
import type { ResolvedConnectionDefinition } from "#runtime/types.js";
|
|
4
|
+
import type { ModuleSourceRef } from "#shared/source-ref.js";
|
|
4
5
|
/**
|
|
5
6
|
* Resolves one compiled connection entry into a runtime-owned definition
|
|
6
7
|
* with the live `auth`, `headers`, and `tools` objects attached
|
|
@@ -13,3 +14,7 @@ import type { ResolvedConnectionDefinition } from "#runtime/types.js";
|
|
|
13
14
|
* variables, `AlsContext`, etc.).
|
|
14
15
|
*/
|
|
15
16
|
export declare function resolveConnectionDefinition(definition: CompiledConnectionDefinition, moduleMap: CompiledModuleMap, nodeId: string | undefined): Promise<ResolvedConnectionDefinition>;
|
|
17
|
+
/** Resolves one branded connection returned by a dynamic connection handler. */
|
|
18
|
+
export declare function resolveDynamicConnectionValue(value: unknown, source: Readonly<ModuleSourceRef & {
|
|
19
|
+
readonly connectionName: string;
|
|
20
|
+
}>): ResolvedConnectionDefinition;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{expectObjectRecord}from"#internal/authored-module.js";import{toErrorMessage}from"#shared/errors.js";import{registerDefinitionSource,stampDefinitionKey}from"#internal/authored-definition/source-identity.js";import{normalizeAuthorizationSpec}from"#shared/validate-authorization.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";async function resolveConnectionDefinition(
|
|
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,stampDefinitionKey}from"#internal/authored-definition/source-identity.js";import{normalizeAuthorizationSpec}from"#shared/validate-authorization.js";import{createConnectionInstanceId}from"#runtime/connections/instance-identity.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";async function resolveConnectionDefinition(n,r,i){try{let c=expectObjectRecord(await loadResolvedModuleExport({definition:n,kindLabel:`connection`,moduleMap:r,nodeId:i}),`Expected the connection export "${n.exportName??`default`}" from "${n.logicalPath}" to return an object.`),l={kind:`connection`,logicalPath:n.logicalPath,name:n.connectionName},u=`connection-source:${n.sourceId}`;stampDefinitionKey(c,u),registerDefinitionSource(u,l),registerDefinitionSource(`connection:${n.url}`,l);let d=c.auth!==void 0,f=c.headers!==void 0,p=n.protocol===`openapi`?c.operations:c.tools,m={connectionName:n.connectionName,description:n.description,exportName:n.exportName,logicalPath:n.logicalPath,instanceId:createConnectionInstanceId({connectionName:n.connectionName,instanceKey:typeof c.instanceKey==`string`?c.instanceKey:void 0,protocol:n.protocol,sourceId:n.sourceId,url:n.url}),protocol:n.protocol,sourceId:n.sourceId,sourceKind:`module`,url:n.url};if(d)if(typeof c.auth==`function`)m.authorization=c.auth;else try{m.authorization=normalizeAuthorizationSpec(c.auth,`Connection "${n.connectionName}" at "${n.logicalPath}":`)}catch(e){throw new ResolveAgentError(toErrorMessage(e),{logicalPath:n.logicalPath,sourceId:n.sourceId})}return f&&(m.headers=c.headers),c.toolCall!==void 0&&(m.toolCall=c.toolCall),p!==void 0&&(m.tools=p),n.protocol===`openapi`&&c.spec!==void 0&&(m.spec=c.spec),typeof c.approval==`function`&&(m.approval=c.approval),m}catch(e){throw e instanceof ResolveAgentError?e:new ResolveAgentError(`Failed to resolve connection "${n.connectionName}" from "${n.logicalPath}": ${toErrorMessage(e)}`,{logicalPath:n.logicalPath,sourceId:n.sourceId})}}function resolveDynamicConnectionValue(e,t){let a=readStampedConnectionProtocol(e),o=`Dynamic connection "${t.connectionName}" from "${t.logicalPath}" must be created by defineMcpClientConnection() or defineOpenAPIConnection().`;if(a===void 0)throw Error(o);let s={kind:`connection`,logicalPath:t.logicalPath,name:t.connectionName},c=`dynamic-connection-source:${t.sourceId}:${t.connectionName}`;if(stampDefinitionKey(e,c),registerDefinitionSource(c,s),a===`openapi`){let n=normalizeOpenApiConnectionDefinition(e,o);return assertAuthenticatedDynamicInstanceKey(n.auth,n.instanceKey,o),omitUndefined({approval:n.approval,authorization:n.auth,connectionName:t.connectionName,description:n.description,exportName:t.exportName,headers:n.headers,instanceId:createConnectionInstanceId({connectionName:t.connectionName,instanceKey:n.instanceKey,protocol:a,sourceId:t.sourceId,url:n.baseUrl??``}),logicalPath:t.logicalPath,protocol:a,sourceId:t.sourceId,sourceKind:`module`,spec:n.spec,toolCall:n.toolCall,tools:n.operations,url:n.baseUrl??``})}let l=normalizeMcpClientConnectionDefinition(e,o);return assertAuthenticatedDynamicInstanceKey(l.auth,l.instanceKey,o),omitUndefined({approval:l.approval,authorization:l.auth,connectionName:t.connectionName,description:l.description,exportName:t.exportName,headers:l.headers,instanceId:createConnectionInstanceId({connectionName:t.connectionName,instanceKey:l.instanceKey,protocol:a,sourceId:t.sourceId,url:l.url}),logicalPath:t.logicalPath,protocol:a,sourceId:t.sourceId,sourceKind:`module`,toolCall:l.toolCall,tools:l.tools,url:l.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};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CompiledDynamicConnectionDefinition } from "#compiler/manifest.js";
|
|
2
|
+
import type { CompiledModuleMap } from "#compiler/module-map.js";
|
|
3
|
+
import type { ResolvedDynamicConnectionResolver } from "#runtime/types.js";
|
|
4
|
+
/** Reattaches live event handlers for one compiled dynamic connection source. */
|
|
5
|
+
export declare function resolveDynamicConnectionDefinition(definition: CompiledDynamicConnectionDefinition, moduleMap: CompiledModuleMap, nodeId: string | undefined): Promise<ResolvedDynamicConnectionResolver>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{expectFunction,expectObjectRecord}from"#internal/authored-module.js";import{toErrorMessage}from"#shared/errors.js";import{isDynamicSentinel}from"#dynamic/definition.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";async function resolveDynamicConnectionDefinition(i,a,o){try{let n=expectObjectRecord(await loadResolvedModuleExport({definition:i,kindLabel:`dynamic connection`,moduleMap:a,nodeId:o}),describe(i,`to return an object`));if(!isDynamicSentinel(n))throw Error(describe(i,`to be created by defineDynamic()`));let r=expectObjectRecord(n.events,describe(i,`to provide an events object`)),s={};for(let t of i.eventNames)s[t]=expectFunction(r[t],describe(i,`to provide a handler for event "${t}"`));return{eventNames:[...i.eventNames],events:s,exportName:i.exportName,extensionNamespace:i.extensionNamespace,logicalPath:i.logicalPath,slug:i.slug,sourceId:i.sourceId,sourceKind:`module`}}catch(e){throw e instanceof ResolveAgentError?e:new ResolveAgentError(`Failed to resolve dynamic connection from "${i.logicalPath}": ${toErrorMessage(e)}`,{logicalPath:i.logicalPath,sourceId:i.sourceId})}}function describe(e,t){return`Expected the dynamic connection export "${e.exportName??`default`}" from "${e.logicalPath}" ${t}.`}export{resolveDynamicConnectionDefinition};
|