@agent-compose/sdk 0.7.0 → 0.8.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 (116) hide show
  1. package/README.md +66 -39
  2. package/dist/agent/__tests__/runtime-json-schema.test.d.ts +10 -0
  3. package/dist/agent/agent-context.d.ts +21 -1
  4. package/dist/agent/agent-loop.d.ts +24 -1
  5. package/dist/client.d.ts +338 -534
  6. package/dist/directives.d.ts +112 -0
  7. package/dist/display.d.ts +242 -0
  8. package/dist/errors.d.ts +24 -1
  9. package/dist/index.d.ts +24 -12
  10. package/dist/index.js +3545 -1667
  11. package/dist/pause/wrappers.d.ts +31 -9
  12. package/dist/runtimes/_acp-client.d.ts +46 -1
  13. package/dist/runtimes/_cli-agent.d.ts +49 -4
  14. package/dist/runtimes/_jsonl-guard.d.ts +103 -0
  15. package/dist/runtimes/amp.d.ts +2 -2
  16. package/dist/runtimes/claude-code.d.ts +59 -0
  17. package/dist/runtimes/claude-code.test.d.ts +14 -0
  18. package/dist/runtimes/claude.d.ts +16 -0
  19. package/dist/runtimes/claude.test.d.ts +8 -0
  20. package/dist/runtimes/codex.d.ts +9 -3
  21. package/dist/runtimes/cursor.d.ts +2 -2
  22. package/dist/runtimes/droid.d.ts +2 -2
  23. package/dist/runtimes/jsonl-guard.test.d.ts +19 -0
  24. package/dist/runtimes/openai-desktop.js +2691 -864
  25. package/dist/runtimes/opencode.d.ts +2 -2
  26. package/dist/runtimes/vercel.js +12 -1
  27. package/dist/sandbox/devbox.d.ts +42 -0
  28. package/dist/sandbox/exec-stream.d.ts +14 -0
  29. package/dist/sandbox/network-policy.d.ts +100 -0
  30. package/dist/sandbox/provider-def.d.ts +79 -0
  31. package/dist/sandbox/providers/desktop.d.ts +10 -0
  32. package/dist/sandbox/providers/e2b.d.ts +17 -0
  33. package/dist/sandbox/providers/local.d.ts +11 -0
  34. package/dist/sandbox/providers/vercel.d.ts +18 -0
  35. package/dist/sandbox/registry.d.ts +45 -0
  36. package/dist/sandbox/sizes.d.ts +68 -0
  37. package/dist/sandbox.d.ts +24 -299
  38. package/dist/step-invocation/__tests__/foreground-recovery.test.d.ts +1 -0
  39. package/dist/step-invocation/invoker.d.ts +10 -0
  40. package/dist/step-invocation/protocol.d.ts +5 -0
  41. package/dist/types/api-compliance.d.ts +71 -0
  42. package/dist/types/api-conversations.d.ts +492 -0
  43. package/dist/types/api-factory.d.ts +309 -0
  44. package/dist/types/api-projects.d.ts +131 -0
  45. package/dist/types/api-runs.d.ts +377 -0
  46. package/dist/types/api-scopes.d.ts +102 -0
  47. package/dist/types/conversation-stream.d.ts +191 -0
  48. package/dist/types/execution-context.d.ts +12 -2
  49. package/dist/types/protocol.d.ts +30 -1
  50. package/dist/types/sandbox-environment.d.ts +8 -5
  51. package/dist/types/sandbox.d.ts +74 -4
  52. package/dist/types/workflow-metadata.d.ts +33 -8
  53. package/dist/types/workflow-plan.d.ts +10 -0
  54. package/dist/types/workflow.d.ts +18 -205
  55. package/dist/utils/bundler.d.ts +12 -1
  56. package/dist/workflow-steps/index.d.ts +1 -1
  57. package/dist/workflow-steps/observability.d.ts +8 -1
  58. package/dist/workflow-steps/runner.d.ts +3 -3
  59. package/dist/workflow-steps/step.d.ts +15 -1
  60. package/dist/workflow-steps/types.d.ts +19 -5
  61. package/dist/workflow-steps/workflow.d.ts +22 -1
  62. package/dist/workflows/engine.d.ts +3 -2
  63. package/dist/workflows/invoke-child.d.ts +2 -2
  64. package/package.json +1 -1
  65. package/src/agent/agent-context.ts +186 -3
  66. package/src/agent/agent-loop.ts +31 -2
  67. package/src/client.ts +909 -621
  68. package/src/directives.ts +184 -0
  69. package/src/display.ts +788 -0
  70. package/src/errors.ts +39 -0
  71. package/src/index.ts +104 -10
  72. package/src/pause/wrappers.ts +44 -9
  73. package/src/runtimes/_acp-client.ts +72 -3
  74. package/src/runtimes/_cli-agent.ts +159 -36
  75. package/src/runtimes/_jsonl-guard.ts +219 -0
  76. package/src/runtimes/claude-code.ts +246 -0
  77. package/src/runtimes/claude.ts +32 -2
  78. package/src/runtimes/codex.ts +55 -3
  79. package/src/runtimes/openai-desktop.ts +59 -14
  80. package/src/sandbox/devbox.ts +48 -0
  81. package/src/sandbox/exec-stream.ts +48 -0
  82. package/src/sandbox/network-policy.ts +181 -0
  83. package/src/sandbox/provider-def.ts +94 -0
  84. package/src/sandbox/providers/desktop.ts +57 -0
  85. package/src/sandbox/providers/e2b.ts +354 -0
  86. package/src/sandbox/providers/local.ts +106 -0
  87. package/src/sandbox/providers/vercel.ts +331 -0
  88. package/src/sandbox/registry.ts +198 -0
  89. package/src/sandbox/sizes.ts +95 -0
  90. package/src/sandbox.ts +59 -1275
  91. package/src/step-invocation/invoker.ts +151 -28
  92. package/src/step-invocation/protocol.ts +8 -0
  93. package/src/types/api-compliance.ts +79 -0
  94. package/src/types/api-conversations.ts +522 -0
  95. package/src/types/api-factory.ts +336 -0
  96. package/src/types/api-projects.ts +140 -0
  97. package/src/types/api-runs.ts +412 -0
  98. package/src/types/api-scopes.ts +102 -0
  99. package/src/types/conversation-stream.ts +231 -0
  100. package/src/types/execution-context.ts +10 -2
  101. package/src/types/protocol.ts +33 -0
  102. package/src/types/sandbox-environment.ts +28 -9
  103. package/src/types/sandbox.ts +73 -4
  104. package/src/types/workflow-metadata.ts +35 -8
  105. package/src/types/workflow-plan.ts +11 -0
  106. package/src/types/workflow.ts +25 -292
  107. package/src/utils/bundler.ts +32 -5
  108. package/src/utils/errors.ts +16 -1
  109. package/src/workflow-steps/index.ts +1 -0
  110. package/src/workflow-steps/observability.ts +19 -8
  111. package/src/workflow-steps/runner.ts +4 -4
  112. package/src/workflow-steps/step.ts +49 -1
  113. package/src/workflow-steps/types.ts +20 -5
  114. package/src/workflow-steps/workflow.ts +22 -1
  115. package/src/workflows/engine.ts +3 -2
  116. package/src/workflows/invoke-child.ts +2 -2
