Skip to content

feat(call-omo-agent): support custom agents via dynamic resolution#2299

Merged
code-yeongyu merged 12 commits into
code-yeongyu:devfrom
brandonwebb-vista:feat/dynamic-custom-agent-support
Apr 15, 2026
Merged

feat(call-omo-agent): support custom agents via dynamic resolution#2299
code-yeongyu merged 12 commits into
code-yeongyu:devfrom
brandonwebb-vista:feat/dynamic-custom-agent-support

Conversation

@brandonwebb-vista

@brandonwebb-vista brandonwebb-vista commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Replace the hardcoded ALLOWED_AGENTS whitelist validation in call_omo_agent with dynamic agent resolution via client.app.agents(), and extend the agent loader to discover agents from all configuration paths.

Closes #1706

Changes

Dynamic Agent Resolution (call-omo-agent)

  • agent-resolver.ts: New resolveCallableAgents() queries registered agents at execute-time and merges them with ALLOWED_AGENTS (built-in agents are always callable, never dropped)
  • tools.ts: Validate subagent_type against the dynamic set; fixed subagent_type parameter description
  • constants.ts: Updated description to be path-agnostic (covers all loader paths, not just ~/.claude/agents/)
  • tools.test.ts: 18 tests covering dynamic resolution, merge behavior, fallback, and validation

Agent Loader Extension (claude-code-agent-loader)

  • loader.ts: Added loadOpencodeGlobalAgents() (~/.config/opencode/agents/) and loadOpencodeProjectAgents() (<cwd>/.opencode/agents/)
  • types.ts: Extended AgentScope with "opencode" and "opencode-project"
  • loader.test.ts: 15 tests covering YAML/MD parsing, tool extraction, scope assignment, and env-var paths

Agent Config Handler Wiring (agent-config-handler.ts)

  • Calls all 4 loaders: user, project, opencode-global, opencode-project
  • OpenCode loaders run unconditionally (not gated by claude_code.agents config flag)
  • Merge priority: opencode-project > opencode-global > user > project > plugin

Test Results

  • bun test src/tools/call-omo-agent/: 18 pass, 0 fail
  • bun test src/features/claude-code-agent-loader/: 15 pass, 0 fail
  • bun run typecheck: clean
  • Full suite: 3540 pass, 5 fail (all 5 are pre-existing failures in unrelated files)

Agent Discovery Paths (after this PR)

Path Scope Loader
~/.claude/agents/ user loadUserAgents()
<cwd>/.claude/agents/ project loadProjectAgents()
~/.config/opencode/agents/ opencode loadOpencodeGlobalAgents()
<cwd>/.opencode/agents/ opencode-project loadOpencodeProjectAgents()

@github-actions

github-actions Bot commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA. Thank you! ✅
Posted by the CLA Assistant Lite bot.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 4 files

Confidence score: 2/5

  • There is a high-confidence compatibility bug in src/tools/call-omo-agent/constants.ts: agent directories point to .claude/agents/ instead of Opencode paths (~/.config/opencode/agents/ and .opencode/agents/), which can prevent custom agents from being discovered at runtime.
  • src/tools/call-omo-agent/tools.ts also documents the wrong directories with high confidence, increasing the chance users configure the feature incorrectly and experience failures even if code paths are corrected elsewhere.
  • The subagent_type wording in src/tools/call-omo-agent/tools.ts is lower-confidence and lower-severity, but it still conflicts with dynamic agent resolution and may mislead usage.
  • Pay close attention to src/tools/call-omo-agent/constants.ts and src/tools/call-omo-agent/tools.ts - directory path compatibility and related guidance need to be aligned with Opencode behavior.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/tools/call-omo-agent/tools.ts">

<violation number="1" location="src/tools/call-omo-agent/tools.ts:19">
P2: Custom agent: **Opencode Compatibility**

