@sentry/junior 0.146.0 → 0.148.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-SLJADYE5.js → agent-hooks-VAUYT6PD.js} +10 -10
- package/dist/api/conversations/access.d.ts +2 -1
- package/dist/api/conversations/archive.d.ts +3 -5
- package/dist/api/conversations/create.d.ts +6 -0
- package/dist/api/conversations/detail.d.ts +2 -295
- package/dist/api/conversations/event-list.d.ts +2 -192
- package/dist/api/conversations/list.d.ts +4 -66
- package/dist/api/conversations/routes.d.ts +1 -1
- package/dist/api/conversations/stats.d.ts +0 -54
- package/dist/api/http.d.ts +2 -6
- package/dist/api/locations/detail.d.ts +3 -111
- package/dist/api/locations/list.d.ts +0 -45
- package/dist/api/locations/query.d.ts +2 -1
- package/dist/api/locations/routes.d.ts +1 -1
- package/dist/api/people/list.d.ts +0 -29
- package/dist/api/people/profile.d.ts +2 -106
- package/dist/api/people/profile.query.d.ts +2 -1
- package/dist/api/people/routes.d.ts +1 -1
- package/dist/api/people/shared.d.ts +1 -1
- package/dist/api/people/spend.d.ts +3 -4
- package/dist/api/personal-tokens/routes.d.ts +2 -2
- package/dist/api/route.d.ts +8 -14
- package/dist/api/schema/conversation.d.ts +64 -29
- package/dist/api/schema/location.d.ts +4 -0
- package/dist/api/schema/person.d.ts +7 -3
- package/dist/api/schema.d.ts +2 -2
- package/dist/api/schema.js +7 -1
- package/dist/api/stats.d.ts +0 -13
- package/dist/api/validation.d.ts +7 -0
- package/dist/api/viewer.d.ts +3 -0
- package/dist/api.d.ts +2 -1
- package/dist/api.js +630 -564
- package/dist/app.js +369 -309
- package/dist/{catalog-runtime-RQIMSDPR.js → catalog-runtime-WADOZVTB.js} +5 -5
- package/dist/chat/actor.d.ts +4 -1
- package/dist/chat/agent/prompt.d.ts +0 -2
- package/dist/chat/agent/request.d.ts +4 -5
- package/dist/chat/agent/resume.d.ts +1 -0
- package/dist/chat/agent/sandbox.d.ts +2 -2
- package/dist/chat/agent/tools.d.ts +0 -2
- package/dist/chat/agent-dispatch/context.d.ts +2 -2
- package/dist/chat/agent-dispatch/types.d.ts +2 -2
- package/dist/chat/agent-invocations/types.d.ts +52 -0
- package/dist/chat/api-turns/work.d.ts +103 -0
- package/dist/chat/capabilities/jr-rpc-command.d.ts +2 -2
- package/dist/chat/configuration/service.d.ts +5 -2
- package/dist/chat/configuration/sql.d.ts +9 -0
- package/dist/chat/configuration/types.d.ts +17 -13
- package/dist/chat/conversations/history.d.ts +63 -0
- package/dist/chat/conversations/projection.d.ts +10 -0
- package/dist/chat/conversations/provenance.d.ts +6 -0
- package/dist/chat/conversations/sql/actor-identity.d.ts +19 -0
- package/dist/chat/conversations/store.d.ts +1 -1
- package/dist/chat/credentials/unlink-provider.d.ts +2 -1
- package/dist/chat/credentials/user-token-store.d.ts +2 -0
- package/dist/chat/event-tasks/tool-support.d.ts +2 -0
- package/dist/chat/identities/sql.d.ts +8 -0
- package/dist/chat/logging.d.ts +2 -0
- package/dist/chat/mcp/auth-store.d.ts +0 -2
- package/dist/chat/mcp/oauth.d.ts +0 -2
- package/dist/chat/oauth-flow.d.ts +3 -1
- package/dist/chat/pi/client.d.ts +2 -0
- package/dist/chat/plugins/credential-hooks.d.ts +2 -0
- package/dist/chat/prompt.d.ts +0 -2
- package/dist/chat/resource-events/notification.d.ts +2 -1
- package/dist/chat/resource-events/store.d.ts +1 -1
- package/dist/chat/runtime/delivered-turn-state.d.ts +1 -4
- package/dist/chat/runtime/reply-executor.d.ts +1 -1
- package/dist/chat/runtime/slack-runtime.d.ts +2 -1
- package/dist/chat/runtime/thread-state.d.ts +8 -11
- package/dist/chat/runtime/turn-input.d.ts +4 -2
- package/dist/chat/runtime/turn-preparation.d.ts +11 -4
- package/dist/chat/sandbox/command-result.d.ts +2 -0
- package/dist/chat/sandbox/egress/schemas.d.ts +6 -0
- package/dist/chat/scheduled-tasks/tool-support.d.ts +7 -5
- package/dist/chat/scheduled-tasks/tools/create.d.ts +4 -2
- package/dist/chat/scheduled-tasks/tools/delete.d.ts +4 -2
- package/dist/chat/scheduled-tasks/tools/list.d.ts +4 -2
- package/dist/chat/scheduled-tasks/tools/run-now.d.ts +4 -2
- package/dist/chat/scheduled-tasks/tools/update.d.ts +4 -2
- package/dist/chat/services/mcp-auth-orchestration.d.ts +0 -3
- package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -1
- package/dist/chat/services/provider-default-config.d.ts +2 -2
- package/dist/chat/services/subscribed-decision.d.ts +3 -0
- package/dist/chat/services/subscribed-reply-policy.d.ts +1 -0
- package/dist/chat/services/turn-result.d.ts +0 -3
- package/dist/chat/services/turn-router.d.ts +3 -0
- package/dist/chat/slack/assistant-thread/lifecycle.d.ts +0 -1
- package/dist/chat/slack/assistant-thread/title.d.ts +0 -3
- package/dist/chat/slack/channel.d.ts +26 -0
- package/dist/chat/slack/dispatch-turn.d.ts +2 -1
- package/dist/chat/slack/timestamp-param.d.ts +0 -2
- package/dist/chat/slack/{tools → tool-support}/canvas/api.d.ts +1 -1
- package/dist/chat/slack/tool-support/canvas/context.d.ts +11 -0
- package/dist/chat/slack/tool-support/channel-access.d.ts +42 -0
- package/dist/chat/slack/tool-support/channel-target.d.ts +27 -0
- package/dist/chat/slack/{tools → tool-support}/list/api.d.ts +8 -1
- package/dist/chat/slack/tool-support/list/params.d.ts +5 -0
- package/dist/chat/slack/tools/canvas/create.d.ts +3 -1
- package/dist/chat/slack/tools/canvas/edit.d.ts +2 -0
- package/dist/chat/slack/tools/canvas/read.d.ts +2 -0
- package/dist/chat/slack/tools/canvas/write.d.ts +2 -0
- package/dist/chat/slack/tools/{user-lookup.d.ts → channel-join.d.ts} +6 -5
- package/dist/chat/slack/tools/channel-list-messages.d.ts +5 -2
- package/dist/chat/slack/tools/conversation-message-search.d.ts +4 -8
- package/dist/chat/slack/tools/list/add-items.d.ts +4 -1
- package/dist/chat/slack/tools/list/create.d.ts +2 -0
- package/dist/chat/slack/tools/list/get-items.d.ts +5 -3
- package/dist/chat/slack/tools/list/update-item.d.ts +5 -1
- package/dist/chat/slack/tools/message-add-reaction.d.ts +3 -1
- package/dist/chat/slack/tools/public-search.d.ts +65 -2
- package/dist/chat/slack/tools/send-files.d.ts +3 -1
- package/dist/chat/slack/tools/thread-read.d.ts +4 -5
- package/dist/chat/slack/vision-cache.d.ts +5 -0
- package/dist/chat/source.d.ts +2 -0
- package/dist/chat/state/conversation.d.ts +4 -5
- package/dist/chat/task-execution/checkpoint.d.ts +1 -0
- package/dist/chat/task-execution/state.d.ts +9 -4
- package/dist/chat/task-execution/store.d.ts +3 -2
- package/dist/chat/task-execution/turn-cursor.d.ts +2 -0
- package/dist/chat/task-execution/worker.d.ts +2 -0
- package/dist/chat/tasks/read.d.ts +1 -1
- package/dist/chat/tool-support/structured-result.d.ts +1 -0
- package/dist/chat/tool-support/timed-out-tool-result.d.ts +11 -0
- package/dist/chat/tools/create-event-task.d.ts +2 -0
- package/dist/chat/tools/delete-event-task.d.ts +2 -0
- package/dist/chat/tools/handoff/tool.d.ts +2 -0
- package/dist/chat/tools/list-event-tasks.d.ts +2 -0
- package/dist/chat/tools/list-resource-event-subscriptions.d.ts +2 -0
- package/dist/chat/tools/runtime/report-progress.d.ts +2 -0
- package/dist/chat/tools/runtime/spawn-agent.d.ts +2 -0
- package/dist/chat/tools/search-conversation-events.d.ts +3 -1
- package/dist/chat/tools/search-resource-event-types.d.ts +2 -0
- package/dist/chat/tools/search-tools.d.ts +2 -0
- package/dist/chat/tools/skill/load-skill.d.ts +2 -0
- package/dist/chat/tools/skill/search-mcp-tools.d.ts +2 -0
- package/dist/chat/tools/stop-watching-resources.d.ts +2 -0
- package/dist/chat/tools/system-time.d.ts +2 -0
- package/dist/chat/tools/types.d.ts +11 -10
- package/dist/chat/tools/update-event-task.d.ts +2 -0
- package/dist/chat/tools/user-lookup.d.ts +29 -0
- package/dist/chat/tools/watch-resource-events.d.ts +4 -2
- package/dist/chat/tools/web/fetch-tool.d.ts +2 -0
- package/dist/chat/tools/web/image-generate.d.ts +2 -0
- package/dist/chat/tools/web/search.d.ts +2 -0
- package/dist/{chunk-GYEKOX7N.js → chunk-2B3PT3V2.js} +1 -1
- package/dist/{chunk-JLMVCNXL.js → chunk-45LOR4PU.js} +22 -4
- package/dist/{chunk-FGHADGIC.js → chunk-4AQZYNHM.js} +2 -2
- package/dist/{chunk-W65V465O.js → chunk-4EA2SFK2.js} +66 -4
- package/dist/{chunk-MKRIZ4VG.js → chunk-4GXJUYJV.js} +4 -2
- package/dist/{chunk-F7REGDKO.js → chunk-55F4QU2V.js} +2 -1
- package/dist/{chunk-M6ZWP4RI.js → chunk-7OEIXFC3.js} +2 -2
- package/dist/{chunk-MCFIXAV5.js → chunk-D3WPMGEX.js} +55 -37
- package/dist/{chunk-AISNSNDV.js → chunk-D6YX4NNN.js} +22 -10
- package/dist/chunk-DUY5CDAM.js +36 -0
- package/dist/{chunk-B63BF443.js → chunk-EAI67NTM.js} +9 -1
- package/dist/{chunk-FEKQHPVA.js → chunk-EINWQFXI.js} +9 -8
- package/dist/chunk-GDFF3BQG.js +136 -0
- package/dist/{chunk-X22KCSCO.js → chunk-GXYDVZKM.js} +7 -5
- package/dist/{chunk-X2WMBTS3.js → chunk-HLPLT3NY.js} +8 -5
- package/dist/{chunk-PB222GIA.js → chunk-HWQGBIH7.js} +1 -1
- package/dist/chunk-IL4EDBMV.js +566 -0
- package/dist/{chunk-HQE6EJS5.js → chunk-LAZGHEYU.js} +1 -1
- package/dist/{chunk-QG7OOKIN.js → chunk-LE5H7LMT.js} +1 -1
- package/dist/chunk-LNVEIJ2L.js +48 -0
- package/dist/{chunk-JUA6VU2Z.js → chunk-OJCP3C3J.js} +12 -23
- package/dist/{chunk-37JJDS4H.js → chunk-POSZWRGL.js} +1 -1
- package/dist/{chunk-TCEJ7XXM.js → chunk-QOWHHM3F.js} +1 -1
- package/dist/{chunk-H6U2U3EP.js → chunk-RRJV5UR5.js} +304 -65
- package/dist/{chunk-OFPYOC3M.js → chunk-ULAU5ZGU.js} +127 -120
- package/dist/{chunk-V6SRLKUB.js → chunk-V2FXMOEA.js} +2 -2
- package/dist/{chunk-GDQEU4I7.js → chunk-VCYSOXON.js} +296 -526
- package/dist/{chunk-BLETMLRX.js → chunk-VMNRXKAH.js} +1374 -989
- package/dist/{chunk-37EVZP66.js → chunk-VRHTNBA6.js} +167 -92
- package/dist/{chunk-FXDDDSPL.js → chunk-VY6W3T43.js} +4 -4
- package/dist/{chunk-ZDGHGY74.js → chunk-WCN4YSH7.js} +13 -6
- package/dist/{chunk-PH4Q3A6W.js → chunk-WOONT5ZP.js} +1 -1
- package/dist/{chunk-47OSH2ZO.js → chunk-XJ42NBP5.js} +395 -206
- package/dist/{chunk-SCGVWUZX.js → chunk-ZCHIC2GM.js} +92 -75
- package/dist/chunk-ZPL2RR7F.js +798 -0
- package/dist/cli/chat.js +33 -35
- package/dist/cli/check.js +6 -6
- package/dist/cli/plugins.js +13 -13
- package/dist/cli/snapshot-create.js +9 -9
- package/dist/cli/upgrade.js +7 -7
- package/dist/db/schema/agent-invocations.d.ts +20 -0
- package/dist/db/schema/conversation-annotations.d.ts +2 -2
- package/dist/db/schema/location-configurations.d.ts +127 -0
- package/dist/db/schema.d.ts +150 -3
- package/dist/{db-WWOMXWTT.js → db-XUKZRFFK.js} +7 -7
- package/dist/instrumentation.js +4 -4
- package/dist/nitro.js +2 -2
- package/dist/{oauth-callback-server-A6ZZX74U.js → oauth-callback-server-LPZMMGFI.js} +25 -26
- package/dist/{runner-KSGB2UAV.js → runner-DGKUTMPX.js} +22 -41
- package/dist/{skills-26QPWKVS.js → skills-P7YUFSXM.js} +6 -6
- package/dist/spawn-DSK3ZEVD.js +38 -0
- package/dist/{validation-OPSRGFGH.js → validation-S7U5M5NR.js} +6 -6
- package/dist/version.js +1 -1
- package/dist/{work-VMSW7STJ.js → work-GAA7TVAD.js} +18 -19
- package/dist/{worker-2JNFB7C7.js → worker-JXPJH3QB.js} +11 -10
- package/migrations/0024_misty_typhoid_mary.sql +12 -0
- package/migrations/meta/0024_snapshot.json +2275 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +6 -5
- package/dist/api/health.d.ts +0 -7
- package/dist/api/personal-tokens/create.d.ts +0 -11
- package/dist/api/personal-tokens/list.d.ts +0 -12
- package/dist/api/personal-tokens/revoke.d.ts +0 -5
- package/dist/api/plugin-reports.d.ts +0 -63
- package/dist/api/plugins.d.ts +0 -8
- package/dist/api/runtime.d.ts +0 -24
- package/dist/api/skills.d.ts +0 -6
- package/dist/chat/slack/tools/canvas/context.d.ts +0 -18
- package/dist/chat/slack/tools/channel-access.d.ts +0 -30
- package/dist/chat/state/artifacts.d.ts +0 -30
- package/dist/chat/tool-support/turn-deadline-result.d.ts +0 -3
- package/dist/chunk-HLXXQI5Q.js +0 -238
- package/dist/chunk-LVW7BLLT.js +0 -115
- package/dist/chunk-Q6QZTTLS.js +0 -55
- package/dist/chunk-QSXZ42KX.js +0 -285
- package/dist/chunk-R776HKPK.js +0 -81
- package/dist/chunk-T5GXFFLA.js +0 -67
- package/dist/spawn-5LAJXZ2P.js +0 -39
- /package/dist/chat/slack/{tools → tool-support}/canvas/markdown.d.ts +0 -0
- /package/dist/chat/slack/{tools → tool-support}/channel-capabilities.d.ts +0 -0
- /package/dist/chat/slack/{tools → tool-support}/context.d.ts +0 -0
- /package/dist/chat/slack/{tools → tool-support}/slack-message-url.d.ts +0 -0
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
PluginCredentialFailureError,
|
|
8
8
|
agentNameSchema,
|
|
9
9
|
createPluginAuthOrchestration
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-EINWQFXI.js";
|
|
11
11
|
import {
|
|
12
12
|
authorizationId
|
|
13
13
|
} from "./chunk-DIB4GX3G.js";
|
|
@@ -21,14 +21,18 @@ import {
|
|
|
21
21
|
getMcpAwareErrorType,
|
|
22
22
|
getMcpAwareTelemetryMessage,
|
|
23
23
|
getMcpProviderErrorAttributes,
|
|
24
|
+
getOAuthAccountProviders,
|
|
24
25
|
hasEgressCredentialHooks,
|
|
25
26
|
issuePluginCredential,
|
|
26
27
|
issueProviderCredentialLease,
|
|
28
|
+
lookupSlackUserByEmail,
|
|
29
|
+
lookupSlackUserProfile,
|
|
27
30
|
onPluginEgressResponse,
|
|
28
31
|
patchMcpAuthSession,
|
|
32
|
+
searchSlackUsers,
|
|
29
33
|
selectPluginGrant,
|
|
30
34
|
toMcpProviderError
|
|
31
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-XJ42NBP5.js";
|
|
32
36
|
import {
|
|
33
37
|
RetryableDeliveryError,
|
|
34
38
|
actorFromRouting,
|
|
@@ -36,7 +40,7 @@ import {
|
|
|
36
40
|
isAgentRunFeatureDisabled,
|
|
37
41
|
surfaceFromRouting,
|
|
38
42
|
toolInvocationDestination
|
|
39
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-GDFF3BQG.js";
|
|
40
44
|
import {
|
|
41
45
|
addReactionToMessage,
|
|
42
46
|
deliverOAuthAuthorization,
|
|
@@ -44,77 +48,7 @@ import {
|
|
|
44
48
|
getSlackMessagePermalink,
|
|
45
49
|
resolveBaseUrl,
|
|
46
50
|
uploadFilesToConversation
|
|
47
|
-
} from "./chunk-
|
|
48
|
-
import {
|
|
49
|
-
estimateTextTokens,
|
|
50
|
-
getAgentContextCompactionTriggerTokens,
|
|
51
|
-
getAgentContextInputLimitTokens
|
|
52
|
-
} from "./chunk-T5GXFFLA.js";
|
|
53
|
-
import {
|
|
54
|
-
AGENTS_REMOVAL_NOTICE,
|
|
55
|
-
AGENTS_REPLACEMENT_NOTICE,
|
|
56
|
-
CooperativeTurnYieldError,
|
|
57
|
-
DEFAULT_SEARCH_COMMAND_TIMEOUT_MS,
|
|
58
|
-
MAX_TEXT_CHARS,
|
|
59
|
-
NO_REPLY_MARKER,
|
|
60
|
-
RIPGREP_EXCLUDED_GLOBS,
|
|
61
|
-
TURN_CONTEXT_TAG,
|
|
62
|
-
TurnInputCommitLostError,
|
|
63
|
-
TurnSliceLimitExceededError,
|
|
64
|
-
abandonReplacedPendingAuth,
|
|
65
|
-
buildAgentsInstructionsMessage,
|
|
66
|
-
canReusePendingAuthLink,
|
|
67
|
-
collectFiles,
|
|
68
|
-
containsNoReplyMarker,
|
|
69
|
-
continuableMessages,
|
|
70
|
-
decideReply,
|
|
71
|
-
extractAssistantText,
|
|
72
|
-
findSingleRepositoryDirectory,
|
|
73
|
-
findVisibleAgentsInstructions,
|
|
74
|
-
getAssistantReplyText,
|
|
75
|
-
getPiMessageRole,
|
|
76
|
-
getRipgrepSearchLocation,
|
|
77
|
-
getTerminalAssistantMessages,
|
|
78
|
-
getUserMessageInstructionText,
|
|
79
|
-
hasRuntimeTurnContext,
|
|
80
|
-
historyItemFromPiMessage,
|
|
81
|
-
isAssistantMessage,
|
|
82
|
-
isContinuablePiBoundary,
|
|
83
|
-
isMissingPathError,
|
|
84
|
-
isNoReplyMarker,
|
|
85
|
-
isToolResultError,
|
|
86
|
-
isToolResultMessage,
|
|
87
|
-
isTurnInputCommitLostError,
|
|
88
|
-
loadConnectedMcpProviders,
|
|
89
|
-
loadConversationProjection,
|
|
90
|
-
loadTurnCheckpoint,
|
|
91
|
-
loadTurnRoute,
|
|
92
|
-
mergeArtifactsState,
|
|
93
|
-
missingPathSearchResult,
|
|
94
|
-
normalizeToLf,
|
|
95
|
-
normalizeToolNameFromResult,
|
|
96
|
-
openConversationProjection,
|
|
97
|
-
piMessageFromHistoryItem,
|
|
98
|
-
positiveInteger,
|
|
99
|
-
recordAgentsInstructionsUpdated,
|
|
100
|
-
recordAuthorizationRequested,
|
|
101
|
-
recordGuardianActionReviewed,
|
|
102
|
-
recordMcpProviderConnected,
|
|
103
|
-
recordToolExecutionStarted,
|
|
104
|
-
recordTurnRoute,
|
|
105
|
-
renderAgentsInstructions,
|
|
106
|
-
resolveRepositoryInstructions,
|
|
107
|
-
resolveWorkspacePath,
|
|
108
|
-
retainRuntimeTurnContext,
|
|
109
|
-
sanitizeAssistantText,
|
|
110
|
-
saveTurnCheckpoint,
|
|
111
|
-
stripRuntimeTurnContext,
|
|
112
|
-
trimTrailingAssistantMessages,
|
|
113
|
-
truncateText
|
|
114
|
-
} from "./chunk-GDQEU4I7.js";
|
|
115
|
-
import {
|
|
116
|
-
JUNIOR_THREAD_STATE_TTL_MS
|
|
117
|
-
} from "./chunk-3Y47VMHV.js";
|
|
51
|
+
} from "./chunk-WCN4YSH7.js";
|
|
118
52
|
import {
|
|
119
53
|
parseSandboxEgressAuthRequiredSignal,
|
|
120
54
|
parseSandboxEgressPermissionDeniedSignal,
|
|
@@ -143,7 +77,7 @@ import {
|
|
|
143
77
|
runNonInteractiveCommand,
|
|
144
78
|
throwSandboxOperationError,
|
|
145
79
|
wrapSandboxSetupError
|
|
146
|
-
} from "./chunk-
|
|
80
|
+
} from "./chunk-VY6W3T43.js";
|
|
147
81
|
import {
|
|
148
82
|
SCHEDULED_TASK_SYSTEM_ACTOR,
|
|
149
83
|
compactEventTask,
|
|
@@ -175,20 +109,85 @@ import {
|
|
|
175
109
|
saveEventTask,
|
|
176
110
|
scheduledTaskAttributes,
|
|
177
111
|
writableEventTask
|
|
178
|
-
} from "./chunk-
|
|
112
|
+
} from "./chunk-GXYDVZKM.js";
|
|
179
113
|
import {
|
|
180
114
|
parseSlackThreadId
|
|
181
|
-
} from "./chunk-
|
|
115
|
+
} from "./chunk-WOONT5ZP.js";
|
|
182
116
|
import {
|
|
183
117
|
SHORT_TITLE_MAX_LENGTH,
|
|
118
|
+
estimateTextTokens,
|
|
184
119
|
generateShortTitle,
|
|
120
|
+
getAgentContextCompactionTriggerTokens,
|
|
121
|
+
getAgentContextInputLimitTokens,
|
|
185
122
|
resolveTaskTitle
|
|
186
|
-
} from "./chunk-
|
|
123
|
+
} from "./chunk-4EA2SFK2.js";
|
|
187
124
|
import {
|
|
125
|
+
AGENTS_REMOVAL_NOTICE,
|
|
126
|
+
AGENTS_REPLACEMENT_NOTICE,
|
|
127
|
+
CooperativeTurnYieldError,
|
|
128
|
+
DEFAULT_SEARCH_COMMAND_TIMEOUT_MS,
|
|
129
|
+
MAX_TEXT_CHARS,
|
|
130
|
+
NO_REPLY_MARKER,
|
|
131
|
+
RIPGREP_EXCLUDED_GLOBS,
|
|
132
|
+
TURN_CONTEXT_TAG,
|
|
188
133
|
ToolInputError,
|
|
134
|
+
TurnInputCommitLostError,
|
|
135
|
+
TurnSliceLimitExceededError,
|
|
136
|
+
abandonReplacedPendingAuth,
|
|
189
137
|
addAgentTurnUsage,
|
|
190
|
-
|
|
191
|
-
|
|
138
|
+
buildAgentsInstructionsMessage,
|
|
139
|
+
canReusePendingAuthLink,
|
|
140
|
+
collectFiles,
|
|
141
|
+
containsNoReplyMarker,
|
|
142
|
+
continuableMessages,
|
|
143
|
+
decideReply,
|
|
144
|
+
extractAssistantText,
|
|
145
|
+
findSingleRepositoryDirectory,
|
|
146
|
+
findVisibleAgentsInstructions,
|
|
147
|
+
getAssistantReplyText,
|
|
148
|
+
getPiMessageRole,
|
|
149
|
+
getRipgrepSearchLocation,
|
|
150
|
+
getTerminalAssistantMessages,
|
|
151
|
+
getUserMessageInstructionText,
|
|
152
|
+
hasAgentTurnUsage,
|
|
153
|
+
hasRuntimeTurnContext,
|
|
154
|
+
historyItemFromPiMessage,
|
|
155
|
+
isAssistantMessage,
|
|
156
|
+
isContinuablePiBoundary,
|
|
157
|
+
isMissingPathError,
|
|
158
|
+
isNoReplyMarker,
|
|
159
|
+
isToolResultError,
|
|
160
|
+
isToolResultMessage,
|
|
161
|
+
isTurnInputCommitLostError,
|
|
162
|
+
loadConnectedMcpProviders,
|
|
163
|
+
loadConversationProjection,
|
|
164
|
+
loadTurnCheckpoint,
|
|
165
|
+
loadTurnRoute,
|
|
166
|
+
missingPathSearchResult,
|
|
167
|
+
normalizeToLf,
|
|
168
|
+
normalizeToolNameFromResult,
|
|
169
|
+
openConversationProjection,
|
|
170
|
+
piMessageFromHistoryItem,
|
|
171
|
+
positiveInteger,
|
|
172
|
+
recordAgentsInstructionsUpdated,
|
|
173
|
+
recordAuthorizationRequested,
|
|
174
|
+
recordGuardianActionReviewed,
|
|
175
|
+
recordMcpProviderConnected,
|
|
176
|
+
recordToolExecutionStarted,
|
|
177
|
+
recordTurnRoute,
|
|
178
|
+
renderAgentsInstructions,
|
|
179
|
+
resolveRepositoryInstructions,
|
|
180
|
+
resolveWorkspacePath,
|
|
181
|
+
retainRuntimeTurnContext,
|
|
182
|
+
sanitizeAssistantText,
|
|
183
|
+
saveTurnCheckpoint,
|
|
184
|
+
stripRuntimeTurnContext,
|
|
185
|
+
trimTrailingAssistantMessages,
|
|
186
|
+
truncateText
|
|
187
|
+
} from "./chunk-VCYSOXON.js";
|
|
188
|
+
import {
|
|
189
|
+
JUNIOR_THREAD_STATE_TTL_MS
|
|
190
|
+
} from "./chunk-3Y47VMHV.js";
|
|
192
191
|
import {
|
|
193
192
|
privateTraceResultAttributes
|
|
194
193
|
} from "./chunk-UIE3R5XU.js";
|
|
@@ -201,7 +200,7 @@ import {
|
|
|
201
200
|
getSlackToolContext,
|
|
202
201
|
readActorIdentity,
|
|
203
202
|
resolveChannelCapabilities
|
|
204
|
-
} from "./chunk-
|
|
203
|
+
} from "./chunk-ZCHIC2GM.js";
|
|
205
204
|
import {
|
|
206
205
|
SlackActionError,
|
|
207
206
|
downloadPrivateSlackFile,
|
|
@@ -210,7 +209,7 @@ import {
|
|
|
210
209
|
isConversationScopedChannel,
|
|
211
210
|
normalizeSlackConversationId,
|
|
212
211
|
withSlackRetries
|
|
213
|
-
} from "./chunk-
|
|
212
|
+
} from "./chunk-V2FXMOEA.js";
|
|
214
213
|
import {
|
|
215
214
|
KNOWN_CONVERSATION_EVENT_TYPES,
|
|
216
215
|
contextProvenance,
|
|
@@ -221,12 +220,11 @@ import {
|
|
|
221
220
|
getSqlExecutor,
|
|
222
221
|
instructionActors,
|
|
223
222
|
instructionProvenanceFor,
|
|
224
|
-
sameActorIdentity
|
|
225
|
-
|
|
226
|
-
} from "./chunk-37EVZP66.js";
|
|
223
|
+
sameActorIdentity
|
|
224
|
+
} from "./chunk-VRHTNBA6.js";
|
|
227
225
|
import {
|
|
228
226
|
juniorIdentities
|
|
229
|
-
} from "./chunk-
|
|
227
|
+
} from "./chunk-D3WPMGEX.js";
|
|
230
228
|
import {
|
|
231
229
|
SANDBOX_DATA_ROOT,
|
|
232
230
|
SANDBOX_SKILLS_ROOT,
|
|
@@ -238,7 +236,7 @@ import {
|
|
|
238
236
|
} from "./chunk-EM225ITJ.js";
|
|
239
237
|
import {
|
|
240
238
|
getStateAdapter
|
|
241
|
-
} from "./chunk-
|
|
239
|
+
} from "./chunk-2B3PT3V2.js";
|
|
242
240
|
import {
|
|
243
241
|
ACTIVE_TURN_COMPACTION_SUMMARY_PREFIX,
|
|
244
242
|
COMPACTION_SUMMARY_PREFIX,
|
|
@@ -271,7 +269,7 @@ import {
|
|
|
271
269
|
resolveGatewayCredential,
|
|
272
270
|
resolveGatewayModel,
|
|
273
271
|
unwrapCurrentInstruction
|
|
274
|
-
} from "./chunk-
|
|
272
|
+
} from "./chunk-4GXJUYJV.js";
|
|
275
273
|
import {
|
|
276
274
|
canExposeConversationPayload,
|
|
277
275
|
resolveConversationPrivacy,
|
|
@@ -281,16 +279,16 @@ import {
|
|
|
281
279
|
toGenAiMessagesTraceAttributes,
|
|
282
280
|
toGenAiPayloadMetadata,
|
|
283
281
|
toGenAiPayloadTraceAttributes
|
|
284
|
-
} from "./chunk-
|
|
282
|
+
} from "./chunk-LE5H7LMT.js";
|
|
285
283
|
import {
|
|
286
284
|
discoverSkills,
|
|
287
285
|
findSkillByName,
|
|
288
286
|
loadSkillsByName,
|
|
289
287
|
parseSkillInvocation
|
|
290
|
-
} from "./chunk-
|
|
288
|
+
} from "./chunk-4AQZYNHM.js";
|
|
291
289
|
import {
|
|
292
290
|
pluginCatalogRuntime
|
|
293
|
-
} from "./chunk-
|
|
291
|
+
} from "./chunk-HWQGBIH7.js";
|
|
294
292
|
import {
|
|
295
293
|
CredentialUnavailableError,
|
|
296
294
|
OAuthProviderError,
|
|
@@ -298,7 +296,7 @@ import {
|
|
|
298
296
|
getOAuthProviderErrorAttributes,
|
|
299
297
|
resolveAuthTokenPlaceholder,
|
|
300
298
|
resolvePluginCommandEnv
|
|
301
|
-
} from "./chunk-
|
|
299
|
+
} from "./chunk-POSZWRGL.js";
|
|
302
300
|
import {
|
|
303
301
|
credentialUserSubjectId
|
|
304
302
|
} from "./chunk-RUIXF3YQ.js";
|
|
@@ -328,7 +326,7 @@ import {
|
|
|
328
326
|
summarizeMessageText,
|
|
329
327
|
withLogContext,
|
|
330
328
|
withSpan
|
|
331
|
-
} from "./chunk-
|
|
329
|
+
} from "./chunk-EAI67NTM.js";
|
|
332
330
|
import {
|
|
333
331
|
startInactiveSpan,
|
|
334
332
|
withActiveSpan
|
|
@@ -810,7 +808,6 @@ import { isRetryableAssistantError } from "@earendil-works/pi-ai";
|
|
|
810
808
|
function buildTurnResult(input) {
|
|
811
809
|
const {
|
|
812
810
|
newMessages,
|
|
813
|
-
artifactStatePatch,
|
|
814
811
|
toolCalls,
|
|
815
812
|
sandboxRef,
|
|
816
813
|
durationMs,
|
|
@@ -906,7 +903,6 @@ function buildTurnResult(input) {
|
|
|
906
903
|
};
|
|
907
904
|
return {
|
|
908
905
|
text: primaryText,
|
|
909
|
-
artifactStatePatch: Object.keys(artifactStatePatch).length > 0 ? artifactStatePatch : void 0,
|
|
910
906
|
sandboxRef,
|
|
911
907
|
piMessages: input.piMessages,
|
|
912
908
|
diagnostics: resolvedDiagnostics
|
|
@@ -986,27 +982,22 @@ function getDiscardedRetryUsage(messages, retryMessages) {
|
|
|
986
982
|
return hasAgentTurnUsage(usage) ? usage : void 0;
|
|
987
983
|
}
|
|
988
984
|
|
|
989
|
-
// src/chat/tool-support/
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
task_status: "active"
|
|
994
|
-
};
|
|
995
|
-
function annotateTurnDeadlineToolResult(result) {
|
|
996
|
-
if (!result.details || typeof result.details !== "object" || Array.isArray(result.details) || !("aborted" in result.details) || result.details.aborted !== true) {
|
|
985
|
+
// src/chat/tool-support/timed-out-tool-result.ts
|
|
986
|
+
function projectTimedOutToolResult(result) {
|
|
987
|
+
const details = result.details;
|
|
988
|
+
if (!details || typeof details !== "object" || Array.isArray(details) || !("aborted" in details) || details.aborted !== true) {
|
|
997
989
|
return void 0;
|
|
998
990
|
}
|
|
999
|
-
const
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
content: result.content.slice(1)
|
|
991
|
+
const record2 = details;
|
|
992
|
+
const target = typeof record2.target === "string" && record2.target.length > 0 ? record2.target : void 0;
|
|
993
|
+
const envelope = makeStructuredToolOutput({
|
|
994
|
+
...target ? { target } : {},
|
|
995
|
+
timed_out: true
|
|
1005
996
|
});
|
|
1006
997
|
return {
|
|
1007
998
|
content: envelope.content,
|
|
1008
999
|
details: envelope.details,
|
|
1009
|
-
isError:
|
|
1000
|
+
isError: false
|
|
1010
1001
|
};
|
|
1011
1002
|
}
|
|
1012
1003
|
|
|
@@ -1227,13 +1218,15 @@ async function classifyTurn(args) {
|
|
|
1227
1218
|
prompt: args.prompt,
|
|
1228
1219
|
thinkingLevel: "low",
|
|
1229
1220
|
system: buildClassifierSystemPrompt(Object.keys(args.profiles)),
|
|
1230
|
-
temperature: 0
|
|
1221
|
+
temperature: 0,
|
|
1222
|
+
promptName: "junior.thinking_route"
|
|
1231
1223
|
});
|
|
1232
1224
|
const parsed = schema.parse(result.object);
|
|
1233
1225
|
const reason = parsed.reason.trim();
|
|
1234
1226
|
if (parsed.confidence < CLASSIFIER_CONFIDENCE_THRESHOLD) {
|
|
1235
1227
|
return {
|
|
1236
1228
|
confidence: parsed.confidence,
|
|
1229
|
+
...result.costUsd !== void 0 ? { costUsd: result.costUsd } : {},
|
|
1237
1230
|
profile: STANDARD_MODEL_PROFILE,
|
|
1238
1231
|
reasoningLevel: CLASSIFIER_FALLBACK_REASONING_LEVEL,
|
|
1239
1232
|
reason: `low_confidence_medium_default:${reason}`,
|
|
@@ -1242,6 +1235,7 @@ async function classifyTurn(args) {
|
|
|
1242
1235
|
}
|
|
1243
1236
|
return {
|
|
1244
1237
|
confidence: parsed.confidence,
|
|
1238
|
+
...result.costUsd !== void 0 ? { costUsd: result.costUsd } : {},
|
|
1245
1239
|
profile: parsed.profile,
|
|
1246
1240
|
reasoningLevel: parsed.reasoning_level,
|
|
1247
1241
|
reason,
|
|
@@ -1764,34 +1758,6 @@ function formatReferenceFilesLines() {
|
|
|
1764
1758
|
return `- ${escapeXml(name)} (${escapeXml(`${SANDBOX_DATA_ROOT}/${name}`)})`;
|
|
1765
1759
|
});
|
|
1766
1760
|
}
|
|
1767
|
-
function formatArtifactsLines(artifactState) {
|
|
1768
|
-
if (!artifactState) return null;
|
|
1769
|
-
const lines = [];
|
|
1770
|
-
if (artifactState.lastCanvasId) {
|
|
1771
|
-
lines.push(`- last_canvas_id: ${escapeXml(artifactState.lastCanvasId)}`);
|
|
1772
|
-
}
|
|
1773
|
-
if (artifactState.lastCanvasUrl) {
|
|
1774
|
-
lines.push(`- last_canvas_url: ${escapeXml(artifactState.lastCanvasUrl)}`);
|
|
1775
|
-
}
|
|
1776
|
-
if (artifactState.recentCanvases && artifactState.recentCanvases.length > 0) {
|
|
1777
|
-
lines.push("- recent_canvases:");
|
|
1778
|
-
for (const canvas of artifactState.recentCanvases) {
|
|
1779
|
-
lines.push(` - id: ${escapeXml(canvas.id)}`);
|
|
1780
|
-
if (canvas.title) lines.push(` title: ${escapeXml(canvas.title)}`);
|
|
1781
|
-
if (canvas.url) lines.push(` url: ${escapeXml(canvas.url)}`);
|
|
1782
|
-
if (canvas.createdAt) {
|
|
1783
|
-
lines.push(` created_at: ${escapeXml(canvas.createdAt)}`);
|
|
1784
|
-
}
|
|
1785
|
-
}
|
|
1786
|
-
}
|
|
1787
|
-
if (artifactState.lastListId) {
|
|
1788
|
-
lines.push(`- last_list_id: ${escapeXml(artifactState.lastListId)}`);
|
|
1789
|
-
}
|
|
1790
|
-
if (artifactState.lastListUrl) {
|
|
1791
|
-
lines.push(`- last_list_url: ${escapeXml(artifactState.lastListUrl)}`);
|
|
1792
|
-
}
|
|
1793
|
-
return lines.length > 0 ? lines : null;
|
|
1794
|
-
}
|
|
1795
1761
|
function formatConfigurationLines(configuration) {
|
|
1796
1762
|
const keys = Object.keys(configuration ?? {}).sort(
|
|
1797
1763
|
(a, b) => a.localeCompare(b)
|
|
@@ -1842,7 +1808,7 @@ var EXECUTION_CONTRACT_RULES = [
|
|
|
1842
1808
|
"- Ask the user only for missing access, approval, or a decision that blocks safe progress. Ask one focused question; otherwise infer conservatively and continue.",
|
|
1843
1809
|
"- For conflicting evidence, compare sources and state which source is authoritative for the answer.",
|
|
1844
1810
|
"- Use `reportProgress` only for work with multiple substantive phases or a materially long wait. Skip short lookups and routine commands; after an initial update, call it again only when the major phase changes.",
|
|
1845
|
-
"-
|
|
1811
|
+
"- A tool result with `timed_out: true` means that attempt did not finish. Continue the active task. Before retrying work that may have side effects, inspect authoritative state and do not repeat a mutation that already applied."
|
|
1846
1812
|
];
|
|
1847
1813
|
var CONVERSATION_RULES = [
|
|
1848
1814
|
"- In thread follow-ups, answer from prior thread context; do not repeat resolved clarifying questions.",
|
|
@@ -1933,19 +1899,22 @@ function buildRuntimeSection(params) {
|
|
|
1933
1899
|
return renderTagBlock("runtime", lines.join("\n"));
|
|
1934
1900
|
}
|
|
1935
1901
|
function formatSourceLines(source) {
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1902
|
+
switch (source.platform) {
|
|
1903
|
+
case "web":
|
|
1904
|
+
case "local":
|
|
1905
|
+
return [
|
|
1906
|
+
`- source.platform: ${source.platform}`,
|
|
1907
|
+
`- source.conversation_id: ${escapeXml(source.conversationId)}`
|
|
1908
|
+
];
|
|
1909
|
+
case "slack":
|
|
1910
|
+
return [
|
|
1911
|
+
"- source.platform: slack",
|
|
1912
|
+
`- source.team_id: ${escapeXml(source.teamId)}`,
|
|
1913
|
+
`- source.channel_id: ${escapeXml(source.channelId)}`,
|
|
1914
|
+
...source.messageTs ? [`- source.message_ts: ${escapeXml(source.messageTs)}`] : [],
|
|
1915
|
+
...source.threadTs ? [`- source.thread_ts: ${escapeXml(source.threadTs)}`] : []
|
|
1916
|
+
];
|
|
1941
1917
|
}
|
|
1942
|
-
return [
|
|
1943
|
-
"- source.platform: slack",
|
|
1944
|
-
`- source.team_id: ${escapeXml(source.teamId)}`,
|
|
1945
|
-
`- source.channel_id: ${escapeXml(source.channelId)}`,
|
|
1946
|
-
...source.messageTs ? [`- source.message_ts: ${escapeXml(source.messageTs)}`] : [],
|
|
1947
|
-
...source.threadTs ? [`- source.thread_ts: ${escapeXml(source.threadTs)}`] : []
|
|
1948
|
-
];
|
|
1949
1918
|
}
|
|
1950
1919
|
function formatDestinationLines(destination) {
|
|
1951
1920
|
if (destination.platform === "local") {
|
|
@@ -2004,10 +1973,6 @@ function buildContextSection(params) {
|
|
|
2004
1973
|
if (dispatchLines) {
|
|
2005
1974
|
blocks.push(dispatchLines);
|
|
2006
1975
|
}
|
|
2007
|
-
const artifactLines = formatArtifactsLines(params.artifactState);
|
|
2008
|
-
if (artifactLines) {
|
|
2009
|
-
blocks.push(renderTag("artifacts", artifactLines));
|
|
2010
|
-
}
|
|
2011
1976
|
const configLines = formatConfigurationLines(params.configuration);
|
|
2012
1977
|
if (configLines) {
|
|
2013
1978
|
blocks.push(
|
|
@@ -2093,7 +2058,8 @@ var STATIC_SYSTEM_PROMPTS = {
|
|
|
2093
2058
|
slack: buildStaticSystemPrompt("slack")
|
|
2094
2059
|
};
|
|
2095
2060
|
function buildSystemPrompt(params) {
|
|
2096
|
-
|
|
2061
|
+
const platform = params.source.platform === "slack" ? "slack" : "local";
|
|
2062
|
+
return STATIC_SYSTEM_PROMPTS[platform];
|
|
2097
2063
|
}
|
|
2098
2064
|
function buildTurnContextPrompt(params) {
|
|
2099
2065
|
const includeSessionContext = params.includeSessionContext ?? true;
|
|
@@ -2112,7 +2078,6 @@ function buildTurnContextPrompt(params) {
|
|
|
2112
2078
|
pluginPromptContributions,
|
|
2113
2079
|
includeSessionContext ? buildContextSection({
|
|
2114
2080
|
actor: params.actor,
|
|
2115
|
-
artifactState: params.artifactState,
|
|
2116
2081
|
configuration: params.configuration,
|
|
2117
2082
|
dispatch: params.dispatch
|
|
2118
2083
|
}) : null,
|
|
@@ -2410,7 +2375,6 @@ async function assemblePrompt(args) {
|
|
|
2410
2375
|
source
|
|
2411
2376
|
} : void 0,
|
|
2412
2377
|
actor: isUserActor(args.currentActor) ? args.currentActor : void 0,
|
|
2413
|
-
artifactState: args.artifactState,
|
|
2414
2378
|
configuration: args.configurationValues
|
|
2415
2379
|
}) : null;
|
|
2416
2380
|
const turnContextParts = turnContextPrompt ? [{ type: "text", text: turnContextPrompt }] : [];
|
|
@@ -2496,9 +2460,9 @@ function commandResult(input) {
|
|
|
2496
2460
|
exitCode: input.exitCode
|
|
2497
2461
|
};
|
|
2498
2462
|
}
|
|
2499
|
-
function
|
|
2500
|
-
if (deps.
|
|
2501
|
-
return { ok: true, configuration: deps.
|
|
2463
|
+
function requireLocationConfiguration(deps) {
|
|
2464
|
+
if (deps.locationConfiguration) {
|
|
2465
|
+
return { ok: true, configuration: deps.locationConfiguration };
|
|
2502
2466
|
}
|
|
2503
2467
|
return {
|
|
2504
2468
|
ok: false,
|
|
@@ -2544,7 +2508,7 @@ async function handleConfigCommand(args, deps) {
|
|
|
2544
2508
|
"jr-rpc config list [--prefix <value>]"
|
|
2545
2509
|
].join("\n");
|
|
2546
2510
|
const subverb = (args[0] ?? "").trim();
|
|
2547
|
-
const configurationResult =
|
|
2511
|
+
const configurationResult = requireLocationConfiguration(deps);
|
|
2548
2512
|
if (!configurationResult.ok) {
|
|
2549
2513
|
return configurationResult.result;
|
|
2550
2514
|
}
|
|
@@ -6039,7 +6003,7 @@ function createAgentSandbox(options) {
|
|
|
6039
6003
|
if (command) {
|
|
6040
6004
|
const result = await maybeExecuteJrRpcCustomCommand(command, {
|
|
6041
6005
|
activeSkill: options.getActiveSkill(),
|
|
6042
|
-
|
|
6006
|
+
locationConfiguration: options.locationConfiguration,
|
|
6043
6007
|
actorId: isUserActor(options.actor) ? options.actor.userId : void 0,
|
|
6044
6008
|
onConfigurationValueChanged: (key, value) => {
|
|
6045
6009
|
if (value === void 0) {
|
|
@@ -6924,7 +6888,8 @@ async function enrichImagePrompt(rawPrompt) {
|
|
|
6924
6888
|
modelId: botConfig.fastModelId,
|
|
6925
6889
|
system: ENRICHMENT_SYSTEM_PROMPT,
|
|
6926
6890
|
messages: [{ role: "user", content: rawPrompt, timestamp: Date.now() }],
|
|
6927
|
-
maxTokens: 1024
|
|
6891
|
+
maxTokens: 1024,
|
|
6892
|
+
promptName: "junior.image_prompt_enrichment"
|
|
6928
6893
|
});
|
|
6929
6894
|
if (text && text.trim().length > 0) {
|
|
6930
6895
|
logInfo("image.prompt.enriched", {
|
|
@@ -9673,94 +9638,382 @@ async function listThreadReplies(input) {
|
|
|
9673
9638
|
}
|
|
9674
9639
|
return replies.slice(0, targetLimit);
|
|
9675
9640
|
}
|
|
9676
|
-
|
|
9677
|
-
|
|
9678
|
-
|
|
9679
|
-
|
|
9680
|
-
|
|
9681
|
-
|
|
9682
|
-
|
|
9683
|
-
|
|
9684
|
-
|
|
9685
|
-
|
|
9686
|
-
|
|
9687
|
-
}
|
|
9688
|
-
function parseSlackTimestampParam(field, value) {
|
|
9689
|
-
if (!value) {
|
|
9690
|
-
return { ok: true, value: void 0 };
|
|
9691
|
-
}
|
|
9692
|
-
const timestamp = parseSlackMessageTs(String(value));
|
|
9693
|
-
if (timestamp) {
|
|
9694
|
-
return { ok: true, value: timestamp };
|
|
9641
|
+
async function getConversationInfo(channelId) {
|
|
9642
|
+
const client = getSlackClient();
|
|
9643
|
+
const response = await withSlackRetries(
|
|
9644
|
+
() => client.conversations.info({
|
|
9645
|
+
channel: channelId
|
|
9646
|
+
}),
|
|
9647
|
+
3,
|
|
9648
|
+
{ action: "conversations.info", idempotent: true }
|
|
9649
|
+
);
|
|
9650
|
+
const channel = response.channel;
|
|
9651
|
+
if (!channel || typeof channel !== "object") {
|
|
9652
|
+
throw new Error(`Slack conversations.info returned no channel for ${channelId}`);
|
|
9695
9653
|
}
|
|
9654
|
+
const record2 = channel;
|
|
9696
9655
|
return {
|
|
9697
|
-
|
|
9698
|
-
|
|
9656
|
+
id: channelId,
|
|
9657
|
+
...typeof record2.name === "string" && record2.name ? { name: record2.name } : {},
|
|
9658
|
+
isChannel: record2.is_channel === true,
|
|
9659
|
+
isPrivate: record2.is_private === true,
|
|
9660
|
+
isIm: record2.is_im === true,
|
|
9661
|
+
isMpim: record2.is_mpim === true,
|
|
9662
|
+
...typeof record2.is_member === "boolean" ? { isMember: record2.is_member } : {}
|
|
9699
9663
|
};
|
|
9700
9664
|
}
|
|
9701
|
-
function
|
|
9702
|
-
const
|
|
9703
|
-
|
|
9704
|
-
|
|
9665
|
+
async function joinPublicChannel(channelId) {
|
|
9666
|
+
const client = getSlackClient();
|
|
9667
|
+
await withSlackRetries(
|
|
9668
|
+
() => client.conversations.join({
|
|
9669
|
+
channel: channelId
|
|
9670
|
+
}),
|
|
9671
|
+
3,
|
|
9672
|
+
{ action: "conversations.join", idempotent: true }
|
|
9673
|
+
);
|
|
9674
|
+
}
|
|
9675
|
+
async function listPublicChannels(input = {}) {
|
|
9676
|
+
const client = getSlackClient();
|
|
9677
|
+
const targetLimit = Math.max(1, Math.min(input.limit ?? 1e3, 1e3));
|
|
9678
|
+
const maxPages = Math.max(1, Math.min(input.maxPages ?? 10, 20));
|
|
9679
|
+
const channels = [];
|
|
9680
|
+
let cursor;
|
|
9681
|
+
let pages = 0;
|
|
9682
|
+
while (channels.length < targetLimit && pages < maxPages) {
|
|
9683
|
+
pages += 1;
|
|
9684
|
+
const pageLimit = Math.max(1, Math.min(200, targetLimit - channels.length));
|
|
9685
|
+
const response = await withSlackRetries(
|
|
9686
|
+
() => client.conversations.list({
|
|
9687
|
+
types: "public_channel",
|
|
9688
|
+
exclude_archived: true,
|
|
9689
|
+
limit: pageLimit,
|
|
9690
|
+
cursor
|
|
9691
|
+
}),
|
|
9692
|
+
3,
|
|
9693
|
+
{ action: "conversations.list", idempotent: true }
|
|
9694
|
+
);
|
|
9695
|
+
const batch = response.channels ?? [];
|
|
9696
|
+
for (const item of batch) {
|
|
9697
|
+
if (typeof item.id !== "string" || !item.id) {
|
|
9698
|
+
continue;
|
|
9699
|
+
}
|
|
9700
|
+
if (item.is_private === true) {
|
|
9701
|
+
continue;
|
|
9702
|
+
}
|
|
9703
|
+
channels.push({
|
|
9704
|
+
id: item.id,
|
|
9705
|
+
...typeof item.name === "string" && item.name ? { name: item.name } : {},
|
|
9706
|
+
...typeof item.is_member === "boolean" ? { isMember: item.is_member } : {},
|
|
9707
|
+
...typeof item.is_archived === "boolean" ? { isArchived: item.is_archived } : {}
|
|
9708
|
+
});
|
|
9709
|
+
}
|
|
9710
|
+
cursor = response.response_metadata?.next_cursor || void 0;
|
|
9711
|
+
if (!cursor) {
|
|
9712
|
+
break;
|
|
9713
|
+
}
|
|
9705
9714
|
}
|
|
9706
|
-
return
|
|
9707
|
-
ok: false,
|
|
9708
|
-
error: `Invalid \`${field}\` Slack timestamp. Use a numeric Slack ts like \`1712345678.123456\`.`
|
|
9709
|
-
};
|
|
9715
|
+
return channels.slice(0, targetLimit);
|
|
9710
9716
|
}
|
|
9711
|
-
|
|
9712
|
-
|
|
9713
|
-
|
|
9714
|
-
|
|
9715
|
-
(value) => value === "true" ? true : value === "false" ? false : value,
|
|
9716
|
-
z36.boolean()
|
|
9717
|
-
).describe(description);
|
|
9718
|
-
function normalizeRangeTimestamp(field, value, targetChannelId) {
|
|
9719
|
-
if (value === void 0) {
|
|
9720
|
-
return { ok: true, value: void 0 };
|
|
9717
|
+
async function resolvePublicChannelByName(channelName) {
|
|
9718
|
+
const normalized = channelName.trim().replace(/^#/, "").toLowerCase();
|
|
9719
|
+
if (!normalized) {
|
|
9720
|
+
return void 0;
|
|
9721
9721
|
}
|
|
9722
|
-
const
|
|
9723
|
-
|
|
9724
|
-
|
|
9722
|
+
const channels = await listPublicChannels();
|
|
9723
|
+
return channels.find(
|
|
9724
|
+
(channel) => channel.name?.trim().toLowerCase() === normalized
|
|
9725
|
+
);
|
|
9726
|
+
}
|
|
9727
|
+
|
|
9728
|
+
// src/chat/slack/tool-support/channel-access.ts
|
|
9729
|
+
var DENIED_PRIVATE = "Cannot read this Slack conversation because it is private. Only the current conversation or public channels are readable.";
|
|
9730
|
+
var DENIED_NOT_FOUND = "Cannot read this Slack conversation because the channel was not found or the bot cannot see it.";
|
|
9731
|
+
var DENIED_NOT_IN_CHANNEL = "Cannot read this Slack conversation because the bot is not in the channel.";
|
|
9732
|
+
var DENIED_MISSING_SCOPE = "Cannot verify Slack channel access because this installation is missing channel read scopes.";
|
|
9733
|
+
function deny(reason, error) {
|
|
9734
|
+
return { allowed: false, reason, error };
|
|
9735
|
+
}
|
|
9736
|
+
async function checkSlackChannelReadAccess(args) {
|
|
9737
|
+
const currentChannels = args.currentChannelIds.filter(
|
|
9738
|
+
(channelId) => Boolean(channelId)
|
|
9739
|
+
);
|
|
9740
|
+
if (currentChannels.includes(args.targetChannelId)) {
|
|
9741
|
+
return { allowed: true, isMember: true };
|
|
9725
9742
|
}
|
|
9726
|
-
const
|
|
9727
|
-
|
|
9728
|
-
|
|
9743
|
+
const visibility = await getConversationStore().getDestinationVisibility({
|
|
9744
|
+
provider: "slack",
|
|
9745
|
+
providerTenantId: args.teamId,
|
|
9746
|
+
providerDestinationId: args.targetChannelId
|
|
9747
|
+
});
|
|
9748
|
+
if (visibility === "private") {
|
|
9749
|
+
return deny("private", DENIED_PRIVATE);
|
|
9729
9750
|
}
|
|
9730
|
-
|
|
9731
|
-
|
|
9732
|
-
|
|
9733
|
-
if (
|
|
9734
|
-
return
|
|
9751
|
+
try {
|
|
9752
|
+
const info = await getConversationInfo(args.targetChannelId);
|
|
9753
|
+
const isPublicChannel = info.isChannel && !info.isPrivate && !info.isIm && !info.isMpim;
|
|
9754
|
+
if (!isPublicChannel) {
|
|
9755
|
+
return deny("private", DENIED_PRIVATE);
|
|
9756
|
+
}
|
|
9757
|
+
return {
|
|
9758
|
+
allowed: true,
|
|
9759
|
+
isPublic: true,
|
|
9760
|
+
...info.name ? { channelName: info.name } : {},
|
|
9761
|
+
...typeof info.isMember === "boolean" ? { isMember: info.isMember } : {}
|
|
9762
|
+
};
|
|
9763
|
+
} catch (error) {
|
|
9764
|
+
if (error instanceof SlackActionError) {
|
|
9765
|
+
if (error.code === "not_found") {
|
|
9766
|
+
return deny("not_found", DENIED_NOT_FOUND);
|
|
9767
|
+
}
|
|
9768
|
+
if (error.code === "not_in_channel") {
|
|
9769
|
+
return deny("not_in_channel", DENIED_NOT_IN_CHANNEL);
|
|
9770
|
+
}
|
|
9771
|
+
if (error.code === "missing_scope") {
|
|
9772
|
+
return deny("missing_scope", DENIED_MISSING_SCOPE);
|
|
9773
|
+
}
|
|
9735
9774
|
}
|
|
9775
|
+
throw error;
|
|
9736
9776
|
}
|
|
9737
|
-
return timestamp;
|
|
9738
9777
|
}
|
|
9739
|
-
function
|
|
9740
|
-
|
|
9741
|
-
|
|
9742
|
-
|
|
9743
|
-
|
|
9744
|
-
|
|
9745
|
-
|
|
9746
|
-
|
|
9747
|
-
|
|
9778
|
+
async function joinPublicChannelForRead(args) {
|
|
9779
|
+
try {
|
|
9780
|
+
await joinPublicChannel(args.targetChannelId);
|
|
9781
|
+
return {
|
|
9782
|
+
ok: true,
|
|
9783
|
+
...args.channelName ? { channelName: args.channelName } : {}
|
|
9784
|
+
};
|
|
9785
|
+
} catch (error) {
|
|
9786
|
+
if (error instanceof SlackActionError) {
|
|
9787
|
+
if (error.code === "missing_scope") {
|
|
9788
|
+
return {
|
|
9789
|
+
ok: false,
|
|
9790
|
+
reason: "missing_scope",
|
|
9791
|
+
error: "Cannot join this public Slack channel because this installation is missing the `channels:join` scope."
|
|
9792
|
+
};
|
|
9793
|
+
}
|
|
9794
|
+
if (error.code === "not_found") {
|
|
9795
|
+
return {
|
|
9796
|
+
ok: false,
|
|
9797
|
+
reason: "not_found",
|
|
9798
|
+
error: DENIED_NOT_FOUND
|
|
9799
|
+
};
|
|
9800
|
+
}
|
|
9801
|
+
if (error.apiError === "method_not_supported_for_channel_type" || error.apiError === "is_archived" || error.apiError === "cant_invite_self") {
|
|
9802
|
+
return {
|
|
9803
|
+
ok: false,
|
|
9804
|
+
reason: "private",
|
|
9805
|
+
error: DENIED_PRIVATE
|
|
9806
|
+
};
|
|
9807
|
+
}
|
|
9808
|
+
return {
|
|
9809
|
+
ok: false,
|
|
9810
|
+
reason: "not_in_channel",
|
|
9811
|
+
error: "Could not join this public Slack channel. Ask an admin to add the bot, then retry."
|
|
9812
|
+
};
|
|
9813
|
+
}
|
|
9814
|
+
throw error;
|
|
9815
|
+
}
|
|
9816
|
+
}
|
|
9817
|
+
|
|
9818
|
+
// src/chat/slack/tool-support/channel-target.ts
|
|
9819
|
+
import { z as z35 } from "zod";
|
|
9820
|
+
var slackChannelRefParam = z35.string().trim().min(1).max(80).describe("Slack channel ID or public channel name.");
|
|
9821
|
+
async function resolveSlackChannelRef(input) {
|
|
9822
|
+
const trimmed = input.value.trim();
|
|
9823
|
+
if (!trimmed) {
|
|
9824
|
+
throw new ToolInputError(
|
|
9825
|
+
`Invalid \`${input.field}\`. Provide a Slack channel id like \`C123\` or a public channel name like \`#proj-foo\`.`
|
|
9826
|
+
);
|
|
9827
|
+
}
|
|
9828
|
+
const channelId = parseSlackChannelId(trimmed);
|
|
9829
|
+
if (channelId) {
|
|
9830
|
+
return {
|
|
9831
|
+
channelId,
|
|
9832
|
+
resolvedFromName: false
|
|
9833
|
+
};
|
|
9834
|
+
}
|
|
9835
|
+
const match = await resolvePublicChannelByName(trimmed);
|
|
9836
|
+
if (!match) {
|
|
9837
|
+
throw new ToolInputError(
|
|
9838
|
+
`No public Slack channel named \`${trimmed}\` was found. Use an exact public channel name or a channel id.`
|
|
9839
|
+
);
|
|
9840
|
+
}
|
|
9841
|
+
return {
|
|
9842
|
+
channelId: match.id,
|
|
9843
|
+
...match.name ? { channelName: match.name } : {},
|
|
9844
|
+
resolvedFromName: true
|
|
9845
|
+
};
|
|
9846
|
+
}
|
|
9847
|
+
async function resolveOptionalSlackChannelRef(input) {
|
|
9848
|
+
if (input.value !== void 0) {
|
|
9849
|
+
return resolveSlackChannelRef({
|
|
9850
|
+
field: input.field ?? "channel_id",
|
|
9851
|
+
value: input.value
|
|
9852
|
+
});
|
|
9853
|
+
}
|
|
9854
|
+
if (input.defaultChannelId) {
|
|
9855
|
+
return {
|
|
9856
|
+
channelId: input.defaultChannelId,
|
|
9857
|
+
resolvedFromName: false
|
|
9858
|
+
};
|
|
9859
|
+
}
|
|
9860
|
+
throw new ToolInputError(
|
|
9861
|
+
"Provide `channel_id`, or use this tool in an active Slack channel context."
|
|
9862
|
+
);
|
|
9863
|
+
}
|
|
9864
|
+
|
|
9865
|
+
// src/chat/slack/tools/channel-join.ts
|
|
9866
|
+
import { z as z36 } from "zod";
|
|
9867
|
+
function createSlackChannelJoinTool(context) {
|
|
9868
|
+
return zodTool({
|
|
9869
|
+
description: "Join a public Slack channel.",
|
|
9870
|
+
annotations: {
|
|
9871
|
+
destructiveHint: false,
|
|
9872
|
+
idempotentHint: false,
|
|
9873
|
+
openWorldHint: true,
|
|
9874
|
+
readOnlyHint: false
|
|
9875
|
+
},
|
|
9748
9876
|
inputSchema: z36.object({
|
|
9749
|
-
|
|
9750
|
-
|
|
9751
|
-
|
|
9752
|
-
|
|
9753
|
-
|
|
9754
|
-
|
|
9755
|
-
|
|
9756
|
-
)
|
|
9877
|
+
channel_id: slackChannelRefParam
|
|
9878
|
+
}),
|
|
9879
|
+
outputSchema: juniorToolOutputSchema,
|
|
9880
|
+
execute: async ({ channel_id }) => {
|
|
9881
|
+
const target = await resolveSlackChannelRef({
|
|
9882
|
+
field: "channel_id",
|
|
9883
|
+
value: channel_id
|
|
9884
|
+
});
|
|
9885
|
+
const access = await checkSlackChannelReadAccess({
|
|
9886
|
+
currentChannelIds: [
|
|
9887
|
+
context.destinationChannelId,
|
|
9888
|
+
context.sourceChannelId
|
|
9889
|
+
],
|
|
9890
|
+
targetChannelId: target.channelId,
|
|
9891
|
+
teamId: context.teamId
|
|
9892
|
+
});
|
|
9893
|
+
if (!access.allowed) {
|
|
9894
|
+
throw new ToolInputError(access.error);
|
|
9895
|
+
}
|
|
9896
|
+
if (access.isMember === true) {
|
|
9897
|
+
return {
|
|
9898
|
+
channel_id: target.channelId,
|
|
9899
|
+
...access.channelName || target.channelName ? { channel_name: access.channelName ?? target.channelName } : {},
|
|
9900
|
+
joined: false,
|
|
9901
|
+
already_member: true
|
|
9902
|
+
};
|
|
9903
|
+
}
|
|
9904
|
+
try {
|
|
9905
|
+
await joinPublicChannel(target.channelId);
|
|
9906
|
+
} catch (error) {
|
|
9907
|
+
if (error instanceof SlackActionError) {
|
|
9908
|
+
if (error.code === "missing_scope") {
|
|
9909
|
+
throw new ToolInputError(
|
|
9910
|
+
"Cannot join this public Slack channel because this installation is missing the `channels:join` scope.",
|
|
9911
|
+
{ cause: error }
|
|
9912
|
+
);
|
|
9913
|
+
}
|
|
9914
|
+
throw new ToolInputError(
|
|
9915
|
+
"Could not join this public Slack channel. Confirm it is public and retry, or ask an admin to add the bot.",
|
|
9916
|
+
{ cause: error }
|
|
9917
|
+
);
|
|
9918
|
+
}
|
|
9919
|
+
throw error;
|
|
9920
|
+
}
|
|
9921
|
+
return {
|
|
9922
|
+
channel_id: target.channelId,
|
|
9923
|
+
...access.channelName || target.channelName ? { channel_name: access.channelName ?? target.channelName } : {},
|
|
9924
|
+
joined: true,
|
|
9925
|
+
already_member: false
|
|
9926
|
+
};
|
|
9927
|
+
}
|
|
9928
|
+
});
|
|
9929
|
+
}
|
|
9930
|
+
|
|
9931
|
+
// src/chat/slack/timestamp-param.ts
|
|
9932
|
+
import { z as z37 } from "zod";
|
|
9933
|
+
function slackTimestampParam(description) {
|
|
9934
|
+
return z37.preprocess(
|
|
9935
|
+
(value) => typeof value === "number" && Number.isFinite(value) ? String(value) : value,
|
|
9936
|
+
z37.string().min(1)
|
|
9937
|
+
).describe(description);
|
|
9938
|
+
}
|
|
9939
|
+
function parseSlackTimestampParam(field, value) {
|
|
9940
|
+
if (!value) {
|
|
9941
|
+
return { ok: true, value: void 0 };
|
|
9942
|
+
}
|
|
9943
|
+
const timestamp = parseSlackMessageTs(String(value));
|
|
9944
|
+
if (timestamp) {
|
|
9945
|
+
return { ok: true, value: timestamp };
|
|
9946
|
+
}
|
|
9947
|
+
return {
|
|
9948
|
+
ok: false,
|
|
9949
|
+
error: `Invalid \`${field}\` Slack timestamp. Use a numeric Slack ts like \`1712345678.123456\`.`
|
|
9950
|
+
};
|
|
9951
|
+
}
|
|
9952
|
+
function parseRequiredSlackTimestampParam(field, value) {
|
|
9953
|
+
const timestamp = parseSlackMessageTs(String(value));
|
|
9954
|
+
if (timestamp) {
|
|
9955
|
+
return { ok: true, value: timestamp };
|
|
9956
|
+
}
|
|
9957
|
+
return {
|
|
9958
|
+
ok: false,
|
|
9959
|
+
error: `Invalid \`${field}\` Slack timestamp. Use a numeric Slack ts like \`1712345678.123456\`.`
|
|
9960
|
+
};
|
|
9961
|
+
}
|
|
9962
|
+
|
|
9963
|
+
// src/chat/slack/tools/channel-list-messages.ts
|
|
9964
|
+
import { z as z38 } from "zod";
|
|
9965
|
+
var booleanInput2 = (description) => z38.preprocess(
|
|
9966
|
+
(value) => value === "true" ? true : value === "false" ? false : value,
|
|
9967
|
+
z38.boolean()
|
|
9968
|
+
).describe(description);
|
|
9969
|
+
function normalizeRangeTimestamp(field, value, targetChannelId) {
|
|
9970
|
+
if (value === void 0) {
|
|
9971
|
+
return { ok: true, value: void 0 };
|
|
9972
|
+
}
|
|
9973
|
+
const trimmed = String(value).trim();
|
|
9974
|
+
if (!trimmed) {
|
|
9975
|
+
return parseSlackTimestampParam(field, value);
|
|
9976
|
+
}
|
|
9977
|
+
const timestamp = parseSlackTimestampParam(field, trimmed);
|
|
9978
|
+
if (timestamp.ok && timestamp.value) {
|
|
9979
|
+
return timestamp;
|
|
9980
|
+
}
|
|
9981
|
+
const threadId = parseSlackThreadId(trimmed);
|
|
9982
|
+
const threadTimestamp = threadId ? parseSlackTimestampParam(field, threadId.threadTs) : void 0;
|
|
9983
|
+
if (threadId && threadTimestamp?.ok && threadTimestamp.value) {
|
|
9984
|
+
if (threadId.channelId === targetChannelId) {
|
|
9985
|
+
return threadTimestamp;
|
|
9986
|
+
}
|
|
9987
|
+
}
|
|
9988
|
+
return timestamp;
|
|
9989
|
+
}
|
|
9990
|
+
function createSlackChannelListMessagesTool(context) {
|
|
9991
|
+
return zodTool({
|
|
9992
|
+
description: "List messages from Slack channel history. Defaults to the active channel. Pass `channel_id` to read another public channel.",
|
|
9993
|
+
annotations: {
|
|
9994
|
+
destructiveHint: false,
|
|
9995
|
+
idempotentHint: true,
|
|
9996
|
+
openWorldHint: true,
|
|
9997
|
+
readOnlyHint: true
|
|
9998
|
+
},
|
|
9999
|
+
inputSchema: z38.object({
|
|
10000
|
+
channel_id: slackChannelRefParam.optional(),
|
|
10001
|
+
limit: z38.coerce.number().int().min(1).max(1e3).describe("Maximum number of messages to return across pages.").optional(),
|
|
10002
|
+
cursor: z38.string().min(1).describe("Optional cursor to continue from a prior call.").optional(),
|
|
10003
|
+
oldest: slackTimestampParam(
|
|
10004
|
+
"Oldest message timestamp (Slack ts) for range filtering."
|
|
10005
|
+
).optional(),
|
|
10006
|
+
latest: slackTimestampParam(
|
|
10007
|
+
"Latest message timestamp (Slack ts) for range filtering."
|
|
10008
|
+
).optional(),
|
|
9757
10009
|
inclusive: booleanInput2(
|
|
9758
10010
|
"Whether oldest/latest bounds should be inclusive."
|
|
9759
10011
|
).optional(),
|
|
9760
|
-
max_pages:
|
|
10012
|
+
max_pages: z38.coerce.number().int().min(1).max(10).describe("Maximum number of API pages to traverse in a single call.").optional()
|
|
9761
10013
|
}),
|
|
9762
10014
|
outputSchema: juniorToolOutputSchema,
|
|
9763
10015
|
execute: async ({
|
|
10016
|
+
channel_id,
|
|
9764
10017
|
limit,
|
|
9765
10018
|
cursor,
|
|
9766
10019
|
oldest,
|
|
@@ -9768,9 +10021,22 @@ function createSlackChannelListMessagesTool(context) {
|
|
|
9768
10021
|
inclusive,
|
|
9769
10022
|
max_pages
|
|
9770
10023
|
}) => {
|
|
9771
|
-
const
|
|
9772
|
-
|
|
9773
|
-
|
|
10024
|
+
const target = await resolveOptionalSlackChannelRef({
|
|
10025
|
+
field: "channel_id",
|
|
10026
|
+
value: channel_id,
|
|
10027
|
+
defaultChannelId: context.destinationChannelId
|
|
10028
|
+
});
|
|
10029
|
+
const targetChannelId = target.channelId;
|
|
10030
|
+
const access = await checkSlackChannelReadAccess({
|
|
10031
|
+
currentChannelIds: [
|
|
10032
|
+
context.destinationChannelId,
|
|
10033
|
+
context.sourceChannelId
|
|
10034
|
+
],
|
|
10035
|
+
targetChannelId,
|
|
10036
|
+
teamId: context.teamId
|
|
10037
|
+
});
|
|
10038
|
+
if (!access.allowed) {
|
|
10039
|
+
throw new ToolInputError(access.error);
|
|
9774
10040
|
}
|
|
9775
10041
|
const normalizedOldest = normalizeRangeTimestamp(
|
|
9776
10042
|
"oldest",
|
|
@@ -9788,39 +10054,84 @@ function createSlackChannelListMessagesTool(context) {
|
|
|
9788
10054
|
if (!normalizedLatest.ok) {
|
|
9789
10055
|
throw new ToolInputError(normalizedLatest.error);
|
|
9790
10056
|
}
|
|
10057
|
+
const readHistory = async () => listChannelMessages({
|
|
10058
|
+
channelId: targetChannelId,
|
|
10059
|
+
limit: limit ?? 100,
|
|
10060
|
+
cursor,
|
|
10061
|
+
oldest: normalizedOldest.value,
|
|
10062
|
+
latest: normalizedLatest.value,
|
|
10063
|
+
inclusive,
|
|
10064
|
+
maxPages: max_pages
|
|
10065
|
+
});
|
|
9791
10066
|
let result;
|
|
10067
|
+
let joined = false;
|
|
10068
|
+
let channelName = access.channelName ?? target.channelName;
|
|
10069
|
+
let readError;
|
|
9792
10070
|
try {
|
|
9793
|
-
result = await
|
|
9794
|
-
channelId: targetChannelId,
|
|
9795
|
-
limit: limit ?? 100,
|
|
9796
|
-
cursor,
|
|
9797
|
-
oldest: normalizedOldest.value,
|
|
9798
|
-
latest: normalizedLatest.value,
|
|
9799
|
-
inclusive,
|
|
9800
|
-
maxPages: max_pages
|
|
9801
|
-
});
|
|
10071
|
+
result = await readHistory();
|
|
9802
10072
|
} catch (error) {
|
|
10073
|
+
readError = error;
|
|
10074
|
+
const canJoin = error instanceof SlackActionError && error.code === "not_in_channel" && access.isMember !== true;
|
|
10075
|
+
if (canJoin) {
|
|
10076
|
+
const joinResult = await joinPublicChannelForRead({
|
|
10077
|
+
channelName,
|
|
10078
|
+
targetChannelId
|
|
10079
|
+
});
|
|
10080
|
+
if (!joinResult.ok) {
|
|
10081
|
+
throw new ToolInputError(joinResult.error);
|
|
10082
|
+
}
|
|
10083
|
+
joined = true;
|
|
10084
|
+
channelName = joinResult.channelName ?? channelName;
|
|
10085
|
+
try {
|
|
10086
|
+
result = await readHistory();
|
|
10087
|
+
readError = void 0;
|
|
10088
|
+
} catch (retryError) {
|
|
10089
|
+
readError = retryError;
|
|
10090
|
+
}
|
|
10091
|
+
}
|
|
10092
|
+
}
|
|
10093
|
+
if (!result) {
|
|
10094
|
+
const error = readError;
|
|
9803
10095
|
if (error instanceof SlackActionError && error.apiError === "invalid_cursor") {
|
|
9804
10096
|
throw new ToolInputError(
|
|
9805
10097
|
"The supplied Slack history cursor is no longer valid. Retry the lookup without `cursor` to start from the newest page again.",
|
|
9806
10098
|
{ cause: error }
|
|
9807
10099
|
);
|
|
9808
10100
|
}
|
|
10101
|
+
if (error instanceof SlackActionError) {
|
|
10102
|
+
if (error.code === "not_in_channel") {
|
|
10103
|
+
throw new ToolInputError(
|
|
10104
|
+
"Could not read this Slack channel history because the bot is not in the channel.",
|
|
10105
|
+
{ cause: error }
|
|
10106
|
+
);
|
|
10107
|
+
}
|
|
10108
|
+
if (error.code === "missing_scope") {
|
|
10109
|
+
throw new ToolInputError(
|
|
10110
|
+
"Could not read this Slack channel history because this installation is missing history scopes.",
|
|
10111
|
+
{ cause: error }
|
|
10112
|
+
);
|
|
10113
|
+
}
|
|
10114
|
+
throw new ToolInputError(
|
|
10115
|
+
"Could not read this Slack channel history.",
|
|
10116
|
+
{ cause: error }
|
|
10117
|
+
);
|
|
10118
|
+
}
|
|
9809
10119
|
throw error;
|
|
9810
10120
|
}
|
|
9811
|
-
|
|
10121
|
+
return {
|
|
9812
10122
|
channel_id: targetChannelId,
|
|
10123
|
+
...channelName ? { channel_name: channelName } : {},
|
|
10124
|
+
...joined ? { joined_channel: true } : {},
|
|
9813
10125
|
count: result.messages.length,
|
|
9814
10126
|
messages: result.messages,
|
|
9815
10127
|
...result.nextCursor ? { next_cursor: result.nextCursor } : {}
|
|
9816
10128
|
};
|
|
9817
|
-
return summary;
|
|
9818
10129
|
}
|
|
9819
10130
|
});
|
|
9820
10131
|
}
|
|
9821
10132
|
|
|
9822
10133
|
// src/chat/slack/tools/conversation-message-search.ts
|
|
9823
|
-
import { z as
|
|
10134
|
+
import { z as z39 } from "zod";
|
|
9824
10135
|
|
|
9825
10136
|
// src/chat/conversations/tool-source.ts
|
|
9826
10137
|
var CONVERSATIONS_TOOL_SOURCE = {
|
|
@@ -9831,35 +10142,32 @@ var CONVERSATIONS_TOOL_SOURCE = {
|
|
|
9831
10142
|
// src/chat/slack/tools/conversation-message-search.ts
|
|
9832
10143
|
var DEFAULT_LIMIT = 5;
|
|
9833
10144
|
var conversationMessageSearchOutputSchema = juniorToolOutputSchema.extend({
|
|
9834
|
-
channel_id:
|
|
9835
|
-
count:
|
|
9836
|
-
query:
|
|
9837
|
-
matches:
|
|
9838
|
-
|
|
9839
|
-
channel_id:
|
|
9840
|
-
channel_name:
|
|
9841
|
-
conversation_id:
|
|
9842
|
-
excerpt:
|
|
9843
|
-
message_id:
|
|
9844
|
-
message_role:
|
|
9845
|
-
message_timestamp:
|
|
9846
|
-
permalink:
|
|
9847
|
-
thread_ts:
|
|
10145
|
+
channel_id: z39.string().min(1).optional(),
|
|
10146
|
+
count: z39.number().int().nonnegative(),
|
|
10147
|
+
query: z39.string().optional(),
|
|
10148
|
+
matches: z39.array(
|
|
10149
|
+
z39.object({
|
|
10150
|
+
channel_id: z39.string().min(1),
|
|
10151
|
+
channel_name: z39.string().min(1).optional(),
|
|
10152
|
+
conversation_id: z39.string().min(1),
|
|
10153
|
+
excerpt: z39.string(),
|
|
10154
|
+
message_id: z39.string().min(1),
|
|
10155
|
+
message_role: z39.enum(["assistant", "user"]),
|
|
10156
|
+
message_timestamp: z39.string().datetime(),
|
|
10157
|
+
permalink: z39.string().url().optional(),
|
|
10158
|
+
thread_ts: z39.string().min(1)
|
|
9848
10159
|
}).strict()
|
|
9849
10160
|
)
|
|
9850
10161
|
});
|
|
9851
|
-
function resolveSearchFilters(input) {
|
|
10162
|
+
async function resolveSearchFilters(input) {
|
|
9852
10163
|
const query = input.query?.trim() || void 0;
|
|
9853
10164
|
let channelId;
|
|
9854
|
-
if (input.channel_id != null) {
|
|
9855
|
-
const
|
|
9856
|
-
"channel_id",
|
|
9857
|
-
input.channel_id
|
|
9858
|
-
);
|
|
9859
|
-
|
|
9860
|
-
throw new ToolInputError(parsed.error);
|
|
9861
|
-
}
|
|
9862
|
-
channelId = parsed.value;
|
|
10165
|
+
if (input.channel_id != null && input.channel_id.trim() !== "") {
|
|
10166
|
+
const target = await resolveSlackChannelRef({
|
|
10167
|
+
field: "channel_id",
|
|
10168
|
+
value: input.channel_id
|
|
10169
|
+
});
|
|
10170
|
+
channelId = target.channelId;
|
|
9863
10171
|
}
|
|
9864
10172
|
if (!query && !channelId) {
|
|
9865
10173
|
throw new ToolInputError(
|
|
@@ -9871,9 +10179,9 @@ function resolveSearchFilters(input) {
|
|
|
9871
10179
|
...query ? { query } : {}
|
|
9872
10180
|
};
|
|
9873
10181
|
}
|
|
9874
|
-
function createSlackConversationMessageSearchTool(scope, currentConversationId
|
|
10182
|
+
function createSlackConversationMessageSearchTool(scope, currentConversationId) {
|
|
9875
10183
|
return zodTool({
|
|
9876
|
-
description: "Search retained user and assistant messages
|
|
10184
|
+
description: "Search retained user and assistant messages from public conversations in this Slack workspace. Excludes the current conversation. Not live Slack workspace search.",
|
|
9877
10185
|
exposure: "deferred",
|
|
9878
10186
|
source: CONVERSATIONS_TOOL_SOURCE,
|
|
9879
10187
|
annotations: {
|
|
@@ -9882,24 +10190,21 @@ function createSlackConversationMessageSearchTool(scope, currentConversationId,
|
|
|
9882
10190
|
openWorldHint: false,
|
|
9883
10191
|
readOnlyHint: true
|
|
9884
10192
|
},
|
|
9885
|
-
inputSchema:
|
|
9886
|
-
channel_id:
|
|
9887
|
-
|
|
9888
|
-
).nullable().optional()
|
|
9889
|
-
query: z37.string().trim().min(1).max(200).nullable().describe("Words or phrase to match in message text.").optional(),
|
|
9890
|
-
limit: z37.number().int().min(1).max(10).describe(`Maximum matches. Default ${DEFAULT_LIMIT}; max 10.`).nullable().optional()
|
|
10193
|
+
inputSchema: z39.object({
|
|
10194
|
+
channel_id: slackChannelRefParam.nullable().optional(),
|
|
10195
|
+
query: z39.string().trim().min(1).max(200).nullable().describe("Words or phrase to match in message text.").optional(),
|
|
10196
|
+
limit: z39.number().int().min(1).max(10).describe(`Maximum matches. Default ${DEFAULT_LIMIT}; max 10.`).nullable().optional()
|
|
9891
10197
|
}).strict(),
|
|
9892
10198
|
outputSchema: conversationMessageSearchOutputSchema,
|
|
9893
10199
|
execute: async (input) => {
|
|
9894
|
-
const filters = resolveSearchFilters(input);
|
|
9895
|
-
const store =
|
|
10200
|
+
const filters = await resolveSearchFilters(input);
|
|
10201
|
+
const store = getConversationMessageSearchStore();
|
|
9896
10202
|
const matches = await store.search({
|
|
9897
10203
|
currentConversationId,
|
|
9898
10204
|
filters,
|
|
9899
10205
|
limit: input.limit ?? DEFAULT_LIMIT,
|
|
9900
10206
|
scope
|
|
9901
10207
|
});
|
|
9902
|
-
const getPermalink = deps.getPermalink ?? getSlackMessagePermalink;
|
|
9903
10208
|
const matchesOutput = await Promise.all(
|
|
9904
10209
|
matches.map(async (match) => {
|
|
9905
10210
|
const reference = parseSlackThreadId(match.conversationId);
|
|
@@ -9908,7 +10213,7 @@ function createSlackConversationMessageSearchTool(scope, currentConversationId,
|
|
|
9908
10213
|
"Stored Slack conversation search returned an invalid destination"
|
|
9909
10214
|
);
|
|
9910
10215
|
}
|
|
9911
|
-
const permalink = await
|
|
10216
|
+
const permalink = await getSlackMessagePermalink({
|
|
9912
10217
|
channelId: reference.channelId,
|
|
9913
10218
|
messageTs: reference.threadTs
|
|
9914
10219
|
});
|
|
@@ -9936,35 +10241,238 @@ function createSlackConversationMessageSearchTool(scope, currentConversationId,
|
|
|
9936
10241
|
}
|
|
9937
10242
|
|
|
9938
10243
|
// src/chat/slack/tools/public-search.ts
|
|
9939
|
-
import { z as
|
|
10244
|
+
import { z as z40 } from "zod";
|
|
9940
10245
|
var DEFAULT_LIMIT2 = 10;
|
|
9941
|
-
var
|
|
9942
|
-
|
|
9943
|
-
|
|
9944
|
-
)
|
|
9945
|
-
|
|
9946
|
-
|
|
9947
|
-
|
|
9948
|
-
|
|
9949
|
-
|
|
9950
|
-
|
|
9951
|
-
|
|
9952
|
-
|
|
9953
|
-
|
|
10246
|
+
var DEFAULT_CONTENT_TYPES = ["messages"];
|
|
10247
|
+
var CONTENT_TYPES = ["messages", "files", "channels", "users"];
|
|
10248
|
+
var unixTimestampParam = z40.coerce.number().int().nonnegative();
|
|
10249
|
+
function optionalUnixTimestampParam(description) {
|
|
10250
|
+
return z40.preprocess(
|
|
10251
|
+
(value) => typeof value === "string" && value.trim() === "" ? void 0 : value,
|
|
10252
|
+
unixTimestampParam.optional()
|
|
10253
|
+
).describe(description);
|
|
10254
|
+
}
|
|
10255
|
+
function normalizeOptionalUnixTimestamp(value) {
|
|
10256
|
+
if (value === void 0 || value === null) {
|
|
10257
|
+
return void 0;
|
|
10258
|
+
}
|
|
10259
|
+
if (typeof value === "string" && value.trim() === "") {
|
|
10260
|
+
return void 0;
|
|
10261
|
+
}
|
|
10262
|
+
return unixTimestampParam.parse(value);
|
|
10263
|
+
}
|
|
10264
|
+
var searchMessageSchema = z40.object({
|
|
10265
|
+
author_name: z40.string().min(1).optional().describe("Author display name."),
|
|
10266
|
+
author_user_id: z40.string().min(1).optional().describe("Author user ID."),
|
|
10267
|
+
channel_id: z40.string().min(1).describe("Channel ID."),
|
|
10268
|
+
channel_name: z40.string().min(1).optional().describe("Channel name."),
|
|
10269
|
+
message_ts: z40.string().min(1).describe("Message timestamp."),
|
|
10270
|
+
content: z40.string().describe("Message text."),
|
|
10271
|
+
is_author_bot: z40.boolean().optional().describe("Whether the author is a bot."),
|
|
10272
|
+
permalink: z40.string().url().describe("Message permalink.")
|
|
10273
|
+
});
|
|
10274
|
+
var searchFileSchema = z40.object({
|
|
10275
|
+
file_id: z40.string().min(1).describe("File ID."),
|
|
10276
|
+
title: z40.string().min(1).optional().describe("File title."),
|
|
10277
|
+
name: z40.string().min(1).optional().describe("File name."),
|
|
10278
|
+
filetype: z40.string().min(1).optional().describe("File type."),
|
|
10279
|
+
user_id: z40.string().min(1).optional().describe("Uploader user ID."),
|
|
10280
|
+
user_name: z40.string().min(1).optional().describe("Uploader user name."),
|
|
10281
|
+
channel_id: z40.string().min(1).optional().describe("Channel ID."),
|
|
10282
|
+
channel_name: z40.string().min(1).optional().describe("Channel name."),
|
|
10283
|
+
permalink: z40.string().url().optional().describe("File permalink."),
|
|
10284
|
+
content: z40.string().min(1).optional().describe("File preview or content snippet.")
|
|
10285
|
+
});
|
|
10286
|
+
var searchChannelSchema = z40.object({
|
|
10287
|
+
channel_id: z40.string().min(1).describe("Channel ID."),
|
|
10288
|
+
channel_name: z40.string().min(1).optional().describe("Channel name."),
|
|
10289
|
+
is_private: z40.boolean().optional().describe("Whether the channel is private."),
|
|
10290
|
+
is_member: z40.boolean().optional().describe("Whether the bot is a member."),
|
|
10291
|
+
topic: z40.string().min(1).optional().describe("Channel topic."),
|
|
10292
|
+
purpose: z40.string().min(1).optional().describe("Channel purpose."),
|
|
10293
|
+
permalink: z40.string().url().optional().describe("Channel permalink.")
|
|
10294
|
+
});
|
|
10295
|
+
var searchUserSchema = z40.object({
|
|
10296
|
+
user_id: z40.string().min(1).describe("User ID."),
|
|
10297
|
+
user_name: z40.string().min(1).optional().describe("Username."),
|
|
10298
|
+
real_name: z40.string().min(1).optional().describe("Real name."),
|
|
10299
|
+
display_name: z40.string().min(1).optional().describe("Display name."),
|
|
10300
|
+
title: z40.string().min(1).optional().describe("Profile title."),
|
|
10301
|
+
permalink: z40.string().url().optional().describe("Profile permalink.")
|
|
9954
10302
|
});
|
|
9955
10303
|
var publicSearchOutputSchema = juniorToolOutputSchema.extend({
|
|
9956
|
-
query:
|
|
9957
|
-
|
|
9958
|
-
|
|
9959
|
-
|
|
10304
|
+
query: z40.string().describe("Search query."),
|
|
10305
|
+
content_types: z40.array(z40.enum(CONTENT_TYPES)).describe("Content types included in the search."),
|
|
10306
|
+
count: z40.number().int().nonnegative().describe("Total matched results."),
|
|
10307
|
+
messages: z40.array(searchMessageSchema).describe("Matched messages."),
|
|
10308
|
+
files: z40.array(searchFileSchema).describe("Matched files."),
|
|
10309
|
+
channels: z40.array(searchChannelSchema).describe("Matched channels."),
|
|
10310
|
+
users: z40.array(searchUserSchema).describe("Matched users."),
|
|
10311
|
+
next_cursor: z40.string().min(1).optional().describe("Cursor for the next result page.")
|
|
9960
10312
|
});
|
|
9961
|
-
|
|
9962
|
-
|
|
9963
|
-
|
|
10313
|
+
var nonEmptyString = z40.string().trim().min(1);
|
|
10314
|
+
var optionalWireString = z40.preprocess((value) => {
|
|
10315
|
+
if (typeof value !== "string") {
|
|
10316
|
+
return void 0;
|
|
10317
|
+
}
|
|
10318
|
+
const trimmed = value.trim();
|
|
10319
|
+
return trimmed === "" ? void 0 : trimmed;
|
|
10320
|
+
}, nonEmptyString.optional());
|
|
10321
|
+
var optionalWireUrl = z40.preprocess((value) => {
|
|
10322
|
+
if (typeof value !== "string") {
|
|
10323
|
+
return void 0;
|
|
10324
|
+
}
|
|
10325
|
+
const trimmed = value.trim();
|
|
10326
|
+
if (!trimmed) {
|
|
10327
|
+
return void 0;
|
|
10328
|
+
}
|
|
10329
|
+
try {
|
|
10330
|
+
new URL(trimmed);
|
|
10331
|
+
return trimmed;
|
|
10332
|
+
} catch {
|
|
10333
|
+
return void 0;
|
|
10334
|
+
}
|
|
10335
|
+
}, z40.string().url().optional());
|
|
10336
|
+
var optionalWireBoolean = z40.preprocess(
|
|
10337
|
+
(value) => typeof value === "boolean" ? value : void 0,
|
|
10338
|
+
z40.boolean().optional()
|
|
10339
|
+
);
|
|
10340
|
+
var slackSearchMessageWireSchema = z40.object({
|
|
10341
|
+
author_name: optionalWireString,
|
|
10342
|
+
author_user_id: optionalWireString,
|
|
10343
|
+
channel_id: nonEmptyString,
|
|
10344
|
+
channel_name: optionalWireString,
|
|
10345
|
+
message_ts: nonEmptyString,
|
|
10346
|
+
content: z40.string(),
|
|
10347
|
+
is_author_bot: optionalWireBoolean,
|
|
10348
|
+
permalink: z40.string().url()
|
|
10349
|
+
}).transform(
|
|
10350
|
+
(value) => ({
|
|
10351
|
+
channel_id: value.channel_id,
|
|
10352
|
+
message_ts: value.message_ts,
|
|
10353
|
+
content: value.content,
|
|
10354
|
+
permalink: value.permalink,
|
|
10355
|
+
...value.author_name ? { author_name: value.author_name } : {},
|
|
10356
|
+
...value.author_user_id ? { author_user_id: value.author_user_id } : {},
|
|
10357
|
+
...value.channel_name ? { channel_name: value.channel_name } : {},
|
|
10358
|
+
...value.is_author_bot !== void 0 ? { is_author_bot: value.is_author_bot } : {}
|
|
10359
|
+
})
|
|
10360
|
+
);
|
|
10361
|
+
var slackSearchFileWireSchema = z40.object({
|
|
10362
|
+
id: optionalWireString,
|
|
10363
|
+
file_id: optionalWireString,
|
|
10364
|
+
title: optionalWireString,
|
|
10365
|
+
name: optionalWireString,
|
|
10366
|
+
filetype: optionalWireString,
|
|
10367
|
+
file_type: optionalWireString,
|
|
10368
|
+
user: optionalWireString,
|
|
10369
|
+
user_id: optionalWireString,
|
|
10370
|
+
username: optionalWireString,
|
|
10371
|
+
user_name: optionalWireString,
|
|
10372
|
+
channel_id: optionalWireString,
|
|
10373
|
+
channel_name: optionalWireString,
|
|
10374
|
+
permalink: optionalWireUrl,
|
|
10375
|
+
content: optionalWireString,
|
|
10376
|
+
preview: optionalWireString
|
|
10377
|
+
}).transform((value) => {
|
|
10378
|
+
const fileId = value.file_id ?? value.id;
|
|
10379
|
+
if (!fileId) {
|
|
10380
|
+
return void 0;
|
|
10381
|
+
}
|
|
10382
|
+
return {
|
|
10383
|
+
file_id: fileId,
|
|
10384
|
+
...value.title ? { title: value.title } : {},
|
|
10385
|
+
...value.name ? { name: value.name } : {},
|
|
10386
|
+
...value.filetype ?? value.file_type ? { filetype: value.filetype ?? value.file_type } : {},
|
|
10387
|
+
...value.user_id ?? value.user ? { user_id: value.user_id ?? value.user } : {},
|
|
10388
|
+
...value.user_name ?? value.username ? { user_name: value.user_name ?? value.username } : {},
|
|
10389
|
+
...value.channel_id ? { channel_id: value.channel_id } : {},
|
|
10390
|
+
...value.channel_name ? { channel_name: value.channel_name } : {},
|
|
10391
|
+
...value.permalink ? { permalink: value.permalink } : {},
|
|
10392
|
+
...value.content ?? value.preview ? { content: value.content ?? value.preview } : {}
|
|
10393
|
+
};
|
|
10394
|
+
});
|
|
10395
|
+
var slackSearchChannelWireSchema = z40.object({
|
|
10396
|
+
id: optionalWireString,
|
|
10397
|
+
channel_id: optionalWireString,
|
|
10398
|
+
name: optionalWireString,
|
|
10399
|
+
channel_name: optionalWireString,
|
|
10400
|
+
is_private: optionalWireBoolean,
|
|
10401
|
+
is_member: optionalWireBoolean,
|
|
10402
|
+
topic: optionalWireString,
|
|
10403
|
+
purpose: optionalWireString,
|
|
10404
|
+
permalink: optionalWireUrl
|
|
10405
|
+
}).transform((value) => {
|
|
10406
|
+
const channelId = value.channel_id ?? value.id;
|
|
10407
|
+
if (!channelId) {
|
|
10408
|
+
return void 0;
|
|
10409
|
+
}
|
|
10410
|
+
return {
|
|
10411
|
+
channel_id: channelId,
|
|
10412
|
+
...value.channel_name ?? value.name ? { channel_name: value.channel_name ?? value.name } : {},
|
|
10413
|
+
...value.is_private !== void 0 ? { is_private: value.is_private } : {},
|
|
10414
|
+
...value.is_member !== void 0 ? { is_member: value.is_member } : {},
|
|
10415
|
+
...value.topic ? { topic: value.topic } : {},
|
|
10416
|
+
...value.purpose ? { purpose: value.purpose } : {},
|
|
10417
|
+
...value.permalink ? { permalink: value.permalink } : {}
|
|
10418
|
+
};
|
|
10419
|
+
});
|
|
10420
|
+
var slackSearchUserWireSchema = z40.object({
|
|
10421
|
+
id: optionalWireString,
|
|
10422
|
+
user_id: optionalWireString,
|
|
10423
|
+
name: optionalWireString,
|
|
10424
|
+
username: optionalWireString,
|
|
10425
|
+
user_name: optionalWireString,
|
|
10426
|
+
real_name: optionalWireString,
|
|
10427
|
+
display_name: optionalWireString,
|
|
10428
|
+
title: optionalWireString,
|
|
10429
|
+
permalink: optionalWireUrl
|
|
10430
|
+
}).transform((value) => {
|
|
10431
|
+
const userId = value.user_id ?? value.id;
|
|
10432
|
+
if (!userId) {
|
|
10433
|
+
return void 0;
|
|
10434
|
+
}
|
|
10435
|
+
return {
|
|
10436
|
+
user_id: userId,
|
|
10437
|
+
...value.user_name ?? value.name ?? value.username ? { user_name: value.user_name ?? value.name ?? value.username } : {},
|
|
10438
|
+
...value.real_name ? { real_name: value.real_name } : {},
|
|
10439
|
+
...value.display_name ? { display_name: value.display_name } : {},
|
|
10440
|
+
...value.title ? { title: value.title } : {},
|
|
10441
|
+
...value.permalink ? { permalink: value.permalink } : {}
|
|
10442
|
+
};
|
|
10443
|
+
});
|
|
10444
|
+
var slackSearchResponseSchema = z40.object({
|
|
10445
|
+
results: z40.object({
|
|
10446
|
+
messages: z40.array(z40.unknown()).default([]),
|
|
10447
|
+
files: z40.array(z40.unknown()).default([]),
|
|
10448
|
+
channels: z40.array(z40.unknown()).default([]),
|
|
10449
|
+
users: z40.array(z40.unknown()).default([]),
|
|
10450
|
+
// Slack often returns "" on the final page; omit rather than fail the parse.
|
|
10451
|
+
next_cursor: optionalWireString
|
|
10452
|
+
}).default({
|
|
10453
|
+
messages: [],
|
|
10454
|
+
files: [],
|
|
10455
|
+
channels: [],
|
|
10456
|
+
users: []
|
|
10457
|
+
})
|
|
10458
|
+
});
|
|
10459
|
+
function parseItems(values, schema) {
|
|
10460
|
+
const items = [];
|
|
10461
|
+
for (const value of values) {
|
|
10462
|
+
const parsed = schema.safeParse(value);
|
|
10463
|
+
if (parsed.success && parsed.data !== void 0) {
|
|
10464
|
+
items.push(parsed.data);
|
|
10465
|
+
}
|
|
10466
|
+
}
|
|
10467
|
+
return items;
|
|
9964
10468
|
}
|
|
9965
10469
|
function explicitSearchError(error) {
|
|
9966
10470
|
if (error.code === "missing_scope") {
|
|
9967
|
-
|
|
10471
|
+
const needed = error.needed?.trim();
|
|
10472
|
+
if (needed) {
|
|
10473
|
+
return `Public Slack search is unavailable because this installation is missing the \`${needed}\` scope.`;
|
|
10474
|
+
}
|
|
10475
|
+
return "Public Slack search is unavailable because this installation is missing a required search scope (`search:read.public`, and `search:read.files` / `search:read.users` when those content types are requested).";
|
|
9968
10476
|
}
|
|
9969
10477
|
if (error.code === "feature_unavailable") {
|
|
9970
10478
|
return "Public Slack search is not available for this Slack workspace or app installation.";
|
|
@@ -9974,33 +10482,33 @@ function explicitSearchError(error) {
|
|
|
9974
10482
|
}
|
|
9975
10483
|
return void 0;
|
|
9976
10484
|
}
|
|
10485
|
+
function normalizeContentTypes(contentTypes) {
|
|
10486
|
+
const selected = contentTypes?.length ? contentTypes : [...DEFAULT_CONTENT_TYPES];
|
|
10487
|
+
return [...new Set(selected)];
|
|
10488
|
+
}
|
|
9977
10489
|
function createSlackPublicSearchTool(actionToken) {
|
|
9978
10490
|
return zodTool({
|
|
9979
|
-
description: "Search public Slack
|
|
10491
|
+
description: "Search live public Slack content across the workspace. Defaults to messages; optionally include files, channels, or users. Private channels and DMs are never searched.",
|
|
9980
10492
|
annotations: {
|
|
9981
10493
|
destructiveHint: false,
|
|
9982
10494
|
idempotentHint: true,
|
|
9983
10495
|
openWorldHint: true,
|
|
9984
10496
|
readOnlyHint: true
|
|
9985
10497
|
},
|
|
9986
|
-
inputSchema:
|
|
9987
|
-
query:
|
|
9988
|
-
|
|
9989
|
-
),
|
|
9990
|
-
|
|
9991
|
-
|
|
9992
|
-
),
|
|
9993
|
-
|
|
9994
|
-
|
|
9995
|
-
),
|
|
9996
|
-
cursor: z38.string().min(1).describe("Cursor for the next result page.").optional(),
|
|
9997
|
-
limit: z38.coerce.number().int().min(1).max(20).describe("Maximum results to return; Slack allows at most 20.").optional(),
|
|
9998
|
-
sort: z38.enum(["score", "timestamp"]).describe("Rank by relevance or timestamp.").optional(),
|
|
9999
|
-
sort_dir: z38.enum(["asc", "desc"]).describe("Sort direction.").optional()
|
|
10498
|
+
inputSchema: z40.object({
|
|
10499
|
+
query: z40.string().trim().min(1).max(500).describe("Slack search query."),
|
|
10500
|
+
content_types: z40.array(z40.enum(CONTENT_TYPES)).min(1).max(4).describe("Content types to include. Defaults to messages.").optional(),
|
|
10501
|
+
after: optionalUnixTimestampParam("Unix timestamp lower bound."),
|
|
10502
|
+
before: optionalUnixTimestampParam("Unix timestamp upper bound."),
|
|
10503
|
+
cursor: z40.string().min(1).describe("Cursor for the next result page.").optional(),
|
|
10504
|
+
limit: z40.coerce.number().int().min(1).max(20).describe("Maximum results to return; Slack allows at most 20.").optional(),
|
|
10505
|
+
sort: z40.enum(["score", "timestamp"]).describe("Rank by relevance or timestamp.").optional(),
|
|
10506
|
+
sort_dir: z40.enum(["asc", "desc"]).describe("Sort direction.").optional()
|
|
10000
10507
|
}),
|
|
10001
10508
|
outputSchema: publicSearchOutputSchema,
|
|
10002
10509
|
execute: async ({
|
|
10003
10510
|
query,
|
|
10511
|
+
content_types,
|
|
10004
10512
|
after,
|
|
10005
10513
|
before,
|
|
10006
10514
|
cursor,
|
|
@@ -10008,36 +10516,63 @@ function createSlackPublicSearchTool(actionToken) {
|
|
|
10008
10516
|
sort,
|
|
10009
10517
|
sort_dir
|
|
10010
10518
|
}) => {
|
|
10519
|
+
if (!actionToken) {
|
|
10520
|
+
throw new ToolInputError(
|
|
10521
|
+
"Public Slack search needs a fresh interactive mention or DM. Slack only issues the short-lived action token on those turns, so resumes and scheduled runs cannot search the workspace. Ask again in a new message, or use channel history / thread read when you already know the channel."
|
|
10522
|
+
);
|
|
10523
|
+
}
|
|
10011
10524
|
try {
|
|
10012
|
-
const
|
|
10013
|
-
const
|
|
10014
|
-
const
|
|
10015
|
-
|
|
10016
|
-
|
|
10017
|
-
|
|
10018
|
-
|
|
10019
|
-
|
|
10020
|
-
|
|
10021
|
-
|
|
10022
|
-
|
|
10023
|
-
|
|
10024
|
-
|
|
10025
|
-
|
|
10026
|
-
|
|
10027
|
-
|
|
10028
|
-
|
|
10029
|
-
|
|
10030
|
-
|
|
10031
|
-
|
|
10032
|
-
|
|
10525
|
+
const normalizedContentTypes = normalizeContentTypes(content_types);
|
|
10526
|
+
const normalizedAfter = normalizeOptionalUnixTimestamp(after);
|
|
10527
|
+
const normalizedBefore = normalizeOptionalUnixTimestamp(before);
|
|
10528
|
+
const response = slackSearchResponseSchema.parse(
|
|
10529
|
+
await withSlackRetries(
|
|
10530
|
+
() => getSlackClient().apiCall("assistant.search.context", {
|
|
10531
|
+
action_token: actionToken,
|
|
10532
|
+
query,
|
|
10533
|
+
channel_types: ["public_channel"],
|
|
10534
|
+
content_types: normalizedContentTypes,
|
|
10535
|
+
include_bots: true,
|
|
10536
|
+
limit: limit ?? DEFAULT_LIMIT2,
|
|
10537
|
+
...normalizedAfter !== void 0 ? { after: normalizedAfter } : {},
|
|
10538
|
+
...normalizedBefore !== void 0 ? { before: normalizedBefore } : {},
|
|
10539
|
+
...cursor ? { cursor } : {},
|
|
10540
|
+
...sort ? { sort } : {},
|
|
10541
|
+
...sort_dir ? { sort_dir } : {}
|
|
10542
|
+
}),
|
|
10543
|
+
3,
|
|
10544
|
+
{
|
|
10545
|
+
action: "assistant.search.context",
|
|
10546
|
+
idempotent: true
|
|
10547
|
+
}
|
|
10548
|
+
)
|
|
10033
10549
|
);
|
|
10034
|
-
const messages = (
|
|
10035
|
-
|
|
10550
|
+
const messages = parseItems(
|
|
10551
|
+
response.results.messages,
|
|
10552
|
+
slackSearchMessageWireSchema
|
|
10553
|
+
);
|
|
10554
|
+
const files = parseItems(
|
|
10555
|
+
response.results.files,
|
|
10556
|
+
slackSearchFileWireSchema
|
|
10557
|
+
);
|
|
10558
|
+
const channels = parseItems(
|
|
10559
|
+
response.results.channels,
|
|
10560
|
+
slackSearchChannelWireSchema
|
|
10561
|
+
);
|
|
10562
|
+
const users = parseItems(
|
|
10563
|
+
response.results.users,
|
|
10564
|
+
slackSearchUserWireSchema
|
|
10565
|
+
);
|
|
10566
|
+
const count = messages.length + files.length + channels.length + users.length;
|
|
10036
10567
|
return {
|
|
10037
10568
|
query,
|
|
10038
|
-
|
|
10569
|
+
content_types: normalizedContentTypes,
|
|
10570
|
+
count,
|
|
10039
10571
|
messages,
|
|
10040
|
-
|
|
10572
|
+
files,
|
|
10573
|
+
channels,
|
|
10574
|
+
users,
|
|
10575
|
+
...response.results.next_cursor ? { next_cursor: response.results.next_cursor } : {}
|
|
10041
10576
|
};
|
|
10042
10577
|
} catch (error) {
|
|
10043
10578
|
if (error instanceof SlackActionError) {
|
|
@@ -10053,7 +10588,7 @@ function createSlackPublicSearchTool(actionToken) {
|
|
|
10053
10588
|
}
|
|
10054
10589
|
|
|
10055
10590
|
// src/chat/slack/tools/message-add-reaction.ts
|
|
10056
|
-
import { z as
|
|
10591
|
+
import { z as z41 } from "zod";
|
|
10057
10592
|
|
|
10058
10593
|
// src/chat/tools/idempotency.ts
|
|
10059
10594
|
function stableSerialize(value) {
|
|
@@ -10083,9 +10618,9 @@ function createSlackMessageAddReactionTool(context, state) {
|
|
|
10083
10618
|
openWorldHint: true,
|
|
10084
10619
|
readOnlyHint: false
|
|
10085
10620
|
},
|
|
10086
|
-
description: "Add an emoji reaction to the current inbound Slack message.
|
|
10087
|
-
inputSchema:
|
|
10088
|
-
emoji:
|
|
10621
|
+
description: "Add an emoji reaction to the current inbound Slack message.",
|
|
10622
|
+
inputSchema: z41.object({
|
|
10623
|
+
emoji: z41.string().min(1).max(64).describe(
|
|
10089
10624
|
"Slack emoji alias name to react with (for example `thumbsup`, `white_check_mark`, or `thumbsup::skin-tone-6`). Optional surrounding colons are allowed."
|
|
10090
10625
|
)
|
|
10091
10626
|
}),
|
|
@@ -10134,14 +10669,14 @@ function createSlackMessageAddReactionTool(context, state) {
|
|
|
10134
10669
|
|
|
10135
10670
|
// src/chat/slack/tools/send-files.ts
|
|
10136
10671
|
import { createHash as createHash4 } from "crypto";
|
|
10137
|
-
import { z as
|
|
10672
|
+
import { z as z42 } from "zod";
|
|
10138
10673
|
var sendFilesResultSchema = juniorToolOutputSchema.extend({
|
|
10139
|
-
target:
|
|
10140
|
-
channel_id:
|
|
10141
|
-
deduplicated:
|
|
10142
|
-
file_count:
|
|
10143
|
-
file_ids:
|
|
10144
|
-
thread_ts:
|
|
10674
|
+
target: z42.string().min(1),
|
|
10675
|
+
channel_id: z42.string().min(1),
|
|
10676
|
+
deduplicated: z42.boolean().optional(),
|
|
10677
|
+
file_count: z42.number().int().nonnegative(),
|
|
10678
|
+
file_ids: z42.array(z42.string().min(1)).optional(),
|
|
10679
|
+
thread_ts: z42.string().min(1)
|
|
10145
10680
|
});
|
|
10146
10681
|
function normalizeFiles(files) {
|
|
10147
10682
|
return files.map((file) => ({
|
|
@@ -10170,9 +10705,9 @@ function createSendFilesTool(context, state, materializeFile) {
|
|
|
10170
10705
|
openWorldHint: true,
|
|
10171
10706
|
readOnlyHint: false
|
|
10172
10707
|
},
|
|
10173
|
-
description: "Send one or more sandbox files into the active Slack conversation.
|
|
10174
|
-
inputSchema:
|
|
10175
|
-
files:
|
|
10708
|
+
description: "Send one or more sandbox files into the active Slack conversation.",
|
|
10709
|
+
inputSchema: z42.object({
|
|
10710
|
+
files: z42.array(sandboxFileReferenceSchema).min(1).describe(
|
|
10176
10711
|
"One or more existing sandbox files. Objects returned by imageGenerate or webFetch can be passed unchanged."
|
|
10177
10712
|
)
|
|
10178
10713
|
}),
|
|
@@ -10258,7 +10793,7 @@ function extractCanvasId(input) {
|
|
|
10258
10793
|
}
|
|
10259
10794
|
}
|
|
10260
10795
|
|
|
10261
|
-
// src/chat/slack/
|
|
10796
|
+
// src/chat/slack/tool-support/canvas/markdown.ts
|
|
10262
10797
|
function getListType(marker) {
|
|
10263
10798
|
return /^\d/.test(marker) ? "numbered" : "bullet";
|
|
10264
10799
|
}
|
|
@@ -10407,7 +10942,7 @@ function normalizeCanvasMarkdown(markdown) {
|
|
|
10407
10942
|
};
|
|
10408
10943
|
}
|
|
10409
10944
|
|
|
10410
|
-
// src/chat/slack/
|
|
10945
|
+
// src/chat/slack/tool-support/canvas/api.ts
|
|
10411
10946
|
async function createCanvas(input) {
|
|
10412
10947
|
const client = getSlackClient();
|
|
10413
10948
|
const normalizedChannelId = normalizeSlackConversationId(input.channelId);
|
|
@@ -10564,47 +11099,8 @@ async function readCanvas(canvasIdOrUrl) {
|
|
|
10564
11099
|
};
|
|
10565
11100
|
}
|
|
10566
11101
|
|
|
10567
|
-
// src/chat/slack/tools/canvas/context.ts
|
|
10568
|
-
var MAX_RECENT_CANVASES = 5;
|
|
10569
|
-
function mergeRecentCanvases(existing, created) {
|
|
10570
|
-
const nextEntry = {
|
|
10571
|
-
id: created.id,
|
|
10572
|
-
title: created.title,
|
|
10573
|
-
url: created.url,
|
|
10574
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10575
|
-
};
|
|
10576
|
-
const prior = existing ?? [];
|
|
10577
|
-
const deduped = prior.filter((entry) => entry.id !== created.id);
|
|
10578
|
-
return [nextEntry, ...deduped].slice(0, MAX_RECENT_CANVASES);
|
|
10579
|
-
}
|
|
10580
|
-
function resolveCanvasTarget(canvas) {
|
|
10581
|
-
const canvasId = extractCanvasId(canvas);
|
|
10582
|
-
if (!canvasId) {
|
|
10583
|
-
return {
|
|
10584
|
-
ok: false,
|
|
10585
|
-
error: "Could not parse a Slack canvas/file ID from input. Provide an F-prefixed ID or a Slack canvas/docs URL."
|
|
10586
|
-
};
|
|
10587
|
-
}
|
|
10588
|
-
return { ok: true, canvasId };
|
|
10589
|
-
}
|
|
10590
|
-
function storedCanvasUrl(state, canvasId) {
|
|
10591
|
-
const lastCanvasUrl = state.artifactState.lastCanvasUrl;
|
|
10592
|
-
if (lastCanvasUrl && extractCanvasId(lastCanvasUrl) === canvasId) {
|
|
10593
|
-
return lastCanvasUrl;
|
|
10594
|
-
}
|
|
10595
|
-
for (const canvas of state.artifactState.recentCanvases ?? []) {
|
|
10596
|
-
if (extractCanvasId(canvas.id) === canvasId) {
|
|
10597
|
-
return canvas.url;
|
|
10598
|
-
}
|
|
10599
|
-
if (canvas.url && extractCanvasId(canvas.url) === canvasId) {
|
|
10600
|
-
return canvas.url;
|
|
10601
|
-
}
|
|
10602
|
-
}
|
|
10603
|
-
return void 0;
|
|
10604
|
-
}
|
|
10605
|
-
|
|
10606
11102
|
// src/chat/slack/tools/canvas/create.ts
|
|
10607
|
-
import { z as
|
|
11103
|
+
import { z as z43 } from "zod";
|
|
10608
11104
|
function createSlackCanvasCreateTool(context, state) {
|
|
10609
11105
|
return zodTool({
|
|
10610
11106
|
annotations: {
|
|
@@ -10613,10 +11109,10 @@ function createSlackCanvasCreateTool(context, state) {
|
|
|
10613
11109
|
openWorldHint: true,
|
|
10614
11110
|
readOnlyHint: false
|
|
10615
11111
|
},
|
|
10616
|
-
description: "Create a Slack canvas
|
|
10617
|
-
inputSchema:
|
|
10618
|
-
title:
|
|
10619
|
-
markdown:
|
|
11112
|
+
description: "Create a Slack canvas in the active channel.",
|
|
11113
|
+
inputSchema: z43.object({
|
|
11114
|
+
title: z43.string().min(1).max(160).describe("Canvas title."),
|
|
11115
|
+
markdown: z43.string().min(1).describe("Canvas markdown body content.")
|
|
10620
11116
|
}),
|
|
10621
11117
|
outputSchema: juniorToolOutputSchema,
|
|
10622
11118
|
execute: async ({ title, markdown }) => {
|
|
@@ -10648,18 +11144,6 @@ function createSlackCanvasCreateTool(context, state) {
|
|
|
10648
11144
|
markdown,
|
|
10649
11145
|
channelId: targetChannelId
|
|
10650
11146
|
});
|
|
10651
|
-
await state.patchArtifactState({
|
|
10652
|
-
lastCanvasId: created.canvasId,
|
|
10653
|
-
lastCanvasUrl: created.permalink,
|
|
10654
|
-
recentCanvases: mergeRecentCanvases(
|
|
10655
|
-
state.artifactState.recentCanvases,
|
|
10656
|
-
{
|
|
10657
|
-
id: created.canvasId,
|
|
10658
|
-
title,
|
|
10659
|
-
url: created.permalink
|
|
10660
|
-
}
|
|
10661
|
-
)
|
|
10662
|
-
});
|
|
10663
11147
|
const response = {
|
|
10664
11148
|
canvas_id: created.canvasId,
|
|
10665
11149
|
permalink: created.permalink,
|
|
@@ -10671,27 +11155,41 @@ function createSlackCanvasCreateTool(context, state) {
|
|
|
10671
11155
|
});
|
|
10672
11156
|
}
|
|
10673
11157
|
|
|
11158
|
+
// src/chat/slack/tool-support/canvas/context.ts
|
|
11159
|
+
import { z as z44 } from "zod";
|
|
11160
|
+
var slackCanvasRefParam = z44.string().min(1).describe("Slack canvas/file ID or canvas/docs URL.");
|
|
11161
|
+
function resolveCanvasTarget(canvas) {
|
|
11162
|
+
const canvasId = extractCanvasId(canvas);
|
|
11163
|
+
if (!canvasId) {
|
|
11164
|
+
return {
|
|
11165
|
+
ok: false,
|
|
11166
|
+
error: "Could not parse a Slack canvas/file ID from input. Provide an F-prefixed ID or a Slack canvas/docs URL."
|
|
11167
|
+
};
|
|
11168
|
+
}
|
|
11169
|
+
return { ok: true, canvasId };
|
|
11170
|
+
}
|
|
11171
|
+
|
|
10674
11172
|
// src/chat/slack/tools/canvas/edit.ts
|
|
10675
|
-
import { z as
|
|
11173
|
+
import { z as z45 } from "zod";
|
|
10676
11174
|
function prepareCanvasEditArguments(input) {
|
|
10677
11175
|
return prepareTextReplacementArguments(input);
|
|
10678
11176
|
}
|
|
10679
|
-
var editReplacementSchema2 =
|
|
10680
|
-
oldText:
|
|
11177
|
+
var editReplacementSchema2 = z45.object({
|
|
11178
|
+
oldText: z45.string().min(1).describe(
|
|
10681
11179
|
"Exact Canvas markdown to replace. It must be unique in the current Canvas body and must not overlap another edit."
|
|
10682
11180
|
),
|
|
10683
|
-
newText:
|
|
11181
|
+
newText: z45.string().describe("Replacement Canvas markdown for this edit.")
|
|
10684
11182
|
});
|
|
10685
11183
|
var slackCanvasEditOutputSchema = juniorToolOutputSchema.extend({
|
|
10686
|
-
canvas_id:
|
|
10687
|
-
title:
|
|
10688
|
-
permalink:
|
|
10689
|
-
diff:
|
|
10690
|
-
first_changed_line:
|
|
10691
|
-
replacements:
|
|
10692
|
-
normalized_heading_count:
|
|
10693
|
-
summary:
|
|
10694
|
-
deduplicated:
|
|
11184
|
+
canvas_id: z45.string().optional(),
|
|
11185
|
+
title: z45.string().optional(),
|
|
11186
|
+
permalink: z45.string().optional(),
|
|
11187
|
+
diff: z45.string().optional(),
|
|
11188
|
+
first_changed_line: z45.number().int().positive().optional(),
|
|
11189
|
+
replacements: z45.number().int().nonnegative().optional(),
|
|
11190
|
+
normalized_heading_count: z45.number().int().nonnegative().optional(),
|
|
11191
|
+
summary: z45.string().optional(),
|
|
11192
|
+
deduplicated: z45.boolean().optional()
|
|
10695
11193
|
}).strict();
|
|
10696
11194
|
function createSlackCanvasEditTool(state) {
|
|
10697
11195
|
return zodTool({
|
|
@@ -10701,12 +11199,12 @@ function createSlackCanvasEditTool(state) {
|
|
|
10701
11199
|
openWorldHint: true,
|
|
10702
11200
|
readOnlyHint: false
|
|
10703
11201
|
},
|
|
10704
|
-
description: "Edit
|
|
11202
|
+
description: "Edit a Slack canvas with exact markdown replacements. Returns a diff.",
|
|
10705
11203
|
prepareArguments: prepareCanvasEditArguments,
|
|
10706
11204
|
executionMode: "sequential",
|
|
10707
|
-
inputSchema:
|
|
10708
|
-
canvas:
|
|
10709
|
-
edits:
|
|
11205
|
+
inputSchema: z45.object({
|
|
11206
|
+
canvas: slackCanvasRefParam,
|
|
11207
|
+
edits: z45.array(editReplacementSchema2).min(1).describe(
|
|
10710
11208
|
"Exact replacements matched against the current Canvas body, not incrementally."
|
|
10711
11209
|
)
|
|
10712
11210
|
}),
|
|
@@ -10738,10 +11236,6 @@ function createSlackCanvasEditTool(state) {
|
|
|
10738
11236
|
canvasId: target.canvasId,
|
|
10739
11237
|
markdown: newContent
|
|
10740
11238
|
});
|
|
10741
|
-
await state.patchArtifactState({
|
|
10742
|
-
lastCanvasId: target.canvasId,
|
|
10743
|
-
lastCanvasUrl: current.permalink ?? state.artifactState.lastCanvasUrl
|
|
10744
|
-
});
|
|
10745
11239
|
const diff = buildCompactDiff(
|
|
10746
11240
|
normalizeCanvasMarkdown(baseContent).markdown,
|
|
10747
11241
|
written.markdown
|
|
@@ -10763,34 +11257,32 @@ function createSlackCanvasEditTool(state) {
|
|
|
10763
11257
|
}
|
|
10764
11258
|
|
|
10765
11259
|
// src/chat/slack/tools/canvas/read.ts
|
|
10766
|
-
import { z as
|
|
11260
|
+
import { z as z46 } from "zod";
|
|
10767
11261
|
var slackCanvasReadOutputSchema = juniorToolOutputSchema.extend({
|
|
10768
|
-
canvas_id:
|
|
10769
|
-
title:
|
|
10770
|
-
permalink:
|
|
10771
|
-
mimetype:
|
|
10772
|
-
filetype:
|
|
10773
|
-
original_byte_length:
|
|
10774
|
-
content:
|
|
10775
|
-
start_line:
|
|
10776
|
-
end_line:
|
|
10777
|
-
total_lines:
|
|
11262
|
+
canvas_id: z46.string().optional(),
|
|
11263
|
+
title: z46.string().optional(),
|
|
11264
|
+
permalink: z46.string().optional(),
|
|
11265
|
+
mimetype: z46.string().optional(),
|
|
11266
|
+
filetype: z46.string().optional(),
|
|
11267
|
+
original_byte_length: z46.number().int().nonnegative().optional(),
|
|
11268
|
+
content: z46.string().optional(),
|
|
11269
|
+
start_line: z46.number().int().positive().optional(),
|
|
11270
|
+
end_line: z46.number().int().nonnegative().optional(),
|
|
11271
|
+
total_lines: z46.number().int().nonnegative().optional()
|
|
10778
11272
|
}).strict();
|
|
10779
11273
|
function createSlackCanvasReadTool() {
|
|
10780
11274
|
return zodTool({
|
|
10781
|
-
description: "Read a bounded line range from a Slack canvas as markdown.
|
|
11275
|
+
description: "Read a bounded line range from a Slack canvas as markdown.",
|
|
10782
11276
|
annotations: {
|
|
10783
11277
|
destructiveHint: false,
|
|
10784
11278
|
idempotentHint: true,
|
|
10785
11279
|
openWorldHint: true,
|
|
10786
11280
|
readOnlyHint: true
|
|
10787
11281
|
},
|
|
10788
|
-
inputSchema:
|
|
10789
|
-
canvas:
|
|
10790
|
-
|
|
10791
|
-
)
|
|
10792
|
-
offset: z43.coerce.number().int().min(1).describe("1-indexed line number to start reading from.").optional(),
|
|
10793
|
-
limit: z43.coerce.number().int().min(1).describe("Maximum number of lines to read. Defaults to 1000.").optional()
|
|
11282
|
+
inputSchema: z46.object({
|
|
11283
|
+
canvas: slackCanvasRefParam,
|
|
11284
|
+
offset: z46.coerce.number().int().min(1).describe("1-indexed line number to start reading from.").optional(),
|
|
11285
|
+
limit: z46.coerce.number().int().min(1).describe("Maximum number of lines to read. Defaults to 1000.").optional()
|
|
10794
11286
|
}),
|
|
10795
11287
|
outputSchema: slackCanvasReadOutputSchema,
|
|
10796
11288
|
execute: async ({ canvas, offset, limit }) => {
|
|
@@ -10826,7 +11318,7 @@ function createSlackCanvasReadTool() {
|
|
|
10826
11318
|
}
|
|
10827
11319
|
|
|
10828
11320
|
// src/chat/slack/tools/canvas/write.ts
|
|
10829
|
-
import { z as
|
|
11321
|
+
import { z as z47 } from "zod";
|
|
10830
11322
|
function createSlackCanvasWriteTool(state) {
|
|
10831
11323
|
return zodTool({
|
|
10832
11324
|
annotations: {
|
|
@@ -10835,11 +11327,11 @@ function createSlackCanvasWriteTool(state) {
|
|
|
10835
11327
|
openWorldHint: true,
|
|
10836
11328
|
readOnlyHint: false
|
|
10837
11329
|
},
|
|
10838
|
-
description: "
|
|
11330
|
+
description: "Replace the full markdown body of a Slack canvas.",
|
|
10839
11331
|
executionMode: "sequential",
|
|
10840
|
-
inputSchema:
|
|
10841
|
-
canvas:
|
|
10842
|
-
content:
|
|
11332
|
+
inputSchema: z47.object({
|
|
11333
|
+
canvas: slackCanvasRefParam,
|
|
11334
|
+
content: z47.string().describe("UTF-8 markdown content to write.")
|
|
10843
11335
|
}),
|
|
10844
11336
|
outputSchema: juniorToolOutputSchema,
|
|
10845
11337
|
execute: async ({ canvas, content }) => {
|
|
@@ -10862,10 +11354,6 @@ function createSlackCanvasWriteTool(state) {
|
|
|
10862
11354
|
canvasId: target.canvasId,
|
|
10863
11355
|
markdown: content
|
|
10864
11356
|
});
|
|
10865
|
-
await state.patchArtifactState({
|
|
10866
|
-
lastCanvasId: target.canvasId,
|
|
10867
|
-
lastCanvasUrl: storedCanvasUrl(state, target.canvasId)
|
|
10868
|
-
});
|
|
10869
11357
|
const response = {
|
|
10870
11358
|
canvas_id: target.canvasId,
|
|
10871
11359
|
normalized_heading_count: written.normalizedHeadingCount,
|
|
@@ -10877,7 +11365,7 @@ function createSlackCanvasWriteTool(state) {
|
|
|
10877
11365
|
});
|
|
10878
11366
|
}
|
|
10879
11367
|
|
|
10880
|
-
// src/chat/slack/
|
|
11368
|
+
// src/chat/slack/tool-support/list/api.ts
|
|
10881
11369
|
function normalizeKey(value) {
|
|
10882
11370
|
return value.toLowerCase().replace(/[^a-z0-9]+/g, "_");
|
|
10883
11371
|
}
|
|
@@ -10950,9 +11438,19 @@ async function createTodoList(name) {
|
|
|
10950
11438
|
permalink
|
|
10951
11439
|
};
|
|
10952
11440
|
}
|
|
11441
|
+
async function getListColumnMap(listId) {
|
|
11442
|
+
const client = getSlackClient();
|
|
11443
|
+
const response = await withSlackRetries(
|
|
11444
|
+
() => client.files.info({ file: listId }),
|
|
11445
|
+
3,
|
|
11446
|
+
{ action: "files.info", idempotent: true }
|
|
11447
|
+
);
|
|
11448
|
+
const file = response.file;
|
|
11449
|
+
return inferListColumnMap(file?.list_metadata?.schema ?? []);
|
|
11450
|
+
}
|
|
10953
11451
|
async function addListItems(input) {
|
|
10954
11452
|
const client = getSlackClient();
|
|
10955
|
-
const listColumnMap = input.listColumnMap ??
|
|
11453
|
+
const listColumnMap = input.listColumnMap ?? await getListColumnMap(input.listId);
|
|
10956
11454
|
if (!listColumnMap.titleColumnId) {
|
|
10957
11455
|
throw new Error(
|
|
10958
11456
|
"Cannot add list items because title column could not be inferred"
|
|
@@ -11021,19 +11519,20 @@ async function listItems(listId, limit = 100) {
|
|
|
11021
11519
|
}
|
|
11022
11520
|
async function updateListItem(input) {
|
|
11023
11521
|
const client = getSlackClient();
|
|
11522
|
+
const listColumnMap = Object.keys(input.listColumnMap).length > 0 ? input.listColumnMap : await getListColumnMap(input.listId);
|
|
11024
11523
|
const cells = [];
|
|
11025
|
-
if (typeof input.completed === "boolean" &&
|
|
11524
|
+
if (typeof input.completed === "boolean" && listColumnMap.completedColumnId) {
|
|
11026
11525
|
cells.push({
|
|
11027
11526
|
row_id: input.itemId,
|
|
11028
|
-
column_id:
|
|
11527
|
+
column_id: listColumnMap.completedColumnId,
|
|
11029
11528
|
checkbox: input.completed
|
|
11030
11529
|
});
|
|
11031
11530
|
}
|
|
11032
|
-
if (typeof input.title === "string" && input.title.trim() &&
|
|
11531
|
+
if (typeof input.title === "string" && input.title.trim() && listColumnMap.titleColumnId) {
|
|
11033
11532
|
cells.push({
|
|
11034
11533
|
row_id: input.itemId,
|
|
11035
11534
|
...richTextField(
|
|
11036
|
-
|
|
11535
|
+
listColumnMap.titleColumnId,
|
|
11037
11536
|
input.title
|
|
11038
11537
|
)
|
|
11039
11538
|
});
|
|
@@ -11053,8 +11552,13 @@ async function updateListItem(input) {
|
|
|
11053
11552
|
);
|
|
11054
11553
|
}
|
|
11055
11554
|
|
|
11555
|
+
// src/chat/slack/tool-support/list/params.ts
|
|
11556
|
+
import { z as z48 } from "zod";
|
|
11557
|
+
var slackListIdParam = z48.string().min(1).describe("Slack list ID.");
|
|
11558
|
+
var slackListItemIdParam = z48.string().min(1).describe("Slack list item ID.");
|
|
11559
|
+
|
|
11056
11560
|
// src/chat/slack/tools/list/add-items.ts
|
|
11057
|
-
import { z as
|
|
11561
|
+
import { z as z49 } from "zod";
|
|
11058
11562
|
function createSlackListAddItemsTool(state) {
|
|
11059
11563
|
return zodTool({
|
|
11060
11564
|
annotations: {
|
|
@@ -11063,26 +11567,23 @@ function createSlackListAddItemsTool(state) {
|
|
|
11063
11567
|
openWorldHint: true,
|
|
11064
11568
|
readOnlyHint: false
|
|
11065
11569
|
},
|
|
11066
|
-
description: "Add tasks to
|
|
11067
|
-
inputSchema:
|
|
11068
|
-
|
|
11570
|
+
description: "Add tasks to a Slack list.",
|
|
11571
|
+
inputSchema: z49.object({
|
|
11572
|
+
list_id: slackListIdParam,
|
|
11573
|
+
items: z49.array(z49.string().min(1)).min(1).max(25).describe("List item titles to create."),
|
|
11069
11574
|
assignee_user_id: slackUserIdParam(
|
|
11070
11575
|
"Optional Slack user ID assigned to all created items."
|
|
11071
11576
|
).optional(),
|
|
11072
|
-
due_date:
|
|
11577
|
+
due_date: z49.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Optional due date in YYYY-MM-DD format.").optional()
|
|
11073
11578
|
}),
|
|
11074
11579
|
outputSchema: juniorToolOutputSchema,
|
|
11075
|
-
execute: async ({ items, assignee_user_id, due_date }) => {
|
|
11076
|
-
const targetListId = state.getCurrentListId();
|
|
11077
|
-
if (!targetListId) {
|
|
11078
|
-
throw new ToolInputError("No active list found in artifact context");
|
|
11079
|
-
}
|
|
11580
|
+
execute: async ({ list_id, items, assignee_user_id, due_date }) => {
|
|
11080
11581
|
const parsedAssigneeUserId = assignee_user_id === void 0 ? void 0 : parseRequiredSlackUserIdParam("assignee_user_id", assignee_user_id);
|
|
11081
11582
|
if (parsedAssigneeUserId?.ok === false) {
|
|
11082
11583
|
throw new ToolInputError(parsedAssigneeUserId.error);
|
|
11083
11584
|
}
|
|
11084
11585
|
const operationKey = createOperationKey("slackListAddItems", {
|
|
11085
|
-
list_id
|
|
11586
|
+
list_id,
|
|
11086
11587
|
items,
|
|
11087
11588
|
assignee_user_id: parsedAssigneeUserId?.value ?? null,
|
|
11088
11589
|
due_date: due_date ?? null
|
|
@@ -11095,18 +11596,13 @@ function createSlackListAddItemsTool(state) {
|
|
|
11095
11596
|
};
|
|
11096
11597
|
}
|
|
11097
11598
|
const result = await addListItems({
|
|
11098
|
-
listId:
|
|
11599
|
+
listId: list_id,
|
|
11099
11600
|
titles: items,
|
|
11100
|
-
listColumnMap: state.artifactState.listColumnMap,
|
|
11101
11601
|
assigneeUserId: parsedAssigneeUserId?.value,
|
|
11102
11602
|
dueDate: due_date
|
|
11103
11603
|
});
|
|
11104
|
-
await state.patchArtifactState({
|
|
11105
|
-
lastListId: targetListId,
|
|
11106
|
-
listColumnMap: result.listColumnMap
|
|
11107
|
-
});
|
|
11108
11604
|
const response = {
|
|
11109
|
-
list_id
|
|
11605
|
+
list_id,
|
|
11110
11606
|
created_item_ids: result.createdItemIds,
|
|
11111
11607
|
created_count: result.createdItemIds.length
|
|
11112
11608
|
};
|
|
@@ -11117,7 +11613,7 @@ function createSlackListAddItemsTool(state) {
|
|
|
11117
11613
|
}
|
|
11118
11614
|
|
|
11119
11615
|
// src/chat/slack/tools/list/create.ts
|
|
11120
|
-
import { z as
|
|
11616
|
+
import { z as z50 } from "zod";
|
|
11121
11617
|
function createSlackListCreateTool(state) {
|
|
11122
11618
|
return zodTool({
|
|
11123
11619
|
annotations: {
|
|
@@ -11126,9 +11622,9 @@ function createSlackListCreateTool(state) {
|
|
|
11126
11622
|
openWorldHint: true,
|
|
11127
11623
|
readOnlyHint: false
|
|
11128
11624
|
},
|
|
11129
|
-
description: "Create a Slack todo list
|
|
11130
|
-
inputSchema:
|
|
11131
|
-
name:
|
|
11625
|
+
description: "Create a Slack todo list.",
|
|
11626
|
+
inputSchema: z50.object({
|
|
11627
|
+
name: z50.string().min(1).max(160).describe("Name for the new Slack list.")
|
|
11132
11628
|
}),
|
|
11133
11629
|
outputSchema: juniorToolOutputSchema,
|
|
11134
11630
|
execute: async ({ name }) => {
|
|
@@ -11141,11 +11637,6 @@ function createSlackListCreateTool(state) {
|
|
|
11141
11637
|
};
|
|
11142
11638
|
}
|
|
11143
11639
|
const list = await createTodoList(name);
|
|
11144
|
-
await state.patchArtifactState({
|
|
11145
|
-
lastListId: list.listId,
|
|
11146
|
-
lastListUrl: list.permalink,
|
|
11147
|
-
listColumnMap: list.listColumnMap
|
|
11148
|
-
});
|
|
11149
11640
|
const response = {
|
|
11150
11641
|
list_id: list.listId,
|
|
11151
11642
|
permalink: list.permalink,
|
|
@@ -11158,29 +11649,26 @@ function createSlackListCreateTool(state) {
|
|
|
11158
11649
|
}
|
|
11159
11650
|
|
|
11160
11651
|
// src/chat/slack/tools/list/get-items.ts
|
|
11161
|
-
import { z as
|
|
11162
|
-
function createSlackListGetItemsTool(
|
|
11652
|
+
import { z as z51 } from "zod";
|
|
11653
|
+
function createSlackListGetItemsTool() {
|
|
11163
11654
|
return zodTool({
|
|
11164
|
-
description: "Read items from
|
|
11655
|
+
description: "Read items from a Slack list.",
|
|
11165
11656
|
annotations: {
|
|
11166
11657
|
destructiveHint: false,
|
|
11167
11658
|
idempotentHint: true,
|
|
11168
11659
|
openWorldHint: true,
|
|
11169
11660
|
readOnlyHint: true
|
|
11170
11661
|
},
|
|
11171
|
-
inputSchema:
|
|
11172
|
-
|
|
11662
|
+
inputSchema: z51.object({
|
|
11663
|
+
list_id: slackListIdParam,
|
|
11664
|
+
limit: z51.coerce.number().int().min(1).max(200).describe("Maximum number of list items to return.").optional()
|
|
11173
11665
|
}),
|
|
11174
11666
|
outputSchema: juniorToolOutputSchema,
|
|
11175
|
-
execute: async ({ limit }) => {
|
|
11176
|
-
const targetListId = state.getCurrentListId();
|
|
11667
|
+
execute: async ({ list_id, limit }) => {
|
|
11177
11668
|
const resolvedLimit = limit ?? 100;
|
|
11178
|
-
|
|
11179
|
-
throw new ToolInputError("No active list found in artifact context");
|
|
11180
|
-
}
|
|
11181
|
-
const items = await listItems(targetListId, resolvedLimit);
|
|
11669
|
+
const items = await listItems(list_id, resolvedLimit);
|
|
11182
11670
|
return {
|
|
11183
|
-
list_id
|
|
11671
|
+
list_id,
|
|
11184
11672
|
items: items.map((item) => ({ id: item.id, fields: item.fields }))
|
|
11185
11673
|
};
|
|
11186
11674
|
}
|
|
@@ -11188,21 +11676,23 @@ function createSlackListGetItemsTool(state) {
|
|
|
11188
11676
|
}
|
|
11189
11677
|
|
|
11190
11678
|
// src/chat/slack/tools/list/update-item.ts
|
|
11191
|
-
import { z as
|
|
11192
|
-
var booleanInput3 = (description) =>
|
|
11679
|
+
import { z as z52 } from "zod";
|
|
11680
|
+
var booleanInput3 = (description) => z52.preprocess(
|
|
11193
11681
|
(value) => value === "true" ? true : value === "false" ? false : value,
|
|
11194
|
-
|
|
11682
|
+
z52.boolean()
|
|
11195
11683
|
).describe(description);
|
|
11196
|
-
var updateListItemInputSchema =
|
|
11197
|
-
|
|
11198
|
-
|
|
11684
|
+
var updateListItemInputSchema = z52.union([
|
|
11685
|
+
z52.object({
|
|
11686
|
+
list_id: slackListIdParam,
|
|
11687
|
+
item_id: slackListItemIdParam,
|
|
11199
11688
|
completed: booleanInput3("Optional completion status update."),
|
|
11200
|
-
title:
|
|
11689
|
+
title: z52.string().min(1).describe("Optional new item title.").optional()
|
|
11201
11690
|
}),
|
|
11202
|
-
|
|
11203
|
-
|
|
11691
|
+
z52.object({
|
|
11692
|
+
list_id: slackListIdParam,
|
|
11693
|
+
item_id: slackListItemIdParam,
|
|
11204
11694
|
completed: booleanInput3("Optional completion status update.").optional(),
|
|
11205
|
-
title:
|
|
11695
|
+
title: z52.string().min(1).describe("Optional new item title.")
|
|
11206
11696
|
})
|
|
11207
11697
|
]);
|
|
11208
11698
|
function createSlackListUpdateItemTool(state) {
|
|
@@ -11213,16 +11703,12 @@ function createSlackListUpdateItemTool(state) {
|
|
|
11213
11703
|
openWorldHint: true,
|
|
11214
11704
|
readOnlyHint: false
|
|
11215
11705
|
},
|
|
11216
|
-
description: "Update an item in
|
|
11706
|
+
description: "Update an item in a Slack list.",
|
|
11217
11707
|
inputSchema: updateListItemInputSchema,
|
|
11218
11708
|
outputSchema: juniorToolOutputSchema,
|
|
11219
|
-
execute: async ({ item_id, completed, title }) => {
|
|
11220
|
-
const targetListId = state.getCurrentListId();
|
|
11221
|
-
if (!targetListId) {
|
|
11222
|
-
throw new ToolInputError("No active list found in artifact context");
|
|
11223
|
-
}
|
|
11709
|
+
execute: async ({ list_id, item_id, completed, title }) => {
|
|
11224
11710
|
const operationKey = createOperationKey("slackListUpdateItem", {
|
|
11225
|
-
list_id
|
|
11711
|
+
list_id,
|
|
11226
11712
|
item_id,
|
|
11227
11713
|
completed: completed ?? null,
|
|
11228
11714
|
title: title ?? null
|
|
@@ -11235,15 +11721,14 @@ function createSlackListUpdateItemTool(state) {
|
|
|
11235
11721
|
};
|
|
11236
11722
|
}
|
|
11237
11723
|
await updateListItem({
|
|
11238
|
-
listId:
|
|
11724
|
+
listId: list_id,
|
|
11239
11725
|
itemId: item_id,
|
|
11240
11726
|
completed,
|
|
11241
11727
|
title,
|
|
11242
|
-
listColumnMap:
|
|
11728
|
+
listColumnMap: {}
|
|
11243
11729
|
});
|
|
11244
|
-
await state.patchArtifactState({ lastListId: targetListId });
|
|
11245
11730
|
const response = {
|
|
11246
|
-
list_id
|
|
11731
|
+
list_id,
|
|
11247
11732
|
item_id,
|
|
11248
11733
|
completed,
|
|
11249
11734
|
title
|
|
@@ -11254,33 +11739,10 @@ function createSlackListUpdateItemTool(state) {
|
|
|
11254
11739
|
});
|
|
11255
11740
|
}
|
|
11256
11741
|
|
|
11257
|
-
// src/chat/slack/tools/channel-access.ts
|
|
11258
|
-
async function checkSlackChannelReadAccess(args) {
|
|
11259
|
-
const currentChannels = args.currentChannelIds.filter(
|
|
11260
|
-
(channelId) => Boolean(channelId)
|
|
11261
|
-
);
|
|
11262
|
-
if (currentChannels.includes(args.targetChannelId)) {
|
|
11263
|
-
return { allowed: true };
|
|
11264
|
-
}
|
|
11265
|
-
const store = args.store ?? getConversationStore();
|
|
11266
|
-
const visibility = await store.getDestinationVisibility({
|
|
11267
|
-
provider: "slack",
|
|
11268
|
-
providerTenantId: args.teamId,
|
|
11269
|
-
providerDestinationId: args.targetChannelId
|
|
11270
|
-
});
|
|
11271
|
-
if (visibility === "public") {
|
|
11272
|
-
return { allowed: true };
|
|
11273
|
-
}
|
|
11274
|
-
return {
|
|
11275
|
-
allowed: false,
|
|
11276
|
-
error: "Cannot read this Slack conversation: only the current conversation or public channels Junior has seen in this workspace are readable."
|
|
11277
|
-
};
|
|
11278
|
-
}
|
|
11279
|
-
|
|
11280
11742
|
// src/chat/slack/tools/thread-read.ts
|
|
11281
|
-
import { z as
|
|
11743
|
+
import { z as z53 } from "zod";
|
|
11282
11744
|
|
|
11283
|
-
// src/chat/slack/
|
|
11745
|
+
// src/chat/slack/tool-support/slack-message-url.ts
|
|
11284
11746
|
var SLACK_HOST_PATTERN = /^[a-z0-9-]+\.slack(?:-gov)?\.com$/;
|
|
11285
11747
|
var ARCHIVE_PATH_PATTERN = /^\/archives\/([CDG][A-Z0-9]+)\/p(\d{10})(\d{6})$/;
|
|
11286
11748
|
function pTimestampToTs(seconds, micros) {
|
|
@@ -11535,27 +11997,23 @@ function truncateMessages(messages, maxChars) {
|
|
|
11535
11997
|
}
|
|
11536
11998
|
return { messages: kept, omitted: messages.length - kept.length };
|
|
11537
11999
|
}
|
|
11538
|
-
function createSlackThreadReadTool(context
|
|
12000
|
+
function createSlackThreadReadTool(context) {
|
|
11539
12001
|
return zodTool({
|
|
11540
|
-
description: "Read a Slack thread from a shared
|
|
12002
|
+
description: "Read a Slack thread from a shared archive URL or explicit channel + timestamp. Works for the current conversation and public channels.",
|
|
11541
12003
|
annotations: {
|
|
11542
12004
|
destructiveHint: false,
|
|
11543
12005
|
idempotentHint: true,
|
|
11544
12006
|
openWorldHint: true,
|
|
11545
12007
|
readOnlyHint: true
|
|
11546
12008
|
},
|
|
11547
|
-
inputSchema:
|
|
11548
|
-
url:
|
|
11549
|
-
|
|
11550
|
-
).optional(),
|
|
11551
|
-
channel_id: slackChannelIdParam(
|
|
11552
|
-
"Slack channel/conversation ID (e.g. C123). Use with `ts` as an alternative to `url`."
|
|
11553
|
-
).optional(),
|
|
12009
|
+
inputSchema: z53.object({
|
|
12010
|
+
url: z53.string().min(1).describe("Slack message archive URL.").optional(),
|
|
12011
|
+
channel_id: slackChannelRefParam.optional(),
|
|
11554
12012
|
ts: slackTimestampParam(
|
|
11555
|
-
"Slack message timestamp
|
|
12013
|
+
"Slack message timestamp. May be the thread root or any message in the thread."
|
|
11556
12014
|
).optional(),
|
|
11557
|
-
limit:
|
|
11558
|
-
max_pages:
|
|
12015
|
+
limit: z53.coerce.number().int().min(1).max(1e3).describe("Maximum number of thread messages to fetch.").optional(),
|
|
12016
|
+
max_pages: z53.coerce.number().int().min(1).max(10).describe("Maximum number of Slack API pages to traverse.").optional()
|
|
11559
12017
|
}),
|
|
11560
12018
|
outputSchema: juniorToolOutputSchema,
|
|
11561
12019
|
execute: async ({ url, channel_id, ts, limit, max_pages }) => {
|
|
@@ -11575,14 +12033,11 @@ function createSlackThreadReadTool(context, deps = {}) {
|
|
|
11575
12033
|
if (!parsedTs.ok) {
|
|
11576
12034
|
throw new ToolInputError(parsedTs.error);
|
|
11577
12035
|
}
|
|
11578
|
-
const
|
|
11579
|
-
"channel_id",
|
|
11580
|
-
channel_id
|
|
11581
|
-
);
|
|
11582
|
-
|
|
11583
|
-
throw new ToolInputError(parsedChannelId.error);
|
|
11584
|
-
}
|
|
11585
|
-
channelId = parsedChannelId.value;
|
|
12036
|
+
const target = await resolveSlackChannelRef({
|
|
12037
|
+
field: "channel_id",
|
|
12038
|
+
value: channel_id
|
|
12039
|
+
});
|
|
12040
|
+
channelId = target.channelId;
|
|
11586
12041
|
messageTs = parsedTs.value;
|
|
11587
12042
|
} else {
|
|
11588
12043
|
throw new ToolInputError(
|
|
@@ -11594,7 +12049,6 @@ function createSlackThreadReadTool(context, deps = {}) {
|
|
|
11594
12049
|
context.destinationChannelId,
|
|
11595
12050
|
context.sourceChannelId
|
|
11596
12051
|
],
|
|
11597
|
-
store: deps.visibilityStore,
|
|
11598
12052
|
targetChannelId: channelId,
|
|
11599
12053
|
teamId: context.teamId
|
|
11600
12054
|
});
|
|
@@ -11602,20 +12056,57 @@ function createSlackThreadReadTool(context, deps = {}) {
|
|
|
11602
12056
|
throw new ToolInputError(access.error);
|
|
11603
12057
|
}
|
|
11604
12058
|
const lookupTs = threadTs ?? messageTs;
|
|
12059
|
+
const readReplies = async () => listThreadReplies({
|
|
12060
|
+
channelId,
|
|
12061
|
+
threadTs: lookupTs,
|
|
12062
|
+
limit: limit ?? 1e3,
|
|
12063
|
+
maxPages: max_pages
|
|
12064
|
+
});
|
|
11605
12065
|
let replies;
|
|
12066
|
+
let joined = false;
|
|
12067
|
+
let channelName = access.channelName;
|
|
12068
|
+
let readError;
|
|
11606
12069
|
try {
|
|
11607
|
-
replies = await
|
|
11608
|
-
channelId,
|
|
11609
|
-
threadTs: lookupTs,
|
|
11610
|
-
limit: limit ?? 1e3,
|
|
11611
|
-
maxPages: max_pages
|
|
11612
|
-
});
|
|
12070
|
+
replies = await readReplies();
|
|
11613
12071
|
} catch (error) {
|
|
12072
|
+
readError = error;
|
|
12073
|
+
const canJoin = error instanceof SlackActionError && error.code === "not_in_channel" && access.isMember !== true;
|
|
12074
|
+
if (canJoin) {
|
|
12075
|
+
const joinResult = await joinPublicChannelForRead({
|
|
12076
|
+
channelName,
|
|
12077
|
+
targetChannelId: channelId
|
|
12078
|
+
});
|
|
12079
|
+
if (!joinResult.ok) {
|
|
12080
|
+
throw new ToolInputError(joinResult.error);
|
|
12081
|
+
}
|
|
12082
|
+
joined = true;
|
|
12083
|
+
channelName = joinResult.channelName ?? channelName;
|
|
12084
|
+
try {
|
|
12085
|
+
replies = await readReplies();
|
|
12086
|
+
readError = void 0;
|
|
12087
|
+
} catch (retryError) {
|
|
12088
|
+
readError = retryError;
|
|
12089
|
+
}
|
|
12090
|
+
}
|
|
12091
|
+
}
|
|
12092
|
+
if (!replies) {
|
|
12093
|
+
const error = readError;
|
|
11614
12094
|
if (error instanceof SlackActionError) {
|
|
11615
|
-
|
|
11616
|
-
|
|
11617
|
-
|
|
11618
|
-
|
|
12095
|
+
if (error.code === "not_in_channel") {
|
|
12096
|
+
throw new ToolInputError(
|
|
12097
|
+
"Could not read this Slack thread because the bot is not in the channel.",
|
|
12098
|
+
{ cause: error }
|
|
12099
|
+
);
|
|
12100
|
+
}
|
|
12101
|
+
if (error.code === "missing_scope") {
|
|
12102
|
+
throw new ToolInputError(
|
|
12103
|
+
"Could not read this Slack thread because this installation is missing history scopes.",
|
|
12104
|
+
{ cause: error }
|
|
12105
|
+
);
|
|
12106
|
+
}
|
|
12107
|
+
throw new ToolInputError("Could not read this Slack thread.", {
|
|
12108
|
+
cause: error
|
|
12109
|
+
});
|
|
11619
12110
|
}
|
|
11620
12111
|
throw error;
|
|
11621
12112
|
}
|
|
@@ -11631,6 +12122,8 @@ function createSlackThreadReadTool(context, deps = {}) {
|
|
|
11631
12122
|
);
|
|
11632
12123
|
return {
|
|
11633
12124
|
channel_id: channelId,
|
|
12125
|
+
...channelName ? { channel_name: channelName } : {},
|
|
12126
|
+
...joined ? { joined_channel: true } : {},
|
|
11634
12127
|
target_message_ts: messageTs,
|
|
11635
12128
|
thread_ts: resolvedThreadTs,
|
|
11636
12129
|
count: messages.length,
|
|
@@ -11643,183 +12136,70 @@ function createSlackThreadReadTool(context, deps = {}) {
|
|
|
11643
12136
|
});
|
|
11644
12137
|
}
|
|
11645
12138
|
|
|
11646
|
-
// src/chat/
|
|
11647
|
-
import { and, eq } from "drizzle-orm";
|
|
11648
|
-
import {
|
|
11649
|
-
|
|
11650
|
-
|
|
11651
|
-
function normalizeUser(raw) {
|
|
11652
|
-
const rawFields = raw.profile?.fields;
|
|
11653
|
-
const profileFields = [];
|
|
11654
|
-
if (rawFields && typeof rawFields === "object") {
|
|
11655
|
-
for (const [id, field] of Object.entries(rawFields)) {
|
|
11656
|
-
if (!field) continue;
|
|
11657
|
-
profileFields.push({
|
|
11658
|
-
id,
|
|
11659
|
-
label: field.label || void 0,
|
|
11660
|
-
value: field.value || void 0,
|
|
11661
|
-
alt: field.alt || void 0
|
|
11662
|
-
});
|
|
11663
|
-
}
|
|
11664
|
-
}
|
|
11665
|
-
return {
|
|
11666
|
-
id: raw.id ?? "",
|
|
11667
|
-
team_id: raw.team_id || void 0,
|
|
11668
|
-
name: raw.name || void 0,
|
|
11669
|
-
real_name: raw.real_name || raw.profile?.real_name || void 0,
|
|
11670
|
-
display_name: raw.profile?.display_name || void 0,
|
|
11671
|
-
title: raw.profile?.title || void 0,
|
|
11672
|
-
email: raw.profile?.email || void 0,
|
|
11673
|
-
status_text: raw.profile?.status_text ?? void 0,
|
|
11674
|
-
status_emoji: raw.profile?.status_emoji ?? void 0,
|
|
11675
|
-
is_bot: raw.is_bot ?? false,
|
|
11676
|
-
is_deleted: raw.deleted ?? false,
|
|
11677
|
-
timezone: raw.tz || void 0,
|
|
11678
|
-
...profileFields.length > 0 ? { profile_fields: profileFields } : {}
|
|
11679
|
-
};
|
|
11680
|
-
}
|
|
11681
|
-
async function lookupSlackUserProfile(userId) {
|
|
11682
|
-
const client = getSlackClient();
|
|
11683
|
-
const result = await withSlackRetries(
|
|
11684
|
-
() => client.users.info({ user: userId }),
|
|
11685
|
-
3,
|
|
11686
|
-
{ action: "users.info" }
|
|
11687
|
-
);
|
|
11688
|
-
const user = result.user;
|
|
11689
|
-
if (!user) {
|
|
11690
|
-
throw new Error(`Slack users.info returned no user for ${userId}`);
|
|
11691
|
-
}
|
|
11692
|
-
return normalizeUser(user);
|
|
11693
|
-
}
|
|
11694
|
-
async function lookupSlackUserByEmail(email) {
|
|
11695
|
-
const client = getSlackClient();
|
|
11696
|
-
let result;
|
|
11697
|
-
try {
|
|
11698
|
-
result = await withSlackRetries(
|
|
11699
|
-
() => client.users.lookupByEmail({ email }),
|
|
11700
|
-
3,
|
|
11701
|
-
{ action: "users.lookupByEmail" }
|
|
11702
|
-
);
|
|
11703
|
-
} catch (error) {
|
|
11704
|
-
const apiError = error.apiError;
|
|
11705
|
-
if (apiError === "users_not_found") {
|
|
11706
|
-
return null;
|
|
11707
|
-
}
|
|
11708
|
-
throw error;
|
|
11709
|
-
}
|
|
11710
|
-
const user = result.user;
|
|
11711
|
-
if (!user) {
|
|
11712
|
-
return null;
|
|
11713
|
-
}
|
|
11714
|
-
return normalizeUser(user);
|
|
11715
|
-
}
|
|
11716
|
-
function scoreMatch(user, queryLower) {
|
|
11717
|
-
const name = (user.name ?? "").toLowerCase();
|
|
11718
|
-
const realName = (user.real_name ?? user.profile?.real_name ?? "").toLowerCase();
|
|
11719
|
-
const displayName = (user.profile?.display_name ?? "").toLowerCase();
|
|
11720
|
-
if (name === queryLower || displayName === queryLower) return 100;
|
|
11721
|
-
if (realName === queryLower) return 90;
|
|
11722
|
-
if (name.startsWith(queryLower) || displayName.startsWith(queryLower))
|
|
11723
|
-
return 70;
|
|
11724
|
-
if (realName.startsWith(queryLower)) return 60;
|
|
11725
|
-
const realNameWords = realName.split(/\s+/);
|
|
11726
|
-
if (realNameWords.some((w) => w === queryLower)) return 55;
|
|
11727
|
-
if (realNameWords.some((w) => w.startsWith(queryLower))) return 50;
|
|
11728
|
-
if (name.includes(queryLower) || displayName.includes(queryLower)) return 30;
|
|
11729
|
-
if (realName.includes(queryLower)) return 20;
|
|
11730
|
-
return 0;
|
|
11731
|
-
}
|
|
11732
|
-
async function searchSlackUsers(options) {
|
|
11733
|
-
const {
|
|
11734
|
-
query,
|
|
11735
|
-
limit = 10,
|
|
11736
|
-
maxPages = 3,
|
|
11737
|
-
includeDeleted = false,
|
|
11738
|
-
includeBots = false
|
|
11739
|
-
} = options;
|
|
11740
|
-
const queryLower = query.toLowerCase().trim();
|
|
11741
|
-
const client = getSlackClient();
|
|
11742
|
-
const matches = [];
|
|
11743
|
-
let cursor;
|
|
11744
|
-
let pages = 0;
|
|
11745
|
-
let totalScanned = 0;
|
|
11746
|
-
let truncated = false;
|
|
11747
|
-
while (pages < maxPages) {
|
|
11748
|
-
pages++;
|
|
11749
|
-
const result = await withSlackRetries(
|
|
11750
|
-
() => client.users.list({
|
|
11751
|
-
limit: 200,
|
|
11752
|
-
...cursor ? { cursor } : {}
|
|
11753
|
-
}),
|
|
11754
|
-
3,
|
|
11755
|
-
{ action: "users.list" }
|
|
11756
|
-
);
|
|
11757
|
-
const members = result.members ?? [];
|
|
11758
|
-
totalScanned += members.length;
|
|
11759
|
-
for (const member of members) {
|
|
11760
|
-
if (!includeDeleted && member.deleted) continue;
|
|
11761
|
-
if (!includeBots && member.is_bot) continue;
|
|
11762
|
-
if (member.id === "USLACKBOT") continue;
|
|
11763
|
-
const score = scoreMatch(member, queryLower);
|
|
11764
|
-
if (score > 0) {
|
|
11765
|
-
matches.push({ user: member, score });
|
|
11766
|
-
}
|
|
11767
|
-
}
|
|
11768
|
-
const nextCursor = result.response_metadata?.next_cursor;
|
|
11769
|
-
if (!nextCursor) {
|
|
11770
|
-
break;
|
|
11771
|
-
}
|
|
11772
|
-
cursor = nextCursor;
|
|
11773
|
-
}
|
|
11774
|
-
if (pages >= maxPages && cursor) {
|
|
11775
|
-
truncated = true;
|
|
11776
|
-
}
|
|
11777
|
-
matches.sort((a, b) => {
|
|
11778
|
-
if (b.score !== a.score) return b.score - a.score;
|
|
11779
|
-
return (a.user.name ?? "").localeCompare(b.user.name ?? "");
|
|
11780
|
-
});
|
|
11781
|
-
return {
|
|
11782
|
-
users: matches.slice(0, limit).map((m) => normalizeUser(m.user)),
|
|
11783
|
-
searched_pages: pages,
|
|
11784
|
-
searched_user_count: totalScanned,
|
|
11785
|
-
truncated
|
|
11786
|
-
};
|
|
11787
|
-
}
|
|
11788
|
-
|
|
11789
|
-
// src/chat/slack/tools/user-lookup.ts
|
|
12139
|
+
// src/chat/tools/user-lookup.ts
|
|
12140
|
+
import { and, eq, or, sql } from "drizzle-orm";
|
|
12141
|
+
import { alias } from "drizzle-orm/pg-core";
|
|
12142
|
+
import { z as z54 } from "zod";
|
|
12143
|
+
var linkedSlackIdentity = alias(juniorIdentities, "user_lookup_slack_identity");
|
|
11790
12144
|
function explicitUserLookupError(error) {
|
|
11791
|
-
if (error.apiError === "user_not_found") {
|
|
12145
|
+
if (error.apiError === "user_not_found" || error.code === "not_found") {
|
|
11792
12146
|
return "No Slack user found for the supplied user ID.";
|
|
11793
12147
|
}
|
|
11794
12148
|
if (error.code === "missing_scope") {
|
|
11795
|
-
return error.needed ? `
|
|
11796
|
-
}
|
|
11797
|
-
if (error.code === "not_found") {
|
|
11798
|
-
return "No Slack user found for the supplied user ID.";
|
|
12149
|
+
return error.needed ? `User lookup is unavailable because this installation is missing the \`${error.needed}\` scope.` : "User lookup is unavailable because this installation is missing a required Slack scope.";
|
|
11799
12150
|
}
|
|
11800
12151
|
if (error.code === "invalid_arguments") {
|
|
11801
12152
|
return `Slack rejected the user lookup arguments (${error.apiError ?? error.code}).`;
|
|
11802
12153
|
}
|
|
11803
12154
|
if (error.code === "feature_unavailable") {
|
|
11804
|
-
return "
|
|
12155
|
+
return "User lookup is not available for this workspace or app installation.";
|
|
11805
12156
|
}
|
|
11806
12157
|
return void 0;
|
|
11807
12158
|
}
|
|
11808
12159
|
function slackMention(userId) {
|
|
11809
12160
|
return `<@${userId}>`;
|
|
11810
12161
|
}
|
|
11811
|
-
|
|
11812
|
-
|
|
11813
|
-
|
|
11814
|
-
|
|
11815
|
-
|
|
11816
|
-
|
|
11817
|
-
|
|
11818
|
-
|
|
11819
|
-
|
|
11820
|
-
|
|
12162
|
+
function asMatch(user) {
|
|
12163
|
+
return { ...user, mention: slackMention(user.id) };
|
|
12164
|
+
}
|
|
12165
|
+
function lookupResult(args) {
|
|
12166
|
+
const users = args.users.map(asMatch);
|
|
12167
|
+
if (users.length === 1) {
|
|
12168
|
+
return {
|
|
12169
|
+
provider: args.provider,
|
|
12170
|
+
query: args.query,
|
|
12171
|
+
count: 1,
|
|
12172
|
+
mention: users[0].mention,
|
|
12173
|
+
user: users[0],
|
|
12174
|
+
...args.search
|
|
12175
|
+
};
|
|
12176
|
+
}
|
|
12177
|
+
return {
|
|
12178
|
+
provider: args.provider,
|
|
12179
|
+
query: args.query,
|
|
12180
|
+
count: users.length,
|
|
12181
|
+
users,
|
|
12182
|
+
...args.search
|
|
12183
|
+
};
|
|
12184
|
+
}
|
|
12185
|
+
function slackProfileFromIdentity(identity) {
|
|
12186
|
+
return {
|
|
12187
|
+
id: identity.providerSubjectId,
|
|
12188
|
+
name: identity.handle ?? void 0,
|
|
12189
|
+
real_name: identity.displayName ?? void 0,
|
|
12190
|
+
display_name: identity.displayName ?? void 0,
|
|
12191
|
+
email: identity.email ?? void 0,
|
|
12192
|
+
is_bot: false,
|
|
12193
|
+
is_deleted: false
|
|
12194
|
+
};
|
|
12195
|
+
}
|
|
12196
|
+
function slackMentionProfileFromIdentity(identity) {
|
|
12197
|
+
return {
|
|
12198
|
+
id: identity.providerSubjectId,
|
|
12199
|
+
name: identity.handle ?? void 0
|
|
12200
|
+
};
|
|
11821
12201
|
}
|
|
11822
|
-
async function
|
|
12202
|
+
async function storedSlackUserByEmail(teamId, email) {
|
|
11823
12203
|
const emailNormalized = normalizeIdentityEmail(email);
|
|
11824
12204
|
if (!emailNormalized) return void 0;
|
|
11825
12205
|
const identities = await getSqlExecutor().db().select().from(juniorIdentities).where(
|
|
@@ -11836,94 +12216,86 @@ async function storedUserByEmail(teamId, email) {
|
|
|
11836
12216
|
`Multiple Slack users share verified email ${emailNormalized} in workspace ${teamId}`
|
|
11837
12217
|
);
|
|
11838
12218
|
}
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
}
|
|
12219
|
+
return identities[0] ? slackProfileFromIdentity(identities[0]) : void 0;
|
|
12220
|
+
}
|
|
12221
|
+
function looksLikeEmail(query) {
|
|
12222
|
+
return /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(query);
|
|
12223
|
+
}
|
|
12224
|
+
async function resolveSlack(teamId, query) {
|
|
12225
|
+
const userId = parseSlackUserId(query);
|
|
12226
|
+
if (userId) {
|
|
12227
|
+
const user = await lookupSlackUserProfile(userId);
|
|
12228
|
+
return lookupResult({ provider: "slack", query, users: [user] });
|
|
12229
|
+
}
|
|
12230
|
+
if (looksLikeEmail(query)) {
|
|
12231
|
+
const stored = await storedSlackUserByEmail(teamId, query);
|
|
12232
|
+
if (stored) {
|
|
12233
|
+
return lookupResult({ provider: "slack", query, users: [stored] });
|
|
12234
|
+
}
|
|
12235
|
+
const profile = await lookupSlackUserByEmail(query);
|
|
12236
|
+
if (!profile) {
|
|
12237
|
+
throw new ToolInputError(
|
|
12238
|
+
`No Slack user found with email address ${query}.`
|
|
12239
|
+
);
|
|
12240
|
+
}
|
|
12241
|
+
return lookupResult({ provider: "slack", query, users: [profile] });
|
|
12242
|
+
}
|
|
12243
|
+
const result = await searchSlackUsers({
|
|
12244
|
+
query,
|
|
12245
|
+
limit: 10,
|
|
12246
|
+
maxPages: 3,
|
|
12247
|
+
includeBots: false
|
|
12248
|
+
});
|
|
12249
|
+
return lookupResult({
|
|
12250
|
+
provider: "slack",
|
|
12251
|
+
query,
|
|
12252
|
+
users: result.users,
|
|
12253
|
+
search: {
|
|
12254
|
+
searched_pages: result.searched_pages,
|
|
12255
|
+
searched_user_count: result.searched_user_count,
|
|
12256
|
+
truncated: result.truncated
|
|
12257
|
+
}
|
|
12258
|
+
});
|
|
12259
|
+
}
|
|
12260
|
+
async function resolveStoredProvider(teamId, provider, query) {
|
|
12261
|
+
const rows = await getSqlExecutor().db().select({ slack: linkedSlackIdentity }).from(juniorIdentities).innerJoin(
|
|
12262
|
+
linkedSlackIdentity,
|
|
12263
|
+
and(
|
|
12264
|
+
eq(linkedSlackIdentity.userId, juniorIdentities.userId),
|
|
12265
|
+
eq(linkedSlackIdentity.kind, "user"),
|
|
12266
|
+
eq(linkedSlackIdentity.provider, "slack"),
|
|
12267
|
+
eq(linkedSlackIdentity.providerTenantId, teamId)
|
|
12268
|
+
)
|
|
12269
|
+
).where(
|
|
12270
|
+
and(
|
|
12271
|
+
eq(juniorIdentities.kind, "user"),
|
|
12272
|
+
eq(juniorIdentities.provider, provider),
|
|
12273
|
+
or(
|
|
12274
|
+
eq(juniorIdentities.providerSubjectId, query),
|
|
12275
|
+
sql`lower(${juniorIdentities.handle}) = lower(${query})`
|
|
12276
|
+
)
|
|
12277
|
+
)
|
|
12278
|
+
).limit(11);
|
|
12279
|
+
const users = rows.slice(0, 10).map((row) => slackMentionProfileFromIdentity(row.slack));
|
|
12280
|
+
return lookupResult({ provider, query, users });
|
|
11850
12281
|
}
|
|
11851
|
-
function
|
|
12282
|
+
function createUserLookupTool(teamId, providers) {
|
|
11852
12283
|
return zodTool({
|
|
11853
|
-
description: "Look up
|
|
12284
|
+
description: "Look up people by identity provider and query. Pass an enabled `provider` and its provider subject ID or handle. The `slack` provider also accepts email and name searches. Returns Slack `mention` values (`<@U\u2026>`) for the current workspace. Use a mention only when one person clearly matches; otherwise ask which person the user means.",
|
|
11854
12285
|
annotations: {
|
|
11855
12286
|
destructiveHint: false,
|
|
11856
12287
|
idempotentHint: true,
|
|
11857
12288
|
openWorldHint: true,
|
|
11858
12289
|
readOnlyHint: true
|
|
11859
12290
|
},
|
|
11860
|
-
inputSchema:
|
|
11861
|
-
|
|
11862
|
-
|
|
11863
|
-
),
|
|
11864
|
-
value: z50.string().trim().min(2).describe(
|
|
11865
|
-
"The Slack user ID, email address, or name to look up, interpreted according to mode."
|
|
11866
|
-
)
|
|
12291
|
+
inputSchema: z54.object({
|
|
12292
|
+
provider: z54.enum(providers).describe("Enabled identity provider to query."),
|
|
12293
|
+
query: z54.string().trim().min(1).describe("Provider subject ID, handle, Slack email, or Slack name.")
|
|
11867
12294
|
}).strict(),
|
|
11868
12295
|
outputSchema: juniorToolOutputSchema,
|
|
11869
|
-
execute: async ({
|
|
12296
|
+
execute: async ({ provider, query }) => {
|
|
11870
12297
|
try {
|
|
11871
|
-
|
|
11872
|
-
const parsedUserId = parseRequiredSlackUserIdParam("value", value);
|
|
11873
|
-
if (!parsedUserId.ok) {
|
|
11874
|
-
throw new ToolInputError(parsedUserId.error);
|
|
11875
|
-
}
|
|
11876
|
-
const user = await lookupSlackUserProfile(parsedUserId.value);
|
|
11877
|
-
await storeProfile(teamId, user);
|
|
11878
|
-
return {
|
|
11879
|
-
mode: "user_id",
|
|
11880
|
-
mention: slackMention(user.id),
|
|
11881
|
-
user
|
|
11882
|
-
};
|
|
11883
|
-
}
|
|
11884
|
-
if (mode === "email") {
|
|
11885
|
-
const stored = await storedUserByEmail(teamId, value);
|
|
11886
|
-
if (stored) {
|
|
11887
|
-
return {
|
|
11888
|
-
mode: "email",
|
|
11889
|
-
mention: slackMention(stored.id),
|
|
11890
|
-
user: stored
|
|
11891
|
-
};
|
|
11892
|
-
}
|
|
11893
|
-
const profile = await lookupSlackUserByEmail(value);
|
|
11894
|
-
if (!profile) {
|
|
11895
|
-
throw new ToolInputError(
|
|
11896
|
-
`No Slack user found with email address ${value}.`
|
|
11897
|
-
);
|
|
11898
|
-
}
|
|
11899
|
-
await storeProfile(teamId, profile);
|
|
11900
|
-
return {
|
|
11901
|
-
mode: "email",
|
|
11902
|
-
mention: slackMention(profile.id),
|
|
11903
|
-
user: profile
|
|
11904
|
-
};
|
|
11905
|
-
}
|
|
11906
|
-
const result = await searchSlackUsers({
|
|
11907
|
-
query: value,
|
|
11908
|
-
limit: 10,
|
|
11909
|
-
maxPages: 3,
|
|
11910
|
-
includeBots: false
|
|
11911
|
-
});
|
|
11912
|
-
if (result.users.length === 1) {
|
|
11913
|
-
await storeProfile(teamId, result.users[0]);
|
|
11914
|
-
}
|
|
11915
|
-
return {
|
|
11916
|
-
mode: "query",
|
|
11917
|
-
query: value,
|
|
11918
|
-
count: result.users.length,
|
|
11919
|
-
searched_pages: result.searched_pages,
|
|
11920
|
-
searched_user_count: result.searched_user_count,
|
|
11921
|
-
truncated: result.truncated,
|
|
11922
|
-
users: result.users.map((user) => ({
|
|
11923
|
-
...user,
|
|
11924
|
-
mention: slackMention(user.id)
|
|
11925
|
-
}))
|
|
11926
|
-
};
|
|
12298
|
+
return provider === "slack" ? await resolveSlack(teamId, query) : await resolveStoredProvider(teamId, provider, query);
|
|
11927
12299
|
} catch (error) {
|
|
11928
12300
|
if (error instanceof SlackActionError) {
|
|
11929
12301
|
const message = explicitUserLookupError(error);
|
|
@@ -11938,18 +12310,18 @@ function createSlackUserLookupTool(teamId) {
|
|
|
11938
12310
|
}
|
|
11939
12311
|
|
|
11940
12312
|
// src/chat/tools/system-time.ts
|
|
11941
|
-
import { z as
|
|
11942
|
-
var systemTimeInputSchema =
|
|
11943
|
-
timezone:
|
|
12313
|
+
import { z as z55 } from "zod";
|
|
12314
|
+
var systemTimeInputSchema = z55.object({
|
|
12315
|
+
timezone: z55.string().trim().min(1).optional().describe(
|
|
11944
12316
|
"Optional IANA timezone, for example America/Los_Angeles. When set, iso_local and timezone_offset_minutes are for that zone."
|
|
11945
12317
|
)
|
|
11946
12318
|
});
|
|
11947
12319
|
var systemTimeOutputSchema = juniorToolOutputSchema.extend({
|
|
11948
|
-
unix_ms:
|
|
11949
|
-
iso_utc:
|
|
11950
|
-
iso_local:
|
|
11951
|
-
timezone:
|
|
11952
|
-
timezone_offset_minutes:
|
|
12320
|
+
unix_ms: z55.number(),
|
|
12321
|
+
iso_utc: z55.string(),
|
|
12322
|
+
iso_local: z55.string(),
|
|
12323
|
+
timezone: z55.string().nullable(),
|
|
12324
|
+
timezone_offset_minutes: z55.number()
|
|
11953
12325
|
});
|
|
11954
12326
|
function createSystemTimeTool() {
|
|
11955
12327
|
return zodTool({
|
|
@@ -12029,27 +12401,27 @@ function getTimeZoneOffsetMinutes(timestampMs, timezone) {
|
|
|
12029
12401
|
}
|
|
12030
12402
|
|
|
12031
12403
|
// src/chat/tools/search-conversation-events.ts
|
|
12032
|
-
import { z as
|
|
12404
|
+
import { z as z56 } from "zod";
|
|
12033
12405
|
var DEFAULT_LIMIT3 = 25;
|
|
12034
12406
|
var MAX_LIMIT = 100;
|
|
12035
12407
|
var MAX_EVENT_DATA_BYTES = 4e3;
|
|
12036
12408
|
var MAX_EVENTS_JSON_BYTES = 2e4;
|
|
12037
12409
|
var MAX_IDENTITY_CHARS = 256;
|
|
12038
12410
|
var textEncoder = new TextEncoder();
|
|
12039
|
-
var knownEventTypeSchema =
|
|
12040
|
-
var projectedEventSchema =
|
|
12041
|
-
seq:
|
|
12042
|
-
history_version:
|
|
12043
|
-
created_at:
|
|
12044
|
-
idempotency_key:
|
|
12045
|
-
data:
|
|
12411
|
+
var knownEventTypeSchema = z56.enum(KNOWN_CONVERSATION_EVENT_TYPES);
|
|
12412
|
+
var projectedEventSchema = z56.object({
|
|
12413
|
+
seq: z56.number().int().nonnegative().describe("Stable event position for pagination."),
|
|
12414
|
+
history_version: z56.number().int().nonnegative().describe("Agent history generation after replacement."),
|
|
12415
|
+
created_at: z56.iso.datetime().describe("When the event was recorded."),
|
|
12416
|
+
idempotency_key: z56.string().min(1).optional().describe("Retry-stable event identity, when assigned."),
|
|
12417
|
+
data: z56.record(z56.string(), z56.unknown()).describe("Bounded event data.")
|
|
12046
12418
|
}).strict();
|
|
12047
12419
|
var searchConversationEventsOutputSchema = juniorToolOutputSchema.extend({
|
|
12048
|
-
conversation_id:
|
|
12049
|
-
events:
|
|
12050
|
-
has_older:
|
|
12051
|
-
has_newer:
|
|
12052
|
-
omitted_event_count:
|
|
12420
|
+
conversation_id: z56.string().min(1),
|
|
12421
|
+
events: z56.array(projectedEventSchema),
|
|
12422
|
+
has_older: z56.boolean().describe("Whether matching older events exist."),
|
|
12423
|
+
has_newer: z56.boolean().describe("Whether matching newer events exist."),
|
|
12424
|
+
omitted_event_count: z56.number().int().nonnegative().optional().describe("Events omitted by the response byte limit.")
|
|
12053
12425
|
});
|
|
12054
12426
|
function createSearchConversationEventsTool(context) {
|
|
12055
12427
|
return zodTool({
|
|
@@ -12062,16 +12434,16 @@ function createSearchConversationEventsTool(context) {
|
|
|
12062
12434
|
openWorldHint: false,
|
|
12063
12435
|
readOnlyHint: true
|
|
12064
12436
|
},
|
|
12065
|
-
inputSchema:
|
|
12066
|
-
conversation_id:
|
|
12437
|
+
inputSchema: z56.object({
|
|
12438
|
+
conversation_id: z56.string().trim().min(1).nullable().describe(
|
|
12067
12439
|
"Conversation ID to search. Omit or null for the current conversation."
|
|
12068
12440
|
).optional(),
|
|
12069
|
-
after_seq:
|
|
12070
|
-
before_seq:
|
|
12071
|
-
limit:
|
|
12441
|
+
after_seq: z56.number().int().nonnegative().nullable().describe("Exclusive event sequence lower bound; returns ascending.").optional(),
|
|
12442
|
+
before_seq: z56.number().int().nonnegative().nullable().describe("Exclusive event sequence upper bound.").optional(),
|
|
12443
|
+
limit: z56.number().int().min(1).max(MAX_LIMIT).nullable().describe(
|
|
12072
12444
|
`Maximum events. Default ${DEFAULT_LIMIT3}; max ${MAX_LIMIT}.`
|
|
12073
12445
|
).optional(),
|
|
12074
|
-
types:
|
|
12446
|
+
types: z56.array(knownEventTypeSchema).min(1).nullable().describe("Event types to include; omit for all types.").optional()
|
|
12075
12447
|
}).strict(),
|
|
12076
12448
|
outputSchema: searchConversationEventsOutputSchema,
|
|
12077
12449
|
execute: async (input) => {
|
|
@@ -12317,10 +12689,10 @@ function stripReplacementHistoryField(value) {
|
|
|
12317
12689
|
}
|
|
12318
12690
|
|
|
12319
12691
|
// src/chat/tools/handoff/tool.ts
|
|
12320
|
-
import { z as
|
|
12692
|
+
import { z as z57 } from "zod";
|
|
12321
12693
|
var HANDOFF_TOOL_NAME = "handoff";
|
|
12322
12694
|
function createHandoffTool(handoff) {
|
|
12323
|
-
const profileSchema =
|
|
12695
|
+
const profileSchema = z57.enum(handoff.profiles);
|
|
12324
12696
|
const handoffResultSchema = juniorToolOutputSchema.extend({
|
|
12325
12697
|
model_profile: modelProfileSchema
|
|
12326
12698
|
});
|
|
@@ -12334,7 +12706,7 @@ function createHandoffTool(handoff) {
|
|
|
12334
12706
|
},
|
|
12335
12707
|
description: `Switch to another execution profile and continue the same task. Profiles: ${profileNames}. Call this as the only tool.`,
|
|
12336
12708
|
executionMode: "sequential",
|
|
12337
|
-
inputSchema:
|
|
12709
|
+
inputSchema: z57.object({
|
|
12338
12710
|
profile: profileSchema.describe("Target execution profile")
|
|
12339
12711
|
}).strict(),
|
|
12340
12712
|
outputSchema: handoffResultSchema,
|
|
@@ -12355,7 +12727,7 @@ function createHandoffTool(handoff) {
|
|
|
12355
12727
|
}
|
|
12356
12728
|
|
|
12357
12729
|
// src/chat/tools/web/fetch-tool.ts
|
|
12358
|
-
import { z as
|
|
12730
|
+
import { z as z58 } from "zod";
|
|
12359
12731
|
|
|
12360
12732
|
// src/chat/tools/web/constants.ts
|
|
12361
12733
|
var USER_AGENT = "junior-bot/0.1";
|
|
@@ -12798,9 +13170,9 @@ function createWebFetchTool(hooks, options = {}) {
|
|
|
12798
13170
|
openWorldHint: true,
|
|
12799
13171
|
readOnlyHint: true
|
|
12800
13172
|
},
|
|
12801
|
-
inputSchema:
|
|
12802
|
-
url:
|
|
12803
|
-
max_chars:
|
|
13173
|
+
inputSchema: z58.object({
|
|
13174
|
+
url: z58.string().min(1).describe("HTTP(S) URL to fetch."),
|
|
13175
|
+
max_chars: z58.coerce.number().int().min(500).max(MAX_FETCH_CHARS).describe("Optional maximum number of extracted characters to return.").optional()
|
|
12804
13176
|
}),
|
|
12805
13177
|
outputSchema: juniorToolOutputSchema,
|
|
12806
13178
|
execute: async ({ url, max_chars }) => {
|
|
@@ -12845,7 +13217,7 @@ function createWebFetchTool(hooks, options = {}) {
|
|
|
12845
13217
|
}
|
|
12846
13218
|
|
|
12847
13219
|
// src/chat/tools/web/search.ts
|
|
12848
|
-
import { z as
|
|
13220
|
+
import { z as z59 } from "zod";
|
|
12849
13221
|
import { generateText } from "ai";
|
|
12850
13222
|
import { createGatewayProvider } from "@ai-sdk/gateway";
|
|
12851
13223
|
var SEARCH_TIMEOUT_MS = 6e4;
|
|
@@ -12887,9 +13259,9 @@ function createWebSearchTool(modelId, override) {
|
|
|
12887
13259
|
openWorldHint: true,
|
|
12888
13260
|
readOnlyHint: true
|
|
12889
13261
|
},
|
|
12890
|
-
inputSchema:
|
|
12891
|
-
query:
|
|
12892
|
-
max_results:
|
|
13262
|
+
inputSchema: z59.object({
|
|
13263
|
+
query: z59.string().min(1).max(500).describe("Search query."),
|
|
13264
|
+
max_results: z59.coerce.number().int().min(1).max(MAX_RESULTS2).describe("Max results to return.").optional()
|
|
12893
13265
|
}),
|
|
12894
13266
|
outputSchema: juniorToolOutputSchema,
|
|
12895
13267
|
execute: async ({ query, max_results }) => {
|
|
@@ -12931,7 +13303,7 @@ function createWebSearchTool(modelId, override) {
|
|
|
12931
13303
|
}
|
|
12932
13304
|
|
|
12933
13305
|
// src/chat/tools/sandbox/write-file.ts
|
|
12934
|
-
import { z as
|
|
13306
|
+
import { z as z60 } from "zod";
|
|
12935
13307
|
function createWriteFileTool() {
|
|
12936
13308
|
return zodTool({
|
|
12937
13309
|
annotations: {
|
|
@@ -12942,9 +13314,9 @@ function createWriteFileTool() {
|
|
|
12942
13314
|
},
|
|
12943
13315
|
description: "Write UTF-8 content to a file in the sandbox workspace. Use for intentional file creation or deliberate full-file replacement after validation; use editFile instead for targeted changes to existing files. Do not use for exploratory analysis-only turns.",
|
|
12944
13316
|
executionMode: "sequential",
|
|
12945
|
-
inputSchema:
|
|
12946
|
-
path:
|
|
12947
|
-
content:
|
|
13317
|
+
inputSchema: z60.object({
|
|
13318
|
+
path: z60.string().min(1).describe("Path to write in the sandbox workspace."),
|
|
13319
|
+
content: z60.string().describe("UTF-8 file content to write.")
|
|
12948
13320
|
}),
|
|
12949
13321
|
outputSchema: juniorToolOutputSchema,
|
|
12950
13322
|
execute: async () => {
|
|
@@ -12956,28 +13328,9 @@ function createWriteFileTool() {
|
|
|
12956
13328
|
}
|
|
12957
13329
|
|
|
12958
13330
|
// src/chat/tools/index.ts
|
|
12959
|
-
function createToolState(
|
|
13331
|
+
function createToolState() {
|
|
12960
13332
|
const operationResultCache = /* @__PURE__ */ new Map();
|
|
12961
|
-
const artifactState = {
|
|
12962
|
-
...context.artifactState ?? {},
|
|
12963
|
-
listColumnMap: {
|
|
12964
|
-
...context.artifactState?.listColumnMap ?? {}
|
|
12965
|
-
}
|
|
12966
|
-
};
|
|
12967
|
-
const patchArtifactState = async (patch) => {
|
|
12968
|
-
Object.assign(artifactState, patch);
|
|
12969
|
-
if (patch.listColumnMap) {
|
|
12970
|
-
artifactState.listColumnMap = {
|
|
12971
|
-
...artifactState.listColumnMap ?? {},
|
|
12972
|
-
...patch.listColumnMap
|
|
12973
|
-
};
|
|
12974
|
-
}
|
|
12975
|
-
await hooks.onArtifactStatePatch?.(patch);
|
|
12976
|
-
};
|
|
12977
13333
|
return {
|
|
12978
|
-
artifactState,
|
|
12979
|
-
patchArtifactState,
|
|
12980
|
-
getCurrentListId: () => artifactState.lastListId,
|
|
12981
13334
|
getOperationResult: (operationKey) => operationResultCache.get(operationKey),
|
|
12982
13335
|
setOperationResult: (operationKey, result) => {
|
|
12983
13336
|
operationResultCache.set(operationKey, result);
|
|
@@ -12985,7 +13338,7 @@ function createToolState(hooks, context) {
|
|
|
12985
13338
|
};
|
|
12986
13339
|
}
|
|
12987
13340
|
function createTools(availableSkills, hooks = {}, context, options = {}) {
|
|
12988
|
-
const state = createToolState(
|
|
13341
|
+
const state = createToolState();
|
|
12989
13342
|
const slackContext = getSlackToolContext(context);
|
|
12990
13343
|
const slackSourceCapabilities = slackContext ? resolveChannelCapabilities(slackContext.sourceChannelId) : void 0;
|
|
12991
13344
|
const canSendFilesToActiveConversation = Boolean(
|
|
@@ -13055,6 +13408,7 @@ function createTools(availableSkills, hooks = {}, context, options = {}) {
|
|
|
13055
13408
|
tools.slackCanvasEdit = createSlackCanvasEditTool(state);
|
|
13056
13409
|
tools.slackCanvasWrite = createSlackCanvasWriteTool(state);
|
|
13057
13410
|
tools.slackThreadRead = createSlackThreadReadTool(slackContext);
|
|
13411
|
+
tools.slackChannelJoin = createSlackChannelJoinTool(slackContext);
|
|
13058
13412
|
if (context.conversationId && slackContext.source.visibility === "public") {
|
|
13059
13413
|
tools.searchConversationMessages = createSlackConversationMessageSearchTool(
|
|
13060
13414
|
{
|
|
@@ -13065,15 +13419,22 @@ function createTools(availableSkills, hooks = {}, context, options = {}) {
|
|
|
13065
13419
|
context.conversationId
|
|
13066
13420
|
);
|
|
13067
13421
|
}
|
|
13068
|
-
if (context.source.platform === "slack"
|
|
13422
|
+
if (context.source.platform === "slack") {
|
|
13069
13423
|
tools.slackPublicSearch = createSlackPublicSearchTool(
|
|
13070
13424
|
context.slackActionToken
|
|
13071
13425
|
);
|
|
13072
13426
|
}
|
|
13073
|
-
|
|
13427
|
+
const identityProviders = [
|
|
13428
|
+
"slack",
|
|
13429
|
+
...getOAuthAccountProviders().filter((provider) => provider !== "slack")
|
|
13430
|
+
];
|
|
13431
|
+
tools.userLookup = createUserLookupTool(
|
|
13432
|
+
slackContext.teamId,
|
|
13433
|
+
identityProviders
|
|
13434
|
+
);
|
|
13074
13435
|
tools.slackListCreate = createSlackListCreateTool(state);
|
|
13075
13436
|
tools.slackListAddItems = createSlackListAddItemsTool(state);
|
|
13076
|
-
tools.slackListGetItems = createSlackListGetItemsTool(
|
|
13437
|
+
tools.slackListGetItems = createSlackListGetItemsTool();
|
|
13077
13438
|
tools.slackListUpdateItem = createSlackListUpdateItemTool(state);
|
|
13078
13439
|
const outputChannelId = slackContext.destinationChannelId;
|
|
13079
13440
|
const outputCapabilities = outputChannelId ? resolveChannelCapabilities(outputChannelId) : void 0;
|
|
@@ -13093,9 +13454,7 @@ function createTools(availableSkills, hooks = {}, context, options = {}) {
|
|
|
13093
13454
|
(input) => readSandboxFileUpload(context.workspace, input)
|
|
13094
13455
|
);
|
|
13095
13456
|
}
|
|
13096
|
-
|
|
13097
|
-
tools.slackChannelListMessages = createSlackChannelListMessagesTool(slackContext);
|
|
13098
|
-
}
|
|
13457
|
+
tools.slackChannelListMessages = createSlackChannelListMessagesTool(slackContext);
|
|
13099
13458
|
if (rawChannelCapabilities.canAddReactions) {
|
|
13100
13459
|
tools.addReaction = createSlackMessageAddReactionTool(
|
|
13101
13460
|
slackContext,
|
|
@@ -13654,7 +14013,7 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, conv
|
|
|
13654
14013
|
}
|
|
13655
14014
|
|
|
13656
14015
|
// src/chat/tools/execute-tool.ts
|
|
13657
|
-
import { z as
|
|
14016
|
+
import { z as z61 } from "zod";
|
|
13658
14017
|
var EXECUTE_TOOL_NAME = "executeTool";
|
|
13659
14018
|
function createExecuteToolTool() {
|
|
13660
14019
|
return zodTool({
|
|
@@ -13666,11 +14025,11 @@ function createExecuteToolTool() {
|
|
|
13666
14025
|
},
|
|
13667
14026
|
description: "Execute any catalog tool by exact tool_name from searchTools or a tool-result execution hint. Put tool-specific parameters inside arguments.",
|
|
13668
14027
|
executionMode: "sequential",
|
|
13669
|
-
inputSchema:
|
|
13670
|
-
tool_name:
|
|
14028
|
+
inputSchema: z61.object({
|
|
14029
|
+
tool_name: z61.string().min(1).describe(
|
|
13671
14030
|
"Exact catalog tool_name returned by searchTools or a tool-result execution hint."
|
|
13672
14031
|
),
|
|
13673
|
-
arguments:
|
|
14032
|
+
arguments: z61.record(z61.string(), z61.unknown()).describe(
|
|
13674
14033
|
'Arguments matching the selected catalog tool schema, for example { "query": "..." }.'
|
|
13675
14034
|
).optional()
|
|
13676
14035
|
}).strict(),
|
|
@@ -13710,7 +14069,7 @@ function planToolExposure(tools) {
|
|
|
13710
14069
|
}
|
|
13711
14070
|
|
|
13712
14071
|
// src/chat/tools/search-tools.ts
|
|
13713
|
-
import { z as
|
|
14072
|
+
import { z as z62 } from "zod";
|
|
13714
14073
|
var SEARCH_TOOLS_NAME = "searchTools";
|
|
13715
14074
|
var DEFAULT_MAX_RESULTS2 = 5;
|
|
13716
14075
|
var MAX_RESULTS3 = 20;
|
|
@@ -13755,29 +14114,29 @@ var SEARCH_STOP_WORDS = /* @__PURE__ */ new Set([
|
|
|
13755
14114
|
"you",
|
|
13756
14115
|
"your"
|
|
13757
14116
|
]);
|
|
13758
|
-
var searchToolsSourceSchema =
|
|
13759
|
-
id:
|
|
13760
|
-
description:
|
|
14117
|
+
var searchToolsSourceSchema = z62.object({
|
|
14118
|
+
id: z62.string(),
|
|
14119
|
+
description: z62.string()
|
|
13761
14120
|
}).strict();
|
|
13762
|
-
var searchToolsToolSchema =
|
|
13763
|
-
tool_name:
|
|
13764
|
-
description:
|
|
13765
|
-
exposure:
|
|
13766
|
-
source:
|
|
13767
|
-
input_schema:
|
|
13768
|
-
call_notes:
|
|
13769
|
-
annotations:
|
|
14121
|
+
var searchToolsToolSchema = z62.object({
|
|
14122
|
+
tool_name: z62.string(),
|
|
14123
|
+
description: z62.string(),
|
|
14124
|
+
exposure: z62.enum(["direct", "deferred", "modelOnly", "hidden"]),
|
|
14125
|
+
source: z62.string().optional(),
|
|
14126
|
+
input_schema: z62.unknown(),
|
|
14127
|
+
call_notes: z62.array(z62.string()),
|
|
14128
|
+
annotations: z62.record(z62.string(), z62.unknown())
|
|
13770
14129
|
}).strict();
|
|
13771
14130
|
var searchToolsOutputSchema = juniorToolOutputSchema.extend({
|
|
13772
|
-
query:
|
|
13773
|
-
source:
|
|
13774
|
-
sources:
|
|
13775
|
-
total_catalog_tools:
|
|
13776
|
-
total_eligible_tools:
|
|
13777
|
-
total_matches:
|
|
13778
|
-
returned_tools:
|
|
13779
|
-
execution_tool:
|
|
13780
|
-
tools:
|
|
14131
|
+
query: z62.string().nullable(),
|
|
14132
|
+
source: z62.string().nullable(),
|
|
14133
|
+
sources: z62.array(searchToolsSourceSchema),
|
|
14134
|
+
total_catalog_tools: z62.number().int().nonnegative(),
|
|
14135
|
+
total_eligible_tools: z62.number().int().nonnegative(),
|
|
14136
|
+
total_matches: z62.number().int().nonnegative(),
|
|
14137
|
+
returned_tools: z62.number().int().nonnegative(),
|
|
14138
|
+
execution_tool: z62.literal("executeTool"),
|
|
14139
|
+
tools: z62.array(searchToolsToolSchema)
|
|
13781
14140
|
}).strict();
|
|
13782
14141
|
function terms(value) {
|
|
13783
14142
|
const chunks = value.match(/[\p{L}\p{N}]+/gu) ?? [];
|
|
@@ -13988,14 +14347,14 @@ function createSearchToolsTool(catalogTools) {
|
|
|
13988
14347
|
openWorldHint: false,
|
|
13989
14348
|
readOnlyHint: true
|
|
13990
14349
|
},
|
|
13991
|
-
inputSchema:
|
|
13992
|
-
query:
|
|
14350
|
+
inputSchema: z62.object({
|
|
14351
|
+
query: z62.string().nullable().describe(
|
|
13993
14352
|
"Optional search terms describing the tool, owner, action, or arguments needed. Empty string lists catalog tools."
|
|
13994
14353
|
).optional(),
|
|
13995
|
-
source:
|
|
14354
|
+
source: z62.string().nullable().describe(
|
|
13996
14355
|
"Optional source id to search within, such as a plugin source returned in sources."
|
|
13997
14356
|
).optional(),
|
|
13998
|
-
max_results:
|
|
14357
|
+
max_results: z62.number().int().min(1).max(MAX_RESULTS3).nullable().describe("Maximum matching catalog tool descriptors to return.").optional()
|
|
13999
14358
|
}).strict(),
|
|
14000
14359
|
outputSchema: searchToolsOutputSchema,
|
|
14001
14360
|
privateTraceResult: (result) => ({
|
|
@@ -14327,7 +14686,6 @@ function createMcpAuthOrchestration(input) {
|
|
|
14327
14686
|
...input.threadTs ? { threadTs: input.threadTs } : {},
|
|
14328
14687
|
...input.toolChannelId ? { toolChannelId: input.toolChannelId } : {},
|
|
14329
14688
|
configuration: input.getConfiguration(),
|
|
14330
|
-
artifactState: input.getArtifactState(),
|
|
14331
14689
|
createAuthorizationState: input.authorization?.createState
|
|
14332
14690
|
});
|
|
14333
14691
|
authSessionIdsByProvider.set(plugin.manifest.name, provider.authSessionId);
|
|
@@ -14365,11 +14723,9 @@ function createMcpAuthOrchestration(input) {
|
|
|
14365
14723
|
});
|
|
14366
14724
|
const reusedAuthSessionId = reusingPendingLink && input.pendingAuth?.kind === "mcp" ? input.pendingAuth.authSessionId : void 0;
|
|
14367
14725
|
const activeAuthSessionId = reusedAuthSessionId ?? authSessionId;
|
|
14368
|
-
const latestArtifactState = input.getMergedArtifactState();
|
|
14369
14726
|
await patchMcpAuthSession(activeAuthSessionId, {
|
|
14370
14727
|
configuration: { ...input.getConfiguration() },
|
|
14371
|
-
|
|
14372
|
-
toolChannelId: input.toolChannelId ?? latestArtifactState.assistantContextChannelId ?? input.channelId
|
|
14728
|
+
toolChannelId: input.toolChannelId ?? input.channelId
|
|
14373
14729
|
});
|
|
14374
14730
|
const providerLabel = formatProviderLabel(provider);
|
|
14375
14731
|
const nextPendingAuth = {
|
|
@@ -15240,7 +15596,7 @@ function createPluginEgress(deps) {
|
|
|
15240
15596
|
}
|
|
15241
15597
|
|
|
15242
15598
|
// src/chat/services/guardian-action-review.ts
|
|
15243
|
-
import { z as
|
|
15599
|
+
import { z as z63 } from "zod";
|
|
15244
15600
|
|
|
15245
15601
|
// src/chat/services/guardian-action-policy.ts
|
|
15246
15602
|
var GUARDIAN_ACTION_POLICY = `You are judging one planned Junior agent action.
|
|
@@ -15308,17 +15664,17 @@ Assess the exact action's intrinsic risk and whether the user's intent authorize
|
|
|
15308
15664
|
- Keep the reason to one concise, specific sentence grounded in the main risk or authorization fact. For ask, name the exact action, target, and material side effects the user must confirm.`;
|
|
15309
15665
|
|
|
15310
15666
|
// src/chat/services/guardian-action-review.ts
|
|
15311
|
-
var guardianDecisionSchema =
|
|
15312
|
-
decision:
|
|
15313
|
-
reason:
|
|
15314
|
-
riskLevel:
|
|
15315
|
-
userAuthorization:
|
|
15667
|
+
var guardianDecisionSchema = z63.object({
|
|
15668
|
+
decision: z63.enum(["allow", "ask", "deny"]),
|
|
15669
|
+
reason: z63.string().trim().min(1).max(500),
|
|
15670
|
+
riskLevel: z63.enum(["low", "medium", "high", "critical"]),
|
|
15671
|
+
userAuthorization: z63.enum(["high", "medium", "low", "unknown"])
|
|
15316
15672
|
}).strict();
|
|
15317
15673
|
var GUARDIAN_REVIEW_TIMEOUT_MS = 6e4;
|
|
15318
15674
|
var GUARDIAN_REVIEW_MAX_TOKENS = 2e3;
|
|
15319
15675
|
var MAX_PROPOSAL_CHARS = 192e3;
|
|
15320
15676
|
function guardianPrompt(proposal) {
|
|
15321
|
-
const proposalJson = JSON.stringify(
|
|
15677
|
+
const proposalJson = JSON.stringify(z63.json().parse(proposal), null, 2);
|
|
15322
15678
|
if (proposalJson.length > MAX_PROPOSAL_CHARS) {
|
|
15323
15679
|
throw new Error(
|
|
15324
15680
|
`Guardian action proposal exceeds ${MAX_PROPOSAL_CHARS} characters.`
|
|
@@ -15346,6 +15702,7 @@ function createGuardianActionReviewer(options) {
|
|
|
15346
15702
|
maxTokens: GUARDIAN_REVIEW_MAX_TOKENS,
|
|
15347
15703
|
recordTelemetryPayloads: false,
|
|
15348
15704
|
temperature: 0,
|
|
15705
|
+
promptName: "junior.guardian_action_review",
|
|
15349
15706
|
signal,
|
|
15350
15707
|
metadata: {
|
|
15351
15708
|
conversationId: proposal.context.conversationId,
|
|
@@ -15562,6 +15919,38 @@ async function tryRecordSkillLoadStat(skill) {
|
|
|
15562
15919
|
});
|
|
15563
15920
|
}
|
|
15564
15921
|
}
|
|
15922
|
+
function resolveToolRuntimeRoute(args) {
|
|
15923
|
+
const destination = toolInvocationDestination(args.routing);
|
|
15924
|
+
switch (args.routing.source.platform) {
|
|
15925
|
+
case "slack": {
|
|
15926
|
+
if (destination.platform !== "slack") {
|
|
15927
|
+
throw new TypeError("Slack tool runtime requires a Slack destination");
|
|
15928
|
+
}
|
|
15929
|
+
return {
|
|
15930
|
+
destination,
|
|
15931
|
+
actor: args.actor?.platform === "slack" ? args.actor : void 0,
|
|
15932
|
+
source: args.routing.source,
|
|
15933
|
+
slackActionToken: args.routing.slackActionToken
|
|
15934
|
+
};
|
|
15935
|
+
}
|
|
15936
|
+
case "local": {
|
|
15937
|
+
if (destination.platform !== "local") {
|
|
15938
|
+
throw new TypeError("Local tool runtime requires a local destination");
|
|
15939
|
+
}
|
|
15940
|
+
return {
|
|
15941
|
+
destination,
|
|
15942
|
+
actor: args.actor?.platform === "local" ? args.actor : void 0,
|
|
15943
|
+
source: args.routing.source
|
|
15944
|
+
};
|
|
15945
|
+
}
|
|
15946
|
+
case "web":
|
|
15947
|
+
return {
|
|
15948
|
+
destination,
|
|
15949
|
+
actor: args.actor?.platform === "web" ? args.actor : void 0,
|
|
15950
|
+
source: args.routing.source
|
|
15951
|
+
};
|
|
15952
|
+
}
|
|
15953
|
+
}
|
|
15565
15954
|
async function wireAgentTools(args) {
|
|
15566
15955
|
const runSource = args.routing.source;
|
|
15567
15956
|
const credentialUserId = args.routing.credentialContext ? credentialUserSubjectId(args.routing.credentialContext) : void 0;
|
|
@@ -15578,7 +15967,7 @@ async function wireAgentTools(args) {
|
|
|
15578
15967
|
egressSignals: args.policy.sandboxEgressSignals,
|
|
15579
15968
|
credentialEgress: args.routing.credentialContext,
|
|
15580
15969
|
actor: args.currentActor,
|
|
15581
|
-
|
|
15970
|
+
locationConfiguration: args.policy.locationConfiguration,
|
|
15582
15971
|
configurationValues: args.configurationValues,
|
|
15583
15972
|
getActiveSkill: () => args.skillSandbox.getActiveSkill(),
|
|
15584
15973
|
prepareSandbox: pluginHooks.prepareSandbox,
|
|
@@ -15600,11 +15989,6 @@ async function wireAgentTools(args) {
|
|
|
15600
15989
|
userMessage: args.userInput,
|
|
15601
15990
|
pendingAuth: args.state.pendingAuth,
|
|
15602
15991
|
getConfiguration: () => args.configurationValues,
|
|
15603
|
-
getArtifactState: () => args.state.artifactState,
|
|
15604
|
-
getMergedArtifactState: () => mergeArtifactsState(
|
|
15605
|
-
args.state.artifactState ?? {},
|
|
15606
|
-
args.artifactStatePatch
|
|
15607
|
-
),
|
|
15608
15992
|
recordPendingAuth: args.durability.recordPendingAuth,
|
|
15609
15993
|
interactiveAuthEnabled: !isAgentRunFeatureDisabled(
|
|
15610
15994
|
args.policy,
|
|
@@ -15617,6 +16001,7 @@ async function wireAgentTools(args) {
|
|
|
15617
16001
|
conversationId: args.conversationId,
|
|
15618
16002
|
sessionId: args.turnId,
|
|
15619
16003
|
actorId: credentialUserId,
|
|
16004
|
+
actor: args.currentActor,
|
|
15620
16005
|
channelId: slackChannelId,
|
|
15621
16006
|
destination: args.routing.destination,
|
|
15622
16007
|
source: runSource,
|
|
@@ -15654,7 +16039,6 @@ async function wireAgentTools(args) {
|
|
|
15654
16039
|
const commonToolRuntimeContext = {
|
|
15655
16040
|
conversationId: args.conversationId,
|
|
15656
16041
|
userText: args.userInput,
|
|
15657
|
-
artifactState: args.state.artifactState,
|
|
15658
16042
|
configuration: args.configurationValues,
|
|
15659
16043
|
egress: createPluginEgress({
|
|
15660
16044
|
credentialContext: args.routing.credentialContext,
|
|
@@ -15683,36 +16067,20 @@ async function wireAgentTools(args) {
|
|
|
15683
16067
|
...args.durability.spawnAgent ? { spawnAgent: args.durability.spawnAgent } : {},
|
|
15684
16068
|
...args.requestHandoff ? { handoff: args.requestHandoff } : {}
|
|
15685
16069
|
};
|
|
15686
|
-
const
|
|
15687
|
-
|
|
15688
|
-
|
|
15689
|
-
|
|
15690
|
-
|
|
15691
|
-
|
|
15692
|
-
|
|
15693
|
-
|
|
15694
|
-
destination: toolDestination,
|
|
15695
|
-
actor: args.currentActor?.platform === "slack" ? args.currentActor : void 0,
|
|
15696
|
-
source: runSource,
|
|
15697
|
-
slackActionToken: args.routing.slackActionToken
|
|
15698
|
-
};
|
|
15699
|
-
} else {
|
|
15700
|
-
if (toolDestination.platform !== "local") {
|
|
15701
|
-
throw new TypeError("Local tool runtime requires a local destination");
|
|
15702
|
-
}
|
|
15703
|
-
toolRuntimeContext = {
|
|
15704
|
-
...commonToolRuntimeContext,
|
|
15705
|
-
destination: toolDestination,
|
|
15706
|
-
actor: args.currentActor?.platform === "local" ? args.currentActor : void 0,
|
|
15707
|
-
source: runSource
|
|
15708
|
-
};
|
|
15709
|
-
}
|
|
16070
|
+
const toolRoute = resolveToolRuntimeRoute({
|
|
16071
|
+
actor: args.currentActor,
|
|
16072
|
+
routing: args.routing
|
|
16073
|
+
});
|
|
16074
|
+
const toolRuntimeContext = {
|
|
16075
|
+
...commonToolRuntimeContext,
|
|
16076
|
+
...toolRoute
|
|
16077
|
+
};
|
|
15710
16078
|
const actionReview = createToolActionReview({
|
|
15711
16079
|
context: {
|
|
15712
16080
|
actor: args.currentActor,
|
|
15713
16081
|
conversationId: args.conversationId,
|
|
15714
16082
|
credentialContext: args.routing.credentialContext,
|
|
15715
|
-
destination:
|
|
16083
|
+
destination: toolRoute.destination,
|
|
15716
16084
|
source: runSource,
|
|
15717
16085
|
userIntent: args.currentUserIntent,
|
|
15718
16086
|
evidence: () => buildToolActionEvidence(args.currentAgentMessages())
|
|
@@ -15742,15 +16110,6 @@ async function wireAgentTools(args) {
|
|
|
15742
16110
|
args.generatedFiles.push(...files);
|
|
15743
16111
|
return refs;
|
|
15744
16112
|
},
|
|
15745
|
-
onArtifactStatePatch: async (patch) => {
|
|
15746
|
-
Object.assign(args.artifactStatePatch, patch);
|
|
15747
|
-
await args.durability.onArtifactStateUpdated?.(
|
|
15748
|
-
mergeArtifactsState(
|
|
15749
|
-
args.state.artifactState ?? {},
|
|
15750
|
-
args.artifactStatePatch
|
|
15751
|
-
)
|
|
15752
|
-
);
|
|
15753
|
-
},
|
|
15754
16113
|
toolOverrides: args.policy.toolOverrides,
|
|
15755
16114
|
onSkillLoaded: async (loadedSkill) => {
|
|
15756
16115
|
const resolvedSkill = await args.skillSandbox.loadSkill(
|
|
@@ -15927,6 +16286,7 @@ function createResumeState(args) {
|
|
|
15927
16286
|
destination: args.destination,
|
|
15928
16287
|
destinationVisibility: args.destinationVisibility,
|
|
15929
16288
|
dispatchId: args.dispatchId,
|
|
16289
|
+
publishExternally: args.publishExternally,
|
|
15930
16290
|
source: args.runSource,
|
|
15931
16291
|
actor: args.actor,
|
|
15932
16292
|
surface: args.surface
|
|
@@ -16329,6 +16689,7 @@ async function summarizeContext(args, deps) {
|
|
|
16329
16689
|
messageAttributeMode: "metadata",
|
|
16330
16690
|
temperature: 0,
|
|
16331
16691
|
signal: args.signal,
|
|
16692
|
+
promptName: "junior.context_compaction",
|
|
16332
16693
|
messages: [
|
|
16333
16694
|
{
|
|
16334
16695
|
role: "user",
|
|
@@ -16734,6 +17095,12 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
16734
17095
|
let connectedMcpProviders = /* @__PURE__ */ new Set();
|
|
16735
17096
|
let turnUsage;
|
|
16736
17097
|
let priorPhaseUsage;
|
|
17098
|
+
let agent;
|
|
17099
|
+
let acceptedToolFreeAssistant = false;
|
|
17100
|
+
const generatedFiles = [];
|
|
17101
|
+
const toolCalls = [];
|
|
17102
|
+
let shouldTrace = false;
|
|
17103
|
+
let getSandboxRef;
|
|
16737
17104
|
const configuredReasoningLevel = policy.reasoningLevel ?? botConfig.reasoningLevel;
|
|
16738
17105
|
let turnRoute = configuredReasoningLevel ? configuredTurnRoute(
|
|
16739
17106
|
STANDARD_MODEL_PROFILE,
|
|
@@ -16772,7 +17139,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
16772
17139
|
activeModelProfile = projection.modelProfile;
|
|
16773
17140
|
activeModelId = modelIdForProfile(botConfig, activeModelProfile);
|
|
16774
17141
|
let durableModelProfile = projection.modelProfile;
|
|
16775
|
-
|
|
17142
|
+
shouldTrace = shouldEmitDevAgentTrace();
|
|
16776
17143
|
const spanContext = { modelId: activeModelId };
|
|
16777
17144
|
const availableSkills = await discoverRunSkills({
|
|
16778
17145
|
skillDirs: policy.skillDirs
|
|
@@ -16829,6 +17196,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
16829
17196
|
...routing.dispatch?.id ? { dispatchId: routing.dispatch.id } : {},
|
|
16830
17197
|
durability,
|
|
16831
17198
|
recordActiveMcpProviders,
|
|
17199
|
+
publishExternally: checkpoint.record?.publishExternally ?? routing.publishExternally ?? false,
|
|
16832
17200
|
actor,
|
|
16833
17201
|
runSource,
|
|
16834
17202
|
conversationId,
|
|
@@ -16851,7 +17219,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
16851
17219
|
});
|
|
16852
17220
|
}
|
|
16853
17221
|
};
|
|
16854
|
-
const persistedConfigurationValues = policy.
|
|
17222
|
+
const persistedConfigurationValues = policy.locationConfiguration ? await policy.locationConfiguration.resolveValues() : {};
|
|
16855
17223
|
const configurationValues = {
|
|
16856
17224
|
...getConfigDefaults(),
|
|
16857
17225
|
...policy.configuration ?? {},
|
|
@@ -16946,6 +17314,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
16946
17314
|
turnId,
|
|
16947
17315
|
modelProfile: routedModelProfile,
|
|
16948
17316
|
modelId: routedModelId,
|
|
17317
|
+
...turnRoute.costUsd !== void 0 ? { costUsd: turnRoute.costUsd } : {},
|
|
16949
17318
|
reasoningLevel: turnRoute.reasoningLevel,
|
|
16950
17319
|
...turnRoute.confidence !== void 0 ? { confidence: turnRoute.confidence } : {},
|
|
16951
17320
|
source: turnRoute.source ?? "configured"
|
|
@@ -16953,10 +17322,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
16953
17322
|
}
|
|
16954
17323
|
activeModelProfile = routedModelProfile;
|
|
16955
17324
|
activeModelId = routedModelId;
|
|
16956
|
-
const generatedFiles = [];
|
|
16957
|
-
const artifactStatePatch = {};
|
|
16958
|
-
const toolCalls = [];
|
|
16959
|
-
let agent;
|
|
16960
17325
|
let pendingPiHookError;
|
|
16961
17326
|
let pendingHandoff;
|
|
16962
17327
|
const currentAgentMessages = () => agent ? [...agent.state.messages] : [];
|
|
@@ -17060,7 +17425,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
17060
17425
|
currentAgentMessages,
|
|
17061
17426
|
currentTurnMessages,
|
|
17062
17427
|
currentUserIntent,
|
|
17063
|
-
artifactStatePatch,
|
|
17064
17428
|
availableSkills,
|
|
17065
17429
|
configurationValues,
|
|
17066
17430
|
connectedMcpProviders,
|
|
@@ -17096,6 +17460,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
17096
17460
|
});
|
|
17097
17461
|
mcpToolManager = wiring.mcpToolManager;
|
|
17098
17462
|
closeTools = wiring.close;
|
|
17463
|
+
getSandboxRef = () => wiring.getSandboxRef();
|
|
17099
17464
|
const initialRepositoryInstructions = wiring.getSandboxRef() ? await wiring.captureRepositoryInstructions() : void 0;
|
|
17100
17465
|
const recordAgentsTransition = async (instructions) => {
|
|
17101
17466
|
try {
|
|
@@ -17149,7 +17514,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
17149
17514
|
} = await assemblePrompt({
|
|
17150
17515
|
activeMcpCatalogs: wiring.activeMcpCatalogs,
|
|
17151
17516
|
currentActor: actor,
|
|
17152
|
-
artifactState: state.artifactState,
|
|
17153
17517
|
availableSkills,
|
|
17154
17518
|
configurationValues,
|
|
17155
17519
|
contextContentParts: [
|
|
@@ -17278,6 +17642,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
17278
17642
|
}
|
|
17279
17643
|
try {
|
|
17280
17644
|
await delivery(message);
|
|
17645
|
+
acceptedToolFreeAssistant = true;
|
|
17281
17646
|
} catch (error) {
|
|
17282
17647
|
assistantMessageDeliveryError = new AssistantMessageDeliveryError(
|
|
17283
17648
|
error
|
|
@@ -17359,13 +17724,13 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
17359
17724
|
return void 0;
|
|
17360
17725
|
},
|
|
17361
17726
|
afterToolCall: async ({ result: result2, toolCall }, signal2) => {
|
|
17362
|
-
const
|
|
17363
|
-
const sourceResult =
|
|
17727
|
+
const timedOutResult = runResume.timedOut && signal2?.aborted ? projectTimedOutToolResult(result2) : void 0;
|
|
17728
|
+
const sourceResult = timedOutResult ?? result2;
|
|
17364
17729
|
const projectedResult = wiring.projectActionReviewResult(
|
|
17365
17730
|
toolCall.id,
|
|
17366
17731
|
sourceResult
|
|
17367
17732
|
);
|
|
17368
|
-
return
|
|
17733
|
+
return timedOutResult || projectedResult !== result2 ? projectedResult : void 0;
|
|
17369
17734
|
},
|
|
17370
17735
|
prepareNextTurnWithContext: async (nextTurn, hookSignal) => {
|
|
17371
17736
|
try {
|
|
@@ -17735,7 +18100,6 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
17735
18100
|
const result = buildTurnResult({
|
|
17736
18101
|
newMessages,
|
|
17737
18102
|
userInput,
|
|
17738
|
-
artifactStatePatch,
|
|
17739
18103
|
toolCalls,
|
|
17740
18104
|
sandboxRef: wiring.getSandboxRef(),
|
|
17741
18105
|
piMessages: [...agent.state.messages],
|
|
@@ -17762,6 +18126,27 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
17762
18126
|
if (resume && runError instanceof AuthorizationPauseError) {
|
|
17763
18127
|
return await resume.parkForAuth(runError, turnUsage);
|
|
17764
18128
|
}
|
|
18129
|
+
if (resume?.timedOut && acceptedToolFreeAssistant && agent && turnRoute) {
|
|
18130
|
+
await recordActiveMcpProviders();
|
|
18131
|
+
const piMessages = [...agent.state.messages];
|
|
18132
|
+
return {
|
|
18133
|
+
status: "completed",
|
|
18134
|
+
result: buildTurnResult({
|
|
18135
|
+
newMessages: piMessages.slice(resume.beforeMessageCount),
|
|
18136
|
+
userInput,
|
|
18137
|
+
toolCalls,
|
|
18138
|
+
sandboxRef: getSandboxRef?.() ?? lastKnownSandboxRef,
|
|
18139
|
+
piMessages,
|
|
18140
|
+
durationMs: Date.now() - replyStartedAtMs,
|
|
18141
|
+
generatedFileCount: generatedFiles.length,
|
|
18142
|
+
shouldTrace,
|
|
18143
|
+
usage: turnUsage,
|
|
18144
|
+
executionProfile: turnRoute,
|
|
18145
|
+
assistantUserName: botConfig.userName,
|
|
18146
|
+
modelId: activeModelId
|
|
18147
|
+
})
|
|
18148
|
+
};
|
|
18149
|
+
}
|
|
17765
18150
|
if (resume) {
|
|
17766
18151
|
const outcome = await resume.translateSuspension({
|
|
17767
18152
|
currentUsage: turnUsage,
|