@sentry/junior 0.113.0 → 0.115.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.
Files changed (98) hide show
  1. package/dist/{agent-hooks-BKEMWR3Z.js → agent-hooks-4EUUXP2F.js} +12 -11
  2. package/dist/api/conversations/detail.d.ts +26 -0
  3. package/dist/api/conversations/event-list.d.ts +26 -0
  4. package/dist/api/conversations/events.d.ts +1 -1
  5. package/dist/api/health.d.ts +7 -0
  6. package/dist/api/plugin-reports.d.ts +62 -0
  7. package/dist/api/plugins.d.ts +9 -0
  8. package/dist/api/runtime.d.ts +24 -0
  9. package/dist/api/schema/conversation.d.ts +104 -0
  10. package/dist/api/schema.d.ts +2 -2
  11. package/dist/api/schema.js +6 -6
  12. package/dist/api/skills.d.ts +6 -0
  13. package/dist/api.js +140 -100
  14. package/dist/app.d.ts +2 -0
  15. package/dist/app.js +1117 -5010
  16. package/dist/catalog-runtime-Y32UEQLB.js +18 -0
  17. package/dist/chat/agent/request.d.ts +6 -0
  18. package/dist/chat/agent/sandbox.d.ts +2 -0
  19. package/dist/chat/agent/tools.d.ts +2 -0
  20. package/dist/chat/config.d.ts +3 -1
  21. package/dist/chat/conversations/history.d.ts +92 -0
  22. package/dist/chat/conversations/projection.d.ts +20 -1
  23. package/dist/chat/local/credential-sync.d.ts +5 -0
  24. package/dist/chat/local/oauth-relay.d.ts +4 -0
  25. package/dist/chat/mcp/oauth.d.ts +1 -0
  26. package/dist/chat/oauth-authorization.d.ts +17 -0
  27. package/dist/chat/oauth-flow.d.ts +9 -0
  28. package/dist/chat/sandbox/egress/schemas.d.ts +46 -0
  29. package/dist/chat/sandbox/egress/signals.d.ts +9 -0
  30. package/dist/chat/sandbox/sandbox.d.ts +2 -0
  31. package/dist/chat/sentry-payload-filter.d.ts +4 -4
  32. package/dist/chat/services/context-budget.d.ts +7 -2
  33. package/dist/chat/services/context-compaction.d.ts +28 -1
  34. package/dist/chat/services/conversation-memory.d.ts +1 -0
  35. package/dist/chat/services/mcp-auth-orchestration.d.ts +5 -3
  36. package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -0
  37. package/dist/chat/services/provider-error.d.ts +1 -0
  38. package/dist/chat/services/turn-router.d.ts +1 -0
  39. package/dist/chat/slack/message-control.d.ts +2 -0
  40. package/dist/chat/slack/oauth-authorization-message.d.ts +3 -0
  41. package/dist/chat/task-execution/slack-work.d.ts +2 -0
  42. package/dist/chat/tool-support/zod-tool.d.ts +1 -1
  43. package/dist/chat/tools/definition.d.ts +5 -0
  44. package/dist/chat/tools/sandbox/edit-file.d.ts +1 -1
  45. package/dist/chat/tools/sandbox/text-edits.d.ts +1 -0
  46. package/dist/{chunk-4WZ7YKDF.js → chunk-2QG4MZQ7.js} +2 -2
  47. package/dist/{chunk-H5ON7XTE.js → chunk-43RYMWJ2.js} +954 -2514
  48. package/dist/chunk-4CODA7P5.js +43 -0
  49. package/dist/{chunk-HMRVILWZ.js → chunk-67CVNDJ7.js} +1 -1
  50. package/dist/{chunk-LR2SKL5Y.js → chunk-6FKLPVF3.js} +1 -1
  51. package/dist/{chunk-2ZTTXTSZ.js → chunk-6OPTF4BQ.js} +10 -4
  52. package/dist/{chunk-3CTIAKSS.js → chunk-6V762AB4.js} +1 -1
  53. package/dist/{chunk-WBB22ANL.js → chunk-AGLQYELI.js} +77 -8
  54. package/dist/{chunk-DXRPHBOU.js → chunk-CEYOL62C.js} +77 -36
  55. package/dist/{chunk-QTS66GMR.js → chunk-CWEZEPD4.js} +3 -3
  56. package/dist/chunk-DIB4GX3G.js +8 -0
  57. package/dist/{chunk-OXE5ZUTS.js → chunk-EW5MLKT5.js} +10 -75
  58. package/dist/{chunk-42WRQLJ6.js → chunk-F3B2YJ76.js} +0 -14
  59. package/dist/chunk-FA6POGLH.js +70 -0
  60. package/dist/{chunk-ZRSUCJGA.js → chunk-FHC4JUSF.js} +1 -1
  61. package/dist/{chunk-6Y5L4BOM.js → chunk-FXOYURO4.js} +5 -3
  62. package/dist/{chunk-UKGNSJQQ.js → chunk-G36V2YGB.js} +108 -82
  63. package/dist/{chunk-K5BXPM74.js → chunk-G5SX4UPR.js} +3 -43
  64. package/dist/chunk-HDSDCEPK.js +80 -0
  65. package/dist/{chunk-LLKDNPYV.js → chunk-HWCQRGLL.js} +37 -3
  66. package/dist/{chunk-C4MZ3GP5.js → chunk-HZF5P5UN.js} +1 -1
  67. package/dist/chunk-LYA2AB5G.js +1914 -0
  68. package/dist/{chunk-36UJA3OD.js → chunk-NVUQSFWX.js} +2 -2
  69. package/dist/chunk-OB42YVAE.js +16 -0
  70. package/dist/{chunk-4VKFQPCW.js → chunk-PVZHG2XZ.js} +4 -4
  71. package/dist/{chunk-YJ44UT7D.js → chunk-RAVKCKXA.js} +7 -7
  72. package/dist/{chunk-RCBUZGIT.js → chunk-SYJT7AKB.js} +23 -20
  73. package/dist/{chunk-NP7TYFYR.js → chunk-TVE25LPW.js} +1 -1
  74. package/dist/chunk-W3U3YQYI.js +71 -0
  75. package/dist/chunk-YCLO7D7M.js +4267 -0
  76. package/dist/cli/chat.js +72 -40
  77. package/dist/cli/check.js +10 -8
  78. package/dist/cli/init.js +1 -0
  79. package/dist/cli/plugins.js +16 -14
  80. package/dist/cli/snapshot-warmup.js +13 -11
  81. package/dist/cli/upgrade.js +10 -8
  82. package/dist/{db-2ASK6MV6.js → db-KBSJHAZU.js} +8 -7
  83. package/dist/handlers/sandbox-egress-signals.d.ts +4 -0
  84. package/dist/instrumentation.js +72 -4
  85. package/dist/nitro.js +2 -2
  86. package/dist/oauth-callback-server-EYRMJTCS.js +231 -0
  87. package/dist/oauth-relay-3ZU72UGL.js +9 -0
  88. package/dist/reporting-schema.d.ts +12 -4
  89. package/dist/reporting.d.ts +5 -5
  90. package/dist/{runner-L363K62Z.js → runner-RQGZ5Z2S.js} +139 -72
  91. package/dist/sandbox-egress-signals-CDFAP67O.js +75 -0
  92. package/dist/{skills-VCPG3NOO.js → skills-JJQIE3BT.js} +10 -8
  93. package/dist/validation-MZ47PZP5.js +21 -0
  94. package/dist/version.js +1 -1
  95. package/package.json +5 -5
  96. package/dist/catalog-runtime-6XYOUVRZ.js +0 -16
  97. package/dist/chat/oauth-authorization-message.d.ts +0 -6
  98. package/dist/validation-GY7AJBLC.js +0 -19
