mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
p2 rewritten by the Chord v2 authoring rules (decision "App authoring rules confirmed by the p2 audit"), in four parts merged together: - core: session lifecycle (relocate, clone, fork, archive) and search rebuild are persisted jobs on a new server store; Sessions v6 with client-chosen ids and visible operations; Retry answers with the worker's real outcome; workers push branch, subagent and status state to the server; roots take the method's ctx. - services: models, envs, ports, login, mcp, logs, sharing and voice follow external state (self.follow, followNative) instead of copy loops; methods answer after their state commits; presence from host.references. - chat: chat mode, artifacts and prompt resources follow Durable and native state; shell commands are Chord jobs (shellId is the requestId); status pushed before send and stop answer; race-free draft claim. - ui: optimistic updates on web (useOptimistic) and terminal (TuiScope.optimistic, extended in Chord with a reducer and a pending flag), pending states for long work, visible rollback, load waterfalls removed; merged with the one composer and immediate first send (ccff9876e) and the folder + button (5a31a6d5f). docs/optimistic-ui.md describes the pattern.
82 lines
2.8 KiB
TypeScript
82 lines
2.8 KiB
TypeScript
import type { Usage } from "@earendil-works/pi-ai";
|
|
import { arr, bool, nul, num, obj, opt, type Static, str, union, unknown } from "@earendil-works/pi-schema";
|
|
import { local, method, param, record, remote, serverHost, unsafe } from "@p2/app/v1";
|
|
|
|
export const StatusSchema = obj({
|
|
/** A worker process runs for the session. */
|
|
running: bool(),
|
|
error: opt(str()),
|
|
usage: opt(unsafe<Usage>(unknown())),
|
|
/** Live Durable tasks (foreground and background). */
|
|
tasks: num(),
|
|
/** Conversations with foreground work, ascending. */
|
|
busy: arr(num()),
|
|
});
|
|
export type Status = Static<typeof StatusSchema>;
|
|
export const StatusesSchema = record(StatusSchema);
|
|
|
|
/** What a worker reports of its work: its live tasks, its busy conversations and its spend. */
|
|
export const ReportFields = {
|
|
tasks: num(),
|
|
busy: arr(num()),
|
|
usage: opt(unsafe<Usage>(unknown())),
|
|
};
|
|
const ReportSchema = obj(ReportFields);
|
|
|
|
/** Live status of every session (server, in memory). Reports are fenced by worker generation. */
|
|
export const StatusStore = local("p2.status-store", {
|
|
version: 1,
|
|
params: {},
|
|
members: {
|
|
statuses: StatusesSchema,
|
|
report: method(obj({ ...ReportFields, session: str(), generation: num() })),
|
|
},
|
|
});
|
|
|
|
/** Readers (owner) see every session's status; a worker reports its own session's (its principal names it). */
|
|
export const SessionStatus = remote("p2.session-status", {
|
|
version: 1,
|
|
params: {},
|
|
hostAddress: serverHost,
|
|
variants: {
|
|
reader: { state: { statuses: StatusesSchema } },
|
|
reporter: { methods: { report: method(ReportSchema) } },
|
|
},
|
|
});
|
|
|
|
/**
|
|
* The session worker's status push (worker, local): reports the worker's work now (its tasks, busy conversations and
|
|
* spend) to the server and returns once the server committed it. A method that starts or stops work (`Chat.send`,
|
|
* `Chat.stop`) awaits it, so the sidebar's working dot is current when the method answers.
|
|
*/
|
|
export const StatusReport = local("p2.status-report", {
|
|
version: 1,
|
|
params: {},
|
|
members: { push: method() },
|
|
});
|
|
|
|
/**
|
|
* Owner-only retry of a failed session worker; reading status never starts it. `restart` answers once the new worker
|
|
* runs, or fails with why it could not start (`worker_failed`).
|
|
*/
|
|
export const WorkerControl = remote("p2.worker-control", {
|
|
version: 1,
|
|
params: { session: param.str() },
|
|
hostAddress: serverHost,
|
|
variants: { owner: { methods: { restart: method() } } },
|
|
});
|
|
|
|
/**
|
|
* What a page shows about its session: how many viewers (distinct `viewer` params holding it: a page holds one for its
|
|
* active session, child views included) and the session's spend.
|
|
*/
|
|
export const SessionMetrics = remote("p2.session-metrics", {
|
|
version: 1,
|
|
params: { session: param.str(), viewer: param.str({ min: 1, max: 80 }) },
|
|
hostAddress: serverHost,
|
|
variants: {
|
|
reader: {
|
|
state: { clients: num(), usage: union([unsafe<Usage>(unknown()), nul()]) },
|
|
},
|
|
},
|
|
});
|