Skip to content

feat(delegate-task): emit subagent_type enum when subagent list is known#3719

Closed
WarGloom wants to merge 1 commit intocode-yeongyu:devfrom
WarGloom:feat/delegate-task-subagent-enum
Closed

feat(delegate-task): emit subagent_type enum when subagent list is known#3719
WarGloom wants to merge 1 commit intocode-yeongyu:devfrom
WarGloom:feat/delegate-task-subagent-enum

Conversation

@WarGloom
Copy link
Copy Markdown

@WarGloom WarGloom commented Apr 29, 2026

Summary

  • Builds the task tool argument subagent_type as a zod.enum(...) when the runtime can enumerate available subagents, instead of a free-form string.
  • Falls back to plain string when no list is available, preserving current behavior.

Changes

  • New optional field on DelegateTaskToolOptions: availableSubagentNames?: readonly string[].
  • createDelegateTask builds its args schema dynamically:
    • non-empty list → tool.schema.enum(names).optional().describe(...)
    • otherwise → existing tool.schema.string().optional().describe(...)
  • tool-registry.ts plumbs the discovery: union of BUILTIN_SUBAGENT_TYPES + agents from loadUserAgents, loadProjectAgents, loadOpencodeGlobalAgents, loadOpencodeProjectAgents, readOpencodeConfigAgents. Filters by mode === "subagent" | "all" | undefined. Removes entries listed in pluginConfig.disabled_agents. Deduplicated.

The description text, runtime branches, category resolution, and execution paths are unchanged.

Motivation

Today subagent_type is tool.schema.string().optional(). The resulting JSON Schema only carries {"type":"string"} — there is no machine-readable list of valid agent names anywhere in the tool definition. Downstream consumers that do not parse the description text (LLM proxies, validators, harness adapters, observability tools) cannot discover the user's configured subagents.

JSON Schema's enum is the canonical place to declare a closed set of string values, and it is what every standard tooling pipeline already understands.

Backward compatibility

  • Public option is fully optional; no caller is required to change.
  • When availableSubagentNames is omitted or empty, the schema is byte-identical to before.
  • The category, subagent_type, and task_id runtime branches in the tool body are untouched.
  • No change to category configs, fallback chains, or sync/background execution.

Testing

bun run typecheck
bun test src/tools/delegate-task/task-schema.test.ts

3 new tests:

  • No availableSubagentNamessubagent_type stays plain string.
  • availableSubagentNames: ["oracle", "librarian", "dev"]subagent_type is enum and contains those names.
  • Empty array → falls back to plain string.

Token impact

Each agent name adds ~3-5 input tokens to the tool definition. The tool definition lives in the cached prompt prefix, so the cost is paid once and amortizes to near-zero across a session.

Why this matters

Without an enum on subagent_type, any harness sitting between OpenCode and the model has to parse natural-language description text to discover the agent list — fragile and version-dependent. With it, the canonical JSON Schema field carries the list, which is what every standard tooling pipeline already knows how to consume.


View in Codesmith
Need help on this PR? Tag @codesmith with what you need.

  • Let Codesmith autofix CI failures and bot reviews

Summary by cubic

Makes task.subagent_type a constrained enum when the runtime knows available subagents, improving validation and tooling. Falls back to a plain string when unknown; the registry now discovers, filters, and passes subagent names.

  • New Features
    • Emit zod.enum(...) for subagent_type when availableSubagentNames is non-empty; otherwise use a string.
    • Discover names from built-ins plus loadUserAgents, loadProjectAgents, loadOpencodeGlobalAgents, loadOpencodeProjectAgents, readOpencodeConfigAgents, and loadAgentDefinitions. Respect pluginConfig.claude_code?.agents, filter by mode, exclude pluginConfig.disabled_agents, dedupe/sort, and pass via availableSubagentNames to createDelegateTask.
    • Add availableSubagentNames?: readonly string[] to DelegateTaskToolOptions; add tests for enum, empty, and missing cases.

Written for commit f142b13. Summary will update on new commits. Review in cubic

@github-actions
Copy link
Copy Markdown
Contributor

