Commit Graph

13 Commits

Author SHA1 Message Date
Carlos Escalante
0d0d60600d Assistant: intercept connect on the single-route transport too
All checks were successful
Deploy to VPS / test (push) Successful in 1m35s
Deploy to VPS / deploy (push) Successful in 22s
The connect intercept only matched POST …/connect, but CopilotKit talks
to the runtime in single-route mode: everything POSTs to
/api/copilotkit with the operation in the body envelope
({method:"agent/connect"}). So the in-memory runner kept replaying the
BFF process's full event history on every CopilotChat mount — every
conversation since server start, across clears — which is exactly the
stacked resurrected conversations seen in prod after navigating away
and back. Now both transports get the immediately-completed stream.

Verified with the reported repro: three conversations with clears
between, navigate away and back → only the third remains; reload
hydration unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 20:23:05 -06:00
Carlos Escalante
0f34a64e51 Assistant: reliable "Nueva conversación" reset
All checks were successful
Deploy to VPS / test (push) Successful in 1m33s
Deploy to VPS / deploy (push) Successful in 29s
Clearing in place (setMessages + remount) left the conversation
rendered — CopilotKit keeps chat state beyond agent.messages — so the
button now reloads the page after deleting the thread: a fresh boot
hydrates from the empty store and shows the welcome screen with
suggestions, which previously only appeared after a manual refresh.

