瀏覽代碼

fix(visualizer): leave motion to presentation choice

ZiyaZhang 4 周之前
父節點
當前提交
e7dc1322a3

+ 2 - 2
.agents/notes/implemented/feature/2026-08-29-inline-visualizer-cordis-extension.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-08-29-inline-visualizer-cordis-extension.md
-2026-08-29-inline-visualizer-cordis-extension.md: 31fb9ae306df93d24d1047d05de2142149f89f29
-2026-08-29-inline-visualizer-cordis-extension.zh.md: f960e51ee3344957208644cd638620e7e3be2499
+2026-08-29-inline-visualizer-cordis-extension.md: e037dcedebf75400c2f53b8f7d0c1b66fb2a261d
+2026-08-29-inline-visualizer-cordis-extension.zh.md: 07210d03868ca4a4dad8984bb4c1d4a9c7bdf9e8

+ 1 - 1
.agents/notes/implemented/feature/2026-08-29-inline-visualizer-cordis-extension.md

@@ -14,7 +14,7 @@ DSH had no first-party Host contract for a model to request a temporary inline v
 
 The package's `./model` function-plugin requires `systemPrompt` and `tools`, then recoverably injects `visualizer`; while authority exists it installs the `tool:visualizer` prompt plus `widget_guidelines` and `show_widget` only in an Agent preset standing scope. `standard` and `cordis` always mount this wrapper, so late authority appearance, withdrawal, and reappearance activate, remove, and reactivate the model surface for existing and new Agents. `minimal` and `ptc` omit it. PTC's nested code-dispatch log does not provide the ordinary `show_widget` call/result identity required by the follow-up bridge. No default application composition mounts the root authority, so the shipped default prompt and tool surfaces remain unchanged.
 
-Each `widget_guidelines` result includes Delivery when `show_widget` is visible, then combines one shared Foundation with only the requested type modules. The Foundation owns host-native composition, responsive flow, theme use, and cross-type accessibility; the type modules own diagram structure, interaction lifecycle, chart semantics, and illustration exceptions.
+Each `widget_guidelines` result includes Delivery when `show_widget` is visible, then combines one shared Foundation with only the requested modules. The Foundation owns host-native composition, responsive flow, theme use, and cross-type accessibility. Content and behavior are independent: callers combine diagram, chart, illustration, or mockup guidance with interactive guidance when motion, manipulation, or adjustable inputs contribute to the presentation.
 
 Mounting the root authority exposes both raw SVG and HTML fragments; source-prefix detection records the kind without exposing renderer deployment policy in the model-visible schema. This change supplies no presentation Client and does not activate the capability in Web, headless, or TUI. The Host exposes no mutable-state report, recovery, or model-read surface. No Visualizer session event, Agent-loop rule, or core schema is added.
 

+ 1 - 1
.agents/notes/implemented/feature/2026-08-29-inline-visualizer-cordis-extension.zh.md

@@ -14,7 +14,7 @@ DSH 缺少一方 Host 契约,让模型请求临时内联视觉内容、渐进
 
 同一包的 `./model` function-plugin 要求 `systemPrompt` 与 `tools`,然后可恢复地注入 `visualizer`;权威存在时,它只在 Agent preset standing scope 安装 `tool:visualizer` 提示词,以及 `widget_guidelines` 与 `show_widget`。`standard` 与 `cordis` 始终挂载该 wrapper,因此权威稍后出现、撤销与再次出现会针对现有及新 Agent 激活、移除与重新激活模型面。`minimal` 与 `ptc` 不包含该 row,因为 PTC 的嵌套 code-dispatch 日志不提供 follow-up bridge 所需的普通 `show_widget` call/result 身份。默认 application composition 均不挂载根权威,因此正式默认提示词与工具面保持不变。
 
