feat(web): name context sources and mark steering in the transcript

Every logged non-user user/message collapsed into one identical
「上下文注入」 row, and mid-turn steering rendered in exactly the bubble a
turn-opening prompt uses, so the transcript could not say what had been
added or which message interrupted a running turn.

TranscriptAdapter and the history fold now attach a provenance view to
each context node, computed by contextProvenance() from the durable
source alone: a role (inject, or recall for a cross-session snapshot)
and a producer name read out of the log — instruction paths for
workspace-instructions, session titles for session-reference, the plugin
id for a plugin source, and the bare kind for any other. No client-side
table of producer names, so a renamed or newly mounted producer stays
identifiable without a client release and a foreign log projects like a
live one. ContextInjectionRow titles itself from the role and shows the
name beside it; MessageItem captions durable and pending steering
bubbles.

The caption reverses one clause of the no-interjection-chrome decision,
which removed it because the composer could not steer; composer steering
shipped afterwards without amending that note, so this change supplies
the product decision its reintroduction clause required and corrects the
stale facts left in it.

Fixes #1291
This commit is contained in:
creatixchu
2026-08-04 17:44:18 +08:00
parent 11bad56fc3
commit de96087923
50 changed files with 380 additions and 74 deletions

View File

@@ -236,7 +236,10 @@ describe('web e2e: seeded history renders through cold resume', () => {
}],
},
}))
await page.getByRole('button', { name: 'Context injection' }).waitFor({ timeout: 10_000 })
// The header names the producer the durable source records, so the
// reconciled instruction file is readable without expanding the row.
await page.getByRole('button', { name: 'Context injection · AGENTS.md', exact: true })
.waitFor({ timeout: 10_000 })
}, 60_000)
it.skipIf(MODE === 'record')('matches the historical conversation aria golden', async () => {
@@ -254,7 +257,7 @@ describe('web e2e: seeded history renders through cold resume', () => {
it.skipIf(MODE === 'record')('matches the Figma context disclosure geometry', async () => {
onTestFailed(() => saveFailureShot(page, 'web-e2e-context-injection'))
const disclosure = page.getByRole('button', { name: 'Context injection' })
const disclosure = page.getByRole('button', { name: 'Context injection · AGENTS.md', exact: true })
expect(await disclosure.getAttribute('aria-expanded')).toBe('false')
const collapsedIcon = disclosure.locator('svg').first()
const collapsedIconBox = await collapsedIcon.boundingBox()
@@ -365,9 +368,8 @@ describe('web e2e: seeded history renders through cold resume', () => {
source: { kind: 'plugin', plugin: 'fixture' },
}))
const disclosures = page.getByRole('button', { name: 'Context injection' })
await expect.poll(() => disclosures.count(), { timeout: 10_000 }).toBe(2)
const disclosure = disclosures.nth(1)
const disclosure = page.getByRole('button', { name: 'Context injection · fixture', exact: true })
await disclosure.waitFor({ timeout: 10_000 })
await disclosure.click()
await expect.poll(() => disclosure.getAttribute('aria-expanded')).toBe('true')

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- 'button "Failed Bash Error: command aborted" [expanded]':
- img
- text: "Failed Bash Error: command aborted"

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- 'button "Think The user wants me to write a single `run_code` program that:"':
- img
- img

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- button "Think The user wants me to:":
- img
- img

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- button "Think The user wants me to run a simple bash command and reply with \"DONE\".":
- img
- img

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- button "Think The user wants me to reply with a single word. Let me comply.":
- img
- img

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- paragraph: partial
- text: Stopped
- button "Copy":

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- status:
- text: This turn failedAPI key is invalid
- code: AUTH

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- paragraph: partial
- status: Deep diving...
- textbox "Message the agent"

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- group:
- status: Retried model request (1/2) · {{duration}}
- button "Think The user is asking for a one-sentence description of event sourcing. This is a straightforward knowledge question that doesn't require any skill loading or tool calls.":

View File

@@ -11,10 +11,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- 'button "Think The user wants me to plan a small change to add a `--greeting` flag to a CLI. They explicitly told me not to read or write any files, and to call exit_plan_mode with a short plan. Let me do that directly."':
- img
- img

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- button "Think The user wants me to use the ask_user_question tool with specific parameters. Let me do exactly that.":
- img
- img

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- paragraph: partial
- status: Deep diving...
- button "2 queued messages"

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- paragraph: partial
- status: Deep diving...
- button "2 queued messages" [disabled] [expanded]

View File

@@ -8,18 +8,18 @@
- img
- img
- text: "goal Goal created Status: active Objective: Keep the composer context panels aligned Rounds: 0/256 Activation: armed Commands: /goal edit <objective>, /goal pause, /goal clear"
- button "Context injection":
- button "Context injection · goal":
- img
- img
- text: Context injection
- button "Context injection":
- text: Context injection · goal
- button "Context injection · goal":
- img
- img
- text: Context injection
- button "Context injection":
- text: Context injection · goal
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- paragraph: partial
- status: Deep diving...
- region "To-dos":

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- paragraph: partial
- text: Stopped
- button "Copy":

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- paragraph: partial
- status: Deep diving...
- list:

View File

@@ -37,10 +37,10 @@
- button "Context compacted View compaction summary":
- img
- text: Context compacted View compaction summary
- button "Context injection":
- button "Context injection · AGENTS.md":
- img
- img
- text: Context injection
- text: Context injection · AGENTS.md
- img
- text: permission preset read-only
- textbox "Message the agent"

View File

@@ -37,10 +37,10 @@
- button "Context compacted View compaction summary":
- img
- text: Context compacted View compaction summary
- button "Context injection":
- button "Context injection · AGENTS.md":
- img
- img
- text: Context injection
- text: Context injection · AGENTS.md
- textbox "Message the agent"
- button "Commands":
- img

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- button "Think The user wants me to use the ask_user_question tool to ask them a specific question with the given parameters. Let me do exactly that.":
- img
- img
@@ -24,7 +24,7 @@
- img
- text: Ask question waiting
- status: Deep diving...
- text: "Interjection: include the word BANANA in your final reply."
- text: "Steer Interjection: include the word BANANA in your final reply."
- button "Copy":
- img
- region "Ready to continue?":

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- button "Think The user wants me to use the ask_user_question tool to ask them a specific question with the given parameters. Let me do exactly that.":
- img
- img
@@ -22,7 +22,7 @@
- img
- img
- text: Ask question 1/1 answered
- text: "Interjection: include the word BANANA in your final reply. {{clock}}"
- text: "Steer Interjection: include the word BANANA in your final reply. {{clock}}"
- button "Copy":
- img
- button "Branch into a new conversation" [disabled]:

View File

@@ -15,10 +15,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- button "Think The user is asking for a one-sentence description of event sourcing. This is a straightforward knowledge question that doesn't require any skill loading or tool calls.":
- img
- img

View File

@@ -10,10 +10,10 @@
- button "Branch into a new conversation" [disabled]:
- img
- text: Available only on the last message of a completed turn
- button "Context injection":
- button "Context injection · @deepseek-ai/dsh-system-prompt":
- img
- img
- text: Context injection
- text: Context injection · @deepseek-ai/dsh-system-prompt
- button "Search DeepSeek Harness snapshot search":
- img
- img