Thank you for your contribution! Before we can merge this PR, we need you to sign our Contributor License Agreement (CLA).

To sign the CLA, please comment on this PR with:

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

This is a one-time requirement. Once signed, all your future contributions will be automatically accepted.


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


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d3633c836c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/plugin/tool-registry.ts
Comment thread src/plugin/tool-registry.ts Outdated
Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

7 issues found across 144 files

Confidence score: 3/5

  • There is some meaningful regression risk here: several medium-severity, high-confidence findings (6/10 with 8–9/10 confidence) indicate concrete runtime behavior issues rather than just style or cleanup concerns.
  • In src/hooks/compaction-context-injector/recovery.ts, exceptions in the catch path do not increment consecutiveRecoveryFailures, so the intended consecutive-failure cutoff can be bypassed and recovery loops may persist longer than expected.
  • Multiple config/capability mismatches could surface user-facing failures: src/config/schema/experimental.ts allows empty advisor identifiers, src/shared/model-capabilities/supplemental-entries.ts sets gpt-5.5 output above provider limits, and src/shared/serena-availability.ts may mis-detect Opencode/JSONC availability.
  • Pay close attention to src/hooks/compaction-context-injector/recovery.ts, src/config/schema/experimental.ts, src/shared/model-capabilities/supplemental-entries.ts, and src/shared/serena-availability.ts - these paths carry the highest likelihood of functional misbehavior at runtime.

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed. cubic prioritises the most important files to review.

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/hooks/compaction-context-injector/recovery.ts">

<violation number="1" location="src/hooks/compaction-context-injector/recovery.ts:51">
P2: Exception failures bypass the new consecutive-failure cutoff because the `catch` path does not increment `consecutiveRecoveryFailures`.</violation>
</file>

<file name="src/cli/run/agent-profile-colors.ts">

<violation number="1" location="src/cli/run/agent-profile-colors.ts:19">
P2: Timeout cleanup runs only on the success path; a fast rejection leaves the timer pending until it fires.</violation>
</file>

<file name="src/config/schema/experimental.ts">

<violation number="1" location="src/config/schema/experimental.ts:6">
P2: New advisor schema accepts empty strings for model/agent identifiers, allowing invalid values to propagate into routing and advisor option construction.</violation>
</file>

<file name="src/shared/model-capabilities/supplemental-entries.ts">

<violation number="1" location="src/shared/model-capabilities/supplemental-entries.ts:33">
P2: `gpt-5.5` max output is configured above documented provider limit (130,000 vs 128,000), which can cause oversized requests and runtime API failures.</violation>
</file>

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

<violation number="1" location="src/plugin/tool-registry.ts:207">
P2: `availableSubagentNames` is built from unsorted discovered agent sources, so subagent enum/list ordering can vary between runs. Sort the final names list to keep tool schema output deterministic.</violation>
</file>

<file name="src/shared/serena-availability.ts">

<violation number="1" location="src/shared/serena-availability.ts:20">
P2: Custom agent: **Opencode Compatibility**

`.jsonc` configs are treated as candidates but parsed with `JSON.parse`, so valid OpenCode JSONC files can be silently ignored.</violation>

<violation number="2" location="src/shared/serena-availability.ts:22">
P2: Custom agent: **Opencode Compatibility**

