chat session context scoping, fix sandboxed pi config mounts, dedupe zai/opencode providers

- Add context/contextId fields to session types, storage, and index
- Filter sessions by context (project, workspace, or default chat)
- Pass context through websocket, REST API, and frontend hooks
- Mount ~/.pi/agent into sandboxed containers for auth + writable sessions
- Remove PI_CODING_AGENT_DIR override so container pi uses ~/.pi/agent
- Deduplicate zai/opencode models (same service, show as opencode)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-26 22:35:02 +00:00
co-authored by Claude Opus 4.6
parent 1cbf9553ec
commit 13cfeac384
15 changed files with 111 additions and 24 deletions
+17 -6
View File
@@ -3,15 +3,26 @@ import { useAuth } from 'hooks/useAuth';
import { useClient } from 'hooks/useClient';
import { useQuery, useQueryClient } from '@tanstack/react-query';
export function useChatSessions() {
type ChatSessionsFilter = {
context?: string;
contextId?: string;
};
export function useChatSessions(filter?: ChatSessionsFilter) {
const client = useClient();
const queryClient = useQueryClient();
const { isAuthenticated } = useAuth();
const { data: sessions = [] } = useQuery<SessionEntry[]>({
queryKey: ['PI_SESSIONS'],
queryKey: ['PI_SESSIONS', filter?.context, filter?.contextId],
enabled: isAuthenticated,
queryFn: () => client.post<{ sessions: SessionEntry[] }>('/pi/sessions').then((r) => r.sessions),
queryFn: () =>
client
.post<{ sessions: SessionEntry[] }>('/pi/sessions', {
...(filter?.context ? { context: filter.context } : {}),
...(filter?.contextId ? { contextId: filter.contextId } : {}),
})
.then((r) => r.sessions),
});
function getSession(sessionId: string) {
@@ -24,13 +35,13 @@ export function useChatSessions() {
async function renameSession(sessionId: string, title: string) {
await client.patch(`/pi/sessions/${sessionId}`, { title });
queryClient.invalidateQueries({ queryKey: ['PI_SESSIONS'] });
queryClient.invalidateQueries({ queryKey: ['PI_SESSIONS', filter?.context, filter?.contextId] });
}
async function deleteSession(sessionId: string) {
await client.delete(`/pi/sessions/${sessionId}`);
queryClient.setQueryData<SessionEntry[]>(
['PI_SESSIONS'],
['PI_SESSIONS', filter?.context, filter?.contextId],
(prev) => prev?.filter((s) => s.id !== sessionId) ?? [],
);
}
@@ -40,7 +51,7 @@ export function useChatSessions() {
}
function invalidate() {
queryClient.invalidateQueries({ queryKey: ['PI_SESSIONS'] });
queryClient.invalidateQueries({ queryKey: ['PI_SESSIONS', filter?.context, filter?.contextId] });
}
return {