@ai-ecoverse/slicc-agent 7.3.1 → 7.4.0

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 CHANGED
@@ -426,7 +426,7 @@ The `memory` section, read before every request, holds the first 200 lines (at m
426
426
 
427
427
  **`memory_write`** saves, replaces (same section and title) or removes one entry in the caller's own file, or in `global` for cones. Writes to a file are serialized and re-read the file, so edits by hand survive. A file holds 16 KB; a write over that must make it smaller. Anything that looks like a secret (API keys, tokens, `Authorization` values, private keys, `password=`, launch URLs with a `#key`) is redacted before it's written. A role with `memory` and write tools gets `memory_write` in its tool list.
428
428
 
429
- **Extraction.** Durable compacts a long conversation into a summary; before it does, a `beforeCompact` hook (which never declines or replaces the summary) schedules a `slicc.memory-extract` task for the cone. A cone that has been idle for `memory.idleMinutes` (30 by default, `0` turns the idle trigger off) gets the same task. The task runs only when there is something new since the last extraction (a cursor per conversation in the session document `slicc.memory-extract`), makes one model call, with the cone's model unless `memory.extractModel` names a cheaper one (`provider/model`), and writes the proposed entries through `memory_write`'s writer into the cone's memory file, within its 16 KB. The transcript it sends is redacted first, its prompt forbids secrets, and the writer redacts again. `"memory": { "extract": false }` in `~/.pi/agent/settings.json` turns extraction off. v6's curator scoop, three-way merge, curation ledger and dreamer aren't ported.
429
+ **Extraction.** Durable compacts a long conversation into a summary; before it does, a `beforeCompact` hook (which never declines or replaces the summary) schedules a `slicc.memory-extract` task for the cone. A cone that has been idle for `memory.idleMinutes` (30 by default, `0` turns the idle trigger off) gets the same task. Each cone's conversation has one background `slicc.memory-idle` task (listed in the session document `slicc.memory-idle`), which pi durable keeps asleep between checks: it wakes `idleMinutes` after the conversation last changed (the newest entry's message time, or when it noticed the change), shows in the monitor as `memory idle watch`, schedules the extraction if it hasn't changed since, and sleeps again. The sleep is stored, so the idle time counts across reloads and while no worker runs, and settings are read at each wake. A cone that goes away (frozen, or its conversation replaced by New conversation) ends its task; a new cone gets one. The task runs only when there is something new since the last extraction (a cursor per conversation in the session document `slicc.memory-extract`), makes one model call, with the cone's model unless `memory.extractModel` names a cheaper one (`provider/model`), and writes the proposed entries through `memory_write`'s writer into the cone's memory file, within its 16 KB. The transcript it sends is redacted first, its prompt forbids secrets, and the writer redacts again. `"memory": { "extract": false }` in `~/.pi/agent/settings.json` turns extraction off. v6's curator scoop, three-way merge, curation ledger and dreamer aren't ported.
430
430
 
431
431
  **The gelatiere.** SLICC's resident advisor, as in v6, is a scoop with the built-in `gelatiere` role. That role has its own memory (`memory: { scope: user, path: gelatiere }`), so it keeps its notes there.
432
432
  - `gelatiere init` starts the scoop in the first cone, writes `~/.pi/agent/GELATIERE.md` (its procedure, which the user can edit) unless it exists, and installs one job `# name: gelatiere` / `0 3 * * * agent send scoop:<handle> --lick=cron 'Nightly pass: …'` in the scoop's own crontab (root's without kernel users), replacing an older one. At start, a gelatiere job an earlier version installed without `--lick=cron` gets it, as migrated jobs do. `gelatiere status` shows its schedule from there.
@@ -208,46 +208,103 @@ function settingsReader(ready) {
208
208
  return extractSettings(read.ok ? read.value : void 0);
209
209
  };
210
210
  }
