@sentry/junior 0.137.0 → 0.138.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 (87) hide show
  1. package/dist/{agent-hooks-MZOKEP3J.js → agent-hooks-SCR74Q3E.js} +11 -9
  2. package/dist/api.js +21 -18
  3. package/dist/app.d.ts +7 -0
  4. package/dist/app.js +248 -689
  5. package/dist/{catalog-runtime-MD66YLFV.js → catalog-runtime-IU3QF4GG.js} +5 -5
  6. package/dist/chat/agent/request.d.ts +32 -2
  7. package/dist/chat/agent-dispatch/heartbeat.d.ts +5 -0
  8. package/dist/chat/agent-dispatch/types.d.ts +1 -1
  9. package/dist/chat/agent-invocations/errors.d.ts +8 -0
  10. package/dist/chat/agent-invocations/spawn.d.ts +12 -0
  11. package/dist/chat/agent-invocations/store.d.ts +44 -0
  12. package/dist/chat/agent-invocations/types.d.ts +449 -0
  13. package/dist/chat/agent-invocations/work.d.ts +31 -0
  14. package/dist/chat/config.d.ts +1 -0
  15. package/dist/chat/conversations/sql/store.d.ts +8 -0
  16. package/dist/chat/conversations/store.d.ts +7 -0
  17. package/dist/chat/experimental.d.ts +16 -0
  18. package/dist/chat/runtime/agent-runner.d.ts +2 -1
  19. package/dist/chat/services/auth-pause.d.ts +0 -1
  20. package/dist/chat/services/mcp-auth-orchestration.d.ts +3 -2
  21. package/dist/chat/services/plugin-auth-orchestration.d.ts +3 -2
  22. package/dist/chat/state/turn-session.d.ts +0 -2
  23. package/dist/chat/task-execution/state.d.ts +23 -11
  24. package/dist/chat/task-execution/store.d.ts +20 -11
  25. package/dist/chat/task-execution/worker.d.ts +2 -2
  26. package/dist/chat/tools/runtime/spawn-agent.d.ts +31 -0
  27. package/dist/chat/tools/types.d.ts +2 -0
  28. package/dist/chunk-3Y47VMHV.js +6 -0
  29. package/dist/chunk-5IDFPCON.js +46 -0
  30. package/dist/chunk-5LTJ4ITU.js +1523 -0
  31. package/dist/{chunk-WPPXIAFB.js → chunk-5MXWHTCK.js} +17 -434
  32. package/dist/{chunk-UOXATPSI.js → chunk-A7WCHXZV.js} +7 -5
  33. package/dist/{chunk-5G34IEK2.js → chunk-BOLJOV5T.js} +2 -56
  34. package/dist/{chunk-UG6ZYPBI.js → chunk-BYW4B4PR.js} +73 -60
  35. package/dist/{chunk-XZ7NPXAB.js → chunk-C7ZVPO4Z.js} +1 -1
  36. package/dist/{chunk-RB4NJKEX.js → chunk-DCLLQGS6.js} +119 -50
  37. package/dist/{chunk-DQXAAVTR.js → chunk-E5UYAIKJ.js} +44 -1467
  38. package/dist/{chunk-6QW2RRQT.js → chunk-ELKW5FIB.js} +5 -5
  39. package/dist/chunk-EM225ITJ.js +56 -0
  40. package/dist/{chunk-SYCX4DOK.js → chunk-FEUNPTGV.js} +7 -60
  41. package/dist/{chunk-YRPC6MJY.js → chunk-FNLBTB4K.js} +1 -1
  42. package/dist/chunk-HIWJWWMT.js +668 -0
  43. package/dist/chunk-IUFM5JWV.js +24 -0
  44. package/dist/{chunk-T6Z5S6PQ.js → chunk-JNNJZURV.js} +1 -1
  45. package/dist/{chunk-6ZK6FZIV.js → chunk-KCBZSJRU.js} +6 -27
  46. package/dist/{chunk-5PNJMOY5.js → chunk-KDCHVT25.js} +1 -1
  47. package/dist/{chunk-BZAMASJP.js → chunk-KFRHRSCJ.js} +1 -1
  48. package/dist/chunk-LPVUNO2W.js +320 -0
  49. package/dist/{chunk-EWDSB24B.js → chunk-N7WARMC6.js} +16 -776
  50. package/dist/chunk-PB3CXNVL.js +41 -0
  51. package/dist/chunk-Q6QZTTLS.js +55 -0
  52. package/dist/{chunk-36EG34YI.js → chunk-QS527AV5.js} +1 -1
  53. package/dist/chunk-R776HKPK.js +81 -0
  54. package/dist/{chunk-KJ4HGRHN.js → chunk-RZIBSCYC.js} +507 -596
  55. package/dist/chunk-SD3OFRWY.js +714 -0
  56. package/dist/{chunk-ZFS67WIR.js → chunk-SIPKWSXK.js} +57 -6
  57. package/dist/chunk-TCS76X5D.js +441 -0
  58. package/dist/{chunk-K2NCQJKH.js → chunk-TDJCLNDH.js} +3 -3
  59. package/dist/{chunk-POBSY47Q.js → chunk-TUUDXEXU.js} +336 -302
  60. package/dist/{chunk-YNFERGKP.js → chunk-VPZFVJND.js} +1 -1
  61. package/dist/{chunk-UZQ4VY3M.js → chunk-YU5QUF67.js} +1 -1
  62. package/dist/chunk-ZBSMCXKV.js +710 -0
  63. package/dist/{chunk-3Q342EJJ.js → chunk-ZXNTJJIE.js} +2 -2
  64. package/dist/cli/chat.js +65 -26
  65. package/dist/cli/check.js +6 -6
  66. package/dist/cli/plugins.js +14 -12
  67. package/dist/cli/snapshot-create.js +10 -9
  68. package/dist/cli/upgrade.js +7 -7
  69. package/dist/conversation-work-KATFHLG3.js +56 -0
  70. package/dist/db/schema/agent-invocations.d.ts +544 -0
  71. package/dist/db/schema.d.ts +543 -1
  72. package/dist/{db-66E7VDNC.js → db-UO2IWXGA.js} +7 -7
  73. package/dist/experimental-HH6OM6UH.js +13 -0
  74. package/dist/instrumentation.js +4 -4
  75. package/dist/nitro.js +4 -3
  76. package/dist/{oauth-callback-server-7QPD4Q7P.js → oauth-callback-server-MAQI43LX.js} +26 -18
  77. package/dist/{runner-L2BKJKOD.js → runner-PIUQEXKE.js} +26 -14
  78. package/dist/{skills-HOQ2NSPW.js → skills-4ARJADHQ.js} +6 -6
  79. package/dist/spawn-G2AWPMCT.js +38 -0
  80. package/dist/{validation-ENHI7S2C.js → validation-S3EE3HWL.js} +6 -6
  81. package/dist/version.js +1 -1
  82. package/dist/work-UARRUAW3.js +46 -0
  83. package/dist/worker-DOCIRVD3.js +24 -0
  84. package/migrations/0021_first_warhawk.sql +35 -0
  85. package/migrations/meta/0021_snapshot.json +2176 -0
  86. package/migrations/meta/_journal.json +8 -1
  87. package/package.json +5 -5
