eve 0.48.0 → 0.49.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/dist/src/channel/channel-address.js +1 -1
- package/dist/src/channel/types.d.ts +10 -0
- package/dist/src/cli/commands/integration-setup.d.ts +1 -0
- package/dist/src/cli/commands/integration-setup.js +1 -1
- package/dist/src/cli/commands/register-integration-commands.d.ts +1 -1
- package/dist/src/cli/commands/register-integration-commands.js +1 -1
- package/dist/src/cli/commands/registry-declared-setups.d.ts +1 -0
- package/dist/src/cli/commands/registry-declared-setups.js +1 -1
- package/dist/src/cli/commands/registry-metadata.d.ts +30 -0
- package/dist/src/cli/commands/registry-metadata.js +1 -1
- package/dist/src/cli/commands/registry-package.d.ts +6 -0
- package/dist/src/cli/commands/registry-package.js +1 -1
- package/dist/src/cli/commands/registry-pnpm-build-policy-flow.d.ts +30 -0
- package/dist/src/cli/commands/registry-pnpm-build-policy-flow.js +1 -0
- package/dist/src/cli/commands/registry-pnpm-build-policy.d.ts +12 -0
- package/dist/src/cli/commands/registry-pnpm-build-policy.js +6 -0
- package/dist/src/cli/commands/registry-recovery.d.ts +4 -0
- package/dist/src/cli/commands/registry-recovery.js +1 -1
- package/dist/src/cli/commands/registry.d.ts +1 -1
- package/dist/src/cli/commands/registry.js +1 -1
- package/dist/src/cli/dev/tui/setup-commands.js +2 -2
- package/dist/src/compiled/.vendor-stamp.json +7 -7
- package/dist/src/compiled/@workflow/core/attribute-changes.d.ts +2 -4
- package/dist/src/compiled/@workflow/core/capabilities.d.ts +10 -9
- package/dist/src/compiled/@workflow/core/capture-stack.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/class-serialization.d.ts +8 -8
- package/dist/src/compiled/@workflow/core/context-violation-error.d.ts +5 -5
- package/dist/src/compiled/@workflow/core/create-hook.d.ts +2 -2
- package/dist/src/compiled/@workflow/core/describe-error.d.ts +7 -7
- package/dist/src/compiled/@workflow/core/encryption.d.ts +5 -5
- package/dist/src/compiled/@workflow/core/events-consumer.d.ts +49 -14
- package/dist/src/compiled/@workflow/core/flushable-stream.d.ts +4 -4
- package/dist/src/compiled/@workflow/core/global.d.ts +4 -2
- package/dist/src/compiled/@workflow/core/index.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/index.js +2 -2
- package/dist/src/compiled/@workflow/core/log-format.d.ts +2 -2
- package/dist/src/compiled/@workflow/core/private.d.ts +40 -78
- package/dist/src/compiled/@workflow/core/private.js +1 -1
- package/dist/src/compiled/@workflow/core/replay-payload-cache.d.ts +13 -17
- package/dist/src/compiled/@workflow/core/runtime/compute-instance.d.ts +4 -3
- package/dist/src/compiled/@workflow/core/runtime/constants.d.ts +27 -27
- package/dist/src/compiled/@workflow/core/runtime/count-step-started-events.d.ts +7 -7
- package/dist/src/compiled/@workflow/core/runtime/deployment-guard.d.ts +7 -7
- package/dist/src/compiled/@workflow/core/runtime/get-port-lazy.d.ts +2 -2
- package/dist/src/compiled/@workflow/core/runtime/get-world-lazy.d.ts +2 -2
- package/dist/src/compiled/@workflow/core/runtime/helpers.d.ts +30 -49
- package/dist/src/compiled/@workflow/core/runtime/quickjs-entrypoint.d.ts +21 -10
- package/dist/src/compiled/@workflow/core/runtime/quickjs-runtime.d.ts +31 -15
- package/dist/src/compiled/@workflow/core/runtime/quickjs-serde.d.ts +10 -10
- package/dist/src/compiled/@workflow/core/runtime/replay-budget.d.ts +4 -4
- package/dist/src/compiled/@workflow/core/runtime/replay-recovery-reporter.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/runtime/resume-hook.d.ts +20 -12
- package/dist/src/compiled/@workflow/core/runtime/resume-latency.d.ts +37 -30
- package/dist/src/compiled/@workflow/core/runtime/run-id-time.d.ts +2 -2
- package/dist/src/compiled/@workflow/core/runtime/run.d.ts +22 -5
- package/dist/src/compiled/@workflow/core/runtime/runs.d.ts +4 -4
- package/dist/src/compiled/@workflow/core/runtime/start.d.ts +3 -3
- package/dist/src/compiled/@workflow/core/runtime/step-executor.d.ts +14 -14
- package/dist/src/compiled/@workflow/core/runtime/step-latency.d.ts +42 -25
- package/dist/src/compiled/@workflow/core/runtime/step-ownership.d.ts +6 -6
- package/dist/src/compiled/@workflow/core/runtime/step-single-flight.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/runtime/suspension-handler.d.ts +38 -24
- package/dist/src/compiled/@workflow/core/runtime/unserializable-step.d.ts +34 -0
- package/dist/src/compiled/@workflow/core/runtime/vm-mode.d.ts +2 -2
- package/dist/src/compiled/@workflow/core/runtime/wait-continuation.d.ts +31 -9
- package/dist/src/compiled/@workflow/core/runtime/wait-until.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/runtime/world-compatibility.d.ts +20 -9
- package/dist/src/compiled/@workflow/core/runtime/world-init.d.ts +5 -5
- package/dist/src/compiled/@workflow/core/runtime.js +3 -3
- package/dist/src/compiled/@workflow/core/sealed-box.d.ts +7 -7
- package/dist/src/compiled/@workflow/core/serialization/codec-devalue-vm.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/serialization/codec-devalue.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/serialization/codec.d.ts +4 -4
- package/dist/src/compiled/@workflow/core/serialization/compression.d.ts +12 -11
- package/dist/src/compiled/@workflow/core/serialization/encryption.d.ts +7 -7
- package/dist/src/compiled/@workflow/core/serialization/format.d.ts +6 -6
- package/dist/src/compiled/@workflow/core/serialization/hardened.d.ts +23 -22
- package/dist/src/compiled/@workflow/core/serialization/index.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/serialization/reducers/class-vm.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/serialization/reducers/step-function-vm.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/serialization/types.d.ts +5 -5
- package/dist/src/compiled/@workflow/core/serialization/workflow-vm.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/serialization-format.d.ts +11 -11
- package/dist/src/compiled/@workflow/core/serialization.d.ts +18 -19
- package/dist/src/compiled/@workflow/core/source-map.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/step/context-storage.d.ts +5 -5
- package/dist/src/compiled/@workflow/core/step/writable-stream.d.ts +3 -3
- package/dist/src/compiled/@workflow/core/symbols.d.ts +2 -2
- package/dist/src/compiled/@workflow/core/telemetry/semantic-conventions.d.ts +71 -20
- package/dist/src/compiled/@workflow/core/telemetry.d.ts +15 -3
- package/dist/src/compiled/@workflow/core/version.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/vm/script-cache.d.ts +9 -11
- package/dist/src/compiled/@workflow/core/workflow/abort-controller.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/workflow/set-attributes.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/workflow/world-init-stub.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/workflow.js +1 -1
- package/dist/src/compiled/@workflow/errors/index.d.ts +18 -18
- package/dist/src/compiled/@workflow/errors/index.js +1 -1
- package/dist/src/compiled/@workflow/world/analytics.d.ts +3 -2
- package/dist/src/compiled/@workflow/world/attributes-validation.d.ts +28 -0
- package/dist/src/compiled/@workflow/world/attributes.d.ts +8 -107
- package/dist/src/compiled/@workflow/world/env-config.d.ts +5 -5
- package/dist/src/compiled/@workflow/world/event-metadata.d.ts +132 -0
- package/dist/src/compiled/@workflow/world/events.d.ts +42 -96
- package/dist/src/compiled/@workflow/world/hooks.d.ts +12 -11
- package/dist/src/compiled/@workflow/world/index.d.ts +3 -3
- package/dist/src/compiled/@workflow/world/interfaces.d.ts +94 -39
- package/dist/src/compiled/@workflow/world/queue.d.ts +29 -22
- package/dist/src/compiled/@workflow/world/runs.d.ts +20 -0
- package/dist/src/compiled/@workflow/world/slot-identity.d.ts +3 -3
- package/dist/src/compiled/@workflow/world/spec-version.d.ts +82 -15
- package/dist/src/compiled/@workflow/world/ulid.d.ts +2 -2
- package/dist/src/compiled/@workflow/world-local/index.js +5 -5
- package/dist/src/compiled/@workflow/world-vercel/index.js +12 -12
- package/dist/src/compiled/_chunks/workflow/{attribute-changes-DXbpwBdw.js → attribute-changes-BwAadFfB.js} +3 -3
- package/dist/src/compiled/_chunks/workflow/debug-log-CVPstO1D.js +1 -0
- package/dist/src/compiled/_chunks/workflow/dist-CgbVZs5l.js +40 -0
- package/dist/src/compiled/_chunks/workflow/dist-DjojkP5e.js +3 -0
- package/dist/src/compiled/_chunks/workflow/frames-CZ9eHShe.js +3 -0
- package/dist/src/compiled/_chunks/workflow/global-singleton-BNinwFrL.js +1 -0
- package/dist/src/compiled/_chunks/workflow/private-CZFMABEf.js +1 -0
- package/dist/src/compiled/_chunks/workflow/resume-hook-BToMtPbH.js +1 -0
- package/dist/src/compiled/_chunks/workflow/run-DzyAoGh4.js +1 -0
- package/dist/src/compiled/_chunks/workflow/sleep-3_A5uOp-.js +1 -0
- package/dist/src/compiled/_chunks/workflow/undici-DfxNX5og.js +95 -0
- package/dist/src/compiled/_chunks/workflow/wait-until-BtySPYD0.js +15 -0
- package/dist/src/compiled/_chunks/workflow/ws-transport-PnVVxT0R.js +1 -0
- package/dist/src/eve-channel/index.js +1 -1
- package/dist/src/execution/agent-handle-dispatch.js +1 -1
- package/dist/src/execution/continuation-conflict-step.d.ts +10 -0
- package/dist/src/execution/continuation-conflict-step.js +1 -0
- package/dist/src/execution/delegated-parent-notification.js +1 -1
- package/dist/src/execution/dispatch-runtime-actions-shared.d.ts +7 -29
- package/dist/src/execution/dispatch-runtime-actions-shared.js +1 -1
- package/dist/src/execution/dispatch-runtime-actions-start.d.ts +33 -0
- package/dist/src/execution/dispatch-runtime-actions-start.js +1 -0
- package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
- package/dist/src/execution/dispatch-turn-step.js +1 -1
- package/dist/src/execution/dynamic-connections.js +1 -1
- package/dist/src/execution/inline-turn.js +1 -1
- package/dist/src/execution/next-driver-action.d.ts +5 -4
- package/dist/src/execution/proxied-deliver-step.js +1 -1
- package/dist/src/execution/runtime-errors.d.ts +0 -12
- package/dist/src/execution/runtime-errors.js +1 -1
- package/dist/src/execution/sandbox/bindings/docker-options.d.ts +1 -1
- package/dist/src/execution/sandbox/bindings/docker-options.js +1 -1
- package/dist/src/execution/sandbox/bindings/eve-image.d.ts +4 -0
- package/dist/src/execution/sandbox/bindings/eve-image.js +1 -0
- package/dist/src/execution/sandbox/bindings/microsandbox-options.d.ts +1 -1
- package/dist/src/execution/sandbox/bindings/microsandbox-options.js +1 -1
- package/dist/src/execution/sandbox/bindings/vercel-create-sdk.js +1 -1
- package/dist/src/execution/session-timeout-steps.js +1 -1
- package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
- package/dist/src/execution/stable-workflow-names.d.ts +2 -2
- package/dist/src/execution/subagent-start-local.js +1 -1
- package/dist/src/execution/tasks/parent/dispatch-task-step.js +1 -1
- package/dist/src/execution/tasks/parent/run-parent.js +1 -1
- package/dist/src/execution/tasks/parent/tool-execution.js +1 -1
- package/dist/src/execution/tool-run/start.js +1 -1
- package/dist/src/execution/tools/subagent/local.js +1 -1
- package/dist/src/execution/turn-workflow.js +1 -1
- package/dist/src/execution/workflow-entry.d.ts +5 -1
- package/dist/src/execution/workflow-entry.js +1 -1
- package/dist/src/execution/workflow-runtime.d.ts +12 -12
- package/dist/src/execution/workflow-runtime.js +1 -1
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/workflow/development-world-client.js +1 -1
- package/dist/src/packages/eve-catalog/src/index.js +1 -1
- package/dist/src/public/channels/slack/activity.d.ts +18 -0
- package/dist/src/public/channels/slack/activity.js +1 -0
- package/dist/src/public/channels/slack/api.js +1 -1
- package/dist/src/public/channels/slack/index.d.ts +1 -0
- package/dist/src/public/channels/slack/index.js +1 -1
- package/dist/src/public/channels/slack/interaction-cards.js +1 -1
- package/dist/src/public/channels/slack/interactions.js +1 -1
- package/dist/src/public/channels/slack/slackChannel.d.ts +12 -1
- package/dist/src/public/channels/slack/slackChannel.js +1 -1
- package/dist/src/public/memory/file/backends/default.js +1 -1
- package/dist/src/public/sandbox/docker-sandbox.d.ts +5 -4
- package/dist/src/public/sandbox/microsandbox-sandbox.d.ts +1 -1
- package/dist/src/public/sandbox/vercel-sandbox.d.ts +3 -1
- package/dist/src/setup/flows/registry.js +1 -1
- package/dist/src/setup/integrations/file-memory/setup.d.ts +15 -0
- package/dist/src/setup/integrations/file-memory/setup.js +2 -0
- package/dist/src/setup/integrations/file-memory/vercel.d.ts +103 -0
- package/dist/src/setup/integrations/file-memory/vercel.js +1 -0
- package/dist/src/setup/integrations/registry.js +1 -1
- package/dist/src/setup/integrations/shared/vercel-project.js +1 -1
- package/dist/src/setup/scaffold/connections/catalog.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/docs/channels/custom.mdx +4 -0
- package/docs/channels/eve.mdx +12 -8
- package/docs/channels/mcp.mdx +4 -1
- package/docs/channels/slack.mdx +1 -1
- package/docs/guides/instrumentation.md +1 -1
- package/docs/install-integrations.mdx +5 -0
- package/docs/instructions.mdx +1 -1
- package/docs/memory/custom-provider.md +214 -0
- package/docs/memory/file.md +168 -0
- package/docs/memory/meta.json +5 -0
- package/docs/memory/overview.mdx +282 -0
- package/docs/patterns/multi-tenant-memory.md +12 -20
- package/docs/reference/cli.md +28 -23
- package/docs/sandbox.mdx +5 -3
- package/package.json +8 -8
- package/dist/src/compiled/_chunks/workflow/dist-CqvWKNQv.js +0 -3
- package/dist/src/compiled/_chunks/workflow/dist-Dk0aQqFO.js +0 -40
- package/dist/src/compiled/_chunks/workflow/dist-DpYyXbJv.js +0 -1
- package/dist/src/compiled/_chunks/workflow/env-config-L94XftKz.js +0 -1
- package/dist/src/compiled/_chunks/workflow/frames-Dl2Hcma4.js +0 -3
- package/dist/src/compiled/_chunks/workflow/private-CuQ4HTFC.js +0 -1
- package/dist/src/compiled/_chunks/workflow/resume-hook-E-Nkx8q_.js +0 -1
- package/dist/src/compiled/_chunks/workflow/run-cIeex2KF.js +0 -1
- package/dist/src/compiled/_chunks/workflow/sleep-CxFsdxB_.js +0 -1
- package/dist/src/compiled/_chunks/workflow/spec-version-DBUVfF_R.js +0 -1
- package/dist/src/compiled/_chunks/workflow/undici-DznrXKcM.js +0 -95
- package/dist/src/compiled/_chunks/workflow/wait-until-BZHmJCAW.js +0 -15
- package/dist/src/compiled/_chunks/workflow/ws-transport-Ct6yyRWZ.js +0 -1
- package/docs/memory.md +0 -408
|
@@ -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,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};
|
|
1
|
+
import{createLogger}from"#internal/logging.js";import{parseInputResponse}from"#shared/input.js";import{buildSlackBinding,buildSlackWorkspaceHandle,resolveSlackBotToken,slackContinuationToken}from"#public/channels/slack/api.js";import{readSlackTextObject}from"#public/channels/slack/inbound-content.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,r){let i=new Response(`ok`,{status:200}),o;try{o=parseSlackWebhookBody(e,{contentType:`application/x-www-form-urlencoded`})}catch{return log.warn(`failed to parse Slack interaction payload`),i}if(o.kind===`view_submission`)return handleViewSubmission(o,t,r);if(o.kind===`slash_command`)return dispatchSlashCommand(o,t,r.config),new Response(null,{status:200});if(o.kind===`unsupported`){let e=parseShortcutPayload(o.raw);return e===null?(log.warn(`unsupported Slack interaction payload ignored`,{type:o.type}),i):(dispatchShortcut(e,readInstallationTeamId(o.raw),t,r),new Response(null,{status:200}))}if(o.kind!==`block_actions`)return log.warn(`unsupported Slack interaction payload ignored`,{type:o.kind}),i;let c=parseBlockActionsPayload(o);if(!c)return i;let l=c.actions.find(e=>isFreeformAction(e.actionId));if(l)return await openFreeformModal({payload:o.raw,interaction:c,freeformAction:l,deps:r}),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:r,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=r.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:r.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 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 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};
|
|
@@ -14,7 +14,8 @@ import { type SlackSessionOperations } from "#public/channels/slack/session-oper
|
|
|
14
14
|
import { type UploadPolicyInput } from "#public/channels/upload-policy.js";
|
|
15
15
|
import { type SlackWebhookVerifier } from "#public/channels/slack/verify.js";
|
|
16
16
|
import { type Channel } from "#public/definitions/channel.js";
|
|
17
|
-
import type
|
|
17
|
+
import { type ChannelAudience } from "#shared/channel-audience.js";
|
|
18
|
+
import { type SlackActivityRenderer } from "#public/channels/slack/activity.js";
|
|
18
19
|
export type { SlackRespondOptions, SlackSendOptions, SlackSessionOperations, } from "#public/channels/slack/session-operations.js";
|
|
19
20
|
type EventData<T extends UnstampedMessageStreamEvent["type"]> = Extract<UnstampedMessageStreamEvent, {
|
|
20
21
|
type: T;
|
|
@@ -184,6 +185,12 @@ export interface SlackChannelCredentials {
|
|
|
184
185
|
export interface SlackReceiveTarget {
|
|
185
186
|
readonly channelId: string;
|
|
186
187
|
readonly threadTs?: string;
|
|
188
|
+
/**
|
|
189
|
+
* Optional audience for proactive receives. Omit to leave `unknown`.
|
|
190
|
+
* Pass when the caller already knows channel visibility, for example a
|
|
191
|
+
* webhook or schedule that classified the Slack destination before handoff.
|
|
192
|
+
*/
|
|
193
|
+
readonly audience?: ChannelAudience;
|
|
187
194
|
/** Slack workspace whose app installation supplies credentials for this send. */
|
|
188
195
|
readonly installationTeamId?: string;
|
|
189
196
|
/**
|
|
@@ -466,6 +473,10 @@ export interface SlackChannelInternalEvents extends Omit<SlackChannelEvents, "au
|
|
|
466
473
|
export interface SlackChannelConfig {
|
|
467
474
|
readonly credentials?: SlackChannelCredentials;
|
|
468
475
|
readonly botName?: string;
|
|
476
|
+
/** Optional presentation-only activity rendered without starting parent turns. */
|
|
477
|
+
readonly activity?: {
|
|
478
|
+
readonly renderers: readonly SlackActivityRenderer[];
|
|
479
|
+
};
|
|
469
480
|
/** Override the default webhook route path (`/eve/v1/slack`). */
|
|
470
481
|
readonly route?: string;
|
|
471
482
|
/** Policy for accepted messages that arrive while a turn is active. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{markEventHandled}from"./utils.js";import{createLogger,logError}from"#internal/logging.js";import{defaultDeliverResult}from"#channel/adapter.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{mergeUploadPolicy}from"#public/channels/upload-policy.js";import{buildSlackBinding,buildSlackWorkspaceHandle,slackContinuationToken}from"#public/channels/slack/api.js";import{buildSlackAuthContext,slackUserIdFromAuthContext}from"#public/channels/slack/auth.js";import{defaultEvents,defaultInputRequestedHandler,defaultOnAppMention,defaultOnDirectMessage}from"#public/channels/slack/defaults.js";import{loadThreadContextMessages}from"#public/channels/slack/thread.js";import{parseSlackWebhookBody}from"#compiled/@chat-adapter/slack/webhook.js";import{bindSlackSessionOperations}from"#public/channels/slack/session-operations.js";import{buildSlackTurnMessage,collectInboundFileParts,createSlackFetchFile}from"#public/channels/slack/attachments.js";import{parseMessageEvent,parseSlackEventEnvelope,slackEventBotUserId,slackEventInstallationTeamId,slackEventReceivingBotUserId,slackMessageFromWebhookPayload}from"#public/channels/slack/inbound.js";import{formatSlackInboundMessage,formatSlackThreadContext}from"#public/channels/slack/model-context.js";import{isPrivateSlackConversation}from"#public/channels/slack/privacy.js";import{SLACK_CHANNEL_DEFAULT_ROUTE}from"#public/channels/slack/constants.js";import{handleInteractionPost}from"#public/channels/slack/interactions.js";import{verifySlackRequest as verifySlackRequest$1}from"#public/channels/slack/verify.js";const log=createLogger(`slack.channel`);function rebuildSlackContext(e,t,n){let{thread:r,slack:i}=buildSlackBinding({botToken:n?.botToken,channelId:e.channelId??``,threadTs:e.threadTs??``,installationTeamId:e.installationTeamId??void 0,teamId:e.teamId??void 0,onThreadTsChanged(n){e.threadTs=n,e.channelId&&t.continuation?.rekey(slackContinuationToken(e.channelId,n))}});return{thread:r,slack:i,state:e}}function slackChannel(e={}){let t=mergeUploadPolicy(e.uploadPolicy),n=createSlackFetchFile({botToken:e.credentials?.botToken}),s=e.onInputResponse??defaultOnInputResponse,c=e.events?.[`authorization.required`],l=e.events?.[`approval.candidate`]??defaultEvents[`approval.candidate`],u=e.events?.[`turn.started`]??defaultEvents[`turn.started`],m={...defaultEvents,...e.events,async"approval.candidate"(e,t,n){let r=t.state.approvalResponderUsers?.[e.responderPrincipalId];if(e.outcome===`pending`&&r!==void 0&&(t.state.pendingApprovalCandidateUsers={...t.state.pendingApprovalCandidateUsers,[e.candidateId]:r}),await l(e,t,n),e.outcome!==`pending`){let n={...t.state.pendingApprovalCandidateUsers};delete n[e.candidateId],t.state.pendingApprovalCandidateUsers=n}},async"turn.started"(e,t,n){let r=slackUserIdFromAuthContext(n.session.auth.current);r!==void 0&&(t.state.triggeringUserId=r),await u(e,t,n)},"input.requested":e.events?.[`input.requested`]??defaultInputRequestedHandler(),"authorization.required":c===void 0?defaultEvents[`authorization.required`]:constrainAuthorizationRequired(c)},h=new Set;return defineChannel({kindHint:`slack`,turnPolicy:e.turnPolicy,state:{audience:`unknown`,channelId:null,threadTs:null,teamId:null,installationTeamId:null,triggeringUserId:null,pendingToolCallMessage:null,lastReasoningTypingAtMs:null,lastReasoningTypingStatus:null,pendingAuthMessageTs:{},pendingApprovalCards:{},pendingApprovalCandidateUsers:{},approvalResponderUsers:{}},fetchFile:n,metadata(e){return{audience:e.audience??`unknown`,channelId:e.channelId,teamId:e.teamId,threadTs:e.threadTs,triggeringUserId:e.triggeringUserId??null}},context(t,n){return rebuildSlackContext(t,n,e.credentials)},deliver(e,t){let n=e.pendingApprovalCards;typeof n==`object`&&n&&(t.state.pendingApprovalCards={...t.state.pendingApprovalCards,...n});let i=e.state?.approvalResponderUsers;return typeof i==`object`&&i&&(t.state.approvalResponderUsers={...t.state.approvalResponderUsers,...i}),defaultDeliverResult(e)},routes:[POST(e.route??SLACK_CHANNEL_DEFAULT_ROUTE,async(n,r)=>{let{waitUntil:i}=r,{from:a,resolveSession:o}=r,c=await verifyInbound(n,e.credentials);return c===null?new Response(`unauthorized`,{status:401}):shouldDropSlackHttpTimeoutRetry(n.headers)?new Response(`ok`):(n.headers.get(`content-type`)??``).includes(`application/x-www-form-urlencoded`)?handleInteractionPost(c,{from:a,resolveSession:o,waitUntil:i},{config:e,onInputResponse:s}):handleEventPost({body:c,from:a,resolveSession:o,waitUntil:i,config:e,uploadPolicy:t,handledEvents:h,headers:n.headers})})],receive(t,{from:n}){return receiveOnSlack(t,{from:n,credentials:e.credentials})},events:m})}function defaultOnInputResponse(e){return{auth:e.defaultAuth}}async function receiveOnSlack(e,t){let n=e.target,r=n.channelId;if(!r||typeof r!=`string`)throw Error(`slackChannel().receive requires target.channelId.`);let i=typeof n.threadTs==`string`?n.threadTs:``,a=typeof n.installationTeamId==`string`?n.installationTeamId:t.installationTeamId,o=n.initialMessage;if(o&&i.length>0)throw Error("slackChannel().receive: `threadTs` and `initialMessage` are mutually exclusive.");let c=i;if(o){let{thread:e}=buildSlackBinding({botToken:t.credentials?.botToken,channelId:r,threadTs:``,installationTeamId:a,teamId:t.teamId}),n={card:o.card};o.fallbackText!==void 0&&(n.fallbackText=o.fallbackText),c=(await e.post(n)).id}let u=c||crypto.randomUUID();return t.from(slackContinuationToken(r,u)).send(e.message,{auth:e.auth,state:{channelId:r,installationTeamId:a??null,threadTs:c||null,teamId:t.teamId??null,triggeringUserId:t.triggeringUserId??null},title:e.title})}function constrainAuthorizationRequired(e){return(t,n,r)=>e(t,{postEphemeral:(e,t)=>n.thread.postEphemeral(e,t),postDirectMessage:(e,t)=>n.thread.postDirectMessage(e,t),state:n.state},r)}function shouldDropSlackHttpTimeoutRetry(e){return Number(e.get(`x-slack-retry-num`)??`0`)>=1&&e.get(`x-slack-retry-reason`)===`http_timeout`}async function handleEventPost(t){let{config:n}=t,r,i;try{r=parseSlackWebhookBody(t.body,{headers:t.headers}),i=parseSlackEventEnvelope(t.body)}catch(e){return log.warn(`inbound webhook body is not valid JSON`,{error:e}),new Response(`ok`)}if(r.kind===`url_verification`)return new Response(r.challenge,{status:200,headers:{"content-type":`text/plain`}});if(i===null)return new Response(`ok`);let a=typeof i.api_app_id==`string`?i.api_app_id:void 0,o=slackEventBotUserId(i),s=slackEventReceivingBotUserId(i),c=slackEventInstallationTeamId(i),dispatch=null,l=null;if(r.kind===`app_mention`||r.kind===`direct_message`){let e=r.kind,i=slackMessageFromWebhookPayload(r);if(i!==null&&!isSelfAuthoredSlackMessage({appId:a,botUserId:o},i)){let dispatchMessageWith=r=>()=>dispatchSlackMessage({appId:a,botUserId:o,receivingBotUserId:s,from:t.from,resolveSession:t.resolveSession,credentials:n.credentials,handler:r,installationTeamId:c,kind:e,message:i,threadContext:n.threadContext,uploadPolicy:t.uploadPolicy}),r=(e===`app_mention`?n.onAppMention:n.onDirectMessage)??n.onMessage;r===void 0?l=dispatchMessageWith(e===`app_mention`?defaultOnAppMention:defaultOnDirectMessage):dispatch=()=>dispatchSlackMessage({appId:a,botUserId:o,receivingBotUserId:s,from:t.from,resolveSession:t.resolveSession,credentials:n.credentials,handler:r,installationTeamId:c,kind:e,message:i,threadContext:n.threadContext,uploadPolicy:t.uploadPolicy})}}if(dispatch===null&&n.onMessage!==void 0){let e=parseMessageEvent(i);e!==null&&!isSelfAuthoredSlackMessage({appId:a,botUserId:o},e)&&(o===void 0||!e.text.includes(`<@${o}`))&&(dispatch=()=>dispatchSlackMessage({appId:a,botUserId:o,receivingBotUserId:s,from:t.from,resolveSession:t.resolveSession,credentials:n.credentials,handler:n.onMessage,installationTeamId:c,kind:`channel_message`,message:e,threadContext:n.threadContext,uploadPolicy:t.uploadPolicy}))}let u=n.onEvent;if(dispatch===null&&u!==void 0&&(dispatch=()=>dispatchSlackEvent({from:t.from,resolveSession:t.resolveSession,credentials:n.credentials,envelope:i,handler:u,installationTeamId:c})),dispatch??=l,dispatch===null)return new Response(`ok`);let d=i.event_id;if(d){if(t.handledEvents.has(d))return log.warn(`received a duplicate event`,{event_id:d,event_time:i.event_time,retry_num:r.retry?.num??`(null)`,retry_reason:r.retry?.reason??`(null)`}),new Response(`ok`);markEventHandled(d,t.handledEvents)}return t.waitUntil(dispatch()),new Response(`ok`)}function isSelfAuthoredSlackMessage(e,t){return e.botUserId!==void 0&&t.author?.userId===e.botUserId||e.appId!==void 0&&t.raw.app_id===e.appId}async function dispatchSlackMessage(e){let t=slackContinuationToken(e.message.channelId,e.message.threadTs),{thread:r,slack:i}=buildSlackBinding({appId:e.appId,botToken:e.credentials?.botToken,botUserId:e.botUserId,channelId:e.message.channelId,threadTs:e.message.threadTs,installationTeamId:e.installationTeamId,teamId:e.message.teamId}),a=e.message.author,o={audience:`unknown`,channelId:e.message.channelId,installationTeamId:e.installationTeamId??null,teamId:e.message.teamId??null,threadTs:e.message.threadTs,triggeringUserId:a?.userId??null},c=bindSlackSessionOperations({address:t,defaultAuth:a===void 0?null:buildSlackAuthContext({channelId:e.message.channelId,fullName:a.fullName,isBot:a.isBot,teamId:e.message.teamId,threadTs:e.message.threadTs,userId:a.userId,userName:a.userName}),from:e.from,resolveSession:e.resolveSession,state:o}),d,isDMOrPrivateChannel=()=>d??=isPrivateSlackConversation({channelId:e.message.channelId,raw:e.message.raw,request:i.request}),f=e.kind===`app_mention`||e.botUserId!==void 0&&e.message.text.includes(`<@${e.botUserId}`),p={...c,isBotMentioned:()=>f,isDMOrPrivateChannel,isSubscribed:async()=>await c.resolveSession()!==void 0,slack:i,thread:r},m;try{m=await e.handler(p,e.message)}catch(t){logError(log,`${e.kind} handler failed`,t,{channelId:e.message.channelId});return}if(m==null)return;let h=await isDMOrPrivateChannel();o.audience=e.kind===`direct_message`||h?`private`:`public`,await deliverSlackMessage({botUserId:e.receivingBotUserId,credentials:e.credentials,kind:e.kind,isPrivateConversation:h,isMentioned:f,message:e.message,result:m,sessionOperations:c,thread:r,threadContext:e.threadContext,uploadPolicy:e.uploadPolicy})}async function dispatchSlackEvent(e){let t=e.envelope.event.team_id,r=typeof t==`string`?t:typeof e.envelope.team_id==`string`?e.envelope.team_id:void 0,i=[],sourceFor=t=>e.from(slackContinuationToken(t.channelId,t.threadTs)),a={cancel:({target:e,turnId:t})=>sourceFor(e).cancel({turnId:t}),clear:({target:e})=>sourceFor(e).clear(),compact:({target:e})=>sourceFor(e).compact(),envelope:e.envelope,reset:({reason:e,target:t})=>sourceFor(t).reset({reason:e}),resolveSession:({target:t})=>e.resolveSession(slackContinuationToken(t.channelId,t.threadTs)),respond:(e,{auth:t,target:n})=>sourceFor(n).respond(e,{auth:t}),send:(t,{auth:n,target:i,title:a})=>receiveOnSlack({auth:n,message:t,target:i,title:a},{from:e.from,credentials:e.credentials,installationTeamId:e.installationTeamId,teamId:r,...typeof e.envelope.event.user==`string`?{triggeringUserId:e.envelope.event.user}:{}}),slack:buildSlackWorkspaceHandle({botToken:e.credentials?.botToken,installationTeamId:e.installationTeamId,teamId:r}),waitUntil(e){i.push(e)}};try{await e.handler(a,e.envelope.event)}catch(t){logError(log,`event handler failed`,t,{eventId:e.envelope.event_id,eventType:e.envelope.event.type})}await Promise.allSettled(i)}async function verifyInbound(e,t){try{return await verifySlackRequest$1(e,{signingSecret:t?.signingSecret??(t?.webhookVerifier?void 0:process.env.SLACK_SIGNING_SECRET),webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`slack inbound verification failed`,{error:e}),null}}async function deliverSlackMessage(e){let{message:t,thread:r}=e;try{let n=formatSlackThreadContext(e.threadContext===void 0?[]:await loadThreadContextMessages(r,t,e.threadContext)),i=await collectInboundFileParts({mention:t,thread:r,policy:e.uploadPolicy}),a=formatSlackInboundMessage({botUserId:e.botUserId,channelId:t.channelId,fullName:t.author?.fullName,isMentioned:e.isMentioned,teamId:t.teamId,threadTs:t.threadTs,userId:t.author?.userId??``,userName:t.author?.userName},t),o=buildSlackTurnMessage(n===void 0?a:`${n}\n\n${a}`,i),s=e.result.context??[],c=e.isPrivateConversation?`Private message`:e.result.title??t.markdown,l=s.length===0?{auth:e.result.auth,title:c}:{auth:e.result.auth,context:s,title:c};await e.sessionOperations.send(o,l)}catch(r){logError(log,`${e.kind} delivery failed`,r,{channelId:t.channelId})}}export{constrainAuthorizationRequired,slackChannel};
|
|
1
|
+
import{markEventHandled}from"./utils.js";import{createLogger,logError}from"#internal/logging.js";import{setChannelActivityRenderers}from"#channel/compiled-channel.js";import{defaultDeliverResult}from"#channel/adapter.js";import{normalizeChannelAudience}from"#shared/channel-audience.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{mergeUploadPolicy}from"#public/channels/upload-policy.js";import{buildSlackBinding,buildSlackWorkspaceHandle,slackContinuationToken}from"#public/channels/slack/api.js";import{buildSlackAuthContext,slackUserIdFromAuthContext}from"#public/channels/slack/auth.js";import{defaultEvents,defaultInputRequestedHandler,defaultOnAppMention,defaultOnDirectMessage}from"#public/channels/slack/defaults.js";import{buildSlackActivityRenderers,hasSlackActivityStatus}from"#public/channels/slack/activity.js";import{loadThreadContextMessages}from"#public/channels/slack/thread.js";import{parseSlackWebhookBody}from"#compiled/@chat-adapter/slack/webhook.js";import{bindSlackSessionOperations}from"#public/channels/slack/session-operations.js";import{buildSlackTurnMessage,collectInboundFileParts,createSlackFetchFile}from"#public/channels/slack/attachments.js";import{parseMessageEvent,parseSlackEventEnvelope,slackEventBotUserId,slackEventInstallationTeamId,slackEventReceivingBotUserId,slackMessageFromWebhookPayload}from"#public/channels/slack/inbound.js";import{formatSlackInboundMessage,formatSlackThreadContext}from"#public/channels/slack/model-context.js";import{isPrivateSlackConversation}from"#public/channels/slack/privacy.js";import{SLACK_CHANNEL_DEFAULT_ROUTE}from"#public/channels/slack/constants.js";import{handleInteractionPost}from"#public/channels/slack/interactions.js";import{verifySlackRequest as verifySlackRequest$1}from"#public/channels/slack/verify.js";const log=createLogger(`slack.channel`),ignoreSlackActivityEvent=async()=>void 0,activityOwnedMessageCompleted=async(e,t)=>{t.state.pendingToolCallMessage=null,e.finishReason!==`tool-calls`&&e.message&&await t.thread.post(e.message)},clearSlackTurnState=async(e,t)=>{t.state.pendingToolCallMessage=null,t.state.lastReasoningTypingAtMs=null,t.state.lastReasoningTypingStatus=null};function rebuildSlackContext(e,t,n){let{thread:r,slack:i}=buildSlackBinding({botToken:n?.botToken,channelId:e.channelId??``,threadTs:e.threadTs??``,installationTeamId:e.installationTeamId??void 0,teamId:e.teamId??void 0,onThreadTsChanged(n){e.threadTs=n,e.channelId&&t.continuation?.rekey(slackContinuationToken(e.channelId,n))}});return{thread:r,slack:i,state:e}}function slackChannel(e={}){let t=mergeUploadPolicy(e.uploadPolicy),n=createSlackFetchFile({botToken:e.credentials?.botToken}),a=buildSlackActivityRenderers({botToken:e.credentials?.botToken,renderers:e.activity?.renderers??[]}),l=e.onInputResponse??defaultOnInputResponse,u=e.events?.[`authorization.required`],d=e.events?.[`approval.candidate`]??defaultEvents[`approval.candidate`],f=hasSlackActivityStatus(e.activity?.renderers),g=e.events?.[`turn.started`]??(f?clearSlackTurnState:defaultEvents[`turn.started`]),_=e.events?.[`reasoning.appended`]??(f?ignoreSlackActivityEvent:defaultEvents[`reasoning.appended`]),v=e.events?.[`actions.requested`]??(f?ignoreSlackActivityEvent:defaultEvents[`actions.requested`]),y=e.events?.[`message.completed`]??(f?activityOwnedMessageCompleted:defaultEvents[`message.completed`]),b={...defaultEvents,...e.events,async"approval.candidate"(e,t,n){let r=t.state.approvalResponderUsers?.[e.responderPrincipalId];if(e.outcome===`pending`&&r!==void 0&&(t.state.pendingApprovalCandidateUsers={...t.state.pendingApprovalCandidateUsers,[e.candidateId]:r}),await d(e,t,n),e.outcome!==`pending`){let n={...t.state.pendingApprovalCandidateUsers};delete n[e.candidateId],t.state.pendingApprovalCandidateUsers=n}},async"turn.started"(e,t,n){let r=slackUserIdFromAuthContext(n.session.auth.current);r!==void 0&&(t.state.triggeringUserId=r),await g(e,t,n)},"reasoning.appended":_,"actions.requested":v,"message.completed":y,"input.requested":e.events?.[`input.requested`]??defaultInputRequestedHandler(),"authorization.required":u===void 0?defaultEvents[`authorization.required`]:constrainAuthorizationRequired(u)},x=new Set,S=defineChannel({kindHint:`slack`,turnPolicy:e.turnPolicy,state:{audience:`unknown`,channelId:null,threadTs:null,teamId:null,installationTeamId:null,triggeringUserId:null,pendingToolCallMessage:null,lastReasoningTypingAtMs:null,lastReasoningTypingStatus:null,pendingAuthMessageTs:{},pendingApprovalCards:{},pendingApprovalCandidateUsers:{},approvalResponderUsers:{}},fetchFile:n,metadata(e){return{audience:e.audience??`unknown`,channelId:e.channelId,teamId:e.teamId,threadTs:e.threadTs,triggeringUserId:e.triggeringUserId??null}},context(t,n){return rebuildSlackContext(t,n,e.credentials)},deliver(e,t){let n=e.pendingApprovalCards;typeof n==`object`&&n&&(t.state.pendingApprovalCards={...t.state.pendingApprovalCards,...n});let r=e.state?.approvalResponderUsers;return typeof r==`object`&&r&&(t.state.approvalResponderUsers={...t.state.approvalResponderUsers,...r}),defaultDeliverResult(e)},routes:[POST(e.route??SLACK_CHANNEL_DEFAULT_ROUTE,async(n,r)=>{let{waitUntil:i}=r,{from:a,resolveSession:o}=r,s=await verifyInbound(n,e.credentials);return s===null?new Response(`unauthorized`,{status:401}):shouldDropSlackHttpTimeoutRetry(n.headers)?new Response(`ok`):(n.headers.get(`content-type`)??``).includes(`application/x-www-form-urlencoded`)?handleInteractionPost(s,{from:a,resolveSession:o,waitUntil:i},{config:e,onInputResponse:l}):handleEventPost({body:s,from:a,resolveSession:o,waitUntil:i,config:e,uploadPolicy:t,handledEvents:x,headers:n.headers})})],receive(t,{from:n}){return receiveOnSlack(t,{from:n,credentials:e.credentials})},events:b});return setChannelActivityRenderers(S,{destination(e){let t=e;return{channelId:t?.channelId??null,installationTeamId:t?.installationTeamId??null,threadTs:t?.threadTs??null}},renderers:a}),S}function defaultOnInputResponse(e){return{auth:e.defaultAuth}}async function receiveOnSlack(e,t){let n=e.target,r=n.channelId;if(!r||typeof r!=`string`)throw Error(`slackChannel().receive requires target.channelId.`);let i=typeof n.threadTs==`string`?n.threadTs:``,o=typeof n.installationTeamId==`string`?n.installationTeamId:t.installationTeamId,s=n.initialMessage;if(s&&i.length>0)throw Error("slackChannel().receive: `threadTs` and `initialMessage` are mutually exclusive.");let c=i;if(s){let{thread:e}=buildSlackBinding({botToken:t.credentials?.botToken,channelId:r,threadTs:``,installationTeamId:o,teamId:t.teamId}),n={card:s.card};s.fallbackText!==void 0&&(n.fallbackText=s.fallbackText),c=(await e.post(n)).id}let u=c||crypto.randomUUID(),f=n.audience===void 0?void 0:normalizeChannelAudience(n.audience),p={channelId:r,installationTeamId:o??null,threadTs:c||null,teamId:t.teamId??null,triggeringUserId:t.triggeringUserId??null};return f!==void 0&&(p.audience=f),t.from(slackContinuationToken(r,u)).send(e.message,{auth:e.auth,state:p,title:e.title})}function constrainAuthorizationRequired(e){return(t,n,r)=>e(t,{postEphemeral:(e,t)=>n.thread.postEphemeral(e,t),postDirectMessage:(e,t)=>n.thread.postDirectMessage(e,t),state:n.state},r)}function shouldDropSlackHttpTimeoutRetry(e){return Number(e.get(`x-slack-retry-num`)??`0`)>=1&&e.get(`x-slack-retry-reason`)===`http_timeout`}async function handleEventPost(t){let{config:n}=t,r,i;try{r=parseSlackWebhookBody(t.body,{headers:t.headers}),i=parseSlackEventEnvelope(t.body)}catch(e){return log.warn(`inbound webhook body is not valid JSON`,{error:e}),new Response(`ok`)}if(r.kind===`url_verification`)return new Response(r.challenge,{status:200,headers:{"content-type":`text/plain`}});if(i===null)return new Response(`ok`);let a=typeof i.api_app_id==`string`?i.api_app_id:void 0,o=slackEventBotUserId(i),s=slackEventReceivingBotUserId(i),c=slackEventInstallationTeamId(i),dispatch=null,l=null;if(r.kind===`app_mention`||r.kind===`direct_message`){let e=r.kind,i=slackMessageFromWebhookPayload(r);if(i!==null&&!isSelfAuthoredSlackMessage({appId:a,botUserId:o},i)){let dispatchMessageWith=r=>()=>dispatchSlackMessage({appId:a,botUserId:o,receivingBotUserId:s,from:t.from,resolveSession:t.resolveSession,credentials:n.credentials,handler:r,installationTeamId:c,kind:e,message:i,threadContext:n.threadContext,uploadPolicy:t.uploadPolicy}),r=(e===`app_mention`?n.onAppMention:n.onDirectMessage)??n.onMessage;r===void 0?l=dispatchMessageWith(e===`app_mention`?defaultOnAppMention:defaultOnDirectMessage):dispatch=()=>dispatchSlackMessage({appId:a,botUserId:o,receivingBotUserId:s,from:t.from,resolveSession:t.resolveSession,credentials:n.credentials,handler:r,installationTeamId:c,kind:e,message:i,threadContext:n.threadContext,uploadPolicy:t.uploadPolicy})}}if(dispatch===null&&n.onMessage!==void 0){let e=parseMessageEvent(i);e!==null&&!isSelfAuthoredSlackMessage({appId:a,botUserId:o},e)&&(o===void 0||!e.text.includes(`<@${o}`))&&(dispatch=()=>dispatchSlackMessage({appId:a,botUserId:o,receivingBotUserId:s,from:t.from,resolveSession:t.resolveSession,credentials:n.credentials,handler:n.onMessage,installationTeamId:c,kind:`channel_message`,message:e,threadContext:n.threadContext,uploadPolicy:t.uploadPolicy}))}let u=n.onEvent;if(dispatch===null&&u!==void 0&&(dispatch=()=>dispatchSlackEvent({from:t.from,resolveSession:t.resolveSession,credentials:n.credentials,envelope:i,handler:u,installationTeamId:c})),dispatch??=l,dispatch===null)return new Response(`ok`);let d=i.event_id;if(d){if(t.handledEvents.has(d))return log.warn(`received a duplicate event`,{event_id:d,event_time:i.event_time,retry_num:r.retry?.num??`(null)`,retry_reason:r.retry?.reason??`(null)`}),new Response(`ok`);markEventHandled(d,t.handledEvents)}return t.waitUntil(dispatch()),new Response(`ok`)}function isSelfAuthoredSlackMessage(e,t){return e.botUserId!==void 0&&t.author?.userId===e.botUserId||e.appId!==void 0&&t.raw.app_id===e.appId}async function dispatchSlackMessage(e){let t=slackContinuationToken(e.message.channelId,e.message.threadTs),{thread:r,slack:i}=buildSlackBinding({appId:e.appId,botToken:e.credentials?.botToken,botUserId:e.botUserId,channelId:e.message.channelId,threadTs:e.message.threadTs,installationTeamId:e.installationTeamId,teamId:e.message.teamId}),a=e.message.author,o={audience:`unknown`,channelId:e.message.channelId,installationTeamId:e.installationTeamId??null,teamId:e.message.teamId??null,threadTs:e.message.threadTs,triggeringUserId:a?.userId??null},s=bindSlackSessionOperations({address:t,defaultAuth:a===void 0?null:buildSlackAuthContext({channelId:e.message.channelId,fullName:a.fullName,isBot:a.isBot,teamId:e.message.teamId,threadTs:e.message.threadTs,userId:a.userId,userName:a.userName}),from:e.from,resolveSession:e.resolveSession,state:o}),c,isDMOrPrivateChannel=()=>c??=isPrivateSlackConversation({channelId:e.message.channelId,raw:e.message.raw,request:i.request}),u=e.kind===`app_mention`||e.botUserId!==void 0&&e.message.text.includes(`<@${e.botUserId}`),p={...s,isBotMentioned:()=>u,isDMOrPrivateChannel,isSubscribed:async()=>await s.resolveSession()!==void 0,slack:i,thread:r},m;try{m=await e.handler(p,e.message)}catch(t){logError(log,`${e.kind} handler failed`,t,{channelId:e.message.channelId});return}if(m==null)return;let h=await isDMOrPrivateChannel();o.audience=e.kind===`direct_message`||h?`private`:`public`,await deliverSlackMessage({botUserId:e.receivingBotUserId,credentials:e.credentials,kind:e.kind,isPrivateConversation:h,isMentioned:u,message:e.message,result:m,sessionOperations:s,thread:r,threadContext:e.threadContext,uploadPolicy:e.uploadPolicy})}async function dispatchSlackEvent(e){let t=e.envelope.event.team_id,r=typeof t==`string`?t:typeof e.envelope.team_id==`string`?e.envelope.team_id:void 0,i=[],sourceFor=t=>e.from(slackContinuationToken(t.channelId,t.threadTs)),a={cancel:({target:e,turnId:t})=>sourceFor(e).cancel({turnId:t}),clear:({target:e})=>sourceFor(e).clear(),compact:({target:e})=>sourceFor(e).compact(),envelope:e.envelope,reset:({reason:e,target:t})=>sourceFor(t).reset({reason:e}),resolveSession:({target:t})=>e.resolveSession(slackContinuationToken(t.channelId,t.threadTs)),respond:(e,{auth:t,target:n})=>sourceFor(n).respond(e,{auth:t}),send:(t,{auth:n,target:i,title:a})=>receiveOnSlack({auth:n,message:t,target:i,title:a},{from:e.from,credentials:e.credentials,installationTeamId:e.installationTeamId,teamId:r,...typeof e.envelope.event.user==`string`?{triggeringUserId:e.envelope.event.user}:{}}),slack:buildSlackWorkspaceHandle({botToken:e.credentials?.botToken,installationTeamId:e.installationTeamId,teamId:r}),waitUntil(e){i.push(e)}};try{await e.handler(a,e.envelope.event)}catch(t){logError(log,`event handler failed`,t,{eventId:e.envelope.event_id,eventType:e.envelope.event.type})}await Promise.allSettled(i)}async function verifyInbound(e,t){try{return await verifySlackRequest$1(e,{signingSecret:t?.signingSecret??(t?.webhookVerifier?void 0:process.env.SLACK_SIGNING_SECRET),webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`slack inbound verification failed`,{error:e}),null}}async function deliverSlackMessage(e){let{message:t,thread:r}=e;try{let n=formatSlackThreadContext(e.threadContext===void 0?[]:await loadThreadContextMessages(r,t,e.threadContext)),i=await collectInboundFileParts({mention:t,thread:r,policy:e.uploadPolicy}),a=formatSlackInboundMessage({botUserId:e.botUserId,channelId:t.channelId,fullName:t.author?.fullName,isMentioned:e.isMentioned,teamId:t.teamId,threadTs:t.threadTs,userId:t.author?.userId??``,userName:t.author?.userName},t),o=buildSlackTurnMessage(n===void 0?a:`${n}\n\n${a}`,i),s=e.result.context??[],c=e.isPrivateConversation?`Private message`:e.result.title??t.markdown,l=s.length===0?{auth:e.result.auth,title:c}:{auth:e.result.auth,context:s,title:c};await e.sessionOperations.send(o,l)}catch(r){logError(log,`${e.kind} delivery failed`,r,{channelId:t.channelId})}}export{constrainAuthorizationRequired,slackChannel};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isEveDevEnvironment}from"#internal/application/dev-environment.js";import{inMemory}from"#public/memory/file/backends/in-memory.js";import{lazyBackend}from"#public/memory/file/backends/lazy.js";import{vercelBlob}from"#public/memory/file/backends/vercel-blob.js";const ENVIRONMENT_PROBES={
|
|
1
|
+
import{isEveDevEnvironment}from"#internal/application/dev-environment.js";import{inMemory}from"#public/memory/file/backends/in-memory.js";import{lazyBackend}from"#public/memory/file/backends/lazy.js";import{vercelBlob}from"#public/memory/file/backends/vercel-blob.js";const ENVIRONMENT_PROBES={vercelBlobCredentials:()=>credentialsFromEnvironment(`EVE_MEMORY_BLOB`)??credentialsFromEnvironment(`BLOB`),isEveDevelopment:isEveDevEnvironment,isDeployedOnVercel:()=>hasEnvironmentValue(`VERCEL`)},DEVELOPMENT_BACKEND=inMemory();function defaultFileMemoryBackend(){return lazyBackend(()=>selectDefaultFileMemoryBackend(ENVIRONMENT_PROBES))}function selectDefaultFileMemoryBackend(e){if(e.isDeployedOnVercel()){let t=e.vercelBlobCredentials();if(t!==void 0)return vercelBlob(t);throw Error("fileMemory() requires Vercel Blob storage. Run `/add memory/file` in eve dev or `eve integration setup file-memory`, or pass fileMemory({ backend }).")}if(e.isEveDevelopment())return DEVELOPMENT_BACKEND;throw Error(`fileMemory() requires an explicit backend outside Vercel and eve dev. Pass fileMemory({ backend }).`)}function hasEnvironmentValue(e){return!!process.env[e]?.trim()}function credentialsFromEnvironment(e){let t=environmentValue(`${e}_READ_WRITE_TOKEN`);if(t!==void 0)return{token:t};let n=environmentValue(`${e}_STORE_ID`);if(n!==void 0)return{oidcToken:environmentValue(`VERCEL_OIDC_TOKEN`),storeId:n}}function environmentValue(e){let t=process.env[e]?.trim();return t===``?void 0:t}export{defaultFileMemoryBackend};
|
|
@@ -21,10 +21,11 @@ export type DockerSandboxNetworkPolicy = "allow-all" | "deny-all";
|
|
|
21
21
|
*/
|
|
22
22
|
export interface DockerSandboxCreateOptions {
|
|
23
23
|
/**
|
|
24
|
-
* Base container image for templates and sessions. Defaults to
|
|
25
|
-
* `ghcr.io/vercel/eve
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
* Base container image for templates and sessions. Defaults to eve's
|
|
25
|
+
* published `ghcr.io/vercel/eve` image, tagged with the installed eve
|
|
26
|
+
* version or `EVE_SANDBOX_IMAGE_TAG` when set. Framework setup creates
|
|
27
|
+
* `/workspace` and verifies Bash. Install
|
|
28
|
+
* any authored runtime tools in sandbox bootstrap or provide them through a
|
|
28
29
|
* custom image.
|
|
29
30
|
*/
|
|
30
31
|
readonly image?: string;
|
|
@@ -16,7 +16,7 @@ export interface MicrosandboxSandboxCreateOptions {
|
|
|
16
16
|
* Python, or ripgrep in sandbox bootstrap or provide them through a
|
|
17
17
|
* custom image.
|
|
18
18
|
*
|
|
19
|
-
* @default
|
|
19
|
+
* @default The `ghcr.io/vercel/eve` tag matching the installed eve version, or `EVE_SANDBOX_IMAGE_TAG` when set.
|
|
20
20
|
*/
|
|
21
21
|
readonly image?: string;
|
|
22
22
|
/** Number of virtual CPUs assigned to each sandbox. @default 1 */
|
|
@@ -22,7 +22,9 @@ type VercelSandboxAuthorCreateOptions<T> = T extends unknown ? Omit<T, "mounts"
|
|
|
22
22
|
* author-supplied values.
|
|
23
23
|
*
|
|
24
24
|
* `runtime` is excluded as well: eve always boots its sandboxes from the
|
|
25
|
-
* published eve image
|
|
25
|
+
* published `vcr.vercel.com/vercel/eve/base` image tagged with the installed
|
|
26
|
+
* eve version or `EVE_SANDBOX_IMAGE_TAG` when set, which is mutually exclusive
|
|
27
|
+
* with a stock runtime.
|
|
26
28
|
*
|
|
27
29
|
* `source` is honored only on the template create at prewarm time, so
|
|
28
30
|
* an author-supplied snapshot, git revision, or tarball becomes the
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createRegistrySession}from"./registry-session.js";import{PlannerNavigationError}from"#setup/prompter.js";import{WizardCancelledError}from"#setup/step.js";import{HumanActionRequiredError}from"#setup/human-action.js";import{withSpinner}from"#setup/with-spinner.js";const PLANNER_STEPS=[`Channels`,`Integrations`,`Review`];var RegistryFlowFailedError=class extends Error{completed;constructor(e,t){super(e instanceof Error?e.message:String(e),{cause:e}),this.name=`RegistryFlowFailedError`,this.completed=t}};const SECTIONS={channels:{title:`Where should people reach your agent?`,description:`You can add more later with /add.`,featured:[`channel/web`,`channel/slack`,`channel/github`,`channel/linear-agent`,`channel/photon-imessage`],includes:e=>e.name.startsWith(`channel/`)},integrations:{title:`What should your agent be able to work with?`,featured:[`extension/github-tools`,`connection/linear`,`connection/notion`,`connection/vercel`,`extension/agent-browser`],includes:e=>!e.name.startsWith(`channel/`)
|
|
1
|
+
import{createRegistrySession}from"./registry-session.js";import{PlannerNavigationError}from"#setup/prompter.js";import{WizardCancelledError}from"#setup/step.js";import{HumanActionRequiredError}from"#setup/human-action.js";import{withSpinner}from"#setup/with-spinner.js";const PLANNER_STEPS=[`Channels`,`Integrations`,`Review`];var RegistryFlowFailedError=class extends Error{completed;constructor(e,t){super(e instanceof Error?e.message:String(e),{cause:e}),this.name=`RegistryFlowFailedError`,this.completed=t}};const SECTIONS={channels:{title:`Where should people reach your agent?`,description:`You can add more later with /add.`,featured:[`channel/web`,`channel/slack`,`channel/github`,`channel/linear-agent`,`channel/photon-imessage`],includes:e=>e.name.startsWith(`channel/`)},integrations:{title:`What should your agent be able to work with?`,featured:[`extension/github-tools`,`connection/linear`,`connection/notion`,`connection/vercel`,`extension/agent-browser`,`experimental/self-modification`],includes:e=>!e.name.startsWith(`channel/`)}};function label(e){return e.title??e.name.split(`/`).at(-1)??e.name}function isPlannerItem(e,t){return t.name.includes(`/`)&&SECTIONS[e].includes(t)}function orderedSectionItems(e,t){let n=t.filter(t=>isPlannerItem(e,t)),r=SECTIONS[e].featured.map(e=>n.find(t=>t.name===e)).filter(e=>e!==void 0),i=new Set(r.map(e=>e.address));return[...r,...n.filter(e=>!i.has(e.address))]}function plannerLabel(e){return e.name===`connection/linear`?`Linear MCP`:label(e)}function sectionRows(e,t){return orderedSectionItems(e,t).map(e=>({value:e.address,label:plannerLabel(e),hint:e.description}))}function selectedInSection(e,t,n){return t.filter(t=>isPlannerItem(e,t)&&n.has(t.address)).map(e=>e.address)}function plannerNavigation(e,t){let n=(t.plannerContext?.prefixSteps??[]).map(e=>({label:e.label,complete:e.complete}));return{kind:`planner`,activeStep:n.length+e,firstNavigableStep:n.length,steps:[...n,...PLANNER_STEPS.map((e,n)=>{if(n===2)return{label:e};let r=selectedInSection(n===0?`channels`:`integrations`,t.catalog,t.selected).length;return r===0?{label:e}:{label:e,count:r}})]}}function replaceSectionSelection(e){for(let t of e.catalog)isPlannerItem(e.section,t)&&e.selected.delete(t.address);for(let t of e.addresses)e.selected.add(t)}async function editSection(e){let{section:n,catalog:r,prompter:i,selected:a}=e,s={message:SECTIONS[n].title,multiple:!0,search:!0,placeholder:n===`channels`?`Search channels`:`Search integrations`,navigation:plannerNavigation(n===`channels`?0:1,e),initialValues:selectedInSection(n,r,a),options:sectionRows(n,r)};n===`channels`&&(s.description=SECTIONS.channels.description),e.notices!==void 0&&(s.notices=e.notices);try{return replaceSectionSelection({section:n,catalog:r,selected:a,addresses:await i.select(s)}),`forward`}catch(e){if(!(e instanceof PlannerNavigationError))throw e;return replaceSectionSelection({section:n,catalog:r,selected:a,addresses:e.values.map(e=>{if(typeof e!=`string`)throw Error(`Registry planner returned a non-string item.`);return e})}),e.direction}}async function editPlan(e){let r=`channels`,i=e.notices;for(;;){if(r!==`review`){try{let t=await editSection({...e,section:r,notices:i});i=void 0,t===`back`?r===`integrations`&&(r=`channels`):r=r===`channels`?`integrations`:`review`}catch(e){if(!(e instanceof WizardCancelledError))throw e;return`cancelled`}continue}try{let t=e.selected.size>0,n=[...e.selected].map(t=>{let n=e.itemsByAddress.get(t);if(n===void 0)throw Error(`Registry item "${t}" is no longer available.`);return n}),r=n.filter(e=>e.name.startsWith(`channel/`)),a=n.filter(e=>!e.name.startsWith(`channel/`)),o=[...r.length===0?[]:[{label:`Channels`,value:r.map(label).join(`, `)}],...a.length===0?[]:[{label:`Integrations`,value:a.map(label).join(`, `)}]],s={message:e.plannerContext?.reviewMessage??`Review additions`,metadata:[...e.plannerContext?.reviewMetadata??[],...o],navigation:plannerNavigation(2,e),options:[{value:`install`,label:t?e.plannerContext?.primaryActionLabel??`Install and set up`:e.plannerContext?.emptyActionLabel??`Finish without adding`},{value:`back`,label:`Back`}]};t||(s.description=`No channels or integrations selected.`),i!==void 0&&(s.notices=i);let c=await e.prompter.select(s);if(i=void 0,c===`install`)return`install`}catch(e){if(e instanceof PlannerNavigationError&&e.direction===`back`){r=`integrations`;continue}if(!(e instanceof WizardCancelledError))throw e;return`cancelled`}r=`integrations`}}function hasSettledOutcomes(e){return e!==void 0&&(e.items.length>0||e.failures.length>0||e.outcomes!==void 0)}async function runRegistryFlow(t){let a;try{let o=t.initialAddress?.trim(),s;if(o!==void 0&&o!==``){if(await t.prompter.select({message:`Add ${o}?`,options:[{value:`install`,label:`Install and set up`},{value:`cancel`,label:`Cancel`}]})===`cancel`)return{kind:`cancelled`};s=[{address:o,name:o,source:`Registry`}]}else{let e=t.deps?.browseRegistryCatalog??(await import(`#cli/commands/registry.js`)).browseRegistryCatalog,n=await withSpinner(t.prompter,`Loading registry…`,()=>e(t.appRoot)),r=[...n.items],a=new Set,o=n.errors.map(e=>({tone:`warning`,text:`${e.registry}: ${e.message}`})),c=new Map(r.map(e=>[e.address,e]));if(await editPlan({prompter:t.prompter,catalog:r,itemsByAddress:c,selected:a,notices:o,plannerContext:t.plannerContext})!==`install`)return{kind:`cancelled`};s=[...a].map(e=>{let t=c.get(e);if(t===void 0)throw Error(`Registry item "${e}" is no longer available.`);return t})}let c=t.deps?.installRegistryItem??(await import(`#cli/commands/registry.js`)).installRegistryItem;a=createRegistrySession({detectDeployment:t.deps?.detectDeployment??(await import(`#setup/project-resolution.js`)).detectDeployment,runDeployFlow:t.deps?.runDeployFlow??(await import(`./deploy.js`)).runDeployFlow});let l=a;for(let[e,i]of s.entries()){t.signal?.throwIfAborted(),t.onItemStart?.(i,e,s.length);try{let install=(e=t.signal)=>c(t.appRoot,i.address,{silent:!0,prompter:t.prompter,signal:e}),run=()=>t.runItem===void 0?install():t.runItem(install),e=await(t.prompter.withExclusiveTerminal?.(run)??run());l.add(label(i),e.output,e.setup)}catch(e){if(t.signal?.throwIfAborted(),e instanceof WizardCancelledError){l.addCancellation(label(i));continue}if(e instanceof HumanActionRequiredError)throw e;let a=(e instanceof Error?e.message:String(e)).trim()||`Installation failed.`,o=a.split(`
|
|
2
2
|
`).find(e=>e.trim()!==``);l.addFailure(label(i),a);let s={message:`Couldn't add ${label(i)}`,options:[{value:`skip`,label:`Skip ${label(i)}`},{value:`cancel`,label:`Cancel setup`}]};if(o!==void 0&&(s.description=o),await t.prompter.select(s)===`cancel`)return{kind:`done`,result:{...l.result(),cancelled:!0}}}}return{kind:`done`,result:await l.continueAfterInstall({appRoot:t.appRoot,prompter:t.prompter,signal:t.signal})}}catch(e){if(e instanceof WizardCancelledError){let e=a?.result();return hasSettledOutcomes(e)?{kind:`done`,result:{...e,cancelled:!0}}:{kind:`cancelled`}}let t=a?.result();throw hasSettledOutcomes(t)?new RegistryFlowFailedError(e,t):e}}export{RegistryFlowFailedError,runRegistryFlow};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type SetupApplyContext, type SetupPrepareContext } from "../types.js";
|
|
2
|
+
import { applyFileMemoryBlob, type FileMemoryBlobPlan, prepareFileMemoryBlob } from "./vercel.js";
|
|
3
|
+
export interface FileMemorySetupDeps {
|
|
4
|
+
readonly applyBlob: typeof applyFileMemoryBlob;
|
|
5
|
+
readonly prepareBlob: typeof prepareFileMemoryBlob;
|
|
6
|
+
}
|
|
7
|
+
export declare function prepareFileMemorySetup(context: SetupPrepareContext, deps?: FileMemorySetupDeps): Promise<FileMemoryBlobPlan>;
|
|
8
|
+
export declare function applyFileMemorySetup(plan: FileMemoryBlobPlan, context: SetupApplyContext, deps?: FileMemorySetupDeps): Promise<{
|
|
9
|
+
deploymentRequired: true;
|
|
10
|
+
facts: {
|
|
11
|
+
label: string;
|
|
12
|
+
value: string;
|
|
13
|
+
}[];
|
|
14
|
+
}>;
|
|
15
|
+
export declare const FILE_MEMORY_SETUP: import("../types.js").SetupIntegration;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{defineSetupIntegration}from"../types.js";import{FILE_MEMORY_BLOB_ENVIRONMENTS,applyFileMemoryBlob,prepareFileMemoryBlob}from"./vercel.js";const defaultDeps={applyBlob:applyFileMemoryBlob,prepareBlob:prepareFileMemoryBlob};async function prepareFileMemorySetup(e,t=defaultDeps){let n=await e.resolveVercelProject(`file memory`);return await t.prepareBlob({appRoot:e.appRoot,project:n,signal:e.signal})}async function applyFileMemorySetup(e,n,r=defaultDeps){n.presenter.note([`Project: ${e.projectName} (${e.project.projectId})`,`Store: ${e.storeName}`,`Region: ${e.region}`,`Environments: ${FILE_MEMORY_BLOB_ENVIRONMENTS.join(`, `)}`,`Setup will create or connect a private Vercel Blob resource. Blob usage may incur charges.`].join(`
|
|
2
|
+
`),`File-memory storage`),e.regionWarning!==void 0&&n.presenter.log.warning(e.regionWarning);let i=await r.applyBlob({appRoot:n.appRoot,log:n.presenter.log,plan:e,signal:n.signal}),a=i.action===`create`?`Created`:i.action===`repair`?`Repaired`:`Reused`;return{deploymentRequired:!0,facts:[{label:`Blob store`,value:i.store.name},{label:`Vercel project`,value:e.projectName},{label:`Region`,value:i.store.region},{label:`Environments`,value:FILE_MEMORY_BLOB_ENVIRONMENTS.join(`, `)},{label:`Setup result`,value:a}]}}const FILE_MEMORY_SETUP=defineSetupIntegration({kind:`file-memory`,label:`File memory`,hint:`Store durable facts in a private Vercel Blob store`,prepare:prepareFileMemorySetup,apply:applyFileMemorySetup});export{FILE_MEMORY_SETUP,applyFileMemorySetup,prepareFileMemorySetup};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { z } from "#compiled/zod/index.js";
|
|
2
|
+
import { type ChannelSetupLog } from "#setup/cli/index.js";
|
|
3
|
+
import type { VercelProjectReference } from "#setup/project-resolution.js";
|
|
4
|
+
import { type RunVercelOptions } from "#setup/primitives/run-vercel.js";
|
|
5
|
+
export declare const FILE_MEMORY_BLOB_PREFIX = "EVE_MEMORY_";
|
|
6
|
+
export declare const FILE_MEMORY_BLOB_ENVIRONMENTS: readonly ["production", "preview", "development"];
|
|
7
|
+
declare const ProjectSchema: z.ZodObject<{
|
|
8
|
+
id: z.ZodString;
|
|
9
|
+
name: z.ZodString;
|
|
10
|
+
resourceConfig: z.ZodOptional<z.ZodObject<{
|
|
11
|
+
functionDefaultRegions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
12
|
+
}, z.core.$strip>>;
|
|
13
|
+
defaultResourceConfig: z.ZodOptional<z.ZodObject<{
|
|
14
|
+
functionDefaultRegions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
15
|
+
}, z.core.$strip>>;
|
|
16
|
+
}, z.core.$loose>;
|
|
17
|
+
declare const StoreReferenceSchema: z.ZodObject<{
|
|
18
|
+
id: z.ZodString;
|
|
19
|
+
name: z.ZodString;
|
|
20
|
+
projects: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
21
|
+
id: z.ZodString;
|
|
22
|
+
name: z.ZodString;
|
|
23
|
+
}, z.core.$loose>>>;
|
|
24
|
+
region: z.ZodOptional<z.ZodString>;
|
|
25
|
+
}, z.core.$loose>;
|
|
26
|
+
declare const StoreSchema: z.ZodObject<{
|
|
27
|
+
access: z.ZodEnum<{
|
|
28
|
+
private: "private";
|
|
29
|
+
public: "public";
|
|
30
|
+
}>;
|
|
31
|
+
id: z.ZodString;
|
|
32
|
+
name: z.ZodString;
|
|
33
|
+
region: z.ZodString;
|
|
34
|
+
type: z.ZodOptional<z.ZodString>;
|
|
35
|
+
}, z.core.$loose>;
|
|
36
|
+
declare const StoreConnectionSchema: z.ZodObject<{
|
|
37
|
+
envVarEnvironments: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
38
|
+
envVarPrefix: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
39
|
+
id: z.ZodOptional<z.ZodString>;
|
|
40
|
+
projectId: z.ZodString;
|
|
41
|
+
}, z.core.$loose>;
|
|
42
|
+
export type VercelProjectConfiguration = z.infer<typeof ProjectSchema>;
|
|
43
|
+
export type BlobStoreReference = z.infer<typeof StoreReferenceSchema>;
|
|
44
|
+
export type BlobStore = z.infer<typeof StoreSchema>;
|
|
45
|
+
export type BlobStoreConnection = z.infer<typeof StoreConnectionSchema>;
|
|
46
|
+
export interface FileMemoryVercelClient {
|
|
47
|
+
createStore(input: {
|
|
48
|
+
name: string;
|
|
49
|
+
region: string;
|
|
50
|
+
}): Promise<BlobStore>;
|
|
51
|
+
connectStore(input: {
|
|
52
|
+
environments: readonly string[];
|
|
53
|
+
prefix: string;
|
|
54
|
+
projectId: string;
|
|
55
|
+
storeName: string;
|
|
56
|
+
}): Promise<void>;
|
|
57
|
+
getConnections(storeId: string): Promise<readonly BlobStoreConnection[]>;
|
|
58
|
+
getProject(): Promise<VercelProjectConfiguration>;
|
|
59
|
+
getStore(storeId: string): Promise<BlobStore>;
|
|
60
|
+
listStores(): Promise<readonly BlobStoreReference[]>;
|
|
61
|
+
pullEnvironment(): Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
export type FileMemoryBlobAction = "create" | "repair" | "reuse";
|
|
64
|
+
export interface FileMemoryBlobPlan {
|
|
65
|
+
readonly action: FileMemoryBlobAction;
|
|
66
|
+
readonly project: VercelProjectReference;
|
|
67
|
+
readonly projectName: string;
|
|
68
|
+
readonly region: string;
|
|
69
|
+
readonly storeId?: string;
|
|
70
|
+
readonly storeName: string;
|
|
71
|
+
readonly regionWarning?: string;
|
|
72
|
+
}
|
|
73
|
+
export interface FileMemoryBlobResult {
|
|
74
|
+
readonly action: FileMemoryBlobAction;
|
|
75
|
+
readonly store: BlobStore;
|
|
76
|
+
}
|
|
77
|
+
interface FileMemoryVercelClientInput {
|
|
78
|
+
readonly appRoot: string;
|
|
79
|
+
readonly project: VercelProjectReference;
|
|
80
|
+
readonly signal?: AbortSignal;
|
|
81
|
+
readonly onOutput?: RunVercelOptions["onOutput"];
|
|
82
|
+
}
|
|
83
|
+
export declare function createFileMemoryVercelClient(input: FileMemoryVercelClientInput): FileMemoryVercelClient;
|
|
84
|
+
export declare function resolveFileMemoryRegion(input: {
|
|
85
|
+
readonly localRegions?: readonly string[];
|
|
86
|
+
readonly project: Pick<VercelProjectConfiguration, "defaultResourceConfig" | "resourceConfig">;
|
|
87
|
+
}): string;
|
|
88
|
+
export declare function fileMemoryStoreName(projectName: string, projectId: string): string;
|
|
89
|
+
export declare function prepareFileMemoryBlob(input: {
|
|
90
|
+
readonly appRoot: string;
|
|
91
|
+
readonly project: VercelProjectReference;
|
|
92
|
+
readonly client?: FileMemoryVercelClient;
|
|
93
|
+
readonly localRegions?: () => Promise<readonly string[] | undefined>;
|
|
94
|
+
readonly signal?: AbortSignal;
|
|
95
|
+
}): Promise<FileMemoryBlobPlan>;
|
|
96
|
+
export declare function applyFileMemoryBlob(input: {
|
|
97
|
+
readonly client?: FileMemoryVercelClient;
|
|
98
|
+
readonly log: ChannelSetupLog;
|
|
99
|
+
readonly plan: FileMemoryBlobPlan;
|
|
100
|
+
readonly appRoot: string;
|
|
101
|
+
readonly signal?: AbortSignal;
|
|
102
|
+
}): Promise<FileMemoryBlobResult>;
|
|
103
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFile}from"node:fs/promises";import{z}from"#compiled/zod/index.js";import{join}from"node:path";import{captureVercel}from"#setup/primitives/run-vercel.js";import{createPromptCommandOutput,withPhase}from"#setup/cli/index.js";const FILE_MEMORY_BLOB_PREFIX=`EVE_MEMORY_`,FILE_MEMORY_BLOB_ENVIRONMENTS=[`production`,`preview`,`development`],ProjectSchema=z.object({id:z.string().min(1),name:z.string().min(1),resourceConfig:z.object({functionDefaultRegions:z.array(z.string().min(1)).optional()}).optional(),defaultResourceConfig:z.object({functionDefaultRegions:z.array(z.string().min(1)).optional()}).optional()}).passthrough(),StoreReferenceSchema=z.object({id:z.string().min(1),name:z.string().min(1),projects:z.array(z.object({id:z.string().min(1),name:z.string().min(1)}).passthrough()).default([]),region:z.string().min(1).optional()}).passthrough(),StoreSchema=z.object({access:z.enum([`private`,`public`]),id:z.string().min(1),name:z.string().min(1),region:z.string().min(1),type:z.string().optional()}).passthrough(),StoreConnectionSchema=z.object({envVarEnvironments:z.array(z.string()).default([]),envVarPrefix:z.string().nullish(),id:z.string().optional(),projectId:z.string().min(1)}).passthrough();function parseJson(e,t,n){try{return t.parse(JSON.parse(e))}catch{throw Error(`Vercel returned invalid ${n} data. Upgrade the Vercel CLI and try again.`)}}function commandFailure(e,t){let n=[t.failure.stderr,t.failure.stdout,t.failure.message].find(e=>e.trim().length>0);return Error(n===void 0?`${e} failed.`:`${e} failed: ${n.trim()}`)}function createFileMemoryVercelClient(e){let n={cwd:e.appRoot,nonInteractive:!0,onOutput:e.onOutput,signal:e.signal},i=[`--scope`,e.project.orgId];async function captureJson(t,i,a,o){let s=await captureVercel(t,{...n,stdin:o});if(e.signal?.throwIfAborted(),!s.ok)throw commandFailure(a,s);return parseJson(s.stdout,i,a.toLowerCase())}async function captureMutation(t,i){let a=await captureVercel(t,n);if(e.signal?.throwIfAborted(),!a.ok)throw commandFailure(i,a)}return{async createStore({name:e,region:n}){return(await captureJson([`api`,`/v1/storage/stores/blob`,`-X`,`POST`,`--input`,`-`,`--raw`,...i],z.object({store:StoreSchema}),`Vercel Blob store creation`,JSON.stringify({access:`private`,name:e,region:n}))).store},async connectStore({environments:e,prefix:t,projectId:n,storeName:r}){await captureMutation([`integration-resource`,`connect`,r,n,`--prefix`,t,...e.flatMap(e=>[`--environment`,e]),`--yes`,`--json`,...i],`Vercel Blob project connection`)},async getConnections(e){return(await captureJson([`api`,`/v1/storage/stores/${encodeURIComponent(e)}/connections`,`--raw`,...i],z.object({connections:z.array(StoreConnectionSchema)}),`Vercel Blob connections lookup`)).connections},async getProject(){return await captureJson([`api`,`/v9/projects/${encodeURIComponent(e.project.projectId)}?teamId=${encodeURIComponent(e.project.orgId)}`,`--raw`,...i],ProjectSchema,`Vercel project lookup`)},async getStore(e){return(await captureJson([`api`,`/v1/storage/stores/${encodeURIComponent(e)}`,`--raw`,...i],z.object({store:StoreSchema}),`Vercel Blob store lookup`)).store},async listStores(){return(await captureJson([`blob`,`list-stores`,`--all`,`--json`,...i],z.object({stores:z.array(StoreReferenceSchema)}),`Vercel Blob stores lookup`)).stores},async pullEnvironment(){await captureMutation([`env`,`pull`,`.env.local`,`--yes`,`--project`,e.project.projectId,...i],`Vercel environment pull`)}}}function resolveFileMemoryRegion(e){return e.localRegions?.[0]??e.project.resourceConfig?.functionDefaultRegions?.[0]??e.project.defaultResourceConfig?.functionDefaultRegions?.[0]??`iad1`}function fileMemoryStoreName(e,t){let n=e.toLowerCase().replace(/[^a-z0-9]+/gu,`-`).replace(/^-+|-+$/gu,``)||`project`,r=t.toLowerCase().replace(/[^a-z0-9]+/gu,``).slice(-8)||`memory`,i=12+r.length;return`eve-memory-${n.slice(0,64-i).replace(/-+$/gu,``)}-${r}`}async function readLocalRegions(r){try{let i=await readFile(join(r,`vercel.json`),`utf8`),a=z.object({regions:z.array(z.string().min(1)).optional()}).safeParse(JSON.parse(i));if(!a.success)throw Error("vercel.json has an invalid `regions` value.");return a.data.regions}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return;throw e instanceof SyntaxError?Error(`vercel.json contains invalid JSON.`):e}}function hasProject(e,t){return e.projects.some(e=>e.id===t)}function exactConnection(e,t){return e.projectId===t&&e.envVarPrefix===`EVE_MEMORY_`}function isEveMemoryConnection(e,t){return e.projectId===t&&e.envVarPrefix?.startsWith(`EVE_MEMORY_`)===!0}function assertPrivateBlobStore(e){if(e.type!==void 0&&e.type!==`blob`)throw Error(`Vercel resource "${e.name}" uses the eve file-memory prefix but is not a Blob store. Disconnect that binding before retrying.`);if(e.access!==`private`)throw Error(`Vercel Blob store "${e.name}" is public. Disconnect an eve-prefixed binding or choose a private store before retrying; eve will not replace it automatically.`)}function assertCompleteConnection(e,t){if(FILE_MEMORY_BLOB_ENVIRONMENTS.filter(t=>!e.envVarEnvironments.includes(t)).length>0)throw Error(`Vercel Blob store "${t}" has an incomplete ${FILE_MEMORY_BLOB_PREFIX} connection. Reconnect it for production, preview, and development before retrying; eve will not disconnect or replace it automatically.`)}async function inspectStore(e,t){let[n,r]=await Promise.all([t.getStore(e.id),t.getConnections(e.id)]);return{connections:r,store:n}}async function prepareFileMemoryBlob(e){let t=e.client??createFileMemoryVercelClient({appRoot:e.appRoot,project:e.project,signal:e.signal}),[n,r,i]=await Promise.all([t.getProject(),e.localRegions?.()??readLocalRegions(e.appRoot),t.listStores()]);if(e.signal?.throwIfAborted(),n.id!==e.project.projectId)throw Error(`Vercel returned project "${n.id}" while file-memory setup expected "${e.project.projectId}". Relink the project and retry.`);let a=resolveFileMemoryRegion({localRegions:r,project:n}),s=fileMemoryStoreName(n.name,n.id),c=i.filter(t=>t.name===s||hasProject(t,e.project.projectId)),l=await Promise.all(c.map(async e=>await inspectStore(e,t))),u=l.flatMap(t=>t.connections.filter(t=>exactConnection(t,e.project.projectId)).map(e=>({candidate:t,connection:e})));if(u.length>1)throw Error(`Multiple Vercel Blob connections target project "${n.name}" with prefix ${FILE_MEMORY_BLOB_PREFIX}. Disconnect the extra binding before retrying.`);if(u.length===1){let t=u[0];if(t===void 0)throw Error(`Expected an eve file-memory Blob store.`);let{candidate:r,connection:i}=t;assertPrivateBlobStore(r.store),assertCompleteConnection(i,r.store.name);let o=r.store.region===a?void 0:`The existing file-memory store remains in ${r.store.region}; the project now prefers ${a}. eve preserved the store to avoid memory loss.`;return{action:`reuse`,project:e.project,projectName:n.name,region:r.store.region,regionWarning:o,storeId:r.store.id,storeName:r.store.name}}let d=l.find(({connections:t})=>t.some(t=>isEveMemoryConnection(t,e.project.projectId)));if(d!==void 0)throw Error(`Vercel resource "${d.store.name}" has an incompatible eve file-memory prefix. Disconnect it before retrying; eve will not change an ambiguous binding automatically.`);let f=l.filter(({store:e})=>e.name===s);if(f.length>1)throw Error(`Multiple Vercel Blob stores match the expected file-memory name "${s}". Rename or remove the duplicate before retrying.`);if(f.length===1){let t=f[0];if(t===void 0)throw Error(`Expected a file-memory Blob store candidate.`);if(assertPrivateBlobStore(t.store),t.store.region!==a)throw Error(`Unconnected Vercel Blob store "${s}" is in ${t.store.region}, but project "${n.name}" uses ${a}. Rename that store or connect it manually; eve will not replace it automatically.`);if(t.connections.length>0)throw Error(`Vercel Blob store "${s}" already has a project connection, so eve cannot safely adopt it. Disconnect it or choose a different store before retrying.`);return{action:`repair`,project:e.project,projectName:n.name,region:a,storeId:t.store.id,storeName:s}}return{action:`create`,project:e.project,projectName:n.name,region:a,storeName:s}}async function verifyFileMemoryBlob(e,t,n){let[r,i]=await Promise.all([n.getStore(t),n.getConnections(t)]);if(assertPrivateBlobStore(r),r.name!==e.storeName)throw Error(`Vercel connected an unexpected Blob store named "${r.name}".`);if(r.region!==e.region)throw Error(`Vercel Blob store "${r.name}" is in ${r.region}, but setup expected ${e.region}.`);let a=i.filter(t=>exactConnection(t,e.project.projectId));if(a.length!==1)throw Error(`Vercel Blob store "${r.name}" does not have exactly one ${FILE_MEMORY_BLOB_PREFIX} connection to project "${e.projectName}".`);let s=a[0];if(s===void 0)throw Error(`Expected a verified eve file-memory connection.`);return assertCompleteConnection(s,r.name),r}async function applyFileMemoryBlob(e){let t=createPromptCommandOutput(e.log),n=e.client??createFileMemoryVercelClient({appRoot:e.appRoot,onOutput:t,project:e.plan.project,signal:e.signal}),r=e.plan.storeId;if(e.plan.action===`create`){let t=await withPhase(e.log,`Creating private Vercel Blob store...`,async()=>await n.createStore({name:e.plan.storeName,region:e.plan.region}));if(assertPrivateBlobStore(t),t.name!==e.plan.storeName||t.region!==e.plan.region)throw Error(`Vercel created Blob store "${t.name}" in ${t.region}, but setup expected "${e.plan.storeName}" in ${e.plan.region}.`);r=t.id}if(r===void 0)throw Error(`File-memory Blob setup did not resolve a store ID.`);e.plan.action!==`reuse`&&await withPhase(e.log,`Connecting file memory to the Vercel project...`,async()=>await n.connectStore({environments:FILE_MEMORY_BLOB_ENVIRONMENTS,prefix:FILE_MEMORY_BLOB_PREFIX,projectId:e.plan.project.projectId,storeName:e.plan.storeName})),await withPhase(e.log,`Pulling Vercel environment variables...`,async()=>await n.pullEnvironment());let c=await withPhase(e.log,`Verifying file-memory storage...`,async()=>await verifyFileMemoryBlob(e.plan,r,n));return{action:e.plan.action,store:c}}export{FILE_MEMORY_BLOB_ENVIRONMENTS,FILE_MEMORY_BLOB_PREFIX,applyFileMemoryBlob,createFileMemoryVercelClient,fileMemoryStoreName,prepareFileMemoryBlob,resolveFileMemoryRegion};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DISCORD_SETUP}from"./discord/setup.js";import{GITHUB_SETUP}from"./github/setup.js";import{LINEAR_SETUP}from"./linear/setup.js";import{LINQ_SETUP}from"./linq/setup.js";import{PHOTON_SETUP}from"./photon/setup.js";import{SHOPIFY_SETUP}from"./shopify/setup.js";import{SLACK_SETUP}from"./slack/setup.js";import{WEB_SETUP}from"./web/setup.js";import{createSetupContexts,createSetupPresenter}from"./shared/ui.js";const SETUP_INTEGRATIONS=[WEB_SETUP,SLACK_SETUP,DISCORD_SETUP,GITHUB_SETUP,LINEAR_SETUP,LINQ_SETUP,PHOTON_SETUP,SHOPIFY_SETUP];function setupIntegration(e){let t=SETUP_INTEGRATIONS.find(t=>t.kind===e);if(t===void 0)throw Error(`Integration setup "${e}" is not available in this version of eve. Upgrade eve and try again.`);return t}export{SETUP_INTEGRATIONS,createSetupContexts,createSetupPresenter,setupIntegration};
|
|
1
|
+
import{DISCORD_SETUP}from"./discord/setup.js";import{FILE_MEMORY_SETUP}from"./file-memory/setup.js";import{GITHUB_SETUP}from"./github/setup.js";import{LINEAR_SETUP}from"./linear/setup.js";import{LINQ_SETUP}from"./linq/setup.js";import{PHOTON_SETUP}from"./photon/setup.js";import{SHOPIFY_SETUP}from"./shopify/setup.js";import{SLACK_SETUP}from"./slack/setup.js";import{WEB_SETUP}from"./web/setup.js";import{createSetupContexts,createSetupPresenter}from"./shared/ui.js";const SETUP_INTEGRATIONS=[WEB_SETUP,FILE_MEMORY_SETUP,SLACK_SETUP,DISCORD_SETUP,GITHUB_SETUP,LINEAR_SETUP,LINQ_SETUP,PHOTON_SETUP,SHOPIFY_SETUP];function setupIntegration(e){let t=SETUP_INTEGRATIONS.find(t=>t.kind===e);if(t===void 0)throw Error(`Integration setup "${e}" is not available in this version of eve. Upgrade eve and try again.`);return t}export{SETUP_INTEGRATIONS,createSetupContexts,createSetupPresenter,setupIntegration};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{SetupPrerequisiteRequired}from"./prerequisite.js";import{readProjectLink}from"#setup/project-resolution.js";const defaultDeps={readProjectLink};async function resolveIntegrationVercelProject(e){e.signal?.throwIfAborted();let t=await(e.deps??defaultDeps).readProjectLink(e.appRoot);if(t!==void 0)return t;throw new SetupPrerequisiteRequired({kind:`command`,code:`vercel-project-link`,message
|
|
1
|
+
import{SetupPrerequisiteRequired}from"./prerequisite.js";import{readProjectLink}from"#setup/project-resolution.js";const defaultDeps={readProjectLink};async function resolveIntegrationVercelProject(e){e.signal?.throwIfAborted();let t=await(e.deps??defaultDeps).readProjectLink(e.appRoot);if(t!==void 0)return t;throw new SetupPrerequisiteRequired({kind:`command`,code:`vercel-project-link`,message:`${e.integration} setup requires a linked Vercel project. Run \`eve link\`, then retry.`,command:`eve link`})}export{resolveIntegrationVercelProject};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{connectionEntries,connectionProtocols}from"../../../packages/eve-catalog/src/index.js";const SUPPORTED_PROTOCOLS=[`mcp`],CUSTOM_CONNECTION_SLUG=`custom`,CONNECTION_AUTH={linear:{kind:`connect`,connector:`linear`,service:`mcp.linear.app`},notion:{kind:`connect`,connector:`notion`,service:`mcp.notion.com`},datadog:{kind:`connect`,connector:`datadog`,service:`mcp.datadoghq.com`},honeycomb:{kind:`connect`,connector:`honeycomb`,service:`mcp.honeycomb.io`}};function buildCatalogEntry(e,n,r){let i=CONNECTION_AUTH[e];if(i===void 0)throw Error(`Connection "${e}" is in the catalog but has no scaffolder auth overlay.`);let a={slug:e,label:n,protocols:connectionProtocols(r),description:r.description,auth:i};return r.mcp&&(a.mcp={url:r.mcp.url}),r.openapi&&(a.openapi={spec:r.openapi.spec,baseUrl:r.openapi.baseUrl}),a}const CONNECTION_CATALOG=connectionEntries().filter(e=>e.surfaces.scaffoldable).map(e=>{if(e.connection===void 0)throw Error(`Catalog connection "${e.slug}" is missing its connection identity.`);return buildCatalogEntry(e.slug,e.name,e.connection)}),CATALOG_BY_SLUG=new Map(CONNECTION_CATALOG.map(e=>[e.slug,e]));function getCatalogEntry(e){return CATALOG_BY_SLUG.get(e)}function catalogSlugs(){return CONNECTION_CATALOG.map(e=>e.slug)}function effectiveProtocols(e){let t=e===void 0||e.length===0?SUPPORTED_PROTOCOLS:e;return SUPPORTED_PROTOCOLS.filter(e=>t.includes(e))}const CONNECTION_SLUG_PATTERN=/^[a-z][a-z0-9-]{0,63}$/;function isValidConnectionSlug(e){return CONNECTION_SLUG_PATTERN.test(e)}function connectorServiceForEntry(e){if(e.auth.kind===`connect`)return e.auth.service?e.auth.service:mcpServiceHost(e.mcp?.url)}function canonicalConnectorNameForEntry(e){if(e.auth?.kind!==`connect`)return;let t=e.auth.connector.trim();return t.length>0?t:void 0}function mcpServiceHost(e){if(e)try{return new URL(e).host||void 0}catch{return}}function endpointForProtocol(e,t){return t===`mcp`?e.mcp??null:e.openapi??null}export{CONNECTION_CATALOG,CUSTOM_CONNECTION_SLUG,SUPPORTED_PROTOCOLS,canonicalConnectorNameForEntry,catalogSlugs,connectorServiceForEntry,effectiveProtocols,endpointForProtocol,getCatalogEntry,isValidConnectionSlug,mcpServiceHost};
|
|
1
|
+
import{connectionEntries,connectionProtocols}from"../../../packages/eve-catalog/src/index.js";const SUPPORTED_PROTOCOLS=[`mcp`],CUSTOM_CONNECTION_SLUG=`custom`,CONNECTION_AUTH={"browser-use":{kind:`header`,headers:[{header:`x-browser-use-api-key`,envVar:`BROWSER_USE_API_KEY`}]},linear:{kind:`connect`,connector:`linear`,service:`mcp.linear.app`},notion:{kind:`connect`,connector:`notion`,service:`mcp.notion.com`},datadog:{kind:`connect`,connector:`datadog`,service:`mcp.datadoghq.com`},honeycomb:{kind:`connect`,connector:`honeycomb`,service:`mcp.honeycomb.io`}};function buildCatalogEntry(e,n,r){let i=CONNECTION_AUTH[e];if(i===void 0)throw Error(`Connection "${e}" is in the catalog but has no scaffolder auth overlay.`);let a={slug:e,label:n,protocols:connectionProtocols(r),description:r.description,auth:i};return r.mcp&&(a.mcp={url:r.mcp.url}),r.openapi&&(a.openapi={spec:r.openapi.spec,baseUrl:r.openapi.baseUrl}),a}const CONNECTION_CATALOG=connectionEntries().filter(e=>e.surfaces.scaffoldable).map(e=>{if(e.connection===void 0)throw Error(`Catalog connection "${e.slug}" is missing its connection identity.`);return buildCatalogEntry(e.slug,e.name,e.connection)}),CATALOG_BY_SLUG=new Map(CONNECTION_CATALOG.map(e=>[e.slug,e]));function getCatalogEntry(e){return CATALOG_BY_SLUG.get(e)}function catalogSlugs(){return CONNECTION_CATALOG.map(e=>e.slug)}function effectiveProtocols(e){let t=e===void 0||e.length===0?SUPPORTED_PROTOCOLS:e;return SUPPORTED_PROTOCOLS.filter(e=>t.includes(e))}const CONNECTION_SLUG_PATTERN=/^[a-z][a-z0-9-]{0,63}$/;function isValidConnectionSlug(e){return CONNECTION_SLUG_PATTERN.test(e)}function connectorServiceForEntry(e){if(e.auth.kind===`connect`)return e.auth.service?e.auth.service:mcpServiceHost(e.mcp?.url)}function canonicalConnectorNameForEntry(e){if(e.auth?.kind!==`connect`)return;let t=e.auth.connector.trim();return t.length>0?t:void 0}function mcpServiceHost(e){if(e)try{return new URL(e).host||void 0}catch{return}}function endpointForProtocol(e,t){return t===`mcp`?e.mcp??null:e.openapi??null}export{CONNECTION_CATALOG,CUSTOM_CONNECTION_SLUG,SUPPORTED_PROTOCOLS,canonicalConnectorNameForEntry,catalogSlugs,connectorServiceForEntry,effectiveProtocols,endpointForProtocol,getCatalogEntry,isValidConnectionSlug,mcpServiceHost};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{parseChatGptModelSelection}from"../../../shared/chatgpt-model.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.82`,DEFAULT_CONNECT_PACKAGE_VERSION=`1.0.0`,DEFAULT_ZOD_PACKAGE_VERSION=`4.5.4`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.
|
|
1
|
+
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{parseChatGptModelSelection}from"../../../shared/chatgpt-model.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.82`,DEFAULT_CONNECT_PACKAGE_VERSION=`1.0.0`,DEFAULT_ZOD_PACKAGE_VERSION=`4.5.4`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.49.1`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e,t){return{"agent/agent.ts":renderAgentTemplate(e,t),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderAgentTemplate(e,n){let r=parseChatGptModelSelection(e);return r===void 0?BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(n)):`import { defineAgent } from "eve";\nimport { chatgpt } from "eve/models/openai";\n\nexport default defineAgent({\n model: chatgpt(${JSON.stringify(r)}),\n${reasoningTemplateLine(n)}});\n`}function reasoningTemplateLine(e){return e===void 0||e===`provider-default`?``:` reasoning: "${e}",\n`}function renderTemplate(e,n){return e===BASE_AGENT_TEMPLATE&&parseChatGptModelSelection(n.model)!==void 0?renderAgentTemplate(n.model,n.reasoning):e.replaceAll(`__EVE_INIT_APP_NAME__`,n.appName).replaceAll(`__EVE_INIT_MODEL__`,n.model).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(n.reasoning)).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(n.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(n.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(n.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,n.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,n.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,n.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,n.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,n.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,n.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
|
|
2
2
|
|
|
3
3
|
export default defineAgent({
|
|
4
4
|
model: "__EVE_INIT_MODEL__",
|
package/docs/channels/custom.mdx
CHANGED
|
@@ -82,6 +82,10 @@ part of the authored channel API.
|
|
|
82
82
|
|
|
83
83
|
Channel operations are dynamic: every call targets whichever session currently
|
|
84
84
|
owns the address. Only `send()` can create a session when the address is unowned.
|
|
85
|
+
Cold-start sends return their accepted candidate without waiting for address
|
|
86
|
+
ownership. If simultaneous sends race, eve forwards the losing candidate's
|
|
87
|
+
message to the winner; resolve the address after startup when you need a fixed
|
|
88
|
+
handle to the canonical owner.
|
|
85
89
|
|
|
86
90
|
```ts
|
|
87
91
|
const source = from(threadId);
|
package/docs/channels/eve.mdx
CHANGED
|
@@ -47,22 +47,26 @@ curl -X POST https://<deployment>/eve/v1/session \
|
|
|
47
47
|
# {"ok":true,"sessionId":"wrun_A","status":"accepted"}
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
The `202` response means Workflow accepted the durable run. The
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
The `202` response means Workflow accepted the durable run. The route does not wait for command
|
|
51
|
+
inbox or continuation-token ownership. The inbox may still be starting, so an immediate follow-up
|
|
52
|
+
or control request can report that the session is not active. The event-stream client retries the
|
|
53
|
+
brief window before the new run becomes readable.
|
|
53
54
|
|
|
54
55
|
Authenticated callers that may retry a create request can pass their own `operationId` for
|
|
55
|
-
create-once semantics.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
create-once semantics. Once the operation owner is active, the same operation under the same
|
|
57
|
+
authenticated principal returns that session instead of dispatching the input again. The create
|
|
58
|
+
route does not wait for a concurrently starting request to publish ownership: simultaneous
|
|
59
|
+
requests can receive different accepted candidate IDs, while only the candidate that claims the
|
|
60
|
+
operation runs its first turn. Retry the operation after startup when you need its canonical
|
|
61
|
+
session ID. Anonymous callers cannot use `operationId`, and operation ownership expires when the
|
|
62
|
+
session is no longer resumable.
|
|
59
63
|
|
|
60
64
|
```bash
|
|
61
65
|
curl -X POST https://<deployment>/eve/v1/session \
|
|
62
66
|
-H "Authorization: Bearer <token>" \
|
|
63
67
|
-H "Content-Type: application/json" \
|
|
64
68
|
-d '{"message":"What is the weather in Paris?","operationId":"order-4213-research"}'
|
|
65
|
-
# {"ok":true,"sessionId":"wrun_A","status":"accepted"}
|
|
69
|
+
# {"ok":true,"sessionId":"wrun_A","status":"accepted"}
|
|
66
70
|
```
|
|
67
71
|
|
|
68
72
|
The first request requires `message`. A follow-up request accepts exactly one of
|
package/docs/channels/mcp.mdx
CHANGED
|
@@ -171,7 +171,10 @@ MCP clients receive four tools:
|
|
|
171
171
|
| `agent_update` | `{ invocationId, responses }` | Answer the complete pending human-input batch. |
|
|
172
172
|
| `agent_cancel` | `{ invocationId }` | Request cooperative cancellation of non-terminal work. |
|
|
173
173
|
|
|
174
|
-
`agent_start` creates one task-mode eve session and returns after durable acceptance
|
|
174
|
+
`agent_start` creates one task-mode eve session and returns after durable acceptance without
|
|
175
|
+
waiting for the session continuation hook to become readable. Keep its `invocationId`, then call
|
|
176
|
+
`agent_get` until the invocation reaches a terminal state. While the status is `working`, wait at
|
|
177
|
+
least `pollAfterMs` before polling again.
|
|
175
178
|
|
|
176
179
|
The invocation response is discriminated by `status`:
|
|
177
180
|
|
package/docs/channels/slack.mdx
CHANGED
|
@@ -410,7 +410,7 @@ when you need the bearer token itself.
|
|
|
410
410
|
|
|
411
411
|
### Delivery
|
|
412
412
|
|
|
413
|
-
The default handlers reply in-thread and show
|
|
413
|
+
The default handlers reply in-thread and show activity. Typing indicators post automatically: `Thinking…` on inbound, `Working…` on `turn.started`, a truncated reasoning snippet on `reasoning.appended`, and an action label on `actions.requested` — the tool name plus its most telling argument (`grep useEveAgent`, `read_file agent/agent.ts`), the subagent or remote-agent name for dispatched calls, and `+N more` when the model requests several actions at once. The model's own pre-tool narration, when present, takes precedence over the derived label. Reasoning snippets build progressively: extensions of at least four characters appear immediately, while smaller streamed deltas use the five-second refresh interval to avoid one Slack request per token. Override `events["reasoning.appended"]` if you prefer generic wording. Override an inbound handler or the `events` handlers to customize.
|
|
414
414
|
|
|
415
415
|
Outbound text preserves bare `@` tokens as literal text. To mention a user, embed Slack's `<@USER_ID>` syntax directly or use `channel.thread.mentionUser(userId)`.
|
|
416
416
|
|
|
@@ -58,7 +58,7 @@ You are responsible for ensuring any observability or eval provider is approved
|
|
|
58
58
|
|
|
59
59
|
The third configurable surface, [runtime context events](#runtime-context), attaches per-model-call values to these spans.
|
|
60
60
|
|
|
61
|
-
Built-in messaging channels classify their instrumentation metadata with an `audience`: `public`, `private`, or `unknown`. Slack public channels and Chat SDK workspace-visible threads are public; direct and private conversations are private; platform surfaces without enough visibility evidence remain unknown.
|
|
61
|
+
Built-in messaging channels classify their instrumentation metadata with an `audience`: `public`, `private`, or `unknown`. Slack public channels and Chat SDK workspace-visible threads are public; direct and private conversations are private; platform surfaces without enough visibility evidence remain unknown. Proactive Slack `receive` / `ctx.send` handoffs stay `unknown` unless the caller passes `audience` on the target, for example when a webhook or schedule already knows the destination channel is public.
|
|
62
62
|
|
|
63
63
|
## Channel delivery traces
|
|
64
64
|
|
|
@@ -14,6 +14,7 @@ Run `eve add` from an eve agent project. This installs the integration's depende
|
|
|
14
14
|
eve add extension/agent-browser
|
|
15
15
|
eve add linear
|
|
16
16
|
eve add instrumentation/braintrust
|
|
17
|
+
eve add memory/file
|
|
17
18
|
```
|
|
18
19
|
|
|
19
20
|
If an item is not found, `eve add` searches the available catalogs and prints close matches without installing anything.
|
|
@@ -26,6 +27,10 @@ Some integrations package several independently installable components. For exam
|
|
|
26
27
|
|
|
27
28
|
When an official item declares an interactive setup flow or flows, eve asks whether to run them after installation and runs multiple flows in declaration order. Run the printed `eve add <item> --skip-install` command to resume a skipped or cancelled setup later; it reruns the selected components' declared flows from the beginning.
|
|
28
29
|
|
|
30
|
+
For example, `eve add memory/file` can provision its required storage through the same setup flow. After **Install and set up**, eve creates or reuses a dedicated private Vercel Blob store, connects production, preview, and development with namespaced credentials, pulls the environment, and offers to deploy. The review and setup transcript show the project, store, primary function region, environments, and possible Blob usage charges before provisioning.
|
|
31
|
+
|
|
32
|
+
An official item may identify optional pnpm dependencies that have build scripts. Before installation, eve asks whether to skip those optional packages, allow their build scripts, or abort. Your choice updates `ignoredOptionalDependencies` or `allowBuilds` in the pnpm workspace that owns the project. Allow build scripts only when you trust the packages named in the prompt.
|
|
33
|
+
|
|
29
34
|
## Automate setup
|
|
30
35
|
|
|
31
36
|
Use `eve add <item> --non-interactive` when a script or coding agent cannot answer terminal prompts. It prints NDJSON events and exits with a status you can branch on:
|
package/docs/instructions.mdx
CHANGED
|
@@ -99,4 +99,4 @@ Where an eve agent communicates with people, you may be required to disclose tha
|
|
|
99
99
|
- [Tools](./tools): typed actions, the next capability to add
|
|
100
100
|
- [Context control](./concepts/context-control): all the levers for what the model sees
|
|
101
101
|
- [Skills](./skills): on-demand procedures, the counterpart to always-on instructions
|
|
102
|
-
- [
|
|
102
|
+
- [Memory](./memory): provider-backed context that outlives a session, recalled before each turn
|