@ai-ecoverse/slicc-agent 3.15.0 → 3.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +19 -3
  2. package/bin/agent +1 -1
  3. package/dist/control.js +49 -33
  4. package/dist/control.js.map +2 -2
  5. package/dist/gelatiere/index.js +307 -0
  6. package/dist/gelatiere/index.js.map +7 -0
  7. package/dist/gelatiere/store.js +122 -0
  8. package/dist/gelatiere/store.js.map +7 -0
  9. package/dist/main.js +14 -0
  10. package/dist/main.js.map +2 -2
  11. package/dist/memory/extract.js +252 -0
  12. package/dist/memory/extract.js.map +7 -0
  13. package/dist/memory/index.js +26 -2
  14. package/dist/memory/index.js.map +2 -2
  15. package/dist/memory/prompt.js.map +2 -2
  16. package/dist/memory/runtime.js +1 -1
  17. package/dist/memory/runtime.js.map +2 -2
  18. package/dist/scoops/cli.js +2 -0
  19. package/dist/scoops/cli.js.map +2 -2
  20. package/dist/scoops/index.js +4 -3
  21. package/dist/scoops/index.js.map +2 -2
  22. package/dist/scoops/requests.js +2 -1
  23. package/dist/scoops/requests.js.map +2 -2
  24. package/dist/services.js.map +2 -2
  25. package/dist/settings.js +12 -9
  26. package/dist/settings.js.map +2 -2
  27. package/dist/skills/index.js +1 -0
  28. package/dist/skills/index.js.map +2 -2
  29. package/dist/spectrum/agent-port.js +6 -2
  30. package/dist/spectrum/agent-port.js.map +2 -2
  31. package/dist/spectrum/messages.js +4 -3
  32. package/dist/spectrum/messages.js.map +2 -2
  33. package/dist/spectrum/settings-port.js +3 -2
  34. package/dist/spectrum/settings-port.js.map +2 -2
  35. package/dist/sprinkles/index.js +37 -29
  36. package/dist/sprinkles/index.js.map +2 -2
  37. package/dist/sprinkles/sprinkles.js +6 -0
  38. package/dist/sprinkles/sprinkles.js.map +2 -2
  39. package/dist/types/gelatiere/index.d.ts +39 -0
  40. package/dist/types/gelatiere/store.d.ts +34 -0
  41. package/dist/types/memory/extract.d.ts +48 -0
  42. package/dist/types/memory/index.d.ts +1 -0
  43. package/dist/types/memory/prompt.d.ts +2 -0
  44. package/dist/types/memory/runtime.d.ts +3 -0
  45. package/dist/types/scoops/cli.d.ts +1 -0
  46. package/dist/types/scoops/index.d.ts +1 -0
  47. package/dist/types/scoops/requests.d.ts +1 -1
  48. package/dist/types/services.d.ts +2 -0
  49. package/dist/types/spectrum/agent-port.d.ts +1 -1
  50. package/dist/types/sprinkles/index.d.ts +1 -0
  51. package/dist/types/sprinkles/sprinkles.d.ts +3 -0
  52. package/package.json +1 -1
  53. package/packages/vfs-root/agents/gelatiere.md +15 -0
  54. package/packages/vfs-root/gelatiere/GELATIERE.md +19 -0
  55. package/packages/vfs-root/skills/gelatiere/SKILL.md +30 -0
  56. package/packages/vfs-root/skills/memory/SKILL.md +4 -0
  57. package/packages/vfs-root/sprinkles/suggestions.shtml +1 -1
@@ -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(models: MutableModels, providers: Provider[]): ModelChoice[] {\n return providers.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 contextWindow: model.contextWindow,\n }))\n );\n}\n\nasync function accounts(\n credentials: CredentialStore,\n providers: Provider[]\n): Promise<AccountState[]> {\n const stored = new Set((await credentials.list()).map((info) => info.providerId));\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 models: choices(models, providers),\n accounts: await accounts(credentials, providers),\n budget: await budget(credentials, usage),\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": "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",
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": "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",
6
6
  "names": []
7
7
  }
