@ai-ecoverse/slicc-agent 3.32.0 → 3.33.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 +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +2 -2
- package/dist/mcp/config.js +2 -2
- package/dist/mcp/config.js.map +1 -1
- package/dist/mcp/connection.js +2 -2
- package/dist/mcp/connection.js.map +1 -1
- package/dist/mcp/index.js +6 -0
- package/dist/mcp/index.js.map +2 -2
- package/dist/mcp/label.js +14 -0
- package/dist/mcp/label.js.map +7 -0
- package/dist/mcp/runtime.js +65 -4
- package/dist/mcp/runtime.js.map +2 -2
- package/dist/remote/events.js +2 -1
- package/dist/remote/events.js.map +2 -2
- package/dist/services.js.map +2 -2
- package/dist/settings.js +14 -2
- package/dist/settings.js.map +2 -2
- package/dist/spectrum/messages.js +2 -1
- package/dist/spectrum/messages.js.map +2 -2
- package/dist/types/mcp/index.d.ts +1 -1
- package/dist/types/mcp/label.d.ts +2 -0
- package/dist/types/mcp/runtime.d.ts +9 -1
- package/dist/types/services.d.ts +3 -1
- package/dist/types/settings.d.ts +2 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -267,7 +267,7 @@ MCP servers reachable over Streamable HTTP become native agent tools. The client
|
|
|
267
267
|
|
|
268
268
|
**Per agent.** Today every cone reads the one file in `/home` and gets every enabled server. A scoop doesn't read a file of its own: it inherits its cone's servers, and a role's `tools:` or `agent --tools` list narrows them. A list with no `mcp__` entry gets no MCP servers. A list with `mcp__docs__search` or `mcp__docs__*` keeps only those, and `codemode` is added so codemode tools stay reachable. The resource tools must be listed by name, and they reach only the servers the list names. A nested scoop without a list inherits its calling scoop's list. A `beforeTool` hook blocks the model's calls outside the list, and codemode scripts only get the tools on it. When kernel users give each cone its own home, each cone reads `~/.pi/agent/mcp.json` in that home, and scoops keep inheriting from their cone.
|
|
269
269
|
|
|
270
|
-
**Secrets.** `${NAME}` placeholders are filled from the agent's encrypted credential store, under `mcp:<server>|<hash of the URL>`, when the worker connects. A server whose secret is missing comes up as needing one, with a lick. Pointing a server at another URL leaves it without its secret. Header values never reach SQLite, the transcript, licks or `~/.pi/agent/mcp.log`, and stored secrets are scrubbed from error texts and server log lines.
|
|
270
|
+
**Secrets.** `${NAME}` placeholders are filled from the agent's encrypted credential store, under `mcp:<server>|<hash of the URL>`, when the worker connects. A server whose secret is missing comes up as needing one, with a lick. Pointing a server at another URL leaves it without its secret. Header values never reach SQLite, the transcript, licks or `~/.pi/agent/mcp.log`, and stored secrets are scrubbed from error texts and server log lines. **Settings › MCP servers** lists each server whose headers use a placeholder, under its own heading below Accounts, with the URL host. Connect takes the token, which fills every placeholder of a server that uses one name; a server whose headers use several different names can't be filled from Settings yet. The server then reconnects. A server that answers 401 shows as **Rejected**, with Reconnect, and Disconnect deletes the token. Tool cards and remote summaries label MCP calls `server · tool`, unless the name is ambiguous (a server name that starts or ends with `_`, or a name with more than two `__` separators); then they show the raw name.
|
|
271
271
|
|
|
272
272
|
**Tools.** Tools are named `mcp__<server>__<tool>` (pi's names: everything but letters, digits and `_` becomes `_`, cut to 64 characters with a hash suffix on a collision). Their exposure follows pi:
|
|
273
273
|
- `codemode` (the default): callable from codemode scripts as `tools.mcp__docs__search(args)`, which resolves to the whole `CallToolResult`, but not declared to the model. The `mcp_servers` section lists these servers with their description or the first line of the server's instructions. It also says that MCP results are data from the server, not instructions.
|
package/dist/main.js
CHANGED
|
@@ -199,7 +199,7 @@ async function start(scope, port, options) {
|
|
|
199
199
|
await memoryRuntime.reload(BACKGROUND_CONTEXT).catch(() => void 0);
|
|
200
200
|
const changes = attachChanges({ agents: agent.agents, env: home, reloadMs: CHANGES_MS });
|
|
201
201
|
return hostAgent(agent, {
|
|
202
|
-
settings: await createAgentSettings(models, credentials, providers),
|
|
202
|
+
settings: await createAgentSettings(models, credentials, providers, { mcp: mcpRuntime }),
|
|
203
203
|
licks: { licks: licks.licks, sources },
|
|
204
204
|
scoops: { scoops: scoops.scoops, runtime },
|
|
205
205
|
skills: skillsRuntime,
|
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 { setupLicks } from './licks/index.ts';\nimport { setupMcp } from './mcp/index.ts';\nimport { setupMemory } from './memory/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 { kernelPort, 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}\n\nasync function start(\n scope: AgentWorkerScope,\n port: Promise<MessagePort>,\n options: AgentWorkerOptions\n): Promise<AgentHost> {\n const attach: KernelAttach = options.attach ?? attachKernel;\n const client = await attach(await port);\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 settings = await client.fs\n .readFile(`${HOME}/.pi/agent/settings.json`)\n .catch(() => undefined);\n const coding = CodingTools.tools as readonly ToolRegistration[];\n const mcp = setupMcp(registry);\n const codemode = disabledBySettings(\n settings === undefined ? undefined : new TextDecoder().decode(settings)\n )\n ? []\n : [\n codemodeTool({\n declared: coding,\n sandbox: sandboxFactory(\n options.codemodeWasm ?? (() => locateWasm(native, new URL(import.meta.url))),\n options.codemodeWorker\n ),\n extra: mcp.codemode,\n }),\n ];\n registry.install(codemodeExtension(codemode));\n const licks = setupLicks(registry);\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 home = new SliccKernelEnv(client, { cwd: HOME });\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 },\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 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 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: await createAgentSettings(models, credentials, providers),\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 });\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, kernelPort(scope), options);\n host.catch(() => undefined);\n serveConnections(scope, host);\n return host;\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
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 { setupLicks } from './licks/index.ts';\nimport { setupMcp } from './mcp/index.ts';\nimport { setupMemory } from './memory/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 { kernelPort, 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}\n\nasync function start(\n scope: AgentWorkerScope,\n port: Promise<MessagePort>,\n options: AgentWorkerOptions\n): Promise<AgentHost> {\n const attach: KernelAttach = options.attach ?? attachKernel;\n const client = await attach(await port);\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 settings = await client.fs\n .readFile(`${HOME}/.pi/agent/settings.json`)\n .catch(() => undefined);\n const coding = CodingTools.tools as readonly ToolRegistration[];\n const mcp = setupMcp(registry);\n const codemode = disabledBySettings(\n settings === undefined ? undefined : new TextDecoder().decode(settings)\n )\n ? []\n : [\n codemodeTool({\n declared: coding,\n sandbox: sandboxFactory(\n options.codemodeWasm ?? (() => locateWasm(native, new URL(import.meta.url))),\n options.codemodeWorker\n ),\n extra: mcp.codemode,\n }),\n ];\n registry.install(codemodeExtension(codemode));\n const licks = setupLicks(registry);\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 home = new SliccKernelEnv(client, { cwd: HOME });\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 },\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 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 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: await createAgentSettings(models, credentials, providers, { mcp: mcpRuntime }),\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 });\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, kernelPort(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/mcp/config.js
CHANGED
|
@@ -56,7 +56,7 @@ function checkHeaders(name, headers) {
|
|
|
56
56
|
if (literalSecret(header, value))
|
|
57
57
|
return fail(
|
|
58
58
|
name,
|
|
59
|
-
`headers.${header} holds a literal secret. mcp.json is readable by every agent: write \${NAME} instead, and add the value in Settings \u203A
|
|
59
|
+
`headers.${header} holds a literal secret. mcp.json is readable by every agent: write \${NAME} instead, and add the value in Settings \u203A MCP servers`,
|
|
60
60
|
`headers.${header}`
|
|
61
61
|
);
|
|
62
62
|
}
|
|
@@ -101,7 +101,7 @@ function checkTransport(name, value) {
|
|
|
101
101
|
if (secret)
|
|
102
102
|
return fail(
|
|
103
103
|
name,
|
|
104
|
-
`${secret} holds a literal secret. Put it in a header as \${NAME} and add the value in Settings \u203A
|
|
104
|
+
`${secret} holds a literal secret. Put it in a header as \${NAME} and add the value in Settings \u203A MCP servers`,
|
|
105
105
|
"url"
|
|
106
106
|
);
|
|
107
107
|
return void 0;
|
package/dist/mcp/config.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/mcp/config.ts"],
|
|
4
|
-
"sourcesContent": ["import { hash } from '../licks/sources.ts';\n\nexport type McpExposure = 'codemode' | 'deferred' | 'direct' | 'hidden';\n\nexport interface McpServerConfig {\n url: string;\n headers?: Record<string, string>;\n exposure?: McpExposure;\n toolExposure?: Record<string, McpExposure>;\n enabled?: boolean;\n timeout?: number;\n description?: string;\n}\n\nexport interface McpServerEntry {\n name: string;\n config: McpServerConfig;\n}\n\nexport interface McpConfigProblem {\n server?: string;\n field?: string;\n message: string;\n}\n\nexport interface McpConfig {\n servers: McpServerEntry[];\n problems: McpConfigProblem[];\n}\n\nconst SERVER_NAME = /^[A-Za-z0-9_-]+$/;\nconst EXPOSURES: readonly string[] = ['codemode', 'deferred', 'direct', 'hidden'];\nconst ALIASES: Record<string, McpExposure> = { 'codemode-deferred': 'codemode' };\nconst ACCEPTED = new Set([\n 'type',\n 'url',\n 'headers',\n 'exposure',\n 'toolExposure',\n 'enabled',\n 'timeout',\n 'description',\n]);\nconst SECRET_HEADER = /authorization|cookie|token|key|secret|password|session/i;\nconst SECRET_PARAM = /token|key|secret|password|signature|sig|auth|code/i;\nconst PLACEHOLDER = /\\$\\{([A-Za-z_][A-Za-z0-9_]*)\\}/g;\nconst SCHEME = /^\\s*(?:bearer|basic|token|apikey|api-key)\\s+/i;\nconst MAX_TOOL_NAME = 64;\nexport const DEFAULT_TIMEOUT_SECONDS = 60;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction alias(value: unknown): unknown {\n return typeof value === 'string' ? (ALIASES[value] ?? value) : value;\n}\n\nfunction isExposure(value: unknown): value is McpExposure {\n return typeof value === 'string' && EXPOSURES.includes(value);\n}\n\nexport function placeholders(value: string): string[] {\n return [...value.matchAll(PLACEHOLDER)].map((match) => match[1] as string);\n}\n\nexport function literalSecret(header: string, value: string): boolean {\n if (!SECRET_HEADER.test(header)) return false;\n return value.replace(PLACEHOLDER, '').replace(SCHEME, '').trim() !== '';\n}\n\nfunction urlSecret(url: URL): string | undefined {\n if (url.username || url.password) return 'url';\n for (const name of url.searchParams.keys()) if (SECRET_PARAM.test(name)) return `url ?${name}`;\n return undefined;\n}\n\ntype Checked = McpServerConfig | McpConfigProblem;\n\nfunction fail(server: string, message: string, field?: string): McpConfigProblem {\n return { server, ...(field ? { field } : {}), message };\n}\n\nfunction checkHeaders(name: string, headers: unknown): McpConfigProblem | undefined {\n if (headers === undefined) return undefined;\n if (!isRecord(headers) || !Object.values(headers).every((value) => typeof value === 'string'))\n return fail(name, 'headers must map names to strings', 'headers');\n for (const [header, value] of Object.entries(headers as Record<string, string>)) {\n if (value.trim().startsWith('!'))\n return fail(\n name,\n `headers.${header} runs a command, which SLICC can't do`,\n `headers.${header}`\n );\n if (literalSecret(header, value))\n return fail(\n name,\n `headers.${header} holds a literal secret. mcp.json is readable by every agent: write \\${NAME} instead, and add the value in Settings \u203A
|
|
4
|
+
"sourcesContent": ["import { hash } from '../licks/sources.ts';\n\nexport type McpExposure = 'codemode' | 'deferred' | 'direct' | 'hidden';\n\nexport interface McpServerConfig {\n url: string;\n headers?: Record<string, string>;\n exposure?: McpExposure;\n toolExposure?: Record<string, McpExposure>;\n enabled?: boolean;\n timeout?: number;\n description?: string;\n}\n\nexport interface McpServerEntry {\n name: string;\n config: McpServerConfig;\n}\n\nexport interface McpConfigProblem {\n server?: string;\n field?: string;\n message: string;\n}\n\nexport interface McpConfig {\n servers: McpServerEntry[];\n problems: McpConfigProblem[];\n}\n\nconst SERVER_NAME = /^[A-Za-z0-9_-]+$/;\nconst EXPOSURES: readonly string[] = ['codemode', 'deferred', 'direct', 'hidden'];\nconst ALIASES: Record<string, McpExposure> = { 'codemode-deferred': 'codemode' };\nconst ACCEPTED = new Set([\n 'type',\n 'url',\n 'headers',\n 'exposure',\n 'toolExposure',\n 'enabled',\n 'timeout',\n 'description',\n]);\nconst SECRET_HEADER = /authorization|cookie|token|key|secret|password|session/i;\nconst SECRET_PARAM = /token|key|secret|password|signature|sig|auth|code/i;\nconst PLACEHOLDER = /\\$\\{([A-Za-z_][A-Za-z0-9_]*)\\}/g;\nconst SCHEME = /^\\s*(?:bearer|basic|token|apikey|api-key)\\s+/i;\nconst MAX_TOOL_NAME = 64;\nexport const DEFAULT_TIMEOUT_SECONDS = 60;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction alias(value: unknown): unknown {\n return typeof value === 'string' ? (ALIASES[value] ?? value) : value;\n}\n\nfunction isExposure(value: unknown): value is McpExposure {\n return typeof value === 'string' && EXPOSURES.includes(value);\n}\n\nexport function placeholders(value: string): string[] {\n return [...value.matchAll(PLACEHOLDER)].map((match) => match[1] as string);\n}\n\nexport function literalSecret(header: string, value: string): boolean {\n if (!SECRET_HEADER.test(header)) return false;\n return value.replace(PLACEHOLDER, '').replace(SCHEME, '').trim() !== '';\n}\n\nfunction urlSecret(url: URL): string | undefined {\n if (url.username || url.password) return 'url';\n for (const name of url.searchParams.keys()) if (SECRET_PARAM.test(name)) return `url ?${name}`;\n return undefined;\n}\n\ntype Checked = McpServerConfig | McpConfigProblem;\n\nfunction fail(server: string, message: string, field?: string): McpConfigProblem {\n return { server, ...(field ? { field } : {}), message };\n}\n\nfunction checkHeaders(name: string, headers: unknown): McpConfigProblem | undefined {\n if (headers === undefined) return undefined;\n if (!isRecord(headers) || !Object.values(headers).every((value) => typeof value === 'string'))\n return fail(name, 'headers must map names to strings', 'headers');\n for (const [header, value] of Object.entries(headers as Record<string, string>)) {\n if (value.trim().startsWith('!'))\n return fail(\n name,\n `headers.${header} runs a command, which SLICC can't do`,\n `headers.${header}`\n );\n if (literalSecret(header, value))\n return fail(\n name,\n `headers.${header} holds a literal secret. mcp.json is readable by every agent: write \\${NAME} instead, and add the value in Settings \u203A MCP servers`,\n `headers.${header}`\n );\n }\n return undefined;\n}\n\nfunction checkExposures(\n name: string,\n value: Record<string, unknown>\n): McpConfigProblem | undefined {\n const allowed = EXPOSURES.map((item) => `\"${item}\"`).join(', ');\n if (value.exposure !== undefined && !isExposure(value.exposure))\n return fail(name, `exposure must be one of ${allowed}`, 'exposure');\n if (value.toolExposure === undefined) return undefined;\n if (!isRecord(value.toolExposure))\n return fail(name, 'toolExposure must map tool names to exposures', 'toolExposure');\n for (const [tool, exposure] of Object.entries(value.toolExposure))\n if (!isExposure(exposure))\n return fail(name, `toolExposure \"${tool}\" must be one of ${allowed}`, `toolExposure.${tool}`);\n return undefined;\n}\n\nfunction checkFields(name: string, value: Record<string, unknown>): McpConfigProblem | undefined {\n if (value.enabled !== undefined && typeof value.enabled !== 'boolean')\n return fail(name, 'enabled must be a boolean', 'enabled');\n if (value.description !== undefined && typeof value.description !== 'string')\n return fail(name, 'description must be a string', 'description');\n if (value.timeout !== undefined && (typeof value.timeout !== 'number' || !(value.timeout > 0)))\n return fail(name, 'timeout must be a positive number of seconds', 'timeout');\n return undefined;\n}\n\nfunction checkTransport(\n name: string,\n value: Record<string, unknown>\n): McpConfigProblem | undefined {\n if (value.command !== undefined || value.type === 'stdio')\n return fail(name, 'stdio servers need slicc-kernel#68, so this one is skipped', 'command');\n if (value.type === 'sse')\n return fail(\n name,\n 'the legacy SSE transport is not supported; use the streamable HTTP URL',\n 'type'\n );\n if (value.type !== undefined && value.type !== 'http' && value.type !== 'streamable-http')\n return fail(name, 'type must be \"http\" or \"streamable-http\"', 'type');\n if (typeof value.url !== 'string') return fail(name, 'needs a \"url\" (streamable HTTP)', 'url');\n if (!URL.canParse(value.url) || !/^https?:$/.test(new URL(value.url).protocol))\n return fail(name, 'url must be an http or https URL', 'url');\n const secret = urlSecret(new URL(value.url));\n if (secret)\n return fail(\n name,\n `${secret} holds a literal secret. Put it in a header as \\${NAME} and add the value in Settings \u203A MCP servers`,\n 'url'\n );\n return undefined;\n}\n\nexport function validateServer(name: string, raw: unknown): Checked {\n if (!SERVER_NAME.test(name))\n return fail(name, `invalid server name \"${name}\" (use letters, digits, \"_\" and \"-\")`);\n if (!isRecord(raw)) return fail(name, 'must be an object');\n const value: Record<string, unknown> = { ...raw, exposure: alias(raw.exposure) };\n if (raw.exposure === undefined) delete value.exposure;\n if (isRecord(raw.toolExposure))\n value.toolExposure = Object.fromEntries(\n Object.entries(raw.toolExposure).map(([tool, exposure]) => [tool, alias(exposure)])\n );\n for (const key of Object.keys(value))\n if (key === 'oauth' || key === 'auth')\n return fail(name, `${key} is not supported in SLICC yet`, key);\n const problem =\n checkTransport(name, value) ??\n checkHeaders(name, value.headers) ??\n checkExposures(name, value) ??\n checkFields(name, value);\n if (problem) return problem;\n const config: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value))\n if (ACCEPTED.has(key) && key !== 'type') config[key] = entry;\n return config as unknown as McpServerConfig;\n}\n\nfunction canonical(name: string): string {\n return name.replace(/-/g, '_');\n}\n\nexport function parseMcpConfig(text: string | undefined): McpConfig {\n if (text === undefined || text.trim() === '') return { servers: [], problems: [] };\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (error) {\n return { servers: [], problems: [{ message: `not valid JSON: ${(error as Error).message}` }] };\n }\n if (!isRecord(parsed) || (parsed.mcpServers !== undefined && !isRecord(parsed.mcpServers)))\n return { servers: [], problems: [{ message: 'mcpServers must be an object' }] };\n const servers: McpServerEntry[] = [];\n const problems: McpConfigProblem[] = [];\n const seen = new Set<string>();\n for (const [name, raw] of Object.entries((parsed.mcpServers ?? {}) as Record<string, unknown>)) {\n const checked = validateServer(name, raw);\n if ('message' in checked) {\n problems.push(checked);\n continue;\n }\n if (seen.has(canonical(name))) {\n problems.push(fail(name, 'names that differ only in \"-\" and \"_\" count as the same server'));\n continue;\n }\n seen.add(canonical(name));\n servers.push({ name, config: checked });\n }\n return { servers, problems };\n}\n\nfunction patternRegExp(pattern: string): RegExp {\n const source = pattern\n .split('*')\n .map((part) => part.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&'))\n .join('.*');\n return new RegExp(`^${source}$`);\n}\n\nexport function nameMatcher(entries: readonly string[]): (name: string) => boolean {\n const names = new Set(entries.filter((entry) => !entry.includes('*')));\n const patterns = entries.filter((entry) => entry.includes('*')).map(patternRegExp);\n return (name) => names.has(name) || patterns.some((pattern) => pattern.test(name));\n}\n\nexport function toolExposure(config: McpServerConfig, tool: string): McpExposure {\n const overrides = config.toolExposure ?? {};\n const exact = overrides[tool];\n if (exact !== undefined) return exact;\n for (const [pattern, exposure] of Object.entries(overrides))\n if (pattern.includes('*') && patternRegExp(pattern).test(tool)) return exposure;\n return config.exposure ?? 'codemode';\n}\n\nexport function mcpNamespace(server: string): string {\n return `mcp__${canonical(server)}`;\n}\n\nexport function mcpToolName(\n server: string,\n tool: string,\n taken: (name: string) => boolean = () => false\n): string {\n const name = `mcp__${server}__${tool}`.replace(/[^A-Za-z0-9_]/g, '_');\n if (name.length <= MAX_TOOL_NAME && !taken(name)) return name;\n const suffix = hash(`${server}\\0${tool}`).padStart(7, '0').slice(0, 7);\n return `${name.slice(0, MAX_TOOL_NAME - suffix.length - 1)}_${suffix}`;\n}\n\nexport function sameConfig(a: McpServerConfig, b: McpServerConfig): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/mcp/connection.js
CHANGED
|
@@ -144,7 +144,7 @@ class McpServerConnection {
|
|
|
144
144
|
void this.#drop(client);
|
|
145
145
|
}
|
|
146
146
|
signInMessage() {
|
|
147
|
-
return `MCP server "${this.name}" rejected
|
|
147
|
+
return `MCP server "${this.name}" rejected its token (401). Update it in Settings \u203A MCP servers.`;
|
|
148
148
|
}
|
|
149
149
|
#mark(state, error) {
|
|
150
150
|
this.state = state;
|
|
@@ -279,7 +279,7 @@ class MissingSecret extends Error {
|
|
|
279
279
|
names;
|
|
280
280
|
constructor(names) {
|
|
281
281
|
super(
|
|
282
|
-
`needs ${names.map((name) => `\${${name}}`).join(", ")}: add the value in Settings \u203A
|
|
282
|
+
`needs ${names.map((name) => `\${${name}}`).join(", ")}: add the value in Settings \u203A MCP servers`
|
|
283
283
|
);
|
|
284
284
|
this.names = names;
|
|
285
285
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/mcp/connection.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n type CallToolResult,\n JSON_RPC_ERROR_CODES,\n type ListResourcesResult,\n type ListResourceTemplatesResult,\n McpAuthRequiredError,\n McpClient,\n McpError,\n McpHttpError,\n type McpRequestOptions,\n McpSessionExpiredError,\n type Tool as McpTool,\n type McpTransport,\n type ReadResourceResult,\n type Resource,\n type ResourceTemplate,\n} from '@earendil-works/pi-mcp';\nimport { DEFAULT_TIMEOUT_SECONDS, type McpServerEntry } from './config.ts';\n\nexport type ServerState =\n | 'connecting'\n | 'connected'\n | 'needs-auth'\n | 'needs-secret'\n | 'failed'\n | 'closed';\n\nexport type TransportFactory = (\n entry: McpServerEntry\n) => Promise<{ transport: McpTransport; secrets: string[] } | { missing: string[] }>;\n\nexport const CONNECT_RETRY_DELAYS_MS = [250, 1_000];\nexport const CLIENT_NAME = 'slicc';\n\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport function isTransient(error: unknown): boolean {\n if (error instanceof McpHttpError)\n return (\n error.status === 408 || error.status === 429 || (error.status >= 500 && error.status !== 501)\n );\n return error instanceof TypeError;\n}\n\nexport function isMcpApp(item: { uri?: string; uriTemplate?: string; mimeType?: string }): boolean {\n const uri = item.uri ?? item.uriTemplate ?? '';\n return uri.startsWith('ui://') || /;\\s*profile\\s*=\\s*\"?mcp-app\"?/i.test(item.mimeType ?? '');\n}\n\nasync function withoutTemplates<T>(list: () => Promise<T>, empty: T): Promise<T> {\n try {\n return await list();\n } catch (error) {\n if (error instanceof McpError && error.code === JSON_RPC_ERROR_CODES.methodNotFound)\n return empty;\n throw error;\n }\n}\n\nconst sleep = (ms: number, signal: AbortSignal) =>\n new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, ms);\n signal.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer);\n resolve();\n },\n { once: true }\n );\n });\n\nexport interface ConnectionOptions {\n entry: McpServerEntry;\n version: string;\n transport: TransportFactory;\n onTools: (connection: McpServerConnection) => void;\n onChange?: (connection: McpServerConnection) => void;\n onLog?: (connection: McpServerConnection, params: unknown) => void;\n}\n\nexport class McpServerConnection {\n readonly entry: McpServerEntry;\n state: ServerState = 'connecting';\n error: string | undefined;\n missing: string[] = [];\n tools: McpTool[] = [];\n hasResources = false;\n resources: Resource[] = [];\n resourceTemplates: ResourceTemplate[] = [];\n instructions: string | undefined;\n secrets: string[] = [];\n #client: McpClient | undefined;\n #opening: Promise<McpClient> | undefined;\n readonly #shutdown = new AbortController();\n readonly #busy = new Map<McpClient, number>();\n #seen = false;\n readonly #expired = new Set<McpClient>();\n readonly #options: ConnectionOptions;\n\n constructor(options: ConnectionOptions) {\n this.entry = options.entry;\n this.#options = options;\n }\n\n get name(): string {\n return this.entry.name;\n }\n\n get timeoutMs(): number {\n return (this.entry.config.timeout ?? DEFAULT_TIMEOUT_SECONDS) * 1000;\n }\n\n get live(): boolean {\n return this.state === 'connected' || (this.state === 'connecting' && this.#seen);\n }\n\n get closed(): boolean {\n return this.#shutdown.signal.aborted;\n }\n\n getClient(): Promise<McpClient> {\n if (this.closed) return Promise.reject(new Error(`MCP server \"${this.name}\" is shut down`));\n if (this.#client?.connectionState === 'connected') return Promise.resolve(this.#client);\n this.#opening ??= this.#open().finally(() => {\n this.#opening = undefined;\n });\n return this.#opening;\n }\n\n callTool(\n name: string,\n args: Record<string, unknown>,\n options: McpRequestOptions\n ): Promise<CallToolResult> {\n return this.#with((client) => client.callTool(name, args, options));\n }\n\n readResource(uri: string, options: McpRequestOptions): Promise<ReadResourceResult> {\n return this.#with((client) => client.readResource(uri, options), true);\n }\n\n resourcesPage(\n cursor: string | undefined,\n options: McpRequestOptions\n ): Promise<ListResourcesResult> {\n return this.#with((client) => client.listResourcesPage(cursor, options), true);\n }\n\n resourceTemplatesPage(\n cursor: string | undefined,\n options: McpRequestOptions\n ): Promise<ListResourceTemplatesResult> {\n return this.#with(\n (client) =>\n withoutTemplates(() => client.listResourceTemplatesPage(cursor, options), {\n resourceTemplates: [],\n }),\n true\n );\n }\n\n allResources(options: McpRequestOptions): Promise<Resource[]> {\n return this.#with((client) => client.listResources(options), true);\n }\n\n allResourceTemplates(options: McpRequestOptions): Promise<ResourceTemplate[]> {\n return this.#with(\n (client) => withoutTemplates(() => client.listResourceTemplates(options), []),\n true\n );\n }\n\n async #with<T>(run: (client: McpClient) => Promise<T>, readOnly = false): Promise<T> {\n for (let attempt = 1; ; attempt++) {\n const client = await this.getClient();\n this.#busy.set(client, (this.#busy.get(client) ?? 0) + 1);\n try {\n return await run(client);\n } catch (error) {\n if (readOnly && attempt === 1 && error instanceof McpHttpError && isTransient(error)) {\n await sleep(CONNECT_RETRY_DELAYS_MS[0] as number, this.#shutdown.signal);\n continue;\n }\n if (error instanceof McpSessionExpiredError && attempt === 1) {\n if (this.#client === client) {\n this.#client = undefined;\n this.#expired.add(client);\n }\n continue;\n }\n if (!(error instanceof McpAuthRequiredError)) throw error;\n await this.#drop(client);\n this.#mark('needs-auth');\n throw new Error(this.signInMessage());\n } finally {\n this.#release(client);\n }\n }\n }\n\n #release(client: McpClient): void {\n const left = (this.#busy.get(client) as number) - 1;\n this.#busy.set(client, left);\n if (left > 0 || !this.#expired.delete(client)) return;\n this.#busy.delete(client);\n void this.#drop(client);\n }\n\n signInMessage(): string {\n return `MCP server \"${this.name}\" rejected the request as unauthorized (401). Check its token in Settings \u203A Accounts.`;\n }\n\n #mark(state: ServerState, error?: string): void {\n this.state = state;\n this.error = error;\n this.#options.onChange?.(this);\n }\n\n async #drop(client: McpClient): Promise<void> {\n if (this.#client === client) this.#client = undefined;\n await client.close().catch(() => undefined);\n }\n\n async #open(): Promise<McpClient> {\n this.#mark('connecting');\n for (let attempt = 0; ; attempt++) {\n try {\n return await this.#connectOnce();\n } catch (error) {\n const delay = CONNECT_RETRY_DELAYS_MS[attempt];\n if (this.closed || delay === undefined || !isTransient(error)) throw this.#failed(error);\n await sleep(delay, this.#shutdown.signal);\n if (this.closed) throw this.#failed(error);\n }\n }\n }\n\n async #connectOnce(): Promise<McpClient> {\n const made = await this.#options.transport(this.entry);\n if ('missing' in made) {\n this.missing = made.missing;\n throw new MissingSecret(made.missing);\n }\n this.secrets = made.secrets;\n const client = new McpClient({\n name: CLIENT_NAME,\n version: this.#options.version,\n requestTimeoutMs: this.timeoutMs,\n });\n const log = this.#options.onLog;\n if (log) client.onNotification('notifications/message', (params) => log(this, params));\n let closing: Promise<void> | undefined;\n const closeClient = () => {\n closing ??= client.close().catch(() => undefined);\n return closing;\n };\n this.#shutdown.signal.addEventListener('abort', closeClient, { once: true });\n try {\n await client.connect(made.transport);\n client.onNotification('notifications/tools/list_changed', () => {\n void this.#refreshTools(client);\n });\n client.onNotification('notifications/resources/list_changed', () => {\n void this.#refreshResources(client);\n });\n const hasResources = client.serverCapabilities?.resources !== undefined;\n const [tools, resources] = await Promise.all([\n client.serverCapabilities?.tools ? client.listTools() : [],\n hasResources ? this.#fetchResources(client) : { resources: [], resourceTemplates: [] },\n ]);\n if (this.closed) throw new Error('shut down while connecting');\n if (client.connectionState !== 'connected') throw new Error('connection closed during setup');\n this.#client = client;\n this.tools = tools;\n this.hasResources = hasResources;\n this.resources = resources.resources;\n this.resourceTemplates = resources.resourceTemplates;\n this.instructions = client.instructions?.trim() || undefined;\n this.missing = [];\n this.#seen = true;\n this.state = 'connected';\n this.error = undefined;\n this.#options.onTools(this);\n this.#options.onChange?.(this);\n return client;\n } catch (error) {\n await closeClient();\n throw error;\n } finally {\n this.#shutdown.signal.removeEventListener('abort', closeClient);\n }\n }\n\n async #fetchResources(client: McpClient) {\n const [resources, resourceTemplates] = await Promise.all([\n client.listResources().catch(() => [] as Resource[]),\n withoutTemplates(() => client.listResourceTemplates(), [] as ResourceTemplate[]).catch(\n () => [] as ResourceTemplate[]\n ),\n ]);\n return {\n resources: resources.filter((resource) => !isMcpApp(resource)),\n resourceTemplates: resourceTemplates.filter((template) => !isMcpApp(template)),\n };\n }\n\n #failed(error: unknown): Error {\n if (error instanceof MissingSecret) {\n this.#mark('needs-secret');\n return new Error(error.message);\n }\n if (error instanceof McpAuthRequiredError && !this.closed) {\n this.#mark('needs-auth');\n return new Error(this.signInMessage());\n }\n this.#mark(this.closed ? 'closed' : 'failed', errorMessage(error));\n return new Error(`MCP server \"${this.name}\" failed to connect: ${this.error}`);\n }\n\n async #refreshTools(client: McpClient): Promise<void> {\n try {\n const tools = await client.listTools();\n if (this.#client !== client || this.closed) return;\n this.tools = tools;\n this.#options.onTools(this);\n } catch (error) {\n this.error = `Failed to refresh tools: ${errorMessage(error)}`;\n }\n this.#options.onChange?.(this);\n }\n\n async #refreshResources(client: McpClient): Promise<void> {\n const { resources, resourceTemplates } = await this.#fetchResources(client);\n if (this.#client !== client || this.closed) return;\n this.resources = resources;\n this.resourceTemplates = resourceTemplates;\n this.#options.onTools(this);\n this.#options.onChange?.(this);\n }\n\n async close(): Promise<void> {\n this.#shutdown.abort();\n this.state = 'closed';\n this.#options.onChange?.(this);\n const client = this.#client;\n this.#client = undefined;\n await Promise.allSettled([client?.close(), this.#opening]);\n }\n}\n\nexport class MissingSecret extends Error {\n readonly names: string[];\n\n constructor(names: string[]) {\n super(\n `needs ${names.map((name) => `\\${${name}}`).join(', ')}: add the value in Settings \u203A Accounts`\n );\n this.names = names;\n }\n}\n"],
|
|
4
|
+
"sourcesContent": ["import {\n type CallToolResult,\n JSON_RPC_ERROR_CODES,\n type ListResourcesResult,\n type ListResourceTemplatesResult,\n McpAuthRequiredError,\n McpClient,\n McpError,\n McpHttpError,\n type McpRequestOptions,\n McpSessionExpiredError,\n type Tool as McpTool,\n type McpTransport,\n type ReadResourceResult,\n type Resource,\n type ResourceTemplate,\n} from '@earendil-works/pi-mcp';\nimport { DEFAULT_TIMEOUT_SECONDS, type McpServerEntry } from './config.ts';\n\nexport type ServerState =\n | 'connecting'\n | 'connected'\n | 'needs-auth'\n | 'needs-secret'\n | 'failed'\n | 'closed';\n\nexport type TransportFactory = (\n entry: McpServerEntry\n) => Promise<{ transport: McpTransport; secrets: string[] } | { missing: string[] }>;\n\nexport const CONNECT_RETRY_DELAYS_MS = [250, 1_000];\nexport const CLIENT_NAME = 'slicc';\n\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport function isTransient(error: unknown): boolean {\n if (error instanceof McpHttpError)\n return (\n error.status === 408 || error.status === 429 || (error.status >= 500 && error.status !== 501)\n );\n return error instanceof TypeError;\n}\n\nexport function isMcpApp(item: { uri?: string; uriTemplate?: string; mimeType?: string }): boolean {\n const uri = item.uri ?? item.uriTemplate ?? '';\n return uri.startsWith('ui://') || /;\\s*profile\\s*=\\s*\"?mcp-app\"?/i.test(item.mimeType ?? '');\n}\n\nasync function withoutTemplates<T>(list: () => Promise<T>, empty: T): Promise<T> {\n try {\n return await list();\n } catch (error) {\n if (error instanceof McpError && error.code === JSON_RPC_ERROR_CODES.methodNotFound)\n return empty;\n throw error;\n }\n}\n\nconst sleep = (ms: number, signal: AbortSignal) =>\n new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, ms);\n signal.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer);\n resolve();\n },\n { once: true }\n );\n });\n\nexport interface ConnectionOptions {\n entry: McpServerEntry;\n version: string;\n transport: TransportFactory;\n onTools: (connection: McpServerConnection) => void;\n onChange?: (connection: McpServerConnection) => void;\n onLog?: (connection: McpServerConnection, params: unknown) => void;\n}\n\nexport class McpServerConnection {\n readonly entry: McpServerEntry;\n state: ServerState = 'connecting';\n error: string | undefined;\n missing: string[] = [];\n tools: McpTool[] = [];\n hasResources = false;\n resources: Resource[] = [];\n resourceTemplates: ResourceTemplate[] = [];\n instructions: string | undefined;\n secrets: string[] = [];\n #client: McpClient | undefined;\n #opening: Promise<McpClient> | undefined;\n readonly #shutdown = new AbortController();\n readonly #busy = new Map<McpClient, number>();\n #seen = false;\n readonly #expired = new Set<McpClient>();\n readonly #options: ConnectionOptions;\n\n constructor(options: ConnectionOptions) {\n this.entry = options.entry;\n this.#options = options;\n }\n\n get name(): string {\n return this.entry.name;\n }\n\n get timeoutMs(): number {\n return (this.entry.config.timeout ?? DEFAULT_TIMEOUT_SECONDS) * 1000;\n }\n\n get live(): boolean {\n return this.state === 'connected' || (this.state === 'connecting' && this.#seen);\n }\n\n get closed(): boolean {\n return this.#shutdown.signal.aborted;\n }\n\n getClient(): Promise<McpClient> {\n if (this.closed) return Promise.reject(new Error(`MCP server \"${this.name}\" is shut down`));\n if (this.#client?.connectionState === 'connected') return Promise.resolve(this.#client);\n this.#opening ??= this.#open().finally(() => {\n this.#opening = undefined;\n });\n return this.#opening;\n }\n\n callTool(\n name: string,\n args: Record<string, unknown>,\n options: McpRequestOptions\n ): Promise<CallToolResult> {\n return this.#with((client) => client.callTool(name, args, options));\n }\n\n readResource(uri: string, options: McpRequestOptions): Promise<ReadResourceResult> {\n return this.#with((client) => client.readResource(uri, options), true);\n }\n\n resourcesPage(\n cursor: string | undefined,\n options: McpRequestOptions\n ): Promise<ListResourcesResult> {\n return this.#with((client) => client.listResourcesPage(cursor, options), true);\n }\n\n resourceTemplatesPage(\n cursor: string | undefined,\n options: McpRequestOptions\n ): Promise<ListResourceTemplatesResult> {\n return this.#with(\n (client) =>\n withoutTemplates(() => client.listResourceTemplatesPage(cursor, options), {\n resourceTemplates: [],\n }),\n true\n );\n }\n\n allResources(options: McpRequestOptions): Promise<Resource[]> {\n return this.#with((client) => client.listResources(options), true);\n }\n\n allResourceTemplates(options: McpRequestOptions): Promise<ResourceTemplate[]> {\n return this.#with(\n (client) => withoutTemplates(() => client.listResourceTemplates(options), []),\n true\n );\n }\n\n async #with<T>(run: (client: McpClient) => Promise<T>, readOnly = false): Promise<T> {\n for (let attempt = 1; ; attempt++) {\n const client = await this.getClient();\n this.#busy.set(client, (this.#busy.get(client) ?? 0) + 1);\n try {\n return await run(client);\n } catch (error) {\n if (readOnly && attempt === 1 && error instanceof McpHttpError && isTransient(error)) {\n await sleep(CONNECT_RETRY_DELAYS_MS[0] as number, this.#shutdown.signal);\n continue;\n }\n if (error instanceof McpSessionExpiredError && attempt === 1) {\n if (this.#client === client) {\n this.#client = undefined;\n this.#expired.add(client);\n }\n continue;\n }\n if (!(error instanceof McpAuthRequiredError)) throw error;\n await this.#drop(client);\n this.#mark('needs-auth');\n throw new Error(this.signInMessage());\n } finally {\n this.#release(client);\n }\n }\n }\n\n #release(client: McpClient): void {\n const left = (this.#busy.get(client) as number) - 1;\n this.#busy.set(client, left);\n if (left > 0 || !this.#expired.delete(client)) return;\n this.#busy.delete(client);\n void this.#drop(client);\n }\n\n signInMessage(): string {\n return `MCP server \"${this.name}\" rejected its token (401). Update it in Settings \u203A MCP servers.`;\n }\n\n #mark(state: ServerState, error?: string): void {\n this.state = state;\n this.error = error;\n this.#options.onChange?.(this);\n }\n\n async #drop(client: McpClient): Promise<void> {\n if (this.#client === client) this.#client = undefined;\n await client.close().catch(() => undefined);\n }\n\n async #open(): Promise<McpClient> {\n this.#mark('connecting');\n for (let attempt = 0; ; attempt++) {\n try {\n return await this.#connectOnce();\n } catch (error) {\n const delay = CONNECT_RETRY_DELAYS_MS[attempt];\n if (this.closed || delay === undefined || !isTransient(error)) throw this.#failed(error);\n await sleep(delay, this.#shutdown.signal);\n if (this.closed) throw this.#failed(error);\n }\n }\n }\n\n async #connectOnce(): Promise<McpClient> {\n const made = await this.#options.transport(this.entry);\n if ('missing' in made) {\n this.missing = made.missing;\n throw new MissingSecret(made.missing);\n }\n this.secrets = made.secrets;\n const client = new McpClient({\n name: CLIENT_NAME,\n version: this.#options.version,\n requestTimeoutMs: this.timeoutMs,\n });\n const log = this.#options.onLog;\n if (log) client.onNotification('notifications/message', (params) => log(this, params));\n let closing: Promise<void> | undefined;\n const closeClient = () => {\n closing ??= client.close().catch(() => undefined);\n return closing;\n };\n this.#shutdown.signal.addEventListener('abort', closeClient, { once: true });\n try {\n await client.connect(made.transport);\n client.onNotification('notifications/tools/list_changed', () => {\n void this.#refreshTools(client);\n });\n client.onNotification('notifications/resources/list_changed', () => {\n void this.#refreshResources(client);\n });\n const hasResources = client.serverCapabilities?.resources !== undefined;\n const [tools, resources] = await Promise.all([\n client.serverCapabilities?.tools ? client.listTools() : [],\n hasResources ? this.#fetchResources(client) : { resources: [], resourceTemplates: [] },\n ]);\n if (this.closed) throw new Error('shut down while connecting');\n if (client.connectionState !== 'connected') throw new Error('connection closed during setup');\n this.#client = client;\n this.tools = tools;\n this.hasResources = hasResources;\n this.resources = resources.resources;\n this.resourceTemplates = resources.resourceTemplates;\n this.instructions = client.instructions?.trim() || undefined;\n this.missing = [];\n this.#seen = true;\n this.state = 'connected';\n this.error = undefined;\n this.#options.onTools(this);\n this.#options.onChange?.(this);\n return client;\n } catch (error) {\n await closeClient();\n throw error;\n } finally {\n this.#shutdown.signal.removeEventListener('abort', closeClient);\n }\n }\n\n async #fetchResources(client: McpClient) {\n const [resources, resourceTemplates] = await Promise.all([\n client.listResources().catch(() => [] as Resource[]),\n withoutTemplates(() => client.listResourceTemplates(), [] as ResourceTemplate[]).catch(\n () => [] as ResourceTemplate[]\n ),\n ]);\n return {\n resources: resources.filter((resource) => !isMcpApp(resource)),\n resourceTemplates: resourceTemplates.filter((template) => !isMcpApp(template)),\n };\n }\n\n #failed(error: unknown): Error {\n if (error instanceof MissingSecret) {\n this.#mark('needs-secret');\n return new Error(error.message);\n }\n if (error instanceof McpAuthRequiredError && !this.closed) {\n this.#mark('needs-auth');\n return new Error(this.signInMessage());\n }\n this.#mark(this.closed ? 'closed' : 'failed', errorMessage(error));\n return new Error(`MCP server \"${this.name}\" failed to connect: ${this.error}`);\n }\n\n async #refreshTools(client: McpClient): Promise<void> {\n try {\n const tools = await client.listTools();\n if (this.#client !== client || this.closed) return;\n this.tools = tools;\n this.#options.onTools(this);\n } catch (error) {\n this.error = `Failed to refresh tools: ${errorMessage(error)}`;\n }\n this.#options.onChange?.(this);\n }\n\n async #refreshResources(client: McpClient): Promise<void> {\n const { resources, resourceTemplates } = await this.#fetchResources(client);\n if (this.#client !== client || this.closed) return;\n this.resources = resources;\n this.resourceTemplates = resourceTemplates;\n this.#options.onTools(this);\n this.#options.onChange?.(this);\n }\n\n async close(): Promise<void> {\n this.#shutdown.abort();\n this.state = 'closed';\n this.#options.onChange?.(this);\n const client = this.#client;\n this.#client = undefined;\n await Promise.allSettled([client?.close(), this.#opening]);\n }\n}\n\nexport class MissingSecret extends Error {\n readonly names: string[];\n\n constructor(names: string[]) {\n super(\n `needs ${names.map((name) => `\\${${name}}`).join(', ')}: add the value in Settings \u203A MCP servers`\n );\n this.names = names;\n }\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/mcp/index.js
CHANGED
|
@@ -2,6 +2,12 @@ import { parseMcpConfig } from "./config.js";
|
|
|
2
2
|
import { allows, McpAllowDoc, mcpEntries, serverAllowed } from "./allow.js";
|
|
3
3
|
const loadRuntime = () => import("./runtime.js");
|
|
4
4
|
const idle = {
|
|
5
|
+
accounts: async () => [],
|
|
6
|
+
connect: async (id) => {
|
|
7
|
+
throw new Error(`${id} is not an MCP server that takes a token`);
|
|
8
|
+
},
|
|
9
|
+
disconnect: async () => void 0,
|
|
10
|
+
onChange: () => () => void 0,
|
|
5
11
|
status: () => [],
|
|
6
12
|
reload: async () => void 0,
|
|
7
13
|
close: async () => void 0
|
package/dist/mcp/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/mcp/index.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type {\n Agent,\n Registry,\n ToolExecutionApi,\n ToolRegistration,\n} from '@earendil-works/pi-durable';\nimport type { CodemodeExtra } from './allow.ts';\nimport type { McpCatalog } from './catalog.ts';\nimport { parseMcpConfig } from './config.ts';\nimport type { McpAttach, McpRuntime } from './runtime.ts';\n\nexport { allows, type CodemodeExtra, McpAllowDoc, mcpEntries, serverAllowed } from './allow.ts';\nexport type { McpAttach, McpRuntime, ServerStatus } from './runtime.ts';\n\nexport type McpLoader = () => Promise<typeof import('./runtime.ts')>;\n\nexport const loadRuntime: McpLoader = () => import('./runtime.ts');\n\nexport interface McpSetup {\n catalog(): McpCatalog | undefined;\n direct(names: readonly string[]): ToolRegistration[];\n codemode(api: ToolExecutionApi, agent: Agent, context: Context): Promise<CodemodeExtra>;\n attach(options: McpAttach, context: Context): Promise<McpRuntime>;\n}\n\nconst idle: McpRuntime = {\n status: () => [],\n reload: async () => undefined,\n close: async () => undefined,\n};\n\nasync function unavailable(options: McpAttach, error: unknown, context: Context) {\n const file = `${options.home}/.pi/agent/mcp.json`;\n const read = await options.env.readTextFile(file, context);\n if (!parseMcpConfig(read.ok ? read.value : undefined).servers.length) return;\n await options.licks\n .deliver(\n {\n channel: 'fswatch',\n source: 'mcp:~/.pi/agent/mcp.json',\n title: \"MCP servers can't start in this SLICC\",\n text: error instanceof Error ? error.message : String(error),\n body: \"The MCP client didn't load, so the servers in ~/.pi/agent/mcp.json stay off until SLICC is updated.\",\n target: 'cone',\n severity: 'warn',\n eventId: 'mcp\\nunavailable',\n },\n context\n )\n .catch(() => undefined);\n}\n\nexport function setupMcp(registry: Registry, load: McpLoader = loadRuntime): McpSetup {\n let catalog: McpCatalog | undefined;\n return {\n catalog: () => catalog,\n direct: (names) => catalog?.direct(names) ?? [],\n codemode: async (api, agent, context) =>\n catalog ? catalog.codemode(api, agent, context) : { tools: [], globals: [] },\n async attach(options, context) {\n let started: Awaited<ReturnType<Awaited<ReturnType<McpLoader>>['startMcp']>>;\n try {\n started = await (await load()).startMcp(registry, options, context);\n } catch (error) {\n await unavailable(options, error, context);\n return idle;\n }\n catalog = started.catalog;\n return started.runtime;\n },\n };\n}\n"],
|
|
5
|
-
"mappings": "AASA,SAAS,sBAAsB;AAG/B,SAAS,QAA4B,aAAa,YAAY,qBAAqB;AAK5E,MAAM,cAAyB,MAAM,OAAO,cAAc;AASjE,MAAM,OAAmB;AAAA,EACvB,QAAQ,MAAM,CAAC;AAAA,EACf,QAAQ,YAAY;AAAA,EACpB,OAAO,YAAY;AACrB;AAEA,eAAe,YAAY,SAAoB,OAAgB,SAAkB;AAC/E,QAAM,OAAO,GAAG,QAAQ,IAAI;AAC5B,QAAM,OAAO,MAAM,QAAQ,IAAI,aAAa,MAAM,OAAO;AACzD,MAAI,CAAC,eAAe,KAAK,KAAK,KAAK,QAAQ,MAAS,EAAE,QAAQ,OAAQ;AACtE,QAAM,QAAQ,MACX;AAAA,IACC;AAAA,MACE,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC3D,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,SAAS;AAAA,IACX;AAAA,IACA;AAAA,EACF,EACC,MAAM,MAAM,MAAS;AAC1B;AAEO,SAAS,SAAS,UAAoB,OAAkB,aAAuB;AACpF,MAAI;AACJ,SAAO;AAAA,IACL,SAAS,MAAM;AAAA,IACf,QAAQ,CAAC,UAAU,SAAS,OAAO,KAAK,KAAK,CAAC;AAAA,IAC9C,UAAU,OAAO,KAAK,OAAO,YAC3B,UAAU,QAAQ,SAAS,KAAK,OAAO,OAAO,IAAI,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,EAAE;AAAA,IAC7E,MAAM,OAAO,SAAS,SAAS;AAC7B,UAAI;AACJ,UAAI;AACF,kBAAU,OAAO,MAAM,KAAK,GAAG,SAAS,UAAU,SAAS,OAAO;AAAA,MACpE,SAAS,OAAO;AACd,cAAM,YAAY,SAAS,OAAO,OAAO;AACzC,eAAO;AAAA,MACT;AACA,gBAAU,QAAQ;AAClB,aAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AACF;",
|
|
4
|
+
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type {\n Agent,\n Registry,\n ToolExecutionApi,\n ToolRegistration,\n} from '@earendil-works/pi-durable';\nimport type { CodemodeExtra } from './allow.ts';\nimport type { McpCatalog } from './catalog.ts';\nimport { parseMcpConfig } from './config.ts';\nimport type { McpAttach, McpRuntime } from './runtime.ts';\n\nexport { allows, type CodemodeExtra, McpAllowDoc, mcpEntries, serverAllowed } from './allow.ts';\nexport type { McpAccounts, McpAttach, McpRuntime, ServerStatus } from './runtime.ts';\n\nexport type McpLoader = () => Promise<typeof import('./runtime.ts')>;\n\nexport const loadRuntime: McpLoader = () => import('./runtime.ts');\n\nexport interface McpSetup {\n catalog(): McpCatalog | undefined;\n direct(names: readonly string[]): ToolRegistration[];\n codemode(api: ToolExecutionApi, agent: Agent, context: Context): Promise<CodemodeExtra>;\n attach(options: McpAttach, context: Context): Promise<McpRuntime>;\n}\n\nconst idle: McpRuntime = {\n accounts: async () => [],\n connect: async (id) => {\n throw new Error(`${id} is not an MCP server that takes a token`);\n },\n disconnect: async () => undefined,\n onChange: () => () => undefined,\n status: () => [],\n reload: async () => undefined,\n close: async () => undefined,\n};\n\nasync function unavailable(options: McpAttach, error: unknown, context: Context) {\n const file = `${options.home}/.pi/agent/mcp.json`;\n const read = await options.env.readTextFile(file, context);\n if (!parseMcpConfig(read.ok ? read.value : undefined).servers.length) return;\n await options.licks\n .deliver(\n {\n channel: 'fswatch',\n source: 'mcp:~/.pi/agent/mcp.json',\n title: \"MCP servers can't start in this SLICC\",\n text: error instanceof Error ? error.message : String(error),\n body: \"The MCP client didn't load, so the servers in ~/.pi/agent/mcp.json stay off until SLICC is updated.\",\n target: 'cone',\n severity: 'warn',\n eventId: 'mcp\\nunavailable',\n },\n context\n )\n .catch(() => undefined);\n}\n\nexport function setupMcp(registry: Registry, load: McpLoader = loadRuntime): McpSetup {\n let catalog: McpCatalog | undefined;\n return {\n catalog: () => catalog,\n direct: (names) => catalog?.direct(names) ?? [],\n codemode: async (api, agent, context) =>\n catalog ? catalog.codemode(api, agent, context) : { tools: [], globals: [] },\n async attach(options, context) {\n let started: Awaited<ReturnType<Awaited<ReturnType<McpLoader>>['startMcp']>>;\n try {\n started = await (await load()).startMcp(registry, options, context);\n } catch (error) {\n await unavailable(options, error, context);\n return idle;\n }\n catalog = started.catalog;\n return started.runtime;\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "AASA,SAAS,sBAAsB;AAG/B,SAAS,QAA4B,aAAa,YAAY,qBAAqB;AAK5E,MAAM,cAAyB,MAAM,OAAO,cAAc;AASjE,MAAM,OAAmB;AAAA,EACvB,UAAU,YAAY,CAAC;AAAA,EACvB,SAAS,OAAO,OAAO;AACrB,UAAM,IAAI,MAAM,GAAG,EAAE,0CAA0C;AAAA,EACjE;AAAA,EACA,YAAY,YAAY;AAAA,EACxB,UAAU,MAAM,MAAM;AAAA,EACtB,QAAQ,MAAM,CAAC;AAAA,EACf,QAAQ,YAAY;AAAA,EACpB,OAAO,YAAY;AACrB;AAEA,eAAe,YAAY,SAAoB,OAAgB,SAAkB;AAC/E,QAAM,OAAO,GAAG,QAAQ,IAAI;AAC5B,QAAM,OAAO,MAAM,QAAQ,IAAI,aAAa,MAAM,OAAO;AACzD,MAAI,CAAC,eAAe,KAAK,KAAK,KAAK,QAAQ,MAAS,EAAE,QAAQ,OAAQ;AACtE,QAAM,QAAQ,MACX;AAAA,IACC;AAAA,MACE,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC3D,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,SAAS;AAAA,IACX;AAAA,IACA;AAAA,EACF,EACC,MAAM,MAAM,MAAS;AAC1B;AAEO,SAAS,SAAS,UAAoB,OAAkB,aAAuB;AACpF,MAAI;AACJ,SAAO;AAAA,IACL,SAAS,MAAM;AAAA,IACf,QAAQ,CAAC,UAAU,SAAS,OAAO,KAAK,KAAK,CAAC;AAAA,IAC9C,UAAU,OAAO,KAAK,OAAO,YAC3B,UAAU,QAAQ,SAAS,KAAK,OAAO,OAAO,IAAI,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,EAAE;AAAA,IAC7E,MAAM,OAAO,SAAS,SAAS;AAC7B,UAAI;AACJ,UAAI;AACF,kBAAU,OAAO,MAAM,KAAK,GAAG,SAAS,UAAU,SAAS,OAAO;AAAA,MACpE,SAAS,OAAO;AACd,cAAM,YAAY,SAAS,OAAO,OAAO;AACzC,eAAO;AAAA,MACT;AACA,gBAAU,QAAQ;AAClB,aAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
function mcpLabel(name) {
|
|
2
|
+
const parts = name.split("__");
|
|
3
|
+
if (parts.length !== 3 || parts[0] !== "mcp") return void 0;
|
|
4
|
+
const [, server, tool] = parts;
|
|
5
|
+
if (!/^[A-Za-z0-9](?:.*[A-Za-z0-9])?$/.test(server) || !/^[A-Za-z0-9]/.test(tool))
|
|
6
|
+
return void 0;
|
|
7
|
+
return `${server} \xB7 ${tool}`;
|
|
8
|
+
}
|
|
9
|
+
const MCP_ACCOUNT = "mcp:";
|
|
10
|
+
export {
|
|
11
|
+
MCP_ACCOUNT,
|
|
12
|
+
mcpLabel
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=label.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/mcp/label.ts"],
|
|
4
|
+
"sourcesContent": ["export function mcpLabel(name: string): string | undefined {\n const parts = name.split('__');\n if (parts.length !== 3 || parts[0] !== 'mcp') return undefined;\n const [, server, tool] = parts as [string, string, string];\n if (!/^[A-Za-z0-9](?:.*[A-Za-z0-9])?$/.test(server) || !/^[A-Za-z0-9]/.test(tool))\n return undefined;\n return `${server} \u00B7 ${tool}`;\n}\n\nexport const MCP_ACCOUNT = 'mcp:';\n"],
|
|
5
|
+
"mappings": "AAAO,SAAS,SAAS,MAAkC;AACzD,QAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,MAAI,MAAM,WAAW,KAAK,MAAM,CAAC,MAAM,MAAO,QAAO;AACrD,QAAM,CAAC,EAAE,QAAQ,IAAI,IAAI;AACzB,MAAI,CAAC,kCAAkC,KAAK,MAAM,KAAK,CAAC,eAAe,KAAK,IAAI;AAC9E,WAAO;AACT,SAAO,GAAG,MAAM,SAAM,IAAI;AAC5B;AAEO,MAAM,cAAc;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/mcp/runtime.js
CHANGED
|
@@ -5,7 +5,8 @@ import {
|
|
|
5
5
|
sameConfig
|
|
6
6
|
} from "./config.js";
|
|
7
7
|
import { McpServerConnection } from "./connection.js";
|
|
8
|
-
import { resolveHeaders, scrub } from "./credentials.js";
|
|
8
|
+
import { credentialKey, resolveHeaders, scrub, secretNames } from "./credentials.js";
|
|
9
|
+
import { MCP_ACCOUNT } from "./label.js";
|
|
9
10
|
import { patchSse } from "./sse.js";
|
|
10
11
|
const MCP_LOG_MAX_BYTES = 5 * 1024 * 1024;
|
|
11
12
|
function configPath(home) {
|
|
@@ -38,8 +39,8 @@ function stateLick(connection, cors) {
|
|
|
38
39
|
if (connection.state === "needs-secret")
|
|
39
40
|
return {
|
|
40
41
|
...base,
|
|
41
|
-
title: `MCP server "${name}" needs a
|
|
42
|
-
text: `Its headers use ${connection.missing.map((item) => `\${${item}}`).join(", ")}. Add the value in Settings \u203A
|
|
42
|
+
title: `MCP server "${name}" needs a token`,
|
|
43
|
+
text: `Its headers use ${connection.missing.map((item) => `\${${item}}`).join(", ")}. Add the value in Settings \u203A MCP servers.`,
|
|
43
44
|
severity: "warn",
|
|
44
45
|
eventId: `${name}
|
|
45
46
|
secret
|
|
@@ -48,7 +49,7 @@ ${connection.missing.join(",")}`
|
|
|
48
49
|
if (connection.state === "needs-auth")
|
|
49
50
|
return {
|
|
50
51
|
...base,
|
|
51
|
-
title: `MCP server "${name}"
|
|
52
|
+
title: `MCP server "${name}" rejected its token`,
|
|
52
53
|
text: connection.signInMessage(),
|
|
53
54
|
severity: "warn",
|
|
54
55
|
eventId: `${name}
|
|
@@ -103,6 +104,52 @@ function serverLog(options, context) {
|
|
|
103
104
|
settled: () => logging
|
|
104
105
|
};
|
|
105
106
|
}
|
|
107
|
+
function mcpAccounts(catalog, credentials, restart, listeners) {
|
|
108
|
+
const find = (id) => {
|
|
109
|
+
const connection = catalog.connections.get(id.slice(MCP_ACCOUNT.length));
|
|
110
|
+
if (!id.startsWith(MCP_ACCOUNT) || !connection || !secretNames(connection.entry.config).length)
|
|
111
|
+
throw new Error(`${id} is not an MCP server that takes a token`);
|
|
112
|
+
return connection;
|
|
113
|
+
};
|
|
114
|
+
const keyOf = (connection) => credentialKey(connection.name, connection.entry.config.url);
|
|
115
|
+
return {
|
|
116
|
+
async accounts() {
|
|
117
|
+
const rows = [];
|
|
118
|
+
for (const connection of catalog.connections.values()) {
|
|
119
|
+
if (!secretNames(connection.entry.config).length) continue;
|
|
120
|
+
const stored = await credentials.read(await keyOf(connection)) !== void 0;
|
|
121
|
+
rows.push({
|
|
122
|
+
id: `${MCP_ACCOUNT}${connection.name}`,
|
|
123
|
+
provider: connection.name,
|
|
124
|
+
identity: new URL(connection.entry.config.url).host,
|
|
125
|
+
status: connection.state === "needs-auth" ? "expired" : stored ? "connected" : "disconnected",
|
|
126
|
+
auth: "api-key",
|
|
127
|
+
needs: null,
|
|
128
|
+
group: "mcp",
|
|
129
|
+
secret: "token"
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return rows;
|
|
133
|
+
},
|
|
134
|
+
async connect(id, secret) {
|
|
135
|
+
const connection = find(id);
|
|
136
|
+
await credentials.modify(await keyOf(connection), async () => ({
|
|
137
|
+
type: "api_key",
|
|
138
|
+
key: secret
|
|
139
|
+
}));
|
|
140
|
+
restart(connection);
|
|
141
|
+
},
|
|
142
|
+
async disconnect(id) {
|
|
143
|
+
const connection = find(id);
|
|
144
|
+
await credentials.delete(await keyOf(connection));
|
|
145
|
+
restart(connection);
|
|
146
|
+
},
|
|
147
|
+
onChange(listener) {
|
|
148
|
+
listeners.add(listener);
|
|
149
|
+
return () => listeners.delete(listener);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
106
153
|
async function attachMcp(catalog, options, context) {
|
|
107
154
|
const { env, home } = options;
|
|
108
155
|
catalog.codemodeOn = options.codemode;
|
|
@@ -112,6 +159,10 @@ async function attachMcp(catalog, options, context) {
|
|
|
112
159
|
reported.add(lick.eventId);
|
|
113
160
|
await options.licks.deliver(lick, using).catch(() => void 0);
|
|
114
161
|
};
|
|
162
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
163
|
+
const notify = () => {
|
|
164
|
+
for (const listener of listeners) listener();
|
|
165
|
+
};
|
|
115
166
|
let initial = /* @__PURE__ */ new Set();
|
|
116
167
|
let first = true;
|
|
117
168
|
const log = serverLog(options, context);
|
|
@@ -138,6 +189,7 @@ async function attachMcp(catalog, options, context) {
|
|
|
138
189
|
void report(connectedLick(changed), context);
|
|
139
190
|
void report(stateLick(changed, options.cors), context);
|
|
140
191
|
if (changed.state !== "connected") catalog.rebuild();
|
|
192
|
+
notify();
|
|
141
193
|
}
|
|
142
194
|
});
|
|
143
195
|
catalog.connections.set(entry.name, connection);
|
|
@@ -161,6 +213,7 @@ async function attachMcp(catalog, options, context) {
|
|
|
161
213
|
first = false;
|
|
162
214
|
for (const [name, entry] of wanted) if (!catalog.connections.has(name)) open(entry);
|
|
163
215
|
catalog.rebuild();
|
|
216
|
+
notify();
|
|
164
217
|
await Promise.all(closing);
|
|
165
218
|
};
|
|
166
219
|
await reload(context);
|
|
@@ -171,7 +224,14 @@ async function attachMcp(catalog, options, context) {
|
|
|
171
224
|
};
|
|
172
225
|
const watched = await env.watch([{ path: configPath(home) }], schedule, context);
|
|
173
226
|
const watcher = watched.ok ? watched.value : void 0;
|
|
227
|
+
const restart = (connection) => {
|
|
228
|
+
catalog.connections.delete(connection.name);
|
|
229
|
+
void connection.close();
|
|
230
|
+
open(connection.entry);
|
|
231
|
+
catalog.rebuild();
|
|
232
|
+
};
|
|
174
233
|
return {
|
|
234
|
+
...mcpAccounts(catalog, options.credentials, restart, listeners),
|
|
175
235
|
status: () => [...catalog.connections.values()].map((connection) => ({
|
|
176
236
|
name: connection.name,
|
|
177
237
|
state: connection.state,
|
|
@@ -202,6 +262,7 @@ export {
|
|
|
202
262
|
connectedLick,
|
|
203
263
|
logLine,
|
|
204
264
|
logPath,
|
|
265
|
+
mcpAccounts,
|
|
205
266
|
problemLick,
|
|
206
267
|
startMcp,
|
|
207
268
|
stateLick
|
package/dist/mcp/runtime.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/mcp/runtime.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { CredentialStore } from '@earendil-works/pi-ai';\nimport type { Registry } from '@earendil-works/pi-durable';\nimport type { ExecutionEnv, FileWatcher } from '@earendil-works/pi-durable/env';\nimport { StreamableHttpTransport } from '@earendil-works/pi-mcp';\nimport type { LickEvent, Licks } from '../licks/licks.ts';\nimport { McpCatalog } from './catalog.ts';\nimport {\n type McpConfigProblem,\n type McpServerEntry,\n parseMcpConfig,\n sameConfig,\n} from './config.ts';\nimport { McpServerConnection } from './connection.ts';\nimport { resolveHeaders, scrub } from './credentials.ts';\nimport { patchSse } from './sse.ts';\n\nexport const MCP_LOG_MAX_BYTES = 5 * 1024 * 1024;\n\nexport function configPath(home: string): string {\n return `${home}/.pi/agent/mcp.json`;\n}\n\nexport function logPath(home: string): string {\n return `${home}/.pi/agent/mcp.log`;\n}\n\nexport interface McpAttach {\n licks: Licks;\n env: ExecutionEnv;\n home: string;\n credentials: CredentialStore;\n fetch: typeof fetch;\n version: string;\n reloadMs: number;\n codemode: boolean;\n cors: boolean;\n}\n\nexport interface ServerStatus {\n name: string;\n state: string;\n tools: number;\n error?: string;\n}\n\nexport interface McpRuntime {\n status(): ServerStatus[];\n reload(context: Context): Promise<void>;\n close(context: Context): Promise<void>;\n}\n\nexport function problemLick(problem: McpConfigProblem, home: string): LickEvent {\n const file = `~${configPath(home).slice(home.length)}`;\n const where = problem.server ? `server \"${problem.server}\"` : file;\n const field = problem.field ? `, field ${problem.field}` : '';\n return {\n channel: 'fswatch',\n source: `mcp:${file}`,\n title: `MCP config problem: ${where}${field}`,\n text: problem.message,\n body: `${file}: the entry is skipped until it is fixed. The format is in the slicc-agent README.`,\n target: 'cone',\n severity: 'warn',\n eventId: `${problem.server ?? ''}\\n${problem.field ?? ''}\\n${problem.message}`,\n };\n}\n\nconst CORS_ERROR = /failed to fetch|networkerror|load failed|cors/i;\n\nexport function stateLick(connection: McpServerConnection, cors: boolean): LickEvent | undefined {\n const name = connection.name;\n const base = { channel: 'fswatch' as const, source: `mcp:${name}`, target: 'cone' as const };\n if (connection.state === 'needs-secret')\n return {\n ...base,\n title: `MCP server \"${name}\" needs a secret`,\n text: `Its headers use ${connection.missing.map((item) => `\\${${item}}`).join(', ')}. Add the value in Settings \u203A Accounts.`,\n severity: 'warn',\n eventId: `${name}\\nsecret\\n${connection.missing.join(',')}`,\n };\n if (connection.state === 'needs-auth')\n return {\n ...base,\n title: `MCP server \"${name}\" needs sign-in`,\n text: connection.signInMessage(),\n severity: 'warn',\n eventId: `${name}\\nauth`,\n };\n if (connection.state !== 'failed') return undefined;\n const error = scrub(connection.error ?? 'unknown error', connection.secrets);\n const blocked = cors && CORS_ERROR.test(error);\n return {\n ...base,\n title: `MCP server \"${name}\" can't connect`,\n text: blocked\n ? \"Seven reaches it with the page's own fetch, and the server sends no CORS headers. Run slicc-node, slicc-swift or the SLICC extension, which fetch without CORS.\"\n : error,\n severity: 'warn',\n eventId: `${name}\\nfailed\\n${blocked ? 'cors' : error}`,\n };\n}\n\nexport function connectedLick(connection: McpServerConnection): LickEvent {\n const count = connection.tools.length;\n return {\n channel: 'fswatch',\n source: `mcp:${connection.name}`,\n title: `MCP server \"${connection.name}\" connected`,\n text: `${connection.entry.config.url} offers ${count} tool${count === 1 ? '' : 's'}.`,\n target: 'cone',\n eventId: `${connection.name}\\nconnected\\n${connection.entry.config.url}`,\n };\n}\n\nexport function logLine(\n server: string,\n params: unknown,\n secrets: readonly string[],\n at: Date\n): string {\n const { level, logger, data } = (params ?? {}) as {\n level?: string;\n logger?: string;\n data?: unknown;\n };\n const text = scrub(typeof data === 'string' ? data : (JSON.stringify(data) ?? ''), secrets);\n return `${at.toISOString()} [${server}] ${level ?? 'info'}${logger ? ` ${logger}` : ''}: ${text}\\n`;\n}\n\nfunction serverLog(options: McpAttach, context: Context) {\n let logging = Promise.resolve();\n const path = logPath(options.home);\n const { env } = options;\n return {\n write(connection: McpServerConnection, params: unknown) {\n const line = logLine(connection.name, params, connection.secrets, new Date());\n logging = logging.then(async () => {\n const info = await env.fileInfo(path, context);\n if (info.ok && info.value.size > MCP_LOG_MAX_BYTES)\n await env.renameFile(path, `${path}.1`, context);\n await env.appendFile(path, line, context);\n });\n },\n settled: () => logging,\n };\n}\n\nexport async function attachMcp(\n catalog: McpCatalog,\n options: McpAttach,\n context: Context\n): Promise<McpRuntime> {\n const { env, home } = options;\n catalog.codemodeOn = options.codemode;\n const reported = new Set<string>();\n const report = async (lick: LickEvent | undefined, using: Context) => {\n if (!lick?.eventId || reported.has(lick.eventId)) return;\n reported.add(lick.eventId);\n await options.licks.deliver(lick, using).catch(() => undefined);\n };\n let initial: Set<string> = new Set();\n let first = true;\n const log = serverLog(options, context);\n const make = (url: string, headers: Record<string, string>) =>\n new StreamableHttpTransport({\n url,\n headers,\n fetch: (input, init) => options.fetch(input, init),\n });\n const transport = async (entry: McpServerEntry) => {\n const resolved = await resolveHeaders(entry.name, entry.config, options.credentials);\n if (!resolved.ok) return { missing: resolved.missing };\n return { transport: make(entry.config.url, resolved.headers), secrets: resolved.secrets };\n };\n const open = (entry: McpServerEntry) => {\n const connection = new McpServerConnection({\n entry,\n version: options.version,\n transport,\n onTools: () => catalog.rebuild(),\n onLog: log.write,\n onChange: (changed) => {\n if (catalog.connections.get(changed.name) !== changed) return;\n if (changed.state === 'connected' && !initial.has(changed.name))\n void report(connectedLick(changed), context);\n void report(stateLick(changed, options.cors), context);\n if (changed.state !== 'connected') catalog.rebuild();\n },\n });\n catalog.connections.set(entry.name, connection);\n void connection.getClient().catch(() => undefined);\n };\n const reload = async (using: Context) => {\n const read = await env.readTextFile(configPath(home), using);\n const parsed = parseMcpConfig(read.ok ? read.value : undefined);\n for (const problem of parsed.problems) await report(problemLick(problem, home), using);\n const wanted = new Map(\n parsed.servers\n .filter((entry) => entry.config.enabled !== false)\n .map((entry) => [entry.name, entry])\n );\n const closing: Promise<void>[] = [];\n for (const [name, connection] of [...catalog.connections]) {\n const next = wanted.get(name);\n if (next && sameConfig(next.config, connection.entry.config)) continue;\n catalog.connections.delete(name);\n closing.push(connection.close());\n }\n if (first) initial = new Set(wanted.keys());\n first = false;\n for (const [name, entry] of wanted) if (!catalog.connections.has(name)) open(entry);\n catalog.rebuild();\n await Promise.all(closing);\n };\n await reload(context);\n let timer: ReturnType<typeof setTimeout> | undefined;\n const schedule = () => {\n clearTimeout(timer);\n timer = setTimeout(() => void reload(context).catch(() => undefined), options.reloadMs);\n };\n const watched = await env.watch([{ path: configPath(home) }], schedule, context);\n const watcher: FileWatcher | undefined = watched.ok ? watched.value : undefined;\n return {\n status: () =>\n [...catalog.connections.values()].map((connection) => ({\n name: connection.name,\n state: connection.state,\n tools: connection.tools.length,\n ...(connection.error ? { error: scrub(connection.error, connection.secrets) } : {}),\n })),\n reload,\n async close(using) {\n clearTimeout(timer);\n await watcher?.close(using);\n const all = [...catalog.connections.values()];\n catalog.connections.clear();\n await Promise.all(all.map((connection) => connection.close()));\n catalog.rebuild();\n await log.settled();\n },\n };\n}\n\nexport async function startMcp(\n registry: Registry,\n options: McpAttach,\n context: Context\n): Promise<{ catalog: McpCatalog; runtime: McpRuntime }> {\n patchSse();\n const catalog = new McpCatalog(registry);\n return { catalog, runtime: await attachMcp(catalog, options, context) };\n}\n"],
|
|
5
|
-
"mappings": "AAIA,SAAS,+BAA+B;
|
|
4
|
+
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { CredentialStore } from '@earendil-works/pi-ai';\nimport type { Registry } from '@earendil-works/pi-durable';\nimport type { ExecutionEnv, FileWatcher } from '@earendil-works/pi-durable/env';\nimport { StreamableHttpTransport } from '@earendil-works/pi-mcp';\nimport type { LickEvent, Licks } from '../licks/licks.ts';\nimport type { AccountState } from '../services.ts';\nimport { McpCatalog } from './catalog.ts';\nimport {\n type McpConfigProblem,\n type McpServerEntry,\n parseMcpConfig,\n sameConfig,\n} from './config.ts';\nimport { McpServerConnection } from './connection.ts';\nimport { credentialKey, resolveHeaders, scrub, secretNames } from './credentials.ts';\nimport { MCP_ACCOUNT } from './label.ts';\nimport { patchSse } from './sse.ts';\n\nexport const MCP_LOG_MAX_BYTES = 5 * 1024 * 1024;\n\nexport function configPath(home: string): string {\n return `${home}/.pi/agent/mcp.json`;\n}\n\nexport function logPath(home: string): string {\n return `${home}/.pi/agent/mcp.log`;\n}\n\nexport interface McpAttach {\n licks: Licks;\n env: ExecutionEnv;\n home: string;\n credentials: CredentialStore;\n fetch: typeof fetch;\n version: string;\n reloadMs: number;\n codemode: boolean;\n cors: boolean;\n}\n\nexport interface ServerStatus {\n name: string;\n state: string;\n tools: number;\n error?: string;\n}\n\nexport interface McpAccounts {\n accounts(): Promise<AccountState[]>;\n connect(id: string, secret: string): Promise<void>;\n disconnect(id: string): Promise<void>;\n onChange(listener: () => void): () => void;\n}\n\nexport interface McpRuntime extends McpAccounts {\n status(): ServerStatus[];\n reload(context: Context): Promise<void>;\n close(context: Context): Promise<void>;\n}\n\nexport function problemLick(problem: McpConfigProblem, home: string): LickEvent {\n const file = `~${configPath(home).slice(home.length)}`;\n const where = problem.server ? `server \"${problem.server}\"` : file;\n const field = problem.field ? `, field ${problem.field}` : '';\n return {\n channel: 'fswatch',\n source: `mcp:${file}`,\n title: `MCP config problem: ${where}${field}`,\n text: problem.message,\n body: `${file}: the entry is skipped until it is fixed. The format is in the slicc-agent README.`,\n target: 'cone',\n severity: 'warn',\n eventId: `${problem.server ?? ''}\\n${problem.field ?? ''}\\n${problem.message}`,\n };\n}\n\nconst CORS_ERROR = /failed to fetch|networkerror|load failed|cors/i;\n\nexport function stateLick(connection: McpServerConnection, cors: boolean): LickEvent | undefined {\n const name = connection.name;\n const base = { channel: 'fswatch' as const, source: `mcp:${name}`, target: 'cone' as const };\n if (connection.state === 'needs-secret')\n return {\n ...base,\n title: `MCP server \"${name}\" needs a token`,\n text: `Its headers use ${connection.missing.map((item) => `\\${${item}}`).join(', ')}. Add the value in Settings \u203A MCP servers.`,\n severity: 'warn',\n eventId: `${name}\\nsecret\\n${connection.missing.join(',')}`,\n };\n if (connection.state === 'needs-auth')\n return {\n ...base,\n title: `MCP server \"${name}\" rejected its token`,\n text: connection.signInMessage(),\n severity: 'warn',\n eventId: `${name}\\nauth`,\n };\n if (connection.state !== 'failed') return undefined;\n const error = scrub(connection.error ?? 'unknown error', connection.secrets);\n const blocked = cors && CORS_ERROR.test(error);\n return {\n ...base,\n title: `MCP server \"${name}\" can't connect`,\n text: blocked\n ? \"Seven reaches it with the page's own fetch, and the server sends no CORS headers. Run slicc-node, slicc-swift or the SLICC extension, which fetch without CORS.\"\n : error,\n severity: 'warn',\n eventId: `${name}\\nfailed\\n${blocked ? 'cors' : error}`,\n };\n}\n\nexport function connectedLick(connection: McpServerConnection): LickEvent {\n const count = connection.tools.length;\n return {\n channel: 'fswatch',\n source: `mcp:${connection.name}`,\n title: `MCP server \"${connection.name}\" connected`,\n text: `${connection.entry.config.url} offers ${count} tool${count === 1 ? '' : 's'}.`,\n target: 'cone',\n eventId: `${connection.name}\\nconnected\\n${connection.entry.config.url}`,\n };\n}\n\nexport function logLine(\n server: string,\n params: unknown,\n secrets: readonly string[],\n at: Date\n): string {\n const { level, logger, data } = (params ?? {}) as {\n level?: string;\n logger?: string;\n data?: unknown;\n };\n const text = scrub(typeof data === 'string' ? data : (JSON.stringify(data) ?? ''), secrets);\n return `${at.toISOString()} [${server}] ${level ?? 'info'}${logger ? ` ${logger}` : ''}: ${text}\\n`;\n}\n\nfunction serverLog(options: McpAttach, context: Context) {\n let logging = Promise.resolve();\n const path = logPath(options.home);\n const { env } = options;\n return {\n write(connection: McpServerConnection, params: unknown) {\n const line = logLine(connection.name, params, connection.secrets, new Date());\n logging = logging.then(async () => {\n const info = await env.fileInfo(path, context);\n if (info.ok && info.value.size > MCP_LOG_MAX_BYTES)\n await env.renameFile(path, `${path}.1`, context);\n await env.appendFile(path, line, context);\n });\n },\n settled: () => logging,\n };\n}\n\nexport function mcpAccounts(\n catalog: McpCatalog,\n credentials: CredentialStore,\n restart: (connection: McpServerConnection) => void,\n listeners: Set<() => void>\n): McpAccounts {\n const find = (id: string) => {\n const connection = catalog.connections.get(id.slice(MCP_ACCOUNT.length));\n if (!id.startsWith(MCP_ACCOUNT) || !connection || !secretNames(connection.entry.config).length)\n throw new Error(`${id} is not an MCP server that takes a token`);\n return connection;\n };\n const keyOf = (connection: McpServerConnection) =>\n credentialKey(connection.name, connection.entry.config.url);\n return {\n async accounts() {\n const rows: AccountState[] = [];\n for (const connection of catalog.connections.values()) {\n if (!secretNames(connection.entry.config).length) continue;\n const stored = (await credentials.read(await keyOf(connection))) !== undefined;\n rows.push({\n id: `${MCP_ACCOUNT}${connection.name}`,\n provider: connection.name,\n identity: new URL(connection.entry.config.url).host,\n status:\n connection.state === 'needs-auth' ? 'expired' : stored ? 'connected' : 'disconnected',\n auth: 'api-key',\n needs: null,\n group: 'mcp',\n secret: 'token',\n });\n }\n return rows;\n },\n async connect(id, secret) {\n const connection = find(id);\n await credentials.modify(await keyOf(connection), async () => ({\n type: 'api_key',\n key: secret,\n }));\n restart(connection);\n },\n async disconnect(id) {\n const connection = find(id);\n await credentials.delete(await keyOf(connection));\n restart(connection);\n },\n onChange(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n}\n\nexport async function attachMcp(\n catalog: McpCatalog,\n options: McpAttach,\n context: Context\n): Promise<McpRuntime> {\n const { env, home } = options;\n catalog.codemodeOn = options.codemode;\n const reported = new Set<string>();\n const report = async (lick: LickEvent | undefined, using: Context) => {\n if (!lick?.eventId || reported.has(lick.eventId)) return;\n reported.add(lick.eventId);\n await options.licks.deliver(lick, using).catch(() => undefined);\n };\n const listeners = new Set<() => void>();\n const notify = () => {\n for (const listener of listeners) listener();\n };\n let initial: Set<string> = new Set();\n let first = true;\n const log = serverLog(options, context);\n const make = (url: string, headers: Record<string, string>) =>\n new StreamableHttpTransport({\n url,\n headers,\n fetch: (input, init) => options.fetch(input, init),\n });\n const transport = async (entry: McpServerEntry) => {\n const resolved = await resolveHeaders(entry.name, entry.config, options.credentials);\n if (!resolved.ok) return { missing: resolved.missing };\n return { transport: make(entry.config.url, resolved.headers), secrets: resolved.secrets };\n };\n const open = (entry: McpServerEntry) => {\n const connection = new McpServerConnection({\n entry,\n version: options.version,\n transport,\n onTools: () => catalog.rebuild(),\n onLog: log.write,\n onChange: (changed) => {\n if (catalog.connections.get(changed.name) !== changed) return;\n if (changed.state === 'connected' && !initial.has(changed.name))\n void report(connectedLick(changed), context);\n void report(stateLick(changed, options.cors), context);\n if (changed.state !== 'connected') catalog.rebuild();\n notify();\n },\n });\n catalog.connections.set(entry.name, connection);\n void connection.getClient().catch(() => undefined);\n };\n const reload = async (using: Context) => {\n const read = await env.readTextFile(configPath(home), using);\n const parsed = parseMcpConfig(read.ok ? read.value : undefined);\n for (const problem of parsed.problems) await report(problemLick(problem, home), using);\n const wanted = new Map(\n parsed.servers\n .filter((entry) => entry.config.enabled !== false)\n .map((entry) => [entry.name, entry])\n );\n const closing: Promise<void>[] = [];\n for (const [name, connection] of [...catalog.connections]) {\n const next = wanted.get(name);\n if (next && sameConfig(next.config, connection.entry.config)) continue;\n catalog.connections.delete(name);\n closing.push(connection.close());\n }\n if (first) initial = new Set(wanted.keys());\n first = false;\n for (const [name, entry] of wanted) if (!catalog.connections.has(name)) open(entry);\n catalog.rebuild();\n notify();\n await Promise.all(closing);\n };\n await reload(context);\n let timer: ReturnType<typeof setTimeout> | undefined;\n const schedule = () => {\n clearTimeout(timer);\n timer = setTimeout(() => void reload(context).catch(() => undefined), options.reloadMs);\n };\n const watched = await env.watch([{ path: configPath(home) }], schedule, context);\n const watcher: FileWatcher | undefined = watched.ok ? watched.value : undefined;\n const restart = (connection: McpServerConnection) => {\n catalog.connections.delete(connection.name);\n void connection.close();\n open(connection.entry);\n catalog.rebuild();\n };\n return {\n ...mcpAccounts(catalog, options.credentials, restart, listeners),\n status: () =>\n [...catalog.connections.values()].map((connection) => ({\n name: connection.name,\n state: connection.state,\n tools: connection.tools.length,\n ...(connection.error ? { error: scrub(connection.error, connection.secrets) } : {}),\n })),\n reload,\n async close(using) {\n clearTimeout(timer);\n await watcher?.close(using);\n const all = [...catalog.connections.values()];\n catalog.connections.clear();\n await Promise.all(all.map((connection) => connection.close()));\n catalog.rebuild();\n await log.settled();\n },\n };\n}\n\nexport async function startMcp(\n registry: Registry,\n options: McpAttach,\n context: Context\n): Promise<{ catalog: McpCatalog; runtime: McpRuntime }> {\n patchSse();\n const catalog = new McpCatalog(registry);\n return { catalog, runtime: await attachMcp(catalog, options, context) };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/remote/events.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { entryLick } from "../licks/state.js";
|
|
2
|
+
import { mcpLabel } from "../mcp/label.js";
|
|
2
3
|
import { redactSecrets } from "../memory/format.js";
|
|
3
4
|
const SUMMARY = 200;
|
|
4
5
|
function clip(text, limit = SUMMARY) {
|
|
@@ -13,7 +14,7 @@ const SUBJECTS = ["command", "path", "pattern", "url", "query", "code", "name"];
|
|
|
13
14
|
function toolSummary(name, args) {
|
|
14
15
|
const subject = SUBJECTS.map((key) => args?.[key]).find((value) => typeof value === "string");
|
|
15
16
|
const detail = typeof subject === "string" ? subject : JSON.stringify(args ?? {});
|
|
16
|
-
return clip(`${name} ${detail}`);
|
|
17
|
+
return clip(`${mcpLabel(name) ?? name} ${detail}`);
|
|
17
18
|
}
|
|
18
19
|
function resultSummary(message) {
|
|
19
20
|
const text = textOf(message.content);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/remote/events.ts"],
|
|
4
|
-
"sourcesContent": ["import type { AgentEvent, EntryRecord } from '@earendil-works/pi-durable';\nimport { entryLick } from '../licks/state.ts';\nimport { redactSecrets } from '../memory/format.ts';\nimport type { Delivered } from '../services.ts';\n\nexport const SUMMARY = 200;\n\nexport type EndReason = 'stop' | 'aborted' | 'error';\n\nexport type RemoteEvent =\n | { t: 'user'; id: string; text: string; delivered: Delivered }\n | { t: 'text'; id: string; delta: string }\n | { t: 'thinking'; id: string; delta: string }\n | { t: 'tool'; id: string; call: string; name: string; summary: string }\n | { t: 'tool-result'; id: string; call: string; ok: boolean; summary: string }\n | { t: 'run'; state: 'start' | 'end'; reason?: EndReason }\n | { t: 'notice'; id: string; text: string }\n | { t: 'error'; id: string; message: string; detail?: string }\n | { t: 'end'; reason: EndReason; message?: string };\n\ntype Json = Record<string, unknown>;\n\ninterface Block {\n type: string;\n text?: string;\n thinking?: string;\n id?: string;\n name?: string;\n arguments?: Json;\n}\n\ninterface ModelMessage {\n role?: string;\n content?: string | Block[];\n timestamp?: number;\n stopReason?: string;\n errorMessage?: string;\n toolCallId?: string;\n toolName?: string;\n isError?: boolean;\n}\n\nexport function clip(text: string, limit = SUMMARY): string {\n const flat = redactSecrets(text).text.replace(/\\s+/g, ' ').trim();\n return flat.length > limit ? `${flat.slice(0, limit - 1)}\u2026` : flat;\n}\n\nfunction textOf(content: ModelMessage['content']): string {\n if (typeof content === 'string') return content;\n return (content ?? []).map((block) => (block.type === 'text' ? (block.text ?? '') : '')).join('');\n}\n\nconst SUBJECTS = ['command', 'path', 'pattern', 'url', 'query', 'code', 'name'];\n\nexport function toolSummary(name: string, args: Json | undefined): string {\n const subject = SUBJECTS.map((key) => args?.[key]).find((value) => typeof value === 'string');\n const detail = typeof subject === 'string' ? subject : JSON.stringify(args ?? {});\n return clip(`${name} ${detail}`);\n}\n\nexport function resultSummary(message: ModelMessage): string {\n const text = textOf(message.content);\n if (message.isError)\n return clip(\n text.split('\\n').find((line) => line.trim() && !/^<\\/?harness>$/.test(line.trim())) ??\n 'failed'\n );\n const lines = text ? text.split('\\n').length : 0;\n return lines === 1 ? '1 line' : `${lines} lines`;\n}\n\nexport function keyOf(timestamp: number | undefined, at: number): string {\n return at > 0 ? `a${timestamp ?? 0}~${at}` : `a${timestamp ?? 0}`;\n}\n\nfunction reasonOf(stopReason: string | undefined): EndReason {\n if (stopReason === 'aborted') return 'aborted';\n return stopReason === 'error' ? 'error' : 'stop';\n}\n\nexport class Mapper {\n readonly #thinking: boolean;\n readonly #emitted = new Map<string, number>();\n readonly #seen = new Set<number>();\n #current: string | undefined;\n #previous: string | undefined;\n #ending: readonly number[] = [];\n readonly #stamps = new Map<number, number[]>();\n reason: EndReason = 'stop';\n error: string | undefined;\n\n constructor(thinking: boolean) {\n this.#thinking = thinking;\n }\n\n #key(message: ModelMessage | undefined, entry?: number): string {\n const stamp = message?.timestamp ?? 0;\n const list = this.#stamps.get(stamp) ?? [];\n this.#stamps.set(stamp, list);\n if (entry === undefined) return keyOf(stamp, list.length);\n if (!list.includes(entry)) list.push(entry);\n return keyOf(stamp, list.indexOf(entry));\n }\n\n #delta(t: 'text' | 'thinking', id: string, full: string): RemoteEvent[] {\n if (t === 'thinking' && !this.#thinking) return [];\n const done = this.#emitted.get(id) ?? 0;\n if (full.length <= done) return [];\n this.#emitted.set(id, full.length);\n return [{ t, id, delta: full.slice(done) }];\n }\n\n partial(message: ModelMessage | undefined): RemoteEvent[] {\n if (!message || !Array.isArray(message.content)) return [];\n const key = this.#key(message);\n this.#current = key;\n return message.content.flatMap((block, at) => {\n if (block.type === 'text') return this.#delta('text', `${key}.${at}`, block.text ?? '');\n if (block.type === 'thinking')\n return this.#delta('thinking', `${key}.${at}`, block.thinking ?? '');\n return [];\n });\n }\n\n #assistant(message: ModelMessage, entry: EntryRecord): RemoteEvent[] {\n const key = this.#key(message, entry.id);\n const blocks = Array.isArray(message.content) ? message.content : [];\n const out = blocks.flatMap((block, at): RemoteEvent[] => {\n const id = `${key}.${at}`;\n if (block.type === 'text') return this.#delta('text', id, block.text ?? '');\n if (block.type === 'thinking') return this.#delta('thinking', id, block.thinking ?? '');\n if (block.type !== 'toolCall') return [];\n const name = block.name ?? 'tool';\n return [\n { t: 'tool', id, call: block.id ?? '', name, summary: toolSummary(name, block.arguments) },\n ];\n });\n if (typeof message.content === 'string')\n out.push(...this.#delta('text', `${key}.0`, message.content));\n this.reason = reasonOf(message.stopReason);\n this.error =\n message.stopReason === 'error' ? clip(message.errorMessage ?? 'error', 1000) : undefined;\n if (this.error) out.push({ t: 'error', id: String(entry.id), message: this.error });\n return out;\n }\n\n #delivered(entry: EntryRecord): Delivered {\n if (entry.byTaskId === undefined) return 'run';\n return this.#previous === 'pi.tool-result' ? 'steer' : 'follow-up';\n }\n\n entry(entry: EntryRecord, delivered: Delivered = this.#delivered(entry)): RemoteEvent[] {\n if (this.#seen.has(entry.id)) return [];\n this.#seen.add(entry.id);\n this.#previous = entry.kind;\n const id = String(entry.id);\n const message = entry.model?.[0] as ModelMessage | undefined;\n if (entry.kind === 'pi.user' && message) {\n const lick = entryLick(entry);\n if (lick) return [{ t: 'notice', id, text: clip(`lick ${lick.channel}: ${lick.title}`) }];\n return [{ t: 'user', id, text: redactSecrets(textOf(message.content)).text, delivered }];\n }\n if (entry.kind === 'pi.assistant' && message) return this.#assistant(message, entry);\n if (entry.kind === 'pi.tool-result' && message)\n return [\n {\n t: 'tool-result',\n id,\n call: message.toolCallId ?? '',\n ok: !message.isError,\n summary: resultSummary(message),\n },\n ];\n if (entry.kind === 'pi.compaction') return [{ t: 'notice', id, text: 'compacted' }];\n if (entry.kind === 'slicc.rewound') return [{ t: 'notice', id, text: 'rewound' }];\n return [];\n }\n\n #ended(reason: EndReason): RemoteEvent[] {\n if (!this.#ending.length) return [];\n this.#ending = [];\n this.reason = reason;\n return [{ t: 'run', state: 'end', reason }];\n }\n\n #settled(record: { id: number; status: string; reason?: unknown }): RemoteEvent[] {\n if (!this.#ending.includes(record.id) || ['queued', 'placed'].includes(record.status))\n return [];\n if (record.status !== 'unanswered') return this.#ended(this.reason);\n if (record.reason === 'aborted') return this.#ended('aborted');\n this.error ??= clip(String(record.reason ?? 'error'), 1000);\n return this.#ended('error');\n }\n\n last(): number {\n return Math.max(0, ...this.#seen);\n }\n\n event(event: AgentEvent): RemoteEvent[] {\n switch (event.type) {\n case 'run_start': {\n const ended = this.#ended(this.reason);\n this.reason = 'stop';\n this.error = undefined;\n return [...ended, { t: 'run', state: 'start' }];\n }\n case 'run_end':\n this.#ending = event.inputs;\n return [];\n case 'submission':\n return this.#settled(event.record);\n case 'message_start':\n if ((event.message as ModelMessage).role === 'assistant')\n this.#current = this.#key(event.message as ModelMessage);\n return [];\n case 'message_update':\n return event.changes.flatMap((change) => {\n if (change.type !== 'text_delta' && change.type !== 'thinking_delta') return [];\n const id = `${this.#current}.${change.contentIndex}`;\n const t = change.type === 'text_delta' ? 'text' : 'thinking';\n const done = this.#emitted.get(id) ?? 0;\n if (t === 'thinking' && !this.#thinking) return [];\n this.#emitted.set(id, done + change.delta.length);\n return [{ t, id, delta: change.delta }];\n });\n case 'message_end':\n return this.entry(event.entry);\n case 'tool_execution_end':\n return event.entry\n ? this.entry(event.entry)\n : [\n {\n t: 'tool-result',\n id: `x${event.toolCallId}`,\n call: event.toolCallId,\n ok: false,\n summary: 'the tool did not finish',\n },\n ];\n case 'auto_retry_start':\n return [\n {\n t: 'notice',\n id: `retry-${event.at}`,\n text: clip(`retrying (attempt ${event.attempt}): ${event.errorMessage}`),\n },\n ];\n case 'compaction_start':\n return [{ t: 'notice', id: `compaction-${event.taskId}`, text: 'compacting' }];\n case 'task_failed':\n return [{ t: 'error', id: `task-${event.taskId}`, message: clip(event.message, 1000) }];\n default:\n return [];\n }\n }\n}\n\nexport function replayOf(\n entries: readonly EntryRecord[],\n partial: ModelMessage | undefined,\n thinking: boolean\n): RemoteEvent[] {\n const mapper = new Mapper(thinking);\n const out: RemoteEvent[] = [];\n for (const entry of entries) out.push(...mapper.entry(entry));\n out.push(...mapper.partial(partial));\n return out;\n}\n\nexport function idOf(event: RemoteEvent): string | undefined {\n return 'id' in event ? event.id : undefined;\n}\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,iBAAiB;AAC1B,SAAS,qBAAqB;AAGvB,MAAM,UAAU;AAqChB,SAAS,KAAK,MAAc,QAAQ,SAAiB;AAC1D,QAAM,OAAO,cAAc,IAAI,EAAE,KAAK,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAChE,SAAO,KAAK,SAAS,QAAQ,GAAG,KAAK,MAAM,GAAG,QAAQ,CAAC,CAAC,WAAM;AAChE;AAEA,SAAS,OAAO,SAA0C;AACxD,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,UAAQ,WAAW,CAAC,GAAG,IAAI,CAAC,UAAW,MAAM,SAAS,SAAU,MAAM,QAAQ,KAAM,EAAG,EAAE,KAAK,EAAE;AAClG;AAEA,MAAM,WAAW,CAAC,WAAW,QAAQ,WAAW,OAAO,SAAS,QAAQ,MAAM;AAEvE,SAAS,YAAY,MAAc,MAAgC;AACxE,QAAM,UAAU,SAAS,IAAI,CAAC,QAAQ,OAAO,GAAG,CAAC,EAAE,KAAK,CAAC,UAAU,OAAO,UAAU,QAAQ;AAC5F,QAAM,SAAS,OAAO,YAAY,WAAW,UAAU,KAAK,UAAU,QAAQ,CAAC,CAAC;AAChF,SAAO,KAAK,GAAG,IAAI,IAAI,MAAM,EAAE;
|
|
4
|
+
"sourcesContent": ["import type { AgentEvent, EntryRecord } from '@earendil-works/pi-durable';\nimport { entryLick } from '../licks/state.ts';\nimport { mcpLabel } from '../mcp/label.ts';\nimport { redactSecrets } from '../memory/format.ts';\nimport type { Delivered } from '../services.ts';\n\nexport const SUMMARY = 200;\n\nexport type EndReason = 'stop' | 'aborted' | 'error';\n\nexport type RemoteEvent =\n | { t: 'user'; id: string; text: string; delivered: Delivered }\n | { t: 'text'; id: string; delta: string }\n | { t: 'thinking'; id: string; delta: string }\n | { t: 'tool'; id: string; call: string; name: string; summary: string }\n | { t: 'tool-result'; id: string; call: string; ok: boolean; summary: string }\n | { t: 'run'; state: 'start' | 'end'; reason?: EndReason }\n | { t: 'notice'; id: string; text: string }\n | { t: 'error'; id: string; message: string; detail?: string }\n | { t: 'end'; reason: EndReason; message?: string };\n\ntype Json = Record<string, unknown>;\n\ninterface Block {\n type: string;\n text?: string;\n thinking?: string;\n id?: string;\n name?: string;\n arguments?: Json;\n}\n\ninterface ModelMessage {\n role?: string;\n content?: string | Block[];\n timestamp?: number;\n stopReason?: string;\n errorMessage?: string;\n toolCallId?: string;\n toolName?: string;\n isError?: boolean;\n}\n\nexport function clip(text: string, limit = SUMMARY): string {\n const flat = redactSecrets(text).text.replace(/\\s+/g, ' ').trim();\n return flat.length > limit ? `${flat.slice(0, limit - 1)}\u2026` : flat;\n}\n\nfunction textOf(content: ModelMessage['content']): string {\n if (typeof content === 'string') return content;\n return (content ?? []).map((block) => (block.type === 'text' ? (block.text ?? '') : '')).join('');\n}\n\nconst SUBJECTS = ['command', 'path', 'pattern', 'url', 'query', 'code', 'name'];\n\nexport function toolSummary(name: string, args: Json | undefined): string {\n const subject = SUBJECTS.map((key) => args?.[key]).find((value) => typeof value === 'string');\n const detail = typeof subject === 'string' ? subject : JSON.stringify(args ?? {});\n return clip(`${mcpLabel(name) ?? name} ${detail}`);\n}\n\nexport function resultSummary(message: ModelMessage): string {\n const text = textOf(message.content);\n if (message.isError)\n return clip(\n text.split('\\n').find((line) => line.trim() && !/^<\\/?harness>$/.test(line.trim())) ??\n 'failed'\n );\n const lines = text ? text.split('\\n').length : 0;\n return lines === 1 ? '1 line' : `${lines} lines`;\n}\n\nexport function keyOf(timestamp: number | undefined, at: number): string {\n return at > 0 ? `a${timestamp ?? 0}~${at}` : `a${timestamp ?? 0}`;\n}\n\nfunction reasonOf(stopReason: string | undefined): EndReason {\n if (stopReason === 'aborted') return 'aborted';\n return stopReason === 'error' ? 'error' : 'stop';\n}\n\nexport class Mapper {\n readonly #thinking: boolean;\n readonly #emitted = new Map<string, number>();\n readonly #seen = new Set<number>();\n #current: string | undefined;\n #previous: string | undefined;\n #ending: readonly number[] = [];\n readonly #stamps = new Map<number, number[]>();\n reason: EndReason = 'stop';\n error: string | undefined;\n\n constructor(thinking: boolean) {\n this.#thinking = thinking;\n }\n\n #key(message: ModelMessage | undefined, entry?: number): string {\n const stamp = message?.timestamp ?? 0;\n const list = this.#stamps.get(stamp) ?? [];\n this.#stamps.set(stamp, list);\n if (entry === undefined) return keyOf(stamp, list.length);\n if (!list.includes(entry)) list.push(entry);\n return keyOf(stamp, list.indexOf(entry));\n }\n\n #delta(t: 'text' | 'thinking', id: string, full: string): RemoteEvent[] {\n if (t === 'thinking' && !this.#thinking) return [];\n const done = this.#emitted.get(id) ?? 0;\n if (full.length <= done) return [];\n this.#emitted.set(id, full.length);\n return [{ t, id, delta: full.slice(done) }];\n }\n\n partial(message: ModelMessage | undefined): RemoteEvent[] {\n if (!message || !Array.isArray(message.content)) return [];\n const key = this.#key(message);\n this.#current = key;\n return message.content.flatMap((block, at) => {\n if (block.type === 'text') return this.#delta('text', `${key}.${at}`, block.text ?? '');\n if (block.type === 'thinking')\n return this.#delta('thinking', `${key}.${at}`, block.thinking ?? '');\n return [];\n });\n }\n\n #assistant(message: ModelMessage, entry: EntryRecord): RemoteEvent[] {\n const key = this.#key(message, entry.id);\n const blocks = Array.isArray(message.content) ? message.content : [];\n const out = blocks.flatMap((block, at): RemoteEvent[] => {\n const id = `${key}.${at}`;\n if (block.type === 'text') return this.#delta('text', id, block.text ?? '');\n if (block.type === 'thinking') return this.#delta('thinking', id, block.thinking ?? '');\n if (block.type !== 'toolCall') return [];\n const name = block.name ?? 'tool';\n return [\n { t: 'tool', id, call: block.id ?? '', name, summary: toolSummary(name, block.arguments) },\n ];\n });\n if (typeof message.content === 'string')\n out.push(...this.#delta('text', `${key}.0`, message.content));\n this.reason = reasonOf(message.stopReason);\n this.error =\n message.stopReason === 'error' ? clip(message.errorMessage ?? 'error', 1000) : undefined;\n if (this.error) out.push({ t: 'error', id: String(entry.id), message: this.error });\n return out;\n }\n\n #delivered(entry: EntryRecord): Delivered {\n if (entry.byTaskId === undefined) return 'run';\n return this.#previous === 'pi.tool-result' ? 'steer' : 'follow-up';\n }\n\n entry(entry: EntryRecord, delivered: Delivered = this.#delivered(entry)): RemoteEvent[] {\n if (this.#seen.has(entry.id)) return [];\n this.#seen.add(entry.id);\n this.#previous = entry.kind;\n const id = String(entry.id);\n const message = entry.model?.[0] as ModelMessage | undefined;\n if (entry.kind === 'pi.user' && message) {\n const lick = entryLick(entry);\n if (lick) return [{ t: 'notice', id, text: clip(`lick ${lick.channel}: ${lick.title}`) }];\n return [{ t: 'user', id, text: redactSecrets(textOf(message.content)).text, delivered }];\n }\n if (entry.kind === 'pi.assistant' && message) return this.#assistant(message, entry);\n if (entry.kind === 'pi.tool-result' && message)\n return [\n {\n t: 'tool-result',\n id,\n call: message.toolCallId ?? '',\n ok: !message.isError,\n summary: resultSummary(message),\n },\n ];\n if (entry.kind === 'pi.compaction') return [{ t: 'notice', id, text: 'compacted' }];\n if (entry.kind === 'slicc.rewound') return [{ t: 'notice', id, text: 'rewound' }];\n return [];\n }\n\n #ended(reason: EndReason): RemoteEvent[] {\n if (!this.#ending.length) return [];\n this.#ending = [];\n this.reason = reason;\n return [{ t: 'run', state: 'end', reason }];\n }\n\n #settled(record: { id: number; status: string; reason?: unknown }): RemoteEvent[] {\n if (!this.#ending.includes(record.id) || ['queued', 'placed'].includes(record.status))\n return [];\n if (record.status !== 'unanswered') return this.#ended(this.reason);\n if (record.reason === 'aborted') return this.#ended('aborted');\n this.error ??= clip(String(record.reason ?? 'error'), 1000);\n return this.#ended('error');\n }\n\n last(): number {\n return Math.max(0, ...this.#seen);\n }\n\n event(event: AgentEvent): RemoteEvent[] {\n switch (event.type) {\n case 'run_start': {\n const ended = this.#ended(this.reason);\n this.reason = 'stop';\n this.error = undefined;\n return [...ended, { t: 'run', state: 'start' }];\n }\n case 'run_end':\n this.#ending = event.inputs;\n return [];\n case 'submission':\n return this.#settled(event.record);\n case 'message_start':\n if ((event.message as ModelMessage).role === 'assistant')\n this.#current = this.#key(event.message as ModelMessage);\n return [];\n case 'message_update':\n return event.changes.flatMap((change) => {\n if (change.type !== 'text_delta' && change.type !== 'thinking_delta') return [];\n const id = `${this.#current}.${change.contentIndex}`;\n const t = change.type === 'text_delta' ? 'text' : 'thinking';\n const done = this.#emitted.get(id) ?? 0;\n if (t === 'thinking' && !this.#thinking) return [];\n this.#emitted.set(id, done + change.delta.length);\n return [{ t, id, delta: change.delta }];\n });\n case 'message_end':\n return this.entry(event.entry);\n case 'tool_execution_end':\n return event.entry\n ? this.entry(event.entry)\n : [\n {\n t: 'tool-result',\n id: `x${event.toolCallId}`,\n call: event.toolCallId,\n ok: false,\n summary: 'the tool did not finish',\n },\n ];\n case 'auto_retry_start':\n return [\n {\n t: 'notice',\n id: `retry-${event.at}`,\n text: clip(`retrying (attempt ${event.attempt}): ${event.errorMessage}`),\n },\n ];\n case 'compaction_start':\n return [{ t: 'notice', id: `compaction-${event.taskId}`, text: 'compacting' }];\n case 'task_failed':\n return [{ t: 'error', id: `task-${event.taskId}`, message: clip(event.message, 1000) }];\n default:\n return [];\n }\n }\n}\n\nexport function replayOf(\n entries: readonly EntryRecord[],\n partial: ModelMessage | undefined,\n thinking: boolean\n): RemoteEvent[] {\n const mapper = new Mapper(thinking);\n const out: RemoteEvent[] = [];\n for (const entry of entries) out.push(...mapper.entry(entry));\n out.push(...mapper.partial(partial));\n return out;\n}\n\nexport function idOf(event: RemoteEvent): string | undefined {\n return 'id' in event ? event.id : undefined;\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,iBAAiB;AAC1B,SAAS,gBAAgB;AACzB,SAAS,qBAAqB;AAGvB,MAAM,UAAU;AAqChB,SAAS,KAAK,MAAc,QAAQ,SAAiB;AAC1D,QAAM,OAAO,cAAc,IAAI,EAAE,KAAK,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAChE,SAAO,KAAK,SAAS,QAAQ,GAAG,KAAK,MAAM,GAAG,QAAQ,CAAC,CAAC,WAAM;AAChE;AAEA,SAAS,OAAO,SAA0C;AACxD,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,UAAQ,WAAW,CAAC,GAAG,IAAI,CAAC,UAAW,MAAM,SAAS,SAAU,MAAM,QAAQ,KAAM,EAAG,EAAE,KAAK,EAAE;AAClG;AAEA,MAAM,WAAW,CAAC,WAAW,QAAQ,WAAW,OAAO,SAAS,QAAQ,MAAM;AAEvE,SAAS,YAAY,MAAc,MAAgC;AACxE,QAAM,UAAU,SAAS,IAAI,CAAC,QAAQ,OAAO,GAAG,CAAC,EAAE,KAAK,CAAC,UAAU,OAAO,UAAU,QAAQ;AAC5F,QAAM,SAAS,OAAO,YAAY,WAAW,UAAU,KAAK,UAAU,QAAQ,CAAC,CAAC;AAChF,SAAO,KAAK,GAAG,SAAS,IAAI,KAAK,IAAI,IAAI,MAAM,EAAE;AACnD;AAEO,SAAS,cAAc,SAA+B;AAC3D,QAAM,OAAO,OAAO,QAAQ,OAAO;AACnC,MAAI,QAAQ;AACV,WAAO;AAAA,MACL,KAAK,MAAM,IAAI,EAAE,KAAK,CAAC,SAAS,KAAK,KAAK,KAAK,CAAC,iBAAiB,KAAK,KAAK,KAAK,CAAC,CAAC,KAChF;AAAA,IACJ;AACF,QAAM,QAAQ,OAAO,KAAK,MAAM,IAAI,EAAE,SAAS;AAC/C,SAAO,UAAU,IAAI,WAAW,GAAG,KAAK;AAC1C;AAEO,SAAS,MAAM,WAA+B,IAAoB;AACvE,SAAO,KAAK,IAAI,IAAI,aAAa,CAAC,IAAI,EAAE,KAAK,IAAI,aAAa,CAAC;AACjE;AAEA,SAAS,SAAS,YAA2C;AAC3D,MAAI,eAAe,UAAW,QAAO;AACrC,SAAO,eAAe,UAAU,UAAU;AAC5C;AAEO,MAAM,OAAO;AAAA,EACT;AAAA,EACA,WAAW,oBAAI,IAAoB;AAAA,EACnC,QAAQ,oBAAI,IAAY;AAAA,EACjC;AAAA,EACA;AAAA,EACA,UAA6B,CAAC;AAAA,EACrB,UAAU,oBAAI,IAAsB;AAAA,EAC7C,SAAoB;AAAA,EACpB;AAAA,EAEA,YAAY,UAAmB;AAC7B,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,KAAK,SAAmC,OAAwB;AAC9D,UAAM,QAAQ,SAAS,aAAa;AACpC,UAAM,OAAO,KAAK,QAAQ,IAAI,KAAK,KAAK,CAAC;AACzC,SAAK,QAAQ,IAAI,OAAO,IAAI;AAC5B,QAAI,UAAU,OAAW,QAAO,MAAM,OAAO,KAAK,MAAM;AACxD,QAAI,CAAC,KAAK,SAAS,KAAK,EAAG,MAAK,KAAK,KAAK;AAC1C,WAAO,MAAM,OAAO,KAAK,QAAQ,KAAK,CAAC;AAAA,EACzC;AAAA,EAEA,OAAO,GAAwB,IAAY,MAA6B;AACtE,QAAI,MAAM,cAAc,CAAC,KAAK,UAAW,QAAO,CAAC;AACjD,UAAM,OAAO,KAAK,SAAS,IAAI,EAAE,KAAK;AACtC,QAAI,KAAK,UAAU,KAAM,QAAO,CAAC;AACjC,SAAK,SAAS,IAAI,IAAI,KAAK,MAAM;AACjC,WAAO,CAAC,EAAE,GAAG,IAAI,OAAO,KAAK,MAAM,IAAI,EAAE,CAAC;AAAA,EAC5C;AAAA,EAEA,QAAQ,SAAkD;AACxD,QAAI,CAAC,WAAW,CAAC,MAAM,QAAQ,QAAQ,OAAO,EAAG,QAAO,CAAC;AACzD,UAAM,MAAM,KAAK,KAAK,OAAO;AAC7B,SAAK,WAAW;AAChB,WAAO,QAAQ,QAAQ,QAAQ,CAAC,OAAO,OAAO;AAC5C,UAAI,MAAM,SAAS,OAAQ,QAAO,KAAK,OAAO,QAAQ,GAAG,GAAG,IAAI,EAAE,IAAI,MAAM,QAAQ,EAAE;AACtF,UAAI,MAAM,SAAS;AACjB,eAAO,KAAK,OAAO,YAAY,GAAG,GAAG,IAAI,EAAE,IAAI,MAAM,YAAY,EAAE;AACrE,aAAO,CAAC;AAAA,IACV,CAAC;AAAA,EACH;AAAA,EAEA,WAAW,SAAuB,OAAmC;AACnE,UAAM,MAAM,KAAK,KAAK,SAAS,MAAM,EAAE;AACvC,UAAM,SAAS,MAAM,QAAQ,QAAQ,OAAO,IAAI,QAAQ,UAAU,CAAC;AACnE,UAAM,MAAM,OAAO,QAAQ,CAAC,OAAO,OAAsB;AACvD,YAAM,KAAK,GAAG,GAAG,IAAI,EAAE;AACvB,UAAI,MAAM,SAAS,OAAQ,QAAO,KAAK,OAAO,QAAQ,IAAI,MAAM,QAAQ,EAAE;AAC1E,UAAI,MAAM,SAAS,WAAY,QAAO,KAAK,OAAO,YAAY,IAAI,MAAM,YAAY,EAAE;AACtF,UAAI,MAAM,SAAS,WAAY,QAAO,CAAC;AACvC,YAAM,OAAO,MAAM,QAAQ;AAC3B,aAAO;AAAA,QACL,EAAE,GAAG,QAAQ,IAAI,MAAM,MAAM,MAAM,IAAI,MAAM,SAAS,YAAY,MAAM,MAAM,SAAS,EAAE;AAAA,MAC3F;AAAA,IACF,CAAC;AACD,QAAI,OAAO,QAAQ,YAAY;AAC7B,UAAI,KAAK,GAAG,KAAK,OAAO,QAAQ,GAAG,GAAG,MAAM,QAAQ,OAAO,CAAC;AAC9D,SAAK,SAAS,SAAS,QAAQ,UAAU;AACzC,SAAK,QACH,QAAQ,eAAe,UAAU,KAAK,QAAQ,gBAAgB,SAAS,GAAI,IAAI;AACjF,QAAI,KAAK,MAAO,KAAI,KAAK,EAAE,GAAG,SAAS,IAAI,OAAO,MAAM,EAAE,GAAG,SAAS,KAAK,MAAM,CAAC;AAClF,WAAO;AAAA,EACT;AAAA,EAEA,WAAW,OAA+B;AACxC,QAAI,MAAM,aAAa,OAAW,QAAO;AACzC,WAAO,KAAK,cAAc,mBAAmB,UAAU;AAAA,EACzD;AAAA,EAEA,MAAM,OAAoB,YAAuB,KAAK,WAAW,KAAK,GAAkB;AACtF,QAAI,KAAK,MAAM,IAAI,MAAM,EAAE,EAAG,QAAO,CAAC;AACtC,SAAK,MAAM,IAAI,MAAM,EAAE;AACvB,SAAK,YAAY,MAAM;AACvB,UAAM,KAAK,OAAO,MAAM,EAAE;AAC1B,UAAM,UAAU,MAAM,QAAQ,CAAC;AAC/B,QAAI,MAAM,SAAS,aAAa,SAAS;AACvC,YAAM,OAAO,UAAU,KAAK;AAC5B,UAAI,KAAM,QAAO,CAAC,EAAE,GAAG,UAAU,IAAI,MAAM,KAAK,QAAQ,KAAK,OAAO,KAAK,KAAK,KAAK,EAAE,EAAE,CAAC;AACxF,aAAO,CAAC,EAAE,GAAG,QAAQ,IAAI,MAAM,cAAc,OAAO,QAAQ,OAAO,CAAC,EAAE,MAAM,UAAU,CAAC;AAAA,IACzF;AACA,QAAI,MAAM,SAAS,kBAAkB,QAAS,QAAO,KAAK,WAAW,SAAS,KAAK;AACnF,QAAI,MAAM,SAAS,oBAAoB;AACrC,aAAO;AAAA,QACL;AAAA,UACE,GAAG;AAAA,UACH;AAAA,UACA,MAAM,QAAQ,cAAc;AAAA,UAC5B,IAAI,CAAC,QAAQ;AAAA,UACb,SAAS,cAAc,OAAO;AAAA,QAChC;AAAA,MACF;AACF,QAAI,MAAM,SAAS,gBAAiB,QAAO,CAAC,EAAE,GAAG,UAAU,IAAI,MAAM,YAAY,CAAC;AAClF,QAAI,MAAM,SAAS,gBAAiB,QAAO,CAAC,EAAE,GAAG,UAAU,IAAI,MAAM,UAAU,CAAC;AAChF,WAAO,CAAC;AAAA,EACV;AAAA,EAEA,OAAO,QAAkC;AACvC,QAAI,CAAC,KAAK,QAAQ,OAAQ,QAAO,CAAC;AAClC,SAAK,UAAU,CAAC;AAChB,SAAK,SAAS;AACd,WAAO,CAAC,EAAE,GAAG,OAAO,OAAO,OAAO,OAAO,CAAC;AAAA,EAC5C;AAAA,EAEA,SAAS,QAAyE;AAChF,QAAI,CAAC,KAAK,QAAQ,SAAS,OAAO,EAAE,KAAK,CAAC,UAAU,QAAQ,EAAE,SAAS,OAAO,MAAM;AAClF,aAAO,CAAC;AACV,QAAI,OAAO,WAAW,aAAc,QAAO,KAAK,OAAO,KAAK,MAAM;AAClE,QAAI,OAAO,WAAW,UAAW,QAAO,KAAK,OAAO,SAAS;AAC7D,SAAK,UAAU,KAAK,OAAO,OAAO,UAAU,OAAO,GAAG,GAAI;AAC1D,WAAO,KAAK,OAAO,OAAO;AAAA,EAC5B;AAAA,EAEA,OAAe;AACb,WAAO,KAAK,IAAI,GAAG,GAAG,KAAK,KAAK;AAAA,EAClC;AAAA,EAEA,MAAM,OAAkC;AACtC,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK,aAAa;AAChB,cAAM,QAAQ,KAAK,OAAO,KAAK,MAAM;AACrC,aAAK,SAAS;AACd,aAAK,QAAQ;AACb,eAAO,CAAC,GAAG,OAAO,EAAE,GAAG,OAAO,OAAO,QAAQ,CAAC;AAAA,MAChD;AAAA,MACA,KAAK;AACH,aAAK,UAAU,MAAM;AACrB,eAAO,CAAC;AAAA,MACV,KAAK;AACH,eAAO,KAAK,SAAS,MAAM,MAAM;AAAA,MACnC,KAAK;AACH,YAAK,MAAM,QAAyB,SAAS;AAC3C,eAAK,WAAW,KAAK,KAAK,MAAM,OAAuB;AACzD,eAAO,CAAC;AAAA,MACV,KAAK;AACH,eAAO,MAAM,QAAQ,QAAQ,CAAC,WAAW;AACvC,cAAI,OAAO,SAAS,gBAAgB,OAAO,SAAS,iBAAkB,QAAO,CAAC;AAC9E,gBAAM,KAAK,GAAG,KAAK,QAAQ,IAAI,OAAO,YAAY;AAClD,gBAAM,IAAI,OAAO,SAAS,eAAe,SAAS;AAClD,gBAAM,OAAO,KAAK,SAAS,IAAI,EAAE,KAAK;AACtC,cAAI,MAAM,cAAc,CAAC,KAAK,UAAW,QAAO,CAAC;AACjD,eAAK,SAAS,IAAI,IAAI,OAAO,OAAO,MAAM,MAAM;AAChD,iBAAO,CAAC,EAAE,GAAG,IAAI,OAAO,OAAO,MAAM,CAAC;AAAA,QACxC,CAAC;AAAA,MACH,KAAK;AACH,eAAO,KAAK,MAAM,MAAM,KAAK;AAAA,MAC/B,KAAK;AACH,eAAO,MAAM,QACT,KAAK,MAAM,MAAM,KAAK,IACtB;AAAA,UACE;AAAA,YACE,GAAG;AAAA,YACH,IAAI,IAAI,MAAM,UAAU;AAAA,YACxB,MAAM,MAAM;AAAA,YACZ,IAAI;AAAA,YACJ,SAAS;AAAA,UACX;AAAA,QACF;AAAA,MACN,KAAK;AACH,eAAO;AAAA,UACL;AAAA,YACE,GAAG;AAAA,YACH,IAAI,SAAS,MAAM,EAAE;AAAA,YACrB,MAAM,KAAK,qBAAqB,MAAM,OAAO,MAAM,MAAM,YAAY,EAAE;AAAA,UACzE;AAAA,QACF;AAAA,MACF,KAAK;AACH,eAAO,CAAC,EAAE,GAAG,UAAU,IAAI,cAAc,MAAM,MAAM,IAAI,MAAM,aAAa,CAAC;AAAA,MAC/E,KAAK;AACH,eAAO,CAAC,EAAE,GAAG,SAAS,IAAI,QAAQ,MAAM,MAAM,IAAI,SAAS,KAAK,MAAM,SAAS,GAAI,EAAE,CAAC;AAAA,MACxF;AACE,eAAO,CAAC;AAAA,IACZ;AAAA,EACF;AACF;AAEO,SAAS,SACd,SACA,SACA,UACe;AACf,QAAM,SAAS,IAAI,OAAO,QAAQ;AAClC,QAAM,MAAqB,CAAC;AAC5B,aAAW,SAAS,QAAS,KAAI,KAAK,GAAG,OAAO,MAAM,KAAK,CAAC;AAC5D,MAAI,KAAK,GAAG,OAAO,QAAQ,OAAO,CAAC;AACnC,SAAO;AACT;AAEO,SAAS,KAAK,OAAwC;AAC3D,SAAO,QAAQ,QAAQ,MAAM,KAAK;AACpC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/services.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/services.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n type Context,\n defineService,\n type JsonValue,\n type ReplicatedState,\n} from '@earendil-works/chord';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport type { ChangesView } from './changes/git.ts';\nimport type { FrozenCone } from './freezer/index.ts';\nimport type { MemoryEntry, MemoryScope, MemoryTag } from './memory/format.ts';\nimport type { AgentRemote } from './remote/host.ts';\nimport type { Sprinkle } from './sprinkles/kind.ts';\n\nexport type SendMode = 'steer' | 'followUp' | 'reject';\n\nexport interface SendRequest {\n text: string;\n whenBusy: SendMode;\n requestId: string | null;\n agentId?: string | null;\n}\n\nexport interface OperationError {\n code: string;\n message: string;\n}\n\nexport type SendResponse =\n | { accepted: true; submissionId: string; error: null }\n | { accepted: false; submissionId: null; error: OperationError };\n\nexport type PromptResult =\n | { status: 'done'; text: string; reason: null }\n | { status: 'unanswered'; text: null; reason: string };\n\nexport interface AgentControl {\n send(request: SendRequest, context: Context): Promise<SendResponse>;\n wait(submissionId: string, context: Context): Promise<PromptResult>;\n withdraw(\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n abort(context: Context): Promise<void>;\n compact(instructions: string | null, context: Context): Promise<SendResponse>;\n compactAgent(\n agentId: string,\n instructions: string | null,\n context: Context\n ): Promise<SendResponse>;\n reset(handoff: string | null, context: Context): Promise<void>;\n configure(change: AgentSettingsChange, context: Context): Promise<void>;\n rewind(messageId: string | null, context: Context): Promise<Rewound>;\n rewindAgent(agentId: string, messageId: string | null, context: Context): Promise<Rewound>;\n resolveLick(\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved>;\n resolveAgentLick(\n agentId: string,\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved>;\n webhook(\n name: string,\n delivery: WebhookRequest,\n context: Context\n ): Promise<{ delivered: boolean }>;\n stopAgent(agentId: string, context: Context): Promise<void>;\n selectCone(agentId: string, context: Context): Promise<void>;\n createCone(name: string, context: Context): Promise<Created>;\n createScoop(parentId: string, name: string, context: Context): Promise<Created>;\n drop(agentId: string, context: Context): Promise<Created>;\n unqueue(\n agentId: string | null,\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n sprinkleSend(\n sprinkleId: string,\n payload: { action: string; data: JsonValue | null; target: string | null },\n context: Context\n ): Promise<{ delivered: boolean }>;\n sprinkleCall(\n sprinkleId: string,\n method: string,\n args: JsonValue[],\n context: Context\n ): Promise<JsonValue>;\n memorySave(draft: MemoryDraft, context: Context): Promise<MemoryEntry>;\n memoryRemove(id: string, context: Context): Promise<{ removed: boolean }>;\n freeze(agentId: string, context: Context): Promise<Created>;\n newChat(agentId: string, context: Context): Promise<Created>;\n thaw(frozenId: string, context: Context): Promise<Created>;\n discard(frozenId: string, context: Context): Promise<Created>;\n changesOpen(context: Context): Promise<void>;\n changeAccept(path: string, context: Context): Promise<Created>;\n changeRevert(path: string, context: Context): Promise<Created>;\n}\n\nexport interface MemoryDraft {\n id: string | null;\n scope: string;\n section: string;\n title: string;\n body: string;\n tag: MemoryTag | null;\n}\n\nexport type Created = { id: string; error: null } | { id: null; error: string };\n\nexport interface AgentSummary {\n id: string;\n name: string;\n kind: 'cone' | 'scoop';\n parentId: string | null;\n role: string | null;\n}\n\nexport interface AgentsSummary {\n active: string;\n agents: AgentSummary[];\n}\n\nexport type LickResolved =\n | { done: true; text: string; error: null }\n | { done: false; text: null; error: string };\n\nexport interface WebhookRequest {\n id: string | null;\n headers: Record<string, string>;\n body: string;\n}\n\nexport type Rewound =\n | { done: true; text: string; reason: null }\n | { done: false; text: null; reason: 'busy' | 'no-turn' };\n\nexport interface AgentSettingsChange {\n model: { provider: string; modelId: string } | null;\n thinkingLevel: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null;\n agentId?: string | null;\n}\n\nexport const AgentControl = defineService<AgentControl>('slicc.agent.control');\n\nexport type Delivered = 'run' | 'steer' | 'follow-up';\n\nexport interface AgentTranscript {\n readonly state: ReplicatedState<ConversationView>;\n readonly deliveries: ReplicatedState<Record<string, Delivered>>;\n readonly agents: ReplicatedState<AgentsSummary>;\n readonly views: ReplicatedState<Record<string, ConversationView>>;\n readonly commands: ReplicatedState<Command[]>;\n readonly sprinkles: ReplicatedState<Sprinkle[]>;\n readonly memories: ReplicatedState<MemoryEntry[]>;\n readonly memoryScopes: ReplicatedState<MemoryScope[]>;\n readonly frozen: ReplicatedState<FrozenCone[]>;\n readonly changes: ReplicatedState<ChangesView>;\n}\n\nexport interface Command {\n name: string;\n description: string;\n kind: 'prompt' | 'skill';\n}\n\nexport const AgentTranscript = defineService<AgentTranscript>('slicc.agent.transcript');\n\nexport interface AgentSessions {\n attach(sessionId: string, context: Context): Promise<void>;\n detach(context: Context): Promise<void>;\n}\n\nexport const AgentSessions = defineService<AgentSessions>('slicc.agent.sessions');\n\nexport const AgentRemoteService = defineService<AgentRemote>('slicc.agent.remote');\n\nexport const AGENT_SESSION = 'agent';\n\nexport interface ModelChoice {\n id: string;\n label: string;\n provider: string;\n kind: 'chat' | 'classifier';\n reasoning: boolean;\n images?: boolean;\n contextWindow: number;\n}\n\nexport interface AccountState {\n id: string;\n provider: string;\n identity: string;\n status: 'connected' | 'disconnected';\n auth: 'api-key' | 'oauth';\n needs: 'cors-free-transport' | null;\n}\n\nexport interface BudgetState {\n provider: string;\n percent: number;\n window: 'weekly';\n resets: string;\n}\n\nexport interface SignIn {\n clientId: string;\n scopes: string;\n imsEnvironment: string;\n}\n\nexport interface SettingsState {\n models: ModelChoice[];\n accounts: AccountState[];\n budget?: BudgetState | null;\n}\n\nexport interface AgentSettings {\n readonly state: ReplicatedState<SettingsState>;\n connect(\n providerId: string,\n secret: string,\n region: string | null,\n context: Context\n ): Promise<void>;\n disconnect(providerId: string, context: Context): Promise<void>;\n signIn(providerId: string, context: Context): Promise<SignIn | null>;\n}\n\nexport const AgentSettings = defineService<AgentSettings>('slicc.agent.settings');\n"],
|
|
5
|
-
"mappings": "AAAA;AAAA,EAEE;AAAA,OAGK;AA4IA,MAAM,eAAe,cAA4B,qBAAqB;AAuBtE,MAAM,kBAAkB,cAA+B,wBAAwB;AAO/E,MAAM,gBAAgB,cAA6B,sBAAsB;AAEzE,MAAM,qBAAqB,cAA2B,oBAAoB;AAE1E,MAAM,gBAAgB;
|
|
4
|
+
"sourcesContent": ["import {\n type Context,\n defineService,\n type JsonValue,\n type ReplicatedState,\n} from '@earendil-works/chord';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport type { ChangesView } from './changes/git.ts';\nimport type { FrozenCone } from './freezer/index.ts';\nimport type { MemoryEntry, MemoryScope, MemoryTag } from './memory/format.ts';\nimport type { AgentRemote } from './remote/host.ts';\nimport type { Sprinkle } from './sprinkles/kind.ts';\n\nexport type SendMode = 'steer' | 'followUp' | 'reject';\n\nexport interface SendRequest {\n text: string;\n whenBusy: SendMode;\n requestId: string | null;\n agentId?: string | null;\n}\n\nexport interface OperationError {\n code: string;\n message: string;\n}\n\nexport type SendResponse =\n | { accepted: true; submissionId: string; error: null }\n | { accepted: false; submissionId: null; error: OperationError };\n\nexport type PromptResult =\n | { status: 'done'; text: string; reason: null }\n | { status: 'unanswered'; text: null; reason: string };\n\nexport interface AgentControl {\n send(request: SendRequest, context: Context): Promise<SendResponse>;\n wait(submissionId: string, context: Context): Promise<PromptResult>;\n withdraw(\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n abort(context: Context): Promise<void>;\n compact(instructions: string | null, context: Context): Promise<SendResponse>;\n compactAgent(\n agentId: string,\n instructions: string | null,\n context: Context\n ): Promise<SendResponse>;\n reset(handoff: string | null, context: Context): Promise<void>;\n configure(change: AgentSettingsChange, context: Context): Promise<void>;\n rewind(messageId: string | null, context: Context): Promise<Rewound>;\n rewindAgent(agentId: string, messageId: string | null, context: Context): Promise<Rewound>;\n resolveLick(\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved>;\n resolveAgentLick(\n agentId: string,\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved>;\n webhook(\n name: string,\n delivery: WebhookRequest,\n context: Context\n ): Promise<{ delivered: boolean }>;\n stopAgent(agentId: string, context: Context): Promise<void>;\n selectCone(agentId: string, context: Context): Promise<void>;\n createCone(name: string, context: Context): Promise<Created>;\n createScoop(parentId: string, name: string, context: Context): Promise<Created>;\n drop(agentId: string, context: Context): Promise<Created>;\n unqueue(\n agentId: string | null,\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n sprinkleSend(\n sprinkleId: string,\n payload: { action: string; data: JsonValue | null; target: string | null },\n context: Context\n ): Promise<{ delivered: boolean }>;\n sprinkleCall(\n sprinkleId: string,\n method: string,\n args: JsonValue[],\n context: Context\n ): Promise<JsonValue>;\n memorySave(draft: MemoryDraft, context: Context): Promise<MemoryEntry>;\n memoryRemove(id: string, context: Context): Promise<{ removed: boolean }>;\n freeze(agentId: string, context: Context): Promise<Created>;\n newChat(agentId: string, context: Context): Promise<Created>;\n thaw(frozenId: string, context: Context): Promise<Created>;\n discard(frozenId: string, context: Context): Promise<Created>;\n changesOpen(context: Context): Promise<void>;\n changeAccept(path: string, context: Context): Promise<Created>;\n changeRevert(path: string, context: Context): Promise<Created>;\n}\n\nexport interface MemoryDraft {\n id: string | null;\n scope: string;\n section: string;\n title: string;\n body: string;\n tag: MemoryTag | null;\n}\n\nexport type Created = { id: string; error: null } | { id: null; error: string };\n\nexport interface AgentSummary {\n id: string;\n name: string;\n kind: 'cone' | 'scoop';\n parentId: string | null;\n role: string | null;\n}\n\nexport interface AgentsSummary {\n active: string;\n agents: AgentSummary[];\n}\n\nexport type LickResolved =\n | { done: true; text: string; error: null }\n | { done: false; text: null; error: string };\n\nexport interface WebhookRequest {\n id: string | null;\n headers: Record<string, string>;\n body: string;\n}\n\nexport type Rewound =\n | { done: true; text: string; reason: null }\n | { done: false; text: null; reason: 'busy' | 'no-turn' };\n\nexport interface AgentSettingsChange {\n model: { provider: string; modelId: string } | null;\n thinkingLevel: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null;\n agentId?: string | null;\n}\n\nexport const AgentControl = defineService<AgentControl>('slicc.agent.control');\n\nexport type Delivered = 'run' | 'steer' | 'follow-up';\n\nexport interface AgentTranscript {\n readonly state: ReplicatedState<ConversationView>;\n readonly deliveries: ReplicatedState<Record<string, Delivered>>;\n readonly agents: ReplicatedState<AgentsSummary>;\n readonly views: ReplicatedState<Record<string, ConversationView>>;\n readonly commands: ReplicatedState<Command[]>;\n readonly sprinkles: ReplicatedState<Sprinkle[]>;\n readonly memories: ReplicatedState<MemoryEntry[]>;\n readonly memoryScopes: ReplicatedState<MemoryScope[]>;\n readonly frozen: ReplicatedState<FrozenCone[]>;\n readonly changes: ReplicatedState<ChangesView>;\n}\n\nexport interface Command {\n name: string;\n description: string;\n kind: 'prompt' | 'skill';\n}\n\nexport const AgentTranscript = defineService<AgentTranscript>('slicc.agent.transcript');\n\nexport interface AgentSessions {\n attach(sessionId: string, context: Context): Promise<void>;\n detach(context: Context): Promise<void>;\n}\n\nexport const AgentSessions = defineService<AgentSessions>('slicc.agent.sessions');\n\nexport const AgentRemoteService = defineService<AgentRemote>('slicc.agent.remote');\n\nexport const AGENT_SESSION = 'agent';\n\nexport interface ModelChoice {\n id: string;\n label: string;\n provider: string;\n kind: 'chat' | 'classifier';\n reasoning: boolean;\n images?: boolean;\n contextWindow: number;\n}\n\nexport interface AccountState {\n id: string;\n provider: string;\n identity: string;\n status: 'connected' | 'disconnected' | 'expired';\n auth: 'api-key' | 'oauth';\n needs: 'cors-free-transport' | null;\n group?: 'providers' | 'mcp';\n secret?: 'api-key' | 'token';\n}\n\nexport interface BudgetState {\n provider: string;\n percent: number;\n window: 'weekly';\n resets: string;\n}\n\nexport interface SignIn {\n clientId: string;\n scopes: string;\n imsEnvironment: string;\n}\n\nexport interface SettingsState {\n models: ModelChoice[];\n accounts: AccountState[];\n budget?: BudgetState | null;\n}\n\nexport interface AgentSettings {\n readonly state: ReplicatedState<SettingsState>;\n connect(\n providerId: string,\n secret: string,\n region: string | null,\n context: Context\n ): Promise<void>;\n disconnect(providerId: string, context: Context): Promise<void>;\n signIn(providerId: string, context: Context): Promise<SignIn | null>;\n}\n\nexport const AgentSettings = defineService<AgentSettings>('slicc.agent.settings');\n"],
|
|
5
|
+
"mappings": "AAAA;AAAA,EAEE;AAAA,OAGK;AA4IA,MAAM,eAAe,cAA4B,qBAAqB;AAuBtE,MAAM,kBAAkB,cAA+B,wBAAwB;AAO/E,MAAM,gBAAgB,cAA6B,sBAAsB;AAEzE,MAAM,qBAAqB,cAA2B,oBAAoB;AAE1E,MAAM,gBAAgB;AAsDtB,MAAM,gBAAgB,cAA6B,sBAAsB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/settings.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
adobeProvider,
|
|
10
10
|
adobeUsage
|
|
11
11
|
} from "./adobe.js";
|
|
12
|
+
import { MCP_ACCOUNT } from "./mcp/label.js";
|
|
12
13
|
const BEDROCK = "amazon-bedrock";
|
|
13
14
|
const DEFAULT_MODEL = { provider: BEDROCK, modelId: "us.anthropic.claude-sonnet-5-5" };
|
|
14
15
|
const DEFAULT_REGIONS = { [BEDROCK]: "us-west-2" };
|
|
@@ -68,13 +69,15 @@ async function budget(credentials, usage) {
|
|
|
68
69
|
return found ? { provider: ADOBE, ...found } : null;
|
|
69
70
|
}
|
|
70
71
|
async function createAgentSettings(models, credentials, providers = sliccProviders(), options = {}) {
|
|
72
|
+
const { mcp } = options;
|
|
73
|
+
const routed = (providerId) => providerId.startsWith(MCP_ACCOUNT) ? mcp : void 0;
|
|
71
74
|
const endpoint = providers.find((provider) => provider.id === ADOBE)?.baseUrl ?? ADOBE_PROXY;
|
|
72
75
|
const usage = options.usage ?? ((token) => adobeUsage(token, { endpoint }));
|
|
73
76
|
const snapshot = async () => {
|
|
74
77
|
const stored = new Set((await credentials.list()).map((info) => info.providerId));
|
|
75
78
|
return {
|
|
76
79
|
models: choices(models, providers, stored),
|
|
77
|
-
accounts: accounts(stored, providers),
|
|
80
|
+
accounts: [...accounts(stored, providers), ...await mcp?.accounts() ?? []],
|
|
78
81
|
budget: await budget(credentials, usage)
|
|
79
82
|
};
|
|
80
83
|
};
|
|
@@ -96,9 +99,16 @@ async function createAgentSettings(models, credentials, providers = sliccProvide
|
|
|
96
99
|
const timer = setInterval(cycle, options.every ?? BUDGET_EVERY);
|
|
97
100
|
timer.unref?.();
|
|
98
101
|
}
|
|
102
|
+
mcp?.onChange(() => void refresh(BACKGROUND_CONTEXT).catch(() => void 0));
|
|
99
103
|
return {
|
|
100
104
|
state,
|
|
101
105
|
async connect(providerId, secret, region, context) {
|
|
106
|
+
const server = routed(providerId);
|
|
107
|
+
if (server) {
|
|
108
|
+
await server.connect(providerId, secret);
|
|
109
|
+
await refresh(context);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
102
112
|
await credentials.modify(providerId, async () => ({
|
|
103
113
|
type: "api_key",
|
|
104
114
|
key: secret,
|
|
@@ -116,7 +126,9 @@ async function createAgentSettings(models, credentials, providers = sliccProvide
|
|
|
116
126
|
return { clientId, scopes, imsEnvironment: imsEnvironment || "prod" };
|
|
117
127
|
},
|
|
118
128
|
async disconnect(providerId, context) {
|
|
119
|
-
|
|
129
|
+
const server = routed(providerId);
|
|
130
|
+
if (server) await server.disconnect(providerId);
|
|
131
|
+
else await credentials.delete(providerId);
|
|
120
132
|
await refresh(context);
|
|
121
133
|
}
|
|
122
134
|
};
|
package/dist/settings.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/settings.ts"],
|
|
4
|
-
"sourcesContent": ["import { type Context, replicatedState } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { CredentialStore, Provider } from '@earendil-works/pi-ai';\nimport { createModels, type MutableModels } from '@earendil-works/pi-ai/models';\nimport { amazonBedrockProvider } from '@earendil-works/pi-ai/providers/amazon-bedrock';\nimport {\n ADOBE,\n ADOBE_PROXY,\n adobeConfig,\n adobeProvider,\n adobeUsage,\n type Budget,\n} from './adobe.ts';\nimport type { AccountState, AgentSettings, ModelChoice, SettingsState } from './services.ts';\n\nexport const BEDROCK = 'amazon-bedrock';\nexport const DEFAULT_MODEL = { provider: BEDROCK, modelId: 'us.anthropic.claude-sonnet-5-5' };\nexport const DEFAULT_REGIONS: Readonly<Record<string, string>> = { [BEDROCK]: 'us-west-2' };\n\nconst corsFree = new Set([BEDROCK, ADOBE]);\nconst signIn = new Set([ADOBE]);\nconst BUDGET_EVERY = 5 * 60 * 1000;\n\nexport function sliccProviders(): Provider[] {\n return [amazonBedrockProvider() as Provider, adobeProvider()];\n}\n\nexport function withDefaultRegions(credentials: CredentialStore): CredentialStore {\n return {\n async read(providerId, options) {\n const credential = await credentials.read(providerId, options);\n const region = DEFAULT_REGIONS[providerId];\n if (credential?.type !== 'api_key' || !region || credential.env?.AWS_REGION) {\n return credential;\n }\n return { ...credential, env: { ...credential.env, AWS_REGION: region } };\n },\n list: (options) => credentials.list(options),\n modify: (providerId, fn, options) => credentials.modify(providerId, fn, options),\n delete: (providerId, options) => credentials.delete(providerId, options),\n };\n}\n\nexport function createSliccModels(\n credentials: CredentialStore,\n providers = sliccProviders()\n): MutableModels {\n const models = createModels({ credentials: withDefaultRegions(credentials) });\n for (const provider of providers) models.setProvider(provider);\n return models;\n}\n\nfunction choices(\n models: MutableModels,\n providers: Provider[],\n stored: ReadonlySet<string>\n): ModelChoice[] {\n return providers\n .filter((provider) => stored.has(provider.id))\n .flatMap((provider) =>\n models.getModels(provider.id).map((model) => ({\n id: `${provider.id}/${model.id}`,\n label: model.name,\n provider: provider.name ?? provider.id,\n kind: 'chat' as const,\n reasoning: Boolean(model.reasoning),\n images: model.input.includes('image'),\n contextWindow: model.contextWindow,\n }))\n );\n}\n\nfunction accounts(stored: ReadonlySet<string>, providers: Provider[]): AccountState[] {\n return providers.map((provider) => ({\n id: provider.id,\n provider: provider.name ?? provider.id,\n identity: stored.has(provider.id) ? (signIn.has(provider.id) ? 'Adobe ID' : 'API key') : '',\n status: stored.has(provider.id) ? 'connected' : 'disconnected',\n auth: signIn.has(provider.id) ? 'oauth' : 'api-key',\n needs: corsFree.has(provider.id) ? 'cors-free-transport' : null,\n }));\n}\n\nexport type UsageReader = (token: string) => Promise<Budget | null>;\n\nasync function budget(credentials: CredentialStore, usage: UsageReader) {\n const credential = await credentials.read(ADOBE);\n const key = credential?.type === 'api_key' ? credential.key : undefined;\n const found = key ? await usage(key).catch(() => null) : null;\n return found ? { provider: ADOBE, ...found } : null;\n}\n\nexport async function createAgentSettings(\n models: MutableModels,\n credentials: CredentialStore,\n providers = sliccProviders(),\n options: { usage?: UsageReader; every?: number } = {}\n): Promise<AgentSettings> {\n const endpoint = providers.find((provider) => provider.id === ADOBE)?.baseUrl ?? ADOBE_PROXY;\n const usage = options.usage ?? ((token: string) => adobeUsage(token, { endpoint }));\n const snapshot = async (): Promise<SettingsState> => {\n const stored = new Set((await credentials.list()).map((info) => info.providerId));\n return {\n models: choices(models, providers, stored),\n accounts: accounts(stored, providers),\n budget: await budget(credentials, usage),\n };\n };\n const state = replicatedState<SettingsState>(await snapshot());\n let latest = Promise.resolve();\n const refresh = (context: Context) => {\n const next = latest.then(async () => state.replace(context, await snapshot()));\n latest = next.catch(() => undefined);\n return next;\n };\n const signedIn = providers\n .filter((provider) => signIn.has(provider.id))\n .map((provider) => provider.id);\n const discover = (ids: string[]) =>\n models.refresh({ providers: ids }).then(\n () => undefined,\n () => undefined\n );\n if (signedIn.length) {\n const cycle = () =>\n void discover(signedIn)\n .then(() => refresh(BACKGROUND_CONTEXT))\n .catch(() => undefined);\n cycle();\n const timer: unknown = setInterval(cycle, options.every ?? BUDGET_EVERY);\n (timer as { unref?: () => void }).unref?.();\n }\n return {\n state,\n async connect(providerId, secret, region, context) {\n await credentials.modify(providerId, async () => ({\n type: 'api_key',\n key: secret,\n ...(region ? { env: { AWS_REGION: region } } : {}),\n }));\n if (signIn.has(providerId)) await discover([providerId]);\n await refresh(context);\n },\n async signIn(providerId) {\n if (providerId !== ADOBE) return null;\n const { clientId, scopes, imsEnvironment } = await adobeConfig(endpoint, (input, init) =>\n globalThis.fetch(input, init)\n );\n return { clientId, scopes, imsEnvironment: imsEnvironment || 'prod' };\n },\n async disconnect(providerId, context) {\n await credentials.delete(providerId);\n await refresh(context);\n },\n };\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAuB,uBAAuB;AAC9C,SAAS,0BAA0B;AAEnC,SAAS,oBAAwC;AACjD,SAAS,6BAA6B;AACtC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;
|
|
4
|
+
"sourcesContent": ["import { type Context, replicatedState } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { CredentialStore, Provider } from '@earendil-works/pi-ai';\nimport { createModels, type MutableModels } from '@earendil-works/pi-ai/models';\nimport { amazonBedrockProvider } from '@earendil-works/pi-ai/providers/amazon-bedrock';\nimport {\n ADOBE,\n ADOBE_PROXY,\n adobeConfig,\n adobeProvider,\n adobeUsage,\n type Budget,\n} from './adobe.ts';\nimport type { McpAccounts } from './mcp/index.ts';\nimport { MCP_ACCOUNT } from './mcp/label.ts';\nimport type { AccountState, AgentSettings, ModelChoice, SettingsState } from './services.ts';\n\nexport const BEDROCK = 'amazon-bedrock';\nexport const DEFAULT_MODEL = { provider: BEDROCK, modelId: 'us.anthropic.claude-sonnet-5-5' };\nexport const DEFAULT_REGIONS: Readonly<Record<string, string>> = { [BEDROCK]: 'us-west-2' };\n\nconst corsFree = new Set([BEDROCK, ADOBE]);\nconst signIn = new Set([ADOBE]);\nconst BUDGET_EVERY = 5 * 60 * 1000;\n\nexport function sliccProviders(): Provider[] {\n return [amazonBedrockProvider() as Provider, adobeProvider()];\n}\n\nexport function withDefaultRegions(credentials: CredentialStore): CredentialStore {\n return {\n async read(providerId, options) {\n const credential = await credentials.read(providerId, options);\n const region = DEFAULT_REGIONS[providerId];\n if (credential?.type !== 'api_key' || !region || credential.env?.AWS_REGION) {\n return credential;\n }\n return { ...credential, env: { ...credential.env, AWS_REGION: region } };\n },\n list: (options) => credentials.list(options),\n modify: (providerId, fn, options) => credentials.modify(providerId, fn, options),\n delete: (providerId, options) => credentials.delete(providerId, options),\n };\n}\n\nexport function createSliccModels(\n credentials: CredentialStore,\n providers = sliccProviders()\n): MutableModels {\n const models = createModels({ credentials: withDefaultRegions(credentials) });\n for (const provider of providers) models.setProvider(provider);\n return models;\n}\n\nfunction choices(\n models: MutableModels,\n providers: Provider[],\n stored: ReadonlySet<string>\n): ModelChoice[] {\n return providers\n .filter((provider) => stored.has(provider.id))\n .flatMap((provider) =>\n models.getModels(provider.id).map((model) => ({\n id: `${provider.id}/${model.id}`,\n label: model.name,\n provider: provider.name ?? provider.id,\n kind: 'chat' as const,\n reasoning: Boolean(model.reasoning),\n images: model.input.includes('image'),\n contextWindow: model.contextWindow,\n }))\n );\n}\n\nfunction accounts(stored: ReadonlySet<string>, providers: Provider[]): AccountState[] {\n return providers.map((provider) => ({\n id: provider.id,\n provider: provider.name ?? provider.id,\n identity: stored.has(provider.id) ? (signIn.has(provider.id) ? 'Adobe ID' : 'API key') : '',\n status: stored.has(provider.id) ? 'connected' : 'disconnected',\n auth: signIn.has(provider.id) ? 'oauth' : 'api-key',\n needs: corsFree.has(provider.id) ? 'cors-free-transport' : null,\n }));\n}\n\nexport type UsageReader = (token: string) => Promise<Budget | null>;\n\nasync function budget(credentials: CredentialStore, usage: UsageReader) {\n const credential = await credentials.read(ADOBE);\n const key = credential?.type === 'api_key' ? credential.key : undefined;\n const found = key ? await usage(key).catch(() => null) : null;\n return found ? { provider: ADOBE, ...found } : null;\n}\n\nexport async function createAgentSettings(\n models: MutableModels,\n credentials: CredentialStore,\n providers = sliccProviders(),\n options: { usage?: UsageReader; every?: number; mcp?: McpAccounts } = {}\n): Promise<AgentSettings> {\n const { mcp } = options;\n const routed = (providerId: string) => (providerId.startsWith(MCP_ACCOUNT) ? mcp : undefined);\n const endpoint = providers.find((provider) => provider.id === ADOBE)?.baseUrl ?? ADOBE_PROXY;\n const usage = options.usage ?? ((token: string) => adobeUsage(token, { endpoint }));\n const snapshot = async (): Promise<SettingsState> => {\n const stored = new Set((await credentials.list()).map((info) => info.providerId));\n return {\n models: choices(models, providers, stored),\n accounts: [...accounts(stored, providers), ...((await mcp?.accounts()) ?? [])],\n budget: await budget(credentials, usage),\n };\n };\n const state = replicatedState<SettingsState>(await snapshot());\n let latest = Promise.resolve();\n const refresh = (context: Context) => {\n const next = latest.then(async () => state.replace(context, await snapshot()));\n latest = next.catch(() => undefined);\n return next;\n };\n const signedIn = providers\n .filter((provider) => signIn.has(provider.id))\n .map((provider) => provider.id);\n const discover = (ids: string[]) =>\n models.refresh({ providers: ids }).then(\n () => undefined,\n () => undefined\n );\n if (signedIn.length) {\n const cycle = () =>\n void discover(signedIn)\n .then(() => refresh(BACKGROUND_CONTEXT))\n .catch(() => undefined);\n cycle();\n const timer: unknown = setInterval(cycle, options.every ?? BUDGET_EVERY);\n (timer as { unref?: () => void }).unref?.();\n }\n mcp?.onChange(() => void refresh(BACKGROUND_CONTEXT).catch(() => undefined));\n return {\n state,\n async connect(providerId, secret, region, context) {\n const server = routed(providerId);\n if (server) {\n await server.connect(providerId, secret);\n await refresh(context);\n return;\n }\n await credentials.modify(providerId, async () => ({\n type: 'api_key',\n key: secret,\n ...(region ? { env: { AWS_REGION: region } } : {}),\n }));\n if (signIn.has(providerId)) await discover([providerId]);\n await refresh(context);\n },\n async signIn(providerId) {\n if (providerId !== ADOBE) return null;\n const { clientId, scopes, imsEnvironment } = await adobeConfig(endpoint, (input, init) =>\n globalThis.fetch(input, init)\n );\n return { clientId, scopes, imsEnvironment: imsEnvironment || 'prod' };\n },\n async disconnect(providerId, context) {\n const server = routed(providerId);\n if (server) await server.disconnect(providerId);\n else await credentials.delete(providerId);\n await refresh(context);\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAuB,uBAAuB;AAC9C,SAAS,0BAA0B;AAEnC,SAAS,oBAAwC;AACjD,SAAS,6BAA6B;AACtC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAEP,SAAS,mBAAmB;AAGrB,MAAM,UAAU;AAChB,MAAM,gBAAgB,EAAE,UAAU,SAAS,SAAS,iCAAiC;AACrF,MAAM,kBAAoD,EAAE,CAAC,OAAO,GAAG,YAAY;AAE1F,MAAM,WAAW,oBAAI,IAAI,CAAC,SAAS,KAAK,CAAC;AACzC,MAAM,SAAS,oBAAI,IAAI,CAAC,KAAK,CAAC;AAC9B,MAAM,eAAe,IAAI,KAAK;AAEvB,SAAS,iBAA6B;AAC3C,SAAO,CAAC,sBAAsB,GAAe,cAAc,CAAC;AAC9D;AAEO,SAAS,mBAAmB,aAA+C;AAChF,SAAO;AAAA,IACL,MAAM,KAAK,YAAY,SAAS;AAC9B,YAAM,aAAa,MAAM,YAAY,KAAK,YAAY,OAAO;AAC7D,YAAM,SAAS,gBAAgB,UAAU;AACzC,UAAI,YAAY,SAAS,aAAa,CAAC,UAAU,WAAW,KAAK,YAAY;AAC3E,eAAO;AAAA,MACT;AACA,aAAO,EAAE,GAAG,YAAY,KAAK,EAAE,GAAG,WAAW,KAAK,YAAY,OAAO,EAAE;AAAA,IACzE;AAAA,IACA,MAAM,CAAC,YAAY,YAAY,KAAK,OAAO;AAAA,IAC3C,QAAQ,CAAC,YAAY,IAAI,YAAY,YAAY,OAAO,YAAY,IAAI,OAAO;AAAA,IAC/E,QAAQ,CAAC,YAAY,YAAY,YAAY,OAAO,YAAY,OAAO;AAAA,EACzE;AACF;AAEO,SAAS,kBACd,aACA,YAAY,eAAe,GACZ;AACf,QAAM,SAAS,aAAa,EAAE,aAAa,mBAAmB,WAAW,EAAE,CAAC;AAC5E,aAAW,YAAY,UAAW,QAAO,YAAY,QAAQ;AAC7D,SAAO;AACT;AAEA,SAAS,QACP,QACA,WACA,QACe;AACf,SAAO,UACJ,OAAO,CAAC,aAAa,OAAO,IAAI,SAAS,EAAE,CAAC,EAC5C;AAAA,IAAQ,CAAC,aACR,OAAO,UAAU,SAAS,EAAE,EAAE,IAAI,CAAC,WAAW;AAAA,MAC5C,IAAI,GAAG,SAAS,EAAE,IAAI,MAAM,EAAE;AAAA,MAC9B,OAAO,MAAM;AAAA,MACb,UAAU,SAAS,QAAQ,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,WAAW,QAAQ,MAAM,SAAS;AAAA,MAClC,QAAQ,MAAM,MAAM,SAAS,OAAO;AAAA,MACpC,eAAe,MAAM;AAAA,IACvB,EAAE;AAAA,EACJ;AACJ;AAEA,SAAS,SAAS,QAA6B,WAAuC;AACpF,SAAO,UAAU,IAAI,CAAC,cAAc;AAAA,IAClC,IAAI,SAAS;AAAA,IACb,UAAU,SAAS,QAAQ,SAAS;AAAA,IACpC,UAAU,OAAO,IAAI,SAAS,EAAE,IAAK,OAAO,IAAI,SAAS,EAAE,IAAI,aAAa,YAAa;AAAA,IACzF,QAAQ,OAAO,IAAI,SAAS,EAAE,IAAI,cAAc;AAAA,IAChD,MAAM,OAAO,IAAI,SAAS,EAAE,IAAI,UAAU;AAAA,IAC1C,OAAO,SAAS,IAAI,SAAS,EAAE,IAAI,wBAAwB;AAAA,EAC7D,EAAE;AACJ;AAIA,eAAe,OAAO,aAA8B,OAAoB;AACtE,QAAM,aAAa,MAAM,YAAY,KAAK,KAAK;AAC/C,QAAM,MAAM,YAAY,SAAS,YAAY,WAAW,MAAM;AAC9D,QAAM,QAAQ,MAAM,MAAM,MAAM,GAAG,EAAE,MAAM,MAAM,IAAI,IAAI;AACzD,SAAO,QAAQ,EAAE,UAAU,OAAO,GAAG,MAAM,IAAI;AACjD;AAEA,eAAsB,oBACpB,QACA,aACA,YAAY,eAAe,GAC3B,UAAsE,CAAC,GAC/C;AACxB,QAAM,EAAE,IAAI,IAAI;AAChB,QAAM,SAAS,CAAC,eAAwB,WAAW,WAAW,WAAW,IAAI,MAAM;AACnF,QAAM,WAAW,UAAU,KAAK,CAAC,aAAa,SAAS,OAAO,KAAK,GAAG,WAAW;AACjF,QAAM,QAAQ,QAAQ,UAAU,CAAC,UAAkB,WAAW,OAAO,EAAE,SAAS,CAAC;AACjF,QAAM,WAAW,YAAoC;AACnD,UAAM,SAAS,IAAI,KAAK,MAAM,YAAY,KAAK,GAAG,IAAI,CAAC,SAAS,KAAK,UAAU,CAAC;AAChF,WAAO;AAAA,MACL,QAAQ,QAAQ,QAAQ,WAAW,MAAM;AAAA,MACzC,UAAU,CAAC,GAAG,SAAS,QAAQ,SAAS,GAAG,GAAK,MAAM,KAAK,SAAS,KAAM,CAAC,CAAE;AAAA,MAC7E,QAAQ,MAAM,OAAO,aAAa,KAAK;AAAA,IACzC;AAAA,EACF;AACA,QAAM,QAAQ,gBAA+B,MAAM,SAAS,CAAC;AAC7D,MAAI,SAAS,QAAQ,QAAQ;AAC7B,QAAM,UAAU,CAAC,YAAqB;AACpC,UAAM,OAAO,OAAO,KAAK,YAAY,MAAM,QAAQ,SAAS,MAAM,SAAS,CAAC,CAAC;AAC7E,aAAS,KAAK,MAAM,MAAM,MAAS;AACnC,WAAO;AAAA,EACT;AACA,QAAM,WAAW,UACd,OAAO,CAAC,aAAa,OAAO,IAAI,SAAS,EAAE,CAAC,EAC5C,IAAI,CAAC,aAAa,SAAS,EAAE;AAChC,QAAM,WAAW,CAAC,QAChB,OAAO,QAAQ,EAAE,WAAW,IAAI,CAAC,EAAE;AAAA,IACjC,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACF,MAAI,SAAS,QAAQ;AACnB,UAAM,QAAQ,MACZ,KAAK,SAAS,QAAQ,EACnB,KAAK,MAAM,QAAQ,kBAAkB,CAAC,EACtC,MAAM,MAAM,MAAS;AAC1B,UAAM;AACN,UAAM,QAAiB,YAAY,OAAO,QAAQ,SAAS,YAAY;AACvE,IAAC,MAAiC,QAAQ;AAAA,EAC5C;AACA,OAAK,SAAS,MAAM,KAAK,QAAQ,kBAAkB,EAAE,MAAM,MAAM,MAAS,CAAC;AAC3E,SAAO;AAAA,IACL;AAAA,IACA,MAAM,QAAQ,YAAY,QAAQ,QAAQ,SAAS;AACjD,YAAM,SAAS,OAAO,UAAU;AAChC,UAAI,QAAQ;AACV,cAAM,OAAO,QAAQ,YAAY,MAAM;AACvC,cAAM,QAAQ,OAAO;AACrB;AAAA,MACF;AACA,YAAM,YAAY,OAAO,YAAY,aAAa;AAAA,QAChD,MAAM;AAAA,QACN,KAAK;AAAA,QACL,GAAI,SAAS,EAAE,KAAK,EAAE,YAAY,OAAO,EAAE,IAAI,CAAC;AAAA,MAClD,EAAE;AACF,UAAI,OAAO,IAAI,UAAU,EAAG,OAAM,SAAS,CAAC,UAAU,CAAC;AACvD,YAAM,QAAQ,OAAO;AAAA,IACvB;AAAA,IACA,MAAM,OAAO,YAAY;AACvB,UAAI,eAAe,MAAO,QAAO;AACjC,YAAM,EAAE,UAAU,QAAQ,eAAe,IAAI,MAAM;AAAA,QAAY;AAAA,QAAU,CAAC,OAAO,SAC/E,WAAW,MAAM,OAAO,IAAI;AAAA,MAC9B;AACA,aAAO,EAAE,UAAU,QAAQ,gBAAgB,kBAAkB,OAAO;AAAA,IACtE;AAAA,IACA,MAAM,WAAW,YAAY,SAAS;AACpC,YAAM,SAAS,OAAO,UAAU;AAChC,UAAI,OAAQ,OAAM,OAAO,WAAW,UAAU;AAAA,UACzC,OAAM,YAAY,OAAO,UAAU;AACxC,YAAM,QAAQ,OAAO;AAAA,IACvB;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { parseLick } from "../licks/lick.js";
|
|
2
2
|
import { entryLick, LICK_TOOLS, lickDecisions } from "../licks/state.js";
|
|
3
|
+
import { mcpLabel } from "../mcp/label.js";
|
|
3
4
|
import { FROM_KIND } from "../scoops/from.js";
|
|
4
5
|
import { SPRINKLE_KIND } from "../sprinkles/kind.js";
|
|
5
6
|
function textOf(content) {
|
|
@@ -74,7 +75,7 @@ function toolCall(block) {
|
|
|
74
75
|
return {
|
|
75
76
|
id: block.id ?? "",
|
|
76
77
|
name: block.name ?? "tool",
|
|
77
|
-
title: title(block.arguments),
|
|
78
|
+
title: mcpLabel(block.name ?? "") ?? title(block.arguments),
|
|
78
79
|
...shape(block.name ?? "tool", args),
|
|
79
80
|
output: "",
|
|
80
81
|
status: "running",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/spectrum/messages.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n AssistantMessage,\n AssistantStatus,\n ErrorAction,\n LickMessage,\n Message,\n MessagePart,\n SystemMessage,\n ToolCall,\n ToolStatus,\n Usage,\n UserMessage,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport type { ConversationView, EntryRecord } from '@earendil-works/pi-durable';\nimport { parseLick } from '../licks/lick.ts';\nimport { entryLick, LICK_TOOLS, type LickDecision, lickDecisions } from '../licks/state.ts';\nimport { FROM_KIND, type From } from '../scoops/from.ts';\nimport type { Delivered } from '../services.ts';\nimport { SPRINKLE_KIND } from '../sprinkles/kind.ts';\n\ntype Json = Record<string, unknown>;\n\ninterface Block {\n type: string;\n text?: string;\n thinking?: string;\n id?: string;\n name?: string;\n arguments?: Json;\n}\n\ninterface ModelMessage {\n role: string;\n content?: string | Block[];\n timestamp?: number;\n stopReason?: string;\n errorMessage?: string;\n provider?: string;\n model?: string;\n usage?: {\n input?: number;\n output?: number;\n cacheRead?: number;\n cacheWrite?: number;\n cost?: { total?: number };\n };\n toolCallId?: string;\n isError?: boolean;\n details?: { patch?: unknown };\n}\n\ninterface Slot {\n callId: string;\n status: string;\n output?: string;\n}\n\ninterface Live {\n run?: unknown;\n generation?: { message?: ModelMessage; retry?: { at: number; error: string } };\n tools?: Slot[];\n compactions?: { taskId: number; reason: string }[];\n}\n\nexport function textOf(content: ModelMessage['content']): string {\n if (typeof content === 'string') return content;\n return (content ?? []).map((block) => (block.type === 'text' ? (block.text ?? '') : '')).join('');\n}\n\nconst paths = (args: Json | undefined): string[] =>\n typeof args?.path === 'string' ? [args.path] : [];\n\nfunction title(args: Json | undefined): string {\n const subject = args?.command ?? args?.path;\n return typeof subject === 'string' ? subject : '';\n}\n\ninterface Replacement {\n oldText?: string;\n newText?: string;\n}\n\nconst GAP = '\u2026';\n\nfunction seconds(value: unknown): string | undefined {\n return typeof value === 'number' ? `timeout ${value}s` : undefined;\n}\n\nfunction lines(args: Json): string | undefined {\n const { offset, limit } = args as { offset?: number; limit?: number };\n if (typeof offset === 'number' && typeof limit === 'number')\n return `lines ${offset}\u2013${offset + limit - 1}`;\n if (typeof offset === 'number') return `from line ${offset}`;\n return typeof limit === 'number' ? `first ${limit} lines` : undefined;\n}\n\nfunction edits(args: Json): ToolCall['diff'] {\n const list = Array.isArray(args.edits) ? (args.edits as Replacement[]) : [];\n if (list.length === 0) return undefined;\n return {\n before: list.map((edit) => edit.oldText ?? '').join(`\\n${GAP}\\n`),\n after: list.map((edit) => edit.newText ?? '').join(`\\n${GAP}\\n`),\n };\n}\n\nexport function fromPatch(patch: string): ToolCall['diff'] {\n const before: string[] = [];\n const after: string[] = [];\n let hunks = 0;\n for (const line of patch.split('\\n')) {\n if (line.startsWith('@@')) {\n if (hunks++ > 0) {\n before.push(GAP);\n after.push(GAP);\n }\n continue;\n }\n if (hunks === 0 || line === '' || line.startsWith('\\\\')) continue;\n const text = line.slice(1);\n if (line.startsWith('-')) before.push(text);\n else if (line.startsWith('+')) after.push(text);\n else {\n before.push(text);\n after.push(text);\n }\n }\n return hunks ? { before: before.join('\\n'), after: after.join('\\n') } : undefined;\n}\n\nfunction shape(name: string, args: Json): Pick<ToolCall, 'input' | 'meta' | 'diff'> {\n const path = typeof args.path === 'string' ? args.path : '';\n const meta = name === 'bash' ? seconds(args.timeout) : name === 'read' ? lines(args) : undefined;\n const base = meta ? { meta } : {};\n if (name === 'bash' && typeof args.command === 'string') return { input: args.command, ...base };\n if (name === 'read' || name === 'write') return { input: path, ...base };\n if (name === 'edit') {\n const diff = edits(args);\n return { input: path, ...(diff ? { diff } : {}) };\n }\n return { input: JSON.stringify(args, null, 2) };\n}\n\nfunction toolCall(block: Block): ToolCall {\n const args = block.arguments ?? {};\n return {\n id: block.id ?? '',\n name: block.name ?? 'tool',\n title: title(block.arguments),\n ...shape(block.name ?? 'tool', args),\n output: '',\n status: 'running',\n paths: paths(block.arguments),\n };\n}\n\nfunction part(block: Block): MessagePart | undefined {\n if (block.type === 'text') return { type: 'text', text: block.text ?? '' };\n if (block.type === 'thinking') return { type: 'thinking', text: block.thinking ?? '' };\n if (block.type === 'toolCall') return { type: 'tool', tool: toolCall(block) };\n return undefined;\n}\n\nfunction usage(message: ModelMessage): Usage | undefined {\n const used = message.usage;\n if (!used) return undefined;\n return {\n input: used.input ?? 0,\n output: used.output ?? 0,\n cost: used.cost?.total ?? 0,\n cacheRead: used.cacheRead ?? 0,\n cacheWrite: used.cacheWrite ?? 0,\n };\n}\n\nconst statuses: Record<string, AssistantStatus> = { error: 'error', aborted: 'stopped' };\n\nconst credentials =\n /security token|unrecognizedclient|not authori[sz]ed|unauthori[sz]ed|forbidden|\\b40[13]\\b|api key|credential|bearer/i;\nconst models = /model/i;\nconst unavailable =\n /access|invalid|not found|identifier|unsupported|not supported|isn['\u2019]t supported|not available|isn['\u2019]t available/i;\n\nconst providerNames: Record<string, string> = { 'amazon-bedrock': 'Bedrock' };\nconst filtered =\n /Provider (?:stopped with|finish_reason): (?:content_filter(?:ed)?|guardrail_intervened|sensitive)|content[_ ]filter(?:ed|ing)?\\b|guardrail[_ ]intervened/i;\nconst refused =\n /refused to complete the request|Provider (?:stopped with|finish_reason): refusal|\\bstop_?reason\\W+refusal\\b/i;\nconst missing = /no api key|missing|not configured|no credentials/i;\n\nexport function errorPart(error: string, provider?: string): MessagePart {\n const action = errorAction(error);\n if (action === 'drop-turn') {\n return {\n type: 'error',\n message: filtered.test(error)\n ? \"The model's content filter stopped this reply.\"\n : 'The model refused to answer this turn.',\n detail: error,\n action,\n };\n }\n if (action === 'settings' && provider === 'adobe') {\n return {\n type: 'error',\n message: 'Your Adobe session has expired.',\n detail: error,\n action: 'login',\n };\n }\n const name = providerNames[provider ?? ''] ?? 'The provider';\n const lead =\n action === 'settings'\n ? missing.test(error)\n ? `${name} needs an API key.`\n : `${name} rejected the API key.`\n : action === 'change-model'\n ? \"This model isn't available with the current account.\"\n : null;\n return lead\n ? { type: 'error', message: lead, detail: error, action }\n : { type: 'error', message: error, action };\n}\n\nexport function errorAction(message: string): ErrorAction {\n if (filtered.test(message) || refused.test(message)) return 'drop-turn';\n if (credentials.test(message)) return 'settings';\n if (models.test(message) && unavailable.test(message)) return 'change-model';\n return 'retry';\n}\n\nfunction sprinkleMessage(id: string, entry: EntryRecord): AssistantMessage {\n const data = (entry.data ?? {}) as { sprinkle?: unknown; at?: unknown };\n return {\n id,\n role: 'assistant',\n parts: [{ type: 'sprinkle', sprinkle: String(data.sprinkle ?? '') }],\n status: 'done',\n createdAt: typeof data.at === 'number' ? data.at : 0,\n };\n}\n\nexport function assistant(\n id: string,\n message: ModelMessage,\n status?: AssistantStatus\n): AssistantMessage {\n const blocks = Array.isArray(message.content) ? message.content : [];\n const parts = blocks.map(part).filter((item): item is MessagePart => item !== undefined);\n if (message.errorMessage) parts.push(errorPart(message.errorMessage, message.provider));\n const used = usage(message);\n return {\n id,\n role: 'assistant',\n parts,\n status: status ?? statuses[message.stopReason ?? ''] ?? 'done',\n createdAt: message.timestamp ?? 0,\n ...(message.provider && message.model ? { model: `${message.provider}/${message.model}` } : {}),\n ...(used ? { usage: used } : {}),\n };\n}\n\nfunction user(\n id: string,\n message: ModelMessage,\n delivered: Delivered | undefined,\n from: From | undefined\n): UserMessage {\n return {\n id,\n role: 'user',\n text: textOf(message.content),\n createdAt: message.timestamp ?? 0,\n ...(delivered ? { delivered } : {}),\n ...(from ? { from: from.from } : {}),\n ...(from?.agent ? { origin: 'agent' as const } : {}),\n };\n}\n\nexport function origins(entries: readonly EntryRecord[]): Map<number, From> {\n const out = new Map<number, From>();\n for (const entry of entries)\n if (entry.kind === FROM_KIND) {\n const note = entry.data as From;\n out.set(note.entry, note);\n }\n return out;\n}\n\nfunction lickMessage(\n id: string,\n entry: EntryRecord,\n decisions: ReadonlyMap<string, LickDecision>\n): LickMessage | undefined {\n const lick = entryLick(entry);\n if (!lick) return undefined;\n const state = lick.actions?.length ? (decisions.get(lick.id) ?? 'pending') : undefined;\n return {\n id,\n role: 'lick',\n channel: lick.channel,\n title: lick.title,\n text: lick.text,\n createdAt: lick.at,\n ...(lick.body ? { body: lick.body } : {}),\n ...(lick.count > 1 ? { count: lick.count } : {}),\n ...(state ? { state } : {}),\n ...(lick.severity ? { severity: lick.severity } : {}),\n };\n}\n\nfunction withoutLickTools(message: AssistantMessage): AssistantMessage {\n const parts = message.parts.filter((item) => item.type !== 'tool' || !LICK_TOOLS[item.tool.name]);\n return parts.length === message.parts.length ? message : { ...message, parts };\n}\n\nfunction system(id: string, entry: EntryRecord, text: string): SystemMessage {\n const reason = (entry.data as Json | undefined)?.reason as SystemMessage['trigger'] | undefined;\n return {\n id,\n role: 'system',\n kind: 'compaction',\n text,\n createdAt: 0,\n state: 'summarized',\n ...(reason ? { trigger: reason } : {}),\n };\n}\n\nfunction tools(messages: Message[]): Map<string, ToolCall> {\n const found = new Map<string, ToolCall>();\n for (const message of messages) {\n if (message.role !== 'assistant') continue;\n for (const item of message.parts) if (item.type === 'tool') found.set(item.tool.id, item.tool);\n }\n return found;\n}\n\nfunction settle(calls: Map<string, ToolCall>, result: ModelMessage): void {\n const call = calls.get(result.toolCallId ?? '');\n if (!call) return;\n call.output = textOf(result.content);\n call.status = result.isError ? 'error' : 'done';\n const image = Array.isArray(result.content)\n ? (result.content as { type: string; data?: string; mimeType?: string }[]).find(\n (part) => part.type === 'image' && part.data && part.mimeType\n )\n : undefined;\n if (image) call.image = `data:${image.mimeType};base64,${image.data}`;\n const patch = result.details?.patch;\n const diff = typeof patch === 'string' ? fromPatch(patch) : undefined;\n if (diff) call.diff = diff;\n else if (result.isError) delete call.diff;\n}\n\nfunction rewound(id: string, entry: EntryRecord): SystemMessage {\n const data = (entry.data ?? {}) as { stopped?: string[]; restored?: string[]; files?: boolean };\n const notes = [\n 'Its prompt is back in the composer.',\n ...(data.stopped?.length\n ? [`Stopped ${data.stopped.map((name) => `scoop ${name}`).join(', ')}.`]\n : []),\n ...(data.restored?.length\n ? [`Restored ${data.restored.map((name) => `scoop ${name}`).join(', ')}.`]\n : []),\n ...(data.files ? ['Changed files stay; use Changes or git to revert them.'] : []),\n ];\n return {\n id,\n role: 'system',\n kind: 'notice',\n title: 'Rewound 1 turn',\n text: notes.join(' '),\n createdAt: 0,\n };\n}\n\nfunction thawed(id: string, entry: EntryRecord): SystemMessage {\n const data = (entry.data ?? {}) as { name?: string; kind?: string };\n const what = data.kind === 'agent' ? 'agent run' : 'scoop';\n return {\n id,\n role: 'system',\n kind: 'notice',\n title: `Thawed from ${what} ${data.name ?? ''}`.trim(),\n text: textOf(entry.model?.[0]?.content ?? ''),\n createdAt: entry.model?.[0]?.timestamp ?? 0,\n };\n}\n\nfunction entryMessage(\n entry: EntryRecord,\n out: Message[],\n calls: Map<string, ToolCall>,\n delivered: Delivered | undefined,\n notes: { decisions: ReadonlyMap<string, LickDecision>; origins: ReadonlyMap<number, From> }\n): void {\n const id = `e${entry.id}`;\n const model = entry.model?.[0] as ModelMessage | undefined;\n if (entry.kind === 'slicc.rewound') out.push(rewound(id, entry));\n if (entry.kind === 'slicc.thawed') out.push(thawed(id, entry));\n else if (entry.kind === SPRINKLE_KIND) out.push(sprinkleMessage(id, entry));\n else if (entry.kind === 'pi.user' && model)\n out.push(\n lickMessage(id, entry, notes.decisions) ??\n user(id, model, delivered, notes.origins.get(entry.id))\n );\n else if (entry.kind === 'pi.assistant' && model) {\n const message = assistant(id, model);\n out.push(withoutLickTools(message));\n for (const [key, value] of tools([message])) calls.set(key, value);\n } else if (entry.kind === 'pi.tool-result' && model) settle(calls, model);\n else if (entry.kind === 'pi.compaction') out.push(system(id, entry, textOf(model?.content)));\n}\n\nconst slotStatus: Record<string, ToolStatus> = {\n pending: 'running',\n running: 'running',\n done: 'done',\n};\n\nfunction live(view: ConversationView, out: Message[], calls: Map<string, ToolCall>): void {\n const state = view.docs['pi.live'] as Live | undefined;\n for (const slot of state?.tools ?? []) {\n const call = calls.get(slot.callId);\n if (call && call.status === 'running') {\n call.status = slotStatus[slot.status] ?? 'running';\n call.output = slot.output ?? call.output;\n }\n }\n const partial = state?.generation?.message;\n if (partial) out.push(assistant('live', partial, 'streaming'));\n for (const compaction of state?.compactions ?? []) {\n out.push({\n id: `compaction-${compaction.taskId}`,\n role: 'system',\n kind: 'compaction',\n text: '',\n createdAt: 0,\n state: 'summarizing',\n trigger: compaction.reason as SystemMessage['trigger'],\n });\n }\n const retry = state?.generation?.retry;\n if (retry)\n out.push({\n id: 'retry',\n role: 'system',\n kind: 'notice',\n text: retry.error,\n createdAt: retry.at,\n });\n}\n\nexport function toMessages(\n view: ConversationView | undefined,\n deliveries: Readonly<Record<string, Delivered>> = {}\n): Message[] {\n const out: Message[] = [];\n if (!view) return out;\n const calls = new Map<string, ToolCall>();\n const notes = { decisions: lickDecisions(view.entries), origins: origins(view.entries) };\n let previous: EntryRecord | undefined;\n for (const entry of view.entries) {\n const steered = previous?.kind === 'pi.tool-result' ? 'steer' : undefined;\n entryMessage(entry, out, calls, deliveries[String(entry.id)] ?? steered, notes);\n previous = entry;\n }\n live(view, out, calls);\n return out;\n}\n\nexport function isBusy(view: ConversationView | undefined): boolean {\n return Boolean((view?.docs['pi.live'] as Live | undefined)?.run);\n}\n\nexport function queued(view: ConversationView | undefined): UserMessage[] {\n const items = ((view?.docs['pi.inbox'] as { items?: Json[] } | undefined)?.items ?? []) as {\n id: number;\n mode: string;\n content?: ModelMessage['content'];\n }[];\n return items\n .filter((item) => item.mode !== 'write' && !parseLick(textOf(item.content)))\n .map((item) => ({\n id: `q${item.id}`,\n role: 'user',\n text: textOf(item.content),\n createdAt: 0,\n queued: true,\n mode: item.mode === 'steer' ? 'steer' : 'queue',\n }));\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import type {\n AssistantMessage,\n AssistantStatus,\n ErrorAction,\n LickMessage,\n Message,\n MessagePart,\n SystemMessage,\n ToolCall,\n ToolStatus,\n Usage,\n UserMessage,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport type { ConversationView, EntryRecord } from '@earendil-works/pi-durable';\nimport { parseLick } from '../licks/lick.ts';\nimport { entryLick, LICK_TOOLS, type LickDecision, lickDecisions } from '../licks/state.ts';\nimport { mcpLabel } from '../mcp/label.ts';\nimport { FROM_KIND, type From } from '../scoops/from.ts';\nimport type { Delivered } from '../services.ts';\nimport { SPRINKLE_KIND } from '../sprinkles/kind.ts';\n\ntype Json = Record<string, unknown>;\n\ninterface Block {\n type: string;\n text?: string;\n thinking?: string;\n id?: string;\n name?: string;\n arguments?: Json;\n}\n\ninterface ModelMessage {\n role: string;\n content?: string | Block[];\n timestamp?: number;\n stopReason?: string;\n errorMessage?: string;\n provider?: string;\n model?: string;\n usage?: {\n input?: number;\n output?: number;\n cacheRead?: number;\n cacheWrite?: number;\n cost?: { total?: number };\n };\n toolCallId?: string;\n isError?: boolean;\n details?: { patch?: unknown };\n}\n\ninterface Slot {\n callId: string;\n status: string;\n output?: string;\n}\n\ninterface Live {\n run?: unknown;\n generation?: { message?: ModelMessage; retry?: { at: number; error: string } };\n tools?: Slot[];\n compactions?: { taskId: number; reason: string }[];\n}\n\nexport function textOf(content: ModelMessage['content']): string {\n if (typeof content === 'string') return content;\n return (content ?? []).map((block) => (block.type === 'text' ? (block.text ?? '') : '')).join('');\n}\n\nconst paths = (args: Json | undefined): string[] =>\n typeof args?.path === 'string' ? [args.path] : [];\n\nfunction title(args: Json | undefined): string {\n const subject = args?.command ?? args?.path;\n return typeof subject === 'string' ? subject : '';\n}\n\ninterface Replacement {\n oldText?: string;\n newText?: string;\n}\n\nconst GAP = '\u2026';\n\nfunction seconds(value: unknown): string | undefined {\n return typeof value === 'number' ? `timeout ${value}s` : undefined;\n}\n\nfunction lines(args: Json): string | undefined {\n const { offset, limit } = args as { offset?: number; limit?: number };\n if (typeof offset === 'number' && typeof limit === 'number')\n return `lines ${offset}\u2013${offset + limit - 1}`;\n if (typeof offset === 'number') return `from line ${offset}`;\n return typeof limit === 'number' ? `first ${limit} lines` : undefined;\n}\n\nfunction edits(args: Json): ToolCall['diff'] {\n const list = Array.isArray(args.edits) ? (args.edits as Replacement[]) : [];\n if (list.length === 0) return undefined;\n return {\n before: list.map((edit) => edit.oldText ?? '').join(`\\n${GAP}\\n`),\n after: list.map((edit) => edit.newText ?? '').join(`\\n${GAP}\\n`),\n };\n}\n\nexport function fromPatch(patch: string): ToolCall['diff'] {\n const before: string[] = [];\n const after: string[] = [];\n let hunks = 0;\n for (const line of patch.split('\\n')) {\n if (line.startsWith('@@')) {\n if (hunks++ > 0) {\n before.push(GAP);\n after.push(GAP);\n }\n continue;\n }\n if (hunks === 0 || line === '' || line.startsWith('\\\\')) continue;\n const text = line.slice(1);\n if (line.startsWith('-')) before.push(text);\n else if (line.startsWith('+')) after.push(text);\n else {\n before.push(text);\n after.push(text);\n }\n }\n return hunks ? { before: before.join('\\n'), after: after.join('\\n') } : undefined;\n}\n\nfunction shape(name: string, args: Json): Pick<ToolCall, 'input' | 'meta' | 'diff'> {\n const path = typeof args.path === 'string' ? args.path : '';\n const meta = name === 'bash' ? seconds(args.timeout) : name === 'read' ? lines(args) : undefined;\n const base = meta ? { meta } : {};\n if (name === 'bash' && typeof args.command === 'string') return { input: args.command, ...base };\n if (name === 'read' || name === 'write') return { input: path, ...base };\n if (name === 'edit') {\n const diff = edits(args);\n return { input: path, ...(diff ? { diff } : {}) };\n }\n return { input: JSON.stringify(args, null, 2) };\n}\n\nfunction toolCall(block: Block): ToolCall {\n const args = block.arguments ?? {};\n return {\n id: block.id ?? '',\n name: block.name ?? 'tool',\n title: mcpLabel(block.name ?? '') ?? title(block.arguments),\n ...shape(block.name ?? 'tool', args),\n output: '',\n status: 'running',\n paths: paths(block.arguments),\n };\n}\n\nfunction part(block: Block): MessagePart | undefined {\n if (block.type === 'text') return { type: 'text', text: block.text ?? '' };\n if (block.type === 'thinking') return { type: 'thinking', text: block.thinking ?? '' };\n if (block.type === 'toolCall') return { type: 'tool', tool: toolCall(block) };\n return undefined;\n}\n\nfunction usage(message: ModelMessage): Usage | undefined {\n const used = message.usage;\n if (!used) return undefined;\n return {\n input: used.input ?? 0,\n output: used.output ?? 0,\n cost: used.cost?.total ?? 0,\n cacheRead: used.cacheRead ?? 0,\n cacheWrite: used.cacheWrite ?? 0,\n };\n}\n\nconst statuses: Record<string, AssistantStatus> = { error: 'error', aborted: 'stopped' };\n\nconst credentials =\n /security token|unrecognizedclient|not authori[sz]ed|unauthori[sz]ed|forbidden|\\b40[13]\\b|api key|credential|bearer/i;\nconst models = /model/i;\nconst unavailable =\n /access|invalid|not found|identifier|unsupported|not supported|isn['\u2019]t supported|not available|isn['\u2019]t available/i;\n\nconst providerNames: Record<string, string> = { 'amazon-bedrock': 'Bedrock' };\nconst filtered =\n /Provider (?:stopped with|finish_reason): (?:content_filter(?:ed)?|guardrail_intervened|sensitive)|content[_ ]filter(?:ed|ing)?\\b|guardrail[_ ]intervened/i;\nconst refused =\n /refused to complete the request|Provider (?:stopped with|finish_reason): refusal|\\bstop_?reason\\W+refusal\\b/i;\nconst missing = /no api key|missing|not configured|no credentials/i;\n\nexport function errorPart(error: string, provider?: string): MessagePart {\n const action = errorAction(error);\n if (action === 'drop-turn') {\n return {\n type: 'error',\n message: filtered.test(error)\n ? \"The model's content filter stopped this reply.\"\n : 'The model refused to answer this turn.',\n detail: error,\n action,\n };\n }\n if (action === 'settings' && provider === 'adobe') {\n return {\n type: 'error',\n message: 'Your Adobe session has expired.',\n detail: error,\n action: 'login',\n };\n }\n const name = providerNames[provider ?? ''] ?? 'The provider';\n const lead =\n action === 'settings'\n ? missing.test(error)\n ? `${name} needs an API key.`\n : `${name} rejected the API key.`\n : action === 'change-model'\n ? \"This model isn't available with the current account.\"\n : null;\n return lead\n ? { type: 'error', message: lead, detail: error, action }\n : { type: 'error', message: error, action };\n}\n\nexport function errorAction(message: string): ErrorAction {\n if (filtered.test(message) || refused.test(message)) return 'drop-turn';\n if (credentials.test(message)) return 'settings';\n if (models.test(message) && unavailable.test(message)) return 'change-model';\n return 'retry';\n}\n\nfunction sprinkleMessage(id: string, entry: EntryRecord): AssistantMessage {\n const data = (entry.data ?? {}) as { sprinkle?: unknown; at?: unknown };\n return {\n id,\n role: 'assistant',\n parts: [{ type: 'sprinkle', sprinkle: String(data.sprinkle ?? '') }],\n status: 'done',\n createdAt: typeof data.at === 'number' ? data.at : 0,\n };\n}\n\nexport function assistant(\n id: string,\n message: ModelMessage,\n status?: AssistantStatus\n): AssistantMessage {\n const blocks = Array.isArray(message.content) ? message.content : [];\n const parts = blocks.map(part).filter((item): item is MessagePart => item !== undefined);\n if (message.errorMessage) parts.push(errorPart(message.errorMessage, message.provider));\n const used = usage(message);\n return {\n id,\n role: 'assistant',\n parts,\n status: status ?? statuses[message.stopReason ?? ''] ?? 'done',\n createdAt: message.timestamp ?? 0,\n ...(message.provider && message.model ? { model: `${message.provider}/${message.model}` } : {}),\n ...(used ? { usage: used } : {}),\n };\n}\n\nfunction user(\n id: string,\n message: ModelMessage,\n delivered: Delivered | undefined,\n from: From | undefined\n): UserMessage {\n return {\n id,\n role: 'user',\n text: textOf(message.content),\n createdAt: message.timestamp ?? 0,\n ...(delivered ? { delivered } : {}),\n ...(from ? { from: from.from } : {}),\n ...(from?.agent ? { origin: 'agent' as const } : {}),\n };\n}\n\nexport function origins(entries: readonly EntryRecord[]): Map<number, From> {\n const out = new Map<number, From>();\n for (const entry of entries)\n if (entry.kind === FROM_KIND) {\n const note = entry.data as From;\n out.set(note.entry, note);\n }\n return out;\n}\n\nfunction lickMessage(\n id: string,\n entry: EntryRecord,\n decisions: ReadonlyMap<string, LickDecision>\n): LickMessage | undefined {\n const lick = entryLick(entry);\n if (!lick) return undefined;\n const state = lick.actions?.length ? (decisions.get(lick.id) ?? 'pending') : undefined;\n return {\n id,\n role: 'lick',\n channel: lick.channel,\n title: lick.title,\n text: lick.text,\n createdAt: lick.at,\n ...(lick.body ? { body: lick.body } : {}),\n ...(lick.count > 1 ? { count: lick.count } : {}),\n ...(state ? { state } : {}),\n ...(lick.severity ? { severity: lick.severity } : {}),\n };\n}\n\nfunction withoutLickTools(message: AssistantMessage): AssistantMessage {\n const parts = message.parts.filter((item) => item.type !== 'tool' || !LICK_TOOLS[item.tool.name]);\n return parts.length === message.parts.length ? message : { ...message, parts };\n}\n\nfunction system(id: string, entry: EntryRecord, text: string): SystemMessage {\n const reason = (entry.data as Json | undefined)?.reason as SystemMessage['trigger'] | undefined;\n return {\n id,\n role: 'system',\n kind: 'compaction',\n text,\n createdAt: 0,\n state: 'summarized',\n ...(reason ? { trigger: reason } : {}),\n };\n}\n\nfunction tools(messages: Message[]): Map<string, ToolCall> {\n const found = new Map<string, ToolCall>();\n for (const message of messages) {\n if (message.role !== 'assistant') continue;\n for (const item of message.parts) if (item.type === 'tool') found.set(item.tool.id, item.tool);\n }\n return found;\n}\n\nfunction settle(calls: Map<string, ToolCall>, result: ModelMessage): void {\n const call = calls.get(result.toolCallId ?? '');\n if (!call) return;\n call.output = textOf(result.content);\n call.status = result.isError ? 'error' : 'done';\n const image = Array.isArray(result.content)\n ? (result.content as { type: string; data?: string; mimeType?: string }[]).find(\n (part) => part.type === 'image' && part.data && part.mimeType\n )\n : undefined;\n if (image) call.image = `data:${image.mimeType};base64,${image.data}`;\n const patch = result.details?.patch;\n const diff = typeof patch === 'string' ? fromPatch(patch) : undefined;\n if (diff) call.diff = diff;\n else if (result.isError) delete call.diff;\n}\n\nfunction rewound(id: string, entry: EntryRecord): SystemMessage {\n const data = (entry.data ?? {}) as { stopped?: string[]; restored?: string[]; files?: boolean };\n const notes = [\n 'Its prompt is back in the composer.',\n ...(data.stopped?.length\n ? [`Stopped ${data.stopped.map((name) => `scoop ${name}`).join(', ')}.`]\n : []),\n ...(data.restored?.length\n ? [`Restored ${data.restored.map((name) => `scoop ${name}`).join(', ')}.`]\n : []),\n ...(data.files ? ['Changed files stay; use Changes or git to revert them.'] : []),\n ];\n return {\n id,\n role: 'system',\n kind: 'notice',\n title: 'Rewound 1 turn',\n text: notes.join(' '),\n createdAt: 0,\n };\n}\n\nfunction thawed(id: string, entry: EntryRecord): SystemMessage {\n const data = (entry.data ?? {}) as { name?: string; kind?: string };\n const what = data.kind === 'agent' ? 'agent run' : 'scoop';\n return {\n id,\n role: 'system',\n kind: 'notice',\n title: `Thawed from ${what} ${data.name ?? ''}`.trim(),\n text: textOf(entry.model?.[0]?.content ?? ''),\n createdAt: entry.model?.[0]?.timestamp ?? 0,\n };\n}\n\nfunction entryMessage(\n entry: EntryRecord,\n out: Message[],\n calls: Map<string, ToolCall>,\n delivered: Delivered | undefined,\n notes: { decisions: ReadonlyMap<string, LickDecision>; origins: ReadonlyMap<number, From> }\n): void {\n const id = `e${entry.id}`;\n const model = entry.model?.[0] as ModelMessage | undefined;\n if (entry.kind === 'slicc.rewound') out.push(rewound(id, entry));\n if (entry.kind === 'slicc.thawed') out.push(thawed(id, entry));\n else if (entry.kind === SPRINKLE_KIND) out.push(sprinkleMessage(id, entry));\n else if (entry.kind === 'pi.user' && model)\n out.push(\n lickMessage(id, entry, notes.decisions) ??\n user(id, model, delivered, notes.origins.get(entry.id))\n );\n else if (entry.kind === 'pi.assistant' && model) {\n const message = assistant(id, model);\n out.push(withoutLickTools(message));\n for (const [key, value] of tools([message])) calls.set(key, value);\n } else if (entry.kind === 'pi.tool-result' && model) settle(calls, model);\n else if (entry.kind === 'pi.compaction') out.push(system(id, entry, textOf(model?.content)));\n}\n\nconst slotStatus: Record<string, ToolStatus> = {\n pending: 'running',\n running: 'running',\n done: 'done',\n};\n\nfunction live(view: ConversationView, out: Message[], calls: Map<string, ToolCall>): void {\n const state = view.docs['pi.live'] as Live | undefined;\n for (const slot of state?.tools ?? []) {\n const call = calls.get(slot.callId);\n if (call && call.status === 'running') {\n call.status = slotStatus[slot.status] ?? 'running';\n call.output = slot.output ?? call.output;\n }\n }\n const partial = state?.generation?.message;\n if (partial) out.push(assistant('live', partial, 'streaming'));\n for (const compaction of state?.compactions ?? []) {\n out.push({\n id: `compaction-${compaction.taskId}`,\n role: 'system',\n kind: 'compaction',\n text: '',\n createdAt: 0,\n state: 'summarizing',\n trigger: compaction.reason as SystemMessage['trigger'],\n });\n }\n const retry = state?.generation?.retry;\n if (retry)\n out.push({\n id: 'retry',\n role: 'system',\n kind: 'notice',\n text: retry.error,\n createdAt: retry.at,\n });\n}\n\nexport function toMessages(\n view: ConversationView | undefined,\n deliveries: Readonly<Record<string, Delivered>> = {}\n): Message[] {\n const out: Message[] = [];\n if (!view) return out;\n const calls = new Map<string, ToolCall>();\n const notes = { decisions: lickDecisions(view.entries), origins: origins(view.entries) };\n let previous: EntryRecord | undefined;\n for (const entry of view.entries) {\n const steered = previous?.kind === 'pi.tool-result' ? 'steer' : undefined;\n entryMessage(entry, out, calls, deliveries[String(entry.id)] ?? steered, notes);\n previous = entry;\n }\n live(view, out, calls);\n return out;\n}\n\nexport function isBusy(view: ConversationView | undefined): boolean {\n return Boolean((view?.docs['pi.live'] as Live | undefined)?.run);\n}\n\nexport function queued(view: ConversationView | undefined): UserMessage[] {\n const items = ((view?.docs['pi.inbox'] as { items?: Json[] } | undefined)?.items ?? []) as {\n id: number;\n mode: string;\n content?: ModelMessage['content'];\n }[];\n return items\n .filter((item) => item.mode !== 'write' && !parseLick(textOf(item.content)))\n .map((item) => ({\n id: `q${item.id}`,\n role: 'user',\n text: textOf(item.content),\n createdAt: 0,\n queued: true,\n mode: item.mode === 'steer' ? 'steer' : 'queue',\n }));\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["part"]
|
|
7
7
|
}
|
|
@@ -4,7 +4,7 @@ import type { CodemodeExtra } from './allow.ts';
|
|
|
4
4
|
import type { McpCatalog } from './catalog.ts';
|
|
5
5
|
import type { McpAttach, McpRuntime } from './runtime.ts';
|
|
6
6
|
export { allows, type CodemodeExtra, McpAllowDoc, mcpEntries, serverAllowed } from './allow.ts';
|
|
7
|
-
export type { McpAttach, McpRuntime, ServerStatus } from './runtime.ts';
|
|
7
|
+
export type { McpAccounts, McpAttach, McpRuntime, ServerStatus } from './runtime.ts';
|
|
8
8
|
export type McpLoader = () => Promise<typeof import('./runtime.ts')>;
|
|
9
9
|
export declare const loadRuntime: McpLoader;
|
|
10
10
|
export interface McpSetup {
|
|
@@ -3,6 +3,7 @@ import type { CredentialStore } from '@earendil-works/pi-ai';
|
|
|
3
3
|
import type { Registry } from '@earendil-works/pi-durable';
|
|
4
4
|
import type { ExecutionEnv } from '@earendil-works/pi-durable/env';
|
|
5
5
|
import type { LickEvent, Licks } from '../licks/licks.ts';
|
|
6
|
+
import type { AccountState } from '../services.ts';
|
|
6
7
|
import { McpCatalog } from './catalog.ts';
|
|
7
8
|
import { type McpConfigProblem } from './config.ts';
|
|
8
9
|
import { McpServerConnection } from './connection.ts';
|
|
@@ -26,7 +27,13 @@ export interface ServerStatus {
|
|
|
26
27
|
tools: number;
|
|
27
28
|
error?: string;
|
|
28
29
|
}
|
|
29
|
-
export interface
|
|
30
|
+
export interface McpAccounts {
|
|
31
|
+
accounts(): Promise<AccountState[]>;
|
|
32
|
+
connect(id: string, secret: string): Promise<void>;
|
|
33
|
+
disconnect(id: string): Promise<void>;
|
|
34
|
+
onChange(listener: () => void): () => void;
|
|
35
|
+
}
|
|
36
|
+
export interface McpRuntime extends McpAccounts {
|
|
30
37
|
status(): ServerStatus[];
|
|
31
38
|
reload(context: Context): Promise<void>;
|
|
32
39
|
close(context: Context): Promise<void>;
|
|
@@ -35,6 +42,7 @@ export declare function problemLick(problem: McpConfigProblem, home: string): Li
|
|
|
35
42
|
export declare function stateLick(connection: McpServerConnection, cors: boolean): LickEvent | undefined;
|
|
36
43
|
export declare function connectedLick(connection: McpServerConnection): LickEvent;
|
|
37
44
|
export declare function logLine(server: string, params: unknown, secrets: readonly string[], at: Date): string;
|
|
45
|
+
export declare function mcpAccounts(catalog: McpCatalog, credentials: CredentialStore, restart: (connection: McpServerConnection) => void, listeners: Set<() => void>): McpAccounts;
|
|
38
46
|
export declare function attachMcp(catalog: McpCatalog, options: McpAttach, context: Context): Promise<McpRuntime>;
|
|
39
47
|
export declare function startMcp(registry: Registry, options: McpAttach, context: Context): Promise<{
|
|
40
48
|
catalog: McpCatalog;
|
package/dist/types/services.d.ts
CHANGED
|
@@ -177,9 +177,11 @@ export interface AccountState {
|
|
|
177
177
|
id: string;
|
|
178
178
|
provider: string;
|
|
179
179
|
identity: string;
|
|
180
|
-
status: 'connected' | 'disconnected';
|
|
180
|
+
status: 'connected' | 'disconnected' | 'expired';
|
|
181
181
|
auth: 'api-key' | 'oauth';
|
|
182
182
|
needs: 'cors-free-transport' | null;
|
|
183
|
+
group?: 'providers' | 'mcp';
|
|
184
|
+
secret?: 'api-key' | 'token';
|
|
183
185
|
}
|
|
184
186
|
export interface BudgetState {
|
|
185
187
|
provider: string;
|
package/dist/types/settings.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CredentialStore, Provider } from '@earendil-works/pi-ai';
|
|
2
2
|
import { type MutableModels } from '@earendil-works/pi-ai/models';
|
|
3
3
|
import { type Budget } from './adobe.ts';
|
|
4
|
+
import type { McpAccounts } from './mcp/index.ts';
|
|
4
5
|
import type { AgentSettings } from './services.ts';
|
|
5
6
|
export declare const BEDROCK = "amazon-bedrock";
|
|
6
7
|
export declare const DEFAULT_MODEL: {
|
|
@@ -15,4 +16,5 @@ export type UsageReader = (token: string) => Promise<Budget | null>;
|
|
|
15
16
|
export declare function createAgentSettings(models: MutableModels, credentials: CredentialStore, providers?: Provider<import("@earendil-works/pi-ai").Api>[], options?: {
|
|
16
17
|
usage?: UsageReader;
|
|
17
18
|
every?: number;
|
|
19
|
+
mcp?: McpAccounts;
|
|
18
20
|
}): Promise<AgentSettings>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/slicc-agent",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.33.0",
|
|
4
4
|
"description": "SLICC's agent core on pi durable: an agent worker, session storage, remoting and pi extensions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@ai-ecoverse/slicc-kernel": "1.47.1",
|
|
65
65
|
"@ai-ecoverse/slicc-shared-web": "1.12.1",
|
|
66
|
-
"@ai-ecoverse/slicc-spectrum": "1.
|
|
66
|
+
"@ai-ecoverse/slicc-spectrum": "1.52.0",
|
|
67
67
|
"@ai-ecoverse/wasm-bash": "5.3.0-17",
|
|
68
68
|
"@ai-ecoverse/wasm-coreutils": "9.12.0-5",
|
|
69
69
|
"@ai-ecoverse/wasm-git": "2.55.0-15",
|