chat: rename the pi chat transport + model list to chat (Stage 4b/1)

Pure rename, no behavior change. Moves the misnamed "pi" chat harness into the
chat namespace:

- api/pi/{websocket,session-manager,types,logger,list-models} → api/chat/
- merge api/pi/rest.ts into api/chat/chat.ts (/pi/models → /chat/models,
  /pi/stt → /chat/stt); drop the piRestRouter mount
- PiEvent → ChatEvent, piWebsocket → chatWebsocket, listPiModels → listChatModels
- WS route /api/pi/chat/ws → /api/chat/ws, provider tag 'pi' → 'chat'
- frontend: useChat/useAudioRecording URLs, usePiModels→useModels /
  useVisiblePiModels→useVisibleModels / useEnabledPiModels→useEnabledModels,
  'PI_MODELS' query key → 'CHAT_MODELS', attachments provider 'pi-mono' → 'chat'

The /pi-mono provider/harness settings router is renamed separately (next commit).
Note: the WS route change requires the mobile app to point at /api/chat/ws.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 15:47:40 +00:00
co-authored by Claude Opus 4.8
parent 70555c8d71
commit 49df1c0b0c
31 changed files with 119 additions and 129 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
import { join } from 'node:path';
import type { Subprocess } from 'bun';
import type { PiEvent } from '../../api/pi/types';
import type { ChatEvent } from '../../api/chat/types';
import type { ClaudeSpawnParams, ClaudeSpawnStreamingParams, ClaudeCodeResult } from '../protocol';
import { buildSandboxPrefix, buildRunuserSuffix, SANDBOX_HOME } from '../sandbox';
import { setClaudeSession, clearClaudeSession, getClaudeSession } from './state';
@@ -145,7 +145,7 @@ export async function spawnClaude(params: ClaudeSpawnParams): Promise<ClaudeCode
export async function spawnClaudeStreaming(
params: ClaudeSpawnStreamingParams,
onEvent: (event: PiEvent) => void,
onEvent: (event: ChatEvent) => void,
): Promise<void> {
const { prompt, sessionKey, email } = params;
@@ -1,10 +1,10 @@
import { describe, test, expect } from 'bun:test';
import { processLine, createParseState, parseStream } from './stream-parser';
import type { PiEvent } from '../../api/pi/types';
import type { ChatEvent } from '../../api/chat/types';
import type { StreamParserCallbacks, ParseState } from './stream-parser';
function makeCallbacks(): { events: PiEvent[]; sessionIds: string[]; callbacks: StreamParserCallbacks } {
const events: PiEvent[] = [];
function makeCallbacks(): { events: ChatEvent[]; sessionIds: string[]; callbacks: StreamParserCallbacks } {
const events: ChatEvent[] = [];
const sessionIds: string[] = [];
return {
events,
+6 -6
View File
@@ -6,12 +6,12 @@
* system init, and result messages.
*/
import type { PiEvent, MessageCost } from '../../api/pi/types';
import type { ChatEvent, MessageCost } from '../../api/chat/types';
type SessionCallback = (sessionId: string) => void;
type StreamParserCallbacks = {
onEvent: (event: PiEvent) => void;
onEvent: (event: ChatEvent) => void;
onSessionId: SessionCallback;
};
@@ -20,14 +20,14 @@ type ParseState = {
gotResult: boolean;
};
function flushTextBuffer(state: ParseState, onEvent: (event: PiEvent) => void): void {
function flushTextBuffer(state: ParseState, onEvent: (event: ChatEvent) => void): void {
if (state.textBuffer) {
onEvent({ type: 'text', text: state.textBuffer });
state.textBuffer = '';
}
}
function handleStreamEvent(msg: Record<string, unknown>, state: ParseState, onEvent: (event: PiEvent) => void): void {
function handleStreamEvent(msg: Record<string, unknown>, state: ParseState, onEvent: (event: ChatEvent) => void): void {
const event = msg.event as Record<string, unknown> | undefined;
if (event?.type === 'content_block_delta') {
const delta = event.delta as Record<string, unknown> | undefined;
@@ -38,7 +38,7 @@ function handleStreamEvent(msg: Record<string, unknown>, state: ParseState, onEv
}
}
function handleAssistant(msg: Record<string, unknown>, state: ParseState, onEvent: (event: PiEvent) => void): void {
function handleAssistant(msg: Record<string, unknown>, state: ParseState, onEvent: (event: ChatEvent) => void): void {
const message = msg.message as Record<string, unknown> | undefined;
const content = message?.content as Array<Record<string, unknown>> | undefined;
if (!Array.isArray(content)) return;
@@ -59,7 +59,7 @@ function handleAssistant(msg: Record<string, unknown>, state: ParseState, onEven
}
}
function handleUser(msg: Record<string, unknown>, onEvent: (event: PiEvent) => void): void {
function handleUser(msg: Record<string, unknown>, onEvent: (event: ChatEvent) => void): void {
const message = msg.message as Record<string, unknown> | undefined;
const content = message?.content as Array<Record<string, unknown>> | undefined;
if (!Array.isArray(content)) return;
+1 -1
View File
@@ -172,7 +172,7 @@ async function handleCommand(cmd: SidecarCommand, reply: ReplyFn) {
case 'claude:spawn-streaming': {
reply({ type: 'claude:spawned', id: cmd.id, sessionKey: cmd.params.sessionKey });
const onEvent = (event: import('../../api/pi/types').PiEvent) => {
const onEvent = (event: import('../../api/chat/types').ChatEvent) => {
connection.send({ type: 'claude:event', sessionKey: cmd.params.sessionKey, event });
};
+2 -2
View File
@@ -1,4 +1,4 @@
import type { MessageCost, PiEvent } from '../api/pi/types';
import type { MessageCost, ChatEvent } from '../api/chat/types';
// ── Envelope ──
@@ -29,7 +29,7 @@ export type SidecarEvent =
| { type: 'proxy:secret'; id: string; secret: string }
// Claude Code
| { type: 'claude:spawned'; id: string; sessionKey: string }
| { type: 'claude:event'; sessionKey: string; event: PiEvent }
| { type: 'claude:event'; sessionKey: string; event: ChatEvent }
| { type: 'claude:result'; id: string; result: ClaudeCodeResult }
| { type: 'claude:error'; id: string; error: string }
| { type: 'claude:killed'; id: string }