Serena availability detection is based only on MCP key presence and ignores Opencode MCP disable semantics (e.g., `enabled: false`), causing false positives versus actual Opencode behavior.</violation>
</file>

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

} from "./recovery-prompt-config"
import { validateCheckpointModel } from "./validated-model"
import {
resolveLatestSessionPromptConfig,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Exception failures bypass the new consecutive-failure cutoff because the catch path does not increment consecutiveRecoveryFailures.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/compaction-context-injector/recovery.ts, line 51:

<comment>Exception failures bypass the new consecutive-failure cutoff because the `catch` path does not increment `consecutiveRecoveryFailures`.</comment>

<file context>
@@ -41,7 +41,18 @@ export function createRecoveryLogic(
+      return false
+    }
+
+    if (tailState.consecutiveRecoveryFailures >= MAX_CONSECUTIVE_RECOVERY_FAILURES) {
+      log(`[compaction-context-injector] Skipping recovery after ${tailState.consecutiveRecoveryFailures} consecutive failures`, {
+        sessionID,
</file context>

Comment thread src/cli/run/agent-profile-colors.ts Outdated
Comment thread src/config/schema/experimental.ts Outdated
Comment thread src/shared/model-capabilities/supplemental-entries.ts Outdated
Comment thread src/plugin/tool-registry.ts Outdated
Comment thread src/shared/serena-availability.ts Outdated
Comment thread src/shared/serena-availability.ts Outdated
@WarGloom WarGloom marked this pull request as draft April 29, 2026 09:10
@WarGloom WarGloom force-pushed the feat/delegate-task-subagent-enum branch from d3633c8 to 12e0a81 Compare April 29, 2026 09:12
Builds the `task` tool argument `subagent_type` as a `zod.enum(...)`
when the runtime can enumerate available subagents, instead of a
free-form string. Falls back to plain string when no list is
available, preserving current behavior.

- New optional `availableSubagentNames?: readonly string[]` field on
  `DelegateTaskToolOptions`.
- `createDelegateTask` builds its args schema dynamically:
  - non-empty list → `tool.schema.enum(names).optional()`
  - empty / undefined → existing `tool.schema.string().optional()`.
- `tool-registry.ts` runs `mergeWithClaudeCodeAgents([], ctx.directory)`
  and forwards filtered subagent names (mode === "subagent" | "all" |
  undefined) to `createDelegateTask`.
- 3 new schema tests covering the enum-on, enum-empty, and missing
  cases.

Net effect: the JSON Schema sent to the model carries an `enum` for
`subagent_type`, which is the canonical place every standard tooling
pipeline (validators, proxies, harness adapters, observability tools)
already knows how to read. Description text and execution path are
unchanged.
@WarGloom WarGloom force-pushed the feat/delegate-task-subagent-enum branch from 12e0a81 to f142b13 Compare April 29, 2026 11:31
@WarGloom
Copy link
Copy Markdown
Author

Review status

In-scope (this PR's diff) — addressed in f142b130

  • P1 — Include plugin and definition agents in subagent enum: agent_definitions agents now included via loadAgentDefinitions(pluginConfig.agent_definitions, "definition-file"). Plugin manifest agents (pluginComponents.agents) require threading pluginComponents through createToolscreateToolRegistry; deferred to a follow-up PR to keep this change focused on schema emission.
  • P2 — Respect claude_code.agents flag: loadUserAgents() / loadProjectAgents() are now gated on pluginConfig.claude_code?.agents ?? true, matching applyAgentConfig.
  • P2 — Sort enum: final list sorted with localeCompare for deterministic output.

Also rebased to a single clean commit on dev.

Out of scope (not in this PR's diff)

The following comments are flagged on file paths that aren't part of this PR's diff (they were attached during the initial review of the pre-rebase commit, which carried unrelated changes from the original branch):

  • src/hooks/compaction-context-injector/recovery.ts
  • src/cli/run/agent-profile-colors.ts
  • src/config/schema/experimental.ts
  • src/shared/model-capabilities/supplemental-entries.ts
  • src/shared/serena-availability.ts

Those files are no longer touched by this PR after the rebase. Happy to file separate PRs for any of them if they're real bugs on dev.

VoidChecksum added a commit to VoidChecksum/oh-my-openagent that referenced this pull request Apr 30, 2026
@acamq
Copy link
Copy Markdown
Collaborator

acamq commented May 11, 2026

Hi @WarGloom, thanks for your contribution!

This PR is being closed because the CLA check has been failing and the PR has been inactive for 7+ days.

The CLA is a requirement for all contributions to this project. To resolve this:

  1. Sign the CLA by following the instructions in the CLA check failure comment on your PR.
  2. Reopen this PR (or open a new one targeting the latest dev branch) once signed.

If you believe this was closed in error, feel free to comment and we'll take another look.

Thanks again for your time and contribution!

@acamq acamq closed this May 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants