@agimon-ai/doompi-model-guidance 0.0.1-alpha.63
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/LICENSE +21 -0
- package/README.md +94 -0
- package/dist/adapters/modelGuidanceStore.cjs +2 -0
- package/dist/adapters/modelGuidanceStore.cjs.map +1 -0
- package/dist/adapters/modelGuidanceStore.d.cts +20 -0
- package/dist/adapters/modelGuidanceStore.d.cts.map +1 -0
- package/dist/adapters/modelGuidanceStore.d.mts +20 -0
- package/dist/adapters/modelGuidanceStore.d.mts.map +1 -0
- package/dist/adapters/modelGuidanceStore.mjs +2 -0
- package/dist/adapters/modelGuidanceStore.mjs.map +1 -0
- package/dist/adapters/pi/extension.cjs +2 -0
- package/dist/adapters/pi/extension.cjs.map +1 -0
- package/dist/adapters/pi/extension.d.cts +6 -0
- package/dist/adapters/pi/extension.d.cts.map +1 -0
- package/dist/adapters/pi/extension.d.mts +6 -0
- package/dist/adapters/pi/extension.d.mts.map +1 -0
- package/dist/adapters/pi/extension.mjs +2 -0
- package/dist/adapters/pi/extension.mjs.map +1 -0
- package/dist/extensions/pi.cjs +1 -0
- package/dist/extensions/pi.d.cts +2 -0
- package/dist/extensions/pi.d.mts +2 -0
- package/dist/extensions/pi.mjs +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +4 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.mjs +1 -0
- package/dist/services/modelGuidance.cjs +2 -0
- package/dist/services/modelGuidance.cjs.map +1 -0
- package/dist/services/modelGuidance.d.cts +29 -0
- package/dist/services/modelGuidance.d.cts.map +1 -0
- package/dist/services/modelGuidance.d.mts +29 -0
- package/dist/services/modelGuidance.d.mts.map +1 -0
- package/dist/services/modelGuidance.mjs +2 -0
- package/dist/services/modelGuidance.mjs.map +1 -0
- package/dist/types/modelGuidance.d.cts +17 -0
- package/dist/types/modelGuidance.d.cts.map +1 -0
- package/dist/types/modelGuidance.d.mts +17 -0
- package/dist/types/modelGuidance.d.mts.map +1 -0
- package/llms.txt +11 -0
- package/package.json +92 -0
- package/src/prompts/doompi-use-model-guidance/SKILL.md +31 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vuong Ngo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# @agimon-ai/doompi-model-guidance
|
|
2
|
+
|
|
3
|
+
Per-model system prompt guidance for Pi agents, layered across global and repository scope.
|
|
4
|
+
|
|
5
|
+
A new model release often needs prompt adjustments that older models do not.
|
|
6
|
+
This package keeps those adjustments in one place, keyed by model id, instead of
|
|
7
|
+
spreading them through every package's prompt.
|
|
8
|
+
|
|
9
|
+
## Configuration
|
|
10
|
+
|
|
11
|
+
Guidance lives in `model-guidance.yaml`, read from two scopes:
|
|
12
|
+
|
|
13
|
+
| Scope | Path |
|
|
14
|
+
| ---------- | ---------------------------------------- |
|
|
15
|
+
| Global | `~/.pi/.doom/model-guidance.yaml` |
|
|
16
|
+
| Repository | `<repository>/.doom/model-guidance.yaml` |
|
|
17
|
+
|
|
18
|
+
```yaml
|
|
19
|
+
modelGuidance:
|
|
20
|
+
claude-opus-5: |
|
|
21
|
+
Keep the task focused. Never go off rails.
|
|
22
|
+
gpt-6-astra: |
|
|
23
|
+
Prefer fewer, larger tool batches.
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Matching
|
|
27
|
+
|
|
28
|
+
Model ids match exactly, against the id Pi reports for the active model. Use the
|
|
29
|
+
value shown by `/model`. A model with no entry gets no guidance, which is never
|
|
30
|
+
an error, so missing guidance usually means the id does not match.
|
|
31
|
+
|
|
32
|
+
Exact matching is deliberate: it keeps the file honest about which model a piece
|
|
33
|
+
of text was written for. The cost is that a provider shipping a new versioned id
|
|
34
|
+
needs a new entry.
|
|
35
|
+
|
|
36
|
+
### Merge rule
|
|
37
|
+
|
|
38
|
+
Both scopes apply. A repository entry wins for the model ids it names, and
|
|
39
|
+
global entries for ids the repository does not mention still apply.
|
|
40
|
+
|
|
41
|
+
| Model id | Global | Repository | Result |
|
|
42
|
+
| --------------- | --------------- | --------------------- | --------------------- |
|
|
43
|
+
| `claude-opus-5` | "Stay focused." | "Cordis rules apply." | "Cordis rules apply." |
|
|
44
|
+
| `gpt-6-astra` | "Batch tools." | absent | "Batch tools." |
|
|
45
|
+
| `local-qwen-3` | absent | "Short answers only." | "Short answers only." |
|
|
46
|
+
|
|
47
|
+
A malformed or unreadable guidance file warns on stderr and yields no guidance,
|
|
48
|
+
rather than ending the session.
|
|
49
|
+
|
|
50
|
+
## Activation
|
|
51
|
+
|
|
52
|
+
The package ships in the `llm` layer and is optional.
|
|
53
|
+
|
|
54
|
+
Mode-scoped, in `.doom/modes.yaml`:
|
|
55
|
+
|
|
56
|
+
```yaml
|
|
57
|
+
layers:
|
|
58
|
+
llm:
|
|
59
|
+
packages:
|
|
60
|
+
- '@agimon-ai/doompi-model-guidance'
|
|
61
|
+
|
|
62
|
+
majorMode:
|
|
63
|
+
copilot:
|
|
64
|
+
layers: [team, ask-user, task, sandbox, llm]
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Always on, by listing it in the `default` package list instead:
|
|
68
|
+
|
|
69
|
+
```yaml
|
|
70
|
+
default:
|
|
71
|
+
packages:
|
|
72
|
+
- '@agimon-ai/doompi-model-guidance'
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
A layer only activates when the selected major mode lists it, so add `llm` to
|
|
76
|
+
every major mode that should carry guidance. The `default` route avoids that but
|
|
77
|
+
makes ordering depend on list position.
|
|
78
|
+
|
|
79
|
+
## Behaviour
|
|
80
|
+
|
|
81
|
+
Guidance is appended to the system prompt at the start of each turn, after the
|
|
82
|
+
default packages have contributed and before the profile persona. The file is
|
|
83
|
+
read per turn, so an edit takes effect on the next message with no restart.
|
|
84
|
+
|
|
85
|
+
## Development
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pnpm nx run @agimon-ai/doompi-model-guidance:lint
|
|
89
|
+
pnpm nx run @agimon-ai/doompi-model-guidance:typecheck
|
|
90
|
+
pnpm nx run @agimon-ai/doompi-model-guidance:build
|
|
91
|
+
pnpm nx run @agimon-ai/doompi-model-guidance:test
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Pi entrypoint: `./dist/extensions/pi.mjs`.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("../services/modelGuidance.cjs");let t=require("@agimon-ai/doompi-config/layeredConfig");const n=`model-guidance.yaml`,r=Object.freeze({});function i(i,a){if(!i)return r;try{let r=(0,t.readDoomConfigSources)(n,i,a);return e.mergeModelGuidance(r.map(e=>e.document))}catch(e){let t=e instanceof Error?e.message:String(e);return process.stderr.write(`[doompi-model-guidance] could not read ${n}: ${t}\n`),r}}exports.GUIDANCE_FILE=n,exports.loadModelGuidance=i;
|
|
2
|
+
//# sourceMappingURL=modelGuidanceStore.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modelGuidanceStore.cjs","names":["readDoomConfigSources","mergeModelGuidance"],"sources":["../../src/adapters/modelGuidanceStore.ts"],"sourcesContent":["import { readDoomConfigSources } from '@agimon-ai/doompi-config/layeredConfig';\nimport { mergeModelGuidance } from '../services/modelGuidance.ts';\nimport type { ModelGuidanceDocument, ModelGuidanceMap } from '../types/modelGuidance.ts';\n\n/** Layered guidance document, read from the global then the repository `.doom` directory. */\nexport const GUIDANCE_FILE = 'model-guidance.yaml';\n\nconst EMPTY: ModelGuidanceMap = Object.freeze({});\n\n/**\n * Reads and folds the global and repository guidance documents.\n *\n * Fails open. The reader parses YAML without a guard, so a typo in an optional\n * prompt file would otherwise throw on every turn of the session. Degrading to\n * \"no guidance\" is the same outcome as the file being absent, which is why this\n * matches the persona precedent rather than the synchronized-state invariant\n * that governs composition artifacts.\n *\n * `homeDirectory` exists so a test can point the global scope at a temporary\n * directory; production callers omit it and the reader falls back to the real home.\n */\nexport function loadModelGuidance(repositoryRoot: string | undefined, homeDirectory?: string): ModelGuidanceMap {\n if (!repositoryRoot) return EMPTY;\n\n try {\n const sources = readDoomConfigSources<ModelGuidanceDocument>(GUIDANCE_FILE, repositoryRoot, homeDirectory);\n return mergeModelGuidance(sources.map((source) => source.document));\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[doompi-model-guidance] could not read ${GUIDANCE_FILE}: ${reason}\\n`);\n return EMPTY;\n }\n}\n"],"mappings":"yGAKA,MAAa,EAAgB,sBAEvB,EAA0B,OAAO,OAAO,CAAC,CAAC,EAchD,SAAgB,EAAkB,EAAoC,EAA0C,CAC9G,GAAI,CAAC,EAAgB,OAAO,EAE5B,GAAI,CACF,IAAM,GAAA,EAAUA,EAAAA,sBAAAA,CAA6C,EAAe,EAAgB,CAAa,EACzG,OAAOC,EAAAA,mBAAmB,EAAQ,IAAK,GAAW,EAAO,QAAQ,CAAC,CACpE,OAAS,EAAO,CACd,IAAM,EAAS,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAEpE,OADA,QAAQ,OAAO,MAAM,0CAA0C,EAAc,IAAI,EAAO,GAAG,EACpF,CACT,CACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ModelGuidanceMap } from "../types/modelGuidance.cjs";
|
|
2
|
+
//#region src/adapters/modelGuidanceStore.d.ts
|
|
3
|
+
/** Layered guidance document, read from the global then the repository `.doom` directory. */
|
|
4
|
+
declare const GUIDANCE_FILE = "model-guidance.yaml";
|
|
5
|
+
/**
|
|
6
|
+
* Reads and folds the global and repository guidance documents.
|
|
7
|
+
*
|
|
8
|
+
* Fails open. The reader parses YAML without a guard, so a typo in an optional
|
|
9
|
+
* prompt file would otherwise throw on every turn of the session. Degrading to
|
|
10
|
+
* "no guidance" is the same outcome as the file being absent, which is why this
|
|
11
|
+
* matches the persona precedent rather than the synchronized-state invariant
|
|
12
|
+
* that governs composition artifacts.
|
|
13
|
+
*
|
|
14
|
+
* `homeDirectory` exists so a test can point the global scope at a temporary
|
|
15
|
+
* directory; production callers omit it and the reader falls back to the real home.
|
|
16
|
+
*/
|
|
17
|
+
declare function loadModelGuidance(repositoryRoot: string | undefined, homeDirectory?: string): ModelGuidanceMap;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { GUIDANCE_FILE, loadModelGuidance };
|
|
20
|
+
//# sourceMappingURL=modelGuidanceStore.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modelGuidanceStore.d.cts","names":[],"sources":["../../src/adapters/modelGuidanceStore.ts"],"mappings":";;;cAKa;;;;;;;;;;;;;iBAgBG,kBAAkB,oCAAoC,yBAAyB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ModelGuidanceMap } from "../types/modelGuidance.mjs";
|
|
2
|
+
//#region src/adapters/modelGuidanceStore.d.ts
|
|
3
|
+
/** Layered guidance document, read from the global then the repository `.doom` directory. */
|
|
4
|
+
declare const GUIDANCE_FILE = "model-guidance.yaml";
|
|
5
|
+
/**
|
|
6
|
+
* Reads and folds the global and repository guidance documents.
|
|
7
|
+
*
|
|
8
|
+
* Fails open. The reader parses YAML without a guard, so a typo in an optional
|
|
9
|
+
* prompt file would otherwise throw on every turn of the session. Degrading to
|
|
10
|
+
* "no guidance" is the same outcome as the file being absent, which is why this
|
|
11
|
+
* matches the persona precedent rather than the synchronized-state invariant
|
|
12
|
+
* that governs composition artifacts.
|
|
13
|
+
*
|
|
14
|
+
* `homeDirectory` exists so a test can point the global scope at a temporary
|
|
15
|
+
* directory; production callers omit it and the reader falls back to the real home.
|
|
16
|
+
*/
|
|
17
|
+
declare function loadModelGuidance(repositoryRoot: string | undefined, homeDirectory?: string): ModelGuidanceMap;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { GUIDANCE_FILE, loadModelGuidance };
|
|
20
|
+
//# sourceMappingURL=modelGuidanceStore.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modelGuidanceStore.d.mts","names":[],"sources":["../../src/adapters/modelGuidanceStore.ts"],"mappings":";;;cAKa;;;;;;;;;;;;;iBAgBG,kBAAkB,oCAAoC,yBAAyB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{mergeModelGuidance as e}from"../services/modelGuidance.mjs";import{readDoomConfigSources as t}from"@agimon-ai/doompi-config/layeredConfig";const n=`model-guidance.yaml`,r=Object.freeze({});function i(i,a){if(!i)return r;try{let r=t(n,i,a);return e(r.map(e=>e.document))}catch(e){let t=e instanceof Error?e.message:String(e);return process.stderr.write(`[doompi-model-guidance] could not read ${n}: ${t}\n`),r}}export{n as GUIDANCE_FILE,i as loadModelGuidance};
|
|
2
|
+
//# sourceMappingURL=modelGuidanceStore.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modelGuidanceStore.mjs","names":[],"sources":["../../src/adapters/modelGuidanceStore.ts"],"sourcesContent":["import { readDoomConfigSources } from '@agimon-ai/doompi-config/layeredConfig';\nimport { mergeModelGuidance } from '../services/modelGuidance.ts';\nimport type { ModelGuidanceDocument, ModelGuidanceMap } from '../types/modelGuidance.ts';\n\n/** Layered guidance document, read from the global then the repository `.doom` directory. */\nexport const GUIDANCE_FILE = 'model-guidance.yaml';\n\nconst EMPTY: ModelGuidanceMap = Object.freeze({});\n\n/**\n * Reads and folds the global and repository guidance documents.\n *\n * Fails open. The reader parses YAML without a guard, so a typo in an optional\n * prompt file would otherwise throw on every turn of the session. Degrading to\n * \"no guidance\" is the same outcome as the file being absent, which is why this\n * matches the persona precedent rather than the synchronized-state invariant\n * that governs composition artifacts.\n *\n * `homeDirectory` exists so a test can point the global scope at a temporary\n * directory; production callers omit it and the reader falls back to the real home.\n */\nexport function loadModelGuidance(repositoryRoot: string | undefined, homeDirectory?: string): ModelGuidanceMap {\n if (!repositoryRoot) return EMPTY;\n\n try {\n const sources = readDoomConfigSources<ModelGuidanceDocument>(GUIDANCE_FILE, repositoryRoot, homeDirectory);\n return mergeModelGuidance(sources.map((source) => source.document));\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[doompi-model-guidance] could not read ${GUIDANCE_FILE}: ${reason}\\n`);\n return EMPTY;\n }\n}\n"],"mappings":"kJAKA,MAAa,EAAgB,sBAEvB,EAA0B,OAAO,OAAO,CAAC,CAAC,EAchD,SAAgB,EAAkB,EAAoC,EAA0C,CAC9G,GAAI,CAAC,EAAgB,OAAO,EAE5B,GAAI,CACF,IAAM,EAAU,EAA6C,EAAe,EAAgB,CAAa,EACzG,OAAO,EAAmB,EAAQ,IAAK,GAAW,EAAO,QAAQ,CAAC,CACpE,OAAS,EAAO,CACd,IAAM,EAAS,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAEpE,OADA,QAAQ,OAAO,MAAM,0CAA0C,EAAc,IAAI,EAAO,GAAG,EACpF,CACT,CACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("../../services/modelGuidance.cjs"),t=require("../modelGuidanceStore.cjs");let n=require("@agimon-ai/doompi-config"),r=require("@agimon-ai/doompi-extension-contracts/cordis-host");function i(e,{pi:t}){a(t)}function a(r){r.on(`before_agent_start`,(r,i)=>{let a=i.model?.id;if(!a)return;let o=e.guidanceForModel(t.loadModelGuidance((0,n.getHarnessState)().root),a),s=e.applyModelGuidance(r.systemPrompt,o);return s?{systemPrompt:s}:void 0})}async function o(e){let t=await(0,r.connectDoomCordisHost)(e,`@agimon-ai/doompi-model-guidance`),n=t.root.plugin(i,{pi:e});try{await n}catch(e){throw await n.dispose(),await t.dispose(),e}let a;e.on(`session_shutdown`,()=>a??=(async()=>{try{await n.dispose()}finally{await t.dispose()}})())}exports.activateModelGuidanceExtension=o,exports.default=o,exports.registerModelGuidanceHandlers=a;
|
|
2
|
+
//# sourceMappingURL=extension.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.cjs","names":["guidanceForModel","loadModelGuidance","getHarnessState","applyModelGuidance","connectDoomCordisHost"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { getHarnessState } from '@agimon-ai/doompi-config';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { applyModelGuidance, guidanceForModel } from '../../services/modelGuidance.ts';\nimport { loadModelGuidance } from '../modelGuidanceStore.ts';\n\n/**\n * Appends per-model guidance to the system prompt.\n *\n * The guidance map is read straight from the layered `.doom` documents rather\n * than through the session config service: the reader is synchronous and the\n * repository root comes from the harness environment, so there is nothing to\n * wait on and no readiness barrier to deadlock against.\n *\n * The file is read per turn on purpose. Two existence checks and two small\n * reads are nothing beside the model call that follows, and editing guidance\n * takes effect on the next turn, which is what tuning a prompt for a freshly\n * released model actually needs.\n */\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-model-guidance';\n\ninterface ModelGuidancePluginConfig {\n readonly pi: ExtensionAPI;\n}\n\nfunction modelGuidancePlugin(_cordis: Context, { pi }: ModelGuidancePluginConfig): void {\n registerModelGuidanceHandlers(pi);\n}\n\nexport function registerModelGuidanceHandlers(pi: ExtensionAPI): void {\n pi.on('before_agent_start', (event, ctx) => {\n const modelId = ctx.model?.id;\n if (!modelId) return undefined;\n\n const guidance = guidanceForModel(loadModelGuidance(getHarnessState().root), modelId);\n const systemPrompt = applyModelGuidance(event.systemPrompt, guidance);\n return systemPrompt ? { systemPrompt } : undefined;\n });\n}\n\nexport async function activateModelGuidanceExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(modelGuidancePlugin, { pi });\n try {\n await fiber;\n } catch (error) {\n await fiber.dispose();\n await connection.dispose();\n throw error;\n }\n\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\nexport default activateModelGuidanceExtension;\n"],"mappings":"oMA0BA,SAAS,EAAoB,EAAkB,CAAE,MAAuC,CACtF,EAA8B,CAAE,CAClC,CAEA,SAAgB,EAA8B,EAAwB,CACpE,EAAG,GAAG,sBAAuB,EAAO,IAAQ,CAC1C,IAAM,EAAU,EAAI,OAAO,GAC3B,GAAI,CAAC,EAAS,OAEd,IAAM,EAAWA,EAAAA,iBAAiBC,EAAAA,mBAAAA,EAAkBC,EAAAA,gBAAAA,CAAgB,CAAC,CAAC,IAAI,EAAG,CAAO,EAC9E,EAAeC,EAAAA,mBAAmB,EAAM,aAAc,CAAQ,EACpE,OAAO,EAAe,CAAE,cAAa,EAAI,IAAA,EAC3C,CAAC,CACH,CAEA,eAAsB,EAA+B,EAAiC,CACpF,IAAM,EAAa,MAAA,EAAMC,EAAAA,sBAAAA,CAAsB,EAAI,kCAAc,EAC3D,EAAQ,EAAW,KAAK,OAAO,EAAqB,CAAE,IAAG,CAAC,EAChE,GAAI,CACF,MAAM,CACR,OAAS,EAAO,CAGd,MAFA,MAAM,EAAM,QAAQ,EACpB,MAAM,EAAW,QAAQ,EACnB,CACR,CAEA,IAAI,EACJ,EAAG,GACD,uBAEG,KAAc,SAAY,CACzB,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACF,EAAA,CAAG,CACP,CACF"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
//#region src/adapters/pi/extension.d.ts
|
|
3
|
+
declare function activateModelGuidanceExtension(pi: ExtensionAPI): Promise<void>;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { activateModelGuidanceExtension, activateModelGuidanceExtension as default };
|
|
6
|
+
//# sourceMappingURL=extension.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;iBAyCsB,+BAA+B,IAAI,eAAe"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
//#region src/adapters/pi/extension.d.ts
|
|
3
|
+
declare function activateModelGuidanceExtension(pi: ExtensionAPI): Promise<void>;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { activateModelGuidanceExtension, activateModelGuidanceExtension as default };
|
|
6
|
+
//# sourceMappingURL=extension.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;iBAyCsB,+BAA+B,IAAI,eAAe"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{applyModelGuidance as e,guidanceForModel as t}from"../../services/modelGuidance.mjs";import{loadModelGuidance as n}from"../modelGuidanceStore.mjs";import{getHarnessState as r}from"@agimon-ai/doompi-config";import{connectDoomCordisHost as i}from"@agimon-ai/doompi-extension-contracts/cordis-host";function a(e,{pi:t}){o(t)}function o(i){i.on(`before_agent_start`,(i,a)=>{let o=a.model?.id;if(!o)return;let s=t(n(r().root),o),c=e(i.systemPrompt,s);return c?{systemPrompt:c}:void 0})}async function s(e){let t=await i(e,`@agimon-ai/doompi-model-guidance`),n=t.root.plugin(a,{pi:e});try{await n}catch(e){throw await n.dispose(),await t.dispose(),e}let r;e.on(`session_shutdown`,()=>r??=(async()=>{try{await n.dispose()}finally{await t.dispose()}})())}export{s as activateModelGuidanceExtension,s as default,o as registerModelGuidanceHandlers};
|
|
2
|
+
//# sourceMappingURL=extension.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { getHarnessState } from '@agimon-ai/doompi-config';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { applyModelGuidance, guidanceForModel } from '../../services/modelGuidance.ts';\nimport { loadModelGuidance } from '../modelGuidanceStore.ts';\n\n/**\n * Appends per-model guidance to the system prompt.\n *\n * The guidance map is read straight from the layered `.doom` documents rather\n * than through the session config service: the reader is synchronous and the\n * repository root comes from the harness environment, so there is nothing to\n * wait on and no readiness barrier to deadlock against.\n *\n * The file is read per turn on purpose. Two existence checks and two small\n * reads are nothing beside the model call that follows, and editing guidance\n * takes effect on the next turn, which is what tuning a prompt for a freshly\n * released model actually needs.\n */\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-model-guidance';\n\ninterface ModelGuidancePluginConfig {\n readonly pi: ExtensionAPI;\n}\n\nfunction modelGuidancePlugin(_cordis: Context, { pi }: ModelGuidancePluginConfig): void {\n registerModelGuidanceHandlers(pi);\n}\n\nexport function registerModelGuidanceHandlers(pi: ExtensionAPI): void {\n pi.on('before_agent_start', (event, ctx) => {\n const modelId = ctx.model?.id;\n if (!modelId) return undefined;\n\n const guidance = guidanceForModel(loadModelGuidance(getHarnessState().root), modelId);\n const systemPrompt = applyModelGuidance(event.systemPrompt, guidance);\n return systemPrompt ? { systemPrompt } : undefined;\n });\n}\n\nexport async function activateModelGuidanceExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(modelGuidancePlugin, { pi });\n try {\n await fiber;\n } catch (error) {\n await fiber.dispose();\n await connection.dispose();\n throw error;\n }\n\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\nexport default activateModelGuidanceExtension;\n"],"mappings":"+SA0BA,SAAS,EAAoB,EAAkB,CAAE,MAAuC,CACtF,EAA8B,CAAE,CAClC,CAEA,SAAgB,EAA8B,EAAwB,CACpE,EAAG,GAAG,sBAAuB,EAAO,IAAQ,CAC1C,IAAM,EAAU,EAAI,OAAO,GAC3B,GAAI,CAAC,EAAS,OAEd,IAAM,EAAW,EAAiB,EAAkB,EAAgB,CAAC,CAAC,IAAI,EAAG,CAAO,EAC9E,EAAe,EAAmB,EAAM,aAAc,CAAQ,EACpE,OAAO,EAAe,CAAE,cAAa,EAAI,IAAA,EAC3C,CAAC,CACH,CAEA,eAAsB,EAA+B,EAAiC,CACpF,IAAM,EAAa,MAAM,EAAsB,EAAI,kCAAc,EAC3D,EAAQ,EAAW,KAAK,OAAO,EAAqB,CAAE,IAAG,CAAC,EAChE,GAAI,CACF,MAAM,CACR,OAAS,EAAO,CAGd,MAFA,MAAM,EAAM,QAAQ,EACpB,MAAM,EAAW,QAAQ,EACnB,CACR,CAEA,IAAI,EACJ,EAAG,GACD,uBAEG,KAAc,SAAY,CACzB,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACF,EAAA,CAAG,CACP,CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../adapters/pi/extension.cjs");exports.activateModelGuidanceExtension=e.activateModelGuidanceExtension,exports.default=e.activateModelGuidanceExtension;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{activateModelGuidanceExtension as e}from"../adapters/pi/extension.mjs";export{e as activateModelGuidanceExtension,e as default};
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./services/modelGuidance.cjs"),t=require("./adapters/modelGuidanceStore.cjs");exports.GUIDANCE_FILE=t.GUIDANCE_FILE,exports.applyModelGuidance=e.applyModelGuidance,exports.guidanceForModel=e.guidanceForModel,exports.loadModelGuidance=t.loadModelGuidance,exports.mergeModelGuidance=e.mergeModelGuidance;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ModelGuidanceDocument, ModelGuidanceMap } from "./types/modelGuidance.cjs";
|
|
2
|
+
import { GUIDANCE_FILE, loadModelGuidance } from "./adapters/modelGuidanceStore.cjs";
|
|
3
|
+
import { applyModelGuidance, guidanceForModel, mergeModelGuidance } from "./services/modelGuidance.cjs";
|
|
4
|
+
export { GUIDANCE_FILE, type ModelGuidanceDocument, type ModelGuidanceMap, applyModelGuidance, guidanceForModel, loadModelGuidance, mergeModelGuidance };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ModelGuidanceDocument, ModelGuidanceMap } from "./types/modelGuidance.mjs";
|
|
2
|
+
import { GUIDANCE_FILE, loadModelGuidance } from "./adapters/modelGuidanceStore.mjs";
|
|
3
|
+
import { applyModelGuidance, guidanceForModel, mergeModelGuidance } from "./services/modelGuidance.mjs";
|
|
4
|
+
export { GUIDANCE_FILE, type ModelGuidanceDocument, type ModelGuidanceMap, applyModelGuidance, guidanceForModel, loadModelGuidance, mergeModelGuidance };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{applyModelGuidance as e,guidanceForModel as t,mergeModelGuidance as n}from"./services/modelGuidance.mjs";import{GUIDANCE_FILE as r,loadModelGuidance as i}from"./adapters/modelGuidanceStore.mjs";export{r as GUIDANCE_FILE,e as applyModelGuidance,t as guidanceForModel,i as loadModelGuidance,n as mergeModelGuidance};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e){let t={};for(let n of e)for(let[e,r]of Object.entries(n.modelGuidance??{})){if(typeof r!=`string`)continue;let n=r.trim();n&&(t[e]=n)}return t}function t(e,t){if(t)return e[t]}function n(e,t){if(t)return`${e}\n\n${t}`}exports.applyModelGuidance=n,exports.guidanceForModel=t,exports.mergeModelGuidance=e;
|
|
2
|
+
//# sourceMappingURL=modelGuidance.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modelGuidance.cjs","names":[],"sources":["../../src/services/modelGuidance.ts"],"sourcesContent":["import type { ModelGuidanceDocument, ModelGuidanceMap } from '../types/modelGuidance.ts';\n\n/**\n * Folds guidance documents in source order, so a later document overrides one\n * model id at a time.\n *\n * The reader hands back global then repository, so a repository entry wins the\n * ids it names while global entries it does not name survive. That per-id\n * granularity is the point: a personal default stays useful inside a project\n * that only pins one model.\n *\n * Non-string values are dropped rather than rejected, because a guidance file is\n * optional user input and one bad entry must not discard the rest.\n */\nexport function mergeModelGuidance(documents: readonly ModelGuidanceDocument[]): ModelGuidanceMap {\n const merged: Record<string, string> = {};\n for (const document of documents) {\n for (const [modelId, guidance] of Object.entries(document.modelGuidance ?? {})) {\n if (typeof guidance !== 'string') continue;\n const trimmed = guidance.trim();\n if (trimmed) merged[modelId] = trimmed;\n }\n }\n return merged;\n}\n\n/** Exact-match lookup. An unknown or absent model id contributes nothing. */\nexport function guidanceForModel(guidance: ModelGuidanceMap, modelId: string | undefined): string | undefined {\n if (!modelId) return undefined;\n return guidance[modelId];\n}\n\n/**\n * Builds the replacement system prompt for one turn.\n *\n * Pi treats a returned `systemPrompt` as a full replacement and chains handlers,\n * so the incoming prompt has to be re-embedded. Returning bare guidance would\n * discard every earlier contribution, including plan mode and the persona.\n * Keeping that in one function leaves a single place for it to be right.\n */\nexport function applyModelGuidance(systemPrompt: string, guidance: string | undefined): string | undefined {\n if (!guidance) return undefined;\n return `${systemPrompt}\\n\\n${guidance}`;\n}\n"],"mappings":"AAcA,SAAgB,EAAmB,EAA+D,CAChG,IAAM,EAAiC,CAAC,EACxC,IAAK,IAAM,KAAY,EACrB,IAAK,GAAM,CAAC,EAAS,KAAa,OAAO,QAAQ,EAAS,eAAiB,CAAC,CAAC,EAAG,CAC9E,GAAI,OAAO,GAAa,SAAU,SAClC,IAAM,EAAU,EAAS,KAAK,EAC1B,IAAS,EAAO,GAAW,EACjC,CAEF,OAAO,CACT,CAGA,SAAgB,EAAiB,EAA4B,EAAiD,CACvG,KACL,OAAO,EAAS,EAClB,CAUA,SAAgB,EAAmB,EAAsB,EAAkD,CACpG,KACL,MAAO,GAAG,EAAa,MAAM,GAC/B"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ModelGuidanceDocument, ModelGuidanceMap } from "../types/modelGuidance.cjs";
|
|
2
|
+
//#region src/services/modelGuidance.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Folds guidance documents in source order, so a later document overrides one
|
|
5
|
+
* model id at a time.
|
|
6
|
+
*
|
|
7
|
+
* The reader hands back global then repository, so a repository entry wins the
|
|
8
|
+
* ids it names while global entries it does not name survive. That per-id
|
|
9
|
+
* granularity is the point: a personal default stays useful inside a project
|
|
10
|
+
* that only pins one model.
|
|
11
|
+
*
|
|
12
|
+
* Non-string values are dropped rather than rejected, because a guidance file is
|
|
13
|
+
* optional user input and one bad entry must not discard the rest.
|
|
14
|
+
*/
|
|
15
|
+
declare function mergeModelGuidance(documents: readonly ModelGuidanceDocument[]): ModelGuidanceMap;
|
|
16
|
+
/** Exact-match lookup. An unknown or absent model id contributes nothing. */
|
|
17
|
+
declare function guidanceForModel(guidance: ModelGuidanceMap, modelId: string | undefined): string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Builds the replacement system prompt for one turn.
|
|
20
|
+
*
|
|
21
|
+
* Pi treats a returned `systemPrompt` as a full replacement and chains handlers,
|
|
22
|
+
* so the incoming prompt has to be re-embedded. Returning bare guidance would
|
|
23
|
+
* discard every earlier contribution, including plan mode and the persona.
|
|
24
|
+
* Keeping that in one function leaves a single place for it to be right.
|
|
25
|
+
*/
|
|
26
|
+
declare function applyModelGuidance(systemPrompt: string, guidance: string | undefined): string | undefined;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { applyModelGuidance, guidanceForModel, mergeModelGuidance };
|
|
29
|
+
//# sourceMappingURL=modelGuidance.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modelGuidance.d.cts","names":[],"sources":["../../src/services/modelGuidance.ts"],"mappings":";;;;;;;;;;;;;;iBAcgB,mBAAmB,oBAAoB,0BAA0B;;iBAajE,iBAAiB,UAAU,kBAAkB;;;;;;;;;iBAa7C,mBAAmB,sBAAsB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ModelGuidanceDocument, ModelGuidanceMap } from "../types/modelGuidance.mjs";
|
|
2
|
+
//#region src/services/modelGuidance.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Folds guidance documents in source order, so a later document overrides one
|
|
5
|
+
* model id at a time.
|
|
6
|
+
*
|
|
7
|
+
* The reader hands back global then repository, so a repository entry wins the
|
|
8
|
+
* ids it names while global entries it does not name survive. That per-id
|
|
9
|
+
* granularity is the point: a personal default stays useful inside a project
|
|
10
|
+
* that only pins one model.
|
|
11
|
+
*
|
|
12
|
+
* Non-string values are dropped rather than rejected, because a guidance file is
|
|
13
|
+
* optional user input and one bad entry must not discard the rest.
|
|
14
|
+
*/
|
|
15
|
+
declare function mergeModelGuidance(documents: readonly ModelGuidanceDocument[]): ModelGuidanceMap;
|
|
16
|
+
/** Exact-match lookup. An unknown or absent model id contributes nothing. */
|
|
17
|
+
declare function guidanceForModel(guidance: ModelGuidanceMap, modelId: string | undefined): string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Builds the replacement system prompt for one turn.
|
|
20
|
+
*
|
|
21
|
+
* Pi treats a returned `systemPrompt` as a full replacement and chains handlers,
|
|
22
|
+
* so the incoming prompt has to be re-embedded. Returning bare guidance would
|
|
23
|
+
* discard every earlier contribution, including plan mode and the persona.
|
|
24
|
+
* Keeping that in one function leaves a single place for it to be right.
|
|
25
|
+
*/
|
|
26
|
+
declare function applyModelGuidance(systemPrompt: string, guidance: string | undefined): string | undefined;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { applyModelGuidance, guidanceForModel, mergeModelGuidance };
|
|
29
|
+
//# sourceMappingURL=modelGuidance.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modelGuidance.d.mts","names":[],"sources":["../../src/services/modelGuidance.ts"],"mappings":";;;;;;;;;;;;;;iBAcgB,mBAAmB,oBAAoB,0BAA0B;;iBAajE,iBAAiB,UAAU,kBAAkB;;;;;;;;;iBAa7C,mBAAmB,sBAAsB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e){let t={};for(let n of e)for(let[e,r]of Object.entries(n.modelGuidance??{})){if(typeof r!=`string`)continue;let n=r.trim();n&&(t[e]=n)}return t}function t(e,t){if(t)return e[t]}function n(e,t){if(t)return`${e}\n\n${t}`}export{n as applyModelGuidance,t as guidanceForModel,e as mergeModelGuidance};
|
|
2
|
+
//# sourceMappingURL=modelGuidance.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modelGuidance.mjs","names":[],"sources":["../../src/services/modelGuidance.ts"],"sourcesContent":["import type { ModelGuidanceDocument, ModelGuidanceMap } from '../types/modelGuidance.ts';\n\n/**\n * Folds guidance documents in source order, so a later document overrides one\n * model id at a time.\n *\n * The reader hands back global then repository, so a repository entry wins the\n * ids it names while global entries it does not name survive. That per-id\n * granularity is the point: a personal default stays useful inside a project\n * that only pins one model.\n *\n * Non-string values are dropped rather than rejected, because a guidance file is\n * optional user input and one bad entry must not discard the rest.\n */\nexport function mergeModelGuidance(documents: readonly ModelGuidanceDocument[]): ModelGuidanceMap {\n const merged: Record<string, string> = {};\n for (const document of documents) {\n for (const [modelId, guidance] of Object.entries(document.modelGuidance ?? {})) {\n if (typeof guidance !== 'string') continue;\n const trimmed = guidance.trim();\n if (trimmed) merged[modelId] = trimmed;\n }\n }\n return merged;\n}\n\n/** Exact-match lookup. An unknown or absent model id contributes nothing. */\nexport function guidanceForModel(guidance: ModelGuidanceMap, modelId: string | undefined): string | undefined {\n if (!modelId) return undefined;\n return guidance[modelId];\n}\n\n/**\n * Builds the replacement system prompt for one turn.\n *\n * Pi treats a returned `systemPrompt` as a full replacement and chains handlers,\n * so the incoming prompt has to be re-embedded. Returning bare guidance would\n * discard every earlier contribution, including plan mode and the persona.\n * Keeping that in one function leaves a single place for it to be right.\n */\nexport function applyModelGuidance(systemPrompt: string, guidance: string | undefined): string | undefined {\n if (!guidance) return undefined;\n return `${systemPrompt}\\n\\n${guidance}`;\n}\n"],"mappings":"AAcA,SAAgB,EAAmB,EAA+D,CAChG,IAAM,EAAiC,CAAC,EACxC,IAAK,IAAM,KAAY,EACrB,IAAK,GAAM,CAAC,EAAS,KAAa,OAAO,QAAQ,EAAS,eAAiB,CAAC,CAAC,EAAG,CAC9E,GAAI,OAAO,GAAa,SAAU,SAClC,IAAM,EAAU,EAAS,KAAK,EAC1B,IAAS,EAAO,GAAW,EACjC,CAEF,OAAO,CACT,CAGA,SAAgB,EAAiB,EAA4B,EAAiD,CACvG,KACL,OAAO,EAAS,EAClB,CAUA,SAAgB,EAAmB,EAAsB,EAAkD,CACpG,KACL,MAAO,GAAG,EAAa,MAAM,GAC/B"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/types/modelGuidance.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Wire and domain shapes for per-model system prompt guidance.
|
|
4
|
+
*
|
|
5
|
+
* Document values are `unknown` rather than `string` because a guidance file is
|
|
6
|
+
* user-authored YAML: the parser cannot promise a string, so the fold narrows
|
|
7
|
+
* each value instead of asserting one.
|
|
8
|
+
*/
|
|
9
|
+
/** Raw shape of one `.doom/model-guidance.yaml` document. */
|
|
10
|
+
interface ModelGuidanceDocument {
|
|
11
|
+
readonly modelGuidance?: Readonly<Record<string, unknown>>;
|
|
12
|
+
}
|
|
13
|
+
/** Model id to guidance text, after the global and repository documents are folded. */
|
|
14
|
+
type ModelGuidanceMap = Readonly<Record<string, string>>;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { ModelGuidanceDocument, ModelGuidanceMap };
|
|
17
|
+
//# sourceMappingURL=modelGuidance.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modelGuidance.d.cts","names":[],"sources":["../../src/types/modelGuidance.ts"],"mappings":";;;;;;;;;UASiB;WACN,gBAAgB,SAAS;;;KAIxB,mBAAmB,SAAS"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/types/modelGuidance.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Wire and domain shapes for per-model system prompt guidance.
|
|
4
|
+
*
|
|
5
|
+
* Document values are `unknown` rather than `string` because a guidance file is
|
|
6
|
+
* user-authored YAML: the parser cannot promise a string, so the fold narrows
|
|
7
|
+
* each value instead of asserting one.
|
|
8
|
+
*/
|
|
9
|
+
/** Raw shape of one `.doom/model-guidance.yaml` document. */
|
|
10
|
+
interface ModelGuidanceDocument {
|
|
11
|
+
readonly modelGuidance?: Readonly<Record<string, unknown>>;
|
|
12
|
+
}
|
|
13
|
+
/** Model id to guidance text, after the global and repository documents are folded. */
|
|
14
|
+
type ModelGuidanceMap = Readonly<Record<string, string>>;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { ModelGuidanceDocument, ModelGuidanceMap };
|
|
17
|
+
//# sourceMappingURL=modelGuidance.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modelGuidance.d.mts","names":[],"sources":["../../src/types/modelGuidance.ts"],"mappings":";;;;;;;;;UASiB;WACN,gBAAgB,SAAS;;;KAIxB,mBAAmB,SAAS"}
|
package/llms.txt
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# @agimon-ai/doompi-model-guidance
|
|
2
|
+
|
|
3
|
+
Package-owned guidance for per-model system prompt guidance, layered across global and repository scope
|
|
4
|
+
|
|
5
|
+
## How to use
|
|
6
|
+
|
|
7
|
+
- [Use Model Guidance](./src/prompts/doompi-use-model-guidance/SKILL.md): Configure per-model system prompt text and understand how the two scopes merge.
|
|
8
|
+
|
|
9
|
+
## Resources
|
|
10
|
+
|
|
11
|
+
- [Package README](./README.md): Installation, development commands, Pi entrypoint, and extension-specific usage.
|
package/package.json
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agimon-ai/doompi-model-guidance",
|
|
3
|
+
"version": "0.0.1-alpha.63",
|
|
4
|
+
"description": "Per-model system prompt guidance for Pi agents, layered across global and repository scope.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai",
|
|
7
|
+
"coding-agent",
|
|
8
|
+
"developer-tools",
|
|
9
|
+
"doompi",
|
|
10
|
+
"model-guidance",
|
|
11
|
+
"pi-coding-agent",
|
|
12
|
+
"pi-extension",
|
|
13
|
+
"pi-package",
|
|
14
|
+
"system-prompt",
|
|
15
|
+
"typescript"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://agimon.ai",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/AgiFlow/doompi/issues"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"author": "Vuong Ngo",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/AgiFlow/doompi.git",
|
|
26
|
+
"directory": "layers/llm/doompi-model-guidance"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"src/prompts",
|
|
31
|
+
"llms.txt",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE",
|
|
34
|
+
"package.json"
|
|
35
|
+
],
|
|
36
|
+
"type": "module",
|
|
37
|
+
"main": "./dist/index.cjs",
|
|
38
|
+
"types": "./dist/index.d.mts",
|
|
39
|
+
"jsnext:main": "./dist/index.mjs",
|
|
40
|
+
"exports": {
|
|
41
|
+
".": {
|
|
42
|
+
"types": "./dist/index.d.mts",
|
|
43
|
+
"import": "./dist/index.mjs",
|
|
44
|
+
"require": "./dist/index.cjs"
|
|
45
|
+
},
|
|
46
|
+
"./extensions/pi": {
|
|
47
|
+
"types": "./dist/extensions/pi.d.mts",
|
|
48
|
+
"import": "./dist/extensions/pi.mjs",
|
|
49
|
+
"require": "./dist/extensions/pi.cjs"
|
|
50
|
+
},
|
|
51
|
+
"./package.json": "./package.json"
|
|
52
|
+
},
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"@deepseek-ai/cordis": "4.0.2",
|
|
58
|
+
"@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.63",
|
|
59
|
+
"@agimon-ai/doompi-config": "0.0.1-alpha.63"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@earendil-works/pi-coding-agent": "0.85.1",
|
|
63
|
+
"@types/node": "26.4.0",
|
|
64
|
+
"@vitest/coverage-v8": "5.0.0",
|
|
65
|
+
"tsdown": "0.22.14",
|
|
66
|
+
"typescript": "7.0.2",
|
|
67
|
+
"vitest": "5.0.0"
|
|
68
|
+
},
|
|
69
|
+
"peerDependencies": {
|
|
70
|
+
"@earendil-works/pi-coding-agent": "0.85.1"
|
|
71
|
+
},
|
|
72
|
+
"peerDependenciesMeta": {
|
|
73
|
+
"@earendil-works/pi-coding-agent": {
|
|
74
|
+
"optional": true
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"engines": {
|
|
78
|
+
"node": ">=22.19.0"
|
|
79
|
+
},
|
|
80
|
+
"pi": {
|
|
81
|
+
"extensions": [
|
|
82
|
+
"./dist/extensions/pi.mjs"
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
"scripts": {
|
|
86
|
+
"build": "tsdown",
|
|
87
|
+
"test": "vitest --run",
|
|
88
|
+
"typecheck": "tsc --noEmit",
|
|
89
|
+
"lint": "oxlint . && oxfmt . --check",
|
|
90
|
+
"fixcode": "oxlint . --fix && oxfmt ."
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: doompi-use-model-guidance
|
|
3
|
+
description: 'Use @agimon-ai/doompi-model-guidance: per-model system prompt guidance, layered across global and repository scope'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Use Model Guidance
|
|
7
|
+
|
|
8
|
+
Read the package [README](../../../README.md) for its exact installation, configuration, and behavior.
|
|
9
|
+
|
|
10
|
+
## Guidance
|
|
11
|
+
|
|
12
|
+
Write guidance for a model id in either scope:
|
|
13
|
+
|
|
14
|
+
- Global, applying to every repository: `~/.pi/.doom/model-guidance.yaml`
|
|
15
|
+
- Repository, applying to one project: `<repository>/.doom/model-guidance.yaml`
|
|
16
|
+
|
|
17
|
+
```yaml
|
|
18
|
+
modelGuidance:
|
|
19
|
+
claude-opus-5: |
|
|
20
|
+
Keep the task focused. Never go off rails.
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Model ids match exactly. Use the id shown by `/model`, not a family or a
|
|
24
|
+
marketing name. An id that does not match contributes nothing and never errors,
|
|
25
|
+
so a silent absence of guidance usually means the id is wrong.
|
|
26
|
+
|
|
27
|
+
Both scopes apply. A repository entry replaces the global entry for the model
|
|
28
|
+
ids it names, and global entries for other ids still apply.
|
|
29
|
+
|
|
30
|
+
Guidance is read per turn, so an edit takes effect on the next message with no
|
|
31
|
+
restart.
|