mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-07-10 01:29:17 +00:00
* docs: add declarative agents port design doc for #4821 * feat(core): add declarative agent frontmatter schema constants and 9 new fields Adds agent-frontmatter-schema.ts as the single source of truth for the CC 2.1.168 declarative-agent enum constants (EFFORT_VALUES, PERMISSION_MODE_VALUES, MEMORY_VALUES, ISOLATION_VALUES, COLOR_VALUES) and lenient parsers (parseEffort, parseMaxTurns, parseBackground, parseStringOrArray) that mirror DL7's warn-and-drop posture. Also adds a permissionModeToApprovalMode bridge to map CC's permission modes onto qwen-code's existing approvalMode semantics. Extends SubagentConfig with 9 optional fields carried verbatim from CC frontmatter: permissionMode, effort, maxTurns, skills, initialPrompt, memory, isolation, mcpServers, hooks. Runtime semantics for the metadata-only fields are deferred to follow-up PRs; this lands the data carrier. Refs #4821 #4721 #4732 * feat(core): parse and serialize 9 new declarative agent frontmatter fields Extends parseSubagentContent and serializeSubagent to round-trip the 9 CC 2.1.168 fields previously added to the SubagentConfig type. Parsing follows DL7's lenient warn-and-drop posture (vs the existing strict throw posture used for approvalMode), so a Claude Code agent file with an invalid optional field still parses with that field dropped — matching CC behavior so users can drop CC agent files into .qwen/agents/ unchanged. Adds a permissionMode → approvalMode bridge: when frontmatter has permissionMode but no approvalMode, the bridge resolves the approvalMode at parse time using the same mapping as claude-converter.ts. If both are set, approvalMode wins (already-explicit values take precedence over inferred ones). Tests: - 22 new parser cases covering happy paths, invalid drops, permissionMode bridge precedence, color allowlist (with auto sentinel preserved), and loose-validation passthrough for mcpServers / hooks. - 9 new serializer cases asserting round-trip and omit-when-unset behavior. Refs #4821 #4721 #4732 * feat(core): promote top-level maxTurns to runConfig.max_turns at convert time Wires the new top-level `maxTurns` field into the existing runtime configuration pipeline so the value declared in agent frontmatter actually limits the agent's turn budget at run time. When both the top-level `maxTurns` and the legacy nested `runConfig.max_turns` are set, the top-level field wins (more specific and matches the CC frontmatter shape upstream agent files use). When only the nested field is set, behavior is unchanged. Refs #4821 #4721 #4732 * refactor(core): use shared permissionMode bridge and parseStringOrArray in claude-converter Replaces the inline claudeToQwenMode table and the local parseStringOrArray helper in claude-converter.ts with the shared exports from agent-frontmatter-schema.ts. One source of truth for the CC ↔ qwen mapping keeps the two import paths (.qwen/agents/*.md frontmatter and Claude plugin import) in sync — when the upstream CC schema changes, only one table needs updating. Adds explicit tests for the bridge mapping (six known modes + unknown fallback). The fallback now happens at the call site rather than inside the table, but the observable behavior is unchanged. Refs #4821 * docs(subagents): document CC-compatible frontmatter fields Adds a Claude Code Compatibility Fields section to the user-facing subagents reference, covering the 9 new frontmatter fields landed in this PR. The intent is for users with existing Claude Code agents to know they can drop the files into `.qwen/agents/` and have them parse identically. Refs #4821 * refactor(core): reuse parseBackground in declarative agent loader Replaces the inline boolean-or-string lenient parse for the background field with the shared parseBackground util added in the schema module. Same observable behavior; one fewer place to keep in sync when the upstream shape changes. Refs #4821 * fix(core): address adversarial review of declarative agents PR Four self-review findings caught and fixed before opening the PR: 1. **mcpServers/hooks round-trip claim was broken.** The local yaml-parser only formats one level of nesting, so serializing an agent with nested mcpServers or hooks would mangle the value into '[object Object]'. The fields are still carried verbatim in memory (read path is fine), but the serializer no longer emits them — losing the field through '/agents' edits is strictly safer than corrupting it. Documented the limitation in docs/users/features/sub-agents.md. 2. **approvalMode throw vs permissionMode lenience asymmetry.** The pre-existing approvalMode parser threw on invalid values, killing the entire agent file. With the new permissionMode bridge, a CC-imported file with 'permissionMode: bypassPermissions' + 'approvalMode: tpyo' would reject the file instead of dropping the typo and using the bridge. Demoted approvalMode to the same DL7-parity warn-and-drop posture all the new fields use; the bridge now runs when approvalMode is invalid. 3. **parseEffort missed numeric strings.** CC's DL7 falls back to parseInt for non-enum effort strings so 'effort: "5"' (quoted YAML) round-trips like 'effort: 5'. Added the same fallback and tests for floats / partial numeric strings / valid numeric strings. 4. **convertAgentFiles stripped 6/9 of the new fields.** The Claude plugin import path read frontmatter into a fixed ClaudeAgentConfig shape, so 'effort', 'maxTurns', 'initialPrompt', 'memory', 'isolation', 'mcpServers', and 'background' were silently dropped when installing a CC plugin agent. Build the rewritten frontmatter from the original keys first, then overlay the converter's transformations for the keys it owns — unknown CC fields now passthrough verbatim, future-proofing against later CC additions. Refs #4821 #4721 #4732 * fix(core): round-2 self-review fixes for declarative agents PR Second adversarial review surfaced 5 more findings; all fixed: 1. **convertAgentFiles passthrough corrupted nested objects.** Round-1 fixed serializeSubagent to skip emitting mcpServers/hooks (the local yaml-parser collapses nested values to '[object Object]'). The plugin-import passthrough I added to claude-converter.ts had the same mangle bug — a CC plugin agent with nested mcpServers got written to disk as 'mcpServers:\n - [object Object]'. Now skips both fields via a NESTED_FIELDS_NOT_ROUND_TRIPPABLE set. 2. **parseEffort accepted 0 and negative integers.** Docs say 'positive integer' and parseMaxTurns already rejects <= 0. parseEffort didn't, accepting '0' / '-5' / 0 / -1 as valid efforts. Aligned both helpers and added tests for the boundary values. 3. **Function name collision: permissionModeToApprovalMode.** packages/core/src/ tools/agent/agent.ts has a module-private permissionModeToApprovalMode that maps the qwen PermissionMode enum to ApprovalMode enum (different domain entirely). My new exported helper used the same name; IDE auto-import would silently return undefined for every qwen enum value. Renamed the export to claudePermissionModeToApprovalMode and updated 4 callers. 4. **color: 'auto' round-trip asymmetry.** Round-1 added a test pinning that the parser preserves the legacy 'auto' sentinel. But serializeSubagent already had a pre-existing 'skip emit when auto' branch, so a parse → serialize → parse cycle dropped the sentinel. The CLI helpers (shouldShowColor / getColorForDisplay) already treat 'auto' identically to undefined, so normalizing 'auto' to undefined at parse time has no downstream effect AND makes round-trip cleanly idempotent. 5. **Converter approvalMode precedence diverged from loader.** When a CC source file had both 'permissionMode: bypassPermissions' AND 'approvalMode: default', the convertClaudeAgentConfig path wrote 'approvalMode: yolo' (bridge wins). The loader's rule is 'approvalMode wins over bridge'. Extended ClaudeAgentConfig with an approvalMode field and gated the bridge emit on 'source approvalMode is unset', aligning convert and load precedence. Refs #4821 #4721 #4732 * fix(core): round-3 self-review fixes — drift, API hygiene, converter contract Three quality findings from the round-3 adversarial pass (after rounds 1+2 fixed 9 issues each). All low-severity but cheap; the runtime was correct, the file-on-disk + public-API surface needed tightening. 1. **Stale runConfig.max_turns duplicated on every write.** Top-level maxTurns was promoted in |
||
|---|---|---|
| .. | ||
| design | ||
| developers | ||
| e2e-tests | ||
| plans | ||
| superpowers/plans | ||
| users | ||
| verification/abort-controller-refactor | ||
| _meta.ts | ||
| declarative-agents-port.md | ||
| index.md | ||