@@ -5,11 +5,19 @@ import type { JuniorSqlDatabase } from "@/db/db";
5
5
  import type { Conversation, ConversationExecution, ConversationSource, ConversationStore } from "../store";
6
6
  import type { AgentTurnUsage } from "@/chat/usage";
7
7
  import { type ProviderConversationBinding, type ProviderConversationReference } from "./bindings";
8
+ /** Serialize one conversation's durable mutations inside a SQL transaction. */
9
+ export declare function withConversationMutationLock<T>(executor: JuniorSqlDatabase, conversationId: string, callback: () => Promise<T>): Promise<T>;
8
10
  export declare class SqlStore implements ConversationStore {
9
11
  private readonly executor;
10
12
  constructor(executor: JuniorSqlDatabase);
11
13
  getConversationIdByProviderConversation(args: ProviderConversationReference): Promise<string | undefined>;
12
14
  bindProviderConversation(args: ProviderConversationBinding): Promise<void>;
15
+ createChild(args: {
16
+ childConversationId: string;
17
+ parentConversationId: string;
18
+ nowMs?: number;
19
+ source?: ConversationSource;
20
+ }): Promise<void>;
13
21
  get(args: {
14
22
  conversationId: string;
15
23
  }): Promise<Conversation | undefined>;
@@ -49,6 +49,13 @@ export interface Conversation {
49
49
  }
50
50
  /** Persist and read durable conversation metadata for reporting surfaces. */
51
51
  export interface ConversationStore {
52
+ /** Create one destinationless child with immutable parent lineage. */
53
+ createChild(args: {
54
+ childConversationId: string;
55
+ parentConversationId: string;
56
+ nowMs?: number;
57
+ source?: ConversationSource;
58
+ }): Promise<void>;
52
59
  get(args: {
53
60
  conversationId: string;
54
61
  }): Promise<Conversation | undefined>;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Known unstable product features that must be opted into explicitly.
3
+ * Add new keys here as features graduate from private experiments; remove them
4
+ * once they become stable defaults.
5
+ */
6
+ export declare const EXPERIMENTAL_FEATURES: readonly ["subagents"];
7
+ /** One known experimental feature name. */
8
+ export type ExperimentalFeature = (typeof EXPERIMENTAL_FEATURES)[number];
9
+ /** App-level opt-ins for unstable product features. */
10
+ export type ExperimentalFeaturesConfig = Readonly<Partial<Record<ExperimentalFeature, boolean>>>;
11
+ /** Replace app-level experimental opt-ins and return the previous setting. */
12
+ export declare function setExperimentalFeatures(config?: ExperimentalFeaturesConfig): ExperimentalFeaturesConfig;
13
+ /** Return a copy of the app-level experimental opt-ins configured by createApp(). */
14
+ export declare function getExperimentalFeatures(): ExperimentalFeaturesConfig;
15
+ /** Return whether one experimental feature is enabled via createApp({ experimental }). */
16
+ export declare function isExperimentalFeatureEnabled(feature: ExperimentalFeature): boolean;
@@ -1,4 +1,4 @@
1
- import type { AgentRunRequest } from "@/chat/agent/request";
1
+ import { type AgentRunRequest, type SpawnAgent } from "@/chat/agent/request";
2
2
  import type { AgentRunOutcome } from "@/chat/runtime/agent-run-outcome";
3
3
  import type { SandboxEgressTracePropagationConfig } from "@/chat/sandbox/egress/tracing";
4
4
  /** Run one agent-run slice behind runtime-owned orchestration boundaries. */
@@ -7,5 +7,6 @@ export interface AgentRunner {
7
7
  }
8
8
  /** Adapt the Pi-facing agent-run executor behind the runtime-owned runner seam. */
9
9
  export declare function createAgentRunner(run: AgentRunner["run"], options?: {
10
+ bindSpawnAgent?: (request: AgentRunRequest) => SpawnAgent | undefined;
10
11
  tracePropagation?: SandboxEgressTracePropagationConfig;
11
12
  }): AgentRunner;
@@ -1,6 +1,5 @@
1
1
  export type AuthorizationPauseKind = "mcp" | "plugin";
2
2
  export type AuthorizationPauseDisposition = "link_already_sent" | "link_sent";
3
- export type AuthorizationFlowMode = "interactive" | "disabled";
4
3
  /**
5
4
  * Runtime-owned signal that the current turn must park until the user
6
5
  * completes an external authorization step.
@@ -9,7 +9,7 @@
9
9
  import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
10
10
  import type { Destination, Source } from "@sentry/junior-plugin-api";
11
11
  import { type OAuthAuthorization } from "@/chat/oauth-authorization";
12
- import { AuthorizationPauseError, type AuthorizationFlowMode } from "@/chat/services/auth-pause";
12
+ import { AuthorizationPauseError } from "@/chat/services/auth-pause";
13
13
  import type { ThreadArtifactsState } from "@/chat/state/artifacts";
14
14
  import type { ConversationPendingAuthState } from "@/chat/state/conversation";
15
15
  import type { PluginDefinition } from "@/chat/plugins/types";
@@ -32,7 +32,8 @@ export interface McpAuthOrchestrationInput {
32
32
  getArtifactState: () => ThreadArtifactsState | undefined;
33
33
  getMergedArtifactState: () => ThreadArtifactsState;
34
34
  recordPendingAuth?: (pendingAuth: ConversationPendingAuthState | undefined) => void | Promise<void>;
35
- authorizationFlowMode?: AuthorizationFlowMode;
35
+ /** When false, required auth hard-fails instead of pausing for an OAuth link. */
36
+ interactiveAuthEnabled?: boolean;
36
37
  authorization?: OAuthAuthorization;
37
38
  }
38
39
  export interface McpAuthOrchestration {
@@ -12,7 +12,7 @@
12
12
  */
13
13
  import type { Destination, Source } from "@sentry/junior-plugin-api";
14
14
  import type { UserTokenStore } from "@/chat/credentials/user-token-store";
15
- import { AuthorizationPauseError, type AuthorizationFlowMode } from "@/chat/services/auth-pause";
15
+ import { AuthorizationPauseError } from "@/chat/services/auth-pause";
16
16
  import type { ConversationPendingAuthState } from "@/chat/state/conversation";
17
17
  import { type OAuthAuthorization } from "@/chat/oauth-authorization";
18
18
  export declare class PluginAuthorizationPauseError extends AuthorizationPauseError {
@@ -34,7 +34,8 @@ export interface PluginAuthOrchestrationInput {
34
34
  userMessage?: string;
35
35
  pendingAuth?: ConversationPendingAuthState;
36
36
  recordPendingAuth?: (pendingAuth: ConversationPendingAuthState) => void | Promise<void>;
37
- authorizationFlowMode?: AuthorizationFlowMode;
37
+ /** When false, required auth hard-fails instead of pausing for an OAuth link. */
38
+ interactiveAuthEnabled?: boolean;
38
39
  userTokenStore?: UserTokenStore;
39
40
  authorization?: OAuthAuthorization;
40
41
  }
@@ -26,12 +26,10 @@ export interface AgentTurnSessionRecord {
26
26
  conversationId: string;
27
27
  cumulativeDurationMs: number;
28
28
  cumulativeUsage?: AgentTurnUsage;
29
- destination?: Destination;
30
29
  dispatchId?: string;
31
30
  dispatchOutcome?: AgentDispatchOutcome;
32
31
  /** Provider-owned identifier returned after visible delivery is accepted. */
33
32
  resultMessageId?: string;
34
- source?: Source;
35
33
  errorMessage?: string;
36
34
  lastProgressAtMs: number;
37
35
  loadedSkillNames?: string[];
@@ -13,6 +13,7 @@ export declare const CONVERSATION_WORK_LEASE_TTL_MS = 90000;
13
13
  export declare const CONVERSATION_WORK_CHECK_IN_INTERVAL_MS = 15000;
14
14
  export declare const CONVERSATION_WORK_STALE_ENQUEUE_MS = 60000;
15
15
  export declare const CONVERSATION_WORK_MAX_DELIVERY_ATTEMPTS = 5;
16
+ export declare const CONVERSATION_WORK_MAX_RETRIES = 5;
16
17
  declare const inboundMessageSourceSchema: z.ZodEnum<{
17
18
  slack: "slack";
18
19
  plugin: "plugin";
@@ -46,14 +47,14 @@ export declare const inboundMessageSchema: z.ZodObject<{
46
47
  defer: "defer";
47
48
  interrupt: "interrupt";
48
49
  }>;
49
- destination: z.ZodDiscriminatedUnion<[z.ZodObject<{
50
+ destination: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
50
51
  platform: z.ZodLiteral<"slack">;
51
52
  teamId: z.ZodString;
52
53
  channelId: z.ZodString;
53
54
  }, z.core.$strict>, z.ZodObject<{
54
55
  platform: z.ZodLiteral<"local">;
55
56
  conversationId: z.ZodString;
56
- }, z.core.$strict>], "platform">;
57
+ }, z.core.$strict>], "platform">>;
57
58
  inboundMessageId: z.ZodString;
58
59
  injectedAtMs: z.ZodOptional<z.ZodNumber>;
59
60
  input: z.ZodObject<{
@@ -84,6 +85,8 @@ export interface ConversationExecution {
84
85
  inboundMessageIds: string[];
85
86
  lastCheckpointAtMs?: number;
86
87
  lastEnqueuedAtMs?: number;
88
+ lastProgressAtMs?: number;
89
+ retryCount?: number;
87
90
  lease?: Lease;
88
91
  pendingCount: number;
89
92
  pendingMessages: InboundMessage[];
@@ -163,7 +166,7 @@ export declare function appendInboundMessage(args: {
163
166
  /** Mark a conversation runnable when there is no new mailbox message. */
164
167
  export declare function requestConversationWork(args: {
165
168
  conversationId: string;
166
- destination: Destination;
169
+ destination?: Destination;
167
170
  nowMs?: number;
168
171
  state?: StateAdapter;
169
172
  }): Promise<RequestConversationWorkResult>;
@@ -251,7 +254,7 @@ export declare function ackMessages(args: {
251
254
  /** Mark the leased conversation as needing another queue-delivered slice. */
252
255
  export declare function requestConversationContinuation(args: {
253
256
  conversationId: string;
254
- destination: Destination;
257
+ destination?: Destination;
255
258
  leaseToken: string;
256
259
  nowMs?: number;
257
260
  state?: StateAdapter;
@@ -270,25 +273,34 @@ export declare function releaseConversationWork(args: {
270
273
  nowMs?: number;
271
274
  state?: StateAdapter;
272
275
  }): Promise<boolean>;
276
+ /** Count one failed execution attempt and stop the conversation when retries are exhausted. */
277
+ export declare function recordConversationRetry(args: {
278
+ conversationId: string;
279
+ leaseToken: string;
280
+ nowMs?: number;
281
+ state?: StateAdapter;
282
+ }): Promise<"lost_lease" | "recorded" | "stopped">;
273
283
  /** Finish a leased conversation and report whether runnable work remains. */
274
284
  export declare function completeConversationWork(args: {
275
285
  conversationId: string;
276
286
  leaseToken: string;
287
+ madeProgress?: boolean;
277
288
  nowMs?: number;
278
289
  state?: StateAdapter;
279
290
  }): Promise<"completed" | "lost_lease" | "pending">;
280
- /** Failure outcome: `lost_lease` (another owner took over), `recorded` (attempt counted), or `skipped` (durable progress was made). */
291
+ /** Failure outcome: `lost_lease` (another owner took over), `recorded` (retry counted), or `skipped` (durable progress was made). */
281
292
  export interface AttemptFailure {
282
293
  pendingCount: number;
283
294
  deadLetteredMessages: InboundMessage[];
295
+ retryCount: number;
284
296
  status: "lost_lease" | "recorded" | "skipped";
285
297
  }
286
298
  /**
287
- * Record one failed delivery attempt for the pending messages a run attempted,
288
- * dead-lettering messages that reach the retry limit so a deterministic
289
- * failure cannot requeue forever.
299
+ * Record one failed execution attempt for pending messages, dead-lettering
300
+ * the conversation when its retry budget or the legacy message delivery limit
301
+ * is exhausted.
290
302
  *
291
- * Attempts are counted only when the run made no durable progress: if any
303
+ * Retries are counted only when the run made no durable progress: if any
292
304
  * attempted message left the mailbox, the remaining pending entries may be
293
305
  * deliberate deferrals and are left untouched. Consumed message ids stay in
294
306
  * `inboundMessageIds` so source retries remain duplicates.
@@ -307,12 +319,12 @@ export declare function deadLetterAttempt(args: {
307
319
  nowMs?: number;
308
320
  state?: StateAdapter;
309
321
  }): Promise<"failed" | "lost_lease" | "pending">;
310
- /** Clear an expired durable lease so a later worker can resume safely. */
322
+ /** Recover an expired lease, consuming the retry budget under the mutation lock. */
311
323
  export declare function clearExpiredConversationLease(args: {
312
324
  conversationId: string;
313
325
  nowMs?: number;
314
326
  state?: StateAdapter;
315
- }): Promise<boolean>;
327
+ }): Promise<"not_expired" | "requeued" | "stopped">;
316
328
  /** Delete one conversation mailbox and all of its index entries. */
317
329
  export declare function deleteConversationState(args: {
318
330
  conversationId: string;
@@ -2,7 +2,7 @@ import type { StateAdapter } from "chat";
2
2
  import type { ConversationStore } from "@/chat/conversations/store";
3
3
  import type { ConversationWorkQueue } from "./queue";
4
4
  import * as workState from "./state";
5
- export { CONVERSATION_ACTIVE_INDEX_KEY, CONVERSATION_BY_ACTIVITY_INDEX_KEY, CONVERSATION_WORK_CHECK_IN_INTERVAL_MS, CONVERSATION_WORK_LEASE_TTL_MS, CONVERSATION_WORK_MAX_DELIVERY_ATTEMPTS, CONVERSATION_WORK_STALE_ENQUEUE_MS, isFinalAttempt, isInvalidConversationRecordError, type AgentInput, type AttemptFailure, type AppendAndEnqueueInboundMessageResult, type AppendInboundMessageResult, type Conversation, type ConversationExecution, type ConversationWorkLease, type ConversationWorkState, type ExecutionStatus, type InboundMessage, type InboundMessageDelivery, type Lease, type RequestConversationWorkResult, type Source, type StartConversationWorkAcquired, type StartConversationWorkActive, type StartConversationWorkNoWork, type StartConversationWorkResult, } from "@/chat/task-execution/state";
5
+ export { CONVERSATION_ACTIVE_INDEX_KEY, CONVERSATION_BY_ACTIVITY_INDEX_KEY, CONVERSATION_WORK_CHECK_IN_INTERVAL_MS, CONVERSATION_WORK_LEASE_TTL_MS, CONVERSATION_WORK_MAX_DELIVERY_ATTEMPTS, CONVERSATION_WORK_MAX_RETRIES, CONVERSATION_WORK_STALE_ENQUEUE_MS, isFinalAttempt, isInvalidConversationRecordError, type AgentInput, type AttemptFailure, type AppendAndEnqueueInboundMessageResult, type AppendInboundMessageResult, type Conversation, type ConversationExecution, type ConversationWorkLease, type ConversationWorkState, type ExecutionStatus, type InboundMessage, type InboundMessageDelivery, type Lease, type RequestConversationWorkResult, type Source, type StartConversationWorkAcquired, type StartConversationWorkActive, type StartConversationWorkNoWork, type StartConversationWorkResult, } from "@/chat/task-execution/state";
6
6
  import type { AppendAndEnqueueInboundMessageResult, Conversation, InboundMessage } from "@/chat/task-execution/state";
7
7
  export type EnsureConversationWakeResult = {
8
8
  queueMessageId?: string;
@@ -20,6 +20,14 @@ export declare function getConversationWorkState(args: {
20
20
  conversationId: string;
21
21
  state?: StateAdapter;
22
22
  }): Promise<workState.ConversationWorkState | undefined>;
23
+ /** Count one failed conversation execution and persist its terminal retry state. */
24
+ export declare function recordConversationRetry(args: {
25
+ conversationId: string;
26
+ conversationStore?: ConversationStore;
27
+ leaseToken: string;
28
+ nowMs?: number;
29
+ state?: StateAdapter;
30
+ }): Promise<"stopped" | "lost_lease" | "recorded">;
23
31
  /** Count mailbox messages that have not yet reached the conversation event log. */
24
32
  export declare function countPendingConversationMessages(conversation: Conversation): number;
25
33
  /** Return whether a conversation has pending or resumable execution work. */
@@ -98,14 +106,6 @@ export declare function drainConversationMailbox(args: Parameters<typeof workSta
98
106
  conversationId: string;
99
107
  createdAtMs: number;
100
108
  delivery: "defer" | "interrupt";
101
- destination: {
102
- platform: "slack";
103
- teamId: string;
104
- channelId: string;
105
- } | {
106
- platform: "local";
107
- conversationId: string;
108
- };
109
109
  inboundMessageId: string;
110
110
  input: {
111
111
  text: string;
@@ -116,6 +116,14 @@ export declare function drainConversationMailbox(args: Parameters<typeof workSta
116
116
  receivedAtMs: number;
117
117
  source: "slack" | "plugin" | "local" | "api" | "internal" | "resource_event" | "scheduler";
118
118
  attemptCount?: number | undefined;
119
+ destination?: {
120
+ platform: "slack";
121
+ teamId: string;
122
+ channelId: string;
123
+ } | {
124
+ platform: "local";
125
+ conversationId: string;
126
+ } | undefined;
119
127
  injectedAtMs?: number | undefined;
120
128
  }[]>;
121
129
  /** Acknowledge leased mailbox entries after the handler accepts responsibility. */
@@ -156,6 +164,7 @@ export declare function releaseConversationWork(args: {
156
164
  export declare function completeConversationWork(args: {
157
165
  conversationId: string;
158
166
  leaseToken: string;
167
+ madeProgress?: boolean;
159
168
  conversationStore?: ConversationStore;
160
169
  nowMs?: number;
161
170
  state?: StateAdapter;
@@ -177,13 +186,13 @@ export declare function deadLetterAttempt(args: {
177
186
  nowMs?: number;
178
187
  state?: StateAdapter;
179
188
  }): Promise<"pending" | "failed" | "lost_lease">;
180
- /** Clear an expired durable lease so a later worker can resume safely. */
189
+ /** Recover an expired lease and persist the resulting retry state. */
181
190
  export declare function clearExpiredConversationLease(args: {
182
191
  conversationId: string;
183
192
  conversationStore?: ConversationStore;
184
193
  nowMs?: number;
185
194
  state?: StateAdapter;
186
- }): Promise<boolean>;
195
+ }): Promise<"stopped" | "not_expired" | "requeued">;
187
196
  /** Remove one conversation from the active index after it is missing or idle. */
188
197
  export declare function removeActiveConversation(args: {
189
198
  conversationId: string;
@@ -8,13 +8,13 @@ export interface ConversationWorkerContext {
8
8
  attempt: InboxAttempt;
9
9
  checkIn(): Promise<boolean>;
10
10
  conversationId: string;
11
- destination: Destination;
11
+ destination?: Destination;
12
12
  shouldYield(): boolean;
13
13
  }
14
14
  export interface InboxAttempt {
15
15
  ack(): Promise<void>;
16
16
  conversationId: string;
17
- destination: Destination;
17
+ destination?: Destination;
18
18
  drain(handle: (messages: InboundMessage[]) => Promise<readonly string[] | void>): Promise<InboundMessage[]>;
19
19
  isFinalAttempt: boolean;
20
20
  messages: InboundMessage[];
@@ -0,0 +1,31 @@
1
+ import type { ToolRuntimeContext } from "@/chat/tools/types";
2
+ export declare const SPAWN_AGENT_TOOL_NAME = "spawnAgent";
3
+ /** Create the asynchronous child-agent tool for one parent run. */
4
+ export declare function createSpawnAgentTool(spawnAgent: NonNullable<ToolRuntimeContext["spawnAgent"]>): Omit<import("../definition").AnyToolDefinition, "inputSchema" | "outputSchema" | "prepareArguments" | "execute"> & {
5
+ inputSchema: import("../definition").JsonSchemaObject;
6
+ outputSchema: import("../definition").JsonSchemaObject;
7
+ prepareArguments(args: unknown): {
8
+ task: string;
9
+ name?: string | null | undefined;
10
+ reasoning_level?: "low" | "medium" | "high" | "xhigh" | "none" | null | undefined;
11
+ };
12
+ execute?: ((input: unknown, options: import("../definition").ToolExecuteOptions) => {
13
+ [x: string]: unknown;
14
+ invocation_id: string;
15
+ target?: string | undefined;
16
+ truncated?: boolean | undefined;
17
+ continuation?: {
18
+ arguments: Record<string, unknown>;
19
+ reason?: string | undefined;
20
+ } | undefined;
21
+ } | Promise<{
22
+ [x: string]: unknown;
23
+ invocation_id: string;
24
+ target?: string | undefined;
25
+ truncated?: boolean | undefined;
26
+ continuation?: {
27
+ arguments: Record<string, unknown>;
28
+ reason?: string | undefined;
29
+ } | undefined;
30
+ }>) | undefined;
31
+ };
@@ -11,6 +11,7 @@ import type { LocalActor, Actor, SlackActor } from "@/chat/actor";
11
11
  import type { SlackActionToken } from "@/chat/slack/action-token";
12
12
  import type { ModelProfile } from "@/chat/model-profile";
13
13
  import type { GeneratedArtifactFileRef } from "@/chat/tools/sandbox/file-uploads";
14
+ import type { SpawnAgent } from "@/chat/agent/request";
14
15
  interface HandoffControl {
15
16
  /** Non-empty catalog of configured targets. */
16
17
  profiles: readonly [ModelProfile, ...ModelProfile[]];
@@ -55,6 +56,7 @@ export interface ToolHooks {
55
56
  }
56
57
  interface BaseToolRuntimeContext {
57
58
  handoff?: HandoffControl;
59
+ spawnAgent?: SpawnAgent;
58
60
  /**
59
61
  * Opaque Junior conversation/session identity for this turn.
60
62
  * Interactive Slack turns use `slack:{channelId}:{threadTs}`.
@@ -0,0 +1,6 @@
1
+ // src/chat/state/ttl.ts
2
+ var JUNIOR_THREAD_STATE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
3
+
4
+ export {
5
+ JUNIOR_THREAD_STATE_TTL_MS
6
+ };
@@ -0,0 +1,46 @@
1
+ // src/chat/experimental.ts
2
+ var EXPERIMENTAL_FEATURES = ["subagents"];
3
+ var EXPERIMENTAL_FEATURE_SET = new Set(EXPERIMENTAL_FEATURES);
4
+ var configuredExperimental = {};
5
+ function isExperimentalFeature(value) {
6
+ return EXPERIMENTAL_FEATURE_SET.has(value);
7
+ }
8
+ function setExperimentalFeatures(config) {
9
+ const previous = { ...configuredExperimental };
10
+ if (config === void 0) {
11
+ configuredExperimental = {};
12
+ return previous;
13
+ }
14
+ const next = {};
15
+ for (const [rawName, enabled] of Object.entries(config)) {
16
+ if (enabled === void 0) {
17
+ continue;
18
+ }
19
+ if (typeof enabled !== "boolean") {
20
+ throw new Error(
21
+ `experimental.${rawName} must be a boolean when provided`
22
+ );
23
+ }
24
+ if (!isExperimentalFeature(rawName)) {
25
+ throw new Error(
26
+ `experimental.${rawName} is not a known experimental feature. Known features: ${EXPERIMENTAL_FEATURES.join(", ")}`
27
+ );
28
+ }
29
+ next[rawName] = enabled;
30
+ }
31
+ configuredExperimental = next;
32
+ return previous;
33
+ }
34
+ function getExperimentalFeatures() {
35
+ return { ...configuredExperimental };
36
+ }
37
+ function isExperimentalFeatureEnabled(feature) {
38
+ return configuredExperimental[feature] === true;
39
+ }
40
+
41
+ export {
42
+ EXPERIMENTAL_FEATURES,
43
+ setExperimentalFeatures,
44
+ getExperimentalFeatures,
45
+ isExperimentalFeatureEnabled
46
+ };