@bivy/bivy 0.16.21 → 0.16.22-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.
|
@@ -623,12 +623,51 @@ function textFromStreamEvent(msg) {
|
|
|
623
623
|
}
|
|
624
624
|
return "";
|
|
625
625
|
}
|
|
626
|
-
/**
|
|
627
|
-
* ACP
|
|
628
|
-
*
|
|
626
|
+
/** Flatten an ACP `ContentBlock[]` (or a single block/string) to plain text.
|
|
627
|
+
* ACP tool updates carry their human-readable output as content blocks —
|
|
628
|
+
* `[{type:"content", content:{type:"text", text}}]` or `[{type:"text", text}]` —
|
|
629
|
+
* which is the display-normalized form to prefer over a raw byte dump. Returns
|
|
630
|
+
* undefined when there is no usable text (so callers fall back to rawOutput). */
|
|
631
|
+
function flattenAcpContent(value) {
|
|
632
|
+
const walk = (v) => {
|
|
633
|
+
if (typeof v === "string")
|
|
634
|
+
return v;
|
|
635
|
+
if (Array.isArray(v))
|
|
636
|
+
return v.map(walk).join("");
|
|
637
|
+
if (v && typeof v === "object") {
|
|
638
|
+
const o = v;
|
|
639
|
+
if (typeof o.text === "string")
|
|
640
|
+
return o.text;
|
|
641
|
+
if (o.content !== undefined)
|
|
642
|
+
return walk(o.content);
|
|
643
|
+
}
|
|
644
|
+
return "";
|
|
645
|
+
};
|
|
646
|
+
const text = walk(value);
|
|
647
|
+
return text.trim() ? text : undefined;
|
|
648
|
+
}
|
|
649
|
+
/** Extract a numeric exit code from a raw tool-output object, if present. */
|
|
650
|
+
function rawExitCode(raw) {
|
|
651
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
652
|
+
return undefined;
|
|
653
|
+
const o = raw;
|
|
654
|
+
const exit = o.exit_code ?? o.exitCode ?? o.code;
|
|
655
|
+
return typeof exit === "number" ? exit : undefined;
|
|
656
|
+
}
|
|
657
|
+
/** Extract an ACP-style tool update. Two transports converge here:
|
|
658
|
+
* 1. A JSON-RPC `session/update` notification (`params.update`), the true ACP
|
|
659
|
+
* wire form used by Gemini/Qwen/Copilot etc.
|
|
660
|
+
* 2. A TOP-LEVEL tool frame (`{type:"tool_call", toolCallId, toolName,
|
|
661
|
+
* rawInput}` / `{type:"tool_call_update", …, rawOutput}`) — the shape the
|
|
662
|
+
* Grok CLI's `--output-format streaming-json` emits without the JSON-RPC
|
|
663
|
+
* envelope. Both name the same fields, so one mapper renders both as the
|
|
664
|
+
* same tool cards (no per-agent branch). */
|
|
629
665
|
function acpToolUpdate(msg) {
|
|
630
666
|
const params = msg.params;
|
|
631
|
-
|
|
667
|
+
// Fall back to the message itself so a top-level tool frame (Grok) is read the
|
|
668
|
+
// same way as a nested `session/update` (canonical ACP). A non-tool top-level
|
|
669
|
+
// frame has no toolCallId and is rejected by the `id` guard below.
|
|
670
|
+
const update = (params?.update ?? msg.update ?? msg);
|
|
632
671
|
if (!update || typeof update !== "object")
|
|
633
672
|
return undefined;
|
|
634
673
|
const type = String(update.sessionUpdate ?? update.type ?? "").toLowerCase();
|
|
@@ -636,15 +675,27 @@ function acpToolUpdate(msg) {
|
|
|
636
675
|
if (!id)
|
|
637
676
|
return undefined;
|
|
638
677
|
if (type === "tool_call" || type === "tool_call_started" || type === "tool_call_start") {
|
|
639
|
-
return { kind: "call", id, name: String(update.title ?? update.name ?? "tool"), input: update.rawInput ?? update.input ?? update.arguments };
|
|
678
|
+
return { kind: "call", id, name: String(update.title ?? update.toolName ?? update.name ?? "tool"), input: update.rawInput ?? update.input ?? update.arguments };
|
|
640
679
|
}
|
|
641
680
|
if (type === "tool_call_update" || type === "tool_result" || type === "tool_call_completed") {
|
|
642
681
|
const status = String(update.status ?? "").toLowerCase();
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
const
|
|
646
|
-
|
|
682
|
+
const terminal = status === "completed" || status === "complete" || status === "success" || status === "done" || status === "failed" || status === "error";
|
|
683
|
+
const hasStatus = update.status !== undefined && update.status !== null && String(update.status).trim() !== "";
|
|
684
|
+
const raw = update.rawOutput ?? update.output ?? update.result;
|
|
685
|
+
// A CLI that streams progress (Grok) tags every frame with a non-terminal
|
|
686
|
+
// status and a partial payload — only a terminal status closes the card. A
|
|
687
|
+
// CLI that sends a single result frame with no status closes as soon as a
|
|
688
|
+
// payload lands. This prevents both a premature close and a duplicate card.
|
|
689
|
+
if (type === "tool_call_update" && (hasStatus ? !terminal : raw === undefined))
|
|
647
690
|
return undefined;
|
|
691
|
+
// Prefer the display-normalized ACP content text over a raw payload (Grok's
|
|
692
|
+
// rawOutput.output is a byte array that would render as garbage). Preserve
|
|
693
|
+
// the exit code from the raw payload when we take the content text instead.
|
|
694
|
+
const contentText = flattenAcpContent(update.content);
|
|
695
|
+
const exit = rawExitCode(raw);
|
|
696
|
+
const output = contentText !== undefined
|
|
697
|
+
? (exit !== undefined ? { content: contentText, exit_code: exit } : contentText)
|
|
698
|
+
: (raw ?? update.content);
|
|
648
699
|
return { kind: "result", id, output, error: status === "failed" || status === "error" };
|
|
649
700
|
}
|
|
650
701
|
return undefined;
|
|
@@ -78,13 +78,14 @@ function str(o, ...keys) {
|
|
|
78
78
|
}
|
|
79
79
|
const SHELL = new Set([
|
|
80
80
|
"bash", "sh", "shell", "run", "runcommand", "command", "commandexecution",
|
|
81
|
-
"exec", "execute", "executecommand", "terminal", "runterminalcmd",
|
|
81
|
+
"exec", "execute", "executecommand", "terminal", "runterminalcmd",
|
|
82
|
+
"runterminalcommand", "localshell",
|
|
82
83
|
]);
|
|
83
84
|
const READ = new Set(["read", "readfile", "view", "viewfile", "cat", "openfile", "fileread"]);
|
|
84
85
|
const WRITE = new Set(["write", "writefile", "create", "createfile", "newfile", "filewrite", "savefile"]);
|
|
85
86
|
const EDIT = new Set([
|
|
86
87
|
"edit", "editfile", "multiedit", "strreplace", "strreplaceeditor", "replace",
|
|
87
|
-
"applypatch", "patch", "filechange", "filechanges", "update", "modify",
|
|
88
|
+
"searchreplace", "applypatch", "patch", "filechange", "filechanges", "update", "modify",
|
|
88
89
|
]);
|
|
89
90
|
const SEARCH = new Set(["search", "grep", "glob", "ripgrep", "rg", "find", "findfiles", "codebasesearch", "filesearch"]);
|
|
90
91
|
const FETCH = new Set(["fetch", "webfetch", "httpfetch", "geturl", "browse", "curl", "openurl"]);
|
|
@@ -96,7 +97,8 @@ const PLAN = new Set(["plan", "updateplan", "setplan", "todo", "todowrite", "exi
|
|
|
96
97
|
// still falls through to the opaque default, never a false "Delegated".
|
|
97
98
|
const DELEGATE = new Set([
|
|
98
99
|
"task", "agent", "subagent", "runagent", "runsubagent", "spawnagent",
|
|
99
|
-
"dispatchagent", "delegate", "delegatetask", "agenttask",
|
|
100
|
+
"spawnsubagent", "dispatchagent", "delegate", "delegatetask", "agenttask",
|
|
101
|
+
"startagent", "startrun",
|
|
100
102
|
// Codex app-server 0.147+ first-class child lifecycle item.
|
|
101
103
|
"subagentactivity",
|
|
102
104
|
]);
|