@particle-academy/prism-acp 0.5.1 → 0.5.3

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
@@ -97,6 +97,12 @@ non-credentials alike. If the child needs an orchestrator session or terminal
97
97
  id, a callback URL, or a feature flag, name it in `allowEnv` or it will not
98
98
  arrive. This failure is silent: the child can start and appear healthy while
99
99
  being unable to identify itself, rather than reporting a missing variable.
100
+ An allowed variable whose parent value is `''` is forwarded as an empty string.
101
+ That can be worse than omitting it: a referenced-but-unset value in an MCP
102
+ config can stop every server in that file. When there is no value to give,
103
+ omit the variable instead of passing its name with a blank value. `childEnv`
104
+ does not filter blanks for you, because an intentionally empty value can be
105
+ meaningful for some variable names and the package will not guess which.
100
106
 
101
107
  Nothing here mutates `process.env`. A workspace may hold an API key on purpose —
102
108
  other consumers beside this one legitimately bill per token — so the child's
@@ -161,6 +167,19 @@ drivers because their measured resume behavior differs. Codex thread ids are
161
167
  the provider's own captured ids and are the same ids accepted by its resume
162
168
  method; ACP-minted ids are refused.
163
169
 
170
+ The human half of the conversation differs too. Against a real Claude child,
171
+ the CLI did not echo the client's prompt as `user_message_chunk`, and loading
172
+ its session replayed zero updates. A Claude client cannot reconstruct the whole
173
+ conversation from ACP alone; record the human turn yourself. Codex's mapping
174
+ does emit text from `userMessage` items as `user_message_chunk` during history
175
+ replay, so a Codex `session/load` will carry that human text. Measured against a
176
+ real Codex child, a live turn reports the user's text as one
177
+ `user_message_chunk`. Releases 0.5.2 and earlier emitted it twice because our
178
+ mapper handled both `item/started` and `item/completed`; client-side
179
+ deduplication added for that behavior is no longer needed. Record the human
180
+ turn yourself for both providers, and treat a live `user_message_chunk` as the
181
+ agent's record of what it received, not as new input to append again.
182
+
164
183
  ### Refusing an unknown id at load, not a turn later
165
184
 
166
185
  Pass `probeSession` and an id naming **no** conversation is refused by
@@ -304,6 +323,14 @@ A client then speaks ACP on those pipes. Several sessions run at once, each with
304
323
  its own agent process, its own in-flight turn and its own updates — tagged with
305
324
  the session they belong to, because a room of agents shares one stream.
306
325
 
326
+ ### Commit streamed messages at the turn boundary
327
+
328
+ `agent_message_chunk` and `agent_thought_chunk` carry no message id. The turn
329
+ boundary is the only delimiter between replies, so commit the accumulated
330
+ message there. Clearing the in-flight message without committing loses the
331
+ reply (including the whole reply in a single-message turn); not clearing it
332
+ appends the next turn to the previous one.
333
+
307
334
  ## Development
308
335
 
309
336
  ```sh
@@ -474,11 +474,13 @@ export class CodexDriver {
474
474
  this.#recordUnmapped('completed Codex item had an unknown status', item);
475
475
  }
476
476
  if (type === 'userMessage') {
477
- const text = textFromContent(item.content);
478
- if (text.length > 0)
479
- this.#emit({ sessionUpdate: 'user_message_chunk', content: { type: 'text', text } });
480
- else
481
- this.#recordUnmapped('Codex userMessage had no text content', item);
477
+ if (replay || completed) {
478
+ const text = textFromContent(item.content);
479
+ if (text.length > 0)
480
+ this.#emit({ sessionUpdate: 'user_message_chunk', content: { type: 'text', text } });
481
+ else
482
+ this.#recordUnmapped('Codex userMessage had no text content', item);
483
+ }
482
484
  return;
483
485
  }
484
486
  if (type === 'agentMessage') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@particle-academy/prism-acp",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "Speak the Agent Client Protocol to a coding-agent CLI the user has already authenticated. No API key, no third-party adapter.",
5
5
  "license": "MIT",
6
6
  "repository": {