@tangle-network/agent-profile-materialize 0.10.3 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +195 -3
- package/dist/index.js +807 -43
- package/dist/model-id.d.ts +42 -0
- package/dist/model-id.js +59 -0
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* `node:fs` IO consumer. It was previously copied byte-for-byte into both
|
|
22
22
|
* cli-bridge and agent-dev-container — this is the single source those re-export.
|
|
23
23
|
*/
|
|
24
|
+
export { modelIdsMatch, qualifyModelId } from "./model-id.js";
|
|
24
25
|
import type { AgentCandidateConfigValue, AgentCandidateProfile, AgentCandidateProfileActivation, AgentCandidateProfileApplication, AgentCandidateProfilePlanEvidence, AgentCandidateProfilePlanMaterial, AgentProfile, AgentProfileConfigValue, AgentProfileMcpServer, AgentProfileSecretProvider, AgentProfileSecretRef, Sha256Digest } from "@tangle-network/agent-interface";
|
|
25
26
|
export declare const UNAVAILABLE_AGENT_PROFILE_SECRET_PROVIDER: AgentProfileSecretProvider;
|
|
26
27
|
/**
|
|
@@ -28,7 +29,7 @@ export declare const UNAVAILABLE_AGENT_PROFILE_SECRET_PROVIDER: AgentProfileSecr
|
|
|
28
29
|
* the canonical harness enum, so a rename upstream is a compile error here rather than an
|
|
29
30
|
* `isMaterializerHarness` that silently returns false for a harness that still exists.
|
|
30
31
|
*/
|
|
31
|
-
export declare const MATERIALIZER_HARNESSES: readonly ["claude-code", "nanoclaw", "codex", "opencode", "kimi-code", "pi", "gemini", "hermes", "openclaw"];
|
|
32
|
+
export declare const MATERIALIZER_HARNESSES: readonly ["claude-code", "nanoclaw", "codex", "opencode", "kimi-code", "pi", "prime", "gemini", "hermes", "openclaw"];
|
|
32
33
|
export type HarnessId = (typeof MATERIALIZER_HARNESSES)[number];
|
|
33
34
|
export declare function isMaterializerHarness(harness: string): harness is HarnessId;
|
|
34
35
|
export interface PlanFile {
|
|
@@ -56,6 +57,25 @@ export interface PlanFile {
|
|
|
56
57
|
* this on every file it emits.
|
|
57
58
|
*/
|
|
58
59
|
source?: "user" | "generated";
|
|
60
|
+
/**
|
|
61
|
+
* Who owns the PATH — which decides whether an existing file there may be
|
|
62
|
+
* replaced.
|
|
63
|
+
*
|
|
64
|
+
* `"materializer"` = a path this package invented. No harness convention
|
|
65
|
+
* names it and no user authors it, so a file already there can only be this
|
|
66
|
+
* materializer's own output from an earlier application into the same
|
|
67
|
+
* workspace, and replacing it is how turn two of a resumed session gets the
|
|
68
|
+
* current profile instead of the previous one.
|
|
69
|
+
*
|
|
70
|
+
* `"shared"` (the default, and every other file) = a path the user or the
|
|
71
|
+
* harness also owns — `CLAUDE.md`, `AGENTS.md`, `opencode.json`,
|
|
72
|
+
* `.gemini/system.md` are all documented, user-authorable names. An existing
|
|
73
|
+
* file there may be the caller's own work, so it is never replaced.
|
|
74
|
+
*
|
|
75
|
+
* Optional because hand-constructed plans have no path provenance to report;
|
|
76
|
+
* absent reads as `"shared"`, the safe answer.
|
|
77
|
+
*/
|
|
78
|
+
ownership?: "materializer" | "shared";
|
|
59
79
|
/**
|
|
60
80
|
* Secret leaves in a generated JSON document. `content` contains `null` at
|
|
61
81
|
* each path until the private executor resolves the named reference. The
|
|
@@ -82,9 +102,47 @@ export type WorkspacePlanArgument = string | WorkspacePlanArgumentTemplate;
|
|
|
82
102
|
/** Public bytes stay strings; secret references stay opaque until application. */
|
|
83
103
|
export type WorkspacePlanConfigValue = string | AgentProfileSecretRef;
|
|
84
104
|
export interface Unsupported {
|
|
85
|
-
dimension: "files" | "skills" | "mcp" | "hooks" | "subagents" | "commands" | "instructions" | "systemPrompt" | "connections" | "confidential" | "permissions" | "tools" | "modes" | "extensions";
|
|
105
|
+
dimension: "files" | "skills" | "mcp" | "hooks" | "subagents" | "commands" | "instructions" | "systemPrompt" | "appendSystemPrompt" | "connections" | "confidential" | "permissions" | "tools" | "modes" | "extensions";
|
|
86
106
|
reason: string;
|
|
87
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* The subset of {@link BINDABLE_LAUNCH_CONTROLS} the plan HANDS OVER rather than
|
|
110
|
+
* executes: controls a caller reaches only by composing the harness's own
|
|
111
|
+
* configuration, so no file, flag or env var the plan writes can touch them.
|
|
112
|
+
*
|
|
113
|
+
* - `opencode.agent-prompt` — opencode's `agent.<name>.prompt` config field,
|
|
114
|
+
* the one control that replaces its built-in provider prompt. It binds to a
|
|
115
|
+
* SINGLE agent, and the agent is chosen at launch. A caller that builds
|
|
116
|
+
* opencode's config itself and picks the agent there reads neither
|
|
117
|
+
* `plan.files` nor `plan.flags`, so for that one the plan names the control
|
|
118
|
+
* and hands over the text in {@link WorkspacePlan.systemPromptBinding}.
|
|
119
|
+
*
|
|
120
|
+
* Every other bindable control names a capability the plan still lowers itself
|
|
121
|
+
* once the caller has declared the plan's launch inputs really reach the spawn.
|
|
122
|
+
*/
|
|
123
|
+
export declare const EXECUTOR_SYSTEM_PROMPT_BINDINGS: readonly ["opencode.agent-prompt"];
|
|
124
|
+
export type ExecutorSystemPromptBinding = (typeof EXECUTOR_SYSTEM_PROMPT_BINDINGS)[number];
|
|
125
|
+
export declare function isExecutorSystemPromptBinding(value: string): value is ExecutorSystemPromptBinding;
|
|
126
|
+
/**
|
|
127
|
+
* A system-prompt intent handed to the launcher that declared it owns the
|
|
128
|
+
* control, instead of being lowered into the workspace.
|
|
129
|
+
*
|
|
130
|
+
* Distinct from {@link WorkspacePlan.systemPrompt} — a launch ARGUMENT the
|
|
131
|
+
* executor hands to a harness flag — and from the file/flag/env lowerings the
|
|
132
|
+
* plan performs on its own. This names the exact control that must receive the
|
|
133
|
+
* text and which of the two intents it is, so the launcher cannot apply it to
|
|
134
|
+
* the wrong channel. Never written into an additive channel and never dropped:
|
|
135
|
+
* a caller that has not declared it owns `control` gets the plan's own lowering
|
|
136
|
+
* (or a refusal where the harness has no control at all) instead of this field.
|
|
137
|
+
*/
|
|
138
|
+
export interface WorkspacePlanSystemPromptBinding {
|
|
139
|
+
/** Which of the two prompt intents this is — never inferred from presence. */
|
|
140
|
+
intent: "replace";
|
|
141
|
+
/** The exact launcher control that must receive `systemPrompt`. */
|
|
142
|
+
control: ExecutorSystemPromptBinding;
|
|
143
|
+
/** Exact text the control receives. */
|
|
144
|
+
systemPrompt: string;
|
|
145
|
+
}
|
|
88
146
|
/**
|
|
89
147
|
* The dimensions `materializeProfile`'s `skip` option honors.
|
|
90
148
|
*
|
|
@@ -95,6 +153,32 @@ export interface Unsupported {
|
|
|
95
153
|
export declare const SKIPPABLE_DIMENSIONS: readonly ["mcp", "extensions"];
|
|
96
154
|
export type SkippableDimension = (typeof SKIPPABLE_DIMENSIONS)[number];
|
|
97
155
|
export declare function isSkippableDimension(value: string): value is SkippableDimension;
|
|
156
|
+
/**
|
|
157
|
+
* Launcher controls an executor can declare it OWNS via `materializeProfile`'s
|
|
158
|
+
* `binds` option.
|
|
159
|
+
*
|
|
160
|
+
* Some harness controls live outside any workspace: opencode's exact
|
|
161
|
+
* system-prompt replacement (`agent.<name>.prompt`) binds to the ONE agent
|
|
162
|
+
* whoever starts the process selects, which a plan-forwarding executor cannot
|
|
163
|
+
* guarantee — so the plan refuses the intent (harnessSystemPromptIntents in
|
|
164
|
+
* @tangle-network/agent-interface answers `replace: false` for opencode).
|
|
165
|
+
*
|
|
166
|
+
* The two declarations describe the two executor shapes that CAN reach it, and
|
|
167
|
+
* each gets the lowering it can actually apply:
|
|
168
|
+
*
|
|
169
|
+
* - `systemPrompt` — the executor applies the plan's launch flags to the
|
|
170
|
+
* spawn it owns, so the plan writes the generated `mode: primary` agent and
|
|
171
|
+
* selects it with `--agent`.
|
|
172
|
+
* - `opencode.agent-prompt` — the executor composes opencode's own config and
|
|
173
|
+
* picks the agent there, reading neither plan files nor plan flags, so the
|
|
174
|
+
* plan hands the text over in {@link WorkspacePlan.systemPromptBinding}
|
|
175
|
+
* instead of writing a workspace agent that would never be selected.
|
|
176
|
+
*
|
|
177
|
+
* They are mutually exclusive claims about the same caller: declaring both is a
|
|
178
|
+
* caller bug, not a broader capability.
|
|
179
|
+
*/
|
|
180
|
+
export declare const BINDABLE_LAUNCH_CONTROLS: readonly ["systemPrompt", "opencode.agent-prompt"];
|
|
181
|
+
export type BindableLaunchControl = (typeof BINDABLE_LAUNCH_CONTROLS)[number];
|
|
98
182
|
/** The plan a caller writes into the run cwd, then applies to the spawn. */
|
|
99
183
|
export interface WorkspacePlan {
|
|
100
184
|
harness: HarnessId;
|
|
@@ -104,8 +188,42 @@ export interface WorkspacePlan {
|
|
|
104
188
|
env: Record<string, WorkspacePlanConfigValue>;
|
|
105
189
|
/** Extra CLI flags to pass (e.g. kimi --mcp-config-file <path>). */
|
|
106
190
|
flags: WorkspacePlanArgument[];
|
|
107
|
-
/**
|
|
191
|
+
/**
|
|
192
|
+
* Exact text that REPLACES the harness's own system prompt, for harnesses
|
|
193
|
+
* whose replacement control takes it as a launch argument the executor
|
|
194
|
+
* supplies (claude-code `--system-prompt`, pi `--system-prompt`).
|
|
195
|
+
*
|
|
196
|
+
* Absent does NOT mean "no replacement was requested": a harness whose
|
|
197
|
+
* control reads a file (codex, gemini) carries the replacement in
|
|
198
|
+
* {@link WorkspacePlan.files} plus a flag or env var instead. Present means
|
|
199
|
+
* the executor MUST bind it to that harness's replacement control — never to
|
|
200
|
+
* an additive one, which would leave the built-in prompt in force.
|
|
201
|
+
*/
|
|
108
202
|
systemPrompt?: string;
|
|
203
|
+
/**
|
|
204
|
+
* Exact text ADDED to the harness's own system prompt, which stays intact.
|
|
205
|
+
*
|
|
206
|
+
* Separate from {@link WorkspacePlan.systemPrompt} because the two are
|
|
207
|
+
* different intents against the same channel, and every harness that has one
|
|
208
|
+
* control may lack the other. An executor binds this ONLY to an additive
|
|
209
|
+
* control (claude-code `--append-system-prompt`, pi
|
|
210
|
+
* `--append-system-prompt`); there is no harness for which folding it into
|
|
211
|
+
* the replacement is correct, because that would delete the built-in prompt
|
|
212
|
+
* the caller asked to keep.
|
|
213
|
+
*/
|
|
214
|
+
appendSystemPrompt?: string;
|
|
215
|
+
/**
|
|
216
|
+
* A prompt intent no workspace file, flag, or env var can execute, addressed
|
|
217
|
+
* to the launcher control that can — see
|
|
218
|
+
* {@link WorkspacePlanSystemPromptBinding}.
|
|
219
|
+
*
|
|
220
|
+
* Present ONLY when the caller declared it owns the named control, so a plan
|
|
221
|
+
* built by a caller that forwards it to someone else's launcher never carries
|
|
222
|
+
* one; that caller gets the intent in {@link WorkspacePlan.unsupported}
|
|
223
|
+
* instead. Whoever reads it must bind it or throw — {@link
|
|
224
|
+
* takeSystemPromptBinding} does both.
|
|
225
|
+
*/
|
|
226
|
+
systemPromptBinding?: WorkspacePlanSystemPromptBinding;
|
|
109
227
|
/** Dimensions requested but with NO cwd path on this harness — fail-closed record. */
|
|
110
228
|
unsupported: Unsupported[];
|
|
111
229
|
/**
|
|
@@ -157,6 +275,9 @@ export interface WorkspacePlanReceipt {
|
|
|
157
275
|
/** Public launch identity only; templates retain opaque secret references. */
|
|
158
276
|
flags: WorkspacePlanArgument[];
|
|
159
277
|
systemPrompt?: string;
|
|
278
|
+
appendSystemPrompt?: string;
|
|
279
|
+
/** The launcher-bound intent, so a receipt says which control owed the work. */
|
|
280
|
+
systemPromptBinding?: WorkspacePlanSystemPromptBinding;
|
|
160
281
|
unsupported: Unsupported[];
|
|
161
282
|
written: string[];
|
|
162
283
|
}
|
|
@@ -165,6 +286,9 @@ export interface WorkspacePlanSpawnInputs {
|
|
|
165
286
|
env: Record<string, string>;
|
|
166
287
|
flags: string[];
|
|
167
288
|
systemPrompt?: string;
|
|
289
|
+
appendSystemPrompt?: string;
|
|
290
|
+
/** Read it with {@link takeSystemPromptBinding}, which refuses a foreign control. */
|
|
291
|
+
systemPromptBinding?: WorkspacePlanSystemPromptBinding;
|
|
168
292
|
}
|
|
169
293
|
/** Result of applying a public plan at the private executor boundary. */
|
|
170
294
|
export interface WorkspacePlanApplication {
|
|
@@ -207,6 +331,7 @@ export interface AgentCandidateWorkspacePlan {
|
|
|
207
331
|
env: Record<string, AgentCandidateConfigValue>;
|
|
208
332
|
flags: AgentCandidateConfigValue[];
|
|
209
333
|
systemPrompt?: AgentCandidateConfigValue;
|
|
334
|
+
appendSystemPrompt?: AgentCandidateConfigValue;
|
|
210
335
|
unsupported: Unsupported[];
|
|
211
336
|
}
|
|
212
337
|
export interface AgentCandidateWorkspacePlanReceipt {
|
|
@@ -215,8 +340,21 @@ export interface AgentCandidateWorkspacePlanReceipt {
|
|
|
215
340
|
env: Record<string, AgentCandidateConfigValue>;
|
|
216
341
|
flags: AgentCandidateConfigValue[];
|
|
217
342
|
systemPrompt?: AgentCandidateConfigValue;
|
|
343
|
+
appendSystemPrompt?: AgentCandidateConfigValue;
|
|
218
344
|
unsupported: Unsupported[];
|
|
219
345
|
}
|
|
346
|
+
/**
|
|
347
|
+
* The replacement text this launcher must bind to `control`, or `undefined`
|
|
348
|
+
* when the plan carries no launcher-bound intent.
|
|
349
|
+
*
|
|
350
|
+
* Throws for a binding addressed to a DIFFERENT control: the reader cannot
|
|
351
|
+
* execute it, and answering `undefined` would start the agent with the
|
|
352
|
+
* harness's own prompt still in force while nothing reported a problem — the
|
|
353
|
+
* silent downgrade the binding exists to prevent. This is the seam where an
|
|
354
|
+
* executor that cannot bind an intent says so, by name, instead of running a
|
|
355
|
+
* profile whose prompt never took effect.
|
|
356
|
+
*/
|
|
357
|
+
export declare function takeSystemPromptBinding(spawn: Pick<WorkspacePlanSpawnInputs, "systemPromptBinding">, control: ExecutorSystemPromptBinding): string | undefined;
|
|
220
358
|
export interface MaterializeCandidateProfileOptions {
|
|
221
359
|
/** Exact text fetched from pinned resource refs, keyed by declared SHA-256. */
|
|
222
360
|
resolvedResources?: ReadonlyMap<Sha256Digest, string>;
|
|
@@ -277,6 +415,18 @@ export declare function normalizeSkillMd(name: string, raw: string): string;
|
|
|
277
415
|
*/
|
|
278
416
|
export declare function materializeProfile(inputProfile: AgentProfile, harness: HarnessId, opts?: {
|
|
279
417
|
skip?: SkippableDimension[];
|
|
418
|
+
/**
|
|
419
|
+
* Launcher controls THIS caller owns and will bind itself — see
|
|
420
|
+
* {@link BINDABLE_LAUNCH_CONTROLS}. Each names a control no workspace file,
|
|
421
|
+
* flag or env var reaches on its own, so declaring one turns a plan-time
|
|
422
|
+
* refusal into the lowering (or the hand-over) that control can execute.
|
|
423
|
+
*
|
|
424
|
+
* A promise, not a hint: declare a control only from the code that starts
|
|
425
|
+
* the harness and writes that control. A caller that hands the plan to
|
|
426
|
+
* someone else's launcher declares nothing and keeps the refusal, which is
|
|
427
|
+
* what it can actually deliver.
|
|
428
|
+
*/
|
|
429
|
+
binds?: readonly BindableLaunchControl[];
|
|
280
430
|
}): WorkspacePlan;
|
|
281
431
|
/**
|
|
282
432
|
* Materialize a sealed candidate profile without weakening its process values.
|
|
@@ -339,3 +489,45 @@ export type OpenCodeMcpConfig = Record<string, {
|
|
|
339
489
|
}>;
|
|
340
490
|
/** Lower canonical MCP definitions to OpenCode's native startup configuration. */
|
|
341
491
|
export declare function openCodeMcpConfig(mcp: Record<string, AgentProfileMcpServer>): OpenCodeMcpConfig;
|
|
492
|
+
export interface PrimeProfileSkill {
|
|
493
|
+
name: string;
|
|
494
|
+
content: string;
|
|
495
|
+
}
|
|
496
|
+
export interface PrimeProfileSubagent {
|
|
497
|
+
name: string;
|
|
498
|
+
description?: string;
|
|
499
|
+
prompt?: string;
|
|
500
|
+
metadata?: Record<string, unknown>;
|
|
501
|
+
}
|
|
502
|
+
/** Validated, materialization-ready view of the profile controls prime applies. */
|
|
503
|
+
export interface PrimeProfileControls {
|
|
504
|
+
systemPrompt?: string;
|
|
505
|
+
appendSystemPrompt?: string;
|
|
506
|
+
skills: PrimeProfileSkill[];
|
|
507
|
+
subagents: PrimeProfileSubagent[];
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Validate and extract the profile controls the prime agent-dir lowering
|
|
511
|
+
* materializes. Throws on any control (or control facet) the fork has no
|
|
512
|
+
* verified read path for — partial acceptance would silently drop the rest.
|
|
513
|
+
*/
|
|
514
|
+
export declare function readPrimeProfileControls(profile: AgentProfile | undefined): PrimeProfileControls;
|
|
515
|
+
/** Deterministic harness-state entry id for a profile subagent name. */
|
|
516
|
+
export declare function primeSubagentEntryId(name: string): string;
|
|
517
|
+
/**
|
|
518
|
+
* Materialize the validated controls into `agentDir` and return the extra
|
|
519
|
+
* spawn args that bind them. Runs before every spawn (same place models.json
|
|
520
|
+
* is materialized), so a continual agent dir is re-pinned to the current
|
|
521
|
+
* profile on each fresh prime process.
|
|
522
|
+
*/
|
|
523
|
+
export declare function materializePrimeProfileControls(agentDir: string, controls: PrimeProfileControls, warn: (msg: string, meta?: Record<string, unknown>) => void): string[];
|
|
524
|
+
/**
|
|
525
|
+
* Upsert profile subagent specs into the fork's global continual-harness
|
|
526
|
+
* store and remove profile-sourced entries the current profile no longer
|
|
527
|
+
* declares. Agent-written entries (`source: "agent"`) are never touched.
|
|
528
|
+
*
|
|
529
|
+
* A pre-existing unparsable store degrades to empty exactly like the fork's
|
|
530
|
+
* own loader (refinement.ts:290-300 — "a corrupt state file must degrade to
|
|
531
|
+
* empty rather than throw"), with a warning so the reset is visible.
|
|
532
|
+
*/
|
|
533
|
+
export declare function seedPrimeProfileSubagents(agentDir: string, subagents: PrimeProfileSubagent[], warn: (msg: string, meta?: Record<string, unknown>) => void): void;
|