Supporting changes:
- CopilotChat gets an explicit agentId="wealthysmart" (without it, it
  resolves DEFAULT_AGENT_ID and can bind a different client agent
  instance than useAgent's).
- The BFF answers CopilotChat's POST …/connect with an
  immediately-completed stream: the runtime's in-memory runner replays
  this PROCESS's event history, which resurrects cleared conversations
  and double-feeds hydration. The empty-messages hydration run against
  the DB store is the single restore path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 19:33:41 -06:00
Carlos Escalante
8f51e33fe0 Assistant: drop mid-run MESSAGES_SNAPSHOT instead of reconciling it
All checks were successful
Deploy to VPS / test (push) Successful in 1m32s
Deploy to VPS / deploy (push) Successful in 20s
Prod bug: earlier assistant replies vanished as new turns completed and
only came back on refresh. Debug capture showed why: with persistence
on, the run-end snapshot rebuilds history under STORE ids while the
client holds it under STREAMED ids (MAF re-mints post-tool-call text
ids, their #3619). ag-ui apply treats the snapshot as authoritative —
matching ids get replaced (streamed text wiped by the store's
empty-content toolCall entry) and the store's text copies were being
filtered out by ReconcileSnapshotMiddleware as presumed duplicates, so
prior answers had no surviving representation.

Reconciling id-mismatched snapshots is unwinnable; skip them instead.
During a normal run the client already built the turn from streamed
events and the snapshot adds nothing. Hydration replays (empty
input.messages) still pass through — there the snapshot IS the
conversation, and every reload converges the client to store ids.
ReconcileSnapshotMiddleware is replaced by the much simpler
DropRunMessagesSnapshotMiddleware.

Verified in dev: multi-turn history persists across runs, one card that
survives follow-ups, reload replays everything, no duplicates.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 18:56:37 -06:00
Carlos Escalante
eb400ab1e9 Assistant: suppress repeated render-tool calls
All checks were successful
Deploy to VPS / test (push) Successful in 1m31s
Deploy to VPS / deploy (push) Successful in 2m1s
After the client returns a render tool's result, the model sometimes
re-issues the identical call with a fresh id on the follow-up run,
painting a second copy of the spending-summary card (observed live on
MAF 1.10 / CK 1.62). DeduplicateToolCallMiddleware now tracks which
render tools already ran in the current user turn and drops repeats —
their streamed TOOL_CALL_* events and their entries in the run's
MESSAGES_SNAPSHOT. The system prompt also tells the model the card is
already displayed once its "ok" result is present.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 18:10:51 -06:00
Carlos Escalante
bbcfaa7808 Assistant: hydrate the persisted thread in the UI
- Asistente.tsx pins threadId "main" on CopilotChat (an explicit stable
  id stops the per-mount message wipe), runs a hydration pass on page
  load — an empty-messages run makes MAF replay the stored snapshot as
  MESSAGES_SNAPSHOT with no LLM call — and sends the Inicio ask-box
  question only after hydration so every normal run carries the full
  client-known history. "Nueva conversación" clears the stored thread
  behind a ConfirmDialog.
- server.ts: the BFF no longer injects context into empty-messages
  requests (that would defeat MAF's hydration trigger), and the snapshot
  reconciliation passes hydration replays through untouched and treats
  ids the client already sent as history rather than duplicates.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 18:10:35 -06:00
Carlos Escalante
0e03284c95 Assistant: restore ReconcileSnapshotMiddleware
Retiring it in the middleware audit was premature: MAF 1.10 reuses the
streamed id for plain-text snapshots but deliberately mints a fresh UUID
for post-tool-call assistant text (their #3619), so tool+text turns
still rendered a duplicate assistant bubble (re-verified live). The
user-message duplication that motivated the retirement only fired on
a2ui retry runs, which no longer exist now that a2ui is disabled.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 16:10:12 -06:00
Carlos Escalante
4687fa9669 Assistant: drop a2ui surfaces, fall back to markdown tables
CK 1.60+ validates generated a2ui ops against a component catalog before
painting, and our agent's ops fail validation — surfaces hang at
"Building interface" forever (MAF also drops RunAgentInput.context, so
the catalog/guidelines never even reach the model). Disable a2ui end to
end until the pipeline matures:

- server.ts: a2ui { enabled: false }; RENDER_TOOLS no longer includes
  render_a2ui
- App.tsx: remove the a2ui provider prop
- agent.py: prompt now asks for clean markdown tables for lists and
  structured data; render_spending_summary card guidance unchanged

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 16:09:56 -06:00
Carlos Escalante
bbae121fec Middleware audit for CK 1.62 / MAF 1.10: retire ReconcileSnapshot, inject dropped AG-UI context
- ReconcileSnapshotMiddleware removed: MAF now reuses the streamed
  message id in MESSAGES_SNAPSHOT (verified in _agent_run.py at
  python-1.10.0 and live event logs); keeping the surgery duplicated
  user messages on a2ui follow-up runs.
- beforeRequestMiddleware now injects RunAgentInput.context as a system
  message: MAF declares the field but never feeds it to the model,
  which starves the model of CopilotKit's A2UI catalog/guidelines.
  Remove when MAF consumes context upstream.
- Workaround chain env-gated: CK_MIDDLEWARES=off runs bare for audits,
  CK_DEBUG_EVENTS=1 enables the event logger.
- Kept: SuppressRenderToolText, StripModelArtifacts,
  DeduplicateToolCall, pairOrphanToolCalls (behavior-verified).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 15:55:29 -06:00
Carlos Escalante
37c2b18300 Dev: derive AGENT_URL from BACKEND_URL so the assistant works locally
Some checks failed
Deploy to VPS / test (push) Successful in 1m31s
Deploy to VPS / deploy (push) Failing after 1m54s
The default pointed at the compose-internal 'backend' hostname, which
never resolves when the Hono runtime runs on the host — every local
agent run died with fetch failed/ENOTFOUND before reaching FastAPI.
Prod is unaffected (sets both URLs explicitly).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 14:16:25 -06:00
Carlos Escalante
b5bb2e8562 Auth probe retries network failures; lazy context init; CK repair logging
A thrown fetch in the auth probe is a network failure, not a 401 — it
now retries once before treating the user as logged out, and logs the
real cause (FE-15). Theme and privacy state initialize lazily from
localStorage so neither the wrong theme nor unmasked sensitive values
flash on reload (FE-07). The CopilotKit orphan-tool-call repair logs
when it has to skip instead of failing silently (FE-11).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 17:30:26 -06:00
Carlos Escalante
bebd7b563e Add security headers and proxy error handling to Hono server
Every response gets X-Frame-Options, X-Content-Type-Options, and
Referrer-Policy (SEC-07/FE-08). Backend proxy failures now return a
logged 502 instead of an opaque uncaught error (FE-23).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:13:32 -06:00
Carlos Escalante
aa4bb6512f Proxy /api/v1 and /api/auth from Hono to FastAPI in prod
All checks were successful
Deploy to VPS / deploy (push) Successful in 45s
In production the browser talks to the Hono server, which only proxied
/api/copilotkit/*. All other /api/* requests hit the SPA static fallback
and got index.html back. Forward /api/v1/* and /api/auth/* to BACKEND_URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 22:43:34 -06:00
Carlos Escalante
5f2a4105f3 Migrate frontend to Vite + Hono CopilotKit runtime
Replaces the Next.js scaffold with a Vite SPA paired with a Hono
sidecar that hosts the CopilotKit runtime and proxies AG-UI traffic
to the MAF backend. Adds dev/prod Dockerfile, .dockerignore,
.gitignore, pnpm workspace config, and updates entrypoints
(main.tsx / App.tsx / index.css / index.html) plus the service
worker accordingly.

Server middleware reconciles MAF MESSAGES_SNAPSHOT id mismatches
so post-tool-call assistant text doesn't render twice, suppresses
duplicate text emitted alongside render tools, and strips OpenAI
training-token leaks from streamed deltas.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 22:01:40 -06:00