Commit Graph
86 Commits
Author SHA1 Message Date
gongzhiyong 216650837a fix: use window.location.origin as fallback URL for Vite proxy in Docker
Deploy LangGraph Server to Azure Web App / build-and-deploy (push) Failing after 12s
Deploy LangGraph UI to Azure Static Web Apps / build-and-deploy (push) Failing after 51s
2026-04-11 12:49:26 +08:00
gongzhiyongandClaude Sonnet 4.6 a505e441ad feat: file upload + context compression + fix maxTokens
Deploy LangGraph Server to Azure Web App / build-and-deploy (push) Failing after 16s
Deploy LangGraph UI to Azure Static Web Apps / build-and-deploy (push) Failing after 49s
- Add file-service.ts: Azure Blob upload + PDF/Excel/image parsing
- Add truncate-messages.ts: context compression for long conversations
- Fix maxTokens: flash 500→2000, auto 2048→4096, pro 4096→8192
- Integrate truncateMessages in general-input and router nodes
- Add @azure/storage-blob, pdf-parse, xlsx dependencies

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 12:31:55 +08:00
gongzhiyong 9b5b98f675 feat: add FileUploadButton and FileAttachmentPreview components
Deploy LangGraph Server to Azure Web App / build-and-deploy (push) Failing after 20s
Deploy LangGraph UI to Azure Static Web Apps / build-and-deploy (push) Has been cancelled
2026-04-11 12:31:24 +08:00
gongzhiyong d878135443 fix: Vite proxy for Docker — frontend routes API through same-origin proxy to langgraph-dev:2024
Deploy LangGraph Server to Azure Web App / build-and-deploy (push) Failing after 12s
Deploy LangGraph UI to Azure Static Web Apps / build-and-deploy (push) Failing after 1m7s
2026-04-11 12:28:52 +08:00
gongzhiyongandClaude Opus 4.6 3eb70fec59 fix: coder agent must always call code_execute, never return plain text code
Deploy LangGraph Server to Azure Web App / build-and-deploy (push) Failing after 20s
Deploy LangGraph UI to Azure Static Web Apps / build-and-deploy (push) Failing after 39s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 11:03:50 +08:00
gongzhiyongandClaude Opus 4.6 e4760ca66e fix: CanvasPanel returns null when no doc, no longer occupies space
Deploy LangGraph Server to Azure Web App / build-and-deploy (push) Failing after 23s
Deploy LangGraph UI to Azure Static Web Apps / build-and-deploy (push) Failing after 44s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 02:24:11 +08:00
gongzhiyongandClaude Opus 4.6 8a5d1c0ea9 fix: router coder/writer distinction + writer must use doc_create tool
Deploy LangGraph Server to Azure Web App / build-and-deploy (push) Failing after 26s
Deploy LangGraph UI to Azure Static Web Apps / build-and-deploy (push) Failing after 42s
- Router prompt now clearly distinguishes "写代码" (execute code → coder)
  from "写文档" (create document → writer)
- Writer prompt strengthened to always use doc_create, never plain text

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 02:20:22 +08:00
gongzhiyongandClaude Opus 4.6 77e64d945e feat: Phase 2 - Deep Search, Code Interpreter, Writer agents + CanvasPanel
Deploy LangGraph Server to Azure Web App / build-and-deploy (push) Failing after 22s
Deploy LangGraph UI to Azure Static Web Apps / build-and-deploy (push) Failing after 43s
- Add searcher agent with Jina deep search + KB search tools
- Add coder agent with Daytona sandbox code execution
- Add writer agent with canvas document creation/editing tools
- Integrate all sub-agents into supervisor router
- Add CanvasPanel drawer UI component for document rendering
- Refactor enterprise tools into shared soc-client module

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 01:52:10 +08:00
gongzhiyongandClaude Sonnet 4.6 08add81409 feat: Phase 2 - CanvasPanel drawer + sidebar search & date groups
- Add CanvasPanel.tsx: right-side 480px drawer, renders markdown via
  MessageBubble or code via SyntaxHighlighter, with Copy/Download/Close
  header; listens to window 'open-canvas' CustomEvent dispatched by Gen-UI cards
