From 6089aa2efa429869520896d088bf1e67188e5995 Mon Sep 17 00:00:00 2001 From: ydflow Date: Sun, 27 Sep 2026 18:40:33 +0800 Subject: [PATCH] fix(agents): carry the agent's model into the Cursor render (#830) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit renderForCursor was the one renderer that dropped spec.model: Claude, the Codex family and Copilot all write the agent's model into their native file, and reverseFromCursor reads it back (COMMON_CURSOR_FIELDS whitelists it), so a team agent with a concrete model ran on Cursor's default model silently. #830's design notes name the gap ('Cursor drops model when it renders agents today') and ask for it as a separate change — this is that change: write the value verbatim, as the other renderers do. The model[effort=...] form stays with the alias proposal. --- docs/usage-guide.md | 2 ++ docs/usage-guide.zh-CN.md | 2 ++ src/__tests__/agent-format.test.ts | 18 ++++++++++++++++++ src/resources/agent-format.ts | 3 +++ 4 files changed, 25 insertions(+) diff --git a/docs/usage-guide.md b/docs/usage-guide.md index d80c62cef..c029fe51c 100644 --- a/docs/usage-guide.md +++ b/docs/usage-guide.md @@ -1873,6 +1873,8 @@ For canonical YAML agents, push compares each local file with the corresponding ### Cursor +Cursor subagents deploy to `.cursor/agents/*.md` with YAML frontmatter carrying `agent_id` (the team agent's name), `description`, `tools`, and the agent's `model` when it declares one, plus any `tool_extras.cursor` fields; `reverseFromCursor` reads the same fields back, so a `pull` → `push` round-trip keeps the model. + Cursor project rules must live in `.cursor/rules/` as **`.mdc`** files with YAML frontmatter — a plain `.md` file there is silently ignored by Cursor. teamai therefore writes rules to Cursor as `.mdc` (every other tool still gets a plain `.md`), deriving the frontmatter from the team rule: - A rule scoped with a `paths:` list becomes `globs: ""` + `alwaysApply: false` (Cursor auto-attaches it when a matching file is in context). The value is quoted because a glob starting with `*` is not valid YAML unquoted. diff --git a/docs/usage-guide.zh-CN.md b/docs/usage-guide.zh-CN.md index a57baeb7a..f76cbb2f8 100644 --- a/docs/usage-guide.zh-CN.md +++ b/docs/usage-guide.zh-CN.md @@ -1767,6 +1767,8 @@ JoyCode 规则清理采用保守策略:不在团队规则列表中的本地 `. ### Cursor +Cursor 的子代理部署到 `.cursor/agents/*.md`,YAML frontmatter 携带 `agent_id`(团队代理名)、`description`、`tools`,以及团队代理声明了的 `model`,外加所有 `tool_extras.cursor` 字段;`reverseFromCursor` 按同样字段读回,因此 `pull` → `push` 往返不会丢 model。 + Cursor 的项目规则必须以 **`.mdc`** 文件形式放在 `.cursor/rules/` 下,且带 YAML frontmatter——放在那里的纯 `.md` 会被 Cursor 直接忽略。因此 teamai 向 Cursor 写规则时用 `.mdc`(其他工具仍写纯 `.md`),并从团队规则派生 frontmatter: - 带 `paths:` 列表的规则会转成 `globs: "<逗号拼接>"` + `alwaysApply: false`(上下文中有匹配文件时 Cursor 自动附加该规则)。值加引号是因为以 `*` 开头的 glob 不加引号时并非合法 YAML。 diff --git a/src/__tests__/agent-format.test.ts b/src/__tests__/agent-format.test.ts index 39359dc25..a2c255735 100644 --- a/src/__tests__/agent-format.test.ts +++ b/src/__tests__/agent-format.test.ts @@ -288,6 +288,24 @@ describe('renderForCursor', () => { expect(content).toContain('You are a helpful assistant.'); }); + it('carries the model into the frontmatter like every other renderer (#830)', () => { + const { content } = renderForCursor(makeSpec({ model: 'claude-opus-4' })); + expect(content).toContain('model: claude-opus-4'); + }); + + it('omits model when the spec has none', () => { + const { content } = renderForCursor(makeSpec()); + expect(content).not.toContain('model:'); + }); + + it('round-trips the model through reverseFromCursor', () => { + const { content } = renderForCursor(makeSpec({ model: 'claude-opus-4' })); + const result = reverseFromCursor('/agents/test-agent.md', content); + expect(result.ok).toBe(true); + if (!result.ok) return; + expect(result.spec.model).toBe('claude-opus-4'); + }); + it('flattens tool_extras.cursor into frontmatter', () => { const spec = makeSpec({ tool_extras: { cursor: { composer_mode: true } } }); const { content } = renderForCursor(spec); diff --git a/src/resources/agent-format.ts b/src/resources/agent-format.ts index 9fbb37344..6c121dc81 100644 --- a/src/resources/agent-format.ts +++ b/src/resources/agent-format.ts @@ -319,6 +319,9 @@ export function renderForCursor(spec: AgentSpec): RenderResult { agent_id: spec.name, description: spec.description, }; + if (spec.model !== undefined) { + frontmatterData['model'] = spec.model; + } if (spec.tools !== undefined && spec.tools.length > 0) { frontmatterData['tools'] = spec.tools; }