@@ -12,6 +12,7 @@ import {
12
12
  import { expandPromptTemplate, loadTemplates } from "./templates.js";
13
13
  const BUILTIN_SKILLS = [
14
14
  "agent",
15
+ "gelatiere",
15
16
  "licks",
16
17
  "memory",
17
18
  "skill-authoring",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/skills/index.ts"],
4
- "sourcesContent": ["import { type Context, type ReplicatedState, replicatedState } from '@earendil-works/chord';\nimport {\n defineExtension,\n type Extension,\n type Registry,\n section,\n} from '@earendil-works/pi-durable';\nimport type { ExecutionEnv, FileWatcher } from '@earendil-works/pi-durable/env';\nimport type { Licks } from '../licks/licks.ts';\nimport { manifestDirs } from '../roles/roles.ts';\nimport type { Command } from '../services.ts';\nimport {\n type Diagnostic,\n expandSkillCommand,\n formatSkillsForPrompt,\n loadSkills,\n type Skill,\n type SkillRoot,\n} from './skills.ts';\nimport { expandPromptTemplate, loadTemplates, type PromptTemplate } from './templates.ts';\n\nexport const BUILTIN_SKILLS = [\n 'agent',\n 'licks',\n 'memory',\n 'skill-authoring',\n 'sprinkles',\n 'welcome',\n];\nexport const BUILTIN_PROMPTS = ['parallel-review', 'review-loop'];\nexport const SKILLS_DIR = '/var/lib/slicc/agent/skills';\nexport const PROMPTS_DIR = '/var/lib/slicc/agent/prompts';\nexport const COMPAT_DIR = '/workspace/skills';\nexport const RELOAD_MS = 300;\n\nexport interface SkillsRuntime {\n readonly commands: ReplicatedState<Command[]>;\n skills(): readonly Skill[];\n dirs(): string[];\n templates(): readonly PromptTemplate[];\n expand(text: string, context: Context): Promise<string>;\n reload(context: Context): Promise<void>;\n close(context: Context): Promise<void>;\n}\n\nexport interface SkillsAttach {\n env: ExecutionEnv;\n home: string;\n assets?: (path: string) => Promise<string>;\n reloadMs: number;\n}\n\nexport interface SkillsSetup {\n extension: Extension;\n attach(options: SkillsAttach, context: Context): Promise<SkillsRuntime>;\n}\n\ntype Manifest = { pi?: { skills?: unknown; prompts?: unknown } };\n\nexport function piResources(dir: string, text: string, kind: 'skills' | 'prompts'): string[] {\n let manifest: Manifest;\n try {\n manifest = JSON.parse(text) as Manifest;\n } catch {\n return [];\n }\n const listed = manifest.pi?.[kind];\n const paths = Array.isArray(listed) ? listed : typeof listed === 'string' ? [listed] : [];\n return paths\n .filter((path): path is string => typeof path === 'string')\n .map((path) => `${dir}/${path.replace(/^\\.\\//, '').replace(/\\/$/, '')}`);\n}\n\nasync function packaged(env: ExecutionEnv, kind: 'skills' | 'prompts', context: Context) {\n const out: string[] = [];\n for (const dir of await manifestDirs(env, '/node_modules', context)) {\n const read = await env.readTextFile(`${dir}/package.json`, context);\n if (read.ok) out.push(...piResources(dir, read.value, kind));\n }\n return out;\n}\n\nasync function installBuiltins(\n env: ExecutionEnv,\n assets: (path: string) => Promise<string>,\n context: Context\n): Promise<void> {\n await env.remove(SKILLS_DIR, { recursive: true, force: true }, context);\n await env.remove(PROMPTS_DIR, { recursive: true, force: true }, context);\n for (const name of BUILTIN_SKILLS) {\n const text = await assets(`packages/vfs-root/skills/${name}/SKILL.md`).catch(() => undefined);\n if (text === undefined) continue;\n await env.createDir(`${SKILLS_DIR}/${name}`, { recursive: true }, context);\n await env.writeFile(`${SKILLS_DIR}/${name}/SKILL.md`, text, context);\n }\n await env.createDir(PROMPTS_DIR, { recursive: true }, context);\n for (const name of BUILTIN_PROMPTS) {\n const text = await assets(`packages/vfs-root/prompts/${name}.md`).catch(() => undefined);\n if (text !== undefined) await env.writeFile(`${PROMPTS_DIR}/${name}.md`, text, context);\n }\n}\n\nexport function problemLick(problem: Diagnostic, home: string) {\n const path = problem.path.startsWith(`${home}/`)\n ? `~${problem.path.slice(home.length)}`\n : problem.path;\n return {\n channel: 'fswatch' as const,\n source: `skills:${path}`,\n title: `Skill or prompt template problem: ${path}`,\n text: problem.message,\n body: 'The file is used with this problem, or skipped if it has no description.\\nThe rules are in the slicc-agent README.',\n target: 'cone' as const,\n severity: 'warn' as const,\n eventId: `${path}\\n${problem.message}`,\n };\n}\n\nexport function commandsOf(\n skills: readonly Skill[],\n templates: readonly PromptTemplate[]\n): Command[] {\n return [\n ...templates.map((template) => ({\n name: template.name,\n description: template.description,\n kind: 'prompt' as const,\n })),\n ...skills.map((skill) => ({\n name: `skill:${skill.name}`,\n description: skill.description,\n kind: 'skill' as const,\n })),\n ];\n}\n\nexport function setupSkills(registry: Registry, licks: Licks): SkillsSetup {\n let current: Skill[] = [];\n const extension = defineExtension({\n name: 'slicc-skills',\n sections: [section('skills', async () => formatSkillsForPrompt(current) || undefined)],\n });\n registry.install(extension);\n return {\n extension,\n async attach(options, context) {\n const { env, home } = options;\n if (options.assets)\n await installBuiltins(env, options.assets, context).catch(() => undefined);\n let templates: PromptTemplate[] = [];\n const commands = replicatedState<Command[]>([]);\n const reported = new Set<string>();\n const reload = async (using: Context) => {\n const roots: SkillRoot[] = [\n { dir: `${home}/.pi/agent/skills`, source: 'user' },\n { dir: `${home}/.agents/skills`, source: 'user' },\n { dir: COMPAT_DIR, source: 'compat' },\n ...(await packaged(env, 'skills', using)).map((dir) => ({\n dir,\n source: 'package' as const,\n })),\n { dir: SKILLS_DIR, source: 'builtin' },\n ];\n const loaded = await loadSkills(env, roots, using);\n const prompts = await loadTemplates(\n env,\n [`${home}/.pi/agent/prompts`, ...(await packaged(env, 'prompts', using)), PROMPTS_DIR],\n using\n );\n current = loaded.skills;\n templates = prompts.templates;\n commands.replace(using, commandsOf(current, templates));\n for (const problem of [...loaded.diagnostics, ...prompts.diagnostics]) {\n const key = `${problem.path}\\n${problem.message}`;\n if (reported.has(key)) continue;\n reported.add(key);\n await licks.deliver(problemLick(problem, home), using).catch(() => undefined);\n }\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(\n [\n { path: `${home}/.pi/agent/skills`, recursive: true },\n { path: `${home}/.pi/agent/prompts` },\n { path: `${home}/.agents/skills`, recursive: true },\n { path: COMPAT_DIR, recursive: true },\n ],\n schedule,\n context\n );\n const watcher: FileWatcher | undefined = watched.ok ? watched.value : undefined;\n return {\n commands,\n skills: () => current,\n dirs: () => current.map((skill) => skill.baseDir),\n templates: () => templates,\n async expand(text, using) {\n const expanded = await expandSkillCommand(text, current, env, using);\n return expanded === text ? expandPromptTemplate(text, templates) : expanded;\n },\n reload,\n async close(using) {\n clearTimeout(timer);\n await watcher?.close(using);\n },\n };\n },\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { type Context, type ReplicatedState, replicatedState } from '@earendil-works/chord';\nimport {\n defineExtension,\n type Extension,\n type Registry,\n section,\n} from '@earendil-works/pi-durable';\nimport type { ExecutionEnv, FileWatcher } from '@earendil-works/pi-durable/env';\nimport type { Licks } from '../licks/licks.ts';\nimport { manifestDirs } from '../roles/roles.ts';\nimport type { Command } from '../services.ts';\nimport {\n type Diagnostic,\n expandSkillCommand,\n formatSkillsForPrompt,\n loadSkills,\n type Skill,\n type SkillRoot,\n} from './skills.ts';\nimport { expandPromptTemplate, loadTemplates, type PromptTemplate } from './templates.ts';\n\nexport const BUILTIN_SKILLS = [\n 'agent',\n 'gelatiere',\n 'licks',\n 'memory',\n 'skill-authoring',\n 'sprinkles',\n 'welcome',\n];\nexport const BUILTIN_PROMPTS = ['parallel-review', 'review-loop'];\nexport const SKILLS_DIR = '/var/lib/slicc/agent/skills';\nexport const PROMPTS_DIR = '/var/lib/slicc/agent/prompts';\nexport const COMPAT_DIR = '/workspace/skills';\nexport const RELOAD_MS = 300;\n\nexport interface SkillsRuntime {\n readonly commands: ReplicatedState<Command[]>;\n skills(): readonly Skill[];\n dirs(): string[];\n templates(): readonly PromptTemplate[];\n expand(text: string, context: Context): Promise<string>;\n reload(context: Context): Promise<void>;\n close(context: Context): Promise<void>;\n}\n\nexport interface SkillsAttach {\n env: ExecutionEnv;\n home: string;\n assets?: (path: string) => Promise<string>;\n reloadMs: number;\n}\n\nexport interface SkillsSetup {\n extension: Extension;\n attach(options: SkillsAttach, context: Context): Promise<SkillsRuntime>;\n}\n\ntype Manifest = { pi?: { skills?: unknown; prompts?: unknown } };\n\nexport function piResources(dir: string, text: string, kind: 'skills' | 'prompts'): string[] {\n let manifest: Manifest;\n try {\n manifest = JSON.parse(text) as Manifest;\n } catch {\n return [];\n }\n const listed = manifest.pi?.[kind];\n const paths = Array.isArray(listed) ? listed : typeof listed === 'string' ? [listed] : [];\n return paths\n .filter((path): path is string => typeof path === 'string')\n .map((path) => `${dir}/${path.replace(/^\\.\\//, '').replace(/\\/$/, '')}`);\n}\n\nasync function packaged(env: ExecutionEnv, kind: 'skills' | 'prompts', context: Context) {\n const out: string[] = [];\n for (const dir of await manifestDirs(env, '/node_modules', context)) {\n const read = await env.readTextFile(`${dir}/package.json`, context);\n if (read.ok) out.push(...piResources(dir, read.value, kind));\n }\n return out;\n}\n\nasync function installBuiltins(\n env: ExecutionEnv,\n assets: (path: string) => Promise<string>,\n context: Context\n): Promise<void> {\n await env.remove(SKILLS_DIR, { recursive: true, force: true }, context);\n await env.remove(PROMPTS_DIR, { recursive: true, force: true }, context);\n for (const name of BUILTIN_SKILLS) {\n const text = await assets(`packages/vfs-root/skills/${name}/SKILL.md`).catch(() => undefined);\n if (text === undefined) continue;\n await env.createDir(`${SKILLS_DIR}/${name}`, { recursive: true }, context);\n await env.writeFile(`${SKILLS_DIR}/${name}/SKILL.md`, text, context);\n }\n await env.createDir(PROMPTS_DIR, { recursive: true }, context);\n for (const name of BUILTIN_PROMPTS) {\n const text = await assets(`packages/vfs-root/prompts/${name}.md`).catch(() => undefined);\n if (text !== undefined) await env.writeFile(`${PROMPTS_DIR}/${name}.md`, text, context);\n }\n}\n\nexport function problemLick(problem: Diagnostic, home: string) {\n const path = problem.path.startsWith(`${home}/`)\n ? `~${problem.path.slice(home.length)}`\n : problem.path;\n return {\n channel: 'fswatch' as const,\n source: `skills:${path}`,\n title: `Skill or prompt template problem: ${path}`,\n text: problem.message,\n body: 'The file is used with this problem, or skipped if it has no description.\\nThe rules are in the slicc-agent README.',\n target: 'cone' as const,\n severity: 'warn' as const,\n eventId: `${path}\\n${problem.message}`,\n };\n}\n\nexport function commandsOf(\n skills: readonly Skill[],\n templates: readonly PromptTemplate[]\n): Command[] {\n return [\n ...templates.map((template) => ({\n name: template.name,\n description: template.description,\n kind: 'prompt' as const,\n })),\n ...skills.map((skill) => ({\n name: `skill:${skill.name}`,\n description: skill.description,\n kind: 'skill' as const,\n })),\n ];\n}\n\nexport function setupSkills(registry: Registry, licks: Licks): SkillsSetup {\n let current: Skill[] = [];\n const extension = defineExtension({\n name: 'slicc-skills',\n sections: [section('skills', async () => formatSkillsForPrompt(current) || undefined)],\n });\n registry.install(extension);\n return {\n extension,\n async attach(options, context) {\n const { env, home } = options;\n if (options.assets)\n await installBuiltins(env, options.assets, context).catch(() => undefined);\n let templates: PromptTemplate[] = [];\n const commands = replicatedState<Command[]>([]);\n const reported = new Set<string>();\n const reload = async (using: Context) => {\n const roots: SkillRoot[] = [\n { dir: `${home}/.pi/agent/skills`, source: 'user' },\n { dir: `${home}/.agents/skills`, source: 'user' },\n { dir: COMPAT_DIR, source: 'compat' },\n ...(await packaged(env, 'skills', using)).map((dir) => ({\n dir,\n source: 'package' as const,\n })),\n { dir: SKILLS_DIR, source: 'builtin' },\n ];\n const loaded = await loadSkills(env, roots, using);\n const prompts = await loadTemplates(\n env,\n [`${home}/.pi/agent/prompts`, ...(await packaged(env, 'prompts', using)), PROMPTS_DIR],\n using\n );\n current = loaded.skills;\n templates = prompts.templates;\n commands.replace(using, commandsOf(current, templates));\n for (const problem of [...loaded.diagnostics, ...prompts.diagnostics]) {\n const key = `${problem.path}\\n${problem.message}`;\n if (reported.has(key)) continue;\n reported.add(key);\n await licks.deliver(problemLick(problem, home), using).catch(() => undefined);\n }\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(\n [\n { path: `${home}/.pi/agent/skills`, recursive: true },\n { path: `${home}/.pi/agent/prompts` },\n { path: `${home}/.agents/skills`, recursive: true },\n { path: COMPAT_DIR, recursive: true },\n ],\n schedule,\n context\n );\n const watcher: FileWatcher | undefined = watched.ok ? watched.value : undefined;\n return {\n commands,\n skills: () => current,\n dirs: () => current.map((skill) => skill.baseDir),\n templates: () => templates,\n async expand(text, using) {\n const expanded = await expandSkillCommand(text, current, env, using);\n return expanded === text ? expandPromptTemplate(text, templates) : expanded;\n },\n reload,\n async close(using) {\n clearTimeout(timer);\n await watcher?.close(using);\n },\n };\n },\n };\n}\n"],
5
+ "mappings": "AAAA,SAA6C,uBAAuB;AACpE;AAAA,EACE;AAAA,EAGA;AAAA,OACK;AAGP,SAAS,oBAAoB;AAE7B;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,sBAAsB,qBAA0C;AAElE,MAAM,iBAAiB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACO,MAAM,kBAAkB,CAAC,mBAAmB,aAAa;AACzD,MAAM,aAAa;AACnB,MAAM,cAAc;AACpB,MAAM,aAAa;AACnB,MAAM,YAAY;AA0BlB,SAAS,YAAY,KAAa,MAAc,MAAsC;AAC3F,MAAI;AACJ,MAAI;AACF,eAAW,KAAK,MAAM,IAAI;AAAA,EAC5B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACA,QAAM,SAAS,SAAS,KAAK,IAAI;AACjC,QAAM,QAAQ,MAAM,QAAQ,MAAM,IAAI,SAAS,OAAO,WAAW,WAAW,CAAC,MAAM,IAAI,CAAC;AACxF,SAAO,MACJ,OAAO,CAAC,SAAyB,OAAO,SAAS,QAAQ,EACzD,IAAI,CAAC,SAAS,GAAG,GAAG,IAAI,KAAK,QAAQ,SAAS,EAAE,EAAE,QAAQ,OAAO,EAAE,CAAC,EAAE;AAC3E;AAEA,eAAe,SAAS,KAAmB,MAA4B,SAAkB;AACvF,QAAM,MAAgB,CAAC;AACvB,aAAW,OAAO,MAAM,aAAa,KAAK,iBAAiB,OAAO,GAAG;AACnE,UAAM,OAAO,MAAM,IAAI,aAAa,GAAG,GAAG,iBAAiB,OAAO;AAClE,QAAI,KAAK,GAAI,KAAI,KAAK,GAAG,YAAY,KAAK,KAAK,OAAO,IAAI,CAAC;AAAA,EAC7D;AACA,SAAO;AACT;AAEA,eAAe,gBACb,KACA,QACA,SACe;AACf,QAAM,IAAI,OAAO,YAAY,EAAE,WAAW,MAAM,OAAO,KAAK,GAAG,OAAO;AACtE,QAAM,IAAI,OAAO,aAAa,EAAE,WAAW,MAAM,OAAO,KAAK,GAAG,OAAO;AACvE,aAAW,QAAQ,gBAAgB;AACjC,UAAM,OAAO,MAAM,OAAO,4BAA4B,IAAI,WAAW,EAAE,MAAM,MAAM,MAAS;AAC5F,QAAI,SAAS,OAAW;AACxB,UAAM,IAAI,UAAU,GAAG,UAAU,IAAI,IAAI,IAAI,EAAE,WAAW,KAAK,GAAG,OAAO;AACzE,UAAM,IAAI,UAAU,GAAG,UAAU,IAAI,IAAI,aAAa,MAAM,OAAO;AAAA,EACrE;AACA,QAAM,IAAI,UAAU,aAAa,EAAE,WAAW,KAAK,GAAG,OAAO;AAC7D,aAAW,QAAQ,iBAAiB;AAClC,UAAM,OAAO,MAAM,OAAO,6BAA6B,IAAI,KAAK,EAAE,MAAM,MAAM,MAAS;AACvF,QAAI,SAAS,OAAW,OAAM,IAAI,UAAU,GAAG,WAAW,IAAI,IAAI,OAAO,MAAM,OAAO;AAAA,EACxF;AACF;AAEO,SAAS,YAAY,SAAqB,MAAc;AAC7D,QAAM,OAAO,QAAQ,KAAK,WAAW,GAAG,IAAI,GAAG,IAC3C,IAAI,QAAQ,KAAK,MAAM,KAAK,MAAM,CAAC,KACnC,QAAQ;AACZ,SAAO;AAAA,IACL,SAAS;AAAA,IACT,QAAQ,UAAU,IAAI;AAAA,IACtB,OAAO,qCAAqC,IAAI;AAAA,IAChD,MAAM,QAAQ;AAAA,IACd,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,SAAS,GAAG,IAAI;AAAA,EAAK,QAAQ,OAAO;AAAA,EACtC;AACF;AAEO,SAAS,WACd,QACA,WACW;AACX,SAAO;AAAA,IACL,GAAG,UAAU,IAAI,CAAC,cAAc;AAAA,MAC9B,MAAM,SAAS;AAAA,MACf,aAAa,SAAS;AAAA,MACtB,MAAM;AAAA,IACR,EAAE;AAAA,IACF,GAAG,OAAO,IAAI,CAAC,WAAW;AAAA,MACxB,MAAM,SAAS,MAAM,IAAI;AAAA,MACzB,aAAa,MAAM;AAAA,MACnB,MAAM;AAAA,IACR,EAAE;AAAA,EACJ;AACF;AAEO,SAAS,YAAY,UAAoB,OAA2B;AACzE,MAAI,UAAmB,CAAC;AACxB,QAAM,YAAY,gBAAgB;AAAA,IAChC,MAAM;AAAA,IACN,UAAU,CAAC,QAAQ,UAAU,YAAY,sBAAsB,OAAO,KAAK,MAAS,CAAC;AAAA,EACvF,CAAC;AACD,WAAS,QAAQ,SAAS;AAC1B,SAAO;AAAA,IACL;AAAA,IACA,MAAM,OAAO,SAAS,SAAS;AAC7B,YAAM,EAAE,KAAK,KAAK,IAAI;AACtB,UAAI,QAAQ;AACV,cAAM,gBAAgB,KAAK,QAAQ,QAAQ,OAAO,EAAE,MAAM,MAAM,MAAS;AAC3E,UAAI,YAA8B,CAAC;AACnC,YAAM,WAAW,gBAA2B,CAAC,CAAC;AAC9C,YAAM,WAAW,oBAAI,IAAY;AACjC,YAAM,SAAS,OAAO,UAAmB;AACvC,cAAM,QAAqB;AAAA,UACzB,EAAE,KAAK,GAAG,IAAI,qBAAqB,QAAQ,OAAO;AAAA,UAClD,EAAE,KAAK,GAAG,IAAI,mBAAmB,QAAQ,OAAO;AAAA,UAChD,EAAE,KAAK,YAAY,QAAQ,SAAS;AAAA,UACpC,IAAI,MAAM,SAAS,KAAK,UAAU,KAAK,GAAG,IAAI,CAAC,SAAS;AAAA,YACtD;AAAA,YACA,QAAQ;AAAA,UACV,EAAE;AAAA,UACF,EAAE,KAAK,YAAY,QAAQ,UAAU;AAAA,QACvC;AACA,cAAM,SAAS,MAAM,WAAW,KAAK,OAAO,KAAK;AACjD,cAAM,UAAU,MAAM;AAAA,UACpB;AAAA,UACA,CAAC,GAAG,IAAI,sBAAsB,GAAI,MAAM,SAAS,KAAK,WAAW,KAAK,GAAI,WAAW;AAAA,UACrF;AAAA,QACF;AACA,kBAAU,OAAO;AACjB,oBAAY,QAAQ;AACpB,iBAAS,QAAQ,OAAO,WAAW,SAAS,SAAS,CAAC;AACtD,mBAAW,WAAW,CAAC,GAAG,OAAO,aAAa,GAAG,QAAQ,WAAW,GAAG;AACrE,gBAAM,MAAM,GAAG,QAAQ,IAAI;AAAA,EAAK,QAAQ,OAAO;AAC/C,cAAI,SAAS,IAAI,GAAG,EAAG;AACvB,mBAAS,IAAI,GAAG;AAChB,gBAAM,MAAM,QAAQ,YAAY,SAAS,IAAI,GAAG,KAAK,EAAE,MAAM,MAAM,MAAS;AAAA,QAC9E;AAAA,MACF;AACA,YAAM,OAAO,OAAO;AACpB,UAAI;AACJ,YAAM,WAAW,MAAM;AACrB,qBAAa,KAAK;AAClB,gBAAQ,WAAW,MAAM,KAAK,OAAO,OAAO,EAAE,MAAM,MAAM,MAAS,GAAG,QAAQ,QAAQ;AAAA,MACxF;AACA,YAAM,UAAU,MAAM,IAAI;AAAA,QACxB;AAAA,UACE,EAAE,MAAM,GAAG,IAAI,qBAAqB,WAAW,KAAK;AAAA,UACpD,EAAE,MAAM,GAAG,IAAI,qBAAqB;AAAA,UACpC,EAAE,MAAM,GAAG,IAAI,mBAAmB,WAAW,KAAK;AAAA,UAClD,EAAE,MAAM,YAAY,WAAW,KAAK;AAAA,QACtC;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,YAAM,UAAmC,QAAQ,KAAK,QAAQ,QAAQ;AACtE,aAAO;AAAA,QACL;AAAA,QACA,QAAQ,MAAM;AAAA,QACd,MAAM,MAAM,QAAQ,IAAI,CAAC,UAAU,MAAM,OAAO;AAAA,QAChD,WAAW,MAAM;AAAA,QACjB,MAAM,OAAO,MAAM,OAAO;AACxB,gBAAM,WAAW,MAAM,mBAAmB,MAAM,SAAS,KAAK,KAAK;AACnE,iBAAO,aAAa,OAAO,qBAAqB,MAAM,SAAS,IAAI;AAAA,QACrE;AAAA,QACA;AAAA,QACA,MAAM,MAAM,OAAO;AACjB,uBAAa,KAAK;AAClB,gBAAM,SAAS,MAAM,KAAK;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -129,8 +129,12 @@ class AgentAdapter extends Emitter {
129
129
  );
130
130
  if (!sent.accepted) throw new Error(sent.error.message);
131
131
  }