- Update ThreadSidebar.tsx: add search input below new-chat button with
  live filtering; group filtered threads by date (今天/昨天/本周/更早)
  with section headings; internal state only, Props interface unchanged
- Update main.tsx: import CanvasPanel, add canvasDoc state, register
  open-canvas event listener on mount, render CanvasPanel alongside
  the main chat column inside a flex-row wrapper

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 01:48:25 +08:00
gongzhiyongandClaude Opus 4.6 251c6586f4 feat: Phase 1 — ReAct loop + Markdown rendering + Docker deployment
Deploy LangGraph Server to Azure Web App / build-and-deploy (push) Failing after 26s
Deploy LangGraph UI to Azure Static Web Apps / build-and-deploy (push) Failing after 1m52s
Backend:
- Enterprise Agent refactored from single-round to ReAct multi-turn loop
- New agent.ts (LLM decision node) + tool-executor.ts (tool execution + Gen-UI)
- tool-defs.ts extracted for shared tool schemas
- MAX_ITERATIONS=6 safeguard against infinite loops

Frontend:
- MessageBubble: Markdown + code highlighting + LaTeX + tables
- ThemeToggle: light/dark/system theme cycling
- chart-result Gen-UI card: recharts bar/line/pie/area charts

Infrastructure:
- Docker Compose (lightweight): only LangGraph + Frontend, Azure cloud for PG/Redis/Blob
- Dockerfiles for dev (hot reload) and prod
- Makefile with dev/prod/down/logs commands
- Updated CLAUDE.md and agent definitions for LangGraph.js architecture

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 01:29:56 +08:00
gongzhiyongandClaude Sonnet 4.6 3263b15554 perf(deploy): pre-install node_modules in CI and enable always-on to fix slow cold start
- CI now runs pnpm install and includes node_modules in the zip artifact
- startup.sh simplified: removed pnpm install fallback, uses direct bin path instead of npx
- Azure Web App always-on enabled to prevent cold starts

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:55:38 +08:00
gongzhiyongandClaude Sonnet 4.6 370726c811 fix(deploy): use Azure-injected PORT instead of hardcoded 2024
- startup.sh now reads ${PORT:-8080} so Azure App Service can inject
  the correct port via its PORT environment variable
- Removed obsolete deploy-backend.yml and deploy-frontend.yml workflows
  (old Python backend and Next.js frontend pipelines)
- Removed WEBSITES_PORT=2024 from soc-langgraph Azure config

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:49:56 +08:00
gongzhiyongandClaude Opus 4.6 b30cb0e758 fix: add .npmrc and CUSTOM_BUILD_COMMAND to resolve Oryx npm peer dep conflict
Oryx runs `npm install` which fails on peer dependency conflicts between
@assistant-ui/react@^0.8.0 and @assistant-ui/react-syntax-highlighter@^0.7.2.
Adding .npmrc with legacy-peer-deps=true and CUSTOM_BUILD_COMMAND for pnpm.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 13:36:30 +08:00
gongzhiyongandClaude Opus 4.6 45685e8b4a fix: resolve Web App startup timeout — exclude node_modules from zip, add startup.sh, increase timeout to 600s
- Remove node_modules from deploy zip (302MB -> ~1MB), let Oryx build on Azure
- Add startup.sh: creates .env/.langgraph_api prereqs, installs pnpm, runs langgraphjs dev
- Azure config: WEBSITES_CONTAINER_START_TIME_LIMIT=600, SCM_DO_BUILD_DURING_DEPLOYMENT=true, ENABLE_ORYX_BUILD=true, PRE_BUILD_COMMAND="npm install -g pnpm@10"
- Delete auto-generated main_soc-langgraph.yml (conflicts with deploy-langgraph.yml)
- Enable Always On to avoid cold starts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 06:17:47 +08:00
Fasthei 092c6fe600 Add or update the Azure App Service build and deployment workflow config 2026-04-10 06:12:14 +08:00
gongzhiyongandClaude Opus 4.6 32f83d714e refactor: migrate LangGraph server from Container App to Azure Web App
## Changes
- Delete Dockerfile and .dockerignore (no longer needed)
- Rewrite deploy-langgraph.yml: zip deploy to Web App (not ACR build)
- Update deploy-langgraph-ui.yml: VITE_LANGGRAPH_URL → soc-langgraph.azurewebsites.net