@@ -0,0 +1,492 @@
1
+ /**
2
+ * Conversation-facing wire types for `AgentComposeClient` — channels, solo
3
+ * chats, sessions, threads, presence, team agents, and the
4
+ * teammate-mention surface.
5
+ *
6
+ * These are deliberate contract pins mirrored in `dashboard/src/lib/api.ts`;
7
+ * when the server changes a response shape, both update in the same change.
8
+ */
9
+ import type { ConversationAgentPresence } from "./conversation-stream.js";
10
+ import type { ConversationMemberRole } from "./api-scopes.js";
11
+ import type { SandboxSize } from "../sandbox/sizes.js";
12
+ import type { SandboxNetworkPolicy } from "../sandbox/network-policy.js";
13
+ /** A human member of your team — the people an agent (or you) can @-flag. */
14
+ export interface TeamMember {
15
+ /** Membership row id. */
16
+ id: string;
17
+ /** The user id — what you pass to `createMentions({ mentionedUserIds })`. */
18
+ userId: string;
19
+ role: string;
20
+ email: string;
21
+ name: string;
22
+ /** OAuth provider image URL, when present. */
23
+ image?: string | null;
24
+ /** Server-relative uploaded-avatar URL (ADR-0056), when set — takes
25
+ * precedence over `image`. Prefix with your API base. */
26
+ avatarUrl?: string | null;
27
+ joinedAt: string;
28
+ }
29
+ /** A "you were flagged" ping, persisted server-side so it reaches the
30
+ * mentioned teammate in their Workbench. */
31
+ export interface Mention {
32
+ id: string;
33
+ factoryId: string;
34
+ mentionedUserId: string;
35
+ /** Who flagged: 'user' | 'api_key' | 'run' | 'system'. */
36
+ actorKind: string;
37
+ actorId: string | null;
38
+ actorLabel: string | null;
39
+ /** Where it lives: 'doc' | 'comment' | 'plan' | 'run'. */
40
+ contextKind: string;
41
+ contextPath: string | null;
42
+ /** Ready-made relative dashboard URL the Workbench card links to. */
43
+ contextUrl: string | null;
44
+ text: string;
45
+ runId: string | null;
46
+ seenAt: string | null;
47
+ resolvedAt: string | null;
48
+ createdAt: string;
49
+ }
50
+ export interface CreateMentionsInput {
51
+ /** Team-member user ids to flag (1–20). Discover them via `listMembers()`.
52
+ * Non-members are dropped server-side. */
53
+ mentionedUserIds: string[];
54
+ /** The flag message shown in the teammate's Workbench. */
55
+ text: string;
56
+ contextKind: "doc" | "comment" | "plan" | "run";
57
+ /** Factory-relative file path or comment thread id, when applicable. */
58
+ contextPath?: string;
59
+ /** Ready-made relative dashboard URL the Workbench card links to (e.g.
60
+ * `/factories/<slug>/files/view?path=<plan>`). */
61
+ contextUrl?: string;
62
+ runId?: string;
63
+ factorySlug?: string;
64
+ }
65
+ /** One part of a conversation message. Text/tool/error parts as persisted by
66
+ * the server; unknown future part types flow through untyped. */
67
+ export type ConversationMessagePart = {
68
+ type: string;
69
+ } & Record<string, unknown>;
70
+ export interface ConversationRow {
71
+ id: string;
72
+ /** null ⇔ visibility "dm" (human pair, no agent). */
73
+ agentId: string | null;
74
+ title: string | null;
75
+ visibility: "solo" | "shared" | "dm";
76
+ access: "public" | "private";
77
+ kind: "chat" | "session";
78
+ /** The dm pair's user ids (sorted); null for solo/shared. */
79
+ dmParticipantIds: string[] | null;
80
+ createdBy: string | null;
81
+ /** Per-conversation agent overrides. The wire always carries the
82
+ * normalized full object (the server defaults every field);
83
+ * `model: "default"` passes through to the agent's own model. */
84
+ agentConfig: {
85
+ model: string;
86
+ effort: string;
87
+ instructions: string;
88
+ };
89
+ createdAt: string;
90
+ updatedAt: string;
91
+ /** Per-viewer unread count — present on the list wire for session
92
+ * callers; key callers see 0. */
93
+ unreadCount?: number;
94
+ }
95
+ export interface ConversationMessageRow {
96
+ id: string;
97
+ authorKind: string;
98
+ authorId: string | null;
99
+ parts: ConversationMessagePart[];
100
+ threadRootId: string | null;
101
+ reactions: Record<string, string[]>;
102
+ replyCount: number;
103
+ lastReplyAt: string | null;
104
+ createdAt: string;
105
+ /** Thread-root facepile (≤3) — present only on roots with replies. */
106
+ replyAuthors?: Array<{
107
+ kind: string;
108
+ id: string | null;
109
+ }>;
110
+ /** Set on a channel message an ATTACHED SESSION posted (ADR-0057 Seam 4)
111
+ * — the session conversation it speaks as. Renderers attribute these
112
+ * rows to the session (title + runtime mark), never a resident agent.
113
+ * Null once the session is deleted; absent on older servers. */
114
+ sourceSessionId?: string | null;
115
+ /** Set on a session-transcript row RELAYED from a channel mention
116
+ * (ADR-0057 Seam 3) — the channel it arrived from. Null once the
117
+ * channel is deleted; absent on older servers. */
118
+ sourceChannelId?: string | null;
119
+ /** Set on relay rows alongside sourceChannelId — the ORIGIN channel
120
+ * message the mention rode in on (the session's default post-back
121
+ * threads under it). Null once deleted; absent on older servers. */
122
+ sourceMessageId?: string | null;
123
+ }
124
+ export interface ConversationsPage {
125
+ conversations: ConversationRow[];
126
+ next_cursor: string | null;
127
+ }
128
+ /** Sessions page — each row additionally carries its resident
129
+ * executor substrate (ADR-0037 §8): `"cloud"` = persistent server-side
130
+ * sandbox (pickers render the ☁ marker), `"local"` = bridge daemon,
131
+ * null = no durable session record yet. */
132
+ export interface SessionsPage {
133
+ conversations: Array<ConversationRow & {
134
+ sessionExecutor: "local" | "cloud" | null;
135
+ }>;
136
+ next_cursor: string | null;
137
+ }
138
+ export interface ConversationDetail {
139
+ conversation: ConversationRow;
140
+ /** Resident executor substrate (ADR-0037 §8): `"local"` = a developer's
141
+ * bridge daemon; `"cloud"` = a persistent server-side sandbox on the
142
+ * factory drive; null = no durable session record (platform agents, or
143
+ * a bridge conversation before its first turn). Surfaces use this for
144
+ * presence labels only — attaching/driving is identical either way. */
145
+ sessionExecutor?: "local" | "cloud" | null;
146
+ /** The session's type (ADR-0055 §9) — the ONE surface decision, fixed at
147
+ * creation: `chat` = transcript + composer (no terminal, ever);
148
+ * `terminal`/`custom` = the PTY (`agentc session terminal`, no chat
149
+ * pane). Null = no durable session record; absent on older servers
150
+ * (read loosely). */
151
+ sessionType?: "chat" | "terminal" | "custom" | null;
152
+ /** The resident agent's slash-command palette, as reported by the
153
+ * executor (ACP `available_commands_update`) — drives "/" autocomplete
154
+ * in drivers. Null/absent when never reported (platform agents, older
155
+ * daemons/servers). */
156
+ sessionCommands?: Array<{
157
+ name: string;
158
+ description: string;
159
+ }> | null;
160
+ viewerLastReadAt: string | null;
161
+ /** The caller's role in this conversation (ADR-0045) — drives client
162
+ * affordances only; the server remains the authority on every action.
163
+ * Public channels report implicit `write` for non-member teammates. */
164
+ viewerRole: ConversationMemberRole;
165
+ /** SSE replay watermark: the conversation's highest durable stream-event
166
+ * id at hydrate time — everything at or below it is already folded into
167
+ * `messages`. Seed the stream's first `Last-Event-ID` from it instead of
168
+ * 0 (0 replays the entire history). Absent on older servers. */
169
+ streamCursor?: number;
170
+ messages: ConversationMessageRow[];
171
+ }
172
+ /** Input for `createCloudSession` (ADR-0037 Phase 3b / ADR-0055 §9). The
173
+ * session runs against a CLOUD CHECKOUT on the factory's drive — never the
174
+ * caller's local files. Its TYPE is fixed at creation, never switched. */
175
+ export interface CreateCloudSessionInput {
176
+ /** Session type (ADR-0055 §9): `chat` = the wrapped agent experience (a
177
+ * coding runtime driven via ACP — no terminal, ever); `terminal` = a raw
178
+ * machine surface (the PTY is the surface — no chat pane); `custom` = a
179
+ * terminal born with a pre-start recipe (`presetId`/`preStart`). Omitted
180
+ * = derived server-side (runtime `terminal` → terminal, else chat) — the
181
+ * wire-level grandfather for older callers; send it explicitly. */
182
+ type?: "chat" | "terminal" | "custom";
183
+ /** In-sandbox coding runtime hosting a CHAT session. Required for chat;
184
+ * omitted (or `"terminal"`) for terminal/custom sessions — those have no
185
+ * harness, the shell is the surface. */
186
+ runtime?: "codex" | "cursor" | "droid" | "opencode" | "claude-code" | "terminal";
187
+ /** Custom sessions: a saved launch preset, resolved server-side and
188
+ * FROZEN into the session's pre-start at create (a later preset edit
189
+ * never changes an existing session). Exactly one of `presetId` /
190
+ * `preStart` is required for custom; both are 400s on other types. */
191
+ presetId?: string;
192
+ /** Custom sessions: an inline pre-start recipe — the bootstrap exec'd
193
+ * into the session's first pty (e.g. boot the claude-code TUI), with
194
+ * `preLaunch` an invisible shell fragment run before it. */
195
+ preStart?: {
196
+ command: string;
197
+ args?: string[];
198
+ env?: Record<string, string>;
199
+ preLaunch?: string | null;
200
+ };
201
+ /** Factory whose durable drive backs the session's working tree. */
202
+ factoryId: string;
203
+ title?: string;
204
+ /** Optional repo bootstrap: an https git URL cloned onto the drive on
205
+ * first turn (idempotent — survives sandbox eviction). */
206
+ repoUrl?: string;
207
+ repoBranch?: string;
208
+ /** Spawn-in-channel (ADR-0057 Seam 1): attach the new session to this
209
+ * channel in the same transaction — born attached, every channel member
210
+ * has derived access from birth. Requires channel role ≥ write. */
211
+ channelId?: string;
212
+ /** Boot from a saved session template (its provider snapshot resolves
213
+ * server-side — snapshot refs never cross the wire). Mutually exclusive
214
+ * with `sandboxSize`: a snapshot captures its machine spec (400). */
215
+ templateId?: string;
216
+ /** Machine size in the run `sandboxSize` vocabulary. Sessions are E2B,
217
+ * so only the E2B-buildable sizes are accepted (400 otherwise).
218
+ * Omitted = the platform default. */
219
+ sandboxSize?: SandboxSize;
220
+ /** Egress policy — the same `SandboxNetworkPolicy` allow-map runs carry
221
+ * ("deny-all" = connectors-only: the platform re-widens it with the
222
+ * drive gateway + attached connector hosts at every acquire). Omitted =
223
+ * open egress. */
224
+ networkPolicy?: SandboxNetworkPolicy;
225
+ /** Birth connector attachment (ADR-0044): one of the owner's connector
226
+ * profile ids, or "none" for a bare session. Omitted = the owner's
227
+ * default profile. */
228
+ connectorProfileId?: string;
229
+ }
230
+ export interface CloudSessionCreated {
231
+ conversation: ConversationRow;
232
+ session: {
233
+ executor: "cloud";
234
+ /** The session's type (ADR-0055 §9) — decides its ONE surface: chat
235
+ * opens the transcript TUI; terminal/custom open with
236
+ * `agentc session terminal <id>` (the PTY, no chat pane). */
237
+ type: "chat" | "terminal" | "custom";
238
+ runtime: string;
239
+ sandboxProvider: string;
240
+ /** Drive-backed working directory inside the session sandbox. */
241
+ cwd: string;
242
+ repoUrl: string | null;
243
+ repoBranch: string | null;
244
+ };
245
+ /** Present when the session was spawned in a channel (`channelId` input)
246
+ * — the channel it was born attached to. */
247
+ attachedChannelId?: string;
248
+ }
249
+ export interface ConversationThread {
250
+ root: ConversationMessageRow;
251
+ /** Oldest→newest; the root is not repeated. */
252
+ messages: ConversationMessageRow[];
253
+ }
254
+ /** One live dev preview on a cloud session (ADR-0052 §4). The directory row
255
+ * the UI lists; the security boundary is the member-gated proxy + the
256
+ * short-lived token, never this row. */
257
+ export interface SessionPreview {
258
+ id: string;
259
+ /** Port bound inside the session sandbox. */
260
+ port: number;
261
+ name: string | null;
262
+ /** The preview's stable SUBDOMAIN label — it serves fully navigable at
263
+ * `<label>.<preview wildcard host>` when the deployment configures
264
+ * `PREVIEW_WILDCARD_ORIGIN`. Null on rows opened before labels existed
265
+ * (they stay on the path-prefixed proxy URL). */
266
+ label: string | null;
267
+ /** The app's announced landing path (e.g. `/dashboard`); null = `/`. */
268
+ path: string | null;
269
+ status: "active" | "closed";
270
+ /** The member-gated preview URL, bound to the requesting viewer — the
271
+ * subdomain bootstrap URL when the deployment supports it, else the
272
+ * path-prefixed proxy URL on the isolated preview origin (ADR-0052 §2.3).
273
+ * `null` when previews are disabled or the caller is not a user. */
274
+ url: string | null;
275
+ createdAt: string;
276
+ lastSeenAt: string;
277
+ }
278
+ /** Result of opening a dev preview (`POST /conversations/:id/preview`). */
279
+ export interface PreviewOpened {
280
+ preview: SessionPreview;
281
+ /** The member-gated proxy URL to open in a browser (never the raw host). */
282
+ url: string;
283
+ }
284
+ /** Input for `openPreview`. */
285
+ export interface OpenPreviewInput {
286
+ /** Port a dev server is LISTENING on inside the session sandbox (1–65535). */
287
+ port: number;
288
+ name?: string;
289
+ /** The app's landing path (e.g. `/dashboard`) — where the preview card and
290
+ * chips land the human. Root-relative (`/…`, never `//…`). */
291
+ path?: string;
292
+ }
293
+ /** Result of forking a cloud session (`POST /conversations/:id/fork`). */
294
+ export interface SessionForked {
295
+ /** The new child conversation to switch to. */
296
+ conversationId: string;
297
+ }
298
+ /** One changed file on a session's drive branch relative to `main`. */
299
+ export interface SessionFileChange {
300
+ /** Factory-relative path. */
301
+ path: string;
302
+ kind: "add" | "modify" | "delete";
303
+ /** Size of the proposed object; null for deletes. */
304
+ sizeBytes: number | null;
305
+ /** The proposed object's etag; null for deletes. */
306
+ etag: string | null;
307
+ }
308
+ /** The session's proposed change set (`GET /conversations/:id/changes`).
309
+ * `state: "unbranched"` = the session predates branching and still writes
310
+ * `main` directly (it transitions at its next fresh sandbox acquire);
311
+ * `branch`/`changes` are null/empty then. The `label` states the freshness
312
+ * contract: the list reflects the branch's last flush and is advisory —
313
+ * the merge re-verifies against fresh state. */
314
+ export interface SessionChangeSet {
315
+ object: "session_change_set";
316
+ conversationId: string;
317
+ branch: string | null;
318
+ state: "unbranched" | "clean" | "dirty";
319
+ label: string;
320
+ /** False = the branch can only be discarded: a FORKED session's branch
321
+ * carries its parent's unmerged work with no main-derived merge base, so
322
+ * `mergeSessionChanges` 409s `fork_branch_unmergeable`. */
323
+ mergeable: boolean;
324
+ changes: SessionFileChange[];
325
+ /** True when the listing was capped — more files changed than shown. */
326
+ truncated: boolean;
327
+ /** Open `factory_file_conflicts` rows from this session's prior merges. */
328
+ openConflicts: number;
329
+ }
330
+ /** Per-file accounting of one session branch merge — the merge core's
331
+ * honest report, returned verbatim. */
332
+ export interface SessionMergeReportDetail {
333
+ branch: string | null;
334
+ merged: number;
335
+ fastForwarded: number;
336
+ autoMerged: number;
337
+ created: number;
338
+ deleted: number;
339
+ skipped: number;
340
+ untouched: number;
341
+ skippedLossy: number;
342
+ droppedPaths: string[];
343
+ conflicts: number;
344
+ }
345
+ /** Result of approving a session's changes
346
+ * (`POST /conversations/:id/changes/merge`): the old branch was 3-way
347
+ * merged into `main` and the session continues on `newBranch`, freshly
348
+ * forked off post-merge `main`. `merged_with_conflicts` means some paths
349
+ * landed as `factory_file_conflicts` rows for human resolution. */
350
+ export interface SessionMergeReport {
351
+ object: "session_merge_report";
352
+ conversationId: string;
353
+ /** The branch that was merged. */
354
+ branch: string;
355
+ /** The session's fresh branch off post-merge `main`. */
356
+ newBranch: string;
357
+ status: "merged" | "merged_with_conflicts";
358
+ report: SessionMergeReportDetail;
359
+ }
360
+ /** Result of rejecting a session's changes
361
+ * (`POST /conversations/:id/changes/discard`): the old branch is abandoned
362
+ * (retained dormant, recoverable by an admin re-merge — never deleted) and
363
+ * the session continues on `newBranch`, freshly forked off `main`. */
364
+ export interface SessionDiscardReport {
365
+ object: "session_discard_report";
366
+ conversationId: string;
367
+ /** The abandoned branch. */
368
+ branch: string;
369
+ /** The session's fresh branch off `main`. */
370
+ newBranch: string;
371
+ discarded: true;
372
+ }
373
+ /** The sender's page stamp (HUD bar sends) — persisted server-side, never
374
+ * echoed back on the wire. Mirrors the server's `PageContext` schema. */
375
+ export interface ConversationPageContext {
376
+ kind: string;
377
+ path: string;
378
+ entity?: {
379
+ type: string;
380
+ id: string;
381
+ label?: string;
382
+ };
383
+ }
384
+ export interface SendConversationMessageInput {
385
+ text: string;
386
+ /** Land the message in this ROOT message's thread (channels only; the
387
+ * triggered turn streams into the same thread). */
388
+ threadRootId?: string;
389
+ pageContext?: ConversationPageContext;
390
+ }
391
+ /** The server's authoritative turn verdict on a send (ADR-0037 §4):
392
+ * `none` = no turn owed (dm, or a channel message that doesn't @-tag the
393
+ * agent); `started` = this send won the turn claim and the reply is
394
+ * streaming; `queued` = a turn is already in flight — the message is owed
395
+ * work and a coalesced follow-up turn will answer it. NOT an error. */
396
+ export type ConversationTurnState = "none" | "started" | "queued";
397
+ export interface SendConversationMessageResult {
398
+ /** The persisted user message's id. */
399
+ messageId: string;
400
+ /** Whether an agent turn was kicked — the "replying" indicator keys off
401
+ * this, never a client-side re-parse. */
402
+ turnTriggered: boolean;
403
+ turnState: ConversationTurnState;
404
+ /** Channel sends only (ADR-0057 Seam 3): the attached sessions this
405
+ * message was relayed into via `[@Title](session:<id>)` mentions —
406
+ * each runs its own turn in its own conversation. Absent on older
407
+ * servers and non-channel sends. */
408
+ relayedSessionIds?: string[];
409
+ }
410
+ /** Response of the presence heartbeat (ADR-0037 §6): a fresh agent-liveness
411
+ * snapshot + the roster TTL. The attach roster itself is NOT returned —
412
+ * there is no server-side roster; subscribers assemble it from the
413
+ * live-only `presence` beats on the conversation stream. */
414
+ export interface ConversationPresenceSnapshot {
415
+ agent: ConversationAgentPresence | null;
416
+ /** A roster entry whose last beat is older than this has detached. */
417
+ ttlMs: number;
418
+ }
419
+ /** Durable rail status for one attached session (ADR-0057 Seam 5) — all
420
+ * derived from existing signals server-side; no background polling. */
421
+ export interface ChannelSessionStatus {
422
+ /** `running` = a turn is executing (turn claim fresh); else `idle`. */
423
+ state: "running" | "idle";
424
+ /** Viewer-scoped unread count (conversation_reads — works for derived
425
+ * viewers). 0 for key callers. */
426
+ unreadCount: number;
427
+ /** An agent ask is awaiting a human answer (bounded transcript scan). */
428
+ awaiting: boolean;
429
+ /** The most recent agent-authored message contains an error part. */
430
+ lastTurnFailed: boolean;
431
+ lastAgentMessageAt: string | null;
432
+ }
433
+ /** One session attached to a channel, as listed by
434
+ * `GET /conversations/:channelId/sessions` (newest attach first). */
435
+ export interface ChannelSessionRow {
436
+ conversationId: string;
437
+ title: string | null;
438
+ /** The hosting in-sandbox runtime (agent_sessions.agent_kind); null for
439
+ * platform-loop sessions. */
440
+ runtime: string | null;
441
+ /** The session's type (ADR-0055 §9); null for platform-loop sessions,
442
+ * absent on older servers (read loosely). */
443
+ sessionType?: "chat" | "terminal" | "custom" | null;
444
+ /** Executor substrate; null = platform-loop session (no durable
445
+ * agent_sessions row). */
446
+ executor: "local" | "cloud" | null;
447
+ attachedAt: string;
448
+ /** Who attached it (provenance only); null when the user is gone. */
449
+ addedBy: string | null;
450
+ status: ChannelSessionStatus;
451
+ }
452
+ /** Response of `GET /conversations/:channelId/sessions`, verbatim. */
453
+ export interface ChannelSessionsResponse {
454
+ sessions: ChannelSessionRow[];
455
+ }
456
+ /** Result of posting into a channel AS a session
457
+ * (`POST /conversations/:channelId/session-messages`, ADR-0057 Seam 4).
458
+ * The post never triggers any turn — it is a report, not an address. */
459
+ export interface SessionChannelMessagePosted {
460
+ messageId: string;
461
+ /** Where the post landed: the thread root it replied under (by default,
462
+ * the message that last addressed the session from that channel), or
463
+ * null for a room post. Absent on older servers. */
464
+ threadRootId?: string | null;
465
+ }
466
+ /** One agent on the team, as listed by `GET /api/v1/agents`. Bridge-runtime
467
+ * rows additionally carry live presence (`online`, from the daemon's
468
+ * heartbeat within the server's TTL) and the hosting machine's label. */
469
+ export interface AgentListRow {
470
+ id: string;
471
+ name: string;
472
+ runtime: string;
473
+ avatarSeed: string;
474
+ model: string;
475
+ systemPrompt: string | null;
476
+ factoryIds: string[];
477
+ /** Verbatim jsonb from the server — tool-policy shape is runtime-defined. */
478
+ toolPolicy: Record<string, unknown>;
479
+ createdAt: string;
480
+ online?: boolean;
481
+ machineName?: string;
482
+ /** Stamped `"cloud"` on rows whose sessions are hosted server-side —
483
+ * session pickers filter on this rather than presence. */
484
+ sessionHost?: "cloud";
485
+ }
486
+ export interface StreamConversationOptions {
487
+ /** Highest durable stream-event id already processed — the server replays
488
+ * only rows with id greater than this. Never advance it from live-only
489
+ * events (`part_partial` / `turn_state` / `presence` / `session_status`). */
490
+ lastEventId?: number;
491
+ signal?: AbortSignal;
492
+ }