@bivy/bivy 0.16.24-staging.1 → 0.16.24-staging.2
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/bin/acp-shim.mjs +8 -1
- package/dist/runtime/cli-parsers.js +44 -2
- package/package.json +1 -1
package/bin/acp-shim.mjs
CHANGED
|
@@ -346,7 +346,14 @@ function onSessionUpdate(params) {
|
|
|
346
346
|
type: "tool.result",
|
|
347
347
|
toolCallId,
|
|
348
348
|
name: toolCallName(state),
|
|
349
|
-
|
|
349
|
+
// Use the ACCUMULATED content (mergeToolCallState keeps the fullest
|
|
350
|
+
// seen across the call's lifecycle), not just this terminal frame's.
|
|
351
|
+
// Agents like opencode stream a command's stdout in an earlier
|
|
352
|
+
// (in_progress) tool_call_update and leave `content` empty on the
|
|
353
|
+
// closing frame — reading only `u.content` there collapsed the result
|
|
354
|
+
// to the bare status ("completed"), dropping the real output. Prefer
|
|
355
|
+
// the terminal frame's content when it has some, else the accumulated.
|
|
356
|
+
result: textOf(u.content) || textOf(state.content) || status,
|
|
350
357
|
isError: status === "failed",
|
|
351
358
|
});
|
|
352
359
|
} else {
|
|
@@ -72,6 +72,7 @@ export function extractTokenUsage(raw) {
|
|
|
72
72
|
* persisted transcript shape matches the live-streaming shape (see protocol.ts). */
|
|
73
73
|
class TurnAccumulator {
|
|
74
74
|
toolContext;
|
|
75
|
+
inferSegmentBoundaries;
|
|
75
76
|
text = "";
|
|
76
77
|
started = false;
|
|
77
78
|
ended = false;
|
|
@@ -88,6 +89,16 @@ class TurnAccumulator {
|
|
|
88
89
|
// already sealed into `content` as its own block.
|
|
89
90
|
content = [];
|
|
90
91
|
textFlushed = "";
|
|
92
|
+
// A tool call interrupts the assistant's prose/reasoning: the text that
|
|
93
|
+
// resumes after it is a NEW message segment, not a continuation of the last
|
|
94
|
+
// token. Without a separator the two run together ("…what it does.The next…",
|
|
95
|
+
// "…shell commandI have…") — exactly the seam the governed ProtocolRuntime
|
|
96
|
+
// guards with its `assistantItemBoundary` \n\n insertion. Mirror that here so
|
|
97
|
+
// every CliParser agent (Grok, Goose, Gemini, the generic streams) gets the
|
|
98
|
+
// same clean paragraph break instead of a concatenated blob. Tracked per
|
|
99
|
+
// stream because text and reasoning accumulate into separate buffers.
|
|
100
|
+
pendingTextBoundary = false;
|
|
101
|
+
pendingReasoningBoundary = false;
|
|
91
102
|
out = [];
|
|
92
103
|
details = new Map();
|
|
93
104
|
// Not every CLI includes a stable id on both halves of a tool exchange.
|
|
@@ -102,8 +113,15 @@ class TurnAccumulator {
|
|
|
102
113
|
if (pending)
|
|
103
114
|
this.content.push({ type: "text", text: pending });
|
|
104
115
|
}
|
|
105
|
-
constructor(toolContext
|
|
116
|
+
constructor(toolContext,
|
|
117
|
+
// Native CLI streams (Grok, Goose, Claude/Codex JSON, …) start a fresh
|
|
118
|
+
// prose/reasoning segment after each tool call without re-emitting a
|
|
119
|
+
// separator, so we infer the paragraph break. The bivy-agent-protocol path
|
|
120
|
+
// instead carries continuation faithfully (a shim can emit an explicit
|
|
121
|
+
// boundary when it wants one), so it opts out.
|
|
122
|
+
inferSegmentBoundaries = true) {
|
|
106
123
|
this.toolContext = toolContext;
|
|
124
|
+
this.inferSegmentBoundaries = inferSegmentBoundaries;
|
|
107
125
|
}
|
|
108
126
|
ensureStart(events) {
|
|
109
127
|
if (!this.started) {
|
|
@@ -121,6 +139,9 @@ class TurnAccumulator {
|
|
|
121
139
|
appendReasoning(text, events) {
|
|
122
140
|
if (!text)
|
|
123
141
|
return;
|
|
142
|
+
if (this.pendingReasoningBoundary && this.reasoning)
|
|
143
|
+
this.reasoning += "\n\n";
|
|
144
|
+
this.pendingReasoningBoundary = false;
|
|
124
145
|
this.reasoning += text;
|
|
125
146
|
events.push({ type: "message_update", message: { role: "assistant", content: [{ type: "thinking", thinking: this.reasoning }] } });
|
|
126
147
|
}
|
|
@@ -133,6 +154,18 @@ class TurnAccumulator {
|
|
|
133
154
|
if (!text)
|
|
134
155
|
return;
|
|
135
156
|
this.ensureStart(events);
|
|
157
|
+
if (this.pendingTextBoundary && this.text) {
|
|
158
|
+
// Advance the sealed prefix over the display-only separator when the prior
|
|
159
|
+
// segment was already flushed to a content block, so the next persisted
|
|
160
|
+
// block holds `Second message`, not `\n\nSecond message` (matching
|
|
161
|
+
// ProtocolRuntime). The cumulative `text` still carries the break for the
|
|
162
|
+
// live stream and the final answer.
|
|
163
|
+
const wasFullyFlushed = this.textFlushed === this.text;
|
|
164
|
+
this.text += "\n\n";
|
|
165
|
+
if (wasFullyFlushed)
|
|
166
|
+
this.textFlushed = this.text;
|
|
167
|
+
}
|
|
168
|
+
this.pendingTextBoundary = false;
|
|
136
169
|
this.text += text;
|
|
137
170
|
events.push({ type: "message_update", message: { role: "assistant", content: this.text } });
|
|
138
171
|
}
|
|
@@ -147,6 +180,12 @@ class TurnAccumulator {
|
|
|
147
180
|
if (detail)
|
|
148
181
|
this.details.set(callId, detail);
|
|
149
182
|
this.flushPendingText();
|
|
183
|
+
// Prose/reasoning that resumes after this call is a fresh segment — arm the
|
|
184
|
+
// boundary so the next appendText/appendReasoning inserts a separator.
|
|
185
|
+
if (this.inferSegmentBoundaries) {
|
|
186
|
+
this.pendingTextBoundary = true;
|
|
187
|
+
this.pendingReasoningBoundary = true;
|
|
188
|
+
}
|
|
150
189
|
this.content.push({ type: "tool_use", id: callId, name, input: input ?? {}, ...(detail ? { detail } : {}) });
|
|
151
190
|
events.push({ type: "tool_call", toolName: name, input, toolCallId: callId, ...(detail ? { detail } : {}) });
|
|
152
191
|
}
|
|
@@ -198,7 +237,10 @@ class TurnAccumulator {
|
|
|
198
237
|
}
|
|
199
238
|
/** Parser for the bivy-agent-protocol JSONL event vocabulary (the universal path). */
|
|
200
239
|
export function bivyProtocolParser() {
|
|
201
|
-
|
|
240
|
+
// The universal protocol carries continuation faithfully: text after a tool is
|
|
241
|
+
// appended verbatim (a shim emits an explicit break when it wants one), so it
|
|
242
|
+
// opts out of inferred segment boundaries.
|
|
243
|
+
const acc = new TurnAccumulator({ provider: "bivy-protocol", protocol: "protocol" }, false);
|
|
202
244
|
return {
|
|
203
245
|
onLine(line) {
|
|
204
246
|
const events = [];
|
package/package.json
CHANGED