eve 0.84.1 → 0.85.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/dist/src/channel/channel-operations.d.ts +2 -18
- package/dist/src/channel/compiled-channel.d.ts +3 -7
- package/dist/src/channel/cross-channel-receive.d.ts +9 -10
- package/dist/src/channel/cross-channel-receive.js +1 -1
- package/dist/src/channel/schedule.js +1 -1
- package/dist/src/channel/session.d.ts +26 -4
- package/dist/src/channel/session.js +1 -1
- package/dist/src/chunks/{use-eve-agent-DMeP0JOF.js → use-eve-agent-B2jCfcnG.js} +3 -2
- package/dist/src/chunks/{use-eve-agent-DP5Rso9C.js → use-eve-agent-DCLFi26P.js} +3 -2
- package/dist/src/client/client.js +1 -1
- package/dist/src/client/open-stream.js +1 -1
- package/dist/src/client/types.d.ts +5 -4
- package/dist/src/compiled/.vendor-stamp.json +1 -1
- package/dist/src/context/keys.d.ts +7 -0
- package/dist/src/context/keys.js +1 -1
- package/dist/src/execution/agent-sessions/context.d.ts +5 -1
- package/dist/src/execution/agent-sessions/context.js +1 -1
- package/dist/src/execution/dynamic-workflow/tool.js +1 -1
- package/dist/src/execution/legacy-session/snapshot.d.ts +1 -2
- package/dist/src/execution/legacy-session/snapshot.js +1 -1
- package/dist/src/execution/proxied-deliver-step.js +1 -1
- package/dist/src/execution/public-destination.d.ts +3 -0
- package/dist/src/execution/public-destination.js +1 -1
- package/dist/src/execution/publish-session-events.js +1 -1
- package/dist/src/execution/session/checkpoint-migrations.d.ts +16 -5
- package/dist/src/execution/session/checkpoint-migrations.js +1 -1
- package/dist/src/execution/session/checkpoint-refusal.d.ts +4 -0
- package/dist/src/execution/session/checkpoint-refusal.js +1 -0
- package/dist/src/execution/session/entry.js +1 -1
- package/dist/src/execution/session/handoff-steps.d.ts +7 -1
- package/dist/src/execution/session/handoff-steps.js +1 -1
- package/dist/src/execution/session/imported-conversation.d.ts +2 -0
- package/dist/src/execution/session/imported-conversation.js +1 -0
- package/dist/src/execution/session/interrupted-step.js +1 -1
- package/dist/src/execution/session/pre-v27-checkpoint.d.ts +36 -0
- package/dist/src/execution/session/pre-v27-checkpoint.js +1 -0
- package/dist/src/execution/session/program.d.ts +2 -0
- package/dist/src/execution/session/program.js +1 -1
- package/dist/src/execution/session/turn-step.js +1 -1
- package/dist/src/execution/session-callback-request.js +1 -1
- package/dist/src/execution/tool-auth.js +1 -1
- package/dist/src/execution/tools/agent-router-workflow.js +1 -1
- package/dist/src/execution/tools/channel-to.d.ts +12 -0
- package/dist/src/execution/tools/channel-to.js +1 -0
- package/dist/src/execution/tools/workflow/body.d.ts +3 -0
- package/dist/src/execution/tools/workflow/body.js +1 -1
- package/dist/src/execution/tools/workflow/step-context.d.ts +5 -0
- package/dist/src/execution/tools/workflow/step-execution.js +1 -1
- package/dist/src/execution/tools/workflow/step.js +1 -1
- package/dist/src/execution/workflow-callback-url.d.ts +2 -3
- package/dist/src/execution/workflow-callback-url.js +1 -1
- package/dist/src/execution/workflow-runtime.js +1 -1
- package/dist/src/harness/compaction/step.js +1 -1
- package/dist/src/harness/model-call/call.js +1 -1
- package/dist/src/harness/model-call/run.js +1 -1
- package/dist/src/harness/session-machine/transitions.js +1 -1
- package/dist/src/internal/application/stamped-package-version.js +1 -1
- package/dist/src/internal/attachments/limited-read.d.ts +2 -0
- package/dist/src/internal/attachments/limited-read.js +1 -1
- package/dist/src/internal/attachments/url-refs.js +1 -1
- package/dist/src/internal/capability-error.d.ts +3 -0
- package/dist/src/internal/capability-error.js +1 -0
- package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +1 -1
- package/dist/src/public/channels/discord/discordChannel.js +1 -1
- package/dist/src/public/channels/github/githubChannel.js +1 -1
- package/dist/src/public/channels/linear/linearChannel.js +1 -1
- package/dist/src/public/channels/linq/inboundContent.js +1 -1
- package/dist/src/public/channels/slack/answers.d.ts +2 -3
- package/dist/src/public/channels/slack/answers.js +1 -1
- package/dist/src/public/channels/slack/api.d.ts +23 -3
- package/dist/src/public/channels/slack/api.js +1 -1
- package/dist/src/public/channels/slack/app-manifest.d.ts +2 -0
- package/dist/src/public/channels/slack/app-manifest.js +1 -1
- package/dist/src/public/channels/slack/auth.d.ts +2 -1
- package/dist/src/public/channels/slack/auth.js +1 -1
- package/dist/src/public/channels/slack/code-channel.d.ts +42 -0
- package/dist/src/public/channels/slack/code-channel.js +1 -0
- package/dist/src/public/channels/slack/defaults.d.ts +7 -3
- package/dist/src/public/channels/slack/defaults.js +3 -3
- package/dist/src/public/channels/slack/hitl.d.ts +7 -17
- package/dist/src/public/channels/slack/hitl.js +1 -1
- package/dist/src/public/channels/slack/index.d.ts +4 -3
- package/dist/src/public/channels/slack/index.js +1 -1
- package/dist/src/public/channels/slack/interaction-cards.d.ts +0 -2
- 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/open-code-channel.d.ts +30 -0
- package/dist/src/public/channels/slack/open-code-channel.js +1 -0
- package/dist/src/public/channels/slack/private-approval-delivery.d.ts +16 -4
- package/dist/src/public/channels/slack/private-approval-delivery.js +1 -1
- package/dist/src/public/channels/slack/renderers.d.ts +58 -6
- package/dist/src/public/channels/slack/renderers.js +1 -1
- package/dist/src/public/channels/slack/reply-delivery.d.ts +4 -0
- package/dist/src/public/channels/slack/reply-delivery.js +1 -1
- package/dist/src/public/channels/slack/request-card-render.d.ts +45 -0
- package/dist/src/public/channels/slack/request-card-render.js +1 -0
- package/dist/src/public/channels/slack/request-cards.d.ts +35 -0
- package/dist/src/public/channels/slack/request-cards.js +3 -0
- package/dist/src/public/channels/slack/sign-in-cancel.d.ts +3 -5
- package/dist/src/public/channels/slack/sign-in-cancel.js +1 -1
- package/dist/src/public/channels/slack/slackChannel.d.ts +109 -22
- package/dist/src/public/channels/slack/slackChannel.js +1 -1
- package/dist/src/public/channels/slack/task-card.d.ts +3 -3
- package/dist/src/public/channels/slack/task-card.js +1 -1
- package/dist/src/public/channels/slack/thread-status.js +1 -1
- package/dist/src/public/channels/teams/api.js +1 -1
- package/dist/src/public/channels/teams/defaults.js +1 -1
- package/dist/src/public/channels/teams/teamsChannel.js +1 -1
- package/dist/src/public/channels/teams/verify.d.ts +9 -5
- package/dist/src/public/channels/teams/verify.js +1 -1
- package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
- package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
- package/dist/src/public/schedules/subscription.d.ts +10 -1
- package/dist/src/runtime/subagents/workflow.js +1 -1
- package/dist/src/setup/index.d.ts +1 -1
- package/dist/src/setup/primitives/index.d.ts +1 -1
- package/dist/src/setup/primitives/pm/run.d.ts +0 -2
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/shared/channel-definition.d.ts +4 -4
- package/dist/src/subagents/adapter.js +1 -1
- package/dist/src/subagents/parent-notification.js +1 -1
- package/dist/src/svelte/index.js +1 -1
- package/dist/src/svelte/use-eve-agent.js +1 -1
- package/dist/src/tools/definition.d.ts +21 -0
- package/dist/src/tools/provided/ask-question-workflow.js +1 -1
- package/dist/src/tools/provided/sleep-workflow.js +1 -1
- package/dist/src/tools/workflow-definition.d.ts +4 -4
- package/dist/src/vue/index.js +1 -1
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/channels/custom.mdx +16 -3
- package/docs/channels/eve.mdx +2 -0
- package/docs/channels/linq.mdx +1 -1
- package/docs/channels/slack.mdx +185 -18
- package/docs/channels/teams.mdx +6 -2
- package/docs/concepts/upgrade-to-v27-events.md +2 -2
- package/docs/experimental/dynamic-schedules.mdx +2 -2
- package/docs/guides/client/overview.mdx +1 -1
- package/docs/guides/remote-agents.md +8 -0
- package/docs/patterns/fork-conversations-into-new-threads.md +159 -0
- package/docs/patterns/meta.json +1 -0
- package/docs/schedules.mdx +1 -1
- package/docs/tools/overview.mdx +34 -0
- package/docs/tools/workflows.mdx +47 -5
- package/package.json +1 -1
- package/dist/src/public/channels/slack/approval-cards.d.ts +0 -25
- package/dist/src/public/channels/slack/approval-cards.js +0 -2
package/docs/schedules.mdx
CHANGED
|
@@ -81,7 +81,7 @@ export default defineSchedule({
|
|
|
81
81
|
|
|
82
82
|
Every run delivers the agent's reply to the channel. To skip a run when there is nothing to report, check that condition in the handler before calling `send`. When only the agent can tell, add the opt-in [`no_reply`](/docs/concepts/built-in-tools#no_reply) tool and ask the agent to call it when there is nothing to report; the run then posts nothing.
|
|
83
83
|
|
|
84
|
-
- `to(channel, target).send(message, { auth })`: starts a session on another channel. It has the same contract as a route handler's `ctx.to(...)` handle.
|
|
84
|
+
- `to(channel, target).send(message, { auth, ...options })`: starts a session on another channel. It has the same contract and [options](./channels/custom#cross-channel-hand-off) as a route handler's `ctx.to(...)` handle.
|
|
85
85
|
- `waitUntil(promise)`: extends the cron task's lifetime so the parked session and any in-flight fetches settle before the task ends. Wrap the `send` call in it.
|
|
86
86
|
- `appAuth`: the app principal (`{ authenticator: "app", principalId: "eve:app", principalType: "runtime" }`). Pass it as `to(...).send(..., { auth: appAuth })` for work the agent does on its own behalf.
|
|
87
87
|
|
package/docs/tools/overview.mdx
CHANGED
|
@@ -254,6 +254,8 @@ examples.
|
|
|
254
254
|
- `ctx.messages`: the model input for the step that requested this call, the same messages a [dynamic capability's](/docs/guides/dynamic-capabilities) `ctx.messages()` returns before that call.
|
|
255
255
|
- `ctx.abortSignal`: aborts when the active turn is cancelled. Pass it to cancellation-aware work; sandbox sessions from `ctx.getSandbox()` are already bound to it.
|
|
256
256
|
- `ctx.getSandbox()`: the live [sandbox](/docs/sandbox) handle.
|
|
257
|
+
- `ctx.channel`: the channel serving the session, as [hooks](/docs/guides/hooks) and [dynamic resolvers](/docs/guides/dynamic-capabilities) read it: `kind`, `continuationToken`, and `metadata`, what the channel's `metadata(state)` hook projects, such as a Slack thread's `channelId` and `threadTs`.
|
|
258
|
+
- `ctx.to(channel, target)`: starts or continues a session on one of the agent's channels. See [Start channel sessions](#start-channel-sessions-ctxto).
|
|
257
259
|
|
|
258
260
|
Running in the app runtime is what lets a tool import shared code from `lib/`, read `process.env`, and take part in eve’s durable pause/resume model.
|
|
259
261
|
|
|
@@ -261,6 +263,38 @@ eve never runs authored tools during discovery. The model sees descriptors first
|
|
|
261
263
|
|
|
262
264
|
Use operation-specific idempotency keys for external writes such as charges or emails. Approval records consent; it does not deduplicate an operation. See [Crash recovery](/docs/concepts/execution-model-and-durability#resuming-after-a-crash).
|
|
263
265
|
|
|
266
|
+
### Start channel sessions: `ctx.to`
|
|
267
|
+
|
|
268
|
+
`ctx.to(channel, target).send(message, options)` starts a session on one of the agent's channels, or continues the one at that target, through the channel's `receive` hook. It's the same call as a route handler's [cross-channel hand-off](/docs/channels/custom#cross-channel-hand-off), with the same [options](/docs/channels/custom#cross-channel-hand-off), and returns the delivery, whose `sessionId` names the session. Use it when the model decides that work should continue somewhere people can follow it, such as a new Slack thread:
|
|
269
|
+
|
|
270
|
+
```ts title="agent/tools/escalate.ts"
|
|
271
|
+
import { defineTool } from "eve/tools";
|
|
272
|
+
import { z } from "zod";
|
|
273
|
+
import slack from "../channels/slack";
|
|
274
|
+
|
|
275
|
+
export default defineTool({
|
|
276
|
+
description: "Hand this investigation to the on-call channel in Slack.",
|
|
277
|
+
inputSchema: z.object({ summary: z.string() }),
|
|
278
|
+
async execute({ summary }, ctx) {
|
|
279
|
+
const delivery = await ctx
|
|
280
|
+
.to(slack, { channelId: "C0123ABC" })
|
|
281
|
+
.send("Take over this investigation.", {
|
|
282
|
+
auth: ctx.session.auth.current,
|
|
283
|
+
history: [{ role: "user", text: summary }],
|
|
284
|
+
idempotencyKey: `${ctx.session.id}:${ctx.callId}`,
|
|
285
|
+
});
|
|
286
|
+
return { sessionId: delivery.sessionId };
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
- The session belongs to the channel. People on that channel continue it, it has no parent, and it keeps running after the tool returns.
|
|
292
|
+
- It runs the root agent with the `auth` you pass. Pass `ctx.session.auth.current` to start it as the caller.
|
|
293
|
+
- A tool call that retries runs the tool again. Pass `` idempotencyKey: `${ctx.session.id}:${ctx.callId}` ``, and the session at the target gets the message once. The destination session dedupes keys from every sender, and `ctx.callId` alone is unique only within the calling session, so include the session id. Built-in channels map a retry to the same session, including a Slack target with only a `channelId`. A platform post made before the session exists, such as an `initialMessage`, repeats.
|
|
294
|
+
- `ctx.to()` throws in a delegated session: a subagent, a root copy, or a remote agent call. A session it started would outlive the delegation and act for the caller, so return the result and send from a tool on the root agent.
|
|
295
|
+
|
|
296
|
+
See [Fork conversations into a new thread](/docs/patterns/fork-conversations-into-new-threads) for a tool that copies the current conversation into a new Slack thread.
|
|
297
|
+
|
|
264
298
|
## When a tool throws
|
|
265
299
|
|
|
266
300
|
If an authored tool's `execute` function throws, eve records the call as `call.settled` with `outcome: "failed"` and gives the error to the model as a tool error. The model can respond, choose another action, or call the tool again. eve does not automatically call the tool again based on the exception type, an upstream HTTP status, or a `retryable` property.
|
package/docs/tools/workflows.mdx
CHANGED
|
@@ -85,14 +85,14 @@ or days later, the run resumes, deploys, and returns. The model sees one tool re
|
|
|
85
85
|
`start`, `getRun`, and `resumeHook` from `workflow/api` belong in steps. Your app does not install
|
|
86
86
|
the SDK; for types, new projects list `eve/workflow-modules` in the tsconfig `types`.
|
|
87
87
|
- In an `execute` or `task` body, `ctx` is a `WorkflowToolContext` with `session`, `callId`,
|
|
88
|
-
`toolName`, `abortSignal`, `agent`, `agents`, and `ask`. A `serve` body gets a
|
|
89
|
-
`WorkflowServeContext` with `session`, `toolName`,
|
|
88
|
+
`toolName`, `abortSignal`, `channel`, `agent`, `agents`, and `ask`. A `serve` body gets a
|
|
89
|
+
`WorkflowServeContext` with `session`, `toolName`, `channel`,
|
|
90
90
|
`agent`, `agents`, `ask`, and `reply`; each call it receives carries its own `callId` and
|
|
91
91
|
`abortSignal`.
|
|
92
92
|
A `"use step"` helper that receives `ctx` directly gets a restricted `WorkflowStepToolContext` with
|
|
93
|
-
`session`, `callId`, `toolName`, `abortSignal`, `getSandbox`, `getToken`, and `
|
|
94
|
-
`ctx.agent()
|
|
95
|
-
Call `getSandbox`, `getToken`, and `
|
|
93
|
+
`session`, `callId`, `toolName`, `abortSignal`, `channel`, `getSandbox`, `getToken`, `requireAuth`, and `to`. Read `ctx.agents`, and call
|
|
94
|
+
`ctx.agent()` and `ctx.ask()` in the workflow body; pass only the serializable values the step needs.
|
|
95
|
+
Call `getSandbox`, `getToken`, `requireAuth`, and `to` in a step: the workflow body throws when it calls them.
|
|
96
96
|
- The tool's input must be a JSON object. Workflow bodies are for static tools under `agent/tools/`,
|
|
97
97
|
not tools a `defineDynamic` function returns.
|
|
98
98
|
|
|
@@ -782,6 +782,48 @@ When an authored tool accepts a JSON Schema supplied by the model, represent tha
|
|
|
782
782
|
|
|
783
783
|
This pattern controls specialist selection, not whether the parent model delegates at all. Route before the parent model runs if every incoming request must go through Jev.
|
|
784
784
|
|
|
785
|
+
## Start channel sessions: `ctx.to`
|
|
786
|
+
|
|
787
|
+
A workflow tool reaches the agent's channels with [`ctx.to(channel, target)`](/docs/tools#start-channel-sessions-ctxto), as an ordinary tool does. Call it in a `"use step"` helper that receives `ctx`, like `ctx.getSandbox()`; the workflow body throws when it calls it:
|
|
788
|
+
|
|
789
|
+
```ts title="agent/tools/open_incident_channel.ts"
|
|
790
|
+
import { defineWorkflowTool, type WorkflowStepToolContext } from "eve/tools";
|
|
791
|
+
import { z } from "zod";
|
|
792
|
+
import slack from "../channels/slack";
|
|
793
|
+
import { createIncidentChannel } from "../lib/incidents";
|
|
794
|
+
|
|
795
|
+
export default defineWorkflowTool({
|
|
796
|
+
description: "Open a Slack channel for an incident and continue the investigation there.",
|
|
797
|
+
inputSchema: z.object({ title: z.string(), summary: z.string() }),
|
|
798
|
+
async task({ title, summary }, ctx) {
|
|
799
|
+
"use workflow";
|
|
800
|
+
const channelId = await createChannel(title);
|
|
801
|
+
return await openIncident(ctx, channelId, summary);
|
|
802
|
+
},
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
async function createChannel(title: string) {
|
|
806
|
+
"use step";
|
|
807
|
+
return await createIncidentChannel(title);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
async function openIncident(ctx: WorkflowStepToolContext, channelId: string, summary: string) {
|
|
811
|
+
"use step";
|
|
812
|
+
const delivery = await ctx
|
|
813
|
+
.to(slack, { channelId })
|
|
814
|
+
.send("Continue the investigation in this channel.", {
|
|
815
|
+
auth: ctx.session.auth.current,
|
|
816
|
+
history: [{ role: "user", text: summary }],
|
|
817
|
+
idempotencyKey: `${ctx.session.id}:${ctx.callId}:incident`,
|
|
818
|
+
});
|
|
819
|
+
return { channelId, sessionId: delivery.sessionId };
|
|
820
|
+
}
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
A step that fails retries, so pass an `idempotencyKey` the retry repeats. The destination session dedupes keys from every sender, and `ctx.callId` is unique only within the calling session and is the same for every step of the call, so include `ctx.session.id` and add a label for each send. Create the channel in its own step: a retried send step then reuses the recorded `channelId` instead of creating another channel.
|
|
824
|
+
|
|
825
|
+
`ctx.channel` holds the `kind`, `continuationToken`, and `metadata` of the channel serving the calling session, in the workflow body and in steps, as in [ordinary tools](/docs/tools#the-ctx-parameter).
|
|
826
|
+
|
|
785
827
|
## Report progress: `yield`
|
|
786
828
|
|
|
787
829
|
A workflow body may be an async generator whose yields report progress. After processing a yield,
|
package/package.json
CHANGED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* eve's default Slack rendering for human-input requests: posting approval
|
|
3
|
-
* and question controls, and retiring an approval's messages once it resolves.
|
|
4
|
-
*/
|
|
5
|
-
import type { RefusedAnswer, RequestBatch, RequestSettlement } from "#channel/interaction-prompts.js";
|
|
6
|
-
import type { SlackApprovalChannelResolver, SlackChannelInternalEvents, SlackEventContext } from "#public/channels/slack/slackChannel.js";
|
|
7
|
-
/**
|
|
8
|
-
* Default `interaction.opened` handler — renders each pending HITL
|
|
9
|
-
* request as Slack `block_actions`. Buttons by default; radio for
|
|
10
|
-
* ≤6-option select requests; static_select for >6-option select
|
|
11
|
-
* requests. Batches split into multiple posts when they would exceed
|
|
12
|
-
* Slack's 50-block message cap.
|
|
13
|
-
*/
|
|
14
|
-
export declare function defaultInteractionsHandler(approvalChannel?: SlackApprovalChannelResolver): (data: RequestBatch, ctx: Parameters<NonNullable<SlackChannelInternalEvents["interaction.opened"]>>[1]) => Promise<void>;
|
|
15
|
-
/**
|
|
16
|
-
* A responder an approval's policy or check refused hears why privately. A pending answer gets
|
|
17
|
-
* no notice: an ephemeral cannot be removed once the approval settles, and the card itself
|
|
18
|
-
* reports the outcome moments later.
|
|
19
|
-
*/
|
|
20
|
-
export declare function notifyRefusedResponder(refused: RefusedAnswer, channel: SlackEventContext): Promise<void>;
|
|
21
|
-
/**
|
|
22
|
-
* Retires an approval's card: with the person whose press decided it, or as no longer needed
|
|
23
|
-
* when it ended any other way (the user replied instead, or it was withdrawn).
|
|
24
|
-
*/
|
|
25
|
-
export declare function settleApproval(resolution: RequestSettlement, channel: SlackEventContext): Promise<void>;
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{createLogger,logError}from"#internal/logging.js";import{slackUserIdForPrincipal,slackUserIdFromAuthContext}from"#public/channels/slack/auth.js";import{SLACK_MAX_BLOCKS_PER_MESSAGE,truncateMessageText}from"#public/channels/slack/limits.js";import{buildAnsweredBlocks,decodeHitlActionId,renderInteractionPostParts}from"#public/channels/slack/hitl.js";import{answeredBlocksFromActionBlock}from"#public/channels/slack/interaction-cards.js";import{deliverPrivateInteraction}from"#public/channels/slack/private-approval-delivery.js";const log=createLogger(`slack.defaults`);function defaultInteractionsHandler(e){return async(t,n)=>{let{channel:r}=n,i=[],a=[];for(let r of t.requests)((e===void 0?`thread`:await e(r,n))===`direct-message`?i:a).push(r);await postPublicInteractions(a,r);for(let e of i){let t=slackUserIdFromAuthContext(n.session.auth.current)??r.state.triggeringUserId;if(!t){log.warn(`direct-message input request not delivered because no reviewer was resolved`,{requestId:e.interactionId,sessionId:n.session.id});continue}let i=await deliverPrivateInteraction({previewMessageTs:r.state.triggeringMessageTs??r.slack.threadTs,request:e,reviewer:t,slack:r.slack});recordApprovalCards(r.state,[e],i);try{let n=await r.thread.post(`Waiting on ${e.request.kind===`approval`?`approval`:`a response`} from <@${t}>…`);n.id&&recordApprovalCards(r.state,[e],{...i,announcementTs:n.id})}catch(t){logError(log,`failed to announce private input request`,t,{requestId:e.interactionId,sessionId:n.session.id})}}}}async function postPublicInteractions(e,t){let n=new Map;for(let r of buildInteractionPosts(e)){let e=await t.thread.post({blocks:r.blocks,text:r.text});if(r.kind===`details`){if(e.id)for(let t of r.requests)n.set(t.interactionId,e.id);continue}for(let i of r.requests){let a=n.get(i.interactionId);recordApprovalCards(t.state,[i],{detailsMessageTs:a,messageBlocks:r.blocks,messageTs:e.id})}}}function recordApprovalCards(e,t,n){if(!n.messageTs)return;let r={...e.pendingApprovalCards};for(let e of t)e.request.kind===`approval`&&(r[e.interactionId]=n);e.pendingApprovalCards=r}async function settleApprovalCard(e,t,n){let r=e.state.pendingApprovalCards??{},i=r[t];if(i===void 0)return;let a={...r};delete a[t],e.state.pendingApprovalCards=a;let o=i.messageChannelId??e.state.channelId;if(o===null)return;let s=i.messageBlocks.flatMap(e=>blockContainsRequestAction(e,t)?answeredBlocksFromActionBlock({answerLabel:n.label,block:e,userId:n.userId})??buildAnsweredBlocks({answerLabel:n.label,promptBlocks:[]}):[e]);for(let[e,t]of Object.entries(a))t.messageTs===i.messageTs&&(a[e]={...t,messageBlocks:s});await settleRequest(e,`chat.update`,t,{blocks:s,channel:o,text:n.text,ts:i.messageTs});let c=i.detailsMessageTs;c!==void 0&&!Object.values(a).some(e=>e.detailsMessageTs===c)&&await settleRequest(e,`chat.delete`,t,{channel:o,ts:c}),i.announcementTs!==void 0&&e.state.channelId!==null&&await settleRequest(e,`chat.update`,t,{channel:e.state.channelId,text:n.announcement,ts:i.announcementTs})}async function settleRequest(e,t,n,r){try{let i=await e.slack.request(t,r);i.ok!==!0&&log.warn(`failed to retire approval message`,{error:i.error,operation:t,requestId:n})}catch(e){logError(log,`failed to retire approval message`,e,{operation:t,requestId:n})}}function buildInteractionPosts(e){let t=[],n=[];for(let r of e){let e=renderInteractionPostParts(r);e.details&&t.push({...e.details,request:r}),n.push({...e.controls,request:r})}return[...groupInteractionPostParts(t).map(e=>({...e,kind:`details`})),...groupInteractionPostParts(n).map(e=>({...e,kind:`controls`}))]}function groupInteractionPostParts(e){let t=[];for(let n of e){let e=t.at(-1);e&&e.blocks.length+n.blocks.length<=SLACK_MAX_BLOCKS_PER_MESSAGE?(e.blocks.push(...n.blocks),e.fallbacks.push(n.text),e.requests.push(n.request)):t.push({blocks:[...n.blocks],fallbacks:[n.text],requests:[n.request]})}return t.map(e=>({blocks:e.blocks,requests:e.requests,text:truncateMessageText(e.fallbacks.join(`
|
|
2
|
-
`))}))}function blockContainsRequestAction(e,t){if(typeof e!=`object`||!e)return!1;let n=e;return[n.actions,n.elements].some(e=>Array.isArray(e)&&e.some(e=>{if(typeof e!=`object`||!e)return!1;let n=e.action_id;return typeof n==`string`&&decodeHitlActionId(n)?.requestId===t}))}async function notifyRefusedResponder(e,t){let n=slackUserIdForPrincipal(t.state,e.responder?.id);n!==void 0&&await t.thread.postEphemeral(n,e.reason??`We couldn’t verify your response. Please try again.`)}async function settleApproval(e,t){if(e.kind!==`approval`)return;if(e.outcome!==`accepted`&&e.outcome!==`declined`){await settleApprovalCard(t,e.interactionId,{announcement:`This approval is no longer needed.`,label:`No longer needed`,text:`No longer needed`});return}let n=e.outcome===`accepted`,r=slackUserIdForPrincipal(t.state,e.responder?.id),i=r===void 0?``:` by <@${r}>`,a=n?`Approve`:`Cancel`;await settleApprovalCard(t,e.interactionId,{announcement:`${n?`Approved`:`Cancelled`}${i}.`,label:a,text:`Answered: ${a}`,userId:r})}export{defaultInteractionsHandler,notifyRefusedResponder,settleApproval};
|