## Azure Resources
- CREATED: soc-langgraph Web App (Node.js 20, B1 Linux, southeastasia)
- CREATED: soc-langgraph-plan (App Service Plan, B1, southeastasia)
- DELETED: soc-langgraph Container App
- DELETED: soc-cae Container App Environment
- DELETED: socsocacr ACR
- All env vars migrated to Web App
- Startup: npx langgraphjs dev --host 0.0.0.0 --port 2024 --no-browser
- WEBSITES_PORT=2024

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 05:47:32 +08:00
gongzhiyong 4a485a9c5b fix(dockerfile): pre-create .langgraph_api to prevent tsx watch restart loop 2026-04-10 05:23:07 +08:00
gongzhiyong 3d35ca43be fix(dockerfile): create empty .env file — langgraphjs dev requires it to exist 2026-04-10 05:05:17 +08:00
gongzhiyong df2b72c53c fix(dockerfile): explicit port binding for Container App health probe 2026-04-10 04:54:47 +08:00
gongzhiyong f8a73e461c fix(ci): point app_location directly to langgraph/dist for SWA upload 2026-04-10 04:44:57 +08:00
gongzhiyong 14a7e79792 fix(ci): use pnpm vite build then SWA upload from repo root with langgraph/dist 2026-04-10 04:43:02 +08:00
gongzhiyong 3edeafa062 fix(ci): let SWA action handle Vite build instead of manual pnpm build 2026-04-10 04:40:14 +08:00
gongzhiyong f43d239e6c fix(main.tsx): cast message prop to any in LoadExternalComponent 2026-04-10 04:37:21 +08:00
gongzhiyong 8d30e0cca0 fix(main.tsx): rename UIMessage→UIMsgLocal to avoid SDK type conflict 2026-04-10 04:35:15 +08:00
gongzhiyong 4f75b65d52 fix(main.tsx): add type field to local UIMessage type 2026-04-10 04:32:06 +08:00
gongzhiyong 844aaa8dcc fix(main.tsx): resolve TypeScript errors — UIMessage type, role→type, ComponentMap cast 2026-04-10 04:28:28 +08:00
gongzhiyongandClaude Sonnet 4.6 7a3cc140b0 refactor: replace SOC system with LangGraph.js gen-ui — full cleanup
## Removed (old SOC system)
- backend/ — Python FastAPI + LangGraph Python ReAct agent
- frontend/ — Next.js Gemini-style UI
- config/, doc/ — old documentation
- .github/workflows/deploy-backend.yml
- .github/workflows/deploy-frontend.yml

## Added (new LangGraph.js system)
- langgraph/src/agent/enterprise/ — enterprise agent with 6 tools
  - kb_search → KnowledgeResultCard
  - ticket_list/detail → TicketSummaryCard / TicketDetailCard
  - web_search (Jina Search+Reader) → SearchResultCard
  - sandbox_run (Daytona REST) → SandboxResultCard
- langgraph/src/agent-uis/enterprise/ — UI card components
- .github/workflows/deploy-langgraph-ui.yml — Vite SPA → Azure Static Web App

## Azure Resources
- soc-backend webapp: DELETED
- soc-frontend Static Web App (eastasia): DELETED
- soc-langgraph-ui Static Web App (eastasia): CREATED
  URL: salmon-mushroom-0d8872e00.7.azurestaticapps.net

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 04:23:51 +08:00
gongzhiyongandClaude Sonnet 4.6 645f1ecaae feat(langgraph): add enterprise UI card components and implement main.tsx Chat entry
- Create 5 enterprise UI card components under src/agent-uis/enterprise/:
  knowledge-result, ticket-summary, ticket-detail, search-result, sandbox-result