The documentation incorrectly references Claude Code's agent directories (`~/.claude/agents/` and `.claude/agents/`) instead of Opencode's agent directories. According to the Opencode documentation, custom agents are loaded from `~/.config/opencode/agents/` and `.opencode/agents/`.</violation>

<violation number="2" location="src/tools/call-omo-agent/tools.ts:51">
P2: `subagent_type` description still claims "explore or librarian only" even though agents are now dynamically resolved; this contradicts the new capability and can mislead tool usage.</violation>
</file>

<file name="src/tools/call-omo-agent/constants.ts">

<violation number="1" location="src/tools/call-omo-agent/constants.ts:16">
P1: Custom agent: **Opencode Compatibility**

Incorrect agent directory paths. OpenCode loads custom agents from `~/.config/opencode/agents/` and `.opencode/agents/`, not `.claude/agents/`.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Add one-off context when rerunning by tagging @cubic-dev-ai with guidance or docs links (including llms.txt)
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/tools/call-omo-agent/constants.ts Outdated
Comment thread src/tools/call-omo-agent/tools.ts
Comment thread src/tools/call-omo-agent/tools.ts Outdated
@brandonwebb-vista

Copy link
Copy Markdown
Contributor Author

I have read the CLA Document and I hereby sign the CLA

github-actions Bot added a commit that referenced this pull request Mar 4, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 18 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/plugin-handlers/agent-config-handler.ts">

<violation number="1" location="src/plugin-handlers/agent-config-handler.ts:209">
P2: Global agents overwrite project-level agents due to incorrect spread order. Project-level configuration should take precedence over global configuration, but the current order means global agents overwrite project agents.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/plugin-handlers/agent-config-handler.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/plugin-handlers/agent-config-handler.ts">

<violation number="1" location="src/plugin-handlers/agent-config-handler.ts:209">
P1: Custom agent: **Opencode Compatibility**

The configuration merge priority violates OpenCode's standard configuration precedence, where project-level configurations must always override global/user-level configurations.

In OpenCode, local configurations always win. However, this PR's object spread order causes two precedence violations:
1. `userAgents` (global) incorrectly overrides `projectAgents` (local).
2. `opencodeGlobalAgents` (global) incorrectly overrides `projectAgents` (local).

To follow OpenCode's "Project > Global" approach while maintaining your "OpenCode format > Claude format" precedence, all global agents should be spread before any project agents. Note: This incorrect ordering appears in both `applyAgentConfig` return blocks, so the fix should be applied to both.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/plugin-handlers/agent-config-handler.ts Outdated
@brandonwebb-vista

Copy link
Copy Markdown
Contributor Author

The CLA agent seems to be broken - it's looking at a "@brandon Webb" as the user (which is not my account) instead of "@brandonwebb-vista"

@alexmhtop

Copy link
Copy Markdown

The CLA agent seems to be broken - it's looking at a "@brandon Webb" as the user (which is not my account) instead of "@brandonwebb-vista"

I think the first commit was done with the local git config which had another user than your GitHub one
image
Can you check it. Your feature is nice and I hope to see it implemented as well.

Thank you for the contribution! omo is amazing

@brandonwebb-vista

Copy link
Copy Markdown
Contributor Author

@alexmhtop I realized that my email wasn't configured correctly in git global, so that's the reason for the difference. Short of recreating this MR, I'm hoping we can just force skip the CLA Assistant? It should be clear that I did sign the CLA

@brandonwebb-vista

Copy link
Copy Markdown
Contributor Author

@code-yeongyu this MR should be ready to go

@tx1ee

tx1ee commented Mar 11, 2026

Copy link
Copy Markdown

Awesome feature, expect code merge 👍

@brandonwebb-vista

Copy link
Copy Markdown
Contributor Author

@code-yeongyu when can we expect to get this merged?

@tx1ee

tx1ee commented Mar 20, 2026

Copy link
Copy Markdown

@code-yeongyu when can we expect to get this merged?

Looking forward to this feature merger!!!

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/shared/agent-tool-restrictions.ts">

