@overmux/pi 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +118 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +40 -0
- package/dist/cli.js.map +1 -0
- package/dist/config-2jNv4tol.d.ts +34 -0
- package/dist/config-2jNv4tol.d.ts.map +1 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +47 -0
- package/dist/config.js.map +1 -0
- package/dist/extension.d.ts +19 -0
- package/dist/extension.d.ts.map +1 -0
- package/dist/extension.js +265 -0
- package/dist/extension.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/jsonl-tail.d.ts +13 -0
- package/dist/jsonl-tail.d.ts.map +1 -0
- package/dist/jsonl-tail.js +83 -0
- package/dist/jsonl-tail.js.map +1 -0
- package/dist/live-events-ClhFOMGW.js +497 -0
- package/dist/live-events-ClhFOMGW.js.map +1 -0
- package/dist/live-events-DAmf6RRx.d.ts +107 -0
- package/dist/live-events-DAmf6RRx.d.ts.map +1 -0
- package/dist/live-events.d.ts +2 -0
- package/dist/live-events.js +2 -0
- package/dist/notification-DzOd9cRc.d.ts +20 -0
- package/dist/notification-DzOd9cRc.d.ts.map +1 -0
- package/dist/notification.d.ts +2 -0
- package/dist/notification.js +54 -0
- package/dist/notification.js.map +1 -0
- package/dist/plugin.d.ts +90 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +213 -0
- package/dist/plugin.js.map +1 -0
- package/dist/projection.d.ts +101 -0
- package/dist/projection.d.ts.map +1 -0
- package/dist/projection.js +550 -0
- package/dist/projection.js.map +1 -0
- package/dist/protocol-CsrnSPOv.d.ts +115 -0
- package/dist/protocol-CsrnSPOv.d.ts.map +1 -0
- package/dist/protocol.d.ts +2 -0
- package/dist/protocol.js +365 -0
- package/dist/protocol.js.map +1 -0
- package/dist/react.d.ts +139 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +796 -0
- package/dist/react.js.map +1 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.js +4 -0
- package/dist/session-status-CZLTo8Km.d.ts +71 -0
- package/dist/session-status-CZLTo8Km.d.ts.map +1 -0
- package/dist/styles.css +619 -0
- package/docs/index.md +10 -0
- package/package.json +115 -0
- package/src/cli.ts +59 -0
- package/src/config.ts +87 -0
- package/src/extension.ts +486 -0
- package/src/index.ts +14 -0
- package/src/jsonl-tail.ts +110 -0
- package/src/live-events.ts +578 -0
- package/src/notification.ts +109 -0
- package/src/plugin.ts +369 -0
- package/src/projection.ts +995 -0
- package/src/protocol.ts +805 -0
- package/src/react.tsx +1293 -0
- package/src/server.ts +15 -0
- package/src/session-status.ts +379 -0
- package/src/styles.css +619 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-events-ClhFOMGW.js","names":["SAFE_PATH_SEGMENT","requirePathSegment","reportError","localHostname","hostname"],"sources":["../src/session-status.ts","../src/live-events.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { watch, type FSWatcher } from \"node:fs\";\nimport {\n mkdir,\n readFile,\n readdir,\n rename,\n rm,\n writeFile,\n} from \"node:fs/promises\";\nimport { hostname as localHostname } from \"node:os\";\nimport { join, resolve } from \"node:path\";\n\nimport { z } from \"zod\";\n\nexport const piSessionStatusSchema = z\n .object({\n version: z.literal(1),\n sessionId: z.string().min(1),\n sessionFile: z.string().min(1),\n streamId: z.string().min(1),\n processInstanceId: z.string().min(1),\n pid: z.number().int().positive(),\n hostname: z.string().min(1),\n tmuxPane: z.string().min(1).optional(),\n startedAt: z.number().int().nonnegative(),\n updatedAt: z.number().int().nonnegative(),\n state: z.enum([\"idle\", \"busy\", \"stopped\"]),\n model: z\n .object({\n provider: z.string().min(1),\n id: z.string().min(1),\n name: z.string().min(1),\n })\n .strict()\n .optional(),\n thinkingLevel: z.string().min(1),\n modelOptions: z\n .array(\n z\n .object({\n provider: z.string().min(1),\n id: z.string().min(1),\n name: z.string().min(1),\n })\n .strict(),\n )\n .max(256)\n .optional(),\n contextUsage: z\n .object({\n tokens: z.number().nonnegative(),\n contextWindow: z.number().positive(),\n percent: z.number().nonnegative(),\n })\n .strict()\n .optional(),\n })\n .strict();\n\nexport type PiSessionStatus = z.infer<typeof piSessionStatusSchema>;\nexport type PiSessionStatusUpdate = Partial<\n Pick<\n PiSessionStatus,\n \"contextUsage\" | \"model\" | \"modelOptions\" | \"state\" | \"thinkingLevel\"\n >\n>;\nexport type PiSessionStatusWriter = {\n filePath: string;\n streamId: string;\n update: (update: PiSessionStatusUpdate) => Promise<void>;\n close: () => Promise<void>;\n};\nexport type PiSessionStatusSource = {\n list: () => Promise<readonly PiSessionStatus[]>;\n subscribe: (\n invalidate: () => void,\n options: { signal: AbortSignal },\n ) => () => void;\n};\n\ntype StatusWriterState = {\n accepting: boolean;\n current: PiSessionStatus;\n filePath: string;\n onError?: (error: unknown) => void;\n sessionDir: string;\n writeChain: Promise<void>;\n};\n\nconst SAFE_PATH_SEGMENT = /^[A-Za-z0-9._-]{1,128}$/;\n\nconst requirePathSegment = (value: string, label: string): string => {\n if (!SAFE_PATH_SEGMENT.test(value)) {\n throw new Error(`Invalid ${label} for Pi session status path`);\n }\n return value;\n};\n\nexport const piSessionStatusPath = (\n rootDir: string,\n sessionId: string,\n streamId: string,\n): string =>\n join(\n resolve(rootDir),\n requirePathSegment(sessionId, \"session ID\"),\n `${requirePathSegment(streamId, \"stream ID\")}.status.json`,\n );\n\nexport const parsePiSessionStatus = (\n value: unknown,\n): PiSessionStatus | undefined => {\n const result = piSessionStatusSchema.safeParse(value);\n return result.success ? result.data : undefined;\n};\n\nconst reportError = (\n onError: ((error: unknown) => void) | undefined,\n error: unknown,\n): void => {\n try {\n onError?.(error);\n } catch {}\n};\n\nconst replaceStatusFile = async (\n state: StatusWriterState,\n status: PiSessionStatus,\n): Promise<void> => {\n await mkdir(state.sessionDir, { recursive: true, mode: 0o700 });\n const temporaryPath = `${state.filePath}.${randomUUID()}.tmp`;\n try {\n await writeFile(temporaryPath, `${JSON.stringify(status)}\\n`, {\n encoding: \"utf8\",\n flag: \"wx\",\n mode: 0o600,\n });\n await rename(temporaryPath, state.filePath);\n } catch (error) {\n await rm(temporaryPath, { force: true }).catch(() => undefined);\n throw error;\n }\n};\n\nconst updateStatus = (\n state: StatusWriterState,\n update: PiSessionStatusUpdate,\n): Promise<void> => {\n if (!state.accepting) {\n return state.writeChain;\n }\n const status = piSessionStatusSchema.parse({\n ...state.current,\n ...update,\n updatedAt: Date.now(),\n });\n state.current = status;\n const write = state.writeChain.then(() => replaceStatusFile(state, status));\n state.writeChain = write.catch((error: unknown) =>\n reportError(state.onError, error),\n );\n return state.writeChain;\n};\n\nexport const createPiSessionStatusWriter = ({\n rootDir,\n status,\n onError,\n}: {\n rootDir: string;\n status: Omit<PiSessionStatus, \"updatedAt\" | \"version\">;\n onError?: (error: unknown) => void;\n}): PiSessionStatusWriter => {\n const filePath = piSessionStatusPath(\n rootDir,\n status.sessionId,\n status.streamId,\n );\n const state: StatusWriterState = {\n accepting: true,\n current: piSessionStatusSchema.parse({\n ...status,\n updatedAt: status.startedAt,\n version: 1,\n }),\n filePath,\n onError,\n sessionDir: join(resolve(rootDir), status.sessionId),\n writeChain: Promise.resolve(),\n };\n\n return {\n filePath,\n streamId: status.streamId,\n update: (update) => updateStatus(state, update),\n close: async () => {\n if (!state.accepting) {\n await state.writeChain;\n return;\n }\n const closing = updateStatus(state, { state: \"stopped\" });\n state.accepting = false;\n await closing;\n },\n };\n};\n\nconst readStatus = async (\n filePath: string,\n sessionId: string,\n streamId: string,\n): Promise<PiSessionStatus | undefined> => {\n try {\n const status = parsePiSessionStatus(\n JSON.parse(await readFile(filePath, \"utf8\")),\n );\n return status?.sessionId === sessionId && status.streamId === streamId\n ? status\n : undefined;\n } catch {\n return undefined;\n }\n};\n\nconst compareRecency = (\n left: PiSessionStatus,\n right: PiSessionStatus,\n): number =>\n left.updatedAt - right.updatedAt ||\n left.startedAt - right.startedAt ||\n left.streamId.localeCompare(right.streamId);\n\nconst newestBy = (\n statuses: readonly PiSessionStatus[],\n keyOf: (status: PiSessionStatus) => string,\n): PiSessionStatus[] => {\n const newest = new Map<string, PiSessionStatus>();\n statuses.forEach((status) => {\n const key = keyOf(status);\n const previous = newest.get(key);\n if (!previous || compareRecency(previous, status) < 0) {\n newest.set(key, status);\n }\n });\n return [...newest.values()];\n};\n\nexport const isLocalPidAlive = (pid: number): boolean => {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n return (error as NodeJS.ErrnoException).code === \"EPERM\";\n }\n};\n\nexport const listPiSessionStatuses = async ({\n rootDir,\n hostname = localHostname(),\n pidAlive = isLocalPidAlive,\n}: {\n rootDir: string;\n hostname?: string;\n pidAlive?: (pid: number) => boolean;\n}): Promise<PiSessionStatus[]> => {\n const sessionDirectories = (\n await readdir(resolve(rootDir), {\n withFileTypes: true,\n }).catch(() => [])\n )\n .filter(\n (entry) => entry.isDirectory() && SAFE_PATH_SEGMENT.test(entry.name),\n )\n .map((entry) => entry.name);\n const statuses = (\n await Promise.all(\n sessionDirectories.map(async (sessionId) => {\n const sessionDir = join(resolve(rootDir), sessionId);\n const files = (\n await readdir(sessionDir, { withFileTypes: true }).catch(() => [])\n ).filter(\n (entry) =>\n entry.isFile() &&\n entry.name.endsWith(\".status.json\") &&\n SAFE_PATH_SEGMENT.test(entry.name.slice(0, -\".status.json\".length)),\n );\n return Promise.all(\n files.map((entry) => {\n const streamId = entry.name.slice(0, -\".status.json\".length);\n return readStatus(\n join(sessionDir, entry.name),\n sessionId,\n streamId,\n );\n }),\n );\n }),\n )\n )\n .flatMap((values) => values)\n .filter((status) => status !== undefined);\n const processStatuses = newestBy(\n statuses,\n ({ hostname: statusHostname, processInstanceId }) =>\n `${statusHostname}\\0${processInstanceId}`,\n ).filter(\n (status) =>\n status.state !== \"stopped\" &&\n status.hostname === hostname &&\n pidAlive(status.pid),\n );\n return newestBy(processStatuses, ({ sessionId }) => sessionId).sort(\n (left, right) => left.sessionId.localeCompare(right.sessionId),\n );\n};\n\nexport const createPiSessionStatusSource = ({\n rootDir,\n pollIntervalMs = 250,\n hostname,\n pidAlive,\n}: {\n rootDir: string;\n pollIntervalMs?: number;\n hostname?: string;\n pidAlive?: (pid: number) => boolean;\n}): PiSessionStatusSource => ({\n list: () => listPiSessionStatuses({ rootDir, hostname, pidAlive }),\n subscribe: (invalidate, { signal }) => {\n if (signal.aborted) {\n return () => undefined;\n }\n let watcher: FSWatcher | undefined;\n let scheduled: ReturnType<typeof setTimeout> | undefined;\n let fingerprint: string | undefined;\n let checkQueue = Promise.resolve();\n const check = () => {\n checkQueue = checkQueue\n .then(async () => {\n const next = JSON.stringify(\n await listPiSessionStatuses({ rootDir, hostname, pidAlive }),\n );\n if (next === fingerprint || signal.aborted) {\n return;\n }\n fingerprint = next;\n invalidate();\n })\n .catch(() => undefined);\n };\n const schedule = () => {\n if (scheduled || signal.aborted) {\n return;\n }\n scheduled = setTimeout(() => {\n scheduled = undefined;\n check();\n }, 10);\n scheduled.unref();\n };\n try {\n watcher = watch(resolve(rootDir), { recursive: true }, schedule);\n } catch {}\n check();\n const timer = setInterval(schedule, pollIntervalMs);\n timer.unref();\n const dispose = () => {\n signal.removeEventListener(\"abort\", dispose);\n if (scheduled) {\n clearTimeout(scheduled);\n }\n clearInterval(timer);\n watcher?.close();\n };\n signal.addEventListener(\"abort\", dispose, { once: true });\n return dispose;\n },\n});\n","import { randomUUID } from \"node:crypto\";\nimport { appendFile, mkdir } from \"node:fs/promises\";\nimport { hostname } from \"node:os\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\n\nimport {\n createPiSessionStatusWriter,\n type PiSessionStatusUpdate,\n type PiSessionStatusWriter,\n} from \"./session-status.js\";\n\nimport type {\n AgentEndEvent,\n AgentSettledEvent,\n AgentStartEvent,\n ExtensionAPI,\n ExtensionContext,\n MessageEndEvent,\n MessageStartEvent,\n MessageUpdateEvent,\n SessionCompactEvent,\n SessionInfoChangedEvent,\n SessionShutdownEvent,\n SessionStartEvent,\n SessionTreeEvent,\n ToolExecutionEndEvent,\n ToolExecutionStartEvent,\n TurnEndEvent,\n TurnStartEvent,\n} from \"@earendil-works/pi-coding-agent\";\n\ntype AssistantMessageEvent = MessageUpdateEvent[\"assistantMessageEvent\"];\ntype StopReason = Extract<\n AssistantMessageEvent,\n { type: \"done\" | \"error\" }\n>[\"reason\"];\ntype ModelIdentity = { provider: string; id: string; name: string };\ntype LiveModelSelectEvent = {\n type: \"model_select\";\n source: \"set\" | \"cycle\" | \"restore\";\n model: ModelIdentity;\n previousModel?: ModelIdentity;\n};\ntype LiveThinkingLevelSelectEvent = {\n type: \"thinking_level_select\";\n level: string;\n previousLevel: string;\n};\n\nexport type CompactAssistantMessageEvent =\n | { type: \"start\" }\n | {\n type:\n | \"text_start\"\n | \"text_end\"\n | \"thinking_start\"\n | \"thinking_end\"\n | \"toolcall_start\"\n | \"toolcall_end\";\n contentIndex: number;\n }\n | {\n type: \"text_delta\" | \"thinking_delta\" | \"toolcall_delta\";\n contentIndex: number;\n delta: string;\n }\n | { type: \"done\"; reason: StopReason }\n | { type: \"error\"; reason: StopReason; errorMessage?: string };\n\nexport type LiveEventPayload =\n | (SessionStartEvent & { cwd: string; sessionFile?: string; pid: number })\n | SessionShutdownEvent\n | SessionInfoChangedEvent\n | SessionCompactEvent\n | SessionTreeEvent\n | AgentStartEvent\n | { type: AgentEndEvent[\"type\"] }\n | AgentSettledEvent\n | TurnStartEvent\n | { type: TurnEndEvent[\"type\"]; turnIndex: number }\n | {\n type: MessageStartEvent[\"type\"];\n messageId: string;\n messageSequence: number;\n message: MessageStartEvent[\"message\"];\n }\n | {\n type: MessageUpdateEvent[\"type\"];\n messageId: string;\n messageSequence: number;\n assistantMessageEvent: CompactAssistantMessageEvent;\n }\n | {\n type: MessageEndEvent[\"type\"];\n messageId: string;\n messageSequence: number;\n message: MessageEndEvent[\"message\"];\n }\n | ToolExecutionStartEvent\n | ToolExecutionEndEvent\n | LiveModelSelectEvent\n | LiveThinkingLevelSelectEvent;\n\nexport type LiveEventEnvelope<Event> = {\n version: 1;\n sessionId: string;\n processInstanceId: string;\n streamId: string;\n sequence: number;\n timestamp: number;\n event: Event;\n};\n\nexport type LiveEventRecord = LiveEventEnvelope<LiveEventPayload>;\nexport type LiveEventWireRecord = LiveEventEnvelope<\n Record<string, unknown> & { type: string }\n>;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nexport const parseLiveEventRecord = (\n value: unknown,\n sessionId?: string,\n): LiveEventWireRecord | undefined => {\n if (!isRecord(value) || value.version !== 1) {\n return undefined;\n }\n if (sessionId !== undefined && value.sessionId !== sessionId) {\n return undefined;\n }\n if (\n typeof value.sessionId !== \"string\" ||\n typeof value.processInstanceId !== \"string\" ||\n typeof value.streamId !== \"string\" ||\n !Number.isSafeInteger(value.sequence) ||\n (value.sequence as number) < 1 ||\n typeof value.timestamp !== \"number\" ||\n !isRecord(value.event) ||\n typeof value.event.type !== \"string\"\n ) {\n return undefined;\n }\n return value as LiveEventWireRecord;\n};\n\nexport type LiveEventWriter = {\n filePath: string;\n streamId: string;\n append: (event: LiveEventPayload) => void;\n close: (event: SessionShutdownEvent) => Promise<void>;\n};\n\ntype LiveEventWriterState = {\n filePath: string;\n sessionDir: string;\n sessionId: string;\n processInstanceId: string;\n streamId: string;\n sequence: number;\n accepting: boolean;\n directoryReady: boolean;\n failed: boolean;\n writeChain: Promise<void>;\n onError?: (error: unknown) => void;\n};\n\ntype LiveEventCapture = {\n start: (event: SessionStartEvent, ctx: ExtensionContext) => Promise<void>;\n stop: (event: SessionShutdownEvent) => Promise<void>;\n};\n\ntype LiveEventCaptureState = {\n writer?: LiveEventWriter;\n statusWriter?: PiSessionStatusWriter;\n messageSequence: number;\n activeMessage?: { id: string; sequence: number; role: string };\n};\n\nconst PROCESS_INSTANCE_KEY = Symbol.for(\n \"overmux-pi.live-events.process-instance-id\",\n);\nconst processGlobals = globalThis as typeof globalThis & {\n [PROCESS_INSTANCE_KEY]?: string;\n};\nconst existingProcessInstanceId = processGlobals[PROCESS_INSTANCE_KEY];\nexport const PROCESS_INSTANCE_ID =\n existingProcessInstanceId ?? `${process.pid}-${randomUUID()}`;\nprocessGlobals[PROCESS_INSTANCE_KEY] = PROCESS_INSTANCE_ID;\n\nconst SAFE_PATH_SEGMENT = /^[A-Za-z0-9._-]{1,128}$/;\n\nconst requirePathSegment = (value: string, label: string): string => {\n if (!SAFE_PATH_SEGMENT.test(value)) {\n throw new Error(`Invalid ${label} for live event path`);\n }\n return value;\n};\n\nexport const liveEventSessionDir = (\n rootDir: string,\n sessionId: string,\n): string =>\n join(resolve(rootDir), requirePathSegment(sessionId, \"session ID\"));\n\nexport const liveEventStreamPath = (\n rootDir: string,\n sessionId: string,\n streamId: string,\n): string =>\n join(\n liveEventSessionDir(rootDir, sessionId),\n `${requirePathSegment(streamId, \"stream ID\")}.jsonl`,\n );\n\nconst isSameOrWithin = (parent: string, candidate: string): boolean => {\n const relativePath = relative(resolve(parent), resolve(candidate));\n return (\n relativePath === \"\" ||\n (relativePath !== \"..\" && !relativePath.startsWith(`..${sep}`))\n );\n};\n\nconst assertSeparateFromSessionFile = (\n rootDir: string,\n sessionFile: string | undefined,\n): void => {\n if (!sessionFile) {\n return;\n }\n const sessionDir = dirname(sessionFile);\n if (\n isSameOrWithin(rootDir, sessionDir) ||\n isSameOrWithin(sessionDir, rootDir)\n ) {\n throw new Error(\n \"Live events directory must be outside the Pi session directory tree\",\n );\n }\n};\n\nconst reportError = (\n onError: ((error: unknown) => void) | undefined,\n error: unknown,\n): void => {\n try {\n onError?.(error);\n } catch {}\n};\n\nconst reportWriterError = (\n state: LiveEventWriterState,\n error: unknown,\n): void => {\n state.failed = true;\n reportError(state.onError, error);\n};\n\nconst appendLiveEvent = (\n state: LiveEventWriterState,\n event: LiveEventPayload,\n): void => {\n if (!state.accepting || state.failed) {\n return;\n }\n\n const record: LiveEventRecord = {\n version: 1,\n sessionId: state.sessionId,\n processInstanceId: state.processInstanceId,\n streamId: state.streamId,\n sequence: state.sequence,\n timestamp: Date.now(),\n event,\n };\n state.sequence += 1;\n\n let line: string;\n try {\n line = `${JSON.stringify(record)}\\n`;\n } catch (error) {\n reportWriterError(state, error);\n return;\n }\n\n state.writeChain = state.writeChain\n .then(async () => {\n if (!state.directoryReady) {\n await mkdir(state.sessionDir, { recursive: true, mode: 0o700 });\n state.directoryReady = true;\n }\n await appendFile(state.filePath, line, { encoding: \"utf8\", mode: 0o600 });\n })\n .catch((error: unknown) => reportWriterError(state, error));\n};\n\nconst closeLiveEventWriter = async (\n state: LiveEventWriterState,\n event: SessionShutdownEvent,\n): Promise<void> => {\n if (!state.accepting) {\n await state.writeChain;\n return;\n }\n\n appendLiveEvent(state, event);\n state.accepting = false;\n await state.writeChain;\n};\n\nexport const createLiveEventWriter = ({\n rootDir,\n sessionId,\n processInstanceId = PROCESS_INSTANCE_ID,\n streamId = randomUUID(),\n onError,\n}: {\n rootDir: string;\n sessionId: string;\n processInstanceId?: string;\n streamId?: string;\n onError?: (error: unknown) => void;\n}): LiveEventWriter => {\n const state: LiveEventWriterState = {\n filePath: liveEventStreamPath(rootDir, sessionId, streamId),\n sessionDir: liveEventSessionDir(rootDir, sessionId),\n sessionId,\n processInstanceId,\n streamId,\n sequence: 1,\n accepting: true,\n directoryReady: false,\n failed: false,\n writeChain: Promise.resolve(),\n onError,\n };\n\n return {\n filePath: state.filePath,\n streamId: state.streamId,\n append: (event) => appendLiveEvent(state, event),\n close: (event) => closeLiveEventWriter(state, event),\n };\n};\n\nexport const compactAssistantMessageEvent = (\n event: AssistantMessageEvent,\n): CompactAssistantMessageEvent => {\n if (event.type === \"start\") {\n return { type: event.type };\n }\n if (event.type === \"done\") {\n return { type: event.type, reason: event.reason };\n }\n if (event.type === \"error\") {\n const errorMessage = event.error.errorMessage;\n return {\n type: event.type,\n reason: event.reason,\n ...(errorMessage ? { errorMessage } : {}),\n };\n }\n if (\n event.type === \"text_delta\" ||\n event.type === \"thinking_delta\" ||\n event.type === \"toolcall_delta\"\n ) {\n return {\n type: event.type,\n contentIndex: event.contentIndex,\n delta: event.delta,\n };\n }\n return { type: event.type, contentIndex: event.contentIndex };\n};\n\nconst modelIdentity = (model: ModelIdentity): ModelIdentity => ({\n provider: model.provider,\n id: model.id,\n name: model.name,\n});\n\nconst modelOptions = (ctx: ExtensionContext): ModelIdentity[] => {\n const scopedModels = ctx.scopedModels ?? [];\n const availableModels = ctx.modelRegistry?.getAvailable?.() ?? [];\n const models = scopedModels.length\n ? scopedModels.map(({ model }) => model)\n : availableModels.length\n ? availableModels\n : (ctx.modelRegistry?.getAll?.() ?? []);\n return [\n ...new Map(\n models.map((model) => {\n const identity = modelIdentity(model);\n return [`${identity.provider}\\0${identity.id}`, identity];\n }),\n ).values(),\n ].slice(0, 256);\n};\n\nconst statusContextUsage = (ctx: ExtensionContext) => {\n const usage = ctx.getContextUsage();\n return usage && usage.tokens !== null && usage.percent !== null\n ? { ...usage, tokens: usage.tokens, percent: usage.percent }\n : undefined;\n};\n\nconst messageRole = (event: MessageStartEvent | MessageEndEvent): string =>\n event.message.role;\n\nexport const registerLiveEventCapture = (\n pi: ExtensionAPI,\n options: {\n rootDir: string | null;\n env: NodeJS.ProcessEnv;\n onError?: (error: unknown) => void;\n },\n): LiveEventCapture => {\n const state: LiveEventCaptureState = { messageSequence: 0 };\n const append = (event: LiveEventPayload) => state.writer?.append(event);\n const updateStatus = (ctx: ExtensionContext, update: PiSessionStatusUpdate) =>\n state.statusWriter?.update({\n contextUsage: statusContextUsage(ctx),\n ...update,\n });\n\n pi.on(\"session_info_changed\", (event) => append(event));\n pi.on(\"session_compact\", (event) => append(event));\n pi.on(\"session_tree\", (event) => append(event));\n pi.on(\"agent_start\", (event, ctx) => {\n append(event);\n return updateStatus(ctx, { state: \"busy\" });\n });\n pi.on(\"agent_end\", (event) => append({ type: event.type }));\n pi.on(\"agent_settled\", (event, ctx) => {\n append(event);\n return updateStatus(ctx, { state: \"idle\" });\n });\n pi.on(\"turn_start\", (event) => append(event));\n pi.on(\"turn_end\", (event, ctx) => {\n append({ type: event.type, turnIndex: event.turnIndex });\n return updateStatus(ctx, {});\n });\n pi.on(\"message_start\", (event) => {\n state.messageSequence += 1;\n const activeMessage = {\n id: `${state.writer?.streamId ?? \"inactive\"}:${state.messageSequence}`,\n sequence: state.messageSequence,\n role: messageRole(event),\n };\n state.activeMessage = activeMessage;\n append({\n type: event.type,\n messageId: activeMessage.id,\n messageSequence: activeMessage.sequence,\n message: event.message,\n });\n });\n pi.on(\"message_update\", (event) => {\n const activeMessage = state.activeMessage;\n if (!activeMessage || activeMessage.role !== \"assistant\") {\n return;\n }\n append({\n type: event.type,\n messageId: activeMessage.id,\n messageSequence: activeMessage.sequence,\n assistantMessageEvent: compactAssistantMessageEvent(\n event.assistantMessageEvent,\n ),\n });\n });\n pi.on(\"message_end\", (event, ctx) => {\n const activeMessage = state.activeMessage;\n if (!activeMessage) {\n state.messageSequence += 1;\n }\n const identity = activeMessage ?? {\n id: `${state.writer?.streamId ?? \"inactive\"}:${state.messageSequence}`,\n sequence: state.messageSequence,\n role: messageRole(event),\n };\n append({\n type: event.type,\n messageId: identity.id,\n messageSequence: identity.sequence,\n message: event.message,\n });\n state.activeMessage = undefined;\n return updateStatus(ctx, {});\n });\n pi.on(\"tool_execution_start\", (event) => append(event));\n pi.on(\"tool_execution_end\", (event) => append(event));\n pi.on(\"model_select\", (event, ctx) => {\n const model = modelIdentity(event.model);\n append({\n type: event.type,\n source: event.source,\n model,\n ...(event.previousModel\n ? { previousModel: modelIdentity(event.previousModel) }\n : {}),\n });\n return updateStatus(ctx, { model });\n });\n pi.on(\"thinking_level_select\", (event, ctx) => {\n append(event);\n return updateStatus(ctx, { thinkingLevel: event.level });\n });\n\n return {\n start: async (event, ctx) => {\n state.messageSequence = 0;\n state.activeMessage = undefined;\n if (!options.rootDir) {\n return;\n }\n try {\n const sessionId = ctx.sessionManager.getSessionId();\n const sessionFile = ctx.sessionManager.getSessionFile();\n if (!sessionFile) {\n throw new Error(\"Pi session has no session file\");\n }\n assertSeparateFromSessionFile(options.rootDir, sessionFile);\n state.writer = createLiveEventWriter({\n rootDir: options.rootDir,\n sessionId,\n onError: options.onError,\n });\n const startedAt = Date.now();\n const contextUsage = statusContextUsage(ctx);\n const availableModelOptions = modelOptions(ctx);\n state.statusWriter = createPiSessionStatusWriter({\n rootDir: options.rootDir,\n onError: options.onError,\n status: {\n sessionId,\n sessionFile,\n streamId: state.writer.streamId,\n processInstanceId: PROCESS_INSTANCE_ID,\n pid: process.pid,\n hostname: hostname(),\n ...(options.env.TMUX_PANE\n ? { tmuxPane: options.env.TMUX_PANE }\n : {}),\n startedAt,\n state: \"idle\",\n ...(ctx.model ? { model: modelIdentity(ctx.model) } : {}),\n ...(availableModelOptions.length\n ? { modelOptions: availableModelOptions }\n : {}),\n thinkingLevel: ctx.thinkingLevel ?? pi.getThinkingLevel(),\n ...(contextUsage ? { contextUsage } : {}),\n },\n });\n append({\n ...event,\n cwd: ctx.cwd,\n sessionFile,\n pid: process.pid,\n });\n await state.statusWriter.update({});\n } catch (error) {\n state.writer = undefined;\n state.statusWriter = undefined;\n reportError(options.onError, error);\n }\n },\n stop: async (event) => {\n const writer = state.writer;\n const statusWriter = state.statusWriter;\n state.writer = undefined;\n state.statusWriter = undefined;\n state.activeMessage = undefined;\n await Promise.all([writer?.close(event), statusWriter?.close()]);\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { AgentEndEvent, AgentSettledEvent, AgentStartEvent, ExtensionAPI, ExtensionContext, MessageEndEvent, MessageStartEvent, MessageUpdateEvent, SessionCompactEvent, SessionInfoChangedEvent, SessionShutdownEvent, SessionStartEvent, SessionTreeEvent, ToolExecutionEndEvent, ToolExecutionStartEvent, TurnEndEvent, TurnStartEvent } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
//#region src/live-events.d.ts
|
|
3
|
+
type AssistantMessageEvent = MessageUpdateEvent["assistantMessageEvent"];
|
|
4
|
+
type StopReason = Extract<AssistantMessageEvent, {
|
|
5
|
+
type: "done" | "error";
|
|
6
|
+
}>["reason"];
|
|
7
|
+
type ModelIdentity = {
|
|
8
|
+
provider: string;
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
type LiveModelSelectEvent = {
|
|
13
|
+
type: "model_select";
|
|
14
|
+
source: "set" | "cycle" | "restore";
|
|
15
|
+
model: ModelIdentity;
|
|
16
|
+
previousModel?: ModelIdentity;
|
|
17
|
+
};
|
|
18
|
+
type LiveThinkingLevelSelectEvent = {
|
|
19
|
+
type: "thinking_level_select";
|
|
20
|
+
level: string;
|
|
21
|
+
previousLevel: string;
|
|
22
|
+
};
|
|
23
|
+
type CompactAssistantMessageEvent = {
|
|
24
|
+
type: "start";
|
|
25
|
+
} | {
|
|
26
|
+
type: "text_start" | "text_end" | "thinking_start" | "thinking_end" | "toolcall_start" | "toolcall_end";
|
|
27
|
+
contentIndex: number;
|
|
28
|
+
} | {
|
|
29
|
+
type: "text_delta" | "thinking_delta" | "toolcall_delta";
|
|
30
|
+
contentIndex: number;
|
|
31
|
+
delta: string;
|
|
32
|
+
} | {
|
|
33
|
+
type: "done";
|
|
34
|
+
reason: StopReason;
|
|
35
|
+
} | {
|
|
36
|
+
type: "error";
|
|
37
|
+
reason: StopReason;
|
|
38
|
+
errorMessage?: string;
|
|
39
|
+
};
|
|
40
|
+
type LiveEventPayload = (SessionStartEvent & {
|
|
41
|
+
cwd: string;
|
|
42
|
+
sessionFile?: string;
|
|
43
|
+
pid: number;
|
|
44
|
+
}) | SessionShutdownEvent | SessionInfoChangedEvent | SessionCompactEvent | SessionTreeEvent | AgentStartEvent | {
|
|
45
|
+
type: AgentEndEvent["type"];
|
|
46
|
+
} | AgentSettledEvent | TurnStartEvent | {
|
|
47
|
+
type: TurnEndEvent["type"];
|
|
48
|
+
turnIndex: number;
|
|
49
|
+
} | {
|
|
50
|
+
type: MessageStartEvent["type"];
|
|
51
|
+
messageId: string;
|
|
52
|
+
messageSequence: number;
|
|
53
|
+
message: MessageStartEvent["message"];
|
|
54
|
+
} | {
|
|
55
|
+
type: MessageUpdateEvent["type"];
|
|
56
|
+
messageId: string;
|
|
57
|
+
messageSequence: number;
|
|
58
|
+
assistantMessageEvent: CompactAssistantMessageEvent;
|
|
59
|
+
} | {
|
|
60
|
+
type: MessageEndEvent["type"];
|
|
61
|
+
messageId: string;
|
|
62
|
+
messageSequence: number;
|
|
63
|
+
message: MessageEndEvent["message"];
|
|
64
|
+
} | ToolExecutionStartEvent | ToolExecutionEndEvent | LiveModelSelectEvent | LiveThinkingLevelSelectEvent;
|
|
65
|
+
type LiveEventEnvelope<Event> = {
|
|
66
|
+
version: 1;
|
|
67
|
+
sessionId: string;
|
|
68
|
+
processInstanceId: string;
|
|
69
|
+
streamId: string;
|
|
70
|
+
sequence: number;
|
|
71
|
+
timestamp: number;
|
|
72
|
+
event: Event;
|
|
73
|
+
};
|
|
74
|
+
type LiveEventRecord = LiveEventEnvelope<LiveEventPayload>;
|
|
75
|
+
type LiveEventWireRecord = LiveEventEnvelope<Record<string, unknown> & {
|
|
76
|
+
type: string;
|
|
77
|
+
}>;
|
|
78
|
+
declare const parseLiveEventRecord: (value: unknown, sessionId?: string) => LiveEventWireRecord | undefined;
|
|
79
|
+
type LiveEventWriter = {
|
|
80
|
+
filePath: string;
|
|
81
|
+
streamId: string;
|
|
82
|
+
append: (event: LiveEventPayload) => void;
|
|
83
|
+
close: (event: SessionShutdownEvent) => Promise<void>;
|
|
84
|
+
};
|
|
85
|
+
type LiveEventCapture = {
|
|
86
|
+
start: (event: SessionStartEvent, ctx: ExtensionContext) => Promise<void>;
|
|
87
|
+
stop: (event: SessionShutdownEvent) => Promise<void>;
|
|
88
|
+
};
|
|
89
|
+
declare const PROCESS_INSTANCE_ID: string;
|
|
90
|
+
declare const liveEventSessionDir: (rootDir: string, sessionId: string) => string;
|
|
91
|
+
declare const liveEventStreamPath: (rootDir: string, sessionId: string, streamId: string) => string;
|
|
92
|
+
declare const createLiveEventWriter: ({ rootDir, sessionId, processInstanceId, streamId, onError }: {
|
|
93
|
+
rootDir: string;
|
|
94
|
+
sessionId: string;
|
|
95
|
+
processInstanceId?: string;
|
|
96
|
+
streamId?: string;
|
|
97
|
+
onError?: (error: unknown) => void;
|
|
98
|
+
}) => LiveEventWriter;
|
|
99
|
+
declare const compactAssistantMessageEvent: (event: AssistantMessageEvent) => CompactAssistantMessageEvent;
|
|
100
|
+
declare const registerLiveEventCapture: (pi: ExtensionAPI, options: {
|
|
101
|
+
rootDir: string | null;
|
|
102
|
+
env: NodeJS.ProcessEnv;
|
|
103
|
+
onError?: (error: unknown) => void;
|
|
104
|
+
}) => LiveEventCapture;
|
|
105
|
+
//#endregion
|
|
106
|
+
export { LiveEventWireRecord as a, compactAssistantMessageEvent as c, liveEventStreamPath as d, parseLiveEventRecord as f, LiveEventRecord as i, createLiveEventWriter as l, LiveEventEnvelope as n, LiveEventWriter as o, registerLiveEventCapture as p, LiveEventPayload as r, PROCESS_INSTANCE_ID as s, CompactAssistantMessageEvent as t, liveEventSessionDir as u };
|
|
107
|
+
//# sourceMappingURL=live-events-DAmf6RRx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-events-DAmf6RRx.d.ts","names":[],"sources":["../src/live-events.ts"],"mappings":";;KA+BK,wBAAwB;KACxB,aAAa,QAChB;EACE;;KAEC;EAAkB;EAAkB;EAAY;;KAChD;EACH;EACA;EACA,OAAO;EACP,gBAAgB;;KAEb;EACH;EACA;EACA;;KAGU;EACN;;EAEA;EAOA;;EAGA;EACA;EACA;;EAEA;EAAc,QAAQ;;EACtB;EAAe,QAAQ;EAAY;;KAE7B,oBACP;EAAsB;EAAa;EAAsB;KAC1D,uBACA,0BACA,sBACA,mBACA;EACE,MAAM;IACR,oBACA;EACE,MAAM;EAAsB;;EAE5B,MAAM;EACN;EACA;EACA,SAAS;;EAGT,MAAM;EACN;EACA;EACA,uBAAuB;;EAGvB,MAAM;EACN;EACA;EACA,SAAS;IAEX,0BACA,wBACA,uBACA;KAEQ,kBAAkB;EAC5B;EACA;EACA;EACA;EACA;EACA;EACA,OAAO;;KAGG,kBAAkB,kBAAkB;KACpC,sBAAsB,kBAChC;EAA4B;;cAMjB,uBACX,gBACA,uBACC;KAsBS;EACV;EACA;EACA,SAAS,OAAO;EAChB,QAAQ,OAAO,yBAAyB;;KAiBrC;EACH,QAAQ,OAAO,mBAAmB,KAAK,qBAAqB;EAC5D,OAAO,OAAO,yBAAyB;;cAiB5B;cAaA,sBACX,iBACA;cAIW,sBACX,iBACA,mBACA;cAsGW,0BAAyB,SAAA,WAAA,mBAAA,UAAA;EAOpC;EACA;EACA;EACA;EACA,WAAW;MACT;cAuBS,+BACX,OAAO,0BACN;cA+DU,2BACX,IAAI,cACJ;EACE;EACA,KAAK,OAAO;EACZ,WAAW;MAEZ"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as LiveEventWireRecord, c as compactAssistantMessageEvent, d as liveEventStreamPath, f as parseLiveEventRecord, i as LiveEventRecord, l as createLiveEventWriter, n as LiveEventEnvelope, o as LiveEventWriter, p as registerLiveEventCapture, r as LiveEventPayload, s as PROCESS_INSTANCE_ID, t as CompactAssistantMessageEvent, u as liveEventSessionDir } from "./live-events-DAmf6RRx.js";
|
|
2
|
+
export { CompactAssistantMessageEvent, LiveEventEnvelope, LiveEventPayload, LiveEventRecord, LiveEventWireRecord, LiveEventWriter, PROCESS_INSTANCE_ID, compactAssistantMessageEvent, createLiveEventWriter, liveEventSessionDir, liveEventStreamPath, parseLiveEventRecord, registerLiveEventCapture };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as liveEventStreamPath, i as liveEventSessionDir, n as compactAssistantMessageEvent, o as parseLiveEventRecord, r as createLiveEventWriter, s as registerLiveEventCapture, t as PROCESS_INSTANCE_ID } from "./live-events-ClhFOMGW.js";
|
|
2
|
+
export { PROCESS_INSTANCE_ID, compactAssistantMessageEvent, createLiveEventWriter, liveEventSessionDir, liveEventStreamPath, parseLiveEventRecord, registerLiveEventCapture };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { n as OvermuxPiConfig } from "./config-2jNv4tol.js";
|
|
2
|
+
import { o as DelegateSettledEnvelope } from "./protocol-CsrnSPOv.js";
|
|
3
|
+
import { ExtensionAPI, MessageRenderer } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
//#region src/notification.d.ts
|
|
5
|
+
declare const OVERMUX_PI_DELEGATE_SETTLED_MESSAGE_TYPE = "overmux-pi.delegate-settled";
|
|
6
|
+
type DelegateNotificationDetails = DelegateSettledEnvelope & {
|
|
7
|
+
output: string;
|
|
8
|
+
};
|
|
9
|
+
declare const truncatePiJqOutput: (output: string, sessionId: string, config: OvermuxPiConfig) => string;
|
|
10
|
+
declare const inspectDelegate: (pi: ExtensionAPI, envelope: DelegateSettledEnvelope, signal: AbortSignal, config: OvermuxPiConfig) => Promise<DelegateNotificationDetails>;
|
|
11
|
+
declare const notificationMessage: (envelope: DelegateSettledEnvelope, details: DelegateNotificationDetails, config: OvermuxPiConfig) => {
|
|
12
|
+
customType: string;
|
|
13
|
+
content: string;
|
|
14
|
+
display: boolean;
|
|
15
|
+
details: DelegateNotificationDetails;
|
|
16
|
+
};
|
|
17
|
+
declare const notificationRenderer: MessageRenderer<DelegateNotificationDetails>;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { notificationRenderer as a, notificationMessage as i, OVERMUX_PI_DELEGATE_SETTLED_MESSAGE_TYPE as n, truncatePiJqOutput as o, inspectDelegate as r, DelegateNotificationDetails as t };
|
|
20
|
+
//# sourceMappingURL=notification-DzOd9cRc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-DzOd9cRc.d.ts","names":[],"sources":["../src/notification.ts"],"mappings":";;;;cAWa;KAGR,8BAA8B;EACjC;;cAmBW,qBACX,gBACA,mBACA,QAAQ;cAWG,kBACX,IAAI,cACJ,UAAU,yBACV,QAAQ,aACR,QAAQ,oBACP,QAAQ;cAkCE,sBACX,UAAU,yBACV,SAAS,6BACT,QAAQ;;;;;;cAUG,sBAAsB,gBACjC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as notificationRenderer, i as notificationMessage, n as OVERMUX_PI_DELEGATE_SETTLED_MESSAGE_TYPE, o as truncatePiJqOutput, r as inspectDelegate, t as DelegateNotificationDetails } from "./notification-DzOd9cRc.js";
|
|
2
|
+
export { type DelegateNotificationDetails, OVERMUX_PI_DELEGATE_SETTLED_MESSAGE_TYPE, inspectDelegate, notificationMessage, notificationRenderer, truncatePiJqOutput };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { formatSize, truncateTail } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { Text } from "@earendil-works/pi-tui";
|
|
3
|
+
//#region src/notification.ts
|
|
4
|
+
const OVERMUX_PI_DELEGATE_SETTLED_MESSAGE_TYPE = "overmux-pi.delegate-settled";
|
|
5
|
+
const inspectionCommand = (config, sessionId) => config.inspectionCommand.map((argument) => argument.replaceAll("{{childSessionId}}", sessionId));
|
|
6
|
+
const inspectionCommandLabel = (config, sessionId) => inspectionCommand(config, sessionId).map((argument) => JSON.stringify(argument)).join(" ");
|
|
7
|
+
const truncatePiJqOutput = (output, sessionId, config) => {
|
|
8
|
+
const truncation = truncateTail(output);
|
|
9
|
+
const content = truncation.content.trimEnd() || "(no output)";
|
|
10
|
+
if (!truncation.truncated) return content;
|
|
11
|
+
return `${content}\n\n[Output truncated: showing last ${truncation.outputLines} of ${truncation.totalLines} lines (${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)}). Full output: ${inspectionCommandLabel(config, sessionId)}]`;
|
|
12
|
+
};
|
|
13
|
+
const inspectDelegate = async (pi, envelope, signal, config) => {
|
|
14
|
+
try {
|
|
15
|
+
const [command, ...args] = inspectionCommand(config, envelope.childSessionId);
|
|
16
|
+
const result = await pi.exec(command, args, {
|
|
17
|
+
signal,
|
|
18
|
+
timeout: config.inspectionTimeoutMs
|
|
19
|
+
});
|
|
20
|
+
const output = [result.stdout, result.stderr].filter(Boolean).join("\n");
|
|
21
|
+
if (result.code === 0 && !result.killed) return {
|
|
22
|
+
...envelope,
|
|
23
|
+
output: truncatePiJqOutput(output, envelope.childSessionId, config)
|
|
24
|
+
};
|
|
25
|
+
const reason = result.killed ? "inspection command timed out" : `inspection command exited with code ${result.code}`;
|
|
26
|
+
const details = truncatePiJqOutput(output, envelope.childSessionId, config);
|
|
27
|
+
return {
|
|
28
|
+
...envelope,
|
|
29
|
+
output: `${reason}${output ? `:\n\n${details}` : "."}\n\nInspect manually: ${inspectionCommandLabel(config, envelope.childSessionId)}`
|
|
30
|
+
};
|
|
31
|
+
} catch (error) {
|
|
32
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
33
|
+
return {
|
|
34
|
+
...envelope,
|
|
35
|
+
output: `Could not run inspection command: ${reason}\n\nInspect manually: ${inspectionCommandLabel(config, envelope.childSessionId)}`
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const notificationMessage = (envelope, details, config) => {
|
|
40
|
+
return {
|
|
41
|
+
customType: OVERMUX_PI_DELEGATE_SETTLED_MESSAGE_TYPE,
|
|
42
|
+
content: `Delegate ${envelope.taskSlug} (${envelope.childSessionId}) finished.\n\n${details.output}\n\n${config.supervisionPrompt}`,
|
|
43
|
+
display: true,
|
|
44
|
+
details
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
const notificationRenderer = (message, { outputPad }, theme) => {
|
|
48
|
+
const details = message.details;
|
|
49
|
+
return new Text(`${`${theme.fg("muted", "[")}${theme.fg("accent", details.taskSlug)}${theme.fg("muted", " finished]")}`}\n\n${details.output}`, outputPad, 0);
|
|
50
|
+
};
|
|
51
|
+
//#endregion
|
|
52
|
+
export { OVERMUX_PI_DELEGATE_SETTLED_MESSAGE_TYPE, inspectDelegate, notificationMessage, notificationRenderer, truncatePiJqOutput };
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=notification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification.js","names":[],"sources":["../src/notification.ts"],"sourcesContent":["import {\n formatSize,\n truncateTail,\n type ExtensionAPI,\n type MessageRenderer,\n} from \"@earendil-works/pi-coding-agent\";\nimport { Text } from \"@earendil-works/pi-tui\";\n\nimport type { OvermuxPiConfig } from \"./config.js\";\nimport type { DelegateSettledEnvelope } from \"./protocol.js\";\n\nexport const OVERMUX_PI_DELEGATE_SETTLED_MESSAGE_TYPE =\n \"overmux-pi.delegate-settled\";\n\ntype DelegateNotificationDetails = DelegateSettledEnvelope & {\n output: string;\n};\n\nconst inspectionCommand = (\n config: OvermuxPiConfig,\n sessionId: string,\n): string[] =>\n config.inspectionCommand.map((argument) =>\n argument.replaceAll(\"{{childSessionId}}\", sessionId),\n );\n\nconst inspectionCommandLabel = (\n config: OvermuxPiConfig,\n sessionId: string,\n): string =>\n inspectionCommand(config, sessionId)\n .map((argument) => JSON.stringify(argument))\n .join(\" \");\n\nexport const truncatePiJqOutput = (\n output: string,\n sessionId: string,\n config: OvermuxPiConfig,\n): string => {\n const truncation = truncateTail(output);\n const content = truncation.content.trimEnd() || \"(no output)\";\n if (!truncation.truncated) {\n return content;\n }\n\n return `${content}\\n\\n[Output truncated: showing last ${truncation.outputLines} of ${truncation.totalLines} lines (${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)}). Full output: ${inspectionCommandLabel(config, sessionId)}]`;\n};\n\nexport const inspectDelegate = async (\n pi: ExtensionAPI,\n envelope: DelegateSettledEnvelope,\n signal: AbortSignal,\n config: OvermuxPiConfig,\n): Promise<DelegateNotificationDetails> => {\n try {\n const [command, ...args] = inspectionCommand(\n config,\n envelope.childSessionId,\n );\n const result = await pi.exec(command!, args, {\n signal,\n timeout: config.inspectionTimeoutMs,\n });\n const output = [result.stdout, result.stderr].filter(Boolean).join(\"\\n\");\n if (result.code === 0 && !result.killed) {\n return {\n ...envelope,\n output: truncatePiJqOutput(output, envelope.childSessionId, config),\n };\n }\n const reason = result.killed\n ? \"inspection command timed out\"\n : `inspection command exited with code ${result.code}`;\n const details = truncatePiJqOutput(output, envelope.childSessionId, config);\n return {\n ...envelope,\n output: `${reason}${output ? `:\\n\\n${details}` : \".\"}\\n\\nInspect manually: ${inspectionCommandLabel(config, envelope.childSessionId)}`,\n };\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n return {\n ...envelope,\n output: `Could not run inspection command: ${reason}\\n\\nInspect manually: ${inspectionCommandLabel(config, envelope.childSessionId)}`,\n };\n }\n};\n\nexport const notificationMessage = (\n envelope: DelegateSettledEnvelope,\n details: DelegateNotificationDetails,\n config: OvermuxPiConfig,\n) => {\n return {\n customType: OVERMUX_PI_DELEGATE_SETTLED_MESSAGE_TYPE,\n content: `Delegate ${envelope.taskSlug} (${envelope.childSessionId}) finished.\\n\\n${details.output}\\n\\n${config.supervisionPrompt}`,\n display: true,\n details,\n };\n};\n\nexport const notificationRenderer: MessageRenderer<\n DelegateNotificationDetails\n> = (message, { outputPad }, theme) => {\n const details = message.details!;\n const label = `${theme.fg(\"muted\", \"[\")}${theme.fg(\"accent\", details.taskSlug)}${theme.fg(\"muted\", \" finished]\")}`;\n return new Text(`${label}\\n\\n${details.output}`, outputPad, 0);\n};\n\nexport type { DelegateNotificationDetails };\n"],"mappings":";;;AAWA,MAAa,2CACX;AAMF,MAAM,qBACJ,QACA,cAEA,OAAO,kBAAkB,KAAK,aAC5B,SAAS,WAAW,sBAAsB,SAAS,CACrD;AAEF,MAAM,0BACJ,QACA,cAEA,kBAAkB,QAAQ,SAAS,CAAC,CACjC,KAAK,aAAa,KAAK,UAAU,QAAQ,CAAC,CAAC,CAC3C,KAAK,GAAG;AAEb,MAAa,sBACX,QACA,WACA,WACW;CACX,MAAM,aAAa,aAAa,MAAM;CACtC,MAAM,UAAU,WAAW,QAAQ,QAAQ,KAAK;CAChD,IAAI,CAAC,WAAW,WACd,OAAO;CAGT,OAAO,GAAG,QAAQ,sCAAsC,WAAW,YAAY,MAAM,WAAW,WAAW,UAAU,WAAW,WAAW,WAAW,EAAE,MAAM,WAAW,WAAW,UAAU,EAAE,kBAAkB,uBAAuB,QAAQ,SAAS,EAAE;AAC9P;AAEA,MAAa,kBAAkB,OAC7B,IACA,UACA,QACA,WACyC;CACzC,IAAI;EACF,MAAM,CAAC,SAAS,GAAG,QAAQ,kBACzB,QACA,SAAS,cACX;EACA,MAAM,SAAS,MAAM,GAAG,KAAK,SAAU,MAAM;GAC3C;GACA,SAAS,OAAO;EAClB,CAAC;EACD,MAAM,SAAS,CAAC,OAAO,QAAQ,OAAO,MAAM,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,IAAI;EACvE,IAAI,OAAO,SAAS,KAAK,CAAC,OAAO,QAC/B,OAAO;GACL,GAAG;GACH,QAAQ,mBAAmB,QAAQ,SAAS,gBAAgB,MAAM;EACpE;EAEF,MAAM,SAAS,OAAO,SAClB,iCACA,uCAAuC,OAAO;EAClD,MAAM,UAAU,mBAAmB,QAAQ,SAAS,gBAAgB,MAAM;EAC1E,OAAO;GACL,GAAG;GACH,QAAQ,GAAG,SAAS,SAAS,QAAQ,YAAY,IAAI,wBAAwB,uBAAuB,QAAQ,SAAS,cAAc;EACrI;CACF,SAAS,OAAO;EACd,MAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACpE,OAAO;GACL,GAAG;GACH,QAAQ,qCAAqC,OAAO,wBAAwB,uBAAuB,QAAQ,SAAS,cAAc;EACpI;CACF;AACF;AAEA,MAAa,uBACX,UACA,SACA,WACG;CACH,OAAO;EACL,YAAY;EACZ,SAAS,YAAY,SAAS,SAAS,IAAI,SAAS,eAAe,iBAAiB,QAAQ,OAAO,MAAM,OAAO;EAChH,SAAS;EACT;CACF;AACF;AAEA,MAAa,wBAER,SAAS,EAAE,aAAa,UAAU;CACrC,MAAM,UAAU,QAAQ;CAExB,OAAO,IAAI,KAAK,GAAG,GADF,MAAM,GAAG,SAAS,GAAG,IAAI,MAAM,GAAG,UAAU,QAAQ,QAAQ,IAAI,MAAM,GAAG,SAAS,YAAY,IACtF,MAAM,QAAQ,UAAU,WAAW,CAAC;AAC/D"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { S as UserMessageResponse, r as AbortResponse } from "./protocol-CsrnSPOv.js";
|
|
2
|
+
import { PiAgentSession, PiConversationSnapshot } from "./projection.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { HandlerContext, StreamHandlerDefinition } from "overmux";
|
|
5
|
+
//#region src/plugin.d.ts
|
|
6
|
+
type Awaitable<T> = T | Promise<T>;
|
|
7
|
+
type Dispose = () => void;
|
|
8
|
+
type PiSessionSource = {
|
|
9
|
+
list: () => Awaitable<readonly PiAgentSession[]>;
|
|
10
|
+
subscribe: (invalidate: () => void, options: {
|
|
11
|
+
signal: AbortSignal;
|
|
12
|
+
}) => Dispose | void;
|
|
13
|
+
};
|
|
14
|
+
type PiAgentListener = () => void;
|
|
15
|
+
type PiAgents = {
|
|
16
|
+
get: (agentId: string) => Promise<PiAgentSession | undefined>;
|
|
17
|
+
list: () => Promise<readonly PiAgentSession[]>;
|
|
18
|
+
subscribe: (listener: PiAgentListener) => Dispose;
|
|
19
|
+
};
|
|
20
|
+
declare const definePiAgents: ({ liveEventsDir, sessions }: {
|
|
21
|
+
liveEventsDir: string;
|
|
22
|
+
sessions: PiSessionSource;
|
|
23
|
+
}) => PiAgents;
|
|
24
|
+
declare const piSessionsResource: ({ agents }: {
|
|
25
|
+
agents: PiAgents;
|
|
26
|
+
}) => {
|
|
27
|
+
contract: import("overmux").ResourceContract<z.ZodVoid, z.ZodArray<z.ZodObject<{
|
|
28
|
+
agentId: z.ZodString;
|
|
29
|
+
}, z.core.$strict>>>;
|
|
30
|
+
kind: "subscription";
|
|
31
|
+
read: (_input: void, _context: HandlerContext) => Promise<{
|
|
32
|
+
agentId: string;
|
|
33
|
+
}[]>;
|
|
34
|
+
subscribe: (_input: void, invalidate: () => void, context: HandlerContext) => Dispose;
|
|
35
|
+
};
|
|
36
|
+
declare const piConversationContract: import("overmux").StreamContract<z.ZodObject<{
|
|
37
|
+
agentId: z.ZodString;
|
|
38
|
+
}, z.core.$strict>, z.ZodNever, z.ZodType<PiConversationSnapshot, unknown, z.core.$ZodTypeInternals<PiConversationSnapshot, unknown>>>;
|
|
39
|
+
declare const piConversationStream: ({ agents, maxEntries }: {
|
|
40
|
+
agents: PiAgents;
|
|
41
|
+
maxEntries?: number;
|
|
42
|
+
}) => StreamHandlerDefinition<typeof piConversationContract.input, typeof piConversationContract.clientMessage, typeof piConversationContract.serverMessage>;
|
|
43
|
+
declare const piOperationHandlers: ({ agents }: {
|
|
44
|
+
agents: PiAgents;
|
|
45
|
+
}) => {
|
|
46
|
+
sendPiMessage: import("overmux").OperationDefinition<z.ZodObject<{
|
|
47
|
+
agentId: z.ZodString;
|
|
48
|
+
deliverAs: z.ZodEnum<{
|
|
49
|
+
steer: "steer";
|
|
50
|
+
followUp: "followUp";
|
|
51
|
+
}>;
|
|
52
|
+
message: z.ZodString;
|
|
53
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
54
|
+
delivery: z.ZodEnum<{
|
|
55
|
+
steer: "steer";
|
|
56
|
+
followUp: "followUp";
|
|
57
|
+
immediate: "immediate";
|
|
58
|
+
}>;
|
|
59
|
+
requestId: z.ZodString;
|
|
60
|
+
}, z.core.$strip>>;
|
|
61
|
+
stopPiAgent: import("overmux").OperationDefinition<z.ZodObject<{
|
|
62
|
+
agentId: z.ZodString;
|
|
63
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
64
|
+
requestId: z.ZodString;
|
|
65
|
+
}, z.core.$strip>>;
|
|
66
|
+
setPiModel: import("overmux").OperationDefinition<z.ZodObject<{
|
|
67
|
+
agentId: z.ZodString;
|
|
68
|
+
provider: z.ZodString;
|
|
69
|
+
id: z.ZodString;
|
|
70
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
71
|
+
requestId: z.ZodString;
|
|
72
|
+
}, z.core.$strip>>;
|
|
73
|
+
setPiThinkingLevel: import("overmux").OperationDefinition<z.ZodObject<{
|
|
74
|
+
agentId: z.ZodString;
|
|
75
|
+
level: z.ZodEnum<{
|
|
76
|
+
off: "off";
|
|
77
|
+
minimal: "minimal";
|
|
78
|
+
low: "low";
|
|
79
|
+
medium: "medium";
|
|
80
|
+
high: "high";
|
|
81
|
+
xhigh: "xhigh";
|
|
82
|
+
max: "max";
|
|
83
|
+
}>;
|
|
84
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
85
|
+
requestId: z.ZodString;
|
|
86
|
+
}, z.core.$strip>>;
|
|
87
|
+
};
|
|
88
|
+
//#endregion
|
|
89
|
+
export { type AbortResponse, PiAgents, PiSessionSource, type UserMessageResponse, definePiAgents, piConversationStream, piOperationHandlers, piSessionsResource };
|
|
90
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","names":[],"sources":["../src/plugin.ts"],"mappings":";;;;;KA8BK,UAAU,KAAK,IAAI,QAAQ;KAC3B;KACO;EACV,YAAY,mBAAmB;EAC/B,YACE,wBACA;IAAW,QAAQ;QAChB;;KAEF;KAEO;EACV,MAAM,oBAAoB,QAAQ;EAClC,YAAY,iBAAiB;EAC7B,YAAY,UAAU,oBAAoB;;cAkE/B,mBAAkB,eAAA;EAI7B;EACA,UAAU;MACR;cAmES,uBAAsB;EAAc,QAAQ;;;;;;EAGlC,OAAA,cAAI,UAAY,mBAAc;;;EAGzC,YAAA,cAAI,wBACU,SACb,mBAAc;;cAWrB,0CAAsB,eAAA,EAAA;;GAI1B,EAAA,KAAA,UAAA,EAAA,UAAA,EAAA,QAAA,iCAAA,EAAA,KAAA,kBAAA;cAUW,yBAAwB,QAAA;EAInC,QAAQ;EACR;MACE,+BACK,uBAAuB,cACvB,uBAAuB,sBACvB,uBAAuB;cAsGnB,wBAAuB;EAAc,QAAQ"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { sendAbort, sendSetModel, sendSetThinkingLevel, sendUserMessage } from "./protocol.js";
|
|
2
|
+
import { createPiAgentConversationService, piConversationSnapshotSchema, piSessionMetadataSchema } from "./projection.js";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { defineOperation, defineResourceContract, defineStreamContract, noInputSchema } from "overmux";
|
|
6
|
+
//#region src/plugin.ts
|
|
7
|
+
const piAgentSessionSchema = z.object({
|
|
8
|
+
id: z.string().min(1),
|
|
9
|
+
liveEventsDir: z.string().min(1).optional(),
|
|
10
|
+
sessionFile: z.string().min(1),
|
|
11
|
+
sessionMetadata: piSessionMetadataSchema.optional()
|
|
12
|
+
}).strict();
|
|
13
|
+
const piSessionSchema = z.object({ agentId: z.string().min(1) }).strict();
|
|
14
|
+
const piMessageInputSchema = z.object({
|
|
15
|
+
agentId: z.string().min(1),
|
|
16
|
+
deliverAs: z.enum(["steer", "followUp"]),
|
|
17
|
+
message: z.string().trim().min(1)
|
|
18
|
+
}).strict();
|
|
19
|
+
const piMessageResultSchema = z.object({
|
|
20
|
+
delivery: z.enum([
|
|
21
|
+
"immediate",
|
|
22
|
+
"steer",
|
|
23
|
+
"followUp"
|
|
24
|
+
]),
|
|
25
|
+
requestId: z.string().min(1)
|
|
26
|
+
});
|
|
27
|
+
const piStopInputSchema = z.object({ agentId: z.string().min(1) }).strict();
|
|
28
|
+
const piStopResultSchema = z.object({ requestId: z.string().min(1) });
|
|
29
|
+
const piModelInputSchema = z.object({
|
|
30
|
+
agentId: z.string().min(1),
|
|
31
|
+
provider: z.string().min(1),
|
|
32
|
+
id: z.string().min(1)
|
|
33
|
+
}).strict();
|
|
34
|
+
const piThinkingInputSchema = z.object({
|
|
35
|
+
agentId: z.string().min(1),
|
|
36
|
+
level: z.enum([
|
|
37
|
+
"off",
|
|
38
|
+
"minimal",
|
|
39
|
+
"low",
|
|
40
|
+
"medium",
|
|
41
|
+
"high",
|
|
42
|
+
"xhigh",
|
|
43
|
+
"max"
|
|
44
|
+
])
|
|
45
|
+
}).strict();
|
|
46
|
+
const piControlResultSchema = z.object({ requestId: z.string().min(1) });
|
|
47
|
+
const once = (dispose) => {
|
|
48
|
+
let disposed = false;
|
|
49
|
+
return () => {
|
|
50
|
+
if (disposed) return;
|
|
51
|
+
disposed = true;
|
|
52
|
+
dispose();
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
const sameSessions = (left, right) => left.length === right.length && left.every((session, index) => session.id === right[index]?.id && session.sessionFile === right[index]?.sessionFile && session.liveEventsDir === right[index]?.liveEventsDir && JSON.stringify(session.sessionMetadata) === JSON.stringify(right[index]?.sessionMetadata));
|
|
56
|
+
const definePiAgents = ({ liveEventsDir, sessions }) => {
|
|
57
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
58
|
+
let cached = [];
|
|
59
|
+
let sourceDispose;
|
|
60
|
+
let refreshQueue = Promise.resolve();
|
|
61
|
+
const refresh = async () => {
|
|
62
|
+
const result = refreshQueue.then(async () => {
|
|
63
|
+
const next = (await sessions.list()).map((session) => piAgentSessionSchema.parse({
|
|
64
|
+
...session,
|
|
65
|
+
liveEventsDir
|
|
66
|
+
})).sort((left, right) => left.id.localeCompare(right.id));
|
|
67
|
+
if (new Set(next.map(({ id }) => id)).size !== next.length) throw new Error("Pi agent discovery returned duplicate IDs");
|
|
68
|
+
if (!sameSessions(cached, next)) {
|
|
69
|
+
cached = next;
|
|
70
|
+
listeners.forEach((listener) => listener());
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
refreshQueue = result.catch(() => void 0);
|
|
74
|
+
await result;
|
|
75
|
+
return cached;
|
|
76
|
+
};
|
|
77
|
+
const stopSource = () => {
|
|
78
|
+
sourceDispose?.();
|
|
79
|
+
sourceDispose = void 0;
|
|
80
|
+
};
|
|
81
|
+
const startSource = () => {
|
|
82
|
+
if (sourceDispose) return;
|
|
83
|
+
const controller = new AbortController();
|
|
84
|
+
const dispose = sessions.subscribe(() => void refresh().catch(() => void 0), { signal: controller.signal });
|
|
85
|
+
sourceDispose = once(() => {
|
|
86
|
+
controller.abort();
|
|
87
|
+
dispose?.();
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
return {
|
|
91
|
+
get: async (agentId) => (await refresh()).find(({ id }) => id === agentId),
|
|
92
|
+
list: refresh,
|
|
93
|
+
subscribe: (listener) => {
|
|
94
|
+
listeners.add(listener);
|
|
95
|
+
startSource();
|
|
96
|
+
return () => {
|
|
97
|
+
listeners.delete(listener);
|
|
98
|
+
if (!listeners.size) stopSource();
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
const piSessionsContract = defineResourceContract({
|
|
104
|
+
input: noInputSchema,
|
|
105
|
+
output: z.array(piSessionSchema)
|
|
106
|
+
});
|
|
107
|
+
const piSessionsResource = ({ agents }) => ({
|
|
108
|
+
contract: piSessionsContract,
|
|
109
|
+
kind: "subscription",
|
|
110
|
+
read: async (_input, _context) => (await agents.list()).map(({ id }) => ({ agentId: id })),
|
|
111
|
+
subscribe: (_input, invalidate, context) => {
|
|
112
|
+
const dispose = once(agents.subscribe(invalidate));
|
|
113
|
+
context.signal.addEventListener("abort", dispose, { once: true });
|
|
114
|
+
return once(() => {
|
|
115
|
+
context.signal.removeEventListener("abort", dispose);
|
|
116
|
+
dispose();
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
const piConversationContract = defineStreamContract({
|
|
121
|
+
clientMessage: z.never(),
|
|
122
|
+
input: z.object({ agentId: z.string().min(1) }).strict(),
|
|
123
|
+
serverMessage: piConversationSnapshotSchema
|
|
124
|
+
});
|
|
125
|
+
const limitConversationEntries = (snapshot, maxEntries) => maxEntries === void 0 ? snapshot : {
|
|
126
|
+
...snapshot,
|
|
127
|
+
entries: snapshot.entries.slice(-maxEntries)
|
|
128
|
+
};
|
|
129
|
+
const piConversationStream = ({ agents, maxEntries }) => {
|
|
130
|
+
if (maxEntries !== void 0 && (!Number.isSafeInteger(maxEntries) || maxEntries < 1)) throw new Error("Pi conversation maxEntries must be a positive integer");
|
|
131
|
+
return {
|
|
132
|
+
contract: piConversationContract,
|
|
133
|
+
open: async ({ agentId }, context) => {
|
|
134
|
+
const service = createPiAgentConversationService({ resolveAgent: async (id) => {
|
|
135
|
+
const agent = await agents.get(id);
|
|
136
|
+
if (!agent) throw new Error(`Pi agent not found: ${id}`);
|
|
137
|
+
return {
|
|
138
|
+
...agent,
|
|
139
|
+
sessionId: agent.id
|
|
140
|
+
};
|
|
141
|
+
} });
|
|
142
|
+
try {
|
|
143
|
+
context.emit(limitConversationEntries(await service.getSnapshot(agentId), maxEntries));
|
|
144
|
+
const unsubscribe = service.subscribe(agentId, (snapshot) => context.emit(limitConversationEntries(snapshot, maxEntries)));
|
|
145
|
+
return { dispose: once(() => {
|
|
146
|
+
unsubscribe();
|
|
147
|
+
service.dispose();
|
|
148
|
+
}) };
|
|
149
|
+
} catch (error) {
|
|
150
|
+
service.dispose();
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
const piMessageResult = async (agent, input) => {
|
|
157
|
+
if (!agent) throw new Error(`Pi agent not found: ${input.agentId}`);
|
|
158
|
+
const response = await sendUserMessage(agent.id, {
|
|
159
|
+
deliverAs: input.deliverAs,
|
|
160
|
+
message: input.message,
|
|
161
|
+
requestId: randomUUID()
|
|
162
|
+
});
|
|
163
|
+
if (!response?.ok) throw new Error("Pi agent is unavailable");
|
|
164
|
+
return response;
|
|
165
|
+
};
|
|
166
|
+
const piStopResult = async (agent, input) => {
|
|
167
|
+
if (!agent) throw new Error(`Pi agent not found: ${input.agentId}`);
|
|
168
|
+
const requestId = randomUUID();
|
|
169
|
+
if (!(await sendAbort(agent.id, { requestId }))?.ok) throw new Error("Pi agent is unavailable");
|
|
170
|
+
return { requestId };
|
|
171
|
+
};
|
|
172
|
+
const piControlResult = async (agent, input, send) => {
|
|
173
|
+
if (!agent) throw new Error(`Pi agent not found: ${input.agentId}`);
|
|
174
|
+
const requestId = randomUUID();
|
|
175
|
+
const response = await send(agent.id, requestId);
|
|
176
|
+
if (response?.ok) return { requestId };
|
|
177
|
+
if (response?.error === "not_found") throw new Error("Pi model was not found");
|
|
178
|
+
if (response?.error === "no_key") throw new Error("No API key is available for this Pi model");
|
|
179
|
+
throw new Error("Pi agent is unavailable");
|
|
180
|
+
};
|
|
181
|
+
const piOperationHandlers = ({ agents }) => ({
|
|
182
|
+
sendPiMessage: defineOperation({
|
|
183
|
+
handle: async (input) => piMessageResult(await agents.get(input.agentId), input),
|
|
184
|
+
input: piMessageInputSchema,
|
|
185
|
+
output: piMessageResultSchema
|
|
186
|
+
}),
|
|
187
|
+
stopPiAgent: defineOperation({
|
|
188
|
+
handle: async (input) => piStopResult(await agents.get(input.agentId), input),
|
|
189
|
+
input: piStopInputSchema,
|
|
190
|
+
output: piStopResultSchema
|
|
191
|
+
}),
|
|
192
|
+
setPiModel: defineOperation({
|
|
193
|
+
handle: async (input) => piControlResult(await agents.get(input.agentId), input, (agentId, requestId) => sendSetModel(agentId, {
|
|
194
|
+
id: input.id,
|
|
195
|
+
provider: input.provider,
|
|
196
|
+
requestId
|
|
197
|
+
})),
|
|
198
|
+
input: piModelInputSchema,
|
|
199
|
+
output: piControlResultSchema
|
|
200
|
+
}),
|
|
201
|
+
setPiThinkingLevel: defineOperation({
|
|
202
|
+
handle: async (input) => piControlResult(await agents.get(input.agentId), input, (agentId, requestId) => sendSetThinkingLevel(agentId, {
|
|
203
|
+
level: input.level,
|
|
204
|
+
requestId
|
|
205
|
+
})),
|
|
206
|
+
input: piThinkingInputSchema,
|
|
207
|
+
output: piControlResultSchema
|
|
208
|
+
})
|
|
209
|
+
});
|
|
210
|
+
//#endregion
|
|
211
|
+
export { definePiAgents, piConversationStream, piOperationHandlers, piSessionsResource };
|
|
212
|
+
|
|
213
|
+
//# sourceMappingURL=plugin.js.map
|