@@ -0,0 +1,231 @@
1
+ import {
2
+ GET,
3
+ GET2,
4
+ syncLocalOAuthCredential
5
+ } from "./chunk-YCLO7D7M.js";
6
+ import "./chunk-FA6POGLH.js";
7
+ import "./chunk-AGLQYELI.js";
8
+ import "./chunk-4CODA7P5.js";
9
+ import "./chunk-MIAKQNYX.js";
10
+ import "./chunk-KNFROR7R.js";
11
+ import {
12
+ createUserTokenStore
13
+ } from "./chunk-LYA2AB5G.js";
14
+ import "./chunk-CEYOL62C.js";
15
+ import "./chunk-MU6HHZEN.js";
16
+ import "./chunk-PDO5BLNM.js";
17
+ import "./chunk-RAVKCKXA.js";
18
+ import "./chunk-67CVNDJ7.js";
19
+ import "./chunk-CWEZEPD4.js";
20
+ import "./chunk-HWCQRGLL.js";
21
+ import "./chunk-JQFJO5WH.js";
22
+ import "./chunk-4ZNGQH7C.js";
23
+ import "./chunk-SYJT7AKB.js";
24
+ import "./chunk-VFUK3X5B.js";
25
+ import "./chunk-FXOYURO4.js";
26
+ import "./chunk-2QG4MZQ7.js";
27
+ import "./chunk-6FKLPVF3.js";
28
+ import "./chunk-EW5MLKT5.js";
29
+ import "./chunk-W3U3YQYI.js";
30
+ import "./chunk-HZF5P5UN.js";
31
+ import "./chunk-NVUQSFWX.js";
32
+ import "./chunk-OB42YVAE.js";
33
+ import "./chunk-F3B2YJ76.js";
34
+ import "./chunk-6GWA276C.js";
35
+ import "./chunk-B3IT5END.js";
36
+ import "./chunk-3V7OFJZC.js";
37
+ import "./chunk-TVE25LPW.js";
38
+ import "./chunk-FHC4JUSF.js";
39
+ import "./chunk-MLKGABMK.js";
40
+
41
+ // src/chat/local/oauth-callback-server.ts
42
+ import { createServer } from "http";
43
+ var LOCAL_OAUTH_TIMEOUT_MS = 10 * 60 * 1e3;
44
+ var LOCAL_OAUTH_CALLBACK_TIMEOUT_MS = 60 * 1e3;
45
+ function decodeProvider(value) {
46
+ if (!value) {
47
+ return void 0;
48
+ }
49
+ try {
50
+ const provider = decodeURIComponent(value);
51
+ return /^[a-z][a-z0-9-]*$/.test(provider) ? provider : void 0;
52
+ } catch {
53
+ return void 0;
54
+ }
55
+ }
56
+ async function startLocalOAuthCallbackServer(agentRunner) {
57
+ let pendingAuthorization;
58
+ const completeAuthorization = (authorization, result) => {
59
+ if (authorization.settled) {
60
+ return;
61
+ }
62
+ authorization.settled = true;
63
+ clearTimeout(authorization.timeout);
64
+ authorization.finish(result);
65
+ };
66
+ const cancelAuthorization = () => {
67
+ const authorization = pendingAuthorization;
68
+ if (!authorization) {
69
+ return;
70
+ }
71
+ pendingAuthorization = void 0;
72
+ completeAuthorization(
73
+ authorization,
74
+ new Error("Local OAuth authorization canceled")
75
+ );
76
+ };
77
+ const server = createServer(async (incoming, outgoing) => {
78
+ const host = incoming.headers.host ?? "127.0.0.1";
79
+ let requestUrl;
80
+ try {
81
+ requestUrl = new URL(incoming.url ?? "/", `http://${host}`);
82
+ } catch {
83
+ outgoing.writeHead(400).end("Invalid callback request");
84
+ return;
85
+ }
86
+ const mcpMatch = requestUrl.pathname.match(
87
+ /^\/api\/oauth\/callback\/mcp\/([^/]+)$/
88
+ );
89
+ const pluginMatch = requestUrl.pathname.match(
90
+ /^\/api\/oauth\/callback\/([^/]+)$/
91
+ );
92
+ const provider = decodeProvider(mcpMatch?.[1] ?? pluginMatch?.[1]);
93
+ if (!provider) {
94
+ outgoing.writeHead(404).end("Not found");
95
+ return;
96
+ }
97
+ const authorization = pendingAuthorization;
98
+ if (!authorization || authorization.callbackStarted || authorization.settled || requestUrl.searchParams.get("state") !== authorization.state) {
99
+ outgoing.writeHead(409).end("No matching authorization request");
100
+ return;
101
+ }
102
+ authorization.callbackStarted = true;
103
+ clearTimeout(authorization.timeout);
104
+ authorization.timeout = setTimeout(() => {
105
+ if (!outgoing.headersSent) {
106
+ outgoing.writeHead(504).end("Authorization callback timed out");
107
+ }
108
+ completeAuthorization(
109
+ authorization,
110
+ new Error("Timed out completing OAuth authorization")
111
+ );
112
+ }, LOCAL_OAUTH_CALLBACK_TIMEOUT_MS);
113
+ const backgroundTasks = [];
114
+ const waitUntil = (task) => {
115
+ backgroundTasks.push(
116
+ typeof task === "function" ? Promise.resolve().then(task) : task
117
+ );
118
+ };
119
+ try {
120
+ const request = new Request(requestUrl, { method: "GET" });
121
+ const response = mcpMatch ? await GET(request, provider, waitUntil, {
122
+ agentRunner
123
+ }) : await GET2(request, provider, waitUntil, {
124
+ agentRunner
125
+ });
126
+ const body = Buffer.from(await response.arrayBuffer());
127
+ await Promise.all(backgroundTasks);
128
+ if (response.ok) {
129
+ if (!mcpMatch) {
130
+ const tokens = await createUserTokenStore().get(
131
+ "local-cli",
132
+ provider
133
+ );
134
+ if (!tokens) {
135
+ throw new Error(
136
+ `${provider} authorization completed without a stored credential`
137
+ );
138
+ }
139
+ await syncLocalOAuthCredential(provider, tokens);
140
+ }
141
+ }
142
+ if (authorization.settled) {
143
+ return;
144
+ }
145
+ if (response.ok) {
146
+ completeAuthorization(authorization, true);
147
+ } else {
148
+ completeAuthorization(
149
+ authorization,
150
+ new Error(
151
+ `${provider} authorization callback failed with HTTP ${response.status}`
152
+ )
153
+ );
154
+ }
155
+ outgoing.writeHead(
156
+ response.status,
157
+ Object.fromEntries(response.headers.entries())
158
+ );
159
+ outgoing.end(body);
160
+ } catch (error) {
161
+ if (!outgoing.headersSent) {
162
+ outgoing.writeHead(500).end("Authorization callback failed");
163
+ }
164
+ completeAuthorization(
165
+ authorization,
166
+ error instanceof Error ? error : new Error(String(error))
167
+ );
168
+ }
169
+ });
170
+ await new Promise((resolve, reject) => {
171
+ server.once("error", reject);
172
+ server.listen(0, "127.0.0.1", () => {
173
+ server.off("error", reject);
174
+ resolve();
175
+ });
176
+ });
177
+ const address = server.address();
178
+ return {
179
+ beginAuthorization: (authorizationUrl) => {
180
+ if (pendingAuthorization) {
181
+ throw new Error("Local OAuth already has an active authorization");
182
+ }
183
+ const state = new URL(authorizationUrl).searchParams.get("state");
184
+ if (!state) {
185
+ throw new Error("Local OAuth authorization URL is missing state");
186
+ }
187
+ let finish = () => void 0;
188
+ const result = new Promise((resolve) => {
189
+ finish = resolve;
190
+ });
191
+ const authorization = {
192
+ callbackStarted: false,
193
+ finish,
194
+ result,
195
+ settled: false,
196
+ state,
197
+ timeout: setTimeout(() => {
198
+ completeAuthorization(
199
+ authorization,
200
+ new Error("Timed out waiting for OAuth authorization")
201
+ );
202
+ }, LOCAL_OAUTH_TIMEOUT_MS)
203
+ };
204
+ pendingAuthorization = authorization;
205
+ },
206
+ cancelAuthorization,
207
+ port: address.port,
208
+ waitForAuthorization: async () => {
209
+ const authorization = pendingAuthorization;
210
+ if (!authorization) {
211
+ throw new Error("Local OAuth has no active authorization");
212
+ }
213
+ const result = await authorization.result;
214
+ if (pendingAuthorization === authorization) {
215
+ pendingAuthorization = void 0;
216
+ }
217
+ if (result instanceof Error) {
218
+ throw result;
219
+ }
220
+ },
221
+ close: async () => {
222
+ cancelAuthorization();
223
+ await new Promise((resolve, reject) => {
224
+ server.close((error) => error ? reject(error) : resolve());
225
+ });
226
+ }
227
+ };
228
+ }
229
+ export {
230
+ startLocalOAuthCallbackServer
231
+ };
@@ -0,0 +1,9 @@
1
+ import {
2
+ createLocalOAuthState,
3
+ relayLocalOAuthCallback
4
+ } from "./chunk-FA6POGLH.js";
5
+ import "./chunk-MLKGABMK.js";
6
+ export {
7
+ createLocalOAuthState,
8
+ relayLocalOAuthCallback
9
+ };
@@ -4,10 +4,18 @@ export declare const healthReportSchema: z.ZodObject<{
4
4
  service: z.ZodString;
5
5
  timestamp: z.ZodString;
6
6
  }, z.core.$strict>;
