@sentry/junior 0.144.0 → 0.145.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 (88) hide show
  1. package/dist/{agent-hooks-GCUTGKY3.js → agent-hooks-L7D2BDVV.js} +10 -10
  2. package/dist/api/conversations/detail.d.ts +1 -0
  3. package/dist/api/schema/conversation.d.ts +2 -0
  4. package/dist/api/schema.js +1 -1
  5. package/dist/api.js +40 -22
  6. package/dist/app.js +335 -409
  7. package/dist/{catalog-runtime-DWVYKDC6.js → catalog-runtime-QLAC4Q3W.js} +5 -5
  8. package/dist/chat/agent/request.d.ts +1 -1
  9. package/dist/chat/agent/resume.d.ts +6 -15
  10. package/dist/chat/agent/tools.d.ts +1 -1
  11. package/dist/chat/agent-dispatch/types.d.ts +1 -1
  12. package/dist/chat/app/conversation-work.d.ts +24 -0
  13. package/dist/chat/conversations/projection.d.ts +11 -3
  14. package/dist/chat/conversations/store.d.ts +1 -1
  15. package/dist/chat/runtime/agent-run-outcome.d.ts +1 -1
  16. package/dist/chat/runtime/reply-executor.d.ts +5 -5
  17. package/dist/chat/runtime/slack-resume.d.ts +12 -4
  18. package/dist/chat/state/locks.d.ts +28 -0
  19. package/dist/chat/task-execution/checkpoint.d.ts +86 -0
  20. package/dist/chat/task-execution/paused-turn.d.ts +29 -0
  21. package/dist/chat/task-execution/queue-signing.d.ts +1 -0
  22. package/dist/chat/task-execution/queue.d.ts +7 -1
  23. package/dist/chat/task-execution/slack-work.d.ts +1 -1
  24. package/dist/chat/task-execution/state.d.ts +4 -4
  25. package/dist/chat/task-execution/store.d.ts +2 -2
  26. package/dist/chat/task-execution/turn-cursor-keys.d.ts +6 -0
  27. package/dist/chat/{state/turn-session.d.ts → task-execution/turn-cursor.d.ts} +52 -42
  28. package/dist/chat/task-execution/turn-wake.d.ts +29 -0
  29. package/dist/chat/tools/types.d.ts +1 -1
  30. package/dist/{chunk-HNO2E5WB.js → chunk-27TEJTZO.js} +1 -1
  31. package/dist/{chunk-RIFJUJSI.js → chunk-2LWPFSB4.js} +1 -1
  32. package/dist/{chunk-SBZP2J5Q.js → chunk-2UH3JI64.js} +10 -9
  33. package/dist/{chunk-QUZJDAQQ.js → chunk-2XET6PKP.js} +93 -89
  34. package/dist/{chunk-SUK7NC5A.js → chunk-5PNPQYTO.js} +2 -2
  35. package/dist/{chunk-SSDTQDYQ.js → chunk-64SBYW2O.js} +132 -127
  36. package/dist/{chunk-DVO5VKYQ.js → chunk-B46ZMVOV.js} +5 -5
  37. package/dist/{chunk-A67GZN73.js → chunk-CD2XFGYQ.js} +1 -1
  38. package/dist/{chunk-WTX2RFJG.js → chunk-DS3J6WGY.js} +1 -1
  39. package/dist/{chunk-PKH6762I.js → chunk-DXEQAIUV.js} +1 -1
  40. package/dist/{chunk-WSOLZJJS.js → chunk-EIX2LQ6L.js} +3 -3
  41. package/dist/{chunk-KQBXT5B7.js → chunk-FUBRJA5F.js} +6 -6
  42. package/dist/{chunk-I44JB7HQ.js → chunk-GDV5LXRA.js} +1 -1
  43. package/dist/{chunk-7KAW7UF4.js → chunk-GUWLDMGF.js} +4 -4
  44. package/dist/{chunk-PELZ2ZSY.js → chunk-HISR3DTV.js} +33 -61
  45. package/dist/{chunk-HD6BHR25.js → chunk-HLOUZC5C.js} +32 -34
  46. package/dist/{chunk-BBCWYXHB.js → chunk-I47UGQPJ.js} +7 -7
  47. package/dist/{chunk-IUFM5JWV.js → chunk-JAL3CH4G.js} +3 -0
  48. package/dist/{chunk-E7HCWOHG.js → chunk-JLMVCNXL.js} +2 -1
  49. package/dist/{chunk-STFCL3K4.js → chunk-JTGS3ZZE.js} +1 -1
  50. package/dist/{chunk-GKA74DRA.js → chunk-LVVSIMBB.js} +1 -1
  51. package/dist/{chunk-SHEEZSLY.js → chunk-PJ4NMVQB.js} +2 -2
  52. package/dist/{chunk-W7JFV5SB.js → chunk-QJBDABQA.js} +14 -17
  53. package/dist/{chunk-UDQMY6RS.js → chunk-QUG4JSZK.js} +43 -1
  54. package/dist/{chunk-4X5KM7Z6.js → chunk-RUSS62EN.js} +14 -14
  55. package/dist/{chunk-ZF3N3JD6.js → chunk-SIN3MXH6.js} +1 -1
  56. package/dist/{chunk-QE3TICD4.js → chunk-TZRXYWRE.js} +2 -2
  57. package/dist/{chunk-CNTWB2SM.js → chunk-VTDMB7XX.js} +1 -1
  58. package/dist/{chunk-LDWNYCZ6.js → chunk-WF5HVH3M.js} +1 -1
  59. package/dist/{chunk-KCBZSJRU.js → chunk-WR76IVA5.js} +5 -2
  60. package/dist/{chunk-3GU4PWA3.js → chunk-XFKIRN3Q.js} +29 -29
  61. package/dist/{chunk-ZZCTGAIT.js → chunk-YD54Q45G.js} +4 -4
  62. package/dist/{chunk-BEGGFVFR.js → chunk-ZIAMN2UW.js} +407 -523
  63. package/dist/{chunk-44RJWAND.js → chunk-ZIMRGFYL.js} +6 -6
  64. package/dist/{chunk-54JMYQYS.js → chunk-ZYAJMESY.js} +2 -2
  65. package/dist/cli/chat.js +32 -32
  66. package/dist/cli/check.js +6 -6
  67. package/dist/cli/plugins.js +13 -13
  68. package/dist/cli/snapshot-create.js +9 -9
  69. package/dist/cli/upgrade.js +7 -7
  70. package/dist/{db-EFLHTBU6.js → db-62PW6LM3.js} +7 -7
  71. package/dist/instrumentation.js +4 -4
  72. package/dist/nitro.js +4 -4
  73. package/dist/{oauth-callback-server-RO3IQKWM.js → oauth-callback-server-6NZNHJAM.js} +25 -25
  74. package/dist/{runner-LOWW7JKA.js → runner-GCRPG3GQ.js} +19 -18
  75. package/dist/{skills-ZLMUG7AE.js → skills-2S3MDFIQ.js} +6 -6
  76. package/dist/spawn-7WK37BTD.js +39 -0
  77. package/dist/{validation-MAKEZNTS.js → validation-HAOLCJ5A.js} +6 -6
  78. package/dist/version.js +1 -1
  79. package/dist/{work-5OAGC3I4.js → work-R4XYKMUW.js} +17 -16
  80. package/dist/worker-U2UCVR7M.js +24 -0
  81. package/package.json +4 -4
  82. package/dist/chat/agent/session.d.ts +0 -19
  83. package/dist/chat/runtime/agent-continue-runner.d.ts +0 -37
  84. package/dist/chat/services/agent-continue.d.ts +0 -29
  85. package/dist/chat/services/turn-session-record.d.ts +0 -164
  86. package/dist/chat/state/turn-session-keys.d.ts +0 -6
  87. package/dist/spawn-R3LUV6RF.js +0 -38
  88. package/dist/worker-KTGGRTTP.js +0 -24
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  pluginCatalogRuntime
3
- } from "./chunk-ZF3N3JD6.js";
4
- import "./chunk-A67GZN73.js";
3
+ } from "./chunk-SIN3MXH6.js";
4
+ import "./chunk-CD2XFGYQ.js";
5
5
  import "./chunk-RUIXF3YQ.js";