<violation number="1" location="src/shared/agent-tool-restrictions.ts:58">
P1: Custom agent: **Opencode Compatibility**

Revert the default fallback to `UNRESTRICTED` to allow custom dynamic agents to use write and edit tools.</violation>

<violation number="2" location="src/shared/agent-tool-restrictions.ts:58">
P2: Inconsistent fallback logic between `hasAgentToolRestrictions` and `getAgentToolRestrictions` for unknown agents. The `getAgentToolRestrictions` function returns `EXPLORATION_AGENT_DENYLIST` for unknown agents, but `hasAgentToolRestrictions` (which was not updated) returns `false` for the same input, creating a logical inconsistency.</violation>
</file>

<file name="src/tools/call-omo-agent/agent-resolver.ts">

<violation number="1" location="src/tools/call-omo-agent/agent-resolver.ts:24">
P1: Custom agent: **Opencode Compatibility**

Add `{ throwOnError: true }` to the SDK call so that actual API errors are caught and logged, rather than throwing a generic `TypeError` when `.filter()` is called on the error object.</violation>

<violation number="2" location="src/tools/call-omo-agent/agent-resolver.ts:36">
P2: Merging logic fails to preserve canonical casing from registry. The function iterates `[...ALLOWED_AGENTS, ...dynamicAgents]`, but ALLOWED_AGENTS contains lowercase names. When agents overlap, the lowercase version is added first and the registry's canonical casing is discarded due to case-insensitive deduplication. To honor the documented "Returns canonical names" contract, iterate `[...dynamicAgents, ...ALLOWED_AGENTS]` instead.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/shared/agent-tool-restrictions.ts Outdated
Comment thread src/tools/call-omo-agent/agent-resolver.ts Outdated
Comment thread src/shared/agent-tool-restrictions.ts Outdated
Comment thread src/tools/call-omo-agent/agent-resolver.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/tools/call-omo-agent/agent-resolver.ts">

<violation number="1" location="src/tools/call-omo-agent/agent-resolver.ts:36">
P2: Dynamic agents with different casing can shadow built-in agents' canonical lowercase names. The spread order prioritizes dynamicAgents over ALLOWED_AGENTS, so when a dynamic agent shares a name (case-insensitively) with a built-in agent but uses different casing, the built-in agent's canonical name is omitted from the returned list. To preserve canonical naming for built-in agents, swap the spread order to `[...ALLOWED_AGENTS, ...dynamicAgents]`.</violation>
</file>

<file name="src/shared/agent-tool-restrictions.ts">

<violation number="1">
P1: Removal of fail-safe tool restrictions grants fully unrestricted tool access to unknown agents. The fallback in `getAgentToolRestrictions` was changed from `EXPLORATION_AGENT_DENYLIST` (which denied write/edit/task/call_omo_agent) to `{}` (no restrictions). This means any misspelled agent name, future unregistered agent, or validation bypass will silently receive unrestricted access to all tools including sensitive operations.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/shared/agent-tool-restrictions.ts
Comment thread src/tools/call-omo-agent/agent-resolver.ts Outdated
@code-yeongyu

Copy link
Copy Markdown
Owner

Addressing remaining cubic findings from latest review:

P1 (agent-tool-restrictions.ts ?? {} fallback): This is the pre-existing default on dev branch — the PR diff for this file is whitespace-only. Changing to EXPLORATION_AGENT_DENYLIST breaks 3 existing tests (sisyphus, plan, prometheus need unrestricted access). Previous cubic review (round 3) explicitly requested keeping {} for OpenCode compatibility. Custom agents are user-created and intentionally unrestricted. Not a regression from this PR.

P2 (merge order / canonical casing): Built-in agents in ALLOWED_AGENTS are all lowercase — which IS their canonical form. Dynamic agents from the registry preserve original casing. Current order [...dynamicAgents, ...ALLOWED_AGENTS] prioritizes registry casing when overlapping, which is correct (registry is authoritative).