7
- export declare const pluginReportSchema: z.ZodObject<{
7
+ export declare const pluginSchema: z.ZodObject<{
8
+ capabilities: z.ZodArray<z.ZodString>;
9
+ configKeys: z.ZodArray<z.ZodString>;
10
+ description: z.ZodString;
11
+ displayName: z.ZodString;
8
12
  name: z.ZodString;
9
13
  }, z.core.$strict>;
10
- export declare const pluginReportsSchema: z.ZodArray<z.ZodObject<{
14
+ export declare const pluginsSchema: z.ZodArray<z.ZodObject<{
15
+ capabilities: z.ZodArray<z.ZodString>;
16
+ configKeys: z.ZodArray<z.ZodString>;
17
+ description: z.ZodString;
18
+ displayName: z.ZodString;
11
19
  name: z.ZodString;
12
20
  }, z.core.$strict>>;
13
21
  export declare const skillReportSchema: z.ZodObject<{
@@ -175,8 +183,8 @@ export declare const pluginOperationalReportFeedSchema: z.ZodObject<{
175
183
  source: z.ZodLiteral<"plugins">;
176
184
  }, z.core.$strict>;
177
185
  export type HealthReport = z.infer<typeof healthReportSchema>;
178
- export type PluginReport = z.infer<typeof pluginReportSchema>;
179
- export type PluginReports = z.infer<typeof pluginReportsSchema>;
186
+ export type Plugin = z.infer<typeof pluginSchema>;
187
+ export type Plugins = z.infer<typeof pluginsSchema>;
180
188
  export type SkillReport = z.infer<typeof skillReportSchema>;
181
189
  export type SkillReports = z.infer<typeof skillReportsSchema>;
182
190
  export type RuntimeInfoReport = z.infer<typeof runtimeInfoReportSchema>;
@@ -1,11 +1,11 @@
1
- import type { PluginOperationalReportFeed, PluginReport, RuntimeInfoReport, SkillReport } from "./reporting-schema";
2
- export { healthReportSchema, pluginOperationalReportFeedSchema, pluginOperationalReportSchema, pluginPackageContentItemReportSchema, pluginPackageContentReportSchema, pluginReportSchema, pluginReportsSchema, runtimeInfoReportSchema, skillReportSchema, skillReportsSchema, } from "./reporting-schema";
1
+ import type { PluginOperationalReportFeed, Plugin, RuntimeInfoReport, SkillReport } from "./reporting-schema";
2
+ export { healthReportSchema, pluginOperationalReportFeedSchema, pluginOperationalReportSchema, pluginPackageContentItemReportSchema, pluginPackageContentReportSchema, pluginSchema, pluginsSchema, runtimeInfoReportSchema, skillReportSchema, skillReportsSchema, } from "./reporting-schema";
3
3
  export { readHealthReport } from "./handlers/health";
4
- export type { HealthReport, PluginOperationalReport, PluginOperationalReportFeed, PluginPackageContentItemReport, PluginPackageContentReport, PluginReport, PluginReports, RuntimeInfoReport, SkillReport, SkillReports, } from "./reporting-schema";
4
+ export type { HealthReport, PluginOperationalReport, PluginOperationalReportFeed, PluginPackageContentItemReport, PluginPackageContentReport, Plugin, Plugins, RuntimeInfoReport, SkillReport, SkillReports, } from "./reporting-schema";
5
5
  /** Read discovered skill names for authenticated runtime diagnostics. */
6
6
  export declare function readSkillReports(): Promise<SkillReport[]>;
7
- /** Read configured plugin names for authenticated runtime diagnostics. */
8
- export declare function readPluginReports(): Promise<PluginReport[]>;
7
+ /** Read safe configured plugin metadata for authenticated runtime diagnostics. */
8
+ export declare function readPlugins(): Promise<Plugin[]>;
9
9
  /** Read authenticated runtime discovery data. */
10
10
  export declare function readRuntimeInfoReport(): Promise<RuntimeInfoReport>;
11
11
  /** Read sanitized operational summaries contributed by plugins. */
@@ -1,11 +1,15 @@
1
1
  import {
2
2
  ConversationTurnLifecycleService,
3
3
  buildDeliveredTurnStatePatch,
4
+ completeAuthPauseTurn,
4
5
  finalizeFailedTurnReplyWithEvent,
5
6
  processPluginTask,
6
7
  scheduleSessionCompletedPluginTasks
7
- } from "./chunk-WBB22ANL.js";
8
+ } from "./chunk-AGLQYELI.js";
8
9
  import "./chunk-KNFROR7R.js";
10
+ import {
11
+ authorizationId
12
+ } from "./chunk-DIB4GX3G.js";
9
13
  import {
10
14
  buildConversationContext,
11
15
  coerceThreadArtifactsState,
@@ -21,34 +25,36 @@ import {
21
25
  persistConversationMessages,
22
26
  persistThreadStateById,
23
27
  persistWithRetry,
28
+ recordAuthorizationCompleted,
24
29
  recordDeliveredAssistantMessage,
25
30
  startActiveTurn,
26
31
  stripRuntimeTurnContext,
27
32
  trimTrailingAssistantMessages,
28
33
  updateConversationStats,
29
34
  upsertConversationMessage
30
- } from "./chunk-DXRPHBOU.js";
35
+ } from "./chunk-CEYOL62C.js";
31
36
  import "./chunk-MU6HHZEN.js";
32
37
  import "./chunk-PDO5BLNM.js";
33
- import "./chunk-YJ44UT7D.js";
34
- import "./chunk-HMRVILWZ.js";
35
- import "./chunk-QTS66GMR.js";
38
+ import "./chunk-RAVKCKXA.js";
39
+ import "./chunk-67CVNDJ7.js";
40
+ import "./chunk-CWEZEPD4.js";
36
41
  import {
37
42
  getConversationEventStore
38
- } from "./chunk-LLKDNPYV.js";
43
+ } from "./chunk-HWCQRGLL.js";
39
44
  import "./chunk-JQFJO5WH.js";
40
45
  import "./chunk-4ZNGQH7C.js";
41
- import "./chunk-RCBUZGIT.js";
46
+ import "./chunk-SYJT7AKB.js";
42
47
  import "./chunk-VFUK3X5B.js";
43
- import "./chunk-6Y5L4BOM.js";
44
- import "./chunk-C4MZ3GP5.js";
48
+ import "./chunk-FXOYURO4.js";
49
+ import "./chunk-HZF5P5UN.js";
45
50
  import {
46
51
  logException
47
- } from "./chunk-36UJA3OD.js";
48
- import "./chunk-42WRQLJ6.js";
52
+ } from "./chunk-NVUQSFWX.js";
53
+ import "./chunk-OB42YVAE.js";
54
+ import "./chunk-F3B2YJ76.js";
49
55
  import "./chunk-6GWA276C.js";