-每个 `widget_guidelines` result 都会在 `show_widget` 可见时包含 Delivery,再把一个共享 Foundation 与所请求的类型模块组合起来。Foundation 拥有宿主原生构图、响应式流、主题使用与跨类型可访问性;类型模块分别拥有 diagram 结构、交互生命周期、chart 语义与 illustration 例外。
+每个 `widget_guidelines` result 都会在 `show_widget` 可见时包含 Delivery,再把一个共享 Foundation 与所请求的模块组合起来。Foundation 拥有宿主原生构图、响应式流、主题使用与跨类型可访问性。内容和行为相互独立:当运动、操控或可调输入有助于呈现时,调用方会将 diagram、chart、illustration 或 mockup 指导与 interactive 指导组合使用。
 
 挂载根权威后会同时公开 raw SVG 与 HTML fragment;源码前缀检测记录 kind,而不在模型可见 schema 中暴露 renderer 部署策略。本次变更不提供展示 Client,也不在 Web、headless 或 TUI 中激活该能力。Host 不提供可变状态上报、恢复或模型读取面。实现不新增 Visualizer session event、Agent loop 规则或 core schema。
 

+ 2 - 2
docs/tool-catalog.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write docs/tool-catalog.md
-tool-catalog.md: 731d7b0c45d2e2834848fbb2e27440e5ac8a7401
-tool-catalog.zh.md: b976a15113cb2272f2e51c8a688abcb34131be68
+tool-catalog.md: 34dc6ebd4f0291fee48d6e8c6d3ac0570cbd1e7b
+tool-catalog.zh.md: 14f7a3a4ab18e632787f1b4462d0bf504c6f3b16

+ 2 - 2
docs/tool-catalog.md

@@ -2085,7 +2085,7 @@ todo_write is session-owned state; UIs render the latest todo/write event as a c
 
 ### `show_widget`
 