132
- async rewind(_agentId, messageId) {
133
- const rewound = await this.#connection.control.rewind(messageId, BACKGROUND_CONTEXT);
132
+ async rewind(agentId, messageId) {
133
+ const rewound = await this.#connection.control.rewindAgent(
134
+ agentId,
135
+ messageId,
136
+ BACKGROUND_CONTEXT
137
+ );
134
138
  return rewound.done ? { text: rewound.text } : null;
135
139
  }
136
140
  stop(agentId = this.active()) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/spectrum/agent-port.ts"],
4
- "sourcesContent": ["import type {\n Agent,\n AgentEvents,\n AgentPort,\n AgentStatus,\n FrozenCone,\n Message,\n Outgoing,\n SlashCommand,\n Thinking,\n UserMessage,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport type { AgentConnection } from '../client.ts';\nimport { entryLick } from '../licks/state.ts';\nimport type { AgentSettingsChange, AgentSummary } from '../services.ts';\nimport { Emitter } from './emitter.ts';\nimport { isBusy, queued, toMessages } from './messages.ts';\n\nexport const CONE = 'cone';\n\nconst thinking: Record<string, Thinking> = {\n off: 'off',\n minimal: 'low',\n low: 'low',\n medium: 'medium',\n high: 'high',\n xhigh: 'high',\n max: 'high',\n};\n\ninterface AgentDoc {\n model?: { provider: string; modelId: string };\n thinkingLevel?: string;\n}\n\nfunction status(view: ConversationView | undefined, messages: readonly Message[]): AgentStatus {\n if (isBusy(view)) {\n const live = view?.docs['pi.live'] as { tools?: { status: string }[] } | undefined;\n return live?.tools?.some((slot) => slot.status === 'running') ? 'working' : 'thinking';\n }\n const last = messages.at(-1);\n return last?.role === 'assistant' && last.status === 'error' ? 'error' : 'idle';\n}\n\nexport class AgentAdapter extends Emitter<AgentEvents> implements AgentPort {\n readonly #connection: AgentConnection;\n readonly #ready: Promise<void>;\n readonly #messages = new Map<string, Message[]>();\n #active: string | null = null;\n #creating = new Map<string, Promise<string | null>>();\n\n constructor(connection: AgentConnection) {\n super();\n this.#connection = connection;\n this.#ready = new Promise((resolve) => {\n connection.transcript.subscribe(() => {\n this.#refresh();\n resolve();\n });\n connection.deliveries.subscribe(() => this.#refresh());\n connection.views?.subscribe(() => this.#refresh());\n connection.agents?.subscribe(() => this.#refresh());\n });\n }\n\n #summary(): readonly AgentSummary[] {\n const agents = this.#connection.agents?.value?.agents;\n return agents?.length\n ? agents\n : [{ id: CONE, name: 'sliccy', kind: 'cone', parentId: null, role: null }];\n }\n\n #view(agentId: string = this.active()): ConversationView | undefined {\n const views = this.#connection.views?.value;\n const view = views?.[agentId];\n if (view) return view;\n const cone = this.#connection.agents?.value?.active ?? CONE;\n return agentId === cone ? this.#connection.transcript.value : undefined;\n }\n\n #refresh(): void {\n this.emit('agents', this.list());\n for (const summary of this.#summary()) this.#update(summary.id);\n for (const id of [...this.#messages.keys()])\n if (!this.#summary().some((summary) => summary.id === id)) this.#messages.delete(id);\n }\n\n #update(agentId: string): void {\n const view = this.#view(agentId);\n if (!view) return;\n const before = this.#messages.get(agentId) ?? [];\n const after = toMessages(view, this.#connection.deliveries.value);\n this.#messages.set(agentId, after);\n if (before.length !== after.length) {\n this.emit('messages', agentId);\n return;\n }\n const changed = after.filter(\n (message, index) => JSON.stringify(message) !== JSON.stringify(before[index])\n );\n if (changed.length === 1) this.emit('message', { agentId, message: changed[0] as Message });\n else if (changed.length > 1) this.emit('messages', agentId);\n }\n\n ready(): Promise<void> {\n return this.#ready;\n }\n\n list(): readonly Agent[] {\n return this.#summary().map((summary) => {\n const view = this.#view(summary.id);\n const doc = view?.docs['pi.agent'] as AgentDoc | undefined;\n return {\n id: summary.id,\n name: summary.role ? `${summary.name} \u00B7 ${summary.role}` : summary.name,\n kind: summary.kind,\n parentId: summary.parentId,\n status: status(view, this.#messages.get(summary.id) ?? []),\n model: doc?.model ? `${doc.model.provider}/${doc.model.modelId}` : '',\n contextFill: 0,\n unread: 0,\n thinking: thinking[doc?.thinkingLevel ?? 'off'] ?? 'off',\n };\n });\n }\n\n active(): string {\n const known = this.#summary();\n if (this.#active && this.#creating.has(this.#active)) return this.#active;\n if (this.#active && known.some((summary) => summary.id === this.#active)) return this.#active;\n return this.#connection.agents?.value?.active ?? CONE;\n }\n\n select(id: string): void {\n if (this.#creating.has(id)) {\n this.#active = id;\n this.emit('active', id);\n return;\n }\n const found = this.#summary().find((summary) => summary.id === id);\n if (!found) return;\n this.#active = id;\n if (found.kind === 'cone') void this.#connection.control.selectCone(id, BACKGROUND_CONTEXT);\n this.emit('active', id);\n this.emit('messages', id);\n }\n\n messages(agentId: string = this.active()): readonly Message[] {\n return this.#messages.get(agentId) ?? [];\n }\n\n async send(agentId: string, input: string | Outgoing): Promise<void> {\n const outgoing = typeof input === 'string' ? { text: input } : input;\n const target = this.#creating.has(agentId) ? await this.#creating.get(agentId) : agentId;\n if (target === null) throw new Error('The scoop could not be created.');\n const sent = await this.#connection.control.send(\n {\n text: outgoing.text,\n whenBusy: outgoing.mode === 'queue' ? 'followUp' : 'steer',\n requestId: crypto.randomUUID(),\n agentId: target || null,\n },\n BACKGROUND_CONTEXT\n );\n if (!sent.accepted) throw new Error(sent.error.message);\n }\n\n async rewind(_agentId: string, messageId: string): Promise<Outgoing | null> {\n const rewound = await this.#connection.control.rewind(messageId, BACKGROUND_CONTEXT);\n return rewound.done ? { text: rewound.text } : null;\n }\n\n stop(agentId: string = this.active()): void {\n void this.#connection.control.stopAgent(agentId, BACKGROUND_CONTEXT);\n }\n\n busy(agentId: string = this.active()): boolean {\n return isBusy(this.#view(agentId));\n }\n\n queue(agentId: string = this.active()): readonly UserMessage[] {\n return queued(this.#view(agentId));\n }\n\n unqueue(agentId: string, messageId: string): void {\n void this.#connection.control.unqueue(agentId, messageId.replace(/^q/, ''), BACKGROUND_CONTEXT);\n }\n\n suggestion(): string | null {\n return null;\n }\n\n answer(): void {}\n\n resolveLick(agentId: string, messageId: string, state: 'confirmed' | 'dismissed'): void {\n const message = this.messages(agentId).find((candidate) => candidate.id === messageId);\n const entry = this.#view(agentId)?.entries.find(\n (candidate) => `e${candidate.id}` === messageId\n );\n const lick = message?.role === 'lick' && entry ? entryLick(entry) : undefined;\n if (lick) void this.#connection.control.resolveLick(lick.id, state, BACKGROUND_CONTEXT);\n }\n\n compact(): void {\n void this.#connection.control.compact(null, BACKGROUND_CONTEXT);\n }\n\n clear(): void {\n void this.#connection.control.reset(null, BACKGROUND_CONTEXT);\n }\n\n #configure(agentId: string, change: Partial<AgentSettingsChange>): void {\n void this.#connection.control.configure(\n {\n model: change.model ?? null,\n thinkingLevel: change.thinkingLevel ?? null,\n agentId,\n },\n BACKGROUND_CONTEXT\n );\n }\n\n setModel(agentId: string, model: string): void {\n const at = model.indexOf('/');\n if (at <= 0) return;\n this.#configure(agentId, {\n model: { provider: model.slice(0, at), modelId: model.slice(at + 1) },\n });\n }\n\n setThinking(agentId: string, level: Thinking): void {\n this.#configure(agentId, { thinkingLevel: level });\n }\n\n async older(): Promise<readonly Message[]> {\n return [];\n }\n\n commands(): readonly SlashCommand[] {\n return (this.#connection.commands?.value ?? []).map((command) => ({ ...command }));\n }\n\n createScoop(parentId: string, name: string): Agent {\n const provisional = `scoop:creating-${crypto.randomUUID()}`;\n const created = this.#connection.control.createScoop(parentId, name, BACKGROUND_CONTEXT).then(\n (result) => result.id,\n () => null\n );\n this.#creating.set(provisional, created);\n void created.then((id) => {\n if (this.#active !== provisional) return;\n this.#active = id ?? parentId;\n this.emit('active', this.#active);\n this.emit('messages', this.#active);\n });\n return {\n id: provisional,\n name,\n kind: 'scoop',\n parentId,\n status: 'idle',\n model: '',\n contextFill: 0,\n unread: 0,\n };\n }\n\n async drop(agentId: string): Promise<void> {\n const parent = this.#summary().find((summary) => summary.id === agentId)?.parentId ?? CONE;\n const dropped = await this.#connection.control.drop(agentId, BACKGROUND_CONTEXT);\n if (dropped.error !== null) throw new Error(dropped.error);\n if (this.#active === agentId) this.select(parent);\n }\n\n async createCone(name: string): Promise<Agent> {\n const created = await this.#connection.control.createCone(name, BACKGROUND_CONTEXT);\n if (created.error !== null) throw new Error(created.error);\n return {\n id: created.id,\n name: name.trim(),\n kind: 'cone',\n parentId: null,\n status: 'idle',\n model: '',\n contextFill: 0,\n unread: 0,\n };\n }\n\n frozen(): readonly FrozenCone[] {\n return [];\n }\n\n thaw(): Agent | null {\n return null;\n }\n\n discard(): void {}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type {\n Agent,\n AgentEvents,\n AgentPort,\n AgentStatus,\n FrozenCone,\n Message,\n Outgoing,\n SlashCommand,\n Thinking,\n UserMessage,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport type { AgentConnection } from '../client.ts';\nimport { entryLick } from '../licks/state.ts';\nimport type { AgentSettingsChange, AgentSummary } from '../services.ts';\nimport { Emitter } from './emitter.ts';\nimport { isBusy, queued, toMessages } from './messages.ts';\n\nexport const CONE = 'cone';\n\nconst thinking: Record<string, Thinking> = {\n off: 'off',\n minimal: 'low',\n low: 'low',\n medium: 'medium',\n high: 'high',\n xhigh: 'high',\n max: 'high',\n};\n\ninterface AgentDoc {\n model?: { provider: string; modelId: string };\n thinkingLevel?: string;\n}\n\nfunction status(view: ConversationView | undefined, messages: readonly Message[]): AgentStatus {\n if (isBusy(view)) {\n const live = view?.docs['pi.live'] as { tools?: { status: string }[] } | undefined;\n return live?.tools?.some((slot) => slot.status === 'running') ? 'working' : 'thinking';\n }\n const last = messages.at(-1);\n return last?.role === 'assistant' && last.status === 'error' ? 'error' : 'idle';\n}\n\nexport class AgentAdapter extends Emitter<AgentEvents> implements AgentPort {\n readonly #connection: AgentConnection;\n readonly #ready: Promise<void>;\n readonly #messages = new Map<string, Message[]>();\n #active: string | null = null;\n #creating = new Map<string, Promise<string | null>>();\n\n constructor(connection: AgentConnection) {\n super();\n this.#connection = connection;\n this.#ready = new Promise((resolve) => {\n connection.transcript.subscribe(() => {\n this.#refresh();\n resolve();\n });\n connection.deliveries.subscribe(() => this.#refresh());\n connection.views?.subscribe(() => this.#refresh());\n connection.agents?.subscribe(() => this.#refresh());\n });\n }\n\n #summary(): readonly AgentSummary[] {\n const agents = this.#connection.agents?.value?.agents;\n return agents?.length\n ? agents\n : [{ id: CONE, name: 'sliccy', kind: 'cone', parentId: null, role: null }];\n }\n\n #view(agentId: string = this.active()): ConversationView | undefined {\n const views = this.#connection.views?.value;\n const view = views?.[agentId];\n if (view) return view;\n const cone = this.#connection.agents?.value?.active ?? CONE;\n return agentId === cone ? this.#connection.transcript.value : undefined;\n }\n\n #refresh(): void {\n this.emit('agents', this.list());\n for (const summary of this.#summary()) this.#update(summary.id);\n for (const id of [...this.#messages.keys()])\n if (!this.#summary().some((summary) => summary.id === id)) this.#messages.delete(id);\n }\n\n #update(agentId: string): void {\n const view = this.#view(agentId);\n if (!view) return;\n const before = this.#messages.get(agentId) ?? [];\n const after = toMessages(view, this.#connection.deliveries.value);\n this.#messages.set(agentId, after);\n if (before.length !== after.length) {\n this.emit('messages', agentId);\n return;\n }\n const changed = after.filter(\n (message, index) => JSON.stringify(message) !== JSON.stringify(before[index])\n );\n if (changed.length === 1) this.emit('message', { agentId, message: changed[0] as Message });\n else if (changed.length > 1) this.emit('messages', agentId);\n }\n\n ready(): Promise<void> {\n return this.#ready;\n }\n\n list(): readonly Agent[] {\n return this.#summary().map((summary) => {\n const view = this.#view(summary.id);\n const doc = view?.docs['pi.agent'] as AgentDoc | undefined;\n return {\n id: summary.id,\n name: summary.role ? `${summary.name} \u00B7 ${summary.role}` : summary.name,\n kind: summary.kind,\n parentId: summary.parentId,\n status: status(view, this.#messages.get(summary.id) ?? []),\n model: doc?.model ? `${doc.model.provider}/${doc.model.modelId}` : '',\n contextFill: 0,\n unread: 0,\n thinking: thinking[doc?.thinkingLevel ?? 'off'] ?? 'off',\n };\n });\n }\n\n active(): string {\n const known = this.#summary();\n if (this.#active && this.#creating.has(this.#active)) return this.#active;\n if (this.#active && known.some((summary) => summary.id === this.#active)) return this.#active;\n return this.#connection.agents?.value?.active ?? CONE;\n }\n\n select(id: string): void {\n if (this.#creating.has(id)) {\n this.#active = id;\n this.emit('active', id);\n return;\n }\n const found = this.#summary().find((summary) => summary.id === id);\n if (!found) return;\n this.#active = id;\n if (found.kind === 'cone') void this.#connection.control.selectCone(id, BACKGROUND_CONTEXT);\n this.emit('active', id);\n this.emit('messages', id);\n }\n\n messages(agentId: string = this.active()): readonly Message[] {\n return this.#messages.get(agentId) ?? [];\n }\n\n async send(agentId: string, input: string | Outgoing): Promise<void> {\n const outgoing = typeof input === 'string' ? { text: input } : input;\n const target = this.#creating.has(agentId) ? await this.#creating.get(agentId) : agentId;\n if (target === null) throw new Error('The scoop could not be created.');\n const sent = await this.#connection.control.send(\n {\n text: outgoing.text,\n whenBusy: outgoing.mode === 'queue' ? 'followUp' : 'steer',\n requestId: crypto.randomUUID(),\n agentId: target || null,\n },\n BACKGROUND_CONTEXT\n );\n if (!sent.accepted) throw new Error(sent.error.message);\n }\n\n async rewind(agentId: string, messageId: string): Promise<Outgoing | null> {\n const rewound = await this.#connection.control.rewindAgent(\n agentId,\n messageId,\n BACKGROUND_CONTEXT\n );\n return rewound.done ? { text: rewound.text } : null;\n }\n\n stop(agentId: string = this.active()): void {\n void this.#connection.control.stopAgent(agentId, BACKGROUND_CONTEXT);\n }\n\n busy(agentId: string = this.active()): boolean {\n return isBusy(this.#view(agentId));\n }\n\n queue(agentId: string = this.active()): readonly UserMessage[] {\n return queued(this.#view(agentId));\n }\n\n unqueue(agentId: string, messageId: string): void {\n void this.#connection.control.unqueue(agentId, messageId.replace(/^q/, ''), BACKGROUND_CONTEXT);\n }\n\n suggestion(): string | null {\n return null;\n }\n\n answer(): void {}\n\n resolveLick(agentId: string, messageId: string, state: 'confirmed' | 'dismissed'): void {\n const message = this.messages(agentId).find((candidate) => candidate.id === messageId);\n const entry = this.#view(agentId)?.entries.find(\n (candidate) => `e${candidate.id}` === messageId\n );\n const lick = message?.role === 'lick' && entry ? entryLick(entry) : undefined;\n if (lick) void this.#connection.control.resolveLick(lick.id, state, BACKGROUND_CONTEXT);\n }\n\n compact(): void {\n void this.#connection.control.compact(null, BACKGROUND_CONTEXT);\n }\n\n clear(): void {\n void this.#connection.control.reset(null, BACKGROUND_CONTEXT);\n }\n\n #configure(agentId: string, change: Partial<AgentSettingsChange>): void {\n void this.#connection.control.configure(\n {\n model: change.model ?? null,\n thinkingLevel: change.thinkingLevel ?? null,\n agentId,\n },\n BACKGROUND_CONTEXT\n );\n }\n\n setModel(agentId: string, model: string): void {\n const at = model.indexOf('/');\n if (at <= 0) return;\n this.#configure(agentId, {\n model: { provider: model.slice(0, at), modelId: model.slice(at + 1) },\n });\n }\n\n setThinking(agentId: string, level: Thinking): void {\n this.#configure(agentId, { thinkingLevel: level });\n }\n\n async older(): Promise<readonly Message[]> {\n return [];\n }\n\n commands(): readonly SlashCommand[] {\n return (this.#connection.commands?.value ?? []).map((command) => ({ ...command }));\n }\n\n createScoop(parentId: string, name: string): Agent {\n const provisional = `scoop:creating-${crypto.randomUUID()}`;\n const created = this.#connection.control.createScoop(parentId, name, BACKGROUND_CONTEXT).then(\n (result) => result.id,\n () => null\n );\n this.#creating.set(provisional, created);\n void created.then((id) => {\n if (this.#active !== provisional) return;\n this.#active = id ?? parentId;\n this.emit('active', this.#active);\n this.emit('messages', this.#active);\n });\n return {\n id: provisional,\n name,\n kind: 'scoop',\n parentId,\n status: 'idle',\n model: '',\n contextFill: 0,\n unread: 0,\n };\n }\n\n async drop(agentId: string): Promise<void> {\n const parent = this.#summary().find((summary) => summary.id === agentId)?.parentId ?? CONE;\n const dropped = await this.#connection.control.drop(agentId, BACKGROUND_CONTEXT);\n if (dropped.error !== null) throw new Error(dropped.error);\n if (this.#active === agentId) this.select(parent);\n }\n\n async createCone(name: string): Promise<Agent> {\n const created = await this.#connection.control.createCone(name, BACKGROUND_CONTEXT);\n if (created.error !== null) throw new Error(created.error);\n return {\n id: created.id,\n name: name.trim(),\n kind: 'cone',\n parentId: null,\n status: 'idle',\n model: '',\n contextFill: 0,\n unread: 0,\n };\n }\n\n frozen(): readonly FrozenCone[] {\n return [];\n }\n\n thaw(): Agent | null {\n return null;\n }\n\n discard(): void {}\n}\n"],
5
+ "mappings": "AAYA,SAAS,0BAA0B;AAGnC,SAAS,iBAAiB;AAE1B,SAAS,eAAe;AACxB,SAAS,QAAQ,QAAQ,kBAAkB;AAEpC,MAAM,OAAO;AAEpB,MAAM,WAAqC;AAAA,EACzC,KAAK;AAAA,EACL,SAAS;AAAA,EACT,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,OAAO;AAAA,EACP,KAAK;AACP;AAOA,SAAS,OAAO,MAAoC,UAA2C;AAC7F,MAAI,OAAO,IAAI,GAAG;AAChB,UAAM,OAAO,MAAM,KAAK,SAAS;AACjC,WAAO,MAAM,OAAO,KAAK,CAAC,SAAS,KAAK,WAAW,SAAS,IAAI,YAAY;AAAA,EAC9E;AACA,QAAM,OAAO,SAAS,GAAG,EAAE;AAC3B,SAAO,MAAM,SAAS,eAAe,KAAK,WAAW,UAAU,UAAU;AAC3E;AAEO,MAAM,qBAAqB,QAA0C;AAAA,EACjE;AAAA,EACA;AAAA,EACA,YAAY,oBAAI,IAAuB;AAAA,EAChD,UAAyB;AAAA,EACzB,YAAY,oBAAI,IAAoC;AAAA,EAEpD,YAAY,YAA6B;AACvC,UAAM;AACN,SAAK,cAAc;AACnB,SAAK,SAAS,IAAI,QAAQ,CAAC,YAAY;AACrC,iBAAW,WAAW,UAAU,MAAM;AACpC,aAAK,SAAS;AACd,gBAAQ;AAAA,MACV,CAAC;AACD,iBAAW,WAAW,UAAU,MAAM,KAAK,SAAS,CAAC;AACrD,iBAAW,OAAO,UAAU,MAAM,KAAK,SAAS,CAAC;AACjD,iBAAW,QAAQ,UAAU,MAAM,KAAK,SAAS,CAAC;AAAA,IACpD,CAAC;AAAA,EACH;AAAA,EAEA,WAAoC;AAClC,UAAM,SAAS,KAAK,YAAY,QAAQ,OAAO;AAC/C,WAAO,QAAQ,SACX,SACA,CAAC,EAAE,IAAI,MAAM,MAAM,UAAU,MAAM,QAAQ,UAAU,MAAM,MAAM,KAAK,CAAC;AAAA,EAC7E;AAAA,EAEA,MAAM,UAAkB,KAAK,OAAO,GAAiC;AACnE,UAAM,QAAQ,KAAK,YAAY,OAAO;AACtC,UAAM,OAAO,QAAQ,OAAO;AAC5B,QAAI,KAAM,QAAO;AACjB,UAAM,OAAO,KAAK,YAAY,QAAQ,OAAO,UAAU;AACvD,WAAO,YAAY,OAAO,KAAK,YAAY,WAAW,QAAQ;AAAA,EAChE;AAAA,EAEA,WAAiB;AACf,SAAK,KAAK,UAAU,KAAK,KAAK,CAAC;AAC/B,eAAW,WAAW,KAAK,SAAS,EAAG,MAAK,QAAQ,QAAQ,EAAE;AAC9D,eAAW,MAAM,CAAC,GAAG,KAAK,UAAU,KAAK,CAAC;AACxC,UAAI,CAAC,KAAK,SAAS,EAAE,KAAK,CAAC,YAAY,QAAQ,OAAO,EAAE,EAAG,MAAK,UAAU,OAAO,EAAE;AAAA,EACvF;AAAA,EAEA,QAAQ,SAAuB;AAC7B,UAAM,OAAO,KAAK,MAAM,OAAO;AAC/B,QAAI,CAAC,KAAM;AACX,UAAM,SAAS,KAAK,UAAU,IAAI,OAAO,KAAK,CAAC;AAC/C,UAAM,QAAQ,WAAW,MAAM,KAAK,YAAY,WAAW,KAAK;AAChE,SAAK,UAAU,IAAI,SAAS,KAAK;AACjC,QAAI,OAAO,WAAW,MAAM,QAAQ;AAClC,WAAK,KAAK,YAAY,OAAO;AAC7B;AAAA,IACF;AACA,UAAM,UAAU,MAAM;AAAA,MACpB,CAAC,SAAS,UAAU,KAAK,UAAU,OAAO,MAAM,KAAK,UAAU,OAAO,KAAK,CAAC;AAAA,IAC9E;AACA,QAAI,QAAQ,WAAW,EAAG,MAAK,KAAK,WAAW,EAAE,SAAS,SAAS,QAAQ,CAAC,EAAa,CAAC;AAAA,aACjF,QAAQ,SAAS,EAAG,MAAK,KAAK,YAAY,OAAO;AAAA,EAC5D;AAAA,EAEA,QAAuB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,OAAyB;AACvB,WAAO,KAAK,SAAS,EAAE,IAAI,CAAC,YAAY;AACtC,YAAM,OAAO,KAAK,MAAM,QAAQ,EAAE;AAClC,YAAM,MAAM,MAAM,KAAK,UAAU;AACjC,aAAO;AAAA,QACL,IAAI,QAAQ;AAAA,QACZ,MAAM,QAAQ,OAAO,GAAG,QAAQ,IAAI,SAAM,QAAQ,IAAI,KAAK,QAAQ;AAAA,QACnE,MAAM,QAAQ;AAAA,QACd,UAAU,QAAQ;AAAA,QAClB,QAAQ,OAAO,MAAM,KAAK,UAAU,IAAI,QAAQ,EAAE,KAAK,CAAC,CAAC;AAAA,QACzD,OAAO,KAAK,QAAQ,GAAG,IAAI,MAAM,QAAQ,IAAI,IAAI,MAAM,OAAO,KAAK;AAAA,QACnE,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,KAAK,iBAAiB,KAAK,KAAK;AAAA,MACrD;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,SAAiB;AACf,UAAM,QAAQ,KAAK,SAAS;AAC5B,QAAI,KAAK,WAAW,KAAK,UAAU,IAAI,KAAK,OAAO,EAAG,QAAO,KAAK;AAClE,QAAI,KAAK,WAAW,MAAM,KAAK,CAAC,YAAY,QAAQ,OAAO,KAAK,OAAO,EAAG,QAAO,KAAK;AACtF,WAAO,KAAK,YAAY,QAAQ,OAAO,UAAU;AAAA,EACnD;AAAA,EAEA,OAAO,IAAkB;AACvB,QAAI,KAAK,UAAU,IAAI,EAAE,GAAG;AAC1B,WAAK,UAAU;AACf,WAAK,KAAK,UAAU,EAAE;AACtB;AAAA,IACF;AACA,UAAM,QAAQ,KAAK,SAAS,EAAE,KAAK,CAAC,YAAY,QAAQ,OAAO,EAAE;AACjE,QAAI,CAAC,MAAO;AACZ,SAAK,UAAU;AACf,QAAI,MAAM,SAAS,OAAQ,MAAK,KAAK,YAAY,QAAQ,WAAW,IAAI,kBAAkB;AAC1F,SAAK,KAAK,UAAU,EAAE;AACtB,SAAK,KAAK,YAAY,EAAE;AAAA,EAC1B;AAAA,EAEA,SAAS,UAAkB,KAAK,OAAO,GAAuB;AAC5D,WAAO,KAAK,UAAU,IAAI,OAAO,KAAK,CAAC;AAAA,EACzC;AAAA,EAEA,MAAM,KAAK,SAAiB,OAAyC;AACnE,UAAM,WAAW,OAAO,UAAU,WAAW,EAAE,MAAM,MAAM,IAAI;AAC/D,UAAM,SAAS,KAAK,UAAU,IAAI,OAAO,IAAI,MAAM,KAAK,UAAU,IAAI,OAAO,IAAI;AACjF,QAAI,WAAW,KAAM,OAAM,IAAI,MAAM,iCAAiC;AACtE,UAAM,OAAO,MAAM,KAAK,YAAY,QAAQ;AAAA,MAC1C;AAAA,QACE,MAAM,SAAS;AAAA,QACf,UAAU,SAAS,SAAS,UAAU,aAAa;AAAA,QACnD,WAAW,OAAO,WAAW;AAAA,QAC7B,SAAS,UAAU;AAAA,MACrB;AAAA,MACA;AAAA,IACF;AACA,QAAI,CAAC,KAAK,SAAU,OAAM,IAAI,MAAM,KAAK,MAAM,OAAO;AAAA,EACxD;AAAA,EAEA,MAAM,OAAO,SAAiB,WAA6C;AACzE,UAAM,UAAU,MAAM,KAAK,YAAY,QAAQ;AAAA,MAC7C;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,WAAO,QAAQ,OAAO,EAAE,MAAM,QAAQ,KAAK,IAAI;AAAA,EACjD;AAAA,EAEA,KAAK,UAAkB,KAAK,OAAO,GAAS;AAC1C,SAAK,KAAK,YAAY,QAAQ,UAAU,SAAS,kBAAkB;AAAA,EACrE;AAAA,EAEA,KAAK,UAAkB,KAAK,OAAO,GAAY;AAC7C,WAAO,OAAO,KAAK,MAAM,OAAO,CAAC;AAAA,EACnC;AAAA,EAEA,MAAM,UAAkB,KAAK,OAAO,GAA2B;AAC7D,WAAO,OAAO,KAAK,MAAM,OAAO,CAAC;AAAA,EACnC;AAAA,EAEA,QAAQ,SAAiB,WAAyB;AAChD,SAAK,KAAK,YAAY,QAAQ,QAAQ,SAAS,UAAU,QAAQ,MAAM,EAAE,GAAG,kBAAkB;AAAA,EAChG;AAAA,EAEA,aAA4B;AAC1B,WAAO;AAAA,EACT;AAAA,EAEA,SAAe;AAAA,EAAC;AAAA,EAEhB,YAAY,SAAiB,WAAmB,OAAwC;AACtF,UAAM,UAAU,KAAK,SAAS,OAAO,EAAE,KAAK,CAAC,cAAc,UAAU,OAAO,SAAS;AACrF,UAAM,QAAQ,KAAK,MAAM,OAAO,GAAG,QAAQ;AAAA,MACzC,CAAC,cAAc,IAAI,UAAU,EAAE,OAAO;AAAA,IACxC;AACA,UAAM,OAAO,SAAS,SAAS,UAAU,QAAQ,UAAU,KAAK,IAAI;AACpE,QAAI,KAAM,MAAK,KAAK,YAAY,QAAQ,YAAY,KAAK,IAAI,OAAO,kBAAkB;AAAA,EACxF;AAAA,EAEA,UAAgB;AACd,SAAK,KAAK,YAAY,QAAQ,QAAQ,MAAM,kBAAkB;AAAA,EAChE;AAAA,EAEA,QAAc;AACZ,SAAK,KAAK,YAAY,QAAQ,MAAM,MAAM,kBAAkB;AAAA,EAC9D;AAAA,EAEA,WAAW,SAAiB,QAA4C;AACtE,SAAK,KAAK,YAAY,QAAQ;AAAA,MAC5B;AAAA,QACE,OAAO,OAAO,SAAS;AAAA,QACvB,eAAe,OAAO,iBAAiB;AAAA,QACvC;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,SAAS,SAAiB,OAAqB;AAC7C,UAAM,KAAK,MAAM,QAAQ,GAAG;AAC5B,QAAI,MAAM,EAAG;AACb,SAAK,WAAW,SAAS;AAAA,MACvB,OAAO,EAAE,UAAU,MAAM,MAAM,GAAG,EAAE,GAAG,SAAS,MAAM,MAAM,KAAK,CAAC,EAAE;AAAA,IACtE,CAAC;AAAA,EACH;AAAA,EAEA,YAAY,SAAiB,OAAuB;AAClD,SAAK,WAAW,SAAS,EAAE,eAAe,MAAM,CAAC;AAAA,EACnD;AAAA,EAEA,MAAM,QAAqC;AACzC,WAAO,CAAC;AAAA,EACV;AAAA,EAEA,WAAoC;AAClC,YAAQ,KAAK,YAAY,UAAU,SAAS,CAAC,GAAG,IAAI,CAAC,aAAa,EAAE,GAAG,QAAQ,EAAE;AAAA,EACnF;AAAA,EAEA,YAAY,UAAkB,MAAqB;AACjD,UAAM,cAAc,kBAAkB,OAAO,WAAW,CAAC;AACzD,UAAM,UAAU,KAAK,YAAY,QAAQ,YAAY,UAAU,MAAM,kBAAkB,EAAE;AAAA,MACvF,CAAC,WAAW,OAAO;AAAA,MACnB,MAAM;AAAA,IACR;AACA,SAAK,UAAU,IAAI,aAAa,OAAO;AACvC,SAAK,QAAQ,KAAK,CAAC,OAAO;AACxB,UAAI,KAAK,YAAY,YAAa;AAClC,WAAK,UAAU,MAAM;AACrB,WAAK,KAAK,UAAU,KAAK,OAAO;AAChC,WAAK,KAAK,YAAY,KAAK,OAAO;AAAA,IACpC,CAAC;AACD,WAAO;AAAA,MACL,IAAI;AAAA,MACJ;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,aAAa;AAAA,MACb,QAAQ;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,SAAgC;AACzC,UAAM,SAAS,KAAK,SAAS,EAAE,KAAK,CAAC,YAAY,QAAQ,OAAO,OAAO,GAAG,YAAY;AACtF,UAAM,UAAU,MAAM,KAAK,YAAY,QAAQ,KAAK,SAAS,kBAAkB;AAC/E,QAAI,QAAQ,UAAU,KAAM,OAAM,IAAI,MAAM,QAAQ,KAAK;AACzD,QAAI,KAAK,YAAY,QAAS,MAAK,OAAO,MAAM;AAAA,EAClD;AAAA,EAEA,MAAM,WAAW,MAA8B;AAC7C,UAAM,UAAU,MAAM,KAAK,YAAY,QAAQ,WAAW,MAAM,kBAAkB;AAClF,QAAI,QAAQ,UAAU,KAAM,OAAM,IAAI,MAAM,QAAQ,KAAK;AACzD,WAAO;AAAA,MACL,IAAI,QAAQ;AAAA,MACZ,MAAM,KAAK,KAAK;AAAA,MAChB,MAAM;AAAA,MACN,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,aAAa;AAAA,MACb,QAAQ;AAAA,IACV;AAAA,EACF;AAAA,EAEA,SAAgC;AAC9B,WAAO,CAAC;AAAA,EACV;AAAA,EAEA,OAAqB;AACnB,WAAO;AAAA,EACT;AAAA,EAEA,UAAgB;AAAA,EAAC;AACnB;",
6
6
  "names": []
