diff --git a/deps/agent-document-renderer b/deps/agent-document-renderer index 0d1c512..31fbe54 160000 --- a/deps/agent-document-renderer +++ b/deps/agent-document-renderer @@ -1 +1 @@ -Subproject commit 0d1c5121d137be817db5f98d3c13320dfa919c8a +Subproject commit 31fbe54fae8bf11be664919ce173da0d68ebfdc9 diff --git a/internal/docgen/comparison.go b/internal/docgen/comparison.go index ad48558..3996cdb 100644 --- a/internal/docgen/comparison.go +++ b/internal/docgen/comparison.go @@ -125,13 +125,13 @@ func compareLegacyAndShared(title string, source []byte, canonical model.Canonic receipt.Dimensions = append(receipt.Dimensions, compareExactDimension("page-margins", legacyDOCX.Margins, sharedDOCX.Margins, "")) } else { receipt.Dimensions = append(receipt.Dimensions, intentionalDimension("page-margins", legacyDOCX.Margins, sharedDOCX.Margins, - comparisonExceptionCorporate, "organization-default candidate owns page margins")) + comparisonExceptionCorporate, "published organization default owns page margins")) } if legacyDOCX.Headers == sharedDOCX.Headers && legacyDOCX.Footers == sharedDOCX.Footers { receipt.Dimensions = append(receipt.Dimensions, compareExactDimension("header-footer", []int{legacyDOCX.Headers, legacyDOCX.Footers}, []int{sharedDOCX.Headers, sharedDOCX.Footers}, "")) } else { receipt.Dimensions = append(receipt.Dimensions, intentionalDimension("header-footer", []int{legacyDOCX.Headers, legacyDOCX.Footers}, []int{sharedDOCX.Headers, sharedDOCX.Footers}, - comparisonExceptionCorporate, "organization-default candidate adds reviewed header/footer rules")) + comparisonExceptionCorporate, "published organization default adds approved header/footer rules")) } if legacyDOCX.Bookmarks == sharedDOCX.Bookmarks { receipt.Dimensions = append(receipt.Dimensions, compareExactDimension("node-bookmarks", legacyDOCX.Bookmarks, sharedDOCX.Bookmarks, "")) diff --git a/internal/docgen/renderer.go b/internal/docgen/renderer.go index 457d768..5ba8fb4 100644 --- a/internal/docgen/renderer.go +++ b/internal/docgen/renderer.go @@ -340,7 +340,7 @@ func generateWithOptions(ctx context.Context, request Request, options RenderOpt Document: parsed.Document, Renderer: result.Manifest, Profile: ProfileReceipt{ ProfileID: profileID, Version: profileVersion, SnapshotHash: bundle.Snapshot.SnapshotHash(), - Candidate: true, ReviewStatus: bundle.Review.Status, PublicationAllowed: bundle.Review.PublicationAllowed, + Candidate: bundle.Snapshot.State() != profile.StatePublished, ReviewStatus: bundle.Review.Status, PublicationAllowed: bundle.Review.PublicationAllowed, Unverified: append([]string(nil), bundle.Review.Unverified...), ProfileSHA256: bundle.Review.ProfileSHA256, AssetManifestSHA256: bundle.Review.AssetManifestSHA256, ReviewSHA256: bundle.Review.ReviewSHA256, }, diff --git a/internal/docgen/renderer_identity_generated.go b/internal/docgen/renderer_identity_generated.go index cae3eec..ec759b3 100644 --- a/internal/docgen/renderer_identity_generated.go +++ b/internal/docgen/renderer_identity_generated.go @@ -2,6 +2,6 @@ package docgen -const rendererRevision = "0d1c5121d137be817db5f98d3c13320dfa919c8a" +const rendererRevision = "31fbe54fae8bf11be664919ce173da0d68ebfdc9" const RendererIdentity = "agent-document-renderer@" + rendererRevision diff --git a/internal/docgen/renderer_integration_test.go b/internal/docgen/renderer_integration_test.go index d7d4074..d8b989d 100644 --- a/internal/docgen/renderer_integration_test.go +++ b/internal/docgen/renderer_integration_test.go @@ -39,7 +39,7 @@ const representativeMarkdown = `# 研发周会纪要 ![公司默认样图](asset:company.default.sample-image@1.0.0) :::callout warning -公司默认规则仍待人工视觉评审。 +公司默认规则只用于普通工作区交付。 ::: :::page-break @@ -89,10 +89,17 @@ func TestGenerateProducesDeterministicHashedDeliveryPackage(t *testing.T) { if err := json.Unmarshal(first.Manifest.Bytes, &manifest); err != nil { t.Fatalf("decode manifest: %v", err) } + bundle, err := profiles.LoadCompanyDefault() + if err != nil { + t.Fatalf("load renderer company default: %v", err) + } if manifest.SchemaVersion != ManifestSchemaVersion || manifest.RendererIdentity != RendererIdentity || - manifest.SelectionSource != "organization-default" || !manifest.Profile.Candidate || - manifest.Profile.ReviewStatus != "pending-human-visual-review" || manifest.Profile.PublicationAllowed { - t.Fatalf("manifest profile provenance = %#v", manifest) + manifest.SelectionSource != "organization-default" || manifest.Profile.Candidate || + manifest.Profile.ReviewStatus != bundle.Review.Status || manifest.Profile.PublicationAllowed != bundle.Review.PublicationAllowed { + t.Fatalf("manifest profile provenance = %#v, renderer review = %#v", manifest, bundle.Review) + } + if manifest.Profile.ReviewStatus != "approved" || !manifest.Profile.PublicationAllowed { + t.Fatalf("published organization default reported review=%q publicationAllowed=%v", manifest.Profile.ReviewStatus, manifest.Profile.PublicationAllowed) } if manifest.Profile.ProfileSHA256 == "" || manifest.Profile.AssetManifestSHA256 == "" || manifest.Profile.ReviewSHA256 == "" { t.Fatalf("manifest omitted source hashes: %#v", manifest.Profile) @@ -360,7 +367,7 @@ func TestPersistedControlledMetadataRoutesBeforeDefaultProfileLoad(t *testing.T) } func TestRendererIdentityMatchesPublishedPin(t *testing.T) { - const want = "agent-document-renderer@0d1c5121d137be817db5f98d3c13320dfa919c8a" + const want = "agent-document-renderer@31fbe54fae8bf11be664919ce173da0d68ebfdc9" if RendererIdentity != want { t.Fatalf("RendererIdentity = %q, want %q", RendererIdentity, want) } @@ -636,6 +643,11 @@ func TestRepresentativeLegacyComparisonRecordsOnlyIntentionalDifferences(t *test t.Errorf("comparison dimension %s = %#v, want match", name, dimension) } } + for _, dimension := range delivery.Comparison.Dimensions { + if dimension.ExceptionID == comparisonExceptionCorporate && !strings.Contains(dimension.Detail, "published organization default") { + t.Errorf("corporate layout exception %s detail = %q, want published organization default", dimension.Name, dimension.Detail) + } + } } func TestComparisonDetectsCanonicalAndDOCXTableAlignmentLoss(t *testing.T) { diff --git a/internal/prompts/library/base-deliverables.md b/internal/prompts/library/base-deliverables.md index 25803e3..d934a69 100644 --- a/internal/prompts/library/base-deliverables.md +++ b/internal/prompts/library/base-deliverables.md @@ -1,7 +1,7 @@ --- id: base.deliverables layer: base -version: 11 +version: 12 title: 交付物工作流 description: 生成文档、表格、演示稿的工作流、样式决策与技能入口(常驻基座) --- @@ -9,10 +9,10 @@ description: 生成文档、表格、演示稿的工作流、样式决策与技 工作流: -1. **先判路由**:普通、非受控的工作区 Word 可用组织默认候选;项目文档、受控文档、专用模板或审签输出必须交给 RDM,禁止调用 Backend 默认规则回退。组织默认候选的 manifest 状态固定显示 `pending-human-visual-review`,不能描述成已发布或已视觉批准。Excel / PPT / 图片再按用户指令、模板、参考文档、会话样式和默认主题的顺序定样式。 +1. **先判路由**:组织默认规则已发布(负责人 2026-10-16 批准,manifest 评审状态 `approved`),但只用于普通、非受控的工作区 Word;项目文档、受控文档、专用模板或审签输出必须交给 RDM,禁止调用 Backend 默认规则回退。Excel / PPT / 图片再按用户指令、模板、参考文档、会话样式和默认主题的顺序定样式。 2. **规划版面**:先定读者、结构和每一节的内容,再写脚本。不要边生成边补空节。 3. **生成 Word**:调用 `render_document`,传本次交付稳定且重试复用的 `operationId`、稳定 `documentId`、标题 `name`、Markdown、语言和 `working|preview` 模式,并显式传 `controlled=false`、`projectDocument=false`;任何一项不是 false 就停止并交给 RDM。时间与 requester 由宿主冻结,禁止传入或声称自定 `frozenAt`。Markdown 用 `#`-`######` 标题、段落、引用、围栏/行内代码、粗体、斜体、删除线、安全链接标签、`-`/`1.` 列表、GFM 表格、`asset:` 图片、`:::callout warning`/`:::` 提示块和 `:::page-break`。工具先保存带稳定 node ID 的 Markdown,再生成确定性 DOCX、manifest 和完整 zip;返回值逐项列出稳定 ID 与 SHA-256。失败时按回执状态重试同一 operationId,绝不调用 legacy Word 路径回退。 -4. **生成其他格式并自检**:Excel/PPT/图片用 `run_python` + house-style 对应 kit;用 lint/outline 回读。Word 的 OPC、安全、锚点与回读校验已经由统一 renderer 执行,复核 manifest 中的诊断、组织默认候选状态和 Markdown/DOCX 哈希。 +4. **生成其他格式并自检**:Excel/PPT/图片用 `run_python` + house-style 对应 kit;用 lint/outline 回读。Word 的 OPC、安全、锚点与回读校验已经由统一 renderer 执行,复核 manifest 中的诊断、组织默认规则评审状态和 Markdown/DOCX 哈希。 5. **登记**:`render_document` 已登记 Markdown、DOCX、manifest 和 zip,不要重复登记。其他格式继续用 `register_artifact`。 6. **收尾**:回复只写结论摘要,并说明这次用的样式(主题、是否模板、是否仿制)以及用户还能怎么调。不要在回复里复述全文,也不要只口头说文件名。 diff --git a/internal/prompts/library/task-doc-minutes.md b/internal/prompts/library/task-doc-minutes.md index 3483fd2..f53af31 100644 --- a/internal/prompts/library/task-doc-minutes.md +++ b/internal/prompts/library/task-doc-minutes.md @@ -1,7 +1,7 @@ --- id: task.doc-minutes layer: task -version: 3 +version: 4 title: 会议纪要生成 description: 依据上传的会议记录/录音稿生成结构完整的会议纪要 priority: 70 @@ -28,4 +28,4 @@ triggers: - 待办事项若原文未指明负责人或期限,写"未指明",不要编造。 - 版面:标题下用键值表写会议信息(时间、地点、主持人、参会人、缺席)。讨论按议题分节,每节含要点、分歧和结论。决议用真编号列表,不要再手写“1.”。待办用表格,列:序号、事项、负责人、期限、状态;原文没有的写“未指明”。发言人用统一称谓(职务或姓名);原文只有“说话人X”时保留并在文末说明。引语只留关键句,并标注是谁说的。 - 日期和数字全文一种格式。不要空节、空段落和手打项目符号。 -- 交付形态:普通工作区纪要按「交付物工作流」调用 `render_document`,生成「<主题>会议纪要.md/.docx/.manifest.json/.zip」;项目或受控纪要交给 RDM。对话里只简述结论、规则候选状态和可调项,不要复述全文。 +- 交付形态:普通工作区纪要按「交付物工作流」调用 `render_document`,生成「<主题>会议纪要.md/.docx/.manifest.json/.zip」;项目或受控纪要交给 RDM。对话里只简述结论、所用组织默认规则和可调项,不要复述全文。 diff --git a/internal/prompts/library/task-report.md b/internal/prompts/library/task-report.md index f17f3df..106291b 100644 --- a/internal/prompts/library/task-report.md +++ b/internal/prompts/library/task-report.md @@ -1,7 +1,7 @@ --- id: task.report layer: task -version: 3 +version: 4 title: 报告撰写 description: 把材料组织成正式报告/公文(含执行摘要与附录建议) priority: 55 @@ -25,4 +25,4 @@ triggers: - 结构服务于阅读动线:先结论后论证;每章开头一句话说清本章要点。 - 篇幅完整不注水:覆盖必要内容,删掉不改变结论的空话。 - 版面:封面(标题、受众、日期)、正文从执行摘要开始。执行摘要用强调块,控制在契约规定的篇幅内。章标题用标题样式,章首一句点明本章要点。数据进表格或附录,不埋在段落里。需要时在正文前放由标题生成的目录说明(页码以文件为准)。 -- 交付普通工作区 Word 时走交付物工作流的 `render_document`,同时保留 Markdown、manifest 和归档;项目或受控报告交给 RDM。回复说明规则候选状态,不复述全文。 +- 交付普通工作区 Word 时走交付物工作流的 `render_document`,同时保留 Markdown、manifest 和归档;项目或受控报告交给 RDM。回复说明所用组织默认规则,不复述全文。 diff --git a/internal/prompts/library/tool-render-document.md b/internal/prompts/library/tool-render-document.md index a121dd0..ceed6a1 100644 --- a/internal/prompts/library/tool-render-document.md +++ b/internal/prompts/library/tool-render-document.md @@ -1,10 +1,10 @@ --- id: tool.render_document layer: tool -version: 1 +version: 2 title: render_document 工具描述 description: 普通工作区 Markdown 到统一 Word 交付包的安全渲染入口 --- -把普通、非受控的工作区 Markdown 交给共享 canonical parser、组织默认候选 profile 和 Word adapter。必须传稳定且重试复用的 operationId,并显式传 `controlled=false` 和 `projectDocument=false`;缺任一字段即拒绝。frozenAt 与 requester 由宿主首次操作时创建并持久化,调用方不能提交。成功回执包含 Markdown、DOCX、manifest、zip 的稳定 ID 与 SHA-256;失败回执明确 partial 或 unknown,重试必须沿用同一 operationId。 +把普通、非受控的工作区 Markdown 交给共享 canonical parser、已发布的组织默认 profile 和 Word adapter。必须传稳定且重试复用的 operationId,并显式传 `controlled=false` 和 `projectDocument=false`;缺任一字段即拒绝。frozenAt 与 requester 由宿主首次操作时创建并持久化,调用方不能提交。成功回执包含 Markdown、DOCX、manifest、zip 的稳定 ID 与 SHA-256;失败回执明确 partial 或 unknown,重试必须沿用同一 operationId。 -只允许 working 或 preview。项目文档、受控文档、专用模板、审阅稿或批准稿必须交给 RDM;失败不得改走 legacy Word builder。当前公司默认规则状态是 pending-human-visual-review,只可用于普通工作/预览交付,不能称为已发布或已视觉批准。 +只允许 working 或 preview。项目文档、受控文档、专用模板、审阅稿或批准稿必须交给 RDM;失败不得改走 legacy Word builder。公司默认规则已发布(负责人 2026-10-16 批准,manifest 评审状态 `approved`),但仍只用于普通、非受控的工作/预览交付,不能代替 RDM 的项目或受控规则。 diff --git a/internal/prompts/prompts_test.go b/internal/prompts/prompts_test.go index 8cda4ce..9a4c8d8 100644 --- a/internal/prompts/prompts_test.go +++ b/internal/prompts/prompts_test.go @@ -101,16 +101,53 @@ func TestBaseDeliverablesRoutesWordThroughUnifiedRenderer(t *testing.T) { if err != nil || !found { t.Fatalf("base.deliverables: found=%v err=%v", found, err) } - for _, required := range []string{"render_document", "Markdown", "manifest", "SHA-256", "pending-human-visual-review", "RDM"} { + for _, required := range []string{"render_document", "Markdown", "manifest", "SHA-256", "已发布", "2026-10-16", "approved", "RDM", "禁止调用 Backend 默认规则回退"} { if !strings.Contains(body, required) { t.Errorf("base.deliverables missing %q", required) } } + for _, stale := range []string{"pending-human-visual-review", "组织默认候选", "不能描述成已发布"} { + if strings.Contains(body, stale) { + t.Errorf("base.deliverables still describes the organization default as unpublished: %q", stale) + } + } if strings.Contains(body, "python3 -m housestyle.build") { t.Fatal("base.deliverables still routes production Word through legacy housestyle.build") } } +func TestRenderDocumentToolDescribesPublishedDefaultWithoutWideningRoute(t *testing.T) { + body, found, err := mustService(t).ModuleBody("", "tool.render_document") + if err != nil || !found { + t.Fatalf("tool.render_document: found=%v err=%v", found, err) + } + for _, required := range []string{"已发布", "2026-10-16", "approved", "working 或 preview", "RDM", "不得改走 legacy Word builder"} { + if !strings.Contains(body, required) { + t.Errorf("tool.render_document missing %q", required) + } + } + for _, stale := range []string{"pending-human-visual-review", "默认候选", "不能称为已发布"} { + if strings.Contains(body, stale) { + t.Errorf("tool.render_document still describes the organization default as unpublished: %q", stale) + } + } +} + +func TestWordTaskPromptsDoNotReportOrganizationDefaultAsCandidate(t *testing.T) { + for _, id := range []string{"task.report", "task.doc-minutes"} { + body, found, err := mustService(t).ModuleBody("", id) + if err != nil || !found { + t.Fatalf("%s: found=%v err=%v", id, found, err) + } + if strings.Contains(body, "规则候选状态") { + t.Errorf("%s still asks the reply to report a candidate rule status", id) + } + if !strings.Contains(body, "RDM") { + t.Errorf("%s no longer routes project or controlled Word to RDM", id) + } + } +} + func TestEnvDeliverablePlaceholders(t *testing.T) { svc := mustService(t) blocks, _, err := svc.ResolveSystem(core.AgentProfile{}, TriggerCtx{Text: "你好"}, EnvData{ diff --git a/internal/skills/recipes/docx-author/SKILL.md b/internal/skills/recipes/docx-author/SKILL.md index 8e24e92..1c1091b 100644 --- a/internal/skills/recipes/docx-author/SKILL.md +++ b/internal/skills/recipes/docx-author/SKILL.md @@ -7,7 +7,7 @@ description: 用统一 renderer 生成 Markdown、DOCX、manifest 和归档 先读 `$AGENT_SKILLS_DIR/house-style/SKILL.md`。普通、非受控工作区 Word 调用 `render_document`;传本次交付稳定且重试复用的 operationId、稳定 documentId、标题和 Markdown,时间由宿主持久冻结。项目或受控 Word、专用模板、审阅与批准输出必须交给 RDM,禁止默认回退。 -成功结果包括 Markdown、DOCX、manifest 和 zip,逐项核对 SHA-256;当前组织默认候选仍是 `pending-human-visual-review`。Python、shell、`docx_kit` 和 `register_artifact` 都不是 Word 交付入口。迁移对照只能由 Backend 内部受信能力启动。生产 Word 的 OPC、安全、锚点与回读结果以共享 renderer manifest 为准;修订以返回的 Markdown 为权威源。 +成功结果包括 Markdown、DOCX、manifest 和 zip,逐项核对 SHA-256;组织默认规则已发布(负责人 2026-10-16 批准,manifest 评审状态 `approved`),但只用于普通、非受控的 working/preview 交付。Python、shell、`docx_kit` 和 `register_artifact` 都不是 Word 交付入口。迁移对照只能由 Backend 内部受信能力启动。生产 Word 的 OPC、安全、锚点与回读结果以共享 renderer manifest 为准;修订以返回的 Markdown 为权威源。 版面范式: diff --git a/internal/skills/recipes/house-style/SKILL.md b/internal/skills/recipes/house-style/SKILL.md index 05fcd36..c7627a1 100644 --- a/internal/skills/recipes/house-style/SKILL.md +++ b/internal/skills/recipes/house-style/SKILL.md @@ -5,7 +5,7 @@ description: 交付物设计系统。普通 Word 使用统一 renderer;housest # house-style -普通、非受控工作区 Word 的生产入口是 `render_document`:它保存 Markdown、确定性 DOCX、manifest 和 zip,并在 manifest 标注组织默认候选 `pending-human-visual-review`。项目或受控 Word、专用模板、审阅和批准输出必须交给 RDM,禁止 Backend 默认回退。 +普通、非受控工作区 Word 的生产入口是 `render_document`:它保存 Markdown、确定性 DOCX、manifest 和 zip,并在 manifest 记录已发布组织默认规则的评审状态 `approved`(负责人 2026-10-16 批准);该规则只用于普通、非受控的 working/preview 交付。项目或受控 Word、专用模板、审阅和批准输出必须交给 RDM,禁止 Backend 默认回退。 housestyle 的 Excel、PowerPoint、图片构件继续用于生产。Python Word 构件不是生产或迁移入口;`housestyle.build` 永久禁用,DOC/DOCX 也不能通过 `register_artifact` 登记。 diff --git a/internal/skills/skills_test.go b/internal/skills/skills_test.go index 857bc8d..ccbaf6a 100644 --- a/internal/skills/skills_test.go +++ b/internal/skills/skills_test.go @@ -183,11 +183,16 @@ func TestHouseStyleRoutesProductionWordThroughUnifiedRenderer(t *testing.T) { t.Fatal(err) } body := string(raw) - for _, required := range []string{"render_document", "pending-human-visual-review", "RDM"} { + for _, required := range []string{"render_document", "已发布", "2026-10-16", "approved", "RDM", "禁止 Backend 默认回退"} { if !strings.Contains(body, required) { t.Errorf("house-style skill missing %q", required) } } + for _, stale := range []string{"pending-human-visual-review", "默认候选"} { + if strings.Contains(body, stale) { + t.Errorf("house-style still describes the organization default as unpublished: %q", stale) + } + } for _, forbidden := range []string{"AGENT_SYSTEM_LEGACY_WORD_COMPARISON", "docx_kit", "new_document(template=", "dx.save("} { if strings.Contains(body, forbidden) { t.Fatalf("house-style still advertises Word bypass %q", forbidden) @@ -195,6 +200,24 @@ func TestHouseStyleRoutesProductionWordThroughUnifiedRenderer(t *testing.T) { } } +func TestDocxAuthorDescribesPublishedDefaultOnlyForWorkspaceWord(t *testing.T) { + raw, err := recipes.ReadFile("recipes/docx-author/SKILL.md") + if err != nil { + t.Fatal(err) + } + body := string(raw) + for _, required := range []string{"render_document", "已发布", "2026-10-16", "approved", "RDM", "禁止默认回退"} { + if !strings.Contains(body, required) { + t.Errorf("docx-author skill missing %q", required) + } + } + for _, stale := range []string{"pending-human-visual-review", "默认候选"} { + if strings.Contains(body, stale) { + t.Errorf("docx-author still describes the organization default as unpublished: %q", stale) + } + } +} + func TestHouseStylePython(t *testing.T) { if _, err := exec.LookPath("python3"); err != nil { t.Skip("python3 not available") diff --git a/internal/tools/document_renderer.go b/internal/tools/document_renderer.go index c3c7a83..6f747a7 100644 --- a/internal/tools/document_renderer.go +++ b/internal/tools/document_renderer.go @@ -17,7 +17,7 @@ import ( func registerDocumentRenderer(r *Registry) error { return r.Register(core.ToolDesc{ Name: "render_document", Source: core.SourceBuiltin, Edits: true, Risk: "medium", - Description: "把普通工作区 Markdown 通过统一文档渲染器生成 Markdown、DOCX、manifest 和可下载归档。只允许非受控工作区交付;项目受控文档必须交给 RDM。公司默认规则仍是待视觉评审候选,状态会写入 manifest。", + Description: "把普通工作区 Markdown 通过统一文档渲染器生成 Markdown、DOCX、manifest 和可下载归档。只允许非受控工作区交付;项目受控文档必须交给 RDM。公司默认规则已发布(负责人 2026-10-16 批准),但只用于普通工作区的 working/preview 交付,评审状态会写入 manifest。", Parameters: json.RawMessage(`{"type":"object","additionalProperties":false,"properties":{` + `"operationId":{"type":"string"},"name":{"type":"string"},"documentId":{"type":"string"},"documentType":{"type":"string"},` + `"language":{"type":"string"},"markdown":{"type":"string"},` + diff --git a/internal/tools/document_renderer_test.go b/internal/tools/document_renderer_test.go index 653bc3b..4e63ea5 100644 --- a/internal/tools/document_renderer_test.go +++ b/internal/tools/document_renderer_test.go @@ -90,6 +90,25 @@ func TestRenderDocumentToolWritesMarkdownFirstAndReportsPackageHashes(t *testing } } +func TestRenderDocumentToolDescriptionReportsPublishedWorkspaceDefault(t *testing.T) { + registry := NewRegistry() + if err := registry.RegisterBuiltin(); err != nil { + t.Fatal(err) + } + description, _, found := registry.Get("render_document") + if !found { + t.Fatal("render_document is not registered") + } + for _, required := range []string{"已发布", "RDM", "非受控工作区"} { + if !strings.Contains(description.Description, required) { + t.Errorf("render_document description missing %q: %s", required, description.Description) + } + } + if strings.Contains(description.Description, "候选") { + t.Errorf("render_document description still calls the organization default a candidate: %s", description.Description) + } +} + func TestRenderDocumentToolSchemaIsClosedAndUsesOnlyOperationIdentity(t *testing.T) { registry := NewRegistry() if err := registry.RegisterBuiltin(); err != nil {