pi-opencode-cli-bridge 0.2.1 → 0.2.4
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/package.json +1 -1
- package/src/index.ts +31 -1
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1009,6 +1009,9 @@ export function parseToolCallResponse(
|
|
|
1009
1009
|
text: string,
|
|
1010
1010
|
allowedToolNames?: ReadonlySet<string>,
|
|
1011
1011
|
): ToolCallParseResult {
|
|
1012
|
+
// A turn without tools (e.g. a compaction summary) cannot call any, so tool
|
|
1013
|
+
// syntax it quotes is prose.
|
|
1014
|
+
if (allowedToolNames?.size === 0) return { ok: true, calls: [] };
|
|
1012
1015
|
const normalizedText = dsmlToMarkers(normalizeQuotedToolCallResponse(text));
|
|
1013
1016
|
if (normalizedText === undefined) {
|
|
1014
1017
|
return { ok: false, rejection: { reason: "incomplete_dsml" } };
|
|
@@ -1410,6 +1413,14 @@ async function createTempAgentDir(): Promise<string> {
|
|
|
1410
1413
|
const pluginsDir = join(configDir, "plugins");
|
|
1411
1414
|
await mkdir(agentsDir, { recursive: true });
|
|
1412
1415
|
await mkdir(pluginsDir, { recursive: true });
|
|
1416
|
+
// `opencode run` streams an OpenCode compaction summary as reply text, where
|
|
1417
|
+
// its quoted markers break the turn. Pi owns compaction, so overflow must
|
|
1418
|
+
// surface as an error instead.
|
|
1419
|
+
await writeFile(
|
|
1420
|
+
join(configDir, "opencode.json"),
|
|
1421
|
+
JSON.stringify({ compaction: { auto: false } }),
|
|
1422
|
+
"utf8",
|
|
1423
|
+
);
|
|
1413
1424
|
await writeFile(
|
|
1414
1425
|
join(agentsDir, `${AGENT_ID}.md`),
|
|
1415
1426
|
`---
|
|
@@ -1704,10 +1715,29 @@ export function streamOpenCode(
|
|
|
1704
1715
|
toolCallRejectionMessage(toolCallResult, allowedToolNames),
|
|
1705
1716
|
);
|
|
1706
1717
|
}
|
|
1707
|
-
const toolCalls = [...toolCallResult.calls, ...(nativeCalls ?? [])];
|
|
1708
1718
|
// Unrecoverable marker text is stripped so it never leaks into the
|
|
1709
1719
|
// visible chat response; remaining prose still displays normally.
|
|
1710
1720
|
const displayText = toolCallResult.cleanedText ?? accumulatedText;
|
|
1721
|
+
let textCalls = toolCallResult.calls;
|
|
1722
|
+
// DeepSeek sometimes writes its only calls in the reasoning and replies
|
|
1723
|
+
// with nothing, which would end the turn silently.
|
|
1724
|
+
if (textCalls.length === 0 && !nativeCalls && !displayText.trim()) {
|
|
1725
|
+
let reasoningResult = parseToolCallResponse(
|
|
1726
|
+
accumulatedThinking,
|
|
1727
|
+
allowedToolNames,
|
|
1728
|
+
);
|
|
1729
|
+
// Markers stripped with no call surviving were meant as calls too.
|
|
1730
|
+
if (reasoningResult.ok && reasoningResult.calls.length === 0 && reasoningResult.cleanedText !== undefined) {
|
|
1731
|
+
reasoningResult = { ok: false, rejection: { reason: "malformed_markers" } };
|
|
1732
|
+
}
|
|
1733
|
+
if (!reasoningResult.ok) {
|
|
1734
|
+
throw new Error(
|
|
1735
|
+
toolCallRejectionMessage(reasoningResult, allowedToolNames),
|
|
1736
|
+
);
|
|
1737
|
+
}
|
|
1738
|
+
textCalls = reasoningResult.calls;
|
|
1739
|
+
}
|
|
1740
|
+
const toolCalls = [...textCalls, ...(nativeCalls ?? [])];
|
|
1711
1741
|
if (toolCalls.length === 0 && displayText.trim()) {
|
|
1712
1742
|
// Check if the model tried to use XML-style tool-use instead of
|
|
1713
1743
|
// <pi_tool_call> markers — a common mistake with Claude-based models.
|