@sentry/junior 0.144.0 → 0.146.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 (104) hide show
  1. package/dist/{agent-hooks-GCUTGKY3.js → agent-hooks-SLJADYE5.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 +400 -461
  7. package/dist/{catalog-runtime-DWVYKDC6.js → catalog-runtime-RQIMSDPR.js} +5 -5
  8. package/dist/chat/agent/request.d.ts +1 -1
  9. package/dist/chat/agent/resume.d.ts +6 -18
  10. package/dist/chat/agent/skills.d.ts +0 -1
  11. package/dist/chat/agent/tools.d.ts +1 -2
  12. package/dist/chat/agent-dispatch/types.d.ts +1 -1
  13. package/dist/chat/app/conversation-work.d.ts +24 -0
  14. package/dist/chat/conversations/message-search.d.ts +32 -0
  15. package/dist/chat/conversations/projection.d.ts +11 -3
  16. package/dist/chat/conversations/sql/message-search.d.ts +4 -0
  17. package/dist/chat/conversations/store.d.ts +1 -1
  18. package/dist/chat/conversations/tool-source.d.ts +5 -0
  19. package/dist/chat/db.d.ts +2 -2
  20. package/dist/chat/runtime/agent-run-outcome.d.ts +1 -1
  21. package/dist/chat/runtime/reply-executor.d.ts +5 -5
  22. package/dist/chat/runtime/slack-resume.d.ts +12 -4
  23. package/dist/chat/slack/message/attachments.d.ts +2 -0
  24. package/dist/chat/slack/message/blocks.d.ts +2 -0
  25. package/dist/chat/slack/message/content.d.ts +18 -0
  26. package/dist/chat/slack/message/identity.d.ts +7 -0
  27. package/dist/chat/slack/tools/{conversation-search.d.ts → conversation-message-search.d.ts} +21 -14
  28. package/dist/chat/slack/tools/user-lookup.d.ts +2 -1
  29. package/dist/chat/state/locks.d.ts +28 -0
  30. package/dist/chat/task-execution/checkpoint.d.ts +84 -0
  31. package/dist/chat/task-execution/paused-turn.d.ts +29 -0
  32. package/dist/chat/task-execution/queue-signing.d.ts +1 -0
  33. package/dist/chat/task-execution/queue.d.ts +7 -1
  34. package/dist/chat/task-execution/slack-work.d.ts +1 -1
  35. package/dist/chat/task-execution/state.d.ts +4 -4
  36. package/dist/chat/task-execution/store.d.ts +2 -2
  37. package/dist/chat/task-execution/turn-cursor-keys.d.ts +6 -0
  38. package/dist/chat/{state/turn-session.d.ts → task-execution/turn-cursor.d.ts} +52 -51
  39. package/dist/chat/task-execution/turn-wake.d.ts +29 -0
  40. package/dist/chat/tools/{query-conversation-events.d.ts → search-conversation-events.d.ts} +3 -3
  41. package/dist/chat/tools/types.d.ts +1 -1
  42. package/dist/{chunk-SBZP2J5Q.js → chunk-37EVZP66.js} +48 -35
  43. package/dist/{chunk-A67GZN73.js → chunk-37JJDS4H.js} +1 -1
  44. package/dist/{chunk-BBCWYXHB.js → chunk-47OSH2ZO.js} +7 -7
  45. package/dist/{chunk-4X5KM7Z6.js → chunk-AISNSNDV.js} +14 -14
  46. package/dist/{chunk-RIFJUJSI.js → chunk-B63BF443.js} +1 -1
  47. package/dist/{chunk-SSDTQDYQ.js → chunk-BLETMLRX.js} +566 -268
  48. package/dist/{chunk-I44JB7HQ.js → chunk-F7REGDKO.js} +1 -1
  49. package/dist/{chunk-DVO5VKYQ.js → chunk-FEKQHPVA.js} +5 -5
  50. package/dist/{chunk-SUK7NC5A.js → chunk-FGHADGIC.js} +2 -2
  51. package/dist/{chunk-7KAW7UF4.js → chunk-FXDDDSPL.js} +4 -4
  52. package/dist/{chunk-BEGGFVFR.js → chunk-GDQEU4I7.js} +414 -542
  53. package/dist/{chunk-UDQMY6RS.js → chunk-GYEKOX7N.js} +43 -1
  54. package/dist/{chunk-W7JFV5SB.js → chunk-H6U2U3EP.js} +14 -17
  55. package/dist/{chunk-WTX2RFJG.js → chunk-HQE6EJS5.js} +1 -1
  56. package/dist/{chunk-IUFM5JWV.js → chunk-JAL3CH4G.js} +3 -0
  57. package/dist/{chunk-E7HCWOHG.js → chunk-JLMVCNXL.js} +2 -1
  58. package/dist/{chunk-PELZ2ZSY.js → chunk-JUA6VU2Z.js} +33 -63
  59. package/dist/{chunk-SHEEZSLY.js → chunk-LVW7BLLT.js} +2 -2
  60. package/dist/{chunk-GKA74DRA.js → chunk-M6ZWP4RI.js} +1 -1
  61. package/dist/{chunk-HNO2E5WB.js → chunk-MCFIXAV5.js} +1 -1
  62. package/dist/{chunk-3GU4PWA3.js → chunk-MKRIZ4VG.js} +29 -30
  63. package/dist/{chunk-QUZJDAQQ.js → chunk-OFPYOC3M.js} +93 -90
  64. package/dist/{chunk-ZF3N3JD6.js → chunk-PB222GIA.js} +1 -1
  65. package/dist/{chunk-PKH6762I.js → chunk-PH4Q3A6W.js} +1 -1
  66. package/dist/{chunk-STFCL3K4.js → chunk-QG7OOKIN.js} +1 -1
  67. package/dist/{chunk-WSOLZJJS.js → chunk-QSXZ42KX.js} +3 -3
  68. package/dist/{chunk-44RJWAND.js → chunk-SCGVWUZX.js} +6 -6
  69. package/dist/{chunk-CNTWB2SM.js → chunk-T5GXFFLA.js} +1 -1
  70. package/dist/{chunk-LDWNYCZ6.js → chunk-TCEJ7XXM.js} +1 -1
  71. package/dist/{chunk-QE3TICD4.js → chunk-V6SRLKUB.js} +2 -2
  72. package/dist/{chunk-54JMYQYS.js → chunk-W65V465O.js} +2 -2
  73. package/dist/{chunk-KCBZSJRU.js → chunk-WR76IVA5.js} +5 -2
  74. package/dist/{chunk-ZZCTGAIT.js → chunk-X22KCSCO.js} +4 -4
  75. package/dist/{chunk-HD6BHR25.js → chunk-X2WMBTS3.js} +32 -34
  76. package/dist/{chunk-KQBXT5B7.js → chunk-ZDGHGY74.js} +6 -6
  77. package/dist/cli/chat.js +32 -32
  78. package/dist/cli/check.js +6 -6
  79. package/dist/cli/plugins.js +13 -13
  80. package/dist/cli/snapshot-create.js +9 -9
  81. package/dist/cli/upgrade.js +7 -7
  82. package/dist/{db-EFLHTBU6.js → db-WWOMXWTT.js} +9 -9
  83. package/dist/instrumentation.js +4 -4
  84. package/dist/nitro.js +4 -4
  85. package/dist/{oauth-callback-server-RO3IQKWM.js → oauth-callback-server-A6ZZX74U.js} +25 -25
  86. package/dist/{runner-LOWW7JKA.js → runner-KSGB2UAV.js} +19 -20
  87. package/dist/{skills-ZLMUG7AE.js → skills-26QPWKVS.js} +6 -6
  88. package/dist/spawn-5LAJXZ2P.js +39 -0
  89. package/dist/{validation-MAKEZNTS.js → validation-OPSRGFGH.js} +6 -6
  90. package/dist/version.js +1 -1
  91. package/dist/{work-5OAGC3I4.js → work-VMSW7STJ.js} +17 -16
  92. package/dist/worker-2JNFB7C7.js +24 -0
  93. package/package.json +5 -5
  94. package/dist/chat/agent/session.d.ts +0 -19
  95. package/dist/chat/conversations/search.d.ts +0 -24
  96. package/dist/chat/conversations/sql/search.d.ts +0 -4
  97. package/dist/chat/runtime/agent-continue-runner.d.ts +0 -37
  98. package/dist/chat/services/agent-continue.d.ts +0 -29
  99. package/dist/chat/services/turn-session-record.d.ts +0 -164
  100. package/dist/chat/slack/legacy-attachments.d.ts +0 -4
  101. package/dist/chat/slack/message.d.ts +0 -12
  102. package/dist/chat/state/turn-session-keys.d.ts +0 -6
  103. package/dist/spawn-R3LUV6RF.js +0 -38
  104. 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-PB222GIA.js";
4
+ import "./chunk-37JJDS4H.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-B63BF443.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-HQE6EJS5.js";
13
+ import "./chunk-F7REGDKO.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,48 +1,39 @@
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;
27
21
  destinationVisibility?: ConversationPrivacy;
28
22
  dispatchId?: string;
29
23
  durability: AgentRunDurability;
30
- getLoadedSkillNames: () => string[];
31
- getModelId: () => string;
32
- getReasoningLevel: () => string | undefined;
33
24
  recordActiveMcpProviders: () => Promise<void>;
34
25
  actor?: Actor;
35
26
  runSource: Source;
36
27
  conversationId: string;
37
28
  turnId: string;
38
- sessionRecordState: LoadedSessionRecordState;
29
+ checkpoint: TurnCheckpoint;
39
30
  startedAtMs: number;
40
31
  surface: AgentTurnSurface;
41
32
  }
