@alisio/core 0.1.0-alpha.9 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/README.md +52 -7
  2. package/dist/agents/active.d.ts +99 -0
  3. package/dist/agents/active.js +218 -0
  4. package/dist/agents/capabilities.d.ts +26 -0
  5. package/dist/agents/capabilities.js +120 -0
  6. package/dist/agents/create-agent-skill.d.ts +11 -0
  7. package/dist/agents/create-agent-skill.js +60 -0
  8. package/dist/agents/definitions.d.ts +88 -0
  9. package/dist/agents/definitions.js +404 -0
  10. package/dist/agents/draft.d.ts +41 -0
  11. package/dist/agents/draft.js +133 -0
  12. package/dist/agents/service.d.ts +57 -0
  13. package/dist/agents/service.js +86 -0
  14. package/dist/agents/templates.d.ts +8 -0
  15. package/dist/agents/templates.js +102 -0
  16. package/dist/analysis/capabilities.d.ts +48 -0
  17. package/dist/analysis/capabilities.js +90 -0
  18. package/dist/analysis/data/csv.d.ts +46 -0
  19. package/dist/analysis/data/csv.js +240 -0
  20. package/dist/analysis/data/datasets.d.ts +132 -0
  21. package/dist/analysis/data/datasets.js +441 -0
  22. package/dist/analysis/data/describe.d.ts +27 -0
  23. package/dist/analysis/data/describe.js +103 -0
  24. package/dist/analysis/data/engine-client.d.ts +58 -0
  25. package/dist/analysis/data/engine-client.js +304 -0
  26. package/dist/analysis/data/engine-entry.d.ts +1 -0
  27. package/dist/analysis/data/engine-entry.js +59 -0
  28. package/dist/analysis/data/engine-source.d.ts +4 -0
  29. package/dist/analysis/data/engine-source.js +6 -0
  30. package/dist/analysis/data/engine-types.d.ts +86 -0
  31. package/dist/analysis/data/engine-types.js +7 -0
  32. package/dist/analysis/data/infer.d.ts +42 -0
  33. package/dist/analysis/data/infer.js +118 -0
  34. package/dist/analysis/data/ingest-worker.d.ts +17 -0
  35. package/dist/analysis/data/ingest-worker.js +365 -0
  36. package/dist/analysis/data/json.d.ts +19 -0
  37. package/dist/analysis/data/json.js +44 -0
  38. package/dist/analysis/data/query-worker.d.ts +12 -0
  39. package/dist/analysis/data/query-worker.js +75 -0
  40. package/dist/analysis/data/rows.d.ts +39 -0
  41. package/dist/analysis/data/rows.js +120 -0
  42. package/dist/analysis/data/sql-guard.d.ts +20 -0
  43. package/dist/analysis/data/sql-guard.js +129 -0
  44. package/dist/analysis/data/stats.d.ts +18 -0
  45. package/dist/analysis/data/stats.js +77 -0
  46. package/dist/analysis/install-hints.d.ts +33 -0
  47. package/dist/analysis/install-hints.js +144 -0
  48. package/dist/analysis/janitor.d.ts +60 -0
  49. package/dist/analysis/janitor.js +264 -0
  50. package/dist/analysis/jobs.d.ts +94 -0
  51. package/dist/analysis/jobs.js +165 -0
  52. package/dist/analysis/oci.d.ts +129 -0
  53. package/dist/analysis/oci.js +330 -0
  54. package/dist/analysis/python/sources.d.ts +2 -0
  55. package/dist/analysis/python/sources.js +10 -0
  56. package/dist/analysis/requirements.d.ts +32 -0
  57. package/dist/analysis/requirements.js +73 -0
  58. package/dist/analysis/rerun.d.ts +40 -0
  59. package/dist/analysis/rerun.js +136 -0
  60. package/dist/analysis/runtime-manager.d.ts +146 -0
  61. package/dist/analysis/runtime-manager.js +472 -0
  62. package/dist/analysis/status.d.ts +21 -0
  63. package/dist/analysis/status.js +52 -0
  64. package/dist/application.d.ts +105 -3
  65. package/dist/application.js +446 -18
  66. package/dist/artifacts/kinds.d.ts +35 -0
  67. package/dist/artifacts/kinds.js +177 -0
  68. package/dist/artifacts/publisher.d.ts +7 -0
  69. package/dist/artifacts/publisher.js +29 -0
  70. package/dist/artifacts/store.d.ts +119 -0
  71. package/dist/artifacts/store.js +581 -0
  72. package/dist/background/janitor.d.ts +22 -0
  73. package/dist/background/janitor.js +62 -0
  74. package/dist/background/mirror.d.ts +14 -0
  75. package/dist/background/mirror.js +41 -0
  76. package/dist/background/notify.d.ts +58 -0
  77. package/dist/background/notify.js +172 -0
  78. package/dist/background/output.d.ts +46 -0
  79. package/dist/background/output.js +179 -0
  80. package/dist/background/service.d.ts +137 -0
  81. package/dist/background/service.js +410 -0
  82. package/dist/background/store.d.ts +103 -0
  83. package/dist/background/store.js +195 -0
  84. package/dist/changelog/data.d.ts +6 -0
  85. package/dist/changelog/data.js +293 -0
  86. package/dist/changelog/index.d.ts +5 -0
  87. package/dist/changelog/index.js +7 -0
  88. package/dist/changelog/parse.d.ts +53 -0
  89. package/dist/changelog/parse.js +160 -0
  90. package/dist/commands/builtins.d.ts +10 -0
  91. package/dist/commands/builtins.js +161 -0
  92. package/dist/commands/catalog.d.ts +86 -0
  93. package/dist/commands/catalog.js +304 -0
  94. package/dist/config.d.ts +206 -6
  95. package/dist/config.js +426 -20
  96. package/dist/core/compaction.js +13 -2
  97. package/dist/core/contracts.d.ts +180 -3
  98. package/dist/core/opt-in.d.ts +12 -0
  99. package/dist/core/opt-in.js +12 -0
  100. package/dist/core/output-limit.d.ts +34 -0
  101. package/dist/core/output-limit.js +39 -0
  102. package/dist/core/run-stats.d.ts +16 -0
  103. package/dist/core/run-stats.js +8 -0
  104. package/dist/core/runner.d.ts +134 -4
  105. package/dist/core/runner.js +780 -138
  106. package/dist/core/timeout.d.ts +15 -0
  107. package/dist/core/timeout.js +61 -0
  108. package/dist/core/truncation.d.ts +30 -0
  109. package/dist/core/truncation.js +83 -0
  110. package/dist/goal/blockers.d.ts +45 -0
  111. package/dist/goal/blockers.js +51 -0
  112. package/dist/goal/budget.d.ts +24 -0
  113. package/dist/goal/budget.js +53 -0
  114. package/dist/goal/command.d.ts +36 -0
  115. package/dist/goal/command.js +98 -0
  116. package/dist/goal/format.d.ts +19 -0
  117. package/dist/goal/format.js +102 -0
  118. package/dist/goal/host.d.ts +29 -0
  119. package/dist/goal/host.js +42 -0
  120. package/dist/goal/index.d.ts +9 -0
  121. package/dist/goal/index.js +9 -0
  122. package/dist/goal/machine.d.ts +186 -0
  123. package/dist/goal/machine.js +344 -0
  124. package/dist/goal/prompts.d.ts +10 -0
  125. package/dist/goal/prompts.js +75 -0
  126. package/dist/goal/service.d.ts +113 -0
  127. package/dist/goal/service.js +273 -0
  128. package/dist/goal/store.d.ts +59 -0
  129. package/dist/goal/store.js +184 -0
  130. package/dist/index.d.ts +50 -5
  131. package/dist/index.js +49 -4
  132. package/dist/mcp/connector.js +38 -6
  133. package/dist/mcp/rich.d.ts +41 -0
  134. package/dist/mcp/rich.js +362 -0
  135. package/dist/permissions/modes.d.ts +72 -0
  136. package/dist/permissions/modes.js +98 -0
  137. package/dist/plan/exit-plan.d.ts +25 -0
  138. package/dist/plan/exit-plan.js +130 -0
  139. package/dist/plan/state.d.ts +102 -0
  140. package/dist/plan/state.js +165 -0
  141. package/dist/plugins/host.d.ts +34 -1
  142. package/dist/plugins/host.js +143 -9
  143. package/dist/providers/settings.d.ts +15 -0
  144. package/dist/providers/settings.js +38 -0
  145. package/dist/reload.d.ts +75 -0
  146. package/dist/reload.js +204 -0
  147. package/dist/resources/context.js +6 -1
  148. package/dist/runtime/access.d.ts +62 -0
  149. package/dist/runtime/access.js +115 -0
  150. package/dist/runtime/blobs.d.ts +51 -0
  151. package/dist/runtime/blobs.js +177 -0
  152. package/dist/runtime/diff.d.ts +23 -0
  153. package/dist/runtime/diff.js +154 -0
  154. package/dist/runtime/ids.d.ts +8 -0
  155. package/dist/runtime/ids.js +32 -0
  156. package/dist/runtime/paths.d.ts +11 -0
  157. package/dist/runtime/paths.js +17 -1
  158. package/dist/runtime/process.d.ts +22 -0
  159. package/dist/runtime/process.js +100 -15
  160. package/dist/runtime/sqlite.d.ts +2 -0
  161. package/dist/runtime/sqlite.js +18 -0
  162. package/dist/runtime/store.d.ts +91 -3
  163. package/dist/runtime/store.js +465 -11
  164. package/dist/runtime/zip.d.ts +24 -0
  165. package/dist/runtime/zip.js +126 -0
  166. package/dist/sessions/children.js +17 -1
  167. package/dist/sessions/side-questions.d.ts +57 -0
  168. package/dist/sessions/side-questions.js +161 -0
  169. package/dist/tools/analysis.d.ts +37 -0
  170. package/dist/tools/analysis.js +573 -0
  171. package/dist/tools/artifacts.d.ts +14 -0
  172. package/dist/tools/artifacts.js +143 -0
  173. package/dist/tools/background.d.ts +7 -0
  174. package/dist/tools/background.js +165 -0
  175. package/dist/tools/data.d.ts +7 -0
  176. package/dist/tools/data.js +160 -0
  177. package/dist/tools/execute.d.ts +5 -0
  178. package/dist/tools/execute.js +15 -3
  179. package/dist/tools/goal.d.ts +19 -0
  180. package/dist/tools/goal.js +126 -0
  181. package/dist/tools/search.d.ts +17 -3
  182. package/dist/tools/search.js +153 -0
  183. package/dist/tools/standard.d.ts +4 -1
  184. package/dist/tools/standard.js +99 -18
  185. package/dist/version.d.ts +5 -3
  186. package/dist/version.js +35 -6
  187. package/package.json +2 -2