7
7
  }
@@ -103,14 +103,15 @@ const credentials = /security token|unrecognizedclient|not authori[sz]ed|unautho
103
103
  const models = /model/i;
104
104
  const unavailable = /access|invalid|not found|identifier|unsupported|not supported|isn['’]t supported|not available|isn['’]t available/i;
105
105
  const providerNames = { "amazon-bedrock": "Bedrock" };
106
- const filtered = /Provider (?:stopped with|finish_reason): (?:content_filter(?:ed)?|guardrail_intervened|sensitive)|refused to complete the request/i;
106
+ const filtered = /Provider (?:stopped with|finish_reason): (?:content_filter(?:ed)?|guardrail_intervened|sensitive)|content[_ ]filter(?:ed|ing)?\b|guardrail[_ ]intervened/i;
107
+ const refused = /refused to complete the request|Provider (?:stopped with|finish_reason): refusal|\bstop_?reason\W+refusal\b/i;
107
108
  const missing = /no api key|missing|not configured|no credentials/i;
108
109
  function errorPart(error, provider) {
109
110
  const action = errorAction(error);
110
111
  if (action === "drop-turn") {
111
112
  return {
112
113
  type: "error",
113
- message: "The model's content filter stopped this reply.",
114
+ message: filtered.test(error) ? "The model's content filter stopped this reply." : "The model refused to answer this turn.",
114
115
  detail: error,
115
116
  action
116
117
  };
@@ -128,7 +129,7 @@ function errorPart(error, provider) {
128
129
  return lead ? { type: "error", message: lead, detail: error, action } : { type: "error", message: error, action };
129
130
  }
130
131
  function errorAction(message) {
131
- if (filtered.test(message)) return "drop-turn";
132
+ if (filtered.test(message) || refused.test(message)) return "drop-turn";
132
133
  if (credentials.test(message)) return "settings";
133
134
  if (models.test(message) && unavailable.test(message)) return "change-model";
134
135
  return "retry";
@@ -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)|refused to complete the request/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: \"The model's content filter stopped this reply.\",\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)) 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 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[] };\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 ];\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 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 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 { 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 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[] };\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 ];\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 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 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": []
7
7
  }
@@ -47,12 +47,13 @@ class SettingsAdapter extends Emitter {
47
47
  this.emit("settings", this.get());
48
48
  }
49
49
  models() {
50
- return this.#state().models.map(({ id, label, provider, kind, reasoning }) => ({
50
+ return this.#state().models.map(({ id, label, provider, kind, reasoning, images }) => ({
51
51
  id,
52
52
  label,
53
53
  provider,
54
54
  kind,
55
- reasoning
55
+ reasoning,
56
+ ...images === void 0 ? {} : { images }
56
57
  }));
