Skip to content

Enforce agent-state UX for app→agent features - #18

Closed
ahmad-ajmal wants to merge 1 commit into
mainfrom
ahmad/enforce-agent-state
Closed

ahmad-ajmal wants to merge 1 commit into
mainfrom
ahmad/enforce-agent-state

Conversation

@ahmad-ajmal

@ahmad-ajmal ahmad-ajmal commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Work an app queues for an agent now has to be visible in the View until it is done. validate enforces it, walk-verify checks it, and every blueprint with a queue and a View ships a component that does it, so the default path is the good one.

What changed

1. Validate gate: new step, "agent work shown in the View" (framework/cli/src/lib/agentState.ts).

  • What it scans for: a static, stack-agnostic scan finds trigger(…) calls in app-owned code that name a capability. It recognises the JS, Go, Ruby, Python (capability=) and Rust (Some(…)) spellings, plus the adapter's object form.
  • When it fails: when no View code renders the agent-task component or reads /api/_a2app/tasks/. The failure names each call site and points at the creator-skill rule.
  • What it ignores: comments, strings, definitions of trigger, system-owned files, dependencies, build output and tests. The component's own file doesn't count, so shipping it is not using it.
  • Apps with no human View (python-fastapi) get no verdict.

2. UI kit: an agent-task panel, badge and useAgentTask hook.

  • Files: AgentTask.jsx for react-node, go-react and rust-react; Vue components plus agentTask.js for rails-vue.
  • Polling: one poller per task, shared by badge and panel, only while unfinished, and slower when unclaimed, rate-limited or the tab is hidden.
  • States:
    • waiting, with elapsed time and a "no agent is listening" hint after ~20 s
    • working, with the agent's step and running time
    • done, with the result in its own full-width block: line breaks kept, links clickable, clamped behind "Show more"
    • failed, with the reason in words (the queue's and bridge's own codes are translated) and "Ask again"
  • Fallbacks:
    • record-written progress for multi-user apps, where the task read answers 401
    • the run's printed output when the bridge closed a task without a summary

3. Starters:

  • Ask an agent: an "Ask an agent" button, and an agentTask field set by request-triage.
  • Re-asks: the previous task id goes in the payload. Identical triggers dedupe to one task even after it finished, so a retry would otherwise get the old failure back.

4. Skills:

  • creator states the result-rendering rule (own full-width block, never the title cell) and the gate.
  • walk-verify gets check 6c, which drives every state with the verifier playing the agent from the CLI.
  • modify points at both.

How it was verified

  • Unit tests: framework/cli/test/agent-state.test.mjs covers every stack spelling, the false-positive cases, the View verdicts, and all five shipped starters passing their own gate. Full suite green, conformance 86/86.
  • Gate as a builder hits it: rewrote a starter View to queue work and only toast. validate failed, naming the line. After rendering the panel, it passed.
  • Real use:
    • react-node: every state driven in a browser, phone width included.
    • Vue View: the same flow, served against the react-node backend.
    • Go: runner exercised over HTTP.
    • Rust: builds and passes its self-test.
    • Python: runner called directly.
    • Real agent: Claude Code took two tasks through agent-app bridge start and both results displayed correctly. That needed the bridge fixes in the companion PR.

Not covered

  • Ruby: the Ruby starter's runner change (lib/a2app_schema.rb) has not been executed (no Ruby on the test machine).
  • Gate scope: the check is app-wide. If one feature already shows its work, a second that only toasts still passes. walk-verify 6c covers each feature.

Work an app queues for an agent now has to be visible in the View until it
is done, and the default path makes that the easy thing to do (#13).

- validate: new "agent work shown in the View" step. A stack-agnostic static
  scan finds trigger(...) calls that name a capability in app-owned code (JS,
  Go, Ruby, Python, Rust spellings; comments, strings, definitions, system
  files, deps and tests ignored) and fails when no View code renders the
  agent-task component or reads /api/_a2app/tasks/. The component's own file
  does not count.
- UI kit: an agent-task panel, badge and useAgentTask hook in every blueprint
  with a queue and a View (AgentTask.jsx for react-node/go/rust; Vue
  components + agentTask.js for rails-vue). One shared poller per task, every
  state rendered (waiting with elapsed time and a no-listener hint, working
  with step, done with a readable full-width result, failed with the reason
  in words and Ask again), record-written progress for multi-user apps, and
  the run's printed output when the bridge closed the task without a summary.
- Starters: "Ask an agent" button, agentTask field set by request-triage, and
  the previous task id in the payload so asking again is a new request.
- Skills: creator states the result-rendering rule and the gate; walk-verify
  gets check 6c for queued work; modify points at both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant