Skip to content

Surface autonomous provider errors in chat - #102

Draft
k2v7n24cbf-cyber wants to merge 4 commits into
sandydasari:mainfrom
k2v7n24cbf-cyber:agent/autonomous-upstream-error-ui
Draft

Surface autonomous provider errors in chat#102
k2v7n24cbf-cyber wants to merge 4 commits into
sandydasari:mainfrom
k2v7n24cbf-cyber:agent/autonomous-upstream-error-ui

Conversation

@k2v7n24cbf-cyber

@k2v7n24cbf-cyber k2v7n24cbf-cyber commented Jul 20, 2026

Copy link
Copy Markdown

Summary

Surface provider/model failures from dispatcher-driven autonomous turns in the chat UI instead of leaving users with a silent run/idle cycle.

This change:

  • captures raw streamText errors in Agent.runAutonomous() via the existing runStream({ onError }) hook
  • persists and broadcasts an assistant data-upstream-error message for autonomous failures
  • preserves dispatcher failure semantics by rethrowing provider errors after the visible message is saved
  • skips memory extraction for failed autonomous turns
  • normalizes provider error text through the shared extractErrorText() helper so thrown plain objects and nested provider responses do not render or log as [object Object]
  • adds a bounded dump fallback for circular values, BigInt, symbols, functions, and unreadable fields
  • routes dispatcher/task parking, subagent, extractor, and compression failure strings through the same formatter
  • logs interactive /api/chat upstream provider failures with session, agent, provider, status, and the same sanitized message shown in the UI
  • adds e2e/unit coverage for autonomous stream failures, nested provider error objects, dispatcher task parking, and interactive chat upstream-error logging

Observation

During an autonomous agent session, a provider-side model rejection was visible in the daemon logs but the browser UI showed no useful error. The session appeared to hang or silently return to idle because no assistant message was appended to the conversation.

Interactive /api/chat turns already had a visible provider-error path: failed turns append a data-upstream-error part that the existing message bubble renders as a Provider error card. Dispatcher-run autonomous turns did not have the same behavior.

A related logging/display failure could still collapse thrown plain objects into [object Object], which hid the useful provider detail even after the visible error path existed. The interactive chat path also persisted the visible error but did not emit a matching structured daemon log line for that captured upstream failure.

Root Cause

runAutonomous() drove the model stream directly and let provider failures propagate to the dispatcher. The dispatcher logged the error and attempted task parking, but that does not guarantee a session-visible message:

  • if the failure happens before the agent claims a task, there may be no in-progress task to annotate
  • even when the dispatcher logs the failure, the chat stream/history receives no messages_appended event
  • the browser only renders persisted messages and known SSE events, so the user sees state movement without a concrete failure reason

The UI was therefore missing the same error-surfacing contract already used by interactive chat.

Separately, several fallback paths converted unknown thrown values with String(error). For plain provider objects, that produces [object Object] instead of the nested message/body that operators need for debugging.

Impact

This is provider-agnostic. It is not specific to ChatGPT OAuth. Any provider/model error that reaches the AI SDK stream error path should now become visible in the autonomous session as a Provider error card, while still being treated as a failed turn by the dispatcher.

The same formatter is now used across the critical agent/provider failure path, so UI messages, dispatcher logs, task parking comments, subagent helper failures, extractor failures, compression failures, and interactive chat upstream-error logs get a readable bounded string when a provider throws a non-Error value.

Timeout handling is unchanged.

Validation

Local validation completed:

  • pnpm build
  • pnpm --filter @openacme/agent-core test -- error-classifier.test.ts subagent.test.ts extractor.test.ts compression.test.ts
  • pnpm --filter @openacme/agent-core test -- error-classifier
  • pnpm --filter @openacme/agent-core check-types
  • pnpm --filter @openacme/server check-types
  • pnpm --filter @openacme/server test -- dispatcher.test.ts
  • pnpm --filter @openacme/server test -- app-upstream-log.test.ts
  • push hook: pnpm build
  • push hook: pnpm --filter @openacme/server test:e2e

The full server e2e push-hook run passed: 13 test files, 27 tests.

k2v7n24cbf-cyber added a commit to k2v7n24cbf-cyber/openacme that referenced this pull request Jul 22, 2026
Merge staged copy of sandydasari#102 into local-stage.
@k2v7n24cbf-cyber

Copy link
Copy Markdown
Author

Added the session title refresh fix to this PR via commit 51bb406 (Broadcast session title updates).

What changed:

  • Agent.fireTitle now writes titles through a helper that also broadcasts session_title.
  • The per-session SSE hook and home stream listen for session_title, so the UI no longer stays on Untitled session after the post-turn title write.
  • The idle refetch path no longer overwrites a freshly received title with a null/stale response.
  • Added unit coverage for both generated-title and fallback-title broadcasts.

Validation completed on the local-stage branch carrying the same fix:

  • pnpm --filter @openacme/agent-core test -- agent-fire-title.test.ts
  • pnpm --filter @openacme/agent-core check-types
  • pnpm --filter @openacme/server check-types
  • pnpm --filter web check-types
  • pnpm --filter @openacme/server exec vitest run --config vitest.e2e.config.ts test/e2e/chat.e2e.ts
  • local-stage commit hook: turbo run check-types and turbo run test
  • local-stage pre-push hook: turbo run build and pnpm --filter @openacme/server test:e2e

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