package/README.md CHANGED
@@ -1,9 +1,24 @@
1
1
  # @alisio/core
2
2
 
3
- Embeddable core of [Alisio](https://github.com/GustavoGutierrez/alisio): the agent tool loop, structured
4
- context compaction, the OpenAI-compatible provider (Chat Completions and Responses), local tools with
5
- explicit permissions, the MCP client, the plugin host (with hook timeouts and failure isolation) and a
6
- SQLite session store. Runs on Node.js >= 22.16 (`node:sqlite` with FTS5) and on Bun.
3
+ **The embeddable core of [Alisio](https://github.com/GustavoGutierrez/alisio): a provider-agnostic
4
+ agent you can drive from your own program.** No TUI, no CLI — just the tool loop, compaction, MCP
5
+ and plugin host as a library.
6
+
7
+ ## What it is
8
+
9
+ `@alisio/core` wires the agent tool loop, structured context compaction, the OpenAI-compatible
10
+ provider (Chat Completions and Responses), local tools behind explicit permissions, the MCP client,
11
+ the plugin host (hook timeouts and failure isolation) and a SQLite session store into one
12
+ `createApplication` entry point. It runs on Node.js >= 22.16 (`node:sqlite` with FTS5) and on Bun,
13
+ and uses only portable Node APIs.
14
+
15
+ ## Installation
16
+
17
+ ```sh
18
+ npm i @alisio/core # or: pnpm add @alisio/core · bun add @alisio/core
19
+ ```
20
+
21
+ ## Quick start
7
22
 
8
23
  ```ts
9
24
  import { createApplication } from "@alisio/core";
@@ -18,8 +33,38 @@ try {
18
33
  }
19
34
  ```
20
35
 
36
+ ## What you get
37
+
38
+ - **Runner**: `AgentRunner` with turn limits, timeouts, token budgets and versioned `RunEvent`
39
+ output (`schemaVersion: 1`).
40
+ - **Context compaction**: `planCompaction`, `summarize`, `renderCheckpoint`,
41
+ `shouldCompactContext` and checkpoint helpers; memory plugins hook in via `CompactionHooks`.
42
+ - **Providers**: `ProviderRegistry` / `ActiveProvider` for OpenAI-compatible, DeepSeek, OpenCode
43
+ Console and OpenCode Go; `ProviderSettingsStore` for non-secret profiles plus a separate
44
+ credentials store.
45
+ - **Local tools**: reads by default, `--allow-write`/`--allow-process`-style policy, path checks
46
+ and standard tools (`ToolRegistry`, `registerStandard`).
47
+ - **MCP**: `McpConnector`, server discovery and tool projection.
48
+ - **Plugin host**: `PluginHost` with built-in plugin catalogs, npm install (`installPlugin`,
49
+ `cliInstall`), hook timeouts and failure isolation.
50
+ - **Sessions**: `SQLiteStore` with reconciliation and crash recovery.
51
+ - **Skills and prompts**: `Skills`, `ProjectContext` (`AGENTS.md`), `loadPromptTemplates`.
52
+ - **Trust**: `resolveTrust` / `setTrust` / `listTrust` for per-directory project trust.
53
+ - **Startup screen**: reusable `renderStartup` sections and the default mascot.
54
+
21
55
  Built-in plugins are opt-in for embedders: pass `builtins` (the `alisio` CLI wires
22
- `@alisio/plugin-memory`). See the [architecture](https://gustavogutierrez.github.io/alisio/architecture) and
23
- [configuration](https://gustavogutierrez.github.io/alisio/configuration) docs.
56
+ `@alisio/plugin-memory` and `@alisio/plugin-subagents`).
57
+
58
+ ## Docs
59
+
60
+ Architecture: <https://gustavogutierrez.github.io/alisio/architecture> ·
61
+ Configuration: <https://gustavogutierrez.github.io/alisio/configuration>.
62
+
63
+ ## Requirements
64
+
65
+ Node.js **>= 22.16** or Bun **>= 1.4.2**.
66
+
67
+ ## License
24
68
 
25
- Maintainer: Gustavo Gutiérrez · License: MIT
69
+ MIT. Maintained by Gustavo Gutiérrez Mercado. Source: <https://github.com/GustavoGutierrez/alisio> ·
70
+ npm: <https://www.npmjs.com/settings/alisio/packages>.
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Pure logic for the ACTIVE (main-session) agent: the built-in catalog, user/plugin
3
+ * contributions, resolution and the per-run options an agent implies. No terminal or pi-tui
4
+ * imports here — the Picker and status-line rendering live in each surface (e.g. the TUI shell).
5
+ *
6
+ * The active agent drives the MAIN session (its `instructions` are appended per run and an
7
+ * agent-specific `model` is offered on selection). This is deliberately separate from the
8
+ * delegated child-session agents of the subagents plugin: a subagent definition becomes a main
9
+ * agent only when it is marked main-capable (`mode: primary|all`), which the subagents plugin
10
+ * publishes for the host to read.
11
+ */
12
+ import type { CommandDescriptor } from "@alisio/sdk";
13
+ export interface ActiveAgent {
14
+ /** Stable id, also the persisted `agents.active` value. */
15
+ id: string;
16
+ name: string;
17
+ description: string;
18
+ /** System prompt appended to the main session's instructions on every run. */
19
+ instructions?: string;
20
+ /** Optional default model selector (`provider/model` or an unambiguous model id). */
21
+ model?: string;
22
+ /** Read-only agents run with write/process/external tools disabled and approvals off. */
23
+ readOnly?: boolean;
24
+ /** Default reasoning effort (`alisio.reasoning.effort`); an explicit session/user effort wins. */
25
+ effort?: string;
26
+ /** Definition file of a contributed agent (shows its Project/Global scope). */
27
+ path?: string;
28
+ /** Product built-ins are shown as built-in and never shadowed by contributed definitions. */
29
+ source: "builtin" | "user" | "plugin";
30
+ }
31
+ export declare const DEFAULT_AGENT_ID = "build";
32
+ export declare const PLAN_AGENT_ID = "plan";
33
+ /** Product built-ins. `build` keeps the CURRENT behavior exactly: no added persona, full power. */
34
+ export declare const BUILTIN_AGENTS: ActiveAgent[];
35
+ export interface MainCapableAgentRecord {
36
+ name: string;
37
+ description: string;
38
+ prompt: string;
39
+ model?: string;
40
+ readOnly?: boolean;
41
+ effort?: string;
42
+ source: string;
43
+ path?: string;
44
+ }
45
+ /** Maps a main-capable definition published by the subagents plugin to an active agent. */
46
+ export declare function mainAgentFromRecord(record: MainCapableAgentRecord): ActiveAgent;
47
+ /** Builds the selectable catalog from the subagents plugin's published state (best-effort). */
48
+ export declare function agentCatalogFromState(untrusted: unknown): ActiveAgent[];
49
+ /**
50
+ * The full selectable catalog: built-ins first, then contributed main-capable definitions.
51
+ * A contributed definition may never shadow a built-in id; later duplicates of a contributed id
52
+ * are dropped (the subagents plugin already resolved precedence by its own discovery order).
53
+ */
54
+ export declare function activeAgentCatalog(contributions?: ActiveAgent[]): ActiveAgent[];
55
+ /**
56
+ * The agents Shift+Tab (and the web selector) cycles through, in a STABLE order: `build`, then
57
+ * `plan`, then every other main-capable agent (`mode: primary|all`) by name. The catalog order of
58
+ * contributed agents follows plugin discovery and is not stable across reloads, so cycling never
59
+ * relies on it. Duplicated ids are dropped.
60
+ */
61
+ export declare function cycleableAgents(agents: ActiveAgent[]): ActiveAgent[];
62
+ /**
63
+ * The agent after (`step` 1) or before (`step` -1) `currentId` in the cycle, wrapping around. An
64
+ * unknown current id starts the cycle at its first agent (`build`). An empty list yields undefined.
65
+ */
66
+ export declare function nextAgent(agents: ActiveAgent[], currentId: string | undefined, step?: 1 | -1): ActiveAgent | undefined;
67
+ /** Resolves the persisted agent id; unknown ids fall back to the built-in default (`build`). */
68
+ export declare function resolveActiveAgent(agents: ActiveAgent[], id: string | undefined): ActiveAgent;
69
+ /** The run options an active agent implies. An undefined agent yields the current behavior. */
70
+ export declare function agentRunOptions(agent: ActiveAgent | undefined): {
71
+ instructions?: string;
72
+ policy?: {
73
+ write: false;
74
+ process: false;
75
+ external: false;
76
+ };
77
+ approvals?: false;
78
+ reasoningEffort?: string;
79
+ optInTools?: string[];
80
+ };
81
+ /**
82
+ * Every loaded agent is also a slash command `/agent:<id>` that activates it. The `agent:`
83
+ * namespace keeps these commands from ever colliding with built-ins, plugin commands, prompt
84
+ * templates or `skill:<id>` entries; when a higher-precedence source already owns the exact name
85
+ * (e.g. a plugin with id `agent`), the agent command is skipped.
86
+ */
87
+ export declare const AGENT_COMMAND_PREFIX = "agent:";
88
+ export declare const agentCommandName: (id: string) => string;
89
+ /** The agent id a `/agent:<id>` command names, or undefined for any other command. */
90
+ export declare function agentIdFromCommand(name: string): string | undefined;
91
+ /** `/agent:<id>` descriptors for `agents`, skipping names already in `taken`. */
92
+ export declare function agentCommandDescriptors(agents: ActiveAgent[], taken?: ReadonlySet<string>): CommandDescriptor[];
93
+ export interface AgentPickerItem {
94
+ value: string;
95
+ label: string;
96
+ description: string;
97
+ }
98
+ /** Picker rows for `/agents`: name with (current), built-in/default and read-only markers. */
99
+ export declare function agentPickerItems(agents: ActiveAgent[], activeId: string): AgentPickerItem[];
@@ -0,0 +1,218 @@
1
+ import { EXIT_PLAN_TOOL } from "../core/opt-in.js";
2
+ export const DEFAULT_AGENT_ID = "build";
3
+ export const PLAN_AGENT_ID = "plan";
4
+ const PLAN_INSTRUCTIONS = `You are the "plan" agent: a read-only planning assistant for this main session.
5
+
6
+ Your job is analysis and planning only. Investigate the repository with read-only tools
7
+ (list_files, search_text, read_file, git_status, git_diff) and return a concrete, ordered plan:
8
+ files to change, functions to touch, risks and verification steps. You may run context and
9
+ inspection tools that do not modify anything.
10
+
11
+ You never edit, write or delete files, and you never start processes that change the workspace
12
+ or the network. If a task requires changes, hand back a precise plan (and the exact commands)
13
+ instead of making them. You do not implement the plan yourself, even when the user approves it:
14
+ approval hands the plan to the build agent.
15
+
16
+ When the plan is complete, finish by calling \`exit_plan\` exactly once with the whole plan in
17
+ Markdown (and a short \`title\`). Do not paste the plan in your reply first: exit_plan shows it to
18
+ the user and asks for a decision. Write the plan with these sections, in this order:
19
+
20
+ # <Title>
21
+ ## Goal
22
+ What will be true when this is done, in one or two sentences.
23
+ ## Context
24
+ What you found in the repository that the plan relies on (files, functions, conventions).
25
+ ## Steps
26
+ A numbered, ordered list. Each step names the files and functions to change and what changes.
27
+ ## Risks
28
+ What could go wrong, what is uncertain, and what you did not verify.
29
+ ## Verification
30
+ The exact commands and checks that prove the work is done.
31
+
32
+ Read the tool result: "approved" means the build agent will implement the plan, so reply with one
33
+ short sentence and stop. "skipped" means stay in plan mode and do not call exit_plan again unless
34
+ asked. "feedback" carries extra context from the user: revise the plan and call exit_plan again
35
+ with the complete updated plan.`;
36
+ /** Product built-ins. `build` keeps the CURRENT behavior exactly: no added persona, full power. */
37
+ export const BUILTIN_AGENTS = [
38
+ {
39
+ id: DEFAULT_AGENT_ID,
40
+ name: "build",
41
+ description: "Default full-power agent: edits code and files, runs processes and verifies its work through the normal permission flow.",
42
+ source: "builtin",
43
+ },
44
+ {
45
+ id: PLAN_AGENT_ID,
46
+ name: "plan",
47
+ description: "Read-only planning agent: analyzes the codebase and returns an implementation plan without modifying anything.",
48
+ instructions: PLAN_INSTRUCTIONS,
49
+ readOnly: true,
50
+ source: "builtin",
51
+ },
52
+ ];
53
+ /** Maps a main-capable definition published by the subagents plugin to an active agent. */
54
+ export function mainAgentFromRecord(record) {
55
+ const source = String(record.source ?? "");
56
+ return {
57
+ id: record.name,
58
+ name: record.name,
59
+ description: record.description,
60
+ ...(record.prompt ? { instructions: record.prompt } : {}),
61
+ ...(record.model ? { model: record.model } : {}),
62
+ ...(record.readOnly ? { readOnly: true } : {}),
63
+ ...(typeof record.effort === "string" && record.effort ? { effort: record.effort } : {}),
64
+ ...(typeof record.path === "string" && record.path ? { path: record.path } : {}),
65
+ ...(source.startsWith("plugin:")
66
+ ? { source: "plugin" }
67
+ : { source: "user" }),
68
+ };
69
+ }
70
+ /** Builds the selectable catalog from the subagents plugin's published state (best-effort). */
71
+ export function agentCatalogFromState(untrusted) {
72
+ if (!Array.isArray(untrusted))
73
+ return activeAgentCatalog([]);
74
+ const records = untrusted.filter((entry) => !!entry &&
75
+ typeof entry === "object" &&
76
+ typeof entry.name === "string" &&
77
+ typeof entry.description === "string" &&
78
+ entry.description.length > 0 &&
79
+ typeof entry.prompt === "string");
80
+ return activeAgentCatalog(records.map(mainAgentFromRecord));
81
+ }
82
+ /**
83
+ * The full selectable catalog: built-ins first, then contributed main-capable definitions.
84
+ * A contributed definition may never shadow a built-in id; later duplicates of a contributed id
85
+ * are dropped (the subagents plugin already resolved precedence by its own discovery order).
86
+ */
87
+ export function activeAgentCatalog(contributions = []) {
88
+ const seen = new Set();
89
+ const out = [];
90
+ for (const agent of [...BUILTIN_AGENTS, ...contributions]) {
91
+ if (seen.has(agent.id))
92
+ continue;
93
+ seen.add(agent.id);
94
+ out.push(agent);
95
+ }
96
+ return out;
97
+ }
98
+ /**
99
+ * The agents Shift+Tab (and the web selector) cycles through, in a STABLE order: `build`, then
100
+ * `plan`, then every other main-capable agent (`mode: primary|all`) by name. The catalog order of
101
+ * contributed agents follows plugin discovery and is not stable across reloads, so cycling never
102
+ * relies on it. Duplicated ids are dropped.
103
+ */
104
+ export function cycleableAgents(agents) {
105
+ const builtinRank = new Map(BUILTIN_AGENTS.map((agent, index) => [agent.id, index]));
106
+ const seen = new Set();
107
+ const unique = agents.filter((agent) => {
108
+ if (seen.has(agent.id))
109
+ return false;
110
+ seen.add(agent.id);
111
+ return true;
112
+ });
113
+ const byName = (a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()) || a.id.localeCompare(b.id);
114
+ return [
115
+ ...unique
116
+ .filter((agent) => builtinRank.has(agent.id))
117
+ .sort((a, b) => (builtinRank.get(a.id) ?? 0) - (builtinRank.get(b.id) ?? 0)),
118
+ ...unique.filter((agent) => !builtinRank.has(agent.id)).sort(byName),
119
+ ];
120
+ }
121
+ /**
122
+ * The agent after (`step` 1) or before (`step` -1) `currentId` in the cycle, wrapping around. An
123
+ * unknown current id starts the cycle at its first agent (`build`). An empty list yields undefined.
124
+ */
125
+ export function nextAgent(agents, currentId, step = 1) {
126
+ const cycle = cycleableAgents(agents);
127
+ if (!cycle.length)
128
+ return undefined;
129
+ const index = cycle.findIndex((agent) => agent.id === currentId);
130
+ if (index < 0)
131
+ return cycle[0];
132
+ return cycle[(index + step + cycle.length) % cycle.length];
133
+ }
134
+ /** Resolves the persisted agent id; unknown ids fall back to the built-in default (`build`). */
135
+ export function resolveActiveAgent(agents, id) {
136
+ const found = id ? agents.find((a) => a.id === id) : undefined;
137
+ if (found)
138
+ return found;
139
+ return agents.find((a) => a.id === DEFAULT_AGENT_ID) ?? agents[0] ?? BUILTIN_AGENTS[0];
140
+ }
141
+ /** The run options an active agent implies. An undefined agent yields the current behavior. */
142
+ export function agentRunOptions(agent) {
143
+ if (!agent)
144
+ return {};
145
+ return {
146
+ ...(agent.instructions ? { instructions: agent.instructions } : {}),
147
+ // `exit_plan` exists for the built-in plan agent only (it is hidden from every other run).
148
+ ...(agent.id === PLAN_AGENT_ID && agent.source === "builtin"
149
+ ? { optInTools: [EXIT_PLAN_TOOL] }
150
+ : {}),
151
+ ...(agent.effort ? { reasoningEffort: agent.effort } : {}),
152
+ ...(agent.readOnly
153
+ ? {
154
+ policy: { write: false, process: false, external: false },
155
+ approvals: false,
156
+ }
157
+ : {}),
158
+ };
159
+ }
160
+ /**
161
+ * Every loaded agent is also a slash command `/agent:<id>` that activates it. The `agent:`
162
+ * namespace keeps these commands from ever colliding with built-ins, plugin commands, prompt
163
+ * templates or `skill:<id>` entries; when a higher-precedence source already owns the exact name
164
+ * (e.g. a plugin with id `agent`), the agent command is skipped.
165
+ */
166
+ export const AGENT_COMMAND_PREFIX = "agent:";
167
+ const COMMAND_SAFE_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
168
+ export const agentCommandName = (id) => `${AGENT_COMMAND_PREFIX}${id}`;
169
+ /** The agent id a `/agent:<id>` command names, or undefined for any other command. */
170
+ export function agentIdFromCommand(name) {
171
+ if (!name.startsWith(AGENT_COMMAND_PREFIX))
172
+ return undefined;
173
+ const id = name.slice(AGENT_COMMAND_PREFIX.length);
174
+ return COMMAND_SAFE_ID.test(id) ? id : undefined;
175
+ }
176
+ /** `/agent:<id>` descriptors for `agents`, skipping names already in `taken`. */
177
+ export function agentCommandDescriptors(agents, taken = new Set()) {
178
+ const out = [];
179
+ const seen = new Set(taken);
180
+ for (const agent of agents) {
181
+ if (!COMMAND_SAFE_ID.test(agent.id))
182
+ continue;
183
+ const name = agentCommandName(agent.id);
184
+ if (seen.has(name))
185
+ continue;
186
+ seen.add(name);
187
+ out.push({
188
+ name,
189
+ description: `Activate the ${agent.name} agent${agent.id === DEFAULT_AGENT_ID ? " (default)" : ""}: ${agent.description}`,
190
+ source: "agent",
191
+ owner: agent.source,
192
+ surfaces: ["tui", "web", "api"],
193
+ execution: "surface",
194
+ });
195
+ }
196
+ return out;
197
+ }
198
+ /** Picker rows for `/agents`: name with (current), built-in/default and read-only markers. */
199
+ export function agentPickerItems(agents, activeId) {
200
+ return agents.map((agent) => ({
201
+ value: agent.id,
202
+ label: [
203
+ agent.name,
204
+ agent.id === activeId ? "(current)" : undefined,
205
+ agent.id === DEFAULT_AGENT_ID ? "(default)" : undefined,
206
+ agent.readOnly ? "read-only" : undefined,
207
+ ]
208
+ .filter(Boolean)
209
+ .join(" · "),
210
+ description: [
211
+ agent.description,
212
+ agent.model ? `default model: ${agent.model}` : undefined,
213
+ agent.instructions ? "injects its system prompt from the next prompt" : undefined,
214
+ ]
215
+ .filter(Boolean)
216
+ .join(" · "),
217
+ }));
218
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Capability-driven agent settings: which reasoning, summary, verbosity and text-format options a
3
+ * model supports, derived only from its catalog metadata (`ModelInfo.effort`, `inputModalities`,
4
+ * `capabilities`). Providers that declare nothing (most OpenAI-compatible `GET /models` answers)
5
+ * get a permissive default: every option is offered and `known` is false, so surfaces can say the
6
+ * support is unverified. Explicit `false` metadata always hides an option.
7
+ */
8
+ import type { AgentDefinitionInput, AgentModelCapabilities, AgentModelOption, AvailableProviderModel, ModelInfo } from "@alisio/sdk";
9
+ /** Levels offered when a reasoning model does not list its own. */
10
+ export declare const DEFAULT_EFFORT_LEVELS: string[];
11
+ /** What `model` supports for the agent editor (permissive when the catalog says nothing). */
12
+ export declare function agentModelCapabilities(model: ModelInfo | undefined): AgentModelCapabilities;
13
+ /** Short labels such as "Reasoning · Tools · Vision", only for declared support. */
14
+ export declare function agentModelLabels(capabilities: AgentModelCapabilities): string[];
15
+ /** The editor's model options from the configured catalogs; `active` marks the running model. */
16
+ export declare function agentModelOptions(available: AvailableProviderModel[], active?: {
17
+ profile?: string;
18
+ provider?: string;
19
+ model: string;
20
+ }): AgentModelOption[];
21
+ /**
22
+ * Drops or replaces settings `capabilities` does not support: unsupported reasoning settings are
23
+ * removed, an unknown effort level falls back to the model default (or is removed), an unsupported
24
+ * text format becomes `text`, unsupported verbosity is removed.
25
+ */
26
+ export declare function fitAgentSettings<T extends Pick<AgentDefinitionInput, "reasoning" | "text">>(settings: T, capabilities: AgentModelCapabilities): T;
@@ -0,0 +1,120 @@
1
+ /** Levels offered when a reasoning model does not list its own. */
2
+ export const DEFAULT_EFFORT_LEVELS = ["low", "medium", "high"];
3
+ const flag = (capabilities, keys) => {
4
+ if (!capabilities)
5
+ return undefined;
6
+ for (const key of keys) {
7
+ const value = capabilities[key];
8
+ if (typeof value === "boolean")
9
+ return value;
10
+ if (value === "true" || value === "supported")
11
+ return true;
12
+ if (value === "false" || value === "unsupported")
13
+ return false;
14
+ }
15
+ return undefined;
16
+ };
17
+ /** What `model` supports for the agent editor (permissive when the catalog says nothing). */
18
+ export function agentModelCapabilities(model) {
19
+ const caps = model?.capabilities;
20
+ const levels = model?.effort?.supportedLevels?.filter(Boolean) ?? [];
21
+ const declaredReasoning = flag(caps, ["reasoning", "reasoning_effort", "thinking"]);
22
+ const reasoning = levels.length > 0 || declaredReasoning !== false;
23
+ const summary = reasoning && flag(caps, ["reasoning_summary", "reasoningSummary"]) !== false;
24
+ const verbosity = flag(caps, ["verbosity", "text_verbosity"]) !== false;
25
+ const json = flag(caps, ["json_mode", "json_object", "response_format"]);
26
+ const schema = flag(caps, ["structured_outputs", "json_schema", "structuredOutputs"]);
27
+ const textFormats = ["text"];
28
+ if (json !== false)
29
+ textFormats.push("json_object");
30
+ if (schema !== false)
31
+ textFormats.push("json_schema");
32
+ const tools = flag(caps, ["tools", "tool_calling", "function_calling", "toolCalling"]);
33
+ const vision = model?.inputModalities?.includes("image") ||
34
+ model?.modalities?.includes("image") ||
35
+ flag(caps, ["vision", "image_input"]) === true
36
+ ? true
37
+ : flag(caps, ["vision", "image_input"]);
38
+ const known = !!levels.length ||
39
+ !!model?.inputModalities?.length ||
40
+ !!model?.modalities?.length ||
41
+ !!(caps && Object.keys(caps).length);
42
+ return {
43
+ known,
44
+ reasoning,
45
+ effortLevels: reasoning ? (levels.length ? levels : DEFAULT_EFFORT_LEVELS) : [],
46
+ ...(reasoning && model?.effort?.defaultLevel
47
+ ? { defaultEffort: model.effort.defaultLevel }
48
+ : {}),
49
+ summary,
50
+ verbosity,
51
+ textFormats,
52
+ ...(tools !== undefined ? { tools } : {}),
53
+ ...(vision !== undefined ? { vision } : {}),
54
+ };
55
+ }
56
+ /** Short labels such as "Reasoning · Tools · Vision", only for declared support. */
57
+ export function agentModelLabels(capabilities) {
58
+ if (!capabilities.known)
59
+ return [];
60
+ return [
61
+ capabilities.reasoning ? "Reasoning" : undefined,
62
+ capabilities.tools ? "Tools" : undefined,
63
+ capabilities.vision ? "Vision" : undefined,
64
+ capabilities.textFormats.includes("json_schema") ? "Structured output" : undefined,
65
+ ].filter((label) => !!label);
66
+ }
67
+ /** The editor's model options from the configured catalogs; `active` marks the running model. */
68
+ export function agentModelOptions(available, active) {
69
+ return available.map((entry) => {
70
+ const capabilities = agentModelCapabilities(entry.model);
71
+ return {
72
+ reference: entry.reference,
73
+ provider: entry.provider,
74
+ profile: entry.profile,
75
+ providerName: entry.providerName,
76
+ id: entry.model.id,
77
+ ...(entry.model.name ? { name: entry.model.name } : {}),
78
+ active: !!active &&
79
+ entry.model.id === active.model &&
80
+ (active.profile ? entry.profile === active.profile : entry.provider === active.provider),
81
+ capabilities,
82
+ labels: agentModelLabels(capabilities),
83
+ };
84
+ });
85
+ }
86
+ /**
87
+ * Drops or replaces settings `capabilities` does not support: unsupported reasoning settings are
88
+ * removed, an unknown effort level falls back to the model default (or is removed), an unsupported
89
+ * text format becomes `text`, unsupported verbosity is removed.
90
+ */
91
+ export function fitAgentSettings(settings, capabilities) {
92
+ const reasoning = { ...(settings.reasoning ?? {}) };
93
+ if (!capabilities.reasoning) {
94
+ delete reasoning.effort;
95
+ delete reasoning.summary;
96
+ }
97
+ else if (reasoning.effort && !capabilities.effortLevels.includes(reasoning.effort)) {
98
+ if (capabilities.defaultEffort)
99
+ reasoning.effort = capabilities.defaultEffort;
100
+ else
101
+ delete reasoning.effort;
102
+ }
103
+ if (!capabilities.summary)
104
+ delete reasoning.summary;
105
+ const text = { ...(settings.text ?? {}) };
106
+ if (text.format && !capabilities.textFormats.includes(text.format.type))
107
+ text.format = { type: "text" };
108
+ if (!capabilities.verbosity)
109
+ delete text.verbosity;
110
+ const out = { ...settings };
111
+ if (Object.keys(reasoning).length)
112
+ out.reasoning = reasoning;
113
+ else
114
+ delete out.reasoning;
115
+ if (Object.keys(text).length)
116
+ out.text = text;
117
+ else
118
+ delete out.text;
119
+ return out;
120
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The bundled `create-agent` skill: agent-authoring standards the ACTIVE model follows when it
3
+ * writes or refines an agent's instructions (assisted creation in the web Agents window and the
4
+ * TUI `/agents` manager). A user or project skill named `create-agent` (or `agent-creator`)
5
+ * replaces it, so teams can encode their own conventions.
6
+ */
7
+ /** Skill names that override the bundled guidance, in order of preference. */
8
+ export declare const AGENT_AUTHORING_SKILL_NAMES: readonly ["create-agent", "agent-creator"];
9
+ export declare const CREATE_AGENT_SKILL = "---\nname: create-agent\ndescription: Standards for writing the system prompt (instructions) of an Alisio agent.\n---\n# Writing agent instructions\n\nAn agent's instructions are its system prompt. They are read on every turn, so every line must\nearn its place. Write them in Markdown, in the second person (\"You ...\"), in English unless the\nuser asks otherwise.\n\n## Required sections\n\n1. **Role** \u2014 one or two sentences: who the agent is and who it serves.\n2. **Goal** \u2014 the outcome a successful turn produces, stated so it can be checked.\n3. **Scope** \u2014 what the agent handles and, explicitly, what it must decline or hand back.\n4. **How to work** \u2014 an ordered method for the typical task (investigate, act, verify, report).\n5. **Tool usage** \u2014 when to read, search, edit or run processes; prefer reading before editing;\n verify changes (tests, type checks) before claiming success; ask before destructive,\n irreversible or external actions (deleting data, deploying, spending money, contacting people).\n6. **Constraints** \u2014 hard rules: safety, privacy, secrets never echoed, repository conventions,\n performance or style limits. Phrase them as testable rules, not vague values.\n7. **Output format** \u2014 the exact shape of the final answer (headings, lists, tables, JSON keys,\n length). Match the agent's text format setting.\n8. **Examples** (optional) \u2014 one short input \u2192 output pair when the format or tone is unusual.\n\n## Quality bar\n\n- Be specific to the described job; remove generic filler (\"be helpful\", \"be accurate\").\n- Prefer short imperative bullets over paragraphs. Target 150\u2013600 words.\n- Never invent tools, files, APIs or data the agent does not have; tell it to say when it lacks\n information instead of guessing.\n- Keep the agent honest: report what was verified and what was not.\n- When refining an existing definition, keep what already works, apply the user's requested\n changes, and fill any missing required section.\n\n## Settings to suggest\n\n- Reasoning effort: `high` for analysis, debugging, security or multi-step refactors; `medium`\n for general engineering; `low` for formatting, summaries and support replies.\n- Reasoning summary: `auto` by default; `none` for short conversational agents; `detailed` when\n the user audits the reasoning.\n- Verbosity: `low` for terse operational agents, `medium` by default, `high` for reports.\n- Text format: `text` unless the agent must return machine-readable output (`json_object`,\n or `json_schema` when a strict schema is given).\n";
10
+ /** The skill body without the loader preamble and frontmatter (what is sent as guidance). */
11
+ export declare function skillBody(text: string): string;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * The bundled `create-agent` skill: agent-authoring standards the ACTIVE model follows when it
3
+ * writes or refines an agent's instructions (assisted creation in the web Agents window and the
4
+ * TUI `/agents` manager). A user or project skill named `create-agent` (or `agent-creator`)
5
+ * replaces it, so teams can encode their own conventions.
6
+ */
7
+ /** Skill names that override the bundled guidance, in order of preference. */
8
+ export const AGENT_AUTHORING_SKILL_NAMES = ["create-agent", "agent-creator"];
9
+ export const CREATE_AGENT_SKILL = `---
10
+ name: create-agent
11
+ description: Standards for writing the system prompt (instructions) of an Alisio agent.
12
+ ---
13
+ # Writing agent instructions
14
+
15
+ An agent's instructions are its system prompt. They are read on every turn, so every line must
16
+ earn its place. Write them in Markdown, in the second person ("You ..."), in English unless the
17
+ user asks otherwise.
18
+
19
+ ## Required sections
20
+
21
+ 1. **Role** — one or two sentences: who the agent is and who it serves.
22
+ 2. **Goal** — the outcome a successful turn produces, stated so it can be checked.
23
+ 3. **Scope** — what the agent handles and, explicitly, what it must decline or hand back.
24
+ 4. **How to work** — an ordered method for the typical task (investigate, act, verify, report).
25
+ 5. **Tool usage** — when to read, search, edit or run processes; prefer reading before editing;
26
+ verify changes (tests, type checks) before claiming success; ask before destructive,
27
+ irreversible or external actions (deleting data, deploying, spending money, contacting people).
28
+ 6. **Constraints** — hard rules: safety, privacy, secrets never echoed, repository conventions,
29
+ performance or style limits. Phrase them as testable rules, not vague values.
30
+ 7. **Output format** — the exact shape of the final answer (headings, lists, tables, JSON keys,
31
+ length). Match the agent's text format setting.
32
+ 8. **Examples** (optional) — one short input → output pair when the format or tone is unusual.
33
+
34
+ ## Quality bar
35
+
36
+ - Be specific to the described job; remove generic filler ("be helpful", "be accurate").
37
+ - Prefer short imperative bullets over paragraphs. Target 150–600 words.
38
+ - Never invent tools, files, APIs or data the agent does not have; tell it to say when it lacks
39
+ information instead of guessing.
40
+ - Keep the agent honest: report what was verified and what was not.
41
+ - When refining an existing definition, keep what already works, apply the user's requested
42
+ changes, and fill any missing required section.
43
+
44
+ ## Settings to suggest
45
+
46
+ - Reasoning effort: \`high\` for analysis, debugging, security or multi-step refactors; \`medium\`
47
+ for general engineering; \`low\` for formatting, summaries and support replies.
48
+ - Reasoning summary: \`auto\` by default; \`none\` for short conversational agents; \`detailed\` when
49
+ the user audits the reasoning.
50
+ - Verbosity: \`low\` for terse operational agents, \`medium\` by default, \`high\` for reports.
51
+ - Text format: \`text\` unless the agent must return machine-readable output (\`json_object\`,
52
+ or \`json_schema\` when a strict schema is given).
53
+ `;
54
+ /** The skill body without the loader preamble and frontmatter (what is sent as guidance). */
55
+ export function skillBody(text) {
56
+ return text
57
+ .replace(/^Skill root:.*\r?\n(?:Use skill_resource.*\r?\n)?/, "")
58
+ .replace(/^---\r?\n[\s\S]*?\r?\n---[ \t]*\r?\n?/, "")
59
+ .trim();
60
+ }