@sentry/junior 0.89.0 → 0.91.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/dist/{agent-hooks-RIJ5TSWP.js → agent-hooks-MXAF7RQL.js} +10 -10
- package/dist/api/people/list.js +8 -8
- package/dist/api/people/profile.js +8 -8
- package/dist/api-reference.d.ts +1 -1
- package/dist/app.js +797 -745
- package/dist/{catalog-runtime-MW7XERSU.js → catalog-runtime-DXE6NXHT.js} +5 -5
- package/dist/chat/agent/index.d.ts +4 -0
- package/dist/chat/agent/prompt.d.ts +78 -0
- package/dist/chat/{respond.d.ts → agent/request.d.ts} +106 -55
- package/dist/chat/agent/resume.d.ts +65 -0
- package/dist/chat/agent/sandbox.d.ts +15 -0
- package/dist/chat/agent/session.d.ts +20 -0
- package/dist/chat/agent/skills.d.ts +26 -0
- package/dist/chat/agent/tools.d.ts +78 -0
- package/dist/chat/agent-dispatch/runner.d.ts +3 -5
- package/dist/chat/app/production.d.ts +3 -1
- package/dist/chat/app/services.d.ts +1 -4
- package/dist/chat/current-instruction.d.ts +5 -3
- package/dist/chat/logging.d.ts +2 -0
- package/dist/chat/mcp/tool-manager.d.ts +1 -6
- package/dist/chat/oauth-authorization-message.d.ts +6 -0
- package/dist/chat/pi/messages.d.ts +18 -2
- package/dist/chat/pi/transcript.d.ts +31 -0
- package/dist/chat/plugins/agent-hooks.d.ts +2 -2
- package/dist/chat/prompt.d.ts +1 -1
- package/dist/chat/runtime/agent-continue-runner.d.ts +5 -5
- package/dist/chat/runtime/agent-run-outcome.d.ts +21 -0
- package/dist/chat/runtime/agent-runner.d.ts +11 -0
- package/dist/chat/runtime/delivered-turn-state.d.ts +2 -2
- package/dist/chat/runtime/generated-artifacts.d.ts +16 -0
- package/dist/chat/runtime/reply-executor.d.ts +2 -2
- package/dist/chat/runtime/slack-resume.d.ts +21 -12
- package/dist/chat/runtime/turn.d.ts +5 -39
- package/dist/chat/services/reply-delivery-plan.d.ts +0 -8
- package/dist/chat/services/turn-failure-response.d.ts +4 -4
- package/dist/chat/services/turn-result.d.ts +4 -7
- package/dist/chat/slack/channel.d.ts +9 -5
- package/dist/chat/slack/client.d.ts +3 -1
- package/dist/chat/slack/context.d.ts +17 -5
- package/dist/chat/slack/id-param.d.ts +25 -0
- package/dist/chat/slack/ids.d.ts +18 -4
- package/dist/chat/slack/mrkdwn.d.ts +6 -0
- package/dist/chat/slack/outbound.d.ts +16 -0
- package/dist/chat/slack/output.d.ts +3 -3
- package/dist/chat/slack/reply.d.ts +4 -7
- package/dist/chat/slack/timestamp-param.d.ts +25 -0
- package/dist/chat/slack/tools/canvas/context.d.ts +18 -0
- package/dist/chat/slack/tools/canvas/create.d.ts +4 -0
- package/dist/chat/slack/tools/canvas/edit.d.ts +3 -0
- package/dist/chat/slack/tools/canvas/read.d.ts +6 -0
- package/dist/chat/slack/tools/canvas/write.d.ts +3 -0
- package/dist/chat/{tools/slack → slack/tools}/channel-access.d.ts +4 -3
- package/dist/chat/{tools → slack/tools}/channel-capabilities.d.ts +2 -0
- package/dist/chat/slack/tools/channel-list-messages.d.ts +3 -0
- package/dist/chat/{tools/slack → slack/tools}/context.d.ts +5 -4
- package/dist/chat/slack/tools/list/add-items.d.ts +3 -0
- package/dist/chat/{tools/slack/lists.d.ts → slack/tools/list/api.d.ts} +2 -1
- package/dist/chat/slack/tools/list/create.d.ts +3 -0
- package/dist/chat/slack/tools/list/get-items.d.ts +3 -0
- package/dist/chat/slack/tools/list/update-item.d.ts +3 -0
- package/dist/chat/slack/tools/message-add-reaction.d.ts +4 -0
- package/dist/chat/slack/tools/send-message.d.ts +11 -0
- package/dist/chat/{tools/slack → slack/tools}/slack-message-url.d.ts +5 -5
- package/dist/chat/slack/tools/thread-read.d.ts +6 -0
- package/dist/chat/slack/tools/user-lookup.d.ts +2 -0
- package/dist/chat/slack/users.d.ts +2 -1
- package/dist/chat/{services → slack}/vision-context.d.ts +4 -2
- package/dist/chat/state/session-log.d.ts +1 -1
- package/dist/chat/tool-exposure.d.ts +10 -0
- package/dist/chat/tool-support/catalog-tool-call.d.ts +10 -0
- package/dist/chat/{tools/execution → tool-support}/normalize-result.d.ts +4 -1
- package/dist/chat/{tools/agent-tools.d.ts → tool-support/pi-tool-adapter.d.ts} +3 -9
- package/dist/chat/tool-support/schema-summary.d.ts +2 -0
- package/dist/chat/{tools → tool-support}/skill/mcp-tool-summary.d.ts +0 -6
- package/dist/chat/tool-support/structured-result.d.ts +73 -0
- package/dist/chat/tool-support/text-range-result.d.ts +58 -0
- package/dist/chat/tool-support/tool-execution-report.d.ts +7 -0
- package/dist/chat/tool-support/zod-tool.d.ts +27 -0
- package/dist/chat/tools/advisor/tool.d.ts +9 -18
- package/dist/chat/tools/definition.d.ts +56 -9
- package/dist/chat/tools/execute-tool.d.ts +3 -0
- package/dist/chat/tools/index.d.ts +3 -2
- package/dist/chat/tools/resource-events.d.ts +3 -13
- package/dist/chat/tools/runtime/report-progress.d.ts +1 -3
- package/dist/chat/tools/sandbox/bash.d.ts +1 -4
- package/dist/chat/tools/sandbox/edit-file.d.ts +25 -7
- package/dist/chat/tools/sandbox/file-uploads.d.ts +30 -0
- package/dist/chat/tools/sandbox/file-utils.d.ts +10 -1
- package/dist/chat/tools/sandbox/find-files.d.ts +12 -11
- package/dist/chat/tools/sandbox/grep.d.ts +18 -12
- package/dist/chat/tools/sandbox/list-dir.d.ts +15 -7
- package/dist/chat/tools/sandbox/read-file.d.ts +2 -31
- package/dist/chat/tools/sandbox/write-file.d.ts +1 -4
- package/dist/chat/tools/search-tools.d.ts +4 -0
- package/dist/chat/tools/skill/call-mcp-tool.d.ts +1 -4
- package/dist/chat/tools/skill/load-skill.d.ts +4 -5
- package/dist/chat/tools/skill/search-mcp-tools.d.ts +1 -5
- package/dist/chat/tools/system-time.d.ts +1 -1
- package/dist/chat/tools/types.d.ts +15 -5
- package/dist/chat/tools/web/fetch-content.d.ts +4 -2
- package/dist/chat/tools/web/fetch-tool.d.ts +4 -4
- package/dist/chat/tools/web/image-generate.d.ts +4 -3
- package/dist/chat/tools/web/search.d.ts +1 -4
- package/dist/{chunk-4IXHIV37.js → chunk-2S7M37HY.js} +6 -8
- package/dist/{chunk-L7OHKDOX.js → chunk-3MPOMK3K.js} +58 -7
- package/dist/{chunk-V6XDCS3X.js → chunk-5GBUZI6M.js} +4 -4
- package/dist/{chunk-7ES37H6U.js → chunk-AN2437E3.js} +4 -4
- package/dist/chunk-AOISHLSF.js +747 -0
- package/dist/{chunk-XS6NLQPA.js → chunk-DACFZ5CI.js} +474 -33
- package/dist/chunk-GCWD2VHP.js +1216 -0
- package/dist/chunk-GHGPTPBL.js +53 -0
- package/dist/{chunk-S35CPNPT.js → chunk-HXL2ZV74.js} +40 -216
- package/dist/{chunk-PBV4ZIVM.js → chunk-IRRMABQD.js} +1 -1
- package/dist/{chunk-2DPZRS3B.js → chunk-IX76WFJV.js} +8 -8
- package/dist/{chunk-66NX7MNW.js → chunk-KC42JAAQ.js} +1 -1
- package/dist/chunk-LFLTJQVR.js +90 -0
- package/dist/{chunk-IATAYWFU.js → chunk-NW7AXDA5.js} +2 -2
- package/dist/{chunk-F22AM3OW.js → chunk-NYWPISSO.js} +1 -1
- package/dist/chunk-OB42YVAE.js +16 -0
- package/dist/chunk-ONFOWI2D.js +955 -0
- package/dist/chunk-PIB4EOW6.js +1093 -0
- package/dist/{chunk-6UPQ5GTJ.js → chunk-QCKGI74V.js} +7 -7
- package/dist/{chunk-YPAE5RH3.js → chunk-RS6ANWVT.js} +1 -1
- package/dist/{chunk-C5NCV3OB.js → chunk-TYUXD3FN.js} +1 -1
- package/dist/{chunk-KBFQXJL4.js → chunk-XP7F4LYB.js} +5 -7
- package/dist/{chunk-NYJLQI42.js → chunk-ZGDTBSQ7.js} +11191 -11891
- package/dist/{chunk-VMBZFPZM.js → chunk-ZUK7BL63.js} +187 -9
- package/dist/cli/chat.js +55 -40
- package/dist/cli/check.js +6 -6
- package/dist/cli/plugins.js +16 -16
- package/dist/cli/snapshot-warmup.js +9 -9
- package/dist/cli/upgrade.js +21 -21
- package/dist/db-CXI7PR5U.js +18 -0
- package/dist/handlers/agent-dispatch.d.ts +3 -3
- package/dist/handlers/mcp-oauth-callback.d.ts +3 -3
- package/dist/handlers/oauth-callback.d.ts +3 -3
- package/dist/instrumentation.js +6 -5
- package/dist/nitro.js +3 -7
- package/dist/reporting.js +23 -25
- package/dist/{runner-BCRF2FCI.js → runner-FKL3RAHA.js} +89 -77
- package/dist/{validation-FMJO3L5P.js → validation-I7GD2YWS.js} +6 -6
- package/package.json +5 -5
- package/dist/chat/respond-helpers.d.ts +0 -82
- package/dist/chat/services/attachment-claims.d.ts +0 -2
- package/dist/chat/services/channel-intent.d.ts +0 -2
- package/dist/chat/tools/sandbox/attach-file.d.ts +0 -7
- package/dist/chat/tools/slack/canvas-tools.d.ts +0 -30
- package/dist/chat/tools/slack/channel-list-messages.d.ts +0 -9
- package/dist/chat/tools/slack/channel-post-message.d.ts +0 -5
- package/dist/chat/tools/slack/list-tools.d.ts +0 -21
- package/dist/chat/tools/slack/message-add-reaction.d.ts +0 -5
- package/dist/chat/tools/slack/thread-read.d.ts +0 -12
- package/dist/chat/tools/slack/user-lookup.d.ts +0 -8
- package/dist/chunk-AHLSXMOU.js +0 -506
- package/dist/chunk-FTMXFBDC.js +0 -49
- package/dist/chunk-KBSLCOGE.js +0 -2226
- package/dist/chunk-KQKIA4CU.js +0 -186
- package/dist/db-37HOGLI7.js +0 -18
- /package/dist/chat/{tools/slack/canvases.d.ts → slack/tools/canvas/api.d.ts} +0 -0
package/dist/app.js
CHANGED
|
@@ -1,81 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
|
-
AuthorizationFlowDisabledError,
|
|
3
|
-
PluginCredentialFailureError,
|
|
4
|
-
SANDBOX_EGRESS_PROXY_PATH,
|
|
5
|
-
TurnInputCommitLostError,
|
|
6
|
-
TurnInputDeferredError,
|
|
7
|
-
addReactionToMessage,
|
|
8
|
-
appendSlackLegacyAttachmentText,
|
|
9
|
-
applyPendingAuthUpdate,
|
|
10
2
|
buildConversationContext,
|
|
11
3
|
buildDeliveredTurnStatePatch,
|
|
12
|
-
buildDeterministicTurnId,
|
|
13
|
-
buildSteeringPiMessage,
|
|
14
|
-
clearPendingAuth,
|
|
15
|
-
coerceThreadArtifactsState,
|
|
16
|
-
completeDeliveredTurn,
|
|
17
4
|
createConversationMemoryService,
|
|
18
|
-
createUserTokenStore,
|
|
19
|
-
deleteMcpAuthSession,
|
|
20
|
-
deliverResourceEventSubscription,
|
|
21
5
|
estimateTextTokens,
|
|
22
|
-
executeCredentialedEgressRequest,
|
|
23
6
|
finalizeFailedTurnReply,
|
|
24
|
-
finalizeMcpAuthorization,
|
|
25
|
-
findMatchingResourceEventSubscriptions,
|
|
26
|
-
formatProviderLabel,
|
|
27
|
-
generateAssistantReply,
|
|
28
7
|
generateConversationId,
|
|
29
8
|
getAgentContextCompactionTriggerTokens,
|
|
30
9
|
getAgentTurnDiagnosticsAttributes,
|
|
31
|
-
getChannelConfigurationService,
|
|
32
|
-
getChannelConfigurationServiceById,
|
|
33
|
-
getConfigDefaults,
|
|
34
10
|
getConversationMessageSlackTs,
|
|
35
|
-
getConversationPendingAuth,
|
|
36
|
-
getMcpStoredOAuthCredentials,
|
|
37
|
-
getPersistedSandboxState,
|
|
38
|
-
getPersistedThreadState,
|
|
39
11
|
getThreadTitleSourceMessage,
|
|
40
|
-
isAuthResumeRetryableTurnError,
|
|
41
|
-
isCooperativeTurnYieldError,
|
|
42
12
|
isHumanConversationMessage,
|
|
43
|
-
isPendingAuthLatestRequest,
|
|
44
|
-
isRetryableTurnError,
|
|
45
|
-
isTurnInputCommitLostError,
|
|
46
|
-
isTurnInputDeferredError,
|
|
47
|
-
listThreadReplies,
|
|
48
13
|
markConversationMessage,
|
|
49
|
-
markTurnClosed,
|
|
50
|
-
markTurnFailed,
|
|
51
|
-
mergeArtifactsState,
|
|
52
14
|
normalizeConversationText,
|
|
53
|
-
normalizeSandboxEgressTracePropagationDomains,
|
|
54
|
-
parseOAuthStatePayload,
|
|
55
|
-
parseSandboxEgressCredentialToken,
|
|
56
|
-
persistCompletedSessionRecord,
|
|
57
|
-
persistThreadState,
|
|
58
|
-
persistThreadStateById,
|
|
59
|
-
persistYieldSessionRecord,
|
|
60
|
-
postSlackMessage,
|
|
61
15
|
processPluginTask,
|
|
62
|
-
removeReactionFromMessage,
|
|
63
|
-
renderSlackLegacyAttachmentText,
|
|
64
16
|
requireTurnFailureEventId,
|
|
65
|
-
resolveBaseUrl,
|
|
66
|
-
resolvePluginOAuthAccount,
|
|
67
|
-
resolveSandboxEgressProviderForHost,
|
|
68
17
|
scheduleSessionCompletedPluginTasks,
|
|
69
|
-
setConfigDefaults,
|
|
70
|
-
shouldEmitDevAgentTrace,
|
|
71
|
-
shouldPropagateSandboxEgressTrace,
|
|
72
|
-
startActiveTurn,
|
|
73
|
-
startOAuthFlow,
|
|
74
|
-
unlinkProvider,
|
|
75
18
|
updateConversationStats,
|
|
76
|
-
uploadFilesToThread,
|
|
77
19
|
upsertConversationMessage
|
|
78
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-AOISHLSF.js";
|
|
79
21
|
import {
|
|
80
22
|
CONVERSATION_WORK_CHECK_IN_INTERVAL_MS,
|
|
81
23
|
CONVERSATION_WORK_STALE_ENQUEUE_MS,
|
|
@@ -99,17 +41,12 @@ import {
|
|
|
99
41
|
requestConversationContinuation,
|
|
100
42
|
requestConversationWork,
|
|
101
43
|
startConversationWork
|
|
102
|
-
} from "./chunk-
|
|
103
|
-
import {
|
|
104
|
-
JUNIOR_THREAD_STATE_TTL_MS,
|
|
105
|
-
coerceThreadConversationState
|
|
106
|
-
} from "./chunk-66NX7MNW.js";
|
|
107
|
-
import "./chunk-V6XDCS3X.js";
|
|
44
|
+
} from "./chunk-IX76WFJV.js";
|
|
108
45
|
import {
|
|
109
46
|
getVercelConversationWorkQueue,
|
|
110
47
|
resolveConversationWorkQueueTopic,
|
|
111
48
|
verifyConversationQueueMessage
|
|
112
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-NYWPISSO.js";
|
|
113
50
|
import {
|
|
114
51
|
PLUGIN_TASK_QUEUE_TOPIC,
|
|
115
52
|
createVercelQueueClient,
|
|
@@ -123,25 +60,11 @@ import {
|
|
|
123
60
|
resolveSlackChannelTypeFromMessage,
|
|
124
61
|
resolveSlackConversationContext,
|
|
125
62
|
setConversationTitle
|
|
126
|
-
} from "./chunk-
|
|
127
|
-
import {
|
|
128
|
-
abandonAgentTurnSessionRecord,
|
|
129
|
-
buildSlackOutputMessage,
|
|
130
|
-
commitMessages,
|
|
131
|
-
failAgentTurnSessionRecord,
|
|
132
|
-
getAgentTurnSessionRecord,
|
|
133
|
-
listAgentTurnSessionSummariesForConversation,
|
|
134
|
-
loadProjection,
|
|
135
|
-
normalizeSlackStatusText,
|
|
136
|
-
recordAgentTurnSessionSummary,
|
|
137
|
-
recordAuthorizationCompleted,
|
|
138
|
-
splitSlackReplyText,
|
|
139
|
-
truncateStatusText
|
|
140
|
-
} from "./chunk-KBSLCOGE.js";
|
|
63
|
+
} from "./chunk-QCKGI74V.js";
|
|
141
64
|
import {
|
|
142
65
|
validatePluginEgressCredentialHooks,
|
|
143
66
|
validatePluginRegistrations
|
|
144
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-TYUXD3FN.js";
|
|
145
68
|
import {
|
|
146
69
|
defineJuniorPlugins,
|
|
147
70
|
pluginCatalogConfigFromEnv,
|
|
@@ -149,51 +72,128 @@ import {
|
|
|
149
72
|
pluginRuntimeRegistrationsFromPluginSet
|
|
150
73
|
} from "./chunk-SG5WAA7H.js";
|
|
151
74
|
import {
|
|
75
|
+
AuthorizationFlowDisabledError,
|
|
76
|
+
PluginCredentialFailureError,
|
|
77
|
+
SANDBOX_EGRESS_PROXY_PATH,
|
|
78
|
+
addReactionToMessage,
|
|
79
|
+
appendSlackLegacyAttachmentText,
|
|
80
|
+
buildSteeringPiMessage,
|
|
81
|
+
createAgentRunner,
|
|
82
|
+
createUserTokenStore,
|
|
83
|
+
deleteMcpAuthSession,
|
|
84
|
+
deliverResourceEventSubscription,
|
|
85
|
+
executeAgentRun,
|
|
86
|
+
executeCredentialedEgressRequest,
|
|
87
|
+
finalizeMcpAuthorization,
|
|
88
|
+
findMatchingResourceEventSubscriptions,
|
|
89
|
+
formatProviderLabel,
|
|
90
|
+
getConfigDefaults,
|
|
91
|
+
getMcpStoredOAuthCredentials,
|
|
92
|
+
listThreadReplies,
|
|
93
|
+
normalizeSandboxEgressTracePropagationDomains,
|
|
94
|
+
parseOAuthStatePayload,
|
|
95
|
+
parseSandboxEgressCredentialToken,
|
|
96
|
+
postSlackMessage,
|
|
97
|
+
removeReactionFromMessage,
|
|
98
|
+
renderSlackLegacyAttachmentText,
|
|
99
|
+
resolveBaseUrl,
|
|
100
|
+
resolvePluginOAuthAccount,
|
|
101
|
+
resolveSandboxEgressProviderForHost,
|
|
102
|
+
setConfigDefaults,
|
|
103
|
+
shouldEmitDevAgentTrace,
|
|
104
|
+
shouldPropagateSandboxEgressTrace,
|
|
105
|
+
startOAuthFlow,
|
|
106
|
+
unlinkProvider
|
|
107
|
+
} from "./chunk-ZGDTBSQ7.js";
|
|
108
|
+
import {
|
|
109
|
+
CooperativeTurnYieldError,
|
|
110
|
+
TurnInputCommitLostError,
|
|
111
|
+
TurnInputDeferredError,
|
|
112
|
+
applyPendingAuthUpdate,
|
|
113
|
+
buildDeterministicTurnId,
|
|
114
|
+
clearPendingAuth,
|
|
115
|
+
coerceThreadArtifactsState,
|
|
116
|
+
completeDeliveredTurn,
|
|
117
|
+
getChannelConfigurationService,
|
|
118
|
+
getChannelConfigurationServiceById,
|
|
119
|
+
getConversationPendingAuth,
|
|
120
|
+
getPersistedSandboxState,
|
|
121
|
+
getPersistedThreadState,
|
|
122
|
+
isCooperativeTurnYieldError,
|
|
123
|
+
isPendingAuthLatestRequest,
|
|
124
|
+
isTurnInputCommitLostError,
|
|
125
|
+
isTurnInputDeferredError,
|
|
126
|
+
markTurnClosed,
|
|
127
|
+
markTurnFailed,
|
|
128
|
+
mergeArtifactsState,
|
|
129
|
+
persistCompletedSessionRecord,
|
|
130
|
+
persistThreadState,
|
|
131
|
+
persistThreadStateById,
|
|
132
|
+
persistYieldSessionRecord,
|
|
133
|
+
startActiveTurn
|
|
134
|
+
} from "./chunk-ONFOWI2D.js";
|
|
135
|
+
import {
|
|
136
|
+
JUNIOR_THREAD_STATE_TTL_MS,
|
|
137
|
+
coerceThreadConversationState
|
|
138
|
+
} from "./chunk-KC42JAAQ.js";
|
|
139
|
+
import "./chunk-5GBUZI6M.js";
|
|
140
|
+
import {
|
|
141
|
+
buildSlackOutputMessage,
|
|
142
|
+
escapeSlackMrkdwnText,
|
|
143
|
+
formatSlackLink,
|
|
144
|
+
normalizeSlackStatusText,
|
|
145
|
+
splitSlackReplyText,
|
|
146
|
+
truncateStatusText,
|
|
147
|
+
unwrapCurrentInstruction
|
|
148
|
+
} from "./chunk-PIB4EOW6.js";
|
|
149
|
+
import {
|
|
150
|
+
abandonAgentTurnSessionRecord,
|
|
151
|
+
commitMessages,
|
|
152
|
+
escapeXml,
|
|
153
|
+
failAgentTurnSessionRecord,
|
|
154
|
+
getAgentTurnSessionRecord,
|
|
155
|
+
listAgentTurnSessionSummariesForConversation,
|
|
156
|
+
loadProjection,
|
|
157
|
+
recordAgentTurnSessionSummary,
|
|
158
|
+
recordAuthorizationCompleted
|
|
159
|
+
} from "./chunk-GCWD2VHP.js";
|
|
160
|
+
import {
|
|
161
|
+
SlackActionError,
|
|
152
162
|
bindSlackDirectCredentialSubject,
|
|
163
|
+
downloadPrivateSlackFile,
|
|
164
|
+
getHeaderString,
|
|
153
165
|
getPluginApiRoutes,
|
|
154
166
|
getPluginRoutes,
|
|
155
167
|
getPluginSlackConversationLink,
|
|
156
168
|
getPlugins,
|
|
157
|
-
|
|
169
|
+
getSlackClient,
|
|
170
|
+
getWorkspaceTeamId,
|
|
171
|
+
isDmChannel,
|
|
172
|
+
normalizeSlackConversationId,
|
|
173
|
+
runWithSlackInstallationToken,
|
|
174
|
+
runWithWorkspaceTeamId,
|
|
158
175
|
setPlugins,
|
|
159
176
|
validatePlugins,
|
|
160
177
|
verifySlackDirectCredentialSubject
|
|
161
|
-
} from "./chunk-
|
|
178
|
+
} from "./chunk-DACFZ5CI.js";
|
|
162
179
|
import {
|
|
163
180
|
createPluginLogger,
|
|
164
181
|
createPluginState
|
|
165
|
-
} from "./chunk-
|
|
182
|
+
} from "./chunk-NW7AXDA5.js";
|
|
166
183
|
import "./chunk-G3E7SCME.js";
|
|
167
184
|
import {
|
|
168
185
|
acquireActiveLock,
|
|
169
186
|
getStateAdapter
|
|
170
|
-
} from "./chunk-
|
|
187
|
+
} from "./chunk-RS6ANWVT.js";
|
|
171
188
|
import {
|
|
172
189
|
getConversationStore,
|
|
173
190
|
getDb
|
|
174
|
-
} from "./chunk-
|
|
175
|
-
import {
|
|
176
|
-
SlackActionError,
|
|
177
|
-
createSlackDestination,
|
|
178
|
-
destinationKey,
|
|
179
|
-
downloadPrivateSlackFile,
|
|
180
|
-
getHeaderString,
|
|
181
|
-
getSlackClient,
|
|
182
|
-
getWorkspaceTeamId,
|
|
183
|
-
isDmChannel,
|
|
184
|
-
normalizeSlackConversationId,
|
|
185
|
-
parseDestination,
|
|
186
|
-
requireSlackDestination,
|
|
187
|
-
runWithSlackInstallationToken,
|
|
188
|
-
runWithWorkspaceTeamId,
|
|
189
|
-
sameDestination
|
|
190
|
-
} from "./chunk-AHLSXMOU.js";
|
|
191
|
+
} from "./chunk-2S7M37HY.js";
|
|
191
192
|
import {
|
|
192
193
|
FUNCTION_TIMEOUT_BUFFER_SECONDS,
|
|
193
194
|
botConfig,
|
|
194
195
|
completeObject,
|
|
195
196
|
completeText,
|
|
196
|
-
escapeXml,
|
|
197
197
|
getChatConfig,
|
|
198
198
|
getRuntimeMetadata,
|
|
199
199
|
getSlackBotToken,
|
|
@@ -205,57 +205,66 @@ import {
|
|
|
205
205
|
normalizeSlackEmojiName,
|
|
206
206
|
setSlackReactionConfig,
|
|
207
207
|
stripRuntimeTurnContext,
|
|
208
|
-
trimTrailingAssistantMessages
|
|
209
|
-
|
|
210
|
-
} from "./chunk-S35CPNPT.js";
|
|
208
|
+
trimTrailingAssistantMessages
|
|
209
|
+
} from "./chunk-HXL2ZV74.js";
|
|
211
210
|
import {
|
|
212
211
|
parseSlackThreadId,
|
|
212
|
+
readSlackRawMessageContext,
|
|
213
213
|
resolveSlackChannelIdFromMessage,
|
|
214
214
|
resolveSlackChannelIdFromThreadId
|
|
215
|
-
} from "./chunk-
|
|
215
|
+
} from "./chunk-3MPOMK3K.js";
|
|
216
|
+
import {
|
|
217
|
+
createSlackDestination,
|
|
218
|
+
destinationKey,
|
|
219
|
+
parseDestination,
|
|
220
|
+
requireSlackDestination,
|
|
221
|
+
sameDestination
|
|
222
|
+
} from "./chunk-GHGPTPBL.js";
|
|
216
223
|
import {
|
|
217
224
|
discoverSkills
|
|
218
|
-
} from "./chunk-
|
|
225
|
+
} from "./chunk-AN2437E3.js";
|
|
219
226
|
import {
|
|
220
227
|
buildOAuthTokenRequest,
|
|
221
228
|
hasRequiredOAuthScope,
|
|
222
229
|
parseOAuthTokenResponse,
|
|
223
230
|
pluginCatalogRuntime
|
|
224
|
-
} from "./chunk-
|
|
225
|
-
import {
|
|
226
|
-
createRequester,
|
|
227
|
-
createSlackRequester,
|
|
228
|
-
createSlackResumeRequester,
|
|
229
|
-
isActorUserId,
|
|
230
|
-
parseActorUserId,
|
|
231
|
-
toStoredSlackRequester
|
|
232
|
-
} from "./chunk-KQKIA4CU.js";
|
|
233
|
-
import {
|
|
234
|
-
homeDir
|
|
235
|
-
} from "./chunk-6APU57E6.js";
|
|
231
|
+
} from "./chunk-XP7F4LYB.js";
|
|
236
232
|
import {
|
|
237
233
|
buildTurnFailureResponse,
|
|
238
234
|
createChatSdkLogger,
|
|
239
235
|
createRequestContext,
|
|
236
|
+
createRequester,
|
|
237
|
+
createSlackRequester,
|
|
238
|
+
createSlackResumeRequester,
|
|
240
239
|
getActiveTraceId,
|
|
240
|
+
isActorUserId,
|
|
241
241
|
logError,
|
|
242
242
|
logException,
|
|
243
243
|
logInfo,
|
|
244
244
|
logWarn,
|
|
245
|
+
parseActorUserId,
|
|
245
246
|
setSentryUser,
|
|
246
247
|
setSpanAttributes,
|
|
247
248
|
setSpanStatus,
|
|
248
249
|
setTags,
|
|
250
|
+
toStoredSlackRequester,
|
|
249
251
|
withContext,
|
|
250
252
|
withSpan
|
|
251
|
-
} from "./chunk-
|
|
253
|
+
} from "./chunk-ZUK7BL63.js";
|
|
252
254
|
import {
|
|
253
|
-
JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE,
|
|
254
255
|
toOptionalString
|
|
255
|
-
} from "./chunk-
|
|
256
|
+
} from "./chunk-OB42YVAE.js";
|
|
256
257
|
import {
|
|
257
258
|
continueTrace
|
|
258
259
|
} from "./chunk-3DA7X2U3.js";
|
|
260
|
+
import {
|
|
261
|
+
homeDir
|
|
262
|
+
} from "./chunk-6APU57E6.js";
|
|
263
|
+
import {
|
|
264
|
+
JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE,
|
|
265
|
+
parseSlackChannelId,
|
|
266
|
+
parseSlackMessageTs
|
|
267
|
+
} from "./chunk-LFLTJQVR.js";
|
|
259
268
|
import "./chunk-MLKGABMK.js";
|
|
260
269
|
|
|
261
270
|
// src/app.ts
|
|
@@ -313,16 +322,7 @@ function getDashboardConversationLink(conversationId) {
|
|
|
313
322
|
return `${baseURL}${path2}`;
|
|
314
323
|
}
|
|
315
324
|
|
|
316
|
-
// src/chat/slack/reply.ts
|
|
317
|
-
import { Buffer as Buffer2 } from "buffer";
|
|
318
|
-
|
|
319
325
|
// src/chat/slack/footer.ts
|
|
320
|
-
function escapeSlackMrkdwn(text) {
|
|
321
|
-
return text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
322
|
-
}
|
|
323
|
-
function escapeSlackLinkUrl(url) {
|
|
324
|
-
return url.replaceAll("&", "&").replaceAll("<", "%3C").replaceAll(">", "%3E");
|
|
325
|
-
}
|
|
326
326
|
function buildSlackReplyFooter(args) {
|
|
327
327
|
const items = [];
|
|
328
328
|
const conversationId = args.conversationId?.trim();
|
|
@@ -354,7 +354,7 @@ function buildSlackReplyBlocks(text, footer) {
|
|
|
354
354
|
type: "context",
|
|
355
355
|
elements: footer.items.map((item) => ({
|
|
356
356
|
type: "mrkdwn",
|
|
357
|
-
text: item.url ? `*${
|
|
357
|
+
text: item.url ? `*${escapeSlackMrkdwnText(item.label)}:* ${formatSlackLink(item.url, item.value)}` : `*${escapeSlackMrkdwnText(item.label)}:* ${escapeSlackMrkdwnText(item.value)}`
|
|
358
358
|
}))
|
|
359
359
|
});
|
|
360
360
|
}
|
|
@@ -362,17 +362,12 @@ function buildSlackReplyBlocks(text, footer) {
|
|
|
362
362
|
}
|
|
363
363
|
|
|
364
364
|
// src/chat/slack/reply.ts
|
|
365
|
-
function
|
|
366
|
-
const replyHasFiles = Boolean(reply.files && reply.files.length > 0);
|
|
365
|
+
function shouldPostThreadReply(reply) {
|
|
367
366
|
const deliveryPlan = reply.deliveryPlan ?? {
|
|
368
367
|
mode: reply.deliveryMode ?? "thread",
|
|
369
|
-
postThreadText: (reply.deliveryMode ?? "thread") !== "channel_only"
|
|
370
|
-
attachFiles: replyHasFiles ? "inline" : "none"
|
|
371
|
-
};
|
|
372
|
-
return {
|
|
373
|
-
shouldPostThreadReply: deliveryPlan.postThreadText,
|
|
374
|
-
attachFiles: replyHasFiles && deliveryPlan.attachFiles !== "none" ? "inline" : "none"
|
|
368
|
+
postThreadText: (reply.deliveryMode ?? "thread") !== "channel_only"
|
|
375
369
|
};
|
|
370
|
+
return deliveryPlan.postThreadText;
|
|
376
371
|
}
|
|
377
372
|
function buildReplyText(text) {
|
|
378
373
|
const message = buildSlackOutputMessage(text);
|
|
@@ -388,28 +383,9 @@ function buildTextPosts(args) {
|
|
|
388
383
|
const chunks = splitSlackReplyText(args.text);
|
|
389
384
|
return chunks.map((chunk, index) => ({
|
|
390
385
|
text: chunk,
|
|
391
|
-
...index === 0 && args.firstFiles ? { files: args.firstFiles } : {},
|
|
392
386
|
stage: index === 0 ? args.firstStage ?? "thread_reply" : "thread_reply_continuation"
|
|
393
387
|
}));
|
|
394
388
|
}
|
|
395
|
-
async function normalizeFileUploads(files) {
|
|
396
|
-
return await Promise.all(
|
|
397
|
-
files.map(async (file) => {
|
|
398
|
-
let data;
|
|
399
|
-
if (Buffer2.isBuffer(file.data)) {
|
|
400
|
-
data = file.data;
|
|
401
|
-
} else if (file.data instanceof ArrayBuffer) {
|
|
402
|
-
data = Buffer2.from(file.data);
|
|
403
|
-
} else {
|
|
404
|
-
data = Buffer2.from(await file.data.arrayBuffer());
|
|
405
|
-
}
|
|
406
|
-
return {
|
|
407
|
-
data,
|
|
408
|
-
filename: file.filename
|
|
409
|
-
};
|
|
410
|
-
})
|
|
411
|
-
);
|
|
412
|
-
}
|
|
413
389
|
function findLastTextPostIndex(posts) {
|
|
414
390
|
for (let index = posts.length - 1; index >= 0; index -= 1) {
|
|
415
391
|
if (posts[index]?.text.trim().length) {
|
|
@@ -418,56 +394,25 @@ function findLastTextPostIndex(posts) {
|
|
|
418
394
|
}
|
|
419
395
|
return -1;
|
|
420
396
|
}
|
|
421
|
-
async function uploadReplyFiles(args) {
|
|
422
|
-
try {
|
|
423
|
-
await uploadFilesToThread({
|
|
424
|
-
channelId: args.channelId,
|
|
425
|
-
threadTs: args.threadTs,
|
|
426
|
-
files: await normalizeFileUploads(args.files)
|
|
427
|
-
});
|
|
428
|
-
} catch (error) {
|
|
429
|
-
if (args.failureMode === "strict") {
|
|
430
|
-
throw error;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
397
|
function planSlackReplyPosts(args) {
|
|
435
|
-
const replyFiles = args.reply.files && args.reply.files.length > 0 ? args.reply.files : void 0;
|
|
436
|
-
const { shouldPostThreadReply, attachFiles } = resolveReplyDelivery(
|
|
437
|
-
args.reply
|
|
438
|
-
);
|
|
439
398
|
const posts = [];
|
|
440
|
-
const textPosts = shouldPostThreadReply ? buildTextPosts({
|
|
441
|
-
text: args.reply.text
|
|
442
|
-
firstFiles: attachFiles === "inline" ? replyFiles : void 0
|
|
399
|
+
const textPosts = shouldPostThreadReply(args.reply) ? buildTextPosts({
|
|
400
|
+
text: args.reply.text
|
|
443
401
|
}) : [];
|
|
444
402
|
posts.push(...textPosts);
|
|
445
|
-
if (
|
|
446
|
-
posts.push({
|
|
447
|
-
files: replyFiles,
|
|
448
|
-
stage: "thread_reply",
|
|
449
|
-
text: ""
|
|
450
|
-
});
|
|
451
|
-
} else if (shouldPostThreadReply && textPosts.length === 0) {
|
|
403
|
+
if (shouldPostThreadReply(args.reply) && textPosts.length === 0) {
|
|
452
404
|
posts.push({
|
|
453
405
|
text: buildReplyText(args.reply.text),
|
|
454
406
|
stage: "thread_reply"
|
|
455
407
|
});
|
|
456
408
|
}
|
|
457
|
-
if (attachFiles === "followup" && replyFiles) {
|
|
458
|
-
posts.push({
|
|
459
|
-
files: replyFiles,
|
|
460
|
-
stage: "thread_reply_files_followup",
|
|
461
|
-
text: ""
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
409
|
return posts;
|
|
465
410
|
}
|
|
466
411
|
async function postSlackApiReplyPosts(args) {
|
|
467
412
|
const lastTextPostIndex = findLastTextPostIndex(args.posts);
|
|
468
413
|
let lastPostedMessageTs;
|
|
469
414
|
for (const [index, post] of args.posts.entries()) {
|
|
470
|
-
const hasVisibleDelivery = post.text.trim().length > 0
|
|
415
|
+
const hasVisibleDelivery = post.text.trim().length > 0;
|
|
471
416
|
if (hasVisibleDelivery) {
|
|
472
417
|
await args.beforePost?.();
|
|
473
418
|
}
|
|
@@ -485,18 +430,7 @@ async function postSlackApiReplyPosts(args) {
|
|
|
485
430
|
messageTs = response.ts;
|
|
486
431
|
lastPostedMessageTs = response.ts;
|
|
487
432
|
}
|
|
488
|
-
|
|
489
|
-
continue;
|
|
490
|
-
}
|
|
491
|
-
if (!args.threadTs && !lastPostedMessageTs) {
|
|
492
|
-
throw new Error("Slack file delivery requires a posted message thread");
|
|
493
|
-
}
|
|
494
|
-
await uploadReplyFiles({
|
|
495
|
-
channelId: args.channelId,
|
|
496
|
-
failureMode: args.fileUploadFailureMode ?? "best_effort",
|
|
497
|
-
threadTs: args.threadTs ?? lastPostedMessageTs,
|
|
498
|
-
files: post.files
|
|
499
|
-
});
|
|
433
|
+
continue;
|
|
500
434
|
} catch (error) {
|
|
501
435
|
await args.onPostError?.({
|
|
502
436
|
error,
|
|
@@ -892,13 +826,19 @@ function getAssistantMessageId(dispatch) {
|
|
|
892
826
|
function buildDispatchConversationText(dispatch) {
|
|
893
827
|
return `[dispatched task] ${dispatch.input}`;
|
|
894
828
|
}
|
|
829
|
+
function shouldPostDispatchReplyText(reply) {
|
|
830
|
+
return reply.deliveryPlan?.postThreadText ?? (reply.deliveryMode ?? "thread") !== "channel_only";
|
|
831
|
+
}
|
|
895
832
|
function ensureVisibleDeliveryText(reply) {
|
|
896
|
-
if (
|
|
833
|
+
if (!shouldPostDispatchReplyText(reply)) {
|
|
834
|
+
return reply;
|
|
835
|
+
}
|
|
836
|
+
if (reply.text.trim().length > 0) {
|
|
897
837
|
return reply;
|
|
898
838
|
}
|
|
899
839
|
return {
|
|
900
840
|
...reply,
|
|
901
|
-
text: "
|
|
841
|
+
text: "The task completed without a visible response."
|
|
902
842
|
};
|
|
903
843
|
}
|
|
904
844
|
function upsertDispatchUserMessage(args) {
|
|
@@ -954,8 +894,7 @@ function canClaimDispatch(record, nowMs) {
|
|
|
954
894
|
}
|
|
955
895
|
return true;
|
|
956
896
|
}
|
|
957
|
-
async function runAgentDispatchSlice(callback, deps
|
|
958
|
-
const generateAssistantReply2 = deps.generateAssistantReply ?? generateAssistantReply;
|
|
897
|
+
async function runAgentDispatchSlice(callback, deps) {
|
|
959
898
|
const scheduleCallback = deps.scheduleCallback ?? scheduleDispatchCallback;
|
|
960
899
|
const scheduleCompletedTasks = deps.scheduleSessionCompletedPluginTasks ?? scheduleSessionCompletedPluginTasks;
|
|
961
900
|
const nowMs = Date.now();
|
|
@@ -1051,61 +990,91 @@ async function runAgentDispatchSlice(callback, deps = {}) {
|
|
|
1051
990
|
const conversationContext = buildConversationContext(conversation, {
|
|
1052
991
|
excludeMessageId: userMessageId
|
|
1053
992
|
});
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
993
|
+
const outcome = await deps.agentRunner.run({
|
|
994
|
+
input: {
|
|
995
|
+
messageText: dispatch.input,
|
|
996
|
+
conversationContext,
|
|
997
|
+
piMessages: conversation.piMessages
|
|
1059
998
|
},
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
999
|
+
routing: {
|
|
1000
|
+
credentialContext: {
|
|
1001
|
+
actor: dispatch.actor,
|
|
1002
|
+
...dispatch.credentialSubject ? { subject: dispatch.credentialSubject } : {}
|
|
1003
|
+
},
|
|
1004
|
+
destination: dispatch.destination,
|
|
1005
|
+
source: dispatch.source,
|
|
1006
|
+
dispatch: {
|
|
1007
|
+
actor: dispatch.actor,
|
|
1008
|
+
metadata: dispatch.metadata,
|
|
1009
|
+
plugin: dispatch.plugin
|
|
1010
|
+
},
|
|
1011
|
+
correlation: {
|
|
1012
|
+
conversationId,
|
|
1013
|
+
threadId: conversationId,
|
|
1014
|
+
turnId,
|
|
1015
|
+
runId: dispatch.id,
|
|
1016
|
+
channelId: dispatch.destination.channelId,
|
|
1017
|
+
teamId: dispatch.destination.teamId
|
|
1018
|
+
},
|
|
1019
|
+
surface: "api",
|
|
1020
|
+
toolChannelId: dispatch.destination.channelId
|
|
1079
1021
|
},
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
sandboxDependencyProfileHash,
|
|
1085
|
-
tracePropagation: deps.tracePropagation
|
|
1022
|
+
policy: {
|
|
1023
|
+
authorizationFlowMode: "disabled",
|
|
1024
|
+
configuration,
|
|
1025
|
+
channelConfiguration
|
|
1086
1026
|
},
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
await persistRuntimePatch({
|
|
1091
|
-
threadId: conversationId,
|
|
1092
|
-
conversation,
|
|
1093
|
-
artifacts,
|
|
1027
|
+
state: {
|
|
1028
|
+
artifactState: artifacts,
|
|
1029
|
+
sandbox: {
|
|
1094
1030
|
sandboxId,
|
|
1095
1031
|
sandboxDependencyProfileHash
|
|
1096
|
-
}
|
|
1032
|
+
}
|
|
1097
1033
|
},
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1034
|
+
durability: {
|
|
1035
|
+
onSandboxAcquired: async (sandbox) => {
|
|
1036
|
+
sandboxId = sandbox.sandboxId;
|
|
1037
|
+
sandboxDependencyProfileHash = sandbox.sandboxDependencyProfileHash;
|
|
1038
|
+
await persistRuntimePatch({
|
|
1039
|
+
threadId: conversationId,
|
|
1040
|
+
conversation,
|
|
1041
|
+
artifacts,
|
|
1042
|
+
sandboxId,
|
|
1043
|
+
sandboxDependencyProfileHash
|
|
1044
|
+
});
|
|
1045
|
+
},
|
|
1046
|
+
onArtifactStateUpdated: async (nextArtifacts2) => {
|
|
1047
|
+
artifacts = nextArtifacts2;
|
|
1048
|
+
await persistRuntimePatch({
|
|
1049
|
+
threadId: conversationId,
|
|
1050
|
+
conversation,
|
|
1051
|
+
artifacts,
|
|
1052
|
+
sandboxId,
|
|
1053
|
+
sandboxDependencyProfileHash
|
|
1054
|
+
});
|
|
1055
|
+
}
|
|
1107
1056
|
}
|
|
1108
1057
|
});
|
|
1058
|
+
if (outcome.status === "awaiting_auth") {
|
|
1059
|
+
await markDispatch({
|
|
1060
|
+
dispatch,
|
|
1061
|
+
status: "blocked",
|
|
1062
|
+
errorMessage: "Dispatch requires authorization from an interactive user turn."
|
|
1063
|
+
});
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
if (outcome.status === "suspended") {
|
|
1067
|
+
const awaiting = await markDispatch({
|
|
1068
|
+
dispatch,
|
|
1069
|
+
status: "awaiting_resume"
|
|
1070
|
+
});
|
|
1071
|
+
await scheduleCallback({
|
|
1072
|
+
id: awaiting.id,
|
|
1073
|
+
expectedVersion: awaiting.version
|
|
1074
|
+
});
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
let reply = outcome.result;
|
|
1109
1078
|
const failure = reply.diagnostics.outcome === "success" ? void 0 : reply.diagnostics.errorMessage ?? `Agent turn ended with ${reply.diagnostics.outcome}.`;
|
|
1110
1079
|
if (failure) {
|
|
1111
1080
|
reply = finalizeFailedTurnReply({
|
|
@@ -1123,8 +1092,7 @@ async function runAgentDispatchSlice(callback, deps = {}) {
|
|
|
1123
1092
|
posts: planSlackReplyPosts({ reply: deliveryReply }),
|
|
1124
1093
|
footer: buildSlackReplyFooter({
|
|
1125
1094
|
conversationId
|
|
1126
|
-
})
|
|
1127
|
-
fileUploadFailureMode: "strict"
|
|
1095
|
+
})
|
|
1128
1096
|
});
|
|
1129
1097
|
markConversationMessage(conversation, userMessageId, {
|
|
1130
1098
|
replied: true,
|
|
@@ -1224,28 +1192,6 @@ async function runAgentDispatchSlice(callback, deps = {}) {
|
|
|
1224
1192
|
});
|
|
1225
1193
|
return;
|
|
1226
1194
|
}
|
|
1227
|
-
if (isRetryableTurnError(error, "mcp_auth_resume") || isRetryableTurnError(error, "plugin_auth_resume")) {
|
|
1228
|
-
await markDispatch({
|
|
1229
|
-
dispatch,
|
|
1230
|
-
status: "blocked",
|
|
1231
|
-
errorMessage: "Dispatch requires authorization from an interactive user turn."
|
|
1232
|
-
});
|
|
1233
|
-
return;
|
|
1234
|
-
}
|
|
1235
|
-
if (isRetryableTurnError(error, "agent_continue")) {
|
|
1236
|
-
const version = error.metadata?.version;
|
|
1237
|
-
if (typeof version === "number") {
|
|
1238
|
-
const awaiting = await markDispatch({
|
|
1239
|
-
dispatch,
|
|
1240
|
-
status: "awaiting_resume"
|
|
1241
|
-
});
|
|
1242
|
-
await scheduleCallback({
|
|
1243
|
-
id: awaiting.id,
|
|
1244
|
-
expectedVersion: awaiting.version
|
|
1245
|
-
});
|
|
1246
|
-
return;
|
|
1247
|
-
}
|
|
1248
|
-
}
|
|
1249
1195
|
logException(
|
|
1250
1196
|
error,
|
|
1251
1197
|
"agent_dispatch_run_failed",
|
|
@@ -1267,14 +1213,14 @@ async function runAgentDispatchSlice(callback, deps = {}) {
|
|
|
1267
1213
|
}
|
|
1268
1214
|
|
|
1269
1215
|
// src/handlers/agent-dispatch.ts
|
|
1270
|
-
async function POST(request, waitUntil, options
|
|
1216
|
+
async function POST(request, waitUntil, options) {
|
|
1271
1217
|
const payload = await verifyDispatchCallbackRequest(request);
|
|
1272
1218
|
if (!payload) {
|
|
1273
1219
|
return new Response("Unauthorized", { status: 401 });
|
|
1274
1220
|
}
|
|
1275
1221
|
waitUntil(
|
|
1276
1222
|
() => runAgentDispatchSlice(payload, {
|
|
1277
|
-
|
|
1223
|
+
agentRunner: options.agentRunner
|
|
1278
1224
|
}).catch((error) => {
|
|
1279
1225
|
logException(
|
|
1280
1226
|
error,
|
|
@@ -3529,6 +3475,12 @@ function isSlackTitlePermissionError(error) {
|
|
|
3529
3475
|
function escapeRegExp(value) {
|
|
3530
3476
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3531
3477
|
}
|
|
3478
|
+
function readObjectField(value, key) {
|
|
3479
|
+
return value[key];
|
|
3480
|
+
}
|
|
3481
|
+
function readOptionalStringField(value, key) {
|
|
3482
|
+
return toOptionalString(readObjectField(value, key));
|
|
3483
|
+
}
|
|
3532
3484
|
function stripLeadingBotMention(text, options = {}) {
|
|
3533
3485
|
if (!text.trim()) return text;
|
|
3534
3486
|
let next = text;
|
|
@@ -3560,7 +3512,7 @@ function getThreadId(thread, _message) {
|
|
|
3560
3512
|
return toOptionalString(thread.id);
|
|
3561
3513
|
}
|
|
3562
3514
|
function getRunId(thread, message) {
|
|
3563
|
-
return
|
|
3515
|
+
return readOptionalStringField(thread, "runId") ?? readOptionalStringField(message, "runId");
|
|
3564
3516
|
}
|
|
3565
3517
|
function getChannelId(thread, message) {
|
|
3566
3518
|
return resolveSlackChannelIdFromThreadId(toOptionalString(thread.id)) ?? normalizeSlackConversationId(toOptionalString(thread.channelId)) ?? resolveSlackChannelIdFromMessage(message);
|
|
@@ -3569,18 +3521,16 @@ function getThreadTs(threadId) {
|
|
|
3569
3521
|
return parseSlackThreadId(threadId)?.threadTs;
|
|
3570
3522
|
}
|
|
3571
3523
|
function getAssistantThreadContext(message) {
|
|
3572
|
-
const
|
|
3573
|
-
const
|
|
3574
|
-
const channelId = toOptionalString(rawRecord?.channel);
|
|
3524
|
+
const rawContext = readSlackRawMessageContext(message);
|
|
3525
|
+
const channelId = rawContext?.channelId;
|
|
3575
3526
|
if (channelId) {
|
|
3576
|
-
const
|
|
3577
|
-
const threadTs = isDmChannel(channelId) ? rawThreadTs : rawThreadTs ?? toOptionalString(rawRecord?.ts);
|
|
3527
|
+
const threadTs = isDmChannel(channelId) ? rawContext.threadTs : rawContext.threadTs ?? rawContext.messageTs;
|
|
3578
3528
|
if (threadTs) {
|
|
3579
3529
|
return { channelId, threadTs };
|
|
3580
3530
|
}
|
|
3581
3531
|
}
|
|
3582
3532
|
const parsedThreadId = parseSlackThreadId(
|
|
3583
|
-
|
|
3533
|
+
readOptionalStringField(message, "threadId")
|
|
3584
3534
|
);
|
|
3585
3535
|
if (!parsedThreadId || isDmChannel(parsedThreadId.channelId)) {
|
|
3586
3536
|
return void 0;
|
|
@@ -3588,22 +3538,16 @@ function getAssistantThreadContext(message) {
|
|
|
3588
3538
|
return parsedThreadId;
|
|
3589
3539
|
}
|
|
3590
3540
|
function getMessageTs(message) {
|
|
3591
|
-
const directTs =
|
|
3592
|
-
message.ts
|
|
3593
|
-
);
|
|
3541
|
+
const directTs = readOptionalStringField(message, "ts");
|
|
3594
3542
|
const parsedDirectTs = parseSlackMessageTs(directTs);
|
|
3595
3543
|
if (parsedDirectTs) {
|
|
3596
3544
|
return parsedDirectTs;
|
|
3597
3545
|
}
|
|
3598
|
-
const
|
|
3599
|
-
if (!
|
|
3546
|
+
const rawContext = readSlackRawMessageContext(message);
|
|
3547
|
+
if (!rawContext) {
|
|
3600
3548
|
return void 0;
|
|
3601
3549
|
}
|
|
3602
|
-
const
|
|
3603
|
-
const candidates = [
|
|
3604
|
-
rawRecord.ts,
|
|
3605
|
-
rawRecord.message?.ts
|
|
3606
|
-
];
|
|
3550
|
+
const candidates = [rawContext.messageTs, rawContext.nestedMessageTs];
|
|
3607
3551
|
for (const candidate of candidates) {
|
|
3608
3552
|
const ts = parseSlackMessageTs(candidate);
|
|
3609
3553
|
if (ts) {
|
|
@@ -3623,7 +3567,7 @@ function isProcessingReactionEmoji(value) {
|
|
|
3623
3567
|
return typeof value === "string" && normalizeSlackEmojiName(value) === getChatConfig().slack.processingReactionEmoji;
|
|
3624
3568
|
}
|
|
3625
3569
|
function shouldKeepProcessingReactionForToolInvocation(input) {
|
|
3626
|
-
return input.toolName === "
|
|
3570
|
+
return input.toolName === "addReaction" && isProcessingReactionEmoji(input.params.emoji);
|
|
3627
3571
|
}
|
|
3628
3572
|
async function startSlackProcessingReaction(args) {
|
|
3629
3573
|
if (args.message.author.isMe) {
|
|
@@ -3824,19 +3768,20 @@ function getDefaultLockKey(channelId, threadTs) {
|
|
|
3824
3768
|
return `slack:${channelId}:${threadTs}`;
|
|
3825
3769
|
}
|
|
3826
3770
|
function getResumeLogContext(args, lockKey) {
|
|
3771
|
+
const routing = args.replyContext?.routing;
|
|
3827
3772
|
return {
|
|
3828
|
-
conversationId:
|
|
3829
|
-
slackThreadId:
|
|
3830
|
-
slackUserId:
|
|
3831
|
-
slackUserName:
|
|
3773
|
+
conversationId: routing?.correlation?.conversationId ?? lockKey,
|
|
3774
|
+
slackThreadId: routing?.correlation?.threadId ?? lockKey,
|
|
3775
|
+
slackUserId: routing?.requester?.userId ?? routing?.correlation?.requesterId,
|
|
3776
|
+
slackUserName: routing?.requester?.userName,
|
|
3832
3777
|
slackChannelId: args.channelId,
|
|
3833
|
-
runId:
|
|
3778
|
+
runId: routing?.correlation?.runId,
|
|
3834
3779
|
assistantUserName: botConfig.userName,
|
|
3835
3780
|
modelId: botConfig.modelId
|
|
3836
3781
|
};
|
|
3837
3782
|
}
|
|
3838
3783
|
function getResumeConversationId(args, lockKey) {
|
|
3839
|
-
return args.replyContext?.correlation?.conversationId ?? lockKey;
|
|
3784
|
+
return args.replyContext?.routing.correlation?.conversationId ?? lockKey;
|
|
3840
3785
|
}
|
|
3841
3786
|
async function postResumeFailureReply(args) {
|
|
3842
3787
|
try {
|
|
@@ -3881,42 +3826,58 @@ function createResumeReplyContext(args, statusSession) {
|
|
|
3881
3826
|
if (!replyContext) {
|
|
3882
3827
|
throw new TypeError("Slack resume requires a reply context");
|
|
3883
3828
|
}
|
|
3884
|
-
if (!replyContext.source) {
|
|
3829
|
+
if (!replyContext.routing.source) {
|
|
3885
3830
|
throw new TypeError("Slack resume requires a reply context source");
|
|
3886
3831
|
}
|
|
3887
|
-
const source = replyContext.source;
|
|
3888
|
-
if (replyContext.destination.platform !== "slack") {
|
|
3832
|
+
const source = replyContext.routing.source;
|
|
3833
|
+
if (replyContext.routing.destination.platform !== "slack") {
|
|
3889
3834
|
throw new TypeError("Slack resume requires a Slack destination");
|
|
3890
3835
|
}
|
|
3891
3836
|
const requestDeadline = getTurnRequestDeadline();
|
|
3892
3837
|
const threadId = args.lockKey ?? getDefaultLockKey(args.channelId, args.threadTs);
|
|
3893
|
-
const persistedChannelConfiguration = replyContext.channelConfiguration ?? (replyContext.configuration ? createReadOnlyConfigService(replyContext.configuration) : void 0);
|
|
3838
|
+
const persistedChannelConfiguration = replyContext.policy?.channelConfiguration ?? (replyContext.policy?.configuration ? createReadOnlyConfigService(replyContext.policy.configuration) : void 0);
|
|
3894
3839
|
return {
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
correlation: {
|
|
3899
|
-
...replyContext.correlation,
|
|
3900
|
-
threadId: replyContext.correlation?.threadId ?? threadId,
|
|
3901
|
-
channelId: replyContext.correlation?.channelId ?? args.channelId,
|
|
3902
|
-
threadTs: replyContext.correlation?.threadTs ?? args.threadTs,
|
|
3903
|
-
requesterId: replyContext.correlation?.requesterId ?? replyContext.requester?.userId
|
|
3840
|
+
input: {
|
|
3841
|
+
...replyContext.input ?? {},
|
|
3842
|
+
messageText: args.messageText
|
|
3904
3843
|
},
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3844
|
+
routing: {
|
|
3845
|
+
...replyContext.routing,
|
|
3846
|
+
source,
|
|
3847
|
+
correlation: {
|
|
3848
|
+
...replyContext.routing.correlation,
|
|
3849
|
+
threadId: replyContext.routing.correlation?.threadId ?? threadId,
|
|
3850
|
+
channelId: replyContext.routing.correlation?.channelId ?? args.channelId,
|
|
3851
|
+
threadTs: replyContext.routing.correlation?.threadTs ?? args.threadTs,
|
|
3852
|
+
requesterId: replyContext.routing.correlation?.requesterId ?? replyContext.routing.requester?.userId
|
|
3853
|
+
}
|
|
3854
|
+
},
|
|
3855
|
+
policy: {
|
|
3856
|
+
...replyContext.policy,
|
|
3857
|
+
turnDeadlineAtMs: replyContext.policy?.turnDeadlineAtMs ?? requestDeadline?.deadlineAtMs,
|
|
3858
|
+
channelConfiguration: persistedChannelConfiguration
|
|
3912
3859
|
},
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3860
|
+
state: replyContext.state,
|
|
3861
|
+
observers: {
|
|
3862
|
+
...replyContext.observers,
|
|
3863
|
+
onStatus: async (nextStatus) => {
|
|
3864
|
+
statusSession.update(nextStatus);
|
|
3865
|
+
await replyContext.observers?.onStatus?.(nextStatus);
|
|
3866
|
+
}
|
|
3916
3867
|
},
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3868
|
+
durability: {
|
|
3869
|
+
...replyContext.durability,
|
|
3870
|
+
onSandboxAcquired: async (sandbox) => {
|
|
3871
|
+
await persistThreadStateById(threadId, {
|
|
3872
|
+
sandboxId: sandbox.sandboxId,
|
|
3873
|
+
sandboxDependencyProfileHash: sandbox.sandboxDependencyProfileHash
|
|
3874
|
+
});
|
|
3875
|
+
await replyContext.durability?.onSandboxAcquired?.(sandbox);
|
|
3876
|
+
},
|
|
3877
|
+
onArtifactStateUpdated: async (artifacts) => {
|
|
3878
|
+
await persistThreadStateById(threadId, { artifacts });
|
|
3879
|
+
await replyContext.durability?.onArtifactStateUpdated?.(artifacts);
|
|
3880
|
+
}
|
|
3920
3881
|
}
|
|
3921
3882
|
};
|
|
3922
3883
|
}
|
|
@@ -3948,16 +3909,18 @@ async function resumeSlackTurn(args) {
|
|
|
3948
3909
|
if (preparedArgs) {
|
|
3949
3910
|
runArgs = { ...args, ...preparedArgs };
|
|
3950
3911
|
}
|
|
3951
|
-
if (!runArgs.replyContext?.requester?.userId) {
|
|
3952
|
-
throw new Error(
|
|
3912
|
+
if (!runArgs.replyContext?.routing.requester?.userId) {
|
|
3913
|
+
throw new Error(
|
|
3914
|
+
"Resumed turn requires replyContext.routing.requester.userId"
|
|
3915
|
+
);
|
|
3953
3916
|
}
|
|
3954
|
-
const credentialContext = runArgs.replyContext.credentialContext;
|
|
3917
|
+
const credentialContext = runArgs.replyContext.routing.credentialContext;
|
|
3955
3918
|
if (!credentialContext) {
|
|
3956
3919
|
throw new Error("Resumed turn requires replyContext.credentialContext");
|
|
3957
3920
|
}
|
|
3958
|
-
if (credentialContext.actor.type !== "user" || credentialContext.actor.userId !== runArgs.replyContext.requester.userId) {
|
|
3921
|
+
if (credentialContext.actor.type !== "user" || credentialContext.actor.userId !== runArgs.replyContext.routing.requester.userId) {
|
|
3959
3922
|
throw new Error(
|
|
3960
|
-
"Resumed turn credential actor must match replyContext.requester.userId"
|
|
3923
|
+
"Resumed turn credential actor must match replyContext.routing.requester.userId"
|
|
3961
3924
|
);
|
|
3962
3925
|
}
|
|
3963
3926
|
if (runArgs.messageTs) {
|
|
@@ -3976,87 +3939,119 @@ async function resumeSlackTurn(args) {
|
|
|
3976
3939
|
);
|
|
3977
3940
|
}
|
|
3978
3941
|
status.start();
|
|
3979
|
-
const generateReply = runArgs.generateReply ?? generateAssistantReply;
|
|
3980
3942
|
const replyContext = createResumeReplyContext(runArgs, status);
|
|
3981
|
-
const replyPromise =
|
|
3943
|
+
const replyPromise = runArgs.agentRunner.run(replyContext);
|
|
3982
3944
|
const replyTimeoutMs = resolveReplyTimeoutMs(runArgs.replyTimeoutMs);
|
|
3983
|
-
|
|
3945
|
+
const outcome = typeof replyTimeoutMs === "number" ? await Promise.race([
|
|
3984
3946
|
replyPromise,
|
|
3985
3947
|
new Promise(
|
|
3986
3948
|
(_, reject) => setTimeout(
|
|
3987
3949
|
() => reject(
|
|
3988
3950
|
new Error(
|
|
3989
|
-
`
|
|
3951
|
+
`executeAgentRun timed out after ${replyTimeoutMs}ms`
|
|
3990
3952
|
)
|
|
3991
3953
|
),
|
|
3992
3954
|
replyTimeoutMs
|
|
3993
3955
|
)
|
|
3994
3956
|
)
|
|
3995
3957
|
]) : await replyPromise;
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
await postSlackApiReplyPosts({
|
|
4006
|
-
channelId: runArgs.channelId,
|
|
4007
|
-
threadTs: runArgs.threadTs,
|
|
4008
|
-
posts: planSlackReplyPosts({ reply }),
|
|
4009
|
-
fileUploadFailureMode: "best_effort",
|
|
4010
|
-
footer
|
|
4011
|
-
});
|
|
4012
|
-
finalReplyDelivered = true;
|
|
4013
|
-
if (replyContext.correlation?.conversationId && replyContext.correlation.turnId && reply.piMessages?.length) {
|
|
4014
|
-
await persistCompletedSessionRecord({
|
|
4015
|
-
conversationId: replyContext.correlation.conversationId,
|
|
4016
|
-
sessionId: replyContext.correlation.turnId,
|
|
4017
|
-
allMessages: reply.piMessages,
|
|
4018
|
-
currentDurationMs: reply.diagnostics.durationMs,
|
|
4019
|
-
currentUsage: reply.diagnostics.usage,
|
|
4020
|
-
destination: replyContext.destination,
|
|
4021
|
-
source: replyContext.source,
|
|
4022
|
-
requester: replyContext.requester,
|
|
4023
|
-
surface: "slack",
|
|
4024
|
-
logContext: {
|
|
4025
|
-
threadId: replyContext.correlation.threadId,
|
|
4026
|
-
requesterId: replyContext.requester?.userId,
|
|
4027
|
-
channelId: runArgs.channelId,
|
|
4028
|
-
runId: replyContext.correlation.runId,
|
|
4029
|
-
assistantUserName: botConfig.userName,
|
|
4030
|
-
modelId: reply.diagnostics.modelId
|
|
4031
|
-
}
|
|
4032
|
-
});
|
|
4033
|
-
}
|
|
4034
|
-
await runArgs.onSuccess?.(reply);
|
|
4035
|
-
if (reply.diagnostics.outcome === "success" && replyContext.correlation?.conversationId && replyContext.correlation.turnId) {
|
|
4036
|
-
try {
|
|
4037
|
-
const params = {
|
|
4038
|
-
conversationId: replyContext.correlation.conversationId,
|
|
4039
|
-
sessionId: replyContext.correlation.turnId
|
|
3958
|
+
if (outcome.status !== "completed") {
|
|
3959
|
+
await status.stop();
|
|
3960
|
+
const onAuthPause = runArgs.onAuthPause;
|
|
3961
|
+
const onTimeoutPause = runArgs.onTimeoutPause;
|
|
3962
|
+
if (outcome.status === "awaiting_auth" && onAuthPause) {
|
|
3963
|
+
deferredPauseKind = "auth";
|
|
3964
|
+
deferredAuthInfo = {
|
|
3965
|
+
providerDisplayName: outcome.providerDisplayName,
|
|
3966
|
+
requesterId: runArgs.replyContext?.routing.requester?.userId
|
|
4040
3967
|
};
|
|
4041
|
-
|
|
4042
|
-
await
|
|
4043
|
-
|
|
4044
|
-
|
|
3968
|
+
deferredPauseHandler = async () => {
|
|
3969
|
+
await onAuthPause({
|
|
3970
|
+
providerDisplayName: outcome.providerDisplayName
|
|
3971
|
+
});
|
|
3972
|
+
};
|
|
3973
|
+
} else if (outcome.status === "suspended" && onTimeoutPause) {
|
|
3974
|
+
deferredPauseKind = "timeout";
|
|
3975
|
+
deferredPauseHandler = async () => {
|
|
3976
|
+
await onTimeoutPause({ resumeVersion: outcome.resumeVersion });
|
|
3977
|
+
};
|
|
3978
|
+
} else {
|
|
3979
|
+
deferredFailureHandler = async () => {
|
|
3980
|
+
await handleResumeFailure({
|
|
3981
|
+
body: "Failed to resume Slack turn",
|
|
3982
|
+
error: new Error(
|
|
3983
|
+
`Resumed run ended ${outcome.status} without a pause handler`
|
|
3984
|
+
),
|
|
3985
|
+
eventName: "slack_resume_turn_failed",
|
|
3986
|
+
lockKey,
|
|
3987
|
+
resumeArgs: runArgs
|
|
3988
|
+
});
|
|
3989
|
+
};
|
|
3990
|
+
}
|
|
3991
|
+
} else {
|
|
3992
|
+
let reply = outcome.result;
|
|
3993
|
+
reply = finalizeFailedTurnReply({
|
|
3994
|
+
reply,
|
|
3995
|
+
logException,
|
|
3996
|
+
context: getResumeLogContext(runArgs, lockKey)
|
|
3997
|
+
});
|
|
3998
|
+
await status.stop();
|
|
3999
|
+
const footer = buildSlackReplyFooter({
|
|
4000
|
+
conversationId: getResumeConversationId(runArgs, lockKey)
|
|
4001
|
+
});
|
|
4002
|
+
await postSlackApiReplyPosts({
|
|
4003
|
+
channelId: runArgs.channelId,
|
|
4004
|
+
threadTs: runArgs.threadTs,
|
|
4005
|
+
posts: planSlackReplyPosts({ reply }),
|
|
4006
|
+
footer
|
|
4007
|
+
});
|
|
4008
|
+
finalReplyDelivered = true;
|
|
4009
|
+
if (replyContext.routing.correlation?.conversationId && replyContext.routing.correlation.turnId && reply.piMessages?.length) {
|
|
4010
|
+
await persistCompletedSessionRecord({
|
|
4011
|
+
conversationId: replyContext.routing.correlation.conversationId,
|
|
4012
|
+
sessionId: replyContext.routing.correlation.turnId,
|
|
4013
|
+
allMessages: reply.piMessages,
|
|
4014
|
+
currentDurationMs: reply.diagnostics.durationMs,
|
|
4015
|
+
currentUsage: reply.diagnostics.usage,
|
|
4016
|
+
destination: replyContext.routing.destination,
|
|
4017
|
+
source: replyContext.routing.source,
|
|
4018
|
+
requester: replyContext.routing.requester,
|
|
4019
|
+
surface: "slack",
|
|
4020
|
+
logContext: {
|
|
4021
|
+
threadId: replyContext.routing.correlation.threadId,
|
|
4022
|
+
requesterId: replyContext.routing.requester?.userId,
|
|
4023
|
+
channelId: runArgs.channelId,
|
|
4024
|
+
runId: replyContext.routing.correlation.runId,
|
|
4025
|
+
assistantUserName: botConfig.userName,
|
|
4026
|
+
modelId: reply.diagnostics.modelId
|
|
4027
|
+
}
|
|
4028
|
+
});
|
|
4029
|
+
}
|
|
4030
|
+
await runArgs.onSuccess?.(reply);
|
|
4031
|
+
if (reply.diagnostics.outcome === "success" && replyContext.routing.correlation?.conversationId && replyContext.routing.correlation.turnId) {
|
|
4032
|
+
try {
|
|
4033
|
+
const params = {
|
|
4034
|
+
conversationId: replyContext.routing.correlation.conversationId,
|
|
4035
|
+
sessionId: replyContext.routing.correlation.turnId
|
|
4036
|
+
};
|
|
4037
|
+
if (runArgs.scheduleSessionCompletedPluginTasks) {
|
|
4038
|
+
await runArgs.scheduleSessionCompletedPluginTasks(params);
|
|
4039
|
+
} else {
|
|
4040
|
+
await scheduleSessionCompletedPluginTasks(params);
|
|
4041
|
+
}
|
|
4042
|
+
} catch (scheduleError) {
|
|
4043
|
+
logException(
|
|
4044
|
+
scheduleError,
|
|
4045
|
+
"plugin_session_completed_task_schedule_failed",
|
|
4046
|
+
getResumeLogContext(runArgs, lockKey),
|
|
4047
|
+
{},
|
|
4048
|
+
"Plugin session.completed task scheduling failed"
|
|
4049
|
+
);
|
|
4045
4050
|
}
|
|
4046
|
-
} catch (scheduleError) {
|
|
4047
|
-
logException(
|
|
4048
|
-
scheduleError,
|
|
4049
|
-
"plugin_session_completed_task_schedule_failed",
|
|
4050
|
-
getResumeLogContext(runArgs, lockKey),
|
|
4051
|
-
{},
|
|
4052
|
-
"Plugin session.completed task scheduling failed"
|
|
4053
|
-
);
|
|
4054
4051
|
}
|
|
4055
4052
|
}
|
|
4056
4053
|
} catch (error) {
|
|
4057
4054
|
await status.stop();
|
|
4058
|
-
const onAuthPause = runArgs.onAuthPause;
|
|
4059
|
-
const onTimeoutPause = runArgs.onTimeoutPause;
|
|
4060
4055
|
if (finalReplyDelivered) {
|
|
4061
4056
|
postDeliveryCommitError = error;
|
|
4062
4057
|
try {
|
|
@@ -4070,21 +4065,6 @@ async function resumeSlackTurn(args) {
|
|
|
4070
4065
|
"Failed to terminalize resumed turn after post-delivery commit failure"
|
|
4071
4066
|
);
|
|
4072
4067
|
}
|
|
4073
|
-
} else if (isAuthResumeRetryableTurnError(error) && onAuthPause) {
|
|
4074
|
-
deferredPauseKind = "auth";
|
|
4075
|
-
deferredAuthInfo = {
|
|
4076
|
-
providerDisplayName: error.metadata.authProviderDisplayName,
|
|
4077
|
-
// The try body validates requester.userId; catch scope does not retain that narrowing.
|
|
4078
|
-
requesterId: runArgs.replyContext?.requester?.userId
|
|
4079
|
-
};
|
|
4080
|
-
deferredPauseHandler = async () => {
|
|
4081
|
-
await onAuthPause(error);
|
|
4082
|
-
};
|
|
4083
|
-
} else if (isRetryableTurnError(error, "agent_continue") && onTimeoutPause) {
|
|
4084
|
-
deferredPauseKind = "timeout";
|
|
4085
|
-
deferredPauseHandler = async () => {
|
|
4086
|
-
await onTimeoutPause(error);
|
|
4087
|
-
};
|
|
4088
4068
|
} else {
|
|
4089
4069
|
deferredFailureHandler = async () => {
|
|
4090
4070
|
await handleResumeFailure({
|
|
@@ -4157,7 +4137,7 @@ async function resumeAuthorizedRequest(args) {
|
|
|
4157
4137
|
replyContext: args.replyContext,
|
|
4158
4138
|
lockKey: args.lockKey,
|
|
4159
4139
|
initialText: args.connectedText,
|
|
4160
|
-
|
|
4140
|
+
agentRunner: args.agentRunner,
|
|
4161
4141
|
onSuccess: args.onSuccess,
|
|
4162
4142
|
onFailure: args.onFailure,
|
|
4163
4143
|
onAuthPause: args.onAuthPause,
|
|
@@ -4354,7 +4334,7 @@ async function persistFailedReplyState(channelId, threadTs, sessionId, expectedV
|
|
|
4354
4334
|
});
|
|
4355
4335
|
}
|
|
4356
4336
|
async function resumeAuthorizedMcpTurn(args) {
|
|
4357
|
-
const { authSession,
|
|
4337
|
+
const { authSession, agentRunner, provider } = args;
|
|
4358
4338
|
if (!authSession.channelId || !authSession.destination || !authSession.threadTs) {
|
|
4359
4339
|
return;
|
|
4360
4340
|
}
|
|
@@ -4397,7 +4377,7 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
4397
4377
|
messageTs: getTurnUserSlackMessageTs(userMessage2),
|
|
4398
4378
|
lockKey: threadId,
|
|
4399
4379
|
connectedText: "",
|
|
4400
|
-
|
|
4380
|
+
agentRunner,
|
|
4401
4381
|
beforeStart: async () => {
|
|
4402
4382
|
const lockedState = await getPersistedThreadState(threadId);
|
|
4403
4383
|
const lockedConversation = coerceThreadConversationState(lockedState);
|
|
@@ -4492,38 +4472,48 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
4492
4472
|
messageText: lockedUserMessage.text,
|
|
4493
4473
|
messageTs: lockedMessageTs,
|
|
4494
4474
|
replyContext: {
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
destination,
|
|
4500
|
-
source: lockedSessionRecord.source,
|
|
4501
|
-
correlation: {
|
|
4502
|
-
conversationId: authSession.conversationId,
|
|
4503
|
-
turnId: lockedSessionId,
|
|
4504
|
-
channelId: authSession.channelId,
|
|
4505
|
-
threadTs: authSession.threadTs,
|
|
4506
|
-
requesterId: requester.userId
|
|
4475
|
+
input: {
|
|
4476
|
+
conversationContext: lockedConversationContext,
|
|
4477
|
+
piMessages: lockedConversation.piMessages,
|
|
4478
|
+
...getTurnUserReplyAttachmentContext(lockedUserMessage)
|
|
4507
4479
|
},
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
recordPendingAuth: async (nextPendingAuth) => {
|
|
4517
|
-
await applyPendingAuthUpdate({
|
|
4518
|
-
conversation: lockedConversation,
|
|
4480
|
+
routing: {
|
|
4481
|
+
credentialContext: {
|
|
4482
|
+
actor: { type: "user", userId: requester.userId }
|
|
4483
|
+
},
|
|
4484
|
+
requester,
|
|
4485
|
+
destination,
|
|
4486
|
+
source: lockedSessionRecord.source,
|
|
4487
|
+
correlation: {
|
|
4519
4488
|
conversationId: authSession.conversationId,
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
}
|
|
4489
|
+
turnId: lockedSessionId,
|
|
4490
|
+
channelId: authSession.channelId,
|
|
4491
|
+
threadTs: authSession.threadTs,
|
|
4492
|
+
requesterId: requester.userId
|
|
4493
|
+
},
|
|
4494
|
+
toolChannelId: authSession.toolChannelId ?? lockedArtifacts.assistantContextChannelId ?? authSession.channelId
|
|
4495
|
+
},
|
|
4496
|
+
policy: {
|
|
4497
|
+
configuration: authSession.configuration,
|
|
4498
|
+
channelConfiguration: lockedChannelConfiguration
|
|
4499
|
+
},
|
|
4500
|
+
state: {
|
|
4501
|
+
artifactState: lockedArtifacts,
|
|
4502
|
+
pendingAuth: lockedPendingAuth,
|
|
4503
|
+
sandbox: getPersistedSandboxState(lockedState)
|
|
4525
4504
|
},
|
|
4526
|
-
|
|
4505
|
+
durability: {
|
|
4506
|
+
recordPendingAuth: async (nextPendingAuth) => {
|
|
4507
|
+
await applyPendingAuthUpdate({
|
|
4508
|
+
conversation: lockedConversation,
|
|
4509
|
+
conversationId: authSession.conversationId,
|
|
4510
|
+
nextPendingAuth
|
|
4511
|
+
});
|
|
4512
|
+
await persistThreadStateById(threadId, {
|
|
4513
|
+
conversation: lockedConversation
|
|
4514
|
+
});
|
|
4515
|
+
}
|
|
4516
|
+
}
|
|
4527
4517
|
},
|
|
4528
4518
|
onSuccess: async (reply) => {
|
|
4529
4519
|
await persistCompletedReplyState(
|
|
@@ -4559,7 +4549,7 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
4559
4549
|
);
|
|
4560
4550
|
}
|
|
4561
4551
|
},
|
|
4562
|
-
onAuthPause: async (
|
|
4552
|
+
onAuthPause: async () => {
|
|
4563
4553
|
await persistAuthPauseTurnState({
|
|
4564
4554
|
sessionId: lockedSessionId,
|
|
4565
4555
|
threadStateId: threadId
|
|
@@ -4567,35 +4557,23 @@ async function resumeAuthorizedMcpTurn(args) {
|
|
|
4567
4557
|
logWarn(
|
|
4568
4558
|
"mcp_oauth_callback_resume_reparked_for_auth",
|
|
4569
4559
|
{},
|
|
4570
|
-
{
|
|
4571
|
-
"app.credential.provider": provider,
|
|
4572
|
-
...isRetryableTurnError(error) ? { "app.ai.retryable_reason": error.reason } : {}
|
|
4573
|
-
},
|
|
4560
|
+
{ "app.credential.provider": provider },
|
|
4574
4561
|
"Resumed MCP turn requested another authorization flow"
|
|
4575
4562
|
);
|
|
4576
4563
|
},
|
|
4577
|
-
onTimeoutPause: async (
|
|
4578
|
-
if (!isRetryableTurnError(error, "agent_continue")) {
|
|
4579
|
-
throw error;
|
|
4580
|
-
}
|
|
4581
|
-
const version = error.metadata?.version;
|
|
4582
|
-
if (typeof version !== "number") {
|
|
4583
|
-
throw new Error(
|
|
4584
|
-
"MCP OAuth agent continuation did not include a session record version"
|
|
4585
|
-
);
|
|
4586
|
-
}
|
|
4564
|
+
onTimeoutPause: async ({ resumeVersion }) => {
|
|
4587
4565
|
await scheduleAgentContinue({
|
|
4588
4566
|
conversationId: authSession.conversationId,
|
|
4589
4567
|
destination,
|
|
4590
4568
|
sessionId: lockedSessionId,
|
|
4591
|
-
expectedVersion:
|
|
4569
|
+
expectedVersion: resumeVersion
|
|
4592
4570
|
});
|
|
4593
4571
|
}
|
|
4594
4572
|
};
|
|
4595
4573
|
}
|
|
4596
4574
|
});
|
|
4597
4575
|
}
|
|
4598
|
-
async function GET3(request, provider, waitUntil, options
|
|
4576
|
+
async function GET3(request, provider, waitUntil, options) {
|
|
4599
4577
|
const url = new URL(request.url);
|
|
4600
4578
|
const state = url.searchParams.get("state")?.trim();
|
|
4601
4579
|
const code = url.searchParams.get("code")?.trim();
|
|
@@ -4625,7 +4603,7 @@ async function GET3(request, provider, waitUntil, options = {}) {
|
|
|
4625
4603
|
waitUntil(
|
|
4626
4604
|
() => resumeAuthorizedMcpTurn({
|
|
4627
4605
|
authSession,
|
|
4628
|
-
|
|
4606
|
+
agentRunner: options.agentRunner,
|
|
4629
4607
|
provider
|
|
4630
4608
|
})
|
|
4631
4609
|
);
|
|
@@ -4927,7 +4905,7 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
|
4927
4905
|
messageTs: getTurnUserSlackMessageTs(userMessage2),
|
|
4928
4906
|
lockKey: stored.resumeConversationId,
|
|
4929
4907
|
initialText: "",
|
|
4930
|
-
|
|
4908
|
+
agentRunner: options.agentRunner,
|
|
4931
4909
|
beforeStart: async () => {
|
|
4932
4910
|
const lockedState = await getPersistedThreadState(
|
|
4933
4911
|
stored.resumeConversationId
|
|
@@ -5025,40 +5003,50 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
|
5025
5003
|
messageText: lockedPendingAuth ? lockedUserMessage.text : stored.pendingMessage ?? lockedUserMessage.text,
|
|
5026
5004
|
messageTs: lockedMessageTs,
|
|
5027
5005
|
replyContext: {
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
}
|
|
5006
|
+
input: {
|
|
5007
|
+
conversationContext: lockedConversationContext,
|
|
5008
|
+
piMessages: lockedConversation.piMessages,
|
|
5009
|
+
...getTurnUserReplyAttachmentContext(lockedUserMessage)
|
|
5033
5010
|
},
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
artifactState: lockedArtifacts,
|
|
5046
|
-
pendingAuth: lockedPendingAuth,
|
|
5047
|
-
conversationContext: lockedConversationContext,
|
|
5048
|
-
channelConfiguration: lockedChannelConfiguration,
|
|
5049
|
-
piMessages: lockedConversation.piMessages,
|
|
5050
|
-
sandbox: getPersistedSandboxState(lockedState),
|
|
5051
|
-
recordPendingAuth: async (nextPendingAuth) => {
|
|
5052
|
-
await applyPendingAuthUpdate({
|
|
5053
|
-
conversation: lockedConversation,
|
|
5011
|
+
routing: {
|
|
5012
|
+
credentialContext: {
|
|
5013
|
+
actor: {
|
|
5014
|
+
type: "user",
|
|
5015
|
+
userId: requester.userId
|
|
5016
|
+
}
|
|
5017
|
+
},
|
|
5018
|
+
requester,
|
|
5019
|
+
destination,
|
|
5020
|
+
source: lockedSessionRecord.source,
|
|
5021
|
+
correlation: {
|
|
5054
5022
|
conversationId: stored.resumeConversationId,
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
}
|
|
5023
|
+
turnId: lockedSessionId,
|
|
5024
|
+
channelId: stored.channelId,
|
|
5025
|
+
threadTs: stored.threadTs,
|
|
5026
|
+
requesterId: requester.userId
|
|
5027
|
+
},
|
|
5028
|
+
toolChannelId: lockedArtifacts.assistantContextChannelId ?? stored.channelId
|
|
5060
5029
|
},
|
|
5061
|
-
|
|
5030
|
+
policy: {
|
|
5031
|
+
channelConfiguration: lockedChannelConfiguration
|
|
5032
|
+
},
|
|
5033
|
+
state: {
|
|
5034
|
+
artifactState: lockedArtifacts,
|
|
5035
|
+
pendingAuth: lockedPendingAuth,
|
|
5036
|
+
sandbox: getPersistedSandboxState(lockedState)
|
|
5037
|
+
},
|
|
5038
|
+
durability: {
|
|
5039
|
+
recordPendingAuth: async (nextPendingAuth) => {
|
|
5040
|
+
await applyPendingAuthUpdate({
|
|
5041
|
+
conversation: lockedConversation,
|
|
5042
|
+
conversationId: stored.resumeConversationId,
|
|
5043
|
+
nextPendingAuth
|
|
5044
|
+
});
|
|
5045
|
+
await persistThreadStateById(stored.resumeConversationId, {
|
|
5046
|
+
conversation: lockedConversation
|
|
5047
|
+
});
|
|
5048
|
+
}
|
|
5049
|
+
}
|
|
5062
5050
|
},
|
|
5063
5051
|
onSuccess: async (reply) => {
|
|
5064
5052
|
logInfo(
|
|
@@ -5098,21 +5086,12 @@ async function resumeOAuthSessionRecordTurn(stored, options) {
|
|
|
5098
5086
|
threadStateId: stored.resumeConversationId
|
|
5099
5087
|
});
|
|
5100
5088
|
},
|
|
5101
|
-
onTimeoutPause: async (
|
|
5102
|
-
if (!isRetryableTurnError(error, "agent_continue")) {
|
|
5103
|
-
throw error;
|
|
5104
|
-
}
|
|
5105
|
-
const version = error.metadata?.version;
|
|
5106
|
-
if (typeof version !== "number") {
|
|
5107
|
-
throw new Error(
|
|
5108
|
-
"OAuth agent continuation did not include a session record version"
|
|
5109
|
-
);
|
|
5110
|
-
}
|
|
5089
|
+
onTimeoutPause: async ({ resumeVersion }) => {
|
|
5111
5090
|
await scheduleAgentContinue({
|
|
5112
5091
|
conversationId: stored.resumeConversationId,
|
|
5113
5092
|
destination,
|
|
5114
5093
|
sessionId: lockedSessionId,
|
|
5115
|
-
expectedVersion:
|
|
5094
|
+
expectedVersion: resumeVersion
|
|
5116
5095
|
});
|
|
5117
5096
|
}
|
|
5118
5097
|
};
|
|
@@ -5148,23 +5127,29 @@ async function resumePendingOAuthMessage(stored, options) {
|
|
|
5148
5127
|
threadTs: stored.threadTs,
|
|
5149
5128
|
messageTs,
|
|
5150
5129
|
connectedText: "",
|
|
5151
|
-
|
|
5130
|
+
agentRunner: options.agentRunner,
|
|
5152
5131
|
replyContext: {
|
|
5153
|
-
|
|
5154
|
-
|
|
5132
|
+
input: {
|
|
5133
|
+
conversationContext,
|
|
5134
|
+
piMessages: conversation.piMessages
|
|
5155
5135
|
},
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5136
|
+
routing: {
|
|
5137
|
+
credentialContext: {
|
|
5138
|
+
actor: { type: "user", userId: stored.userId }
|
|
5139
|
+
},
|
|
5140
|
+
requester,
|
|
5141
|
+
destination: stored.destination,
|
|
5142
|
+
source,
|
|
5143
|
+
correlation: {
|
|
5144
|
+
conversationId: threadId,
|
|
5145
|
+
channelId: stored.channelId,
|
|
5146
|
+
threadTs: stored.threadTs,
|
|
5147
|
+
requesterId: stored.userId
|
|
5148
|
+
}
|
|
5164
5149
|
},
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5150
|
+
policy: {
|
|
5151
|
+
configuration: stored.configuration
|
|
5152
|
+
}
|
|
5168
5153
|
},
|
|
5169
5154
|
onSuccess: async (reply) => {
|
|
5170
5155
|
logInfo(
|
|
@@ -5180,7 +5165,7 @@ async function resumePendingOAuthMessage(stored, options) {
|
|
|
5180
5165
|
}
|
|
5181
5166
|
});
|
|
5182
5167
|
}
|
|
5183
|
-
async function GET4(request, provider, waitUntil, options
|
|
5168
|
+
async function GET4(request, provider, waitUntil, options) {
|
|
5184
5169
|
const providerConfig = pluginCatalogRuntime.getOAuthConfig(provider);
|
|
5185
5170
|
if (!providerConfig) {
|
|
5186
5171
|
return htmlErrorResponse(
|
|
@@ -7532,7 +7517,7 @@ function getQueuedMessages(context, options) {
|
|
|
7532
7517
|
stripLeadingSlackMentionToken: options.explicitMention || Boolean(message.isMention)
|
|
7533
7518
|
});
|
|
7534
7519
|
return {
|
|
7535
|
-
explicitMention:
|
|
7520
|
+
explicitMention: Boolean(message.isMention),
|
|
7536
7521
|
message,
|
|
7537
7522
|
rawText: appendSlackLegacyAttachmentText(message.text, message.raw),
|
|
7538
7523
|
userText: appendSlackLegacyAttachmentText(stripped, message.raw)
|
|
@@ -7908,16 +7893,6 @@ function createSlackTurnRuntime(deps) {
|
|
|
7908
7893
|
channelId: deps.getChannelId(thread, message),
|
|
7909
7894
|
runId: deps.getRunId(thread, message)
|
|
7910
7895
|
});
|
|
7911
|
-
if (isRetryableTurnError(error, "mcp_auth_resume") || isRetryableTurnError(error, "plugin_auth_resume")) {
|
|
7912
|
-
deps.logException(
|
|
7913
|
-
error,
|
|
7914
|
-
"mention_handler_auth_pause",
|
|
7915
|
-
errorContext,
|
|
7916
|
-
{ "app.ai.retryable_reason": error.reason },
|
|
7917
|
-
"onNewMention parked turn for auth resume"
|
|
7918
|
-
);
|
|
7919
|
-
return;
|
|
7920
|
-
}
|
|
7921
7896
|
if (error instanceof AuthorizationFlowDisabledError) {
|
|
7922
7897
|
return;
|
|
7923
7898
|
}
|
|
@@ -8178,16 +8153,6 @@ function createSlackTurnRuntime(deps) {
|
|
|
8178
8153
|
channelId: deps.getChannelId(thread, message),
|
|
8179
8154
|
runId: deps.getRunId(thread, message)
|
|
8180
8155
|
});
|
|
8181
|
-
if (isRetryableTurnError(error, "mcp_auth_resume") || isRetryableTurnError(error, "plugin_auth_resume")) {
|
|
8182
|
-
deps.logException(
|
|
8183
|
-
error,
|
|
8184
|
-
"subscribed_message_handler_auth_pause",
|
|
8185
|
-
errorContext,
|
|
8186
|
-
{ "app.ai.retryable_reason": error.reason },
|
|
8187
|
-
"onSubscribedMessage parked turn for auth resume"
|
|
8188
|
-
);
|
|
8189
|
-
return;
|
|
8190
|
-
}
|
|
8191
8156
|
if (error instanceof AuthorizationFlowDisabledError) {
|
|
8192
8157
|
return;
|
|
8193
8158
|
}
|
|
@@ -8601,7 +8566,7 @@ function createSubscribedReplyPolicy(deps) {
|
|
|
8601
8566
|
};
|
|
8602
8567
|
}
|
|
8603
8568
|
|
|
8604
|
-
// src/chat/
|
|
8569
|
+
// src/chat/slack/vision-context.ts
|
|
8605
8570
|
var MAX_USER_ATTACHMENTS = 3;
|
|
8606
8571
|
var MAX_USER_ATTACHMENT_BYTES = 5 * 1024 * 1024;
|
|
8607
8572
|
var MAX_MESSAGE_IMAGE_ATTACHMENTS = 3;
|
|
@@ -8907,6 +8872,14 @@ async function hydrateConversationVisionContextWithDeps(conversation, context, d
|
|
|
8907
8872
|
if (!context.channelId || !context.threadTs) {
|
|
8908
8873
|
return;
|
|
8909
8874
|
}
|
|
8875
|
+
const channelId = parseSlackChannelId(context.channelId);
|
|
8876
|
+
if (!channelId) {
|
|
8877
|
+
return;
|
|
8878
|
+
}
|
|
8879
|
+
const threadTs = parseSlackMessageTs(context.threadTs);
|
|
8880
|
+
if (!threadTs) {
|
|
8881
|
+
return;
|
|
8882
|
+
}
|
|
8910
8883
|
const messagesByTs = /* @__PURE__ */ new Map();
|
|
8911
8884
|
for (const message of conversation.messages) {
|
|
8912
8885
|
if (!isHumanConversationMessage(message)) continue;
|
|
@@ -8921,8 +8894,8 @@ async function hydrateConversationVisionContextWithDeps(conversation, context, d
|
|
|
8921
8894
|
let replies;
|
|
8922
8895
|
try {
|
|
8923
8896
|
replies = await deps.listThreadReplies({
|
|
8924
|
-
channelId
|
|
8925
|
-
threadTs
|
|
8897
|
+
channelId,
|
|
8898
|
+
threadTs,
|
|
8926
8899
|
limit: 1e3,
|
|
8927
8900
|
maxPages: 10,
|
|
8928
8901
|
targetMessageTs: [...messagesByTs.keys()]
|
|
@@ -9120,15 +9093,6 @@ function createVisionContextService(deps) {
|
|
|
9120
9093
|
}
|
|
9121
9094
|
|
|
9122
9095
|
// src/chat/app/services.ts
|
|
9123
|
-
function withSandboxTracePropagation(generateReply, tracePropagation) {
|
|
9124
|
-
return async (messageText2, context) => await generateReply(messageText2, {
|
|
9125
|
-
...context,
|
|
9126
|
-
sandbox: {
|
|
9127
|
-
...context?.sandbox,
|
|
9128
|
-
tracePropagation: context?.sandbox?.tracePropagation ?? tracePropagation
|
|
9129
|
-
}
|
|
9130
|
-
});
|
|
9131
|
-
}
|
|
9132
9096
|
function createJuniorRuntimeServices(overrides = {}) {
|
|
9133
9097
|
const conversationMemory = createConversationMemoryService({
|
|
9134
9098
|
completeText: overrides.conversationMemory?.completeText ?? completeText
|
|
@@ -9147,10 +9111,9 @@ function createJuniorRuntimeServices(overrides = {}) {
|
|
|
9147
9111
|
contextCompactor,
|
|
9148
9112
|
replyExecutor: {
|
|
9149
9113
|
contextCompactor: overrides.replyExecutor?.contextCompactor ?? contextCompactor,
|
|
9150
|
-
|
|
9151
|
-
|
|
9152
|
-
|
|
9153
|
-
),
|
|
9114
|
+
agentRunner: overrides.replyExecutor?.agentRunner ?? createAgentRunner(executeAgentRun, {
|
|
9115
|
+
tracePropagation: overrides.sandbox?.tracePropagation
|
|
9116
|
+
}),
|
|
9154
9117
|
getAwaitingAgentContinueRequest: overrides.replyExecutor?.getAwaitingAgentContinueRequest ?? getAwaitingAgentContinueRequest,
|
|
9155
9118
|
lookupSlackUser: overrides.replyExecutor?.lookupSlackUser ?? lookupSlackUser,
|
|
9156
9119
|
scheduleAgentContinue: overrides.replyExecutor?.scheduleAgentContinue ?? scheduleAgentContinue,
|
|
@@ -9317,6 +9280,56 @@ function parkedInputKey(message) {
|
|
|
9317
9280
|
const text = first && typeof first === "object" && "text" in first ? String(first.text ?? "") : "";
|
|
9318
9281
|
return `${message.timestamp}:${text}`;
|
|
9319
9282
|
}
|
|
9283
|
+
function renderRecentThreadMessages(conversationContext, messages) {
|
|
9284
|
+
const passiveMessages = messages.filter((queued) => {
|
|
9285
|
+
if (queued.explicitMention) {
|
|
9286
|
+
return false;
|
|
9287
|
+
}
|
|
9288
|
+
const slackTs = queuedInstructionActor(queued)?.slackTs;
|
|
9289
|
+
return !slackTs || !conversationContext?.includes(`slack_ts="${slackTs}"`);
|
|
9290
|
+
});
|
|
9291
|
+
if (passiveMessages.length === 0) {
|
|
9292
|
+
return void 0;
|
|
9293
|
+
}
|
|
9294
|
+
const lines = ["<recent-thread-messages>"];
|
|
9295
|
+
for (const queued of passiveMessages) {
|
|
9296
|
+
const actor = queuedInstructionActor(queued);
|
|
9297
|
+
const attrs = [
|
|
9298
|
+
actor?.authorId ? `author_id="${escapeXml(actor.authorId)}"` : void 0,
|
|
9299
|
+
actor?.authorName ? `author_name="${escapeXml(actor.authorName)}"` : void 0,
|
|
9300
|
+
actor?.slackTs ? `slack_ts="${escapeXml(actor.slackTs)}"` : void 0
|
|
9301
|
+
].filter((attr) => Boolean(attr)).join(" ");
|
|
9302
|
+
lines.push(
|
|
9303
|
+
attrs ? ` <message ${attrs}>` : " <message>",
|
|
9304
|
+
escapeXml(queued.userText),
|
|
9305
|
+
" </message>"
|
|
9306
|
+
);
|
|
9307
|
+
}
|
|
9308
|
+
lines.push("</recent-thread-messages>");
|
|
9309
|
+
return lines.join("\n");
|
|
9310
|
+
}
|
|
9311
|
+
function appendRecentThreadMessagesToContext(conversationContext, messages, options) {
|
|
9312
|
+
const recentThreadMessages = renderRecentThreadMessages(
|
|
9313
|
+
conversationContext,
|
|
9314
|
+
messages
|
|
9315
|
+
);
|
|
9316
|
+
const contextParts = [
|
|
9317
|
+
options?.includeConversationContext === false ? void 0 : conversationContext?.trim(),
|
|
9318
|
+
recentThreadMessages
|
|
9319
|
+
].filter((part) => Boolean(part));
|
|
9320
|
+
return contextParts.length > 0 ? contextParts.join("\n\n") : void 0;
|
|
9321
|
+
}
|
|
9322
|
+
function queuedInstructionActor(queued) {
|
|
9323
|
+
const actor = getMessageActorIdentity(queued.message);
|
|
9324
|
+
const authorId = actor?.userId ?? parseActorUserId(queued.message.author.userId);
|
|
9325
|
+
const authorName = actor?.fullName ?? actor?.userName;
|
|
9326
|
+
const slackTs = getSlackMessageTs(queued.message);
|
|
9327
|
+
return {
|
|
9328
|
+
...authorId ? { authorId } : {},
|
|
9329
|
+
...authorName ? { authorName } : {},
|
|
9330
|
+
...slackTs ? { slackTs } : {}
|
|
9331
|
+
};
|
|
9332
|
+
}
|
|
9320
9333
|
function isResourceEventMessage(message) {
|
|
9321
9334
|
const raw = message.raw && typeof message.raw === "object" ? message.raw : void 0;
|
|
9322
9335
|
return raw?.event_type === "resource_event";
|
|
@@ -9440,10 +9453,6 @@ function createReplyToThread(deps) {
|
|
|
9440
9453
|
message.raw
|
|
9441
9454
|
)
|
|
9442
9455
|
};
|
|
9443
|
-
const effectiveUserText = combineTurnText(
|
|
9444
|
-
options.queuedMessages ?? [],
|
|
9445
|
-
currentText
|
|
9446
|
-
).userText;
|
|
9447
9456
|
await Promise.all(
|
|
9448
9457
|
(options.queuedMessages ?? []).filter((queued) => !isResourceEventMessage(queued.message)).map(
|
|
9449
9458
|
(queued) => ensureSlackMessageActorIdentity(
|
|
@@ -9453,6 +9462,7 @@ function createReplyToThread(deps) {
|
|
|
9453
9462
|
)
|
|
9454
9463
|
)
|
|
9455
9464
|
);
|
|
9465
|
+
const effectiveUserText = currentText.userText;
|
|
9456
9466
|
const credentialContext = resourceEventCredentialContext(message) ?? {
|
|
9457
9467
|
actor: { type: "user", userId: message.author.userId }
|
|
9458
9468
|
};
|
|
@@ -9544,6 +9554,7 @@ function createReplyToThread(deps) {
|
|
|
9544
9554
|
queuedMessages.map(async (queued) => {
|
|
9545
9555
|
const attachments = queued.message.attachments;
|
|
9546
9556
|
return {
|
|
9557
|
+
actor: queuedInstructionActor(queued),
|
|
9547
9558
|
text: queued.userText,
|
|
9548
9559
|
timestampMs: queued.message.metadata.dateSent.getTime(),
|
|
9549
9560
|
omittedImageAttachmentCount: !isVisionEnabled() && hasPotentialImageAttachment(attachments) ? countPotentialImageAttachments(attachments) : 0,
|
|
@@ -9864,7 +9875,8 @@ function createReplyToThread(deps) {
|
|
|
9864
9875
|
let finalReplyDelivered = false;
|
|
9865
9876
|
let latestArtifacts = preparedState.artifacts;
|
|
9866
9877
|
let assistantTitleArtifacts = {};
|
|
9867
|
-
|
|
9878
|
+
let agentContinueScheduleError;
|
|
9879
|
+
const hasVisibleSlackDelivery = (post) => post.text.trim().length > 0;
|
|
9868
9880
|
try {
|
|
9869
9881
|
const loadedPiMessages = await loadPiMessagesForTurn({
|
|
9870
9882
|
conversationId,
|
|
@@ -9893,6 +9905,18 @@ function createReplyToThread(deps) {
|
|
|
9893
9905
|
});
|
|
9894
9906
|
}
|
|
9895
9907
|
}
|
|
9908
|
+
const hasDurablePromptHistory = Boolean(piMessages?.length);
|
|
9909
|
+
const queuedInstructionPiMessages = (await resolveSteeringMessages(
|
|
9910
|
+
(options.queuedMessages ?? []).filter(
|
|
9911
|
+
(queued) => queued.explicitMention
|
|
9912
|
+
)
|
|
9913
|
+
)).map(buildSteeringPiMessage);
|
|
9914
|
+
if (queuedInstructionPiMessages.length > 0) {
|
|
9915
|
+
piMessages = [
|
|
9916
|
+
...piMessages ?? [],
|
|
9917
|
+
...queuedInstructionPiMessages
|
|
9918
|
+
];
|
|
9919
|
+
}
|
|
9896
9920
|
status.start();
|
|
9897
9921
|
const assistantTitleTask = maybeUpdateAssistantTitle({
|
|
9898
9922
|
assistantThreadContext,
|
|
@@ -9956,6 +9980,12 @@ function createReplyToThread(deps) {
|
|
|
9956
9980
|
);
|
|
9957
9981
|
});
|
|
9958
9982
|
const toolChannelId = preparedState.artifacts.assistantContextChannelId ?? channelId;
|
|
9983
|
+
const activeInstructionAuthorId = requester?.userId ?? parseActorUserId(message.author.userId);
|
|
9984
|
+
const activeInstructionAuthorName = requester?.fullName ?? requester?.userName;
|
|
9985
|
+
const promptConversationContext = appendRecentThreadMessagesToContext(
|
|
9986
|
+
preparedState.conversationContext,
|
|
9987
|
+
options.queuedMessages ?? []
|
|
9988
|
+
);
|
|
9959
9989
|
const drainSteeringMessages = options.drainSteeringMessages ? async (accept) => {
|
|
9960
9990
|
let acceptedMessages;
|
|
9961
9991
|
const drained = await options.drainSteeringMessages(
|
|
@@ -9967,26 +9997,28 @@ function createReplyToThread(deps) {
|
|
|
9967
9997
|
);
|
|
9968
9998
|
return acceptedMessages ?? await resolveSteeringMessages(drained);
|
|
9969
9999
|
} : void 0;
|
|
9970
|
-
|
|
9971
|
-
|
|
9972
|
-
|
|
9973
|
-
|
|
9974
|
-
|
|
9975
|
-
|
|
9976
|
-
|
|
10000
|
+
const outcome = await deps.services.agentRunner.run({
|
|
10001
|
+
input: {
|
|
10002
|
+
actor: {
|
|
10003
|
+
...activeInstructionAuthorId ? { authorId: activeInstructionAuthorId } : {},
|
|
10004
|
+
...activeInstructionAuthorName ? { authorName: activeInstructionAuthorName } : {},
|
|
10005
|
+
...slackMessageTs ? { slackTs: slackMessageTs } : {}
|
|
10006
|
+
},
|
|
10007
|
+
includeConversationContextWithPiMessages: hasDurablePromptHistory,
|
|
10008
|
+
messageText: effectiveUserText,
|
|
10009
|
+
conversationContext: promptConversationContext,
|
|
9977
10010
|
piMessages,
|
|
9978
|
-
pendingAuth: preparedState.conversation.processing.pendingAuth,
|
|
9979
|
-
configuration: preparedState.configuration,
|
|
9980
|
-
channelConfiguration: preparedState.channelConfiguration,
|
|
9981
10011
|
inboundAttachmentCount: turnAttachments.length,
|
|
9982
10012
|
omittedImageAttachmentCount,
|
|
9983
|
-
userAttachments
|
|
10013
|
+
userAttachments
|
|
10014
|
+
},
|
|
10015
|
+
routing: {
|
|
10016
|
+
credentialContext,
|
|
10017
|
+
requester,
|
|
9984
10018
|
slackConversation,
|
|
9985
10019
|
source,
|
|
9986
10020
|
destination,
|
|
9987
10021
|
surface: "slack",
|
|
9988
|
-
authorizationFlowMode: message.author.isBot === true ? "disabled" : void 0,
|
|
9989
|
-
turnDeadlineAtMs: getTurnRequestDeadline()?.deadlineAtMs,
|
|
9990
10022
|
correlation: {
|
|
9991
10023
|
conversationId,
|
|
9992
10024
|
threadId,
|
|
@@ -9999,11 +10031,30 @@ function createReplyToThread(deps) {
|
|
|
9999
10031
|
channelName,
|
|
10000
10032
|
requesterId: slackRequesterId
|
|
10001
10033
|
},
|
|
10002
|
-
toolChannelId
|
|
10034
|
+
toolChannelId
|
|
10035
|
+
},
|
|
10036
|
+
policy: {
|
|
10037
|
+
configuration: preparedState.configuration,
|
|
10038
|
+
channelConfiguration: preparedState.channelConfiguration,
|
|
10039
|
+
authorizationFlowMode: message.author.isBot === true ? "disabled" : void 0,
|
|
10040
|
+
turnDeadlineAtMs: getTurnRequestDeadline()?.deadlineAtMs
|
|
10041
|
+
},
|
|
10042
|
+
state: {
|
|
10043
|
+
artifactState: preparedState.artifacts,
|
|
10044
|
+
pendingAuth: preparedState.conversation.processing.pendingAuth,
|
|
10003
10045
|
sandbox: {
|
|
10004
10046
|
sandboxId: preparedState.sandboxId,
|
|
10005
10047
|
sandboxDependencyProfileHash: preparedState.sandboxDependencyProfileHash
|
|
10006
|
-
}
|
|
10048
|
+
}
|
|
10049
|
+
},
|
|
10050
|
+
observers: {
|
|
10051
|
+
onStatus: (nextStatus) => status.update(nextStatus),
|
|
10052
|
+
onToolInvocation: options.onToolInvocation
|
|
10053
|
+
},
|
|
10054
|
+
durability: {
|
|
10055
|
+
onInputCommitted: options.ack,
|
|
10056
|
+
drainSteeringMessages,
|
|
10057
|
+
shouldYield: options.shouldYield,
|
|
10007
10058
|
onSandboxAcquired: async (sandbox) => {
|
|
10008
10059
|
await persistThreadState(thread, {
|
|
10009
10060
|
sandboxId: sandbox.sandboxId,
|
|
@@ -10028,14 +10079,98 @@ function createReplyToThread(deps) {
|
|
|
10028
10079
|
await persistThreadState(thread, {
|
|
10029
10080
|
conversation: preparedState.conversation
|
|
10030
10081
|
});
|
|
10031
|
-
}
|
|
10032
|
-
onStatus: (nextStatus) => status.update(nextStatus),
|
|
10033
|
-
onToolInvocation: options.onToolInvocation,
|
|
10034
|
-
onInputCommitted: options.ack,
|
|
10035
|
-
drainSteeringMessages,
|
|
10036
|
-
shouldYield: options.shouldYield
|
|
10082
|
+
}
|
|
10037
10083
|
}
|
|
10038
|
-
);
|
|
10084
|
+
});
|
|
10085
|
+
if (outcome.status === "awaiting_auth") {
|
|
10086
|
+
if (!requester) {
|
|
10087
|
+
const text = `I could not act on this subscribed event because ${outcome.providerDisplayName} needs user authorization. Ask me in this thread to connect ${outcome.providerDisplayName} before retrying.`;
|
|
10088
|
+
await postThreadReply(
|
|
10089
|
+
buildSlackOutputMessage(text),
|
|
10090
|
+
"thread_reply"
|
|
10091
|
+
);
|
|
10092
|
+
markConversationMessage(
|
|
10093
|
+
preparedState.conversation,
|
|
10094
|
+
preparedState.userMessageId,
|
|
10095
|
+
{
|
|
10096
|
+
replied: true,
|
|
10097
|
+
skippedReason: void 0
|
|
10098
|
+
}
|
|
10099
|
+
);
|
|
10100
|
+
upsertConversationMessage(preparedState.conversation, {
|
|
10101
|
+
id: generateConversationId("assistant"),
|
|
10102
|
+
role: "assistant",
|
|
10103
|
+
text: normalizeConversationText(text),
|
|
10104
|
+
createdAtMs: Date.now(),
|
|
10105
|
+
author: {
|
|
10106
|
+
userName: botConfig.userName,
|
|
10107
|
+
isBot: true
|
|
10108
|
+
},
|
|
10109
|
+
meta: {
|
|
10110
|
+
replied: true
|
|
10111
|
+
}
|
|
10112
|
+
});
|
|
10113
|
+
markTurnClosed({
|
|
10114
|
+
conversation: preparedState.conversation,
|
|
10115
|
+
nowMs: Date.now(),
|
|
10116
|
+
sessionId: turnId,
|
|
10117
|
+
updateConversationStats
|
|
10118
|
+
});
|
|
10119
|
+
await persistThreadState(thread, {
|
|
10120
|
+
conversation: preparedState.conversation
|
|
10121
|
+
});
|
|
10122
|
+
persistedAtLeastOnce = true;
|
|
10123
|
+
shouldPersistFailureState = false;
|
|
10124
|
+
return;
|
|
10125
|
+
}
|
|
10126
|
+
await postAuthPauseNotice(outcome.providerDisplayName);
|
|
10127
|
+
completeAuthPauseTurn({
|
|
10128
|
+
conversation: preparedState.conversation,
|
|
10129
|
+
sessionId: turnId
|
|
10130
|
+
});
|
|
10131
|
+
await persistThreadState(thread, {
|
|
10132
|
+
conversation: preparedState.conversation
|
|
10133
|
+
});
|
|
10134
|
+
persistedAtLeastOnce = true;
|
|
10135
|
+
shouldPersistFailureState = false;
|
|
10136
|
+
return;
|
|
10137
|
+
}
|
|
10138
|
+
if (outcome.status === "suspended") {
|
|
10139
|
+
if (options.shouldYield?.()) {
|
|
10140
|
+
shouldPersistFailureState = false;
|
|
10141
|
+
throw new CooperativeTurnYieldError();
|
|
10142
|
+
}
|
|
10143
|
+
if (!destination || !conversationId) {
|
|
10144
|
+
throw new Error(
|
|
10145
|
+
"Agent continuation requires a destination and conversation id"
|
|
10146
|
+
);
|
|
10147
|
+
}
|
|
10148
|
+
try {
|
|
10149
|
+
await deps.services.scheduleAgentContinue({
|
|
10150
|
+
conversationId,
|
|
10151
|
+
destination,
|
|
10152
|
+
sessionId: turnId,
|
|
10153
|
+
expectedVersion: outcome.resumeVersion
|
|
10154
|
+
});
|
|
10155
|
+
shouldPersistFailureState = false;
|
|
10156
|
+
} catch (scheduleError) {
|
|
10157
|
+
logException(
|
|
10158
|
+
scheduleError,
|
|
10159
|
+
"agent_continue_schedule_failed",
|
|
10160
|
+
turnTraceContext,
|
|
10161
|
+
{
|
|
10162
|
+
...messageTs ? { "messaging.message.id": messageTs } : {},
|
|
10163
|
+
"app.ai.resume_session_version": outcome.resumeVersion
|
|
10164
|
+
},
|
|
10165
|
+
"Failed to schedule agent continuation"
|
|
10166
|
+
);
|
|
10167
|
+
shouldPersistFailureState = true;
|
|
10168
|
+
agentContinueScheduleError = scheduleError;
|
|
10169
|
+
throw scheduleError;
|
|
10170
|
+
}
|
|
10171
|
+
return;
|
|
10172
|
+
}
|
|
10173
|
+
let reply = outcome.result;
|
|
10039
10174
|
const diagnosticsContext = {
|
|
10040
10175
|
slackThreadId: threadId,
|
|
10041
10176
|
slackUserId: message.author.userId,
|
|
@@ -10081,7 +10216,6 @@ function createReplyToThread(deps) {
|
|
|
10081
10216
|
channelId: slackChannelId,
|
|
10082
10217
|
threadTs: slackThreadTs,
|
|
10083
10218
|
posts: plannedPosts,
|
|
10084
|
-
fileUploadFailureMode: "strict",
|
|
10085
10219
|
footer: replyFooter,
|
|
10086
10220
|
onPostError: ({ error, messageTs: messageTs2, stage }) => {
|
|
10087
10221
|
logException(
|
|
@@ -10103,7 +10237,7 @@ function createReplyToThread(deps) {
|
|
|
10103
10237
|
continue;
|
|
10104
10238
|
}
|
|
10105
10239
|
await postThreadReply(
|
|
10106
|
-
buildSlackOutputMessage(post.text
|
|
10240
|
+
buildSlackOutputMessage(post.text),
|
|
10107
10241
|
post.stage
|
|
10108
10242
|
);
|
|
10109
10243
|
}
|
|
@@ -10229,99 +10363,13 @@ function createReplyToThread(deps) {
|
|
|
10229
10363
|
);
|
|
10230
10364
|
return;
|
|
10231
10365
|
}
|
|
10232
|
-
if (
|
|
10366
|
+
if (error instanceof CooperativeTurnYieldError) {
|
|
10233
10367
|
shouldPersistFailureState = false;
|
|
10234
10368
|
throw error;
|
|
10235
10369
|
}
|
|
10236
|
-
if (
|
|
10237
|
-
|
|
10238
|
-
|
|
10239
|
-
await postThreadReply(
|
|
10240
|
-
buildSlackOutputMessage(text),
|
|
10241
|
-
"thread_reply"
|
|
10242
|
-
);
|
|
10243
|
-
markConversationMessage(
|
|
10244
|
-
preparedState.conversation,
|
|
10245
|
-
preparedState.userMessageId,
|
|
10246
|
-
{
|
|
10247
|
-
replied: true,
|
|
10248
|
-
skippedReason: void 0
|
|
10249
|
-
}
|
|
10250
|
-
);
|
|
10251
|
-
upsertConversationMessage(preparedState.conversation, {
|
|
10252
|
-
id: generateConversationId("assistant"),
|
|
10253
|
-
role: "assistant",
|
|
10254
|
-
text: normalizeConversationText(text),
|
|
10255
|
-
createdAtMs: Date.now(),
|
|
10256
|
-
author: {
|
|
10257
|
-
userName: botConfig.userName,
|
|
10258
|
-
isBot: true
|
|
10259
|
-
},
|
|
10260
|
-
meta: {
|
|
10261
|
-
replied: true
|
|
10262
|
-
}
|
|
10263
|
-
});
|
|
10264
|
-
markTurnClosed({
|
|
10265
|
-
conversation: preparedState.conversation,
|
|
10266
|
-
nowMs: Date.now(),
|
|
10267
|
-
sessionId: turnId,
|
|
10268
|
-
updateConversationStats
|
|
10269
|
-
});
|
|
10270
|
-
await persistThreadState(thread, {
|
|
10271
|
-
conversation: preparedState.conversation
|
|
10272
|
-
});
|
|
10273
|
-
persistedAtLeastOnce = true;
|
|
10274
|
-
shouldPersistFailureState = false;
|
|
10275
|
-
return;
|
|
10276
|
-
}
|
|
10277
|
-
await postAuthPauseNotice(error.metadata.authProviderDisplayName);
|
|
10278
|
-
completeAuthPauseTurn({
|
|
10279
|
-
conversation: preparedState.conversation,
|
|
10280
|
-
sessionId: error.metadata?.sessionId ?? turnId
|
|
10281
|
-
});
|
|
10282
|
-
await persistThreadState(thread, {
|
|
10283
|
-
conversation: preparedState.conversation
|
|
10284
|
-
});
|
|
10285
|
-
persistedAtLeastOnce = true;
|
|
10286
|
-
shouldPersistFailureState = false;
|
|
10287
|
-
return;
|
|
10288
|
-
}
|
|
10289
|
-
if (isRetryableTurnError(error, "agent_continue")) {
|
|
10290
|
-
const conversationIdForResume = error.metadata?.conversationId;
|
|
10291
|
-
const sessionIdForResume = error.metadata?.sessionId;
|
|
10292
|
-
const version = error.metadata?.version;
|
|
10293
|
-
if (conversationIdForResume && sessionIdForResume && typeof version === "number" && destination) {
|
|
10294
|
-
try {
|
|
10295
|
-
await deps.services.scheduleAgentContinue({
|
|
10296
|
-
conversationId: conversationIdForResume,
|
|
10297
|
-
destination,
|
|
10298
|
-
sessionId: sessionIdForResume,
|
|
10299
|
-
expectedVersion: version
|
|
10300
|
-
});
|
|
10301
|
-
shouldPersistFailureState = false;
|
|
10302
|
-
} catch (scheduleError) {
|
|
10303
|
-
logException(
|
|
10304
|
-
scheduleError,
|
|
10305
|
-
"agent_continue_schedule_failed",
|
|
10306
|
-
turnTraceContext,
|
|
10307
|
-
{
|
|
10308
|
-
...messageTs ? { "messaging.message.id": messageTs } : {},
|
|
10309
|
-
"app.ai.resume_session_version": version
|
|
10310
|
-
},
|
|
10311
|
-
"Failed to schedule agent continuation"
|
|
10312
|
-
);
|
|
10313
|
-
shouldPersistFailureState = true;
|
|
10314
|
-
throw scheduleError;
|
|
10315
|
-
}
|
|
10316
|
-
return;
|
|
10317
|
-
} else {
|
|
10318
|
-
logWarn(
|
|
10319
|
-
"agent_continue_metadata_missing",
|
|
10320
|
-
turnTraceContext,
|
|
10321
|
-
messageTs ? { "messaging.message.id": messageTs } : {},
|
|
10322
|
-
"Agent continuation could not be scheduled because retry metadata was incomplete"
|
|
10323
|
-
);
|
|
10324
|
-
}
|
|
10370
|
+
if (error === agentContinueScheduleError) {
|
|
10371
|
+
shouldPersistFailureState = true;
|
|
10372
|
+
throw error;
|
|
10325
10373
|
}
|
|
10326
10374
|
shouldPersistFailureState = true;
|
|
10327
10375
|
const createdCanvasUrl = getCurrentTurnCanvasUrl({
|
|
@@ -10962,7 +11010,7 @@ async function failUnresumableContinuation(args) {
|
|
|
10962
11010
|
errorMessage: args.errorMessage
|
|
10963
11011
|
});
|
|
10964
11012
|
}
|
|
10965
|
-
async function continueSlackAgentRun(payload, options
|
|
11013
|
+
async function continueSlackAgentRun(payload, options) {
|
|
10966
11014
|
const thread = parseSlackThreadId(payload.conversationId);
|
|
10967
11015
|
if (!thread) {
|
|
10968
11016
|
throw new Error(
|
|
@@ -10976,7 +11024,7 @@ async function continueSlackAgentRun(payload, options = {}) {
|
|
|
10976
11024
|
channelId: thread.channelId,
|
|
10977
11025
|
threadTs: thread.threadTs,
|
|
10978
11026
|
lockKey: payload.conversationId,
|
|
10979
|
-
|
|
11027
|
+
agentRunner: options.agentRunner,
|
|
10980
11028
|
scheduleSessionCompletedPluginTasks: options.scheduleSessionCompletedPluginTasks,
|
|
10981
11029
|
beforeStart: async () => {
|
|
10982
11030
|
let sessionRecord;
|
|
@@ -11041,40 +11089,50 @@ async function continueSlackAgentRun(payload, options = {}) {
|
|
|
11041
11089
|
messageText: userMessage2.text,
|
|
11042
11090
|
messageTs: getTurnUserSlackMessageTs(userMessage2),
|
|
11043
11091
|
replyContext: {
|
|
11044
|
-
|
|
11045
|
-
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
}
|
|
11049
|
-
},
|
|
11050
|
-
requester,
|
|
11051
|
-
destination: payload.destination,
|
|
11052
|
-
source: activeSessionRecord.source,
|
|
11053
|
-
correlation: {
|
|
11054
|
-
conversationId: payload.conversationId,
|
|
11055
|
-
turnId: payload.sessionId,
|
|
11056
|
-
channelId: thread.channelId,
|
|
11057
|
-
threadTs: thread.threadTs,
|
|
11058
|
-
requesterId: requester.userId
|
|
11092
|
+
input: {
|
|
11093
|
+
conversationContext,
|
|
11094
|
+
piMessages: conversation.piMessages,
|
|
11095
|
+
...getTurnUserReplyAttachmentContext(userMessage2)
|
|
11059
11096
|
},
|
|
11060
|
-
|
|
11061
|
-
|
|
11062
|
-
|
|
11063
|
-
|
|
11064
|
-
|
|
11065
|
-
|
|
11066
|
-
|
|
11067
|
-
|
|
11068
|
-
|
|
11069
|
-
|
|
11097
|
+
routing: {
|
|
11098
|
+
credentialContext: {
|
|
11099
|
+
actor: {
|
|
11100
|
+
type: "user",
|
|
11101
|
+
userId: requester.userId
|
|
11102
|
+
}
|
|
11103
|
+
},
|
|
11104
|
+
requester,
|
|
11105
|
+
destination: payload.destination,
|
|
11106
|
+
source: activeSessionRecord.source,
|
|
11107
|
+
correlation: {
|
|
11070
11108
|
conversationId: payload.conversationId,
|
|
11071
|
-
|
|
11072
|
-
|
|
11073
|
-
|
|
11074
|
-
|
|
11075
|
-
}
|
|
11109
|
+
turnId: payload.sessionId,
|
|
11110
|
+
channelId: thread.channelId,
|
|
11111
|
+
threadTs: thread.threadTs,
|
|
11112
|
+
requesterId: requester.userId
|
|
11113
|
+
},
|
|
11114
|
+
toolChannelId: artifacts.assistantContextChannelId ?? thread.channelId
|
|
11115
|
+
},
|
|
11116
|
+
policy: {
|
|
11117
|
+
channelConfiguration
|
|
11076
11118
|
},
|
|
11077
|
-
|
|
11119
|
+
state: {
|
|
11120
|
+
artifactState: artifacts,
|
|
11121
|
+
pendingAuth: conversation.processing.pendingAuth,
|
|
11122
|
+
sandbox
|
|
11123
|
+
},
|
|
11124
|
+
durability: {
|
|
11125
|
+
recordPendingAuth: async (nextPendingAuth) => {
|
|
11126
|
+
await applyPendingAuthUpdate({
|
|
11127
|
+
conversation,
|
|
11128
|
+
conversationId: payload.conversationId,
|
|
11129
|
+
nextPendingAuth
|
|
11130
|
+
});
|
|
11131
|
+
await persistThreadStateById(payload.conversationId, {
|
|
11132
|
+
conversation
|
|
11133
|
+
});
|
|
11134
|
+
}
|
|
11135
|
+
}
|
|
11078
11136
|
},
|
|
11079
11137
|
onSuccess: async (reply) => {
|
|
11080
11138
|
await persistCompletedReplyState2({
|
|
@@ -11108,21 +11166,12 @@ async function continueSlackAgentRun(payload, options = {}) {
|
|
|
11108
11166
|
"Continued agent run parked for auth"
|
|
11109
11167
|
);
|
|
11110
11168
|
},
|
|
11111
|
-
onTimeoutPause: async (
|
|
11112
|
-
if (!isRetryableTurnError(error, "agent_continue")) {
|
|
11113
|
-
throw error;
|
|
11114
|
-
}
|
|
11115
|
-
const version = error.metadata?.version;
|
|
11116
|
-
if (typeof version !== "number") {
|
|
11117
|
-
throw new Error(
|
|
11118
|
-
"Agent continuation did not include a session record version"
|
|
11119
|
-
);
|
|
11120
|
-
}
|
|
11169
|
+
onTimeoutPause: async ({ resumeVersion }) => {
|
|
11121
11170
|
await scheduleAgentContinue2({
|
|
11122
11171
|
conversationId: payload.conversationId,
|
|
11123
11172
|
destination: payload.destination,
|
|
11124
11173
|
sessionId: payload.sessionId,
|
|
11125
|
-
expectedVersion:
|
|
11174
|
+
expectedVersion: resumeVersion
|
|
11126
11175
|
});
|
|
11127
11176
|
}
|
|
11128
11177
|
};
|
|
@@ -11240,7 +11289,7 @@ async function recoverStrandedRunningSession(args) {
|
|
|
11240
11289
|
});
|
|
11241
11290
|
return false;
|
|
11242
11291
|
}
|
|
11243
|
-
async function resumeAwaitingSlackContinuation(conversationId, options
|
|
11292
|
+
async function resumeAwaitingSlackContinuation(conversationId, options) {
|
|
11244
11293
|
const summaries = await listAgentTurnSessionSummariesForConversation(conversationId);
|
|
11245
11294
|
const newest = summaries[0];
|
|
11246
11295
|
if (newest?.state === "running") {
|
|
@@ -11278,7 +11327,7 @@ async function resumeAwaitingSlackContinuation(conversationId, options = {}) {
|
|
|
11278
11327
|
}
|
|
11279
11328
|
return false;
|
|
11280
11329
|
}
|
|
11281
|
-
async function continueSlackAgentRunWithLockRetry(payload, options
|
|
11330
|
+
async function continueSlackAgentRunWithLockRetry(payload, options) {
|
|
11282
11331
|
const scheduleAgentContinue2 = options.scheduleAgentContinue ?? scheduleAgentContinue;
|
|
11283
11332
|
for (const [attempt, delayMs] of [
|
|
11284
11333
|
...AGENT_CONTINUE_LOCK_RETRY_DELAYS_MS,
|
|
@@ -11362,9 +11411,17 @@ function createProductionSlackWebhookServices(options) {
|
|
|
11362
11411
|
}
|
|
11363
11412
|
function createProductionConversationWorkOptions(options) {
|
|
11364
11413
|
const conversationStore = getProductionConversationStore();
|
|
11414
|
+
const { agentRunner } = options;
|
|
11415
|
+
const services = {
|
|
11416
|
+
...options.services,
|
|
11417
|
+
replyExecutor: {
|
|
11418
|
+
...options.services?.replyExecutor,
|
|
11419
|
+
agentRunner
|
|
11420
|
+
}
|
|
11421
|
+
};
|
|
11365
11422
|
const runtime = createSlackRuntime({
|
|
11366
11423
|
getSlackAdapter: getProductionSlackAdapter,
|
|
11367
|
-
services
|
|
11424
|
+
services
|
|
11368
11425
|
});
|
|
11369
11426
|
return {
|
|
11370
11427
|
conversationStore,
|
|
@@ -11373,11 +11430,8 @@ function createProductionConversationWorkOptions(options) {
|
|
|
11373
11430
|
getSlackAdapter: getProductionSlackAdapter,
|
|
11374
11431
|
conversationStore,
|
|
11375
11432
|
resumeAwaitingContinuation: async (conversationId) => await resumeAwaitingSlackContinuation(conversationId, {
|
|
11376
|
-
|
|
11377
|
-
|
|
11378
|
-
options?.services?.sandbox?.tracePropagation
|
|
11379
|
-
),
|
|
11380
|
-
scheduleSessionCompletedPluginTasks: options?.services?.replyExecutor?.scheduleSessionCompletedPluginTasks
|
|
11433
|
+
agentRunner,
|
|
11434
|
+
scheduleSessionCompletedPluginTasks: services.replyExecutor?.scheduleSessionCompletedPluginTasks
|
|
11381
11435
|
}),
|
|
11382
11436
|
runtime
|
|
11383
11437
|
})
|
|
@@ -11699,18 +11753,17 @@ async function createApp(options) {
|
|
|
11699
11753
|
throw error;
|
|
11700
11754
|
}
|
|
11701
11755
|
const waitUntil = options?.waitUntil ?? await defaultWaitUntil();
|
|
11756
|
+
const tracePropagation = { domains: sandboxEgressTracePropagationDomains };
|
|
11757
|
+
const agentRunner = createAgentRunner(executeAgentRun, {
|
|
11758
|
+
tracePropagation
|
|
11759
|
+
});
|
|
11702
11760
|
const runtimeServiceOverrides = {
|
|
11703
|
-
|
|
11704
|
-
|
|
11705
|
-
}
|
|
11761
|
+
replyExecutor: { agentRunner },
|
|
11762
|
+
sandbox: { tracePropagation }
|
|
11706
11763
|
};
|
|
11707
11764
|
const slackWebhookServices = createProductionSlackWebhookServices({
|
|
11708
11765
|
services: runtimeServiceOverrides
|
|
11709
11766
|
});
|
|
11710
|
-
const generateReplyWithTracePropagation = withSandboxTracePropagation(
|
|
11711
|
-
generateAssistantReply,
|
|
11712
|
-
runtimeServiceOverrides.sandbox.tracePropagation
|
|
11713
|
-
);
|
|
11714
11767
|
const app = new Hono();
|
|
11715
11768
|
app.onError((err, c) => {
|
|
11716
11769
|
logException(err, "unhandled_route_error");
|
|
@@ -11736,24 +11789,23 @@ async function createApp(options) {
|
|
|
11736
11789
|
app.get("/health", () => GET());
|
|
11737
11790
|
app.get("/api/oauth/callback/mcp/:provider", (c) => {
|
|
11738
11791
|
return GET3(c.req.raw, c.req.param("provider"), waitUntil, {
|
|
11739
|
-
|
|
11792
|
+
agentRunner
|
|
11740
11793
|
});
|
|
11741
11794
|
});
|
|
11742
11795
|
app.get("/api/oauth/callback/:provider", (c) => {
|
|
11743
11796
|
return GET4(c.req.raw, c.req.param("provider"), waitUntil, {
|
|
11744
|
-
|
|
11797
|
+
agentRunner
|
|
11745
11798
|
});
|
|
11746
11799
|
});
|
|
11747
11800
|
app.post("/api/internal/agent-dispatch", (c) => {
|
|
11748
|
-
return POST(c.req.raw, waitUntil, {
|
|
11749
|
-
tracePropagation: { domains: sandboxEgressTracePropagationDomains }
|
|
11750
|
-
});
|
|
11801
|
+
return POST(c.req.raw, waitUntil, { agentRunner });
|
|
11751
11802
|
});
|
|
11752
11803
|
let agentContinuePOST;
|
|
11753
11804
|
let pluginTaskPOST;
|
|
11754
11805
|
let conversationWorkOptions;
|
|
11755
11806
|
const getConversationWorkOptions = () => {
|
|
11756
11807
|
conversationWorkOptions ??= options?.conversationWork ?? createProductionConversationWorkOptions({
|
|
11808
|
+
agentRunner,
|
|
11757
11809
|
services: runtimeServiceOverrides
|
|
11758
11810
|
});
|
|
11759
11811
|
return conversationWorkOptions;
|