-Render one temporary inline graphic or interactive widget from conversation content or completed tool results. Source beginning with <svg uses SVG; anything else uses HTML. Pass one small, complete source in this call; validation occurs after submission.
+Render one temporary inline visual from conversation content or completed tool results. Source beginning with <svg uses SVG; anything else uses HTML. Pass one small, complete source in this call; validation occurs after submission.
 
 ```json
 {
@@ -2119,7 +2119,7 @@ Load request-matched construction guidance for a widget response.
   "properties": {
     "modules": {
       "type": "array",
-      "description": "Choose every module that fits the requested result. diagram: a fixed view of nodes and relationships. chart: quantitative data. illustration: a scene or image. interactive: an adjustable calculation, simulation, or animated demonstration. mockup: a product surface shown to explain one interaction.",
+      "description": "Choose every relevant module; content and behavior are independent, so combine modules when useful. diagram: nodes and relationships. chart: quantitative data. illustration: a scene or image. interactive: motion that contributes to the presentation, or direct manipulation and adjustable inputs requested by the user. mockup: a product surface shown to explain one interaction.",
       "items": {
         "type": "string",
         "enum": [

+ 2 - 2
docs/tool-catalog.zh.md

@@ -2092,7 +2092,7 @@ todo_write 是会话所有的状态;UI 将最新的 todo/write 事件渲染为
 
 ### `show_widget`
 
-从对话内容或已完成的工具结果渲染一个临时内联图形或交互组件。以 <svg 开头的源码使用 SVG,其余源码使用 HTML。在本次调用中传入一份小而完整的源码;提交后才会进行校验。
+从对话内容或已完成的工具结果渲染一份临时内联视觉内容。以 <svg 开头的源码使用 SVG,其余源码使用 HTML。在本次调用中传入一份小而完整的源码;提交后才会进行校验。
 
 ```json
 {
@@ -2126,7 +2126,7 @@ todo_write 是会话所有的状态;UI 将最新的 todo/write 事件渲染为
   "properties": {
     "modules": {
       "type": "array",
-      "description": "Choose every module that fits the requested result. diagram: a fixed view of nodes and relationships. chart: quantitative data. illustration: a scene or image. interactive: an adjustable calculation, simulation, or animated demonstration. mockup: a product surface shown to explain one interaction.",
+      "description": "Choose every relevant module; content and behavior are independent, so combine modules when useful. diagram: nodes and relationships. chart: quantitative data. illustration: a scene or image. interactive: motion that contributes to the presentation, or direct manipulation and adjustable inputs requested by the user. mockup: a product surface shown to explain one interaction.",
       "items": {
         "type": "string",
         "enum": [

+ 3 - 2
packages/visualizer/tool-visualizer/src/guidelines.ts

@@ -22,7 +22,7 @@ const FOUNDATION_GUIDANCE = `## Foundation
 
 const GUIDELINES: Readonly<Record<WidgetGuidelineModule, string>> = Object.freeze({
   diagram: `## Diagram
-- Use raw SVG for a fixed diagram, beginning the source with <svg> and putting any styles inside it. Give it one responsive viewBox that fills the available width; do not assume a fixed card width.
+- When using raw SVG for a diagram, begin the source with <svg>, put any styles inside it, and give it one responsive viewBox that fills the available width; do not assume a fixed card width.
 - Match layout to the relationship: use one reading direction for sequences, a cycle only when recurrence is the point, a staged state view when stages need inspection, shallow nested regions for containment, and simplified forms with outside labels for spatial structure. Keep connectors behind nodes, avoid crossings, and label relationships directly.
 - Keep node text to labels and short phrases; move sentence-level explanation to the reply. Fit labels by widening or wrapping nodes. If the relationships still cannot fit at a readable size, split the visual into overview and detail views instead of shrinking text. Use semantic groups, consistent radii and spacing, and a visible hierarchy before decoration. If geometry is illustrative rather than sourced, label it as schematic or not to scale. Do not use emoji as decoration.`,
   mockup: `## Mockup
@@ -34,7 +34,7 @@ const GUIDELINES: Readonly<Record<WidgetGuidelineModule, string>> = Object.freez
 - Match each input to its semantics with one primary control per value: fields for exact entry, choice controls for discrete values, and ranges only for values meant to be swept. Give every control a clear label. Native controls come styled, focusable, and keyboard-accessible; custom controls must match that.
 - Within an HTML fragment, use inspectable DOM or inline SVG elements when they can represent the scene directly; use canvas only when retaining one element per visual mark would be impractical.
 - Keep self-contained interactions and computation local; they must not call the model.
-- Use motion only when change over time carries the explanation. Otherwise start stable; continuous motion waits for a user action unless immediate motion is the requested content. Honor reduced-motion preferences.
+- Use motion when change over time materially contributes to the meaning or experience. Motion may start immediately when it is central to the result; otherwise begin stable and let continuous motion follow a user action. Honor reduced-motion preferences.
 - Reuse a bounded set of DOM or SVG nodes for recurring updates; change textContent or attributes in place instead of rebuilding markup, and stop scheduling while idle, paused, or settled.
 - Keep changing numeric readouts from shifting the layout by using tabular numerals and reserving enough width for expected values.
 - Call window.dshWidget.sendPrompt(text, event) directly from a trusted click or keydown handler, at most once per event, and only when the next step genuinely needs the model. The message enters the conversation immediately, labelled as widget-authored; there is no confirmation step.
@@ -47,6 +47,7 @@ const GUIDELINES: Readonly<Record<WidgetGuidelineModule, string>> = Object.freez
   illustration: `## Illustration
 - Use illustration only when its visual form carries information that prose does not.
 - Derive the visual language from the subject and requested tone, with one clear focal point.
+- An illustration may be still or animated. Combine it with Interactive when motion or manipulation contributes to the presentation.
 - Use canvas for dense or procedurally repeated imagery; use raw SVG when a modest set of inspectable shapes is enough.`,
 })
 

+ 2 - 2
packages/visualizer/tool-visualizer/src/tools.ts

@@ -59,7 +59,7 @@ export function registerVisualizerTools(
         type: 'array',
         required: true,
         items: { type: 'string', enum: WIDGET_GUIDELINE_MODULES },
-        description: 'Choose every module that fits the requested result. diagram: a fixed view of nodes and relationships. chart: quantitative data. illustration: a scene or image. interactive: an adjustable calculation, simulation, or animated demonstration. mockup: a product surface shown to explain one interaction.',
+        description: 'Choose every relevant module; content and behavior are independent, so combine modules when useful. diagram: nodes and relationships. chart: quantitative data. illustration: a scene or image. interactive: motion that contributes to the presentation, or direct manipulation and adjustable inputs requested by the user. mockup: a product surface shown to explain one interaction.',
       },
     },
     output: {
@@ -76,7 +76,7 @@ export function registerVisualizerTools(
 
   ctx.tools.register(defineTool({
     name: 'show_widget',
-    description: 'Render one temporary inline graphic or interactive widget from conversation content or completed tool results. Source beginning with <svg uses SVG; anything else uses HTML. Pass one small, complete source in this call; validation occurs after submission.',
+    description: 'Render one temporary inline visual from conversation content or completed tool results. Source beginning with <svg uses SVG; anything else uses HTML. Pass one small, complete source in this call; validation occurs after submission.',
     parameters: {
       title: { type: 'string', required: true, description: 'Short user-facing title in the user\'s language.' },
       widget_code: { type: 'string', required: true, description: sourceDescription },

+ 5 - 4
packages/visualizer/tool-visualizer/tests/__snapshots__/model-surface.spec.ts.snap

@@ -21,7 +21,7 @@ exports[`Visualizer model surface > ships one neutral SVG and HTML model surface
 - Give every primary visual a concise accessible name and summary.
 
 ## Diagram
-- Use raw SVG for a fixed diagram, beginning the source with <svg> and putting any styles inside it. Give it one responsive viewBox that fills the available width; do not assume a fixed card width.
+- When using raw SVG for a diagram, begin the source with <svg>, put any styles inside it, and give it one responsive viewBox that fills the available width; do not assume a fixed card width.
 - Match layout to the relationship: use one reading direction for sequences, a cycle only when recurrence is the point, a staged state view when stages need inspection, shallow nested regions for containment, and simplified forms with outside labels for spatial structure. Keep connectors behind nodes, avoid crossings, and label relationships directly.
 - Keep node text to labels and short phrases; move sentence-level explanation to the reply. Fit labels by widening or wrapping nodes. If the relationships still cannot fit at a readable size, split the visual into overview and detail views instead of shrinking text. Use semantic groups, consistent radii and spacing, and a visible hierarchy before decoration. If geometry is illustrative rather than sourced, label it as schematic or not to scale. Do not use emoji as decoration.
 
@@ -35,7 +35,7 @@ exports[`Visualizer model surface > ships one neutral SVG and HTML model surface
 - Match each input to its semantics with one primary control per value: fields for exact entry, choice controls for discrete values, and ranges only for values meant to be swept. Give every control a clear label. Native controls come styled, focusable, and keyboard-accessible; custom controls must match that.
 - Within an HTML fragment, use inspectable DOM or inline SVG elements when they can represent the scene directly; use canvas only when retaining one element per visual mark would be impractical.
 - Keep self-contained interactions and computation local; they must not call the model.
-- Use motion only when change over time carries the explanation. Otherwise start stable; continuous motion waits for a user action unless immediate motion is the requested content. Honor reduced-motion preferences.
+- Use motion when change over time materially contributes to the meaning or experience. Motion may start immediately when it is central to the result; otherwise begin stable and let continuous motion follow a user action. Honor reduced-motion preferences.
 - Reuse a bounded set of DOM or SVG nodes for recurring updates; change textContent or attributes in place instead of rebuilding markup, and stop scheduling while idle, paused, or settled.
 - Keep changing numeric readouts from shifting the layout by using tabular numerals and reserving enough width for expected values.
 - Call window.dshWidget.sendPrompt(text, event) directly from a trusted click or keydown handler, at most once per event, and only when the next step genuinely needs the model. The message enters the conversation immediately, labelled as widget-authored; there is no confirmation step.
@@ -50,6 +50,7 @@ exports[`Visualizer model surface > ships one neutral SVG and HTML model surface
 ## Illustration
 - Use illustration only when its visual form carries information that prose does not.
 - Derive the visual language from the subject and requested tone, with one clear focal point.
+- An illustration may be still or animated. Combine it with Interactive when motion or manipulation contributes to the presentation.
 - Use canvas for dense or procedurally repeated imagery; use raw SVG when a modest set of inspectable shapes is enough.",
         "type": "text",
       },
@@ -63,7 +64,7 @@ exports[`Visualizer model surface > ships one neutral SVG and HTML model surface
   },
   "tools": {
     "show_widget": {
-      "description": "Render one temporary inline graphic or interactive widget from conversation content or completed tool results. Source beginning with <svg uses SVG; anything else uses HTML. Pass one small, complete source in this call; validation occurs after submission.",
+      "description": "Render one temporary inline visual from conversation content or completed tool results. Source beginning with <svg uses SVG; anything else uses HTML. Pass one small, complete source in this call; validation occurs after submission.",
       "output": {
         "additionalProperties": false,
         "properties": {
@@ -106,7 +107,7 @@ exports[`Visualizer model surface > ships one neutral SVG and HTML model surface
       "parameters": {
         "properties": {
           "modules": {
-            "description": "Choose every module that fits the requested result. diagram: a fixed view of nodes and relationships. chart: quantitative data. illustration: a scene or image. interactive: an adjustable calculation, simulation, or animated demonstration. mockup: a product surface shown to explain one interaction.",
+            "description": "Choose every relevant module; content and behavior are independent, so combine modules when useful. diagram: nodes and relationships. chart: quantitative data. illustration: a scene or image. interactive: motion that contributes to the presentation, or direct manipulation and adjustable inputs requested by the user. mockup: a product surface shown to explain one interaction.",
             "items": {
               "enum": [
                 "diagram",

+ 2 - 2
packages/visualizer/tool-visualizer/tests/model-surface.spec.ts

@@ -150,13 +150,13 @@ describe('Visualizer model surface', () => {
         modules: {
           type: 'array',
           items: { type: 'string', enum: ['diagram', 'mockup', 'interactive', 'chart', 'illustration'] },
-          description: 'Choose every module that fits the requested result. diagram: a fixed view of nodes and relationships. chart: quantitative data. illustration: a scene or image. interactive: an adjustable calculation, simulation, or animated demonstration. mockup: a product surface shown to explain one interaction.',
+          description: 'Choose every relevant module; content and behavior are independent, so combine modules when useful. diagram: nodes and relationships. chart: quantitative data. illustration: a scene or image. interactive: motion that contributes to the presentation, or direct manipulation and adjustable inputs requested by the user. mockup: a product surface shown to explain one interaction.',
         },
       },
       required: ['modules'],
     })
     expect(show.description)
-      .toBe('Render one temporary inline graphic or interactive widget from conversation content or completed tool results. Source beginning with <svg uses SVG; anything else uses HTML. Pass one small, complete source in this call; validation occurs after submission.')
+      .toBe('Render one temporary inline visual from conversation content or completed tool results. Source beginning with <svg uses SVG; anything else uses HTML. Pass one small, complete source in this call; validation occurs after submission.')
     const staticReceipt = show.output.render?.(
       { title: 'Static', widget_code: '<svg></svg>' },
       { kind: 'svg' },

文件差異過大導致無法顯示
+ 0 - 0
snapshots/web/visualizer-host/session.v2.jsonl


+ 2 - 2
snapshots/web/visualizer-host/tool-schemas.expected.json

@@ -406,7 +406,7 @@
     },
     {
       "name": "show_widget",
-      "description": "Render one temporary inline graphic or interactive widget from conversation content or completed tool results. Source beginning with <svg uses SVG; anything else uses HTML. Pass one small, complete source in this call; validation occurs after submission.",
+      "description": "Render one temporary inline visual from conversation content or completed tool results. Source beginning with <svg uses SVG; anything else uses HTML. Pass one small, complete source in this call; validation occurs after submission.",
       "parameters": {
         "type": "object",
         "properties": {
@@ -618,7 +618,7 @@
         "properties": {
           "modules": {
             "type": "array",
-            "description": "Choose every module that fits the requested result. diagram: a fixed view of nodes and relationships. chart: quantitative data. illustration: a scene or image. interactive: an adjustable calculation, simulation, or animated demonstration. mockup: a product surface shown to explain one interaction.",
+            "description": "Choose every relevant module; content and behavior are independent, so combine modules when useful. diagram: nodes and relationships. chart: quantitative data. illustration: a scene or image. interactive: motion that contributes to the presentation, or direct manipulation and adjustable inputs requested by the user. mockup: a product surface shown to explain one interaction.",
             "items": {
               "type": "string",
               "enum": [

部分文件因文件數量過多而無法顯示