50
- import "./chunk-NP7TYFYR.js";
51
- import "./chunk-ZRSUCJGA.js";
56
+ import "./chunk-TVE25LPW.js";
57
+ import "./chunk-FHC4JUSF.js";
52
58
  import "./chunk-MLKGABMK.js";
53
59
 
54
60
  // src/chat/local/runner.ts
@@ -77,11 +83,17 @@ function localDestination(conversationId) {
77
83
  function localTurnId() {
78
84
  return `local-turn-${randomUUID()}`;
79
85
  }
86
+ function localRunId() {
87
+ return `local-run-${randomUUID()}`;
88
+ }
80
89
  function captureLocalBoundaryFailure(args) {
81
90
  const eventId = args.capture(
82
91
  args.error,
83
92
  LOCAL_FAILURE_EVENT_NAMES[args.failureCode],
84
- { conversationId: args.conversationId, runId: args.turnId },
93
+ {
94
+ conversationId: args.conversationId,
95
+ ...args.runId ? { runId: args.runId } : {}
96
+ },
85
97
  { "app.ai.failure_code": args.failureCode },
86
98
  "Local agent turn failed at its owning runtime boundary"
87
99
  );
@@ -157,6 +169,8 @@ async function runLocalAgentTurn(input, deps) {
157
169
  let failureCode = "persistence_failed";
158
170
  let modelFailureEventId;
159
171
  let modelFailureCaptureAttempted = false;
172
+ let currentRunId;
173
+ let completionSliceId = 1;
160
174
  const localActor = {
161
175
  fullName: "Local CLI",
162
176
  platform: "local",
@@ -201,66 +215,117 @@ async function runLocalAgentTurn(input, deps) {
201
215
  conversationId: input.conversationId
202
216
  });
203
217
  failureCode = "agent_run_failed";
204
- const outcome = await deps.agentRunner.run({
205
- conversationId: input.conversationId,
206
- turnId,
207
- runId: turnId,
208
- input: {
209
- messageText: text,
210
- conversationContext: buildConversationContext(conversation, {
211
- excludeMessageId: userMessageId
212
- }),
213
- piMessages
214
- },
215
- routing: {
216
- credentialContext: {
217
- actor: { platform: "system", name: "local-cli" }
218
+ const runAgent = async (messages) => {
219
+ currentRunId = localRunId();
220
+ const authorization = deps.authorization ? {
221
+ createState: deps.authorization.createState,
222
+ deliver: deps.authorization.deliver
223
+ } : void 0;
224
+ return await deps.agentRunner.run({
225
+ conversationId: input.conversationId,
226
+ turnId,
227
+ runId: currentRunId,
228
+ input: {
229
+ messageText: text,
230
+ conversationContext: buildConversationContext(conversation, {
231
+ excludeMessageId: userMessageId
232
+ }),
233
+ piMessages: messages
218
234
  },
219
- destination,
220
- source,
221
- actor: localActor,
222
- surface: "internal"
223
- },
224
- policy: {
225
- authorizationFlowMode: "disabled"
226
- },
227
- state: {
228
- artifactState: artifacts,
229
- sandboxRef
230
- },
231
- observers: {
232
- onStatus: async (status) => {
233
- await deps.onStatus?.(status.text);
235
+ routing: {
236
+ credentialContext: {
237
+ actor: { type: "user", userId: "local-cli" }
238
+ },
239
+ destination,
240
+ source,
241
+ actor: localActor,
242
+ surface: "internal"
234
243
  },
235
- onToolInvocation: async (invocation) => {
236
- await deps.onToolInvocation?.(invocation);
244
+ authorization,
245
+ policy: {
246
+ authorizationFlowMode: deps.authorization ? "interactive" : "disabled",
247
+ sandboxEgressSignals: deps.sandboxEgressSignals
237
248
  },
238
- onToolResult: async (result) => {
239
- await deps.onToolResult?.(result);
240
- }
241
- },
242
- delivery: {
243
- onAssistantMessage: deliverAssistantMessage
244
- },
245
- durability: {
246
- onArtifactStateUpdated: async (nextArtifacts) => {
247
- artifacts = nextArtifacts;
248
- await persistThreadStateById(input.conversationId, {
249
- artifacts,
250
- conversation,
251
- sandboxRef
252
- });
249
+ state: {
250
+ artifactState: artifacts,
251
+ pendingAuth: conversation.processing.pendingAuth,
252
+ sandboxRef
253
+ },
254
+ observers: {
255
+ onStatus: async (status) => {
256
+ await deps.onStatus?.(status.text);
257
+ },
258
+ onToolInvocation: async (invocation) => {
259
+ await deps.onToolInvocation?.(invocation);
260
+ },
261
+ onToolResult: async (result) => {
262
+ await deps.onToolResult?.(result);
263
+ }
264
+ },
265
+ delivery: {
266
+ onAssistantMessage: deliverAssistantMessage
253
267
  },
254
- onSandboxRefChanged: async (nextSandboxRef) => {
255
- sandboxRef = nextSandboxRef;
256
- await persistThreadStateById(input.conversationId, {
257
- artifacts,
258
- conversation,
259
- sandboxRef
260
- });
268
+ durability: {
269
+ onArtifactStateUpdated: async (nextArtifacts) => {
270
+ artifacts = nextArtifacts;
271
+ await persistThreadStateById(input.conversationId, {
272
+ artifacts,
273
+ conversation,
274
+ sandboxRef
275
+ });
276
+ },
277
+ onSandboxRefChanged: async (nextSandboxRef) => {
278
+ sandboxRef = nextSandboxRef;
279
+ await persistThreadStateById(input.conversationId, {
280
+ artifacts,
281
+ conversation,
282
+ sandboxRef
283
+ });
284
+ },
285
+ recordPendingAuth: async (pendingAuth) => {
286
+ conversation.processing.pendingAuth = pendingAuth;
287
+ await persistThreadStateById(input.conversationId, {
288
+ artifacts,
289
+ conversation,
290
+ sandboxRef
291
+ });
292
+ }
261
293
  }
294
+ });
295
+ };
296
+ let outcome = await runAgent(piMessages);
297
+ while (outcome.status === "awaiting_auth") {
298
+ const pendingAuth = conversation.processing.pendingAuth;
299
+ if (!pendingAuth || !deps.authorization) {
300
+ throw new Error(
301
+ "Local OAuth requires an active callback server and authorization delivery."
302
+ );
262
303
  }
263
- });
304
+ completeAuthPauseTurn({ conversation, sessionId: turnId });
305
+ await persistThreadStateById(input.conversationId, {
306
+ artifacts,
307
+ conversation,
308
+ sandboxRef
309
+ });
310
+ await deps.authorization.wait();
311
+ await recordAuthorizationCompleted({
312
+ conversationId: input.conversationId,
313
+ kind: pendingAuth.kind,
314
+ provider: pendingAuth.provider,
315
+ actorId: pendingAuth.actorId,
316
+ authorizationId: authorizationId({
317
+ sessionId: turnId,
318
+ kind: pendingAuth.kind,
319
+ provider: pendingAuth.provider
320
+ })
321
+ });
322
+ completionSliceId += 1;
323
+ outcome = await runAgent(
324
+ await (deps.loadPiMessages ?? loadLocalPiMessages)({
325
+ conversationId: input.conversationId
326
+ })
327
+ );
328
+ }
264
329
  if (outcome.status !== "completed") {
265
330
  throw new Error(`Local agent run ended with ${outcome.status}`);
266
331
  }
@@ -284,12 +349,13 @@ async function runLocalAgentTurn(input, deps) {
284
349
  userMessageId
285
350
  });
286
351
  } catch (error) {
352
+ deps.authorization?.cancel();
287
353
  const failureEventId = modelFailureCaptureAttempted && failureCode === "agent_run_failed" ? modelFailureEventId : captureLocalBoundaryFailure({
288
354
  capture: deps.logException ?? logException,
289
355
  conversationId: input.conversationId,
290
356
  error,
291
357
  failureCode,
292
- turnId
358
+ runId: currentRunId
293
359
  });
294
360
  try {
295
361
  markTurnFailed({
@@ -311,7 +377,7 @@ async function runLocalAgentTurn(input, deps) {
311
377
  conversationId: input.conversationId,
312
378
  error: persistenceError,
313
379
  failureCode: "persistence_failed",
314
- turnId
380
+ runId: currentRunId
315
381
  });
316
382
  await lifecycle.fail({
317
383
  conversationId: input.conversationId,
@@ -334,6 +400,7 @@ async function runLocalAgentTurn(input, deps) {
334
400
  });
335
401
  throw error;
336
402
  }
403
+ deps.authorization?.cancel();
337
404
  try {
338
405
  await persistThreadStateById(input.conversationId, {
339
406
  artifacts: completedState.artifacts ?? artifacts,
@@ -344,7 +411,7 @@ async function runLocalAgentTurn(input, deps) {
344
411
  await (deps.completeDeliveredTurn ?? completeDeliveredTurn)({
345
412
  conversationId: input.conversationId,
346
413
  sessionId: turnId,
347
- sliceId: 1,
414
+ sliceId: completionSliceId,
348
415
  messages: reply.piMessages,
349
416
  modelId: reply.diagnostics.modelId,
350
417
  durationMs: reply.diagnostics.durationMs,
@@ -362,7 +429,7 @@ async function runLocalAgentTurn(input, deps) {
362
429
  conversationId: input.conversationId,
363
430
  error,
364
431
  failureCode: "persistence_failed",
365
- turnId
432
+ runId: currentRunId
366
433
  });
367
434
  await lifecycle.fail({
368
435
  conversationId: input.conversationId,
@@ -0,0 +1,75 @@
1
+ import {
2
+ sandboxEgressSignalsResponseSchema
3
+ } from "./chunk-HDSDCEPK.js";
4
+ import "./chunk-W3U3YQYI.js";
5
+ import "./chunk-HZF5P5UN.js";
6
+ import "./chunk-F3B2YJ76.js";
7
+ import "./chunk-MLKGABMK.js";
8
+
9
+ // src/chat/local/sandbox-egress-signals.ts
10
+ var SANDBOX_EGRESS_SIGNALS_PATH = "/api/internal/sandbox-egress/signals";
11
+ var LOCAL_DEV_SERVER_TIMEOUT_MS = 1e3;
12
+ function signalRequest(baseUrl, credentialToken) {
13
+ return {
14
+ headers: {
15
+ "x-junior-sandbox-egress-token": credentialToken
16
+ },
17
+ url: `${baseUrl}${SANDBOX_EGRESS_SIGNALS_PATH}`
18
+ };
19
+ }
20
+ async function requestLocalDevServer(request, init) {
21
+ try {
22
+ return await fetch(request.url, {
23
+ ...init,
24
+ headers: request.headers,
25
+ signal: AbortSignal.timeout(LOCAL_DEV_SERVER_TIMEOUT_MS)
26
+ });
27
+ } catch {
28
+ return void 0;
29
+ }
30
+ }
31
+ function createLocalSandboxEgressSignalTransport(baseUrl) {
32
+ return {
33
+ clear: async (credentialToken) => {
34
+ const request = signalRequest(baseUrl, credentialToken);
35
+ const response = await requestLocalDevServer(request, {
36
+ method: "DELETE"
37
+ });
38
+ if (!response) {
39
+ return;
40
+ }
41
+ if (!response.ok) {
42
+ throw new Error(
43
+ `Could not clear dev-server sandbox egress signals: HTTP ${response.status}`
44
+ );
45
+ }
46
+ },
47
+ consume: async (credentialToken) => {
48
+ const request = signalRequest(baseUrl, credentialToken);
49
+ const response = await requestLocalDevServer(request);
50
+ if (!response) {
51
+ return {};
52
+ }
53
+ if (!response.ok) {
54
+ throw new Error(
55
+ `Could not consume dev-server sandbox egress signals: HTTP ${response.status}`
56
+ );
57
+ }
58
+ const value = sandboxEgressSignalsResponseSchema.safeParse(
59
+ await response.json()
60
+ );
61
+ if (!value.success) {
62
+ throw new Error("Dev-server sandbox egress signals were invalid");
63
+ }
64
+ const authRequired = value.data.auth_required;
65
+ const permissionDenied = value.data.permission_denied;
66
+ return {
67
+ ...authRequired ? { authRequired } : {},
68
+ ...permissionDenied ? { permissionDenied } : {}
69
+ };
70
+ }
71
+ };
72
+ }
73
+ export {
74
+ createLocalSandboxEgressSignalTransport
75
+ };