@ellipsis-dev/sdk 0.1.0 → 0.2.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.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as AgentSessionWire, L as ListSessionRecordsResponse, a as ListSessionTurnsResponse, S as SessionMessageWire } from './types-BRE4NMnS.js';
2
- export { b as AgentSessionExitStatus, c as AgentSessionPr, d as AgentSessionSource, e as AgentSessionStatus, f as AgentTurn, g as AgentTurnStatus, h as AttributionType, B as BudgetSource, D as DefaultResolution, i as DeltaFrame, j as DoneFrame, E as ErrorFrame, G as GithubAccountSnippet, k as GithubAccountType, H as Harness, l as HeartbeatFrame, M as MessagesFrame, m as ModelTokensInfo, P as ParentKind, R as RecordsAppendFrame, n as SendSessionMessageRequest, o as SessionFrame, p as SessionLiveness, q as SessionMessageStatus, r as SessionRecordWire, s as SessionState, t as SessionStreamFrame, u as SessionSurface, v as SnapshotFrame, w as StreamFrame, T as TokensInfo, x as TurnTokensInfo, y as components, z as paths } from './types-BRE4NMnS.js';
1
+ import { A as AgentSessionWire, L as ListSessionRecordsResponse, a as ListSessionTurnsResponse, S as SessionMessageWire } from './types-F94JllmC.js';
2
+ export { b as AgentSessionExitStatus, c as AgentSessionPr, d as AgentSessionSource, e as AgentSessionStatus, f as AgentTurn, g as AgentTurnStatus, h as AttributionType, B as BudgetSource, D as DefaultResolution, i as DeltaFrame, j as DoneFrame, E as ErrorFrame, G as GithubAccountSnippet, k as GithubAccountType, H as Harness, l as HeartbeatFrame, M as ModelTokensInfo, P as ParentKind, R as RecordsAppendFrame, m as SendSessionMessageRequest, n as SessionFrame, o as SessionLiveness, p as SessionMessageStatus, q as SessionRecordWire, r as SessionState, s as SessionStreamFrame, t as SessionSurface, u as SnapshotFrame, v as StreamFrame, T as TokensInfo, w as TurnTokensInfo, x as components, y as paths } from './types-F94JllmC.js';
3
3
 
