pi-opencode-cli-bridge 0.2.1 → 0.2.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.ts +23 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-opencode-cli-bridge",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Bridge the OpenCode CLI into Pi Coding Agent",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
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" } };
@@ -1704,10 +1707,29 @@ export function streamOpenCode(
1704
1707
  toolCallRejectionMessage(toolCallResult, allowedToolNames),
1705
1708
  );
1706
1709
  }
1707
- const toolCalls = [...toolCallResult.calls, ...(nativeCalls ?? [])];
1708
1710
  // Unrecoverable marker text is stripped so it never leaks into the
1709
1711
  // visible chat response; remaining prose still displays normally.
1710
1712
  const displayText = toolCallResult.cleanedText ?? accumulatedText;
1713
+ let textCalls = toolCallResult.calls;
1714
+ // DeepSeek sometimes writes its only calls in the reasoning and replies
1715
+ // with nothing, which would end the turn silently.
1716
+ if (textCalls.length === 0 && !nativeCalls && !displayText.trim()) {
1717
+ let reasoningResult = parseToolCallResponse(
1718
+ accumulatedThinking,
1719
+ allowedToolNames,
1720
+ );
1721
+ // Markers stripped with no call surviving were meant as calls too.
1722
+ if (reasoningResult.ok && reasoningResult.calls.length === 0 && reasoningResult.cleanedText !== undefined) {
1723
+ reasoningResult = { ok: false, rejection: { reason: "malformed_markers" } };
1724
+ }
1725
+ if (!reasoningResult.ok) {
1726
+ throw new Error(
1727
+ toolCallRejectionMessage(reasoningResult, allowedToolNames),
1728
+ );
1729
+ }
1730
+ textCalls = reasoningResult.calls;
1731
+ }
1732
+ const toolCalls = [...textCalls, ...(nativeCalls ?? [])];
1711
1733
  if (toolCalls.length === 0 && displayText.trim()) {
1712
1734
  // Check if the model tried to use XML-style tool-use instead of
1713
1735
  // <pi_tool_call> markers — a common mistake with Claude-based models.