refactor(chat): route browser chat through one runtime (P3 Slice-Zero Task 5) (#1172)
ci/woodpecker/push/publish Pipeline failed
ci/woodpecker/push/publish Pipeline failed
Co-authored-by: shaggy <[email protected]>
This commit was merged in pull request #1172.
This commit is contained in:
@@ -6,6 +6,7 @@ import type {
|
||||
SlashCommandResultPayload,
|
||||
SystemReloadPayload,
|
||||
} from '../commands/index.js';
|
||||
import type { HarnessErrorCode, HarnessSelection, HarnessTurnState } from '../harness/index.js';
|
||||
|
||||
export interface MessageAckPayload {
|
||||
conversationId: string;
|
||||
@@ -107,8 +108,70 @@ export interface AbortPayload {
|
||||
conversationId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The frozen P3 `turn:send` wire contract (Task Five; reused unchanged by Tasks 15 and 16).
|
||||
* Accepts no attachments or authority-bearing fields in Slice Zero. Gateway validation
|
||||
* requires a UUID conversation id, non-empty bounded content, a nested selection with exactly
|
||||
* `harnessId`/`providerId`/`modelId` (each 1..255 chars), and a UUID-v4 idempotency key; it
|
||||
* rejects unknown fields, top-level `provider`/`modelId`, malformed nesting, and empty values
|
||||
* before any runtime dispatch.
|
||||
*/
|
||||
export interface HarnessTurnSendPayload {
|
||||
readonly conversationId: string; // UUID; required before send
|
||||
readonly content: string; // trimmed, 1..10_000 characters
|
||||
readonly selection: HarnessSelection; // nested; exactly three ids
|
||||
readonly idempotencyKey: string; // browser-generated UUID v4
|
||||
}
|
||||
|
||||
/**
|
||||
* The frozen `turn:ack` wire contract. Success echoes the accepted idempotency key and the
|
||||
* exact requested selection tuple; failure carries only fixed/safe text and never a
|
||||
* substituted effective selection or raw exception text.
|
||||
*/
|
||||
export type HarnessTurnAckPayload =
|
||||
| {
|
||||
readonly ok: true;
|
||||
readonly conversationId: string;
|
||||
readonly idempotencyKey: string;
|
||||
readonly turnId: string;
|
||||
readonly correlationId: string;
|
||||
readonly state: HarnessTurnState;
|
||||
readonly selection: HarnessSelection;
|
||||
}
|
||||
| {
|
||||
readonly ok: false;
|
||||
readonly conversationId?: string;
|
||||
readonly idempotencyKey?: string;
|
||||
readonly code: HarnessErrorCode | 'request_invalid' | 'runtime_unsupported';
|
||||
readonly message: string; // fixed/safe text only
|
||||
readonly retryable: boolean;
|
||||
readonly correlationId: string;
|
||||
/** Present only when a complete tuple was validated; always the requested tuple. */
|
||||
readonly selection?: HarnessSelection;
|
||||
};
|
||||
|
||||
/**
|
||||
* The frozen browser send-protocol advertisement (Task Five; server → client only).
|
||||
*
|
||||
* A conversation id or a harness selection never proves that the connected Gateway actually
|
||||
* handles a given wire event, so after BetterAuth authenticates a browser Socket connection the
|
||||
* Gateway advertises — exactly once, targeted to that socket — which send event the client may
|
||||
* use. `legacy-message` in legacy mode, `unavailable` in `pi-rpc` (including test-ready Pi
|
||||
* graphs); Task Five never advertises `turn-send` (its authenticated handler lands in Task 15).
|
||||
* Capability is routing information, never authorization: every server handler still enforces
|
||||
* authentication, ownership, DTO, mode, and runtime checks.
|
||||
*/
|
||||
export type ChatSendProtocol = 'legacy-message' | 'turn-send' | 'unavailable';
|
||||
|
||||
export interface ChatSendCapabilityPayload {
|
||||
readonly protocol: ChatSendProtocol;
|
||||
/** Exact Socket.IO id for the authenticated browser connection this advertisement is bound to. */
|
||||
readonly connectionId: string;
|
||||
}
|
||||
|
||||
/** Socket.IO typed event map: server → client */
|
||||
export interface ServerToClientEvents {
|
||||
'chat:send-capability': (payload: ChatSendCapabilityPayload) => void;
|
||||
'message:ack': (payload: MessageAckPayload) => void;
|
||||
'agent:start': (payload: AgentStartPayload) => void;
|
||||
'agent:end': (payload: AgentEndPayload) => void;
|
||||
@@ -121,12 +184,14 @@ export interface ServerToClientEvents {
|
||||
'command:result': (payload: SlashCommandResultPayload) => void;
|
||||
'command:approval': (payload: SlashCommandApprovalResultPayload) => void;
|
||||
'system:reload': (payload: SystemReloadPayload) => void;
|
||||
'turn:ack': (payload: HarnessTurnAckPayload) => void;
|
||||
error: (payload: ErrorPayload) => void;
|
||||
}
|
||||
|
||||
/** Socket.IO typed event map: client → server */
|
||||
export interface ClientToServerEvents {
|
||||
message: (data: ChatMessagePayload) => void;
|
||||
'turn:send': (data: HarnessTurnSendPayload) => void;
|
||||
'set:thinking': (data: SetThinkingPayload) => void;
|
||||
'command:execute': (data: SlashCommandPayload) => void;
|
||||
'command:approve': (data: SlashCommandPayload) => void;
|
||||
|
||||
@@ -14,6 +14,10 @@ export type {
|
||||
AbortPayload,
|
||||
ErrorPayload,
|
||||
ChatMessagePayload,
|
||||
HarnessTurnSendPayload,
|
||||
HarnessTurnAckPayload,
|
||||
ChatSendProtocol,
|
||||
ChatSendCapabilityPayload,
|
||||
ServerToClientEvents,
|
||||
ClientToServerEvents,
|
||||
} from './events.js';
|
||||
|
||||
Reference in New Issue
Block a user