Skip to content

fix(app): bind ambient chat to the platform ask agent - #607

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-586-default-agent
Aug 2, 2026
Merged

fix(app): bind ambient chat to the platform ask agent#607
os-zhuang merged 1 commit into
mainfrom
claude/issue-586-default-agent

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #586

Description

crm_enterprise 仍然声明 defaultAgent: 'sales_copilot' —— 这个 app 自建 agent 早在 #512 就随「skills-only surface」(ADR-0063 §2)一起退役了。

按 ADR-0063 §1/§2,defaultAgent 是一个 surface 绑定,不是自定义 agent 的插槽:可解析的取值只有两个平台 agent —— ask(数据面,隐式默认)与 build(Studio 这类编排面)。运行时 loadAgent() 会拒绝非平台记录,所以这条绑定是死元数据:app-shell 挂载的悬浮 chatbot 解析不到 agent。

为什么没人发现App.defaultAgent 的类型是 SnakeCaseIdentifierSchema,任何合法 snake_case 都能通过校验;而平台的 agent authoring lint 只遍历 stack.agents,从不看 app.defaultAgent。于是 os validatepnpm buildpnpm lint 全绿,缺陷一直沉默到 demo 现场才暴露。

HotCRM 是数据面,因此绑定 ask。app 自身的 AI 能力以 skills 形式交付(src/skills/,共 6 个),它们本来就通过 surface 亲和挂到平台 agent 上 —— 修好绑定后助手即可带着完整技能集回答。

Type of Change

  • Bug fix (non-breaking change which fixes an issue)

Related Issues

Fixes #586
Related to #512

Changes Made

  • src/apps/crm.app.tsdefaultAgent: 'sales_copilot''ask',并补注释说明这是 surface 绑定而非自定义 agent 插槽(避免下一个作者再填一个"业务味"的名字)。
  • src/pages/account_detail.page.ts — 清理注释里同样过期的 sales_copilot 引用。
  • test/metadata-references.test.ts — 新增 app AI bindings resolve to a platform agent 守卫(3 条断言)。
  • .changeset/app-default-agent-platform-binding.md — patch。

守卫为什么这样写

平台 agent 集合从 spec 自身读出,不在测试里再抄一份:

const surface = ( AgentSchema as AnyRec ).shape.surface;
const enumSchema = typeof surface.removeDefault === 'function' ? surface.removeDefault() : surface;
return enumSchema.options as string[]; // ['ask', 'build']

agent 名与 surface 名是同两个 token(AgentSchema.surfacez.enum(['ask','build'])),所以这个集合跟着契约走,不会随平台演进而在 app 侧腐化。这是刻意的 contract-first 选择:与其在消费侧写宽容回退,不如让约束在写元数据时就咬人。

三条断言:

  1. the spec still exposes exactly the two platform agents —— guard the guard,内省一旦返回 [],下面的检查会变成空断言而假绿。
  2. every app defaultAgent names a platform agent —— 本 issue 的核心。缺省 key 是合法的(ask 是隐式默认),只校验显式取值。
  3. the app authors no agents of its own —— ADR-0063 §2。重新引入 app agent 正是让 sales_copilot 这类名字"看起来合理"的前提;同时断言 skills 非空,避免这条退化成永真。

Testing

  • Unit tests pass (pnpm test)
  • Linting passes (pnpm lint)
  • Build succeeds (pnpm build)
  • New tests added
pnpm validate  → ✓ Validation passed (3053ms)
pnpm typecheck → ✓ (no errors)
pnpm lint      → 1 warning(s), 13 suggestion(s) — exit 0,均为既有项,与本次改动无关
pnpm build     → ✓ Build complete · Artifact: dist/objectstack.json (1015.8 KB)
pnpm test      → Test Files 34 passed (34) · Tests 649 passed | 1 skipped (650)

反向验证(证明守卫真的会咬,而不是恰好全绿):把 defaultAgent 临时改回 'sales_copilot' 后单跑该用例 ——

× app AI bindings resolve to a platform agent > every app defaultAgent names a platform agent
  → dangling app agent bindings:
      crm_enterprise: defaultAgent "sales_copilot" is not a platform agent
      (ask | build) — it will not resolve at chat time

改回 'ask' 后恢复绿色。

Checklist

  • I have added a changeset
  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective
  • New and existing unit tests pass locally with my changes

Additional Notes

范围外发现,已另行开单 #606sales_copilotsrc/ 之外还有 4 处存活引用 —— scripts/wow1-live-schema.sh:82 与三个语种的 content/docs/ai-copilot/live-schema*.mdx,都是 Wow #1 demo 里 POST /api/v1/ai/chat 的请求体。那不是过期注释而是会真的失败的可执行路径(脚本用 curl -fsS,第二步直接中止)。本 PR 未改动它们,因为 #586 的验收明确限定在 src/#606 里也一并记了 objectstack.config.ts:76 那句「the two agents + skills」的过期注释。

上游缺口(属 objectstack 侧,本 PR 不涉及):agent authoring lint 只走 stack.agents,不校验 app.defaultAgent 的引用完整性。本 PR 的守卫是 app 侧的补位,不应替代上游修复。

🤖 Generated with Claude Code

https://claude.ai/code/session_019SS7C5SXpniKeCApxgARyf


Generated by Claude Code

`crm_enterprise` still declared `defaultAgent: 'sales_copilot'`, an
app-authored agent retired in #512. Per ADR-0063 §1/§2 `defaultAgent` is a
surface binding, not a custom-agent slot: the only resolvable values are the
two platform agents (`ask` for data surfaces, `build` for authoring surfaces),
so `loadAgent()` refused the record and the floating chatbot resolved to
nothing.

Nothing caught it — `App.defaultAgent` is typed `SnakeCaseIdentifierSchema`, so
any well-formed snake_case name parses, and the platform's agent lint only
walks `stack.agents`.

Adds a guard to `test/metadata-references.test.ts` pinning every app's
`defaultAgent` against the platform agent set, read off the spec's own
`AgentSchema.shape.surface` rather than transcribed, so the set tracks the
contract instead of drifting from it. Also clears the stale `sales_copilot`
mention in the `account_detail` page comment.

Fixes #586

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019SS7C5SXpniKeCApxgARyf
@vercel

vercel Bot commented Aug 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hotcrm Ignored Ignored Aug 2, 2026 11:09am

Request Review

@github-actions github-actions Bot added ci/cd CI plumbing and the verification pipeline metadata Declarative metadata — schema, security posture, UI surfaces labels Aug 2, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review August 2, 2026 11:13
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 2, 2026
Merged via the queue into main with commit 9588c36 Aug 2, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd CI plumbing and the verification pipeline metadata Declarative metadata — schema, security posture, UI surfaces

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dangling defaultAgent: 'sales_copilot' — the agent was retired in #512

2 participants