- POST /api/client-log endpoint in http.ts (Hono, no auth, 204 response)
prints batched log entries to stdout so `docker compose logs` shows them
- New src/utils/remote-log.ts: remoteLog/remoteWarn batch to backend every 500ms
- Replace all bracket-tagged diagnostic console.log/warn calls in main.tsx and
ToolCallStatus.tsx with remoteLog/remoteWarn (tags: thread-ui, ui-debug,
render-msg, orphan-match, orphan-name-match, orphan-result, streaming-orphan,
tool-ui-match)
- Add /api/client-log proxy entry to vite.config.ts so dev server forwards
the request to the LangGraph backend (port 2024)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When modelMode is "pro", searcher/enterprise/coder agents now call the
Responses API directly via fetch to obtain reasoning summary blocks.
The reasoning text is injected as a { type: "thinking" } content block
in the AIMessage, while flash/auto modes remain unchanged using the
existing Chat Completions path through AzureChatOpenAI.
Key changes:
- create-llm.ts: add invokeWithReasoning() with inline zod-to-JSON-Schema
converter and Responses API output parser (reasoning/message/function_call)
- All three agent nodes: Pro branch converts LangChain messages to
Responses API format (developer role, function_call_output for tool
results, function_call for AI tool invocations)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Streaming orphan UI cards section was rendering all cards with message_id=NONE
as orphans, even when they were already claimed by the message-level orphan
matching logic via card_id. Added card_id+tool_call_id check to prevent
double rendering.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
With streamSubgraphs:true, subgraph values events push messages that
the parent Supervisor later merges, causing the same message.id to
appear multiple times in thread.messages. Similarly, the same card_id
can appear in both subgraph and parent values snapshots.
- Add deduplicateMessages() at module level: keeps the last (most
up-to-date) copy per message.id, eliminating duplicate AI messages
caused by subgraph-then-parent merge events.
- Apply deduplicateUiItems() to the full allUi array before per-message
card matching, so loading→done card pairs pushed by subgraphs and
parent are collapsed globally before orphan attribution runs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both thread.submit() calls now use streamMode: ["values", "messages"] so the
frontend receives real-time LLM token stream from subgraphs (searcher/coder/writer)
during the tool execution phase, eliminating the skeleton-only blank period.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add [thread-ui], [ui-debug], [tool-ui-match] console logs to trace
why searcher search-result cards show only skeleton after search completes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add checkpoint guard in all 4 tool-executors ensuring every
tool_call_id gets a ToolMessage response
- Add cleanPollutedToolCalls utility to heal corrupted message history
- Add error banner with "重置此对话" button in frontend
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SearchResultProps does not declare a card_id field, so passing it caused
TS2769 type errors. search-result cards do not need loading→done dedup
(each google_search/web_search_deep call produces a complete result in one
push), so the card_id and associated local variables are unnecessary.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each search result card now carries a unique card_id containing the tool call id
(e.g. google-search-<tc.id>), enabling the ToolCallStatus exact-match logic to
correctly bind cards to their originating tool call without index-based offset errors.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add parallel_tool_calls: false to searcher agentNode bindTools call so the
LLM is forced to execute search tools one at a time (google_search first,
then web_read in a separate turn); prompt-level "strict禁止" alone cannot
override model-side parallel tool calling behaviour
- Remove card_id field from google_search and web_search_deep ui.push props;
SearchResultProps does not declare card_id so the field caused TS2769
overload errors; these cards do not need deduplication (each search is a
distinct query), while the card_id variables were introduced by a previous
commit and are now unused
- Clean up unused googleCardId and deepCardId local variables
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add web_read -> web-read-progress mapping to standaloneUiItems filter in main.tsx
so web-read-progress cards are no longer mistakenly treated as standalone
- Add web-read-progress to CARD_TYPE_PRIORITY (550) to ensure stable sort order
and prevent search-result cards (500) from being reordered relative to web-read cards
- Add unique card_id (containing tc.id) to google_search and web_search_deep ui.push
calls so each search result card can be precisely identified
- Improve uiItem matching in ToolCallStatus to first try exact match via card_id
containing tc.id, falling back to index-based matching only when necessary;
this prevents index offset bugs when multiple same-type tools run concurrently
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When LLM sends multiple parallel tool_calls but one throws unexpectedly,
Promise.all loses all results causing 400 error from OpenAI.
Promise.allSettled ensures every tool_call_id gets a response.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Azure Container App auto-deploy workflow replaces our manual
deploy-langgraph.yml. CD is now managed via Azure Portal.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
8s timeout caused Jina Reader failures on slower sites like news.cn.
Increased to 30s with 2 retries and 1s backoff.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wraps all LoadExternalComponent usages with CardErrorBoundary so
card rendering errors show an inline error message instead of
crashing the entire app.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tool call status cards and execution log panel now expand by default
so users can see CoT process and results without clicking.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace soc-langgraph Web App with Azure Container App (soc-cae environment)
- New URL: soc-langgraph.victorioussand-69befc84.southeastasia.azurecontainerapps.io
- Update deploy-langgraph.yml: Web App restart -> az containerapp update --image
- Update deploy-langgraph-ui.yml: VITE_LANGGRAPH_URL to Container App URL
- Container App: min 1 replica, max 3, CPU 1.0, Memory 2Gi, port 8080
- Update CLAUDE.md architecture and deployment docs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
server.ts production mode crashes on startup (exit code 1).
Revert to langgraphjs dev until startServer() compatibility is resolved.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
server.ts uses createRequire to resolve @langchain/langgraph-api at startup.
With pnpm, indirect dependencies are not hoisted to node_modules/@langchain/,
causing "Cannot find module" error and container exit code 1 on Azure.
Adding it as an explicit dependency ensures pnpm creates the direct symlink.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add web-read-progress Gen-UI card for real-time web reading feedback
- Searcher tool-executor pushes loading→complete cards during web_read
- ToolCallStatus supports expanding during loading state
- Switch from langgraphjs dev to production mode (server.ts)
- Add Hono middleware to strip sensitive request headers
- Bundle splitting via Vite manualChunks (1.85MB → 8 chunks)
- SPA fallback via staticwebapp.config.json
- Agent model configs updated (sonnet 1M → standard sonnet)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously web_search_deep tool calls were missing from the UI_NAME_MAP,
causing their search-result cards to render as standalone cards instead of
being embedded within the ToolCallStatus component row.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When tool rounds hit MAX_ITERATIONS, the router was jumping directly to
END without giving the LLM a chance to produce a final text reply.
Added a `force-summary` node that invokes the LLM without tools,
ensuring a coherent Chinese summary is always generated after all
search results are collected.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The LangGraph API server injects all x-* request headers into
thread.config.configurable, which gets persisted and exposed via
POST /threads/search. This leaked Azure-injected headers (x-forwarded-for,
x-client-ip, x-arr-ssl, etc.) to any user.
Adds a Hono middleware (http.app) that strips sensitive infrastructure
headers at the HTTP layer before they reach the LangGraph API routes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace single pendingSubmitRef with pendingQueueRef array supporting multiple queued messages
- Add SubmitPayload interface to snapshot text/file/tools/modelMode at submission time
- Rewrite handleSubmit/doSubmit to use payload snapshots instead of closures over mutable state
- Rewrite handleConcurrentQueue with polling loop that drains the queue sequentially
- Rewrite handleConcurrentInterrupt and handleConcurrentCancel for queue awareness
- StreamStatusBar queued state now shows count (N 条消息已排队) and inline cancel button
- Add key={concurrentStatus} to StreamStatusBar div for fade-in animation on status change
- Config panel summary button shows numeric badge instead of dot when tools are active
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>