@ai-ecoverse/slicc-agent 3.52.1 → 4.0.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 +17 -13
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/dist/host.js.map +1 -1
- package/dist/index.js +0 -3
- package/dist/index.js.map +2 -2
- package/dist/main.js +95 -22
- package/dist/main.js.map +2 -2
- package/dist/mcp/accounts.js +18 -14
- package/dist/mcp/accounts.js.map +2 -2
- package/dist/mcp/connection.js +0 -2
- package/dist/mcp/connection.js.map +2 -2
- package/dist/mcp/credentials.js +6 -15
- package/dist/mcp/credentials.js.map +2 -2
- package/dist/mcp/index.js +0 -1
- package/dist/mcp/index.js.map +2 -2
- package/dist/mcp/oauth.js +15 -20
- package/dist/mcp/oauth.js.map +2 -2
- package/dist/mcp/runtime.js +36 -14
- package/dist/mcp/runtime.js.map +2 -2
- package/dist/mcp/tools.js +4 -6
- package/dist/mcp/tools.js.map +2 -2
- package/dist/models/index.js +7 -4
- package/dist/models/index.js.map +2 -2
- package/dist/monitor/index.js +5 -10
- package/dist/monitor/index.js.map +2 -2
- package/dist/monitor/redact.js +4 -5
- package/dist/monitor/redact.js.map +2 -2
- package/dist/secrets/credentials.js +32 -0
- package/dist/secrets/credentials.js.map +7 -0
- package/dist/secrets/endpoints.js +111 -0
- package/dist/secrets/endpoints.js.map +7 -0
- package/dist/secrets/fetch.js +160 -0
- package/dist/secrets/fetch.js.map +7 -0
- package/dist/secrets/records.js +35 -0
- package/dist/secrets/records.js.map +7 -0
- package/dist/secrets/store.js +50 -0
- package/dist/secrets/store.js.map +7 -0
- package/dist/secrets/vault.js +58 -13
- package/dist/secrets/vault.js.map +2 -2
- package/dist/services.js.map +2 -2
- package/dist/settings.js +85 -23
- package/dist/settings.js.map +2 -2
- package/dist/spectrum/settings-port.js +24 -6
- package/dist/spectrum/settings-port.js.map +2 -2
- package/dist/types/host.d.ts +1 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/main.d.ts +7 -2
- package/dist/types/mcp/accounts.d.ts +10 -4
- package/dist/types/mcp/connection.d.ts +0 -2
- package/dist/types/mcp/credentials.d.ts +6 -4
- package/dist/types/mcp/oauth.d.ts +3 -2
- package/dist/types/mcp/runtime.d.ts +18 -4
- package/dist/types/models/index.d.ts +2 -0
- package/dist/types/monitor/index.d.ts +0 -1
- package/dist/types/monitor/redact.d.ts +2 -2
- package/dist/types/secrets/credentials.d.ts +5 -0
- package/dist/types/secrets/endpoints.d.ts +27 -0
- package/dist/types/secrets/fetch.d.ts +13 -0
- package/dist/types/secrets/records.d.ts +13 -0
- package/dist/types/secrets/store.d.ts +7 -0
- package/dist/types/secrets/vault.d.ts +31 -1
- package/dist/types/services.d.ts +8 -1
- package/dist/types/settings.d.ts +17 -2
- package/dist/types/spectrum/settings-port.d.ts +6 -4
- package/package.json +5 -3
- package/dist/credentials.js +0 -100
- package/dist/credentials.js.map +0 -7
- package/dist/types/credentials.d.ts +0 -12
package/dist/models/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/models/index.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { Models } from '@earendil-works/pi-ai/models';\nimport type { AgentChange, Conversation } from '@earendil-works/pi-durable';\nimport type { Agents } from '../agents.ts';\nimport { THINKING } from '../scoops/cli.ts';\nimport type { AgentSettings, ModelChoice, SettingsState } from '../services.ts';\n\nexport type Answer = { code: number; out: string };\n\nconst LEVELS = [...THINKING].join(', ');\n\nexport const USAGE = `usage:\n models [list] [--json] the models you can use, * marks the current one\n models current [--json] the current model\n models use <provider/model> [--thinking <level>] switch this agent's model, as the Settings picker does\n\nlevels: ${LEVELS}\nIn an agent's bash, models switches that cone or scoop; in a terminal, the active cone.\n`;\n\nexport interface ModelsOptions {\n agents: Agents;\n settings: Pick<AgentSettings, 'state'>;\n catalog: Pick<Models, 'getProviders' | 'getModels'>;\n}\n\nconst ok = (out: string): Answer => ({ code: 0, out });\nconst fail = (out: string, code = 1): Answer => ({ code, out: `models: ${out}\\n` });\n\nfunction distance(a: string, b: string): number {\n let previous = Array.from({ length: b.length + 1 }, (_, at) => at);\n for (let i = 1; i <= a.length; i++) {\n const row = [i];\n for (let j = 1; j <= b.length; j++)\n row[j] = Math.min(\n (previous[j] as number) + 1,\n (row[j - 1] as number) + 1,\n (previous[j - 1] as number) + (a[i - 1] === b[j - 1] ? 0 : 1)\n );\n previous = row;\n }\n return previous[b.length] as number;\n}\n\nexport function closest(wanted: string, ids: readonly string[], count = 3): string[] {\n const target = wanted.toLowerCase();\n const score = (id: string) => {\n const lower = id.toLowerCase();\n const tail = lower.slice(lower.indexOf('/') + 1);\n const near = Math.min(distance(target, lower), distance(target, tail));\n return lower.includes(target) || target.includes(tail) ? near - 1000 : near;\n };\n return [...new Set(ids)]\n .map((id) => ({ id, score: score(id) }))\n .sort((a, b) => a.score - b.score || a.id.localeCompare(b.id))\n .slice(0, count)\n .map((entry) => entry.id);\n}\n\nfunction agentOf(agents: Agents, caller: string | null): string {\n if (caller?.startsWith('cone:')) return caller.slice(5);\n return caller ?? agents.activeCone();\n}\n\nasync function conversationOf(agents: Agents, caller: string | null, context: Context) {\n const id = agentOf(agents, caller);\n const found = await agents.conversation(id, context);\n if (!found) throw new Error(`there is no agent ${id}`);\n return found;\n}\n\ntype Current = { id: string | null; thinking: string };\n\nasync function currentOf(conversation: Conversation, context: Context): Promise<Current> {\n const agent = await conversation.agent(context);\n return {\n id: agent.model ? `${agent.model.provider}/${agent.model.modelId}` : null,\n thinking: agent.thinkingLevel,\n };\n}\n\nfunction stateOf(options: ModelsOptions): SettingsState {\n return options.settings.state.value ?? { models: [], accounts: [] };\n}\n\nfunction account(state: SettingsState, choice: ModelChoice): string {\n const providerId = choice.id.slice(0, choice.id.indexOf('/'));\n const found = state.accounts.find((entry) => entry.id === providerId);\n return found?.identity ? `${choice.provider} (${found.identity})` : choice.provider;\n}\n\nfunction rows(state: SettingsState, current: Current) {\n return state.models.map((choice) => ({\n id: choice.id,\n label: choice.label,\n provider: choice.provider,\n account: account(state, choice),\n reasoning: choice.reasoning,\n contextWindow: choice.contextWindow,\n current: choice.id === current.id,\n }));\n}\n\nfunction missing(state: SettingsState, id: string): string {\n const providerId = id.slice(0, id.indexOf('/'));\n const connected = state.accounts.some(\n (entry) => entry.id === providerId && entry.status === 'connected'\n );\n return connected\n ? `current: ${id}, which its account no longer offers`\n : `current: ${id}, whose account is not connected`;\n}\n\nfunction list(state: SettingsState, current: Current, json: boolean): Answer {\n const listed = rows(state, current);\n if (json) return ok(`${JSON.stringify(listed, null, 2)}\\n`);\n const lines = listed.map(\n (row) => `${row.current ? '*' : ' '} ${row.id}\\t${row.label}\\t${row.account}`\n );\n if (!listed.length) lines.push('no models: connect an account in Settings');\n if (current.id && !listed.some((row) => row.current)) lines.push(missing(state, current.id));\n return ok(`${lines.join('\\n')}\\n`);\n}\n\nfunction show(state: SettingsState, current: Current, json: boolean): Answer {\n if (!json) return ok(`${current.id ?? 'none'}\\n`);\n const found = rows(state, current).find((row) => row.current);\n return ok(\n `${JSON.stringify({ id: current.id, thinking: current.thinking, label: found?.label ?? null, provider: found?.provider ?? null, available: Boolean(found) }, null, 2)}\\n`\n );\n}\n\nfunction refuse(options: ModelsOptions, state: SettingsState, wanted: string): Answer {\n const at = wanted.indexOf('/');\n const providerId = at > 0 ? wanted.slice(0, at) : '';\n const modelId = wanted.slice(at + 1);\n const disconnected = state.accounts.find(\n (entry) => entry.id === providerId && entry.status !== 'connected'\n );\n const known = options.catalog.getModels(providerId);\n if (disconnected && (!known.length || known.some((model) => model.id === modelId)))\n return fail(\n `${wanted} needs the ${disconnected.provider} account; connect it in Settings, then try again`\n );\n const ids = [\n ...state.models.map((choice) => choice.id),\n ...options.catalog\n .getProviders()\n .flatMap((provider) =>\n options.catalog.getModels(provider.id).map((model) => `${provider.id}/${model.id}`)\n ),\n ];\n const near = closest(wanted, ids);\n return fail(\n `there is no model ${wanted}${near.length ? `; the closest are ${near.join(', ')}` : ''}`\n );\n}\n\nasync function use(\n options: ModelsOptions,\n argv: readonly string[],\n caller: string | null,\n context: Context\n): Promise<Answer> {\n const rest: string[] = [];\n let thinking: string | undefined;\n for (let at = 0; at < argv.length; at++) {\n const arg = argv[at] as string;\n if (arg === '--thinking') {\n thinking = argv[++at];\n if (thinking === undefined) return fail('--thinking needs a level', 2);\n } else if (arg.startsWith('-')) return fail(`unknown option ${arg}`, 2);\n else rest.push(arg);\n }\n if (rest.length !== 1) return { code: 2, out: USAGE };\n if (thinking !== undefined && !THINKING.has(thinking))\n return fail(`--thinking must be one of ${LEVELS}`, 2);\n const wanted = rest[0] as string;\n const state = stateOf(options);\n const choice = state.models.find((entry) => entry.id === wanted);\n if (!choice) return refuse(options, state, wanted);\n const at = wanted.indexOf('/');\n const change: AgentChange = {\n model: { provider: wanted.slice(0, at), modelId: wanted.slice(at + 1) },\n ...(thinking ? { thinkingLevel: thinking as AgentChange['thinkingLevel'] } : {}),\n };\n const conversation = await conversationOf(options.agents, caller, context);\n await conversation.configure(change, context);\n const now = await currentOf(conversation, context);\n return ok(`now using ${now.id} (${choice.label}), thinking ${now.thinking}\\n`);\n}\n\nexport function modelsCommand(options: ModelsOptions) {\n return async (argv: readonly string[], caller: string | null, context: Context) => {\n try {\n const [verb = 'list', ...rest] = argv;\n if (verb === '--help' || verb === '-h' || verb === 'help') return ok(USAGE);\n if (verb === 'use') return await use(options, rest, caller, context);\n const listing = verb === 'list' || verb === '--json';\n if (!listing && verb !== 'current') return { code: 2, out: USAGE };\n const flags = verb === '--json' ? argv : rest;\n const unknown = flags.find((arg) => arg !== '--json');\n if (unknown) return { code: 2, out: USAGE };\n const json = flags.includes('--json');\n const state = stateOf(options);\n const current = await currentOf(\n await conversationOf(options.agents, caller, context),\n context\n );\n return listing
|
|
5
|
-
"mappings": "AAIA,SAAS,gBAAgB;AAKzB,MAAM,SAAS,CAAC,GAAG,QAAQ,EAAE,KAAK,IAAI;AAE/B,MAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,UAKX,MAAM;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { Models } from '@earendil-works/pi-ai/models';\nimport type { AgentChange, Conversation } from '@earendil-works/pi-durable';\nimport type { Agents } from '../agents.ts';\nimport { THINKING } from '../scoops/cli.ts';\nimport type { AgentSettings, ModelChoice, SettingsState } from '../services.ts';\n\nexport type Answer = { code: number; out: string };\n\nconst LEVELS = [...THINKING].join(', ');\n\nexport const USAGE = `usage:\n models [list] [--json] the models you can use, * marks the current one\n models current [--json] the current model\n models use <provider/model> [--thinking <level>] switch this agent's model, as the Settings picker does\n\nlevels: ${LEVELS}\nIn an agent's bash, models switches that cone or scoop; in a terminal, the active cone.\n`;\n\nexport interface ModelsOptions {\n agents: Agents;\n settings: Pick<AgentSettings, 'state'>;\n catalog: Pick<Models, 'getProviders' | 'getModels'>;\n locked?: () => boolean;\n}\n\nexport const LOCKED_NOTE = 'the vault is locked: unlock it to use these accounts';\n\nconst ok = (out: string): Answer => ({ code: 0, out });\nconst fail = (out: string, code = 1): Answer => ({ code, out: `models: ${out}\\n` });\n\nfunction distance(a: string, b: string): number {\n let previous = Array.from({ length: b.length + 1 }, (_, at) => at);\n for (let i = 1; i <= a.length; i++) {\n const row = [i];\n for (let j = 1; j <= b.length; j++)\n row[j] = Math.min(\n (previous[j] as number) + 1,\n (row[j - 1] as number) + 1,\n (previous[j - 1] as number) + (a[i - 1] === b[j - 1] ? 0 : 1)\n );\n previous = row;\n }\n return previous[b.length] as number;\n}\n\nexport function closest(wanted: string, ids: readonly string[], count = 3): string[] {\n const target = wanted.toLowerCase();\n const score = (id: string) => {\n const lower = id.toLowerCase();\n const tail = lower.slice(lower.indexOf('/') + 1);\n const near = Math.min(distance(target, lower), distance(target, tail));\n return lower.includes(target) || target.includes(tail) ? near - 1000 : near;\n };\n return [...new Set(ids)]\n .map((id) => ({ id, score: score(id) }))\n .sort((a, b) => a.score - b.score || a.id.localeCompare(b.id))\n .slice(0, count)\n .map((entry) => entry.id);\n}\n\nfunction agentOf(agents: Agents, caller: string | null): string {\n if (caller?.startsWith('cone:')) return caller.slice(5);\n return caller ?? agents.activeCone();\n}\n\nasync function conversationOf(agents: Agents, caller: string | null, context: Context) {\n const id = agentOf(agents, caller);\n const found = await agents.conversation(id, context);\n if (!found) throw new Error(`there is no agent ${id}`);\n return found;\n}\n\ntype Current = { id: string | null; thinking: string };\n\nasync function currentOf(conversation: Conversation, context: Context): Promise<Current> {\n const agent = await conversation.agent(context);\n return {\n id: agent.model ? `${agent.model.provider}/${agent.model.modelId}` : null,\n thinking: agent.thinkingLevel,\n };\n}\n\nfunction stateOf(options: ModelsOptions): SettingsState {\n return options.settings.state.value ?? { models: [], accounts: [] };\n}\n\nfunction account(state: SettingsState, choice: ModelChoice): string {\n const providerId = choice.id.slice(0, choice.id.indexOf('/'));\n const found = state.accounts.find((entry) => entry.id === providerId);\n return found?.identity ? `${choice.provider} (${found.identity})` : choice.provider;\n}\n\nfunction rows(state: SettingsState, current: Current) {\n return state.models.map((choice) => ({\n id: choice.id,\n label: choice.label,\n provider: choice.provider,\n account: account(state, choice),\n reasoning: choice.reasoning,\n contextWindow: choice.contextWindow,\n current: choice.id === current.id,\n }));\n}\n\nfunction missing(state: SettingsState, id: string): string {\n const providerId = id.slice(0, id.indexOf('/'));\n const connected = state.accounts.some(\n (entry) => entry.id === providerId && entry.status === 'connected'\n );\n return connected\n ? `current: ${id}, which its account no longer offers`\n : `current: ${id}, whose account is not connected`;\n}\n\nfunction list(state: SettingsState, current: Current, json: boolean, locked: boolean): Answer {\n const listed = rows(state, current);\n if (json) return ok(`${JSON.stringify(listed, null, 2)}\\n`);\n const lines = listed.map(\n (row) => `${row.current ? '*' : ' '} ${row.id}\\t${row.label}\\t${row.account}`\n );\n if (locked) lines.push(LOCKED_NOTE);\n if (!listed.length) lines.push('no models: connect an account in Settings \u203A Accounts');\n if (current.id && !listed.some((row) => row.current)) lines.push(missing(state, current.id));\n return ok(`${lines.join('\\n')}\\n`);\n}\n\nfunction show(state: SettingsState, current: Current, json: boolean): Answer {\n if (!json) return ok(`${current.id ?? 'none'}\\n`);\n const found = rows(state, current).find((row) => row.current);\n return ok(\n `${JSON.stringify({ id: current.id, thinking: current.thinking, label: found?.label ?? null, provider: found?.provider ?? null, available: Boolean(found) }, null, 2)}\\n`\n );\n}\n\nfunction refuse(options: ModelsOptions, state: SettingsState, wanted: string): Answer {\n const at = wanted.indexOf('/');\n const providerId = at > 0 ? wanted.slice(0, at) : '';\n const modelId = wanted.slice(at + 1);\n const disconnected = state.accounts.find(\n (entry) => entry.id === providerId && entry.status !== 'connected'\n );\n const known = options.catalog.getModels(providerId);\n if (disconnected && (!known.length || known.some((model) => model.id === modelId)))\n return fail(\n `${wanted} needs the ${disconnected.provider} account; connect it in Settings \u203A Accounts, then try again`\n );\n const ids = [\n ...state.models.map((choice) => choice.id),\n ...options.catalog\n .getProviders()\n .flatMap((provider) =>\n options.catalog.getModels(provider.id).map((model) => `${provider.id}/${model.id}`)\n ),\n ];\n const near = closest(wanted, ids);\n return fail(\n `there is no model ${wanted}${near.length ? `; the closest are ${near.join(', ')}` : ''}`\n );\n}\n\nasync function use(\n options: ModelsOptions,\n argv: readonly string[],\n caller: string | null,\n context: Context\n): Promise<Answer> {\n const rest: string[] = [];\n let thinking: string | undefined;\n for (let at = 0; at < argv.length; at++) {\n const arg = argv[at] as string;\n if (arg === '--thinking') {\n thinking = argv[++at];\n if (thinking === undefined) return fail('--thinking needs a level', 2);\n } else if (arg.startsWith('-')) return fail(`unknown option ${arg}`, 2);\n else rest.push(arg);\n }\n if (rest.length !== 1) return { code: 2, out: USAGE };\n if (thinking !== undefined && !THINKING.has(thinking))\n return fail(`--thinking must be one of ${LEVELS}`, 2);\n const wanted = rest[0] as string;\n const state = stateOf(options);\n const choice = state.models.find((entry) => entry.id === wanted);\n if (!choice) return refuse(options, state, wanted);\n const at = wanted.indexOf('/');\n const change: AgentChange = {\n model: { provider: wanted.slice(0, at), modelId: wanted.slice(at + 1) },\n ...(thinking ? { thinkingLevel: thinking as AgentChange['thinkingLevel'] } : {}),\n };\n const conversation = await conversationOf(options.agents, caller, context);\n await conversation.configure(change, context);\n const now = await currentOf(conversation, context);\n return ok(`now using ${now.id} (${choice.label}), thinking ${now.thinking}\\n`);\n}\n\nexport function modelsCommand(options: ModelsOptions) {\n return async (argv: readonly string[], caller: string | null, context: Context) => {\n try {\n const [verb = 'list', ...rest] = argv;\n if (verb === '--help' || verb === '-h' || verb === 'help') return ok(USAGE);\n if (verb === 'use') return await use(options, rest, caller, context);\n const listing = verb === 'list' || verb === '--json';\n if (!listing && verb !== 'current') return { code: 2, out: USAGE };\n const flags = verb === '--json' ? argv : rest;\n const unknown = flags.find((arg) => arg !== '--json');\n if (unknown) return { code: 2, out: USAGE };\n const json = flags.includes('--json');\n const state = stateOf(options);\n const current = await currentOf(\n await conversationOf(options.agents, caller, context),\n context\n );\n return listing\n ? list(state, current, json, options.locked?.() ?? false)\n : show(state, current, json);\n } catch (error) {\n return fail((error as Error).message);\n }\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["at"]
|
|
7
7
|
}
|
package/dist/monitor/index.js
CHANGED
|
@@ -251,10 +251,7 @@ class Session {
|
|
|
251
251
|
at: this.#settings.now(),
|
|
252
252
|
agentId: conversations(this.#options.agents.state()).get(task.conversationId) ?? null,
|
|
253
253
|
kind: "task",
|
|
254
|
-
message: redacted(
|
|
255
|
-
outcome.status === "faulted" ? outcome.error.message : outcome.reason,
|
|
256
|
-
this.#settings.secrets()
|
|
257
|
-
)
|
|
254
|
+
message: redacted(outcome.status === "faulted" ? outcome.error.message : outcome.reason)
|
|
258
255
|
});
|
|
259
256
|
return true;
|
|
260
257
|
}
|
|
@@ -271,7 +268,6 @@ class Session {
|
|
|
271
268
|
return at;
|
|
272
269
|
}
|
|
273
270
|
#agent(agent, view, tools) {
|
|
274
|
-
const secrets = this.#settings.secrets();
|
|
275
271
|
const liveDoc = view?.docs["pi.live"];
|
|
276
272
|
for (const slot of liveDoc?.tools ?? [])
|
|
277
273
|
if (slot.taskId !== void 0) tools.set(String(slot.taskId), slot.name);
|
|
@@ -281,7 +277,7 @@ class Session {
|
|
|
281
277
|
const retry = generation?.retry ? {
|
|
282
278
|
attempt: generation.attempt,
|
|
283
279
|
since: this.#since(`retry:${agent.id}`),
|
|
284
|
-
error: redacted(generation.retry.error
|
|
280
|
+
error: redacted(generation.retry.error)
|
|
285
281
|
} : null;
|
|
286
282
|
if (retry)
|
|
287
283
|
this.#problem({
|
|
@@ -292,7 +288,7 @@ class Session {
|
|
|
292
288
|
message: retry.error
|
|
293
289
|
});
|
|
294
290
|
const last = lastAssistant(view);
|
|
295
|
-
const failed = last?.message.stopReason === "error" ? redacted(last.message.errorMessage || "error"
|
|
291
|
+
const failed = last?.message.stopReason === "error" ? redacted(last.message.errorMessage || "error") : null;
|
|
296
292
|
if (failed && last)
|
|
297
293
|
this.#problem({
|
|
298
294
|
id: `turn:${last.id}`,
|
|
@@ -344,7 +340,7 @@ class Session {
|
|
|
344
340
|
pgid,
|
|
345
341
|
user: uid === void 0 ? null : this.#users.get(uid) ?? (uid === 0 ? "root" : `uid ${uid}`),
|
|
346
342
|
agentId: groups.get(pgid) ?? null,
|
|
347
|
-
command: commandLine(argv
|
|
343
|
+
command: commandLine(argv),
|
|
348
344
|
state: zombie ? "Z" : "S",
|
|
349
345
|
started: entry.started ?? 0,
|
|
350
346
|
zombie: zombie ? this.#since(`zombie:${entry.pid}`) : null,
|
|
@@ -404,8 +400,7 @@ function createMonitor(options) {
|
|
|
404
400
|
psMs: options.psMs ?? PS_MS,
|
|
405
401
|
psTimeoutMs: options.psTimeoutMs ?? PS_TIMEOUT_MS,
|
|
406
402
|
throttleMs: options.throttleMs ?? THROTTLE_MS,
|
|
407
|
-
usageMs: options.usageMs ?? USAGE_MS
|
|
408
|
-
secrets: () => options.secrets?.() ?? []
|
|
403
|
+
usageMs: options.usageMs ?? USAGE_MS
|
|
409
404
|
};
|
|
410
405
|
const { now, timers, context } = settings;
|
|
411
406
|
const ttlMs = options.ttlMs ?? TTL_MS;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/monitor/index.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n type Context,\n type JsonValue,\n type ReplicatedState,\n replicatedState,\n} from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type {\n CommitPublication,\n ConversationView,\n Harness,\n TaskGraph,\n TaskGraphNode,\n TaskGraphWatch,\n TaskRecord,\n UsageState,\n} from '@earendil-works/pi-durable';\nimport { type AgentsState, live } from '../agents.ts';\nimport { contextTokens } from '../context.ts';\nimport type {\n MonitorAgent,\n MonitorFeed,\n MonitorLease,\n MonitorProblem,\n MonitorProcess,\n MonitorTask,\n} from '../services.ts';\nimport { commandLine, program, redacted } from './redact.ts';\n\nexport interface PsEntry {\n pid: number;\n ppid?: number;\n pgid?: number;\n argv?: readonly string[];\n tty?: unknown;\n started?: number;\n state?: string;\n uid?: number;\n rss?: number;\n utime?: number;\n stime?: number;\n}\n\nexport interface CpuMark {\n started: number;\n total: number;\n at: number;\n}\n\nexport interface CpuReading {\n marks: Map<number, CpuMark>;\n shares: Map<number, number | null>;\n}\n\nfunction timed(entry: PsEntry): entry is PsEntry & { utime: number; stime: number } {\n return typeof entry.utime === 'number' && typeof entry.stime === 'number';\n}\n\nexport function cpuShares(\n entries: readonly PsEntry[],\n previous: ReadonlyMap<number, CpuMark>,\n at: number\n): CpuReading {\n const marks = new Map<number, CpuMark>();\n const shares = new Map<number, number | null>();\n for (const entry of entries) {\n if (!timed(entry)) continue;\n const mark = { started: entry.started ?? 0, total: entry.utime + entry.stime, at };\n const last = previous.get(entry.pid);\n marks.set(entry.pid, mark);\n shares.set(\n entry.pid,\n last && last.started === mark.started && mark.total >= last.total && at > last.at\n ? Math.round(((mark.total - last.total) / (at - last.at)) * 1000) / 1000\n : null\n );\n }\n return { marks, shares };\n}\n\nexport function agentCpu(processes: readonly MonitorProcess[], agentId: string): number | null {\n if (!processes.some((row) => typeof row.cpu === 'number')) return null;\n let sum = 0;\n for (const row of processes) if (row.agentId === agentId) sum += row.cpu ?? 0;\n return Math.round(sum * 1000) / 1000;\n}\n\nexport interface Timers {\n set(run: () => void, ms: number): unknown;\n clear(handle: unknown): void;\n}\n\nexport interface MonitorOptions {\n harness: Pick<Harness, 'watchTaskGraph' | 'usage' | 'subscribeCommits' | 'inspect'>;\n agents: { state(): Readonly<AgentsState>; onChange(listener: () => void): () => void };\n views: ReplicatedState<Record<string, ConversationView>>;\n kernel?: { ps?(): Promise<readonly PsEntry[]> };\n groups?: { owned(owner: number): number[] };\n users?: () => Promise<readonly { name: string; uid: number }[]>;\n secrets?: () => readonly string[];\n now?: () => number;\n timers?: Timers;\n ttlMs?: number;\n psMs?: number;\n psTimeoutMs?: number;\n throttleMs?: number;\n usageMs?: number;\n context?: Context;\n}\n\nexport interface Monitor {\n readonly state: ReplicatedState<MonitorFeed>;\n readonly viewState: ReplicatedState<MonitorFeed>;\n open(lease: string | null, resync: boolean, context: Context): Promise<MonitorLease>;\n close(lease: string, context: Context): Promise<void>;\n active(): boolean;\n dispose(): Promise<void>;\n}\n\nexport const TTL_MS = 30000;\nexport const PS_MS = 2000;\nexport const PS_TIMEOUT_MS = 5000;\nexport const THROTTLE_MS = 1000;\nexport const USAGE_MS = 2000;\nexport const PROBLEMS_MAX = 50;\n\nexport const globalTimers: Timers = {\n set: (run, ms) => setTimeout(run, ms),\n clear: (handle) => clearTimeout(handle as ReturnType<typeof setTimeout>),\n};\n\nexport function emptyFeed(): MonitorFeed {\n return {\n open: false,\n at: 0,\n usage: null,\n agents: [],\n tasks: [],\n processes: null,\n kernel: 'checking',\n problems: [],\n paused: false,\n };\n}\n\ninterface Live {\n run?: unknown;\n generation?: { attempt: number; retry?: { at: number; error: string } };\n tools?: { name: string; status: string; taskId?: unknown }[];\n}\n\ninterface ModelMessage {\n stopReason?: string;\n errorMessage?: string;\n}\n\nexport function totals(usage: UsageState): { tokens: number; cost: number; free: boolean } {\n let tokens = 0;\n let cost = 0;\n for (const bucket of [usage.models, usage.tools])\n for (const entry of Object.values(bucket)) {\n tokens += entry.totalTokens ?? 0;\n cost += entry.cost?.total ?? 0;\n }\n return { tokens, cost, free: cost === 0 };\n}\n\nfunction phaseOf(node: TaskGraphNode): string {\n return 'phase' in node.state ? node.state.phase : node.state.outcome;\n}\n\nfunction lastAssistant(view: ConversationView | undefined) {\n const entries = view?.entries ?? [];\n for (let at = entries.length - 1; at >= 0; at--) {\n const entry = entries[at] as (typeof entries)[number];\n if (entry.kind === 'pi.assistant')\n return { id: String(entry.id), message: (entry.model?.[0] ?? {}) as ModelMessage };\n }\n return undefined;\n}\n\nfunction conversations(state: Readonly<AgentsState>): Map<number, string> {\n const out = new Map<number, string>();\n for (const [id, scoop] of Object.entries(state.scoops)) out.set(scoop.conversation, id);\n for (const [id, cone] of Object.entries(state.cones)) out.set(cone.conversation, id);\n return out;\n}\n\nfunction liveAgents(state: Readonly<AgentsState>) {\n const cones = Object.entries(state.cones).map(([id, cone]) => ({\n id,\n name: cone.name,\n kind: 'cone' as const,\n parentId: null,\n conversation: cone.conversation,\n }));\n const scoops = Object.entries(state.scoops)\n .filter(([, scoop]) => live(scoop))\n .map(([id, scoop]) => ({\n id,\n name: scoop.name,\n kind: 'scoop' as const,\n parentId: scoop.parent,\n conversation: scoop.conversation,\n }));\n return [...cones, ...scoops];\n}\n\nexport function narrowed(feed: MonitorFeed, programs: ReadonlyMap<number, string>): MonitorFeed {\n if (!feed.processes) return feed;\n return {\n ...feed,\n processes: feed.processes.map((row) => ({ ...row, command: programs.get(row.pid) ?? '' })),\n };\n}\n\ninterface Settings {\n now: () => number;\n timers: Timers;\n context: Context;\n psMs: number;\n psTimeoutMs: number;\n throttleMs: number;\n usageMs: number;\n secrets: () => readonly string[];\n}\n\ntype Agent = ReturnType<typeof liveAgents>[number];\n\nclass Session {\n stopped = false;\n readonly #options: MonitorOptions;\n readonly #settings: Settings;\n readonly #publish: (feed: MonitorFeed, view: MonitorFeed) => void;\n readonly #off: (() => void)[] = [];\n readonly #handles = new Set<unknown>();\n #watch: TaskGraphWatch | undefined;\n #graph: TaskGraph = { tasks: {} };\n #usage: UsageState | null = null;\n #processes: readonly PsEntry[] | null = null;\n #cpu: CpuReading = { marks: new Map(), shares: new Map() };\n #kernel: MonitorFeed['kernel'];\n #users = new Map<number, string>();\n #paused = false;\n #problems: MonitorProblem[] = [];\n #seen = new Map<string, number>();\n #next = new Map<string, number>();\n #build: unknown;\n #usageTimer: unknown;\n #lastBuild = Number.NEGATIVE_INFINITY;\n #last = '';\n\n constructor(\n options: MonitorOptions,\n settings: Settings,\n publish: (feed: MonitorFeed, view: MonitorFeed) => void\n ) {\n this.#options = options;\n this.#settings = settings;\n this.#publish = publish;\n this.#kernel = options.kernel?.ps ? 'checking' : 'unreachable';\n }\n\n start(): void {\n const options = this.#options;\n this.#off.push(\n options.harness.subscribeCommits((publication) => this.#commit(publication)),\n options.agents.onChange(() => this.schedule()),\n options.views.subscribe(() => this.schedule())\n );\n void options.harness.watchTaskGraph(this.#settings.context).then(\n (watch) => this.#watching(watch),\n () => undefined\n );\n void options.users?.().then(\n (list) => {\n this.#users = new Map(list.map((user) => [user.uid, user.name]));\n this.schedule();\n },\n () => undefined\n );\n this.#poll();\n this.refresh();\n }\n\n stop(): void {\n this.stopped = true;\n for (const off of this.#off) off();\n for (const handle of this.#handles) this.#settings.timers.clear(handle);\n this.#handles.clear();\n void this.#watch?.stop();\n }\n\n refresh(): void {\n void this.#readUsage();\n void this.#options.harness.inspect(this.#settings.context).then(\n (inspection) => {\n this.#paused = inspection.scheduling === 'paused';\n this.schedule();\n },\n () => undefined\n );\n this.schedule();\n }\n\n schedule(): void {\n if (this.stopped || this.#build !== undefined) return;\n const wait = Math.max(0, this.#lastBuild + this.#settings.throttleMs - this.#settings.now());\n this.#build = this.#later(() => {\n this.#build = undefined;\n this.#emit();\n }, wait);\n }\n\n #later(task: () => void, ms: number): unknown {\n if (this.stopped) return undefined;\n const handle = this.#settings.timers.set(() => {\n this.#handles.delete(handle);\n if (!this.stopped) task();\n }, ms);\n this.#handles.add(handle);\n return handle;\n }\n\n #watching(watch: TaskGraphWatch): void {\n if (this.stopped) {\n void watch.stop();\n return;\n }\n this.#watch = watch;\n this.#graph = watch.value;\n this.schedule();\n watch.start(async (graph) => {\n this.#graph = graph;\n this.schedule();\n });\n }\n\n #readUsage(): Promise<void> {\n return this.#options.harness.usage(this.#settings.context).then(\n (usage) => {\n this.#usage = usage;\n this.schedule();\n },\n () => undefined\n );\n }\n\n #poll(): void {\n const kernel = this.#options.kernel;\n if (!kernel?.ps) return;\n let settled = false;\n const settle = (entries: readonly PsEntry[] | null) => {\n if (settled || this.stopped) return;\n settled = true;\n this.#settings.timers.clear(timeout);\n this.#handles.delete(timeout);\n this.#processes = entries;\n if (entries) this.#cpu = cpuShares(entries, this.#cpu.marks, this.#settings.now());\n this.#kernel = entries ? 'ok' : 'unreachable';\n this.schedule();\n this.#later(() => this.#poll(), this.#settings.psMs);\n };\n const timeout = this.#later(() => settle(null), this.#settings.psTimeoutMs);\n kernel.ps().then(settle, () => settle(null));\n }\n\n #problem(entry: MonitorProblem): void {\n if (this.#problems.some((known) => known.id === entry.id)) return;\n this.#problems.unshift(entry);\n this.#problems.length = Math.min(this.#problems.length, PROBLEMS_MAX);\n }\n\n #commit(publication: CommitPublication): void {\n let changed = false;\n for (const change of publication.changes) {\n if (change.type === 'task') changed = this.#failed(change.value) || changed;\n else if (change.type === 'document' && change.record.kind === 'pi.usage')\n this.#usageChanged();\n }\n if (changed) this.schedule();\n }\n\n #failed(task: TaskRecord<JsonValue, JsonValue, JsonValue>): boolean {\n if (task.state.status !== 'terminal') return false;\n const outcome = task.state.outcome;\n if (outcome.status !== 'faulted' && outcome.status !== 'orphaned') return false;\n this.#problem({\n id: `task:${task.id}`,\n at: this.#settings.now(),\n agentId: conversations(this.#options.agents.state()).get(task.conversationId) ?? null,\n kind: 'task',\n message: redacted(\n outcome.status === 'faulted' ? outcome.error.message : outcome.reason,\n this.#settings.secrets()\n ),\n });\n return true;\n }\n\n #usageChanged(): void {\n if (this.#usageTimer !== undefined) return;\n this.#usageTimer = this.#later(() => {\n this.#usageTimer = undefined;\n void this.#readUsage();\n }, this.#settings.usageMs);\n }\n\n #since(key: string): number {\n const at = this.#seen.get(key) ?? this.#settings.now();\n this.#next.set(key, at);\n return at;\n }\n\n #agent(agent: Agent, view: ConversationView | undefined, tools: Map<string, string>) {\n const secrets = this.#settings.secrets();\n const liveDoc = view?.docs['pi.live'] as Live | undefined;\n for (const slot of liveDoc?.tools ?? [])\n if (slot.taskId !== undefined) tools.set(String(slot.taskId), slot.name);\n const inbox = view?.docs['pi.inbox'] as { items?: unknown[] } | undefined;\n const doc = view?.docs['pi.agent'] as\n | { model?: { provider: string; modelId: string } }\n | undefined;\n const generation = liveDoc?.generation;\n const retry = generation?.retry\n ? {\n attempt: generation.attempt,\n since: this.#since(`retry:${agent.id}`),\n error: redacted(generation.retry.error, secrets),\n }\n : null;\n if (retry)\n this.#problem({\n id: `retry:${agent.id}:${retry.since}`,\n at: retry.since,\n agentId: agent.id,\n kind: 'retry',\n message: retry.error,\n });\n const last = lastAssistant(view);\n const failed =\n last?.message.stopReason === 'error'\n ? redacted(last.message.errorMessage || 'error', secrets)\n : null;\n if (failed && last)\n this.#problem({\n id: `turn:${last.id}`,\n at: this.#settings.now(),\n agentId: agent.id,\n kind: 'turn',\n message: failed,\n });\n return {\n id: agent.id,\n name: agent.name,\n kind: agent.kind,\n parentId: agent.parentId,\n model: doc?.model ? `${doc.model.provider}/${doc.model.modelId}` : null,\n running: Boolean(liveDoc?.run),\n queued: inbox?.items?.length ?? 0,\n tool: liveDoc?.tools?.find((slot) => slot.status === 'running')?.name ?? null,\n retry,\n failed,\n context: contextTokens(view),\n };\n }\n\n #task(node: TaskGraphNode, owners: Map<number, string>, details: Map<string, string>) {\n const id = String(node.id);\n const status = node.state.status;\n return {\n id,\n kind: node.kind,\n detail: details.get(id) ?? null,\n agentId: owners.get(node.conversationId) ?? null,\n owner: node.owner === undefined ? null : String(node.owner),\n status,\n phase: phaseOf(node),\n background: node.background,\n aborting: node.abortRequested ? this.#since(`abort:${id}`) : null,\n since: this.#since(`task:${id}:${status}`),\n waits: node.state.status === 'waiting' ? node.state.on.length : 0,\n };\n }\n\n #process(entry: PsEntry, groups: Map<number, string>, programs: Map<number, string>) {\n const argv = entry.argv ?? [];\n const pgid = entry.pgid ?? entry.pid;\n const zombie = entry.state === 'Z';\n programs.set(entry.pid, program(argv));\n const uid = entry.uid;\n return {\n pid: entry.pid,\n ppid: entry.ppid ?? 0,\n pgid,\n user:\n uid === undefined ? null : (this.#users.get(uid) ?? (uid === 0 ? 'root' : `uid ${uid}`)),\n agentId: groups.get(pgid) ?? null,\n command: commandLine(argv, this.#settings.secrets()),\n state: zombie ? ('Z' as const) : ('S' as const),\n started: entry.started ?? 0,\n zombie: zombie ? this.#since(`zombie:${entry.pid}`) : null,\n tty: Boolean(entry.tty),\n rss: typeof entry.rss === 'number' ? entry.rss : null,\n ...(timed(entry)\n ? { utime: entry.utime, stime: entry.stime, cpu: this.#cpu.shares.get(entry.pid) ?? null }\n : {}),\n };\n }\n\n #emit(): void {\n this.#lastBuild = this.#settings.now();\n this.#next = new Map();\n const registry = this.#options.agents.state();\n const views = this.#options.views.value ?? {};\n const agents = liveAgents(registry);\n const details = new Map<string, string>();\n const rows: MonitorAgent[] = agents.map((agent) =>\n this.#agent(agent, views[agent.id], details)\n );\n for (const scoop of Object.values(registry.scoops))\n details.set(String(scoop.anchor), scoop.name);\n const owners = conversations(registry);\n const tasks: MonitorTask[] = Object.values(this.#graph.tasks).map((node) =>\n this.#task(node, owners, details)\n );\n const groups = new Map<number, string>();\n for (const agent of agents)\n for (const pgid of this.#options.groups?.owned(agent.conversation) ?? [])\n groups.set(pgid, agent.id);\n const programs = new Map<number, string>();\n const entries = this.#processes;\n const processes: MonitorProcess[] | null =\n entries?.map((entry) => this.#process(entry, groups, programs)) ?? null;\n if (entries?.some(timed))\n for (const row of rows) row.cpu = agentCpu(processes as MonitorProcess[], row.id);\n this.#seen = this.#next;\n const feed: MonitorFeed = {\n open: true,\n at: this.#lastBuild,\n usage: this.#usage ? totals(this.#usage) : null,\n agents: rows,\n tasks,\n processes,\n kernel: this.#kernel,\n problems: [...this.#problems],\n paused: this.#paused,\n };\n const key = JSON.stringify({ ...feed, at: 0 });\n if (key === this.#last) return;\n this.#last = key;\n this.#publish(feed, narrowed(feed, programs));\n }\n}\n\nexport function createMonitor(options: MonitorOptions): Monitor {\n const settings: Settings = {\n now: options.now ?? Date.now,\n timers: options.timers ?? globalTimers,\n context: options.context ?? BACKGROUND_CONTEXT,\n psMs: options.psMs ?? PS_MS,\n psTimeoutMs: options.psTimeoutMs ?? PS_TIMEOUT_MS,\n throttleMs: options.throttleMs ?? THROTTLE_MS,\n usageMs: options.usageMs ?? USAGE_MS,\n secrets: () => options.secrets?.() ?? [],\n };\n const { now, timers, context } = settings;\n const ttlMs = options.ttlMs ?? TTL_MS;\n const state = replicatedState<MonitorFeed>(emptyFeed());\n const viewState = replicatedState<MonitorFeed>(emptyFeed());\n const leases = new Map<string, number>();\n let session: Session | undefined;\n let sweep: unknown;\n const publish = (feed: MonitorFeed, view: MonitorFeed) => {\n state.replace(context, feed);\n viewState.replace(context, view);\n };\n const stop = () => {\n if (sweep !== undefined) timers.clear(sweep);\n sweep = undefined;\n const current = session;\n if (!current) return;\n session = undefined;\n current.stop();\n publish(\n { ...(state.value as MonitorFeed), open: false },\n { ...(viewState.value as MonitorFeed), open: false }\n );\n };\n const arm = () => {\n if (sweep !== undefined) timers.clear(sweep);\n sweep = timers.set(expire, Math.max(0, Math.min(...leases.values()) - now()));\n };\n const expire = () => {\n sweep = undefined;\n const at = now();\n for (const [lease, until] of [...leases]) if (until <= at) leases.delete(lease);\n if (leases.size) arm();\n else stop();\n };\n return {\n state,\n viewState,\n async open(lease, resync) {\n const id = lease ?? crypto.randomUUID();\n leases.set(id, now() + ttlMs);\n arm();\n if (!session) {\n session = new Session(options, settings, publish);\n session.start();\n } else if (resync) session.refresh();\n return { lease: id, ttlMs };\n },\n async close(lease) {\n if (!leases.delete(lease)) return;\n if (leases.size) arm();\n else stop();\n },\n active: () => session !== undefined,\n async dispose() {\n leases.clear();\n stop();\n },\n };\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import {\n type Context,\n type JsonValue,\n type ReplicatedState,\n replicatedState,\n} from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type {\n CommitPublication,\n ConversationView,\n Harness,\n TaskGraph,\n TaskGraphNode,\n TaskGraphWatch,\n TaskRecord,\n UsageState,\n} from '@earendil-works/pi-durable';\nimport { type AgentsState, live } from '../agents.ts';\nimport { contextTokens } from '../context.ts';\nimport type {\n MonitorAgent,\n MonitorFeed,\n MonitorLease,\n MonitorProblem,\n MonitorProcess,\n MonitorTask,\n} from '../services.ts';\nimport { commandLine, program, redacted } from './redact.ts';\n\nexport interface PsEntry {\n pid: number;\n ppid?: number;\n pgid?: number;\n argv?: readonly string[];\n tty?: unknown;\n started?: number;\n state?: string;\n uid?: number;\n rss?: number;\n utime?: number;\n stime?: number;\n}\n\nexport interface CpuMark {\n started: number;\n total: number;\n at: number;\n}\n\nexport interface CpuReading {\n marks: Map<number, CpuMark>;\n shares: Map<number, number | null>;\n}\n\nfunction timed(entry: PsEntry): entry is PsEntry & { utime: number; stime: number } {\n return typeof entry.utime === 'number' && typeof entry.stime === 'number';\n}\n\nexport function cpuShares(\n entries: readonly PsEntry[],\n previous: ReadonlyMap<number, CpuMark>,\n at: number\n): CpuReading {\n const marks = new Map<number, CpuMark>();\n const shares = new Map<number, number | null>();\n for (const entry of entries) {\n if (!timed(entry)) continue;\n const mark = { started: entry.started ?? 0, total: entry.utime + entry.stime, at };\n const last = previous.get(entry.pid);\n marks.set(entry.pid, mark);\n shares.set(\n entry.pid,\n last && last.started === mark.started && mark.total >= last.total && at > last.at\n ? Math.round(((mark.total - last.total) / (at - last.at)) * 1000) / 1000\n : null\n );\n }\n return { marks, shares };\n}\n\nexport function agentCpu(processes: readonly MonitorProcess[], agentId: string): number | null {\n if (!processes.some((row) => typeof row.cpu === 'number')) return null;\n let sum = 0;\n for (const row of processes) if (row.agentId === agentId) sum += row.cpu ?? 0;\n return Math.round(sum * 1000) / 1000;\n}\n\nexport interface Timers {\n set(run: () => void, ms: number): unknown;\n clear(handle: unknown): void;\n}\n\nexport interface MonitorOptions {\n harness: Pick<Harness, 'watchTaskGraph' | 'usage' | 'subscribeCommits' | 'inspect'>;\n agents: { state(): Readonly<AgentsState>; onChange(listener: () => void): () => void };\n views: ReplicatedState<Record<string, ConversationView>>;\n kernel?: { ps?(): Promise<readonly PsEntry[]> };\n groups?: { owned(owner: number): number[] };\n users?: () => Promise<readonly { name: string; uid: number }[]>;\n now?: () => number;\n timers?: Timers;\n ttlMs?: number;\n psMs?: number;\n psTimeoutMs?: number;\n throttleMs?: number;\n usageMs?: number;\n context?: Context;\n}\n\nexport interface Monitor {\n readonly state: ReplicatedState<MonitorFeed>;\n readonly viewState: ReplicatedState<MonitorFeed>;\n open(lease: string | null, resync: boolean, context: Context): Promise<MonitorLease>;\n close(lease: string, context: Context): Promise<void>;\n active(): boolean;\n dispose(): Promise<void>;\n}\n\nexport const TTL_MS = 30000;\nexport const PS_MS = 2000;\nexport const PS_TIMEOUT_MS = 5000;\nexport const THROTTLE_MS = 1000;\nexport const USAGE_MS = 2000;\nexport const PROBLEMS_MAX = 50;\n\nexport const globalTimers: Timers = {\n set: (run, ms) => setTimeout(run, ms),\n clear: (handle) => clearTimeout(handle as ReturnType<typeof setTimeout>),\n};\n\nexport function emptyFeed(): MonitorFeed {\n return {\n open: false,\n at: 0,\n usage: null,\n agents: [],\n tasks: [],\n processes: null,\n kernel: 'checking',\n problems: [],\n paused: false,\n };\n}\n\ninterface Live {\n run?: unknown;\n generation?: { attempt: number; retry?: { at: number; error: string } };\n tools?: { name: string; status: string; taskId?: unknown }[];\n}\n\ninterface ModelMessage {\n stopReason?: string;\n errorMessage?: string;\n}\n\nexport function totals(usage: UsageState): { tokens: number; cost: number; free: boolean } {\n let tokens = 0;\n let cost = 0;\n for (const bucket of [usage.models, usage.tools])\n for (const entry of Object.values(bucket)) {\n tokens += entry.totalTokens ?? 0;\n cost += entry.cost?.total ?? 0;\n }\n return { tokens, cost, free: cost === 0 };\n}\n\nfunction phaseOf(node: TaskGraphNode): string {\n return 'phase' in node.state ? node.state.phase : node.state.outcome;\n}\n\nfunction lastAssistant(view: ConversationView | undefined) {\n const entries = view?.entries ?? [];\n for (let at = entries.length - 1; at >= 0; at--) {\n const entry = entries[at] as (typeof entries)[number];\n if (entry.kind === 'pi.assistant')\n return { id: String(entry.id), message: (entry.model?.[0] ?? {}) as ModelMessage };\n }\n return undefined;\n}\n\nfunction conversations(state: Readonly<AgentsState>): Map<number, string> {\n const out = new Map<number, string>();\n for (const [id, scoop] of Object.entries(state.scoops)) out.set(scoop.conversation, id);\n for (const [id, cone] of Object.entries(state.cones)) out.set(cone.conversation, id);\n return out;\n}\n\nfunction liveAgents(state: Readonly<AgentsState>) {\n const cones = Object.entries(state.cones).map(([id, cone]) => ({\n id,\n name: cone.name,\n kind: 'cone' as const,\n parentId: null,\n conversation: cone.conversation,\n }));\n const scoops = Object.entries(state.scoops)\n .filter(([, scoop]) => live(scoop))\n .map(([id, scoop]) => ({\n id,\n name: scoop.name,\n kind: 'scoop' as const,\n parentId: scoop.parent,\n conversation: scoop.conversation,\n }));\n return [...cones, ...scoops];\n}\n\nexport function narrowed(feed: MonitorFeed, programs: ReadonlyMap<number, string>): MonitorFeed {\n if (!feed.processes) return feed;\n return {\n ...feed,\n processes: feed.processes.map((row) => ({ ...row, command: programs.get(row.pid) ?? '' })),\n };\n}\n\ninterface Settings {\n now: () => number;\n timers: Timers;\n context: Context;\n psMs: number;\n psTimeoutMs: number;\n throttleMs: number;\n usageMs: number;\n}\n\ntype Agent = ReturnType<typeof liveAgents>[number];\n\nclass Session {\n stopped = false;\n readonly #options: MonitorOptions;\n readonly #settings: Settings;\n readonly #publish: (feed: MonitorFeed, view: MonitorFeed) => void;\n readonly #off: (() => void)[] = [];\n readonly #handles = new Set<unknown>();\n #watch: TaskGraphWatch | undefined;\n #graph: TaskGraph = { tasks: {} };\n #usage: UsageState | null = null;\n #processes: readonly PsEntry[] | null = null;\n #cpu: CpuReading = { marks: new Map(), shares: new Map() };\n #kernel: MonitorFeed['kernel'];\n #users = new Map<number, string>();\n #paused = false;\n #problems: MonitorProblem[] = [];\n #seen = new Map<string, number>();\n #next = new Map<string, number>();\n #build: unknown;\n #usageTimer: unknown;\n #lastBuild = Number.NEGATIVE_INFINITY;\n #last = '';\n\n constructor(\n options: MonitorOptions,\n settings: Settings,\n publish: (feed: MonitorFeed, view: MonitorFeed) => void\n ) {\n this.#options = options;\n this.#settings = settings;\n this.#publish = publish;\n this.#kernel = options.kernel?.ps ? 'checking' : 'unreachable';\n }\n\n start(): void {\n const options = this.#options;\n this.#off.push(\n options.harness.subscribeCommits((publication) => this.#commit(publication)),\n options.agents.onChange(() => this.schedule()),\n options.views.subscribe(() => this.schedule())\n );\n void options.harness.watchTaskGraph(this.#settings.context).then(\n (watch) => this.#watching(watch),\n () => undefined\n );\n void options.users?.().then(\n (list) => {\n this.#users = new Map(list.map((user) => [user.uid, user.name]));\n this.schedule();\n },\n () => undefined\n );\n this.#poll();\n this.refresh();\n }\n\n stop(): void {\n this.stopped = true;\n for (const off of this.#off) off();\n for (const handle of this.#handles) this.#settings.timers.clear(handle);\n this.#handles.clear();\n void this.#watch?.stop();\n }\n\n refresh(): void {\n void this.#readUsage();\n void this.#options.harness.inspect(this.#settings.context).then(\n (inspection) => {\n this.#paused = inspection.scheduling === 'paused';\n this.schedule();\n },\n () => undefined\n );\n this.schedule();\n }\n\n schedule(): void {\n if (this.stopped || this.#build !== undefined) return;\n const wait = Math.max(0, this.#lastBuild + this.#settings.throttleMs - this.#settings.now());\n this.#build = this.#later(() => {\n this.#build = undefined;\n this.#emit();\n }, wait);\n }\n\n #later(task: () => void, ms: number): unknown {\n if (this.stopped) return undefined;\n const handle = this.#settings.timers.set(() => {\n this.#handles.delete(handle);\n if (!this.stopped) task();\n }, ms);\n this.#handles.add(handle);\n return handle;\n }\n\n #watching(watch: TaskGraphWatch): void {\n if (this.stopped) {\n void watch.stop();\n return;\n }\n this.#watch = watch;\n this.#graph = watch.value;\n this.schedule();\n watch.start(async (graph) => {\n this.#graph = graph;\n this.schedule();\n });\n }\n\n #readUsage(): Promise<void> {\n return this.#options.harness.usage(this.#settings.context).then(\n (usage) => {\n this.#usage = usage;\n this.schedule();\n },\n () => undefined\n );\n }\n\n #poll(): void {\n const kernel = this.#options.kernel;\n if (!kernel?.ps) return;\n let settled = false;\n const settle = (entries: readonly PsEntry[] | null) => {\n if (settled || this.stopped) return;\n settled = true;\n this.#settings.timers.clear(timeout);\n this.#handles.delete(timeout);\n this.#processes = entries;\n if (entries) this.#cpu = cpuShares(entries, this.#cpu.marks, this.#settings.now());\n this.#kernel = entries ? 'ok' : 'unreachable';\n this.schedule();\n this.#later(() => this.#poll(), this.#settings.psMs);\n };\n const timeout = this.#later(() => settle(null), this.#settings.psTimeoutMs);\n kernel.ps().then(settle, () => settle(null));\n }\n\n #problem(entry: MonitorProblem): void {\n if (this.#problems.some((known) => known.id === entry.id)) return;\n this.#problems.unshift(entry);\n this.#problems.length = Math.min(this.#problems.length, PROBLEMS_MAX);\n }\n\n #commit(publication: CommitPublication): void {\n let changed = false;\n for (const change of publication.changes) {\n if (change.type === 'task') changed = this.#failed(change.value) || changed;\n else if (change.type === 'document' && change.record.kind === 'pi.usage')\n this.#usageChanged();\n }\n if (changed) this.schedule();\n }\n\n #failed(task: TaskRecord<JsonValue, JsonValue, JsonValue>): boolean {\n if (task.state.status !== 'terminal') return false;\n const outcome = task.state.outcome;\n if (outcome.status !== 'faulted' && outcome.status !== 'orphaned') return false;\n this.#problem({\n id: `task:${task.id}`,\n at: this.#settings.now(),\n agentId: conversations(this.#options.agents.state()).get(task.conversationId) ?? null,\n kind: 'task',\n message: redacted(outcome.status === 'faulted' ? outcome.error.message : outcome.reason),\n });\n return true;\n }\n\n #usageChanged(): void {\n if (this.#usageTimer !== undefined) return;\n this.#usageTimer = this.#later(() => {\n this.#usageTimer = undefined;\n void this.#readUsage();\n }, this.#settings.usageMs);\n }\n\n #since(key: string): number {\n const at = this.#seen.get(key) ?? this.#settings.now();\n this.#next.set(key, at);\n return at;\n }\n\n #agent(agent: Agent, view: ConversationView | undefined, tools: Map<string, string>) {\n const liveDoc = view?.docs['pi.live'] as Live | undefined;\n for (const slot of liveDoc?.tools ?? [])\n if (slot.taskId !== undefined) tools.set(String(slot.taskId), slot.name);\n const inbox = view?.docs['pi.inbox'] as { items?: unknown[] } | undefined;\n const doc = view?.docs['pi.agent'] as\n | { model?: { provider: string; modelId: string } }\n | undefined;\n const generation = liveDoc?.generation;\n const retry = generation?.retry\n ? {\n attempt: generation.attempt,\n since: this.#since(`retry:${agent.id}`),\n error: redacted(generation.retry.error),\n }\n : null;\n if (retry)\n this.#problem({\n id: `retry:${agent.id}:${retry.since}`,\n at: retry.since,\n agentId: agent.id,\n kind: 'retry',\n message: retry.error,\n });\n const last = lastAssistant(view);\n const failed =\n last?.message.stopReason === 'error' ? redacted(last.message.errorMessage || 'error') : null;\n if (failed && last)\n this.#problem({\n id: `turn:${last.id}`,\n at: this.#settings.now(),\n agentId: agent.id,\n kind: 'turn',\n message: failed,\n });\n return {\n id: agent.id,\n name: agent.name,\n kind: agent.kind,\n parentId: agent.parentId,\n model: doc?.model ? `${doc.model.provider}/${doc.model.modelId}` : null,\n running: Boolean(liveDoc?.run),\n queued: inbox?.items?.length ?? 0,\n tool: liveDoc?.tools?.find((slot) => slot.status === 'running')?.name ?? null,\n retry,\n failed,\n context: contextTokens(view),\n };\n }\n\n #task(node: TaskGraphNode, owners: Map<number, string>, details: Map<string, string>) {\n const id = String(node.id);\n const status = node.state.status;\n return {\n id,\n kind: node.kind,\n detail: details.get(id) ?? null,\n agentId: owners.get(node.conversationId) ?? null,\n owner: node.owner === undefined ? null : String(node.owner),\n status,\n phase: phaseOf(node),\n background: node.background,\n aborting: node.abortRequested ? this.#since(`abort:${id}`) : null,\n since: this.#since(`task:${id}:${status}`),\n waits: node.state.status === 'waiting' ? node.state.on.length : 0,\n };\n }\n\n #process(entry: PsEntry, groups: Map<number, string>, programs: Map<number, string>) {\n const argv = entry.argv ?? [];\n const pgid = entry.pgid ?? entry.pid;\n const zombie = entry.state === 'Z';\n programs.set(entry.pid, program(argv));\n const uid = entry.uid;\n return {\n pid: entry.pid,\n ppid: entry.ppid ?? 0,\n pgid,\n user:\n uid === undefined ? null : (this.#users.get(uid) ?? (uid === 0 ? 'root' : `uid ${uid}`)),\n agentId: groups.get(pgid) ?? null,\n command: commandLine(argv),\n state: zombie ? ('Z' as const) : ('S' as const),\n started: entry.started ?? 0,\n zombie: zombie ? this.#since(`zombie:${entry.pid}`) : null,\n tty: Boolean(entry.tty),\n rss: typeof entry.rss === 'number' ? entry.rss : null,\n ...(timed(entry)\n ? { utime: entry.utime, stime: entry.stime, cpu: this.#cpu.shares.get(entry.pid) ?? null }\n : {}),\n };\n }\n\n #emit(): void {\n this.#lastBuild = this.#settings.now();\n this.#next = new Map();\n const registry = this.#options.agents.state();\n const views = this.#options.views.value ?? {};\n const agents = liveAgents(registry);\n const details = new Map<string, string>();\n const rows: MonitorAgent[] = agents.map((agent) =>\n this.#agent(agent, views[agent.id], details)\n );\n for (const scoop of Object.values(registry.scoops))\n details.set(String(scoop.anchor), scoop.name);\n const owners = conversations(registry);\n const tasks: MonitorTask[] = Object.values(this.#graph.tasks).map((node) =>\n this.#task(node, owners, details)\n );\n const groups = new Map<number, string>();\n for (const agent of agents)\n for (const pgid of this.#options.groups?.owned(agent.conversation) ?? [])\n groups.set(pgid, agent.id);\n const programs = new Map<number, string>();\n const entries = this.#processes;\n const processes: MonitorProcess[] | null =\n entries?.map((entry) => this.#process(entry, groups, programs)) ?? null;\n if (entries?.some(timed))\n for (const row of rows) row.cpu = agentCpu(processes as MonitorProcess[], row.id);\n this.#seen = this.#next;\n const feed: MonitorFeed = {\n open: true,\n at: this.#lastBuild,\n usage: this.#usage ? totals(this.#usage) : null,\n agents: rows,\n tasks,\n processes,\n kernel: this.#kernel,\n problems: [...this.#problems],\n paused: this.#paused,\n };\n const key = JSON.stringify({ ...feed, at: 0 });\n if (key === this.#last) return;\n this.#last = key;\n this.#publish(feed, narrowed(feed, programs));\n }\n}\n\nexport function createMonitor(options: MonitorOptions): Monitor {\n const settings: Settings = {\n now: options.now ?? Date.now,\n timers: options.timers ?? globalTimers,\n context: options.context ?? BACKGROUND_CONTEXT,\n psMs: options.psMs ?? PS_MS,\n psTimeoutMs: options.psTimeoutMs ?? PS_TIMEOUT_MS,\n throttleMs: options.throttleMs ?? THROTTLE_MS,\n usageMs: options.usageMs ?? USAGE_MS,\n };\n const { now, timers, context } = settings;\n const ttlMs = options.ttlMs ?? TTL_MS;\n const state = replicatedState<MonitorFeed>(emptyFeed());\n const viewState = replicatedState<MonitorFeed>(emptyFeed());\n const leases = new Map<string, number>();\n let session: Session | undefined;\n let sweep: unknown;\n const publish = (feed: MonitorFeed, view: MonitorFeed) => {\n state.replace(context, feed);\n viewState.replace(context, view);\n };\n const stop = () => {\n if (sweep !== undefined) timers.clear(sweep);\n sweep = undefined;\n const current = session;\n if (!current) return;\n session = undefined;\n current.stop();\n publish(\n { ...(state.value as MonitorFeed), open: false },\n { ...(viewState.value as MonitorFeed), open: false }\n );\n };\n const arm = () => {\n if (sweep !== undefined) timers.clear(sweep);\n sweep = timers.set(expire, Math.max(0, Math.min(...leases.values()) - now()));\n };\n const expire = () => {\n sweep = undefined;\n const at = now();\n for (const [lease, until] of [...leases]) if (until <= at) leases.delete(lease);\n if (leases.size) arm();\n else stop();\n };\n return {\n state,\n viewState,\n async open(lease, resync) {\n const id = lease ?? crypto.randomUUID();\n leases.set(id, now() + ttlMs);\n arm();\n if (!session) {\n session = new Session(options, settings, publish);\n session.start();\n } else if (resync) session.refresh();\n return { lease: id, ttlMs };\n },\n async close(lease) {\n if (!leases.delete(lease)) return;\n if (leases.size) arm();\n else stop();\n },\n active: () => session !== undefined,\n async dispose() {\n leases.clear();\n stop();\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/monitor/redact.js
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import { scrub } from "../mcp/credentials.js";
|
|
2
1
|
import { redactSecrets } from "../memory/format.js";
|
|
3
2
|
const TEXT_MAX = 160;
|
|
4
3
|
function cut(text, max = TEXT_MAX) {
|
|
5
4
|
return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
|
|
6
5
|
}
|
|
7
|
-
function redacted(text
|
|
8
|
-
return cut(redactSecrets(
|
|
6
|
+
function redacted(text) {
|
|
7
|
+
return cut(redactSecrets(text).text.replace(/\s+/g, " ").trim());
|
|
9
8
|
}
|
|
10
9
|
const EXPORTS = /^export (?:[A-Z_][A-Z0-9_]*='(?:[^']|'\\'')*' ?)+; /;
|
|
11
|
-
function commandLine(argv
|
|
12
|
-
return redacted(argv.map((arg) => arg.replace(EXPORTS, "")).join(" ")
|
|
10
|
+
function commandLine(argv) {
|
|
11
|
+
return redacted(argv.map((arg) => arg.replace(EXPORTS, "")).join(" "));
|
|
13
12
|
}
|
|
14
13
|
function program(argv) {
|
|
15
14
|
const first = argv[0] ?? "";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/monitor/redact.ts"],
|
|
4
|
-
"sourcesContent": ["import {
|
|
5
|
-
"mappings": "AAAA,SAAS,
|
|
4
|
+
"sourcesContent": ["import { redactSecrets } from '../memory/format.ts';\n\nexport const TEXT_MAX = 160;\n\nexport function cut(text: string, max = TEXT_MAX): string {\n return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;\n}\n\nexport function redacted(text: string): string {\n return cut(redactSecrets(text).text.replace(/\\s+/g, ' ').trim());\n}\n\nconst EXPORTS = /^export (?:[A-Z_][A-Z0-9_]*='(?:[^']|'\\\\'')*' ?)+; /;\n\nexport function commandLine(argv: readonly string[]): string {\n return redacted(argv.map((arg) => arg.replace(EXPORTS, '')).join(' '));\n}\n\nexport function program(argv: readonly string[]): string {\n const first = argv[0] ?? '';\n return cut(first.split('/').pop() || first);\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,qBAAqB;AAEvB,MAAM,WAAW;AAEjB,SAAS,IAAI,MAAc,MAAM,UAAkB;AACxD,SAAO,KAAK,SAAS,MAAM,GAAG,KAAK,MAAM,GAAG,MAAM,CAAC,CAAC,WAAM;AAC5D;AAEO,SAAS,SAAS,MAAsB;AAC7C,SAAO,IAAI,cAAc,IAAI,EAAE,KAAK,QAAQ,QAAQ,GAAG,EAAE,KAAK,CAAC;AACjE;AAEA,MAAM,UAAU;AAET,SAAS,YAAY,MAAiC;AAC3D,SAAO,SAAS,KAAK,IAAI,CAAC,QAAQ,IAAI,QAAQ,SAAS,EAAE,CAAC,EAAE,KAAK,GAAG,CAAC;AACvE;AAEO,SAAS,QAAQ,MAAiC;AACvD,QAAM,QAAQ,KAAK,CAAC,KAAK;AACzB,SAAO,IAAI,MAAM,MAAM,GAAG,EAAE,IAAI,KAAK,KAAK;AAC5C;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const KEYS_IN_VAULT = "model keys are kept in seven's vault: enter them in Settings \u203A Accounts";
|
|
2
|
+
function vaultCredentials(records, env = () => void 0) {
|
|
3
|
+
return {
|
|
4
|
+
async read(providerId) {
|
|
5
|
+
const record = records.model(providerId);
|
|
6
|
+
if (!record) return void 0;
|
|
7
|
+
const extra = env(providerId);
|
|
8
|
+
return {
|
|
9
|
+
type: "api_key",
|
|
10
|
+
key: record.placeholder,
|
|
11
|
+
...extra && Object.keys(extra).length ? { env: { ...extra } } : {}
|
|
12
|
+
};
|
|
13
|
+
},
|
|
14
|
+
async list() {
|
|
15
|
+
const providers = records.state.value.filter((record) => record.kind === "model" && record.provider !== void 0).map((record) => record.provider);
|
|
16
|
+
return [...new Set(providers)].map(
|
|
17
|
+
(providerId) => ({ providerId, type: "api_key" })
|
|
18
|
+
);
|
|
19
|
+
},
|
|
20
|
+
async modify() {
|
|
21
|
+
throw new Error(KEYS_IN_VAULT);
|
|
22
|
+
},
|
|
23
|
+
async delete() {
|
|
24
|
+
throw new Error(KEYS_IN_VAULT);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
KEYS_IN_VAULT,
|
|
30
|
+
vaultCredentials
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/secrets/credentials.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Credential, CredentialInfo, CredentialStore } from '@earendil-works/pi-ai';\nimport type { VaultRecords } from './records.ts';\n\nexport const KEYS_IN_VAULT =\n \"model keys are kept in seven's vault: enter them in Settings \u203A Accounts\";\n\nexport type FieldsOf = (providerId: string) => Readonly<Record<string, string>> | undefined;\n\nexport function vaultCredentials(\n records: Pick<VaultRecords, 'model' | 'state'>,\n env: FieldsOf = () => undefined\n): CredentialStore {\n return {\n async read(providerId) {\n const record = records.model(providerId);\n if (!record) return undefined;\n const extra = env(providerId);\n return {\n type: 'api_key',\n key: record.placeholder,\n ...(extra && Object.keys(extra).length ? { env: { ...extra } } : {}),\n } satisfies Credential;\n },\n async list() {\n const providers = records.state.value\n .filter((record) => record.kind === 'model' && record.provider !== undefined)\n .map((record) => record.provider as string);\n return [...new Set(providers)].map(\n (providerId): CredentialInfo => ({ providerId, type: 'api_key' })\n );\n },\n async modify() {\n throw new Error(KEYS_IN_VAULT);\n },\n async delete() {\n throw new Error(KEYS_IN_VAULT);\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "AAGO,MAAM,gBACX;AAIK,SAAS,iBACd,SACA,MAAgB,MAAM,QACL;AACjB,SAAO;AAAA,IACL,MAAM,KAAK,YAAY;AACrB,YAAM,SAAS,QAAQ,MAAM,UAAU;AACvC,UAAI,CAAC,OAAQ,QAAO;AACpB,YAAM,QAAQ,IAAI,UAAU;AAC5B,aAAO;AAAA,QACL,MAAM;AAAA,QACN,KAAK,OAAO;AAAA,QACZ,GAAI,SAAS,OAAO,KAAK,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,IAAI,CAAC;AAAA,MACpE;AAAA,IACF;AAAA,IACA,MAAM,OAAO;AACX,YAAM,YAAY,QAAQ,MAAM,MAC7B,OAAO,CAAC,WAAW,OAAO,SAAS,WAAW,OAAO,aAAa,MAAS,EAC3E,IAAI,CAAC,WAAW,OAAO,QAAkB;AAC5C,aAAO,CAAC,GAAG,IAAI,IAAI,SAAS,CAAC,EAAE;AAAA,QAC7B,CAAC,gBAAgC,EAAE,YAAY,MAAM,UAAU;AAAA,MACjE;AAAA,IACF;AAAA,IACA,MAAM,SAAS;AACb,YAAM,IAAI,MAAM,aAAa;AAAA,IAC/B;AAAA,IACA,MAAM,SAAS;AACb,YAAM,IAAI,MAAM,aAAa;AAAA,IAC/B;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const BEDROCK_ENDPOINTS = [
|
|
2
|
+
"https://bedrock-runtime.{region}.amazonaws.com",
|
|
3
|
+
"https://bedrock-runtime-fips.{region}.amazonaws.com"
|
|
4
|
+
];
|
|
5
|
+
const NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
6
|
+
const KERNEL = /^(\d{1,5})\.kernel\.localhost$/;
|
|
7
|
+
const FACADE = 9222;
|
|
8
|
+
function plain(url) {
|
|
9
|
+
return !url.username && !url.password && (url.port === "" || url.port === "443");
|
|
10
|
+
}
|
|
11
|
+
function modelUrl(raw) {
|
|
12
|
+
const url = URL.parse(raw);
|
|
13
|
+
return !!url && url.protocol === "https:" && plain(url) && !raw.includes("{");
|
|
14
|
+
}
|
|
15
|
+
function kernelUrl(url) {
|
|
16
|
+
const port = Number(KERNEL.exec(url.hostname)?.[1] ?? 0);
|
|
17
|
+
return url.protocol === "http:" && url.port === "" && port >= 1 && port <= 65535 && port !== FACADE;
|
|
18
|
+
}
|
|
19
|
+
function mcpUrl(raw) {
|
|
20
|
+
const url = URL.parse(raw);
|
|
21
|
+
return !!url && !url.username && !url.password && (kernelUrl(url) || url.protocol === "https:" && plain(url));
|
|
22
|
+
}
|
|
23
|
+
const escaped = (text) => text.replace(/[.*+?^$()|[\]\\]/g, "\\$&");
|
|
24
|
+
function pattern(base) {
|
|
25
|
+
const trimmed = base.replace(/\/+$/, "");
|
|
26
|
+
const source = trimmed.split(/(\{[^}]+\})/).map((part) => /^\{[^}]+\}$/.test(part) ? "[^./]+" : escaped(part)).join("");
|
|
27
|
+
return new RegExp(`^${source}(?:[/?#]|$)`, "i");
|
|
28
|
+
}
|
|
29
|
+
function modelRoute(bases, records) {
|
|
30
|
+
return (request) => {
|
|
31
|
+
const url = request.url;
|
|
32
|
+
const matched = bases().filter(({ urls }) => urls.some((base) => pattern(base).test(url))).map(({ provider }) => provider);
|
|
33
|
+
const head = [url, ...[...request.headers].map(([, value]) => value)].join("\n");
|
|
34
|
+
const held = records().filter((record) => record.kind === "model" && head.includes(record.placeholder)).map((record) => record.provider);
|
|
35
|
+
const owned = matched.filter((provider) => held.includes(provider));
|
|
36
|
+
if (owned.length === 1) return owned[0];
|
|
37
|
+
if (matched.length === 1 && !held.length) return matched[0];
|
|
38
|
+
return matched.length || held.length ? null : void 0;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function modelEndpoints(bases) {
|
|
42
|
+
const seen = /* @__PURE__ */ new Set();
|
|
43
|
+
return bases.flatMap(
|
|
44
|
+
({ provider, urls }) => urls.filter(modelUrl).flatMap((url) => {
|
|
45
|
+
const key = `${provider} ${url}`;
|
|
46
|
+
if (seen.has(key)) return [];
|
|
47
|
+
seen.add(key);
|
|
48
|
+
return [{ provider, url }];
|
|
49
|
+
})
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
function mcpEndpoints(servers, tokens) {
|
|
53
|
+
return servers.filter((entry) => mcpUrl(entry.url)).map(({ server, url, names }) => {
|
|
54
|
+
const tokenUrl = tokens.get(server);
|
|
55
|
+
const valid = names.filter((name) => NAME.test(name));
|
|
56
|
+
return {
|
|
57
|
+
server,
|
|
58
|
+
url,
|
|
59
|
+
...valid.length ? { names: valid } : {},
|
|
60
|
+
...tokenUrl && modelUrl(tokenUrl) ? { tokenUrl } : {}
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function vaultEndpoints(vault) {
|
|
65
|
+
let model = [];
|
|
66
|
+
let servers = [];
|
|
67
|
+
const tokens = /* @__PURE__ */ new Map();
|
|
68
|
+
let last = "";
|
|
69
|
+
const send = async (force = false) => {
|
|
70
|
+
const set = { model, mcp: mcpEndpoints(servers, tokens) };
|
|
71
|
+
const key = JSON.stringify(set);
|
|
72
|
+
if (!vault.connected || !force && key === last) return;
|
|
73
|
+
last = key;
|
|
74
|
+
await vault.endpoints(set).catch((error) => {
|
|
75
|
+
if (last === key) last = "";
|
|
76
|
+
throw error;
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
let port = vault.state.value.port;
|
|
80
|
+
const off = vault.state.subscribe((value) => {
|
|
81
|
+
const opened = port === "none" && value.port !== "none";
|
|
82
|
+
port = value.port;
|
|
83
|
+
if (opened) void send(true).catch(() => void 0);
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
models(bases) {
|
|
87
|
+
model = modelEndpoints(bases);
|
|
88
|
+
return send();
|
|
89
|
+
},
|
|
90
|
+
servers(next) {
|
|
91
|
+
servers = next;
|
|
92
|
+
return send();
|
|
93
|
+
},
|
|
94
|
+
token(server, url) {
|
|
95
|
+
if (!tokens.has(server)) tokens.set(server, new URL(url).href);
|
|
96
|
+
return send();
|
|
97
|
+
},
|
|
98
|
+
close: off
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
BEDROCK_ENDPOINTS,
|
|
103
|
+
mcpEndpoints,
|
|
104
|
+
mcpUrl,
|
|
105
|
+
modelEndpoints,
|
|
106
|
+
modelRoute,
|
|
107
|
+
modelUrl,
|
|
108
|
+
pattern,
|
|
109
|
+
vaultEndpoints
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=endpoints.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/secrets/endpoints.ts"],
|
|
4
|
+
"sourcesContent": ["import type { McpServerEntry, ModelEndpoint } from '@ai-ecoverse/slicc-vault';\nimport type { ModelRoute } from './fetch.ts';\nimport type { AgentRecord } from './records.ts';\nimport type { Vault } from './vault.ts';\n\nexport const BEDROCK_ENDPOINTS = [\n 'https://bedrock-runtime.{region}.amazonaws.com',\n 'https://bedrock-runtime-fips.{region}.amazonaws.com',\n];\n\nconst NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;\nconst KERNEL = /^(\\d{1,5})\\.kernel\\.localhost$/;\nconst FACADE = 9222;\n\nfunction plain(url: URL): boolean {\n return !url.username && !url.password && (url.port === '' || url.port === '443');\n}\n\nexport function modelUrl(raw: string): boolean {\n const url = URL.parse(raw);\n return !!url && url.protocol === 'https:' && plain(url) && !raw.includes('{');\n}\n\nfunction kernelUrl(url: URL): boolean {\n const port = Number(KERNEL.exec(url.hostname)?.[1] ?? 0);\n return (\n url.protocol === 'http:' && url.port === '' && port >= 1 && port <= 65535 && port !== FACADE\n );\n}\n\nexport function mcpUrl(raw: string): boolean {\n const url = URL.parse(raw);\n return (\n !!url &&\n !url.username &&\n !url.password &&\n (kernelUrl(url) || (url.protocol === 'https:' && plain(url)))\n );\n}\n\nconst escaped = (text: string) => text.replace(/[.*+?^$()|[\\]\\\\]/g, '\\\\$&');\n\nexport function pattern(base: string): RegExp {\n const trimmed = base.replace(/\\/+$/, '');\n const source = trimmed\n .split(/(\\{[^}]+\\})/)\n .map((part) => (/^\\{[^}]+\\}$/.test(part) ? '[^./]+' : escaped(part)))\n .join('');\n return new RegExp(`^${source}(?:[/?#]|$)`, 'i');\n}\n\nexport interface ModelBases {\n provider: string;\n urls: readonly string[];\n}\n\nexport function modelRoute(\n bases: () => readonly ModelBases[],\n records: () => readonly AgentRecord[]\n): ModelRoute {\n return (request) => {\n const url = request.url;\n const matched = bases()\n .filter(({ urls }) => urls.some((base) => pattern(base).test(url)))\n .map(({ provider }) => provider);\n const head = [url, ...[...request.headers].map(([, value]) => value)].join('\\n');\n const held = records()\n .filter((record) => record.kind === 'model' && head.includes(record.placeholder))\n .map((record) => record.provider);\n const owned = matched.filter((provider) => held.includes(provider));\n if (owned.length === 1) return owned[0];\n if (matched.length === 1 && !held.length) return matched[0];\n return matched.length || held.length ? null : undefined;\n };\n}\n\nexport function modelEndpoints(bases: readonly ModelBases[]): ModelEndpoint[] {\n const seen = new Set<string>();\n return bases.flatMap(({ provider, urls }) =>\n urls.filter(modelUrl).flatMap((url) => {\n const key = `${provider} ${url}`;\n if (seen.has(key)) return [];\n seen.add(key);\n return [{ provider, url }];\n })\n );\n}\n\nexport interface McpServerSource {\n server: string;\n url: string;\n names: readonly string[];\n}\n\nexport function mcpEndpoints(\n servers: readonly McpServerSource[],\n tokens: ReadonlyMap<string, string>\n): McpServerEntry[] {\n return servers\n .filter((entry) => mcpUrl(entry.url))\n .map(({ server, url, names }) => {\n const tokenUrl = tokens.get(server);\n const valid = names.filter((name) => NAME.test(name));\n return {\n server,\n url,\n ...(valid.length ? { names: valid } : {}),\n ...(tokenUrl && modelUrl(tokenUrl) ? { tokenUrl } : {}),\n };\n });\n}\n\nexport interface Endpoints {\n models(bases: readonly ModelBases[]): Promise<void>;\n servers(servers: readonly McpServerSource[]): Promise<void>;\n token(server: string, url: string): Promise<void>;\n close(): void;\n}\n\nexport function vaultEndpoints(vault: Pick<Vault, 'state' | 'connected' | 'endpoints'>): Endpoints {\n let model: ModelEndpoint[] = [];\n let servers: readonly McpServerSource[] = [];\n const tokens = new Map<string, string>();\n let last = '';\n const send = async (force = false) => {\n const set = { model, mcp: mcpEndpoints(servers, tokens) };\n const key = JSON.stringify(set);\n if (!vault.connected || (!force && key === last)) return;\n last = key;\n await vault.endpoints(set).catch((error: unknown) => {\n if (last === key) last = '';\n throw error;\n });\n };\n let port = vault.state.value.port;\n const off = vault.state.subscribe((value) => {\n const opened = port === 'none' && value.port !== 'none';\n port = value.port;\n if (opened) void send(true).catch(() => undefined);\n });\n return {\n models(bases) {\n model = modelEndpoints(bases);\n return send();\n },\n servers(next) {\n servers = next;\n return send();\n },\n token(server, url) {\n if (!tokens.has(server)) tokens.set(server, new URL(url).href);\n return send();\n },\n close: off,\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|