@robota-sdk/agent-preset 3.0.0-beta.100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # @robota-sdk/agent-preset
2
+
3
+ Presets and output styles for the Robota SDK. A preset is a named bundle of
4
+ `@robota-sdk/agent-framework` session option overrides: persona, model and effort, permission
5
+ posture, command-module selection, execution capabilities and autonomy. An output style is a named
6
+ set of instructions for how responses are written. This package owns both contracts, the built-in
7
+ presets and styles, and the registries that resolve them.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @robota-sdk/agent-preset @robota-sdk/agent-framework
13
+ ```
14
+
15
+ Requires Node.js 22.12 or later.
16
+
17
+ ## Presets
18
+
19
+ ```typescript
20
+ import { createPresetRegistry } from '@robota-sdk/agent-preset';
21
+
22
+ // A registry holds its own list: the built-ins plus any external presets you pass.
23
+ // Two registries in one process never see each other's presets.
24
+ const registry = createPresetRegistry();
25
+
26
+ // Resolve a preset into session option overrides.
27
+ // Precedence (low → high): preset < cliOverrides < explicit.
28
+ const options = registry.resolvePreset('careful-reviewer', {
29
+ cliOverrides: { model: 'some-model' },
30
+ explicit: { temperature: 0.2 },
31
+ });
32
+
33
+ // List presets for a picker, or read one definition.
34
+ const summaries = registry.listPresets(); // [{ id, title, description }, ...]
35
+ const preset = registry.getPreset('autonomous-builder');
36
+ console.log(options, summaries, preset);
37
+ ```
38
+
39
+ Resolving an unknown ID throws, naming the available presets. `deniedTools` from every layer are
40
+ combined rather than replaced. When no layer sets `permissionMode`, it comes from
41
+ `defaultPermissionMode`, or else from `autonomy` (`ask-first` and `balanced` map to `default`,
42
+ `act-first` to `acceptEdits`).
43
+
44
+ ### Built-in presets
45
+
46
+ | ID | Posture |
47
+ | -------------------- | -------------------------------------------------------------------------------------- |
48
+ | `default` | No overrides; resolving it reproduces the standard agent behaviour |
49
+ | `autonomous-builder` | High effort, acts first, parallel subagents, self-verification |
50
+ | `careful-reviewer` | High effort, asks first, no parallel subagents, self-verification |
51
+ | `neutral-executor` | Medium effort, balanced autonomy, follows instructions literally, no self-verification |
52
+
53
+ `defaultPreset` and `autonomousBuilderPreset` are also exported as values.
54
+
55
+ ### External presets
56
+
57
+ External presets are JSON files in a directory your product chooses:
58
+
59
+ ```typescript
60
+ import { createPresetRegistry, loadExternalPresetsFromDir } from '@robota-sdk/agent-preset';
61
+
62
+ const { presets, loaded, errors } = loadExternalPresetsFromDir('/path/to/my-app/presets');
63
+ for (const { file, error } of errors) console.warn(`${file}: ${error}`);
64
+
65
+ const registry = createPresetRegistry(presets);
66
+ console.log(loaded);
67
+ ```
68
+
69
+ Each file is checked with `validateExternalPreset`. A malformed file, an ID that collides with a
70
+ built-in, or a duplicate ID is reported in `errors` and skipped; the rest still load. A missing
71
+ directory yields no presets. `partitionExternalPresets` applies the same collision rules to presets
72
+ you already have in memory.
73
+
74
+ ## Output styles
75
+
76
+ `createOutputStyleRegistry(sources)` combines the built-in styles (`default`, `concise`,
77
+ `proactive`, `explanatory`, `learning`) with Markdown style files from sources you pass
78
+ (`managed`, `user` or `project` scope, each with a precedence; a higher precedence wins). A style
79
+ file's ID is its file name without `.md`; it has optional frontmatter (`name`, `description`,
80
+ `keep-coding-instructions`, `token-cost`) and a non-empty body with the instructions. A file cannot
81
+ replace a built-in style. `loadOutputStylesFromSources` returns the styles plus per-file errors, and
82
+ `parseOutputStyleFile` parses one file.
83
+
84
+ ```typescript
85
+ import { createOutputStyleRegistry } from '@robota-sdk/agent-preset';
86
+
87
+ const styles = createOutputStyleRegistry([
88
+ {
89
+ scope: 'user',
90
+ displayName: '~/.my-app/output-styles',
91
+ precedence: 1,
92
+ files: [
93
+ {
94
+ fileName: 'terse.md',
95
+ content: '---\nname: Terse\ntoken-cost: low\n---\nAnswer in as few words as possible.',
96
+ },
97
+ ],
98
+ },
99
+ ]);
100
+
101
+ console.log(styles.listOutputStyles().map((style) => style.id));
102
+ const terse = styles.getOutputStyle('terse');
103
+ console.log(terse?.instructions);
104
+ ```
105
+
106
+ ## Where it sits
107
+
108
+ ```
109
+ agent-framework ← session option types this package overrides
110
+ ↑
111
+ agent-preset ← this package
112
+ ↑
113
+ agent-cli, agent-command, agent-product ← create registries and apply presets
114
+ ```
115
+
116
+ This package depends only on `@robota-sdk/agent-framework` and does not re-export it.
117
+
118
+ ## Documentation
119
+
120
+ - [docs/SPEC.md](./docs/SPEC.md) — package contract, precedence and design decisions
121
+
122
+ ## License
123
+
124
+ This package is dual-licensed under the [GNU AGPL-3.0](../../LICENSE) or a [commercial license](../../COMMERCIAL.md). See [LICENSING.md](../../LICENSING.md).
@@ -0,0 +1,6 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("node:fs"),t=require("node:path"),n=require("@robota-sdk/agent-framework");const r={id:`default`,title:`Default`,description:`Neutral baseline preset — no overrides; reproduces the standard agent behaviour.`},i={id:`autonomous-builder`,title:`Autonomous Builder`,description:`Proactive, self-verifying builder posture — high effort, acts first, dispatches parallel subagents (proactive autonomous-builder persona; original English wording).`,effort:`high`,autonomy:`act-first`,enableParallelSubagents:!0,selfVerification:!0,persona:[`You are a proactive, high-autonomy builder. When you have enough to proceed, proceed and`,`complete the task — act rather than stop to ask. Keep going through the points where a more`,`hesitant assistant would pause for confirmation, and only check in when something is genuinely`,`ambiguous or risky.`,``,`Stay inside the scope of the task. Do the simplest thing that works; do not refactor, add`,`abstractions, or expand scope beyond what was asked. Handle the adjacent detail that the task`,`plainly needs, but resist turning a focused change into a sweeping one.`,``,`After making changes, verify your own work — run the tests, re-read the goal, and confirm the`,`result actually matches what was requested before you call it done.`,``,`Ground your claims in evidence. Before reporting progress, check each claim against an actual`,`tool result from this session; if something is not yet verified, say so plainly rather than`,`implying it is finished.`,``,`Be warm and honest without being sycophantic — tell people what is useful, not just what they`,`want to hear. Stay even-handed and let your conclusions follow from the evidence. When you get`,`something wrong, own it directly, correct it, and move on.`,``,`Lead with the outcome. Report results plainly instead of narrating each step, keep formatting`,`light, and stay concise.`].join(`
2
+ `)},a={id:`careful-reviewer`,title:`Careful Reviewer`,description:`Conservative, ask-first reviewing posture — reads and plans before changing, prompts on write/exec, self-verifies, runs focused (no parallel subagents) at high effort.`,effort:`high`,autonomy:`ask-first`,enableParallelSubagents:!1,selfVerification:!0,persona:[`You are a careful, review-oriented assistant. Read and analyse before you change anything —`,`understand the surrounding code and context first, then lay out a short plan for the change and`,`wait for confirmation before you write or run things that have side effects.`,``,`When you propose a change, explain why — the reasoning behind it and the trade-offs against the`,`alternatives you considered, so the choice can be reviewed rather than taken on trust.`,``,`Stay conservative in scope. Make the change that was asked for and the detail it plainly needs;`,`do not widen the blast radius with unrequested refactors or rewrites.`,``,`Ground your claims in evidence. Before reporting progress or completion, check each claim against`,`an actual tool result from this session; if something is not yet verified, say so plainly rather`,`than implying it is done.`,``,`Be warm and honest without being sycophantic — tell people what is useful, not just what they`,`want to hear. Stay even-handed and let your conclusions follow from the evidence. When you get`,`something wrong, own it directly, correct it, and move on.`].join(`
3
+ `)},o={id:`neutral-executor`,title:`Neutral Executor`,description:`Thin, steerable executor — follows instructions literally, minimal editorialising, strict scope, terse output; balanced autonomy, no parallel subagents, no self-verification, medium effort for predictable scripted use (neutral-alignment work-style; original English wording).`,effort:`medium`,autonomy:`balanced`,enableParallelSubagents:!1,selfVerification:!1,persona:[`Follow the system and user instructions literally. Do what was asked, the way it was asked, and`,`defer to the given instructions over your own preferences.`,``,`Editorialise as little as possible. Skip unrequested commentary, caveats, and asides — give the`,`result, not a narration of it.`,``,`Stay strictly in scope. Make only the change that was requested and the detail it plainly needs;`,`do not add adjacent refactors, comments, or features that were not asked for.`,``,`Keep output terse. Prefer the shortest response that fully answers, so the result is predictable`,`and easy to consume in a script or pipeline.`].join(`
4
+ `)},s={"ask-first":`default`,balanced:`default`,"act-first":`acceptEdits`},c=[r,i,a,o];function l(e){let t=new Set(c.map(e=>e.id)),n=[],r=[];for(let i of e){if(t.has(i.id)){r.push({id:i.id,reason:`collides with built-in preset`});continue}if(n.some(e=>e.id===i.id)){r.push({id:i.id,reason:`duplicate preset id`});continue}n.push(i)}return{accepted:n,rejected:r}}function u(e){let{id:t,title:n,description:r,...i}=e;return i}function d(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>e!==void 0))}function f(e,t){if(!t)return e;let n={...e,...d(t)};return t.deniedTools!==void 0||e.deniedTools!==void 0?{...n,deniedTools:p(e.deniedTools,t.deniedTools)}:n}function p(e,t){return[...new Set([...e??[],...t??[]])]}function m(e,t,n={}){let r=e.find(e=>e.id===t);if(!r){let n=e.map(e=>e.id).join(`, `);throw Error(`Unknown preset: "${t}". Available presets: ${n}.`)}let i=u(r);return i=f(i,n.cliOverrides),i=f(i,n.explicit),g(i)}function h(e=[]){let t=[...c,...l(e).accepted];return{resolvePreset:(e,n={})=>m(t,e,n),getPreset:e=>t.find(t=>t.id===e),listPresets:()=>t.map(({id:e,title:t,description:n})=>({id:e,title:t,description:n}))}}function g(e){return e.permissionMode===void 0?e.defaultPermissionMode===void 0?e.autonomy===void 0?e:{...e,permissionMode:s[e.autonomy]}:{...e,permissionMode:e.defaultPermissionMode}:e}const _=[`ask-first`,`act-first`,`balanced`],v=n.VALID_PERMISSION_MODES;function y(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function b(e){return Array.isArray(e)&&e.every(e=>typeof e==`string`)}function x(e,t){let n=[[`persona`,e.persona,e=>t.persona=e],[`systemPrompt`,e.systemPrompt,e=>t.systemPrompt=e],[`appendSystemPrompt`,e.appendSystemPrompt,e=>t.appendSystemPrompt=e],[`agentName`,e.agentName,e=>t.agentName=e],[`model`,e.model,e=>t.model=e],[`language`,e.language,e=>t.language=e]];for(let[e,t,r]of n)if(t!==void 0){if(typeof t!=`string`)return`${e}: expected a string`;r(t)}}function S(e,t){let n=[[`temperature`,e.temperature,e=>t.temperature=e],[`maxOutputTokens`,e.maxOutputTokens,e=>t.maxOutputTokens=e]];for(let[e,t,r]of n)if(t!==void 0){if(typeof t!=`number`||Number.isNaN(t))return`${e}: expected a number`;r(t)}let r=[[`enableParallelSubagents`,e.enableParallelSubagents,e=>t.enableParallelSubagents=e],[`selfVerification`,e.selfVerification,e=>t.selfVerification=e]];for(let[e,t,n]of r)if(t!==void 0){if(typeof t!=`boolean`)return`${e}: expected a boolean`;n(t)}}function C(e,t){if(e.effort!==void 0){if(typeof e.effort!=`string`)return`effort: expected a string`;try{let r=(0,n.parseModelEffort)(e.effort,`effort`);if(r===void 0)return`effort: expected a Core-owned effort selection`;t.effort=r}catch(e){return`effort: ${e instanceof Error?e.message:String(e)}`}}if(e.autonomy!==void 0){if(!_.includes(e.autonomy))return`autonomy: expected one of ${_.join(`, `)}`;t.autonomy=e.autonomy}let r=[[`permissionMode`,e.permissionMode,e=>t.permissionMode=e],[`defaultPermissionMode`,e.defaultPermissionMode,e=>t.defaultPermissionMode=e]];for(let[e,t,n]of r)if(t!==void 0){if(!v.includes(t))return`${e}: expected one of ${v.join(`, `)}`;n(t)}}function w(e,t){let n=[[`allowedTools`,e.allowedTools,e=>t.allowedTools=e],[`deniedTools`,e.deniedTools,e=>t.deniedTools=e],[`enabledCommandModules`,e.enabledCommandModules,e=>t.enabledCommandModules=e],[`disabledCommandModules`,e.disabledCommandModules,e=>t.disabledCommandModules=e]];for(let[e,t,r]of n)if(t!==void 0){if(!b(t))return`${e}: expected an array of strings`;r(t)}}function T(e){if(!y(e))return{ok:!1,error:`preset: expected a non-null object`};let t=[[`id`,e.id],[`title`,e.title],[`description`,e.description]];for(let[e,n]of t)if(typeof n!=`string`||n.length===0)return{ok:!1,error:`${e}: expected a non-empty string`};let n={},r=x(e,n)??S(e,n)??C(e,n)??w(e,n);return r===void 0?{ok:!0,preset:{id:e.id,title:e.title,description:e.description,...n}}:{ok:!1,error:r}}function E(n){if(!(0,e.existsSync)(n))return{presets:[],loaded:[],errors:[]};let r=[],i=[],a=new Map,o=(0,e.readdirSync)(n).filter(e=>e.endsWith(`.json`));for(let s of o){let o=(0,t.join)(n,s),c;try{c=JSON.parse((0,e.readFileSync)(o,`utf8`))}catch(e){r.push({file:s,error:e instanceof Error?e.message:String(e)});continue}let l=T(c);if(!l.ok){r.push({file:s,error:l.error});continue}i.push(l.preset),a.set(l.preset.id,s)}let{accepted:s,rejected:c}=l(i);for(let e of c)r.push({file:a.get(e.id)??e.id,error:e.reason});return{presets:s,loaded:s.map(e=>e.id),errors:r}}const D=[{id:`default`,name:`Default`,description:`The ordinary response style.`,instructions:``,keepCodingInstructions:!0,tokenCost:`baseline`,source:`built-in`},{id:`concise`,name:`Concise`,description:`Lead with the result and keep routine responses short.`,instructions:`Lead with the answer and skip routine preamble or tool narration. Keep responses concise while doing the same engineering work. Expand fully when asked for detail. Always keep error reports, security warnings and destructive-action confirmations complete.`,keepCodingInstructions:!0,tokenCost:`low`,source:`built-in`},{id:`proactive`,name:`Proactive`,description:`Take the next reasonable step without pausing on routine choices.`,instructions:`Act on reasonable routine assumptions and take the next useful step. State assumptions when they matter. The active permission mode remains authoritative; this style never grants, changes, or bypasses permission.`,keepCodingInstructions:!0,tokenCost:`medium`,source:`built-in`},{id:`explanatory`,name:`Explanatory`,description:`Teach the reasoning and trade-offs behind the answer.`,instructions:`Explain the reasoning, important trade-offs, and relevant terminology as you work. Keep the explanation connected to the requested outcome and do not omit complete error, security, or destructive-action guidance.`,keepCodingInstructions:!0,tokenCost:`high`,source:`built-in`},{id:`learning`,name:`Learning`,description:`Teach by marking useful gaps for the human to fill.`,instructions:`Teach the requested subject step by step. Mark a small number of useful gaps with [Your turn:] and invite the human to fill them before revealing the explanation. Never turn safety, security, error, or destructive-action guidance into a gap.`,keepCodingInstructions:!0,tokenCost:`high`,source:`built-in`}],O=new Set([`baseline`,`low`,`medium`,`high`,`unspecified`]);function k(e){return e.replace(/^(?:"([\s\S]*)"|'([\s\S]*)')$/,`$1$2`)}function A(e,t){if(t===`true`)return!0;if(t===`false`)return!1;throw Error(`${e}: expected boolean, received "${t}"`)}function j(e,t){let n=t.split(`
5
+ `);if(n[0]?.trim()!==`---`)throw Error(`frontmatter: expected an opening --- marker`);let r={},i=-1;for(let e=1;e<n.length;e+=1){let t=n[e];if(t.trim()===`---`){i=e;break}if(t.trim()===``)continue;let a=/^([a-z][a-z0-9-]*):\s*(\S[^\n\r\u2028\u2029]*)?$/.exec(t);if(!a)throw Error(`frontmatter: invalid entry at line ${e+1}`);let o=a[1];if(r[o]!==void 0)throw Error(`frontmatter.${o}: duplicate field`);r[o]=k((a[2]??``).trim())}if(i<0)throw Error(`frontmatter: expected a closing --- marker`);let a=Object.keys(r).filter(e=>![`name`,`description`,`keep-coding-instructions`,`token-cost`].includes(e));if(a.length>0)throw Error(`frontmatter.${a[0]}: unknown field`);return{values:r,instructions:n.slice(i+1).join(`
6
+ `).trim()}}function M(e){let n=(0,t.basename)(e,(0,t.extname)(e)).trim();if(!/^[a-z0-9][a-z0-9-]*$/i.test(n))throw Error(`id: expected the Markdown filename stem to be a slug, received "${n}"`);return n.toLowerCase()}function N(e,n){if(!e.fileName.endsWith(`.md`))throw Error(`file: expected a .md output-style file`);let r=M(e.fileName),i=j(e.fileName,e.content),a=i.values.name?.trim()||(0,t.basename)(e.fileName,`.md`),o=i.values.description?.trim()||`Custom output style: ${a}`,s=i.values[`keep-coding-instructions`]!==void 0&&A(`frontmatter.keep-coding-instructions`,i.values[`keep-coding-instructions`]),c=i.values[`token-cost`]??`unspecified`;if(!O.has(c))throw Error(`frontmatter.token-cost: expected baseline|low|medium|high|unspecified, received "${c}"`);if(i.instructions.length===0)throw Error(`body: expected non-empty style instructions`);return{id:r,name:a,description:o,instructions:i.instructions,keepCodingInstructions:s,tokenCost:c,source:n}}function P(e){return{id:e.id,name:e.name,description:e.description,tokenCost:e.tokenCost,source:e.source}}function F(e){let t=new Map,n=[];for(let e of D)t.set(e.id,e);let r=[...e].sort((e,t)=>e.precedence-t.precedence);for(let e of r){let r=new Set;for(let i of[...e.files].sort((e,t)=>e.fileName.localeCompare(t.fileName))){let a=`${e.displayName}/${i.fileName}`,o;try{o=N(i,e.scope)}catch(e){n.push({file:a,error:e instanceof Error?e.message:String(e)});continue}if(r.has(o.id)){n.push({file:a,error:`duplicate style id "${o.id}" in source`});continue}if(r.add(o.id),t.get(o.id)?.source===`built-in`){n.push({file:a,error:`style id "${o.id}" collides with a built-in`});continue}t.set(o.id,o)}}return{styles:[...t.values()],loaded:[...t.values()].filter(e=>e.source!==`built-in`).map(e=>e.id),errors:n}}function I(e=[]){let t=F(e),n=new Map(t.styles.map(e=>[e.id,e]));return{listOutputStyles:()=>t.styles.map(P),getOutputStyle:e=>n.get(e)}}exports.autonomousBuilderPreset=i,exports.builtInOutputStyles=D,exports.createOutputStyleRegistry=I,exports.createPresetRegistry=h,exports.defaultPreset=r,exports.loadExternalPresetsFromDir=E,exports.loadOutputStylesFromSources=F,exports.parseOutputStyleFile=N,exports.partitionExternalPresets=l,exports.validateExternalPreset=T;
@@ -0,0 +1,255 @@
1
+ import { ICreateSessionOptions } from "@robota-sdk/agent-framework";
2
+ //#region src/preset-types.d.ts
3
+ /**
4
+ * Effort dial passed through to the model invocation (mechanism, not persona text).
5
+ * `'xhigh'` corresponds to the long-running ("ultra") tier; `'high'` is the neutral default.
6
+ *
7
+ * Reuses the framework's `ICreateSessionOptions['effort']` channel (which is the
8
+ * `agent-core` `TModelEffort` SSOT) so a resolved preset effort threads straight to the
9
+ * provider invocation seam (PRESET-008) without introducing a parallel union.
10
+ */
11
+ type TPresetEffort = NonNullable<ICreateSessionOptions['effort']>;
12
+ /**
13
+ * Behavioural autonomy posture. Drives the permission posture (`permissionMode`) — it is a mechanism
14
+ * mapping, not a display label.
15
+ */
16
+ type TPresetAutonomy = 'ask-first' | 'balanced' | 'act-first';
17
+ /**
18
+ * Permission mode reused from the framework option SSOT (`ICreateSessionOptions`).
19
+ * Reusing the indexed access keeps a single source of truth for the permission-mode union.
20
+ */
21
+ type TPresetPermissionMode = ICreateSessionOptions['permissionMode'];
22
+ /**
23
+ * The framework-facing option subset a preset resolves into. Every field maps to an
24
+ * existing `agent-framework` session/assembly seam; presets never introduce new option types.
25
+ */
26
+ interface IResolvedPresetOptions {
27
+ /**
28
+ * Portable persona/behaviour block (tone, refusal philosophy, output style, proactivity).
29
+ * Composed by the framework as a `source: 'persona'` system-prompt section (priority 5) —
30
+ * never runtime/tool/product-identity text. Empty/undefined adds no section (no regression).
31
+ */
32
+ persona?: string;
33
+ systemPrompt?: string;
34
+ appendSystemPrompt?: string;
35
+ agentName?: string;
36
+ model?: string;
37
+ language?: string;
38
+ effort?: TPresetEffort;
39
+ temperature?: number;
40
+ maxOutputTokens?: number;
41
+ /**
42
+ * Resolved framework permission-mode seam. The end value the assembly applies.
43
+ * Populated either directly, from `defaultPermissionMode`, or from the
44
+ * `autonomy` mapping (precedence: explicit `permissionMode` > `defaultPermissionMode`
45
+ * > `autonomy` mapping).
46
+ */
47
+ permissionMode?: TPresetPermissionMode;
48
+ /**
49
+ * Coarse permission posture declared by a preset. When set (and no explicit
50
+ * `permissionMode`), {@link resolvePreset} promotes it to `permissionMode`.
51
+ */
52
+ defaultPermissionMode?: TPresetPermissionMode;
53
+ allowedTools?: readonly string[];
54
+ deniedTools?: readonly string[];
55
+ enabledCommandModules?: readonly string[];
56
+ disabledCommandModules?: readonly string[];
57
+ enableParallelSubagents?: boolean;
58
+ selfVerification?: boolean;
59
+ autonomy?: TPresetAutonomy;
60
+ }
61
+ /**
62
+ * A named, pre-tuned bundle of framework option overrides plus display identity.
63
+ * Extends `IResolvedPresetOptions` (type SSOT) and adds the identity triple.
64
+ */
65
+ interface IPreset extends IResolvedPresetOptions {
66
+ id: string;
67
+ title: string;
68
+ description: string;
69
+ }
70
+ //#endregion
71
+ //#region src/output-style-types.d.ts
72
+ type TOutputStyleSource = 'built-in' | 'managed' | 'user' | 'project';
73
+ type TOutputStyleTokenCost = 'baseline' | 'low' | 'medium' | 'high' | 'unspecified';
74
+ /** The provider-neutral response-shaping value carried into the framework prompt. */
75
+ interface IOutputStyle {
76
+ readonly id: string;
77
+ readonly name: string;
78
+ readonly description: string;
79
+ readonly instructions: string;
80
+ readonly keepCodingInstructions: boolean;
81
+ readonly tokenCost: TOutputStyleTokenCost;
82
+ readonly source: TOutputStyleSource;
83
+ }
84
+ /** Secret-free discovery projection used by command and UI surfaces. */
85
+ type IOutputStyleSummary = Pick<IOutputStyle, 'id' | 'name' | 'description' | 'tokenCost' | 'source'>;
86
+ interface IOutputStyleFile {
87
+ readonly fileName: string;
88
+ readonly content: string;
89
+ }
90
+ /** A source is already bounded by its owner; this package only decodes the supplied Markdown. */
91
+ interface IOutputStyleSource {
92
+ readonly scope: Exclude<TOutputStyleSource, 'built-in'>;
93
+ readonly displayName: string;
94
+ /** Lower values are applied first. The last scope with an id wins. */
95
+ readonly precedence: number;
96
+ readonly files: readonly IOutputStyleFile[];
97
+ }
98
+ interface IOutputStyleLoadResult {
99
+ readonly styles: readonly IOutputStyle[];
100
+ readonly loaded: readonly string[];
101
+ readonly errors: readonly {
102
+ file: string;
103
+ error: string;
104
+ }[];
105
+ }
106
+ interface IOutputStyleRegistry {
107
+ listOutputStyles(): readonly IOutputStyleSummary[];
108
+ getOutputStyle(id: string): IOutputStyle | undefined;
109
+ }
110
+ //#endregion
111
+ //#region src/presets/default.d.ts
112
+ /**
113
+ * The neutral baseline preset. It carries NO option overrides so that resolving it is a
114
+ * pure no-op — applying `default` reproduces the standard agent behaviour exactly (no regression).
115
+ * The default agent identity is chosen by the product shell, not here,
116
+ * so that this preset stays a true identity element under merging.
117
+ */
118
+ declare const defaultPreset: IPreset;
119
+ //#endregion
120
+ //#region src/presets/autonomous-builder.d.ts
121
+ /**
122
+ * The first opinionated built-in preset: an autonomous, self-verifying builder posture.
123
+ *
124
+ * It both ships a portable persona block AND sets the framework/executor mechanism flags
125
+ * (`effort`, `autonomy`, `enableParallelSubagents`, `selfVerification`) so the style is backed
126
+ * by real, observable behaviour rather than persona text alone. The identifier is generic; the
127
+ * sourcing footnote in `description` is the only place a work-style attribution appears.
128
+ *
129
+ * For long-running tasks the effort dial may be raised to a higher tier; `'high'` is the
130
+ * neutral default carried here.
131
+ */
132
+ declare const autonomousBuilderPreset: IPreset;
133
+ //#endregion
134
+ //#region src/resolve-preset.d.ts
135
+ /** Lightweight `{ id, title, description }` view of a preset for discovery/UX. */
136
+ interface IPresetSummary {
137
+ id: string;
138
+ title: string;
139
+ description: string;
140
+ }
141
+ /** Outcome of {@link partitionExternalPresets}: which presets were accepted and which rejected. */
142
+ interface IPresetRegistrationResult {
143
+ accepted: readonly IPreset[];
144
+ rejected: readonly {
145
+ id: string;
146
+ reason: string;
147
+ }[];
148
+ }
149
+ /**
150
+ * Apply the external-preset conflict policy to one list, reading and mutating NOTHING outside it.
151
+ *
152
+ * Conflict policy: an external preset whose id matches a BUILT-IN preset is rejected
153
+ * (`'collides with built-in preset'`) — built-ins always win. An external preset whose id matches an
154
+ * earlier ACCEPTED external preset is rejected (`'duplicate preset id'`) — first one wins.
155
+ *
156
+ * ARCH-009. This is the whole of what the module-global registry used to be, minus the register:
157
+ * the policy was never the process's to hold, only the list it was applied to was. Both callers —
158
+ * {@link createPresetRegistry} and the external-preset loader — now pass their own list, so two
159
+ * products in one process cannot see each other's presets, and a repeated load cannot accumulate.
160
+ */
161
+ declare function partitionExternalPresets(presets: readonly IPreset[]): IPresetRegistrationResult;
162
+ /**
163
+ * Override layers for {@link resolvePreset}, in increasing precedence.
164
+ * `cliOverrides` model CLI flags; `explicit` models programmatic/SDK options.
165
+ */
166
+ interface IResolvePresetContext {
167
+ cliOverrides?: IResolvedPresetOptions;
168
+ explicit?: IResolvedPresetOptions;
169
+ }
170
+ /**
171
+ * A per-call, instance-scoped preset registry (ARCH-005 R8) — since ARCH-009 the ONLY one there is.
172
+ *
173
+ * A registry holds its own merged list `[built-ins, ...accepted externals]`, so two products in one
174
+ * process do not share one and repeat construction does not accumulate. The
175
+ * `@robota-sdk/agent-product` assembler builds one per `assembleProduct` call and surfaces it on the
176
+ * command-host context, which is how `/preset` inside a live session reaches THIS product's presets
177
+ * rather than the process's.
178
+ */
179
+ interface IPresetRegistry {
180
+ /** Resolve a preset id against this registry's presets. */
181
+ resolvePreset(id: string, context?: IResolvePresetContext): IResolvedPresetOptions;
182
+ /** Look up a preset by id within this registry, or `undefined`. */
183
+ getPreset(id: string): IPreset | undefined;
184
+ /** `{ id, title, description }` summaries of every preset in this registry. */
185
+ listPresets(): readonly IPresetSummary[];
186
+ }
187
+ /**
188
+ * Build an instance-scoped {@link IPresetRegistry} over `[built-ins, ...externalPresets]`.
189
+ *
190
+ * The conflict policy is {@link partitionExternalPresets}, applied to the argument list only: built-ins
191
+ * always win, and among the external presets the first one wins. No module-level state is read or
192
+ * mutated — this is a pure factory, and since ARCH-009 there is no module-level state to read.
193
+ *
194
+ * Called with no argument it is the BUILT-INS, which is the registry a host that supplies none gets.
195
+ */
196
+ declare function createPresetRegistry(externalPresets?: readonly IPreset[]): IPresetRegistry;
197
+ //#endregion
198
+ //#region src/load-external-presets.d.ts
199
+ /**
200
+ * Outcome of an external-preset load: the presets themselves, their ids, and per-file errors.
201
+ *
202
+ * ARCH-009 added `presets`. `loaded` used to be the only way out, because the presets went into a
203
+ * module-global registry and the caller read them back by id — which is what made the global
204
+ * load-bearing at startup. The caller now receives the values it loaded and builds its own registry
205
+ * over them, so nothing has to be looked up from process state.
206
+ */
207
+ interface IExternalPresetLoadResult {
208
+ presets: readonly IPreset[];
209
+ loaded: readonly string[];
210
+ errors: readonly {
211
+ file: string;
212
+ error: string;
213
+ }[];
214
+ }
215
+ /**
216
+ * Load and validate every `*.json` external preset from `dir`.
217
+ *
218
+ * A missing directory yields an empty result (no error). Each file is JSON-parsed and validated;
219
+ * a parse or validation failure is recorded as a per-file error and skipped — the remaining files
220
+ * still load. The surviving presets go through {@link partitionExternalPresets}, whose rejections
221
+ * (built-in id collision or duplicate id) are folded into `errors` against their file.
222
+ *
223
+ * Loading REGISTERS NOTHING. The result is a value the caller owns.
224
+ */
225
+ declare function loadExternalPresetsFromDir(dir: string): IExternalPresetLoadResult;
226
+ //#endregion
227
+ //#region src/preset-validation.d.ts
228
+ /** Result of {@link validateExternalPreset}: the validated preset, or a single error message. */
229
+ type TPresetValidationResult = {
230
+ ok: true;
231
+ preset: IPreset;
232
+ } | {
233
+ ok: false;
234
+ error: string;
235
+ };
236
+ /**
237
+ * Manually validate an unknown value as an {@link IPreset} (no schema library).
238
+ *
239
+ * Required fields: non-empty `id`, `title`, `description` strings. Every other field is
240
+ * optional and is validated only when present; an unrecognised field is dropped (the built
241
+ * preset carries the recognised fields only, never unknown keys). On the first failed check
242
+ * returns `{ ok: false, error: '<field>: <reason>' }`.
243
+ */
244
+ declare function validateExternalPreset(value: unknown): TPresetValidationResult;
245
+ //#endregion
246
+ //#region src/output-styles.d.ts
247
+ declare const builtInOutputStyles: readonly IOutputStyle[];
248
+ //#endregion
249
+ //#region src/output-style-registry.d.ts
250
+ declare function parseOutputStyleFile(file: IOutputStyleFile, source: TOutputStyleSource): IOutputStyle;
251
+ declare function loadOutputStylesFromSources(sources: readonly IOutputStyleSource[]): IOutputStyleLoadResult;
252
+ declare function createOutputStyleRegistry(sources?: readonly IOutputStyleSource[]): IOutputStyleRegistry;
253
+ //#endregion
254
+ export { type IExternalPresetLoadResult, type IOutputStyle, type IOutputStyleFile, type IOutputStyleLoadResult, type IOutputStyleRegistry, type IOutputStyleSource, type IOutputStyleSummary, type IPreset, type IPresetRegistrationResult, type IPresetRegistry, type IPresetSummary, type IResolvePresetContext, type IResolvedPresetOptions, type TOutputStyleSource, type TOutputStyleTokenCost, type TPresetAutonomy, type TPresetEffort, type TPresetPermissionMode, type TPresetValidationResult, autonomousBuilderPreset, builtInOutputStyles, createOutputStyleRegistry, createPresetRegistry, defaultPreset, loadExternalPresetsFromDir, loadOutputStylesFromSources, parseOutputStyleFile, partitionExternalPresets, validateExternalPreset };
255
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/preset-types.ts","../../src/output-style-types.ts","../../src/presets/default.ts","../../src/presets/autonomous-builder.ts","../../src/resolve-preset.ts","../../src/load-external-presets.ts","../../src/preset-validation.ts","../../src/output-styles.ts","../../src/output-style-registry.ts"],"mappings":";;;;;;;;;;KAUY,gBAAgB,YAAY;;;;;KAM5B;;;;;KAMA,wBAAwB;;;;;UAMnB;;;;;;EAOf;EACA;EACA;EACA;EAGA;EACA;EACA,SAAS;EACT;EACA;;;;;;;EASA,iBAAiB;;;;;EAKjB,wBAAwB;EACxB;EACA;EAGA;EACA;EAGA;EACA;EAGA,WAAW;;;;;;UAOI,gBAAgB;EAC/B;EACA;EACA;;;;KClFU;KAEA;;UAGK;WACN;WACA;WACA;WACA;WACA;WACA,WAAW;WACX,QAAQ;;;KAIP,sBAAsB,KAChC;UAIe;WACN;WACA;;;UAIM;WACN,OAAO,QAAQ;WACf;;WAEA;WACA,gBAAgB;;UAGV;WACN,iBAAiB;WACjB;WACA;IAAmB;IAAc;;;UAG3B;EACf,6BAA6B;EAC7B,eAAe,aAAa;;;;;;;;;;cCnCjB,eAAe;;;;;;;;;;;;;;cCsCf,yBAAyB;;;;UCXrB;EACf;EACA;EACA;;;UAIe;EACf,mBAAmB;EACnB;IAAqB;IAAY;;;;;;;;;;;;;;;iBAenB,yBAAyB,kBAAkB,YAAY;;;;;UAwBtD;EACf,eAAe;EACf,WAAW;;;;;;;;;;;UAuFI;;EAEf,cAAc,YAAY,UAAU,wBAAwB;;EAE5D,UAAU,aAAa;;EAEvB,wBAAwB;;;;;;;;;;;iBAYV,qBAAqB,2BAA0B,YAAiB;;;;;;;;;;;UC9K/D;EACf,kBAAkB;EAClB;EACA;IAAmB;IAAc;;;;;;;;;;;;;iBAanB,2BAA2B,cAAc;;;;KCtB7C;EAA4B;EAAU,QAAQ;;EAAc;EAAW;;;;;;;;;;iBAyKnE,uBAAuB,iBAAiB;;;cC/K3C,8BAA8B;;;iBCgF3B,qBACd,MAAM,kBACN,QAAQ,qBACP;iBA6Ca,4BACd,kBAAkB,uBACjB;iBA4Ca,0BACd,mBAAkB,uBACjB"}