@ellipsis-dev/sdk 0.27.0 → 0.30.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/README.md CHANGED
@@ -38,3 +38,28 @@ contract) is documented at https://www.ellipsis.dev/docs. The compatibility
38
38
  rule clients must follow: **ignore unknown frame types and unknown
39
39
  `source`/`record_type`/`kind` values** — additive server changes are not a
40
40
  protocol break.
41
+
42
+ ## Shared chat work sections
43
+
44
+ Web and CLI renderers can use `splitLedger(groupRecordsToChatTurns(records))`
45
+ and `entryBody(entry, { live, now, liveText, liveSummary })` from `@ellipsis-dev/sdk/store`.
46
+ `now` is epoch milliseconds. The returned `items` are the collapsed view:
47
+ one `isWorkFold(item)` section for progress, thinking and tools, with final
48
+ replies, sleep and cancellation notices kept visible. Wake milestones stay
49
+ inside the work section. `members.get(item.key)` contains
50
+ that section's rows; nested tool folds use the same map and `isToolFold`.
51
+ Renderers own expansion state and can recursively display the members.
52
+
53
+ The work key stays stable as records stream in and after replay. The live
54
+ label advances from `Waking session` to `Starting agent` to `Working` as
55
+ the platform and native turn events arrive. While the agent works, the heading
56
+ from `store.getSnapshot().liveSummary` replaces `Working` when available.
57
+ Pass the summary only to the entry being answered (`loading: true`, add a loading
58
+ indicator in the renderer). The returned `seconds` uses platform turn start
59
+ and completion timestamps, even before the first content item arrives. It is
60
+ null before a turn starts; omit the clock then. `entry.progress.phase` identifies
61
+ each message's activity independently of the latest message or session status.
62
+ The settled label is `Worked for 4m 43s`. Only the work header is loading; partial
63
+ text stays inside it. Codex message phases identify final answers; for records
64
+ without phases, the final message of a settled turn stays outside the fold.
65
+ No DOM, React, or terminal dependencies are required.
@@ -1,5 +1,5 @@
1
1
  // src/stream/index.ts
2
- var SESSION_STREAM_PROTOCOL_VERSION = 3;
2
+ var SESSION_STREAM_PROTOCOL_VERSION = 6;
3
3
  var WS_CLOSE_NORMAL = 1e3;
4
4
  var WS_CLOSE_GOING_AWAY = 1001;
5
5
  var WS_CLOSE_UNSUPPORTED_PROTOCOL_VERSION = 1002;
@@ -8,7 +8,7 @@ var WS_CLOSE_AUTH_FAILED = 1008;
8
8
  var WS_CLOSE_SERVER_ERROR = 1011;
9
9
  var WS_CLOSE_OVER_CAPACITY = 1013;
10
10
  function sessionStatusWord(session) {
11
- return session.surface?.status ?? session.status;
11
+ return session.lifecycle.status;
12
12
  }
13
13
  var StreamUnavailableError = class extends Error {
14
14
  constructor(message) {
@@ -93,6 +93,16 @@ function connectOnce(sock, emit, signal) {
93
93
  } catch {
94
94
  return;
95
95
  }
96
+ if (!frame || ![
97
+ "snapshot",
98
+ "records_append",
99
+ "session",
100
+ "delta",
101
+ "heartbeat",
102
+ "done",
103
+ "error"
104
+ ].includes(frame.type))
105
+ return;
96
106
  emit(frame);
97
107
  if (frame.type === "done") {
98
108
  finish({ kind: "done" });
@@ -140,7 +150,7 @@ async function streamSession(opts) {
140
150
  } else if (frame.type === "snapshot" || frame.type === "session") {
141
151
  const session = frame.session;
142
152
  lastStatusWord = sessionStatusWord(session);
143
- lastExitStatus = session.exit_status ?? null;
153
+ lastExitStatus = session.lifecycle.last_execution_result?.completion_reason ?? null;
144
154
  }
145
155
  opts.onFrame(frame);
146
156
  };