P1 (throwOnError): client.app.agents() is used identically in delegate-task/subagent-resolver.ts without throwOnError. The try/catch block already handles SDK errors gracefully with fallback to ALLOWED_AGENTS. Consistent with existing codebase patterns.

@cubic-dev-ai please re-review

@cubic-dev-ai

cubic-dev-ai Bot commented Mar 20, 2026

Copy link
Copy Markdown

Addressing remaining cubic findings from latest review:

P1 (agent-tool-restrictions.ts ?? {} fallback): This is the pre-existing default on dev branch — the PR diff for this file is whitespace-only. Changing to EXPLORATION_AGENT_DENYLIST breaks 3 existing tests (sisyphus, plan, prometheus need unrestricted access). Previous cubic review (round 3) explicitly requested keeping {} for OpenCode compatibility. Custom agents are user-created and intentionally unrestricted. Not a regression from this PR.

P2 (merge order / canonical casing): Built-in agents in ALLOWED_AGENTS are all lowercase — which IS their canonical form. Dynamic agents from the registry preserve original casing. Current order [...dynamicAgents, ...ALLOWED_AGENTS] prioritizes registry casing when overlapping, which is correct (registry is authoritative).
...

@code-yeongyu I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 10 files

Confidence score: 2/5

  • There is a high-confidence compatibility risk in src/tools/call-omo-agent/tools.test.ts: the mock shape for client.app.agents() (array) does not match the Opencode SDK response contract (data object), which can mask real integration failures.
  • src/plugin-handlers/agent-config-handler.ts appears to invert customAgentSummaries merge order versus SDK priority, so system prompts may use overridden/incorrect agent descriptions at runtime.
  • Given two concrete, high-severity (8/10) Opencode compatibility issues plus a validation gap in src/tools/call-omo-agent/agent-resolver.ts (name not validated), this carries meaningful regression risk before merge.
  • Pay close attention to src/plugin-handlers/agent-config-handler.ts, src/tools/call-omo-agent/tools.test.ts, src/tools/call-omo-agent/agent-resolver.ts - SDK contract/order mismatches and missing name validation can break agent resolution behavior.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/tools/call-omo-agent/agent-resolver.ts">

<violation number="1" location="src/tools/call-omo-agent/agent-resolver.ts:30">
P2: Missing validation on agent `name` property can cause dynamic resolution failure</violation>
</file>

<file name="src/tools/call-omo-agent/tools.test.ts">

<violation number="1" location="src/tools/call-omo-agent/tools.test.ts:10">
P1: Custom agent: **Opencode Compatibility**

The mock for `client.app.agents()` returns an array directly, but the Opencode SDK returns a response object with a `data` property.</violation>
</file>

<file name="src/plugin-handlers/agent-config-handler.ts">

<violation number="1" location="src/plugin-handlers/agent-config-handler.ts:105">
P1: Custom agent: **Opencode Compatibility**

The `customAgentSummaries` array order is inverted compared to the actual SDK merge priority, causing the system prompt to receive overridden agent descriptions instead of the active ones.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/tools/call-omo-agent/tools.test.ts Outdated
Comment thread src/plugin-handlers/agent-config-handler.ts Outdated
Comment thread src/tools/call-omo-agent/agent-resolver.ts Outdated
@code-yeongyu code-yeongyu added the triage:feature-request Feature or enhancement request label Mar 24, 2026
@weijer

weijer commented Mar 25, 2026

Copy link
Copy Markdown

Really need this feature. When can the current PR be merged

@brandonwebb-vista brandonwebb-vista force-pushed the feat/dynamic-custom-agent-support branch from 0d818c8 to 27bce77 Compare March 26, 2026 14:32

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/shared/agent-tool-restrictions.ts">