42
33
  type AuthPauseOutcome = Extract<AgentRunOutcome, {
43
34
  status: "awaiting_auth";
44
35
  }>;
45
- /** Create the run's resume state: checkpoints, snapshots, and ending translation. */
36
+ /** Create resume state for one slice. */
46
37
  export declare function createResumeState(args: ResumeStateArgs): {
47
38
  readonly inputCommitted: boolean;
48
39
  readonly beforeMessageCount: number;
@@ -50,7 +41,7 @@ export declare function createResumeState(args: ResumeStateArgs): {
50
41
  setTurnStartMessageIndex(index: number | undefined): void;
51
42
  setBeforeMessageCount(count: number): void;
52
43
  setTurnContexts(contexts: PluginTurnContext[]): void;
53
- /** Adopt an already committed epoch replacement as every resume baseline. */
44
+ /** Use an already committed boundary as the resume baseline. */
54
45
  adoptCommittedBoundary(messages: PiMessage[]): void;
55
46
  captureResumeSnapshot(messages: PiMessage[]): void;
56
47
  getResumeSnapshot(currentMessages: PiMessage[]): PiMessage[];
@@ -58,11 +49,8 @@ export declare function createResumeState(args: ResumeStateArgs): {
58
49
  commitInput(): Promise<void>;
59
50
  persistSafeBoundary(messages: PiMessage[], trailingMessageProvenance?: ConversationMessageProvenance[]): Promise<boolean>;
60
51
  requireDurableInputCheckpoint(messages: PiMessage[], trailingMessageProvenance?: ConversationMessageProvenance[]): Promise<boolean>;
61
- /** Prepare a cooperative yield at the current durable boundary. */
62
52
  prepareYieldIfDue(currentMessages: PiMessage[]): CooperativeTurnYieldError | undefined;
63
- /** Persist an auth pause; only a durable pause may return `awaiting_auth`. */
64
53
  parkForAuth(pause: AuthorizationPauseError, currentUsage?: AgentTurnUsage): Promise<AuthPauseOutcome>;
65
- /** Persist a yield, retry, or timeout as a suspended run. */
66
54
  translateSuspension(ending: {
67
55
  currentUsage?: AgentTurnUsage;
68
56
  error: unknown;
@@ -13,5 +13,4 @@ export declare function restoreSkillRuntime(args: {
13
13
  invokedSkill: SkillMetadata | null;
14
14
  priorPiMessages: PiMessage[] | undefined;
15
15
  skillSandbox: SkillSandbox;
16
- syncLoadedSkillNamesForResume: () => void;
17
16
  }): Promise<void>;
@@ -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 {
@@ -66,7 +66,6 @@ interface ToolWiringArgs {
66
66
  state: AgentRunState;
67
67
  supportsImageInput: () => boolean;
68
68
  surface: AgentTurnSurface;
69
- syncLoadedSkillNamesForResume: () => void;
70
69
  toolCalls: string[];
71
70
  userInput: string;
72
71
  }
@@ -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 {};
@@ -0,0 +1,32 @@
1
+ /** One relevant chat-message match from a prior conversation. */
2
+ export interface ConversationMessageSearchResult {
3
+ channelName?: string;
4
+ conversationId: string;
5
+ excerpt: string;
6
+ messageCreatedAtMs: number;
7
+ messageId: string;
8
+ providerDestinationId: string;
9
+ role: "assistant" | "user";
10
+ }
11
+ /** Runtime-derived public workspace scope for cross-conversation search. */
12
+ export interface ConversationMessageSearchScope {
13
+ kind: "public_provider_tenant";
14
+ provider: "slack";
15
+ providerTenantId: string;
16
+ }
17
+ /** Optional filters that narrow retained public workspace search. */
18
+ export interface ConversationMessageSearchFilters {
19
+ /** Slack channel id of the conversation destination. */
20
+ channelId?: string;
21
+ /** Full-text query over retained visible message text. */
22
+ query?: string;
23
+ }
24
+ /** Search retained public messages within an authorized workspace. */
25
+ export interface ConversationMessageSearchStore {
26
+ search(args: {
27
+ currentConversationId: string;
28
+ filters: ConversationMessageSearchFilters;
29
+ limit: number;
30
+ scope: ConversationMessageSearchScope;
31
+ }): Promise<ConversationMessageSearchResult[]>;
32
+ }
@@ -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;
@@ -0,0 +1,4 @@
1
+ import type { JuniorSqlDatabase } from "@/db/db";
2
+ import type { ConversationMessageSearchStore } from "../message-search";
3
+ /** Create a SQL-backed public workspace message search store. */
4
+ export declare function createSqlConversationMessageSearchStore(executor: JuniorSqlDatabase): ConversationMessageSearchStore;
@@ -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;
@@ -0,0 +1,5 @@
1
+ /** Deferred tool catalog source for retained Junior conversations. */
2
+ export declare const CONVERSATIONS_TOOL_SOURCE: {
3
+ readonly id: "conversations";
4
+ readonly description: "Search messages and events in retained Junior conversations.";
5
+ };
package/dist/chat/db.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { ConversationStore } from "@/chat/conversations/store";
2
2
  import type { ConversationEventStore } from "@/chat/conversations/history";
3
- import type { ConversationSearchStore } from "@/chat/conversations/search";
3
+ import type { ConversationMessageSearchStore } from "@/chat/conversations/message-search";
4
4
  import type { JuniorDatabase, JuniorSqlExecutor } from "@/db/db";
5
5
  /** Return the process SQL executor for SQL-specific queries and transactions. */
6
6
  export declare function getSqlExecutor(): JuniorSqlExecutor;
@@ -11,6 +11,6 @@ export declare function getConversationStore(): ConversationStore;
11
11
  /** Return the canonical SQL-backed conversation event store. */
12
12
  export declare function getConversationEventStore(): ConversationEventStore;
13
13
  /** Return the SQL-backed public provider-tenant conversation search store. */
14
- export declare function getConversationSearchStore(): ConversationSearchStore;
14
+ export declare function getConversationMessageSearchStore(): ConversationMessageSearchStore;
15
15
  /** Close the process SQL database when it has been opened. */
16
16
  export declare function closeDb(): Promise<void>;
@@ -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 {};
@@ -0,0 +1,2 @@
1
+ /** Render legacy attachment fields so attachment-only messages still carry context. */
2
+ export declare function renderAttachmentText(input: unknown): string;
@@ -0,0 +1,2 @@
1
+ /** Render visible block text without exposing hidden interaction data. */
2
+ export declare function renderBlockText(value: unknown): string;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Slack message content projection.
3
+ *
4
+ * This module is the typed entry point for agent-visible Slack text. Raw block
5
+ * and attachment details stay behind this boundary.
6
+ */
7
+ import { type Message } from "chat";
8
+ /** Agent-visible content projected from a Slack message. */
9
+ export interface MessageContent {
10
+ attachmentText: string;
11
+ hasAttachments: boolean;
12
+ text: string;
13
+ topLevelText: string;
14
+ }
15
+ /** Replace top-level text while preserving the parsed attachment projection. */
16
+ export declare function replaceTopLevelText(content: Pick<MessageContent, "attachmentText">, text: string): string;
17
+ /** Parse the agent-visible content and attachment state of a Slack message. */
18
+ export declare function parseContent(message: Pick<Message, "attachments" | "formatted" | "raw" | "text">): MessageContent;
@@ -0,0 +1,7 @@
1
+ import type { Message } from "chat";
2
+ import { type SlackMessageTs } from "@/chat/slack/timestamp";
3
+ /**
4
+ * Preserve the native Slack message timestamp when a synthetic message ID is
5
+ * used for routing or deduplication.
6
+ */
7
+ export declare function getMessageTimestamp(message: Pick<Message, "id" | "raw">): SlackMessageTs | undefined;
@@ -1,28 +1,30 @@
1
- import type { ConversationSearchScope, ConversationSearchStore } from "@/chat/conversations/search";
1
+ import type { ConversationMessageSearchScope, ConversationMessageSearchStore } from "@/chat/conversations/message-search";
2
2
  import { getSlackMessagePermalink } from "@/chat/slack/outbound";
3
- interface ConversationSearchToolDeps {
3
+ interface ConversationMessageSearchToolDeps {
4
4
  getPermalink?: typeof getSlackMessagePermalink;
5
- store?: ConversationSearchStore;
5
+ store?: ConversationMessageSearchStore;
6
6
  }
7
- /** Create a tool that searches retained public Junior threads across an authorized Slack workspace. */
8
- export declare function createSlackConversationSearchTool(scope: ConversationSearchScope, currentConversationId: string, deps?: ConversationSearchToolDeps): Omit<import("../../tools/definition").AnyToolDefinition, "inputSchema" | "outputSchema" | "prepareArguments" | "execute"> & {
7
+ /** Create a tool that searches retained public messages in an authorized Slack workspace. */
8
+ export declare function createSlackConversationMessageSearchTool(scope: ConversationMessageSearchScope, currentConversationId: string, deps?: ConversationMessageSearchToolDeps): Omit<import("../../tools/definition").AnyToolDefinition, "inputSchema" | "outputSchema" | "prepareArguments" | "execute"> & {
9
9
  inputSchema: import("../../tools/definition").JsonSchemaObject;
10
10
  outputSchema: import("../../tools/definition").JsonSchemaObject;
11
11
  prepareArguments(args: unknown): {
12
- query: string;
12
+ channel_id?: string | null | undefined;
13
+ query?: string | null | undefined;
13
14
  limit?: number | null | undefined;
14
15
  };
15
16
  execute?: ((input: unknown, options: import("../../tools/definition").ToolExecuteOptions) => {
16
17
  [x: string]: unknown;
17
- query: string;
18
18
  count: number;
19
- threads: {
19
+ matches: {
20
+ channel_id: string;
20
21
  conversation_id: string;
21
- thread_ts: string;
22
+ excerpt: string;
22
23
  message_id: string;
23
24
  message_role: "user" | "assistant";
24
25
  message_timestamp: string;
25
- excerpt: string;
26
+ thread_ts: string;
27
+ channel_name?: string | undefined;
26
28
  permalink?: string | undefined;
27
29
  }[];
28
30
  target?: string | undefined;
@@ -31,17 +33,20 @@ export declare function createSlackConversationSearchTool(scope: ConversationSea
31
33
  arguments: Record<string, unknown>;
32
34
  reason?: string | undefined;
33
35
  } | undefined;
36
+ channel_id?: string | undefined;
37
+ query?: string | undefined;
34
38
  } | Promise<{
35
39
  [x: string]: unknown;
36
- query: string;
37
40
  count: number;
38
- threads: {
41
+ matches: {
42
+ channel_id: string;
39
43
  conversation_id: string;
40
- thread_ts: string;
44
+ excerpt: string;
41
45
  message_id: string;
42
46
  message_role: "user" | "assistant";
43
47
  message_timestamp: string;
44
- excerpt: string;
48
+ thread_ts: string;
49
+ channel_name?: string | undefined;
45
50
  permalink?: string | undefined;
46
51
  }[];
47
52
  target?: string | undefined;
@@ -50,6 +55,8 @@ export declare function createSlackConversationSearchTool(scope: ConversationSea
50
55
  arguments: Record<string, unknown>;
51
56
  reason?: string | undefined;
52
57
  } | undefined;
58
+ channel_id?: string | undefined;
59
+ query?: string | undefined;
53
60
  }>) | undefined;
54
61
  };
55
62
  export {};
@@ -1,5 +1,6 @@
1
+ import type { SlackTeamId } from "@/chat/slack/ids";
1
2
  /** Create the tool that resolves Slack users by ID, handle, or email. */
2
- export declare function createSlackUserLookupTool(): Omit<import("../../tools/definition").AnyToolDefinition, "inputSchema" | "outputSchema" | "prepareArguments" | "execute"> & {
3
+ export declare function createSlackUserLookupTool(teamId: SlackTeamId): Omit<import("../../tools/definition").AnyToolDefinition, "inputSchema" | "outputSchema" | "prepareArguments" | "execute"> & {
3
4
  inputSchema: import("../../tools/definition").JsonSchemaObject;
4
5
  outputSchema: import("../../tools/definition").JsonSchemaObject;
5
6
  prepareArguments(args: unknown): {
@@ -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,84 @@
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
+ * Profile, reasoning, concrete model id, and skills are not checkpoint fields.
36
+ */
37
+ interface TurnCheckpointWrite {
38
+ conversationId: string;
39
+ turnId: string;
40
+ messages: PiMessage[];
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
+ turnStartMessageIndex?: number;
52
+ trailingMessageProvenance?: ConversationMessageProvenance[];
53
+ turnContexts?: PluginTurnContext[];
54
+ durationMs?: number;
55
+ usage?: AgentTurnUsage;
56
+ errorMessage?: string;
57
+ resultMessageId?: string;
58
+ }
59
+ type ProgressCheckpointArgs = (TurnCheckpointWrite & {
60
+ mode: "running";
61
+ sliceId: number;
62
+ }) | (TurnCheckpointWrite & {
63
+ mode: "paused";
64
+ reason: TurnPauseReason;
65
+ sliceId: number;
66
+ });
67
+ type TerminalCheckpointArgs = TurnCheckpointWrite & {
68
+ mode: "completed" | "failed";
69
+ };
70
+ /** Boundary safe to continue after auth/timeout (trim mid-assistant). */
71
+ export declare function continuableMessages(messages: PiMessage[], fallback?: PiMessage[]): PiMessage[];
72
+ /** Load resume cursor for one turn. */
73
+ export declare function loadTurnCheckpoint(args: {
74
+ conversationId: string;
75
+ turnId: string;
76
+ }): Promise<TurnCheckpoint>;
77
+ /**
78
+ * Save turn progress.
79
+ *
80
+ * - `running` / `paused`: best-effort; returns the stored record or undefined
81
+ * - `completed` / `failed`: retries until write accepts; throws on hard failure
82
+ */
83
+ export declare function saveTurnCheckpoint(args: ProgressCheckpointArgs): Promise<TurnRecord | undefined>;
84
+ 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">;