@sentry/junior 0.74.1 → 0.76.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/README.md +1 -1
- package/bin/junior.mjs +4 -66
- package/dist/agent-hooks-ZOE7RIED.js +37 -0
- package/dist/api-reference.d.ts +3 -1
- package/dist/app.js +5516 -5422
- package/dist/build/copy-build-content.d.ts +1 -1
- package/dist/build/virtual-config.d.ts +2 -2
- package/dist/chat/agent-dispatch/context.d.ts +2 -3
- package/dist/chat/agent-dispatch/runner.d.ts +2 -0
- package/dist/chat/agent-dispatch/types.d.ts +2 -1
- package/dist/chat/config.d.ts +3 -0
- package/dist/chat/credentials/state-adapter-token-store.d.ts +2 -0
- package/dist/chat/credentials/subject.d.ts +3 -3
- package/dist/chat/credentials/user-token-store.d.ts +17 -12
- package/dist/chat/db.d.ts +8 -0
- package/dist/chat/mcp/auth-store.d.ts +2 -1
- package/dist/chat/mcp/oauth.d.ts +2 -1
- package/dist/chat/oauth-flow.d.ts +3 -1
- package/dist/chat/pi/client.d.ts +15 -7
- package/dist/chat/plugins/agent-hooks.d.ts +20 -13
- package/dist/chat/plugins/auth/oauth-request.d.ts +11 -7
- package/dist/chat/plugins/credential-hooks.d.ts +6 -6
- package/dist/chat/plugins/logging.d.ts +2 -2
- package/dist/chat/plugins/model.d.ts +9 -0
- package/dist/chat/plugins/package-discovery.d.ts +2 -1
- package/dist/chat/plugins/prompt.d.ts +5 -0
- package/dist/chat/plugins/registry.d.ts +4 -0
- package/dist/chat/plugins/state.d.ts +3 -5
- package/dist/chat/plugins/task-callback.d.ts +5 -0
- package/dist/chat/plugins/task-message.d.ts +23 -0
- package/dist/chat/plugins/task-queue.d.ts +5 -0
- package/dist/chat/plugins/task-runner.d.ts +12 -0
- package/dist/chat/plugins/task-signing.d.ts +31 -0
- package/dist/chat/plugins/types.d.ts +1 -0
- package/dist/chat/plugins/validation.d.ts +5 -0
- package/dist/chat/prompt.d.ts +15 -1
- package/dist/chat/requester.d.ts +6 -5
- package/dist/chat/respond-helpers.d.ts +2 -0
- package/dist/chat/respond.d.ts +13 -2
- package/dist/chat/runtime/agent-continue-runner.d.ts +4 -0
- package/dist/chat/runtime/reply-executor.d.ts +5 -1
- package/dist/chat/runtime/slack-resume.d.ts +10 -2
- package/dist/chat/runtime/slack-runtime.d.ts +6 -1
- package/dist/chat/sandbox/egress-credentials.d.ts +8 -8
- package/dist/chat/sandbox/sandbox.d.ts +2 -2
- package/dist/chat/sentry.d.ts +1 -0
- package/dist/chat/services/mcp-auth-orchestration.d.ts +2 -1
- package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -1
- package/dist/chat/services/subscribed-decision.d.ts +2 -2
- package/dist/chat/services/turn-session-record.d.ts +11 -7
- package/dist/chat/sql/db.d.ts +3 -0
- package/dist/chat/sql/executor.d.ts +7 -0
- package/dist/chat/sql/neon.d.ts +2 -4
- package/dist/chat/sql/postgres.d.ts +6 -0
- package/dist/chat/state/turn-session.d.ts +8 -5
- package/dist/chat/task-execution/state.d.ts +7 -2
- package/dist/chat/task-execution/worker.d.ts +1 -1
- package/dist/chat/tools/agent-tools.d.ts +9 -2
- package/dist/chat/tools/slack/context.d.ts +2 -2
- package/dist/chat/tools/types.d.ts +7 -4
- package/dist/chat/vercel-queue-client.d.ts +3 -0
- package/dist/{chunk-YOHFWWBV.js → chunk-2ECJXSVQ.js} +5 -107
- package/dist/{chunk-OR6NQJ5E.js → chunk-4SCWV7TJ.js} +3 -3
- package/dist/chunk-4UO6FK4G.js +64 -0
- package/dist/chunk-56TBVRJG.js +115 -0
- package/dist/{chunk-3BYAPS6B.js → chunk-EJN6G5A2.js} +17 -11
- package/dist/{chunk-SQGMG7OD.js → chunk-HHDUKWVG.js} +508 -149
- package/dist/{chunk-6UP2Z2RZ.js → chunk-JBASI5VV.js} +7 -7
- package/dist/chunk-KNFROR7R.js +127 -0
- package/dist/{chunk-HYHKTFG2.js → chunk-KOIMO7S3.js} +186 -910
- package/dist/chunk-MLKGABMK.js +9 -0
- package/dist/chunk-NFTMTIP3.js +964 -0
- package/dist/chunk-NYKJ3KON.js +1082 -0
- package/dist/{chunk-SJHUF3DP.js → chunk-OJ53FYVG.js} +2 -10
- package/dist/{chunk-KVZL5NZS.js → chunk-Q3XNY442.js} +17 -7
- package/dist/{chunk-YRDS7VKO.js → chunk-Q6XFTRV5.js} +2 -2
- package/dist/chunk-R6Z5XWY3.js +1076 -0
- package/dist/chunk-RV5RYIJW.js +56 -0
- package/dist/chunk-SG5WAA7H.js +132 -0
- package/dist/chunk-ST6YNAXG.js +54 -0
- package/dist/{chunk-GM7HTXYC.js → chunk-T77LUIX3.js} +148 -151
- package/dist/{chunk-CYUI7JU5.js → chunk-VALUBQ7R.js} +22 -30
- package/dist/chunk-XBBC6W45.js +71 -0
- package/dist/chunk-Y2CM7HXH.js +111 -0
- package/dist/{chunk-F6HWCPOC.js → chunk-Y5OFBCBZ.js} +1 -1
- package/dist/{chunk-M4FLLXXD.js → chunk-Z4CIQ3EB.js} +5 -1
- package/dist/{chunk-7Q5YOUUT.js → chunk-ZLMBNBUG.js} +146 -52
- package/dist/{chunk-2LUZA3LY.js → chunk-ZQB37HUX.js} +11 -11
- package/dist/cli/chat.js +87 -8
- package/dist/cli/check.js +8 -7
- package/dist/cli/env.js +4 -53
- package/dist/cli/init.js +6 -1
- package/dist/cli/main.js +84 -0
- package/dist/cli/plugins.js +244 -0
- package/dist/cli/run.js +5 -52
- package/dist/cli/snapshot-warmup.js +12 -11
- package/dist/cli/upgrade.js +385 -26
- package/dist/db-7A7PFRGL.js +17 -0
- package/dist/deployment.d.ts +1 -0
- package/dist/handlers/sandbox-egress-route.d.ts +4 -0
- package/dist/handlers/slack-webhook.d.ts +4 -0
- package/dist/handlers/webhooks.d.ts +6 -13
- package/dist/instrumentation.js +14 -18
- package/dist/nitro.d.ts +1 -1
- package/dist/nitro.js +67 -101
- package/dist/plugin-module.d.ts +21 -0
- package/dist/plugins-PZMDS7AT.js +15 -0
- package/dist/plugins.d.ts +9 -5
- package/dist/registry-OIPAJU2O.js +46 -0
- package/dist/reporting/conversations.d.ts +3 -3
- package/dist/reporting.d.ts +6 -5
- package/dist/reporting.js +42 -28
- package/dist/{runner-27NP2TEO.js → runner-KPLNHDCV.js} +77 -19
- package/dist/sentry-4CP5NNQ5.js +31 -0
- package/dist/validation-SLA6IGF7.js +15 -0
- package/dist/vercel.js +1 -1
- package/package.json +14 -11
- package/dist/chat/conversations/configured.d.ts +0 -5
- package/dist/chat/conversations/state.d.ts +0 -4
- package/dist/chunk-2KG3PWR4.js +0 -17
- package/dist/chunk-JL2SLRAT.js +0 -1970
|
@@ -1,31 +1,62 @@
|
|
|
1
|
+
import {
|
|
2
|
+
JUNIOR_THREAD_STATE_TTL_MS,
|
|
3
|
+
buildConversationStatePatch
|
|
4
|
+
} from "./chunk-Z4CIQ3EB.js";
|
|
5
|
+
import {
|
|
6
|
+
buildNonInteractiveShellScript,
|
|
7
|
+
createSandboxInstance,
|
|
8
|
+
getRuntimeDependencyProfileHash,
|
|
9
|
+
getVercelSandboxCredentials,
|
|
10
|
+
isSnapshotMissingError,
|
|
11
|
+
resolveRuntimeDependencySnapshot,
|
|
12
|
+
runNonInteractiveCommand
|
|
13
|
+
} from "./chunk-JBASI5VV.js";
|
|
14
|
+
import {
|
|
15
|
+
pluginTaskId,
|
|
16
|
+
pluginTaskParamsSchema,
|
|
17
|
+
sendVercelPluginTask
|
|
18
|
+
} from "./chunk-KNFROR7R.js";
|
|
1
19
|
import {
|
|
2
20
|
JUNIOR_PERSONALITY,
|
|
3
21
|
abandonAgentTurnSessionRecord,
|
|
22
|
+
buildPluginSystemPromptContributions,
|
|
4
23
|
buildSystemPrompt,
|
|
5
24
|
buildTurnContextPrompt,
|
|
6
|
-
createAgentPluginHookRunner,
|
|
7
25
|
escapeXml,
|
|
8
|
-
getAgentPluginTools,
|
|
9
26
|
getAgentTurnSessionRecord,
|
|
10
|
-
getSlackToolContext,
|
|
11
27
|
loadConnectedMcpProviders,
|
|
12
28
|
recordAuthorizationRequested,
|
|
13
29
|
recordMcpProviderConnected,
|
|
14
|
-
resolveChannelCapabilities,
|
|
15
30
|
upsertAgentTurnSessionRecord
|
|
16
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-KOIMO7S3.js";
|
|
17
32
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
33
|
+
createPluginEmbedder,
|
|
34
|
+
createPluginHookRunner,
|
|
35
|
+
createPluginModel,
|
|
36
|
+
getPluginSystemPromptContributions,
|
|
37
|
+
getPluginTools,
|
|
38
|
+
getPluginUserPromptContributions,
|
|
39
|
+
getPlugins,
|
|
40
|
+
getSlackToolContext,
|
|
41
|
+
resolveChannelCapabilities
|
|
42
|
+
} from "./chunk-NFTMTIP3.js";
|
|
23
43
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
44
|
+
createPluginLogger,
|
|
45
|
+
createPluginState
|
|
46
|
+
} from "./chunk-56TBVRJG.js";
|
|
47
|
+
import {
|
|
48
|
+
getDb
|
|
49
|
+
} from "./chunk-NYKJ3KON.js";
|
|
50
|
+
import {
|
|
51
|
+
SANDBOX_DATA_ROOT,
|
|
52
|
+
SANDBOX_SKILLS_ROOT,
|
|
53
|
+
SANDBOX_WORKSPACE_ROOT,
|
|
54
|
+
sandboxSkillDir,
|
|
55
|
+
sandboxSkillFile
|
|
56
|
+
} from "./chunk-G3E7SCME.js";
|
|
26
57
|
import {
|
|
27
|
-
|
|
28
|
-
} from "./chunk-
|
|
58
|
+
getStateAdapter
|
|
59
|
+
} from "./chunk-Y5OFBCBZ.js";
|
|
29
60
|
import {
|
|
30
61
|
SlackActionError,
|
|
31
62
|
downloadPrivateSlackFile,
|
|
@@ -36,43 +67,7 @@ import {
|
|
|
36
67
|
normalizeSlackConversationId,
|
|
37
68
|
parseDestination,
|
|
38
69
|
withSlackRetries
|
|
39
|
-
} from "./chunk-
|
|
40
|
-
import {
|
|
41
|
-
buildNonInteractiveShellScript,
|
|
42
|
-
createSandboxInstance,
|
|
43
|
-
getRuntimeDependencyProfileHash,
|
|
44
|
-
getVercelSandboxCredentials,
|
|
45
|
-
isSnapshotMissingError,
|
|
46
|
-
resolveRuntimeDependencySnapshot,
|
|
47
|
-
runNonInteractiveCommand
|
|
48
|
-
} from "./chunk-6UP2Z2RZ.js";
|
|
49
|
-
import {
|
|
50
|
-
SANDBOX_DATA_ROOT,
|
|
51
|
-
SANDBOX_SKILLS_ROOT,
|
|
52
|
-
SANDBOX_WORKSPACE_ROOT,
|
|
53
|
-
sandboxSkillDir,
|
|
54
|
-
sandboxSkillFile
|
|
55
|
-
} from "./chunk-G3E7SCME.js";
|
|
56
|
-
import {
|
|
57
|
-
createPluginBroker,
|
|
58
|
-
credentialContextSchema,
|
|
59
|
-
getPluginCapabilityProviders,
|
|
60
|
-
getPluginCatalogSignature,
|
|
61
|
-
getPluginDefinition,
|
|
62
|
-
getPluginDisplayName,
|
|
63
|
-
getPluginMcpProviders,
|
|
64
|
-
getPluginOAuthConfig,
|
|
65
|
-
getPluginProviders,
|
|
66
|
-
isPluginConfigKey,
|
|
67
|
-
resolveAuthTokenPlaceholder,
|
|
68
|
-
resolvePluginCommandEnv
|
|
69
|
-
} from "./chunk-7Q5YOUUT.js";
|
|
70
|
-
import {
|
|
71
|
-
listReferenceFiles
|
|
72
|
-
} from "./chunk-KVZL5NZS.js";
|
|
73
|
-
import {
|
|
74
|
-
getStateAdapter
|
|
75
|
-
} from "./chunk-F6HWCPOC.js";
|
|
70
|
+
} from "./chunk-Q6XFTRV5.js";
|
|
76
71
|
import {
|
|
77
72
|
GEN_AI_PROVIDER_NAME,
|
|
78
73
|
GEN_AI_SERVER_ADDRESS,
|
|
@@ -85,7 +80,7 @@ import {
|
|
|
85
80
|
encodeNonImageAttachmentForPrompt,
|
|
86
81
|
extractAssistantText,
|
|
87
82
|
getGatewayApiKey,
|
|
88
|
-
|
|
83
|
+
getPiGatewayApiKey,
|
|
89
84
|
getPiMessageRole,
|
|
90
85
|
getSessionIdentifiers,
|
|
91
86
|
getTerminalAssistantMessages,
|
|
@@ -100,9 +95,9 @@ import {
|
|
|
100
95
|
normalizeSlackEmojiName,
|
|
101
96
|
normalizeToolNameFromResult,
|
|
102
97
|
parseSlackThreadId,
|
|
103
|
-
prependMissingRuntimeTurnContext,
|
|
104
98
|
resolveConversationPrivacy,
|
|
105
99
|
resolveGatewayModel,
|
|
100
|
+
stripRuntimeTurnContext,
|
|
106
101
|
summarizeMessageText,
|
|
107
102
|
toGenAiMessageMetadata,
|
|
108
103
|
toGenAiMessagesTraceAttributes,
|
|
@@ -112,12 +107,34 @@ import {
|
|
|
112
107
|
toObservablePromptPart,
|
|
113
108
|
trimTrailingAssistantMessages,
|
|
114
109
|
upsertActiveSkill
|
|
115
|
-
} from "./chunk-
|
|
110
|
+
} from "./chunk-T77LUIX3.js";
|
|
111
|
+
import {
|
|
112
|
+
discoverSkills,
|
|
113
|
+
findSkillByName,
|
|
114
|
+
loadSkillsByName,
|
|
115
|
+
parseSkillInvocation
|
|
116
|
+
} from "./chunk-4SCWV7TJ.js";
|
|
117
|
+
import {
|
|
118
|
+
createPluginBroker,
|
|
119
|
+
credentialContextSchema,
|
|
120
|
+
getPluginCapabilityProviders,
|
|
121
|
+
getPluginCatalogSignature,
|
|
122
|
+
getPluginDefinition,
|
|
123
|
+
getPluginDisplayName,
|
|
124
|
+
getPluginMcpProviders,
|
|
125
|
+
getPluginOAuthConfig,
|
|
126
|
+
getPluginProviders,
|
|
127
|
+
isPluginConfigKey,
|
|
128
|
+
resolveAuthTokenPlaceholder,
|
|
129
|
+
resolvePluginCommandEnv
|
|
130
|
+
} from "./chunk-ZLMBNBUG.js";
|
|
116
131
|
import {
|
|
117
132
|
createRequester,
|
|
118
|
-
parseActorUserId
|
|
119
|
-
|
|
120
|
-
|
|
133
|
+
parseActorUserId
|
|
134
|
+
} from "./chunk-VALUBQ7R.js";
|
|
135
|
+
import {
|
|
136
|
+
listReferenceFiles
|
|
137
|
+
} from "./chunk-Q3XNY442.js";
|
|
121
138
|
import {
|
|
122
139
|
extractGenAiUsageAttributes,
|
|
123
140
|
extractGenAiUsageSummary,
|
|
@@ -136,10 +153,11 @@ import {
|
|
|
136
153
|
setTags,
|
|
137
154
|
toOptionalString,
|
|
138
155
|
withSpan
|
|
139
|
-
} from "./chunk-
|
|
156
|
+
} from "./chunk-EJN6G5A2.js";
|
|
140
157
|
import {
|
|
141
|
-
|
|
142
|
-
|
|
158
|
+
startInactiveSpan,
|
|
159
|
+
withActiveSpan
|
|
160
|
+
} from "./chunk-ST6YNAXG.js";
|
|
143
161
|
|
|
144
162
|
// src/chat/configuration/defaults.ts
|
|
145
163
|
var installDefaults = {};
|
|
@@ -724,31 +742,65 @@ var ProviderCredentialRouter = class {
|
|
|
724
742
|
}
|
|
725
743
|
};
|
|
726
744
|
|
|
745
|
+
// src/chat/credentials/user-token-store.ts
|
|
746
|
+
import {
|
|
747
|
+
pluginStoredTokensSchema
|
|
748
|
+
} from "@sentry/junior-plugin-api";
|
|
749
|
+
var storedTokensSchema = pluginStoredTokensSchema;
|
|
750
|
+
|
|
727
751
|
// src/chat/credentials/state-adapter-token-store.ts
|
|
728
752
|
var KEY_PREFIX = "oauth-token";
|
|
729
753
|
var BUFFER_MS = 24 * 60 * 60 * 1e3;
|
|
730
754
|
var LONG_LIVED_TTL_MS = 365 * 24 * 60 * 60 * 1e3;
|
|
755
|
+
var REFRESH_LOCK_TTL_MS = 3e4;
|
|
756
|
+
var REFRESH_LOCK_WAIT_MS = 3e4;
|
|
757
|
+
var REFRESH_LOCK_RETRY_MS = 100;
|
|
731
758
|
function tokenKey(userId, provider) {
|
|
732
759
|
return `${KEY_PREFIX}:${userId}:${provider}`;
|
|
733
760
|
}
|
|
761
|
+
function refreshLockKey(userId, provider) {
|
|
762
|
+
return `${tokenKey(userId, provider)}:refresh`;
|
|
763
|
+
}
|
|
764
|
+
async function sleep(ms) {
|
|
765
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
766
|
+
}
|
|
734
767
|
var StateAdapterTokenStore = class {
|
|
735
768
|
state;
|
|
736
769
|
constructor(stateAdapter) {
|
|
737
770
|
this.state = stateAdapter;
|
|
738
771
|
}
|
|
739
772
|
async get(userId, provider) {
|
|
740
|
-
const stored = await this.state.get(
|
|
741
|
-
|
|
742
|
-
);
|
|
743
|
-
return stored ?? void 0;
|
|
773
|
+
const stored = await this.state.get(tokenKey(userId, provider));
|
|
774
|
+
return stored === null || stored === void 0 ? void 0 : storedTokensSchema.parse(stored);
|
|
744
775
|
}
|
|
745
776
|
async set(userId, provider, tokens) {
|
|
746
|
-
const
|
|
747
|
-
|
|
777
|
+
const parsed = storedTokensSchema.parse(tokens);
|
|
778
|
+
const expiresAt = parsed.refreshTokenExpiresAt ?? parsed.expiresAt;
|
|
779
|
+
const ttlMs = expiresAt ? Math.max(expiresAt - Date.now() + BUFFER_MS, BUFFER_MS) : LONG_LIVED_TTL_MS;
|
|
780
|
+
await this.state.set(tokenKey(userId, provider), parsed, ttlMs);
|
|
748
781
|
}
|
|
749
782
|
async delete(userId, provider) {
|
|
750
783
|
await this.state.delete(tokenKey(userId, provider));
|
|
751
784
|
}
|
|
785
|
+
/** Wait for the per-slot refresh gate so rotated refresh tokens are used once. */
|
|
786
|
+
async withRefresh(userId, provider, callback) {
|
|
787
|
+
const lockKey = refreshLockKey(userId, provider);
|
|
788
|
+
const deadline = Date.now() + REFRESH_LOCK_WAIT_MS;
|
|
789
|
+
while (true) {
|
|
790
|
+
const lock = await this.state.acquireLock(lockKey, REFRESH_LOCK_TTL_MS);
|
|
791
|
+
if (lock) {
|
|
792
|
+
try {
|
|
793
|
+
return await callback();
|
|
794
|
+
} finally {
|
|
795
|
+
await this.state.releaseLock(lock);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
if (Date.now() >= deadline) {
|
|
799
|
+
throw new Error(`Could not acquire OAuth token refresh lock`);
|
|
800
|
+
}
|
|
801
|
+
await sleep(REFRESH_LOCK_RETRY_MS);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
752
804
|
};
|
|
753
805
|
|
|
754
806
|
// src/chat/capabilities/factory.ts
|
|
@@ -1008,18 +1060,48 @@ ${usage}
|
|
|
1008
1060
|
exitCode: 2
|
|
1009
1061
|
});
|
|
1010
1062
|
}
|
|
1063
|
+
async function handlePluginsCommand(args) {
|
|
1064
|
+
const usage = "jr-rpc plugins list";
|
|
1065
|
+
const subverb = (args[0] ?? "").trim();
|
|
1066
|
+
if (subverb !== "list" || args.length !== 1) {
|
|
1067
|
+
return commandResult({
|
|
1068
|
+
stderr: `Usage:
|
|
1069
|
+
${usage}
|
|
1070
|
+
`,
|
|
1071
|
+
exitCode: 2
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
const plugins = getPluginProviders().map((plugin) => ({
|
|
1075
|
+
name: plugin.manifest.name,
|
|
1076
|
+
displayName: plugin.manifest.displayName,
|
|
1077
|
+
description: plugin.manifest.description,
|
|
1078
|
+
capabilities: [...plugin.manifest.capabilities],
|
|
1079
|
+
configKeys: [...plugin.manifest.configKeys]
|
|
1080
|
+
})).sort((left, right) => left.name.localeCompare(right.name));
|
|
1081
|
+
return commandResult({
|
|
1082
|
+
stdout: {
|
|
1083
|
+
ok: true,
|
|
1084
|
+
plugins
|
|
1085
|
+
},
|
|
1086
|
+
exitCode: 0
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1011
1089
|
function createJrRpcCommand(deps) {
|
|
1012
1090
|
return defineCommand("jr-rpc", async (args) => {
|
|
1013
1091
|
const usage = [
|
|
1014
1092
|
"jr-rpc config get <key>",
|
|
1015
1093
|
"jr-rpc config set <key> <value> [--json]",
|
|
1016
1094
|
"jr-rpc config unset <key>",
|
|
1017
|
-
"jr-rpc config list [--prefix <value>]"
|
|
1095
|
+
"jr-rpc config list [--prefix <value>]",
|
|
1096
|
+
"jr-rpc plugins list"
|
|
1018
1097
|
].join("\n");
|
|
1019
1098
|
const verb = (args[0] ?? "").trim();
|
|
1020
1099
|
if (verb === "config") {
|
|
1021
1100
|
return handleConfigCommand(args.slice(1), deps);
|
|
1022
1101
|
}
|
|
1102
|
+
if (verb === "plugins") {
|
|
1103
|
+
return handlePluginsCommand(args.slice(1));
|
|
1104
|
+
}
|
|
1023
1105
|
return commandResult({
|
|
1024
1106
|
stderr: `Unsupported jr-rpc command. Use:
|
|
1025
1107
|
${usage}
|
|
@@ -5874,8 +5956,9 @@ function createAdvisorTool(context) {
|
|
|
5874
5956
|
"Advisor guidance is unavailable because advisor history could not be loaded. Continue without assuming advisor history."
|
|
5875
5957
|
);
|
|
5876
5958
|
}
|
|
5959
|
+
const apiKeyOverride = getPiGatewayApiKey();
|
|
5877
5960
|
const advisorAgent = new Agent({
|
|
5878
|
-
getApiKey: () =>
|
|
5961
|
+
...apiKeyOverride ? { getApiKey: () => apiKeyOverride } : {},
|
|
5879
5962
|
initialState: {
|
|
5880
5963
|
systemPrompt: ADVISOR_SYSTEM_PROMPT,
|
|
5881
5964
|
model: resolveGatewayModel(context.config.modelId),
|
|
@@ -6685,6 +6768,7 @@ function createTools(availableSkills, hooks = {}, context) {
|
|
|
6685
6768
|
tools.slackListUpdateItem = createSlackListUpdateItemTool(state);
|
|
6686
6769
|
const outputChannelId = slackContext.destinationChannelId;
|
|
6687
6770
|
const outputCapabilities = outputChannelId ? resolveChannelCapabilities(outputChannelId) : void 0;
|
|
6771
|
+
const canPostStandaloneSlackMessage = context.surface === void 0 || context.surface === "slack";
|
|
6688
6772
|
const rawChannelCapabilities = resolveChannelCapabilities(
|
|
6689
6773
|
slackContext.sourceChannelId
|
|
6690
6774
|
);
|
|
@@ -6694,11 +6778,13 @@ function createTools(availableSkills, hooks = {}, context) {
|
|
|
6694
6778
|
state
|
|
6695
6779
|
);
|
|
6696
6780
|
}
|
|
6697
|
-
if (outputCapabilities?.canPostToChannel) {
|
|
6781
|
+
if (outputCapabilities?.canPostToChannel && canPostStandaloneSlackMessage) {
|
|
6698
6782
|
tools.slackChannelPostMessage = createSlackChannelPostMessageTool(
|
|
6699
6783
|
slackContext,
|
|
6700
6784
|
state
|
|
6701
6785
|
);
|
|
6786
|
+
}
|
|
6787
|
+
if (outputCapabilities?.canPostToChannel) {
|
|
6702
6788
|
tools.slackChannelListMessages = createSlackChannelListMessagesTool(slackContext);
|
|
6703
6789
|
}
|
|
6704
6790
|
if (rawChannelCapabilities.canAddReactions) {
|
|
@@ -6708,9 +6794,7 @@ function createTools(availableSkills, hooks = {}, context) {
|
|
|
6708
6794
|
);
|
|
6709
6795
|
}
|
|
6710
6796
|
}
|
|
6711
|
-
for (const [name, pluginTool] of Object.entries(
|
|
6712
|
-
getAgentPluginTools(context)
|
|
6713
|
-
)) {
|
|
6797
|
+
for (const [name, pluginTool] of Object.entries(getPluginTools(context))) {
|
|
6714
6798
|
if (tools[name]) {
|
|
6715
6799
|
throw new Error(`Plugin tool "${name}" conflicts with a core tool`);
|
|
6716
6800
|
}
|
|
@@ -6784,7 +6868,7 @@ function createTracedStreamFn(baseOrOptions = streamSimple) {
|
|
|
6784
6868
|
const conversationPrivacy = typeof baseOrOptions === "function" ? void 0 : baseOrOptions.conversationPrivacy;
|
|
6785
6869
|
const effectivePrivacy = conversationPrivacy ?? "private";
|
|
6786
6870
|
return async (model, context, options) => {
|
|
6787
|
-
const span =
|
|
6871
|
+
const span = startInactiveSpan({
|
|
6788
6872
|
name: `chat ${model.id}`,
|
|
6789
6873
|
op: "gen_ai.chat",
|
|
6790
6874
|
attributes: {
|
|
@@ -6793,7 +6877,7 @@ function createTracedStreamFn(baseOrOptions = streamSimple) {
|
|
|
6793
6877
|
}
|
|
6794
6878
|
});
|
|
6795
6879
|
try {
|
|
6796
|
-
const stream = await
|
|
6880
|
+
const stream = await withActiveSpan(
|
|
6797
6881
|
span,
|
|
6798
6882
|
() => Promise.resolve(base(model, context, options))
|
|
6799
6883
|
);
|
|
@@ -6829,6 +6913,9 @@ import fs3 from "fs/promises";
|
|
|
6829
6913
|
|
|
6830
6914
|
// src/chat/oauth-flow.ts
|
|
6831
6915
|
import { randomBytes } from "crypto";
|
|
6916
|
+
import {
|
|
6917
|
+
sourceSchema
|
|
6918
|
+
} from "@sentry/junior-plugin-api";
|
|
6832
6919
|
var OAUTH_STATE_TTL_MS = 10 * 60 * 1e3;
|
|
6833
6920
|
function optionalString(value) {
|
|
6834
6921
|
return typeof value === "string" ? value : void 0;
|
|
@@ -6844,13 +6931,22 @@ function parseOAuthStatePayload(value) {
|
|
|
6844
6931
|
if (value.destination !== void 0 && !destination) {
|
|
6845
6932
|
return void 0;
|
|
6846
6933
|
}
|
|
6934
|
+
const source = value.source === void 0 ? void 0 : sourceSchema.safeParse(value.source);
|
|
6935
|
+
if (value.source !== void 0 && (!source || !source.success)) {
|
|
6936
|
+
return void 0;
|
|
6937
|
+
}
|
|
6938
|
+
const pendingMessage = optionalString(value.pendingMessage);
|
|
6939
|
+
if (pendingMessage && !source?.success) {
|
|
6940
|
+
return void 0;
|
|
6941
|
+
}
|
|
6847
6942
|
return {
|
|
6848
6943
|
userId: value.userId,
|
|
6849
6944
|
provider: value.provider,
|
|
6850
6945
|
...optionalString(value.channelId) ? { channelId: optionalString(value.channelId) } : {},
|
|
6851
6946
|
...destination ? { destination } : {},
|
|
6947
|
+
...source?.success ? { source: source.data } : {},
|
|
6852
6948
|
...optionalString(value.threadTs) ? { threadTs: optionalString(value.threadTs) } : {},
|
|
6853
|
-
...
|
|
6949
|
+
...pendingMessage ? { pendingMessage } : {},
|
|
6854
6950
|
...isRecord(value.configuration) ? { configuration: value.configuration } : {},
|
|
6855
6951
|
...optionalString(value.resumeConversationId) ? { resumeConversationId: optionalString(value.resumeConversationId) } : {},
|
|
6856
6952
|
...optionalString(value.resumeSessionId) ? { resumeSessionId: optionalString(value.resumeSessionId) } : {},
|
|
@@ -6972,6 +7068,7 @@ async function startOAuthFlow(provider, input) {
|
|
|
6972
7068
|
provider,
|
|
6973
7069
|
...input.channelId ? { channelId: input.channelId } : {},
|
|
6974
7070
|
...input.destination ? { destination: input.destination } : {},
|
|
7071
|
+
...input.source ? { source: input.source } : {},
|
|
6975
7072
|
...input.threadTs ? { threadTs: input.threadTs } : {},
|
|
6976
7073
|
...input.userMessage ? { pendingMessage: input.userMessage } : {},
|
|
6977
7074
|
...configuration && Object.keys(configuration).length > 0 ? { configuration } : {},
|
|
@@ -7021,16 +7118,16 @@ import { createHmac, randomUUID, timingSafeEqual } from "crypto";
|
|
|
7021
7118
|
// src/chat/sandbox/egress-schemas.ts
|
|
7022
7119
|
import { z } from "zod";
|
|
7023
7120
|
import {
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7121
|
+
pluginAuthorizationSchema,
|
|
7122
|
+
pluginCredentialHeaderTransformSchema,
|
|
7123
|
+
pluginGrantSchema,
|
|
7124
|
+
pluginProviderAccountSchema
|
|
7028
7125
|
} from "@sentry/junior-plugin-api";
|
|
7029
7126
|
var finiteNumberSchema = z.number().refine(Number.isFinite);
|
|
7030
7127
|
var httpStatusSchema = z.number().int().min(100).max(599);
|
|
7031
7128
|
var providerNameSchema = z.string().regex(/^[a-z][a-z0-9-]*$/);
|
|
7032
7129
|
var credentialSignalKindSchema = z.enum(["auth_required", "unavailable"]);
|
|
7033
|
-
var sandboxEgressGrantSchema =
|
|
7130
|
+
var sandboxEgressGrantSchema = pluginGrantSchema;
|
|
7034
7131
|
var sandboxEgressCredentialContextSchema = z.object({
|
|
7035
7132
|
credentials: credentialContextSchema,
|
|
7036
7133
|
egressId: z.string().min(1),
|
|
@@ -7038,15 +7135,15 @@ var sandboxEgressCredentialContextSchema = z.object({
|
|
|
7038
7135
|
contextId: z.string().min(1)
|
|
7039
7136
|
}).strict();
|
|
7040
7137
|
var sandboxEgressCredentialLeaseSchema = z.object({
|
|
7041
|
-
account:
|
|
7042
|
-
authorization:
|
|
7138
|
+
account: pluginProviderAccountSchema.optional(),
|
|
7139
|
+
authorization: pluginAuthorizationSchema.optional(),
|
|
7043
7140
|
grant: sandboxEgressGrantSchema,
|
|
7044
7141
|
provider: providerNameSchema,
|
|
7045
7142
|
expiresAt: z.string().min(1),
|
|
7046
|
-
headerTransforms: z.array(
|
|
7143
|
+
headerTransforms: z.array(pluginCredentialHeaderTransformSchema).min(1)
|
|
7047
7144
|
}).strict();
|
|
7048
7145
|
var sandboxEgressAuthRequiredSignalSchema = z.object({
|
|
7049
|
-
authorization:
|
|
7146
|
+
authorization: pluginAuthorizationSchema.optional(),
|
|
7050
7147
|
grant: sandboxEgressGrantSchema,
|
|
7051
7148
|
kind: credentialSignalKindSchema.default("auth_required"),
|
|
7052
7149
|
provider: providerNameSchema,
|
|
@@ -7062,7 +7159,7 @@ var sandboxEgressAuthRequiredSignalSchema = z.object({
|
|
|
7062
7159
|
}
|
|
7063
7160
|
});
|
|
7064
7161
|
var sandboxEgressPermissionDeniedSignalSchema = z.object({
|
|
7065
|
-
account:
|
|
7162
|
+
account: pluginProviderAccountSchema.optional(),
|
|
7066
7163
|
acceptedPermissions: z.string().optional(),
|
|
7067
7164
|
grant: sandboxEgressGrantSchema,
|
|
7068
7165
|
message: z.string().min(1),
|
|
@@ -7808,7 +7905,7 @@ function truncateOutput(output, maxLength) {
|
|
|
7808
7905
|
truncated: true
|
|
7809
7906
|
};
|
|
7810
7907
|
}
|
|
7811
|
-
function
|
|
7908
|
+
function sleep2(ms) {
|
|
7812
7909
|
return new Promise((resolve) => {
|
|
7813
7910
|
setTimeout(resolve, ms);
|
|
7814
7911
|
});
|
|
@@ -7979,7 +8076,7 @@ function createSandboxSessionManager(options) {
|
|
|
7979
8076
|
if (!isSnapshottingError(error) || attempt === SNAPSHOT_BOOT_RETRY_COUNT - 1) {
|
|
7980
8077
|
throw error;
|
|
7981
8078
|
}
|
|
7982
|
-
await
|
|
8079
|
+
await sleep2(SNAPSHOT_BOOT_RETRY_DELAY_MS);
|
|
7983
8080
|
}
|
|
7984
8081
|
}
|
|
7985
8082
|
throw new Error(`Failed to boot sandbox from snapshot ${snapshotId}`);
|
|
@@ -9100,12 +9197,15 @@ function normalizeToolResult(result, isSandboxResult) {
|
|
|
9100
9197
|
}
|
|
9101
9198
|
|
|
9102
9199
|
// src/chat/tools/execution/tool-error-handler.ts
|
|
9103
|
-
import {
|
|
9200
|
+
import { PluginToolInputError } from "@sentry/junior-plugin-api";
|
|
9104
9201
|
|
|
9105
9202
|
// src/chat/services/plugin-auth-orchestration.ts
|
|
9106
9203
|
import { THREAD_STATE_TTL_MS } from "chat";
|
|
9107
9204
|
|
|
9108
9205
|
// src/chat/mcp/auth-store.ts
|
|
9206
|
+
import {
|
|
9207
|
+
sourceSchema as sourceSchema2
|
|
9208
|
+
} from "@sentry/junior-plugin-api";
|
|
9109
9209
|
var MCP_AUTH_SESSION_PREFIX = "junior:mcp_auth_session";
|
|
9110
9210
|
var MCP_AUTH_CREDENTIALS_PREFIX = "junior:mcp_auth_credentials";
|
|
9111
9211
|
var MCP_AUTH_SESSION_INDEX_PREFIX = "junior:mcp_auth_session_index";
|
|
@@ -9157,12 +9257,17 @@ function parseMcpAuthSession(value) {
|
|
|
9157
9257
|
if (parsed.destination !== void 0 && !destination) {
|
|
9158
9258
|
return void 0;
|
|
9159
9259
|
}
|
|
9260
|
+
const source = parsed.source === void 0 ? void 0 : sourceSchema2.safeParse(parsed.source);
|
|
9261
|
+
if (parsed.source !== void 0 && (!source || !source.success)) {
|
|
9262
|
+
return void 0;
|
|
9263
|
+
}
|
|
9160
9264
|
return {
|
|
9161
9265
|
authSessionId: parsed.authSessionId,
|
|
9162
9266
|
provider: parsed.provider,
|
|
9163
9267
|
userId: parsed.userId,
|
|
9164
9268
|
conversationId: parsed.conversationId,
|
|
9165
9269
|
...destination ? { destination } : {},
|
|
9270
|
+
...source?.success ? { source: source.data } : {},
|
|
9166
9271
|
sessionId: parsed.sessionId,
|
|
9167
9272
|
userMessage: parsed.userMessage,
|
|
9168
9273
|
createdAtMs: parsed.createdAtMs,
|
|
@@ -9483,6 +9588,7 @@ function createPluginAuthOrchestration(input) {
|
|
|
9483
9588
|
requesterId: input.requesterId,
|
|
9484
9589
|
channelId: input.channelId,
|
|
9485
9590
|
destination: input.destination,
|
|
9591
|
+
source: input.source,
|
|
9486
9592
|
threadTs: input.threadTs,
|
|
9487
9593
|
userMessage: input.userMessage,
|
|
9488
9594
|
channelConfiguration: input.channelConfiguration,
|
|
@@ -9580,7 +9686,7 @@ function createPluginAuthOrchestration(input) {
|
|
|
9580
9686
|
|
|
9581
9687
|
// src/chat/tools/execution/tool-error-handler.ts
|
|
9582
9688
|
function isPluginToolInputError(error) {
|
|
9583
|
-
return error instanceof
|
|
9689
|
+
return error instanceof PluginToolInputError || error instanceof Error && error.name === "PluginToolInputError";
|
|
9584
9690
|
}
|
|
9585
9691
|
function getToolErrorType(error) {
|
|
9586
9692
|
if (error instanceof McpToolError) return "tool_error";
|
|
@@ -9661,12 +9767,27 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, trac
|
|
|
9661
9767
|
}
|
|
9662
9768
|
|
|
9663
9769
|
// src/chat/tools/agent-tools.ts
|
|
9664
|
-
function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor, pluginAuthOrchestration, onToolCall, agentHooks, conversationPrivacy) {
|
|
9770
|
+
function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor, pluginAuthOrchestration, onToolCall, agentHooks, conversationPrivacy, onToolResult) {
|
|
9665
9771
|
const shouldTrace = shouldEmitDevAgentTrace();
|
|
9666
9772
|
const effectiveConversationPrivacy = conversationPrivacy ?? "private";
|
|
9667
9773
|
const serializeToolPayload = (payload) => serializeGenAiAttribute(
|
|
9668
9774
|
effectiveConversationPrivacy === "private" ? toGenAiPayloadMetadata(payload) : payload
|
|
9669
9775
|
);
|
|
9776
|
+
const notifyToolResult = async (report) => {
|
|
9777
|
+
try {
|
|
9778
|
+
await onToolResult?.(report);
|
|
9779
|
+
} catch (error) {
|
|
9780
|
+
logWarn(
|
|
9781
|
+
"tool_result_observer_failed",
|
|
9782
|
+
spanContext,
|
|
9783
|
+
{
|
|
9784
|
+
"gen_ai.tool.name": report.toolName,
|
|
9785
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
9786
|
+
},
|
|
9787
|
+
"Tool result observer failed"
|
|
9788
|
+
);
|
|
9789
|
+
}
|
|
9790
|
+
};
|
|
9670
9791
|
return Object.entries(tools).map(([toolName, toolDef]) => ({
|
|
9671
9792
|
name: toolName,
|
|
9672
9793
|
label: toolName,
|
|
@@ -9716,7 +9837,7 @@ function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor
|
|
|
9716
9837
|
input: parsed
|
|
9717
9838
|
}) : { input: parsed, env: {} };
|
|
9718
9839
|
const toolInput = beforeTool.input;
|
|
9719
|
-
onToolCall?.(toolName, toolInput);
|
|
9840
|
+
await onToolCall?.(toolName, toolInput);
|
|
9720
9841
|
const sandboxInput = buildSandboxInput(toolName, toolInput);
|
|
9721
9842
|
const isSandbox = Boolean(sandboxExecutor?.canExecute(toolName));
|
|
9722
9843
|
const result = isSandbox ? await sandboxExecutor.execute({
|
|
@@ -9731,7 +9852,9 @@ function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor
|
|
|
9731
9852
|
});
|
|
9732
9853
|
const normalized = normalizeToolResult(result, isSandbox);
|
|
9733
9854
|
if (isSandbox && pluginAuthOrchestration) {
|
|
9734
|
-
await pluginAuthOrchestration.maybeHandleAuthSignal(
|
|
9855
|
+
await pluginAuthOrchestration.maybeHandleAuthSignal(
|
|
9856
|
+
normalized.details
|
|
9857
|
+
);
|
|
9735
9858
|
}
|
|
9736
9859
|
const resultAttributeValue = normalized.details && typeof normalized.details === "object" && "rawResult" in normalized.details && normalized.details.rawResult !== void 0 ? normalized.details.rawResult : normalized.details;
|
|
9737
9860
|
const toolResultAttribute = serializeToolPayload(resultAttributeValue);
|
|
@@ -9744,8 +9867,20 @@ function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor
|
|
|
9744
9867
|
)
|
|
9745
9868
|
});
|
|
9746
9869
|
}
|
|
9870
|
+
await notifyToolResult({
|
|
9871
|
+
ok: true,
|
|
9872
|
+
params: toolInput,
|
|
9873
|
+
result: resultAttributeValue,
|
|
9874
|
+
toolName
|
|
9875
|
+
});
|
|
9747
9876
|
return normalized;
|
|
9748
9877
|
} catch (error) {
|
|
9878
|
+
await notifyToolResult({
|
|
9879
|
+
error: error instanceof Error ? error.message : String(error),
|
|
9880
|
+
ok: false,
|
|
9881
|
+
params: parsed,
|
|
9882
|
+
toolName
|
|
9883
|
+
});
|
|
9749
9884
|
if (error instanceof AuthorizationPauseError || error instanceof AuthorizationFlowDisabledError) {
|
|
9750
9885
|
throw error;
|
|
9751
9886
|
}
|
|
@@ -10352,7 +10487,7 @@ async function loadTurnSessionRecord(ctx) {
|
|
|
10352
10487
|
const canUseTurnSession = Boolean(ctx.conversationId && ctx.sessionId);
|
|
10353
10488
|
const existingSessionRecord = canUseTurnSession && ctx.conversationId && ctx.sessionId ? await getAgentTurnSessionRecord(ctx.conversationId, ctx.sessionId) : void 0;
|
|
10354
10489
|
const hasAwaitingResumeRecord = Boolean(
|
|
10355
|
-
existingSessionRecord && existingSessionRecord.state === "awaiting_resume"
|
|
10490
|
+
existingSessionRecord && existingSessionRecord.state === "awaiting_resume"
|
|
10356
10491
|
);
|
|
10357
10492
|
return {
|
|
10358
10493
|
canUseTurnSession,
|
|
@@ -10376,6 +10511,7 @@ async function persistRunningSessionRecord(args) {
|
|
|
10376
10511
|
cumulativeDurationMs: latestSessionRecord?.cumulativeDurationMs,
|
|
10377
10512
|
cumulativeUsage: latestSessionRecord?.cumulativeUsage,
|
|
10378
10513
|
...args.destination ?? latestSessionRecord?.destination ? { destination: args.destination ?? latestSessionRecord?.destination } : {},
|
|
10514
|
+
...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
|
|
10379
10515
|
sessionId: args.sessionId,
|
|
10380
10516
|
sliceId: args.sliceId,
|
|
10381
10517
|
state: "running",
|
|
@@ -10420,6 +10556,7 @@ async function persistCompletedSessionRecord(args) {
|
|
|
10420
10556
|
args.currentUsage
|
|
10421
10557
|
),
|
|
10422
10558
|
...args.destination ?? latestSessionRecord?.destination ? { destination: args.destination ?? latestSessionRecord?.destination } : {},
|
|
10559
|
+
...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
|
|
10423
10560
|
sessionId: args.sessionId,
|
|
10424
10561
|
sliceId: args.sliceId,
|
|
10425
10562
|
state: "completed",
|
|
@@ -10455,7 +10592,7 @@ async function persistAuthPauseSessionRecord(args) {
|
|
|
10455
10592
|
args.messages,
|
|
10456
10593
|
latestSessionRecord?.piMessages
|
|
10457
10594
|
);
|
|
10458
|
-
if (piMessages.length
|
|
10595
|
+
if (piMessages.length > 0 && !isContinuableBoundary(piMessages)) {
|
|
10459
10596
|
return void 0;
|
|
10460
10597
|
}
|
|
10461
10598
|
return await upsertAgentTurnSessionRecord({
|
|
@@ -10470,6 +10607,7 @@ async function persistAuthPauseSessionRecord(args) {
|
|
|
10470
10607
|
args.currentUsage
|
|
10471
10608
|
),
|
|
10472
10609
|
...args.destination ?? latestSessionRecord?.destination ? { destination: args.destination ?? latestSessionRecord?.destination } : {},
|
|
10610
|
+
...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
|
|
10473
10611
|
sessionId: args.sessionId,
|
|
10474
10612
|
sliceId: nextSliceId,
|
|
10475
10613
|
state: "awaiting_resume",
|
|
@@ -10529,6 +10667,7 @@ async function persistTimeoutSessionRecord(args) {
|
|
|
10529
10667
|
...args.destination ?? latestSessionRecord?.destination ? {
|
|
10530
10668
|
destination: args.destination ?? latestSessionRecord?.destination
|
|
10531
10669
|
} : {},
|
|
10670
|
+
...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
|
|
10532
10671
|
sessionId: args.sessionId,
|
|
10533
10672
|
sliceId: args.currentSliceId,
|
|
10534
10673
|
state: "failed",
|
|
@@ -10548,6 +10687,7 @@ async function persistTimeoutSessionRecord(args) {
|
|
|
10548
10687
|
cumulativeDurationMs,
|
|
10549
10688
|
cumulativeUsage,
|
|
10550
10689
|
...args.destination ?? latestSessionRecord?.destination ? { destination: args.destination ?? latestSessionRecord?.destination } : {},
|
|
10690
|
+
...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
|
|
10551
10691
|
sessionId: args.sessionId,
|
|
10552
10692
|
sliceId: nextSliceId,
|
|
10553
10693
|
state: "awaiting_resume",
|
|
@@ -10599,6 +10739,7 @@ async function persistYieldSessionRecord(args) {
|
|
|
10599
10739
|
args.currentUsage
|
|
10600
10740
|
),
|
|
10601
10741
|
...args.destination ?? latestSessionRecord?.destination ? { destination: args.destination ?? latestSessionRecord?.destination } : {},
|
|
10742
|
+
...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
|
|
10602
10743
|
sessionId: args.sessionId,
|
|
10603
10744
|
sliceId: args.currentSliceId,
|
|
10604
10745
|
state: "awaiting_resume",
|
|
@@ -10815,6 +10956,7 @@ async function createMcpOAuthClientProvider(input) {
|
|
|
10815
10956
|
userId: input.userId,
|
|
10816
10957
|
conversationId: input.conversationId,
|
|
10817
10958
|
...input.destination ? { destination: input.destination } : {},
|
|
10959
|
+
...input.source ? { source: input.source } : {},
|
|
10818
10960
|
sessionId: input.sessionId,
|
|
10819
10961
|
userMessage: input.userMessage,
|
|
10820
10962
|
...input.channelId ? { channelId: input.channelId } : {},
|
|
@@ -10916,6 +11058,7 @@ function createMcpAuthOrchestration(input) {
|
|
|
10916
11058
|
provider: plugin.manifest.name,
|
|
10917
11059
|
conversationId: input.conversationId,
|
|
10918
11060
|
destination: input.destination,
|
|
11061
|
+
source: input.source,
|
|
10919
11062
|
sessionId: input.sessionId,
|
|
10920
11063
|
userId: input.requesterId,
|
|
10921
11064
|
userMessage: input.userMessage,
|
|
@@ -11021,7 +11164,7 @@ function createMcpAuthOrchestration(input) {
|
|
|
11021
11164
|
|
|
11022
11165
|
// src/chat/respond.ts
|
|
11023
11166
|
var AGENT_ABORT_SETTLE_GRACE_MS = 5e3;
|
|
11024
|
-
function
|
|
11167
|
+
function sleep3(ms) {
|
|
11025
11168
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
11026
11169
|
}
|
|
11027
11170
|
function waitForAbortSettlement(promise, timeoutMs) {
|
|
@@ -11078,8 +11221,7 @@ function extractSliceUsage(messages, beforeMessageCount) {
|
|
|
11078
11221
|
return hasAgentTurnUsage(usage) ? usage : void 0;
|
|
11079
11222
|
}
|
|
11080
11223
|
function requesterFromContext(context) {
|
|
11081
|
-
|
|
11082
|
-
return identity?.platform === "slack" ? toStoredSlackRequester(identity) : void 0;
|
|
11224
|
+
return actorRequesterFromContext(context);
|
|
11083
11225
|
}
|
|
11084
11226
|
function assertRequesterDestinationMatch(context) {
|
|
11085
11227
|
const { destination, requester } = context;
|
|
@@ -11113,23 +11255,11 @@ function assertCorrelationDestinationMatch(context) {
|
|
|
11113
11255
|
}
|
|
11114
11256
|
function actorRequesterFromContext(context) {
|
|
11115
11257
|
return createRequester(context.requester, {
|
|
11116
|
-
platform: context.requester?.platform ?? (context.destination
|
|
11117
|
-
teamId: (context.destination
|
|
11258
|
+
platform: context.requester?.platform ?? (context.destination.platform === "slack" ? "slack" : void 0),
|
|
11259
|
+
teamId: (context.destination.platform === "slack" ? context.destination.teamId : void 0) ?? context.correlation?.teamId ?? (context.requester?.platform === "slack" ? context.requester.teamId : void 0),
|
|
11118
11260
|
userId: context.correlation?.requesterId
|
|
11119
11261
|
});
|
|
11120
11262
|
}
|
|
11121
|
-
function toolInvocationSource(context) {
|
|
11122
|
-
if (context.destination.platform !== "slack") {
|
|
11123
|
-
return context.destination;
|
|
11124
|
-
}
|
|
11125
|
-
return {
|
|
11126
|
-
platform: "slack",
|
|
11127
|
-
teamId: context.destination.teamId,
|
|
11128
|
-
channelId: context.destination.channelId,
|
|
11129
|
-
...context.correlation?.messageTs ? { messageTs: context.correlation.messageTs } : {},
|
|
11130
|
-
...context.correlation?.threadTs ? { threadTs: context.correlation.threadTs } : {}
|
|
11131
|
-
};
|
|
11132
|
-
}
|
|
11133
11263
|
function toolInvocationDestination(context) {
|
|
11134
11264
|
if (context.destination.platform !== "slack" || !context.toolChannelId) {
|
|
11135
11265
|
return context.destination;
|
|
@@ -11148,10 +11278,6 @@ function surfaceFromContext(context) {
|
|
|
11148
11278
|
if (context.slackConversation || (conversationId ? parseSlackThreadId(conversationId) : void 0)) {
|
|
11149
11279
|
return "slack";
|
|
11150
11280
|
}
|
|
11151
|
-
const actor = context.credentialContext?.actor;
|
|
11152
|
-
if (actor?.type === "system" && actor.id === "scheduler") {
|
|
11153
|
-
return "scheduler";
|
|
11154
|
-
}
|
|
11155
11281
|
if (conversationId) {
|
|
11156
11282
|
return "api";
|
|
11157
11283
|
}
|
|
@@ -11245,7 +11371,20 @@ function buildSteeringPiMessage(message) {
|
|
|
11245
11371
|
timestamp: message.timestampMs ?? Date.now()
|
|
11246
11372
|
};
|
|
11247
11373
|
}
|
|
11248
|
-
|
|
11374
|
+
function withoutTrailingUncheckpointedUserPrompt(messages, userContentParts) {
|
|
11375
|
+
if (!messages || messages.length === 0) {
|
|
11376
|
+
return [];
|
|
11377
|
+
}
|
|
11378
|
+
const lastMessage = messages.at(-1);
|
|
11379
|
+
if (lastMessage?.role !== "user") {
|
|
11380
|
+
return messages;
|
|
11381
|
+
}
|
|
11382
|
+
if (JSON.stringify(lastMessage.content) !== JSON.stringify(userContentParts)) {
|
|
11383
|
+
return messages;
|
|
11384
|
+
}
|
|
11385
|
+
return messages.slice(0, -1);
|
|
11386
|
+
}
|
|
11387
|
+
async function generateAssistantReply(messageText2, context) {
|
|
11249
11388
|
if (!context.destination) {
|
|
11250
11389
|
throw new TypeError("Assistant reply generation requires a destination");
|
|
11251
11390
|
}
|
|
@@ -11277,6 +11416,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11277
11416
|
const requester = requesterFromContext(context);
|
|
11278
11417
|
const actorRequester = actorRequesterFromContext(context);
|
|
11279
11418
|
const surface = surfaceFromContext(context);
|
|
11419
|
+
const runSource = context.source;
|
|
11280
11420
|
const credentialActor = context.credentialContext?.actor;
|
|
11281
11421
|
const credentialActorLogContext = credentialActor ? {
|
|
11282
11422
|
actorType: credentialActor.type,
|
|
@@ -11357,7 +11497,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11357
11497
|
}
|
|
11358
11498
|
let baseInstructions = "";
|
|
11359
11499
|
let configurationValues;
|
|
11360
|
-
const userInput =
|
|
11500
|
+
const userInput = messageText2;
|
|
11361
11501
|
if (shouldTrace) {
|
|
11362
11502
|
const inboundAttachmentCount = context.inboundAttachmentCount ?? 0;
|
|
11363
11503
|
const promptAttachmentCount = context.userAttachments?.length ?? 0;
|
|
@@ -11404,7 +11544,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11404
11544
|
};
|
|
11405
11545
|
const authRequesterId = context.credentialContext?.actor.type === "user" ? context.credentialContext.actor.userId : void 0;
|
|
11406
11546
|
const userTokenStore = createUserTokenStore();
|
|
11407
|
-
const
|
|
11547
|
+
const pluginHooks = createPluginHookRunner({
|
|
11408
11548
|
requester: actorRequester
|
|
11409
11549
|
});
|
|
11410
11550
|
sandboxExecutor = createSandboxExecutor({
|
|
@@ -11413,7 +11553,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11413
11553
|
traceContext: spanContext,
|
|
11414
11554
|
tracePropagation: context.sandbox?.tracePropagation,
|
|
11415
11555
|
credentialEgress: context.credentialContext,
|
|
11416
|
-
agentHooks:
|
|
11556
|
+
agentHooks: pluginHooks,
|
|
11417
11557
|
onSandboxAcquired: async (sandbox2) => {
|
|
11418
11558
|
lastKnownSandboxId = sandbox2.sandboxId;
|
|
11419
11559
|
lastKnownSandboxDependencyProfileHash = sandbox2.sandboxDependencyProfileHash;
|
|
@@ -11514,14 +11654,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11514
11654
|
userAttachments: context.userAttachments,
|
|
11515
11655
|
userTurnText
|
|
11516
11656
|
});
|
|
11517
|
-
const preAgentPromptMessages = () => existingSessionRecord?.piMessages ?? [
|
|
11518
|
-
...context.piMessages ?? [],
|
|
11519
|
-
{
|
|
11520
|
-
role: "user",
|
|
11521
|
-
content: userContentParts,
|
|
11522
|
-
timestamp: Date.now()
|
|
11523
|
-
}
|
|
11524
|
-
];
|
|
11657
|
+
const preAgentPromptMessages = () => existingSessionRecord?.piMessages ?? [...context.piMessages ?? []];
|
|
11525
11658
|
thinkingSelection = await selectTurnThinkingLevel({
|
|
11526
11659
|
completeObject,
|
|
11527
11660
|
conversationContext: context.conversationContext,
|
|
@@ -11564,6 +11697,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11564
11697
|
requesterId: authRequesterId,
|
|
11565
11698
|
channelId: slackChannelId,
|
|
11566
11699
|
destination: context.destination,
|
|
11700
|
+
source: runSource,
|
|
11567
11701
|
threadTs: context.correlation?.threadTs,
|
|
11568
11702
|
toolChannelId: context.toolChannelId,
|
|
11569
11703
|
userMessage: userInput,
|
|
@@ -11581,6 +11715,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11581
11715
|
requesterId: authRequesterId,
|
|
11582
11716
|
channelId: slackChannelId,
|
|
11583
11717
|
destination: context.destination,
|
|
11718
|
+
source: runSource,
|
|
11584
11719
|
threadTs: context.correlation?.threadTs,
|
|
11585
11720
|
userMessage: userInput,
|
|
11586
11721
|
channelConfiguration: context.channelConfiguration,
|
|
@@ -11615,6 +11750,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11615
11750
|
configuration: configurationValues,
|
|
11616
11751
|
mcpToolManager: turnMcpToolManager,
|
|
11617
11752
|
sandbox,
|
|
11753
|
+
surface,
|
|
11618
11754
|
advisor: {
|
|
11619
11755
|
config: botConfig.advisor,
|
|
11620
11756
|
conversationId: sessionConversationId,
|
|
@@ -11624,20 +11760,26 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11624
11760
|
streamFn: createTracedStreamFn({ conversationPrivacy })
|
|
11625
11761
|
}
|
|
11626
11762
|
};
|
|
11627
|
-
const toolSource =
|
|
11763
|
+
const toolSource = runSource;
|
|
11628
11764
|
const toolDestination = toolInvocationDestination(context);
|
|
11629
11765
|
let toolRuntimeContext;
|
|
11630
11766
|
if (toolSource.platform === "slack") {
|
|
11767
|
+
if (toolDestination.platform !== "slack") {
|
|
11768
|
+
throw new TypeError("Slack tool runtime requires a Slack destination");
|
|
11769
|
+
}
|
|
11631
11770
|
toolRuntimeContext = {
|
|
11632
11771
|
...commonToolRuntimeContext,
|
|
11633
|
-
|
|
11772
|
+
destination: toolDestination,
|
|
11634
11773
|
requester: actorRequester?.platform === "slack" ? actorRequester : void 0,
|
|
11635
11774
|
source: toolSource
|
|
11636
11775
|
};
|
|
11637
11776
|
} else {
|
|
11777
|
+
if (toolDestination.platform !== "local") {
|
|
11778
|
+
throw new TypeError("Local tool runtime requires a local destination");
|
|
11779
|
+
}
|
|
11638
11780
|
toolRuntimeContext = {
|
|
11639
11781
|
...commonToolRuntimeContext,
|
|
11640
|
-
|
|
11782
|
+
destination: toolDestination,
|
|
11641
11783
|
requester: actorRequester?.platform === "local" ? actorRequester : void 0,
|
|
11642
11784
|
source: toolSource
|
|
11643
11785
|
};
|
|
@@ -11722,17 +11864,39 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11722
11864
|
const activeMcpCatalogs = toActiveMcpCatalogSummaries(
|
|
11723
11865
|
turnMcpToolManager.getActiveToolCatalog()
|
|
11724
11866
|
);
|
|
11725
|
-
|
|
11726
|
-
const
|
|
11727
|
-
const
|
|
11867
|
+
const hasPromptCheckpoint = resumedFromSessionRecord && existingSessionRecord?.turnStartMessageIndex !== void 0;
|
|
11868
|
+
const shouldPromptAgent = !resumedFromSessionRecord || !hasPromptCheckpoint;
|
|
11869
|
+
const promptHistoryMessages = shouldPromptAgent && resumedFromSessionRecord ? withoutTrailingUncheckpointedUserPrompt(
|
|
11870
|
+
priorPiMessages,
|
|
11871
|
+
userContentParts
|
|
11872
|
+
) : shouldPromptAgent ? priorPiMessages ?? [] : existingSessionRecord.piMessages;
|
|
11873
|
+
const needsBootstrapContextForPrompt = shouldPromptAgent && !hasRuntimeTurnContext(promptHistoryMessages);
|
|
11874
|
+
const systemPromptContributions = await getPluginSystemPromptContributions(toolSource);
|
|
11875
|
+
const pluginSystemPrompt = buildPluginSystemPromptContributions(
|
|
11876
|
+
systemPromptContributions
|
|
11877
|
+
);
|
|
11878
|
+
baseInstructions = [
|
|
11879
|
+
buildSystemPrompt({ source: toolSource }),
|
|
11880
|
+
pluginSystemPrompt
|
|
11881
|
+
].filter((section) => Boolean(section)).join("\n\n");
|
|
11882
|
+
const pluginUserPromptContributions = !shouldPromptAgent ? [] : await getPluginUserPromptContributions({
|
|
11883
|
+
context: toolRuntimeContext
|
|
11884
|
+
});
|
|
11885
|
+
const turnContextPrompt = needsBootstrapContextForPrompt || pluginUserPromptContributions.length > 0 ? buildTurnContextPrompt({
|
|
11728
11886
|
availableSkills,
|
|
11729
11887
|
activeMcpCatalogs,
|
|
11730
|
-
includeSessionContext:
|
|
11888
|
+
includeSessionContext: needsBootstrapContextForPrompt,
|
|
11889
|
+
pluginPromptContributions: pluginUserPromptContributions,
|
|
11731
11890
|
toolGuidance,
|
|
11732
11891
|
runtime: {
|
|
11733
11892
|
conversationId: spanContext.conversationId,
|
|
11734
11893
|
slackConversation: context.slackConversation
|
|
11735
11894
|
},
|
|
11895
|
+
dispatch: context.dispatch ? {
|
|
11896
|
+
...context.dispatch,
|
|
11897
|
+
destination: context.destination,
|
|
11898
|
+
source: toolSource
|
|
11899
|
+
} : void 0,
|
|
11736
11900
|
invocation: skillInvocation,
|
|
11737
11901
|
requester: actorRequester,
|
|
11738
11902
|
artifactState: context.artifactState,
|
|
@@ -11756,10 +11920,10 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11756
11920
|
const inputMessagesAttribute = serializeGenAiAttribute(
|
|
11757
11921
|
conversationPrivacy !== "public" ? inputMessages.map(toGenAiMessageMetadata) : inputMessages
|
|
11758
11922
|
);
|
|
11759
|
-
const onToolCall = (toolName, params) => {
|
|
11923
|
+
const onToolCall = async (toolName, params) => {
|
|
11760
11924
|
toolCalls.push(toolName);
|
|
11761
11925
|
try {
|
|
11762
|
-
context.onToolInvocation?.({ toolName, params });
|
|
11926
|
+
await context.onToolInvocation?.({ toolName, params });
|
|
11763
11927
|
} catch (error) {
|
|
11764
11928
|
logWarn(
|
|
11765
11929
|
"tool_invocation_observer_failed",
|
|
@@ -11780,8 +11944,9 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11780
11944
|
sandboxExecutor,
|
|
11781
11945
|
pluginAuth,
|
|
11782
11946
|
onToolCall,
|
|
11783
|
-
|
|
11784
|
-
conversationPrivacy
|
|
11947
|
+
pluginHooks,
|
|
11948
|
+
conversationPrivacy,
|
|
11949
|
+
context.onToolResult
|
|
11785
11950
|
);
|
|
11786
11951
|
advisorTools = createAgentTools(
|
|
11787
11952
|
createAdvisorToolDefinitions(tools),
|
|
@@ -11791,8 +11956,9 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11791
11956
|
sandboxExecutor,
|
|
11792
11957
|
pluginAuth,
|
|
11793
11958
|
onToolCall,
|
|
11794
|
-
|
|
11795
|
-
conversationPrivacy
|
|
11959
|
+
pluginHooks,
|
|
11960
|
+
conversationPrivacy,
|
|
11961
|
+
context.onToolResult
|
|
11796
11962
|
);
|
|
11797
11963
|
let hasEmittedText = false;
|
|
11798
11964
|
let needsSeparator = false;
|
|
@@ -11811,6 +11977,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11811
11977
|
channelName: context.correlation?.channelName,
|
|
11812
11978
|
conversationId: sessionConversationId,
|
|
11813
11979
|
destination: context.destination,
|
|
11980
|
+
source: runSource,
|
|
11814
11981
|
sessionId,
|
|
11815
11982
|
sliceId: currentSliceId,
|
|
11816
11983
|
messages,
|
|
@@ -11889,8 +12056,9 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11889
12056
|
);
|
|
11890
12057
|
throw cooperativeYieldError;
|
|
11891
12058
|
};
|
|
12059
|
+
const apiKeyOverride = getPiGatewayApiKey();
|
|
11892
12060
|
agent = new Agent2({
|
|
11893
|
-
getApiKey: () =>
|
|
12061
|
+
...apiKeyOverride ? { getApiKey: () => apiKeyOverride } : {},
|
|
11894
12062
|
streamFn: createTracedStreamFn({ conversationPrivacy }),
|
|
11895
12063
|
steeringMode: "all",
|
|
11896
12064
|
prepareNextTurn: async () => {
|
|
@@ -11949,16 +12117,13 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11949
12117
|
beforeMessageCount = agent.state.messages.length;
|
|
11950
12118
|
try {
|
|
11951
12119
|
if (resumedFromSessionRecord) {
|
|
11952
|
-
agent.state.messages =
|
|
11953
|
-
existingSessionRecord.piMessages,
|
|
11954
|
-
turnContextPrompt
|
|
11955
|
-
) : existingSessionRecord.piMessages;
|
|
12120
|
+
agent.state.messages = shouldPromptAgent ? promptHistoryMessages ?? [] : existingSessionRecord.piMessages;
|
|
11956
12121
|
turnStartMessageIndex = existingSessionRecord.turnStartMessageIndex;
|
|
11957
12122
|
} else if (context.piMessages && context.piMessages.length > 0) {
|
|
11958
12123
|
agent.state.messages = [...context.piMessages];
|
|
11959
12124
|
}
|
|
11960
12125
|
beforeMessageCount = agent.state.messages.length;
|
|
11961
|
-
if (
|
|
12126
|
+
if (shouldPromptAgent) {
|
|
11962
12127
|
turnStartMessageIndex = beforeMessageCount;
|
|
11963
12128
|
}
|
|
11964
12129
|
await withSpan(
|
|
@@ -11972,7 +12137,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11972
12137
|
content: promptContentParts,
|
|
11973
12138
|
timestamp: Date.now()
|
|
11974
12139
|
};
|
|
11975
|
-
if (
|
|
12140
|
+
if (shouldPromptAgent) {
|
|
11976
12141
|
const promptPersisted = await requireDurableInputCheckpoint([
|
|
11977
12142
|
...agent.state.messages,
|
|
11978
12143
|
freshPromptMessage
|
|
@@ -12049,7 +12214,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
12049
12214
|
}
|
|
12050
12215
|
}
|
|
12051
12216
|
};
|
|
12052
|
-
let run =
|
|
12217
|
+
let run = shouldPromptAgent ? agent.prompt(freshPromptMessage) : agent.continue();
|
|
12053
12218
|
let retryUsage;
|
|
12054
12219
|
for (let attempt = 0; ; attempt += 1) {
|
|
12055
12220
|
promptResult = await runAgentStep(run);
|
|
@@ -12098,7 +12263,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
12098
12263
|
{},
|
|
12099
12264
|
"Retrying transient provider failure"
|
|
12100
12265
|
);
|
|
12101
|
-
await
|
|
12266
|
+
await sleep3(providerRetry.delayMs);
|
|
12102
12267
|
run = agent.continue();
|
|
12103
12268
|
}
|
|
12104
12269
|
},
|
|
@@ -12129,6 +12294,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
12129
12294
|
currentDurationMs: Date.now() - replyStartedAtMs,
|
|
12130
12295
|
currentUsage: turnUsage,
|
|
12131
12296
|
destination: context.destination,
|
|
12297
|
+
source: runSource,
|
|
12132
12298
|
sessionId,
|
|
12133
12299
|
sliceId: currentSliceId,
|
|
12134
12300
|
allMessages: agent.state.messages,
|
|
@@ -12165,6 +12331,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
12165
12331
|
channelName: context.correlation?.channelName,
|
|
12166
12332
|
conversationId: timeoutResumeConversationId,
|
|
12167
12333
|
destination: context.destination,
|
|
12334
|
+
source: runSource,
|
|
12168
12335
|
sessionId: timeoutResumeSessionId,
|
|
12169
12336
|
currentSliceId: timeoutResumeSliceId,
|
|
12170
12337
|
currentDurationMs: Date.now() - replyStartedAtMs,
|
|
@@ -12190,6 +12357,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
12190
12357
|
channelName: context.correlation?.channelName,
|
|
12191
12358
|
conversationId: timeoutResumeConversationId,
|
|
12192
12359
|
destination: context.destination,
|
|
12360
|
+
source: runSource,
|
|
12193
12361
|
sessionId: timeoutResumeSessionId,
|
|
12194
12362
|
currentSliceId: timeoutResumeSliceId,
|
|
12195
12363
|
currentDurationMs: Date.now() - replyStartedAtMs,
|
|
@@ -12234,6 +12402,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
12234
12402
|
channelName: context.correlation?.channelName,
|
|
12235
12403
|
conversationId: timeoutResumeConversationId,
|
|
12236
12404
|
destination: context.destination,
|
|
12405
|
+
source: runSource,
|
|
12237
12406
|
sessionId: timeoutResumeSessionId,
|
|
12238
12407
|
currentSliceId: timeoutResumeSliceId,
|
|
12239
12408
|
currentDurationMs: Date.now() - replyStartedAtMs,
|
|
@@ -12687,6 +12856,194 @@ function getConversationMessageSlackTs(message) {
|
|
|
12687
12856
|
return message.meta?.slackTs ?? toOptionalString(message.id);
|
|
12688
12857
|
}
|
|
12689
12858
|
|
|
12859
|
+
// src/chat/plugins/task-runner.ts
|
|
12860
|
+
import { pluginRunContextSchema } from "@sentry/junior-plugin-api";
|
|
12861
|
+
var PLUGIN_TASK_LOCK_TTL_MS = 5 * 60 * 1e3;
|
|
12862
|
+
function isRecord4(value) {
|
|
12863
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
12864
|
+
}
|
|
12865
|
+
function textPart(value) {
|
|
12866
|
+
if (isRecord4(value) && value.type === "text" && typeof value.text === "string") {
|
|
12867
|
+
return value.text;
|
|
12868
|
+
}
|
|
12869
|
+
return void 0;
|
|
12870
|
+
}
|
|
12871
|
+
function messageText(message) {
|
|
12872
|
+
const content = message.content;
|
|
12873
|
+
if (typeof content === "string") {
|
|
12874
|
+
return sanitizeText(content);
|
|
12875
|
+
}
|
|
12876
|
+
if (!Array.isArray(content)) {
|
|
12877
|
+
return "";
|
|
12878
|
+
}
|
|
12879
|
+
return sanitizeText(content.map(textPart).filter(Boolean).join("\n"));
|
|
12880
|
+
}
|
|
12881
|
+
function toolResultText(message) {
|
|
12882
|
+
const record = message;
|
|
12883
|
+
const parts = [
|
|
12884
|
+
messageText(message),
|
|
12885
|
+
record.output,
|
|
12886
|
+
record.result,
|
|
12887
|
+
record.stdout,
|
|
12888
|
+
record.stderr,
|
|
12889
|
+
record.toolResult
|
|
12890
|
+
].filter(
|
|
12891
|
+
(value) => typeof value === "string" && value.length > 0
|
|
12892
|
+
);
|
|
12893
|
+
return sanitizeText(parts.join("\n"));
|
|
12894
|
+
}
|
|
12895
|
+
function sanitizeText(text) {
|
|
12896
|
+
return text.replace(
|
|
12897
|
+
/<data_base64>[\s\S]*?<\/data_base64>/g,
|
|
12898
|
+
"<data_base64>[omitted]</data_base64>"
|
|
12899
|
+
).replace(
|
|
12900
|
+
/data:image\/[a-z0-9.+-]+;base64,[a-z0-9+/=]+/gi,
|
|
12901
|
+
"[image data omitted]"
|
|
12902
|
+
).replaceAll("\0", " ").trim();
|
|
12903
|
+
}
|
|
12904
|
+
function runTranscriptEntry(message) {
|
|
12905
|
+
const role = getPiMessageRole(message);
|
|
12906
|
+
if (role === "user" || role === "assistant") {
|
|
12907
|
+
const text2 = messageText(message);
|
|
12908
|
+
if (!text2) {
|
|
12909
|
+
return void 0;
|
|
12910
|
+
}
|
|
12911
|
+
return { type: "message", role, text: text2 };
|
|
12912
|
+
}
|
|
12913
|
+
if (!isToolResultMessage(message)) {
|
|
12914
|
+
return void 0;
|
|
12915
|
+
}
|
|
12916
|
+
const toolName = normalizeToolNameFromResult(message);
|
|
12917
|
+
if (!toolName) {
|
|
12918
|
+
return void 0;
|
|
12919
|
+
}
|
|
12920
|
+
const text = toolResultText(message);
|
|
12921
|
+
return {
|
|
12922
|
+
type: "toolResult",
|
|
12923
|
+
toolName,
|
|
12924
|
+
isError: isToolResultError(message),
|
|
12925
|
+
...text ? { text } : {}
|
|
12926
|
+
};
|
|
12927
|
+
}
|
|
12928
|
+
async function withPluginTaskLock(taskId, callback) {
|
|
12929
|
+
const state = getStateAdapter();
|
|
12930
|
+
await state.connect();
|
|
12931
|
+
const lock = await state.acquireLock(
|
|
12932
|
+
`plugin:task:${taskId}`,
|
|
12933
|
+
PLUGIN_TASK_LOCK_TTL_MS
|
|
12934
|
+
);
|
|
12935
|
+
if (!lock) {
|
|
12936
|
+
throw new Error(`Could not acquire plugin task lock for ${taskId}`);
|
|
12937
|
+
}
|
|
12938
|
+
try {
|
|
12939
|
+
return await callback();
|
|
12940
|
+
} finally {
|
|
12941
|
+
await state.releaseLock(lock);
|
|
12942
|
+
}
|
|
12943
|
+
}
|
|
12944
|
+
async function loadPluginRun(params) {
|
|
12945
|
+
const record = await getAgentTurnSessionRecord(
|
|
12946
|
+
params.conversationId,
|
|
12947
|
+
params.sessionId
|
|
12948
|
+
);
|
|
12949
|
+
if (!record) {
|
|
12950
|
+
throw new Error("Completed plugin task session record is unavailable");
|
|
12951
|
+
}
|
|
12952
|
+
if (record.state !== "completed") {
|
|
12953
|
+
throw new Error("Completed plugin task session record is not completed");
|
|
12954
|
+
}
|
|
12955
|
+
if (!record.source || !record.destination) {
|
|
12956
|
+
throw new Error(
|
|
12957
|
+
"Completed plugin task session record is missing source or destination"
|
|
12958
|
+
);
|
|
12959
|
+
}
|
|
12960
|
+
const sessionMessages = stripRuntimeTurnContext(
|
|
12961
|
+
record.piMessages.slice(record.turnStartMessageIndex ?? 0)
|
|
12962
|
+
);
|
|
12963
|
+
return pluginRunContextSchema.parse({
|
|
12964
|
+
completedAtMs: record.updatedAtMs,
|
|
12965
|
+
conversationId: record.conversationId,
|
|
12966
|
+
destination: record.destination,
|
|
12967
|
+
...record.requester ? { requester: record.requester } : {},
|
|
12968
|
+
runId: record.sessionId,
|
|
12969
|
+
source: record.source,
|
|
12970
|
+
transcript: sessionMessages.map(runTranscriptEntry).filter((entry) => Boolean(entry))
|
|
12971
|
+
});
|
|
12972
|
+
}
|
|
12973
|
+
function taskPluginContext(plugin, message, options = {}) {
|
|
12974
|
+
const pluginName = plugin.manifest.name;
|
|
12975
|
+
const sessionParams = pluginTaskParamsSchema.parse(message.params);
|
|
12976
|
+
return {
|
|
12977
|
+
db: getDb(),
|
|
12978
|
+
embedder: createPluginEmbedder(pluginName, {
|
|
12979
|
+
signal: options.signal
|
|
12980
|
+
}),
|
|
12981
|
+
id: pluginTaskId(message),
|
|
12982
|
+
log: createPluginLogger(pluginName),
|
|
12983
|
+
model: createPluginModel(pluginName, plugin.model, {
|
|
12984
|
+
signal: options.signal
|
|
12985
|
+
}),
|
|
12986
|
+
name: message.name,
|
|
12987
|
+
plugin: { name: pluginName },
|
|
12988
|
+
run: {
|
|
12989
|
+
async load() {
|
|
12990
|
+
return await loadPluginRun(sessionParams);
|
|
12991
|
+
}
|
|
12992
|
+
},
|
|
12993
|
+
state: createPluginState(pluginName)
|
|
12994
|
+
};
|
|
12995
|
+
}
|
|
12996
|
+
function findPluginTask(message) {
|
|
12997
|
+
const plugin = getPlugins().find(
|
|
12998
|
+
(candidate) => candidate.manifest.name === message.plugin
|
|
12999
|
+
);
|
|
13000
|
+
if (!plugin?.tasks || !Object.hasOwn(plugin.tasks, message.name)) {
|
|
13001
|
+
return void 0;
|
|
13002
|
+
}
|
|
13003
|
+
const task = plugin.tasks[message.name];
|
|
13004
|
+
return { plugin, task };
|
|
13005
|
+
}
|
|
13006
|
+
async function scheduleSessionCompletedPluginTasks(params, options = {}) {
|
|
13007
|
+
const coreParams = pluginTaskParamsSchema.parse(params);
|
|
13008
|
+
const taskRegistrations = getPlugins().flatMap(
|
|
13009
|
+
(plugin) => Object.keys(plugin.tasks ?? {}).map((name) => ({ name, plugin }))
|
|
13010
|
+
);
|
|
13011
|
+
if (taskRegistrations.length === 0) {
|
|
13012
|
+
return;
|
|
13013
|
+
}
|
|
13014
|
+
const record = await getAgentTurnSessionRecord(
|
|
13015
|
+
coreParams.conversationId,
|
|
13016
|
+
coreParams.sessionId
|
|
13017
|
+
);
|
|
13018
|
+
if (!record || record.state !== "completed") {
|
|
13019
|
+
throw new Error("Completed plugin task session record is not ready");
|
|
13020
|
+
}
|
|
13021
|
+
const send = options.send ?? sendVercelPluginTask;
|
|
13022
|
+
const messages = taskRegistrations.map(({ name, plugin }) => ({
|
|
13023
|
+
name,
|
|
13024
|
+
params: coreParams,
|
|
13025
|
+
plugin: plugin.manifest.name
|
|
13026
|
+
}));
|
|
13027
|
+
await Promise.all(
|
|
13028
|
+
messages.map(async (message) => {
|
|
13029
|
+
await send(message);
|
|
13030
|
+
})
|
|
13031
|
+
);
|
|
13032
|
+
}
|
|
13033
|
+
async function processPluginTask(message, options = {}) {
|
|
13034
|
+
await withPluginTaskLock(pluginTaskId(message), async () => {
|
|
13035
|
+
const resolved = findPluginTask(message);
|
|
13036
|
+
if (!resolved) {
|
|
13037
|
+
throw new Error(
|
|
13038
|
+
`Plugin task "${message.plugin}.${message.name}" is not registered`
|
|
13039
|
+
);
|
|
13040
|
+
}
|
|
13041
|
+
await resolved.task.run(
|
|
13042
|
+
taskPluginContext(resolved.plugin, message, options)
|
|
13043
|
+
);
|
|
13044
|
+
});
|
|
13045
|
+
}
|
|
13046
|
+
|
|
12690
13047
|
// src/chat/runtime/delivered-turn-state.ts
|
|
12691
13048
|
function buildDeliveredTurnStatePatch(args) {
|
|
12692
13049
|
const conversation = structuredClone(args.conversation);
|
|
@@ -12797,5 +13154,7 @@ export {
|
|
|
12797
13154
|
createConversationMemoryService,
|
|
12798
13155
|
isHumanConversationMessage,
|
|
12799
13156
|
getConversationMessageSlackTs,
|
|
13157
|
+
scheduleSessionCompletedPluginTasks,
|
|
13158
|
+
processPluginTask,
|
|
12800
13159
|
buildDeliveredTurnStatePatch
|
|
12801
13160
|
};
|