57
58
  }
58
59
  accounts() {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/spectrum/settings-port.ts"],
4
- "sourcesContent": ["import type {\n Account,\n ModelOption,\n Settings,\n SettingsEvents,\n SettingsPort,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { AgentSettings, SettingsState, SignIn } from '../services.ts';\nimport type { AgentAdapter } from './agent-port.ts';\nimport { Emitter } from './emitter.ts';\n\nexport const SETTINGS_KEY = 'slicc-agent.settings';\n\nconst defaults: Settings = {\n color: 'system',\n model: '',\n thinking: 'off',\n sendOnEnter: true,\n showThinking: false,\n diffStyle: 'unified',\n};\n\ntype Local = Omit<Settings, 'model' | 'thinking'>;\n\nexport type Login = (providerId: string, signIn: () => Promise<SignIn | null>) => Promise<string>;\n\nexport class SettingsAdapter extends Emitter<SettingsEvents> implements SettingsPort {\n readonly #settings: AgentSettings;\n readonly #agent: AgentAdapter;\n readonly #storage: Pick<Storage, 'getItem' | 'setItem'> | null;\n readonly #login: Login | null;\n #local: Local;\n\n constructor(\n settings: AgentSettings,\n agent: AgentAdapter,\n storage: Pick<Storage, 'getItem' | 'setItem'> | null,\n login: Login | null = null\n ) {\n super();\n this.#settings = settings;\n this.#agent = agent;\n this.#storage = storage;\n this.#login = login;\n const saved = JSON.parse(storage?.getItem(SETTINGS_KEY) ?? '{}') as Partial<Local>;\n const { model: _model, thinking: _thinking, ...local } = { ...defaults, ...saved };\n this.#local = local;\n settings.state.subscribe(() => {\n this.emit('accounts', this.accounts());\n this.emit('settings', this.get());\n });\n agent.on('agents', () => this.emit('settings', this.get()));\n }\n\n #state(): SettingsState {\n return this.#settings.state.value ?? { models: [], accounts: [] };\n }\n\n get(): Settings {\n const cone = this.#agent.list()[0];\n return { ...this.#local, model: cone?.model ?? '', thinking: cone?.thinking ?? 'off' };\n }\n\n update(patch: Partial<Settings>): void {\n const { model, thinking, ...local } = patch;\n const id = this.#agent.active();\n if (model !== undefined) this.#agent.setModel(id, model);\n if (thinking !== undefined) this.#agent.setThinking(id, thinking);\n this.#local = { ...this.#local, ...local };\n this.#storage?.setItem(SETTINGS_KEY, JSON.stringify(this.#local));\n this.emit('settings', this.get());\n }\n\n models(): readonly ModelOption[] {\n return this.#state().models.map(({ id, label, provider, kind, reasoning }) => ({\n id,\n label,\n provider,\n kind,\n reasoning,\n }));\n }\n\n accounts(): readonly Account[] {\n return this.#state().accounts.map(({ needs, ...account }) =>\n needs ? { ...account, needs } : account\n );\n }\n\n async connect(id: string, secret?: string, options: { region?: string } = {}): Promise<void> {\n const account = this.#state().accounts.find((candidate) => candidate.id === id);\n const login = account?.auth === 'oauth' ? this.#login : null;\n const key =\n secret ??\n (login ? await login(id, () => this.#settings.signIn(id, BACKGROUND_CONTEXT)) : undefined);\n if (!key)\n throw new Error(`${id} needs ${account?.auth === 'oauth' ? 'a sign-in' : 'an API key'}`);\n await this.#settings.connect(id, key, options.region ?? null, BACKGROUND_CONTEXT);\n }\n\n disconnect(id: string): void {\n void this.#settings.disconnect(id, BACKGROUND_CONTEXT);\n }\n}\n"],
5
- "mappings": "AAOA,SAAS,0BAA0B;AAGnC,SAAS,eAAe;AAEjB,MAAM,eAAe;AAE5B,MAAM,WAAqB;AAAA,EACzB,OAAO;AAAA,EACP,OAAO;AAAA,EACP,UAAU;AAAA,EACV,aAAa;AAAA,EACb,cAAc;AAAA,EACd,WAAW;AACb;AAMO,MAAM,wBAAwB,QAAgD;AAAA,EAC1E;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT;AAAA,EAEA,YACE,UACA,OACA,SACA,QAAsB,MACtB;AACA,UAAM;AACN,SAAK,YAAY;AACjB,SAAK,SAAS;AACd,SAAK,WAAW;AAChB,SAAK,SAAS;AACd,UAAM,QAAQ,KAAK,MAAM,SAAS,QAAQ,YAAY,KAAK,IAAI;AAC/D,UAAM,EAAE,OAAO,QAAQ,UAAU,WAAW,GAAG,MAAM,IAAI,EAAE,GAAG,UAAU,GAAG,MAAM;AACjF,SAAK,SAAS;AACd,aAAS,MAAM,UAAU,MAAM;AAC7B,WAAK,KAAK,YAAY,KAAK,SAAS,CAAC;AACrC,WAAK,KAAK,YAAY,KAAK,IAAI,CAAC;AAAA,IAClC,CAAC;AACD,UAAM,GAAG,UAAU,MAAM,KAAK,KAAK,YAAY,KAAK,IAAI,CAAC,CAAC;AAAA,EAC5D;AAAA,EAEA,SAAwB;AACtB,WAAO,KAAK,UAAU,MAAM,SAAS,EAAE,QAAQ,CAAC,GAAG,UAAU,CAAC,EAAE;AAAA,EAClE;AAAA,EAEA,MAAgB;AACd,UAAM,OAAO,KAAK,OAAO,KAAK,EAAE,CAAC;AACjC,WAAO,EAAE,GAAG,KAAK,QAAQ,OAAO,MAAM,SAAS,IAAI,UAAU,MAAM,YAAY,MAAM;AAAA,EACvF;AAAA,EAEA,OAAO,OAAgC;AACrC,UAAM,EAAE,OAAO,UAAU,GAAG,MAAM,IAAI;AACtC,UAAM,KAAK,KAAK,OAAO,OAAO;AAC9B,QAAI,UAAU,OAAW,MAAK,OAAO,SAAS,IAAI,KAAK;AACvD,QAAI,aAAa,OAAW,MAAK,OAAO,YAAY,IAAI,QAAQ;AAChE,SAAK,SAAS,EAAE,GAAG,KAAK,QAAQ,GAAG,MAAM;AACzC,SAAK,UAAU,QAAQ,cAAc,KAAK,UAAU,KAAK,MAAM,CAAC;AAChE,SAAK,KAAK,YAAY,KAAK,IAAI,CAAC;AAAA,EAClC;AAAA,EAEA,SAAiC;AAC/B,WAAO,KAAK,OAAO,EAAE,OAAO,IAAI,CAAC,EAAE,IAAI,OAAO,UAAU,MAAM,UAAU,OAAO;AAAA,MAC7E;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE;AAAA,EACJ;AAAA,EAEA,WAA+B;AAC7B,WAAO,KAAK,OAAO,EAAE,SAAS;AAAA,MAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,MACrD,QAAQ,EAAE,GAAG,SAAS,MAAM,IAAI;AAAA,IAClC;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ,IAAY,QAAiB,UAA+B,CAAC,GAAkB;AAC3F,UAAM,UAAU,KAAK,OAAO,EAAE,SAAS,KAAK,CAAC,cAAc,UAAU,OAAO,EAAE;AAC9E,UAAM,QAAQ,SAAS,SAAS,UAAU,KAAK,SAAS;AACxD,UAAM,MACJ,WACC,QAAQ,MAAM,MAAM,IAAI,MAAM,KAAK,UAAU,OAAO,IAAI,kBAAkB,CAAC,IAAI;AAClF,QAAI,CAAC;AACH,YAAM,IAAI,MAAM,GAAG,EAAE,UAAU,SAAS,SAAS,UAAU,cAAc,YAAY,EAAE;AACzF,UAAM,KAAK,UAAU,QAAQ,IAAI,KAAK,QAAQ,UAAU,MAAM,kBAAkB;AAAA,EAClF;AAAA,EAEA,WAAW,IAAkB;AAC3B,SAAK,KAAK,UAAU,WAAW,IAAI,kBAAkB;AAAA,EACvD;AACF;",
4
+ "sourcesContent": ["import type {\n Account,\n ModelOption,\n Settings,\n SettingsEvents,\n SettingsPort,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { AgentSettings, SettingsState, SignIn } from '../services.ts';\nimport type { AgentAdapter } from './agent-port.ts';\nimport { Emitter } from './emitter.ts';\n\nexport const SETTINGS_KEY = 'slicc-agent.settings';\n\nconst defaults: Settings = {\n color: 'system',\n model: '',\n thinking: 'off',\n sendOnEnter: true,\n showThinking: false,\n diffStyle: 'unified',\n};\n\ntype Local = Omit<Settings, 'model' | 'thinking'>;\n\nexport type Login = (providerId: string, signIn: () => Promise<SignIn | null>) => Promise<string>;\n\nexport class SettingsAdapter extends Emitter<SettingsEvents> implements SettingsPort {\n readonly #settings: AgentSettings;\n readonly #agent: AgentAdapter;\n readonly #storage: Pick<Storage, 'getItem' | 'setItem'> | null;\n readonly #login: Login | null;\n #local: Local;\n\n constructor(\n settings: AgentSettings,\n agent: AgentAdapter,\n storage: Pick<Storage, 'getItem' | 'setItem'> | null,\n login: Login | null = null\n ) {\n super();\n this.#settings = settings;\n this.#agent = agent;\n this.#storage = storage;\n this.#login = login;\n const saved = JSON.parse(storage?.getItem(SETTINGS_KEY) ?? '{}') as Partial<Local>;\n const { model: _model, thinking: _thinking, ...local } = { ...defaults, ...saved };\n this.#local = local;\n settings.state.subscribe(() => {\n this.emit('accounts', this.accounts());\n this.emit('settings', this.get());\n });\n agent.on('agents', () => this.emit('settings', this.get()));\n }\n\n #state(): SettingsState {\n return this.#settings.state.value ?? { models: [], accounts: [] };\n }\n\n get(): Settings {\n const cone = this.#agent.list()[0];\n return { ...this.#local, model: cone?.model ?? '', thinking: cone?.thinking ?? 'off' };\n }\n\n update(patch: Partial<Settings>): void {\n const { model, thinking, ...local } = patch;\n const id = this.#agent.active();\n if (model !== undefined) this.#agent.setModel(id, model);\n if (thinking !== undefined) this.#agent.setThinking(id, thinking);\n this.#local = { ...this.#local, ...local };\n this.#storage?.setItem(SETTINGS_KEY, JSON.stringify(this.#local));\n this.emit('settings', this.get());\n }\n\n models(): readonly ModelOption[] {\n return this.#state().models.map(({ id, label, provider, kind, reasoning, images }) => ({\n id,\n label,\n provider,\n kind,\n reasoning,\n ...(images === undefined ? {} : { images }),\n }));\n }\n\n accounts(): readonly Account[] {\n return this.#state().accounts.map(({ needs, ...account }) =>\n needs ? { ...account, needs } : account\n );\n }\n\n async connect(id: string, secret?: string, options: { region?: string } = {}): Promise<void> {\n const account = this.#state().accounts.find((candidate) => candidate.id === id);\n const login = account?.auth === 'oauth' ? this.#login : null;\n const key =\n secret ??\n (login ? await login(id, () => this.#settings.signIn(id, BACKGROUND_CONTEXT)) : undefined);\n if (!key)\n throw new Error(`${id} needs ${account?.auth === 'oauth' ? 'a sign-in' : 'an API key'}`);\n await this.#settings.connect(id, key, options.region ?? null, BACKGROUND_CONTEXT);\n }\n\n disconnect(id: string): void {\n void this.#settings.disconnect(id, BACKGROUND_CONTEXT);\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -8,6 +8,9 @@ import {
8
8
  SPRINKLE_KIND,
9
9
  SPRINKLES_DIR,
10
10
  SprinklesDoc,
11
+ SUGGESTIONS,
12
+ SUGGESTIONS_DIR,
13
+ SUGGESTIONS_STORE,
11
14
  sprinkleFiles,
12
15
  WELCOME,
13
16
  WELCOMED
@@ -40,40 +43,43 @@ function named(agents, value) {
40
43
  const id = value.startsWith("scoop:") ? value : `scoop:${value}`;
41
44
  return id in state.scoops ? id : void 0;
42
45
  }
46
+ function entry(name, html, agentId) {
47
+ return { id: name, name, ...describe(name, html), agentId, html };
48
+ }
49
+ function reloader(options, dir, builtins, sprinkles, owners) {
50
+ const { env, agents } = options;
51
+ const { welcome, suggestions } = builtins;
52
+ return async (using) => {
53
+ const owned = await owners(using);
54
+ const stored = suggestions === void 0 ? void 0 : await env.exists(SUGGESTIONS_STORE, using);
55
+ const offered = stored?.ok === true && stored.value;
56
+ const reserved = /* @__PURE__ */ new Set([WELCOME, ...offered ? [SUGGESTIONS] : []]);
57
+ const out = [];
58
+ for (const { name, path } of await sprinkleFiles(env, dir, using)) {
59
+ if (reserved.has(name)) continue;
60
+ const read = await env.readTextFile(path, using);
61
+ if (read.ok) out.push(entry(name, read.value, owned[name] ?? agents.activeCone()));
62
+ }
63
+ if (offered)
64
+ out.push(
65
+ entry(SUGGESTIONS, suggestions, owned[SUGGESTIONS] ?? agents.activeCone())
66
+ );
67
+ if (welcome !== void 0)
68
+ out.push({ ...entry(WELCOME, welcome, owned[WELCOME] ?? "cone"), inline: true });
69
+ sprinkles.replace(using, out);
70
+ };
71
+ }
43
72
  function setupSprinkles() {
44
73
  return {
45
74
  async attach(options, context) {
46
75
  const { harness, agents, licks, env } = options;
47
76
  const dir = options.dir ?? SPRINKLES_DIR;
48
77
  const sprinkles = replicatedState([]);
49
- const welcome = options.assets ? await options.assets("packages/vfs-root/sprinkles/welcome.shtml").catch(() => void 0) : void 0;
78
+ const builtin = (name) => options.assets ? options.assets(`packages/vfs-root/sprinkles/${name}.shtml`).catch(() => void 0) : Promise.resolve(void 0);
79
+ const welcome = await builtin(WELCOME);
80
+ const suggestions = await builtin(SUGGESTIONS);
50
81
  const owners = async (using) => (await harness.snapshot(SprinklesDoc, using))?.owners ?? {};
51
- const reload = async (using) => {
52
- const owned = await owners(using);
53
- const out = [];
54
- for (const { name, path } of await sprinkleFiles(env, dir, using)) {
55
- if (name === WELCOME) continue;
56
- const read = await env.readTextFile(path, using);
57
- if (!read.ok) continue;
58
- out.push({
59
- id: name,
60
- name,
61
- ...describe(name, read.value),
62
- agentId: owned[name] ?? agents.activeCone(),
63
- html: read.value
64
- });
65
- }
66
- if (welcome !== void 0)
67
- out.push({
68
- id: WELCOME,
69
- name: WELCOME,
70
- ...describe(WELCOME, welcome),
71
- agentId: owned[WELCOME] ?? "cone",
72
- html: welcome,
73
- inline: true
74
- });
75
- sprinkles.replace(using, out);
76
- };
82
+ const reload = reloader(options, dir, { welcome, suggestions }, sprinkles, owners);
77
83
  const inside = async (path, using) => {
78
84
  const asked = homePath(path);
79
85
  const real = await env.canonicalPath(asked, using);
@@ -105,7 +111,7 @@ function setupSprinkles() {
105
111
  }
106
112
  let timer;
107
113
  const watched = await env.watch(
108
- [{ path: dir, recursive: true }],
114
+ [{ path: dir, recursive: true }, { path: SUGGESTIONS_DIR }],
109
115
  () => {
110
116
  clearTimeout(timer);
111
117
  timer = setTimeout(() => void reload(context).catch(() => void 0), options.reloadMs);
@@ -127,7 +133,8 @@ function setupSprinkles() {
127
133
  ` };
128
134
  const agentId = agentOf(caller, agents);
129
135
  await post(name, agentId, using);
130
- if (!(await owners(using))[name]) await setOwner(name, agentId, using);
136
+ if (name !== SUGGESTIONS && !(await owners(using))[name])
137
+ await setOwner(name, agentId, using);
131
138
  return { code: 0, out: `showed ${name} in the chat of ${agentId}
132
139
  ` };
133
140
  },
@@ -148,6 +155,7 @@ function setupSprinkles() {
148
155
  async send(id, payload, using) {
149
156
  const sprinkle = find(id);
150
157
  if (!sprinkle) return { delivered: false };
158
+ if (await options.intercept?.(id, payload, using)) return { delivered: true };
151
159
  if (id === WELCOME && payload.action === "onboarding-complete")
152
160
  await env.writeFile(WELCOMED, `${(/* @__PURE__ */ new Date()).toISOString()}
153
161
  `, using);