Merge remote-tracking branch 'origin/master' into xtr/agent-loop-message-machine
# Conflicts: # docs/core-data-structures/tools.i18n.yaml # examples/acp-agent/tests/snapshots/code-mode-workspace-context/session.jsonl # packages/core/tools/README.i18n.yaml
This commit is contained in:
@@ -162,7 +162,14 @@ export class SessionManager {
|
||||
* @param text - exact controlled-input value for the active frontend Session.
|
||||
*/
|
||||
updateIntent(text: string): void {
|
||||
this.getIntent()?.updatePendingPrompt(text)
|
||||
const session = this.getIntent()
|
||||
if (session === undefined) return
|
||||
session.updatePendingPrompt(text)
|
||||
// The intent watch defers via markDirty, but the hero composer reads this
|
||||
// prompt from the LIST snapshot as a controlled value: it must flush in
|
||||
// the same tick as onChange (see Notifier.notifyNow) or React rolls the
|
||||
// textarea back and IME composition breaks.
|
||||
this.notifier.notifyNow()
|
||||
}
|
||||
|
||||
private discardIntent(): void {
|
||||
|
||||
@@ -60,6 +60,34 @@ describe('frontend Session and Workspace intents', () => {
|
||||
expect(workspaces.list.getSnapshot().intent).toBeUndefined()
|
||||
})
|
||||
|
||||
it('echoes updateIntent into the list snapshot in the same tick (controlled-input contract)', async () => {
|
||||
const api = new FakeApiClient()
|
||||
const { sessions, workspaces } = services(api)
|
||||
await ready(api, workspaces, sessions, [workspace('target')])
|
||||
let notified = 0
|
||||
sessions.list.subscribe(() => { notified += 1 })
|
||||
// IME composition drives change events that a controlled textarea must see
|
||||
// reflected before the handler returns; a microtask-deferred echo makes
|
||||
// React roll the DOM back and the composition commits partial keystrokes.
|
||||
sessions.updateIntent('你')
|
||||
expect(sessions.list.getSnapshot().intent?.prompt).toBe('你')
|
||||
expect(notified).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('ignores updateIntent with no active Intent', async () => {
|
||||
const api = new FakeApiClient()
|
||||
const { sessions, workspaces } = services(api)
|
||||
await ready(api, workspaces, sessions, [workspace('only', [sid('s-real')])], [
|
||||
{ sessionId: sid('s-real'), updatedAt: 1, running: false },
|
||||
])
|
||||
sessions.open(sid('s-real'))
|
||||
expect(sessions.list.getSnapshot().intent).toBeUndefined()
|
||||
let notified = 0
|
||||
sessions.list.subscribe(() => { notified += 1 })
|
||||
sessions.updateIntent('dropped')
|
||||
expect(notified).toBe(0)
|
||||
})
|
||||
|
||||
it('materializes zero-state Workspace and Session intents and retains a rejected first prompt', async () => {
|
||||
const api = new FakeApiClient()
|
||||
const { sessions, workspaces } = services(api)
|
||||
|
||||
Reference in New Issue
Block a user