6
6
  import "./chunk-HZF5P5UN.js";
7
7
  import "./chunk-F3B2YJ76.js";
8
- import "./chunk-RIFJUJSI.js";
8
+ import "./chunk-2LWPFSB4.js";
9
9
  import "./chunk-6GWA276C.js";
10
10
  import "./chunk-OOUNJNMR.js";
11
11
  import "./chunk-H4HBKISO.js";
12
- import "./chunk-WTX2RFJG.js";
13
- import "./chunk-I44JB7HQ.js";
12
+ import "./chunk-DS3J6WGY.js";
13
+ import "./chunk-GDV5LXRA.js";
14
14
  import "./chunk-MLKGABMK.js";
15
15
  export {
16
16
  pluginCatalogRuntime
@@ -22,7 +22,7 @@ import type { SlackConversationContext } from "@/chat/slack/conversation-context
22
22
  import type { ThreadArtifactsState } from "@/chat/state/artifacts";
23
23
  import type { ConversationPendingAuthState } from "@/chat/state/conversation";
24
24
  import type { ConversationMessageProvenance } from "@/chat/conversations/provenance";
25
- import type { AgentTurnSurface } from "@/chat/state/turn-session";
25
+ import type { AgentTurnSurface } from "@/chat/task-execution/checkpoint";
26
26
  import type { ToolExecutionReport } from "@/chat/tool-support/tool-execution-report";
27
27
  import type { SlackActionToken } from "@/chat/slack/action-token";
28
28
  import type { TurnReasoningLevel } from "@/chat/reasoning-level";
@@ -1,26 +1,20 @@
1
1
  /**
2
- * Run resumability.
2
+ * In-memory resume helpers for one execution slice.
3
3
  *
4
- * Owns the durable state that lets a run slice stop without losing work:
5
- * safe-boundary checkpoints, the durable input commit, resume snapshots, and
6
- * persistence of the expected endings (cooperative yield, continuable
7
- * timeout, auth pause) translated into `AgentRunOutcome` values so the
8
- * executor's catch block stays a thin translation over genuine errors.
4
+ * Durable writes go through `saveTurnCheckpoint` only.
9
5
  */
10
6
  import type { Destination, Source } from "@sentry/junior-plugin-api";
11
7
  import type { PiMessage } from "@/chat/pi/messages";
12
8
  import type { ConversationMessageProvenance } from "@/chat/conversations/provenance";
13
9
  import { CooperativeTurnYieldError } from "@/chat/runtime/turn";
14
10
  import type { AgentRunOutcome } from "@/chat/runtime/agent-run-outcome";
15
- import type { AgentTurnSurface } from "@/chat/state/turn-session";
16
11
  import type { Actor } from "@/chat/actor";
17
- import { loadTurnSessionRecord } from "@/chat/services/turn-session-record";
12
+ import { type AgentTurnSurface, type TurnCheckpoint } from "@/chat/task-execution/checkpoint";
18
13
  import { type AuthorizationPauseError } from "@/chat/services/auth-pause";
19
14
  import { type AgentTurnUsage } from "@/chat/usage";
20
15
  import { type AgentRunDurability } from "@/chat/agent/request";
21
16
  import type { PluginTurnContext } from "@/chat/plugins/prompt";
22
17
  import type { ConversationPrivacy } from "@/chat/conversation-privacy";
23
- type LoadedSessionRecordState = Awaited<ReturnType<typeof loadTurnSessionRecord>>;
24
18
  interface ResumeStateArgs {
25
19
  channelName?: string;
26
20
  destination: Destination;
@@ -35,14 +29,14 @@ interface ResumeStateArgs {
35
29
  runSource: Source;
36
30
  conversationId: string;
37
31
  turnId: string;
38
- sessionRecordState: LoadedSessionRecordState;
32
+ checkpoint: TurnCheckpoint;
39
33
  startedAtMs: number;
40
34
  surface: AgentTurnSurface;
41
35
  }
42
36
  type AuthPauseOutcome = Extract<AgentRunOutcome, {
43
37
  status: "awaiting_auth";
44
38
  }>;
45
- /** Create the run's resume state: checkpoints, snapshots, and ending translation. */
39
+ /** Create resume state for one slice. */
46
40
  export declare function createResumeState(args: ResumeStateArgs): {
47
41
  readonly inputCommitted: boolean;
48
42
  readonly beforeMessageCount: number;
@@ -50,7 +44,7 @@ export declare function createResumeState(args: ResumeStateArgs): {
50
44
  setTurnStartMessageIndex(index: number | undefined): void;
51
45
  setBeforeMessageCount(count: number): void;
52
46
  setTurnContexts(contexts: PluginTurnContext[]): void;
53
- /** Adopt an already committed epoch replacement as every resume baseline. */
47
+ /** Use an already committed boundary as the resume baseline. */
54
48
  adoptCommittedBoundary(messages: PiMessage[]): void;
55
49
  captureResumeSnapshot(messages: PiMessage[]): void;
56
50
  getResumeSnapshot(currentMessages: PiMessage[]): PiMessage[];
@@ -58,11 +52,8 @@ export declare function createResumeState(args: ResumeStateArgs): {
58
52
  commitInput(): Promise<void>;
59
53
  persistSafeBoundary(messages: PiMessage[], trailingMessageProvenance?: ConversationMessageProvenance[]): Promise<boolean>;
60
54
  requireDurableInputCheckpoint(messages: PiMessage[], trailingMessageProvenance?: ConversationMessageProvenance[]): Promise<boolean>;
61
- /** Prepare a cooperative yield at the current durable boundary. */
62
55
  prepareYieldIfDue(currentMessages: PiMessage[]): CooperativeTurnYieldError | undefined;
63
- /** Persist an auth pause; only a durable pause may return `awaiting_auth`. */
64
56
  parkForAuth(pause: AuthorizationPauseError, currentUsage?: AgentTurnUsage): Promise<AuthPauseOutcome>;
65
- /** Persist a yield, retry, or timeout as a suspended run. */
66
57
  translateSuspension(ending: {
67
58
  currentUsage?: AgentTurnUsage;
68
59
  error: unknown;
@@ -25,7 +25,7 @@ import type { OAuthAuthorization } from "@/chat/oauth-authorization";
25
25
  import type { Actor } from "@/chat/actor";
26
26
  import type { ThreadArtifactsState } from "@/chat/state/artifacts";
27
27
  import type { AuthorizationPauseError } from "@/chat/services/auth-pause";
28
- import type { AgentTurnSurface } from "@/chat/state/turn-session";
28
+ import type { AgentTurnSurface } from "@/chat/task-execution/checkpoint";
29
29
  import { type AgentRunDurability, type AgentRunObservers, type AgentRunPolicy, type AgentRunRouting, type AgentRunState } from "@/chat/agent/request";
30
30
  import type { ResumeState } from "@/chat/agent/resume";
31
31
  interface ToolWiringArgs {
@@ -1,7 +1,7 @@
1
1
  import type { DispatchOptions, DestinationVisibility, ReplyAttribution, Source, SlackDestination } from "@sentry/junior-plugin-api";
2
2
  import type { CredentialContext, CredentialSubject, CredentialSystemActor } from "@/chat/credentials/context";
3
3
  import type { AgentRunRouting } from "@/chat/agent/request";
4
- import type { AgentTurnSurface } from "@/chat/state/turn-session";
4
+ import type { AgentTurnSurface } from "@/chat/task-execution/checkpoint";
5
5
  import type { ChannelConfigurationService } from "@/chat/configuration/types";
6
6
  export type DispatchStatus = "pending" | "running" | "awaiting_resume" | "completed" | "failed" | "blocked";
7
7
  export type SlackDispatchOptions = Omit<DispatchOptions, "destination"> & {
@@ -0,0 +1,24 @@
1
+ import type { SlackAdapter } from "@chat-adapter/slack";
2
+ import type { StateAdapter } from "chat";
3
+ import type { AgentRunner } from "@/chat/runtime/agent-runner";
4
+ import type { ConversationStore } from "@/chat/conversations/store";
5
+ import type { ConversationWorkQueue } from "@/chat/task-execution/queue";
6
+ import type { VercelConversationWorkCallbackOptions } from "@/chat/task-execution/vercel-callback";
7
+ import { createSlackRuntime } from "./factory";
8
+ import type { JuniorRuntimeServiceOverrides } from "./services";
9
+ interface ConversationWorkOptions {
10
+ agentRunner: AgentRunner;
11
+ conversationStore: ConversationStore;
12
+ getSlackAdapter: () => SlackAdapter;
13
+ queue: ConversationWorkQueue;
14
+ services?: JuniorRuntimeServiceOverrides;
15
+ state?: StateAdapter;
16
+ }
17
+ /**
18
+ * Compose conversation work once for production and integration tests.
19
+ * Environment-specific queue, state, Slack, and agent adapters stop here.
20
+ */
21
+ export declare function createConversationWork(options: ConversationWorkOptions): VercelConversationWorkCallbackOptions & {
22
+ runtime: ReturnType<typeof createSlackRuntime>;
23
+ };
24
+ export {};
@@ -10,6 +10,10 @@ import type { TurnReasoningLevel } from "@/chat/reasoning-level";
10
10
  import type { PluginTurnContext } from "@/chat/plugins/prompt";
11
11
  import type { ThreadConversationState } from "@/chat/state/conversation";
12
12
  import type { AssistantMessage } from "@earendil-works/pi-ai";
13
+ /** A checkpoint tried to replace already committed agent history. */
14
+ export declare class AgentHistoryBranchError extends Error {
15
+ constructor(conversationId: string);
16
+ }
13
17
  interface ScopedConversation {
14
18
  conversationId: string;
15
19
  }
@@ -38,9 +42,13 @@ export declare function loadTurnProjection(args: {
38
42
  /** Load MCP providers connected in the current agent-history version. */
39
43
  export declare function loadConnectedMcpProviders(args: ScopedConversation): Promise<string[]>;
40
44
  /**
41
- * Append newly stable native history items. A shorter or changed prefix indicates
42
- * that a caller persisted volatile Pi state; only compaction and handoff may
43
- * intentionally replace active model history.
45
+ * Append newly stable native history items.
46
+ *
47
+ * Checkpoints are append-only against the durable identity of the committed
48
+ * prefix (role, timestamp, content; tool results also match call id). A shorter
49
+ * history or a true content branch is rejected — only compaction and handoff may
50
+ * intentionally replace active model history. In-place Pi mutations of already
51
+ * committed assistant envelopes (usage/stopReason) do not block the suffix.
44
52
  */
45
53
  export declare function commitMessages(args: {
46
54
  conversationId: string;
@@ -5,7 +5,7 @@ import type { Location } from "@/chat/conversations/location";
5
5
  import type { SessionSource } from "@/chat/source";
6
6
  import type { AgentTurnUsage } from "@/chat/usage";
7
7
  export type ConversationSource = "api" | "internal" | "local" | "plugin" | "resource_event" | "scheduler" | "slack";
8
- export type ConversationStatus = "awaiting_resume" | "failed" | "idle" | "pending" | "running";
8
+ export type ConversationStatus = "paused" | "failed" | "idle" | "pending" | "running";
9
9
  export interface ConversationExecution {
10
10
  lastCheckpointAtMs?: number;
11
11
  lastEnqueuedAtMs?: number;
@@ -3,7 +3,7 @@ import type { AgentTurnUsage } from "@/chat/usage";
3
3
  /**
4
4
  * How an agent run ended. `completed` carries the terminal result (success or
5
5
  * failure — `result.diagnostics` distinguishes them). `suspended` means the run
6
- * persisted an awaiting_resume session record and stopped at a safe boundary;
6
+ * persisted an paused session record and stopped at a safe boundary;
7
7
  * the caller resumes it by scheduling a continuation against `resumeVersion`,
8
8
  * the session record's optimistic-concurrency version. `awaiting_auth` means
9
9
  * the run parked for user authorization.
@@ -15,20 +15,20 @@ import { type PrepareTurnStateInput, type QueuedTurnMessage, type TurnToolInvoca
15
15
  import { type ConversationMemoryService } from "@/chat/services/conversation-memory";
16
16
  import type { ContextCompactor } from "@/chat/services/context-compaction";
17
17
  import { lookupSlackUser } from "@/chat/slack/user";
18
- import type { AgentContinueRequest } from "@/chat/services/agent-continue";
18
+ import type { PausedTurnRequest } from "@/chat/task-execution/turn-wake";
19
19
  import type { ConversationTurnLifecycle } from "@/chat/conversations/turn-lifecycle";
20
20
  import type { DispatchTurnContext, DispatchTurnResult } from "@/chat/agent-dispatch/types";
21
21
  export interface ReplyExecutorServices {
22
22
  agentRunner: AgentRunner;
23
23
  contextCompactor: ContextCompactor;
24
24
  generateThreadTitle: ConversationMemoryService["generateThreadTitle"];
25
- getAwaitingAgentContinueRequest: (args: {
25
+ getPausedTurnRequest: (args: {
26
26
  conversationId: string;
27
- sessionId: string;
28
- }) => Promise<AgentContinueRequest | undefined>;
27
+ turnId: string;
28
+ }) => Promise<PausedTurnRequest | undefined>;
29
29
  lookupSlackUser: typeof lookupSlackUser;
30
30
  turnLifecycle: ConversationTurnLifecycle;
31
- scheduleAgentContinue: (request: AgentContinueRequest) => Promise<void>;
31
+ wakePausedTurn: (request: PausedTurnRequest) => Promise<void>;
32
32
  scheduleSessionCompletedPluginTasks: (params: {
33
33
  conversationId: string;
34
34
  sessionId: string;
@@ -19,6 +19,12 @@ interface ResumeSlackTurnArgs {
19
19
  messageTs?: SlackMessageTs;
20
20
  replyContext?: ResumeReplyContext;
21
21
  lockKey?: string;
22
+ /**
23
+ * When true, the caller already holds the conversation work lease.
24
+ * Skip the second resume lock so queue continue is one owner, not two.
25
+ * OAuth and other out-of-band resumes leave this false.
26
+ */
27
+ ownsConversationLease?: boolean;
22
28
  initialText?: string;
23
29
  initialStatus?: AssistantStatusSpec;
24
30
  agentRunner: AgentRunner;
@@ -58,11 +64,13 @@ interface ResumePreparedTurn {
58
64
  onPostDeliveryCommitFailure?: (error: unknown) => Promise<void>;
59
65
  }
60
66
  /**
61
- * Resume a paused Slack turn under the normal thread lock.
67
+ * Resume a paused Slack turn.
62
68
  *
63
- * Started resumes own their completion side effects: assistant-message
64
- * delivery, pause persistence, or failure response. Returns false only when
65
- * `beforeStart` proves the resume is stale before generation begins.
69
+ * Queue continues pass `ownsConversationLease` and skip the second lock
70
+ * (worker lease is already held). OAuth and other out-of-band resumes still
71
+ * take the thread lock. Started resumes own their completion side effects.
72
+ * Returns false only when `beforeStart` proves the resume is stale before
73
+ * generation begins.
66
74
  */
67
75
  export declare function resumeSlackTurn(args: ResumeSlackTurnArgs): Promise<boolean>;
68
76
  export {};
@@ -1,7 +1,35 @@
1
1
  import type { Lock, StateAdapter } from "chat";
2
2
  export declare const ACTIVE_LOCK_TTL_MS = 90000;
3
+ export declare const MUTATION_LOCK_TTL_MS = 10000;
3
4
  /**
4
5
  * Acquire a lock for long-running work that the queued state adapter should
5
6
  * keep alive while the owning invocation is still making progress.
6
7
  */
7
8
  export declare function acquireActiveLock(state: StateAdapter, threadId: string): Promise<Lock | null>;
9
+ type LockAttempt<T> = {
10
+ acquired: false;
11
+ } | {
12
+ acquired: true;
13
+ value: T;
14
+ };
15
+ /**
16
+ * Run work under one lock, optionally waiting for the current owner.
17
+ * `keepAlive` is for multi-store mutations that must retain ownership until all
18
+ * side effects finish; callers should still fence each blind write.
19
+ */
20
+ export declare function withLock<T>(state: StateAdapter, key: string, run: (lock: Lock) => Promise<T>, options?: {
21
+ keepAlive?: boolean;
22
+ retryMs?: number;
23
+ ttlMs?: number;
24
+ waitMs?: number;
25
+ }): Promise<LockAttempt<T>>;
26
+ /**
27
+ * Prove lock ownership immediately before a blind write.
28
+ *
29
+ * Whole-record mutations must stop if their lock expired rather than overwrite
30
+ * state committed by a newer owner.
31
+ */
32
+ export declare function fenceLock(state: StateAdapter, lock: Lock, ttlMs?: number): Promise<void>;
33
+ /** Run work under the active lock, reporting contention without ambiguity. */
34
+ export declare function withActiveLock<T>(state: StateAdapter, key: string, run: () => Promise<T>): Promise<LockAttempt<T>>;
35
+ export {};
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Turn checkpoint — public resume cursor for one turn.
3
+ *
4
+ * Part of conversation execution with mailbox + lease + worker.
5
+ * History is SQL (`commitMessages`). This module is the only external gate
6
+ * for turn cursor storage (`turn-cursor.ts` is internal).
7
+ *
8
+ * Public API:
9
+ * - `loadTurnCheckpoint({ conversationId, turnId })`
10
+ * - `saveTurnCheckpoint({ mode, conversationId, turnId, messages, ... })`
11
+ * - fail / abandon / summary helpers for terminal and recovery edges
12
+ */
13
+ import type { ConversationPrivacy } from "@/chat/conversation-privacy";
14
+ import type { Destination, Actor, Source } from "@sentry/junior-plugin-api";
15
+ import type { PiMessage } from "@/chat/pi/messages";
16
+ import type { ConversationMessageProvenance } from "@/chat/conversations/provenance";
17
+ import { type AgentTurnUsage } from "@/chat/usage";
18
+ import type { PluginTurnContext } from "@/chat/plugins/prompt";
19
+ import { abandonTurnRecord, failTurnRecord, getTurnRecord, listTurnSummaries, recordTurnSummary, type AgentDispatchOutcome, type TurnPauseReason, type TurnRecord, type TurnSummary, type AgentTurnSurface } from "./turn-cursor";
20
+ export type { AgentDispatchOutcome, TurnRecord, TurnSummary, AgentTurnSurface };
21
+ export { abandonTurnRecord, failTurnRecord, getTurnRecord, listTurnSummaries, recordTurnSummary, };
22
+ /** Loaded resume cursor. A resumed checkpoint always has its record. */
23
+ export type TurnCheckpoint = {
24
+ resumed: true;
25
+ sliceId: number;
26
+ record: TurnRecord;
27
+ } | {
28
+ resumed: false;
29
+ sliceId: 1;
30
+ record?: TurnRecord;
31
+ };
32
+ /**
33
+ * Lifecycle fields for a checkpoint write.
34
+ * Routing/metrics/provenance are only for SQL dual-write / resume restore.
35
+ */
36
+ interface TurnCheckpointWrite {
37
+ conversationId: string;
38
+ turnId: string;
39
+ messages: PiMessage[];
40
+ modelId: string;
41
+ /** Required for running/paused; optional for completed/failed (falls back to stored). */
42
+ sliceId?: number;
43
+ actor?: Actor;
44
+ channelName?: string;
45
+ destination?: Destination;
46
+ destinationVisibility?: ConversationPrivacy;
47
+ dispatchId?: string;
48
+ dispatchOutcome?: AgentDispatchOutcome;
49
+ source?: Source;
50
+ surface?: AgentTurnSurface;
51
+ loadedSkillNames?: string[];
52
+ reasoningLevel?: string;
53
+ turnStartMessageIndex?: number;
54
+ trailingMessageProvenance?: ConversationMessageProvenance[];
55
+ turnContexts?: PluginTurnContext[];
56
+ durationMs?: number;
57
+ usage?: AgentTurnUsage;
58
+ errorMessage?: string;
59
+ resultMessageId?: string;
60
+ }
61
+ type ProgressCheckpointArgs = (TurnCheckpointWrite & {
62
+ mode: "running";
63
+ sliceId: number;
64
+ }) | (TurnCheckpointWrite & {
65
+ mode: "paused";
66
+ reason: TurnPauseReason;
67
+ sliceId: number;
68
+ });
69
+ type TerminalCheckpointArgs = TurnCheckpointWrite & {
70
+ mode: "completed" | "failed";
71
+ };
72
+ /** Boundary safe to continue after auth/timeout (trim mid-assistant). */
73
+ export declare function continuableMessages(messages: PiMessage[], fallback?: PiMessage[]): PiMessage[];
74
+ /** Load resume cursor for one turn. */
75
+ export declare function loadTurnCheckpoint(args: {
76
+ conversationId: string;
77
+ turnId: string;
78
+ }): Promise<TurnCheckpoint>;
79
+ /**
80
+ * Save turn progress.
81
+ *
82
+ * - `running` / `paused`: best-effort; returns the stored record or undefined
83
+ * - `completed` / `failed`: retries until write accepts; throws on hard failure
84
+ */
85
+ export declare function saveTurnCheckpoint(args: ProgressCheckpointArgs): Promise<TurnRecord | undefined>;
86
+ export declare function saveTurnCheckpoint(args: TerminalCheckpointArgs): Promise<void>;
@@ -0,0 +1,29 @@
1
+ import { resumeSlackTurn } from "@/chat/runtime/slack-resume";
2
+ import { type PausedTurnRequest } from "@/chat/task-execution/turn-wake";
3
+ import type { AgentRunner } from "@/chat/runtime/agent-runner";
4
+ import type { AgentRunRouting } from "@/chat/agent/request";
5
+ /** Runtime ports for paused turn scheduling. */
6
+ export interface PausedTurnOptions {
7
+ agentRunner: AgentRunner;
8
+ /** Exact persisted input ids accepted while running the paused turn. */
9
+ inputMessageIds?: readonly string[];
10
+ routingContext?: Pick<AgentRunRouting, "actor" | "credentialContext" | "destinationVisibility" | "dispatch" | "surface">;
11
+ resumeTurn?: typeof resumeSlackTurn;
12
+ wakePausedTurn?: (request: PausedTurnRequest) => Promise<void>;
13
+ scheduleSessionCompletedPluginTasks?: (params: {
14
+ conversationId: string;
15
+ sessionId: string;
16
+ }) => Promise<void>;
17
+ }
18
+ /** Per-worker controls for one paused turn. */
19
+ export interface PausedTurnRunOptions {
20
+ shouldYield?: () => boolean;
21
+ }
22
+ /**
23
+ * Continue one paused Slack agent run from durable conversation state.
24
+ *
25
+ * Returns false when the session became stale before generation began.
26
+ */
27
+ export declare function runPausedTurn(payload: PausedTurnRequest, options: PausedTurnOptions, runOptions?: PausedTurnRunOptions): Promise<boolean>;
28
+ /** Resume the first valid paused Slack session for an idle conversation. */
29
+ export declare function runNextPausedTurn(conversationId: string, options: PausedTurnOptions, runOptions?: PausedTurnRunOptions): Promise<boolean>;
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
  import { type ConversationQueueMessage } from "./queue";
3
3
  export declare const CONVERSATION_WORK_QUEUE_SIGNATURE_MAX_SKEW_MS: number;
4
4
  declare const signedConversationQueueMessageSchema: z.ZodObject<{
5
+ schemaVersion: z.ZodLiteral<2>;
5
6
  conversationId: z.ZodString;
6
7
  signature: z.ZodString;
7
8
  signatureVersion: z.ZodLiteral<"v2">;
@@ -1,6 +1,8 @@
1
1
  import { z } from "zod";
2
- /** Validate the conversation work hint sent through Vercel Queue. */
2
+ export declare const CONVERSATION_QUEUE_SCHEMA_VERSION = 2;
3
+ /** Validate the v2 conversation work hint sent through Vercel Queue. */
3
4
  export declare const conversationQueueMessageSchema: z.ZodObject<{
5
+ schemaVersion: z.ZodLiteral<2>;
4
6
  conversationId: z.ZodString;
5
7
  }, z.core.$strict>;
6
8
  /** Conversation work hint accepted by the queue callback and worker. */
@@ -22,6 +24,10 @@ export interface ConversationQueueSendOptions {
22
24
  export interface ConversationQueueSendResult {
23
25
  messageId?: string;
24
26
  }
27
+ /**
28
+ * External transport for wake-up hints. Durable work stays in the mailbox;
29
+ * transports only need to accept one hint and may return a provider message id.
30
+ */
25
31
  export interface ConversationWorkQueue {
26
32
  send(message: ConversationQueueMessage, options?: ConversationQueueSendOptions): Promise<ConversationQueueSendResult | void>;
27
33
  }
@@ -274,7 +274,7 @@ export interface CreateSlackConversationWorkerOptions {
274
274
  crossActorMidRunMode?: CrossActorMidRunMode;
275
275
  getSlackAdapter: () => SlackAdapter;
276
276
  lookupSlackUser?: (teamId: string, userId: string) => Promise<SlackActorProfile | null | undefined>;
277
- resumeAwaitingContinuation: (conversationId: string, options: {
277
+ runNextPausedTurn: (conversationId: string, options: {
278
278
  shouldYield: () => boolean;
279
279
  }) => Promise<boolean>;
280
280
  conversationStore?: ConversationStore;
@@ -7,8 +7,8 @@ declare class InvalidConversationRecordError extends Error {
7
7
  }
8
8
  /** Return whether an error means a stored conversation record failed validation. */
9
9
  export declare function isInvalidConversationRecordError(error: unknown): error is InvalidConversationRecordError;
10
- export declare const CONVERSATION_BY_ACTIVITY_INDEX_KEY = "junior:conversation:by-activity";
11
- export declare const CONVERSATION_ACTIVE_INDEX_KEY = "junior:conversation:active";
10
+ export declare const CONVERSATION_BY_ACTIVITY_INDEX_KEY = "junior:conversation:v2:by-activity";
11
+ export declare const CONVERSATION_ACTIVE_INDEX_KEY = "junior:conversation:v2:active";
12
12
  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;
@@ -24,7 +24,7 @@ declare const inboundMessageSourceSchema: z.ZodEnum<{
24
24
  scheduler: "scheduler";
25
25
  }>;
26
26
  export type Source = z.output<typeof inboundMessageSourceSchema>;
27
- export type ExecutionStatus = "awaiting_resume" | "failed" | "idle" | "pending" | "running";
27
+ export type ExecutionStatus = "paused" | "failed" | "idle" | "pending" | "running";
28
28
  declare const agentInputSchema: z.ZodObject<{
29
29
  attachments: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
30
30
  authorId: z.ZodOptional<z.ZodString>;
@@ -252,7 +252,7 @@ export declare function ackMessages(args: {
252
252
  state?: StateAdapter;
253
253
  }): Promise<boolean>;
254
254
  /** Mark the leased conversation as needing another queue-delivered slice. */
255
- export declare function requestConversationContinuation(args: {
255
+ export declare function requestAnotherSlice(args: {
256
256
  conversationId: string;
257
257
  destination?: Destination;
258
258
  leaseToken: string;
@@ -1,6 +1,6 @@
1
1
  import type { StateAdapter } from "chat";
2
2
  import type { ConversationStore } from "@/chat/conversations/store";
3
- import type { ConversationWorkQueue } from "./queue";
3
+ import { type ConversationWorkQueue } from "./queue";
4
4
  import * as workState from "./state";
5
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";
@@ -136,7 +136,7 @@ export declare function ackMessages(args: {
136
136
  state?: StateAdapter;
137
137
  }): Promise<boolean>;
138
138
  /** Mark the leased conversation as needing another queue-delivered slice. */
139
- export declare function requestConversationContinuation(args: {
139
+ export declare function requestAnotherSlice(args: {
140
140
  conversationId: string;
141
141
  destination: InboundMessage["destination"];
142
142
  leaseToken: string;
@@ -0,0 +1,6 @@
1
+ /** Return the Redis key for one turn cursor. */
2
+ export declare function turnCursorKey(conversationId: string, turnId: string): string;
3
+ /** Return the Redis index key for one conversation's turns. */
4
+ export declare function turnCursorIndexKey(conversationId: string): string;
5
+ /** Return the lock key that serializes writes to one turn cursor. */
6
+ export declare function turnCursorMutationKey(conversationId: string, turnId: string): string;