diff --git a/CHANGELOG.md b/CHANGELOG.md index 429fdf59..98935bbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ # Changelog ## [Unreleased] +### Added + +- **Read-Only Initial Context**: Initial context is now locked after the first message, providing consistent session context + - Chat TUI: `--initial-context` CLI option sets background context for the session + - Context can be edited via command palette before the first message is sent + - After first message, context becomes read-only (view only) + - Clearing chat resets context to CLI value and unlocks editing + - Web app: Memory panel now serves dual purpose - edit initial context before first message, view session context after + - Agent uses `initial_context` as fallback when `session_context` is empty + ## [0.27.1] - 2026-01-27 ### Added diff --git a/app/backend/main.py b/app/backend/main.py index ff297a30..506f15d3 100644 --- a/app/backend/main.py +++ b/app/backend/main.py @@ -83,6 +83,7 @@ async def stream_chat(request: Request) -> Response: initial_qa_history: list[QAResponse] = [] session_id: str | None = None document_filter: list[str] = [] + initial_context: str | None = None state = getattr(run_input, "state", None) if state: chat_state = state.get(AGUI_STATE_KEY, state) @@ -92,6 +93,7 @@ async def stream_chat(request: Request) -> Response: ] session_id = chat_state.get("session_id") document_filter = chat_state.get("document_filter", []) + initial_context = chat_state.get("initial_context") deps = ChatDeps( client=get_client(db_path), @@ -99,6 +101,7 @@ async def stream_chat(request: Request) -> Response: session_state=ChatSessionState( qa_history=initial_qa_history, document_filter=document_filter, + initial_context=initial_context, **({"session_id": session_id} if session_id else {}), ), state_key=AGUI_STATE_KEY, diff --git a/app/frontend/components/Chat.tsx b/app/frontend/components/Chat.tsx index da553fe4..4a0e11d3 100644 --- a/app/frontend/components/Chat.tsx +++ b/app/frontend/components/Chat.tsx @@ -42,6 +42,7 @@ interface SessionContext { interface ChatSessionState { session_id: string; + initial_context: string | null; citations: Citation[]; qa_history: QAResponse[]; session_context: SessionContext | null; @@ -398,6 +399,7 @@ function ChatContentInner() { initialState: { [AGUI_STATE_KEY]: { session_id: "", + initial_context: null, citations: [], qa_history: [], session_context: null, @@ -407,9 +409,14 @@ function ChatContentInner() { }, ); - // Extract session context and document filter from agent state + // Extract session context, document filter, and initial context from agent state const sessionContext = agentState?.[AGUI_STATE_KEY]?.session_context ?? null; const documentFilter = agentState?.[AGUI_STATE_KEY]?.document_filter ?? []; + const initialContext = agentState?.[AGUI_STATE_KEY]?.initial_context ?? ""; + + // Context is locked after first message (qa_history has entries) + const isContextLocked = + (agentState?.[AGUI_STATE_KEY]?.qa_history?.length ?? 0) > 0; const handleFilterApply = (selected: string[]) => { setAgentState({ @@ -417,6 +424,7 @@ function ChatContentInner() { [AGUI_STATE_KEY]: { ...agentState?.[AGUI_STATE_KEY], session_id: agentState?.[AGUI_STATE_KEY]?.session_id ?? "", + initial_context: agentState?.[AGUI_STATE_KEY]?.initial_context ?? null, citations: agentState?.[AGUI_STATE_KEY]?.citations ?? [], qa_history: agentState?.[AGUI_STATE_KEY]?.qa_history ?? [], session_context: agentState?.[AGUI_STATE_KEY]?.session_context ?? null, @@ -425,6 +433,22 @@ function ChatContentInner() { }); }; + const handleInitialContextChange = (value: string) => { + if (isContextLocked) return; + setAgentState({ + ...agentState, + [AGUI_STATE_KEY]: { + ...agentState?.[AGUI_STATE_KEY], + session_id: agentState?.[AGUI_STATE_KEY]?.session_id ?? "", + initial_context: value || null, + citations: agentState?.[AGUI_STATE_KEY]?.citations ?? [], + qa_history: agentState?.[AGUI_STATE_KEY]?.qa_history ?? [], + session_context: agentState?.[AGUI_STATE_KEY]?.session_context ?? null, + document_filter: agentState?.[AGUI_STATE_KEY]?.document_filter ?? [], + }, + }); + }; + useCoAgentStateRender({ name: "chat_agent", render: ({ state }) => { @@ -568,12 +592,16 @@ function ChatContentInner() {