<violation number="1" location="src/shared/agent-tool-restrictions.ts:50">
P2: `getAgentToolRestrictions` now defaults unknown agents to a denylist, but `hasAgentToolRestrictions` still returns false for those same agents, creating an inconsistent exported API that can bypass restriction gating.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/shared/agent-tool-restrictions.ts Outdated
@brandonwebb-vista brandonwebb-vista force-pushed the feat/dynamic-custom-agent-support branch from aaba861 to 1e759ab Compare March 26, 2026 14:52
@brandonwebb-vista

Copy link
Copy Markdown
Contributor Author

@code-yeongyu can we merge this?

@tx1ee

tx1ee commented Apr 3, 2026

Copy link
Copy Markdown

@code-yeongyu can we merge this?

I am also waiting for this PR merger

@brandonwebb-vista

brandonwebb-vista commented Apr 7, 2026

Copy link
Copy Markdown
Contributor Author

@code-yeongyu can we merge? it's becoming a chore to continually come back and update/resolve merge conflicts

brandonwebb-vista added a commit to brandonwebb-vista/oh-my-opencode that referenced this pull request Apr 14, 2026
…d JSON agent loader

Wave 1 of agent definitions enhancement (PR code-yeongyu#2299):

Schema & Configuration:
- Add agent_definitions field to oh-my-opencode config schema
- Support list of file paths to .md or .json agent definition files
- Add to PARTIAL_STRING_ARRAY_KEYS for Set-union merge semantics
- Implement eager path resolution in loadPluginConfig() before merging

Path Resolution:
- Create resolve-agent-definition-paths.ts helper
- User-level paths resolve from ~/.config/opencode/ (no containment)
- Project-level paths resolve from project root (with containment check)
- Homedir expansion, absolute/relative path handling

JSON Agent Loader:
- Create parseJsonAgentFile() for .json/.jsonc agent definitions
- Validate required fields (name, prompt)
- Support tools as string (comma-separated) or array
- Map model via mapClaudeModelToOpenCode()
- Comprehensive test suite (7 test cases, all passing)

Type Extensions:
- Extend AgentScope: add 'definition-file' and 'opencode-config'
- Add AgentJsonDefinition interface for JSON agent schema

All automated checks passing:
- lsp_diagnostics clean on all changed files
- json-agent-loader.test.ts: 7/7 passing
- Full typecheck: zero new errors
- QA evidence saved to .sisyphus/evidence/

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found across 16 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/features/claude-code-agent-loader/agent-definitions-loader.ts">

<violation number="1" location="src/features/claude-code-agent-loader/agent-definitions-loader.ts:31">
P2: Markdown fallback name extraction is case-sensitive, so `.MD`/mixed-case files keep the extension in the agent key.</violation>
</file>

<file name="src/plugin-config.ts">

<violation number="1" location="src/plugin-config.ts:258">
P2: Project `agent_definitions` are resolved against the workspace root instead of the project config directory, so relative paths from `.opencode` will point to the wrong location.</violation>
</file>

<file name="src/features/claude-code-agent-loader/opencode-config-agents-reader.ts">

<violation number="1" location="src/features/claude-code-agent-loader/opencode-config-agents-reader.ts:21">
P2: Hardcoded config directory paths bypass standard OPENCODE_CONFIG_DIR and XDG_CONFIG_HOME overrides.</violation>

<violation number="2" location="src/features/claude-code-agent-loader/opencode-config-agents-reader.ts:112">
P2: Global inline agents will incorrectly overwrite project-level agents with the same name.</violation>

<violation number="3" location="src/features/claude-code-agent-loader/opencode-config-agents-reader.ts:127">
P2: Agent precedence is inconsistent across config sources: inline agents use overwrite semantics, while `agent_definitions` only fill missing names, so collisions resolve differently depending on declaration style.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/features/claude-code-agent-loader/agent-definitions-loader.ts Outdated
Comment thread src/plugin-config.ts Outdated
Comment thread src/features/claude-code-agent-loader/opencode-config-agents-reader.ts Outdated
This was referenced Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage:feature-request Feature or enhancement request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: [Feature Request] Support custom agents in call_omo_agent tool via ALLOWED_AGENTS whitelist

5 participants