4
4
  type FetchJson = (path: string, init?: {
5
5
  method?: string;
@@ -1,4 +1,4 @@
1
- import { r as SessionRecordWire, A as AgentSessionWire, S as SessionMessageWire, w as StreamFrame } from '../types-BRE4NMnS.js';
1
+ import { q as SessionRecordWire, A as AgentSessionWire, S as SessionMessageWire, v as StreamFrame } from '../types-F94JllmC.js';
2
2
 
3
3
  interface ChatToolNode {
4
4
  key: string;
@@ -8,6 +8,8 @@ interface ChatToolNode {
8
8
  summary: string;
9
9
  result: string | null;
10
10
  isError: boolean;
11
+ startedAt: string | null;
12
+ completedAt: string | null;
11
13
  }
12
14
  type ChatNode = {
13
15
  key: string;
@@ -26,7 +28,9 @@ type ChatNode = {
26
28
  kind: 'lifecycle';
27
29
  text: string;
28
30
  recordType: string;
29
- hook?: string;
31
+ step?: string;
32
+ lines?: string[];
33
+ payload?: Record<string, unknown>;
30
34
  } | ChatToolNode;
31
35
  interface ChatTurn {
32
36
  key: string;
@@ -41,8 +45,11 @@ interface ChatTurn {
41
45
  }
42
46
  declare function groupRecordsToChatTurns(records: readonly SessionRecordWire[]): ChatTurn[];
43
47
 
44
- declare function setupOutputHook(payload: Record<string, unknown>): string;
45
- declare function setupOutputLine(payload: Record<string, unknown>): string | null;
48
+ declare function sandboxOutputStep(payload: Record<string, unknown>): string;
49
+ declare function sandboxOutputLines(payload: Record<string, unknown>): string[];
50
+ declare function sandboxOutputLine(payload: Record<string, unknown>): string | null;
51
+ declare function cacheTierLabel(tier: unknown): string | null;
52
+ declare function sandboxPhaseLabel(phase: unknown): string;
46
53
  declare function lifecycleText(recordType: string, payload: Record<string, unknown>): string | null;
47
54
 
48
55
  interface CCContentBlock {
@@ -132,6 +139,7 @@ declare class SessionTranscriptStore {
132
139
  private snapshot;
133
140
  private listeners;
134
141
  private acknowledged;
142
+ private inbox;
135
143
  private cursorSeq;
136
144
  private turnsFor;
137
145
  private turnsCache;
@@ -139,7 +147,9 @@ declare class SessionTranscriptStore {
139
147
  subscribe: (listener: () => void) => (() => void);
140
148
  getSnapshot: () => SessionTranscriptSnapshot;
141
149
  chatTurns: () => ChatTurn[];
150
+ private pendingMessages;
151
+ private applyMessageRecord;
142
152
  ingest: (rawFrame: StreamFrame) => void;
143
153
  }
144
154
 
145
- export { type CCContentBlock, type CCEvent, type ChatNode, type ChatToolNode, type ChatTurn, type EventToItemsOptions, type ItemKind, LineBuffer, type SessionTranscriptSnapshot, SessionTranscriptStore, StreamFrame, type TranscriptItem, clampLines, collapseToolRuns, emptySessionTranscriptSnapshot, eventToItems, foldCosts, formatDuration, groupRecordsToChatTurns, isConnectVisibleRecord, isConversationOver, lifecycleText, oneLine, parseEventLine, pendingToolCalls, recordToItems, resultCostUsd, setupOutputHook, setupOutputLine, statusActivityText, summarizeToolInput };
155
+ export { type CCContentBlock, type CCEvent, type ChatNode, type ChatToolNode, type ChatTurn, type EventToItemsOptions, type ItemKind, LineBuffer, type SessionTranscriptSnapshot, SessionTranscriptStore, StreamFrame, type TranscriptItem, cacheTierLabel, clampLines, collapseToolRuns, emptySessionTranscriptSnapshot, eventToItems, foldCosts, formatDuration, groupRecordsToChatTurns, isConnectVisibleRecord, isConversationOver, lifecycleText, oneLine, parseEventLine, pendingToolCalls, recordToItems, resultCostUsd, sandboxOutputLine, sandboxOutputLines, sandboxOutputStep, sandboxPhaseLabel, statusActivityText, summarizeToolInput };
@@ -1,11 +1,15 @@
1
1
  // src/store/lifecycle.ts
2
- function setupOutputHook(payload) {
3
- return typeof payload.hook === "string" ? payload.hook : "setup";
2
+ function sandboxOutputStep(payload) {
3
+ if (typeof payload.step === "string" && payload.step) return payload.step;
4
+ return typeof payload.phase === "string" ? payload.phase : "setup";
4
5
  }
5
- function setupOutputLine(payload) {
6
- const lines = Array.isArray(payload.lines) ? payload.lines.filter(
6
+ function sandboxOutputLines(payload) {
7
+ return Array.isArray(payload.lines) ? payload.lines.filter(
7
8
  (l) => typeof l === "string" && l.trim().length > 0
8
9
  ) : [];
10
+ }
11
+ function sandboxOutputLine(payload) {
12
+ const lines = sandboxOutputLines(payload);
9
13
  return lines.length ? lines[lines.length - 1].trim() : null;
10
14
  }
11
15
  function cacheTierLabel(tier) {
@@ -20,13 +24,71 @@ function cacheTierLabel(tier) {
20
24
  return null;
21
25
  }
22
26
  }
27
+ function sandboxPhaseLabel(phase) {
28
+ switch (phase) {
29
+ case "image":
30
+ return "Preparing image";
31
+ case "clone":
32
+ return "Fetching repositories";
33
+ case "setup":
34
+ return "Running setup";
35
+ case "snapshot":
36
+ return "Snapshotting";
37
+ case "hooks":
38
+ return "Running hooks";
39
+ case "restore":
40
+ return "Restoring workspace";
41
+ default:
42
+ return typeof phase === "string" && phase ? phase.charAt(0).toUpperCase() + phase.slice(1) : "Working";
43
+ }
44
+ }
45
+ function durationLabel(ms) {
46
+ if (typeof ms !== "number" || !isFinite(ms) || ms < 0) return null;
47
+ return ms >= 1e3 ? `${(ms / 1e3).toFixed(1)}s` : `${Math.round(ms)}ms`;
48
+ }
49
+ function sandboxPhaseText(payload) {
50
+ const label = sandboxPhaseLabel(payload.phase);
51
+ const detail = payload.detail && typeof payload.detail === "object" ? payload.detail : {};
52
+ switch (payload.status) {
53
+ case "started":
54
+ return `${label}\u2026`;
55
+ case "completed": {
56
+ const parts = [label];
57
+ const tier = cacheTierLabel(detail.cache_tier);
58
+ if (tier) parts.push(tier);
59
+ const duration = durationLabel(payload.duration_ms);
60
+ if (duration) parts.push(duration);
61
+ return parts.join(" \xB7 ");
62
+ }
63
+ case "failed": {
64
+ const duration = durationLabel(payload.duration_ms);
65
+ return duration ? `${label} failed \xB7 ${duration}` : `${label} failed`;
66
+ }
67
+ default:
68
+ return label;
69
+ }
70
+ }
23
71
  function lifecycleText(recordType, payload) {
24
72
  switch (recordType) {
73
+ case "session_scheduled": {
74
+ const config = typeof payload.config_name === "string" ? payload.config_name : null;
75
+ return config ? `Session scheduled \xB7 ${config}` : "Session scheduled";
76
+ }
77
+ case "session_starting": {
78
+ const attempt = typeof payload.attempt === "number" ? payload.attempt : 0;
79
+ if (attempt > 0) return "Retrying\u2026";
80
+ const wakeIndex = typeof payload.wake_index === "number" ? payload.wake_index : 0;
81
+ return wakeIndex > 0 ? "Waking the session\u2026" : "Session starting\u2026";
82
+ }
83
+ case "session_retrying":
84
+ return typeof payload.reason === "string" && payload.reason ? `Retrying \xB7 ${payload.reason}` : "Retrying after a transient error\u2026";
25
85
  case "sandbox_starting":
26
86
  return "Starting sandbox\u2026";
27
- case "sandbox_setup_output": {
28
- const last = setupOutputLine(payload);
29
- return last ? `${setupOutputHook(payload)} \xB7 ${last}` : null;
87
+ case "sandbox_phase":
88
+ return sandboxPhaseText(payload);
89
+ case "sandbox_output": {
90
+ const last = sandboxOutputLine(payload);
91
+ return last ? `${sandboxOutputStep(payload)} \xB7 ${last}` : null;
30
92
  }
31
93
  case "sandbox_ready": {
32
94
  const repos = Array.isArray(payload.repositories) ? payload.repositories.filter(
@@ -40,8 +102,8 @@ function lifecycleText(recordType, payload) {
40
102
  }
41
103
  case "session_resumed":
42
104
  return "Resumed the conversation";
43
- case "session_paused":
44
- return "Sleeping \u2014 your next message wakes it";
105
+ case "session_idle":
106
+ return "Idle \u2014 your next message wakes it";
45
107
  case "session_closed":
46
108
  return "Conversation closed";
47
109
  case "session_cancelled": {
@@ -314,6 +376,12 @@ var TOOL_USE_BLOCK_TYPES = /* @__PURE__ */ new Set([
314
376
  "server_tool_use",
315
377
  "mcp_tool_use"
316
378
  ]);
379
+ var SANDBOX_RECORD_TYPES = /* @__PURE__ */ new Set([
380
+ "sandbox_starting",
381
+ "sandbox_phase",
382
+ "sandbox_output",
383
+ "sandbox_ready"
384
+ ]);
317
385
  function toolResultText2(block) {
318
386
  const c = block.content;
319
387
  if (typeof c === "string") return c.trim();
@@ -331,6 +399,7 @@ function groupRecordsToChatTurns(records) {
331
399
  let seq = 0;
332
400
  const nextKey = (base) => `${base}:${seq++}`;
333
401
  let openIdx = -1;
402
+ let prevCumulativeCostUsd = 0;
334
403
  let initCount = 0;
335
404
  let pendingResume = false;
336
405
  const openAgentTurn = (record) => {
@@ -354,36 +423,64 @@ function groupRecordsToChatTurns(records) {
354
423
  for (const record of records) {
355
424
  if (record.source === "lifecycle") {
356
425
  const text = lifecycleText(record.record_type, record.payload);
357
- if (text) {
358
- const isSetupOutput = record.record_type === "sandbox_setup_output";
359
- const hook = isSetupOutput ? setupOutputHook(record.payload) : void 0;
360
- const prev = turns.length > 0 ? turns[turns.length - 1] : null;
361
- const prevNode = prev?.nodes[0];
362
- if (isSetupOutput && prev && prevNode && prevNode.kind === "lifecycle" && prevNode.hook === hook) {
363
- prevNode.text = text;
364
- prev.completedAt = record.created_at;
365
- continue;
426
+ if (!text) continue;
427
+ const isSandbox = SANDBOX_RECORD_TYPES.has(record.record_type);
428
+ const isSandboxOutput = record.record_type === "sandbox_output";
429
+ const step = isSandboxOutput ? sandboxOutputStep(record.payload) : void 0;
430
+ const lines = isSandboxOutput ? sandboxOutputLines(record.payload) : void 0;
431
+ let foldTarget = null;
432
+ if (isSandbox && record.record_type !== "sandbox_starting") {
433
+ for (let i = turns.length - 1; i >= 0; i--) {
434
+ const candidate = turns[i];
435
+ if (candidate.role !== "lifecycle") break;
436
+ if (candidate.nodes.some(
437
+ (n) => n.kind === "lifecycle" && SANDBOX_RECORD_TYPES.has(n.recordType)
438
+ )) {
439
+ foldTarget = candidate;
440
+ break;
441
+ }
366
442
  }
367
- turns.push({
368
- key: nextKey(record.id),
369
- role: "lifecycle",
370
- nodes: [
371
- {
372
- key: nextKey(record.id),
373
- kind: "lifecycle",
374
- text,
375
- recordType: record.record_type,
376
- hook
377
- }
378
- ],
379
- startedAt: record.created_at,
380
- completedAt: record.created_at,
381
- durationMs: null,
382
- costUsd: null,
383
- tokens: null,
384
- resumed: false
385
- });
386
443
  }
444
+ if (foldTarget) {
445
+ const last = foldTarget.nodes[foldTarget.nodes.length - 1];
446
+ if (isSandboxOutput && last && last.kind === "lifecycle" && last.recordType === "sandbox_output" && last.step === step) {
447
+ last.text = text;
448
+ last.lines = [...last.lines ?? [], ...lines ?? []];
449
+ } else {
450
+ foldTarget.nodes.push({
451
+ key: nextKey(record.id),
452
+ kind: "lifecycle",
453
+ text,
454
+ recordType: record.record_type,
455
+ step,
456
+ lines,
457
+ payload: record.payload
458
+ });
459
+ }
460
+ foldTarget.completedAt = record.created_at;
461
+ continue;
462
+ }
463
+ turns.push({
464
+ key: nextKey(record.id),
465
+ role: "lifecycle",
466
+ nodes: [
467
+ {
468
+ key: nextKey(record.id),
469
+ kind: "lifecycle",
470
+ text,
471
+ recordType: record.record_type,
472
+ step,
473
+ lines,
474
+ payload: record.payload
475
+ }
476
+ ],
477
+ startedAt: record.created_at,
478
+ completedAt: record.created_at,
479
+ durationMs: null,
480
+ costUsd: null,
481
+ tokens: null,
482
+ resumed: false
483
+ });
387
484
  continue;
388
485
  }
389
486
  if (record.source !== "claude_code") continue;
@@ -399,8 +496,13 @@ function groupRecordsToChatTurns(records) {
399
496
  if (openIdx >= 0) {
400
497
  turns[openIdx].completedAt = record.created_at;
401
498
  turns[openIdx].durationMs = typeof data.duration_ms === "number" ? data.duration_ms : null;
402
- if (typeof data.total_cost_usd === "number")
403
- turns[openIdx].costUsd = data.total_cost_usd;
499
+ if (typeof data.total_cost_usd === "number") {
500
+ turns[openIdx].costUsd = Math.max(
501
+ 0,
502
+ data.total_cost_usd - prevCumulativeCostUsd
503
+ );
504
+ prevCumulativeCostUsd = data.total_cost_usd;
505
+ }
404
506
  openIdx = -1;
405
507
  }
406
508
  continue;
@@ -437,6 +539,7 @@ function groupRecordsToChatTurns(records) {
437
539
  if (node) {
438
540
  node.result = body;
439
541
  node.isError = !!block.is_error;
542
+ node.completedAt = record.created_at;
440
543
  } else {
441
544
  const orphan = {
442
545
  key: nextKey(record.id),
@@ -445,7 +548,9 @@ function groupRecordsToChatTurns(records) {
445
548
  input: null,
446
549
  summary: "",
447
550
  result: body,
448
- isError: !!block.is_error
551
+ isError: !!block.is_error,
552
+ startedAt: null,
553
+ completedAt: record.created_at
449
554
  };
450
555
  openAgentTurn(record).nodes.push(orphan);
451
556
  if (useId != null) toolNodeByUseId.set(useId, orphan);
@@ -476,7 +581,9 @@ function groupRecordsToChatTurns(records) {
476
581
  input: block.input ?? null,
477
582
  summary: summarizeToolInput(name, block.input ?? void 0),
478
583
  result: null,
479
- isError: false
584
+ isError: false,
585
+ startedAt: record.created_at,
586
+ completedAt: null
480
587
  };
481
588
  turn.nodes.push(node);
482
589
  if (block.id) toolNodeByUseId.set(block.id, node);
@@ -523,6 +630,11 @@ var SessionTranscriptStore = class {
523
630
  snapshot = EMPTY_SNAPSHOT;
524
631
  listeners = /* @__PURE__ */ new Set();
525
632
  acknowledged = /* @__PURE__ */ new Set();
633
+ // The inbox projection (protocol v3): message_received/delivered/requeued
634
+ // RECORDS drive it; the snapshot seeds the pending set at connect. Keyed by
635
+ // message id so a requeue can restore a message the delivered record
636
+ // removed from the pending view.
637
+ inbox = /* @__PURE__ */ new Map();
526
638
  // The resume cursor: the highest feed_seq received via records_append. Only
527
639
  // records advance it (§3.4) — never messages/session frames. streamSession
528
640
  // tracks its own copy; this one seeds a NEW streamSession call (e.g. a
@@ -551,6 +663,57 @@ var SessionTranscriptStore = class {
551
663
  }
552
664
  return this.turnsCache;
553
665
  };
666
+ // The current pending set, in feed order — what queued chips render.
667
+ pendingMessages = () => [...this.inbox.values()].filter((m) => m.status === "pending").sort((a, b) => (a.feed_seq ?? 0) - (b.feed_seq ?? 0));
668
+ // Fold one lifecycle record into the inbox projection; returns whether the
669
+ // pending view changed. Unknown fields/types are ignored (§3.6).
670
+ applyMessageRecord = (record) => {
671
+ const payload = record.payload;
672
+ const messageId = typeof payload.message_id === "string" ? payload.message_id : null;
673
+ switch (record.record_type) {
674
+ case "message_received": {
675
+ if (messageId == null || this.inbox.has(messageId)) return false;
676
+ this.inbox.set(messageId, {
677
+ id: messageId,
678
+ agent_session_id: record.agent_session_id,
679
+ feed_seq: record.feed_seq,
680
+ status: "pending",
681
+ body: typeof payload.body === "string" ? payload.body : "",
682
+ author: typeof payload.author === "string" ? payload.author : null,
683
+ sender_attribution_type: typeof payload.sender_attribution_type === "string" ? payload.sender_attribution_type : null,
684
+ sender_attribution_id: typeof payload.sender_attribution_id === "string" ? payload.sender_attribution_id : null,
685
+ created_at: record.created_at,
686
+ delivered_at: null,
687
+ delivered_turn_id: null
688
+ });
689
+ return true;
690
+ }
691
+ case "message_delivered": {
692
+ const existing = messageId != null ? this.inbox.get(messageId) : null;
693
+ if (!existing || existing.status !== "pending") return false;
694
+ this.inbox.set(messageId, {
695
+ ...existing,
696
+ status: "delivered",
697
+ delivered_at: record.created_at,
698
+ delivered_turn_id: typeof payload.turn_id === "string" ? payload.turn_id : null
699
+ });
700
+ return true;
701
+ }
702
+ case "message_requeued": {
703
+ const existing = messageId != null ? this.inbox.get(messageId) : null;
704
+ if (!existing || existing.status === "pending") return false;
705
+ this.inbox.set(messageId, {
706
+ ...existing,
707
+ status: "pending",
708
+ delivered_at: null,
709
+ delivered_turn_id: null
710
+ });
711
+ return true;
712
+ }
713
+ default:
714
+ return false;
715
+ }
716
+ };
554
717
  // Ingest one frame from the stream client. Unknown frame types stamp
555
718
  // liveness and change nothing else (§3.6).
556
719
  ingest = (rawFrame) => {
@@ -563,8 +726,11 @@ var SessionTranscriptStore = class {
563
726
  switch (frame.type) {
564
727
  case "snapshot": {
565
728
  next.session = frame.session;
566
- next.messages = frame.messages;
567
- for (const message of frame.messages) this.acknowledged.add(message.id);
729
+ for (const message of frame.messages) {
730
+ this.inbox.set(message.id, message);
731
+ this.acknowledged.add(message.id);
732
+ }
733
+ next.messages = this.pendingMessages();
568
734
  next.acknowledgedMessageIds = new Set(this.acknowledged);
569
735
  next.conversationOver = isConversationOver(frame.session);
570
736
  next.historyTruncated = frame.earliest_feed_seq != null && this.cursorSeq < frame.earliest_feed_seq - 1;
@@ -576,12 +742,24 @@ var SessionTranscriptStore = class {
576
742
  this.cursorSeq = fresh[fresh.length - 1].feed_seq;
577
743
  next.records = [...prev.records, ...fresh];
578
744
  let acknowledgedNew = false;
745
+ let inboxChanged = false;
579
746
  for (const record of fresh) {
580
747
  if (record.session_message_id != null) {
581
748
  this.acknowledged.add(record.session_message_id);
582
749
  acknowledgedNew = true;
583
750
  }
751
+ if (record.source === "lifecycle") {
752
+ inboxChanged = this.applyMessageRecord(record) || inboxChanged;
753
+ if (record.record_type === "message_received" || record.record_type === "message_delivered") {
754
+ const payload = record.payload;
755
+ if (typeof payload.message_id === "string") {
756
+ this.acknowledged.add(payload.message_id);
757
+ acknowledgedNew = true;
758
+ }
759
+ }
760
+ }
584
761
  }
762
+ if (inboxChanged) next.messages = this.pendingMessages();
585
763
  if (acknowledgedNew) {
586
764
  next.acknowledgedMessageIds = new Set(this.acknowledged);
587
765
  }
@@ -589,12 +767,6 @@ var SessionTranscriptStore = class {
589
767
  next.liveOutputTokens = null;
590
768
  break;
591
769
  }
592
- case "messages": {
593
- next.messages = frame.messages;
594
- for (const message of frame.messages) this.acknowledged.add(message.id);
595
- next.acknowledgedMessageIds = new Set(this.acknowledged);
596
- break;
597
- }
598
770
  case "session": {
599
771
  next.session = frame.session;
600
772
  next.conversationOver = isConversationOver(frame.session);
@@ -621,6 +793,7 @@ var SessionTranscriptStore = class {
621
793
  export {
622
794
  LineBuffer,
623
795
  SessionTranscriptStore,
796
+ cacheTierLabel,
624
797
  clampLines,
625
798
  collapseToolRuns,
626
799
  emptySessionTranscriptSnapshot,
@@ -636,8 +809,10 @@ export {
636
809
  pendingToolCalls,
637
810
  recordToItems,
638
811
  resultCostUsd,
639
- setupOutputHook,
640
- setupOutputLine,
812
+ sandboxOutputLine,
813
+ sandboxOutputLines,
814
+ sandboxOutputStep,
815
+ sandboxPhaseLabel,
641
816
  statusActivityText,
642
817
  summarizeToolInput
643
818
  };
@@ -1,6 +1,6 @@
1
- import { w as StreamFrame, A as AgentSessionWire } from '../types-BRE4NMnS.js';
1
+ import { v as StreamFrame, A as AgentSessionWire } from '../types-F94JllmC.js';
2
2
 
3
- declare const SESSION_STREAM_PROTOCOL_VERSION = 2;
3
+ declare const SESSION_STREAM_PROTOCOL_VERSION = 3;
4
4
  declare const WS_CLOSE_NORMAL = 1000;
5
5
  declare const WS_CLOSE_GOING_AWAY = 1001;
6
6
  declare const WS_CLOSE_UNSUPPORTED_PROTOCOL_VERSION = 1002;
@@ -1,5 +1,5 @@
1
1
  // src/stream/index.ts
2
- var SESSION_STREAM_PROTOCOL_VERSION = 2;
2
+ var SESSION_STREAM_PROTOCOL_VERSION = 3;
3
3
  var WS_CLOSE_NORMAL = 1e3;
4
4
  var WS_CLOSE_GOING_AWAY = 1001;
5
5
  var WS_CLOSE_UNSUPPORTED_PROTOCOL_VERSION = 1002;
@@ -876,9 +876,9 @@ interface operations {
876
876
  }
877
877
 
878
878
  /**
879
- * One server-to-client frame of the Ellipsis session stream protocol v2 (WS /v1/sessions/{id}/stream?protocol=2). Clients MUST ignore frames with unknown `type` values — additive frames are not a protocol break.
879
+ * One server-to-client frame of the Ellipsis session stream protocol v3 (WS /v1/sessions/{id}/stream?protocol=3). Clients MUST ignore frames with unknown `type` values — additive frames are not a protocol break.
880
880
  */
881
- type SessionStreamFrame = SnapshotFrame | RecordsAppendFrame | MessagesFrame | SessionFrame | DeltaFrame | HeartbeatFrame | DoneFrame | ErrorFrame;
881
+ type SessionStreamFrame = SnapshotFrame | RecordsAppendFrame | SessionFrame | DeltaFrame | HeartbeatFrame | DoneFrame | ErrorFrame;
882
882
  type AttributionType = 'github_user' | 'linear_user' | 'slack_user' | 'api_key';
883
883
  type SessionMessageStatus = 'pending' | 'delivered';
884
884
  type GithubAccountType = 'User' | 'Organization' | 'Bot' | 'Mannequin';
@@ -1123,17 +1123,6 @@ interface TurnTokensInfo {
1123
1123
  input_tokens: number;
1124
1124
  output_tokens: number;
1125
1125
  }
1126
- /**
1127
- * LWW snapshot of the OPEN inbox slice: all PENDING rows plus rows that
1128
- * flipped (delivered, re-pended) within this connection since the last frame.
1129
- * Deliberately not the full message history — delivered rows render through
1130
- * their transcript user-echo records; structural history stays on REST
1131
- * /turns (§3.3).
1132
- */
1133
- interface MessagesFrame {
1134
- messages: SessionMessageWire[];
1135
- type: 'messages';
1136
- }
1137
1126
  /**
1138
1127
  * LWW snapshot of the enriched public session (§4.1) — the only way
1139
1128
  * status/state/cost arrive. Resent whole on any field change.
@@ -1189,4 +1178,4 @@ type ListSessionTurnsResponse = components['schemas']['ListSessionTurnsResponse'
1189
1178
  type AgentTurn = components['schemas']['AgentTurn'];
1190
1179
  type AgentTurnStatus = components['schemas']['AgentTurnStatus'];
1191
1180
 
1192
- export type { AgentSessionWire as A, BudgetSource as B, DefaultResolution as D, ErrorFrame as E, GithubAccountSnippet as G, Harness as H, ListSessionRecordsResponse as L, MessagesFrame as M, ParentKind as P, RecordsAppendFrame as R, SessionMessageWire as S, TokensInfo as T, ListSessionTurnsResponse as a, AgentSessionExitStatus as b, AgentSessionPr as c, AgentSessionSource as d, AgentSessionStatus as e, AgentTurn as f, AgentTurnStatus as g, AttributionType as h, DeltaFrame as i, DoneFrame as j, GithubAccountType as k, HeartbeatFrame as l, ModelTokensInfo as m, SendSessionMessageRequest as n, SessionFrame as o, SessionLiveness as p, SessionMessageStatus as q, SessionRecordWire as r, SessionState as s, SessionStreamFrame as t, SessionSurface as u, SnapshotFrame as v, StreamFrame as w, TurnTokensInfo as x, components as y, paths as z };
1181
+ export type { AgentSessionWire as A, BudgetSource as B, DefaultResolution as D, ErrorFrame as E, GithubAccountSnippet as G, Harness as H, ListSessionRecordsResponse as L, ModelTokensInfo as M, ParentKind as P, RecordsAppendFrame as R, SessionMessageWire as S, TokensInfo as T, ListSessionTurnsResponse as a, AgentSessionExitStatus as b, AgentSessionPr as c, AgentSessionSource as d, AgentSessionStatus as e, AgentTurn as f, AgentTurnStatus as g, AttributionType as h, DeltaFrame as i, DoneFrame as j, GithubAccountType as k, HeartbeatFrame as l, SendSessionMessageRequest as m, SessionFrame as n, SessionLiveness as o, SessionMessageStatus as p, SessionRecordWire as q, SessionState as r, SessionStreamFrame as s, SessionSurface as t, SnapshotFrame as u, StreamFrame as v, TurnTokensInfo as w, components as x, paths as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ellipsis-dev/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "TypeScript SDK for the Ellipsis agents platform: /v1 REST types + client, the session stream WebSocket client, and the session transcript store.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -757,30 +757,6 @@
757
757
  "title": "HeartbeatFrame",
758
758
  "type": "object"
759
759
  },
760
- "MessagesFrame": {
761
- "description": "LWW snapshot of the OPEN inbox slice: all PENDING rows plus rows that\nflipped (delivered, re-pended) within this connection since the last frame.\nDeliberately not the full message history \u2014 delivered rows render through\ntheir transcript user-echo records; structural history stays on REST\n/turns (\u00a73.3).",
762
- "properties": {
763
- "messages": {
764
- "items": {
765
- "$ref": "#/$defs/SessionMessageWire"
766
- },
767
- "title": "Messages",
768
- "type": "array"
769
- },
770
- "type": {
771
- "const": "messages",
772
- "default": "messages",
773
- "title": "Type",
774
- "type": "string"
775
- }
776
- },
777
- "required": [
778
- "messages",
779
- "type"
780
- ],
781
- "title": "MessagesFrame",
782
- "type": "object"
783
- },
784
760
  "ModelTokensInfo": {
785
761
  "properties": {
786
762
  "cache_creation_input_tokens": {
@@ -1243,7 +1219,7 @@
1243
1219
  "type": "array"
1244
1220
  },
1245
1221
  "protocol": {
1246
- "default": 2,
1222
+ "default": 3,
1247
1223
  "title": "Protocol",
1248
1224
  "type": "integer"
1249
1225
  },
@@ -1396,7 +1372,7 @@
1396
1372
  }
1397
1373
  },
1398
1374
  "$schema": "https://json-schema.org/draft/2020-12/schema",
1399
- "description": "One server-to-client frame of the Ellipsis session stream protocol v2 (WS /v1/sessions/{id}/stream?protocol=2). Clients MUST ignore frames with unknown `type` values \u2014 additive frames are not a protocol break.",
1375
+ "description": "One server-to-client frame of the Ellipsis session stream protocol v3 (WS /v1/sessions/{id}/stream?protocol=3). Clients MUST ignore frames with unknown `type` values \u2014 additive frames are not a protocol break.",
1400
1376
  "oneOf": [
1401
1377
  {
1402
1378
  "$ref": "#/$defs/SnapshotFrame"
@@ -1404,9 +1380,6 @@
1404
1380
  {
1405
1381
  "$ref": "#/$defs/RecordsAppendFrame"
1406
1382
  },
1407
- {
1408
- "$ref": "#/$defs/MessagesFrame"
1409
- },
1410
1383
  {
1411
1384
  "$ref": "#/$defs/SessionFrame"
1412
1385
  },
@@ -0,0 +1,505 @@
1
+ {
2
+ "$defs": {
3
+ "MessageDeliveredPayload": {
4
+ "description": "message_delivered \u2014 a turn consumed the message.",
5
+ "properties": {
6
+ "message_id": {
7
+ "title": "Message Id",
8
+ "type": "string"
9
+ },
10
+ "turn_id": {
11
+ "title": "Turn Id",
12
+ "type": "string"
13
+ }
14
+ },
15
+ "required": [
16
+ "message_id",
17
+ "turn_id"
18
+ ],
19
+ "title": "MessageDeliveredPayload",
20
+ "type": "object"
21
+ },
22
+ "MessageReceivedPayload": {
23
+ "description": "message_received \u2014 a message landed in the session inbox. Puts \"what\narrived, from whom, when\" in the downloadable log; the session_messages\nrow is the internal delivery projection.",
24
+ "properties": {
25
+ "author": {
26
+ "anyOf": [
27
+ {
28
+ "type": "string"
29
+ },
30
+ {
31
+ "type": "null"
32
+ }
33
+ ],
34
+ "default": null,
35
+ "title": "Author"
36
+ },
37
+ "body": {
38
+ "title": "Body",
39
+ "type": "string"
40
+ },
41
+ "closes_session": {
42
+ "default": false,
43
+ "title": "Closes Session",
44
+ "type": "boolean"
45
+ },
46
+ "message_id": {
47
+ "title": "Message Id",
48
+ "type": "string"
49
+ },
50
+ "sender_attribution_id": {
51
+ "anyOf": [
52
+ {
53
+ "type": "string"
54
+ },
55
+ {
56
+ "type": "null"
57
+ }
58
+ ],
59
+ "default": null,
60
+ "title": "Sender Attribution Id"
61
+ },
62
+ "sender_attribution_type": {
63
+ "anyOf": [
64
+ {
65
+ "type": "string"
66
+ },
67
+ {
68
+ "type": "null"
69
+ }
70
+ ],
71
+ "default": null,
72
+ "title": "Sender Attribution Type"
73
+ }
74
+ },
75
+ "required": [
76
+ "message_id",
77
+ "body"
78
+ ],
79
+ "title": "MessageReceivedPayload",
80
+ "type": "object"
81
+ },
82
+ "MessageRequeuedPayload": {
83
+ "description": "message_requeued \u2014 an errored turn returned the message to the inbox\n(at-least-once delivery; the next wake redelivers).",
84
+ "properties": {
85
+ "message_id": {
86
+ "title": "Message Id",
87
+ "type": "string"
88
+ },
89
+ "turn_id": {
90
+ "title": "Turn Id",
91
+ "type": "string"
92
+ }
93
+ },
94
+ "required": [
95
+ "message_id",
96
+ "turn_id"
97
+ ],
98
+ "title": "MessageRequeuedPayload",
99
+ "type": "object"
100
+ },
101
+ "SandboxOutputPayload": {
102
+ "description": "sandbox_output \u2014 one chunk of provisioning/lifecycle-script output.\nMany fire per execution; `chunk` rides the idempotency key. These records\nARE the durable copy (archived into the session log's S3 segments), under\na high per-session cap + truncation marker.",
103
+ "properties": {
104
+ "chunk": {
105
+ "title": "Chunk",
106
+ "type": "integer"
107
+ },
108
+ "lines": {
109
+ "items": {
110
+ "type": "string"
111
+ },
112
+ "title": "Lines",
113
+ "type": "array"
114
+ },
115
+ "phase": {
116
+ "title": "Phase",
117
+ "type": "string"
118
+ },
119
+ "step": {
120
+ "anyOf": [
121
+ {
122
+ "type": "string"
123
+ },
124
+ {
125
+ "type": "null"
126
+ }
127
+ ],
128
+ "default": null,
129
+ "title": "Step"
130
+ },
131
+ "stream": {
132
+ "default": "stdout",
133
+ "title": "Stream",
134
+ "type": "string"
135
+ }
136
+ },
137
+ "required": [
138
+ "phase",
139
+ "chunk",
140
+ "lines"
141
+ ],
142
+ "title": "SandboxOutputPayload",
143
+ "type": "object"
144
+ },
145
+ "SandboxPhasePayload": {
146
+ "description": "sandbox_phase \u2014 one transition of the provisioning state machine, so\nclients can narrate 'found a cached image' / 'cloning' / 'snapshotting'\nlive and locate failures. Phases are an OPEN vocabulary (SandboxPhase has\nthe known values); `detail` carries phase-specific extras additively\n(e.g. {\"cache_tier\": \"incremental\"} on image completion).",
147
+ "properties": {
148
+ "detail": {
149
+ "anyOf": [
150
+ {
151
+ "additionalProperties": true,
152
+ "type": "object"
153
+ },
154
+ {
155
+ "type": "null"
156
+ }
157
+ ],
158
+ "default": null,
159
+ "title": "Detail"
160
+ },
161
+ "duration_ms": {
162
+ "anyOf": [
163
+ {
164
+ "type": "integer"
165
+ },
166
+ {
167
+ "type": "null"
168
+ }
169
+ ],
170
+ "default": null,
171
+ "title": "Duration Ms"
172
+ },
173
+ "phase": {
174
+ "title": "Phase",
175
+ "type": "string"
176
+ },
177
+ "status": {
178
+ "title": "Status",
179
+ "type": "string"
180
+ },
181
+ "step": {
182
+ "anyOf": [
183
+ {
184
+ "type": "string"
185
+ },
186
+ {
187
+ "type": "null"
188
+ }
189
+ ],
190
+ "default": null,
191
+ "title": "Step"
192
+ }
193
+ },
194
+ "required": [
195
+ "phase",
196
+ "status"
197
+ ],
198
+ "title": "SandboxPhasePayload",
199
+ "type": "object"
200
+ },
201
+ "SandboxReadyPayload": {
202
+ "description": "sandbox_ready \u2014 the box is up and the harness is about to launch: the\nsummary anchor closing the provisioning story. cache_tier/phase_timings\nduplicate the sandboxes-row columns purely for rendering convenience \u2014 the\nrow is the authority (\u00a72).",
203
+ "properties": {
204
+ "cache_tier": {
205
+ "anyOf": [
206
+ {
207
+ "type": "string"
208
+ },
209
+ {
210
+ "type": "null"
211
+ }
212
+ ],
213
+ "default": null,
214
+ "title": "Cache Tier"
215
+ },
216
+ "phase_timings": {
217
+ "additionalProperties": {
218
+ "type": "number"
219
+ },
220
+ "default": {},
221
+ "title": "Phase Timings",
222
+ "type": "object"
223
+ },
224
+ "repositories": {
225
+ "items": {
226
+ "type": "string"
227
+ },
228
+ "title": "Repositories",
229
+ "type": "array"
230
+ }
231
+ },
232
+ "required": [
233
+ "repositories"
234
+ ],
235
+ "title": "SandboxReadyPayload",
236
+ "type": "object"
237
+ },
238
+ "SandboxStartingPayload": {
239
+ "description": "sandbox_starting \u2014 provisioning begins for this execution.",
240
+ "properties": {
241
+ "repositories": {
242
+ "items": {
243
+ "type": "string"
244
+ },
245
+ "title": "Repositories",
246
+ "type": "array"
247
+ }
248
+ },
249
+ "required": [
250
+ "repositories"
251
+ ],
252
+ "title": "SandboxStartingPayload",
253
+ "type": "object"
254
+ },
255
+ "SessionCancelledPayload": {
256
+ "description": "session_cancelled \u2014 a preflight gate cancelled the session before any\nsandbox existed. Session-scoped (no execution).",
257
+ "properties": {
258
+ "reason": {
259
+ "title": "Reason",
260
+ "type": "string"
261
+ }
262
+ },
263
+ "required": [
264
+ "reason"
265
+ ],
266
+ "title": "SessionCancelledPayload",
267
+ "type": "object"
268
+ },
269
+ "SessionClosedPayload": {
270
+ "description": "session_closed \u2014 the conversation terminalized (closing event's final\nturn, or an ephemeral session's terminal).",
271
+ "properties": {},
272
+ "title": "SessionClosedPayload",
273
+ "type": "object"
274
+ },
275
+ "SessionIdlePayload": {
276
+ "description": "session_idle \u2014 the warm loop ended and the durable conversation is\nparked; the next message wakes it.",
277
+ "properties": {},
278
+ "title": "SessionIdlePayload",
279
+ "type": "object"
280
+ },
281
+ "SessionResumedPayload": {
282
+ "description": "session_resumed \u2014 a wake mounted the teardown snapshots and --resumed\nthe transcript. Its ABSENCE after a wake is the degraded-wake signal.",
283
+ "properties": {
284
+ "wake_index": {
285
+ "title": "Wake Index",
286
+ "type": "integer"
287
+ }
288
+ },
289
+ "required": [
290
+ "wake_index"
291
+ ],
292
+ "title": "SessionResumedPayload",
293
+ "type": "object"
294
+ },
295
+ "SessionRetryingPayload": {
296
+ "description": "session_retrying \u2014 a transient infra failure before the agent acted\nhanded the session back for another attempt (bounded).",
297
+ "properties": {
298
+ "attempt": {
299
+ "title": "Attempt",
300
+ "type": "integer"
301
+ },
302
+ "reason": {
303
+ "title": "Reason",
304
+ "type": "string"
305
+ }
306
+ },
307
+ "required": [
308
+ "reason",
309
+ "attempt"
310
+ ],
311
+ "title": "SessionRetryingPayload",
312
+ "type": "object"
313
+ },
314
+ "SessionScheduledPayload": {
315
+ "description": "session_scheduled \u2014 the session row exists and is queued for a worker.\nThe one session-scoped record emitted at creation (no execution yet).",
316
+ "properties": {
317
+ "config_name": {
318
+ "anyOf": [
319
+ {
320
+ "type": "string"
321
+ },
322
+ {
323
+ "type": "null"
324
+ }
325
+ ],
326
+ "default": null,
327
+ "title": "Config Name"
328
+ },
329
+ "source": {
330
+ "title": "Source",
331
+ "type": "string"
332
+ }
333
+ },
334
+ "required": [
335
+ "source"
336
+ ],
337
+ "title": "SessionScheduledPayload",
338
+ "type": "object"
339
+ },
340
+ "SessionStartingPayload": {
341
+ "description": "session_starting \u2014 a worker claimed the session and preflight passed.\nEmitted on EVERY claim; clients render wake_index > 0 as a wake.",
342
+ "properties": {
343
+ "attempt": {
344
+ "title": "Attempt",
345
+ "type": "integer"
346
+ },
347
+ "wake_index": {
348
+ "title": "Wake Index",
349
+ "type": "integer"
350
+ }
351
+ },
352
+ "required": [
353
+ "attempt",
354
+ "wake_index"
355
+ ],
356
+ "title": "SessionStartingPayload",
357
+ "type": "object"
358
+ },
359
+ "TurnCompletedPayload": {
360
+ "description": "turn_completed \u2014 the turn's result event closed it.",
361
+ "properties": {
362
+ "duration_ms": {
363
+ "anyOf": [
364
+ {
365
+ "type": "integer"
366
+ },
367
+ {
368
+ "type": "null"
369
+ }
370
+ ],
371
+ "default": null,
372
+ "title": "Duration Ms"
373
+ },
374
+ "turn_id": {
375
+ "title": "Turn Id",
376
+ "type": "string"
377
+ },
378
+ "turn_index": {
379
+ "title": "Turn Index",
380
+ "type": "integer"
381
+ }
382
+ },
383
+ "required": [
384
+ "turn_id",
385
+ "turn_index"
386
+ ],
387
+ "title": "TurnCompletedPayload",
388
+ "type": "object"
389
+ },
390
+ "TurnFailedPayload": {
391
+ "description": "turn_failed \u2014 the turn terminalized without completing (its consumed\nmessages requeue).",
392
+ "properties": {
393
+ "turn_id": {
394
+ "title": "Turn Id",
395
+ "type": "string"
396
+ },
397
+ "turn_index": {
398
+ "title": "Turn Index",
399
+ "type": "integer"
400
+ }
401
+ },
402
+ "required": [
403
+ "turn_id",
404
+ "turn_index"
405
+ ],
406
+ "title": "TurnFailedPayload",
407
+ "type": "object"
408
+ },
409
+ "TurnStartedPayload": {
410
+ "description": "turn_started \u2014 a message-exchange began.",
411
+ "properties": {
412
+ "turn_id": {
413
+ "title": "Turn Id",
414
+ "type": "string"
415
+ },
416
+ "turn_index": {
417
+ "title": "Turn Index",
418
+ "type": "integer"
419
+ }
420
+ },
421
+ "required": [
422
+ "turn_id",
423
+ "turn_index"
424
+ ],
425
+ "title": "TurnStartedPayload",
426
+ "type": "object"
427
+ }
428
+ },
429
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
430
+ "description": "Payloads of source='lifecycle' session records, keyed by record_type. Contract (SESSION_LIFECYCLE_EVENTS.md \u00a72): payload changes are additive-only; clients MUST ignore unknown record types and unknown payload fields, and MUST render unknown phase/step/status values generically.",
431
+ "properties": {
432
+ "message_delivered": {
433
+ "$ref": "#/$defs/MessageDeliveredPayload"
434
+ },
435
+ "message_received": {
436
+ "$ref": "#/$defs/MessageReceivedPayload"
437
+ },
438
+ "message_requeued": {
439
+ "$ref": "#/$defs/MessageRequeuedPayload"
440
+ },
441
+ "sandbox_output": {
442
+ "$ref": "#/$defs/SandboxOutputPayload"
443
+ },
444
+ "sandbox_phase": {
445
+ "$ref": "#/$defs/SandboxPhasePayload"
446
+ },
447
+ "sandbox_ready": {
448
+ "$ref": "#/$defs/SandboxReadyPayload"
449
+ },
450
+ "sandbox_starting": {
451
+ "$ref": "#/$defs/SandboxStartingPayload"
452
+ },
453
+ "session_cancelled": {
454
+ "$ref": "#/$defs/SessionCancelledPayload"
455
+ },
456
+ "session_closed": {
457
+ "$ref": "#/$defs/SessionClosedPayload"
458
+ },
459
+ "session_idle": {
460
+ "$ref": "#/$defs/SessionIdlePayload"
461
+ },
462
+ "session_resumed": {
463
+ "$ref": "#/$defs/SessionResumedPayload"
464
+ },
465
+ "session_retrying": {
466
+ "$ref": "#/$defs/SessionRetryingPayload"
467
+ },
468
+ "session_scheduled": {
469
+ "$ref": "#/$defs/SessionScheduledPayload"
470
+ },
471
+ "session_starting": {
472
+ "$ref": "#/$defs/SessionStartingPayload"
473
+ },
474
+ "turn_completed": {
475
+ "$ref": "#/$defs/TurnCompletedPayload"
476
+ },
477
+ "turn_failed": {
478
+ "$ref": "#/$defs/TurnFailedPayload"
479
+ },
480
+ "turn_started": {
481
+ "$ref": "#/$defs/TurnStartedPayload"
482
+ }
483
+ },
484
+ "required": [
485
+ "message_delivered",
486
+ "message_received",
487
+ "message_requeued",
488
+ "sandbox_output",
489
+ "sandbox_phase",
490
+ "sandbox_ready",
491
+ "sandbox_starting",
492
+ "session_cancelled",
493
+ "session_closed",
494
+ "session_idle",
495
+ "session_resumed",
496
+ "session_retrying",
497
+ "session_scheduled",
498
+ "session_starting",
499
+ "turn_completed",
500
+ "turn_failed",
501
+ "turn_started"
502
+ ],
503
+ "title": "LifecyclePayloads",
504
+ "type": "object"
505
+ }