211
- function idleWatch(host, schedule, settings, everyMs, context, now = Date.now) {
212
- const seen = /* @__PURE__ */ new Map();
213
- const check = async () => {
214
- const { idleMinutes, extract } = await settings(context);
215
- if (!extract || idleMinutes === 0) return;
216
- for (const cone of Object.values(host.agents.state().cones)) {
217
- const conversation = await host.harness.conversation(
218
- cone.conversation,
219
- context
220
- );
221
- const view = await conversation?.context(context);
222
- const tail = view?.entries.at(-1)?.id ?? 0;
223
- const last = seen.get(cone.conversation);
224
- if (!last || last.tail !== tail) {
225
- seen.set(cone.conversation, { tail, since: now() });
226
- continue;
211
+ const IDLE_TASK = "slicc.memory-idle";
212
+ const IdleDoc = defineDoc({
213
+ kind: "slicc.memory-idle",
214
+ checkpointWhen: deltasOnly,
215
+ version: 1,
216
+ scope: "session",
217
+ initial: () => ({ tasks: {} })
218
+ });
219
+ function idleTask(ready, schedule, settings) {
220
+ return defineTask({
221
+ name: IDLE_TASK,
222
+ version: 1,
223
+ initial: () => ({ phase: "watch", tail: -1, since: 0 }),
224
+ phases: {
225
+ async watch(task, runtime, context) {
226
+ const host = await ready;
227
+ const conversation = runtime.conversationId;
228
+ const key = String(conversation);
229
+ const who = whoIs(host.agents.state(), conversation);
230
+ if (who.kind !== "cone")
231
+ return runtime.commit(async (tx) => {
232
+ const doc = await tx.doc(IdleDoc);
233
+ if (doc.tasks[key] === Number(task.id)) delete doc.tasks[key];
234
+ return { status: "terminal", outcome: { status: "completed", result: null } };
235
+ }, context);
236
+ const { extract, idleMinutes } = await settings(context);
237
+ const on = extract && idleMinutes > 0;
238
+ const idleMs = (on ? idleMinutes : DEFAULT_IDLE_MINUTES) * 6e4;
239
+ const now = runtime.now();
240
+ const view = await runtime.context(conversation, context);
241
+ const last = view.entries.at(-1);
242
+ const tail = last?.id ?? 0;
243
+ const seen = task.state.checkpoint;
244
+ if (tail !== seen.tail) {
245
+ const stamp = last?.model?.at(-1)?.timestamp;
246
+ const since = typeof stamp === "number" && stamp <= now ? stamp : now;
247
+ return runtime.sleepUntil(since + idleMs, { phase: "watch", tail, since }, context);
248
+ }
249
+ const due = seen.since + idleMs;
250
+ if (now < due) return runtime.sleepUntil(due, seen, context);
251
+ if (on) await schedule(conversation, tail, context, who.id);
252
+ return runtime.sleepUntil(now + idleMs, seen, context);
227
253
  }
228
- if (now() - last.since >= idleMinutes * 6e4)
229
- await schedule(cone.conversation, tail, context);
230
- }
254
+ },
255
+ abort: (task, runtime, context) => runtime.commit(async (tx) => {
256
+ const doc = await tx.doc(IdleDoc);
257
+ const key = String(runtime.conversationId);
258
+ if (doc.tasks[key] === Number(task.id)) delete doc.tasks[key];
259
+ return { status: "terminal", outcome: { status: "aborted" } };
260
+ }, context)
261
+ });
262
+ }
263
+ function idleWatch(host, task, context) {
264
+ let stopped = false;
265
+ let line = Promise.resolve();
266
+ const ensure = () => {
267
+ line = line.then(async () => {
268
+ if (stopped) return;
269
+ await host.harness.commit(async (tx) => {
270
+ const doc = await tx.doc(IdleDoc);
271
+ for (const [id, cone] of Object.entries(host.agents.state().cones)) {
272
+ const key = String(cone.conversation);
273
+ const known = doc.tasks[key];
274
+ const record = known === void 0 ? void 0 : await tx.task(known);
275
+ if (record && record.state.status !== "terminal") continue;
276
+ doc.tasks[key] = await tx.createTask(
277
+ task,
278
+ { cone: id },
279
+ {
280
+ ownership: { kind: "conversation" },
281
+ conversationId: cone.conversation,
282
+ background: true
283
+ }
284
+ );
285
+ }
286
+ }, context);
287
+ }).catch(() => void 0);
288
+ };
289
+ const off = host.agents.onChange(ensure);
290
+ ensure();
291
+ return () => {
292
+ stopped = true;
293
+ off();
231
294
  };
232
- let running = false;
233
- const timer = setInterval(() => {
234
- if (running) return;
235
- running = true;
236
- void check().catch(() => void 0).finally(() => {
237
- running = false;
238
- });
239
- }, everyMs);
240
- return () => clearInterval(timer);
241
295
  }
242
296
  export {
243
297
  DEFAULT_IDLE_MINUTES,
244
298
  EXTRACT_PROMPT,
245
299
  EXTRACT_TASK,
246
300
  ExtractDoc,
301
+ IDLE_TASK,
302
+ IdleDoc,
247
303
  TRANSCRIPT_CHARS,
248
304
  compactionHook,
249
305
  extractSettings,
250
306
  extractTask,
307
+ idleTask,
251
308
  idleWatch,
252
309
  proposals,
253
310
  scheduler,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/memory/extract.ts"],
4
- "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { Message } from '@earendil-works/pi-ai';\nimport {\n CompactionTask,\n type ConversationId,\n defineDoc,\n defineTask,\n type EntryId,\n hook,\n type ModelRef,\n} from '@earendil-works/pi-durable';\nimport { deltasOnly } from '../checkpoints.ts';\nimport type { MemoryTag } from './format.ts';\nimport { MAX_BYTES, parseMemory, redactSecrets, serializeMemory } from './format.ts';\nimport { type Host, whoIs } from './prompt.ts';\nimport { type Place, placeOf } from './store.ts';\n\nexport const EXTRACT_TASK = 'slicc.memory-extract';\nexport const TRANSCRIPT_CHARS = 60_000;\nexport const DEFAULT_IDLE_MINUTES = 30;\n\nexport type ExtractState = {\n cursors: Record<string, number>;\n pending: Record<string, number>;\n};\n\nexport const ExtractDoc = defineDoc<ExtractState>({\n kind: 'slicc.memory-extract',\n checkpointWhen: deltasOnly,\n version: 1,\n scope: 'session',\n initial: () => ({ cursors: {}, pending: {} }),\n});\n\nexport type ExtractSettings = { extract: boolean; model: ModelRef | null; idleMinutes: number };\n\nexport function extractSettings(text: string | undefined): ExtractSettings {\n let memory: { extract?: unknown; extractModel?: unknown; idleMinutes?: unknown } = {};\n try {\n const parsed = JSON.parse(text ?? '{}') as { memory?: typeof memory };\n memory = parsed.memory && typeof parsed.memory === 'object' ? parsed.memory : {};\n } catch {\n memory = {};\n }\n const named = typeof memory.extractModel === 'string' ? memory.extractModel.split('/') : [];\n const model =\n named.length >= 2 && named[0] && named.slice(1).join('/')\n ? { provider: named[0], modelId: named.slice(1).join('/') }\n : null;\n const idle =\n typeof memory.idleMinutes === 'number' && memory.idleMinutes >= 0\n ? memory.idleMinutes\n : DEFAULT_IDLE_MINUTES;\n return { extract: memory.extract !== false, model, idleMinutes: idle };\n}\n\nfunction textOf(message: Message): string {\n const content = (message as { content?: unknown }).content;\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return '';\n return content\n .map((part: { type?: string; text?: string; name?: string }) =>\n part.type === 'text'\n ? (part.text ?? '')\n : part.type === 'toolCall'\n ? `[tool ${part.name}]`\n : ''\n )\n .filter(Boolean)\n .join('\\n');\n}\n\nexport function transcriptOf(messages: readonly Message[]): string {\n const lines: string[] = [];\n for (const message of messages) {\n if (message.role !== 'user' && message.role !== 'assistant') continue;\n const text = textOf(message).trim();\n if (text) lines.push(`${message.role === 'user' ? 'User' : 'Agent'}: ${text}`);\n }\n const joined = redactSecrets(lines.join('\\n\\n')).text;\n return joined.length > TRANSCRIPT_CHARS ? joined.slice(-TRANSCRIPT_CHARS) : joined;\n}\n\nexport const EXTRACT_PROMPT = [\n 'You keep the long-term memory of a personal agent. Read the conversation excerpt and the current memory file, and propose memory entries worth keeping across conversations:',\n '- who the user is (tag \"user\"), how they want the agent to work, including corrections (tag \"feedback\"), and durable facts about their projects (tag \"project\");',\n '- only facts that will still matter in a later conversation; nothing about this one task, no transcripts, no guesses;',\n '- never secrets: no keys, tokens, passwords, Authorization values or URLs that carry a key;',\n '- to change an entry that exists, repeat its section and title with the new body; leave entries alone that need no change.',\n 'Answer with a JSON array and nothing else: [{\"section\": \"...\", \"title\": \"...\", \"body\": \"...\", \"tag\": \"user\" | \"feedback\" | \"project\"}]. An empty array is a fine answer.',\n].join('\\n');\n\nexport type Proposal = { section: string; title: string; body: string; tag: MemoryTag | null };\n\nconst TAGS = new Set(['user', 'feedback', 'project']);\n\nexport function proposals(text: string): Proposal[] {\n const start = text.indexOf('[');\n const end = text.lastIndexOf(']');\n if (start < 0 || end < start) return [];\n let parsed: unknown;\n try {\n parsed = JSON.parse(text.slice(start, end + 1));\n } catch {\n return [];\n }\n if (!Array.isArray(parsed)) return [];\n const out: Proposal[] = [];\n for (const item of parsed as Record<string, unknown>[]) {\n if (!item || typeof item !== 'object') continue;\n const { section, title, body, tag } = item;\n if (typeof section !== 'string' || typeof title !== 'string' || typeof body !== 'string')\n continue;\n if (!section.trim() || !title.trim() || !body.trim()) continue;\n out.push({\n section,\n title,\n body,\n tag: typeof tag === 'string' && TAGS.has(tag) ? (tag as MemoryTag) : null,\n });\n }\n return out.slice(0, 20);\n}\n\ntype Input = { cone: string; after: number; tail: number; model: ModelRef | null };\ntype State = { phase: 'extract' };\nexport type ExtractResult = { saved: number; skipped: string | null };\n\nasync function save(host: Host, place: Place, found: Proposal[], context: Context) {\n let saved = 0;\n for (const proposal of found) {\n try {\n await host.files.change(place, { kind: 'save', ...proposal }, context);\n saved++;\n } catch {\n break;\n }\n }\n if (saved) await host.changed(context).catch(() => undefined);\n return saved;\n}\n\nexport function extractTask(\n ready: Promise<Host>,\n settings: (context: Context) => Promise<ExtractSettings>\n) {\n return defineTask<Input, State, ExtractResult>({\n name: EXTRACT_TASK,\n version: 1,\n initial: () => ({ phase: 'extract' }),\n phases: {\n async extract(task, runtime, context) {\n const { cone, after, tail } = task.input;\n const key = String(runtime.conversationId);\n const done = (result: ExtractResult) =>\n runtime.commit(async (tx) => {\n const doc = await tx.doc(ExtractDoc);\n doc.cursors[key] = Math.max(doc.cursors[key] ?? 0, tail);\n delete doc.pending[key];\n return { status: 'terminal', outcome: { status: 'completed', result } };\n }, context);\n if (!(await settings(context)).extract) return done({ saved: 0, skipped: 'turned off' });\n const host = await ready;\n const place = placeOf(host.home, cone);\n const view = await runtime.context(runtime.conversationId, context, {\n at: tail as EntryId,\n });\n const fresh = view.entries.flatMap((entry, index) =>\n entry.id > after ? (view.contributions[index] as readonly Message[]) : []\n );\n const transcript = transcriptOf(fresh);\n if (!place || !transcript) return done({ saved: 0, skipped: 'nothing new' });\n const ref = task.input.model ?? (await runtime.agent(context)).model;\n const model = ref ? runtime.models.getModel(ref.provider, ref.modelId) : undefined;\n if (!model) return done({ saved: 0, skipped: 'no model' });\n const current = await host.files.read(place.file, context);\n const memory = current ? serializeMemory(parseMemory(current.text)) : '';\n const now = Date.now();\n const message = await runtime.models.completeSimple(\n model,\n {\n messages: [\n { role: 'system', content: EXTRACT_PROMPT, timestamp: now } as unknown as Message,\n {\n role: 'user',\n content: [\n {\n type: 'text',\n text: `<memory_file bytes_left=\"${MAX_BYTES - new TextEncoder().encode(memory).length}\">\\n${memory}</memory_file>\\n\\n<conversation>\\n${transcript}\\n</conversation>`,\n },\n ],\n timestamp: now,\n },\n ],\n },\n { maxTokens: 2000, signal: runtime.signal, cacheRetention: 'none' }\n );\n runtime.signal.throwIfAborted();\n if (message.stopReason === 'error') return done({ saved: 0, skipped: 'model error' });\n const saved = await save(host, place, proposals(textOf(message as Message)), context);\n return done({ saved, skipped: null });\n },\n },\n abort: (_task, runtime, context) =>\n runtime.commit(async (tx) => {\n delete (await tx.doc(ExtractDoc)).pending[String(runtime.conversationId)];\n return { status: 'terminal', outcome: { status: 'aborted' } };\n }, context),\n });\n}\n\nexport type Schedule = (\n conversation: number,\n tail: number,\n context: Context,\n cone?: string\n) => Promise<boolean>;\n\nexport function compactionHook(schedule: Schedule) {\n return hook(CompactionTask, {\n beforeCompact(compaction, api) {\n const tail = compaction.entries.reduce((max, entry) => Math.max(max, entry.id), 0);\n void schedule(api.conversationId, tail, BACKGROUND_CONTEXT).catch(() => false);\n return undefined;\n },\n });\n}\n\nexport function scheduler(\n ready: Promise<Host>,\n task: ReturnType<typeof extractTask>,\n settings: (context: Context) => Promise<ExtractSettings>\n): Schedule {\n return async (conversation, tail, context, cone) => {\n const host = await ready;\n const chosen = await settings(context);\n const who = cone\n ? { kind: 'cone' as const, id: cone }\n : whoIs(host.agents.state(), conversation);\n if (who.kind !== 'cone') return false;\n return host.harness.commit(async (tx) => {\n const doc = await tx.doc(ExtractDoc);\n const key = String(conversation);\n const after = doc.cursors[key] ?? 0;\n if (doc.pending[key] !== undefined || tail <= after) return false;\n doc.pending[key] = (await tx.createTask(\n task,\n { cone: who.id, after, tail, model: chosen.model },\n {\n ownership: { kind: 'conversation' },\n conversationId: conversation as ConversationId,\n background: true,\n }\n )) as number;\n return true;\n }, context);\n };\n}\n\nexport function settingsReader(ready: Promise<Host>) {\n return async (context: Context): Promise<ExtractSettings> => {\n const host = await ready;\n const dir = host.agentDir ?? `${host.home}/.pi/agent`;\n const read = await host.env.readTextFile(`${dir}/settings.json`, context);\n return extractSettings(read.ok ? read.value : undefined);\n };\n}\n\nexport function idleWatch(\n host: Pick<Host, 'agents' | 'harness'>,\n schedule: Schedule,\n settings: (context: Context) => Promise<ExtractSettings>,\n everyMs: number,\n context: Context,\n now: () => number = Date.now\n): () => void {\n const seen = new Map<number, { tail: number; since: number }>();\n const check = async () => {\n const { idleMinutes, extract } = await settings(context);\n if (!extract || idleMinutes === 0) return;\n for (const cone of Object.values(host.agents.state().cones)) {\n const conversation = await host.harness.conversation(\n cone.conversation as ConversationId,\n context\n );\n const view = await conversation?.context(context);\n const tail = view?.entries.at(-1)?.id ?? 0;\n const last = seen.get(cone.conversation);\n if (!last || last.tail !== tail) {\n seen.set(cone.conversation, { tail, since: now() });\n continue;\n }\n if (now() - last.since >= idleMinutes * 60_000)\n await schedule(cone.conversation, tail, context);\n }\n };\n let running = false;\n const timer = setInterval(() => {\n if (running) return;\n running = true;\n void check()\n .catch(() => undefined)\n .finally(() => {\n running = false;\n });\n }, everyMs);\n return () => clearInterval(timer);\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { Message } from '@earendil-works/pi-ai';\nimport {\n CompactionTask,\n type ConversationId,\n defineDoc,\n defineTask,\n type EntryId,\n hook,\n type ModelRef,\n type TaskId,\n} from '@earendil-works/pi-durable';\nimport { deltasOnly } from '../checkpoints.ts';\nimport type { MemoryTag } from './format.ts';\nimport { MAX_BYTES, parseMemory, redactSecrets, serializeMemory } from './format.ts';\nimport { type Host, whoIs } from './prompt.ts';\nimport { type Place, placeOf } from './store.ts';\n\nexport const EXTRACT_TASK = 'slicc.memory-extract';\nexport const TRANSCRIPT_CHARS = 60_000;\nexport const DEFAULT_IDLE_MINUTES = 30;\n\nexport type ExtractState = {\n cursors: Record<string, number>;\n pending: Record<string, number>;\n};\n\nexport const ExtractDoc = defineDoc<ExtractState>({\n kind: 'slicc.memory-extract',\n checkpointWhen: deltasOnly,\n version: 1,\n scope: 'session',\n initial: () => ({ cursors: {}, pending: {} }),\n});\n\nexport type ExtractSettings = { extract: boolean; model: ModelRef | null; idleMinutes: number };\n\nexport function extractSettings(text: string | undefined): ExtractSettings {\n let memory: { extract?: unknown; extractModel?: unknown; idleMinutes?: unknown } = {};\n try {\n const parsed = JSON.parse(text ?? '{}') as { memory?: typeof memory };\n memory = parsed.memory && typeof parsed.memory === 'object' ? parsed.memory : {};\n } catch {\n memory = {};\n }\n const named = typeof memory.extractModel === 'string' ? memory.extractModel.split('/') : [];\n const model =\n named.length >= 2 && named[0] && named.slice(1).join('/')\n ? { provider: named[0], modelId: named.slice(1).join('/') }\n : null;\n const idle =\n typeof memory.idleMinutes === 'number' && memory.idleMinutes >= 0\n ? memory.idleMinutes\n : DEFAULT_IDLE_MINUTES;\n return { extract: memory.extract !== false, model, idleMinutes: idle };\n}\n\nfunction textOf(message: Message): string {\n const content = (message as { content?: unknown }).content;\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return '';\n return content\n .map((part: { type?: string; text?: string; name?: string }) =>\n part.type === 'text'\n ? (part.text ?? '')\n : part.type === 'toolCall'\n ? `[tool ${part.name}]`\n : ''\n )\n .filter(Boolean)\n .join('\\n');\n}\n\nexport function transcriptOf(messages: readonly Message[]): string {\n const lines: string[] = [];\n for (const message of messages) {\n if (message.role !== 'user' && message.role !== 'assistant') continue;\n const text = textOf(message).trim();\n if (text) lines.push(`${message.role === 'user' ? 'User' : 'Agent'}: ${text}`);\n }\n const joined = redactSecrets(lines.join('\\n\\n')).text;\n return joined.length > TRANSCRIPT_CHARS ? joined.slice(-TRANSCRIPT_CHARS) : joined;\n}\n\nexport const EXTRACT_PROMPT = [\n 'You keep the long-term memory of a personal agent. Read the conversation excerpt and the current memory file, and propose memory entries worth keeping across conversations:',\n '- who the user is (tag \"user\"), how they want the agent to work, including corrections (tag \"feedback\"), and durable facts about their projects (tag \"project\");',\n '- only facts that will still matter in a later conversation; nothing about this one task, no transcripts, no guesses;',\n '- never secrets: no keys, tokens, passwords, Authorization values or URLs that carry a key;',\n '- to change an entry that exists, repeat its section and title with the new body; leave entries alone that need no change.',\n 'Answer with a JSON array and nothing else: [{\"section\": \"...\", \"title\": \"...\", \"body\": \"...\", \"tag\": \"user\" | \"feedback\" | \"project\"}]. An empty array is a fine answer.',\n].join('\\n');\n\nexport type Proposal = { section: string; title: string; body: string; tag: MemoryTag | null };\n\nconst TAGS = new Set(['user', 'feedback', 'project']);\n\nexport function proposals(text: string): Proposal[] {\n const start = text.indexOf('[');\n const end = text.lastIndexOf(']');\n if (start < 0 || end < start) return [];\n let parsed: unknown;\n try {\n parsed = JSON.parse(text.slice(start, end + 1));\n } catch {\n return [];\n }\n if (!Array.isArray(parsed)) return [];\n const out: Proposal[] = [];\n for (const item of parsed as Record<string, unknown>[]) {\n if (!item || typeof item !== 'object') continue;\n const { section, title, body, tag } = item;\n if (typeof section !== 'string' || typeof title !== 'string' || typeof body !== 'string')\n continue;\n if (!section.trim() || !title.trim() || !body.trim()) continue;\n out.push({\n section,\n title,\n body,\n tag: typeof tag === 'string' && TAGS.has(tag) ? (tag as MemoryTag) : null,\n });\n }\n return out.slice(0, 20);\n}\n\ntype Input = { cone: string; after: number; tail: number; model: ModelRef | null };\ntype State = { phase: 'extract' };\nexport type ExtractResult = { saved: number; skipped: string | null };\n\nasync function save(host: Host, place: Place, found: Proposal[], context: Context) {\n let saved = 0;\n for (const proposal of found) {\n try {\n await host.files.change(place, { kind: 'save', ...proposal }, context);\n saved++;\n } catch {\n break;\n }\n }\n if (saved) await host.changed(context).catch(() => undefined);\n return saved;\n}\n\nexport function extractTask(\n ready: Promise<Host>,\n settings: (context: Context) => Promise<ExtractSettings>\n) {\n return defineTask<Input, State, ExtractResult>({\n name: EXTRACT_TASK,\n version: 1,\n initial: () => ({ phase: 'extract' }),\n phases: {\n async extract(task, runtime, context) {\n const { cone, after, tail } = task.input;\n const key = String(runtime.conversationId);\n const done = (result: ExtractResult) =>\n runtime.commit(async (tx) => {\n const doc = await tx.doc(ExtractDoc);\n doc.cursors[key] = Math.max(doc.cursors[key] ?? 0, tail);\n delete doc.pending[key];\n return { status: 'terminal', outcome: { status: 'completed', result } };\n }, context);\n if (!(await settings(context)).extract) return done({ saved: 0, skipped: 'turned off' });\n const host = await ready;\n const place = placeOf(host.home, cone);\n const view = await runtime.context(runtime.conversationId, context, {\n at: tail as EntryId,\n });\n const fresh = view.entries.flatMap((entry, index) =>\n entry.id > after ? (view.contributions[index] as readonly Message[]) : []\n );\n const transcript = transcriptOf(fresh);\n if (!place || !transcript) return done({ saved: 0, skipped: 'nothing new' });\n const ref = task.input.model ?? (await runtime.agent(context)).model;\n const model = ref ? runtime.models.getModel(ref.provider, ref.modelId) : undefined;\n if (!model) return done({ saved: 0, skipped: 'no model' });\n const current = await host.files.read(place.file, context);\n const memory = current ? serializeMemory(parseMemory(current.text)) : '';\n const now = Date.now();\n const message = await runtime.models.completeSimple(\n model,\n {\n messages: [\n { role: 'system', content: EXTRACT_PROMPT, timestamp: now } as unknown as Message,\n {\n role: 'user',\n content: [\n {\n type: 'text',\n text: `<memory_file bytes_left=\"${MAX_BYTES - new TextEncoder().encode(memory).length}\">\\n${memory}</memory_file>\\n\\n<conversation>\\n${transcript}\\n</conversation>`,\n },\n ],\n timestamp: now,\n },\n ],\n },\n { maxTokens: 2000, signal: runtime.signal, cacheRetention: 'none' }\n );\n runtime.signal.throwIfAborted();\n if (message.stopReason === 'error') return done({ saved: 0, skipped: 'model error' });\n const saved = await save(host, place, proposals(textOf(message as Message)), context);\n return done({ saved, skipped: null });\n },\n },\n abort: (_task, runtime, context) =>\n runtime.commit(async (tx) => {\n delete (await tx.doc(ExtractDoc)).pending[String(runtime.conversationId)];\n return { status: 'terminal', outcome: { status: 'aborted' } };\n }, context),\n });\n}\n\nexport type Schedule = (\n conversation: number,\n tail: number,\n context: Context,\n cone?: string\n) => Promise<boolean>;\n\nexport function compactionHook(schedule: Schedule) {\n return hook(CompactionTask, {\n beforeCompact(compaction, api) {\n const tail = compaction.entries.reduce((max, entry) => Math.max(max, entry.id), 0);\n void schedule(api.conversationId, tail, BACKGROUND_CONTEXT).catch(() => false);\n return undefined;\n },\n });\n}\n\nexport function scheduler(\n ready: Promise<Host>,\n task: ReturnType<typeof extractTask>,\n settings: (context: Context) => Promise<ExtractSettings>\n): Schedule {\n return async (conversation, tail, context, cone) => {\n const host = await ready;\n const chosen = await settings(context);\n const who = cone\n ? { kind: 'cone' as const, id: cone }\n : whoIs(host.agents.state(), conversation);\n if (who.kind !== 'cone') return false;\n return host.harness.commit(async (tx) => {\n const doc = await tx.doc(ExtractDoc);\n const key = String(conversation);\n const after = doc.cursors[key] ?? 0;\n if (doc.pending[key] !== undefined || tail <= after) return false;\n doc.pending[key] = (await tx.createTask(\n task,\n { cone: who.id, after, tail, model: chosen.model },\n {\n ownership: { kind: 'conversation' },\n conversationId: conversation as ConversationId,\n background: true,\n }\n )) as number;\n return true;\n }, context);\n };\n}\n\nexport function settingsReader(ready: Promise<Host>) {\n return async (context: Context): Promise<ExtractSettings> => {\n const host = await ready;\n const dir = host.agentDir ?? `${host.home}/.pi/agent`;\n const read = await host.env.readTextFile(`${dir}/settings.json`, context);\n return extractSettings(read.ok ? read.value : undefined);\n };\n}\n\nexport const IDLE_TASK = 'slicc.memory-idle';\n\nexport const IdleDoc = defineDoc<{ tasks: Record<string, number> }>({\n kind: 'slicc.memory-idle',\n checkpointWhen: deltasOnly,\n version: 1,\n scope: 'session',\n initial: () => ({ tasks: {} }),\n});\n\ntype IdleState = { phase: 'watch'; tail: number; since: number };\n\nexport function idleTask(\n ready: Promise<Host>,\n schedule: Schedule,\n settings: (context: Context) => Promise<ExtractSettings>\n) {\n return defineTask<{ cone: string }, IdleState, null>({\n name: IDLE_TASK,\n version: 1,\n initial: () => ({ phase: 'watch', tail: -1, since: 0 }),\n phases: {\n async watch(task, runtime, context) {\n const host = await ready;\n const conversation = runtime.conversationId;\n const key = String(conversation);\n const who = whoIs(host.agents.state(), conversation);\n if (who.kind !== 'cone')\n return runtime.commit(async (tx) => {\n const doc = await tx.doc(IdleDoc);\n if (doc.tasks[key] === Number(task.id)) delete doc.tasks[key];\n return { status: 'terminal', outcome: { status: 'completed', result: null } };\n }, context);\n const { extract, idleMinutes } = await settings(context);\n const on = extract && idleMinutes > 0;\n const idleMs = (on ? idleMinutes : DEFAULT_IDLE_MINUTES) * 60_000;\n const now = runtime.now();\n const view = await runtime.context(conversation, context);\n const last = view.entries.at(-1);\n const tail = last?.id ?? 0;\n const seen = task.state.checkpoint;\n if (tail !== seen.tail) {\n const stamp = last?.model?.at(-1)?.timestamp;\n const since = typeof stamp === 'number' && stamp <= now ? stamp : now;\n return runtime.sleepUntil(since + idleMs, { phase: 'watch', tail, since }, context);\n }\n const due = seen.since + idleMs;\n if (now < due) return runtime.sleepUntil(due, seen, context);\n if (on) await schedule(conversation, tail, context, who.id);\n return runtime.sleepUntil(now + idleMs, seen, context);\n },\n },\n abort: (task, runtime, context) =>\n runtime.commit(async (tx) => {\n const doc = await tx.doc(IdleDoc);\n const key = String(runtime.conversationId);\n if (doc.tasks[key] === Number(task.id)) delete doc.tasks[key];\n return { status: 'terminal', outcome: { status: 'aborted' } };\n }, context),\n });\n}\n\nexport function idleWatch(\n host: Pick<Host, 'agents' | 'harness'>,\n task: ReturnType<typeof idleTask>,\n context: Context\n): () => void {\n let stopped = false;\n let line = Promise.resolve();\n const ensure = () => {\n line = line\n .then(async () => {\n if (stopped) return;\n await host.harness.commit(async (tx) => {\n const doc = await tx.doc(IdleDoc);\n for (const [id, cone] of Object.entries(host.agents.state().cones)) {\n const key = String(cone.conversation);\n const known = doc.tasks[key];\n const record = known === undefined ? undefined : await tx.task(known as TaskId);\n if (record && record.state.status !== 'terminal') continue;\n doc.tasks[key] = (await tx.createTask(\n task,\n { cone: id },\n {\n ownership: { kind: 'conversation' },\n conversationId: cone.conversation as ConversationId,\n background: true,\n }\n )) as number;\n }\n }, context);\n })\n .catch(() => undefined);\n };\n const off = host.agents.onChange(ensure);\n ensure();\n return () => {\n stopped = true;\n off();\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,12 +1,18 @@
1
1
  import {
2
2
  defineExtension
3
3
  } from "@earendil-works/pi-durable";
4
- import { compactionHook, extractTask, idleWatch, scheduler, settingsReader } from "./extract.js";
4
+ import {
5
+ compactionHook,
6
+ extractTask,
7
+ idleTask,
8
+ idleWatch,
9
+ scheduler,
10
+ settingsReader
11
+ } from "./extract.js";
5
12
  import { contextSection, memorySection, memoryWriteTool } from "./prompt.js";
6
13
  import { attachMemory } from "./runtime.js";
7
14
  import { MEMORY_WRITE, whoIs } from "./prompt.js";
8
15
  import { USAGE } from "./runtime.js";
9
- const IDLE_CHECK_MS = 6e4;
10
16
  function setupMemory(registry) {
11
17
  let connect = () => void 0;
12
18
  const ready = new Promise((resolve) => {
@@ -16,11 +22,12 @@ function setupMemory(registry) {
16
22
  const settings = settingsReader(ready);
17
23
  const task = extractTask(ready, settings);
18
24
  const schedule = scheduler(ready, task, settings);
25
+ const idle = idleTask(ready, schedule, settings);
19
26
  const extension = defineExtension({
20
27
  name: "slicc-memory",
21
28
  sections: [contextSection(ready), memorySection(ready)],
22
29
  tools: [tool],
23
- tasks: [task],
30
+ tasks: [task, idle],
24
31
  hooks: [compactionHook(schedule)]
25
32
  });
26
33
  registry.install(extension);
@@ -30,13 +37,7 @@ function setupMemory(registry) {
30
37
  extract: schedule,
31
38
  async attach(options, context) {
32
39
  const runtime = await attachMemory(options, connect, context);
33
- const stop = idleWatch(
34
- await ready,
35
- schedule,
36
- settings,
37
- options.idleCheckMs ?? IDLE_CHECK_MS,
38
- context
39
- );
40
+ const stop = idleWatch(await ready, idle, context);
40
41
  return {
41
42
  ...runtime,
42
43
  async close(using) {
@@ -48,7 +49,6 @@ function setupMemory(registry) {
48
49
  };
49
50
  }
50
51
  export {
51
- IDLE_CHECK_MS,
52
52
  MEMORY_WRITE,
53
53
  USAGE,
54
54
  setupMemory,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/memory/index.ts"],
4
- "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport {\n defineExtension,\n type Extension,\n type Registry,\n type ToolRegistration,\n} from '@earendil-works/pi-durable';\nimport { compactionHook, extractTask, idleWatch, scheduler, settingsReader } from './extract.ts';\nimport { contextSection, type Host, memorySection, memoryWriteTool } from './prompt.ts';\nimport { attachMemory, type MemoryAttach, type MemoryRuntime } from './runtime.ts';\n\nexport { MEMORY_WRITE, whoIs } from './prompt.ts';\nexport type { MemoryAttach, MemoryDraft, MemoryRuntime } from './runtime.ts';\nexport { USAGE } from './runtime.ts';\n\nexport const IDLE_CHECK_MS = 60_000;\n\nexport interface MemorySetup {\n extension: Extension;\n tools: readonly ToolRegistration[];\n extract(conversation: number, tail: number, context: Context, cone?: string): Promise<boolean>;\n attach(options: MemoryAttach, context: Context): Promise<MemoryRuntime>;\n}\n\nexport function setupMemory(registry: Registry): MemorySetup {\n let connect: (host: Host) => void = () => undefined;\n const ready = new Promise<Host>((resolve) => {\n connect = resolve;\n });\n const tool = memoryWriteTool(ready);\n const settings = settingsReader(ready);\n const task = extractTask(ready, settings);\n const schedule = scheduler(ready, task, settings);\n const extension = defineExtension({\n name: 'slicc-memory',\n sections: [contextSection(ready), memorySection(ready)],\n tools: [tool],\n tasks: [task],\n hooks: [compactionHook(schedule)],\n });\n registry.install(extension);\n return {\n extension,\n tools: [tool],\n extract: schedule,\n async attach(options, context) {\n const runtime = await attachMemory(options, connect, context);\n const stop = idleWatch(\n await ready,\n schedule,\n settings,\n options.idleCheckMs ?? IDLE_CHECK_MS,\n context\n );\n return {\n ...runtime,\n async close(using) {\n stop();\n await runtime.close(using);\n },\n };\n },\n };\n}\n"],
5
- "mappings": "AACA;AAAA,EACE;AAAA,OAIK;AACP,SAAS,gBAAgB,aAAa,WAAW,WAAW,sBAAsB;AAClF,SAAS,gBAA2B,eAAe,uBAAuB;AAC1E,SAAS,oBAA2D;AAEpE,SAAS,cAAc,aAAa;AAEpC,SAAS,aAAa;AAEf,MAAM,gBAAgB;AAStB,SAAS,YAAY,UAAiC;AAC3D,MAAI,UAAgC,MAAM;AAC1C,QAAM,QAAQ,IAAI,QAAc,CAAC,YAAY;AAC3C,cAAU;AAAA,EACZ,CAAC;AACD,QAAM,OAAO,gBAAgB,KAAK;AAClC,QAAM,WAAW,eAAe,KAAK;AACrC,QAAM,OAAO,YAAY,OAAO,QAAQ;AACxC,QAAM,WAAW,UAAU,OAAO,MAAM,QAAQ;AAChD,QAAM,YAAY,gBAAgB;AAAA,IAChC,MAAM;AAAA,IACN,UAAU,CAAC,eAAe,KAAK,GAAG,cAAc,KAAK,CAAC;AAAA,IACtD,OAAO,CAAC,IAAI;AAAA,IACZ,OAAO,CAAC,IAAI;AAAA,IACZ,OAAO,CAAC,eAAe,QAAQ,CAAC;AAAA,EAClC,CAAC;AACD,WAAS,QAAQ,SAAS;AAC1B,SAAO;AAAA,IACL;AAAA,IACA,OAAO,CAAC,IAAI;AAAA,IACZ,SAAS;AAAA,IACT,MAAM,OAAO,SAAS,SAAS;AAC7B,YAAM,UAAU,MAAM,aAAa,SAAS,SAAS,OAAO;AAC5D,YAAM,OAAO;AAAA,QACX,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA,QAAQ,eAAe;AAAA,QACvB;AAAA,MACF;AACA,aAAO;AAAA,QACL,GAAG;AAAA,QACH,MAAM,MAAM,OAAO;AACjB,eAAK;AACL,gBAAM,QAAQ,MAAM,KAAK;AAAA,QAC3B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport {\n defineExtension,\n type Extension,\n type Registry,\n type ToolRegistration,\n} from '@earendil-works/pi-durable';\nimport {\n compactionHook,\n extractTask,\n idleTask,\n idleWatch,\n scheduler,\n settingsReader,\n} from './extract.ts';\nimport { contextSection, type Host, memorySection, memoryWriteTool } from './prompt.ts';\nimport { attachMemory, type MemoryAttach, type MemoryRuntime } from './runtime.ts';\n\nexport { MEMORY_WRITE, whoIs } from './prompt.ts';\nexport type { MemoryAttach, MemoryDraft, MemoryRuntime } from './runtime.ts';\nexport { USAGE } from './runtime.ts';\n\nexport interface MemorySetup {\n extension: Extension;\n tools: readonly ToolRegistration[];\n extract(conversation: number, tail: number, context: Context, cone?: string): Promise<boolean>;\n attach(options: MemoryAttach, context: Context): Promise<MemoryRuntime>;\n}\n\nexport function setupMemory(registry: Registry): MemorySetup {\n let connect: (host: Host) => void = () => undefined;\n const ready = new Promise<Host>((resolve) => {\n connect = resolve;\n });\n const tool = memoryWriteTool(ready);\n const settings = settingsReader(ready);\n const task = extractTask(ready, settings);\n const schedule = scheduler(ready, task, settings);\n const idle = idleTask(ready, schedule, settings);\n const extension = defineExtension({\n name: 'slicc-memory',\n sections: [contextSection(ready), memorySection(ready)],\n tools: [tool],\n tasks: [task, idle],\n hooks: [compactionHook(schedule)],\n });\n registry.install(extension);\n return {\n extension,\n tools: [tool],\n extract: schedule,\n async attach(options, context) {\n const runtime = await attachMemory(options, connect, context);\n const stop = idleWatch(await ready, idle, context);\n return {\n ...runtime,\n async close(using) {\n stop();\n await runtime.close(using);\n },\n };\n },\n };\n}\n"],
5
+ "mappings": "AACA;AAAA,EACE;AAAA,OAIK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,gBAA2B,eAAe,uBAAuB;AAC1E,SAAS,oBAA2D;AAEpE,SAAS,cAAc,aAAa;AAEpC,SAAS,aAAa;AASf,SAAS,YAAY,UAAiC;AAC3D,MAAI,UAAgC,MAAM;AAC1C,QAAM,QAAQ,IAAI,QAAc,CAAC,YAAY;AAC3C,cAAU;AAAA,EACZ,CAAC;AACD,QAAM,OAAO,gBAAgB,KAAK;AAClC,QAAM,WAAW,eAAe,KAAK;AACrC,QAAM,OAAO,YAAY,OAAO,QAAQ;AACxC,QAAM,WAAW,UAAU,OAAO,MAAM,QAAQ;AAChD,QAAM,OAAO,SAAS,OAAO,UAAU,QAAQ;AAC/C,QAAM,YAAY,gBAAgB;AAAA,IAChC,MAAM;AAAA,IACN,UAAU,CAAC,eAAe,KAAK,GAAG,cAAc,KAAK,CAAC;AAAA,IACtD,OAAO,CAAC,IAAI;AAAA,IACZ,OAAO,CAAC,MAAM,IAAI;AAAA,IAClB,OAAO,CAAC,eAAe,QAAQ,CAAC;AAAA,EAClC,CAAC;AACD,WAAS,QAAQ,SAAS;AAC1B,SAAO;AAAA,IACL;AAAA,IACA,OAAO,CAAC,IAAI;AAAA,IACZ,SAAS;AAAA,IACT,MAAM,OAAO,SAAS,SAAS;AAC7B,YAAM,UAAU,MAAM,aAAa,SAAS,SAAS,OAAO;AAC5D,YAAM,OAAO,UAAU,MAAM,OAAO,MAAM,OAAO;AACjD,aAAO;AAAA,QACL,GAAG;AAAA,QACH,MAAM,MAAM,OAAO;AACjB,eAAK;AACL,gBAAM,QAAQ,MAAM,KAAK;AAAA,QAC3B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/memory/runtime.ts"],
4
- "sourcesContent": ["import {\n type Context,\n type MutableReplicatedState,\n type ReplicatedState,\n replicatedState,\n} from '@earendil-works/chord';\nimport { awaitWithContext, withCancel } from '@earendil-works/chord/context';\nimport type { Harness } from '@earendil-works/pi-durable';\nimport type { ExecutionEnv, FileWatcher } from '@earendil-works/pi-durable/env';\nimport type { Agents } from '../agents.ts';\nimport type { Role } from '../roles/roles.ts';\nimport { workspace } from '../scoops/service.ts';\nimport { MEMORY_FILE, type MemoryEntry, type MemoryScope, type MemoryTag } from './format.ts';\nimport type { Host } from './prompt.ts';\nimport { MEMORY_WRITE } from './prompt.ts';\nimport {\n GLOBAL,\n MemoryFiles,\n memoryRoot,\n type Place,\n placeOf,\n ROLE_PREFIX,\n rolePlace,\n roleRoot,\n} from './store.ts';\n\nexport type Answer = { code: number; out: string };\n\nexport interface MemoryDraft {\n id?: string;\n scope: string;\n section: string;\n title: string;\n body: string;\n tag: MemoryTag | null;\n}\n\nexport interface MemoryRuntime {\n readonly memories: ReplicatedState<MemoryEntry[]>;\n readonly scopes: ReplicatedState<MemoryScope[]>;\n save(draft: MemoryDraft, context: Context): Promise<MemoryEntry>;\n remove(id: string, context: Context): Promise<boolean>;\n command(argv: readonly string[], caller: string | null, context: Context): Promise<Answer>;\n reload(context: Context): Promise<void>;\n close(context: Context): Promise<void>;\n}\n\nexport interface MemoryAttach {\n harness: Harness;\n agents: Agents;\n env: ExecutionEnv;\n home: string;\n agentDir?: string;\n reloadMs: number;\n idleCheckMs?: number;\n roles?: (context: Context) => Promise<{ roles: readonly Role[] } | undefined>;\n}\n\nexport const USAGE = `usage:\n memory show [<scope>] print a memory file (yours by default)\n memory scopes every memory scope, its entries and its file\n\nScopes: global (everyone), a cone's id, or role:<path> for a role's memory.\nAgents write memory with the ${MEMORY_WRITE} tool; the files are plain markdown you can edit.\n`;\n\ntype Listed = Place & { group?: 'cones' | 'roles'; name: string };\n\nasync function roleDirs(\n env: ExecutionEnv,\n dir: string,\n prefix: string,\n context: Context,\n depth = 0\n): Promise<string[]> {\n const listed = await env.listDir(dir, context);\n if (!listed.ok || depth > 4) return [];\n const out: string[] = [];\n for (const info of listed.value) {\n if (info.kind !== 'directory') continue;\n const path = prefix ? `${prefix}/${info.name}` : info.name;\n const found = await env.exists(`${dir}/${info.name}/${MEMORY_FILE}`, context);\n if (found.ok && found.value) out.push(path);\n out.push(...(await roleDirs(env, `${dir}/${info.name}`, path, context, depth + 1)));\n }\n return out;\n}\n\nexport async function listPlaces(options: MemoryAttach, context: Context): Promise<Listed[]> {\n const { agents, env, home } = options;\n const state = agents.state();\n const out: Listed[] = [{ ...(placeOf(home, GLOBAL) as Place), name: 'Shared' }];\n const cones = new Set(Object.keys(state.cones));\n const stored = await env.listDir(memoryRoot(home), context);\n if (stored.ok)\n for (const info of stored.value) if (info.kind === 'directory') cones.add(info.name);\n for (const id of cones) {\n const place = placeOf(home, id);\n if (place) out.push({ ...place, group: 'cones', name: state.cones[id]?.name ?? id });\n }\n const roles = new Set(await roleDirs(env, roleRoot(home), '', context));\n const known = await options.roles?.(context).catch(() => undefined);\n for (const role of known?.roles ?? [])\n if (role.memory?.scope === 'user') roles.add(role.memory.path);\n for (const path of [...roles].sort()) {\n const place = placeOf(home, `${ROLE_PREFIX}${path}`);\n if (place) out.push({ ...place, group: 'roles', name: path.split('/').at(-1) ?? path });\n }\n return out;\n}\n\nasync function callerPlace(\n options: MemoryAttach,\n caller: string | null,\n context: Context\n): Promise<Place | { problem: string }> {\n const { agents, env, home } = options;\n const record = caller ? agents.state().scoops[caller] : undefined;\n if (record?.memory)\n return rolePlace(env, home, record.memory, record.origin ?? workspace(record.folder), context);\n const cone = caller?.startsWith('cone:') ? caller.slice('cone:'.length) : agents.activeCone();\n return placeOf(home, cone) ?? { problem: `there is no memory scope ${cone}` };\n}\n\ntype Parts = {\n options: MemoryAttach;\n files: MemoryFiles;\n memories: MutableReplicatedState<MemoryEntry[]>;\n scopes: MutableReplicatedState<MemoryScope[]>;\n reload: (context: Context) => Promise<void>;\n};\n\nfunction placeFor(home: string, scope: string): Place {\n const place = placeOf(home, scope);\n if (!place) throw new Error(`there is no memory scope ${scope}`);\n return place;\n}\n\nasync function save(parts: Parts, draft: MemoryDraft, context: Context): Promise<MemoryEntry> {\n const { files, memories, options } = parts;\n const place = placeFor(options.home, draft.scope);\n const previous = draft.id ? memories.value.find((item) => item.id === draft.id) : undefined;\n const moved = previous && previous.scope !== draft.scope;\n try {\n const written = await files.change(\n place,\n {\n kind: 'save',\n ...(previous && !moved ? { id: previous.id } : {}),\n section: draft.section,\n title: draft.title,\n body: draft.body,\n tag: draft.tag,\n },\n context\n );\n if (previous && moved)\n await files.change(\n placeFor(options.home, previous.scope),\n { kind: 'remove', id: previous.id },\n context\n );\n return written.entry as MemoryEntry;\n } finally {\n await parts.reload(context).catch(() => undefined);\n }\n}\n\nasync function command(\n parts: Parts,\n argv: readonly string[],\n caller: string | null,\n context: Context\n): Promise<Answer> {\n const { files, memories, scopes, options } = parts;\n const verb = argv[0] ?? 'help';\n if (verb === 'scopes') {\n await parts.reload(context);\n const rows = scopes.value.map((scope) => {\n const count = memories.value.filter((item) => item.scope === scope.id).length;\n const file = placeFor(options.home, scope.id).file;\n return `${scope.id}\\t${scope.label}\\t${count} entr${count === 1 ? 'y' : 'ies'}\\t${file}`;\n });\n return { code: 0, out: `${rows.join('\\n')}\\n` };\n }\n if (verb !== 'show') return { code: verb === 'help' || verb === '--help' ? 0 : 2, out: USAGE };\n const place = argv[1]\n ? (placeOf(options.home, argv[1]) ?? { problem: `there is no memory scope ${argv[1]}` })\n : await callerPlace(options, caller, context);\n if ('problem' in place) return { code: 1, out: `memory: ${place.problem}\\n` };\n const read = await files.read(place.file, context);\n return {\n code: 0,\n out: read?.text.trim()\n ? `# ${place.file}\\n\\n${read.text.trimEnd()}\\n`\n : `${place.file} is empty\\n`,\n };\n}\n\nexport async function attachMemory(\n options: MemoryAttach,\n connect: (host: Host) => void,\n context: Context\n): Promise<MemoryRuntime> {\n const { agents, env, home } = options;\n const files = new MemoryFiles(env);\n const memories = replicatedState<MemoryEntry[]>([]);\n const scopes = replicatedState<MemoryScope[]>([]);\n const load = async (using: Context) => {\n const found = await listPlaces(options, using);\n const entries: MemoryEntry[] = [];\n for (const place of found) entries.push(...(await files.entries(place, using)));\n if (using.abortSignal?.aborted) return;\n scopes.replace(\n using,\n found.map((place) => ({\n id: place.scope,\n label: place.name,\n ...(place.group ? { group: place.group } : {}),\n }))\n );\n memories.replace(using, entries);\n };\n const life = withCancel(context);\n let latest: Promise<void> = Promise.resolve();\n let stop: (reason?: unknown) => void = () => undefined;\n const reload = (using: Context) => {\n stop();\n const run = withCancel(life.context);\n stop = run.cancel;\n const loading: Promise<void> = awaitWithContext(load(run.context), run.context).catch(\n (error: unknown) =>\n life.context.abortSignal?.aborted || latest === loading ? Promise.reject(error) : latest\n );\n latest = loading;\n return awaitWithContext(loading, using);\n };\n const parts: Parts = { options, files, memories, scopes, reload };\n connect({\n harness: options.harness,\n agents,\n env,\n home,\n ...(options.agentDir ? { agentDir: options.agentDir } : {}),\n files,\n changed: reload,\n });\n await reload(context).catch(() => undefined);\n let timer: ReturnType<typeof setTimeout> | undefined;\n const schedule = () => {\n clearTimeout(timer);\n timer = setTimeout(() => void reload(context).catch(() => undefined), options.reloadMs);\n };\n const named = () =>\n JSON.stringify(Object.entries(agents.state().cones).map(([id, cone]) => [id, cone.name]));\n let cones = named();\n const offCones = agents.onChange(() => {\n const next = named();\n if (next === cones) return;\n cones = next;\n schedule();\n });\n const watched = await env.watch(\n [\n { path: memoryRoot(home), recursive: true },\n { path: roleRoot(home), recursive: true },\n ],\n schedule,\n context\n );\n const watcher: FileWatcher | undefined = watched.ok ? watched.value : undefined;\n return {\n memories,\n scopes,\n save: (draft, using) => save(parts, draft, using),\n async remove(id, using) {\n const entry = memories.value.find((item) => item.id === id);\n if (!entry) return false;\n const written = await files.change(\n placeFor(home, entry.scope),\n { kind: 'remove', id },\n using\n );\n await reload(using);\n return written.found;\n },\n command: (argv, caller, using) => command(parts, argv, caller, using),\n reload,\n async close(using) {\n offCones();\n clearTimeout(timer);\n life.cancel();\n await watcher?.close(using);\n },\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n type Context,\n type MutableReplicatedState,\n type ReplicatedState,\n replicatedState,\n} from '@earendil-works/chord';\nimport { awaitWithContext, withCancel } from '@earendil-works/chord/context';\nimport type { Harness } from '@earendil-works/pi-durable';\nimport type { ExecutionEnv, FileWatcher } from '@earendil-works/pi-durable/env';\nimport type { Agents } from '../agents.ts';\nimport type { Role } from '../roles/roles.ts';\nimport { workspace } from '../scoops/service.ts';\nimport { MEMORY_FILE, type MemoryEntry, type MemoryScope, type MemoryTag } from './format.ts';\nimport type { Host } from './prompt.ts';\nimport { MEMORY_WRITE } from './prompt.ts';\nimport {\n GLOBAL,\n MemoryFiles,\n memoryRoot,\n type Place,\n placeOf,\n ROLE_PREFIX,\n rolePlace,\n roleRoot,\n} from './store.ts';\n\nexport type Answer = { code: number; out: string };\n\nexport interface MemoryDraft {\n id?: string;\n scope: string;\n section: string;\n title: string;\n body: string;\n tag: MemoryTag | null;\n}\n\nexport interface MemoryRuntime {\n readonly memories: ReplicatedState<MemoryEntry[]>;\n readonly scopes: ReplicatedState<MemoryScope[]>;\n save(draft: MemoryDraft, context: Context): Promise<MemoryEntry>;\n remove(id: string, context: Context): Promise<boolean>;\n command(argv: readonly string[], caller: string | null, context: Context): Promise<Answer>;\n reload(context: Context): Promise<void>;\n close(context: Context): Promise<void>;\n}\n\nexport interface MemoryAttach {\n harness: Harness;\n agents: Agents;\n env: ExecutionEnv;\n home: string;\n agentDir?: string;\n reloadMs: number;\n roles?: (context: Context) => Promise<{ roles: readonly Role[] } | undefined>;\n}\n\nexport const USAGE = `usage:\n memory show [<scope>] print a memory file (yours by default)\n memory scopes every memory scope, its entries and its file\n\nScopes: global (everyone), a cone's id, or role:<path> for a role's memory.\nAgents write memory with the ${MEMORY_WRITE} tool; the files are plain markdown you can edit.\n`;\n\ntype Listed = Place & { group?: 'cones' | 'roles'; name: string };\n\nasync function roleDirs(\n env: ExecutionEnv,\n dir: string,\n prefix: string,\n context: Context,\n depth = 0\n): Promise<string[]> {\n const listed = await env.listDir(dir, context);\n if (!listed.ok || depth > 4) return [];\n const out: string[] = [];\n for (const info of listed.value) {\n if (info.kind !== 'directory') continue;\n const path = prefix ? `${prefix}/${info.name}` : info.name;\n const found = await env.exists(`${dir}/${info.name}/${MEMORY_FILE}`, context);\n if (found.ok && found.value) out.push(path);\n out.push(...(await roleDirs(env, `${dir}/${info.name}`, path, context, depth + 1)));\n }\n return out;\n}\n\nexport async function listPlaces(options: MemoryAttach, context: Context): Promise<Listed[]> {\n const { agents, env, home } = options;\n const state = agents.state();\n const out: Listed[] = [{ ...(placeOf(home, GLOBAL) as Place), name: 'Shared' }];\n const cones = new Set(Object.keys(state.cones));\n const stored = await env.listDir(memoryRoot(home), context);\n if (stored.ok)\n for (const info of stored.value) if (info.kind === 'directory') cones.add(info.name);\n for (const id of cones) {\n const place = placeOf(home, id);\n if (place) out.push({ ...place, group: 'cones', name: state.cones[id]?.name ?? id });\n }\n const roles = new Set(await roleDirs(env, roleRoot(home), '', context));\n const known = await options.roles?.(context).catch(() => undefined);\n for (const role of known?.roles ?? [])\n if (role.memory?.scope === 'user') roles.add(role.memory.path);\n for (const path of [...roles].sort()) {\n const place = placeOf(home, `${ROLE_PREFIX}${path}`);\n if (place) out.push({ ...place, group: 'roles', name: path.split('/').at(-1) ?? path });\n }\n return out;\n}\n\nasync function callerPlace(\n options: MemoryAttach,\n caller: string | null,\n context: Context\n): Promise<Place | { problem: string }> {\n const { agents, env, home } = options;\n const record = caller ? agents.state().scoops[caller] : undefined;\n if (record?.memory)\n return rolePlace(env, home, record.memory, record.origin ?? workspace(record.folder), context);\n const cone = caller?.startsWith('cone:') ? caller.slice('cone:'.length) : agents.activeCone();\n return placeOf(home, cone) ?? { problem: `there is no memory scope ${cone}` };\n}\n\ntype Parts = {\n options: MemoryAttach;\n files: MemoryFiles;\n memories: MutableReplicatedState<MemoryEntry[]>;\n scopes: MutableReplicatedState<MemoryScope[]>;\n reload: (context: Context) => Promise<void>;\n};\n\nfunction placeFor(home: string, scope: string): Place {\n const place = placeOf(home, scope);\n if (!place) throw new Error(`there is no memory scope ${scope}`);\n return place;\n}\n\nasync function save(parts: Parts, draft: MemoryDraft, context: Context): Promise<MemoryEntry> {\n const { files, memories, options } = parts;\n const place = placeFor(options.home, draft.scope);\n const previous = draft.id ? memories.value.find((item) => item.id === draft.id) : undefined;\n const moved = previous && previous.scope !== draft.scope;\n try {\n const written = await files.change(\n place,\n {\n kind: 'save',\n ...(previous && !moved ? { id: previous.id } : {}),\n section: draft.section,\n title: draft.title,\n body: draft.body,\n tag: draft.tag,\n },\n context\n );\n if (previous && moved)\n await files.change(\n placeFor(options.home, previous.scope),\n { kind: 'remove', id: previous.id },\n context\n );\n return written.entry as MemoryEntry;\n } finally {\n await parts.reload(context).catch(() => undefined);\n }\n}\n\nasync function command(\n parts: Parts,\n argv: readonly string[],\n caller: string | null,\n context: Context\n): Promise<Answer> {\n const { files, memories, scopes, options } = parts;\n const verb = argv[0] ?? 'help';\n if (verb === 'scopes') {\n await parts.reload(context);\n const rows = scopes.value.map((scope) => {\n const count = memories.value.filter((item) => item.scope === scope.id).length;\n const file = placeFor(options.home, scope.id).file;\n return `${scope.id}\\t${scope.label}\\t${count} entr${count === 1 ? 'y' : 'ies'}\\t${file}`;\n });\n return { code: 0, out: `${rows.join('\\n')}\\n` };\n }\n if (verb !== 'show') return { code: verb === 'help' || verb === '--help' ? 0 : 2, out: USAGE };\n const place = argv[1]\n ? (placeOf(options.home, argv[1]) ?? { problem: `there is no memory scope ${argv[1]}` })\n : await callerPlace(options, caller, context);\n if ('problem' in place) return { code: 1, out: `memory: ${place.problem}\\n` };\n const read = await files.read(place.file, context);\n return {\n code: 0,\n out: read?.text.trim()\n ? `# ${place.file}\\n\\n${read.text.trimEnd()}\\n`\n : `${place.file} is empty\\n`,\n };\n}\n\nexport async function attachMemory(\n options: MemoryAttach,\n connect: (host: Host) => void,\n context: Context\n): Promise<MemoryRuntime> {\n const { agents, env, home } = options;\n const files = new MemoryFiles(env);\n const memories = replicatedState<MemoryEntry[]>([]);\n const scopes = replicatedState<MemoryScope[]>([]);\n const load = async (using: Context) => {\n const found = await listPlaces(options, using);\n const entries: MemoryEntry[] = [];\n for (const place of found) entries.push(...(await files.entries(place, using)));\n if (using.abortSignal?.aborted) return;\n scopes.replace(\n using,\n found.map((place) => ({\n id: place.scope,\n label: place.name,\n ...(place.group ? { group: place.group } : {}),\n }))\n );\n memories.replace(using, entries);\n };\n const life = withCancel(context);\n let latest: Promise<void> = Promise.resolve();\n let stop: (reason?: unknown) => void = () => undefined;\n const reload = (using: Context) => {\n stop();\n const run = withCancel(life.context);\n stop = run.cancel;\n const loading: Promise<void> = awaitWithContext(load(run.context), run.context).catch(\n (error: unknown) =>\n life.context.abortSignal?.aborted || latest === loading ? Promise.reject(error) : latest\n );\n latest = loading;\n return awaitWithContext(loading, using);\n };\n const parts: Parts = { options, files, memories, scopes, reload };\n connect({\n harness: options.harness,\n agents,\n env,\n home,\n ...(options.agentDir ? { agentDir: options.agentDir } : {}),\n files,\n changed: reload,\n });\n await reload(context).catch(() => undefined);\n let timer: ReturnType<typeof setTimeout> | undefined;\n const schedule = () => {\n clearTimeout(timer);\n timer = setTimeout(() => void reload(context).catch(() => undefined), options.reloadMs);\n };\n const named = () =>\n JSON.stringify(Object.entries(agents.state().cones).map(([id, cone]) => [id, cone.name]));\n let cones = named();\n const offCones = agents.onChange(() => {\n const next = named();\n if (next === cones) return;\n cones = next;\n schedule();\n });\n const watched = await env.watch(\n [\n { path: memoryRoot(home), recursive: true },\n { path: roleRoot(home), recursive: true },\n ],\n schedule,\n context\n );\n const watcher: FileWatcher | undefined = watched.ok ? watched.value : undefined;\n return {\n memories,\n scopes,\n save: (draft, using) => save(parts, draft, using),\n async remove(id, using) {\n const entry = memories.value.find((item) => item.id === id);\n if (!entry) return false;\n const written = await files.change(\n placeFor(home, entry.scope),\n { kind: 'remove', id },\n using\n );\n await reload(using);\n return written.found;\n },\n command: (argv, caller, using) => command(parts, argv, caller, using),\n reload,\n async close(using) {\n offCones();\n clearTimeout(timer);\n life.cancel();\n await watcher?.close(using);\n },\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -39,7 +39,8 @@ const KINDS = {
39
39
  "pi.compaction": "compacting",
40
40
  "slicc.scoop-wait": "agent wait",
41
41
  "slicc.scoop-reporter": "report",
42
- "slicc.memory-extract": "memory extraction"
42
+ "slicc.memory-extract": "memory extraction",
43
+ "slicc.memory-idle": "memory idle watch"
43
44
  };
44
45
  function age(ms) {
45
46
  const seconds = Math.max(0, Math.round(ms / 1e3));
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/spectrum/monitor-port.ts"],
4
- "sourcesContent": ["import type {\n MonitorAlert,\n MonitorEvents,\n MonitorPort,\n MonitorRow,\n MonitorSection,\n MonitorSnapshot,\n MonitorStatus,\n MonitorVital,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { AgentConnection } from '../client.ts';\nimport { contextRatio } from '../context.ts';\nimport type {\n BudgetState,\n ModelChoice,\n MonitorAgent,\n MonitorFeed,\n MonitorProblem,\n MonitorProcess,\n MonitorTask,\n} from '../services.ts';\nimport { budgetName, type Selected, selectedBudget } from './budget.ts';\nimport { Emitter } from './emitter.ts';\n\nexport const RENEW_MS = 10000;\nexport const SAMPLE_MS = 2000;\nexport const ROWS_MAX = 200;\nexport const HISTORY = 24;\nexport const CPU_HISTORY = 30;\nexport const CPU_QUIET = 0.01;\nexport const BUDGET_WARN = 80;\nexport const BUDGET_ERROR = 95;\nexport const RETRY_WARN = 3;\nexport const RETRY_ERROR = 6;\nexport const RETRY_SLOW_MS = 120000;\nexport const FAILED_MS = 600000;\nexport const ABORT_MS = 30000;\nexport const ABORT_ROW_MS = 10000;\nexport const GROUP_MAX = 32;\nexport const TOTAL_MAX = 128;\nexport const ZOMBIE_MS = 60000;\nexport const STALE_MS = 1800000;\nexport const CPU_SHARE = 0.9;\nexport const CPU_SUSTAIN_MS = 120000;\nexport const CONTEXT_WARN = 0.8;\nexport const DEPTH_MAX = 6;\nconst MINUTE = 60000;\nconst HOUR = 3600000;\nconst DAY = 86400000;\n\nexport type AgentMonitorAlert = MonitorAlert & { command?: string; commandLabel?: string };\n\nexport interface Sample {\n at: number;\n cost: number;\n tokens: number;\n active: number;\n}\n\nexport interface MonitorInput {\n feed: MonitorFeed | undefined;\n budget: BudgetState | null | undefined;\n models: readonly ModelChoice[];\n changes: readonly { path: string; status: string }[];\n sprinkles?: readonly { name: string; title: string }[];\n extra: readonly MonitorSection[];\n history: readonly Sample[];\n now: number;\n hot?: ReadonlyMap<number, number>;\n cpu?: readonly number[];\n processes?: readonly number[];\n memory?: readonly number[];\n}\n\nexport function record<T>(list: T[], value: T, max: number): void {\n list.push(value);\n if (list.length > max) list.shift();\n}\n\nfunction trend(series: readonly number[] | undefined): { series?: number[] } {\n return series && series.length > 1 ? { series: [...series] } : {};\n}\n\nconst KINDS: Record<string, string> = {\n 'pi.generation': 'generating',\n 'pi.compaction': 'compacting',\n 'slicc.scoop-wait': 'agent wait',\n 'slicc.scoop-reporter': 'report',\n 'slicc.memory-extract': 'memory extraction',\n};\n\nexport function age(ms: number): string {\n const seconds = Math.max(0, Math.round(ms / 1000));\n if (seconds < 60) return `${seconds}s`;\n if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;\n return `${Math.floor(seconds / 3600)}h`;\n}\n\nexport function money(value: number): string {\n if (value > 0 && value < 0.01) return '<$0.01';\n return `$${value.toFixed(2)}`;\n}\n\nexport function count(value: number): string {\n if (value < 1000) return String(value);\n if (value < 1000000) return `${(value / 1000).toFixed(1)}k`;\n return `${(value / 1000000).toFixed(1)}M`;\n}\n\nexport function bytes(value: number): string {\n if (value < 1024) return `${value} B`;\n const units = ['KiB', 'MiB', 'GiB', 'TiB'];\n let size = value / 1024;\n let unit = 0;\n while (size >= 1024 && unit < units.length - 1) {\n size /= 1024;\n unit++;\n }\n return `${size.toFixed(size < 10 ? 1 : 0)} ${units[unit]}`;\n}\n\nexport function cpuText(share: number | null | undefined): string | null {\n if (typeof share !== 'number' || share < CPU_QUIET) return null;\n return `${Math.round(share * 100)}%\\u00a0CPU`;\n}\n\nexport function agentsCpu(feed: MonitorFeed): number | null {\n const shares = feed.agents\n .map((agent) => agent.cpu)\n .filter((share): share is number => typeof share === 'number');\n return shares.length ? shares.reduce((sum, share) => sum + share, 0) : null;\n}\n\nfunction cpuVital(feed: MonitorFeed, history: readonly number[]): MonitorVital[] {\n const share = agentsCpu(feed);\n if (share === null) return [];\n return [\n {\n id: 'cpu',\n label: 'CPU',\n value: `${Math.round(share * 100)}%`,\n unit: 'of one core',\n ...trend(history.map((value) => Math.round(value * 100))),\n },\n ];\n}\n\nfunction measuredOf(processes: readonly MonitorProcess[]): MonitorProcess[] {\n return processes.filter((row) => typeof row.rss === 'number');\n}\n\nexport function memoryTotal(processes: readonly MonitorProcess[]): number | null {\n const measured = measuredOf(processes);\n return measured.length ? measured.reduce((sum, row) => sum + (row.rss as number), 0) : null;\n}\n\nfunction memoryVital(\n processes: readonly MonitorProcess[],\n history: readonly number[] | undefined\n): MonitorVital[] {\n const total = memoryTotal(processes);\n if (total === null) return [];\n const measured = measuredOf(processes);\n const agents = measured\n .filter((row) => row.agentId)\n .reduce((sum, row) => sum + (row.rss as number), 0);\n return [\n {\n id: 'memory',\n label: 'Process memory',\n value: bytes(total),\n unit: `${bytes(agents)} by agents`,\n ...trend(history),\n },\n ];\n}\n\nexport function taskLabel(task: MonitorTask): string {\n if (task.kind === 'pi.tool') return task.detail ? `tool ${task.detail}` : 'tool';\n if (task.kind === 'slicc.scoop-anchor') return task.detail ? `scoop ${task.detail}` : 'scoop';\n return KINDS[task.kind] ?? task.kind;\n}\n\nfunction coneOf(agents: ReadonlyMap<string, MonitorAgent>, id: string | null): string | null {\n const visited = new Set<string>();\n let current = id === null ? undefined : agents.get(id);\n while (current?.parentId && !visited.has(current.id)) {\n visited.add(current.id);\n const parent = agents.get(current.parentId);\n if (!parent) break;\n current = parent;\n }\n return current ? current.id : null;\n}\n\nfunction ordered(feed: MonitorFeed): MonitorAgent[] {\n const byId = new Map(feed.agents.map((agent) => [agent.id, agent]));\n const out: MonitorAgent[] = [];\n for (const cone of feed.agents.filter((agent) => agent.kind === 'cone')) {\n out.push(cone);\n for (const agent of feed.agents)\n if (agent.kind === 'scoop' && coneOf(byId, agent.id) === cone.id) out.push(agent);\n }\n for (const agent of feed.agents) if (!out.includes(agent)) out.push(agent);\n return out;\n}\n\nexport function taskTree(feed: MonitorFeed): { task: MonitorTask; depth: number }[] {\n const agents = new Map(feed.agents.map((agent) => [agent.id, agent]));\n const order = ordered(feed).map((agent) => agent.id);\n const rank = (task: MonitorTask) => {\n const at = task.agentId === null ? -1 : order.indexOf(task.agentId);\n return at < 0 ? order.length : at;\n };\n const groupOf = (task: MonitorTask) => coneOf(agents, task.agentId) ?? '';\n const byId = new Map(feed.tasks.map((task) => [task.id, task]));\n const children = new Map<string, MonitorTask[]>();\n const roots: MonitorTask[] = [];\n for (const task of feed.tasks) {\n const owner = task.owner === null ? undefined : byId.get(task.owner);\n if (owner && groupOf(owner) === groupOf(task)) {\n const list = children.get(owner.id) ?? [];\n list.push(task);\n children.set(owner.id, list);\n } else roots.push(task);\n }\n const sort = (list: MonitorTask[]) =>\n list.sort((a, b) => rank(a) - rank(b) || Number(a.id) - Number(b.id));\n const out: { task: MonitorTask; depth: number }[] = [];\n const visit = (task: MonitorTask, depth: number) => {\n out.push({ task, depth });\n for (const child of sort(children.get(task.id) ?? [])) visit(child, depth + 1);\n };\n for (const root of sort(roots)) visit(root, 0);\n return out;\n}\n\nfunction capped(rows: MonitorRow[]): MonitorRow[] {\n if (rows.length <= ROWS_MAX) return rows;\n const shown = rows.slice(0, ROWS_MAX - 1);\n return [\n ...shown,\n { id: 'more', name: `+${rows.length - shown.length} more`, meta: '', status: 'idle' },\n ];\n}\n\nfunction agentContext(agent: MonitorAgent, models: readonly ModelChoice[]): number | null {\n return contextRatio(agent.context, agent.model, models);\n}\n\nfunction rate(history: readonly Sample[], pick: (sample: Sample) => number): number | null {\n const first = history[0];\n const last = history.at(-1);\n if (!first || !last || last.at - first.at < MINUTE) return null;\n return ((pick(last) - pick(first)) / (last.at - first.at)) * HOUR;\n}\n\nconst RELATIVE = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });\n\nfunction resetsIn(at: number, now: number): string {\n const ms = at - now;\n if (ms <= 0) return 'resets soon';\n if (ms >= DAY)\n return `resets ${RELATIVE.format(Math.floor(at / DAY) - Math.floor(now / DAY), 'day')}`;\n if (ms >= HOUR) return `resets ${RELATIVE.format(Math.floor(ms / HOUR), 'hour')}`;\n return `resets ${RELATIVE.format(Math.ceil(ms / MINUTE), 'minute')}`;\n}\n\nfunction budgetVital(budget: BudgetState, now: number): MonitorVital {\n const resets = new Date(budget.resets);\n return {\n id: 'budget',\n provider: budget.provider,\n window: budget.window,\n label: `Budget (${budget.window})`,\n value: `${budget.percent}%`,\n ...(Number.isNaN(resets.getTime())\n ? {}\n : {\n unit: resetsIn(resets.getTime(), now),\n hint: `resets ${resets.toISOString().slice(0, 16).replace('T', ' ')} UTC`,\n }),\n ratio: Math.min(1, Math.max(0, budget.percent / 100)),\n };\n}\n\nfunction vitals(input: MonitorInput, feed: MonitorFeed): MonitorVital[] {\n const out: MonitorVital[] = [];\n if (feed.usage) {\n const free = feed.usage.free;\n const pick = (sample: Sample) => (free ? sample.tokens : sample.cost);\n const perHour = rate(input.history, pick);\n const series = input.history.map(pick);\n out.push({\n id: 'spend',\n label: free ? 'Tokens' : 'Spend',\n value: free ? count(feed.usage.tokens) : money(feed.usage.cost),\n unit: free ? 'tokens' : `${count(feed.usage.tokens)} tokens`,\n ...(perHour === null ? {} : { delta: `${free ? count(perHour) : money(perHour)}/h` }),\n ...trend(series),\n });\n }\n const active = feed.agents.filter((agent) => agent.running).length;\n out.push({\n id: 'agents',\n label: 'Active agents',\n value: String(active),\n unit: `of ${feed.agents.length}`,\n ...trend(input.history.map((sample) => sample.active)),\n });\n const tools = feed.tasks.filter(\n (task) => task.kind === 'pi.tool' && task.status === 'running'\n ).length;\n out.push({\n id: 'tasks',\n label: 'Running',\n value: String(tools),\n unit: `${tools === 1 ? 'tool' : 'tools'} \u00B7 ${feed.tasks.length} ${feed.tasks.length === 1 ? 'task' : 'tasks'}`,\n });\n out.push(\n feed.processes\n ? {\n id: 'processes',\n label: 'Processes',\n value: String(feed.processes.length),\n unit: `${feed.processes.filter((row) => row.agentId).length} by agents`,\n ...trend(input.processes),\n }\n : feed.kernel === 'checking'\n ? { id: 'processes', label: 'Processes', value: '\u2026', unit: 'checking' }\n : { id: 'processes', label: 'Processes', value: '\u2014', unit: 'kernel not reachable' }\n );\n out.push(...memoryVital(feed.processes ?? [], input.memory));\n out.push(...cpuVital(feed, input.cpu ?? []));\n const ratios = feed.agents\n .map((agent) => agentContext(agent, input.models))\n .filter((ratio): ratio is number => ratio !== null);\n if (ratios.length) {\n const fullest = Math.max(...ratios);\n out.push({\n id: 'context',\n label: 'Fullest context',\n value: `${Math.round(fullest * 100)}%`,\n ratio: fullest,\n });\n }\n return out;\n}\n\nfunction stale(process: MonitorProcess, agents: ReadonlyMap<string, MonitorAgent>, now: number) {\n if (!process.agentId || process.state === 'Z' || !process.started) return false;\n if (typeof process.utime === 'number') return false;\n if (agents.get(process.agentId)?.tool === 'bash') return false;\n return now - process.started > STALE_MS;\n}\n\nfunction zombied(process: MonitorProcess, now: number): boolean {\n return process.zombie !== null && now - process.zombie > ZOMBIE_MS;\n}\n\nfunction groups(processes: readonly MonitorProcess[]): Map<number, MonitorProcess[]> {\n const out = new Map<number, MonitorProcess[]>();\n for (const process of processes) {\n if (!process.agentId) continue;\n const list = out.get(process.pgid) ?? [];\n list.push(process);\n out.set(process.pgid, list);\n }\n return out;\n}\n\ntype Names = (id: string | null) => string;\n\nexport function groupCpu(\n processes: readonly MonitorProcess[]\n): Map<number, { agentId: string; share: number }> {\n const out = new Map<number, { agentId: string; share: number }>();\n for (const [pgid, members] of groups(processes)) {\n const measured = members.filter((row) => typeof row.cpu === 'number');\n if (!measured.length) continue;\n const share = measured.reduce((sum, row) => sum + (row.cpu as number), 0);\n out.set(pgid, { agentId: (members[0] as MonitorProcess).agentId as string, share });\n }\n return out;\n}\n\nexport function hotGroups(\n processes: readonly MonitorProcess[],\n at: number,\n previous: ReadonlyMap<number, number>\n): Map<number, number> {\n const out = new Map<number, number>();\n for (const [pgid, { share }] of groupCpu(processes))\n if (share >= CPU_SHARE) out.set(pgid, previous.get(pgid) ?? at);\n return out;\n}\n\nfunction busy(input: MonitorInput, processes: readonly MonitorProcess[]) {\n const shares = groupCpu(processes);\n const out: { pgid: number; agentId: string; share: number; held: number }[] = [];\n for (const [pgid, since] of input.hot ?? []) {\n const group = shares.get(pgid);\n const held = input.now - since;\n if (group && group.share >= CPU_SHARE && held >= CPU_SUSTAIN_MS)\n out.push({ pgid, ...group, held });\n }\n return out;\n}\n\nfunction cpuAlerts(input: MonitorInput, processes: readonly MonitorProcess[], nameOf: Names) {\n return busy(input, processes).map(\n (group): AgentMonitorAlert => ({\n id: `runaway-cpu-${group.pgid}`,\n title: `${nameOf(group.agentId)} is using a lot of CPU`,\n detail: `${Math.round(group.share * 100)}% of one core for ${Math.floor(group.held / MINUTE)} minutes.`,\n command: `kill -- -${group.pgid}`,\n commandLabel: 'To stop it, run',\n severity: cpuSeverity(group),\n })\n );\n}\n\nfunction cpuSeverity(group: { share: number; held: number }): 'warn' | 'error' {\n return group.share >= CPU_SHARE * 2 || group.held >= CPU_SUSTAIN_MS * 2 ? 'error' : 'warn';\n}\n\nfunction crowdSeverity(members: readonly MonitorProcess[]): 'warn' | 'error' {\n return members.length > GROUP_MAX * 2 ? 'error' : 'warn';\n}\n\nfunction staleSeverity(process: MonitorProcess, now: number): 'warn' | 'error' {\n return now - process.started > STALE_MS * 2 ? 'error' : 'warn';\n}\n\nfunction worse(\n a: 'warn' | 'error' | undefined,\n b: 'warn' | 'error' | undefined\n): 'warn' | 'error' | undefined {\n return a === 'error' || b === 'error' ? 'error' : (a ?? b);\n}\n\nfunction resetLine(budget: BudgetState): string {\n const resets = new Date(budget.resets);\n return Number.isNaN(resets.getTime())\n ? `The ${budget.window} budget is nearly used up.`\n : `Resets ${resets.toISOString().slice(0, 16).replace('T', ' ')} UTC.`;\n}\n\nfunction budgetAlerts(budget: BudgetState | null | undefined): AgentMonitorAlert[] {\n if (!budget || budget.percent < BUDGET_WARN) return [];\n return [\n {\n id: 'budget',\n title: `${budgetName(budget.provider)} budget ${budget.percent}% used`,\n detail: resetLine(budget),\n severity: budget.percent >= BUDGET_ERROR ? 'error' : 'warn',\n },\n ];\n}\n\nfunction agentAlerts(input: MonitorInput, feed: MonitorFeed): AgentMonitorAlert[] {\n const out: AgentMonitorAlert[] = [];\n for (const agent of feed.agents) {\n const retry = agent.retry;\n if (retry && (retry.attempt >= RETRY_WARN || input.now - retry.since > RETRY_SLOW_MS))\n out.push({\n id: `retry-${agent.id}`,\n title: `${agent.name} is retrying (attempt ${retry.attempt})`,\n detail: retry.error,\n severity: retry.attempt >= RETRY_ERROR ? 'error' : 'warn',\n });\n if (agent.failed && !agent.running)\n out.push({\n id: `turn-${agent.id}`,\n title: `${agent.name}'s last turn failed`,\n detail: agent.failed,\n severity: 'error',\n });\n }\n return out;\n}\n\nfunction taskAlerts(input: MonitorInput, feed: MonitorFeed, nameOf: Names): AgentMonitorAlert[] {\n const out: AgentMonitorAlert[] = [];\n for (const problem of feed.problems)\n if (problem.kind === 'task' && input.now - problem.at < FAILED_MS)\n out.push({\n id: `failed-${problem.id}`,\n title: `A task of ${nameOf(problem.agentId)} failed`,\n detail: problem.message,\n severity: 'error',\n });\n else if (\n problem.kind === 'report' &&\n SERIOUS.has(problem.report?.type ?? '') &&\n input.now - problem.at < FAILED_MS\n )\n out.push({\n id: `reported-${problem.id}`,\n title: `${nameOf(problem.agentId)}: ${problemName(problem)}`,\n detail: problem.message,\n severity: 'error',\n });\n for (const task of feed.tasks)\n if (task.blocked === 'restart_limit')\n out.push({\n id: `parked-${task.id}`,\n title: `${taskLabel(task)} of ${nameOf(task.agentId)} is parked`,\n detail:\n 'It was cut off by 5 restarts in a row without getting further, so it no longer starts by itself.',\n severity: 'error',\n command: `agent retry ${task.id}`,\n commandLabel: 'To run it again, run',\n });\n for (const task of feed.tasks)\n if (task.aborting !== null && input.now - task.aborting > ABORT_MS)\n out.push({\n id: `abort-${task.id}`,\n title: `Stop is still waiting for ${taskLabel(task)}`,\n detail: `${nameOf(task.agentId)} asked it to stop ${age(input.now - task.aborting)} ago.`,\n severity: 'warn',\n });\n return out;\n}\n\nfunction crowdAlerts(processes: readonly MonitorProcess[], nameOf: Names): AgentMonitorAlert[] {\n const out: AgentMonitorAlert[] = [];\n for (const [pgid, members] of groups(processes))\n if (members.length > GROUP_MAX)\n out.push({\n id: `runaway-${pgid}`,\n title: `${nameOf((members[0] as MonitorProcess).agentId)} has ${members.length} processes`,\n detail: 'Something in it may be starting processes in a loop.',\n command: `kill -- -${pgid}`,\n commandLabel: 'To stop them, run',\n severity: crowdSeverity(members),\n });\n if (processes.length > TOTAL_MAX)\n out.push({\n id: 'runaway-total',\n title: `The kernel has ${processes.length} processes`,\n detail: 'Something may be starting processes in a loop.',\n severity: processes.length > TOTAL_MAX * 2 ? 'error' : 'warn',\n });\n return out;\n}\n\nfunction processAlerts(input: MonitorInput, feed: MonitorFeed, nameOf: Names): AgentMonitorAlert[] {\n const processes = feed.processes ?? [];\n const agents = new Map(feed.agents.map((agent) => [agent.id, agent]));\n const out = [...crowdAlerts(processes, nameOf), ...cpuAlerts(input, processes, nameOf)];\n for (const process of processes) {\n if (zombied(process, input.now))\n out.push({\n id: `zombie-${process.pid}`,\n title: `Process ${process.pid} is a zombie`,\n detail: `Its parent ${process.ppid} hasn't reaped it.`,\n ...(process.ppid > 1\n ? { command: `kill ${process.ppid}`, commandLabel: 'To clear it, stop the parent' }\n : {}),\n severity: 'warn',\n });\n if (stale(process, agents, input.now))\n out.push({\n id: `stale-${process.pid}`,\n title: `${process.command || `Process ${process.pid}`} has run for ${age(input.now - process.started)}`,\n detail: `${nameOf(process.agentId)} started it in the background.`,\n command: `kill ${process.pid}`,\n commandLabel: 'To stop it, run',\n severity: staleSeverity(process, input.now),\n });\n }\n return out;\n}\n\nfunction contextAlerts(input: MonitorInput, feed: MonitorFeed): AgentMonitorAlert[] {\n const out: AgentMonitorAlert[] = [];\n for (const agent of feed.agents) {\n const ratio = agentContext(agent, input.models);\n if (ratio !== null && ratio >= CONTEXT_WARN)\n out.push({\n id: `context-${agent.id}`,\n title: `${agent.name} is ${Math.round(ratio * 100)}% full`,\n detail: 'Compact it soon to keep replies fast.',\n severity: 'warn',\n });\n }\n if (feed.paused)\n out.push({\n id: 'scheduler',\n title: \"The agent isn't scheduling work\",\n detail: 'Its scheduler is paused.',\n severity: 'warn',\n });\n return out;\n}\n\nfunction alerts(input: MonitorInput, feed: MonitorFeed): AgentMonitorAlert[] {\n const agents = new Map(feed.agents.map((agent) => [agent.id, agent]));\n const nameOf: Names = (id) => (id ? (agents.get(id)?.name ?? id) : 'the session');\n return [\n ...budgetAlerts(input.budget),\n ...agentAlerts(input, feed),\n ...taskAlerts(input, feed, nameOf),\n ...processAlerts(input, feed, nameOf),\n ...contextAlerts(input, feed),\n ];\n}\n\nconst BLOCKED: Record<NonNullable<MonitorTask['blocked']>, string> = {\n missing_task: 'blocked: no definition',\n task_too_old: 'blocked: definition too old',\n migration_failed: 'blocked: migration failed',\n restart_limit: 'blocked: restart limit',\n};\n\nfunction taskRow(\n task: MonitorTask,\n depth: number,\n nameOf: (id: string | null) => string,\n now: number\n): MonitorRow {\n const aborting = task.aborting !== null && now - task.aborting > ABORT_ROW_MS;\n const status: MonitorStatus =\n aborting || task.blocked\n ? 'warn'\n : task.status === 'running' || task.status === 'completing'\n ? 'active'\n : 'idle';\n const badges = [\n ...(task.background ? ['background'] : []),\n ...(task.aborting !== null ? ['aborting'] : []),\n ...(task.waits ? [`waits on ${task.waits}`] : []),\n ...(typeof task.until === 'number' ? [`sleeps ${age(task.until - now)}`] : []),\n ...(task.blocked ? [BLOCKED[task.blocked]] : []),\n ];\n return {\n id: task.id,\n name: taskLabel(task),\n depth: Math.min(depth, DEPTH_MAX),\n meta: [nameOf(task.agentId), task.phase, age(now - task.since)].filter(Boolean).join(' \u00B7 '),\n status,\n ...(badges.length ? { badges } : {}),\n };\n}\n\nfunction drivers(members: readonly MonitorProcess[]): MonitorProcess[] {\n const hot = members.filter((row) => (row.cpu ?? 0) >= CPU_SHARE);\n if (hot.length) return hot;\n const top = members.reduce((best, row) => ((row.cpu ?? 0) > (best.cpu ?? 0) ? row : best));\n return [top];\n}\n\nfunction processRows(input: MonitorInput, feed: MonitorFeed): MonitorRow[] {\n const agents = new Map(feed.agents.map((agent) => [agent.id, agent]));\n const members = groups(feed.processes ?? []);\n const flagged = new Map<number, 'warn' | 'error'>();\n for (const group of busy(input, feed.processes ?? []))\n for (const row of drivers(members.get(group.pgid) as MonitorProcess[]))\n flagged.set(row.pid, cpuSeverity(group));\n return (feed.processes ?? []).map((process) => {\n const runaway = worse(\n worse(\n flagged.get(process.pid),\n stale(process, agents, input.now) ? staleSeverity(process, input.now) : undefined\n ),\n zombied(process, input.now) ? 'warn' : undefined\n );\n const badges = [\n ...(process.agentId ? [agents.get(process.agentId)?.name ?? process.agentId] : []),\n ...(process.tty ? ['terminal'] : []),\n ];\n return {\n id: String(process.pid),\n name: process.command || `[${process.pid}]`,\n meta: [\n `pid ${process.pid}`,\n process.user,\n typeof process.rss === 'number' ? bytes(process.rss) : null,\n cpuText(process.cpu),\n process.started ? age(input.now - process.started) : null,\n ]\n .filter(Boolean)\n .join(' \u00B7 '),\n status: runaway ?? 'idle',\n ...(badges.length ? { badges } : {}),\n };\n });\n}\n\nconst PROBLEM_KINDS = {\n task: 'task failed',\n retry: 'retry',\n turn: 'turn failed',\n report: 'problem',\n} as const;\n\nconst REPORTED: Record<string, string> = {\n session_failed: 'session failed',\n task_faulted: 'task failed',\n task_parked: 'task parked',\n migration_failed: 'migration failed',\n task_outdated: 'task outdated',\n task_error: 'task error',\n extension_error: 'extension error',\n host_error: 'host error',\n listener_error: 'listener error',\n};\n\nconst SERIOUS = new Set(['session_failed', 'task_faulted', 'task_parked', 'migration_failed']);\n\nfunction problemName(problem: MonitorProblem): string {\n const report = problem.report;\n if (!report) return PROBLEM_KINDS[problem.kind];\n const label = REPORTED[report.type] ?? PROBLEM_KINDS[problem.kind];\n return report.source ? `${label} (${report.source})` : label;\n}\n\nfunction problemStatus(problem: MonitorProblem): MonitorStatus {\n if (problem.kind === 'retry') return 'warn';\n if (problem.kind === 'report' && !SERIOUS.has(problem.report?.type ?? '')) return 'warn';\n return 'error';\n}\n\nfunction sections(input: MonitorInput, feed: MonitorFeed): MonitorSection[] {\n const agents = new Map(feed.agents.map((agent) => [agent.id, agent]));\n const nameOf = (id: string | null) => (id ? (agents.get(id)?.name ?? id) : 'session');\n return [\n {\n id: 'tasks',\n label: 'Tasks',\n rows: capped(\n taskTree(feed).map(({ task, depth }) => taskRow(task, depth, nameOf, input.now))\n ),\n },\n { id: 'processes', label: 'Processes', rows: capped(processRows(input, feed)) },\n {\n id: 'problems',\n label: 'Recent problems',\n rows: feed.problems.map((problem) => ({\n id: problem.id,\n name: `${nameOf(problem.agentId)} \u00B7 ${problemName(problem)}`,\n meta: problem.message,\n status: problemStatus(problem),\n })),\n },\n ];\n}\n\nfunction pageSections(input: MonitorInput): MonitorSection[] {\n return [\n {\n id: 'changes',\n label: 'Pending changes',\n rows: input.changes.map((change) => ({\n id: change.path,\n name: change.path,\n meta: change.status,\n status: 'warn',\n })),\n },\n ...input.extra,\n ];\n}\n\nexport function monitorSnapshot(input: MonitorInput): MonitorSnapshot {\n const budget = input.budget ? [budgetVital(input.budget, input.now)] : [];\n const feed = input.feed;\n if (!feed?.at)\n return {\n vitals: budget,\n alerts: [],\n sections: pageSections(input),\n updatedAt: input.now,\n };\n return {\n vitals: [...budget, ...vitals(input, feed)],\n alerts: alerts(input, feed),\n sections: [...sections(input, feed), ...pageSections(input)],\n updatedAt: feed.at,\n };\n}\n\nexport interface Intervals {\n every(run: () => void, ms: number): unknown;\n stop(handle: unknown): void;\n}\n\nexport const globalIntervals: Intervals = {\n every: (run, ms) => setInterval(run, ms),\n stop: (handle) => clearInterval(handle as ReturnType<typeof setInterval>),\n};\n\nexport interface MonitorAdapterOptions {\n extra?: () => readonly MonitorSection[];\n renewMs?: number;\n sampleMs?: number;\n intervals?: Intervals;\n now?: () => number;\n selected?: Selected;\n}\n\ninterface Open {\n lease: Promise<string | null>;\n timer: unknown;\n sampler: unknown;\n}\n\nexport class MonitorAdapter implements MonitorPort {\n readonly #connection: AgentConnection;\n readonly #emitter = new Emitter<MonitorEvents>();\n readonly #extra: () => readonly MonitorSection[];\n readonly #renewMs: number;\n readonly #sampleMs: number;\n readonly #intervals: Intervals;\n readonly #now: () => number;\n readonly #selected: Selected | undefined;\n #listeners = 0;\n #open: Open | undefined;\n #history: Sample[] = [];\n #hot = new Map<number, number>();\n #hotAt = -1;\n #cpu: number[] = [];\n #processes: number[] = [];\n #memory: number[] = [];\n\n constructor(connection: AgentConnection, options: MonitorAdapterOptions = {}) {\n this.#connection = connection;\n this.#extra = options.extra ?? (() => []);\n this.#renewMs = options.renewMs ?? RENEW_MS;\n this.#sampleMs = options.sampleMs ?? SAMPLE_MS;\n this.#intervals = options.intervals ?? globalIntervals;\n this.#now = options.now ?? Date.now;\n this.#selected = options.selected;\n let provider = options.selected?.provider();\n options.selected?.onChange(() => {\n const next = options.selected?.provider();\n if (next === provider) return;\n provider = next;\n if (this.#listeners) this.#emitter.emit('snapshot', this.snapshot());\n });\n connection.monitor?.subscribe(() => this.#update());\n connection.settings.state.subscribe(() => this.#update());\n connection.changes?.subscribe(() => this.#update());\n }\n\n on<K extends keyof MonitorEvents>(\n type: K,\n listener: (detail: MonitorEvents[K]) => void\n ): () => void {\n const off = this.#emitter.on(type, listener);\n this.#listeners++;\n if (this.#listeners === 1) this.#start();\n let done = false;\n return () => {\n if (done) return;\n done = true;\n off();\n this.#listeners--;\n if (!this.#listeners) this.#stop();\n };\n }\n\n snapshot(): MonitorSnapshot {\n const settings = this.#connection.settings.state.value;\n return monitorSnapshot({\n feed: this.#connection.monitor?.value,\n budget: selectedBudget(settings, this.#selected?.provider()),\n models: settings?.models ?? [],\n changes: this.#connection.changes?.value?.changes ?? [],\n extra: this.#extra(),\n history: this.#history,\n now: this.#now(),\n hot: this.#hot,\n cpu: this.#cpu,\n processes: this.#processes,\n memory: this.#memory,\n });\n }\n\n resync(): void {\n const open = this.#open;\n const control = this.#connection.control;\n if (open)\n void open.lease\n .then((lease) => (lease ? control.monitorOpen(lease, true, BACKGROUND_CONTEXT) : undefined))\n .catch(() => undefined);\n this.#emitter.emit('snapshot', this.snapshot());\n }\n\n #start(): void {\n const control = this.#connection.control;\n this.#history = [];\n this.#hot = new Map();\n this.#hotAt = -1;\n this.#cpu = [];\n this.#processes = [];\n this.#memory = [];\n void control.changesOpen(BACKGROUND_CONTEXT).catch(() => undefined);\n const lease = control.monitorOpen(null, true, BACKGROUND_CONTEXT).then(\n (opened) => opened.lease || null,\n () => null\n );\n const renew = () =>\n void lease\n .then((held) => (held ? control.monitorOpen(held, false, BACKGROUND_CONTEXT) : undefined))\n .catch(() => undefined);\n this.#open = {\n lease,\n timer: this.#intervals.every(renew, this.#renewMs),\n sampler: this.#intervals.every(() => this.#poll(), this.#sampleMs),\n };\n }\n\n #stop(): void {\n const open = this.#open;\n if (!open) return;\n this.#open = undefined;\n this.#intervals.stop(open.timer);\n this.#intervals.stop(open.sampler);\n const control = this.#connection.control;\n void open.lease\n .then((held) => (held ? control.monitorClose(held, BACKGROUND_CONTEXT) : undefined))\n .catch(() => undefined);\n }\n\n #sample(): void {\n const feed = this.#connection.monitor?.value;\n if (!feed?.open || !feed.usage || this.#history.at(-1)?.at === feed.at) return;\n record(\n this.#history,\n {\n at: feed.at,\n cost: feed.usage.cost,\n tokens: feed.usage.tokens,\n active: feed.agents.filter((agent) => agent.running).length,\n },\n HISTORY\n );\n }\n\n #track(): void {\n const feed = this.#connection.monitor?.value;\n if (!feed?.open || feed.at === this.#hotAt) return;\n this.#hotAt = feed.at;\n this.#hot = hotGroups(feed.processes ?? [], feed.at, this.#hot);\n const share = agentsCpu(feed);\n if (share !== null) record(this.#cpu, share, CPU_HISTORY);\n }\n\n #poll(): void {\n const feed = this.#connection.monitor?.value;\n if (!feed?.open || !feed.processes) return;\n record(this.#processes, feed.processes.length, CPU_HISTORY);\n const memory = memoryTotal(feed.processes);\n if (memory !== null) record(this.#memory, memory, CPU_HISTORY);\n this.#emitter.emit('snapshot', this.snapshot());\n }\n\n #update(): void {\n if (!this.#listeners) return;\n this.#sample();\n this.#track();\n this.#emitter.emit('snapshot', this.snapshot());\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type {\n MonitorAlert,\n MonitorEvents,\n MonitorPort,\n MonitorRow,\n MonitorSection,\n MonitorSnapshot,\n MonitorStatus,\n MonitorVital,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { AgentConnection } from '../client.ts';\nimport { contextRatio } from '../context.ts';\nimport type {\n BudgetState,\n ModelChoice,\n MonitorAgent,\n MonitorFeed,\n MonitorProblem,\n MonitorProcess,\n MonitorTask,\n} from '../services.ts';\nimport { budgetName, type Selected, selectedBudget } from './budget.ts';\nimport { Emitter } from './emitter.ts';\n\nexport const RENEW_MS = 10000;\nexport const SAMPLE_MS = 2000;\nexport const ROWS_MAX = 200;\nexport const HISTORY = 24;\nexport const CPU_HISTORY = 30;\nexport const CPU_QUIET = 0.01;\nexport const BUDGET_WARN = 80;\nexport const BUDGET_ERROR = 95;\nexport const RETRY_WARN = 3;\nexport const RETRY_ERROR = 6;\nexport const RETRY_SLOW_MS = 120000;\nexport const FAILED_MS = 600000;\nexport const ABORT_MS = 30000;\nexport const ABORT_ROW_MS = 10000;\nexport const GROUP_MAX = 32;\nexport const TOTAL_MAX = 128;\nexport const ZOMBIE_MS = 60000;\nexport const STALE_MS = 1800000;\nexport const CPU_SHARE = 0.9;\nexport const CPU_SUSTAIN_MS = 120000;\nexport const CONTEXT_WARN = 0.8;\nexport const DEPTH_MAX = 6;\nconst MINUTE = 60000;\nconst HOUR = 3600000;\nconst DAY = 86400000;\n\nexport type AgentMonitorAlert = MonitorAlert & { command?: string; commandLabel?: string };\n\nexport interface Sample {\n at: number;\n cost: number;\n tokens: number;\n active: number;\n}\n\nexport interface MonitorInput {\n feed: MonitorFeed | undefined;\n budget: BudgetState | null | undefined;\n models: readonly ModelChoice[];\n changes: readonly { path: string; status: string }[];\n sprinkles?: readonly { name: string; title: string }[];\n extra: readonly MonitorSection[];\n history: readonly Sample[];\n now: number;\n hot?: ReadonlyMap<number, number>;\n cpu?: readonly number[];\n processes?: readonly number[];\n memory?: readonly number[];\n}\n\nexport function record<T>(list: T[], value: T, max: number): void {\n list.push(value);\n if (list.length > max) list.shift();\n}\n\nfunction trend(series: readonly number[] | undefined): { series?: number[] } {\n return series && series.length > 1 ? { series: [...series] } : {};\n}\n\nconst KINDS: Record<string, string> = {\n 'pi.generation': 'generating',\n 'pi.compaction': 'compacting',\n 'slicc.scoop-wait': 'agent wait',\n 'slicc.scoop-reporter': 'report',\n 'slicc.memory-extract': 'memory extraction',\n 'slicc.memory-idle': 'memory idle watch',\n};\n\nexport function age(ms: number): string {\n const seconds = Math.max(0, Math.round(ms / 1000));\n if (seconds < 60) return `${seconds}s`;\n if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;\n return `${Math.floor(seconds / 3600)}h`;\n}\n\nexport function money(value: number): string {\n if (value > 0 && value < 0.01) return '<$0.01';\n return `$${value.toFixed(2)}`;\n}\n\nexport function count(value: number): string {\n if (value < 1000) return String(value);\n if (value < 1000000) return `${(value / 1000).toFixed(1)}k`;\n return `${(value / 1000000).toFixed(1)}M`;\n}\n\nexport function bytes(value: number): string {\n if (value < 1024) return `${value} B`;\n const units = ['KiB', 'MiB', 'GiB', 'TiB'];\n let size = value / 1024;\n let unit = 0;\n while (size >= 1024 && unit < units.length - 1) {\n size /= 1024;\n unit++;\n }\n return `${size.toFixed(size < 10 ? 1 : 0)} ${units[unit]}`;\n}\n\nexport function cpuText(share: number | null | undefined): string | null {\n if (typeof share !== 'number' || share < CPU_QUIET) return null;\n return `${Math.round(share * 100)}%\\u00a0CPU`;\n}\n\nexport function agentsCpu(feed: MonitorFeed): number | null {\n const shares = feed.agents\n .map((agent) => agent.cpu)\n .filter((share): share is number => typeof share === 'number');\n return shares.length ? shares.reduce((sum, share) => sum + share, 0) : null;\n}\n\nfunction cpuVital(feed: MonitorFeed, history: readonly number[]): MonitorVital[] {\n const share = agentsCpu(feed);\n if (share === null) return [];\n return [\n {\n id: 'cpu',\n label: 'CPU',\n value: `${Math.round(share * 100)}%`,\n unit: 'of one core',\n ...trend(history.map((value) => Math.round(value * 100))),\n },\n ];\n}\n\nfunction measuredOf(processes: readonly MonitorProcess[]): MonitorProcess[] {\n return processes.filter((row) => typeof row.rss === 'number');\n}\n\nexport function memoryTotal(processes: readonly MonitorProcess[]): number | null {\n const measured = measuredOf(processes);\n return measured.length ? measured.reduce((sum, row) => sum + (row.rss as number), 0) : null;\n}\n\nfunction memoryVital(\n processes: readonly MonitorProcess[],\n history: readonly number[] | undefined\n): MonitorVital[] {\n const total = memoryTotal(processes);\n if (total === null) return [];\n const measured = measuredOf(processes);\n const agents = measured\n .filter((row) => row.agentId)\n .reduce((sum, row) => sum + (row.rss as number), 0);\n return [\n {\n id: 'memory',\n label: 'Process memory',\n value: bytes(total),\n unit: `${bytes(agents)} by agents`,\n ...trend(history),\n },\n ];\n}\n\nexport function taskLabel(task: MonitorTask): string {\n if (task.kind === 'pi.tool') return task.detail ? `tool ${task.detail}` : 'tool';\n if (task.kind === 'slicc.scoop-anchor') return task.detail ? `scoop ${task.detail}` : 'scoop';\n return KINDS[task.kind] ?? task.kind;\n}\n\nfunction coneOf(agents: ReadonlyMap<string, MonitorAgent>, id: string | null): string | null {\n const visited = new Set<string>();\n let current = id === null ? undefined : agents.get(id);\n while (current?.parentId && !visited.has(current.id)) {\n visited.add(current.id);\n const parent = agents.get(current.parentId);\n if (!parent) break;\n current = parent;\n }\n return current ? current.id : null;\n}\n\nfunction ordered(feed: MonitorFeed): MonitorAgent[] {\n const byId = new Map(feed.agents.map((agent) => [agent.id, agent]));\n const out: MonitorAgent[] = [];\n for (const cone of feed.agents.filter((agent) => agent.kind === 'cone')) {\n out.push(cone);\n for (const agent of feed.agents)\n if (agent.kind === 'scoop' && coneOf(byId, agent.id) === cone.id) out.push(agent);\n }\n for (const agent of feed.agents) if (!out.includes(agent)) out.push(agent);\n return out;\n}\n\nexport function taskTree(feed: MonitorFeed): { task: MonitorTask; depth: number }[] {\n const agents = new Map(feed.agents.map((agent) => [agent.id, agent]));\n const order = ordered(feed).map((agent) => agent.id);\n const rank = (task: MonitorTask) => {\n const at = task.agentId === null ? -1 : order.indexOf(task.agentId);\n return at < 0 ? order.length : at;\n };\n const groupOf = (task: MonitorTask) => coneOf(agents, task.agentId) ?? '';\n const byId = new Map(feed.tasks.map((task) => [task.id, task]));\n const children = new Map<string, MonitorTask[]>();\n const roots: MonitorTask[] = [];\n for (const task of feed.tasks) {\n const owner = task.owner === null ? undefined : byId.get(task.owner);\n if (owner && groupOf(owner) === groupOf(task)) {\n const list = children.get(owner.id) ?? [];\n list.push(task);\n children.set(owner.id, list);\n } else roots.push(task);\n }\n const sort = (list: MonitorTask[]) =>\n list.sort((a, b) => rank(a) - rank(b) || Number(a.id) - Number(b.id));\n const out: { task: MonitorTask; depth: number }[] = [];\n const visit = (task: MonitorTask, depth: number) => {\n out.push({ task, depth });\n for (const child of sort(children.get(task.id) ?? [])) visit(child, depth + 1);\n };\n for (const root of sort(roots)) visit(root, 0);\n return out;\n}\n\nfunction capped(rows: MonitorRow[]): MonitorRow[] {\n if (rows.length <= ROWS_MAX) return rows;\n const shown = rows.slice(0, ROWS_MAX - 1);\n return [\n ...shown,\n { id: 'more', name: `+${rows.length - shown.length} more`, meta: '', status: 'idle' },\n ];\n}\n\nfunction agentContext(agent: MonitorAgent, models: readonly ModelChoice[]): number | null {\n return contextRatio(agent.context, agent.model, models);\n}\n\nfunction rate(history: readonly Sample[], pick: (sample: Sample) => number): number | null {\n const first = history[0];\n const last = history.at(-1);\n if (!first || !last || last.at - first.at < MINUTE) return null;\n return ((pick(last) - pick(first)) / (last.at - first.at)) * HOUR;\n}\n\nconst RELATIVE = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });\n\nfunction resetsIn(at: number, now: number): string {\n const ms = at - now;\n if (ms <= 0) return 'resets soon';\n if (ms >= DAY)\n return `resets ${RELATIVE.format(Math.floor(at / DAY) - Math.floor(now / DAY), 'day')}`;\n if (ms >= HOUR) return `resets ${RELATIVE.format(Math.floor(ms / HOUR), 'hour')}`;\n return `resets ${RELATIVE.format(Math.ceil(ms / MINUTE), 'minute')}`;\n}\n\nfunction budgetVital(budget: BudgetState, now: number): MonitorVital {\n const resets = new Date(budget.resets);\n return {\n id: 'budget',\n provider: budget.provider,\n window: budget.window,\n label: `Budget (${budget.window})`,\n value: `${budget.percent}%`,\n ...(Number.isNaN(resets.getTime())\n ? {}\n : {\n unit: resetsIn(resets.getTime(), now),\n hint: `resets ${resets.toISOString().slice(0, 16).replace('T', ' ')} UTC`,\n }),\n ratio: Math.min(1, Math.max(0, budget.percent / 100)),\n };\n}\n\nfunction vitals(input: MonitorInput, feed: MonitorFeed): MonitorVital[] {\n const out: MonitorVital[] = [];\n if (feed.usage) {\n const free = feed.usage.free;\n const pick = (sample: Sample) => (free ? sample.tokens : sample.cost);\n const perHour = rate(input.history, pick);\n const series = input.history.map(pick);\n out.push({\n id: 'spend',\n label: free ? 'Tokens' : 'Spend',\n value: free ? count(feed.usage.tokens) : money(feed.usage.cost),\n unit: free ? 'tokens' : `${count(feed.usage.tokens)} tokens`,\n ...(perHour === null ? {} : { delta: `${free ? count(perHour) : money(perHour)}/h` }),\n ...trend(series),\n });\n }\n const active = feed.agents.filter((agent) => agent.running).length;\n out.push({\n id: 'agents',\n label: 'Active agents',\n value: String(active),\n unit: `of ${feed.agents.length}`,\n ...trend(input.history.map((sample) => sample.active)),\n });\n const tools = feed.tasks.filter(\n (task) => task.kind === 'pi.tool' && task.status === 'running'\n ).length;\n out.push({\n id: 'tasks',\n label: 'Running',\n value: String(tools),\n unit: `${tools === 1 ? 'tool' : 'tools'} \u00B7 ${feed.tasks.length} ${feed.tasks.length === 1 ? 'task' : 'tasks'}`,\n });\n out.push(\n feed.processes\n ? {\n id: 'processes',\n label: 'Processes',\n value: String(feed.processes.length),\n unit: `${feed.processes.filter((row) => row.agentId).length} by agents`,\n ...trend(input.processes),\n }\n : feed.kernel === 'checking'\n ? { id: 'processes', label: 'Processes', value: '\u2026', unit: 'checking' }\n : { id: 'processes', label: 'Processes', value: '\u2014', unit: 'kernel not reachable' }\n );\n out.push(...memoryVital(feed.processes ?? [], input.memory));\n out.push(...cpuVital(feed, input.cpu ?? []));\n const ratios = feed.agents\n .map((agent) => agentContext(agent, input.models))\n .filter((ratio): ratio is number => ratio !== null);\n if (ratios.length) {\n const fullest = Math.max(...ratios);\n out.push({\n id: 'context',\n label: 'Fullest context',\n value: `${Math.round(fullest * 100)}%`,\n ratio: fullest,\n });\n }\n return out;\n}\n\nfunction stale(process: MonitorProcess, agents: ReadonlyMap<string, MonitorAgent>, now: number) {\n if (!process.agentId || process.state === 'Z' || !process.started) return false;\n if (typeof process.utime === 'number') return false;\n if (agents.get(process.agentId)?.tool === 'bash') return false;\n return now - process.started > STALE_MS;\n}\n\nfunction zombied(process: MonitorProcess, now: number): boolean {\n return process.zombie !== null && now - process.zombie > ZOMBIE_MS;\n}\n\nfunction groups(processes: readonly MonitorProcess[]): Map<number, MonitorProcess[]> {\n const out = new Map<number, MonitorProcess[]>();\n for (const process of processes) {\n if (!process.agentId) continue;\n const list = out.get(process.pgid) ?? [];\n list.push(process);\n out.set(process.pgid, list);\n }\n return out;\n}\n\ntype Names = (id: string | null) => string;\n\nexport function groupCpu(\n processes: readonly MonitorProcess[]\n): Map<number, { agentId: string; share: number }> {\n const out = new Map<number, { agentId: string; share: number }>();\n for (const [pgid, members] of groups(processes)) {\n const measured = members.filter((row) => typeof row.cpu === 'number');\n if (!measured.length) continue;\n const share = measured.reduce((sum, row) => sum + (row.cpu as number), 0);\n out.set(pgid, { agentId: (members[0] as MonitorProcess).agentId as string, share });\n }\n return out;\n}\n\nexport function hotGroups(\n processes: readonly MonitorProcess[],\n at: number,\n previous: ReadonlyMap<number, number>\n): Map<number, number> {\n const out = new Map<number, number>();\n for (const [pgid, { share }] of groupCpu(processes))\n if (share >= CPU_SHARE) out.set(pgid, previous.get(pgid) ?? at);\n return out;\n}\n\nfunction busy(input: MonitorInput, processes: readonly MonitorProcess[]) {\n const shares = groupCpu(processes);\n const out: { pgid: number; agentId: string; share: number; held: number }[] = [];\n for (const [pgid, since] of input.hot ?? []) {\n const group = shares.get(pgid);\n const held = input.now - since;\n if (group && group.share >= CPU_SHARE && held >= CPU_SUSTAIN_MS)\n out.push({ pgid, ...group, held });\n }\n return out;\n}\n\nfunction cpuAlerts(input: MonitorInput, processes: readonly MonitorProcess[], nameOf: Names) {\n return busy(input, processes).map(\n (group): AgentMonitorAlert => ({\n id: `runaway-cpu-${group.pgid}`,\n title: `${nameOf(group.agentId)} is using a lot of CPU`,\n detail: `${Math.round(group.share * 100)}% of one core for ${Math.floor(group.held / MINUTE)} minutes.`,\n command: `kill -- -${group.pgid}`,\n commandLabel: 'To stop it, run',\n severity: cpuSeverity(group),\n })\n );\n}\n\nfunction cpuSeverity(group: { share: number; held: number }): 'warn' | 'error' {\n return group.share >= CPU_SHARE * 2 || group.held >= CPU_SUSTAIN_MS * 2 ? 'error' : 'warn';\n}\n\nfunction crowdSeverity(members: readonly MonitorProcess[]): 'warn' | 'error' {\n return members.length > GROUP_MAX * 2 ? 'error' : 'warn';\n}\n\nfunction staleSeverity(process: MonitorProcess, now: number): 'warn' | 'error' {\n return now - process.started > STALE_MS * 2 ? 'error' : 'warn';\n}\n\nfunction worse(\n a: 'warn' | 'error' | undefined,\n b: 'warn' | 'error' | undefined\n): 'warn' | 'error' | undefined {\n return a === 'error' || b === 'error' ? 'error' : (a ?? b);\n}\n\nfunction resetLine(budget: BudgetState): string {\n const resets = new Date(budget.resets);\n return Number.isNaN(resets.getTime())\n ? `The ${budget.window} budget is nearly used up.`\n : `Resets ${resets.toISOString().slice(0, 16).replace('T', ' ')} UTC.`;\n}\n\nfunction budgetAlerts(budget: BudgetState | null | undefined): AgentMonitorAlert[] {\n if (!budget || budget.percent < BUDGET_WARN) return [];\n return [\n {\n id: 'budget',\n title: `${budgetName(budget.provider)} budget ${budget.percent}% used`,\n detail: resetLine(budget),\n severity: budget.percent >= BUDGET_ERROR ? 'error' : 'warn',\n },\n ];\n}\n\nfunction agentAlerts(input: MonitorInput, feed: MonitorFeed): AgentMonitorAlert[] {\n const out: AgentMonitorAlert[] = [];\n for (const agent of feed.agents) {\n const retry = agent.retry;\n if (retry && (retry.attempt >= RETRY_WARN || input.now - retry.since > RETRY_SLOW_MS))\n out.push({\n id: `retry-${agent.id}`,\n title: `${agent.name} is retrying (attempt ${retry.attempt})`,\n detail: retry.error,\n severity: retry.attempt >= RETRY_ERROR ? 'error' : 'warn',\n });\n if (agent.failed && !agent.running)\n out.push({\n id: `turn-${agent.id}`,\n title: `${agent.name}'s last turn failed`,\n detail: agent.failed,\n severity: 'error',\n });\n }\n return out;\n}\n\nfunction taskAlerts(input: MonitorInput, feed: MonitorFeed, nameOf: Names): AgentMonitorAlert[] {\n const out: AgentMonitorAlert[] = [];\n for (const problem of feed.problems)\n if (problem.kind === 'task' && input.now - problem.at < FAILED_MS)\n out.push({\n id: `failed-${problem.id}`,\n title: `A task of ${nameOf(problem.agentId)} failed`,\n detail: problem.message,\n severity: 'error',\n });\n else if (\n problem.kind === 'report' &&\n SERIOUS.has(problem.report?.type ?? '') &&\n input.now - problem.at < FAILED_MS\n )\n out.push({\n id: `reported-${problem.id}`,\n title: `${nameOf(problem.agentId)}: ${problemName(problem)}`,\n detail: problem.message,\n severity: 'error',\n });\n for (const task of feed.tasks)\n if (task.blocked === 'restart_limit')\n out.push({\n id: `parked-${task.id}`,\n title: `${taskLabel(task)} of ${nameOf(task.agentId)} is parked`,\n detail:\n 'It was cut off by 5 restarts in a row without getting further, so it no longer starts by itself.',\n severity: 'error',\n command: `agent retry ${task.id}`,\n commandLabel: 'To run it again, run',\n });\n for (const task of feed.tasks)\n if (task.aborting !== null && input.now - task.aborting > ABORT_MS)\n out.push({\n id: `abort-${task.id}`,\n title: `Stop is still waiting for ${taskLabel(task)}`,\n detail: `${nameOf(task.agentId)} asked it to stop ${age(input.now - task.aborting)} ago.`,\n severity: 'warn',\n });\n return out;\n}\n\nfunction crowdAlerts(processes: readonly MonitorProcess[], nameOf: Names): AgentMonitorAlert[] {\n const out: AgentMonitorAlert[] = [];\n for (const [pgid, members] of groups(processes))\n if (members.length > GROUP_MAX)\n out.push({\n id: `runaway-${pgid}`,\n title: `${nameOf((members[0] as MonitorProcess).agentId)} has ${members.length} processes`,\n detail: 'Something in it may be starting processes in a loop.',\n command: `kill -- -${pgid}`,\n commandLabel: 'To stop them, run',\n severity: crowdSeverity(members),\n });\n if (processes.length > TOTAL_MAX)\n out.push({\n id: 'runaway-total',\n title: `The kernel has ${processes.length} processes`,\n detail: 'Something may be starting processes in a loop.',\n severity: processes.length > TOTAL_MAX * 2 ? 'error' : 'warn',\n });\n return out;\n}\n\nfunction processAlerts(input: MonitorInput, feed: MonitorFeed, nameOf: Names): AgentMonitorAlert[] {\n const processes = feed.processes ?? [];\n const agents = new Map(feed.agents.map((agent) => [agent.id, agent]));\n const out = [...crowdAlerts(processes, nameOf), ...cpuAlerts(input, processes, nameOf)];\n for (const process of processes) {\n if (zombied(process, input.now))\n out.push({\n id: `zombie-${process.pid}`,\n title: `Process ${process.pid} is a zombie`,\n detail: `Its parent ${process.ppid} hasn't reaped it.`,\n ...(process.ppid > 1\n ? { command: `kill ${process.ppid}`, commandLabel: 'To clear it, stop the parent' }\n : {}),\n severity: 'warn',\n });\n if (stale(process, agents, input.now))\n out.push({\n id: `stale-${process.pid}`,\n title: `${process.command || `Process ${process.pid}`} has run for ${age(input.now - process.started)}`,\n detail: `${nameOf(process.agentId)} started it in the background.`,\n command: `kill ${process.pid}`,\n commandLabel: 'To stop it, run',\n severity: staleSeverity(process, input.now),\n });\n }\n return out;\n}\n\nfunction contextAlerts(input: MonitorInput, feed: MonitorFeed): AgentMonitorAlert[] {\n const out: AgentMonitorAlert[] = [];\n for (const agent of feed.agents) {\n const ratio = agentContext(agent, input.models);\n if (ratio !== null && ratio >= CONTEXT_WARN)\n out.push({\n id: `context-${agent.id}`,\n title: `${agent.name} is ${Math.round(ratio * 100)}% full`,\n detail: 'Compact it soon to keep replies fast.',\n severity: 'warn',\n });\n }\n if (feed.paused)\n out.push({\n id: 'scheduler',\n title: \"The agent isn't scheduling work\",\n detail: 'Its scheduler is paused.',\n severity: 'warn',\n });\n return out;\n}\n\nfunction alerts(input: MonitorInput, feed: MonitorFeed): AgentMonitorAlert[] {\n const agents = new Map(feed.agents.map((agent) => [agent.id, agent]));\n const nameOf: Names = (id) => (id ? (agents.get(id)?.name ?? id) : 'the session');\n return [\n ...budgetAlerts(input.budget),\n ...agentAlerts(input, feed),\n ...taskAlerts(input, feed, nameOf),\n ...processAlerts(input, feed, nameOf),\n ...contextAlerts(input, feed),\n ];\n}\n\nconst BLOCKED: Record<NonNullable<MonitorTask['blocked']>, string> = {\n missing_task: 'blocked: no definition',\n task_too_old: 'blocked: definition too old',\n migration_failed: 'blocked: migration failed',\n restart_limit: 'blocked: restart limit',\n};\n\nfunction taskRow(\n task: MonitorTask,\n depth: number,\n nameOf: (id: string | null) => string,\n now: number\n): MonitorRow {\n const aborting = task.aborting !== null && now - task.aborting > ABORT_ROW_MS;\n const status: MonitorStatus =\n aborting || task.blocked\n ? 'warn'\n : task.status === 'running' || task.status === 'completing'\n ? 'active'\n : 'idle';\n const badges = [\n ...(task.background ? ['background'] : []),\n ...(task.aborting !== null ? ['aborting'] : []),\n ...(task.waits ? [`waits on ${task.waits}`] : []),\n ...(typeof task.until === 'number' ? [`sleeps ${age(task.until - now)}`] : []),\n ...(task.blocked ? [BLOCKED[task.blocked]] : []),\n ];\n return {\n id: task.id,\n name: taskLabel(task),\n depth: Math.min(depth, DEPTH_MAX),\n meta: [nameOf(task.agentId), task.phase, age(now - task.since)].filter(Boolean).join(' \u00B7 '),\n status,\n ...(badges.length ? { badges } : {}),\n };\n}\n\nfunction drivers(members: readonly MonitorProcess[]): MonitorProcess[] {\n const hot = members.filter((row) => (row.cpu ?? 0) >= CPU_SHARE);\n if (hot.length) return hot;\n const top = members.reduce((best, row) => ((row.cpu ?? 0) > (best.cpu ?? 0) ? row : best));\n return [top];\n}\n\nfunction processRows(input: MonitorInput, feed: MonitorFeed): MonitorRow[] {\n const agents = new Map(feed.agents.map((agent) => [agent.id, agent]));\n const members = groups(feed.processes ?? []);\n const flagged = new Map<number, 'warn' | 'error'>();\n for (const group of busy(input, feed.processes ?? []))\n for (const row of drivers(members.get(group.pgid) as MonitorProcess[]))\n flagged.set(row.pid, cpuSeverity(group));\n return (feed.processes ?? []).map((process) => {\n const runaway = worse(\n worse(\n flagged.get(process.pid),\n stale(process, agents, input.now) ? staleSeverity(process, input.now) : undefined\n ),\n zombied(process, input.now) ? 'warn' : undefined\n );\n const badges = [\n ...(process.agentId ? [agents.get(process.agentId)?.name ?? process.agentId] : []),\n ...(process.tty ? ['terminal'] : []),\n ];\n return {\n id: String(process.pid),\n name: process.command || `[${process.pid}]`,\n meta: [\n `pid ${process.pid}`,\n process.user,\n typeof process.rss === 'number' ? bytes(process.rss) : null,\n cpuText(process.cpu),\n process.started ? age(input.now - process.started) : null,\n ]\n .filter(Boolean)\n .join(' \u00B7 '),\n status: runaway ?? 'idle',\n ...(badges.length ? { badges } : {}),\n };\n });\n}\n\nconst PROBLEM_KINDS = {\n task: 'task failed',\n retry: 'retry',\n turn: 'turn failed',\n report: 'problem',\n} as const;\n\nconst REPORTED: Record<string, string> = {\n session_failed: 'session failed',\n task_faulted: 'task failed',\n task_parked: 'task parked',\n migration_failed: 'migration failed',\n task_outdated: 'task outdated',\n task_error: 'task error',\n extension_error: 'extension error',\n host_error: 'host error',\n listener_error: 'listener error',\n};\n\nconst SERIOUS = new Set(['session_failed', 'task_faulted', 'task_parked', 'migration_failed']);\n\nfunction problemName(problem: MonitorProblem): string {\n const report = problem.report;\n if (!report) return PROBLEM_KINDS[problem.kind];\n const label = REPORTED[report.type] ?? PROBLEM_KINDS[problem.kind];\n return report.source ? `${label} (${report.source})` : label;\n}\n\nfunction problemStatus(problem: MonitorProblem): MonitorStatus {\n if (problem.kind === 'retry') return 'warn';\n if (problem.kind === 'report' && !SERIOUS.has(problem.report?.type ?? '')) return 'warn';\n return 'error';\n}\n\nfunction sections(input: MonitorInput, feed: MonitorFeed): MonitorSection[] {\n const agents = new Map(feed.agents.map((agent) => [agent.id, agent]));\n const nameOf = (id: string | null) => (id ? (agents.get(id)?.name ?? id) : 'session');\n return [\n {\n id: 'tasks',\n label: 'Tasks',\n rows: capped(\n taskTree(feed).map(({ task, depth }) => taskRow(task, depth, nameOf, input.now))\n ),\n },\n { id: 'processes', label: 'Processes', rows: capped(processRows(input, feed)) },\n {\n id: 'problems',\n label: 'Recent problems',\n rows: feed.problems.map((problem) => ({\n id: problem.id,\n name: `${nameOf(problem.agentId)} \u00B7 ${problemName(problem)}`,\n meta: problem.message,\n status: problemStatus(problem),\n })),\n },\n ];\n}\n\nfunction pageSections(input: MonitorInput): MonitorSection[] {\n return [\n {\n id: 'changes',\n label: 'Pending changes',\n rows: input.changes.map((change) => ({\n id: change.path,\n name: change.path,\n meta: change.status,\n status: 'warn',\n })),\n },\n ...input.extra,\n ];\n}\n\nexport function monitorSnapshot(input: MonitorInput): MonitorSnapshot {\n const budget = input.budget ? [budgetVital(input.budget, input.now)] : [];\n const feed = input.feed;\n if (!feed?.at)\n return {\n vitals: budget,\n alerts: [],\n sections: pageSections(input),\n updatedAt: input.now,\n };\n return {\n vitals: [...budget, ...vitals(input, feed)],\n alerts: alerts(input, feed),\n sections: [...sections(input, feed), ...pageSections(input)],\n updatedAt: feed.at,\n };\n}\n\nexport interface Intervals {\n every(run: () => void, ms: number): unknown;\n stop(handle: unknown): void;\n}\n\nexport const globalIntervals: Intervals = {\n every: (run, ms) => setInterval(run, ms),\n stop: (handle) => clearInterval(handle as ReturnType<typeof setInterval>),\n};\n\nexport interface MonitorAdapterOptions {\n extra?: () => readonly MonitorSection[];\n renewMs?: number;\n sampleMs?: number;\n intervals?: Intervals;\n now?: () => number;\n selected?: Selected;\n}\n\ninterface Open {\n lease: Promise<string | null>;\n timer: unknown;\n sampler: unknown;\n}\n\nexport class MonitorAdapter implements MonitorPort {\n readonly #connection: AgentConnection;\n readonly #emitter = new Emitter<MonitorEvents>();\n readonly #extra: () => readonly MonitorSection[];\n readonly #renewMs: number;\n readonly #sampleMs: number;\n readonly #intervals: Intervals;\n readonly #now: () => number;\n readonly #selected: Selected | undefined;\n #listeners = 0;\n #open: Open | undefined;\n #history: Sample[] = [];\n #hot = new Map<number, number>();\n #hotAt = -1;\n #cpu: number[] = [];\n #processes: number[] = [];\n #memory: number[] = [];\n\n constructor(connection: AgentConnection, options: MonitorAdapterOptions = {}) {\n this.#connection = connection;\n this.#extra = options.extra ?? (() => []);\n this.#renewMs = options.renewMs ?? RENEW_MS;\n this.#sampleMs = options.sampleMs ?? SAMPLE_MS;\n this.#intervals = options.intervals ?? globalIntervals;\n this.#now = options.now ?? Date.now;\n this.#selected = options.selected;\n let provider = options.selected?.provider();\n options.selected?.onChange(() => {\n const next = options.selected?.provider();\n if (next === provider) return;\n provider = next;\n if (this.#listeners) this.#emitter.emit('snapshot', this.snapshot());\n });\n connection.monitor?.subscribe(() => this.#update());\n connection.settings.state.subscribe(() => this.#update());\n connection.changes?.subscribe(() => this.#update());\n }\n\n on<K extends keyof MonitorEvents>(\n type: K,\n listener: (detail: MonitorEvents[K]) => void\n ): () => void {\n const off = this.#emitter.on(type, listener);\n this.#listeners++;\n if (this.#listeners === 1) this.#start();\n let done = false;\n return () => {\n if (done) return;\n done = true;\n off();\n this.#listeners--;\n if (!this.#listeners) this.#stop();\n };\n }\n\n snapshot(): MonitorSnapshot {\n const settings = this.#connection.settings.state.value;\n return monitorSnapshot({\n feed: this.#connection.monitor?.value,\n budget: selectedBudget(settings, this.#selected?.provider()),\n models: settings?.models ?? [],\n changes: this.#connection.changes?.value?.changes ?? [],\n extra: this.#extra(),\n history: this.#history,\n now: this.#now(),\n hot: this.#hot,\n cpu: this.#cpu,\n processes: this.#processes,\n memory: this.#memory,\n });\n }\n\n resync(): void {\n const open = this.#open;\n const control = this.#connection.control;\n if (open)\n void open.lease\n .then((lease) => (lease ? control.monitorOpen(lease, true, BACKGROUND_CONTEXT) : undefined))\n .catch(() => undefined);\n this.#emitter.emit('snapshot', this.snapshot());\n }\n\n #start(): void {\n const control = this.#connection.control;\n this.#history = [];\n this.#hot = new Map();\n this.#hotAt = -1;\n this.#cpu = [];\n this.#processes = [];\n this.#memory = [];\n void control.changesOpen(BACKGROUND_CONTEXT).catch(() => undefined);\n const lease = control.monitorOpen(null, true, BACKGROUND_CONTEXT).then(\n (opened) => opened.lease || null,\n () => null\n );\n const renew = () =>\n void lease\n .then((held) => (held ? control.monitorOpen(held, false, BACKGROUND_CONTEXT) : undefined))\n .catch(() => undefined);\n this.#open = {\n lease,\n timer: this.#intervals.every(renew, this.#renewMs),\n sampler: this.#intervals.every(() => this.#poll(), this.#sampleMs),\n };\n }\n\n #stop(): void {\n const open = this.#open;\n if (!open) return;\n this.#open = undefined;\n this.#intervals.stop(open.timer);\n this.#intervals.stop(open.sampler);\n const control = this.#connection.control;\n void open.lease\n .then((held) => (held ? control.monitorClose(held, BACKGROUND_CONTEXT) : undefined))\n .catch(() => undefined);\n }\n\n #sample(): void {\n const feed = this.#connection.monitor?.value;\n if (!feed?.open || !feed.usage || this.#history.at(-1)?.at === feed.at) return;\n record(\n this.#history,\n {\n at: feed.at,\n cost: feed.usage.cost,\n tokens: feed.usage.tokens,\n active: feed.agents.filter((agent) => agent.running).length,\n },\n HISTORY\n );\n }\n\n #track(): void {\n const feed = this.#connection.monitor?.value;\n if (!feed?.open || feed.at === this.#hotAt) return;\n this.#hotAt = feed.at;\n this.#hot = hotGroups(feed.processes ?? [], feed.at, this.#hot);\n const share = agentsCpu(feed);\n if (share !== null) record(this.#cpu, share, CPU_HISTORY);\n }\n\n #poll(): void {\n const feed = this.#connection.monitor?.value;\n if (!feed?.open || !feed.processes) return;\n record(this.#processes, feed.processes.length, CPU_HISTORY);\n const memory = memoryTotal(feed.processes);\n if (memory !== null) record(this.#memory, memory, CPU_HISTORY);\n this.#emitter.emit('snapshot', this.snapshot());\n }\n\n #update(): void {\n if (!this.#listeners) return;\n this.#sample();\n this.#track();\n this.#emitter.emit('snapshot', this.snapshot());\n }\n}\n"],
5
+ "mappings": "AAUA,SAAS,0BAA0B;AAEnC,SAAS,oBAAoB;AAU7B,SAAS,YAA2B,sBAAsB;AAC1D,SAAS,eAAe;AAEjB,MAAM,WAAW;AACjB,MAAM,YAAY;AAClB,MAAM,WAAW;AACjB,MAAM,UAAU;AAChB,MAAM,cAAc;AACpB,MAAM,YAAY;AAClB,MAAM,cAAc;AACpB,MAAM,eAAe;AACrB,MAAM,aAAa;AACnB,MAAM,cAAc;AACpB,MAAM,gBAAgB;AACtB,MAAM,YAAY;AAClB,MAAM,WAAW;AACjB,MAAM,eAAe;AACrB,MAAM,YAAY;AAClB,MAAM,YAAY;AAClB,MAAM,YAAY;AAClB,MAAM,WAAW;AACjB,MAAM,YAAY;AAClB,MAAM,iBAAiB;AACvB,MAAM,eAAe;AACrB,MAAM,YAAY;AACzB,MAAM,SAAS;AACf,MAAM,OAAO;AACb,MAAM,MAAM;AA0BL,SAAS,OAAU,MAAW,OAAU,KAAmB;AAChE,OAAK,KAAK,KAAK;AACf,MAAI,KAAK,SAAS,IAAK,MAAK,MAAM;AACpC;AAEA,SAAS,MAAM,QAA8D;AAC3E,SAAO,UAAU,OAAO,SAAS,IAAI,EAAE,QAAQ,CAAC,GAAG,MAAM,EAAE,IAAI,CAAC;AAClE;AAEA,MAAM,QAAgC;AAAA,EACpC,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,wBAAwB;AAAA,EACxB,wBAAwB;AAAA,EACxB,qBAAqB;AACvB;AAEO,SAAS,IAAI,IAAoB;AACtC,QAAM,UAAU,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,GAAI,CAAC;AACjD,MAAI,UAAU,GAAI,QAAO,GAAG,OAAO;AACnC,MAAI,UAAU,KAAM,QAAO,GAAG,KAAK,MAAM,UAAU,EAAE,CAAC;AACtD,SAAO,GAAG,KAAK,MAAM,UAAU,IAAI,CAAC;AACtC;AAEO,SAAS,MAAM,OAAuB;AAC3C,MAAI,QAAQ,KAAK,QAAQ,KAAM,QAAO;AACtC,SAAO,IAAI,MAAM,QAAQ,CAAC,CAAC;AAC7B;AAEO,SAAS,MAAM,OAAuB;AAC3C,MAAI,QAAQ,IAAM,QAAO,OAAO,KAAK;AACrC,MAAI,QAAQ,IAAS,QAAO,IAAI,QAAQ,KAAM,QAAQ,CAAC,CAAC;AACxD,SAAO,IAAI,QAAQ,KAAS,QAAQ,CAAC,CAAC;AACxC;AAEO,SAAS,MAAM,OAAuB;AAC3C,MAAI,QAAQ,KAAM,QAAO,GAAG,KAAK;AACjC,QAAM,QAAQ,CAAC,OAAO,OAAO,OAAO,KAAK;AACzC,MAAI,OAAO,QAAQ;AACnB,MAAI,OAAO;AACX,SAAO,QAAQ,QAAQ,OAAO,MAAM,SAAS,GAAG;AAC9C,YAAQ;AACR;AAAA,EACF;AACA,SAAO,GAAG,KAAK,QAAQ,OAAO,KAAK,IAAI,CAAC,CAAC,IAAI,MAAM,IAAI,CAAC;AAC1D;AAEO,SAAS,QAAQ,OAAiD;AACvE,MAAI,OAAO,UAAU,YAAY,QAAQ,UAAW,QAAO;AAC3D,SAAO,GAAG,KAAK,MAAM,QAAQ,GAAG,CAAC;AACnC;AAEO,SAAS,UAAU,MAAkC;AAC1D,QAAM,SAAS,KAAK,OACjB,IAAI,CAAC,UAAU,MAAM,GAAG,EACxB,OAAO,CAAC,UAA2B,OAAO,UAAU,QAAQ;AAC/D,SAAO,OAAO,SAAS,OAAO,OAAO,CAAC,KAAK,UAAU,MAAM,OAAO,CAAC,IAAI;AACzE;AAEA,SAAS,SAAS,MAAmB,SAA4C;AAC/E,QAAM,QAAQ,UAAU,IAAI;AAC5B,MAAI,UAAU,KAAM,QAAO,CAAC;AAC5B,SAAO;AAAA,IACL;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,OAAO,GAAG,KAAK,MAAM,QAAQ,GAAG,CAAC;AAAA,MACjC,MAAM;AAAA,MACN,GAAG,MAAM,QAAQ,IAAI,CAAC,UAAU,KAAK,MAAM,QAAQ,GAAG,CAAC,CAAC;AAAA,IAC1D;AAAA,EACF;AACF;AAEA,SAAS,WAAW,WAAwD;AAC1E,SAAO,UAAU,OAAO,CAAC,QAAQ,OAAO,IAAI,QAAQ,QAAQ;AAC9D;AAEO,SAAS,YAAY,WAAqD;AAC/E,QAAM,WAAW,WAAW,SAAS;AACrC,SAAO,SAAS,SAAS,SAAS,OAAO,CAAC,KAAK,QAAQ,MAAO,IAAI,KAAgB,CAAC,IAAI;AACzF;AAEA,SAAS,YACP,WACA,SACgB;AAChB,QAAM,QAAQ,YAAY,SAAS;AACnC,MAAI,UAAU,KAAM,QAAO,CAAC;AAC5B,QAAM,WAAW,WAAW,SAAS;AACrC,QAAM,SAAS,SACZ,OAAO,CAAC,QAAQ,IAAI,OAAO,EAC3B,OAAO,CAAC,KAAK,QAAQ,MAAO,IAAI,KAAgB,CAAC;AACpD,SAAO;AAAA,IACL;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,OAAO,MAAM,KAAK;AAAA,MAClB,MAAM,GAAG,MAAM,MAAM,CAAC;AAAA,MACtB,GAAG,MAAM,OAAO;AAAA,IAClB;AAAA,EACF;AACF;AAEO,SAAS,UAAU,MAA2B;AACnD,MAAI,KAAK,SAAS,UAAW,QAAO,KAAK,SAAS,QAAQ,KAAK,MAAM,KAAK;AAC1E,MAAI,KAAK,SAAS,qBAAsB,QAAO,KAAK,SAAS,SAAS,KAAK,MAAM,KAAK;AACtF,SAAO,MAAM,KAAK,IAAI,KAAK,KAAK;AAClC;AAEA,SAAS,OAAO,QAA2C,IAAkC;AAC3F,QAAM,UAAU,oBAAI,IAAY;AAChC,MAAI,UAAU,OAAO,OAAO,SAAY,OAAO,IAAI,EAAE;AACrD,SAAO,SAAS,YAAY,CAAC,QAAQ,IAAI,QAAQ,EAAE,GAAG;AACpD,YAAQ,IAAI,QAAQ,EAAE;AACtB,UAAM,SAAS,OAAO,IAAI,QAAQ,QAAQ;AAC1C,QAAI,CAAC,OAAQ;AACb,cAAU;AAAA,EACZ;AACA,SAAO,UAAU,QAAQ,KAAK;AAChC;AAEA,SAAS,QAAQ,MAAmC;AAClD,QAAM,OAAO,IAAI,IAAI,KAAK,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AAClE,QAAM,MAAsB,CAAC;AAC7B,aAAW,QAAQ,KAAK,OAAO,OAAO,CAAC,UAAU,MAAM,SAAS,MAAM,GAAG;AACvE,QAAI,KAAK,IAAI;AACb,eAAW,SAAS,KAAK;AACvB,UAAI,MAAM,SAAS,WAAW,OAAO,MAAM,MAAM,EAAE,MAAM,KAAK,GAAI,KAAI,KAAK,KAAK;AAAA,EACpF;AACA,aAAW,SAAS,KAAK,OAAQ,KAAI,CAAC,IAAI,SAAS,KAAK,EAAG,KAAI,KAAK,KAAK;AACzE,SAAO;AACT;AAEO,SAAS,SAAS,MAA2D;AAClF,QAAM,SAAS,IAAI,IAAI,KAAK,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AACpE,QAAM,QAAQ,QAAQ,IAAI,EAAE,IAAI,CAAC,UAAU,MAAM,EAAE;AACnD,QAAM,OAAO,CAAC,SAAsB;AAClC,UAAM,KAAK,KAAK,YAAY,OAAO,KAAK,MAAM,QAAQ,KAAK,OAAO;AAClE,WAAO,KAAK,IAAI,MAAM,SAAS;AAAA,EACjC;AACA,QAAM,UAAU,CAAC,SAAsB,OAAO,QAAQ,KAAK,OAAO,KAAK;AACvE,QAAM,OAAO,IAAI,IAAI,KAAK,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;AAC9D,QAAM,WAAW,oBAAI,IAA2B;AAChD,QAAM,QAAuB,CAAC;AAC9B,aAAW,QAAQ,KAAK,OAAO;AAC7B,UAAM,QAAQ,KAAK,UAAU,OAAO,SAAY,KAAK,IAAI,KAAK,KAAK;AACnE,QAAI,SAAS,QAAQ,KAAK,MAAM,QAAQ,IAAI,GAAG;AAC7C,YAAM,OAAO,SAAS,IAAI,MAAM,EAAE,KAAK,CAAC;AACxC,WAAK,KAAK,IAAI;AACd,eAAS,IAAI,MAAM,IAAI,IAAI;AAAA,IAC7B,MAAO,OAAM,KAAK,IAAI;AAAA,EACxB;AACA,QAAM,OAAO,CAAC,SACZ,KAAK,KAAK,CAAC,GAAG,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,OAAO,EAAE,EAAE,IAAI,OAAO,EAAE,EAAE,CAAC;AACtE,QAAM,MAA8C,CAAC;AACrD,QAAM,QAAQ,CAAC,MAAmB,UAAkB;AAClD,QAAI,KAAK,EAAE,MAAM,MAAM,CAAC;AACxB,eAAW,SAAS,KAAK,SAAS,IAAI,KAAK,EAAE,KAAK,CAAC,CAAC,EAAG,OAAM,OAAO,QAAQ,CAAC;AAAA,EAC/E;AACA,aAAW,QAAQ,KAAK,KAAK,EAAG,OAAM,MAAM,CAAC;AAC7C,SAAO;AACT;AAEA,SAAS,OAAO,MAAkC;AAChD,MAAI,KAAK,UAAU,SAAU,QAAO;AACpC,QAAM,QAAQ,KAAK,MAAM,GAAG,WAAW,CAAC;AACxC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,EAAE,IAAI,QAAQ,MAAM,IAAI,KAAK,SAAS,MAAM,MAAM,SAAS,MAAM,IAAI,QAAQ,OAAO;AAAA,EACtF;AACF;AAEA,SAAS,aAAa,OAAqB,QAA+C;AACxF,SAAO,aAAa,MAAM,SAAS,MAAM,OAAO,MAAM;AACxD;AAEA,SAAS,KAAK,SAA4B,MAAiD;AACzF,QAAM,QAAQ,QAAQ,CAAC;AACvB,QAAM,OAAO,QAAQ,GAAG,EAAE;AAC1B,MAAI,CAAC,SAAS,CAAC,QAAQ,KAAK,KAAK,MAAM,KAAK,OAAQ,QAAO;AAC3D,UAAS,KAAK,IAAI,IAAI,KAAK,KAAK,MAAM,KAAK,KAAK,MAAM,MAAO;AAC/D;AAEA,MAAM,WAAW,IAAI,KAAK,mBAAmB,MAAM,EAAE,SAAS,OAAO,CAAC;AAEtE,SAAS,SAAS,IAAY,KAAqB;AACjD,QAAM,KAAK,KAAK;AAChB,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,MAAM;AACR,WAAO,UAAU,SAAS,OAAO,KAAK,MAAM,KAAK,GAAG,IAAI,KAAK,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC;AACvF,MAAI,MAAM,KAAM,QAAO,UAAU,SAAS,OAAO,KAAK,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC;AAC/E,SAAO,UAAU,SAAS,OAAO,KAAK,KAAK,KAAK,MAAM,GAAG,QAAQ,CAAC;AACpE;AAEA,SAAS,YAAY,QAAqB,KAA2B;AACnE,QAAM,SAAS,IAAI,KAAK,OAAO,MAAM;AACrC,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,UAAU,OAAO;AAAA,IACjB,QAAQ,OAAO;AAAA,IACf,OAAO,WAAW,OAAO,MAAM;AAAA,IAC/B,OAAO,GAAG,OAAO,OAAO;AAAA,IACxB,GAAI,OAAO,MAAM,OAAO,QAAQ,CAAC,IAC7B,CAAC,IACD;AAAA,MACE,MAAM,SAAS,OAAO,QAAQ,GAAG,GAAG;AAAA,MACpC,MAAM,UAAU,OAAO,YAAY,EAAE,MAAM,GAAG,EAAE,EAAE,QAAQ,KAAK,GAAG,CAAC;AAAA,IACrE;AAAA,IACJ,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,OAAO,UAAU,GAAG,CAAC;AAAA,EACtD;AACF;AAEA,SAAS,OAAO,OAAqB,MAAmC;AACtE,QAAM,MAAsB,CAAC;AAC7B,MAAI,KAAK,OAAO;AACd,UAAM,OAAO,KAAK,MAAM;AACxB,UAAM,OAAO,CAAC,WAAoB,OAAO,OAAO,SAAS,OAAO;AAChE,UAAM,UAAU,KAAK,MAAM,SAAS,IAAI;AACxC,UAAM,SAAS,MAAM,QAAQ,IAAI,IAAI;AACrC,QAAI,KAAK;AAAA,MACP,IAAI;AAAA,MACJ,OAAO,OAAO,WAAW;AAAA,MACzB,OAAO,OAAO,MAAM,KAAK,MAAM,MAAM,IAAI,MAAM,KAAK,MAAM,IAAI;AAAA,MAC9D,MAAM,OAAO,WAAW,GAAG,MAAM,KAAK,MAAM,MAAM,CAAC;AAAA,MACnD,GAAI,YAAY,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,MAAM,OAAO,IAAI,MAAM,OAAO,CAAC,KAAK;AAAA,MACnF,GAAG,MAAM,MAAM;AAAA,IACjB,CAAC;AAAA,EACH;AACA,QAAM,SAAS,KAAK,OAAO,OAAO,CAAC,UAAU,MAAM,OAAO,EAAE;AAC5D,MAAI,KAAK;AAAA,IACP,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO,OAAO,MAAM;AAAA,IACpB,MAAM,MAAM,KAAK,OAAO,MAAM;AAAA,IAC9B,GAAG,MAAM,MAAM,QAAQ,IAAI,CAAC,WAAW,OAAO,MAAM,CAAC;AAAA,EACvD,CAAC;AACD,QAAM,QAAQ,KAAK,MAAM;AAAA,IACvB,CAAC,SAAS,KAAK,SAAS,aAAa,KAAK,WAAW;AAAA,EACvD,EAAE;AACF,MAAI,KAAK;AAAA,IACP,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,OAAO,OAAO,KAAK;AAAA,IACnB,MAAM,GAAG,UAAU,IAAI,SAAS,OAAO,SAAM,KAAK,MAAM,MAAM,IAAI,KAAK,MAAM,WAAW,IAAI,SAAS,OAAO;AAAA,EAC9G,CAAC;AACD,MAAI;AAAA,IACF,KAAK,YACD;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,OAAO,OAAO,KAAK,UAAU,MAAM;AAAA,MACnC,MAAM,GAAG,KAAK,UAAU,OAAO,CAAC,QAAQ,IAAI,OAAO,EAAE,MAAM;AAAA,MAC3D,GAAG,MAAM,MAAM,SAAS;AAAA,IAC1B,IACA,KAAK,WAAW,aACd,EAAE,IAAI,aAAa,OAAO,aAAa,OAAO,UAAK,MAAM,WAAW,IACpE,EAAE,IAAI,aAAa,OAAO,aAAa,OAAO,UAAK,MAAM,uBAAuB;AAAA,EACxF;AACA,MAAI,KAAK,GAAG,YAAY,KAAK,aAAa,CAAC,GAAG,MAAM,MAAM,CAAC;AAC3D,MAAI,KAAK,GAAG,SAAS,MAAM,MAAM,OAAO,CAAC,CAAC,CAAC;AAC3C,QAAM,SAAS,KAAK,OACjB,IAAI,CAAC,UAAU,aAAa,OAAO,MAAM,MAAM,CAAC,EAChD,OAAO,CAAC,UAA2B,UAAU,IAAI;AACpD,MAAI,OAAO,QAAQ;AACjB,UAAM,UAAU,KAAK,IAAI,GAAG,MAAM;AAClC,QAAI,KAAK;AAAA,MACP,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,OAAO,GAAG,KAAK,MAAM,UAAU,GAAG,CAAC;AAAA,MACnC,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,SAAS,MAAM,SAAyB,QAA2C,KAAa;AAC9F,MAAI,CAAC,QAAQ,WAAW,QAAQ,UAAU,OAAO,CAAC,QAAQ,QAAS,QAAO;AAC1E,MAAI,OAAO,QAAQ,UAAU,SAAU,QAAO;AAC9C,MAAI,OAAO,IAAI,QAAQ,OAAO,GAAG,SAAS,OAAQ,QAAO;AACzD,SAAO,MAAM,QAAQ,UAAU;AACjC;AAEA,SAAS,QAAQ,SAAyB,KAAsB;AAC9D,SAAO,QAAQ,WAAW,QAAQ,MAAM,QAAQ,SAAS;AAC3D;AAEA,SAAS,OAAO,WAAqE;AACnF,QAAM,MAAM,oBAAI,IAA8B;AAC9C,aAAW,WAAW,WAAW;AAC/B,QAAI,CAAC,QAAQ,QAAS;AACtB,UAAM,OAAO,IAAI,IAAI,QAAQ,IAAI,KAAK,CAAC;AACvC,SAAK,KAAK,OAAO;AACjB,QAAI,IAAI,QAAQ,MAAM,IAAI;AAAA,EAC5B;AACA,SAAO;AACT;AAIO,SAAS,SACd,WACiD;AACjD,QAAM,MAAM,oBAAI,IAAgD;AAChE,aAAW,CAAC,MAAM,OAAO,KAAK,OAAO,SAAS,GAAG;AAC/C,UAAM,WAAW,QAAQ,OAAO,CAAC,QAAQ,OAAO,IAAI,QAAQ,QAAQ;AACpE,QAAI,CAAC,SAAS,OAAQ;AACtB,UAAM,QAAQ,SAAS,OAAO,CAAC,KAAK,QAAQ,MAAO,IAAI,KAAgB,CAAC;AACxE,QAAI,IAAI,MAAM,EAAE,SAAU,QAAQ,CAAC,EAAqB,SAAmB,MAAM,CAAC;AAAA,EACpF;AACA,SAAO;AACT;AAEO,SAAS,UACd,WACA,IACA,UACqB;AACrB,QAAM,MAAM,oBAAI,IAAoB;AACpC,aAAW,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,SAAS,SAAS;AAChD,QAAI,SAAS,UAAW,KAAI,IAAI,MAAM,SAAS,IAAI,IAAI,KAAK,EAAE;AAChE,SAAO;AACT;AAEA,SAAS,KAAK,OAAqB,WAAsC;AACvE,QAAM,SAAS,SAAS,SAAS;AACjC,QAAM,MAAwE,CAAC;AAC/E,aAAW,CAAC,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,GAAG;AAC3C,UAAM,QAAQ,OAAO,IAAI,IAAI;AAC7B,UAAM,OAAO,MAAM,MAAM;AACzB,QAAI,SAAS,MAAM,SAAS,aAAa,QAAQ;AAC/C,UAAI,KAAK,EAAE,MAAM,GAAG,OAAO,KAAK,CAAC;AAAA,EACrC;AACA,SAAO;AACT;AAEA,SAAS,UAAU,OAAqB,WAAsC,QAAe;AAC3F,SAAO,KAAK,OAAO,SAAS,EAAE;AAAA,IAC5B,CAAC,WAA8B;AAAA,MAC7B,IAAI,eAAe,MAAM,IAAI;AAAA,MAC7B,OAAO,GAAG,OAAO,MAAM,OAAO,CAAC;AAAA,MAC/B,QAAQ,GAAG,KAAK,MAAM,MAAM,QAAQ,GAAG,CAAC,qBAAqB,KAAK,MAAM,MAAM,OAAO,MAAM,CAAC;AAAA,MAC5F,SAAS,YAAY,MAAM,IAAI;AAAA,MAC/B,cAAc;AAAA,MACd,UAAU,YAAY,KAAK;AAAA,IAC7B;AAAA,EACF;AACF;AAEA,SAAS,YAAY,OAA0D;AAC7E,SAAO,MAAM,SAAS,YAAY,KAAK,MAAM,QAAQ,iBAAiB,IAAI,UAAU;AACtF;AAEA,SAAS,cAAc,SAAsD;AAC3E,SAAO,QAAQ,SAAS,YAAY,IAAI,UAAU;AACpD;AAEA,SAAS,cAAc,SAAyB,KAA+B;AAC7E,SAAO,MAAM,QAAQ,UAAU,WAAW,IAAI,UAAU;AAC1D;AAEA,SAAS,MACP,GACA,GAC8B;AAC9B,SAAO,MAAM,WAAW,MAAM,UAAU,UAAW,KAAK;AAC1D;AAEA,SAAS,UAAU,QAA6B;AAC9C,QAAM,SAAS,IAAI,KAAK,OAAO,MAAM;AACrC,SAAO,OAAO,MAAM,OAAO,QAAQ,CAAC,IAChC,OAAO,OAAO,MAAM,+BACpB,UAAU,OAAO,YAAY,EAAE,MAAM,GAAG,EAAE,EAAE,QAAQ,KAAK,GAAG,CAAC;AACnE;AAEA,SAAS,aAAa,QAA6D;AACjF,MAAI,CAAC,UAAU,OAAO,UAAU,YAAa,QAAO,CAAC;AACrD,SAAO;AAAA,IACL;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,GAAG,WAAW,OAAO,QAAQ,CAAC,WAAW,OAAO,OAAO;AAAA,MAC9D,QAAQ,UAAU,MAAM;AAAA,MACxB,UAAU,OAAO,WAAW,eAAe,UAAU;AAAA,IACvD;AAAA,EACF;AACF;AAEA,SAAS,YAAY,OAAqB,MAAwC;AAChF,QAAM,MAA2B,CAAC;AAClC,aAAW,SAAS,KAAK,QAAQ;AAC/B,UAAM,QAAQ,MAAM;AACpB,QAAI,UAAU,MAAM,WAAW,cAAc,MAAM,MAAM,MAAM,QAAQ;AACrE,UAAI,KAAK;AAAA,QACP,IAAI,SAAS,MAAM,EAAE;AAAA,QACrB,OAAO,GAAG,MAAM,IAAI,yBAAyB,MAAM,OAAO;AAAA,QAC1D,QAAQ,MAAM;AAAA,QACd,UAAU,MAAM,WAAW,cAAc,UAAU;AAAA,MACrD,CAAC;AACH,QAAI,MAAM,UAAU,CAAC,MAAM;AACzB,UAAI,KAAK;AAAA,QACP,IAAI,QAAQ,MAAM,EAAE;AAAA,QACpB,OAAO,GAAG,MAAM,IAAI;AAAA,QACpB,QAAQ,MAAM;AAAA,QACd,UAAU;AAAA,MACZ,CAAC;AAAA,EACL;AACA,SAAO;AACT;AAEA,SAAS,WAAW,OAAqB,MAAmB,QAAoC;AAC9F,QAAM,MAA2B,CAAC;AAClC,aAAW,WAAW,KAAK;AACzB,QAAI,QAAQ,SAAS,UAAU,MAAM,MAAM,QAAQ,KAAK;AACtD,UAAI,KAAK;AAAA,QACP,IAAI,UAAU,QAAQ,EAAE;AAAA,QACxB,OAAO,aAAa,OAAO,QAAQ,OAAO,CAAC;AAAA,QAC3C,QAAQ,QAAQ;AAAA,QAChB,UAAU;AAAA,MACZ,CAAC;AAAA,aAED,QAAQ,SAAS,YACjB,QAAQ,IAAI,QAAQ,QAAQ,QAAQ,EAAE,KACtC,MAAM,MAAM,QAAQ,KAAK;AAEzB,UAAI,KAAK;AAAA,QACP,IAAI,YAAY,QAAQ,EAAE;AAAA,QAC1B,OAAO,GAAG,OAAO,QAAQ,OAAO,CAAC,KAAK,YAAY,OAAO,CAAC;AAAA,QAC1D,QAAQ,QAAQ;AAAA,QAChB,UAAU;AAAA,MACZ,CAAC;AACL,aAAW,QAAQ,KAAK;AACtB,QAAI,KAAK,YAAY;AACnB,UAAI,KAAK;AAAA,QACP,IAAI,UAAU,KAAK,EAAE;AAAA,QACrB,OAAO,GAAG,UAAU,IAAI,CAAC,OAAO,OAAO,KAAK,OAAO,CAAC;AAAA,QACpD,QACE;AAAA,QACF,UAAU;AAAA,QACV,SAAS,eAAe,KAAK,EAAE;AAAA,QAC/B,cAAc;AAAA,MAChB,CAAC;AACL,aAAW,QAAQ,KAAK;AACtB,QAAI,KAAK,aAAa,QAAQ,MAAM,MAAM,KAAK,WAAW;AACxD,UAAI,KAAK;AAAA,QACP,IAAI,SAAS,KAAK,EAAE;AAAA,QACpB,OAAO,6BAA6B,UAAU,IAAI,CAAC;AAAA,QACnD,QAAQ,GAAG,OAAO,KAAK,OAAO,CAAC,qBAAqB,IAAI,MAAM,MAAM,KAAK,QAAQ,CAAC;AAAA,QAClF,UAAU;AAAA,MACZ,CAAC;AACL,SAAO;AACT;AAEA,SAAS,YAAY,WAAsC,QAAoC;AAC7F,QAAM,MAA2B,CAAC;AAClC,aAAW,CAAC,MAAM,OAAO,KAAK,OAAO,SAAS;AAC5C,QAAI,QAAQ,SAAS;AACnB,UAAI,KAAK;AAAA,QACP,IAAI,WAAW,IAAI;AAAA,QACnB,OAAO,GAAG,OAAQ,QAAQ,CAAC,EAAqB,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,QAC9E,QAAQ;AAAA,QACR,SAAS,YAAY,IAAI;AAAA,QACzB,cAAc;AAAA,QACd,UAAU,cAAc,OAAO;AAAA,MACjC,CAAC;AACL,MAAI,UAAU,SAAS;AACrB,QAAI,KAAK;AAAA,MACP,IAAI;AAAA,MACJ,OAAO,kBAAkB,UAAU,MAAM;AAAA,MACzC,QAAQ;AAAA,MACR,UAAU,UAAU,SAAS,YAAY,IAAI,UAAU;AAAA,IACzD,CAAC;AACH,SAAO;AACT;AAEA,SAAS,cAAc,OAAqB,MAAmB,QAAoC;AACjG,QAAM,YAAY,KAAK,aAAa,CAAC;AACrC,QAAM,SAAS,IAAI,IAAI,KAAK,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AACpE,QAAM,MAAM,CAAC,GAAG,YAAY,WAAW,MAAM,GAAG,GAAG,UAAU,OAAO,WAAW,MAAM,CAAC;AACtF,aAAW,WAAW,WAAW;AAC/B,QAAI,QAAQ,SAAS,MAAM,GAAG;AAC5B,UAAI,KAAK;AAAA,QACP,IAAI,UAAU,QAAQ,GAAG;AAAA,QACzB,OAAO,WAAW,QAAQ,GAAG;AAAA,QAC7B,QAAQ,cAAc,QAAQ,IAAI;AAAA,QAClC,GAAI,QAAQ,OAAO,IACf,EAAE,SAAS,QAAQ,QAAQ,IAAI,IAAI,cAAc,+BAA+B,IAChF,CAAC;AAAA,QACL,UAAU;AAAA,MACZ,CAAC;AACH,QAAI,MAAM,SAAS,QAAQ,MAAM,GAAG;AAClC,UAAI,KAAK;AAAA,QACP,IAAI,SAAS,QAAQ,GAAG;AAAA,QACxB,OAAO,GAAG,QAAQ,WAAW,WAAW,QAAQ,GAAG,EAAE,gBAAgB,IAAI,MAAM,MAAM,QAAQ,OAAO,CAAC;AAAA,QACrG,QAAQ,GAAG,OAAO,QAAQ,OAAO,CAAC;AAAA,QAClC,SAAS,QAAQ,QAAQ,GAAG;AAAA,QAC5B,cAAc;AAAA,QACd,UAAU,cAAc,SAAS,MAAM,GAAG;AAAA,MAC5C,CAAC;AAAA,EACL;AACA,SAAO;AACT;AAEA,SAAS,cAAc,OAAqB,MAAwC;AAClF,QAAM,MAA2B,CAAC;AAClC,aAAW,SAAS,KAAK,QAAQ;AAC/B,UAAM,QAAQ,aAAa,OAAO,MAAM,MAAM;AAC9C,QAAI,UAAU,QAAQ,SAAS;AAC7B,UAAI,KAAK;AAAA,QACP,IAAI,WAAW,MAAM,EAAE;AAAA,QACvB,OAAO,GAAG,MAAM,IAAI,OAAO,KAAK,MAAM,QAAQ,GAAG,CAAC;AAAA,QAClD,QAAQ;AAAA,QACR,UAAU;AAAA,MACZ,CAAC;AAAA,EACL;AACA,MAAI,KAAK;AACP,QAAI,KAAK;AAAA,MACP,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,UAAU;AAAA,IACZ,CAAC;AACH,SAAO;AACT;AAEA,SAAS,OAAO,OAAqB,MAAwC;AAC3E,QAAM,SAAS,IAAI,IAAI,KAAK,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AACpE,QAAM,SAAgB,CAAC,OAAQ,KAAM,OAAO,IAAI,EAAE,GAAG,QAAQ,KAAM;AACnE,SAAO;AAAA,IACL,GAAG,aAAa,MAAM,MAAM;AAAA,IAC5B,GAAG,YAAY,OAAO,IAAI;AAAA,IAC1B,GAAG,WAAW,OAAO,MAAM,MAAM;AAAA,IACjC,GAAG,cAAc,OAAO,MAAM,MAAM;AAAA,IACpC,GAAG,cAAc,OAAO,IAAI;AAAA,EAC9B;AACF;AAEA,MAAM,UAA+D;AAAA,EACnE,cAAc;AAAA,EACd,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,eAAe;AACjB;AAEA,SAAS,QACP,MACA,OACA,QACA,KACY;AACZ,QAAM,WAAW,KAAK,aAAa,QAAQ,MAAM,KAAK,WAAW;AACjE,QAAM,SACJ,YAAY,KAAK,UACb,SACA,KAAK,WAAW,aAAa,KAAK,WAAW,eAC3C,WACA;AACR,QAAM,SAAS;AAAA,IACb,GAAI,KAAK,aAAa,CAAC,YAAY,IAAI,CAAC;AAAA,IACxC,GAAI,KAAK,aAAa,OAAO,CAAC,UAAU,IAAI,CAAC;AAAA,IAC7C,GAAI,KAAK,QAAQ,CAAC,YAAY,KAAK,KAAK,EAAE,IAAI,CAAC;AAAA,IAC/C,GAAI,OAAO,KAAK,UAAU,WAAW,CAAC,UAAU,IAAI,KAAK,QAAQ,GAAG,CAAC,EAAE,IAAI,CAAC;AAAA,IAC5E,GAAI,KAAK,UAAU,CAAC,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC;AAAA,EAChD;AACA,SAAO;AAAA,IACL,IAAI,KAAK;AAAA,IACT,MAAM,UAAU,IAAI;AAAA,IACpB,OAAO,KAAK,IAAI,OAAO,SAAS;AAAA,IAChC,MAAM,CAAC,OAAO,KAAK,OAAO,GAAG,KAAK,OAAO,IAAI,MAAM,KAAK,KAAK,CAAC,EAAE,OAAO,OAAO,EAAE,KAAK,QAAK;AAAA,IAC1F;AAAA,IACA,GAAI,OAAO,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,EACpC;AACF;AAEA,SAAS,QAAQ,SAAsD;AACrE,QAAM,MAAM,QAAQ,OAAO,CAAC,SAAS,IAAI,OAAO,MAAM,SAAS;AAC/D,MAAI,IAAI,OAAQ,QAAO;AACvB,QAAM,MAAM,QAAQ,OAAO,CAAC,MAAM,SAAU,IAAI,OAAO,MAAM,KAAK,OAAO,KAAK,MAAM,IAAK;AACzF,SAAO,CAAC,GAAG;AACb;AAEA,SAAS,YAAY,OAAqB,MAAiC;AACzE,QAAM,SAAS,IAAI,IAAI,KAAK,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AACpE,QAAM,UAAU,OAAO,KAAK,aAAa,CAAC,CAAC;AAC3C,QAAM,UAAU,oBAAI,IAA8B;AAClD,aAAW,SAAS,KAAK,OAAO,KAAK,aAAa,CAAC,CAAC;AAClD,eAAW,OAAO,QAAQ,QAAQ,IAAI,MAAM,IAAI,CAAqB;AACnE,cAAQ,IAAI,IAAI,KAAK,YAAY,KAAK,CAAC;AAC3C,UAAQ,KAAK,aAAa,CAAC,GAAG,IAAI,CAAC,YAAY;AAC7C,UAAM,UAAU;AAAA,MACd;AAAA,QACE,QAAQ,IAAI,QAAQ,GAAG;AAAA,QACvB,MAAM,SAAS,QAAQ,MAAM,GAAG,IAAI,cAAc,SAAS,MAAM,GAAG,IAAI;AAAA,MAC1E;AAAA,MACA,QAAQ,SAAS,MAAM,GAAG,IAAI,SAAS;AAAA,IACzC;AACA,UAAM,SAAS;AAAA,MACb,GAAI,QAAQ,UAAU,CAAC,OAAO,IAAI,QAAQ,OAAO,GAAG,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,MAChF,GAAI,QAAQ,MAAM,CAAC,UAAU,IAAI,CAAC;AAAA,IACpC;AACA,WAAO;AAAA,MACL,IAAI,OAAO,QAAQ,GAAG;AAAA,MACtB,MAAM,QAAQ,WAAW,IAAI,QAAQ,GAAG;AAAA,MACxC,MAAM;AAAA,QACJ,OAAO,QAAQ,GAAG;AAAA,QAClB,QAAQ;AAAA,QACR,OAAO,QAAQ,QAAQ,WAAW,MAAM,QAAQ,GAAG,IAAI;AAAA,QACvD,QAAQ,QAAQ,GAAG;AAAA,QACnB,QAAQ,UAAU,IAAI,MAAM,MAAM,QAAQ,OAAO,IAAI;AAAA,MACvD,EACG,OAAO,OAAO,EACd,KAAK,QAAK;AAAA,MACb,QAAQ,WAAW;AAAA,MACnB,GAAI,OAAO,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IACpC;AAAA,EACF,CAAC;AACH;AAEA,MAAM,gBAAgB;AAAA,EACpB,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,QAAQ;AACV;AAEA,MAAM,WAAmC;AAAA,EACvC,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,YAAY;AAAA,EACZ,gBAAgB;AAClB;AAEA,MAAM,UAAU,oBAAI,IAAI,CAAC,kBAAkB,gBAAgB,eAAe,kBAAkB,CAAC;AAE7F,SAAS,YAAY,SAAiC;AACpD,QAAM,SAAS,QAAQ;AACvB,MAAI,CAAC,OAAQ,QAAO,cAAc,QAAQ,IAAI;AAC9C,QAAM,QAAQ,SAAS,OAAO,IAAI,KAAK,cAAc,QAAQ,IAAI;AACjE,SAAO,OAAO,SAAS,GAAG,KAAK,KAAK,OAAO,MAAM,MAAM;AACzD;AAEA,SAAS,cAAc,SAAwC;AAC7D,MAAI,QAAQ,SAAS,QAAS,QAAO;AACrC,MAAI,QAAQ,SAAS,YAAY,CAAC,QAAQ,IAAI,QAAQ,QAAQ,QAAQ,EAAE,EAAG,QAAO;AAClF,SAAO;AACT;AAEA,SAAS,SAAS,OAAqB,MAAqC;AAC1E,QAAM,SAAS,IAAI,IAAI,KAAK,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AACpE,QAAM,SAAS,CAAC,OAAuB,KAAM,OAAO,IAAI,EAAE,GAAG,QAAQ,KAAM;AAC3E,SAAO;AAAA,IACL;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,MAAM;AAAA,QACJ,SAAS,IAAI,EAAE,IAAI,CAAC,EAAE,MAAM,MAAM,MAAM,QAAQ,MAAM,OAAO,QAAQ,MAAM,GAAG,CAAC;AAAA,MACjF;AAAA,IACF;AAAA,IACA,EAAE,IAAI,aAAa,OAAO,aAAa,MAAM,OAAO,YAAY,OAAO,IAAI,CAAC,EAAE;AAAA,IAC9E;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,MAAM,KAAK,SAAS,IAAI,CAAC,aAAa;AAAA,QACpC,IAAI,QAAQ;AAAA,QACZ,MAAM,GAAG,OAAO,QAAQ,OAAO,CAAC,SAAM,YAAY,OAAO,CAAC;AAAA,QAC1D,MAAM,QAAQ;AAAA,QACd,QAAQ,cAAc,OAAO;AAAA,MAC/B,EAAE;AAAA,IACJ;AAAA,EACF;AACF;AAEA,SAAS,aAAa,OAAuC;AAC3D,SAAO;AAAA,IACL;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,MAAM,MAAM,QAAQ,IAAI,CAAC,YAAY;AAAA,QACnC,IAAI,OAAO;AAAA,QACX,MAAM,OAAO;AAAA,QACb,MAAM,OAAO;AAAA,QACb,QAAQ;AAAA,MACV,EAAE;AAAA,IACJ;AAAA,IACA,GAAG,MAAM;AAAA,EACX;AACF;AAEO,SAAS,gBAAgB,OAAsC;AACpE,QAAM,SAAS,MAAM,SAAS,CAAC,YAAY,MAAM,QAAQ,MAAM,GAAG,CAAC,IAAI,CAAC;AACxE,QAAM,OAAO,MAAM;AACnB,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ,CAAC;AAAA,MACT,UAAU,aAAa,KAAK;AAAA,MAC5B,WAAW,MAAM;AAAA,IACnB;AACF,SAAO;AAAA,IACL,QAAQ,CAAC,GAAG,QAAQ,GAAG,OAAO,OAAO,IAAI,CAAC;AAAA,IAC1C,QAAQ,OAAO,OAAO,IAAI;AAAA,IAC1B,UAAU,CAAC,GAAG,SAAS,OAAO,IAAI,GAAG,GAAG,aAAa,KAAK,CAAC;AAAA,IAC3D,WAAW,KAAK;AAAA,EAClB;AACF;AAOO,MAAM,kBAA6B;AAAA,EACxC,OAAO,CAAC,KAAK,OAAO,YAAY,KAAK,EAAE;AAAA,EACvC,MAAM,CAAC,WAAW,cAAc,MAAwC;AAC1E;AAiBO,MAAM,eAAsC;AAAA,EACxC;AAAA,EACA,WAAW,IAAI,QAAuB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT,aAAa;AAAA,EACb;AAAA,EACA,WAAqB,CAAC;AAAA,EACtB,OAAO,oBAAI,IAAoB;AAAA,EAC/B,SAAS;AAAA,EACT,OAAiB,CAAC;AAAA,EAClB,aAAuB,CAAC;AAAA,EACxB,UAAoB,CAAC;AAAA,EAErB,YAAY,YAA6B,UAAiC,CAAC,GAAG;AAC5E,SAAK,cAAc;AACnB,SAAK,SAAS,QAAQ,UAAU,MAAM,CAAC;AACvC,SAAK,WAAW,QAAQ,WAAW;AACnC,SAAK,YAAY,QAAQ,YAAY;AACrC,SAAK,aAAa,QAAQ,aAAa;AACvC,SAAK,OAAO,QAAQ,OAAO,KAAK;AAChC,SAAK,YAAY,QAAQ;AACzB,QAAI,WAAW,QAAQ,UAAU,SAAS;AAC1C,YAAQ,UAAU,SAAS,MAAM;AAC/B,YAAM,OAAO,QAAQ,UAAU,SAAS;AACxC,UAAI,SAAS,SAAU;AACvB,iBAAW;AACX,UAAI,KAAK,WAAY,MAAK,SAAS,KAAK,YAAY,KAAK,SAAS,CAAC;AAAA,IACrE,CAAC;AACD,eAAW,SAAS,UAAU,MAAM,KAAK,QAAQ,CAAC;AAClD,eAAW,SAAS,MAAM,UAAU,MAAM,KAAK,QAAQ,CAAC;AACxD,eAAW,SAAS,UAAU,MAAM,KAAK,QAAQ,CAAC;AAAA,EACpD;AAAA,EAEA,GACE,MACA,UACY;AACZ,UAAM,MAAM,KAAK,SAAS,GAAG,MAAM,QAAQ;AAC3C,SAAK;AACL,QAAI,KAAK,eAAe,EAAG,MAAK,OAAO;AACvC,QAAI,OAAO;AACX,WAAO,MAAM;AACX,UAAI,KAAM;AACV,aAAO;AACP,UAAI;AACJ,WAAK;AACL,UAAI,CAAC,KAAK,WAAY,MAAK,MAAM;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,WAA4B;AAC1B,UAAM,WAAW,KAAK,YAAY,SAAS,MAAM;AACjD,WAAO,gBAAgB;AAAA,MACrB,MAAM,KAAK,YAAY,SAAS;AAAA,MAChC,QAAQ,eAAe,UAAU,KAAK,WAAW,SAAS,CAAC;AAAA,MAC3D,QAAQ,UAAU,UAAU,CAAC;AAAA,MAC7B,SAAS,KAAK,YAAY,SAAS,OAAO,WAAW,CAAC;AAAA,MACtD,OAAO,KAAK,OAAO;AAAA,MACnB,SAAS,KAAK;AAAA,MACd,KAAK,KAAK,KAAK;AAAA,MACf,KAAK,KAAK;AAAA,MACV,KAAK,KAAK;AAAA,MACV,WAAW,KAAK;AAAA,MAChB,QAAQ,KAAK;AAAA,IACf,CAAC;AAAA,EACH;AAAA,EAEA,SAAe;AACb,UAAM,OAAO,KAAK;AAClB,UAAM,UAAU,KAAK,YAAY;AACjC,QAAI;AACF,WAAK,KAAK,MACP,KAAK,CAAC,UAAW,QAAQ,QAAQ,YAAY,OAAO,MAAM,kBAAkB,IAAI,MAAU,EAC1F,MAAM,MAAM,MAAS;AAC1B,SAAK,SAAS,KAAK,YAAY,KAAK,SAAS,CAAC;AAAA,EAChD;AAAA,EAEA,SAAe;AACb,UAAM,UAAU,KAAK,YAAY;AACjC,SAAK,WAAW,CAAC;AACjB,SAAK,OAAO,oBAAI,IAAI;AACpB,SAAK,SAAS;AACd,SAAK,OAAO,CAAC;AACb,SAAK,aAAa,CAAC;AACnB,SAAK,UAAU,CAAC;AAChB,SAAK,QAAQ,YAAY,kBAAkB,EAAE,MAAM,MAAM,MAAS;AAClE,UAAM,QAAQ,QAAQ,YAAY,MAAM,MAAM,kBAAkB,EAAE;AAAA,MAChE,CAAC,WAAW,OAAO,SAAS;AAAA,MAC5B,MAAM;AAAA,IACR;AACA,UAAM,QAAQ,MACZ,KAAK,MACF,KAAK,CAAC,SAAU,OAAO,QAAQ,YAAY,MAAM,OAAO,kBAAkB,IAAI,MAAU,EACxF,MAAM,MAAM,MAAS;AAC1B,SAAK,QAAQ;AAAA,MACX;AAAA,MACA,OAAO,KAAK,WAAW,MAAM,OAAO,KAAK,QAAQ;AAAA,MACjD,SAAS,KAAK,WAAW,MAAM,MAAM,KAAK,MAAM,GAAG,KAAK,SAAS;AAAA,IACnE;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,UAAM,OAAO,KAAK;AAClB,QAAI,CAAC,KAAM;AACX,SAAK,QAAQ;AACb,SAAK,WAAW,KAAK,KAAK,KAAK;AAC/B,SAAK,WAAW,KAAK,KAAK,OAAO;AACjC,UAAM,UAAU,KAAK,YAAY;AACjC,SAAK,KAAK,MACP,KAAK,CAAC,SAAU,OAAO,QAAQ,aAAa,MAAM,kBAAkB,IAAI,MAAU,EAClF,MAAM,MAAM,MAAS;AAAA,EAC1B;AAAA,EAEA,UAAgB;AACd,UAAM,OAAO,KAAK,YAAY,SAAS;AACvC,QAAI,CAAC,MAAM,QAAQ,CAAC,KAAK,SAAS,KAAK,SAAS,GAAG,EAAE,GAAG,OAAO,KAAK,GAAI;AACxE;AAAA,MACE,KAAK;AAAA,MACL;AAAA,QACE,IAAI,KAAK;AAAA,QACT,MAAM,KAAK,MAAM;AAAA,QACjB,QAAQ,KAAK,MAAM;AAAA,QACnB,QAAQ,KAAK,OAAO,OAAO,CAAC,UAAU,MAAM,OAAO,EAAE;AAAA,MACvD;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,SAAe;AACb,UAAM,OAAO,KAAK,YAAY,SAAS;AACvC,QAAI,CAAC,MAAM,QAAQ,KAAK,OAAO,KAAK,OAAQ;AAC5C,SAAK,SAAS,KAAK;AACnB,SAAK,OAAO,UAAU,KAAK,aAAa,CAAC,GAAG,KAAK,IAAI,KAAK,IAAI;AAC9D,UAAM,QAAQ,UAAU,IAAI;AAC5B,QAAI,UAAU,KAAM,QAAO,KAAK,MAAM,OAAO,WAAW;AAAA,EAC1D;AAAA,EAEA,QAAc;AACZ,UAAM,OAAO,KAAK,YAAY,SAAS;AACvC,QAAI,CAAC,MAAM,QAAQ,CAAC,KAAK,UAAW;AACpC,WAAO,KAAK,YAAY,KAAK,UAAU,QAAQ,WAAW;AAC1D,UAAM,SAAS,YAAY,KAAK,SAAS;AACzC,QAAI,WAAW,KAAM,QAAO,KAAK,SAAS,QAAQ,WAAW;AAC7D,SAAK,SAAS,KAAK,YAAY,KAAK,SAAS,CAAC;AAAA,EAChD;AAAA,EAEA,UAAgB;AACd,QAAI,CAAC,KAAK,WAAY;AACtB,SAAK,QAAQ;AACb,SAAK,OAAO;AACZ,SAAK,SAAS,KAAK,YAAY,KAAK,SAAS,CAAC;AAAA,EAChD;AACF;",
6
6
  "names": []
7
7
  }
@@ -44,5 +44,17 @@ export type Schedule = (conversation: number, tail: number, context: Context, co
44
44
  export declare function compactionHook(schedule: Schedule): import("@earendil-works/pi-durable").HookRegistration;
45
45
  export declare function scheduler(ready: Promise<Host>, task: ReturnType<typeof extractTask>, settings: (context: Context) => Promise<ExtractSettings>): Schedule;
46
46
  export declare function settingsReader(ready: Promise<Host>): (context: Context) => Promise<ExtractSettings>;
47
- export declare function idleWatch(host: Pick<Host, 'agents' | 'harness'>, schedule: Schedule, settings: (context: Context) => Promise<ExtractSettings>, everyMs: number, context: Context, now?: () => number): () => void;
47
+ export declare const IDLE_TASK = "slicc.memory-idle";
48
+ export declare const IdleDoc: import("@earendil-works/pi-durable").SessionDocToken<{
49
+ tasks: Record<string, number>;
50
+ }>;
51
+ type IdleState = {
52
+ phase: 'watch';
53
+ tail: number;
54
+ since: number;
55
+ };
56
+ export declare function idleTask(ready: Promise<Host>, schedule: Schedule, settings: (context: Context) => Promise<ExtractSettings>): import("@earendil-works/pi-durable").Task<{
57
+ cone: string;
58
+ }, IdleState, null, object>;
59
+ export declare function idleWatch(host: Pick<Host, 'agents' | 'harness'>, task: ReturnType<typeof idleTask>, context: Context): () => void;
48
60
  export {};
@@ -4,7 +4,6 @@ import { type MemoryAttach, type MemoryRuntime } from './runtime.ts';
4
4
  export { MEMORY_WRITE, whoIs } from './prompt.ts';
5
5
  export type { MemoryAttach, MemoryDraft, MemoryRuntime } from './runtime.ts';
6
6
  export { USAGE } from './runtime.ts';
7
- export declare const IDLE_CHECK_MS = 60000;
8
7
  export interface MemorySetup {
9
8
  extension: Extension;
10
9
  tools: readonly ToolRegistration[];
@@ -34,7 +34,6 @@ export interface MemoryAttach {
34
34
  home: string;
35
35
  agentDir?: string;
36
36
  reloadMs: number;
37
- idleCheckMs?: number;
38
37
  roles?: (context: Context) => Promise<{
39
38
  roles: readonly Role[];
40
39
  } | undefined>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-agent",
3
- "version": "7.3.1",
3
+ "version": "7.4.0",
4
4
  "description": "SLICC's agent core on pi durable: an agent worker, session storage, remoting and pi extensions",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -65,7 +65,7 @@
65
65
  "release": "semantic-release"
66
66
  },
67
67
  "devDependencies": {
68
- "@ai-ecoverse/slicc-kernel": "1.146.5",
68
+ "@ai-ecoverse/slicc-kernel": "1.146.7",
69
69
  "@ai-ecoverse/slicc-scrub": "1.0.0",
70
70
  "@ai-ecoverse/slicc-shared-web": "2.10.4",
71
71
  "@ai-ecoverse/slicc-spectrum": "1.107.1",