test(web): replay the page card through propose_action
The creation fixture now offers the card with a propose_action call, the tool schema pin records the tool addition after the skill load, and the card goldens follow the shared frame and its Show more and Show less controls.
This commit is contained in:
1 parent
9b04d772b9
commit
1fbebc433f
9 files changed
+1143
-34
No files matched your search
@@ -1,4 +1,4 @@
|
||||
/** The completed answer offers creation; choosing a location does not start it. */
|
||||
/** The completed answer offers creation through a propose_action card; choosing a location does not start it. */
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
@@ -37,17 +37,17 @@ describe('creation recommendation after an explicit wish', () => {
|
||||
await input.fill(fixtureUserPrompts(await readFile(fixture, 'utf8'))[0]!)
|
||||
await input.press('Enter')
|
||||
await settled
|
||||
const card = page.locator('[data-creation-recommendation]')
|
||||
const card = page.locator('[data-action-card]')
|
||||
await card.waitFor({ state: 'visible' })
|
||||
expect(await card.count()).toBe(1)
|
||||
expect(await page.locator('[data-turn-tail] [data-creation-recommendation]').count()).toBe(1)
|
||||
expect(await page.locator('[data-turn-tail] [data-action-card]').count()).toBe(1)
|
||||
const answer = page.getByText('I can create a persistent counter with increment and reset controls. Choose its location below.', { exact: true })
|
||||
const answerBox = await answer.boundingBox()
|
||||
const cardBox = await card.boundingBox()
|
||||
expect(answerBox).not.toBeNull()
|
||||
expect(cardBox!.y).toBeGreaterThanOrEqual(answerBox!.y + answerBox!.height)
|
||||
expect(await card.getByRole('button', { name: 'Create', exact: true }).isEnabled()).toBe(true)
|
||||
await compareOrRefreshGolden(join(directory, 'offered.expected.md'), await captureStableAria(page, '[data-creation-recommendation]', scaffold.workspaceCwd), scaffold.mode)
|
||||
await compareOrRefreshGolden(join(directory, 'offered.expected.md'), await captureStableAria(page, '[data-action-card]', scaffold.workspaceCwd), scaffold.mode)
|
||||
const info = card.getByRole('button', { name: 'How creation works and token usage', exact: true })
|
||||
expect(await info.getAttribute('aria-expanded')).toBe('true')
|
||||
expect(await card.getByRole('note').innerText()).toContain('large number of tokens')
|
||||
@@ -66,11 +66,11 @@ describe('creation recommendation after an explicit wish', () => {
|
||||
expect(await card.getByRole('note').innerText()).toContain('keep chatting here')
|
||||
expect(await card.getByRole('button', { name: 'Create', exact: true }).isEnabled()).toBe(true)
|
||||
expect(await card.evaluate(element => element.scrollWidth <= element.clientWidth)).toBe(true)
|
||||
await compareOrRefreshGolden(join(directory, 'info.expected.md'), await captureStableAria(page, '[data-creation-recommendation]', scaffold.workspaceCwd), scaffold.mode)
|
||||
await compareOrRefreshGolden(join(directory, 'info.expected.md'), await captureStableAria(page, '[data-action-card]', scaffold.workspaceCwd), scaffold.mode)
|
||||
await info.press('Space')
|
||||
expect(await info.getAttribute('aria-expanded')).toBe('false')
|
||||
expect(await card.getByRole('note').count()).toBe(0)
|
||||
const expand = card.getByRole('button', { name: 'View full plan', exact: true })
|
||||
const expand = card.getByRole('button', { name: 'Show more', exact: true })
|
||||
const plan = page.locator(`[id="${await expand.getAttribute('aria-controls')}"]`)
|
||||
const compactHeight = await plan.evaluate(element => element.clientHeight)
|
||||
const previewText = await plan.innerText()
|
||||
@@ -82,8 +82,8 @@ describe('creation recommendation after an explicit wish', () => {
|
||||
await expand.click()
|
||||
expect(await plan.evaluate(element => element.clientHeight)).toBeGreaterThan(compactHeight)
|
||||
expect(await card.getByRole('button', { name: 'Create', exact: true }).isEnabled()).toBe(true)
|
||||
await compareOrRefreshGolden(join(directory, 'expanded.expected.md'), await captureStableAria(page, '[data-creation-recommendation]', scaffold.workspaceCwd), scaffold.mode)
|
||||
await card.getByRole('button', { name: 'Collapse plan', exact: true }).click()
|
||||
await compareOrRefreshGolden(join(directory, 'expanded.expected.md'), await captureStableAria(page, '[data-action-card]', scaffold.workspaceCwd), scaffold.mode)
|
||||
await card.getByRole('button', { name: 'Show less', exact: true }).click()
|
||||
const location = card.getByRole('button', { name: 'Add to: Right sidebar', exact: true })
|
||||
await location.click()
|
||||
expect(await page.getByRole('menuitem').count()).toBe(4)
|
||||
@@ -97,12 +97,12 @@ describe('creation recommendation after an explicit wish', () => {
|
||||
expect(await card.getByRole('button', { name: 'Create', exact: true }).isEnabled()).toBe(false)
|
||||
await custom.fill('A left sidebar entry that opens a full-page calendar')
|
||||
expect(await card.getByRole('button', { name: 'Create', exact: true }).isEnabled()).toBe(true)
|
||||
await compareOrRefreshGolden(join(directory, 'custom-location.expected.md'), await captureStableAria(page, '[data-creation-recommendation]', scaffold.workspaceCwd), scaffold.mode)
|
||||
await compareOrRefreshGolden(join(directory, 'custom-location.expected.md'), await captureStableAria(page, '[data-action-card]', scaffold.workspaceCwd), scaffold.mode)
|
||||
await card.getByRole('button', { name: 'Add to: Write your own', exact: true }).click()
|
||||
await page.getByRole('menuitem', { name: /Session tab/ }).click()
|
||||
expect(await card.getByRole('button', { name: 'Add to: Session tab', exact: true }).isVisible()).toBe(true)
|
||||
expect(await custom.count()).toBe(0)
|
||||
await compareOrRefreshGolden(join(directory, 'options.expected.md'), await captureStableAria(page, '[data-creation-recommendation]', scaffold.workspaceCwd), scaffold.mode)
|
||||
await compareOrRefreshGolden(join(directory, 'options.expected.md'), await captureStableAria(page, '[data-action-card]', scaffold.workspaceCwd), scaffold.mode)
|
||||
expect(await card.evaluate(element => element.scrollWidth <= element.clientWidth)).toBe(true)
|
||||
await card.getByRole('button', { name: 'Not now', exact: true }).click()
|
||||
await card.getByRole('status').getByText('Dismissed', { exact: true }).waitFor()
|
||||
@@ -111,9 +111,9 @@ describe('creation recommendation after an explicit wish', () => {
|
||||
await card.getByRole('status').getByText('Dismissed', { exact: true }).waitFor()
|
||||
acknowledgeReloadConnectionLoss(tripwire, warnings)
|
||||
expect(await card.getByRole('button', { name: 'Create', exact: true }).count()).toBe(0)
|
||||
expect(await card.getByRole('button', { name: 'View full plan', exact: true }).isVisible()).toBe(true)
|
||||
expect(await card.getByRole('button', { name: 'Show more', exact: true }).isVisible()).toBe(true)
|
||||
expect((await scaffold.ctx.pluginManager.listBundles()).some(bundle => bundle.name.startsWith('@dsh-local/view-'))).toBe(false)
|
||||
await compareOrRefreshGolden(join(directory, 'dismissed.expected.md'), await captureStableAria(page, '[data-creation-recommendation]', scaffold.workspaceCwd), scaffold.mode)
|
||||
await compareOrRefreshGolden(join(directory, 'dismissed.expected.md'), await captureStableAria(page, '[data-action-card]', scaffold.workspaceCwd), scaffold.mode)
|
||||
const statusSettled = scaffold.whenTurnSettled()
|
||||
await input.fill(fixtureUserPrompts(await readFile(fixture, 'utf8'))[1]!)
|
||||
await input.press('Enter')
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
- region "Personalized pages":
|
||||
- region "Counter":
|
||||
- text: Personalized pages
|
||||
- button "How creation works and token usage"
|
||||
- strong: Counter
|
||||
- paragraph: "Need: Keep a small counter visible across conversations. Location: A card titled Today’s achievements in the right sidebar. Controls: Increment and reset buttons beside the current value. Storage: Save changes in browser storage across navigation and refresh.…"
|
||||
- button "View full plan"
|
||||
- button "Show more"
|
||||
- text: Add to
|
||||
- 'button "Add to: Write your own"': Write your own
|
||||
- text: Where should it appear?
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
- region "Personalized pages":
|
||||
- region "Counter":
|
||||
- text: Personalized pages
|
||||
- button "How creation works and token usage"
|
||||
- status: Dismissed
|
||||
- strong: Counter
|
||||
- paragraph: "Need: Keep a small counter visible across conversations. Location: A card titled Today’s achievements in the right sidebar. Controls: Increment and reset buttons beside the current value. Storage: Save changes in browser storage across navigation and refresh.…"
|
||||
- button "View full plan"
|
||||
- button "Show more"
|
||||
- paragraph: Add to · Session tab
|
||||
@@ -1,9 +1,9 @@
|
||||
- region "Personalized pages":
|
||||
- region "Counter":
|
||||
- text: Personalized pages
|
||||
- button "How creation works and token usage"
|
||||
- strong: Counter
|
||||
- paragraph: "Need: Keep a small counter visible across conversations. Location: A card titled Today’s achievements in the right sidebar. Controls: Increment and reset buttons beside the current value. Storage: Save changes in browser storage across navigation and refresh. Appearance: Follow the existing sidebar theme in light and dark mode. Completion: Both controls work and reopening restores the saved value."
|
||||
- button "Collapse plan" [expanded]
|
||||
- button "Show less" [expanded]
|
||||
- text: Add to
|
||||
- 'button "Add to: Right sidebar"': Right sidebar
|
||||
- button "Not now"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
- region "Personalized pages":
|
||||
- region "Counter":
|
||||
- text: Personalized pages
|
||||
- button "How creation works and token usage" [expanded]
|
||||
- note:
|
||||
@@ -8,7 +8,7 @@
|
||||
- paragraph: Click Create to start in the background. You can keep chatting here.
|
||||
- strong: Counter
|
||||
- paragraph: "Need: Keep a small counter visible across conversations. Location: A card titled Today’s achievements in the right sidebar. Controls: Increment and reset buttons beside the current value. Storage: Save changes in browser storage across navigation and refresh.…"
|
||||
- button "View full plan"
|
||||
- button "Show more"
|
||||
- text: Add to
|
||||
- 'button "Add to: Right sidebar"': Right sidebar
|
||||
- button "Not now"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
- region "Personalized pages":
|
||||
- region "Counter":
|
||||
- text: Personalized pages
|
||||
- button "How creation works and token usage" [expanded]
|
||||
- note:
|
||||
@@ -8,7 +8,7 @@
|
||||
- paragraph: Click Create to start in the background. You can keep chatting here.
|
||||
- strong: Counter
|
||||
- paragraph: "Need: Keep a small counter visible across conversations. Location: A card titled Today’s achievements in the right sidebar. Controls: Increment and reset buttons beside the current value. Storage: Save changes in browser storage across navigation and refresh.…"
|
||||
- button "View full plan"
|
||||
- button "Show more"
|
||||
- text: Add to
|
||||
- 'button "Add to: Right sidebar"': Right sidebar
|
||||
- button "Not now"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
- region "Personalized pages":
|
||||
- region "Counter":
|
||||
- text: Personalized pages
|
||||
- button "How creation works and token usage"
|
||||
- strong: Counter
|
||||
- paragraph: "Need: Keep a small counter visible across conversations. Location: A card titled Today’s achievements in the right sidebar. Controls: Increment and reset buttons beside the current value. Storage: Save changes in browser storage across navigation and refresh.…"
|
||||
- button "View full plan"
|
||||
- button "Show more"
|
||||
- text: Add to
|
||||
- 'button "Add to: Session tab"': Session tab
|
||||
- button "Not now"
|
||||
|
||||
@@ -11,24 +11,31 @@
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval policy: ask. Operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nCurrent DeepSeek Harness implementation checkout: \"{{sourceRoot}}\".\n\nCurrent DeepSeek Harness Web GUI URL: \"{{webUrl}}\"."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval policy: ask. Operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"harness:source","text":"Current DeepSeek Harness implementation checkout: \"{{sourceRoot}}\"."},{"name":"app:web-surface","text":"Current DeepSeek Harness Web GUI URL: \"{{webUrl}}\"."}]},"role":"user","id":"{{message:3}}"},"surfaceOp":"append"}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"<system-reminder>\nA skill is a reusable set of task-specific instructions. The following skills are available in this session:\n\n<available_skills>\n- `personalized-pages`: Plan an optional page or small tool when the user asks for a page, tab, panel, tool or interface in this app (even for one-off use), wants something to keep, revisit or update later, will keep changing data in your answer, or wants a live view of this app’s own data (Sessions, tasks, logs, workspace). Load this before reading any files or source; it says how to submit the proposal. Not for requested files or code, ordinary answers, existing-feature questions, quoted wishes or declined offers.\n</available_skills>\n\nIf the user names a skill, or the task clearly matches a skill's description, call the `skill` tool with the exact skill name before taking task actions. Load all applicable skills, then follow their full instructions. This catalog contains summaries only; do not infer or follow a skill's instructions until it has been loaded.\nA user may also invoke a skill directly; its <skill_content> block then appears in this conversation. Follow it, and do not call the `skill` tool again for that skill.\n</system-reminder>"}],"source":{"kind":"skill-catalog","form":"catalog","entries":[{"name":"personalized-pages","description":"Plan an optional page or small tool when the user asks for a page, tab, panel, tool or interface in this app (even for one-off use), wants something to keep, revisit or update later, will keep changing data in your answer, or wants a live view of this app’s own data (Sessions, tasks, logs, workspace). Load this before reading any files or source; it says how to submit the proposal. Not for requested files or code, ordinary answers, existing-feature questions, quoted wishes or declined offers."}]},"role":"user","id":"{{message:4}}"},"surfaceOp":"append"}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"Time sampled while preparing turn 1, step 1: {{timeContextTimestamp}}\nBrowser time zone for this request: {{clientTimeZone}}. Interpret otherwise-unqualified dates and times in this zone.\nElapsed since the preceding model-visible message: {{elapsed}}"}],"source":{"kind":"time-context","form":"snapshot","sections":[{"name":"time-context","text":"Time sampled while preparing turn 1, step 1: {{timeContextTimestamp}}\nBrowser time zone for this request: {{clientTimeZone}}. Interpret otherwise-unqualified dates and times in this zone.\nElapsed since the preceding model-visible message: {{elapsed}}"}]},"role":"user","id":"{{message:5}}"},"surfaceOp":"append"}
|
||||
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":"{{tools}}"},"reason":"initial"}}
|
||||
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":["ask_user_question","bash","create_goal","edit","get_goal","glob","grep","interrupt_agent","job_kill","job_list","job_output","list_agents","list_subagent_models","plugin_manager","present","read","read_image","schedule_create","schedule_delete","schedule_list","schedule_update","send_message","skill","subagent","subagent_fork","todo_write","update_goal","web_fetch","web_search","workflow","working_directory","write"]},"reason":"initial"}}
|
||||
{"type":"request/context","data":{"provider":"deepseek-official","model":"deepseek-v4-flash","contextWindow":128000}}
|
||||
{"type":"session/title","data":{"title":"I wish I had a","messageSeqs":[8],"source":{"kind":"fallback"}}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_creation_skill","name":"skill","arguments":"{\"name\":\"personalized-pages\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:6}}"},"stream":[{"type":"chunk","time":1792505538988,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"chunk","time":1792505538988,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_creation_skill","name":"skill","arguments":"{\"name\":\"personalized-pages\"}"}}},{"type":"chunk","time":1792505538988,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_creation_skill","name":"skill","arguments":"{\"name\":\"personalized-pages\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:6}}"},"stream":[{"type":"chunk","time":1792674450282,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"chunk","time":1792674450282,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_creation_skill","name":"skill","arguments":"{\"name\":\"personalized-pages\"}"}}},{"type":"chunk","time":1792674450283,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":1,"callId":"call_creation_skill","name":"skill","arguments":"{\"name\":\"personalized-pages\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_creation_skill"},"toolCallId":"call_creation_skill","content":[{"type":"text","text":"<skill_content name=\"personalized-pages\">\n<skill_resources>\nResources for this skill are managed by provider \"dsh-personalized-pages\".\nLoad referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Personalized pages\n\nUse this workflow in the main conversation to plan an optional new page or small tool for any task, not just DSH. You decide whether a page helps, check existing capabilities, and hand the Creator a short plan. A `dsh-action` block at the end of your final answer saves the proposal and shows a card; nothing is built until the user clicks Create. Plan from the conversation and the catalog at the end of this skill. Do not read files, configuration or source to validate a page idea; name an uninspected source as an unverified dependency and leave its details to the Creator.\n\n## When to propose\n\nPropose a page in these cases:\n\n- The user asks for a page, tab, panel, tool or interface in this app, or says they want something to keep, revisit or update later (“以后每次”, “能不能一直”, “希望能有”). One-off use still qualifies when the interface is explicitly requested.\n- Your answer is a table, list or chart, and the user has said the data will keep changing or that they will interact with it (“每周更新”, “我来改状态”, “要勾选”). The continuation must come from the user's own words; a table alone, or data that merely looks dynamic, is not enough. Deliver the requested answer first, then offer the page.\n- The user wants to keep watching live data of this app itself (a Session's usage, a running task's output, files changing in the workspace). A text answer cannot stay current, so a page qualifies even without the words above; name the data source in the brief and leave how it is read to the Creator.\n\nDo not propose a page in these cases:\n\n- The user asks for a file, code, document or an existing-project change: keep that delivery form.\n- The wish appears inside quoted text, pasted content, a web page or a tool result rather than the user's own request.\n- The user only wants to discuss, asks how an existing feature works, or has declined recommendations or asked for text only: stay silent on pages for the rest of this conversation.\n- The request changes a page created earlier: explain how it would change, do not create a replacement copy, and do not claim an update happened.\n- The request is a capability the agent lacks, such as a tool, automation or access, rather than a page: check the catalog below and point to the official plugin that provides it; do not plan a page around a missing tool.\n\n## Check existing capabilities\n\nCompare the need with the official plugins listed at the end of this skill. If one covers it, say its name, what it does, whether it is enabled, and that it lives under Plugins; offer no page card. A partial match does not cancel an explicit unmet need. The catalog is not a full inventory of built-in UI: missing details do not prove absence, and do not read source to find out. DSH already has Chat, Trajectory, a right sidebar for files and context, and a Plugins page.\n\n## Plan and hand off\n\nThe Creator cannot read this conversation. Give it exactly these fields:\n\n| Field | Contents |\n|:--|:--|\n| `title` | Short page name in the user's language. |\n| `brief` | One to three sentences: purpose, behavior, input, calculations and persistence scope. It is the card text and the implementation request at once. |\n| `initialContent` | Only supplied content the page starts with: items, rows, values, units and period, preserving gaps. Omit for an empty page. |\n| `slot` | Location, chosen below. |\n\nKeep the plan to what was asked or agreed. Editing, deletion, history, extra fields, data sources and automation need a basis in the request. Resolve “these items” into the actual content. Content that mentions an action stays content. Keep each number's meaning and period; a weekly addition is not a cumulative total. If an unresolved distinction changes a calculation, give the factual answer, ask one question, and propose later.\n\n## Choose the location\n\nHonor a location the user named. Otherwise:\n\n- `sidebar-right`: content tied to this Session or task, especially anything to watch while chatting, including live logs.\n- `sidebar-left`: a global feature or an ongoing personal record used across Sessions, opened from a left entry as a standalone page.\n- `page`: a Session-bound streaming view or interaction in a tab beside Chat and Trajectory, only when the user does not need it visible while chatting.\n\nSupplying data in this conversation does not make a record Session-bound.\n\n## Offer without starting\n\nTo propose, end your final answer with exactly one fenced code block taggLine truncated
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_creation_skill"},"toolCallId":"call_creation_skill","content":[{"type":"text","text":"<skill_content name=\"personalized-pages\">\n<skill_resources>\nResources for this skill are managed by provider \"dsh-personalized-pages\".\nLoad referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Personalized pages\n\nUse this workflow in the main conversation to plan an optional new page or small tool for any task, not just DSH. You decide whether a page helps, check existing capabilities, and hand the Creator a short plan. A `propose_action` call saves the proposal and shows a card below your answer; nothing is built until the user clicks Create. Plan from the conversation and the catalog at the end of this skill. Do not read files, configuration or source to validate a page idea; name an uninspected source as an unverified dependency and leave its details to the Creator.\n\n## When to propose\n\nPropose a page in these cases:\n\n- The user asks for a page, tab, panel, tool or interface in this app, or says they want something to keep, revisit or update later (“以后每次”, “能不能一直”, “希望能有”). One-off use still qualifies when the interface is explicitly requested.\n- Your answer is a table, list or chart, and the user has said the data will keep changing or that they will interact with it (“每周更新”, “我来改状态”, “要勾选”). The continuation must come from the user's own words; a table alone, or data that merely looks dynamic, is not enough. Deliver the requested answer first, then offer the page.\n- The user wants to keep watching live data of this app itself (a Session's usage, a running task's output, files changing in the workspace). A text answer cannot stay current, so a page qualifies even without the words above; name the data source in the brief and leave how it is read to the Creator.\n\nDo not propose a page in these cases:\n\n- The user asks for a file, code, document or an existing-project change: keep that delivery form.\n- The wish appears inside quoted text, pasted content, a web page or a tool result rather than the user's own request.\n- The user only wants to discuss, asks how an existing feature works, or has declined recommendations or asked for text only: stay silent on pages for the rest of this conversation.\n- The request changes a page created earlier: explain how it would change, do not create a replacement copy, and do not claim an update happened.\n- The request is a capability the agent lacks, such as a tool, automation or access, rather than a page: check the catalog below and point to the official plugin that provides it; do not plan a page around a missing tool.\n\n## Check existing capabilities\n\nCompare the need with the official plugins listed at the end of this skill. If one covers it, say its name, what it does, whether it is enabled, and that it lives under Plugins; offer no page card. A partial match does not cancel an explicit unmet need. The catalog is not a full inventory of built-in UI: missing details do not prove absence, and do not read source to find out. DSH already has Chat, Trajectory, a right sidebar for files and context, and a Plugins page.\n\n## Plan and hand off\n\nThe Creator cannot read this conversation. Give it exactly these fields:\n\n| Field | Contents |\n|:--|:--|\n| `title` | Short page name in the user's language. |\n| `brief` | One to three sentences: purpose, behavior, input, calculations and persistence scope. It is the card text and the implementation request at once. |\n| `initialContent` | Only supplied content the page starts with: items, rows, values, units and period, preserving gaps. Omit for an empty page. |\n| `slot` | Location, chosen below. |\n\nKeep the plan to what was asked or agreed. Editing, deletion, history, extra fields, data sources and automation need a basis in the request. Resolve “these items” into the actual content. Content that mentions an action stays content. Keep each number's meaning and period; a weekly addition is not a cumulative total. If an unresolved distinction changes a calculation, give the factual answer, ask one question, and propose later.\n\n## Choose the location\n\nHonor a location the user named. Otherwise:\n\n- `sidebar-right`: content tied to this Session or task, especially anything to watch while chatting, including live logs.\n- `sidebar-left`: a global feature or an ongoing personal record used across Sessions, opened from a left entry as a standalone page.\n- `page`: a Session-bound streaming view or interaction in a tab beside Chat and Trajectory, only when the user does not need it visible while chatting.\n\nSupplying data in this conversation does not make a record Session-bound.\n\n## Offer without starting\n\nTo propose, call `propose_action` once, in the same turn as loading this skill, withLine truncated
|
||||
{"type":"step/end","data":{"turn":1,"step":1}}
|
||||
{"type":"step/start","data":{"turn":1,"step":2}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"text","text":"I can create a persistent counter with increment and reset controls. Choose its location below.\n\n```dsh-action\n{\"action\": \"create_personalized_page\", \"title\": \"Counter\", \"brief\": \"Need: Keep a small counter visible across conversations.\\nLocation: A card titled Today’s achievements in the right sidebar.\\nControls: Increment and reset buttons beside the current value.\\nStorage: Save changes in browser storage across navigation and refresh.\\nAppearance: Follow the existing sidebar theme in light and dark mode.\\nCompletion: Both controls work and reopening restores the saved value.\", \"slot\": \"sidebar-right\"}\n```"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:8}}"},"stream":[{"type":"chunk","time":1792505539242,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":1792505539242,"index":0,"dt":[],"texts":["I can create a persistent counter with increment and reset controls. Choose its location below.\n\n```dsh-action\n{\"action\": \"create_personalized_page\", \"title\": \"Counter\", \"brief\": \"Need: Keep a small counter visible across conversations.\\nLocation: A card titled Today’s achievements in the right sidebar.\\nControls: Increment and reset buttons beside the current value.\\nStorage: Save changes in browser storage across navigation and refresh.\\nAppearance: Follow the existing sidebar theme in light and dark mode.\\nCompletion: Both controls work and reopening restores the saved value.\", \"slot\": \"sidebar-right\"}\n```"]},{"type":"chunk","time":1792505539242,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"I can create a persistent counter with increment and reset controls. Choose its location below.\n\n```dsh-action\n{\"action\": \"create_personalized_page\", \"title\": \"Counter\", \"brief\": \"Need: Keep a small counter visible across conversations.\\nLocation: A card titled Today’s achievements in the right sidebar.\\nControls: Increment and reset buttons beside the current value.\\nStorage: Save changes in browser storage across navigation and refresh.\\nAppearance: Follow the existing sidebar theme in light and dark mode.\\nCompletion: Both controls work and reopening restores the saved value.\", \"slot\": \"sidebar-right\"}\n```"}}},{"type":"chunk","time":1792505539242,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}
|
||||
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":["ask_user_question","bash","create_goal","edit","get_goal","glob","grep","interrupt_agent","job_kill","job_list","job_output","list_agents","list_subagent_models","plugin_manager","present","propose_action","read","read_image","schedule_create","schedule_delete","schedule_list","schedule_update","send_message","skill","subagent","subagent_fork","todo_write","update_goal","web_fetch","web_search","workflow","working_directory","write"]},"reason":"change"}}
|
||||
{"type":"developer/message","data":{"turn":1,"step":2,"message":{"source":{"kind":"tool-registry"},"content":[{"type":"tool-addition","toolName":"propose_action"}],"role":"developer","id":"{{message:8}}"},"headerSeq":20},"surfaceOp":"append"}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_creation_card","name":"propose_action","arguments":"{\"action\":\"create_personalized_page\",\"title\":\"Counter\",\"brief\":\"Need: Keep a small counter visible across conversations.\\nLocation: A card titled Today’s achievements in the right sidebar.\\nControls: Increment and reset buttons beside the current value.\\nStorage: Save changes in browser storage across navigation and refresh.\\nAppearance: Follow the existing sidebar theme in light and dark mode.\\nCompletion: Both controls work and reopening restores the saved value.\",\"details\":{\"slot\":\"sidebar-right\"}}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:9}}"},"stream":[{"type":"chunk","time":1792674450652,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"chunk","time":1792674450652,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_creation_card","name":"propose_action","arguments":"{\"action\":\"create_personalized_page\",\"title\":\"Counter\",\"brief\":\"Need: Keep a small counter visible across conversations.\\nLocation: A card titled Today’s achievements in the right sidebar.\\nControls: Increment and reset buttons beside the current value.\\nStorage: Save changes in browser storage across navigation and refresh.\\nAppearance: Follow the existing sidebar theme in light and dark mode.\\nCompletion: Both controls work and reopening restores the saved value.\",\"details\":{\"slot\":\"sidebar-right\"}}"}}},{"type":"chunk","time":1792674450652,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":2,"callId":"call_creation_card","name":"propose_action","arguments":"{\"action\":\"create_personalized_page\",\"title\":\"Counter\",\"brief\":\"Need: Keep a small counter visible across conversations.\\nLocation: A card titled Today’s achievements in the right sidebar.\\nControls: Increment and reset buttons beside the current value.\\nStorage: Save changes in browser storage across navigation and refresh.\\nAppearance: Follow the existing sidebar theme in light and dark mode.\\nCompletion: Both controls work and reopening restores the saved value.\",\"details\":{\"slot\":\"sidebar-right\"}}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":2,"message":{"role":"tool","source":{"kind":"tool","callId":"call_creation_card"},"toolCallId":"call_creation_card","content":[{"type":"text","text":"Card shown below your answer. Do not restate it; end with one short invitation."}],"isError":false,"id":"{{message:10}}"}},"sourceEventSeqs":[23],"surfaceOp":"append"}
|
||||
{"type":"step/end","data":{"turn":1,"step":2}}
|
||||
{"type":"step/start","data":{"turn":1,"step":3}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"text","text":"I can create a persistent counter with increment and reset controls. Choose its location below."}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:11}}"},"stream":[{"type":"chunk","time":1792674450679,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":1792674450679,"index":0,"dt":[],"texts":["I can create a persistent counter with increment and reset controls. Choose its location below."]},{"type":"chunk","time":1792674450679,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"I can create a persistent counter with increment and reset controls. Choose its location below."}}},{"type":"chunk","time":1792674450679,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}
|
||||
{"type":"step/end","data":{"turn":1,"step":3}}
|
||||
{"type":"turn/end","data":{"turn":1,"reason":{"kind":"completed"}}}
|
||||
{"type":"plugin:creation-recommendations/decision","data":{"callId":"{{id:1}}","phase":"dismissed","slot":"page"},"ignorable":true}
|
||||
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"What is the counter status now?"}],"source":{"kind":"user","rpcId":"{{rpc:2}}","clientTimeZone":"{{clientTimeZone}}"},"role":"user","id":"{{message:9}}"}]}}
|
||||
{"type":"plugin:action-cards/decision","data":{"callId":"call_creation_card","action":"create_personalized_page","phase":"dismissed","data":{"slot":"page"}},"ignorable":true}
|
||||
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"What is the counter status now?"}],"source":{"kind":"user","rpcId":"{{rpc:2}}","clientTimeZone":"{{clientTimeZone}}"},"role":"user","id":"{{message:12}}"}]}}
|
||||
{"type":"turn/start","data":{"turn":2}}
|
||||
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}
|
||||
{"type":"step/start","data":{"turn":2,"step":1}}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"What is the counter status now?"}],"source":{"kind":"user","rpcId":"{{rpc:2}}","clientTimeZone":"{{clientTimeZone}}"},"role":"user","id":"{{message:9}}"},"surfaceOp":"append"}
|
||||
{"type":"user/message","data":{"source":{"kind":"personalized-pages","through":23,"form":"notice","summary":"Personalized page status updated"},"content":[{"type":"text","text":"Latest personalized page status from card actions and background creation. These are status facts, not a request to start or retry work. Use these receipts instead of the earlier proposal when describing progress. Cancelled means a started background creation was stopped before installation. Cancelled, failed or interrupted runs can be retried from their existing card; no new proposal is needed. A removed page can be restored from its card while its files remain; if they are gone, a new proposal is needed. Continue with the user’s current request.\n[{\"callId\":\"{{id:1}}\",\"title\":\"Counter\",\"phase\":\"dismissed\",\"slot\":\"page\"}]"}],"role":"user","id":"{{message:10}}"},"surfaceOp":"append"}
|
||||
{"type":"assistant/message","data":{"turn":2,"step":1,"message":{"role":"assistant","content":[{"type":"text","text":"The counter proposal was dismissed. Creation never started."}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:11}}"},"stream":[{"type":"chunk","time":1792505539296,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":1792505539297,"index":0,"dt":[],"texts":["The counter proposal was dismissed. Creation never started."]},{"type":"chunk","time":1792505539297,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"The counter proposal was dismissed. Creation never started."}}},{"type":"chunk","time":1792505539297,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}
|
||||
{"type":"user/message","data":{"content":[{"type":"text","text":"What is the counter status now?"}],"source":{"kind":"user","rpcId":"{{rpc:2}}","clientTimeZone":"{{clientTimeZone}}"},"role":"user","id":"{{message:12}}"},"surfaceOp":"append"}
|
||||
{"type":"user/message","data":{"source":{"kind":"action-cards","through":30,"form":"notice","summary":"Action card status updated"},"content":[{"type":"text","text":"Latest status of action cards from user actions and background work. These are status facts, not a request to start or retry work. Use these receipts instead of the earlier proposal when describing progress. Cancelled means a started background creation was stopped before installation. Cancelled, failed or interrupted runs can be retried from their existing card; no new proposal is needed. A removed page can be restored from its card while its files remain; if they are gone, a new proposal is needed. Continue with the user’s current request.\n[{\"action\":\"create_personalized_page\",\"callId\":\"call_creation_card\",\"title\":\"Counter\",\"phase\":\"dismissed\",\"data\":{\"slot\":\"page\"}}]"}],"role":"user","id":"{{message:13}}"},"surfaceOp":"append"}
|
||||
{"type":"assistant/message","data":{"turn":2,"step":1,"message":{"role":"assistant","content":[{"type":"text","text":"The counter proposal was dismissed. Creation never started."}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:14}}"},"stream":[{"type":"chunk","time":1792674451829,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":1792674451829,"index":0,"dt":[],"texts":["The counter proposal was dismissed. Creation never started."]},{"type":"chunk","time":1792674451829,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"The counter proposal was dismissed. Creation never started."}}},{"type":"chunk","time":1792674451829,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}
|
||||
{"type":"step/end","data":{"turn":2,"step":1}}
|
||||
{"type":"turn/end","data":{"turn":2,"reason":{"kind":"completed"}}}
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user