Skip to content

Commit f40dda2

Browse files
committed
fix(providers/opencode): address code review findings
- Add CHANGELOG.md entry for assistants.opencode provider (#1703) - Elevate silent debug catches to warn level with context (session, multi-agent, runtime) - Preserve error cause chain in retry loop (provider.ts) - Include retry count in final throw message - Fix doc typo: cofnig -> config - Update CLAUDE.md monorepo layout with community/opencode/
1 parent 9c4143e commit f40dda2

7 files changed

Lines changed: 13 additions & 14 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- **`assistants.opencode` provider**: community provider that runs OpenCode as an embedded runtime, with per-node agent materialization, multi-agent sessions, structured output, token usage, and multi-agent MCP tool execution (#1703).
1213
- MCP server support for Codex workflow nodes via the shared `loadMcpConfig` module — pass `mcp: <path>` on a Codex node and the config is translated to Codex's `mcp_servers` overrides at runtime. MCP client errors are surfaced to the workflow author as `system` chunks when MCP is explicitly configured for the node (#1459).
1314

1415
## [0.3.12] - 2026-05-14

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ packages/
285285
│ ├── claude/ # ClaudeProvider + parseClaudeConfig + MCP/hooks/skills translation
286286
│ ├── codex/ # CodexProvider + parseCodexConfig + binary-resolver
287287
│ ├── community/pi/ # PiProvider (builtIn: false) — @mariozechner/pi-coding-agent, ~20 LLM backends
288+
│ ├── community/opencode/ # OpenCodeProvider (builtIn: false) — @archon/opencode SDK, local embedded runtime
288289
│ └── index.ts # Package exports
289290
├── core/ # @archon/core - Shared business logic
290291
│ └── src/

packages/docs-web/src/content/docs/getting-started/ai-assistants.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ assistants:
286286
| Tool restrictions | ✅ | `tools` / `disallowedTools` per agent; deny wins over allow |
287287
| Inline agents (`agents:`) | ✅ | File-materialized agents; single and parallel multi-agent fan-out |
288288
| Hooks | ✅ | Plugin hook system (tool, session, message hooks) |
289-
| Effort / reasoning control | ❌ | No per-request param; not configurable in agent file, opencode put it in cofnig file. |
289+
| Effort / reasoning control | ❌ | No per-request param; not configurable in agent file, opencode puts it in config. |
290290
| Thinking control | ❌ | No explicit `thinking` field in agent frontmatter; OpenCode auto-enables reasoning when `agents[].model` is a reasoning-capable model (e.g. `anthropic/claude-sonnet-4-5`) |
291291
| Fallback model | ❌ | No native failover in the SDK |
292292
| Sandbox | ❌ | Not native in the SDK; Archon uses worktree isolation |

packages/providers/src/community/opencode/multi-agent.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,7 @@ async function readStructuredOutput(
5555
return info.structured_output;
5656
}
5757
} catch (error) {
58-
getLog().debug(
59-
{ err: error, sessionId, messageId },
60-
'opencode.structured_output_lookup_failed'
61-
);
58+
getLog().warn({ err: error, sessionId, messageId }, 'opencode.structured_output_lookup_failed');
6259
}
6360
return undefined;
6461
}

packages/providers/src/community/opencode/provider.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,13 +199,16 @@ export class OpencodeProvider implements IAgentProvider {
199199
const delayMs = this.retryBaseDelayMs * 2 ** attempt;
200200
getLog().info({ attempt, delayMs, errorClass }, 'opencode.retrying_query');
201201
await delay(delayMs);
202+
if (lastError) {
203+
enrichedError.cause = lastError;
204+
}
202205
lastError = enrichedError;
203206
} finally {
204207
runtime.release();
205208
}
206209
}
207210

208-
throw lastError ?? new Error('OpenCode query failed after retries');
211+
throw lastError ?? new Error(`OpenCode query failed after ${MAX_RETRIES} retries`);
209212
}
210213

211214
getType(): string {

packages/providers/src/community/opencode/runtime.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ function killProcess(pid: number): void {
123123
process.kill(pid, 'SIGKILL');
124124
}
125125
} catch (error) {
126-
getLog().debug({ err: error, pid }, 'opencode.process_kill_failed');
126+
getLog().warn({ err: error, pid }, 'opencode.process_kill_failed');
127127
}
128128
}
129129

@@ -270,7 +270,7 @@ export async function disposeInstanceForDirectory(
270270
try {
271271
await client.instance.dispose({ query: { directory } });
272272
} catch (error) {
273-
getLog().debug(
273+
getLog().warn(
274274
{
275275
err: error,
276276
directory,

packages/providers/src/community/opencode/session.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ export async function resolveSessionId(
3838
if (typeof sessionId === 'string' && sessionId.length > 0) {
3939
return { sessionId, resumed: true };
4040
}
41-
} catch {
42-
// Fall through to fresh session creation and surface a warning upstream.
41+
} catch (error) {
42+
getLog().warn({ err: error, resumeSessionId, cwd }, 'opencode.session_resume_failed');
4343
}
4444
}
4545

@@ -110,10 +110,7 @@ async function readStructuredOutput(
110110
return info.structured_output;
111111
}
112112
} catch (error) {
113-
getLog().debug(
114-
{ err: error, sessionId, messageId },
115-
'opencode.structured_output_lookup_failed'
116-
);
113+
getLog().warn({ err: error, sessionId, messageId }, 'opencode.structured_output_lookup_failed');
117114
}
118115

119116
return undefined;

0 commit comments

Comments
 (0)