@poncho-ai/harness 0.38.0 → 0.39.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @poncho-ai/harness@0.38.0 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
2
+ > @poncho-ai/harness@0.39.0 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
3
3
  > node scripts/embed-docs.js && tsup src/index.ts --format esm --dts
4
4
 
5
5
  [embed-docs] Generated poncho-docs.ts with 4 topics
@@ -8,9 +8,9 @@
8
8
  CLI tsup v8.5.1
9
9
  CLI Target: es2022
10
10
  ESM Build start
11
- ESM dist/index.js 402.58 KB
11
+ ESM dist/index.js 479.07 KB
12
12
  ESM dist/isolate-TCWTUVG4.js 47.34 KB
13
- ESM ⚡️ Build success in 197ms
13
+ ESM ⚡️ Build success in 251ms
14
14
  DTS Build start
15
- DTS ⚡️ Build success in 7534ms
16
- DTS dist/index.d.ts 58.26 KB
15
+ DTS ⚡️ Build success in 8269ms
16
+ DTS dist/index.d.ts 73.95 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,201 @@
1
1
  # @poncho-ai/harness
2
2
 
3
+ ## 0.39.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#97](https://github.com/cesr/poncho-ai/pull/97) [`1eb1b1e`](https://github.com/cesr/poncho-ai/commit/1eb1b1e71641f79aa089a967811dcfe2de59be8d) Thanks [@cesr](https://github.com/cesr)! - refactor: extract subagent lifecycle into AgentOrchestrator (phase 5)
8
+
9
+ Move subagent orchestration (~1100 lines) from the CLI into the
10
+ AgentOrchestrator class in the harness package. The orchestrator now
11
+ owns all subagent state (activeSubagentRuns, pendingSubagentApprovals,
12
+ pendingCallbackNeeded), lifecycle methods (runSubagent,
13
+ processSubagentCallback, triggerParentCallback), SubagentManager
14
+ creation, approval handling, and stale recovery.
15
+
16
+ New hooks on OrchestratorHooks allow transport-specific concerns
17
+ (child harness creation, serverless dispatch, SSE stream lifecycle,
18
+ messaging notifications) to stay in the CLI while the orchestrator
19
+ handles all orchestration logic.
20
+
21
+ Also fixes subagent approval persistence (decisions now explicitly
22
+ written to the conversation store) and adds live SSE streaming for
23
+ parent callback runs in the web UI.
24
+
25
+ - [#95](https://github.com/cesr/poncho-ai/pull/95) [`21ee02a`](https://github.com/cesr/poncho-ai/commit/21ee02a577cd0a85823cc3922dd0dc54c630f417) Thanks [@cesr](https://github.com/cesr)! - perf: eliminate per-conversation archive egress on the hot read path
26
+
27
+ Three related fixes that together dramatically reduce database and
28
+ server→browser egress for any long-lived conversation:
29
+ - `conversationStore.get()` no longer loads the `tool_result_archive`
30
+ column. Callers that actually need to reseed the harness archive —
31
+ run entry points, cron runs, reminder firings — must now use the new
32
+ `conversationStore.getWithArchive()` method instead.
33
+ - The `GET /api/conversations/:id` response strips `_toolResultArchive`
34
+ alongside the already-stripped `_continuationMessages` and
35
+ `_harnessMessages`, so the browser never receives the archive payload.
36
+ - Adds a cheap `GET /api/conversations/:id/status` endpoint backed by a
37
+ new `getStatusSnapshot()` method that reads only summary columns (no
38
+ `data` blob). The web UI poll loops now hit this endpoint every 2s
39
+ and only refetch the full conversation when `updatedAt`,
40
+ `messageCount`, or the pending-approval counts actually change.
41
+
42
+ The SQL upsert was also updated to preserve `tool_result_archive` via
43
+ `COALESCE(excluded, conversations.tool_result_archive)` so that updates
44
+ on conversations loaded via the light `get()` do not clobber the
45
+ existing archive.
46
+
47
+ - [#100](https://github.com/cesr/poncho-ai/pull/100) [`ef4fe5d`](https://github.com/cesr/poncho-ai/commit/ef4fe5d1fd4bb31c201fd240f4524b64f01e3e6d) Thanks [@cesr](https://github.com/cesr)! - feat: Slack-style message threads
48
+
49
+ Users can now fork any persisted message into one or more threads. Each
50
+ thread is a new conversation whose initial history is a snapshot of the
51
+ parent up to and including the anchor message; replies in the thread
52
+ evolve independently of the parent. Multiple threads per parent message
53
+ are supported.
54
+
55
+ ## Web UI
56
+ - Hover any message in the main pane to reveal a "Reply in thread" pill
57
+ positioned just below the bubble (offset varies by role). The pill is
58
+ invisible by default and only appears on hover; a delayed-hide bridges
59
+ the empty space between message and pill so the user can move the
60
+ mouse onto it without it flickering off.
61
+ - Once a thread exists on a message, the pill is replaced by an
62
+ always-visible badge (`"N replies · 5m ago"`, count bold + meta muted).
63
+ Multiple threads stack vertically under the message, each with its own
64
+ badge. Hovering a badge reveals an outside-positioned `×` delete with
65
+ the same two-step "× → sure?" confirmation as the sidebar
66
+ conversation-delete.
67
+ - Clicking a badge opens the thread in a right-side panel that mirrors
68
+ the existing browser-panel pattern: a flex sibling of `.main-chat`
69
+ with a 1px drag-resize handle. The panel has its own composer
70
+ (independent file uploads, paste-to-attach, attachment preview)
71
+ rendered alongside the main composer so users can keep typing in the
72
+ parent conversation. Vertical padding matches the main composer so
73
+ both chatboxes line up at the same baseline.
74
+ - The pinned parent message and replies inside the panel render through
75
+ the same DOM construction logic as the main pane (assistant avatar +
76
+ markdown, user bubble + file thumbnails). Reply submissions stream
77
+ token-by-token via SSE (parsed model:chunk events feed an optimistic
78
+ assistant placeholder; a thinking-indicator shows until the first
79
+ chunk lands).
80
+ - The open thread is reflected in the URL hash (`#thread=<id>`) so a
81
+ page reload restores the panel. Switching conversations or closing
82
+ the panel clears the hash and any sticky drag-resize widths.
83
+
84
+ ## DB
85
+ - New `parent_message_id TEXT` column on `conversations` (migration 6)
86
+ plus a partial index on `(parent_conversation_id, parent_message_id)
87
+ WHERE parent_message_id IS NOT NULL`.
88
+ - The existing `parent_conversation_id` plumbing is reused; subagents
89
+ and threads coexist on that column, discriminated by whether
90
+ `parent_message_id` is set (subagents leave it `NULL`).
91
+ - `threadMeta` (snapshot length + cached parent-message summary)
92
+ round-trips inside the conversation `data` blob.
93
+
94
+ ## API
95
+ - `GET /api/conversations/:id/threads` → `{ threads: ApiThreadSummary[] }`
96
+ - `POST /api/conversations/:id/threads { parentMessageId, title? }` →
97
+ 201 `{ thread, conversationId }` |
98
+ 404 `PARENT_MESSAGE_NOT_FOUND` |
99
+ 409 `MESSAGE_ID_REQUIRED` (anchor lacks a stable id) |
100
+ 409 `ANCHOR_IN_FLIGHT` (anchor is the streaming tail of a live run)
101
+ - The two `SUBAGENT_READ_ONLY` gates on `/messages` and `/continue` are
102
+ now keyed on `subagentMeta` rather than `parentConversationId` so
103
+ threads remain writable.
104
+ - New `ApiThreadSummary`, `ApiThreadListResponse`,
105
+ `ApiCreateThreadRequest`, `ApiCreateThreadResponse` types in
106
+ `@poncho-ai/sdk`. New `AgentClient.listThreads` /
107
+ `AgentClient.createThread` wrappers in `@poncho-ai/client`.
108
+
109
+ ## Storage interface
110
+ - `ConversationStore.listThreads(parentConversationId)` and the
111
+ matching `StorageEngine.conversations.listThreads(...)`. External
112
+ implementers of these interfaces will need to add the method.
113
+ - `Conversation` / `ConversationCreateInit` / `ConversationSummary`
114
+ gained optional `parentMessageId` and `threadMeta` fields.
115
+
116
+ ## Fork semantics
117
+ - Stable `metadata.id` on every persisted message: `randomUUID()` is
118
+ hoisted once per turn and reused for both the user message and the
119
+ in-flight assistant message across all persist sites (cli messaging
120
+ run, cli `/messages` handler, cron path). `buildAssistantMetadata`
121
+ takes an optional `{ id, timestamp }` opt-arg.
122
+ - No DB backfill of legacy id-less messages; the SPA hides the
123
+ "Reply in thread" affordance on rows whose `metadata.id` is missing.
124
+ - The visible-sequence used for the anchor lookup is reconstructed as
125
+ `[...compactedHistory, ...messages.filter(notCompactionSummary)]`,
126
+ so pre-compaction anchors are supported. For pre-compaction anchors,
127
+ `_harnessMessages` is reset to `undefined` so the harness rebuilds
128
+ canonical history from `messages` on the thread's first run.
129
+ - Forking on the actively-streaming tail message of a live run returns
130
+ 409 `ANCHOR_IN_FLIGHT`; any prior, already-persisted message is
131
+ fork-able even while the parent is mid-run.
132
+ - Tool-result archive entries are filtered to only those referenced by
133
+ tool calls in the trimmed `_harnessMessages` (no whole-archive clones).
134
+ - All run-specific state is reset on the new thread:
135
+ `runtimeRunId`, `pendingApprovals`, `runStatus`,
136
+ `pendingSubagentResults`, `subagentCallbackCount`,
137
+ `runningCallbackSince`, `_continuationMessages`. `channelMeta` and
138
+ `subagentMeta` are explicitly NOT inherited so threads aren't bound
139
+ to the parent's Slack/Telegram thread and aren't subagent runs.
140
+ - Thread conversations stay out of the sidebar list (already-existing
141
+ `!c.parentConversationId` filter) and are cascade-deleted with their
142
+ parent.
143
+
144
+ ### Patch Changes
145
+
146
+ - [#100](https://github.com/cesr/poncho-ai/pull/100) [`ef4fe5d`](https://github.com/cesr/poncho-ai/commit/ef4fe5d1fd4bb31c201fd240f4524b64f01e3e6d) Thanks [@cesr](https://github.com/cesr)! - feat(logging): readable, scoped, level-aware dev server logs
147
+
148
+ `poncho dev` output is now formatted consistently across the CLI and
149
+ harness:
150
+
151
+ ```
152
+ 20:23:45 ✓ poncho dev server ready at http://localhost:3000
153
+ 20:23:45 • slack enabled at /api/messaging/slack
154
+ 20:23:45 • cron scheduled 2 jobs: hourly_check, nightly_summary
155
+ 20:24:15 → cron:hourly_check started
156
+ 20:24:17 ✓ cron:hourly_check completed in 1.2s (3 chats)
157
+ 20:25:00 ⚠ telegram approval not found: req-7f42a
158
+ 20:25:01 ✗ poncho internal error: ECONNREFUSED
159
+ ```
160
+
161
+ Format: `HH:mm:ss <symbol> <scope> <message>`. Scopes (`poncho`, `cron`,
162
+ `reminder`, `messaging`, `slack`, `telegram`, `resend`, `subagent`,
163
+ `approval`, `browser`, `csrf`, `upload`, `serverless`, `self-fetch`,
164
+ `mcp`, `telemetry`, `cost`, `model`, `harness`, `event`, `tools`)
165
+ replace the previous mix of `[poncho]`, `[poncho][cost]`, `[cron]`,
166
+ `[messaging-runner]`, `[event] ...`, etc.
167
+ - New `createLogger(scope)` exported from `@poncho-ai/sdk` with
168
+ `.debug/.info/.warn/.error/.success/.ready/.item/.child(sub)` and
169
+ helpers `formatError`, `url`, `muted`, `num`.
170
+ - Honors `NO_COLOR` / `FORCE_COLOR` and `LOG_LEVEL=debug|info|warn|error|silent`.
171
+ Verbose telemetry/cost/event lines now log at `debug` and are silent
172
+ by default.
173
+ - `poncho dev` gains `-v`/`--verbose` (debug), `-q`/`--quiet` (warn+),
174
+ and `--log-level <level>` flags.
175
+ - Each scope tag is colored with a stable pastel hue (truecolor), with
176
+ 256-color and 16-color fallbacks. Children (`cron:hourly_check`)
177
+ inherit their parent's color.
178
+ - TTY-aware: ANSI color is stripped when stdout is piped.
179
+ - Conversation-egress logging (`[poncho][egress] read: …`) is now opt-in
180
+ via `PONCHO_LOG_EGRESS=1` (matching the documented behavior; it had
181
+ been logging unconditionally).
182
+ - No behavior changes to which events are emitted — only formatting.
183
+
184
+ - [`fcf6a02`](https://github.com/cesr/poncho-ai/commit/fcf6a027880ac94ada2e3fd732b11eed9f5f15b8) Thanks [@cesr](https://github.com/cesr)! - chore: drop browser-frame noise from the dev log
185
+
186
+ Two sources of per-frame log noise during interactive browser use
187
+ are now silenced:
188
+ - `TelemetryEmitter.emit` skips `browser:frame` events alongside the
189
+ already-skipped `model:chunk`. OTLP forwarding and custom handlers
190
+ still receive every event unchanged.
191
+ - The CLI's browser SSE endpoint no longer prints the
192
+ `[poncho][browser-sse] Frame N: WxH, data bytes: ...` counter
193
+ (which fired for the first 3 frames and every 50th). Related
194
+ `frameCount` / `droppedFrames` state dropped with it.
195
+
196
+ - Updated dependencies [[`ef4fe5d`](https://github.com/cesr/poncho-ai/commit/ef4fe5d1fd4bb31c201fd240f4524b64f01e3e6d), [`ef4fe5d`](https://github.com/cesr/poncho-ai/commit/ef4fe5d1fd4bb31c201fd240f4524b64f01e3e6d)]:
197
+ - @poncho-ai/sdk@1.9.0
198
+
3
199
  ## 0.38.0
4
200
 
5
201
  ### Minor Changes