@ai-ecoverse/slicc-agent 3.41.0 → 3.42.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 +23 -4
- package/bin/agent +9 -4
- package/dist/client.js +4 -1
- package/dist/client.js.map +2 -2
- package/dist/host.js +59 -21
- package/dist/host.js.map +3 -3
- package/dist/index.js +6 -0
- package/dist/index.js.map +2 -2
- package/dist/main.js +4 -0
- package/dist/main.js.map +2 -2
- package/dist/owner.js +2 -1
- package/dist/owner.js.map +2 -2
- package/dist/readonly.js +13 -0
- package/dist/readonly.js.map +2 -2
- package/dist/remote/host.js +10 -4
- package/dist/remote/host.js.map +2 -2
- package/dist/remote/pages.js +216 -0
- package/dist/remote/pages.js.map +7 -0
- package/dist/scoops/cli.js +17 -0
- package/dist/scoops/cli.js.map +2 -2
- package/dist/scoops/index.js +4 -2
- package/dist/scoops/index.js.map +2 -2
- package/dist/scoops/requests.js +14 -2
- package/dist/scoops/requests.js.map +2 -2
- package/dist/scoops/service.js.map +1 -1
- package/dist/services.js +2 -0
- package/dist/services.js.map +2 -2
- package/dist/spectrum/index.js +7 -0
- package/dist/spectrum/index.js.map +3 -3
- package/dist/spectrum/page-port.js +132 -0
- package/dist/spectrum/page-port.js.map +7 -0
- package/dist/sprinkles/index.js +1 -2
- package/dist/sprinkles/index.js.map +2 -2
- package/dist/types/client.d.ts +2 -0
- package/dist/types/host.d.ts +8 -3
- package/dist/types/index.d.ts +3 -2
- package/dist/types/owner.d.ts +1 -0
- package/dist/types/readonly.d.ts +2 -0
- package/dist/types/remote/host.d.ts +10 -0
- package/dist/types/remote/pages.d.ts +76 -0
- package/dist/types/scoops/cli.d.ts +7 -0
- package/dist/types/scoops/index.d.ts +1 -0
- package/dist/types/scoops/requests.d.ts +2 -1
- package/dist/types/scoops/service.d.ts +1 -0
- package/dist/types/services.d.ts +2 -0
- package/dist/types/spectrum/index.d.ts +4 -0
- package/dist/types/spectrum/page-port.d.ts +32 -0
- package/dist/types/sprinkles/index.d.ts +1 -1
- package/dist/worker.js +2 -1
- package/dist/worker.js.map +2 -2
- package/package.json +1 -1
- package/packages/vfs-root/skills/agent/SKILL.md +2 -0
- package/packages/vfs-root/skills/sprinkles/SKILL.md +1 -1
package/dist/main.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/main.ts"],
|
|
4
|
-
"sourcesContent": ["import { attachKernel } from '@ai-ecoverse/slicc-kernel';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { CredentialStore, Provider } from '@earendil-works/pi-ai';\nimport {\n createRegistry,\n type ModelRef,\n type Storage,\n type ToolRegistration,\n} from '@earendil-works/pi-durable';\nimport { CodingTools } from '@earendil-works/pi-durable/tools';\nimport { type Agent, openAgent } from './agent.ts';\nimport { attachChanges, CHANGES_MS } from './changes/index.ts';\nimport {\n codemodeExtension,\n codemodeTool,\n disabledBySettings,\n locateWasm,\n sandboxFactory,\n} from './codemode/index.ts';\nimport { EncryptedCredentialStore } from './credentials.ts';\nimport { attachFreezer } from './freezer/index.ts';\nimport { settingsText, titler } from './freezer/title.ts';\nimport { lateGelatiere } from './gelatiere/index.ts';\nimport { type AgentHost, hostAgent } from './host.ts';\nimport { imageReads } from './images/index.ts';\nimport { createActivity } from './kernel/activity.ts';\nimport type { KernelClient } from './kernel/client.ts';\nimport { HOME, kernelEnvironment, SliccKernelEnv } from './kernel/env.ts';\nimport { processGroups } from './kernel/groups.ts';\nimport { adminOver, type UserClient, type UserClients, userClients } from './kernel/users.ts';\nimport { setupLicks } from './licks/index.ts';\nimport { lickTriage } from './licks/triage.ts';\nimport { setupMcp } from './mcp/index.ts';\nimport { setupMemory } from './memory/index.ts';\nimport { modelsCommand } from './models/index.ts';\nimport { type Transport, transportFetch } from './net.ts';\nimport { sliccPrompt } from './prompt.ts';\nimport { identity } from './scoops/identity.ts';\nimport { type Assets, packageAssets, type ScoopsRuntime, setupScoops } from './scoops/index.ts';\nimport {\n createAgentSettings,\n createSliccModels,\n DEFAULT_MODEL,\n sliccProviders,\n} from './settings.ts';\nimport { RELOAD_MS, setupSkills } from './skills/index.ts';\nimport { setupSprinkles } from './sprinkles/index.ts';\nimport { openOpfsSqliteStorage } from './sqlite.ts';\nimport {\n agentVersion,\n browserConnected,\n commandsOnPath,\n kernelBoot,\n transportName,\n} from './system.ts';\nimport { type KernelPorts, kernelPorts, serveConnections, type WorkerScope } from './worker.ts';\n\nexport interface AgentWorkerScope extends WorkerScope {\n fetch: typeof fetch;\n location: { origin: string };\n}\n\nexport type KernelAttach = (port: MessagePort) => Promise<KernelClient & { transport: Transport }>;\n\nexport interface AgentWorkerOptions {\n model?: ModelRef;\n providers?: Provider[];\n attach?: KernelAttach;\n credentials?: () => Promise<CredentialStore>;\n storage?: () => Promise<Storage>;\n assets?: Assets;\n codemodeWasm?: () => Promise<WebAssembly.Module | undefined>;\n codemodeWorker?: string | URL;\n catalog?: string;\n users?: boolean;\n mcpRedirect?: string;\n}\n\nexport function usersOf(\n admin: MessagePort | undefined,\n wanted: boolean | undefined,\n attach: KernelAttach\n): UserClients | undefined {\n if (!admin) return undefined;\n if (wanted === false) {\n admin.close();\n return undefined;\n }\n return userClients(adminOver(admin), attach as (port: MessagePort) => Promise<UserClient>);\n}\n\nexport const STORE_DIR = '/.slicc';\n\nasync function attached(ports: Promise<KernelPorts>, options: AgentWorkerOptions) {\n const attach: KernelAttach = options.attach ?? attachKernel;\n const { kernel, admin } = await ports;\n const client = await attach(kernel);\n return { client, users: usersOf(admin, options.users, attach) };\n}\n\nfunction privateStore(env: SliccKernelEnv): Promise<unknown> {\n return env.exec(`mkdir -p ${STORE_DIR} && chmod 700 ${STORE_DIR}`, undefined, BACKGROUND_CONTEXT);\n}\n\nasync function codemodeTools(\n client: KernelClient,\n options: AgentWorkerOptions,\n native: typeof fetch,\n extra: Parameters<typeof codemodeTool>[0]['extra']\n) {\n const settings = await client.fs\n .readFile(`${HOME}/.pi/agent/settings.json`)\n .catch(() => undefined);\n if (disabledBySettings(settings === undefined ? undefined : new TextDecoder().decode(settings)))\n return [];\n const sandbox = sandboxFactory(\n options.codemodeWasm ?? (() => locateWasm(native, new URL(import.meta.url))),\n options.codemodeWorker\n );\n return [\n codemodeTool({ declared: CodingTools.tools as readonly ToolRegistration[], sandbox, extra }),\n ];\n}\n\nexport const MCP_CALLBACK = '/oauth/mcp-callback';\n\nasync function start(\n scope: AgentWorkerScope,\n ports: Promise<KernelPorts>,\n options: AgentWorkerOptions\n): Promise<AgentHost> {\n const { client, users } = await attached(ports, options);\n const home = new SliccKernelEnv(client, { cwd: HOME });\n await privateStore(home);\n const native = scope.fetch.bind(scope);\n scope.fetch = transportFetch(client.transport, scope.location.origin, native);\n const facts = {\n version: await agentVersion((url) => native(url)),\n commands: await commandsOnPath(client),\n transport: transportName(client.transport),\n browser: await browserConnected(client),\n };\n const credentials = await (options.credentials ?? (() => EncryptedCredentialStore.open()))();\n const providers = options.providers ?? sliccProviders();\n const models = createSliccModels(credentials, providers);\n const registry = createRegistry();\n registry.install(CodingTools);\n registry.install(sliccPrompt(facts));\n registry.install(\n imageReads(\n (CodingTools.tools as readonly ToolRegistration[]).find(\n (tool) => tool.name === 'read'\n ) as ToolRegistration\n )\n );\n const memory = setupMemory(registry);\n const coding = CodingTools.tools as readonly ToolRegistration[];\n const mcp = setupMcp(registry);\n const codemode = await codemodeTools(client, options, native, mcp.codemode);\n registry.install(codemodeExtension(codemode));\n const licks = setupLicks(registry);\n licks.licks.triage(lickTriage(models));\n const scoops = setupScoops(registry, licks.licks, [...coding, ...codemode, ...memory.tools]);\n const skills = setupSkills(registry, licks.licks);\n const activity = createActivity();\n const groups = processGroups(client);\n const model = options.model ?? DEFAULT_MODEL;\n let opened: Agent | undefined;\n const environment = kernelEnvironment(client, {\n activity,\n groups,\n identify: identity(() => opened?.agents, model),\n });\n const agent = await openAgent({\n models,\n model,\n storage: await (options.storage ?? (() => openOpfsSqliteStorage()))(),\n registry,\n env: environment,\n });\n opened = agent;\n const sources = licks.attach(agent, { env: home, home: HOME, activity });\n await sources.start(BACKGROUND_CONTEXT);\n await sources.boot(\n { version: facts.version, boot: await kernelBoot(client) },\n BACKGROUND_CONTEXT\n );\n const skillsRuntime = await skills.attach(\n { env: home, home: HOME, assets: options.assets ?? packageAssets(), reloadMs: RELOAD_MS },\n BACKGROUND_CONTEXT\n );\n const mcpRuntime = await mcp.attach(\n {\n env: home,\n home: HOME,\n credentials,\n licks: licks.licks,\n fetch: scope.fetch,\n version: facts.version,\n reloadMs: RELOAD_MS,\n codemode: codemode.length > 0,\n cors: client.transport.traits?.crossOrigin === 'cors',\n redirect: options.mcpRedirect ?? new URL(MCP_CALLBACK, scope.location.origin).href,\n },\n BACKGROUND_CONTEXT\n );\n const gelatiere = lateGelatiere();\n const sprinkles = await setupSprinkles().attach(\n {\n intercept: gelatiere.intercept,\n harness: agent.harness,\n agents: agent.agents,\n licks: licks.licks,\n env: home,\n assets: options.assets ?? packageAssets(),\n reloadMs: RELOAD_MS,\n },\n BACKGROUND_CONTEXT\n );\n let roles: ScoopsRuntime | undefined;\n const memoryRuntime = await memory.attach(\n {\n harness: agent.harness,\n agents: agent.agents,\n env: home,\n home: HOME,\n reloadMs: RELOAD_MS,\n roles: async (using) => roles?.roles(using),\n },\n BACKGROUND_CONTEXT\n );\n const freezer = attachFreezer({\n harness: agent.harness,\n agents: agent.agents,\n env: home,\n extract: memory.extract,\n title: titler(models, settingsText(home, HOME)),\n });\n licks.licks.guard(freezer.frozenTarget);\n const settings = await createAgentSettings(models, credentials, providers, { mcp: mcpRuntime });\n const runtime = await scoops.attach(\n {\n harness: agent.harness,\n agents: agent.agents,\n groups,\n env: home,\n home: HOME,\n alive: alive(client),\n reads: skillsRuntime.dirs,\n sprinkle: sprinkles.command,\n memory: memoryRuntime.command,\n gelatiere: gelatiere.command,\n freezer: freezer.command,\n models: modelsCommand({ agents: agent.agents, settings, catalog: models }),\n mcp: mcp.direct,\n ...(options.assets ? { assets: options.assets } : {}),\n },\n BACKGROUND_CONTEXT\n );\n roles = runtime;\n gelatiere.attach({\n agents: agent.agents,\n licks: licks.licks,\n env: home,\n home: HOME,\n scoops: scoops.scoops,\n roles: runtime.roles,\n assets: options.assets ?? packageAssets(),\n fetch: scope.fetch,\n skills: skillsRuntime.skills,\n ...(options.catalog ? { catalog: options.catalog } : {}),\n });\n await memoryRuntime.reload(BACKGROUND_CONTEXT).catch(() => undefined);\n const changes = attachChanges({ agents: agent.agents, env: home, reloadMs: CHANGES_MS });\n return hostAgent(agent, {\n settings,\n licks: { licks: licks.licks, sources },\n scoops: { scoops: scoops.scoops, runtime },\n skills: skillsRuntime,\n sprinkles,\n memory: memoryRuntime,\n freezer,\n changes,\n mcp: mcpRuntime,\n ...(users ? { users } : {}),\n monitor: {\n kernel: client,\n groups,\n ...(users ? { users: () => users.users.list() } : {}),\n secrets: () => mcpRuntime.secrets(),\n },\n });\n}\n\nexport function alive(client: KernelClient) {\n return async (pid: number): Promise<boolean> => {\n if (!client.ps) return true;\n return (await client.ps()).some((process) => process.pid === pid);\n };\n}\n\nexport function runAgentWorker(\n scope: AgentWorkerScope,\n options: AgentWorkerOptions = {}\n): Promise<AgentHost> {\n const host = start(scope, kernelPorts(scope), options);\n host.catch(() => undefined);\n serveConnections(scope, host);\n return host;\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AAEnC;AAAA,EACE;AAAA,OAIK;AACP,SAAS,mBAAmB;AAC5B,SAAqB,iBAAiB;AACtC,SAAS,eAAe,kBAAkB;AAC1C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,gCAAgC;AACzC,SAAS,qBAAqB;AAC9B,SAAS,cAAc,cAAc;AACrC,SAAS,qBAAqB;AAC9B,SAAyB,iBAAiB;AAC1C,SAAS,kBAAkB;AAC3B,SAAS,sBAAsB;AAE/B,SAAS,MAAM,mBAAmB,sBAAsB;AACxD,SAAS,qBAAqB;AAC9B,SAAS,WAA8C,mBAAmB;AAC1E,SAAS,kBAAkB;AAC3B,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,SAAS,mBAAmB;AAC5B,SAAS,qBAAqB;AAC9B,SAAyB,sBAAsB;AAC/C,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB;AACzB,SAAsB,eAAmC,mBAAmB;AAC5E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,WAAW,mBAAmB;AACvC,SAAS,sBAAsB;AAC/B,SAAS,6BAA6B;AACtC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAA2B,aAAa,wBAA0C;AAuB3E,SAAS,QACd,OACA,QACA,QACyB;AACzB,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,WAAW,OAAO;AACpB,UAAM,MAAM;AACZ,WAAO;AAAA,EACT;AACA,SAAO,YAAY,UAAU,KAAK,GAAG,MAAoD;AAC3F;AAEO,MAAM,YAAY;AAEzB,eAAe,SAAS,OAA6B,SAA6B;AAChF,QAAM,SAAuB,QAAQ,UAAU;AAC/C,QAAM,EAAE,QAAQ,MAAM,IAAI,MAAM;AAChC,QAAM,SAAS,MAAM,OAAO,MAAM;AAClC,SAAO,EAAE,QAAQ,OAAO,QAAQ,OAAO,QAAQ,OAAO,MAAM,EAAE;AAChE;AAEA,SAAS,aAAa,KAAuC;AAC3D,SAAO,IAAI,KAAK,YAAY,SAAS,iBAAiB,SAAS,IAAI,QAAW,kBAAkB;AAClG;AAEA,eAAe,cACb,QACA,SACA,QACA,OACA;AACA,QAAM,WAAW,MAAM,OAAO,GAC3B,SAAS,GAAG,IAAI,0BAA0B,EAC1C,MAAM,MAAM,MAAS;AACxB,MAAI,mBAAmB,aAAa,SAAY,SAAY,IAAI,YAAY,EAAE,OAAO,QAAQ,CAAC;AAC5F,WAAO,CAAC;AACV,QAAM,UAAU;AAAA,IACd,QAAQ,iBAAiB,MAAM,WAAW,QAAQ,IAAI,IAAI,YAAY,GAAG,CAAC;AAAA,IAC1E,QAAQ;AAAA,EACV;AACA,SAAO;AAAA,IACL,aAAa,EAAE,UAAU,YAAY,OAAsC,SAAS,MAAM,CAAC;AAAA,EAC7F;AACF;AAEO,MAAM,eAAe;AAE5B,eAAe,MACb,OACA,OACA,SACoB;AACpB,QAAM,EAAE,QAAQ,MAAM,IAAI,MAAM,SAAS,OAAO,OAAO;AACvD,QAAM,OAAO,IAAI,eAAe,QAAQ,EAAE,KAAK,KAAK,CAAC;AACrD,QAAM,aAAa,IAAI;AACvB,QAAM,SAAS,MAAM,MAAM,KAAK,KAAK;AACrC,QAAM,QAAQ,eAAe,OAAO,WAAW,MAAM,SAAS,QAAQ,MAAM;AAC5E,QAAM,QAAQ;AAAA,IACZ,SAAS,MAAM,aAAa,CAAC,QAAQ,OAAO,GAAG,CAAC;AAAA,IAChD,UAAU,MAAM,eAAe,MAAM;AAAA,IACrC,WAAW,cAAc,OAAO,SAAS;AAAA,IACzC,SAAS,MAAM,iBAAiB,MAAM;AAAA,EACxC;AACA,QAAM,cAAc,OAAO,QAAQ,gBAAgB,MAAM,yBAAyB,KAAK,IAAI;AAC3F,QAAM,YAAY,QAAQ,aAAa,eAAe;AACtD,QAAM,SAAS,kBAAkB,aAAa,SAAS;AACvD,QAAM,WAAW,eAAe;AAChC,WAAS,QAAQ,WAAW;AAC5B,WAAS,QAAQ,YAAY,KAAK,CAAC;AACnC,WAAS;AAAA,IACP;AAAA,MACG,YAAY,MAAsC;AAAA,QACjD,CAAC,SAAS,KAAK,SAAS;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AACA,QAAM,SAAS,YAAY,QAAQ;AACnC,QAAM,SAAS,YAAY;AAC3B,QAAM,MAAM,SAAS,QAAQ;AAC7B,QAAM,WAAW,MAAM,cAAc,QAAQ,SAAS,QAAQ,IAAI,QAAQ;AAC1E,WAAS,QAAQ,kBAAkB,QAAQ,CAAC;AAC5C,QAAM,QAAQ,WAAW,QAAQ;AACjC,QAAM,MAAM,OAAO,WAAW,MAAM,CAAC;AACrC,QAAM,SAAS,YAAY,UAAU,MAAM,OAAO,CAAC,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,KAAK,CAAC;AAC3F,QAAM,SAAS,YAAY,UAAU,MAAM,KAAK;AAChD,QAAM,WAAW,eAAe;AAChC,QAAM,SAAS,cAAc,MAAM;AACnC,QAAM,QAAQ,QAAQ,SAAS;AAC/B,MAAI;AACJ,QAAM,cAAc,kBAAkB,QAAQ;AAAA,IAC5C;AAAA,IACA;AAAA,IACA,UAAU,SAAS,MAAM,QAAQ,QAAQ,KAAK;AAAA,EAChD,CAAC;AACD,QAAM,QAAQ,MAAM,UAAU;AAAA,IAC5B;AAAA,IACA;AAAA,IACA,SAAS,OAAO,QAAQ,YAAY,MAAM,sBAAsB,IAAI;AAAA,IACpE;AAAA,IACA,KAAK;AAAA,EACP,CAAC;AACD,WAAS;AACT,QAAM,UAAU,MAAM,OAAO,OAAO,EAAE,KAAK,MAAM,MAAM,MAAM,SAAS,CAAC;AACvE,QAAM,QAAQ,MAAM,kBAAkB;AACtC,QAAM,QAAQ;AAAA,IACZ,EAAE,SAAS,MAAM,SAAS,MAAM,MAAM,WAAW,MAAM,EAAE;AAAA,IACzD;AAAA,EACF;AACA,QAAM,gBAAgB,MAAM,OAAO;AAAA,IACjC,EAAE,KAAK,MAAM,MAAM,MAAM,QAAQ,QAAQ,UAAU,cAAc,GAAG,UAAU,UAAU;AAAA,IACxF;AAAA,EACF;AACA,QAAM,aAAa,MAAM,IAAI;AAAA,IAC3B;AAAA,MACE,KAAK;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA,OAAO,MAAM;AAAA,MACb,OAAO,MAAM;AAAA,MACb,SAAS,MAAM;AAAA,MACf,UAAU;AAAA,MACV,UAAU,SAAS,SAAS;AAAA,MAC5B,MAAM,OAAO,UAAU,QAAQ,gBAAgB;AAAA,MAC/C,UAAU,QAAQ,eAAe,IAAI,IAAI,cAAc,MAAM,SAAS,MAAM,EAAE;AAAA,IAChF;AAAA,IACA;AAAA,EACF;AACA,QAAM,YAAY,cAAc;AAChC,QAAM,YAAY,MAAM,eAAe,EAAE;AAAA,IACvC;AAAA,MACE,WAAW,UAAU;AAAA,MACrB,SAAS,MAAM;AAAA,MACf,QAAQ,MAAM;AAAA,MACd,OAAO,MAAM;AAAA,MACb,KAAK;AAAA,MACL,QAAQ,QAAQ,UAAU,cAAc;AAAA,MACxC,UAAU;AAAA,IACZ;AAAA,IACA;AAAA,EACF;AACA,MAAI;AACJ,QAAM,gBAAgB,MAAM,OAAO;AAAA,IACjC;AAAA,MACE,SAAS,MAAM;AAAA,MACf,QAAQ,MAAM;AAAA,MACd,KAAK;AAAA,MACL,MAAM;AAAA,MACN,UAAU;AAAA,MACV,OAAO,OAAO,UAAU,OAAO,MAAM,KAAK;AAAA,IAC5C;AAAA,IACA;AAAA,EACF;AACA,QAAM,UAAU,cAAc;AAAA,IAC5B,SAAS,MAAM;AAAA,IACf,QAAQ,MAAM;AAAA,IACd,KAAK;AAAA,IACL,SAAS,OAAO;AAAA,IAChB,OAAO,OAAO,QAAQ,aAAa,MAAM,IAAI,CAAC;AAAA,EAChD,CAAC;AACD,QAAM,MAAM,MAAM,QAAQ,YAAY;AACtC,QAAM,WAAW,MAAM,oBAAoB,QAAQ,aAAa,WAAW,EAAE,KAAK,WAAW,CAAC;AAC9F,QAAM,UAAU,MAAM,OAAO;AAAA,IAC3B;AAAA,MACE,SAAS,MAAM;AAAA,MACf,QAAQ,MAAM;AAAA,MACd;AAAA,MACA,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO,MAAM,MAAM;AAAA,MACnB,OAAO,cAAc;AAAA,MACrB,UAAU,UAAU;AAAA,MACpB,QAAQ,cAAc;AAAA,MACtB,WAAW,UAAU;AAAA,MACrB,SAAS,QAAQ;AAAA,MACjB,QAAQ,cAAc,EAAE,QAAQ,MAAM,QAAQ,UAAU,SAAS,OAAO,CAAC;AAAA,MACzE,KAAK,IAAI;AAAA,MACT,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,IACrD;AAAA,IACA;AAAA,EACF;AACA,UAAQ;AACR,YAAU,OAAO;AAAA,IACf,QAAQ,MAAM;AAAA,IACd,OAAO,MAAM;AAAA,IACb,KAAK;AAAA,IACL,MAAM;AAAA,IACN,QAAQ,OAAO;AAAA,IACf,OAAO,QAAQ;AAAA,IACf,QAAQ,QAAQ,UAAU,cAAc;AAAA,IACxC,OAAO,MAAM;AAAA,IACb,QAAQ,cAAc;AAAA,IACtB,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;AAAA,EACxD,CAAC;AACD,QAAM,cAAc,OAAO,kBAAkB,EAAE,MAAM,MAAM,MAAS;AACpE,QAAM,UAAU,cAAc,EAAE,QAAQ,MAAM,QAAQ,KAAK,MAAM,UAAU,WAAW,CAAC;AACvF,SAAO,UAAU,OAAO;AAAA,IACtB;AAAA,IACA,OAAO,EAAE,OAAO,MAAM,OAAO,QAAQ;AAAA,IACrC,QAAQ,EAAE,QAAQ,OAAO,QAAQ,QAAQ;AAAA,IACzC,QAAQ;AAAA,IACR;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA,KAAK;AAAA,IACL,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IACzB,SAAS;AAAA,MACP,QAAQ;AAAA,MACR;AAAA,MACA,GAAI,QAAQ,EAAE,OAAO,MAAM,MAAM,MAAM,KAAK,EAAE,IAAI,CAAC;AAAA,MACnD,SAAS,MAAM,WAAW,QAAQ;AAAA,IACpC;AAAA,EACF,CAAC;AACH;AAEO,SAAS,MAAM,QAAsB;AAC1C,SAAO,OAAO,QAAkC;AAC9C,QAAI,CAAC,OAAO,GAAI,QAAO;AACvB,YAAQ,MAAM,OAAO,GAAG,GAAG,KAAK,CAAC,YAAY,QAAQ,QAAQ,GAAG;AAAA,EAClE;AACF;AAEO,SAAS,eACd,OACA,UAA8B,CAAC,GACX;AACpB,QAAM,OAAO,MAAM,OAAO,YAAY,KAAK,GAAG,OAAO;AACrD,OAAK,MAAM,MAAM,MAAS;AAC1B,mBAAiB,OAAO,IAAI;AAC5B,SAAO;AACT;",
|
|
4
|
+
"sourcesContent": ["import { attachKernel } from '@ai-ecoverse/slicc-kernel';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { CredentialStore, Provider } from '@earendil-works/pi-ai';\nimport {\n createRegistry,\n type ModelRef,\n type Storage,\n type ToolRegistration,\n} from '@earendil-works/pi-durable';\nimport { CodingTools } from '@earendil-works/pi-durable/tools';\nimport { type Agent, openAgent } from './agent.ts';\nimport { attachChanges, CHANGES_MS } from './changes/index.ts';\nimport {\n codemodeExtension,\n codemodeTool,\n disabledBySettings,\n locateWasm,\n sandboxFactory,\n} from './codemode/index.ts';\nimport { EncryptedCredentialStore } from './credentials.ts';\nimport { attachFreezer } from './freezer/index.ts';\nimport { settingsText, titler } from './freezer/title.ts';\nimport { lateGelatiere } from './gelatiere/index.ts';\nimport { type AgentHost, hostAgent } from './host.ts';\nimport { imageReads } from './images/index.ts';\nimport { createActivity } from './kernel/activity.ts';\nimport type { KernelClient } from './kernel/client.ts';\nimport { HOME, kernelEnvironment, SliccKernelEnv } from './kernel/env.ts';\nimport { processGroups } from './kernel/groups.ts';\nimport { adminOver, type UserClient, type UserClients, userClients } from './kernel/users.ts';\nimport { setupLicks } from './licks/index.ts';\nimport { lickTriage } from './licks/triage.ts';\nimport { setupMcp } from './mcp/index.ts';\nimport { setupMemory } from './memory/index.ts';\nimport { modelsCommand } from './models/index.ts';\nimport { type Transport, transportFetch } from './net.ts';\nimport { sliccPrompt } from './prompt.ts';\nimport { createPages } from './remote/pages.ts';\nimport { identity } from './scoops/identity.ts';\nimport { type Assets, packageAssets, type ScoopsRuntime, setupScoops } from './scoops/index.ts';\nimport {\n createAgentSettings,\n createSliccModels,\n DEFAULT_MODEL,\n sliccProviders,\n} from './settings.ts';\nimport { RELOAD_MS, setupSkills } from './skills/index.ts';\nimport { setupSprinkles } from './sprinkles/index.ts';\nimport { openOpfsSqliteStorage } from './sqlite.ts';\nimport {\n agentVersion,\n browserConnected,\n commandsOnPath,\n kernelBoot,\n transportName,\n} from './system.ts';\nimport { type KernelPorts, kernelPorts, serveConnections, type WorkerScope } from './worker.ts';\n\nexport interface AgentWorkerScope extends WorkerScope {\n fetch: typeof fetch;\n location: { origin: string };\n}\n\nexport type KernelAttach = (port: MessagePort) => Promise<KernelClient & { transport: Transport }>;\n\nexport interface AgentWorkerOptions {\n model?: ModelRef;\n providers?: Provider[];\n attach?: KernelAttach;\n credentials?: () => Promise<CredentialStore>;\n storage?: () => Promise<Storage>;\n assets?: Assets;\n codemodeWasm?: () => Promise<WebAssembly.Module | undefined>;\n codemodeWorker?: string | URL;\n catalog?: string;\n users?: boolean;\n mcpRedirect?: string;\n}\n\nexport function usersOf(\n admin: MessagePort | undefined,\n wanted: boolean | undefined,\n attach: KernelAttach\n): UserClients | undefined {\n if (!admin) return undefined;\n if (wanted === false) {\n admin.close();\n return undefined;\n }\n return userClients(adminOver(admin), attach as (port: MessagePort) => Promise<UserClient>);\n}\n\nexport const STORE_DIR = '/.slicc';\n\nasync function attached(ports: Promise<KernelPorts>, options: AgentWorkerOptions) {\n const attach: KernelAttach = options.attach ?? attachKernel;\n const { kernel, admin } = await ports;\n const client = await attach(kernel);\n return { client, users: usersOf(admin, options.users, attach) };\n}\n\nfunction privateStore(env: SliccKernelEnv): Promise<unknown> {\n return env.exec(`mkdir -p ${STORE_DIR} && chmod 700 ${STORE_DIR}`, undefined, BACKGROUND_CONTEXT);\n}\n\nasync function codemodeTools(\n client: KernelClient,\n options: AgentWorkerOptions,\n native: typeof fetch,\n extra: Parameters<typeof codemodeTool>[0]['extra']\n) {\n const settings = await client.fs\n .readFile(`${HOME}/.pi/agent/settings.json`)\n .catch(() => undefined);\n if (disabledBySettings(settings === undefined ? undefined : new TextDecoder().decode(settings)))\n return [];\n const sandbox = sandboxFactory(\n options.codemodeWasm ?? (() => locateWasm(native, new URL(import.meta.url))),\n options.codemodeWorker\n );\n return [\n codemodeTool({ declared: CodingTools.tools as readonly ToolRegistration[], sandbox, extra }),\n ];\n}\n\nexport const MCP_CALLBACK = '/oauth/mcp-callback';\n\nasync function start(\n scope: AgentWorkerScope,\n ports: Promise<KernelPorts>,\n options: AgentWorkerOptions\n): Promise<AgentHost> {\n const { client, users } = await attached(ports, options);\n const home = new SliccKernelEnv(client, { cwd: HOME });\n await privateStore(home);\n const native = scope.fetch.bind(scope);\n scope.fetch = transportFetch(client.transport, scope.location.origin, native);\n const facts = {\n version: await agentVersion((url) => native(url)),\n commands: await commandsOnPath(client),\n transport: transportName(client.transport),\n browser: await browserConnected(client),\n };\n const credentials = await (options.credentials ?? (() => EncryptedCredentialStore.open()))();\n const providers = options.providers ?? sliccProviders();\n const models = createSliccModels(credentials, providers);\n const registry = createRegistry();\n registry.install(CodingTools);\n registry.install(sliccPrompt(facts));\n registry.install(\n imageReads(\n (CodingTools.tools as readonly ToolRegistration[]).find(\n (tool) => tool.name === 'read'\n ) as ToolRegistration\n )\n );\n const memory = setupMemory(registry);\n const coding = CodingTools.tools as readonly ToolRegistration[];\n const mcp = setupMcp(registry);\n const codemode = await codemodeTools(client, options, native, mcp.codemode);\n registry.install(codemodeExtension(codemode));\n const licks = setupLicks(registry);\n licks.licks.triage(lickTriage(models));\n const scoops = setupScoops(registry, licks.licks, [...coding, ...codemode, ...memory.tools]);\n const skills = setupSkills(registry, licks.licks);\n const activity = createActivity();\n const groups = processGroups(client);\n const model = options.model ?? DEFAULT_MODEL;\n let opened: Agent | undefined;\n const environment = kernelEnvironment(client, {\n activity,\n groups,\n identify: identity(() => opened?.agents, model),\n });\n const agent = await openAgent({\n models,\n model,\n storage: await (options.storage ?? (() => openOpfsSqliteStorage()))(),\n registry,\n env: environment,\n });\n opened = agent;\n const sources = licks.attach(agent, { env: home, home: HOME, activity });\n await sources.start(BACKGROUND_CONTEXT);\n await sources.boot(\n { version: facts.version, boot: await kernelBoot(client) },\n BACKGROUND_CONTEXT\n );\n const skillsRuntime = await skills.attach(\n { env: home, home: HOME, assets: options.assets ?? packageAssets(), reloadMs: RELOAD_MS },\n BACKGROUND_CONTEXT\n );\n const mcpRuntime = await mcp.attach(\n {\n env: home,\n home: HOME,\n credentials,\n licks: licks.licks,\n fetch: scope.fetch,\n version: facts.version,\n reloadMs: RELOAD_MS,\n codemode: codemode.length > 0,\n cors: client.transport.traits?.crossOrigin === 'cors',\n redirect: options.mcpRedirect ?? new URL(MCP_CALLBACK, scope.location.origin).href,\n },\n BACKGROUND_CONTEXT\n );\n const gelatiere = lateGelatiere();\n const sprinkles = await setupSprinkles().attach(\n {\n intercept: gelatiere.intercept,\n harness: agent.harness,\n agents: agent.agents,\n licks: licks.licks,\n env: home,\n assets: options.assets ?? packageAssets(),\n reloadMs: RELOAD_MS,\n },\n BACKGROUND_CONTEXT\n );\n let roles: ScoopsRuntime | undefined;\n const memoryRuntime = await memory.attach(\n {\n harness: agent.harness,\n agents: agent.agents,\n env: home,\n home: HOME,\n reloadMs: RELOAD_MS,\n roles: async (using) => roles?.roles(using),\n },\n BACKGROUND_CONTEXT\n );\n const freezer = attachFreezer({\n harness: agent.harness,\n agents: agent.agents,\n env: home,\n extract: memory.extract,\n title: titler(models, settingsText(home, HOME)),\n });\n licks.licks.guard(freezer.frozenTarget);\n const settings = await createAgentSettings(models, credentials, providers, { mcp: mcpRuntime });\n const pages = createPages();\n const runtime = await scoops.attach(\n {\n harness: agent.harness,\n agents: agent.agents,\n groups,\n env: home,\n home: HOME,\n alive: alive(client),\n reads: skillsRuntime.dirs,\n sprinkle: sprinkles.command,\n memory: memoryRuntime.command,\n gelatiere: gelatiere.command,\n freezer: freezer.command,\n models: modelsCommand({ agents: agent.agents, settings, catalog: models }),\n panel: pages.command,\n mcp: mcp.direct,\n ...(options.assets ? { assets: options.assets } : {}),\n },\n BACKGROUND_CONTEXT\n );\n roles = runtime;\n gelatiere.attach({\n agents: agent.agents,\n licks: licks.licks,\n env: home,\n home: HOME,\n scoops: scoops.scoops,\n roles: runtime.roles,\n assets: options.assets ?? packageAssets(),\n fetch: scope.fetch,\n skills: skillsRuntime.skills,\n ...(options.catalog ? { catalog: options.catalog } : {}),\n });\n await memoryRuntime.reload(BACKGROUND_CONTEXT).catch(() => undefined);\n const changes = attachChanges({ agents: agent.agents, env: home, reloadMs: CHANGES_MS });\n return hostAgent(agent, {\n settings,\n licks: { licks: licks.licks, sources },\n scoops: { scoops: scoops.scoops, runtime },\n skills: skillsRuntime,\n sprinkles,\n memory: memoryRuntime,\n freezer,\n changes,\n pages,\n mcp: mcpRuntime,\n ...(users ? { users } : {}),\n monitor: {\n kernel: client,\n groups,\n ...(users ? { users: () => users.users.list() } : {}),\n secrets: () => mcpRuntime.secrets(),\n },\n });\n}\n\nexport function alive(client: KernelClient) {\n return async (pid: number): Promise<boolean> => {\n if (!client.ps) return true;\n return (await client.ps()).some((process) => process.pid === pid);\n };\n}\n\nexport function runAgentWorker(\n scope: AgentWorkerScope,\n options: AgentWorkerOptions = {}\n): Promise<AgentHost> {\n const host = start(scope, kernelPorts(scope), options);\n host.catch(() => undefined);\n serveConnections(scope, host);\n return host;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/owner.js
CHANGED
|
@@ -46,7 +46,8 @@ async function startAgent(options) {
|
|
|
46
46
|
if (!ready) throw new Error("the agent was released");
|
|
47
47
|
const { port1, port2 } = channel();
|
|
48
48
|
const readOnly = portOptions.readOnly === true ? { readOnly: true } : {};
|
|
49
|
-
|
|
49
|
+
const pages = portOptions.pages === false ? { pages: false } : {};
|
|
50
|
+
ready.postMessage({ connect: port2, ...readOnly, ...pages }, [port2]);
|
|
50
51
|
return port1;
|
|
51
52
|
};
|
|
52
53
|
return {
|
package/dist/owner.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/owner.ts"],
|
|
4
|
-
"sourcesContent": ["import { type AgentConnection, connectAgent } from './client.ts';\nimport { type KernelSource, serveAdmin } from './kernel/users.ts';\nimport { holdLock } from './opfs-pool.ts';\nimport type { PortEndpoint } from './wire.ts';\n\nexport const AGENT_LOCK = 'slicc-agent';\n\nexport interface AgentWorker {\n postMessage(message: unknown, transfer: Transferable[]): void;\n terminate(): void;\n}\n\nexport interface PortOptions {\n readOnly?: boolean;\n}\n\nexport interface AgentOwner {\n connect(options?: PortOptions): Promise<AgentConnection>;\n port(options?: PortOptions): Promise<PortEndpoint & Transferable>;\n restart(): Promise<void>;\n release(): Promise<void>;\n}\n\nexport type { KernelSource } from './kernel/users.ts';\n\nexport interface OwnerOptions {\n worker: () => AgentWorker;\n kernel?: KernelSource;\n locks?: LockManager;\n held?: boolean;\n channel?: () => { port1: PortEndpoint & Transferable; port2: Transferable };\n}\n\nexport async function startAgent(options: OwnerOptions): Promise<AgentOwner> {\n const release = options.held\n ? () => undefined\n : await holdLock(options.locks ?? navigator.locks, AGENT_LOCK);\n const channel = options.channel ?? (() => new MessageChannel());\n const spawn = async (): Promise<AgentWorker> => {\n const created = options.worker();\n let admin: (PortEndpoint & Transferable) | undefined;\n try {\n if (options.kernel) {\n const port = await options.kernel.connect();\n if (!options.kernel.users) created.postMessage({ kernel: port }, [port]);\n else {\n const { port1, port2 } = channel();\n admin = port1;\n serveAdmin(port1, options.kernel);\n created.postMessage({ kernel: port, admin: port2 }, [port, port2]);\n }\n }\n } catch (error) {\n admin?.close?.();\n created.terminate();\n throw error;\n }\n if (!admin) return created;\n const served = admin;\n return {\n postMessage: (message, transfer) => created.postMessage(message, transfer),\n terminate() {\n served.close?.();\n created.terminate();\n },\n };\n };\n let worker: Promise<AgentWorker | undefined> = Promise.resolve().then(spawn);\n try {\n await worker;\n } catch (error) {\n release();\n throw error;\n }\n const open = async (portOptions: PortOptions = {}): Promise<PortEndpoint & Transferable> => {\n const ready = await worker;\n if (!ready) throw new Error('the agent was released');\n const { port1, port2 } = channel();\n const readOnly = portOptions.readOnly === true ? { readOnly: true } : {};\n ready.postMessage({ connect: port2, ...readOnly }, [port2]);\n return port1;\n };\n return {\n async connect(portOptions) {\n return connectAgent(await open(portOptions));\n },\n port: open,\n restart() {\n worker = worker\n .catch(() => undefined)\n .then((old) => {\n old?.terminate();\n return spawn();\n });\n return worker.then(() => undefined);\n },\n async release() {\n const previous = worker;\n worker = Promise.resolve(undefined);\n try {\n (await previous.catch(() => undefined))?.terminate();\n } finally {\n release();\n }\n },\n };\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAA+B,oBAAoB;AACnD,SAA4B,kBAAkB;AAC9C,SAAS,gBAAgB;AAGlB,MAAM,aAAa;
|
|
4
|
+
"sourcesContent": ["import { type AgentConnection, connectAgent } from './client.ts';\nimport { type KernelSource, serveAdmin } from './kernel/users.ts';\nimport { holdLock } from './opfs-pool.ts';\nimport type { PortEndpoint } from './wire.ts';\n\nexport const AGENT_LOCK = 'slicc-agent';\n\nexport interface AgentWorker {\n postMessage(message: unknown, transfer: Transferable[]): void;\n terminate(): void;\n}\n\nexport interface PortOptions {\n readOnly?: boolean;\n pages?: boolean;\n}\n\nexport interface AgentOwner {\n connect(options?: PortOptions): Promise<AgentConnection>;\n port(options?: PortOptions): Promise<PortEndpoint & Transferable>;\n restart(): Promise<void>;\n release(): Promise<void>;\n}\n\nexport type { KernelSource } from './kernel/users.ts';\n\nexport interface OwnerOptions {\n worker: () => AgentWorker;\n kernel?: KernelSource;\n locks?: LockManager;\n held?: boolean;\n channel?: () => { port1: PortEndpoint & Transferable; port2: Transferable };\n}\n\nexport async function startAgent(options: OwnerOptions): Promise<AgentOwner> {\n const release = options.held\n ? () => undefined\n : await holdLock(options.locks ?? navigator.locks, AGENT_LOCK);\n const channel = options.channel ?? (() => new MessageChannel());\n const spawn = async (): Promise<AgentWorker> => {\n const created = options.worker();\n let admin: (PortEndpoint & Transferable) | undefined;\n try {\n if (options.kernel) {\n const port = await options.kernel.connect();\n if (!options.kernel.users) created.postMessage({ kernel: port }, [port]);\n else {\n const { port1, port2 } = channel();\n admin = port1;\n serveAdmin(port1, options.kernel);\n created.postMessage({ kernel: port, admin: port2 }, [port, port2]);\n }\n }\n } catch (error) {\n admin?.close?.();\n created.terminate();\n throw error;\n }\n if (!admin) return created;\n const served = admin;\n return {\n postMessage: (message, transfer) => created.postMessage(message, transfer),\n terminate() {\n served.close?.();\n created.terminate();\n },\n };\n };\n let worker: Promise<AgentWorker | undefined> = Promise.resolve().then(spawn);\n try {\n await worker;\n } catch (error) {\n release();\n throw error;\n }\n const open = async (portOptions: PortOptions = {}): Promise<PortEndpoint & Transferable> => {\n const ready = await worker;\n if (!ready) throw new Error('the agent was released');\n const { port1, port2 } = channel();\n const readOnly = portOptions.readOnly === true ? { readOnly: true } : {};\n const pages = portOptions.pages === false ? { pages: false } : {};\n ready.postMessage({ connect: port2, ...readOnly, ...pages }, [port2]);\n return port1;\n };\n return {\n async connect(portOptions) {\n return connectAgent(await open(portOptions));\n },\n port: open,\n restart() {\n worker = worker\n .catch(() => undefined)\n .then((old) => {\n old?.terminate();\n return spawn();\n });\n return worker.then(() => undefined);\n },\n async release() {\n const previous = worker;\n worker = Promise.resolve(undefined);\n try {\n (await previous.catch(() => undefined))?.terminate();\n } finally {\n release();\n }\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAA+B,oBAAoB;AACnD,SAA4B,kBAAkB;AAC9C,SAAS,gBAAgB;AAGlB,MAAM,aAAa;AA6B1B,eAAsB,WAAW,SAA4C;AAC3E,QAAM,UAAU,QAAQ,OACpB,MAAM,SACN,MAAM,SAAS,QAAQ,SAAS,UAAU,OAAO,UAAU;AAC/D,QAAM,UAAU,QAAQ,YAAY,MAAM,IAAI,eAAe;AAC7D,QAAM,QAAQ,YAAkC;AAC9C,UAAM,UAAU,QAAQ,OAAO;AAC/B,QAAI;AACJ,QAAI;AACF,UAAI,QAAQ,QAAQ;AAClB,cAAM,OAAO,MAAM,QAAQ,OAAO,QAAQ;AAC1C,YAAI,CAAC,QAAQ,OAAO,MAAO,SAAQ,YAAY,EAAE,QAAQ,KAAK,GAAG,CAAC,IAAI,CAAC;AAAA,aAClE;AACH,gBAAM,EAAE,OAAO,MAAM,IAAI,QAAQ;AACjC,kBAAQ;AACR,qBAAW,OAAO,QAAQ,MAAM;AAChC,kBAAQ,YAAY,EAAE,QAAQ,MAAM,OAAO,MAAM,GAAG,CAAC,MAAM,KAAK,CAAC;AAAA,QACnE;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,aAAO,QAAQ;AACf,cAAQ,UAAU;AAClB,YAAM;AAAA,IACR;AACA,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,SAAS;AACf,WAAO;AAAA,MACL,aAAa,CAAC,SAAS,aAAa,QAAQ,YAAY,SAAS,QAAQ;AAAA,MACzE,YAAY;AACV,eAAO,QAAQ;AACf,gBAAQ,UAAU;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AACA,MAAI,SAA2C,QAAQ,QAAQ,EAAE,KAAK,KAAK;AAC3E,MAAI;AACF,UAAM;AAAA,EACR,SAAS,OAAO;AACd,YAAQ;AACR,UAAM;AAAA,EACR;AACA,QAAM,OAAO,OAAO,cAA2B,CAAC,MAA4C;AAC1F,UAAM,QAAQ,MAAM;AACpB,QAAI,CAAC,MAAO,OAAM,IAAI,MAAM,wBAAwB;AACpD,UAAM,EAAE,OAAO,MAAM,IAAI,QAAQ;AACjC,UAAM,WAAW,YAAY,aAAa,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;AACvE,UAAM,QAAQ,YAAY,UAAU,QAAQ,EAAE,OAAO,MAAM,IAAI,CAAC;AAChE,UAAM,YAAY,EAAE,SAAS,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC;AACpE,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,MAAM,QAAQ,aAAa;AACzB,aAAO,aAAa,MAAM,KAAK,WAAW,CAAC;AAAA,IAC7C;AAAA,IACA,MAAM;AAAA,IACN,UAAU;AACR,eAAS,OACN,MAAM,MAAM,MAAS,EACrB,KAAK,CAAC,QAAQ;AACb,aAAK,UAAU;AACf,eAAO,MAAM;AAAA,MACf,CAAC;AACH,aAAO,OAAO,KAAK,MAAM,MAAS;AAAA,IACpC;AAAA,IACA,MAAM,UAAU;AACd,YAAM,WAAW;AACjB,eAAS,QAAQ,QAAQ,MAAS;AAClC,UAAI;AACF,SAAC,MAAM,SAAS,MAAM,MAAM,MAAS,IAAI,UAAU;AAAA,MACrD,UAAE;AACA,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/readonly.js
CHANGED
|
@@ -23,6 +23,18 @@ function viewControl(control) {
|
|
|
23
23
|
function viewSettings(settings) {
|
|
24
24
|
return { state: settings.state, connect: refuse, disconnect: refuse, signIn: refuse };
|
|
25
25
|
}
|
|
26
|
+
function viewPages() {
|
|
27
|
+
return {
|
|
28
|
+
open: async () => ({ error: VIEW_ONLY }),
|
|
29
|
+
report: async () => {
|
|
30
|
+
},
|
|
31
|
+
next: async () => ({ requests: [], done: true }),
|
|
32
|
+
answer: async () => {
|
|
33
|
+
},
|
|
34
|
+
close: async () => {
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
26
38
|
function viewRemote(remote) {
|
|
27
39
|
const mine = /* @__PURE__ */ new Set();
|
|
28
40
|
return {
|
|
@@ -48,6 +60,7 @@ function viewRemote(remote) {
|
|
|
48
60
|
export {
|
|
49
61
|
VIEW_ONLY,
|
|
50
62
|
viewControl,
|
|
63
|
+
viewPages,
|
|
51
64
|
viewRemote,
|
|
52
65
|
viewSettings
|
|
53
66
|
};
|
package/dist/readonly.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/readonly.ts"],
|
|
4
|
-
"sourcesContent": ["import { ServerError } from '@earendil-works/pi-server';\nimport type { AgentRemote } from './remote/host.ts';\nimport type { AgentControl, AgentSettings } from './services.ts';\nimport { VIEW_ONLY } from './view-only.ts';\n\nexport { VIEW_ONLY };\n\nconst READS = new Set<keyof AgentControl>(['wait', 'changesOpen', 'monitorOpen', 'monitorClose']);\n\nfunction refuse(): Promise<never> {\n return Promise.reject(new ServerError('EACCES' as never, VIEW_ONLY));\n}\n\nconst refused = async () => ({\n accepted: false as const,\n submissionId: null,\n error: { code: 'EACCES', message: VIEW_ONLY },\n});\n\nconst ANSWERS: Partial<Record<keyof AgentControl, () => Promise<unknown>>> = {\n send: refused,\n compact: refused,\n compactAgent: refused,\n};\n\nexport function viewControl(control: AgentControl): AgentControl {\n const view: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(control))\n view[key] =\n typeof value !== 'function' || READS.has(key as keyof AgentControl)\n ? value\n : (ANSWERS[key as keyof AgentControl] ?? refuse);\n return view as unknown as AgentControl;\n}\n\nexport function viewSettings(settings: AgentSettings): AgentSettings {\n return { state: settings.state, connect: refuse, disconnect: refuse, signIn: refuse };\n}\n\nexport function viewRemote(remote: AgentRemote): AgentRemote {\n const mine = new Set<string>();\n return {\n prompt: async () => ({ ok: false, code: 'EACCES', message: VIEW_ONLY }),\n async watch(request, context) {\n const opened = await remote.watch(request, context);\n if (opened.ok) mine.add(opened.stream);\n return opened;\n },\n async next(stream, waitMs, context) {\n if (!mine.has(stream)) return { events: [], done: true };\n const batch = await remote.next(stream, waitMs, context);\n if (batch.done) mine.delete(stream);\n return batch;\n },\n async close(stream, context) {\n if (!mine.delete(stream)) return;\n await remote.close(stream, context);\n },\n abort: refuse,\n };\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,mBAAmB;
|
|
4
|
+
"sourcesContent": ["import { ServerError } from '@earendil-works/pi-server';\nimport type { AgentRemote } from './remote/host.ts';\nimport type { AgentPages } from './remote/pages.ts';\nimport type { AgentControl, AgentSettings } from './services.ts';\nimport { VIEW_ONLY } from './view-only.ts';\n\nexport { VIEW_ONLY };\n\nconst READS = new Set<keyof AgentControl>(['wait', 'changesOpen', 'monitorOpen', 'monitorClose']);\n\nfunction refuse(): Promise<never> {\n return Promise.reject(new ServerError('EACCES' as never, VIEW_ONLY));\n}\n\nconst refused = async () => ({\n accepted: false as const,\n submissionId: null,\n error: { code: 'EACCES', message: VIEW_ONLY },\n});\n\nconst ANSWERS: Partial<Record<keyof AgentControl, () => Promise<unknown>>> = {\n send: refused,\n compact: refused,\n compactAgent: refused,\n};\n\nexport function viewControl(control: AgentControl): AgentControl {\n const view: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(control))\n view[key] =\n typeof value !== 'function' || READS.has(key as keyof AgentControl)\n ? value\n : (ANSWERS[key as keyof AgentControl] ?? refuse);\n return view as unknown as AgentControl;\n}\n\nexport function viewSettings(settings: AgentSettings): AgentSettings {\n return { state: settings.state, connect: refuse, disconnect: refuse, signIn: refuse };\n}\n\nexport function viewPages(): AgentPages {\n return {\n open: async () => ({ error: VIEW_ONLY }),\n report: async () => {},\n next: async () => ({ requests: [], done: true }),\n answer: async () => {},\n close: async () => {},\n };\n}\n\nexport function viewRemote(remote: AgentRemote): AgentRemote {\n const mine = new Set<string>();\n return {\n prompt: async () => ({ ok: false, code: 'EACCES', message: VIEW_ONLY }),\n async watch(request, context) {\n const opened = await remote.watch(request, context);\n if (opened.ok) mine.add(opened.stream);\n return opened;\n },\n async next(stream, waitMs, context) {\n if (!mine.has(stream)) return { events: [], done: true };\n const batch = await remote.next(stream, waitMs, context);\n if (batch.done) mine.delete(stream);\n return batch;\n },\n async close(stream, context) {\n if (!mine.delete(stream)) return;\n await remote.close(stream, context);\n },\n abort: refuse,\n };\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,mBAAmB;AAI5B,SAAS,iBAAiB;AAI1B,MAAM,QAAQ,oBAAI,IAAwB,CAAC,QAAQ,eAAe,eAAe,cAAc,CAAC;AAEhG,SAAS,SAAyB;AAChC,SAAO,QAAQ,OAAO,IAAI,YAAY,UAAmB,SAAS,CAAC;AACrE;AAEA,MAAM,UAAU,aAAa;AAAA,EAC3B,UAAU;AAAA,EACV,cAAc;AAAA,EACd,OAAO,EAAE,MAAM,UAAU,SAAS,UAAU;AAC9C;AAEA,MAAM,UAAuE;AAAA,EAC3E,MAAM;AAAA,EACN,SAAS;AAAA,EACT,cAAc;AAChB;AAEO,SAAS,YAAY,SAAqC;AAC/D,QAAM,OAAgC,CAAC;AACvC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO;AAC/C,SAAK,GAAG,IACN,OAAO,UAAU,cAAc,MAAM,IAAI,GAAyB,IAC9D,QACC,QAAQ,GAAyB,KAAK;AAC/C,SAAO;AACT;AAEO,SAAS,aAAa,UAAwC;AACnE,SAAO,EAAE,OAAO,SAAS,OAAO,SAAS,QAAQ,YAAY,QAAQ,QAAQ,OAAO;AACtF;AAEO,SAAS,YAAwB;AACtC,SAAO;AAAA,IACL,MAAM,aAAa,EAAE,OAAO,UAAU;AAAA,IACtC,QAAQ,YAAY;AAAA,IAAC;AAAA,IACrB,MAAM,aAAa,EAAE,UAAU,CAAC,GAAG,MAAM,KAAK;AAAA,IAC9C,QAAQ,YAAY;AAAA,IAAC;AAAA,IACrB,OAAO,YAAY;AAAA,IAAC;AAAA,EACtB;AACF;AAEO,SAAS,WAAW,QAAkC;AAC3D,QAAM,OAAO,oBAAI,IAAY;AAC7B,SAAO;AAAA,IACL,QAAQ,aAAa,EAAE,IAAI,OAAO,MAAM,UAAU,SAAS,UAAU;AAAA,IACrE,MAAM,MAAM,SAAS,SAAS;AAC5B,YAAM,SAAS,MAAM,OAAO,MAAM,SAAS,OAAO;AAClD,UAAI,OAAO,GAAI,MAAK,IAAI,OAAO,MAAM;AACrC,aAAO;AAAA,IACT;AAAA,IACA,MAAM,KAAK,QAAQ,QAAQ,SAAS;AAClC,UAAI,CAAC,KAAK,IAAI,MAAM,EAAG,QAAO,EAAE,QAAQ,CAAC,GAAG,MAAM,KAAK;AACvD,YAAM,QAAQ,MAAM,OAAO,KAAK,QAAQ,QAAQ,OAAO;AACvD,UAAI,MAAM,KAAM,MAAK,OAAO,MAAM;AAClC,aAAO;AAAA,IACT;AAAA,IACA,MAAM,MAAM,QAAQ,SAAS;AAC3B,UAAI,CAAC,KAAK,OAAO,MAAM,EAAG;AAC1B,YAAM,OAAO,MAAM,QAAQ,OAAO;AAAA,IACpC;AAAA,IACA,OAAO;AAAA,EACT;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/remote/host.js
CHANGED
|
@@ -12,17 +12,19 @@ class Stream {
|
|
|
12
12
|
#wake;
|
|
13
13
|
#stop;
|
|
14
14
|
#limit;
|
|
15
|
-
|
|
15
|
+
#overflow;
|
|
16
|
+
constructor(stop, now, limit, overflow) {
|
|
16
17
|
this.#stop = stop;
|
|
17
18
|
this.touched = now;
|
|
18
19
|
this.#limit = limit;
|
|
20
|
+
this.#overflow = overflow;
|
|
19
21
|
}
|
|
20
22
|
push(events) {
|
|
21
23
|
if (this.done || !events.length) return;
|
|
22
24
|
this.queue.push(...events);
|
|
23
25
|
if (this.queue.length > this.#limit) {
|
|
24
26
|
this.queue.length = 0;
|
|
25
|
-
this.queue.push(
|
|
27
|
+
this.queue.push(...this.#overflow);
|
|
26
28
|
void this.finish();
|
|
27
29
|
}
|
|
28
30
|
this.#wake?.();
|
|
@@ -33,12 +35,14 @@ class Stream {
|
|
|
33
35
|
this.#wake?.();
|
|
34
36
|
await this.#stop().catch(() => void 0);
|
|
35
37
|
}
|
|
36
|
-
wait(ms) {
|
|
38
|
+
wait(ms, signal) {
|
|
37
39
|
if (this.queue.length || this.done) return Promise.resolve();
|
|
38
40
|
return new Promise((resolve) => {
|
|
39
41
|
const timer = setTimeout(done, ms);
|
|
42
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
40
43
|
function done() {
|
|
41
44
|
clearTimeout(timer);
|
|
45
|
+
signal?.removeEventListener("abort", done);
|
|
42
46
|
resolve();
|
|
43
47
|
}
|
|
44
48
|
this.#wake = () => {
|
|
@@ -157,7 +161,8 @@ function createRemote(host) {
|
|
|
157
161
|
cancel.cancel();
|
|
158
162
|
},
|
|
159
163
|
now(),
|
|
160
|
-
host.limit ?? MAX_QUEUED
|
|
164
|
+
host.limit ?? MAX_QUEUED,
|
|
165
|
+
[{ t: "end", reason: "error", message: "the stream fell too far behind" }]
|
|
161
166
|
);
|
|
162
167
|
const id = `s${++serial}-${crypto.randomUUID()}`;
|
|
163
168
|
track(id, stream);
|
|
@@ -266,6 +271,7 @@ export {
|
|
|
266
271
|
Follower,
|
|
267
272
|
IDLE_MS,
|
|
268
273
|
MAX_QUEUED,
|
|
274
|
+
Stream,
|
|
269
275
|
createRemote,
|
|
270
276
|
followed,
|
|
271
277
|
resync
|
package/dist/remote/host.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/remote/host.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT, withCancel } from '@earendil-works/chord/context';\nimport {\n type AgentEvent,\n type AgentEventStream,\n type Conversation,\n type EntryRecord,\n type Harness,\n type SnapshotEvent,\n type SubmissionId,\n watchEvents,\n} from '@earendil-works/pi-durable';\nimport type { Delivered, SendMode, SendRequest, SendResponse } from '../services.ts';\nimport { type EndReason, idOf, Mapper, type RemoteEvent, replayOf } from './events.ts';\n\nexport const MAX_QUEUED = 10000;\nexport const IDLE_MS = 120000;\n\nexport type RemoteOpened =\n | { ok: true; stream: string; delivered: Delivered | null; head: string | null; gap: boolean }\n | { ok: false; code: string; message: string };\n\nexport interface RemoteBatch {\n events: RemoteEvent[];\n done: boolean;\n}\n\nexport interface AgentRemote {\n prompt(\n request: { agentId: string | null; text: string; whenBusy: SendMode; thinking: boolean },\n context: Context\n ): Promise<RemoteOpened>;\n watch(\n request: { agentId: string | null; since: string | null; thinking: boolean },\n context: Context\n ): Promise<RemoteOpened>;\n next(stream: string, waitMs: number, context: Context): Promise<RemoteBatch>;\n close(stream: string, context: Context): Promise<void>;\n abort(agentId: string | null, context: Context): Promise<{ aborted: boolean }>;\n}\n\nexport interface RemoteHost {\n harness: Harness;\n conversation(agentId: string | null, context: Context): Promise<Conversation>;\n send(request: SendRequest, context: Context): Promise<SendResponse>;\n now?: () => number;\n limit?: number;\n sweepMs?: number;\n}\n\nclass Stream {\n readonly queue: RemoteEvent[] = [];\n done = false;\n touched: number;\n #wake: (() => void) | undefined;\n readonly #stop: () => Promise<unknown>;\n readonly #limit: number;\n\n constructor(stop: () => Promise<unknown>, now: number, limit: number) {\n this.#stop = stop;\n this.touched = now;\n this.#limit = limit;\n }\n\n push(events: readonly RemoteEvent[]): void {\n if (this.done || !events.length) return;\n this.queue.push(...events);\n if (this.queue.length > this.#limit) {\n this.queue.length = 0;\n this.queue.push({ t: 'end', reason: 'error', message: 'the stream fell too far behind' });\n void this.finish();\n }\n this.#wake?.();\n }\n\n async finish(): Promise<void> {\n if (this.done) return;\n this.done = true;\n this.#wake?.();\n await this.#stop().catch(() => undefined);\n }\n\n wait(ms: number): Promise<void> {\n if (this.queue.length || this.done) return Promise.resolve();\n return new Promise((resolve) => {\n const timer = setTimeout(done, ms);\n function done() {\n clearTimeout(timer);\n resolve();\n }\n this.#wake = () => {\n this.#wake = undefined;\n done();\n };\n });\n }\n}\n\nfunction deliveredOf(\n status: { status: string } | undefined,\n whenBusy: SendMode,\n busy: boolean\n): Delivered {\n if (status?.status === 'queued') return whenBusy === 'followUp' ? 'follow-up' : 'steer';\n return busy ? 'steer' : 'run';\n}\n\nfunction headOf(events: readonly RemoteEvent[]): string | null {\n for (let at = events.length - 1; at >= 0; at--) {\n const id = idOf(events[at] as RemoteEvent);\n if (id) return id;\n }\n return null;\n}\n\nexport function followed(mapper: Mapper, event: AgentEvent): RemoteEvent[] {\n return event.type === 'snapshot' ? resync(mapper, event) : mapper.event(event);\n}\n\nexport function resync(mapper: Mapper, snapshot: SnapshotEvent): RemoteEvent[] {\n const last = mapper.last();\n return [\n ...snapshot.entries.filter((entry) => entry.id > last).flatMap((entry) => mapper.entry(entry)),\n ...mapper.partial(snapshot.generation?.message as never),\n ];\n}\n\nfunction placedEntry(value: unknown): number | undefined {\n const entry = (value as { entry?: unknown } | undefined)?.entry;\n return typeof entry === 'number' ? entry : undefined;\n}\n\nexport class Follower {\n readonly #mapper: Mapper;\n readonly #entries: Map<number, EntryRecord>;\n readonly #submission: SubmissionId;\n readonly #delivered: Delivered;\n readonly #out: RemoteEvent[] = [];\n #user: number | undefined;\n #started = false;\n\n constructor(\n mapper: Mapper,\n entries: readonly EntryRecord[],\n submission: SubmissionId,\n delivered: Delivered,\n record: unknown\n ) {\n this.#mapper = mapper;\n this.#entries = new Map(entries.map((entry) => [entry.id, entry]));\n this.#submission = submission;\n this.#delivered = delivered;\n this.#user = placedEntry(record);\n }\n\n drain(): RemoteEvent[] {\n return this.#out.splice(0);\n }\n\n #begin(): void {\n const entry = this.#user === undefined ? undefined : this.#entries.get(this.#user);\n if (!entry) return;\n this.#started = true;\n this.#out.push(...this.#mapper.entry(entry, this.#delivered));\n }\n\n #end(reason: EndReason, message?: string): true {\n this.#out.push({ t: 'end', reason, ...(message ? { message } : {}) });\n return true;\n }\n\n #ours(event: AgentEvent): boolean {\n if (event.type !== 'submission' || event.record.id !== this.#submission) return false;\n this.#user = placedEntry(event.record) ?? this.#user;\n return this.#user === undefined && !['queued', 'placed'].includes(event.record.status);\n }\n\n take(batch: readonly AgentEvent[]): boolean {\n for (const event of batch) {\n if (event.type === 'message_end') this.#entries.set(event.entry.id, event.entry);\n if (this.#ours(event)) return this.#end('aborted');\n if (!this.#started) {\n this.#begin();\n continue;\n }\n const mapped = this.#mapper.event(event).filter((item) => item.t !== 'user');\n this.#out.push(...mapped);\n if (mapped.some((item) => item.t === 'run' && item.state === 'end'))\n return this.#end(this.#mapper.reason, this.#mapper.error);\n }\n return false;\n }\n}\n\nexport function createRemote(host: RemoteHost): AgentRemote & { dispose(): Promise<void> } {\n const now = host.now ?? Date.now;\n const streams = new Map<string, Stream>();\n let serial = 0;\n let timer: ReturnType<typeof setInterval> | undefined;\n const sweep = () => {\n for (const [id, stream] of streams)\n if (now() - stream.touched > IDLE_MS) {\n streams.delete(id);\n void stream.finish();\n }\n if (!streams.size && timer !== undefined) {\n clearInterval(timer);\n timer = undefined;\n }\n };\n const track = (id: string, stream: Stream) => {\n streams.set(id, stream);\n timer ??= setInterval(sweep, host.sweepMs ?? IDLE_MS / 4);\n };\n const watching = async (agentId: string | null, context: Context) => {\n const conversation = await host.conversation(agentId, context);\n const cancel = withCancel(BACKGROUND_CONTEXT);\n const events: AgentEventStream = await watchEvents(\n host.harness,\n conversation.id,\n cancel.context\n );\n const open = (onEvents: (batch: readonly AgentEvent[]) => void) => {\n const stream = new Stream(\n async () => {\n await events.stop();\n cancel.cancel();\n },\n now(),\n host.limit ?? MAX_QUEUED\n );\n const id = `s${++serial}-${crypto.randomUUID()}`;\n track(id, stream);\n events.start(async (batch) => onEvents(batch));\n return { id, stream };\n };\n return { conversation, snapshot: events.snapshot, open, stop: () => events.stop() };\n };\n return {\n async prompt(request, context) {\n sweep();\n const watched = await watching(request.agentId, context);\n const busy = Boolean(watched.snapshot.run);\n const response = await host.send(\n {\n text: request.text,\n whenBusy: request.whenBusy,\n requestId: null,\n ...(request.agentId ? { agentId: request.agentId } : {}),\n },\n context\n );\n if (!response.accepted) {\n await watched.stop();\n return {\n ok: false,\n code: response.error.code === 'busy' ? 'EBUSY' : 'EIO',\n message: response.error.message,\n };\n }\n const submission = Number(response.submissionId) as SubmissionId;\n const record = await (await host.harness.submission(submission, context))?.status(context);\n const delivered = deliveredOf(record, request.whenBusy, busy);\n const follower = new Follower(\n new Mapper(request.thinking),\n watched.snapshot.entries,\n submission,\n delivered,\n record\n );\n const { id, stream } = watched.open((batch) => {\n const ended = follower.take(batch);\n stream.push(follower.drain());\n if (ended) void stream.finish();\n });\n return { ok: true, stream: id, delivered, head: null, gap: false };\n },\n async watch(request, context) {\n sweep();\n const watched = await watching(request.agentId, context);\n const partial = watched.snapshot.generation?.message as never;\n const all = replayOf(watched.snapshot.entries, partial, request.thinking);\n const head = headOf(all);\n const at = request.since === null ? -1 : all.findIndex((e) => idOf(e) === request.since);\n const gap = request.since !== null && at < 0;\n const mapper = new Mapper(request.thinking);\n for (const entry of watched.snapshot.entries) mapper.entry(entry);\n mapper.partial(partial);\n const { id, stream } = watched.open((batch) =>\n stream.push(batch.flatMap((event) => followed(mapper, event)))\n );\n if (at >= 0) {\n const own = all[at] as RemoteEvent;\n const sinceId = idOf(own);\n let last = at;\n while (last + 1 < all.length && idOf(all[last + 1] as RemoteEvent) === sinceId) last++;\n const replay = own.t === 'text' || own.t === 'thinking' ? [own] : [];\n stream.push([...replay, ...all.slice(last + 1)]);\n }\n return { ok: true, stream: id, delivered: null, head, gap };\n },\n async next(id, waitMs, context) {\n const stream = streams.get(id);\n if (!stream) return { events: [], done: true };\n stream.touched = now();\n await stream.wait(Math.max(0, Math.min(waitMs, 30000)));\n context.abortSignal?.throwIfAborted();\n const events = stream.queue.splice(0);\n const done = stream.done && stream.queue.length === 0;\n if (done) streams.delete(id);\n return { events, done };\n },\n async close(id) {\n const stream = streams.get(id);\n streams.delete(id);\n await stream?.finish();\n },\n async abort(agentId, context) {\n const conversation = await host.conversation(agentId, context);\n const watched = await watchEvents(host.harness, conversation.id, context);\n const busy = Boolean(watched.snapshot.run);\n await watched.stop();\n if (busy) await conversation.abort(context);\n return { aborted: busy };\n },\n async dispose() {\n clearInterval(timer);\n timer = undefined;\n const all = [...streams.values()];\n streams.clear();\n await Promise.all(all.map((stream) => stream.finish()));\n },\n };\n}\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,oBAAoB,kBAAkB;AAC/C;AAAA,EAQE;AAAA,OACK;AAEP,SAAyB,MAAM,QAA0B,gBAAgB;AAElE,MAAM,aAAa;AACnB,MAAM,UAAU;
|
|
4
|
+
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT, withCancel } from '@earendil-works/chord/context';\nimport {\n type AgentEvent,\n type AgentEventStream,\n type Conversation,\n type EntryRecord,\n type Harness,\n type SnapshotEvent,\n type SubmissionId,\n watchEvents,\n} from '@earendil-works/pi-durable';\nimport type { Delivered, SendMode, SendRequest, SendResponse } from '../services.ts';\nimport { type EndReason, idOf, Mapper, type RemoteEvent, replayOf } from './events.ts';\n\nexport const MAX_QUEUED = 10000;\nexport const IDLE_MS = 120000;\n\nexport type RemoteOpened =\n | { ok: true; stream: string; delivered: Delivered | null; head: string | null; gap: boolean }\n | { ok: false; code: string; message: string };\n\nexport interface RemoteBatch {\n events: RemoteEvent[];\n done: boolean;\n}\n\nexport interface AgentRemote {\n prompt(\n request: { agentId: string | null; text: string; whenBusy: SendMode; thinking: boolean },\n context: Context\n ): Promise<RemoteOpened>;\n watch(\n request: { agentId: string | null; since: string | null; thinking: boolean },\n context: Context\n ): Promise<RemoteOpened>;\n next(stream: string, waitMs: number, context: Context): Promise<RemoteBatch>;\n close(stream: string, context: Context): Promise<void>;\n abort(agentId: string | null, context: Context): Promise<{ aborted: boolean }>;\n}\n\nexport interface RemoteHost {\n harness: Harness;\n conversation(agentId: string | null, context: Context): Promise<Conversation>;\n send(request: SendRequest, context: Context): Promise<SendResponse>;\n now?: () => number;\n limit?: number;\n sweepMs?: number;\n}\n\nexport class Stream<T = RemoteEvent> {\n readonly queue: T[] = [];\n done = false;\n touched: number;\n #wake: (() => void) | undefined;\n readonly #stop: () => Promise<unknown>;\n readonly #limit: number;\n readonly #overflow: readonly T[];\n\n constructor(stop: () => Promise<unknown>, now: number, limit: number, overflow: readonly T[]) {\n this.#stop = stop;\n this.touched = now;\n this.#limit = limit;\n this.#overflow = overflow;\n }\n\n push(events: readonly T[]): void {\n if (this.done || !events.length) return;\n this.queue.push(...events);\n if (this.queue.length > this.#limit) {\n this.queue.length = 0;\n this.queue.push(...this.#overflow);\n void this.finish();\n }\n this.#wake?.();\n }\n\n async finish(): Promise<void> {\n if (this.done) return;\n this.done = true;\n this.#wake?.();\n await this.#stop().catch(() => undefined);\n }\n\n wait(ms: number, signal?: AbortSignal): Promise<void> {\n if (this.queue.length || this.done) return Promise.resolve();\n return new Promise((resolve) => {\n const timer = setTimeout(done, ms);\n signal?.addEventListener('abort', done, { once: true });\n function done() {\n clearTimeout(timer);\n signal?.removeEventListener('abort', done);\n resolve();\n }\n this.#wake = () => {\n this.#wake = undefined;\n done();\n };\n });\n }\n}\n\nfunction deliveredOf(\n status: { status: string } | undefined,\n whenBusy: SendMode,\n busy: boolean\n): Delivered {\n if (status?.status === 'queued') return whenBusy === 'followUp' ? 'follow-up' : 'steer';\n return busy ? 'steer' : 'run';\n}\n\nfunction headOf(events: readonly RemoteEvent[]): string | null {\n for (let at = events.length - 1; at >= 0; at--) {\n const id = idOf(events[at] as RemoteEvent);\n if (id) return id;\n }\n return null;\n}\n\nexport function followed(mapper: Mapper, event: AgentEvent): RemoteEvent[] {\n return event.type === 'snapshot' ? resync(mapper, event) : mapper.event(event);\n}\n\nexport function resync(mapper: Mapper, snapshot: SnapshotEvent): RemoteEvent[] {\n const last = mapper.last();\n return [\n ...snapshot.entries.filter((entry) => entry.id > last).flatMap((entry) => mapper.entry(entry)),\n ...mapper.partial(snapshot.generation?.message as never),\n ];\n}\n\nfunction placedEntry(value: unknown): number | undefined {\n const entry = (value as { entry?: unknown } | undefined)?.entry;\n return typeof entry === 'number' ? entry : undefined;\n}\n\nexport class Follower {\n readonly #mapper: Mapper;\n readonly #entries: Map<number, EntryRecord>;\n readonly #submission: SubmissionId;\n readonly #delivered: Delivered;\n readonly #out: RemoteEvent[] = [];\n #user: number | undefined;\n #started = false;\n\n constructor(\n mapper: Mapper,\n entries: readonly EntryRecord[],\n submission: SubmissionId,\n delivered: Delivered,\n record: unknown\n ) {\n this.#mapper = mapper;\n this.#entries = new Map(entries.map((entry) => [entry.id, entry]));\n this.#submission = submission;\n this.#delivered = delivered;\n this.#user = placedEntry(record);\n }\n\n drain(): RemoteEvent[] {\n return this.#out.splice(0);\n }\n\n #begin(): void {\n const entry = this.#user === undefined ? undefined : this.#entries.get(this.#user);\n if (!entry) return;\n this.#started = true;\n this.#out.push(...this.#mapper.entry(entry, this.#delivered));\n }\n\n #end(reason: EndReason, message?: string): true {\n this.#out.push({ t: 'end', reason, ...(message ? { message } : {}) });\n return true;\n }\n\n #ours(event: AgentEvent): boolean {\n if (event.type !== 'submission' || event.record.id !== this.#submission) return false;\n this.#user = placedEntry(event.record) ?? this.#user;\n return this.#user === undefined && !['queued', 'placed'].includes(event.record.status);\n }\n\n take(batch: readonly AgentEvent[]): boolean {\n for (const event of batch) {\n if (event.type === 'message_end') this.#entries.set(event.entry.id, event.entry);\n if (this.#ours(event)) return this.#end('aborted');\n if (!this.#started) {\n this.#begin();\n continue;\n }\n const mapped = this.#mapper.event(event).filter((item) => item.t !== 'user');\n this.#out.push(...mapped);\n if (mapped.some((item) => item.t === 'run' && item.state === 'end'))\n return this.#end(this.#mapper.reason, this.#mapper.error);\n }\n return false;\n }\n}\n\nexport function createRemote(host: RemoteHost): AgentRemote & { dispose(): Promise<void> } {\n const now = host.now ?? Date.now;\n const streams = new Map<string, Stream>();\n let serial = 0;\n let timer: ReturnType<typeof setInterval> | undefined;\n const sweep = () => {\n for (const [id, stream] of streams)\n if (now() - stream.touched > IDLE_MS) {\n streams.delete(id);\n void stream.finish();\n }\n if (!streams.size && timer !== undefined) {\n clearInterval(timer);\n timer = undefined;\n }\n };\n const track = (id: string, stream: Stream) => {\n streams.set(id, stream);\n timer ??= setInterval(sweep, host.sweepMs ?? IDLE_MS / 4);\n };\n const watching = async (agentId: string | null, context: Context) => {\n const conversation = await host.conversation(agentId, context);\n const cancel = withCancel(BACKGROUND_CONTEXT);\n const events: AgentEventStream = await watchEvents(\n host.harness,\n conversation.id,\n cancel.context\n );\n const open = (onEvents: (batch: readonly AgentEvent[]) => void) => {\n const stream = new Stream<RemoteEvent>(\n async () => {\n await events.stop();\n cancel.cancel();\n },\n now(),\n host.limit ?? MAX_QUEUED,\n [{ t: 'end', reason: 'error', message: 'the stream fell too far behind' }]\n );\n const id = `s${++serial}-${crypto.randomUUID()}`;\n track(id, stream);\n events.start(async (batch) => onEvents(batch));\n return { id, stream };\n };\n return { conversation, snapshot: events.snapshot, open, stop: () => events.stop() };\n };\n return {\n async prompt(request, context) {\n sweep();\n const watched = await watching(request.agentId, context);\n const busy = Boolean(watched.snapshot.run);\n const response = await host.send(\n {\n text: request.text,\n whenBusy: request.whenBusy,\n requestId: null,\n ...(request.agentId ? { agentId: request.agentId } : {}),\n },\n context\n );\n if (!response.accepted) {\n await watched.stop();\n return {\n ok: false,\n code: response.error.code === 'busy' ? 'EBUSY' : 'EIO',\n message: response.error.message,\n };\n }\n const submission = Number(response.submissionId) as SubmissionId;\n const record = await (await host.harness.submission(submission, context))?.status(context);\n const delivered = deliveredOf(record, request.whenBusy, busy);\n const follower = new Follower(\n new Mapper(request.thinking),\n watched.snapshot.entries,\n submission,\n delivered,\n record\n );\n const { id, stream } = watched.open((batch) => {\n const ended = follower.take(batch);\n stream.push(follower.drain());\n if (ended) void stream.finish();\n });\n return { ok: true, stream: id, delivered, head: null, gap: false };\n },\n async watch(request, context) {\n sweep();\n const watched = await watching(request.agentId, context);\n const partial = watched.snapshot.generation?.message as never;\n const all = replayOf(watched.snapshot.entries, partial, request.thinking);\n const head = headOf(all);\n const at = request.since === null ? -1 : all.findIndex((e) => idOf(e) === request.since);\n const gap = request.since !== null && at < 0;\n const mapper = new Mapper(request.thinking);\n for (const entry of watched.snapshot.entries) mapper.entry(entry);\n mapper.partial(partial);\n const { id, stream } = watched.open((batch) =>\n stream.push(batch.flatMap((event) => followed(mapper, event)))\n );\n if (at >= 0) {\n const own = all[at] as RemoteEvent;\n const sinceId = idOf(own);\n let last = at;\n while (last + 1 < all.length && idOf(all[last + 1] as RemoteEvent) === sinceId) last++;\n const replay = own.t === 'text' || own.t === 'thinking' ? [own] : [];\n stream.push([...replay, ...all.slice(last + 1)]);\n }\n return { ok: true, stream: id, delivered: null, head, gap };\n },\n async next(id, waitMs, context) {\n const stream = streams.get(id);\n if (!stream) return { events: [], done: true };\n stream.touched = now();\n await stream.wait(Math.max(0, Math.min(waitMs, 30000)));\n context.abortSignal?.throwIfAborted();\n const events = stream.queue.splice(0);\n const done = stream.done && stream.queue.length === 0;\n if (done) streams.delete(id);\n return { events, done };\n },\n async close(id) {\n const stream = streams.get(id);\n streams.delete(id);\n await stream?.finish();\n },\n async abort(agentId, context) {\n const conversation = await host.conversation(agentId, context);\n const watched = await watchEvents(host.harness, conversation.id, context);\n const busy = Boolean(watched.snapshot.run);\n await watched.stop();\n if (busy) await conversation.abort(context);\n return { aborted: busy };\n },\n async dispose() {\n clearInterval(timer);\n timer = undefined;\n const all = [...streams.values()];\n streams.clear();\n await Promise.all(all.map((stream) => stream.finish()));\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,oBAAoB,kBAAkB;AAC/C;AAAA,EAQE;AAAA,OACK;AAEP,SAAyB,MAAM,QAA0B,gBAAgB;AAElE,MAAM,aAAa;AACnB,MAAM,UAAU;AAkChB,MAAM,OAAwB;AAAA,EAC1B,QAAa,CAAC;AAAA,EACvB,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACS;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,MAA8B,KAAa,OAAe,UAAwB;AAC5F,SAAK,QAAQ;AACb,SAAK,UAAU;AACf,SAAK,SAAS;AACd,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,KAAK,QAA4B;AAC/B,QAAI,KAAK,QAAQ,CAAC,OAAO,OAAQ;AACjC,SAAK,MAAM,KAAK,GAAG,MAAM;AACzB,QAAI,KAAK,MAAM,SAAS,KAAK,QAAQ;AACnC,WAAK,MAAM,SAAS;AACpB,WAAK,MAAM,KAAK,GAAG,KAAK,SAAS;AACjC,WAAK,KAAK,OAAO;AAAA,IACnB;AACA,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,MAAM,SAAwB;AAC5B,QAAI,KAAK,KAAM;AACf,SAAK,OAAO;AACZ,SAAK,QAAQ;AACb,UAAM,KAAK,MAAM,EAAE,MAAM,MAAM,MAAS;AAAA,EAC1C;AAAA,EAEA,KAAK,IAAY,QAAqC;AACpD,QAAI,KAAK,MAAM,UAAU,KAAK,KAAM,QAAO,QAAQ,QAAQ;AAC3D,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,YAAM,QAAQ,WAAW,MAAM,EAAE;AACjC,cAAQ,iBAAiB,SAAS,MAAM,EAAE,MAAM,KAAK,CAAC;AACtD,eAAS,OAAO;AACd,qBAAa,KAAK;AAClB,gBAAQ,oBAAoB,SAAS,IAAI;AACzC,gBAAQ;AAAA,MACV;AACA,WAAK,QAAQ,MAAM;AACjB,aAAK,QAAQ;AACb,aAAK;AAAA,MACP;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,SAAS,YACP,QACA,UACA,MACW;AACX,MAAI,QAAQ,WAAW,SAAU,QAAO,aAAa,aAAa,cAAc;AAChF,SAAO,OAAO,UAAU;AAC1B;AAEA,SAAS,OAAO,QAA+C;AAC7D,WAAS,KAAK,OAAO,SAAS,GAAG,MAAM,GAAG,MAAM;AAC9C,UAAM,KAAK,KAAK,OAAO,EAAE,CAAgB;AACzC,QAAI,GAAI,QAAO;AAAA,EACjB;AACA,SAAO;AACT;AAEO,SAAS,SAAS,QAAgB,OAAkC;AACzE,SAAO,MAAM,SAAS,aAAa,OAAO,QAAQ,KAAK,IAAI,OAAO,MAAM,KAAK;AAC/E;AAEO,SAAS,OAAO,QAAgB,UAAwC;AAC7E,QAAM,OAAO,OAAO,KAAK;AACzB,SAAO;AAAA,IACL,GAAG,SAAS,QAAQ,OAAO,CAAC,UAAU,MAAM,KAAK,IAAI,EAAE,QAAQ,CAAC,UAAU,OAAO,MAAM,KAAK,CAAC;AAAA,IAC7F,GAAG,OAAO,QAAQ,SAAS,YAAY,OAAgB;AAAA,EACzD;AACF;AAEA,SAAS,YAAY,OAAoC;AACvD,QAAM,QAAS,OAA2C;AAC1D,SAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C;AAEO,MAAM,SAAS;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAsB,CAAC;AAAA,EAChC;AAAA,EACA,WAAW;AAAA,EAEX,YACE,QACA,SACA,YACA,WACA,QACA;AACA,SAAK,UAAU;AACf,SAAK,WAAW,IAAI,IAAI,QAAQ,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AACjE,SAAK,cAAc;AACnB,SAAK,aAAa;AAClB,SAAK,QAAQ,YAAY,MAAM;AAAA,EACjC;AAAA,EAEA,QAAuB;AACrB,WAAO,KAAK,KAAK,OAAO,CAAC;AAAA,EAC3B;AAAA,EAEA,SAAe;AACb,UAAM,QAAQ,KAAK,UAAU,SAAY,SAAY,KAAK,SAAS,IAAI,KAAK,KAAK;AACjF,QAAI,CAAC,MAAO;AACZ,SAAK,WAAW;AAChB,SAAK,KAAK,KAAK,GAAG,KAAK,QAAQ,MAAM,OAAO,KAAK,UAAU,CAAC;AAAA,EAC9D;AAAA,EAEA,KAAK,QAAmB,SAAwB;AAC9C,SAAK,KAAK,KAAK,EAAE,GAAG,OAAO,QAAQ,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC,EAAG,CAAC;AACpE,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAA4B;AAChC,QAAI,MAAM,SAAS,gBAAgB,MAAM,OAAO,OAAO,KAAK,YAAa,QAAO;AAChF,SAAK,QAAQ,YAAY,MAAM,MAAM,KAAK,KAAK;AAC/C,WAAO,KAAK,UAAU,UAAa,CAAC,CAAC,UAAU,QAAQ,EAAE,SAAS,MAAM,OAAO,MAAM;AAAA,EACvF;AAAA,EAEA,KAAK,OAAuC;AAC1C,eAAW,SAAS,OAAO;AACzB,UAAI,MAAM,SAAS,cAAe,MAAK,SAAS,IAAI,MAAM,MAAM,IAAI,MAAM,KAAK;AAC/E,UAAI,KAAK,MAAM,KAAK,EAAG,QAAO,KAAK,KAAK,SAAS;AACjD,UAAI,CAAC,KAAK,UAAU;AAClB,aAAK,OAAO;AACZ;AAAA,MACF;AACA,YAAM,SAAS,KAAK,QAAQ,MAAM,KAAK,EAAE,OAAO,CAAC,SAAS,KAAK,MAAM,MAAM;AAC3E,WAAK,KAAK,KAAK,GAAG,MAAM;AACxB,UAAI,OAAO,KAAK,CAAC,SAAS,KAAK,MAAM,SAAS,KAAK,UAAU,KAAK;AAChE,eAAO,KAAK,KAAK,KAAK,QAAQ,QAAQ,KAAK,QAAQ,KAAK;AAAA,IAC5D;AACA,WAAO;AAAA,EACT;AACF;AAEO,SAAS,aAAa,MAA8D;AACzF,QAAM,MAAM,KAAK,OAAO,KAAK;AAC7B,QAAM,UAAU,oBAAI,IAAoB;AACxC,MAAI,SAAS;AACb,MAAI;AACJ,QAAM,QAAQ,MAAM;AAClB,eAAW,CAAC,IAAI,MAAM,KAAK;AACzB,UAAI,IAAI,IAAI,OAAO,UAAU,SAAS;AACpC,gBAAQ,OAAO,EAAE;AACjB,aAAK,OAAO,OAAO;AAAA,MACrB;AACF,QAAI,CAAC,QAAQ,QAAQ,UAAU,QAAW;AACxC,oBAAc,KAAK;AACnB,cAAQ;AAAA,IACV;AAAA,EACF;AACA,QAAM,QAAQ,CAAC,IAAY,WAAmB;AAC5C,YAAQ,IAAI,IAAI,MAAM;AACtB,cAAU,YAAY,OAAO,KAAK,WAAW,UAAU,CAAC;AAAA,EAC1D;AACA,QAAM,WAAW,OAAO,SAAwB,YAAqB;AACnE,UAAM,eAAe,MAAM,KAAK,aAAa,SAAS,OAAO;AAC7D,UAAM,SAAS,WAAW,kBAAkB;AAC5C,UAAM,SAA2B,MAAM;AAAA,MACrC,KAAK;AAAA,MACL,aAAa;AAAA,MACb,OAAO;AAAA,IACT;AACA,UAAM,OAAO,CAAC,aAAqD;AACjE,YAAM,SAAS,IAAI;AAAA,QACjB,YAAY;AACV,gBAAM,OAAO,KAAK;AAClB,iBAAO,OAAO;AAAA,QAChB;AAAA,QACA,IAAI;AAAA,QACJ,KAAK,SAAS;AAAA,QACd,CAAC,EAAE,GAAG,OAAO,QAAQ,SAAS,SAAS,iCAAiC,CAAC;AAAA,MAC3E;AACA,YAAM,KAAK,IAAI,EAAE,MAAM,IAAI,OAAO,WAAW,CAAC;AAC9C,YAAM,IAAI,MAAM;AAChB,aAAO,MAAM,OAAO,UAAU,SAAS,KAAK,CAAC;AAC7C,aAAO,EAAE,IAAI,OAAO;AAAA,IACtB;AACA,WAAO,EAAE,cAAc,UAAU,OAAO,UAAU,MAAM,MAAM,MAAM,OAAO,KAAK,EAAE;AAAA,EACpF;AACA,SAAO;AAAA,IACL,MAAM,OAAO,SAAS,SAAS;AAC7B,YAAM;AACN,YAAM,UAAU,MAAM,SAAS,QAAQ,SAAS,OAAO;AACvD,YAAM,OAAO,QAAQ,QAAQ,SAAS,GAAG;AACzC,YAAM,WAAW,MAAM,KAAK;AAAA,QAC1B;AAAA,UACE,MAAM,QAAQ;AAAA,UACd,UAAU,QAAQ;AAAA,UAClB,WAAW;AAAA,UACX,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;AAAA,QACxD;AAAA,QACA;AAAA,MACF;AACA,UAAI,CAAC,SAAS,UAAU;AACtB,cAAM,QAAQ,KAAK;AACnB,eAAO;AAAA,UACL,IAAI;AAAA,UACJ,MAAM,SAAS,MAAM,SAAS,SAAS,UAAU;AAAA,UACjD,SAAS,SAAS,MAAM;AAAA,QAC1B;AAAA,MACF;AACA,YAAM,aAAa,OAAO,SAAS,YAAY;AAC/C,YAAM,SAAS,OAAO,MAAM,KAAK,QAAQ,WAAW,YAAY,OAAO,IAAI,OAAO,OAAO;AACzF,YAAM,YAAY,YAAY,QAAQ,QAAQ,UAAU,IAAI;AAC5D,YAAM,WAAW,IAAI;AAAA,QACnB,IAAI,OAAO,QAAQ,QAAQ;AAAA,QAC3B,QAAQ,SAAS;AAAA,QACjB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,YAAM,EAAE,IAAI,OAAO,IAAI,QAAQ,KAAK,CAAC,UAAU;AAC7C,cAAM,QAAQ,SAAS,KAAK,KAAK;AACjC,eAAO,KAAK,SAAS,MAAM,CAAC;AAC5B,YAAI,MAAO,MAAK,OAAO,OAAO;AAAA,MAChC,CAAC;AACD,aAAO,EAAE,IAAI,MAAM,QAAQ,IAAI,WAAW,MAAM,MAAM,KAAK,MAAM;AAAA,IACnE;AAAA,IACA,MAAM,MAAM,SAAS,SAAS;AAC5B,YAAM;AACN,YAAM,UAAU,MAAM,SAAS,QAAQ,SAAS,OAAO;AACvD,YAAM,UAAU,QAAQ,SAAS,YAAY;AAC7C,YAAM,MAAM,SAAS,QAAQ,SAAS,SAAS,SAAS,QAAQ,QAAQ;AACxE,YAAM,OAAO,OAAO,GAAG;AACvB,YAAM,KAAK,QAAQ,UAAU,OAAO,KAAK,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,MAAM,QAAQ,KAAK;AACvF,YAAM,MAAM,QAAQ,UAAU,QAAQ,KAAK;AAC3C,YAAM,SAAS,IAAI,OAAO,QAAQ,QAAQ;AAC1C,iBAAW,SAAS,QAAQ,SAAS,QAAS,QAAO,MAAM,KAAK;AAChE,aAAO,QAAQ,OAAO;AACtB,YAAM,EAAE,IAAI,OAAO,IAAI,QAAQ;AAAA,QAAK,CAAC,UACnC,OAAO,KAAK,MAAM,QAAQ,CAAC,UAAU,SAAS,QAAQ,KAAK,CAAC,CAAC;AAAA,MAC/D;AACA,UAAI,MAAM,GAAG;AACX,cAAM,MAAM,IAAI,EAAE;AAClB,cAAM,UAAU,KAAK,GAAG;AACxB,YAAI,OAAO;AACX,eAAO,OAAO,IAAI,IAAI,UAAU,KAAK,IAAI,OAAO,CAAC,CAAgB,MAAM,QAAS;AAChF,cAAM,SAAS,IAAI,MAAM,UAAU,IAAI,MAAM,aAAa,CAAC,GAAG,IAAI,CAAC;AACnE,eAAO,KAAK,CAAC,GAAG,QAAQ,GAAG,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC;AAAA,MACjD;AACA,aAAO,EAAE,IAAI,MAAM,QAAQ,IAAI,WAAW,MAAM,MAAM,IAAI;AAAA,IAC5D;AAAA,IACA,MAAM,KAAK,IAAI,QAAQ,SAAS;AAC9B,YAAM,SAAS,QAAQ,IAAI,EAAE;AAC7B,UAAI,CAAC,OAAQ,QAAO,EAAE,QAAQ,CAAC,GAAG,MAAM,KAAK;AAC7C,aAAO,UAAU,IAAI;AACrB,YAAM,OAAO,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,GAAK,CAAC,CAAC;AACtD,cAAQ,aAAa,eAAe;AACpC,YAAM,SAAS,OAAO,MAAM,OAAO,CAAC;AACpC,YAAM,OAAO,OAAO,QAAQ,OAAO,MAAM,WAAW;AACpD,UAAI,KAAM,SAAQ,OAAO,EAAE;AAC3B,aAAO,EAAE,QAAQ,KAAK;AAAA,IACxB;AAAA,IACA,MAAM,MAAM,IAAI;AACd,YAAM,SAAS,QAAQ,IAAI,EAAE;AAC7B,cAAQ,OAAO,EAAE;AACjB,YAAM,QAAQ,OAAO;AAAA,IACvB;AAAA,IACA,MAAM,MAAM,SAAS,SAAS;AAC5B,YAAM,eAAe,MAAM,KAAK,aAAa,SAAS,OAAO;AAC7D,YAAM,UAAU,MAAM,YAAY,KAAK,SAAS,aAAa,IAAI,OAAO;AACxE,YAAM,OAAO,QAAQ,QAAQ,SAAS,GAAG;AACzC,YAAM,QAAQ,KAAK;AACnB,UAAI,KAAM,OAAM,aAAa,MAAM,OAAO;AAC1C,aAAO,EAAE,SAAS,KAAK;AAAA,IACzB;AAAA,IACA,MAAM,UAAU;AACd,oBAAc,KAAK;AACnB,cAAQ;AACR,YAAM,MAAM,CAAC,GAAG,QAAQ,OAAO,CAAC;AAChC,cAAQ,MAAM;AACd,YAAM,QAAQ,IAAI,IAAI,IAAI,CAAC,WAAW,OAAO,OAAO,CAAC,CAAC;AAAA,IACxD;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
|
|
2
|
+
import { Stream } from "./host.js";
|
|
3
|
+
const PAGES_IDLE_MS = 3e4;
|
|
4
|
+
const PICK_MS = 5e3;
|
|
5
|
+
const ANSWER_MS = 5e3;
|
|
6
|
+
const MAX_PENDING = 100;
|
|
7
|
+
function tabOf(value) {
|
|
8
|
+
return {
|
|
9
|
+
tab: String(value?.tab ?? ""),
|
|
10
|
+
kinds: Array.isArray(value?.kinds) ? value.kinds.map(String) : [],
|
|
11
|
+
cone: typeof value?.cone === "string" ? value.cone : null,
|
|
12
|
+
visible: value?.visible === true,
|
|
13
|
+
focused: value?.focused === true,
|
|
14
|
+
lastActive: Number.isFinite(value?.lastActive) ? Number(value.lastActive) : 0
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function resultOf(value) {
|
|
18
|
+
return {
|
|
19
|
+
stdout: typeof value?.stdout === "string" ? value.stdout : "",
|
|
20
|
+
stderr: typeof value?.stderr === "string" ? value.stderr : "",
|
|
21
|
+
code: Number.isInteger(value?.code) ? value.code : 1
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function rank(entry) {
|
|
25
|
+
if (entry.tab.visible && entry.tab.focused) return 2;
|
|
26
|
+
return entry.tab.visible ? 1 : 0;
|
|
27
|
+
}
|
|
28
|
+
function noTab(cone) {
|
|
29
|
+
return {
|
|
30
|
+
stdout: "",
|
|
31
|
+
stderr: `panel: no open SLICC tab shows cone ${cone}; open SLICC or switch a tab to ${cone}
|
|
32
|
+
`,
|
|
33
|
+
code: 3
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function noAnswer(cone) {
|
|
37
|
+
return {
|
|
38
|
+
stdout: "",
|
|
39
|
+
stderr: `panel: the tab showing cone ${cone} didn't answer; try again
|
|
40
|
+
`,
|
|
41
|
+
code: 4
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function ownedPages(pages) {
|
|
45
|
+
const mine = /* @__PURE__ */ new Set();
|
|
46
|
+
return {
|
|
47
|
+
async open(tab, context) {
|
|
48
|
+
const opened = await pages.open(tab, context);
|
|
49
|
+
if ("stream" in opened) mine.add(opened.stream);
|
|
50
|
+
return opened;
|
|
51
|
+
},
|
|
52
|
+
async report(stream, tab, context) {
|
|
53
|
+
if (mine.has(stream)) await pages.report(stream, tab, context);
|
|
54
|
+
},
|
|
55
|
+
async next(stream, waitMs, context) {
|
|
56
|
+
if (!mine.has(stream)) return { requests: [], done: true };
|
|
57
|
+
const batch = await pages.next(stream, waitMs, context);
|
|
58
|
+
if (batch.done) mine.delete(stream);
|
|
59
|
+
return batch;
|
|
60
|
+
},
|
|
61
|
+
async answer(stream, id, result, context) {
|
|
62
|
+
if (mine.has(stream)) await pages.answer(stream, id, result, context);
|
|
63
|
+
},
|
|
64
|
+
async close(stream, context) {
|
|
65
|
+
if (mine.delete(stream)) await pages.close(stream, context);
|
|
66
|
+
},
|
|
67
|
+
release() {
|
|
68
|
+
for (const stream of mine) void pages.close(stream, BACKGROUND_CONTEXT);
|
|
69
|
+
mine.clear();
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function createPages(options = {}) {
|
|
74
|
+
const now = options.now ?? Date.now;
|
|
75
|
+
const idleMs = options.idleMs ?? PAGES_IDLE_MS;
|
|
76
|
+
const pickMs = options.pickMs ?? PICK_MS;
|
|
77
|
+
const answerMs = options.answerMs ?? ANSWER_MS;
|
|
78
|
+
const entries = /* @__PURE__ */ new Map();
|
|
79
|
+
const pending = /* @__PURE__ */ new Map();
|
|
80
|
+
let serial = 0;
|
|
81
|
+
let timer;
|
|
82
|
+
const drop = (id) => {
|
|
83
|
+
const entry = entries.get(id);
|
|
84
|
+
if (!entry) return;
|
|
85
|
+
entries.delete(id);
|
|
86
|
+
void entry.stream.finish();
|
|
87
|
+
};
|
|
88
|
+
const sweep = () => {
|
|
89
|
+
for (const [id, entry] of entries) if (now() - entry.stream.touched > idleMs) drop(id);
|
|
90
|
+
if (!entries.size && timer !== void 0) {
|
|
91
|
+
clearInterval(timer);
|
|
92
|
+
timer = void 0;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const fail = (stream) => {
|
|
96
|
+
for (const waiting of [...pending.values()])
|
|
97
|
+
if (waiting.stream === stream) waiting.settle(noAnswer(waiting.cone));
|
|
98
|
+
};
|
|
99
|
+
const choose = (ask) => {
|
|
100
|
+
const live = [...entries.values()].filter((entry) => entry.tab.kinds.includes(ask.kind));
|
|
101
|
+
const named = ask.tab ? live.filter((entry) => entry.tab.tab === ask.tab).sort((a, b) => b.serial - a.serial)[0] : void 0;
|
|
102
|
+
if (named) return named;
|
|
103
|
+
return live.filter((entry) => entry.tab.cone === ask.cone).sort(
|
|
104
|
+
(a, b) => rank(b) - rank(a) || b.tab.lastActive - a.tab.lastActive || b.serial - a.serial
|
|
105
|
+
)[0];
|
|
106
|
+
};
|
|
107
|
+
const request = (ask) => {
|
|
108
|
+
sweep();
|
|
109
|
+
const entry = choose(ask);
|
|
110
|
+
const cone = entry?.tab.cone ?? ask.cone;
|
|
111
|
+
if (!entry) return Promise.resolve(noTab(cone));
|
|
112
|
+
const id = `p${++serial}-${crypto.randomUUID()}`;
|
|
113
|
+
const item = {
|
|
114
|
+
id,
|
|
115
|
+
kind: ask.kind,
|
|
116
|
+
argv: [...ask.argv],
|
|
117
|
+
caller: { agentId: ask.agentId, cone, readOnly: false }
|
|
118
|
+
};
|
|
119
|
+
return new Promise((resolve) => {
|
|
120
|
+
const settle = (result) => {
|
|
121
|
+
const waiting = pending.get(id);
|
|
122
|
+
if (!waiting) return;
|
|
123
|
+
clearTimeout(waiting.timer);
|
|
124
|
+
pending.delete(id);
|
|
125
|
+
const at = entry.stream.queue.indexOf(item);
|
|
126
|
+
if (at >= 0) entry.stream.queue.splice(at, 1);
|
|
127
|
+
resolve(result);
|
|
128
|
+
};
|
|
129
|
+
pending.set(id, {
|
|
130
|
+
stream: entry.id,
|
|
131
|
+
cone,
|
|
132
|
+
timer: setTimeout(() => settle(noAnswer(cone)), pickMs),
|
|
133
|
+
settle
|
|
134
|
+
});
|
|
135
|
+
entry.stream.push([item]);
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
const pages = {
|
|
139
|
+
async open(tab) {
|
|
140
|
+
sweep();
|
|
141
|
+
const id = `t${++serial}-${crypto.randomUUID()}`;
|
|
142
|
+
const stream = new Stream(
|
|
143
|
+
async () => {
|
|
144
|
+
entries.delete(id);
|
|
145
|
+
fail(id);
|
|
146
|
+
},
|
|
147
|
+
now(),
|
|
148
|
+
MAX_PENDING,
|
|
149
|
+
[]
|
|
150
|
+
);
|
|
151
|
+
entries.set(id, { id, stream, tab: tabOf(tab), serial });
|
|
152
|
+
timer ??= setInterval(sweep, options.sweepMs ?? idleMs / 4);
|
|
153
|
+
return { stream: id };
|
|
154
|
+
},
|
|
155
|
+
async report(id, tab) {
|
|
156
|
+
const entry = entries.get(id);
|
|
157
|
+
if (!entry) return;
|
|
158
|
+
entry.tab = tabOf(tab);
|
|
159
|
+
entry.stream.touched = now();
|
|
160
|
+
},
|
|
161
|
+
async next(id, waitMs, context) {
|
|
162
|
+
const entry = entries.get(id);
|
|
163
|
+
if (!entry) return { requests: [], done: true };
|
|
164
|
+
entry.stream.touched = now();
|
|
165
|
+
const signal = context.abortSignal;
|
|
166
|
+
await entry.stream.wait(Math.max(0, Math.min(waitMs, idleMs / 2)), signal);
|
|
167
|
+
if (signal?.aborted) {
|
|
168
|
+
drop(id);
|
|
169
|
+
signal.throwIfAborted();
|
|
170
|
+
}
|
|
171
|
+
entry.stream.touched = now();
|
|
172
|
+
const requests = entry.stream.queue.splice(0);
|
|
173
|
+
for (const item of requests) {
|
|
174
|
+
const waiting = pending.get(item.id);
|
|
175
|
+
if (!waiting) continue;
|
|
176
|
+
clearTimeout(waiting.timer);
|
|
177
|
+
waiting.timer = setTimeout(() => waiting.settle(noAnswer(waiting.cone)), answerMs);
|
|
178
|
+
}
|
|
179
|
+
const done = entry.stream.done;
|
|
180
|
+
if (done) entries.delete(id);
|
|
181
|
+
return { requests, done };
|
|
182
|
+
},
|
|
183
|
+
async answer(id, request2, result) {
|
|
184
|
+
const waiting = pending.get(request2);
|
|
185
|
+
if (waiting?.stream !== id) return;
|
|
186
|
+
waiting.settle(resultOf(result));
|
|
187
|
+
},
|
|
188
|
+
async close(id) {
|
|
189
|
+
drop(id);
|
|
190
|
+
},
|
|
191
|
+
request,
|
|
192
|
+
async command(argv, caller) {
|
|
193
|
+
const result = await request({ kind: "panel", argv, ...caller });
|
|
194
|
+
return { code: result.code, out: result.stdout, err: result.stderr };
|
|
195
|
+
},
|
|
196
|
+
tabs: () => [...entries.values()].map((entry) => ({ ...entry.tab })),
|
|
197
|
+
async dispose() {
|
|
198
|
+
clearInterval(timer);
|
|
199
|
+
timer = void 0;
|
|
200
|
+
const all = [...entries.keys()];
|
|
201
|
+
for (const id of all) drop(id);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
return pages;
|
|
205
|
+
}
|
|
206
|
+
export {
|
|
207
|
+
ANSWER_MS,
|
|
208
|
+
MAX_PENDING,
|
|
209
|
+
PAGES_IDLE_MS,
|
|
210
|
+
PICK_MS,
|
|
211
|
+
createPages,
|
|
212
|
+
noAnswer,
|
|
213
|
+
noTab,
|
|
214
|
+
ownedPages
|
|
215
|
+
};
|
|
216
|
+
//# sourceMappingURL=pages.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/remote/pages.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { Answer } from '../scoops/service.ts';\nimport { Stream } from './host.ts';\n\nexport const PAGES_IDLE_MS = 30000;\nexport const PICK_MS = 5000;\nexport const ANSWER_MS = 5000;\nexport const MAX_PENDING = 100;\n\nexport interface PageTab {\n tab: string;\n kinds: string[];\n cone: string | null;\n visible: boolean;\n focused: boolean;\n lastActive: number;\n}\n\nexport interface PageCaller {\n agentId: string | null;\n cone: string;\n readOnly?: boolean;\n}\n\nexport interface PageRequest {\n id: string;\n kind: 'panel';\n argv: string[];\n caller: PageCaller;\n}\n\nexport interface PageResult {\n stdout: string;\n stderr: string;\n code: number;\n}\n\nexport type PagesOpened = { stream: string } | { error: string };\n\nexport interface PageBatch {\n requests: PageRequest[];\n done: boolean;\n}\n\nexport interface AgentPages {\n open(tab: PageTab, context: Context): Promise<PagesOpened>;\n report(stream: string, tab: PageTab, context: Context): Promise<void>;\n next(stream: string, waitMs: number, context: Context): Promise<PageBatch>;\n answer(stream: string, id: string, result: PageResult, context: Context): Promise<void>;\n close(stream: string, context: Context): Promise<void>;\n}\n\nexport interface PageAsk {\n kind: 'panel';\n argv: readonly string[];\n agentId: string | null;\n cone: string;\n tab: string | null;\n}\n\nexport interface Pages extends AgentPages {\n request(ask: PageAsk): Promise<PageResult>;\n command(\n argv: readonly string[],\n caller: { agentId: string | null; cone: string; tab: string | null },\n context: Context\n ): Promise<Answer>;\n tabs(): PageTab[];\n dispose(): Promise<void>;\n}\n\nexport interface PagesOptions {\n now?: () => number;\n idleMs?: number;\n sweepMs?: number;\n pickMs?: number;\n answerMs?: number;\n}\n\ninterface Pending {\n stream: string;\n cone: string;\n timer: ReturnType<typeof setTimeout>;\n settle(result: PageResult): void;\n}\n\ninterface Entry {\n id: string;\n stream: Stream<PageRequest>;\n tab: PageTab;\n serial: number;\n}\n\nfunction tabOf(value: PageTab): PageTab {\n return {\n tab: String(value?.tab ?? ''),\n kinds: Array.isArray(value?.kinds) ? value.kinds.map(String) : [],\n cone: typeof value?.cone === 'string' ? value.cone : null,\n visible: value?.visible === true,\n focused: value?.focused === true,\n lastActive: Number.isFinite(value?.lastActive) ? Number(value.lastActive) : 0,\n };\n}\n\nfunction resultOf(value: PageResult): PageResult {\n return {\n stdout: typeof value?.stdout === 'string' ? value.stdout : '',\n stderr: typeof value?.stderr === 'string' ? value.stderr : '',\n code: Number.isInteger(value?.code) ? value.code : 1,\n };\n}\n\nfunction rank(entry: Entry): number {\n if (entry.tab.visible && entry.tab.focused) return 2;\n return entry.tab.visible ? 1 : 0;\n}\n\nexport function noTab(cone: string): PageResult {\n return {\n stdout: '',\n stderr: `panel: no open SLICC tab shows cone ${cone}; open SLICC or switch a tab to ${cone}\\n`,\n code: 3,\n };\n}\n\nexport function noAnswer(cone: string): PageResult {\n return {\n stdout: '',\n stderr: `panel: the tab showing cone ${cone} didn't answer; try again\\n`,\n code: 4,\n };\n}\n\nexport function ownedPages(pages: AgentPages): AgentPages & { release(): void } {\n const mine = new Set<string>();\n return {\n async open(tab, context) {\n const opened = await pages.open(tab, context);\n if ('stream' in opened) mine.add(opened.stream);\n return opened;\n },\n async report(stream, tab, context) {\n if (mine.has(stream)) await pages.report(stream, tab, context);\n },\n async next(stream, waitMs, context) {\n if (!mine.has(stream)) return { requests: [], done: true };\n const batch = await pages.next(stream, waitMs, context);\n if (batch.done) mine.delete(stream);\n return batch;\n },\n async answer(stream, id, result, context) {\n if (mine.has(stream)) await pages.answer(stream, id, result, context);\n },\n async close(stream, context) {\n if (mine.delete(stream)) await pages.close(stream, context);\n },\n release() {\n for (const stream of mine) void pages.close(stream, BACKGROUND_CONTEXT);\n mine.clear();\n },\n };\n}\n\nexport function createPages(options: PagesOptions = {}): Pages {\n const now = options.now ?? Date.now;\n const idleMs = options.idleMs ?? PAGES_IDLE_MS;\n const pickMs = options.pickMs ?? PICK_MS;\n const answerMs = options.answerMs ?? ANSWER_MS;\n const entries = new Map<string, Entry>();\n const pending = new Map<string, Pending>();\n let serial = 0;\n let timer: ReturnType<typeof setInterval> | undefined;\n\n const drop = (id: string) => {\n const entry = entries.get(id);\n if (!entry) return;\n entries.delete(id);\n void entry.stream.finish();\n };\n const sweep = () => {\n for (const [id, entry] of entries) if (now() - entry.stream.touched > idleMs) drop(id);\n if (!entries.size && timer !== undefined) {\n clearInterval(timer);\n timer = undefined;\n }\n };\n const fail = (stream: string) => {\n for (const waiting of [...pending.values()])\n if (waiting.stream === stream) waiting.settle(noAnswer(waiting.cone));\n };\n const choose = (ask: PageAsk): Entry | undefined => {\n const live = [...entries.values()].filter((entry) => entry.tab.kinds.includes(ask.kind));\n const named = ask.tab\n ? live.filter((entry) => entry.tab.tab === ask.tab).sort((a, b) => b.serial - a.serial)[0]\n : undefined;\n if (named) return named;\n return live\n .filter((entry) => entry.tab.cone === ask.cone)\n .sort(\n (a, b) => rank(b) - rank(a) || b.tab.lastActive - a.tab.lastActive || b.serial - a.serial\n )[0];\n };\n const request = (ask: PageAsk): Promise<PageResult> => {\n sweep();\n const entry = choose(ask);\n const cone = entry?.tab.cone ?? ask.cone;\n if (!entry) return Promise.resolve(noTab(cone));\n const id = `p${++serial}-${crypto.randomUUID()}`;\n const item: PageRequest = {\n id,\n kind: ask.kind,\n argv: [...ask.argv],\n caller: { agentId: ask.agentId, cone, readOnly: false },\n };\n return new Promise((resolve) => {\n const settle = (result: PageResult) => {\n const waiting = pending.get(id);\n if (!waiting) return;\n clearTimeout(waiting.timer);\n pending.delete(id);\n const at = entry.stream.queue.indexOf(item);\n if (at >= 0) entry.stream.queue.splice(at, 1);\n resolve(result);\n };\n pending.set(id, {\n stream: entry.id,\n cone,\n timer: setTimeout(() => settle(noAnswer(cone)), pickMs),\n settle,\n });\n entry.stream.push([item]);\n });\n };\n const pages: Pages = {\n async open(tab) {\n sweep();\n const id = `t${++serial}-${crypto.randomUUID()}`;\n const stream = new Stream<PageRequest>(\n async () => {\n entries.delete(id);\n fail(id);\n },\n now(),\n MAX_PENDING,\n []\n );\n entries.set(id, { id, stream, tab: tabOf(tab), serial });\n timer ??= setInterval(sweep, options.sweepMs ?? idleMs / 4);\n return { stream: id };\n },\n async report(id, tab) {\n const entry = entries.get(id);\n if (!entry) return;\n entry.tab = tabOf(tab);\n entry.stream.touched = now();\n },\n async next(id, waitMs, context) {\n const entry = entries.get(id);\n if (!entry) return { requests: [], done: true };\n entry.stream.touched = now();\n const signal = context.abortSignal;\n await entry.stream.wait(Math.max(0, Math.min(waitMs, idleMs / 2)), signal);\n if (signal?.aborted) {\n drop(id);\n signal.throwIfAborted();\n }\n entry.stream.touched = now();\n const requests = entry.stream.queue.splice(0);\n for (const item of requests) {\n const waiting = pending.get(item.id);\n if (!waiting) continue;\n clearTimeout(waiting.timer);\n waiting.timer = setTimeout(() => waiting.settle(noAnswer(waiting.cone)), answerMs);\n }\n const done = entry.stream.done;\n if (done) entries.delete(id);\n return { requests, done };\n },\n async answer(id, request, result) {\n const waiting = pending.get(request);\n if (waiting?.stream !== id) return;\n waiting.settle(resultOf(result));\n },\n async close(id) {\n drop(id);\n },\n request,\n async command(argv, caller) {\n const result = await request({ kind: 'panel', argv, ...caller });\n return { code: result.code, out: result.stdout, err: result.stderr };\n },\n tabs: () => [...entries.values()].map((entry) => ({ ...entry.tab })),\n async dispose() {\n clearInterval(timer);\n timer = undefined;\n const all = [...entries.keys()];\n for (const id of all) drop(id);\n },\n };\n return pages;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["request"]
|
|
7
|
+
}
|
package/dist/scoops/cli.js
CHANGED
|
@@ -340,7 +340,22 @@ function noScoop(state, name) {
|
|
|
340
340
|
if (frozen) return `scoop ${name} is frozen with cone ${frozen.name}; thaw the cone first`;
|
|
341
341
|
return `there is no scoop ${name}`.trim();
|
|
342
342
|
}
|
|
343
|
+
function panelCaller(request, who) {
|
|
344
|
+
const agentId = who.scoop ?? (who.fromAgent ? who.cone : null);
|
|
345
|
+
return { agentId, cone: who.cone, tab: agentId === null ? request.tab ?? null : null };
|
|
346
|
+
}
|
|
347
|
+
const ALIASES = /* @__PURE__ */ new Set(["open", "close"]);
|
|
348
|
+
function panelArgv(request) {
|
|
349
|
+
if (request.as === "panel") return request.argv;
|
|
350
|
+
const [verb, name, ...rest] = request.argv;
|
|
351
|
+
if (request.as !== "sprinkle" || !ALIASES.has(verb ?? "")) return void 0;
|
|
352
|
+
if (!name) return [verb];
|
|
353
|
+
return [verb, name.startsWith("sprinkle:") ? name : `sprinkle:${name}`, ...rest];
|
|
354
|
+
}
|
|
343
355
|
async function dispatch(deps, request, who, context) {
|
|
356
|
+
const forwarded = panelArgv(request);
|
|
357
|
+
if (forwarded)
|
|
358
|
+
return deps.panel ? deps.panel(forwarded, panelCaller(request, who), context) : { code: 1, out: "panel: panels are not available in this agent\n" };
|
|
344
359
|
if (request.as === "sprinkle")
|
|
345
360
|
return deps.sprinkle ? deps.sprinkle(request.argv, who.id, context) : fail("sprinkles are not available in this agent");
|
|
346
361
|
if (request.as === "memory")
|
|
@@ -377,6 +392,7 @@ function createCli(options) {
|
|
|
377
392
|
const deps = { ...options, now: options.now ?? Date.now, sync: { pending: /* @__PURE__ */ new Map() } };
|
|
378
393
|
return {
|
|
379
394
|
blocking(request) {
|
|
395
|
+
if (panelArgv(request)) return true;
|
|
380
396
|
const first = request.argv[0] ?? "";
|
|
381
397
|
if (BLOCKING.has(first)) return true;
|
|
382
398
|
return request.as === "agent" && !VERBS[first] && !request.argv.includes("--async");
|
|
@@ -405,6 +421,7 @@ export {
|
|
|
405
421
|
last,
|
|
406
422
|
noScoop,
|
|
407
423
|
ok,
|
|
424
|
+
panelCaller,
|
|
408
425
|
prompts,
|
|
409
426
|
readText,
|
|
410
427
|
role,
|