- 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>
- 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>
- 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>
- 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>
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>
- 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>
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>
## 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>
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>
- 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>
- 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>
- 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>
- 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>
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>
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>