@sentry/junior 0.75.0 → 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 +2 -0
- package/dist/app.js +317 -118
- package/dist/build/virtual-config.d.ts +2 -2
- package/dist/chat/agent-dispatch/runner.d.ts +2 -0
- package/dist/chat/config.d.ts +1 -0
- package/dist/chat/credentials/state-adapter-token-store.d.ts +2 -0
- 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 +7 -0
- package/dist/chat/plugins/auth/oauth-request.d.ts +11 -7
- package/dist/chat/plugins/model.d.ts +9 -0
- package/dist/chat/plugins/prompt.d.ts +5 -0
- 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/prompt.d.ts +4 -0
- package/dist/chat/requester.d.ts +6 -5
- package/dist/chat/respond-helpers.d.ts +2 -0
- package/dist/chat/respond.d.ts +4 -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/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/state/turn-session.d.ts +8 -5
- package/dist/chat/tools/agent-tools.d.ts +8 -1
- package/dist/chat/tools/slack/context.d.ts +2 -2
- package/dist/chat/tools/types.d.ts +4 -4
- package/dist/chat/vercel-queue-client.d.ts +3 -0
- package/dist/{chunk-C3AM4Z4J.js → chunk-2ECJXSVQ.js} +5 -5
- package/dist/{chunk-OJODNL2P.js → chunk-4SCWV7TJ.js} +2 -2
- package/dist/chunk-4UO6FK4G.js +64 -0
- package/dist/{chunk-BNJIEFQC.js → chunk-56TBVRJG.js} +2 -2
- package/dist/{chunk-OK4KKR7B.js → chunk-EJN6G5A2.js} +28 -12
- package/dist/{chunk-TQ74BATR.js → chunk-HHDUKWVG.js} +428 -111
- package/dist/{chunk-XJHDZUGD.js → chunk-JBASI5VV.js} +4 -4
- package/dist/chunk-KNFROR7R.js +127 -0
- package/dist/{chunk-VNTLUFTY.js → chunk-KOIMO7S3.js} +126 -87
- package/dist/chunk-MLKGABMK.js +9 -0
- package/dist/{chunk-NPVUAXUE.js → chunk-NFTMTIP3.js} +303 -33
- package/dist/chunk-NYKJ3KON.js +1082 -0
- package/dist/{chunk-SJHUF3DP.js → chunk-OJ53FYVG.js} +2 -10
- package/dist/{chunk-62FUNJYS.js → chunk-Q6XFTRV5.js} +54 -3
- package/dist/{chunk-UJ7OTHPO.js → chunk-R6Z5XWY3.js} +12 -670
- package/dist/chunk-RV5RYIJW.js +56 -0
- package/dist/{chunk-EE6PJWY4.js → chunk-SG5WAA7H.js} +7 -5
- package/dist/chunk-ST6YNAXG.js +54 -0
- package/dist/{chunk-FCZO7LAR.js → chunk-T77LUIX3.js} +139 -153
- package/dist/{chunk-EIYL7I4S.js → chunk-VALUBQ7R.js} +22 -30
- package/dist/{chunk-OZSPLAQ4.js → chunk-XBBC6W45.js} +1 -1
- package/dist/{chunk-ZNNTSPNF.js → chunk-Y5OFBCBZ.js} +1 -1
- package/dist/{chunk-74HO27II.js → chunk-Z4CIQ3EB.js} +5 -1
- package/dist/{chunk-2RWFUS5F.js → chunk-ZLMBNBUG.js} +101 -44
- package/dist/{chunk-JEELK46E.js → chunk-ZQB37HUX.js} +11 -11
- package/dist/cli/chat.js +52 -23
- package/dist/cli/check.js +7 -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 +9 -9
- package/dist/cli/upgrade.js +167 -48
- package/dist/db-7A7PFRGL.js +17 -0
- package/dist/deployment.d.ts +1 -0
- package/dist/instrumentation.js +14 -18
- package/dist/nitro.d.ts +1 -1
- package/dist/nitro.js +43 -22
- package/dist/plugins-PZMDS7AT.js +15 -0
- package/dist/plugins.d.ts +4 -2
- package/dist/{registry-NLZFIW23.js → registry-OIPAJU2O.js} +6 -6
- package/dist/reporting.js +34 -26
- package/dist/{runner-LUQZ5G67.js → runner-KPLNHDCV.js} +76 -23
- package/dist/sentry-4CP5NNQ5.js +31 -0
- package/dist/validation-SLA6IGF7.js +15 -0
- package/dist/vercel.js +1 -1
- package/package.json +7 -6
- package/dist/agent-hooks-2HEB4C3Q.js +0 -33
- package/dist/chat/conversations/configured.d.ts +0 -7
- package/dist/chat/conversations/state.d.ts +0 -4
- package/dist/chat/plugins/db.d.ts +0 -31
- package/dist/chunk-2KG3PWR4.js +0 -17
- package/dist/chunk-D7NFH5GD.js +0 -570
- package/dist/chunk-MCMROINU.js +0 -12
- package/dist/chunk-WBZ4M5N5.js +0 -59
- package/dist/db-A3ILH67H.js +0 -20
- package/dist/plugins-OMJKLRJ2.js +0 -13
- package/dist/validation-VMCPP3YO.js +0 -15
|
@@ -1,6 +1,25 @@
|
|
|
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
25
|
escapeXml,
|
|
@@ -9,28 +28,35 @@ import {
|
|
|
9
28
|
recordAuthorizationRequested,
|
|
10
29
|
recordMcpProviderConnected,
|
|
11
30
|
upsertAgentTurnSessionRecord
|
|
12
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-KOIMO7S3.js";
|
|
13
32
|
import {
|
|
33
|
+
createPluginEmbedder,
|
|
14
34
|
createPluginHookRunner,
|
|
35
|
+
createPluginModel,
|
|
36
|
+
getPluginSystemPromptContributions,
|
|
15
37
|
getPluginTools,
|
|
38
|
+
getPluginUserPromptContributions,
|
|
39
|
+
getPlugins,
|
|
16
40
|
getSlackToolContext,
|
|
17
41
|
resolveChannelCapabilities
|
|
18
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-NFTMTIP3.js";
|
|
19
43
|
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
parseSkillInvocation
|
|
24
|
-
} from "./chunk-OJODNL2P.js";
|
|
44
|
+
createPluginLogger,
|
|
45
|
+
createPluginState
|
|
46
|
+
} from "./chunk-56TBVRJG.js";
|
|
25
47
|
import {
|
|
26
|
-
|
|
27
|
-
} from "./chunk-
|
|
48
|
+
getDb
|
|
49
|
+
} from "./chunk-NYKJ3KON.js";
|
|
28
50
|
import {
|
|
29
|
-
|
|
30
|
-
|
|
51
|
+
SANDBOX_DATA_ROOT,
|
|
52
|
+
SANDBOX_SKILLS_ROOT,
|
|
53
|
+
SANDBOX_WORKSPACE_ROOT,
|
|
54
|
+
sandboxSkillDir,
|
|
55
|
+
sandboxSkillFile
|
|
56
|
+
} from "./chunk-G3E7SCME.js";
|
|
31
57
|
import {
|
|
32
|
-
|
|
33
|
-
} from "./chunk-
|
|
58
|
+
getStateAdapter
|
|
59
|
+
} from "./chunk-Y5OFBCBZ.js";
|
|
34
60
|
import {
|
|
35
61
|
SlackActionError,
|
|
36
62
|
downloadPrivateSlackFile,
|
|
@@ -39,27 +65,9 @@ import {
|
|
|
39
65
|
isConversationScopedChannel,
|
|
40
66
|
isDmChannel,
|
|
41
67
|
normalizeSlackConversationId,
|
|
68
|
+
parseDestination,
|
|
42
69
|
withSlackRetries
|
|
43
|
-
} from "./chunk-
|
|
44
|
-
import {
|
|
45
|
-
buildNonInteractiveShellScript,
|
|
46
|
-
createSandboxInstance,
|
|
47
|
-
getRuntimeDependencyProfileHash,
|
|
48
|
-
getVercelSandboxCredentials,
|
|
49
|
-
isSnapshotMissingError,
|
|
50
|
-
resolveRuntimeDependencySnapshot,
|
|
51
|
-
runNonInteractiveCommand
|
|
52
|
-
} from "./chunk-XJHDZUGD.js";
|
|
53
|
-
import {
|
|
54
|
-
SANDBOX_DATA_ROOT,
|
|
55
|
-
SANDBOX_SKILLS_ROOT,
|
|
56
|
-
SANDBOX_WORKSPACE_ROOT,
|
|
57
|
-
sandboxSkillDir,
|
|
58
|
-
sandboxSkillFile
|
|
59
|
-
} from "./chunk-G3E7SCME.js";
|
|
60
|
-
import {
|
|
61
|
-
getStateAdapter
|
|
62
|
-
} from "./chunk-ZNNTSPNF.js";
|
|
70
|
+
} from "./chunk-Q6XFTRV5.js";
|
|
63
71
|
import {
|
|
64
72
|
GEN_AI_PROVIDER_NAME,
|
|
65
73
|
GEN_AI_SERVER_ADDRESS,
|
|
@@ -72,7 +80,7 @@ import {
|
|
|
72
80
|
encodeNonImageAttachmentForPrompt,
|
|
73
81
|
extractAssistantText,
|
|
74
82
|
getGatewayApiKey,
|
|
75
|
-
|
|
83
|
+
getPiGatewayApiKey,
|
|
76
84
|
getPiMessageRole,
|
|
77
85
|
getSessionIdentifiers,
|
|
78
86
|
getTerminalAssistantMessages,
|
|
@@ -87,9 +95,9 @@ import {
|
|
|
87
95
|
normalizeSlackEmojiName,
|
|
88
96
|
normalizeToolNameFromResult,
|
|
89
97
|
parseSlackThreadId,
|
|
90
|
-
prependMissingRuntimeTurnContext,
|
|
91
98
|
resolveConversationPrivacy,
|
|
92
99
|
resolveGatewayModel,
|
|
100
|
+
stripRuntimeTurnContext,
|
|
93
101
|
summarizeMessageText,
|
|
94
102
|
toGenAiMessageMetadata,
|
|
95
103
|
toGenAiMessagesTraceAttributes,
|
|
@@ -99,7 +107,13 @@ import {
|
|
|
99
107
|
toObservablePromptPart,
|
|
100
108
|
trimTrailingAssistantMessages,
|
|
101
109
|
upsertActiveSkill
|
|
102
|
-
} from "./chunk-
|
|
110
|
+
} from "./chunk-T77LUIX3.js";
|
|
111
|
+
import {
|
|
112
|
+
discoverSkills,
|
|
113
|
+
findSkillByName,
|
|
114
|
+
loadSkillsByName,
|
|
115
|
+
parseSkillInvocation
|
|
116
|
+
} from "./chunk-4SCWV7TJ.js";
|
|
103
117
|
import {
|
|
104
118
|
createPluginBroker,
|
|
105
119
|
credentialContextSchema,
|
|
@@ -113,15 +127,14 @@ import {
|
|
|
113
127
|
isPluginConfigKey,
|
|
114
128
|
resolveAuthTokenPlaceholder,
|
|
115
129
|
resolvePluginCommandEnv
|
|
116
|
-
} from "./chunk-
|
|
130
|
+
} from "./chunk-ZLMBNBUG.js";
|
|
131
|
+
import {
|
|
132
|
+
createRequester,
|
|
133
|
+
parseActorUserId
|
|
134
|
+
} from "./chunk-VALUBQ7R.js";
|
|
117
135
|
import {
|
|
118
136
|
listReferenceFiles
|
|
119
137
|
} from "./chunk-Q3XNY442.js";
|
|
120
|
-
import {
|
|
121
|
-
createRequester,
|
|
122
|
-
parseActorUserId,
|
|
123
|
-
toStoredSlackRequester
|
|
124
|
-
} from "./chunk-EIYL7I4S.js";
|
|
125
138
|
import {
|
|
126
139
|
extractGenAiUsageAttributes,
|
|
127
140
|
extractGenAiUsageSummary,
|
|
@@ -140,10 +153,11 @@ import {
|
|
|
140
153
|
setTags,
|
|
141
154
|
toOptionalString,
|
|
142
155
|
withSpan
|
|
143
|
-
} from "./chunk-
|
|
156
|
+
} from "./chunk-EJN6G5A2.js";
|
|
144
157
|
import {
|
|
145
|
-
|
|
146
|
-
|
|
158
|
+
startInactiveSpan,
|
|
159
|
+
withActiveSpan
|
|
160
|
+
} from "./chunk-ST6YNAXG.js";
|
|
147
161
|
|
|
148
162
|
// src/chat/configuration/defaults.ts
|
|
149
163
|
var installDefaults = {};
|
|
@@ -728,31 +742,65 @@ var ProviderCredentialRouter = class {
|
|
|
728
742
|
}
|
|
729
743
|
};
|
|
730
744
|
|
|
745
|
+
// src/chat/credentials/user-token-store.ts
|
|
746
|
+
import {
|
|
747
|
+
pluginStoredTokensSchema
|
|
748
|
+
} from "@sentry/junior-plugin-api";
|
|
749
|
+
var storedTokensSchema = pluginStoredTokensSchema;
|
|
750
|
+
|
|
731
751
|
// src/chat/credentials/state-adapter-token-store.ts
|
|
732
752
|
var KEY_PREFIX = "oauth-token";
|
|
733
753
|
var BUFFER_MS = 24 * 60 * 60 * 1e3;
|
|
734
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;
|
|
735
758
|
function tokenKey(userId, provider) {
|
|
736
759
|
return `${KEY_PREFIX}:${userId}:${provider}`;
|
|
737
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
|
+
}
|
|
738
767
|
var StateAdapterTokenStore = class {
|
|
739
768
|
state;
|
|
740
769
|
constructor(stateAdapter) {
|
|
741
770
|
this.state = stateAdapter;
|
|
742
771
|
}
|
|
743
772
|
async get(userId, provider) {
|
|
744
|
-
const stored = await this.state.get(
|
|
745
|
-
|
|
746
|
-
);
|
|
747
|
-
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);
|
|
748
775
|
}
|
|
749
776
|
async set(userId, provider, tokens) {
|
|
750
|
-
const
|
|
751
|
-
|
|
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);
|
|
752
781
|
}
|
|
753
782
|
async delete(userId, provider) {
|
|
754
783
|
await this.state.delete(tokenKey(userId, provider));
|
|
755
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
|
+
}
|
|
756
804
|
};
|
|
757
805
|
|
|
758
806
|
// src/chat/capabilities/factory.ts
|
|
@@ -5908,8 +5956,9 @@ function createAdvisorTool(context) {
|
|
|
5908
5956
|
"Advisor guidance is unavailable because advisor history could not be loaded. Continue without assuming advisor history."
|
|
5909
5957
|
);
|
|
5910
5958
|
}
|
|
5959
|
+
const apiKeyOverride = getPiGatewayApiKey();
|
|
5911
5960
|
const advisorAgent = new Agent({
|
|
5912
|
-
getApiKey: () =>
|
|
5961
|
+
...apiKeyOverride ? { getApiKey: () => apiKeyOverride } : {},
|
|
5913
5962
|
initialState: {
|
|
5914
5963
|
systemPrompt: ADVISOR_SYSTEM_PROMPT,
|
|
5915
5964
|
model: resolveGatewayModel(context.config.modelId),
|
|
@@ -6819,7 +6868,7 @@ function createTracedStreamFn(baseOrOptions = streamSimple) {
|
|
|
6819
6868
|
const conversationPrivacy = typeof baseOrOptions === "function" ? void 0 : baseOrOptions.conversationPrivacy;
|
|
6820
6869
|
const effectivePrivacy = conversationPrivacy ?? "private";
|
|
6821
6870
|
return async (model, context, options) => {
|
|
6822
|
-
const span =
|
|
6871
|
+
const span = startInactiveSpan({
|
|
6823
6872
|
name: `chat ${model.id}`,
|
|
6824
6873
|
op: "gen_ai.chat",
|
|
6825
6874
|
attributes: {
|
|
@@ -6828,7 +6877,7 @@ function createTracedStreamFn(baseOrOptions = streamSimple) {
|
|
|
6828
6877
|
}
|
|
6829
6878
|
});
|
|
6830
6879
|
try {
|
|
6831
|
-
const stream = await
|
|
6880
|
+
const stream = await withActiveSpan(
|
|
6832
6881
|
span,
|
|
6833
6882
|
() => Promise.resolve(base(model, context, options))
|
|
6834
6883
|
);
|
|
@@ -6864,6 +6913,9 @@ import fs3 from "fs/promises";
|
|
|
6864
6913
|
|
|
6865
6914
|
// src/chat/oauth-flow.ts
|
|
6866
6915
|
import { randomBytes } from "crypto";
|
|
6916
|
+
import {
|
|
6917
|
+
sourceSchema
|
|
6918
|
+
} from "@sentry/junior-plugin-api";
|
|
6867
6919
|
var OAUTH_STATE_TTL_MS = 10 * 60 * 1e3;
|
|
6868
6920
|
function optionalString(value) {
|
|
6869
6921
|
return typeof value === "string" ? value : void 0;
|
|
@@ -6879,13 +6931,22 @@ function parseOAuthStatePayload(value) {
|
|
|
6879
6931
|
if (value.destination !== void 0 && !destination) {
|
|
6880
6932
|
return void 0;
|
|
6881
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
|
+
}
|
|
6882
6942
|
return {
|
|
6883
6943
|
userId: value.userId,
|
|
6884
6944
|
provider: value.provider,
|
|
6885
6945
|
...optionalString(value.channelId) ? { channelId: optionalString(value.channelId) } : {},
|
|
6886
6946
|
...destination ? { destination } : {},
|
|
6947
|
+
...source?.success ? { source: source.data } : {},
|
|
6887
6948
|
...optionalString(value.threadTs) ? { threadTs: optionalString(value.threadTs) } : {},
|
|
6888
|
-
...
|
|
6949
|
+
...pendingMessage ? { pendingMessage } : {},
|
|
6889
6950
|
...isRecord(value.configuration) ? { configuration: value.configuration } : {},
|
|
6890
6951
|
...optionalString(value.resumeConversationId) ? { resumeConversationId: optionalString(value.resumeConversationId) } : {},
|
|
6891
6952
|
...optionalString(value.resumeSessionId) ? { resumeSessionId: optionalString(value.resumeSessionId) } : {},
|
|
@@ -7007,6 +7068,7 @@ async function startOAuthFlow(provider, input) {
|
|
|
7007
7068
|
provider,
|
|
7008
7069
|
...input.channelId ? { channelId: input.channelId } : {},
|
|
7009
7070
|
...input.destination ? { destination: input.destination } : {},
|
|
7071
|
+
...input.source ? { source: input.source } : {},
|
|
7010
7072
|
...input.threadTs ? { threadTs: input.threadTs } : {},
|
|
7011
7073
|
...input.userMessage ? { pendingMessage: input.userMessage } : {},
|
|
7012
7074
|
...configuration && Object.keys(configuration).length > 0 ? { configuration } : {},
|
|
@@ -7843,7 +7905,7 @@ function truncateOutput(output, maxLength) {
|
|
|
7843
7905
|
truncated: true
|
|
7844
7906
|
};
|
|
7845
7907
|
}
|
|
7846
|
-
function
|
|
7908
|
+
function sleep2(ms) {
|
|
7847
7909
|
return new Promise((resolve) => {
|
|
7848
7910
|
setTimeout(resolve, ms);
|
|
7849
7911
|
});
|
|
@@ -8014,7 +8076,7 @@ function createSandboxSessionManager(options) {
|
|
|
8014
8076
|
if (!isSnapshottingError(error) || attempt === SNAPSHOT_BOOT_RETRY_COUNT - 1) {
|
|
8015
8077
|
throw error;
|
|
8016
8078
|
}
|
|
8017
|
-
await
|
|
8079
|
+
await sleep2(SNAPSHOT_BOOT_RETRY_DELAY_MS);
|
|
8018
8080
|
}
|
|
8019
8081
|
}
|
|
8020
8082
|
throw new Error(`Failed to boot sandbox from snapshot ${snapshotId}`);
|
|
@@ -9141,6 +9203,9 @@ import { PluginToolInputError } from "@sentry/junior-plugin-api";
|
|
|
9141
9203
|
import { THREAD_STATE_TTL_MS } from "chat";
|
|
9142
9204
|
|
|
9143
9205
|
// src/chat/mcp/auth-store.ts
|
|
9206
|
+
import {
|
|
9207
|
+
sourceSchema as sourceSchema2
|
|
9208
|
+
} from "@sentry/junior-plugin-api";
|
|
9144
9209
|
var MCP_AUTH_SESSION_PREFIX = "junior:mcp_auth_session";
|
|
9145
9210
|
var MCP_AUTH_CREDENTIALS_PREFIX = "junior:mcp_auth_credentials";
|
|
9146
9211
|
var MCP_AUTH_SESSION_INDEX_PREFIX = "junior:mcp_auth_session_index";
|
|
@@ -9192,12 +9257,17 @@ function parseMcpAuthSession(value) {
|
|
|
9192
9257
|
if (parsed.destination !== void 0 && !destination) {
|
|
9193
9258
|
return void 0;
|
|
9194
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
|
+
}
|
|
9195
9264
|
return {
|
|
9196
9265
|
authSessionId: parsed.authSessionId,
|
|
9197
9266
|
provider: parsed.provider,
|
|
9198
9267
|
userId: parsed.userId,
|
|
9199
9268
|
conversationId: parsed.conversationId,
|
|
9200
9269
|
...destination ? { destination } : {},
|
|
9270
|
+
...source?.success ? { source: source.data } : {},
|
|
9201
9271
|
sessionId: parsed.sessionId,
|
|
9202
9272
|
userMessage: parsed.userMessage,
|
|
9203
9273
|
createdAtMs: parsed.createdAtMs,
|
|
@@ -9518,6 +9588,7 @@ function createPluginAuthOrchestration(input) {
|
|
|
9518
9588
|
requesterId: input.requesterId,
|
|
9519
9589
|
channelId: input.channelId,
|
|
9520
9590
|
destination: input.destination,
|
|
9591
|
+
source: input.source,
|
|
9521
9592
|
threadTs: input.threadTs,
|
|
9522
9593
|
userMessage: input.userMessage,
|
|
9523
9594
|
channelConfiguration: input.channelConfiguration,
|
|
@@ -9696,12 +9767,27 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, trac
|
|
|
9696
9767
|
}
|
|
9697
9768
|
|
|
9698
9769
|
// src/chat/tools/agent-tools.ts
|
|
9699
|
-
function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor, pluginAuthOrchestration, onToolCall, agentHooks, conversationPrivacy) {
|
|
9770
|
+
function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor, pluginAuthOrchestration, onToolCall, agentHooks, conversationPrivacy, onToolResult) {
|
|
9700
9771
|
const shouldTrace = shouldEmitDevAgentTrace();
|
|
9701
9772
|
const effectiveConversationPrivacy = conversationPrivacy ?? "private";
|
|
9702
9773
|
const serializeToolPayload = (payload) => serializeGenAiAttribute(
|
|
9703
9774
|
effectiveConversationPrivacy === "private" ? toGenAiPayloadMetadata(payload) : payload
|
|
9704
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
|
+
};
|
|
9705
9791
|
return Object.entries(tools).map(([toolName, toolDef]) => ({
|
|
9706
9792
|
name: toolName,
|
|
9707
9793
|
label: toolName,
|
|
@@ -9751,7 +9837,7 @@ function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor
|
|
|
9751
9837
|
input: parsed
|
|
9752
9838
|
}) : { input: parsed, env: {} };
|
|
9753
9839
|
const toolInput = beforeTool.input;
|
|
9754
|
-
onToolCall?.(toolName, toolInput);
|
|
9840
|
+
await onToolCall?.(toolName, toolInput);
|
|
9755
9841
|
const sandboxInput = buildSandboxInput(toolName, toolInput);
|
|
9756
9842
|
const isSandbox = Boolean(sandboxExecutor?.canExecute(toolName));
|
|
9757
9843
|
const result = isSandbox ? await sandboxExecutor.execute({
|
|
@@ -9781,8 +9867,20 @@ function createAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecutor
|
|
|
9781
9867
|
)
|
|
9782
9868
|
});
|
|
9783
9869
|
}
|
|
9870
|
+
await notifyToolResult({
|
|
9871
|
+
ok: true,
|
|
9872
|
+
params: toolInput,
|
|
9873
|
+
result: resultAttributeValue,
|
|
9874
|
+
toolName
|
|
9875
|
+
});
|
|
9784
9876
|
return normalized;
|
|
9785
9877
|
} catch (error) {
|
|
9878
|
+
await notifyToolResult({
|
|
9879
|
+
error: error instanceof Error ? error.message : String(error),
|
|
9880
|
+
ok: false,
|
|
9881
|
+
params: parsed,
|
|
9882
|
+
toolName
|
|
9883
|
+
});
|
|
9786
9884
|
if (error instanceof AuthorizationPauseError || error instanceof AuthorizationFlowDisabledError) {
|
|
9787
9885
|
throw error;
|
|
9788
9886
|
}
|
|
@@ -10389,7 +10487,7 @@ async function loadTurnSessionRecord(ctx) {
|
|
|
10389
10487
|
const canUseTurnSession = Boolean(ctx.conversationId && ctx.sessionId);
|
|
10390
10488
|
const existingSessionRecord = canUseTurnSession && ctx.conversationId && ctx.sessionId ? await getAgentTurnSessionRecord(ctx.conversationId, ctx.sessionId) : void 0;
|
|
10391
10489
|
const hasAwaitingResumeRecord = Boolean(
|
|
10392
|
-
existingSessionRecord && existingSessionRecord.state === "awaiting_resume"
|
|
10490
|
+
existingSessionRecord && existingSessionRecord.state === "awaiting_resume"
|
|
10393
10491
|
);
|
|
10394
10492
|
return {
|
|
10395
10493
|
canUseTurnSession,
|
|
@@ -10413,6 +10511,7 @@ async function persistRunningSessionRecord(args) {
|
|
|
10413
10511
|
cumulativeDurationMs: latestSessionRecord?.cumulativeDurationMs,
|
|
10414
10512
|
cumulativeUsage: latestSessionRecord?.cumulativeUsage,
|
|
10415
10513
|
...args.destination ?? latestSessionRecord?.destination ? { destination: args.destination ?? latestSessionRecord?.destination } : {},
|
|
10514
|
+
...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
|
|
10416
10515
|
sessionId: args.sessionId,
|
|
10417
10516
|
sliceId: args.sliceId,
|
|
10418
10517
|
state: "running",
|
|
@@ -10457,6 +10556,7 @@ async function persistCompletedSessionRecord(args) {
|
|
|
10457
10556
|
args.currentUsage
|
|
10458
10557
|
),
|
|
10459
10558
|
...args.destination ?? latestSessionRecord?.destination ? { destination: args.destination ?? latestSessionRecord?.destination } : {},
|
|
10559
|
+
...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
|
|
10460
10560
|
sessionId: args.sessionId,
|
|
10461
10561
|
sliceId: args.sliceId,
|
|
10462
10562
|
state: "completed",
|
|
@@ -10492,7 +10592,7 @@ async function persistAuthPauseSessionRecord(args) {
|
|
|
10492
10592
|
args.messages,
|
|
10493
10593
|
latestSessionRecord?.piMessages
|
|
10494
10594
|
);
|
|
10495
|
-
if (piMessages.length
|
|
10595
|
+
if (piMessages.length > 0 && !isContinuableBoundary(piMessages)) {
|
|
10496
10596
|
return void 0;
|
|
10497
10597
|
}
|
|
10498
10598
|
return await upsertAgentTurnSessionRecord({
|
|
@@ -10507,6 +10607,7 @@ async function persistAuthPauseSessionRecord(args) {
|
|
|
10507
10607
|
args.currentUsage
|
|
10508
10608
|
),
|
|
10509
10609
|
...args.destination ?? latestSessionRecord?.destination ? { destination: args.destination ?? latestSessionRecord?.destination } : {},
|
|
10610
|
+
...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
|
|
10510
10611
|
sessionId: args.sessionId,
|
|
10511
10612
|
sliceId: nextSliceId,
|
|
10512
10613
|
state: "awaiting_resume",
|
|
@@ -10566,6 +10667,7 @@ async function persistTimeoutSessionRecord(args) {
|
|
|
10566
10667
|
...args.destination ?? latestSessionRecord?.destination ? {
|
|
10567
10668
|
destination: args.destination ?? latestSessionRecord?.destination
|
|
10568
10669
|
} : {},
|
|
10670
|
+
...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
|
|
10569
10671
|
sessionId: args.sessionId,
|
|
10570
10672
|
sliceId: args.currentSliceId,
|
|
10571
10673
|
state: "failed",
|
|
@@ -10585,6 +10687,7 @@ async function persistTimeoutSessionRecord(args) {
|
|
|
10585
10687
|
cumulativeDurationMs,
|
|
10586
10688
|
cumulativeUsage,
|
|
10587
10689
|
...args.destination ?? latestSessionRecord?.destination ? { destination: args.destination ?? latestSessionRecord?.destination } : {},
|
|
10690
|
+
...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
|
|
10588
10691
|
sessionId: args.sessionId,
|
|
10589
10692
|
sliceId: nextSliceId,
|
|
10590
10693
|
state: "awaiting_resume",
|
|
@@ -10636,6 +10739,7 @@ async function persistYieldSessionRecord(args) {
|
|
|
10636
10739
|
args.currentUsage
|
|
10637
10740
|
),
|
|
10638
10741
|
...args.destination ?? latestSessionRecord?.destination ? { destination: args.destination ?? latestSessionRecord?.destination } : {},
|
|
10742
|
+
...args.source ?? latestSessionRecord?.source ? { source: args.source ?? latestSessionRecord?.source } : {},
|
|
10639
10743
|
sessionId: args.sessionId,
|
|
10640
10744
|
sliceId: args.currentSliceId,
|
|
10641
10745
|
state: "awaiting_resume",
|
|
@@ -10852,6 +10956,7 @@ async function createMcpOAuthClientProvider(input) {
|
|
|
10852
10956
|
userId: input.userId,
|
|
10853
10957
|
conversationId: input.conversationId,
|
|
10854
10958
|
...input.destination ? { destination: input.destination } : {},
|
|
10959
|
+
...input.source ? { source: input.source } : {},
|
|
10855
10960
|
sessionId: input.sessionId,
|
|
10856
10961
|
userMessage: input.userMessage,
|
|
10857
10962
|
...input.channelId ? { channelId: input.channelId } : {},
|
|
@@ -10953,6 +11058,7 @@ function createMcpAuthOrchestration(input) {
|
|
|
10953
11058
|
provider: plugin.manifest.name,
|
|
10954
11059
|
conversationId: input.conversationId,
|
|
10955
11060
|
destination: input.destination,
|
|
11061
|
+
source: input.source,
|
|
10956
11062
|
sessionId: input.sessionId,
|
|
10957
11063
|
userId: input.requesterId,
|
|
10958
11064
|
userMessage: input.userMessage,
|
|
@@ -11058,7 +11164,7 @@ function createMcpAuthOrchestration(input) {
|
|
|
11058
11164
|
|
|
11059
11165
|
// src/chat/respond.ts
|
|
11060
11166
|
var AGENT_ABORT_SETTLE_GRACE_MS = 5e3;
|
|
11061
|
-
function
|
|
11167
|
+
function sleep3(ms) {
|
|
11062
11168
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
11063
11169
|
}
|
|
11064
11170
|
function waitForAbortSettlement(promise, timeoutMs) {
|
|
@@ -11115,8 +11221,7 @@ function extractSliceUsage(messages, beforeMessageCount) {
|
|
|
11115
11221
|
return hasAgentTurnUsage(usage) ? usage : void 0;
|
|
11116
11222
|
}
|
|
11117
11223
|
function requesterFromContext(context) {
|
|
11118
|
-
|
|
11119
|
-
return identity?.platform === "slack" ? toStoredSlackRequester(identity) : void 0;
|
|
11224
|
+
return actorRequesterFromContext(context);
|
|
11120
11225
|
}
|
|
11121
11226
|
function assertRequesterDestinationMatch(context) {
|
|
11122
11227
|
const { destination, requester } = context;
|
|
@@ -11150,26 +11255,11 @@ function assertCorrelationDestinationMatch(context) {
|
|
|
11150
11255
|
}
|
|
11151
11256
|
function actorRequesterFromContext(context) {
|
|
11152
11257
|
return createRequester(context.requester, {
|
|
11153
|
-
platform: context.requester?.platform ?? (context.destination
|
|
11154
|
-
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),
|
|
11155
11260
|
userId: context.correlation?.requesterId
|
|
11156
11261
|
});
|
|
11157
11262
|
}
|
|
11158
|
-
function toolInvocationSource(context) {
|
|
11159
|
-
if (context.source) {
|
|
11160
|
-
return context.source;
|
|
11161
|
-
}
|
|
11162
|
-
if (context.destination.platform !== "slack") {
|
|
11163
|
-
return context.destination;
|
|
11164
|
-
}
|
|
11165
|
-
return {
|
|
11166
|
-
platform: "slack",
|
|
11167
|
-
teamId: context.destination.teamId,
|
|
11168
|
-
channelId: context.destination.channelId,
|
|
11169
|
-
...context.correlation?.messageTs ? { messageTs: context.correlation.messageTs } : {},
|
|
11170
|
-
...context.correlation?.threadTs ? { threadTs: context.correlation.threadTs } : {}
|
|
11171
|
-
};
|
|
11172
|
-
}
|
|
11173
11263
|
function toolInvocationDestination(context) {
|
|
11174
11264
|
if (context.destination.platform !== "slack" || !context.toolChannelId) {
|
|
11175
11265
|
return context.destination;
|
|
@@ -11281,7 +11371,20 @@ function buildSteeringPiMessage(message) {
|
|
|
11281
11371
|
timestamp: message.timestampMs ?? Date.now()
|
|
11282
11372
|
};
|
|
11283
11373
|
}
|
|
11284
|
-
|
|
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) {
|
|
11285
11388
|
if (!context.destination) {
|
|
11286
11389
|
throw new TypeError("Assistant reply generation requires a destination");
|
|
11287
11390
|
}
|
|
@@ -11313,6 +11416,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11313
11416
|
const requester = requesterFromContext(context);
|
|
11314
11417
|
const actorRequester = actorRequesterFromContext(context);
|
|
11315
11418
|
const surface = surfaceFromContext(context);
|
|
11419
|
+
const runSource = context.source;
|
|
11316
11420
|
const credentialActor = context.credentialContext?.actor;
|
|
11317
11421
|
const credentialActorLogContext = credentialActor ? {
|
|
11318
11422
|
actorType: credentialActor.type,
|
|
@@ -11393,7 +11497,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11393
11497
|
}
|
|
11394
11498
|
let baseInstructions = "";
|
|
11395
11499
|
let configurationValues;
|
|
11396
|
-
const userInput =
|
|
11500
|
+
const userInput = messageText2;
|
|
11397
11501
|
if (shouldTrace) {
|
|
11398
11502
|
const inboundAttachmentCount = context.inboundAttachmentCount ?? 0;
|
|
11399
11503
|
const promptAttachmentCount = context.userAttachments?.length ?? 0;
|
|
@@ -11550,14 +11654,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11550
11654
|
userAttachments: context.userAttachments,
|
|
11551
11655
|
userTurnText
|
|
11552
11656
|
});
|
|
11553
|
-
const preAgentPromptMessages = () => existingSessionRecord?.piMessages ?? [
|
|
11554
|
-
...context.piMessages ?? [],
|
|
11555
|
-
{
|
|
11556
|
-
role: "user",
|
|
11557
|
-
content: userContentParts,
|
|
11558
|
-
timestamp: Date.now()
|
|
11559
|
-
}
|
|
11560
|
-
];
|
|
11657
|
+
const preAgentPromptMessages = () => existingSessionRecord?.piMessages ?? [...context.piMessages ?? []];
|
|
11561
11658
|
thinkingSelection = await selectTurnThinkingLevel({
|
|
11562
11659
|
completeObject,
|
|
11563
11660
|
conversationContext: context.conversationContext,
|
|
@@ -11600,6 +11697,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11600
11697
|
requesterId: authRequesterId,
|
|
11601
11698
|
channelId: slackChannelId,
|
|
11602
11699
|
destination: context.destination,
|
|
11700
|
+
source: runSource,
|
|
11603
11701
|
threadTs: context.correlation?.threadTs,
|
|
11604
11702
|
toolChannelId: context.toolChannelId,
|
|
11605
11703
|
userMessage: userInput,
|
|
@@ -11617,6 +11715,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11617
11715
|
requesterId: authRequesterId,
|
|
11618
11716
|
channelId: slackChannelId,
|
|
11619
11717
|
destination: context.destination,
|
|
11718
|
+
source: runSource,
|
|
11620
11719
|
threadTs: context.correlation?.threadTs,
|
|
11621
11720
|
userMessage: userInput,
|
|
11622
11721
|
channelConfiguration: context.channelConfiguration,
|
|
@@ -11661,20 +11760,26 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11661
11760
|
streamFn: createTracedStreamFn({ conversationPrivacy })
|
|
11662
11761
|
}
|
|
11663
11762
|
};
|
|
11664
|
-
const toolSource =
|
|
11763
|
+
const toolSource = runSource;
|
|
11665
11764
|
const toolDestination = toolInvocationDestination(context);
|
|
11666
11765
|
let toolRuntimeContext;
|
|
11667
11766
|
if (toolSource.platform === "slack") {
|
|
11767
|
+
if (toolDestination.platform !== "slack") {
|
|
11768
|
+
throw new TypeError("Slack tool runtime requires a Slack destination");
|
|
11769
|
+
}
|
|
11668
11770
|
toolRuntimeContext = {
|
|
11669
11771
|
...commonToolRuntimeContext,
|
|
11670
|
-
|
|
11772
|
+
destination: toolDestination,
|
|
11671
11773
|
requester: actorRequester?.platform === "slack" ? actorRequester : void 0,
|
|
11672
11774
|
source: toolSource
|
|
11673
11775
|
};
|
|
11674
11776
|
} else {
|
|
11777
|
+
if (toolDestination.platform !== "local") {
|
|
11778
|
+
throw new TypeError("Local tool runtime requires a local destination");
|
|
11779
|
+
}
|
|
11675
11780
|
toolRuntimeContext = {
|
|
11676
11781
|
...commonToolRuntimeContext,
|
|
11677
|
-
|
|
11782
|
+
destination: toolDestination,
|
|
11678
11783
|
requester: actorRequester?.platform === "local" ? actorRequester : void 0,
|
|
11679
11784
|
source: toolSource
|
|
11680
11785
|
};
|
|
@@ -11759,12 +11864,29 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11759
11864
|
const activeMcpCatalogs = toActiveMcpCatalogSummaries(
|
|
11760
11865
|
turnMcpToolManager.getActiveToolCatalog()
|
|
11761
11866
|
);
|
|
11762
|
-
|
|
11763
|
-
const
|
|
11764
|
-
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({
|
|
11765
11886
|
availableSkills,
|
|
11766
11887
|
activeMcpCatalogs,
|
|
11767
|
-
includeSessionContext:
|
|
11888
|
+
includeSessionContext: needsBootstrapContextForPrompt,
|
|
11889
|
+
pluginPromptContributions: pluginUserPromptContributions,
|
|
11768
11890
|
toolGuidance,
|
|
11769
11891
|
runtime: {
|
|
11770
11892
|
conversationId: spanContext.conversationId,
|
|
@@ -11798,10 +11920,10 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11798
11920
|
const inputMessagesAttribute = serializeGenAiAttribute(
|
|
11799
11921
|
conversationPrivacy !== "public" ? inputMessages.map(toGenAiMessageMetadata) : inputMessages
|
|
11800
11922
|
);
|
|
11801
|
-
const onToolCall = (toolName, params) => {
|
|
11923
|
+
const onToolCall = async (toolName, params) => {
|
|
11802
11924
|
toolCalls.push(toolName);
|
|
11803
11925
|
try {
|
|
11804
|
-
context.onToolInvocation?.({ toolName, params });
|
|
11926
|
+
await context.onToolInvocation?.({ toolName, params });
|
|
11805
11927
|
} catch (error) {
|
|
11806
11928
|
logWarn(
|
|
11807
11929
|
"tool_invocation_observer_failed",
|
|
@@ -11823,7 +11945,8 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11823
11945
|
pluginAuth,
|
|
11824
11946
|
onToolCall,
|
|
11825
11947
|
pluginHooks,
|
|
11826
|
-
conversationPrivacy
|
|
11948
|
+
conversationPrivacy,
|
|
11949
|
+
context.onToolResult
|
|
11827
11950
|
);
|
|
11828
11951
|
advisorTools = createAgentTools(
|
|
11829
11952
|
createAdvisorToolDefinitions(tools),
|
|
@@ -11834,7 +11957,8 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11834
11957
|
pluginAuth,
|
|
11835
11958
|
onToolCall,
|
|
11836
11959
|
pluginHooks,
|
|
11837
|
-
conversationPrivacy
|
|
11960
|
+
conversationPrivacy,
|
|
11961
|
+
context.onToolResult
|
|
11838
11962
|
);
|
|
11839
11963
|
let hasEmittedText = false;
|
|
11840
11964
|
let needsSeparator = false;
|
|
@@ -11853,6 +11977,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11853
11977
|
channelName: context.correlation?.channelName,
|
|
11854
11978
|
conversationId: sessionConversationId,
|
|
11855
11979
|
destination: context.destination,
|
|
11980
|
+
source: runSource,
|
|
11856
11981
|
sessionId,
|
|
11857
11982
|
sliceId: currentSliceId,
|
|
11858
11983
|
messages,
|
|
@@ -11931,8 +12056,9 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11931
12056
|
);
|
|
11932
12057
|
throw cooperativeYieldError;
|
|
11933
12058
|
};
|
|
12059
|
+
const apiKeyOverride = getPiGatewayApiKey();
|
|
11934
12060
|
agent = new Agent2({
|
|
11935
|
-
getApiKey: () =>
|
|
12061
|
+
...apiKeyOverride ? { getApiKey: () => apiKeyOverride } : {},
|
|
11936
12062
|
streamFn: createTracedStreamFn({ conversationPrivacy }),
|
|
11937
12063
|
steeringMode: "all",
|
|
11938
12064
|
prepareNextTurn: async () => {
|
|
@@ -11991,16 +12117,13 @@ async function generateAssistantReply(messageText, context) {
|
|
|
11991
12117
|
beforeMessageCount = agent.state.messages.length;
|
|
11992
12118
|
try {
|
|
11993
12119
|
if (resumedFromSessionRecord) {
|
|
11994
|
-
agent.state.messages =
|
|
11995
|
-
existingSessionRecord.piMessages,
|
|
11996
|
-
turnContextPrompt
|
|
11997
|
-
) : existingSessionRecord.piMessages;
|
|
12120
|
+
agent.state.messages = shouldPromptAgent ? promptHistoryMessages ?? [] : existingSessionRecord.piMessages;
|
|
11998
12121
|
turnStartMessageIndex = existingSessionRecord.turnStartMessageIndex;
|
|
11999
12122
|
} else if (context.piMessages && context.piMessages.length > 0) {
|
|
12000
12123
|
agent.state.messages = [...context.piMessages];
|
|
12001
12124
|
}
|
|
12002
12125
|
beforeMessageCount = agent.state.messages.length;
|
|
12003
|
-
if (
|
|
12126
|
+
if (shouldPromptAgent) {
|
|
12004
12127
|
turnStartMessageIndex = beforeMessageCount;
|
|
12005
12128
|
}
|
|
12006
12129
|
await withSpan(
|
|
@@ -12014,7 +12137,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
12014
12137
|
content: promptContentParts,
|
|
12015
12138
|
timestamp: Date.now()
|
|
12016
12139
|
};
|
|
12017
|
-
if (
|
|
12140
|
+
if (shouldPromptAgent) {
|
|
12018
12141
|
const promptPersisted = await requireDurableInputCheckpoint([
|
|
12019
12142
|
...agent.state.messages,
|
|
12020
12143
|
freshPromptMessage
|
|
@@ -12091,7 +12214,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
12091
12214
|
}
|
|
12092
12215
|
}
|
|
12093
12216
|
};
|
|
12094
|
-
let run =
|
|
12217
|
+
let run = shouldPromptAgent ? agent.prompt(freshPromptMessage) : agent.continue();
|
|
12095
12218
|
let retryUsage;
|
|
12096
12219
|
for (let attempt = 0; ; attempt += 1) {
|
|
12097
12220
|
promptResult = await runAgentStep(run);
|
|
@@ -12140,7 +12263,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
12140
12263
|
{},
|
|
12141
12264
|
"Retrying transient provider failure"
|
|
12142
12265
|
);
|
|
12143
|
-
await
|
|
12266
|
+
await sleep3(providerRetry.delayMs);
|
|
12144
12267
|
run = agent.continue();
|
|
12145
12268
|
}
|
|
12146
12269
|
},
|
|
@@ -12171,6 +12294,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
12171
12294
|
currentDurationMs: Date.now() - replyStartedAtMs,
|
|
12172
12295
|
currentUsage: turnUsage,
|
|
12173
12296
|
destination: context.destination,
|
|
12297
|
+
source: runSource,
|
|
12174
12298
|
sessionId,
|
|
12175
12299
|
sliceId: currentSliceId,
|
|
12176
12300
|
allMessages: agent.state.messages,
|
|
@@ -12207,6 +12331,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
12207
12331
|
channelName: context.correlation?.channelName,
|
|
12208
12332
|
conversationId: timeoutResumeConversationId,
|
|
12209
12333
|
destination: context.destination,
|
|
12334
|
+
source: runSource,
|
|
12210
12335
|
sessionId: timeoutResumeSessionId,
|
|
12211
12336
|
currentSliceId: timeoutResumeSliceId,
|
|
12212
12337
|
currentDurationMs: Date.now() - replyStartedAtMs,
|
|
@@ -12232,6 +12357,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
12232
12357
|
channelName: context.correlation?.channelName,
|
|
12233
12358
|
conversationId: timeoutResumeConversationId,
|
|
12234
12359
|
destination: context.destination,
|
|
12360
|
+
source: runSource,
|
|
12235
12361
|
sessionId: timeoutResumeSessionId,
|
|
12236
12362
|
currentSliceId: timeoutResumeSliceId,
|
|
12237
12363
|
currentDurationMs: Date.now() - replyStartedAtMs,
|
|
@@ -12276,6 +12402,7 @@ async function generateAssistantReply(messageText, context) {
|
|
|
12276
12402
|
channelName: context.correlation?.channelName,
|
|
12277
12403
|
conversationId: timeoutResumeConversationId,
|
|
12278
12404
|
destination: context.destination,
|
|
12405
|
+
source: runSource,
|
|
12279
12406
|
sessionId: timeoutResumeSessionId,
|
|
12280
12407
|
currentSliceId: timeoutResumeSliceId,
|
|
12281
12408
|
currentDurationMs: Date.now() - replyStartedAtMs,
|
|
@@ -12729,6 +12856,194 @@ function getConversationMessageSlackTs(message) {
|
|
|
12729
12856
|
return message.meta?.slackTs ?? toOptionalString(message.id);
|
|
12730
12857
|
}
|
|
12731
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
|
+
|
|
12732
13047
|
// src/chat/runtime/delivered-turn-state.ts
|
|
12733
13048
|
function buildDeliveredTurnStatePatch(args) {
|
|
12734
13049
|
const conversation = structuredClone(args.conversation);
|
|
@@ -12839,5 +13154,7 @@ export {
|
|
|
12839
13154
|
createConversationMemoryService,
|
|
12840
13155
|
isHumanConversationMessage,
|
|
12841
13156
|
getConversationMessageSlackTs,
|
|
13157
|
+
scheduleSessionCompletedPluginTasks,
|
|
13158
|
+
processPluginTask,
|
|
12842
13159
|
buildDeliveredTurnStatePatch
|
|
12843
13160
|
};
|