- Update ComponentMap in src/agent-uis/index.tsx to replace () => null placeholders
  with real component imports
- Implement src/main.tsx with useStream + LoadExternalComponent for full Chat UI,
  connecting to LangGraph agent with VITE_LANGGRAPH_URL env var

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 04:23:32 +08:00
gongzhiyong b621fbae92 fix(langgraph): add missing pnpm-lock.yaml for Docker build 2026-04-10 04:04:27 +08:00
gongzhiyongandClaude Sonnet 4.6 ac388b3c07 feat: add langgraph/ — LangGraph.js gen-ui server with CI/CD to Azure Container App
## Azure Resources Created
- ACR: socsocacr.azurecr.io (Operation, southeastasia)
- Container App Environment: soc-cae (Operation, southeastasia)
- Container App: soc-langgraph (Operation, southeastasia, port 2024)
  - Scale: 0-2 replicas, 0.5 vCPU / 1GB
  - Registry: socsocacr.azurecr.io (system-assigned managed identity)
- OIDC: oidc-msi-8ac6 granted Contributor on Operation resource group

## What's included
- Full langgraphjs-gen-ui-examples codebase under langgraph/
- Dockerfile: node:20-slim + pnpm, exposes port 2024
- .dockerignore, .gitignore
- GitHub Actions: .github/workflows/deploy-langgraph.yml
  - Trigger: push to main, paths langgraph/**
  - Uses az acr build (cloud build, no local Docker needed)
  - Deploys to soc-langgraph Container App

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 04:01:06 +08:00
gongzhiyongandClaude Sonnet 4.6 c6ca9dc126 fix: restore workspace components accidentally dropped from git index
workspace/ files existed on disk but were not included in previous
incremental commit, causing git to record them as deleted. Re-adding
all workspace card components, AgentWorkspace, ActivityTimeline, and
WorkspaceCardRenderer to properly track them.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 03:09:41 +08:00
gongzhiyongandClaude Sonnet 4.6 47921d1a45 fix: resolve 6 gen-ui issues — timeline completeness, regen sync, localStorage persistence
## Fixes
- [#3] Status events now add/update a status ActivityNode in timeline (upsertWsStatusNode)
- [#4] Done callback adds done node; error callback adds error node + sets session.status="error"
- [#5] handleRegenerate fully synced with workspace: status/tool/card/done/error all handled
- [#1][#2] localStorage persistence: completed/error sessions auto-saved, lazy-loaded on demand
- [#1] handleSelectConversation preloads workspace sessions from localStorage for history messages
- Refactored completeWsSession to include done ActivityNode in timeline
- Added errorWsSession, upsertWsStatusNode, saveWsToStorage, loadWsFromStorage helpers

## Known limitation
- [#7] workspace_card merge:true not yet used by backend (all cards are append-only for now)
- History workspace recovery depends on localStorage (browser-local, not cross-device)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 03:08:23 +08:00
gongzhiyongandClaude Sonnet 4.6 0a2b339550 feat: implement Generative UI — Agent Workspace + workspace_card SSE protocol
## Backend
- Add workspace_card SSE event protocol: {id, name, props, merge}
- Add _extract_llm_text / _maybe_emit_workspace_card helpers in chat.py
- Refactor all tools to dual-output format: {llm_text, ui: {name, props}}
  - kb_search → KnowledgeResultCard
  - ticket_list/detail → TicketSummaryCard / TicketDetailCard
  - web_search → SearchResultCard
  - generate_document → DocumentResultCard
  - sandbox_run → SandboxResultCard
- Update SYSTEM_PROMPT: instruct LLM not to repeat tool data (UI shows it)

## Frontend
- Three-column layout: sidebar + chat + Agent Workspace (360px right panel)
- WorkspaceSession state model with ActivityNode + WorkspaceCard
- New components/workspace/: AgentWorkspace, ActivityTimeline, WorkspaceCardRenderer
- 6 card components: Knowledge/Ticket/Search/Document/Sandbox/ErrorCard
- GeminiChat: workspace state management, SSE routing for workspace_card events
- GeminiMessage: replace TracePanel with lightweight activity summary line
- lib/api.ts: add WorkspaceSession/ActivityNode/WorkspaceCard types

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 02:57:09 +08:00
gongzhiyongandClaude Sonnet 4.6 1ad75a3602 fix: prevent duplicate AI message when switching conversations during stream
Two bugs caused the same AI response to appear twice:

1. handleSelectConversation would fetch conversation history even while
   a stream was in progress (isLoading). If the fetch resolved mid-stream,
   fetchConversation overwrote the conversation messages unconditionally,
   writing the server-persisted AI message (with a real UUID) alongside the
   still-streaming client-side message (with a temp ID), producing a duplicate.
   Fix: guard the fetch with !isLoading, and add a second check inside the
   .then callback so setConversations only writes history if the messages
   array is still empty (protects against slow-resolving network requests).

2. onDone in streamChat could theoretically be called a second time if the
   ReadableStream completed without a "done" SSE event. Fix: call
   reader.cancel() immediately after onDone so the while loop exits cleanly.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 22:58:47 +08:00
gongzhiyongandClaude Sonnet 4.6 d86d9b8b32 fix(backend): handle MCP tool output format and read_url list input
- Add _extract_output_str() to unwrap MCP ToolMessage content objects
  instead of calling str() on the raw object
- Handle read_url url param when LLM passes a list instead of a string

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 22:46:58 +08:00
gongzhiyongandClaude Sonnet 4.6 ac843da725 feat: add Google Serper search tool alongside Jina MCP
- Add langchain-community dependency for GoogleSerperAPIWrapper
- Add serper_api_key to config with default key
- Create app/tools/serper.py with async serper_search tool
- Register "serper" key in tools/__init__.py (independent from "search"/Jina MCP)
- Add tool title and input/output summaries in chat.py
- Set SERPER_API_KEY on Azure App Service (Operation resource group)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 21:11:22 +08:00
gongzhiyongandClaude Sonnet 4.6 707f6bce4b feat: replace Jina REST with MCP tools for web search
- Add langchain-mcp-adapters dependency
- New app/tools/mcp_jina.py: Jina MCP client with filtered tool loading
  (search_web, read_url, sort_by_relevance)
- Update resolve_tools to return (tools, needs_jina_mcp) tuple
- Update builder.py: skip graph cache for MCP-bound tools, add search
  tool guidance to system prompt
- Refactor chat.py: extract _run_graph_stream, add MCP/non-MCP paths,
  update tool titles and summaries for MCP tool names
- Tested locally: both MCP search path and non-MCP knowledge path work

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 21:01:21 +08:00
gongzhiyongandClaude Sonnet 4.6 a11cb56962 feat: emit real status events from on_chain_start (thinking/generating)
- Add has_tool_activity flag to distinguish first agent pass (thinking)
  from post-tool agent pass (generating)
- Replace on_chain_start debug logging with status SSE emission
- Filter to only graph-level agent nodes via graph:step: tag prefix

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 17:52:55 +08:00
gongzhiyong 0cd19b527b feat: handle status events to create assistant placeholder early 2026-04-09 17:51:52 +08:00
gongzhiyongandClaude Sonnet 4.6 bb7a4f6629 chore: temporarily use logger.warning for on_chain_start observation
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 17:17:15 +08:00
gongzhiyongandClaude Sonnet 4.6 f03efbfe0c feat: add call_id (run_id) to tool events, add on_chain_start debug logging
- tool_start/tool_end/tool_error SSE payloads now include call_id field
  derived from LangGraph run_id for reliable tool event correlation
- tool_start_ts dict keyed by call_id instead of tool_name to handle
  concurrent calls to the same tool
- Added on_chain_start debug logging to observe chain names and metadata
  (no SSE emission yet, observation only)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 17:01:27 +08:00
gongzhiyong 056cf6be9d feat: stable trace matching via call_id 2026-04-09 16:59:17 +08:00
gongzhiyongandClaude Sonnet 4.6 5b5a55933c refactor: redesign CoT trace panel — clean summary line, real tool trace only, remove fabricated status steps
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 13:49:22 +08:00
gongzhiyongandClaude Sonnet 4.6 0207f34902 feat(frontend): CoT execution trace UI — TracePanel + full SSE event handling
Add TracePanel component for collapsible execution trace display,
extend Message interface with traceItems, and implement complete
SSE event processing (trace/status/content/error/done) in GeminiChat.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 13:00:50 +08:00
gongzhiyongandClaude Sonnet 4.6 722ec3e81d feat: add structured execution trace SSE events (status/tool_start/tool_end/tool_error)
Add CoT execution trace to the SSE stream: status events for stage
transitions, enriched tool_start with input_summary, tool_end with
output_summary and duration_ms, and tool_error for failed tool calls.
Helper functions _sse, _summarize_input, _summarize_output provide
human-readable summaries for each tool type.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 13:00:49 +08:00
gongzhiyongandClaude Sonnet 4.6 fe8c361127 feat(input): replace model selector buttons with Select dropdown
Replace the three pill buttons (Auto/Flash/Pro) in GeminiInput with a
single shadcn/ui Select component. Selection logic and onSelectedModelChange
callback are unchanged; only the UI widget is swapped.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 23:47:35 +08:00
gongzhiyongandClaude Sonnet 4.6 c54e2be5c4 fix(backend): validate conversation_id FK before inserting attachment
When the frontend passes a conversation_id that does not exist in the
conversations table (e.g. new conversation before first message, or
invalid ID), the INSERT into attachments failed with
ForeignKeyViolationError.

Now upload_attachment checks session.get(Conversation, conversation_id)
before inserting. If the conversation does not exist, conversation_id is
set to None and the attachment is stored as unlinked (blob path uses
_unlinked/ prefix). This avoids the FK constraint error while keeping
the file safely uploaded.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:02:03 +08:00
gongzhiyongandClaude Sonnet 4.6 5d0127bfb4 fix(backend): auto-purge polluted checkpoint when tool_calls lack ToolMessage
When a tool call crashes (e.g. httpx timeout in kb_search), the LangGraph
checkpoint retains an AIMessage with tool_calls but no corresponding
ToolMessage. Subsequent requests to the same conversation_id fail with:
  ValueError: Found AIMessages with tool_calls that do not have a
  corresponding ToolMessage

Now the except block in _stream_response detects this specific ValueError
by checking for "tool_calls" and "ToolMessage" in the error string, then
calls checkpointer.adelete_thread() to purge the corrupted thread state.
The frontend receives {"type":"error","content":"对话状态异常,已自动重置..."}
followed by {"type":"done"}, so the user can simply resend their message.

API confirmed: AsyncPostgresSaver.adelete_thread(thread_id) deletes from
checkpoints, checkpoint_blobs, and checkpoint_writes tables for the thread.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 20:53:54 +08:00
gongzhiyongandClaude Sonnet 4.6 0f2db39655 fix(backend): handle KB Agent cold-start timeout with retry and graceful errors
KB Agent runs on Azure App Service which cold-starts after idle periods,
taking 20-30s to respond. The previous 15s timeout caused httpx.ReadTimeout
that crashed the ReAct agent tool node and killed the SSE stream.

Changes:
- Increase kb_agent_search_timeout_sec default from 15 to 30 in config.py
- Add single retry with 2s backoff on ReadTimeout in kb_search tool
- Catch all exceptions and return friendly Chinese error messages instead
  of propagating exceptions to the agent loop

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 20:51:18 +08:00
gongzhiyongandClaude Opus 4.6 1e735202fc fix(backend): wrap SSE astream_events in try/except/finally
Tool call failures (httpx network errors) propagated as unhandled exceptions
through LangGraph TaskGroup, killing SSE stream mid-flight. Frontend received
neither tokens nor done event, leaving it stuck.

- except: sends {"type":"error"} SSE event so frontend shows error message
- finally: persists partial AI content and always sends {"type":"done"}

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 20:36:39 +08:00