@tangle-network/agent-interface 2.9.0 → 2.11.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/README.md +24 -0
- package/dist/agent-profile.d.ts +80 -1
- package/dist/agent-profile.js +65 -0
- package/dist/environment-interactive-start.d.ts +1 -1
- package/dist/profile-kb/harnesses.d.ts +9 -0
- package/dist/profile-kb/harnesses.js +115 -0
- package/dist/profile-kb/index.d.ts +52 -0
- package/dist/profile-kb/index.js +127 -0
- package/dist/profile-kb/models.d.ts +9 -0
- package/dist/profile-kb/models.js +321 -0
- package/dist/profile-kb/records.d.ts +12 -0
- package/dist/profile-kb/records.js +62 -0
- package/dist/profile-kb/types.d.ts +76 -0
- package/dist/profile-kb/types.js +1 -0
- package/dist/profile-schema.d.ts +112 -2
- package/dist/profile-schema.js +101 -3
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -172,6 +172,30 @@ When caller environment values merge into a bridge or harness process, reject na
|
|
|
172
172
|
Use `isCredentialBearingProfileConfigName(name)` before retaining public config.
|
|
173
173
|
These checks do not apply to a replacement environment owned by caller code.
|
|
174
174
|
|
|
175
|
+
## Profile knowledge base
|
|
176
|
+
|
|
177
|
+
`@tangle-network/agent-interface/profile-kb` holds how to get the best from each frontier harness and model this platform runs.
|
|
178
|
+
Every entry cites a vendor source or a command run on a dated check.
|
|
179
|
+
Guidance is specific to one harness or model and never compares models.
|
|
180
|
+
|
|
181
|
+
`withProfileKb(profile)` composes harness guidance, then model guidance, then the profile's own text into the profile's prompt:
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
import { withProfileKb } from "@tangle-network/agent-interface/profile-kb";
|
|
185
|
+
|
|
186
|
+
const worker = withProfileKb({
|
|
187
|
+
harness: "claude-code",
|
|
188
|
+
model: { default: "claude-opus-5-5" },
|
|
189
|
+
prompt: { appendSystemPrompt: "Cite the file you read." },
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Guidance goes into `appendSystemPrompt` where the harness owns an additive system-prompt control, and into `instructions` otherwise.
|
|
194
|
+
Recomposing replaces earlier guidance, so a second call, or a call with an executor's harness or model override, yields a stable profile.
|
|
195
|
+
`composeAgentProfileGuidance` is the underlying composer for other knowledge layers.
|
|
196
|
+
|
|
197
|
+
The module also exports the data (`profileKbHarnesses`, `profileKbModels`), operator notes for launching each harness and model, platform learnings (admitted only after an agent-eval check reproduced them), and `profileKbDiscrepancies`, which records where a vendor source states a requested name differently.
|
|
198
|
+
|
|
175
199
|
## Failed execution accounting
|
|
176
200
|
|
|
177
201
|
An adapter can reject with `AgentExecutionError` and retain observed usage and timing in its immutable `receipt`.
|
package/dist/agent-profile.d.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* fixed. This package is the canonical public home for these symbols.
|
|
13
13
|
*/
|
|
14
14
|
import type { HarnessType } from "./harness.js";
|
|
15
|
+
import type { Sha256Digest } from "./agent-candidate.js";
|
|
15
16
|
/**
|
|
16
17
|
* Permission policy value for a capability.
|
|
17
18
|
*/
|
|
@@ -343,6 +344,53 @@ export interface AgentProfileConnection {
|
|
|
343
344
|
*/
|
|
344
345
|
alias?: string;
|
|
345
346
|
}
|
|
347
|
+
/** Router namespace reserved for checkpoint-backed models. Receipt-free profiles cannot use it. */
|
|
348
|
+
export declare const TRAINED_MODEL_PREFIX = "tangle-trained/";
|
|
349
|
+
/** An immutable Router alias; serving must independently attest this artifact-to-route binding. */
|
|
350
|
+
export declare function trainedModelIdForArtifact(digest: Sha256Digest): string;
|
|
351
|
+
/** Identity of a task whose data was exposed to training or model selection. */
|
|
352
|
+
export interface AgentTrainingTask {
|
|
353
|
+
benchmark: string;
|
|
354
|
+
task: string;
|
|
355
|
+
contentDigest: Sha256Digest;
|
|
356
|
+
}
|
|
357
|
+
/** Complete exposure inventory, derived from the exact dataset delivered to a trainer. */
|
|
358
|
+
export interface AgentTrainingDatasetIdentity {
|
|
359
|
+
digest: Sha256Digest;
|
|
360
|
+
taskSetDigest: Sha256Digest;
|
|
361
|
+
tasks: AgentTrainingTask[];
|
|
362
|
+
}
|
|
363
|
+
export interface AgentTrainingReceipt {
|
|
364
|
+
version: 1;
|
|
365
|
+
dataset: AgentTrainingDatasetIdentity;
|
|
366
|
+
parentProfileDigest: Sha256Digest;
|
|
367
|
+
/** Null only when the parent has no training receipt. */
|
|
368
|
+
parentReceiptDigest: Sha256Digest | null;
|
|
369
|
+
executionRef: Sha256Digest;
|
|
370
|
+
trainer: {
|
|
371
|
+
mode: "command" | "managed";
|
|
372
|
+
id: string;
|
|
373
|
+
revision: Sha256Digest;
|
|
374
|
+
/** Public hyperparameters only; credentials belong to the private executor. */
|
|
375
|
+
parameters: Record<string, string | number | boolean | null>;
|
|
376
|
+
};
|
|
377
|
+
checkpoint: {
|
|
378
|
+
artifactDigest: Sha256Digest;
|
|
379
|
+
artifactBytes: number;
|
|
380
|
+
routerModelId: string;
|
|
381
|
+
/** Digest of independently verified serving evidence, not trainer stdout. */
|
|
382
|
+
servingDigest: Sha256Digest;
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
export interface AgentProfileTraining {
|
|
386
|
+
receipt: AgentTrainingReceipt;
|
|
387
|
+
/** Immediate parent first, terminating at a receipt with parentReceiptDigest=null. */
|
|
388
|
+
ancestors: AgentTrainingReceipt[];
|
|
389
|
+
}
|
|
390
|
+
export interface AgentProfileMetadata extends Record<string, unknown> {
|
|
391
|
+
/** Reserved: a trained model is admitted only with a complete checkpoint receipt. */
|
|
392
|
+
training?: AgentProfileTraining;
|
|
393
|
+
}
|
|
346
394
|
/**
|
|
347
395
|
* Public provider-neutral agent profile contract.
|
|
348
396
|
*/
|
|
@@ -374,7 +422,7 @@ export interface AgentProfile {
|
|
|
374
422
|
hooks?: Record<string, AgentProfileHookCommand[]>;
|
|
375
423
|
modes?: Record<string, AgentProfileMode>;
|
|
376
424
|
confidential?: AgentProfileConfidential;
|
|
377
|
-
metadata?:
|
|
425
|
+
metadata?: AgentProfileMetadata;
|
|
378
426
|
/**
|
|
379
427
|
* Non-portable backend-specific extensions.
|
|
380
428
|
*
|
|
@@ -471,4 +519,35 @@ export interface AgentProfileValidationResult {
|
|
|
471
519
|
* base-first with a blank line between them.
|
|
472
520
|
*/
|
|
473
521
|
export declare function mergeAgentProfiles(base: AgentProfile | undefined, overlay: AgentProfile | undefined): AgentProfile | undefined;
|
|
522
|
+
/**
|
|
523
|
+
* One block of standing guidance composed into a profile's prompt.
|
|
524
|
+
*
|
|
525
|
+
* `source` names the layer the text came from (`harness`, `model`, or another
|
|
526
|
+
* knowledge layer) and `id` names the subject, so a composed block can be
|
|
527
|
+
* found and replaced later. The profile's own prompt text is never a block:
|
|
528
|
+
* it is what the blocks are composed in front of.
|
|
529
|
+
*/
|
|
530
|
+
export interface AgentProfileGuidanceBlock {
|
|
531
|
+
source: string;
|
|
532
|
+
id: string;
|
|
533
|
+
text: string;
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Where composed guidance lands. `appendSystemPrompt` keeps the harness's
|
|
537
|
+
* system prompt and adds the guidance to it; `instructions` uses the
|
|
538
|
+
* harness's caller-instruction surface, for harnesses that own no additive
|
|
539
|
+
* system-prompt control.
|
|
540
|
+
*/
|
|
541
|
+
export type AgentProfileGuidanceChannel = "appendSystemPrompt" | "instructions";
|
|
542
|
+
/**
|
|
543
|
+
* Compose harness, model, and other layered guidance into a profile's prompt.
|
|
544
|
+
*
|
|
545
|
+
* The blocks come first, in the order given, and the profile's own text comes
|
|
546
|
+
* last, so the most specific instruction (the profile's) is the one a model
|
|
547
|
+
* reads after the general guidance. Composition replaces any blocks a previous
|
|
548
|
+
* composition added, on both channels, so recomposing after a harness or
|
|
549
|
+
* model change never stacks stale guidance. Composing the same blocks twice
|
|
550
|
+
* yields the same profile, and with it the same canonical identity.
|
|
551
|
+
*/
|
|
552
|
+
export declare function composeAgentProfileGuidance(profile: AgentProfile, blocks: readonly AgentProfileGuidanceBlock[], channel: AgentProfileGuidanceChannel): AgentProfile;
|
|
474
553
|
export {};
|
package/dist/agent-profile.js
CHANGED
|
@@ -63,6 +63,12 @@ export function defineAgentProfileSecretRef(key, format) {
|
|
|
63
63
|
...(format === undefined ? {} : { format }),
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
|
+
/** Router namespace reserved for checkpoint-backed models. Receipt-free profiles cannot use it. */
|
|
67
|
+
export const TRAINED_MODEL_PREFIX = "tangle-trained/";
|
|
68
|
+
/** An immutable Router alias; serving must independently attest this artifact-to-route binding. */
|
|
69
|
+
export function trainedModelIdForArtifact(digest) {
|
|
70
|
+
return `${TRAINED_MODEL_PREFIX}${digest.slice("sha256:".length)}`;
|
|
71
|
+
}
|
|
66
72
|
/**
|
|
67
73
|
* Helper for declaring typed profiles in application code.
|
|
68
74
|
*/
|
|
@@ -167,3 +173,62 @@ export function mergeAgentProfiles(base, overlay) {
|
|
|
167
173
|
extensions: mergeRecord(base?.extensions, overlay?.extensions),
|
|
168
174
|
});
|
|
169
175
|
}
|
|
176
|
+
const GUIDANCE_OPEN = /^<profile-guidance source="[^"]*" id="[^"]*">\n/;
|
|
177
|
+
const GUIDANCE_BLOCK = /<profile-guidance source="[^"]*" id="[^"]*">\n[\s\S]*?\n<\/profile-guidance>(\n\n)?/g;
|
|
178
|
+
function renderGuidanceBlock(block) {
|
|
179
|
+
if (/["\n]/.test(block.source) || /["\n]/.test(block.id)) {
|
|
180
|
+
throw new TypeError("profile guidance source and id must not contain quotes or newlines");
|
|
181
|
+
}
|
|
182
|
+
if (block.text.includes("</profile-guidance>")) {
|
|
183
|
+
throw new TypeError("profile guidance text must not contain the closing block marker");
|
|
184
|
+
}
|
|
185
|
+
return `<profile-guidance source="${block.source}" id="${block.id}">\n${block.text}\n</profile-guidance>`;
|
|
186
|
+
}
|
|
187
|
+
/** Remove every previously composed guidance block from appended prompt text. */
|
|
188
|
+
function stripGuidanceText(text) {
|
|
189
|
+
if (text === undefined || text === "")
|
|
190
|
+
return text;
|
|
191
|
+
const stripped = text.replace(GUIDANCE_BLOCK, "");
|
|
192
|
+
return stripped === "" ? undefined : stripped;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Compose harness, model, and other layered guidance into a profile's prompt.
|
|
196
|
+
*
|
|
197
|
+
* The blocks come first, in the order given, and the profile's own text comes
|
|
198
|
+
* last, so the most specific instruction (the profile's) is the one a model
|
|
199
|
+
* reads after the general guidance. Composition replaces any blocks a previous
|
|
200
|
+
* composition added, on both channels, so recomposing after a harness or
|
|
201
|
+
* model change never stacks stale guidance. Composing the same blocks twice
|
|
202
|
+
* yields the same profile, and with it the same canonical identity.
|
|
203
|
+
*/
|
|
204
|
+
export function composeAgentProfileGuidance(profile, blocks, channel) {
|
|
205
|
+
const prompt = profile.prompt ?? {};
|
|
206
|
+
const ownAppend = stripGuidanceText(prompt.appendSystemPrompt);
|
|
207
|
+
const ownInstructions = prompt.instructions?.filter((line) => !GUIDANCE_OPEN.test(line));
|
|
208
|
+
const rendered = blocks.map(renderGuidanceBlock);
|
|
209
|
+
const next = { ...prompt };
|
|
210
|
+
delete next.appendSystemPrompt;
|
|
211
|
+
delete next.instructions;
|
|
212
|
+
if (channel === "appendSystemPrompt") {
|
|
213
|
+
const parts = [...rendered, ...(ownAppend ? [ownAppend] : [])];
|
|
214
|
+
if (parts.length > 0)
|
|
215
|
+
next.appendSystemPrompt = parts.join("\n\n");
|
|
216
|
+
else if (ownAppend !== undefined)
|
|
217
|
+
next.appendSystemPrompt = ownAppend;
|
|
218
|
+
if (ownInstructions !== undefined)
|
|
219
|
+
next.instructions = ownInstructions;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
if (ownAppend !== undefined)
|
|
223
|
+
next.appendSystemPrompt = ownAppend;
|
|
224
|
+
const lines = [...rendered, ...(ownInstructions ?? [])];
|
|
225
|
+
if (lines.length > 0 || prompt.instructions !== undefined) {
|
|
226
|
+
next.instructions = lines;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const result = { ...profile };
|
|
230
|
+
if (Object.keys(next).length > 0 || profile.prompt !== undefined) {
|
|
231
|
+
result.prompt = next;
|
|
232
|
+
}
|
|
233
|
+
return result;
|
|
234
|
+
}
|
|
@@ -216,7 +216,7 @@ export declare const AgentInteractiveSessionStartSchema: z.ZodObject<{
|
|
|
216
216
|
sealed: z.ZodOptional<z.ZodBoolean>;
|
|
217
217
|
attestationRefresh: z.ZodOptional<z.ZodBoolean>;
|
|
218
218
|
}, z.core.$strict>>;
|
|
219
|
-
metadata: z.ZodOptional<z.ZodType<
|
|
219
|
+
metadata: z.ZodOptional<z.ZodType<import("./agent-profile.js").AgentProfileMetadata, unknown, z.core.$ZodTypeInternals<import("./agent-profile.js").AgentProfileMetadata, unknown>>>;
|
|
220
220
|
extensions: z.ZodOptional<z.ZodType<Record<string, Record<string, unknown> | undefined>, unknown, z.core.$ZodTypeInternals<Record<string, Record<string, unknown> | undefined>, unknown>>>;
|
|
221
221
|
}, z.core.$strict>;
|
|
222
222
|
requestedProfileDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ProfileKbHarness } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The frontier coding harnesses this platform runs, checked against the
|
|
4
|
+
* installed CLI on 2026-09-22.
|
|
5
|
+
*
|
|
6
|
+
* `prompt` lines go into the agent's prompt; `operator` lines are launch
|
|
7
|
+
* facts. Each harness is described on its own terms.
|
|
8
|
+
*/
|
|
9
|
+
export declare const profileKbHarnesses: readonly ProfileKbHarness[];
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
const CHECKED = "2026-09-22";
|
|
2
|
+
/**
|
|
3
|
+
* The frontier coding harnesses this platform runs, checked against the
|
|
4
|
+
* installed CLI on 2026-09-22.
|
|
5
|
+
*
|
|
6
|
+
* `prompt` lines go into the agent's prompt; `operator` lines are launch
|
|
7
|
+
* facts. Each harness is described on its own terms.
|
|
8
|
+
*/
|
|
9
|
+
export const profileKbHarnesses = [
|
|
10
|
+
{
|
|
11
|
+
id: "claude-code",
|
|
12
|
+
name: "Claude Code",
|
|
13
|
+
version: "2.1.280",
|
|
14
|
+
sources: [
|
|
15
|
+
{
|
|
16
|
+
url: "https://code.claude.com/docs/en/cli-reference",
|
|
17
|
+
checkedAt: CHECKED,
|
|
18
|
+
},
|
|
19
|
+
{ url: "cli:claude --help", checkedAt: CHECKED, note: "2.1.280" },
|
|
20
|
+
],
|
|
21
|
+
prompt: [
|
|
22
|
+
"Delegate independent slices to subagents, several in one turn so they run in parallel, then synthesize their results.",
|
|
23
|
+
"Use the skills listed in your session for procedures they cover.",
|
|
24
|
+
"Run long commands in the background and keep working while they finish.",
|
|
25
|
+
],
|
|
26
|
+
operator: [
|
|
27
|
+
"Headless: `claude -p <prompt> --model <id> --effort <level> --output-format stream-json`.",
|
|
28
|
+
"`--append-system-prompt` adds to the built-in prompt; `--system-prompt` replaces it.",
|
|
29
|
+
"`--max-budget-usd` caps spend; `--json-schema` validates structured output; `--mcp-config` loads MCP servers.",
|
|
30
|
+
"`--bg` starts a background session; `--bare` skips hooks, plugins, memory, and CLAUDE.md discovery.",
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "codex",
|
|
35
|
+
name: "Codex CLI",
|
|
36
|
+
version: "0.152.1",
|
|
37
|
+
sources: [
|
|
38
|
+
{ url: "https://learn.chatgpt.com/docs/models", checkedAt: CHECKED },
|
|
39
|
+
{
|
|
40
|
+
url: "cli:codex exec --help; codex features list",
|
|
41
|
+
checkedAt: CHECKED,
|
|
42
|
+
note: "0.152.1; multi_agent stable and enabled",
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
prompt: [
|
|
46
|
+
"Split independent work across child agents with spawn_agent, and join them with wait_agent.",
|
|
47
|
+
"Edit with apply_patch and search with rg.",
|
|
48
|
+
"Carry the task end to end in this turn: gather context, implement, run the checks, and report the evidence.",
|
|
49
|
+
],
|
|
50
|
+
operator: [
|
|
51
|
+
"Headless: `codex exec <prompt> -m <model> -c model_reasoning_effort=<level> --json -o <last-message-file>`.",
|
|
52
|
+
"`--output-schema <file>` enforces structured output. `codex review` runs a non-interactive review.",
|
|
53
|
+
"Reasoning levels are per model; read them from `$CODEX_HOME/models_cache.json`.",
|
|
54
|
+
"System-prompt replacement uses the `model_instructions_file` config key; standing instructions go in AGENTS.md.",
|
|
55
|
+
"`/goal` runs long unattended work; `resume` and `fork` continue a session.",
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: "opencode",
|
|
60
|
+
name: "OpenCode",
|
|
61
|
+
version: "1.18.18",
|
|
62
|
+
sources: [
|
|
63
|
+
{ url: "https://opencode.ai/docs/cli/", checkedAt: CHECKED },
|
|
64
|
+
{ url: "cli:opencode run --help", checkedAt: CHECKED, note: "1.18.18" },
|
|
65
|
+
],
|
|
66
|
+
prompt: [
|
|
67
|
+
"Delegate a focused subtask to a named agent when its persona or model fits the subtask.",
|
|
68
|
+
"Use the mounted MCP tools for external actions.",
|
|
69
|
+
],
|
|
70
|
+
operator: [
|
|
71
|
+
"Headless: `opencode run <message> -m <provider/model> --agent <name> --variant <effort> --format json`.",
|
|
72
|
+
"Standing text goes through `instructions` files or appended system text; the built-in prompt stays in place.",
|
|
73
|
+
"`opencode serve` with `run --attach <url>`, or `opencode acp`, gives a parent live control.",
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "pi",
|
|
78
|
+
name: "Pi",
|
|
79
|
+
version: "0.83.0",
|
|
80
|
+
sources: [
|
|
81
|
+
{ url: "cli:pi --help", checkedAt: CHECKED, note: "0.83.0" },
|
|
82
|
+
],
|
|
83
|
+
prompt: [
|
|
84
|
+
"Expect steering messages mid-run and fold each one into the current plan.",
|
|
85
|
+
"Fan out independent work by running `pi -p <task> --mode json` from bash, several at once, and read the results back.",
|
|
86
|
+
],
|
|
87
|
+
operator: [
|
|
88
|
+
"Headless: `pi -p <prompt> --model <provider/id[:thinking]> --mode json`.",
|
|
89
|
+
"`--mode rpc` takes JSONL commands on stdin (steer, follow-up, set model, compact, fork) for live control.",
|
|
90
|
+
"`--thinking` takes off, minimal, low, medium, high, xhigh, or max.",
|
|
91
|
+
"`--system-prompt` replaces the default; `--append-system-prompt` adds to it.",
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: "kimi-code",
|
|
96
|
+
name: "Kimi Code CLI",
|
|
97
|
+
version: "0.36.1",
|
|
98
|
+
sources: [
|
|
99
|
+
{ url: "https://moonshotai.github.io/kimi-code/", checkedAt: CHECKED },
|
|
100
|
+
{
|
|
101
|
+
url: "cli:kimi --help; ~/.kimi-code/config.toml",
|
|
102
|
+
checkedAt: CHECKED,
|
|
103
|
+
note: "0.36.1",
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
prompt: [
|
|
107
|
+
"Plan the change first, then edit and verify each step against tests and runtime output.",
|
|
108
|
+
],
|
|
109
|
+
operator: [
|
|
110
|
+
"Headless: `kimi -p <prompt> -m kimi-code/k3 --output-format stream-json`.",
|
|
111
|
+
"`--auto` runs fully autonomous; `--agent-file <path>` loads an agent definition; `--plan` starts in plan mode.",
|
|
112
|
+
"Effort is the `[thinking] effort` key in `~/.kimi-code/config.toml`: low, high, or max.",
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile knowledge base: how to get the best from each frontier harness and
|
|
3
|
+
* model this platform runs, from current vendor sources, composed into an
|
|
4
|
+
* {@link AgentProfile}'s prompt.
|
|
5
|
+
*
|
|
6
|
+
* The data is plain, dated, and sourced. Composition is pure: the same profile
|
|
7
|
+
* yields the same composed profile, so profile identity stays deterministic.
|
|
8
|
+
*/
|
|
9
|
+
import { type AgentProfile, type AgentProfileGuidanceBlock } from "../agent-profile.js";
|
|
10
|
+
import type { HarnessType } from "../harness.js";
|
|
11
|
+
import { profileKbHarnesses } from "./harnesses.js";
|
|
12
|
+
import { profileKbModels } from "./models.js";
|
|
13
|
+
import { profileKbDiscrepancies, profileKbLearnings } from "./records.js";
|
|
14
|
+
import type { ProfileKbHarness, ProfileKbModel } from "./types.js";
|
|
15
|
+
export type * from "./types.js";
|
|
16
|
+
export { profileKbDiscrepancies, profileKbHarnesses, profileKbLearnings, profileKbModels, };
|
|
17
|
+
/** Date the knowledge base was last checked against its sources. */
|
|
18
|
+
export declare const PROFILE_KB_CHECKED_AT = "2026-09-22";
|
|
19
|
+
/** Find a harness entry by its {@link HarnessType}. */
|
|
20
|
+
export declare function findProfileKbHarness(harness: HarnessType | string | undefined): ProfileKbHarness | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Find a model entry by id or alias.
|
|
23
|
+
*
|
|
24
|
+
* Accepts the spellings harnesses and routers use: a provider prefix
|
|
25
|
+
* (`anthropic/claude-opus-5-5`), a route prefix
|
|
26
|
+
* (`pi/tangle-router/deepseek/deepseek-v4.1-flash`), and a trailing `:suffix`
|
|
27
|
+
* such as pi's thinking level or a router's `:batch`. A different version is a
|
|
28
|
+
* different model and never matches.
|
|
29
|
+
*/
|
|
30
|
+
export declare function findProfileKbModel(model: string | undefined): ProfileKbModel | undefined;
|
|
31
|
+
/** Which harness and model to compose guidance for. */
|
|
32
|
+
export interface ProfileKbSelection {
|
|
33
|
+
harness?: HarnessType | string;
|
|
34
|
+
model?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The guidance blocks for one harness and model: the harness's, then the
|
|
38
|
+
* model's, then any reproduced platform learnings for either. Unknown names
|
|
39
|
+
* contribute nothing.
|
|
40
|
+
*/
|
|
41
|
+
export declare function profileKbGuidance(selection: ProfileKbSelection): AgentProfileGuidanceBlock[];
|
|
42
|
+
/**
|
|
43
|
+
* Compose harness, model, and profile guidance into the profile's prompt.
|
|
44
|
+
*
|
|
45
|
+
* The harness and model default to the profile's own `harness` and
|
|
46
|
+
* `model.default`; pass a selection to compose for an executor's override.
|
|
47
|
+
* Guidance goes into `appendSystemPrompt` where the harness owns an additive
|
|
48
|
+
* system-prompt control and into `instructions` otherwise, so a harness that
|
|
49
|
+
* refuses appended system text still receives it. The profile's own text
|
|
50
|
+
* stays last. Recomposing replaces earlier guidance, so the result is stable.
|
|
51
|
+
*/
|
|
52
|
+
export declare function withProfileKb(profile: AgentProfile, selection?: ProfileKbSelection): AgentProfile;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile knowledge base: how to get the best from each frontier harness and
|
|
3
|
+
* model this platform runs, from current vendor sources, composed into an
|
|
4
|
+
* {@link AgentProfile}'s prompt.
|
|
5
|
+
*
|
|
6
|
+
* The data is plain, dated, and sourced. Composition is pure: the same profile
|
|
7
|
+
* yields the same composed profile, so profile identity stays deterministic.
|
|
8
|
+
*/
|
|
9
|
+
import { composeAgentProfileGuidance, } from "../agent-profile.js";
|
|
10
|
+
import { harnessSystemPromptIntents } from "../harness-capabilities.js";
|
|
11
|
+
import { profileKbHarnesses } from "./harnesses.js";
|
|
12
|
+
import { profileKbModels } from "./models.js";
|
|
13
|
+
import { profileKbDiscrepancies, profileKbLearnings } from "./records.js";
|
|
14
|
+
export { profileKbDiscrepancies, profileKbHarnesses, profileKbLearnings, profileKbModels, };
|
|
15
|
+
/** Date the knowledge base was last checked against its sources. */
|
|
16
|
+
export const PROFILE_KB_CHECKED_AT = "2026-09-22";
|
|
17
|
+
/** Find a harness entry by its {@link HarnessType}. */
|
|
18
|
+
export function findProfileKbHarness(harness) {
|
|
19
|
+
if (!harness)
|
|
20
|
+
return undefined;
|
|
21
|
+
return profileKbHarnesses.find((entry) => entry.id === harness);
|
|
22
|
+
}
|
|
23
|
+
const modelIndex = (() => {
|
|
24
|
+
const index = new Map();
|
|
25
|
+
for (const model of profileKbModels) {
|
|
26
|
+
for (const name of [model.id, ...model.aliases]) {
|
|
27
|
+
const key = name.toLowerCase();
|
|
28
|
+
if (index.has(key)) {
|
|
29
|
+
throw new Error(`profile-kb: model name ${name} is declared twice`);
|
|
30
|
+
}
|
|
31
|
+
index.set(key, model);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return index;
|
|
35
|
+
})();
|
|
36
|
+
/**
|
|
37
|
+
* Find a model entry by id or alias.
|
|
38
|
+
*
|
|
39
|
+
* Accepts the spellings harnesses and routers use: a provider prefix
|
|
40
|
+
* (`anthropic/claude-opus-5-5`), a route prefix
|
|
41
|
+
* (`pi/tangle-router/deepseek/deepseek-v4.1-flash`), and a trailing `:suffix`
|
|
42
|
+
* such as pi's thinking level or a router's `:batch`. A different version is a
|
|
43
|
+
* different model and never matches.
|
|
44
|
+
*/
|
|
45
|
+
export function findProfileKbModel(model) {
|
|
46
|
+
if (!model)
|
|
47
|
+
return undefined;
|
|
48
|
+
const colon = model.lastIndexOf(":");
|
|
49
|
+
let candidate = (colon > 0 ? model.slice(0, colon) : model)
|
|
50
|
+
.trim()
|
|
51
|
+
.toLowerCase();
|
|
52
|
+
for (;;) {
|
|
53
|
+
const found = modelIndex.get(candidate);
|
|
54
|
+
if (found)
|
|
55
|
+
return found;
|
|
56
|
+
const slash = candidate.indexOf("/");
|
|
57
|
+
if (slash < 0)
|
|
58
|
+
return undefined;
|
|
59
|
+
candidate = candidate.slice(slash + 1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function learningsFor(harness, model) {
|
|
63
|
+
return profileKbLearnings.filter((learning) => {
|
|
64
|
+
const scope = learning.appliesTo;
|
|
65
|
+
if (scope.harness !== undefined && scope.harness !== harness?.id) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
if (scope.model !== undefined && scope.model !== model?.id)
|
|
69
|
+
return false;
|
|
70
|
+
return scope.harness !== undefined || scope.model !== undefined;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function bullets(lines) {
|
|
74
|
+
return lines.map((line) => `- ${line}`).join("\n");
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The guidance blocks for one harness and model: the harness's, then the
|
|
78
|
+
* model's, then any reproduced platform learnings for either. Unknown names
|
|
79
|
+
* contribute nothing.
|
|
80
|
+
*/
|
|
81
|
+
export function profileKbGuidance(selection) {
|
|
82
|
+
const harness = findProfileKbHarness(selection.harness);
|
|
83
|
+
const model = findProfileKbModel(selection.model);
|
|
84
|
+
const blocks = [];
|
|
85
|
+
if (harness && harness.prompt.length > 0) {
|
|
86
|
+
blocks.push({
|
|
87
|
+
source: "harness",
|
|
88
|
+
id: harness.id,
|
|
89
|
+
text: `You are running in ${harness.name}.\n${bullets(harness.prompt)}`,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (model && model.prompt.length > 0) {
|
|
93
|
+
blocks.push({
|
|
94
|
+
source: "model",
|
|
95
|
+
id: model.id,
|
|
96
|
+
text: `You are ${model.name}.\n${bullets(model.prompt)}`,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
const learnings = learningsFor(harness, model);
|
|
100
|
+
if (learnings.length > 0) {
|
|
101
|
+
blocks.push({
|
|
102
|
+
source: "learning",
|
|
103
|
+
id: learnings.map((learning) => learning.id).join(","),
|
|
104
|
+
text: bullets(learnings.map((learning) => learning.text)),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return blocks;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Compose harness, model, and profile guidance into the profile's prompt.
|
|
111
|
+
*
|
|
112
|
+
* The harness and model default to the profile's own `harness` and
|
|
113
|
+
* `model.default`; pass a selection to compose for an executor's override.
|
|
114
|
+
* Guidance goes into `appendSystemPrompt` where the harness owns an additive
|
|
115
|
+
* system-prompt control and into `instructions` otherwise, so a harness that
|
|
116
|
+
* refuses appended system text still receives it. The profile's own text
|
|
117
|
+
* stays last. Recomposing replaces earlier guidance, so the result is stable.
|
|
118
|
+
*/
|
|
119
|
+
export function withProfileKb(profile, selection = {}) {
|
|
120
|
+
const harness = selection.harness ?? profile.harness;
|
|
121
|
+
const model = selection.model ?? profile.model?.default;
|
|
122
|
+
const blocks = profileKbGuidance({ harness, model });
|
|
123
|
+
const channel = harnessSystemPromptIntents(findProfileKbHarness(harness)?.id ?? harness).append
|
|
124
|
+
? "appendSystemPrompt"
|
|
125
|
+
: "instructions";
|
|
126
|
+
return composeAgentProfileGuidance(profile, blocks, channel);
|
|
127
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ProfileKbModel } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Current frontier models, from vendor sources read on 2026-09-22.
|
|
4
|
+
*
|
|
5
|
+
* `prompt` lines go into the model's prompt; `operator` lines configure the
|
|
6
|
+
* run. Vendor facts carry their source. Nothing here compares one model with
|
|
7
|
+
* another.
|
|
8
|
+
*/
|
|
9
|
+
export declare const profileKbModels: readonly ProfileKbModel[];
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
const CHECKED = "2026-09-22";
|
|
2
|
+
const claudeDocs = "https://platform.claude.com/docs/en";
|
|
3
|
+
/**
|
|
4
|
+
* Current frontier models, from vendor sources read on 2026-09-22.
|
|
5
|
+
*
|
|
6
|
+
* `prompt` lines go into the model's prompt; `operator` lines configure the
|
|
7
|
+
* run. Vendor facts carry their source. Nothing here compares one model with
|
|
8
|
+
* another.
|
|
9
|
+
*/
|
|
10
|
+
export const profileKbModels = [
|
|
11
|
+
{
|
|
12
|
+
id: "claude-opus-5-5",
|
|
13
|
+
name: "Claude Opus 5.5",
|
|
14
|
+
vendor: "Anthropic",
|
|
15
|
+
surfaces: ["api", "router"],
|
|
16
|
+
aliases: ["anthropic/claude-opus-5-5", "anthropic.claude-opus-5-5"],
|
|
17
|
+
defaultEffort: "medium",
|
|
18
|
+
sources: [
|
|
19
|
+
{ url: `${claudeDocs}/models/opus-5-5/overview`, checkedAt: CHECKED },
|
|
20
|
+
{
|
|
21
|
+
url: `${claudeDocs}/build-with-claude/prompt-engineering/prompting-claude-opus-5-5`,
|
|
22
|
+
checkedAt: CHECKED,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
url: "https://www.anthropic.com/claude-opus-5-5-system-card",
|
|
26
|
+
checkedAt: CHECKED,
|
|
27
|
+
note: "system card, linked from the model overview",
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
prompt: [
|
|
31
|
+
"Keep the task's parts in a checklist you update, and keep working until every item is done or blocked.",
|
|
32
|
+
"Put status notes and recommendations in the same message as your next tool call; end the turn only when the work is complete or nothing can move without the user.",
|
|
33
|
+
"Before acting on a loosely specified task, explore the relevant files, records, and sources, including ones the task does not name, and use what you find.",
|
|
34
|
+
"When a lead agent can delegate, run independent slices in parallel subagents and pace the work to finish early.",
|
|
35
|
+
"For dense charts, diagrams, or screenshots, crop and zoom with the available image tools before reading values.",
|
|
36
|
+
],
|
|
37
|
+
operator: [
|
|
38
|
+
"Model id claude-opus-5-5; 1M context, 128K max output; released 2026-09-22.",
|
|
39
|
+
"Adaptive thinking is always on. Start at effort medium, measure low for cost, and reserve xhigh and max for measured gains.",
|
|
40
|
+
"Set max_tokens to 128000 for long agentic turns: thinking counts toward it.",
|
|
41
|
+
"Keep history append-only and pass thinking blocks back unchanged; change instructions with mid-conversation system messages.",
|
|
42
|
+
"Set thinking display to updates to receive progress notes between tool calls.",
|
|
43
|
+
"For unattended loops, treat a text-only end of turn as a report: name the open items in a short user message, at most two or three times.",
|
|
44
|
+
"For multi-agent runs, append elapsed time against a budget (for example `elapsed 340s / 1200s`) to each message.",
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: "claude-fable-5-1",
|
|
49
|
+
name: "Claude Fable 5.1",
|
|
50
|
+
vendor: "Anthropic",
|
|
51
|
+
surfaces: ["api", "router"],
|
|
52
|
+
aliases: ["anthropic/claude-fable-5-1", "anthropic.claude-fable-5-1"],
|
|
53
|
+
defaultEffort: "high",
|
|
54
|
+
sources: [
|
|
55
|
+
{ url: `${claudeDocs}/models/fable-5-1/overview`, checkedAt: CHECKED },
|
|
56
|
+
{
|
|
57
|
+
url: `${claudeDocs}/build-with-claude/prompt-engineering/prompting-claude-fable-5-1`,
|
|
58
|
+
checkedAt: CHECKED,
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
prompt: [
|
|
62
|
+
"You are operating autonomously: for reversible actions that follow from the request, proceed without asking; stop only for destructive actions or scope changes the user must decide.",
|
|
63
|
+
"Before ending your turn, check your last paragraph: if it is a plan, a list of next steps, or a promise, do that work now with tool calls.",
|
|
64
|
+
"The request sets the scope: deliver all of it, keep changes to what it needs, and report other findings as follow-ups.",
|
|
65
|
+
"First privately list what you need next; then request every item that does not depend on another's result in one response.",
|
|
66
|
+
"Say in a line what you are about to do, give brief updates while you work, and close with a recap that stands on its own.",
|
|
67
|
+
"Edit files surgically when a targeted edit gives the same result.",
|
|
68
|
+
"Write plainly: when a literal phrase is available, use it.",
|
|
69
|
+
],
|
|
70
|
+
operator: [
|
|
71
|
+
"Model id claude-fable-5-1; 1M context, 128K max output; released 2026-09-01. For demanding reasoning and long-horizon agentic work.",
|
|
72
|
+
"Adaptive thinking only. Start at effort high and sweep low, medium, xhigh, and max against your evals.",
|
|
73
|
+
"Keep history append-only; send per-turn reminders as turn-scoped system messages (clear_at next_user_message).",
|
|
74
|
+
"Let the lead agent keep working while subagents run: return from the spawn tool immediately and deliver results in a later user message.",
|
|
75
|
+
"At xhigh and max, leave max_tokens room for thinking plus the deliverable.",
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: "claude-sonnet-5",
|
|
80
|
+
name: "Claude Sonnet 5",
|
|
81
|
+
vendor: "Anthropic",
|
|
82
|
+
surfaces: ["api", "router"],
|
|
83
|
+
aliases: ["anthropic/claude-sonnet-5", "anthropic.claude-sonnet-5"],
|
|
84
|
+
defaultEffort: "high",
|
|
85
|
+
sources: [
|
|
86
|
+
{ url: `${claudeDocs}/models/overview`, checkedAt: CHECKED },
|
|
87
|
+
{
|
|
88
|
+
url: `${claudeDocs}/build-with-claude/prompt-engineering/prompting-claude-sonnet-5`,
|
|
89
|
+
checkedAt: CHECKED,
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
prompt: [
|
|
93
|
+
"Apply each instruction to every case it names; where an instruction should apply broadly, the prompt says so.",
|
|
94
|
+
"For review work, report every issue you find with a confidence and severity; a later step filters them.",
|
|
95
|
+
"Give regular, short progress updates through long agentic work.",
|
|
96
|
+
],
|
|
97
|
+
operator: [
|
|
98
|
+
"Model id claude-sonnet-5; 1M context, 128K max output.",
|
|
99
|
+
"Adaptive thinking is on by default. Effort defaults to high; use xhigh for the hardest coding and agentic tasks.",
|
|
100
|
+
"Instructions are followed literally, especially at low effort: state scope explicitly.",
|
|
101
|
+
"Give the task, intent, and constraints up front in the first turn.",
|
|
102
|
+
"Temperature, top_p, and top_k stay at defaults; steer tone and variety in the prompt.",
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: "claude-haiku-4-5",
|
|
107
|
+
name: "Claude Haiku 4.5",
|
|
108
|
+
vendor: "Anthropic",
|
|
109
|
+
surfaces: ["api", "router"],
|
|
110
|
+
aliases: [
|
|
111
|
+
"claude-haiku-4-5-20251001",
|
|
112
|
+
"anthropic/claude-haiku-4-5",
|
|
113
|
+
"anthropic.claude-haiku-4-5",
|
|
114
|
+
],
|
|
115
|
+
sources: [
|
|
116
|
+
{ url: `${claudeDocs}/models/haiku-4-5/overview`, checkedAt: CHECKED },
|
|
117
|
+
],
|
|
118
|
+
prompt: [
|
|
119
|
+
"Answer directly and keep each step scoped to the task in hand.",
|
|
120
|
+
],
|
|
121
|
+
operator: [
|
|
122
|
+
"Model id claude-haiku-4-5-20251001 (alias claude-haiku-4-5); 200K context, 64K max output. The fastest model in the current lineup.",
|
|
123
|
+
"Uses manual extended thinking (thinking.type enabled with budget_tokens); it takes no effort parameter.",
|
|
124
|
+
"Retirement not sooner than 2026-10-15.",
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
id: "gpt-6-pro",
|
|
129
|
+
name: "GPT-6 Pro",
|
|
130
|
+
vendor: "OpenAI",
|
|
131
|
+
surfaces: ["chatgpt"],
|
|
132
|
+
aliases: ["GPT-6 Pro"],
|
|
133
|
+
sources: [
|
|
134
|
+
{
|
|
135
|
+
url: "https://help.openai.com/en/articles/20001354-gpt-56-and-gpt-6-pro-in-chatgpt",
|
|
136
|
+
checkedAt: CHECKED,
|
|
137
|
+
note: "read through search results; direct fetch returned HTTP 403",
|
|
138
|
+
},
|
|
139
|
+
{ url: "https://learn.chatgpt.com/docs/prompting", checkedAt: CHECKED },
|
|
140
|
+
],
|
|
141
|
+
prompt: [
|
|
142
|
+
"Start with the result you want, then give the goal, the context that helps, the output format, and what must stay unchanged.",
|
|
143
|
+
"Describe a process only when the process itself matters; otherwise leave room to search, compare, and adjust.",
|
|
144
|
+
"End with a final check: confirm each deliverable and flag anything you could not verify.",
|
|
145
|
+
],
|
|
146
|
+
operator: [
|
|
147
|
+
"A ChatGPT model mode powered by GPT-6 Astra, on Pro, Business, and Enterprise plans. It has a weekly usage limit.",
|
|
148
|
+
"No API model id; reach it through ChatGPT (chatgpt-fleet).",
|
|
149
|
+
],
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
id: "gpt-5.6-sol",
|
|
153
|
+
name: "GPT-5.6 Sol",
|
|
154
|
+
vendor: "OpenAI",
|
|
155
|
+
surfaces: ["codex", "api", "router"],
|
|
156
|
+
aliases: ["openai/gpt-5.6-sol"],
|
|
157
|
+
defaultEffort: "medium",
|
|
158
|
+
sources: [
|
|
159
|
+
{
|
|
160
|
+
url: "https://developers.openai.com/api/docs/models/gpt-5.6-sol",
|
|
161
|
+
checkedAt: CHECKED,
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
url: "https://openai.com/index/builders-guide-to-gpt-5-6/",
|
|
165
|
+
checkedAt: CHECKED,
|
|
166
|
+
note: "read through search results; direct fetch returned HTTP 403",
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
url: "file://~/.codex/models_cache.json",
|
|
170
|
+
checkedAt: CHECKED,
|
|
171
|
+
note: "codex-cli 0.152.1 served list; `codex exec -m gpt-5.6-sol` returned OK",
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
prompt: [
|
|
175
|
+
"Work from the outcome: know what good looks like and the stopping condition, then choose the method yourself.",
|
|
176
|
+
"Carry the task to completion: gather context, plan, implement, verify, and report the evidence.",
|
|
177
|
+
"Run independent reads and checks in parallel.",
|
|
178
|
+
],
|
|
179
|
+
operator: [
|
|
180
|
+
"Flagship GPT-5.6 tier for complex professional work: architecture, security review, repo-wide debugging.",
|
|
181
|
+
"Keep the system prompt lean: objective, context, hard constraints, approval boundaries, success criteria, required evidence, and output format.",
|
|
182
|
+
"Efforts: none, low, medium (API default), high, xhigh, max; Codex adds ultra, which runs parallel agents. Codex lists low as its default for this model.",
|
|
183
|
+
"1,050,000-token context, 128K max output.",
|
|
184
|
+
],
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
id: "gpt-5.6-terra",
|
|
188
|
+
name: "GPT-5.6 Terra",
|
|
189
|
+
vendor: "OpenAI",
|
|
190
|
+
surfaces: ["codex", "api", "router"],
|
|
191
|
+
aliases: ["openai/gpt-5.6-terra"],
|
|
192
|
+
defaultEffort: "medium",
|
|
193
|
+
sources: [
|
|
194
|
+
{
|
|
195
|
+
url: "https://developers.openai.com/api/docs/models/gpt-5.6-terra",
|
|
196
|
+
checkedAt: CHECKED,
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
url: "file://~/.codex/models_cache.json",
|
|
200
|
+
checkedAt: CHECKED,
|
|
201
|
+
note: "codex-cli 0.152.1 served list; `codex exec -m gpt-5.6-terra` returned OK",
|
|
202
|
+
},
|
|
203
|
+
],
|
|
204
|
+
prompt: [
|
|
205
|
+
"Work from the outcome and the stopping condition; choose the method yourself and verify before you report.",
|
|
206
|
+
],
|
|
207
|
+
operator: [
|
|
208
|
+
"Balanced GPT-5.6 tier for everyday professional coding.",
|
|
209
|
+
"Efforts: none, low, medium (default), high, xhigh, max; Codex adds ultra.",
|
|
210
|
+
"1,050,000-token context, 128K max output.",
|
|
211
|
+
],
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
id: "gpt-5.6-luna",
|
|
215
|
+
name: "GPT-5.6 Luna",
|
|
216
|
+
vendor: "OpenAI",
|
|
217
|
+
surfaces: ["codex", "api", "router"],
|
|
218
|
+
aliases: ["openai/gpt-5.6-luna"],
|
|
219
|
+
defaultEffort: "medium",
|
|
220
|
+
sources: [
|
|
221
|
+
{
|
|
222
|
+
url: "https://developers.openai.com/api/docs/models/gpt-5.6-luna",
|
|
223
|
+
checkedAt: CHECKED,
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
url: "file://~/.codex/models_cache.json",
|
|
227
|
+
checkedAt: CHECKED,
|
|
228
|
+
note: "codex-cli 0.152.1 served list; `codex exec -m gpt-5.6-luna` returned OK",
|
|
229
|
+
},
|
|
230
|
+
],
|
|
231
|
+
prompt: [
|
|
232
|
+
"Follow the stated format exactly and finish each item before moving to the next.",
|
|
233
|
+
],
|
|
234
|
+
operator: [
|
|
235
|
+
"GPT-5.6 tier for cost-sensitive, high-volume work: summarizing, labeling, extraction, scaffolds.",
|
|
236
|
+
"Efforts: none, low, medium (default), high, xhigh, max. Raise effort for harder items.",
|
|
237
|
+
"1,050,000-token context, 128K max output.",
|
|
238
|
+
],
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
id: "deepseek-v4.1-flash",
|
|
242
|
+
name: "DeepSeek V4.1 Flash",
|
|
243
|
+
vendor: "DeepSeek",
|
|
244
|
+
surfaces: ["api", "router"],
|
|
245
|
+
aliases: ["deepseek-flash", "deepseek/deepseek-v4.1-flash"],
|
|
246
|
+
sources: [
|
|
247
|
+
{
|
|
248
|
+
url: "https://api-docs.deepseek.com/news/news260910/",
|
|
249
|
+
checkedAt: CHECKED,
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
url: "https://api-docs.deepseek.com/quick_start/pricing",
|
|
253
|
+
checkedAt: CHECKED,
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
url: "https://router.tangle.tools/v1/chat/completions",
|
|
257
|
+
checkedAt: CHECKED,
|
|
258
|
+
note: "deepseek/deepseek-v4.1-flash returned HTTP 200 and served that id",
|
|
259
|
+
},
|
|
260
|
+
],
|
|
261
|
+
prompt: [
|
|
262
|
+
"State the goal and the finished result up front, and use the tools you are given to check your work.",
|
|
263
|
+
],
|
|
264
|
+
operator: [
|
|
265
|
+
"Vendor API id deepseek-flash (released 2026-09-10); on the Tangle router, deepseek/deepseek-v4.1-flash.",
|
|
266
|
+
"1M context, 384K max output; thinking mode is the default and non-thinking is available. Native vision.",
|
|
267
|
+
"OpenCode supports it as an official partner harness.",
|
|
268
|
+
],
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
id: "glm-5.3",
|
|
272
|
+
name: "GLM-5.3",
|
|
273
|
+
vendor: "Z.ai",
|
|
274
|
+
surfaces: ["api", "router"],
|
|
275
|
+
aliases: ["z-ai/glm-5.3", "zai-coding-plan/glm-5.3"],
|
|
276
|
+
defaultEffort: "ultracode",
|
|
277
|
+
sources: [
|
|
278
|
+
{ url: "https://docs.z.ai/guides/llm/glm-5.3", checkedAt: CHECKED },
|
|
279
|
+
{
|
|
280
|
+
url: "https://router.tangle.tools/v1/chat/completions",
|
|
281
|
+
checkedAt: CHECKED,
|
|
282
|
+
note: "glm-5.3 returned HTTP 200, served as z-ai/glm-5.3",
|
|
283
|
+
},
|
|
284
|
+
],
|
|
285
|
+
prompt: [
|
|
286
|
+
"Work the task through to a verified result, using the tools to run and check each change.",
|
|
287
|
+
],
|
|
288
|
+
operator: [
|
|
289
|
+
"Model id glm-5.3; text only; 1M context, 128K max output. Built for long-horizon software engineering.",
|
|
290
|
+
"Reasoning is always on: thinking.type enabled with reasoning_effort low, high, or max (default). Use max for coding.",
|
|
291
|
+
],
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
id: "kimi-k3",
|
|
295
|
+
name: "Kimi K3",
|
|
296
|
+
vendor: "Moonshot AI",
|
|
297
|
+
surfaces: ["api", "router"],
|
|
298
|
+
aliases: ["moonshotai/kimi-k3", "kimi-code/k3"],
|
|
299
|
+
defaultEffort: "ultracode",
|
|
300
|
+
sources: [
|
|
301
|
+
{
|
|
302
|
+
url: "https://platform.kimi.ai/docs/guide/kimi-k3-quickstart",
|
|
303
|
+
checkedAt: CHECKED,
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
url: "https://router.tangle.tools/v1/chat/completions",
|
|
307
|
+
checkedAt: CHECKED,
|
|
308
|
+
note: "kimi-k3 returned HTTP 200, served as moonshotai/kimi-k3",
|
|
309
|
+
},
|
|
310
|
+
],
|
|
311
|
+
prompt: [
|
|
312
|
+
"Navigate the repository, run the code, and iterate against tests, logs, and runtime output until the result holds.",
|
|
313
|
+
],
|
|
314
|
+
operator: [
|
|
315
|
+
"Model id kimi-k3; 1M context; native vision. For long-horizon coding, knowledge work, and reasoning.",
|
|
316
|
+
"Thinking is always on: reasoning_effort low, high, or max (default).",
|
|
317
|
+
"Sampling is fixed (temperature 1.0, top_p 0.95); omit sampling parameters.",
|
|
318
|
+
"Return the complete assistant message unchanged in multi-turn and tool-call histories.",
|
|
319
|
+
],
|
|
320
|
+
},
|
|
321
|
+
];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ProfileKbDiscrepancy, ProfileKbLearning } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Lessons this platform measured itself. A lesson enters only after an
|
|
4
|
+
* agent-eval check reproduced it strongly; none has met that bar yet, so the
|
|
5
|
+
* list is empty rather than filled with single-run observations.
|
|
6
|
+
*/
|
|
7
|
+
export declare const profileKbLearnings: readonly ProfileKbLearning[];
|
|
8
|
+
/**
|
|
9
|
+
* Names the platform asked for that vendor sources state differently, as read
|
|
10
|
+
* on 2026-09-22. Recorded instead of guessed.
|
|
11
|
+
*/
|
|
12
|
+
export declare const profileKbDiscrepancies: readonly ProfileKbDiscrepancy[];
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const CHECKED = "2026-09-22";
|
|
2
|
+
/**
|
|
3
|
+
* Lessons this platform measured itself. A lesson enters only after an
|
|
4
|
+
* agent-eval check reproduced it strongly; none has met that bar yet, so the
|
|
5
|
+
* list is empty rather than filled with single-run observations.
|
|
6
|
+
*/
|
|
7
|
+
export const profileKbLearnings = [];
|
|
8
|
+
/**
|
|
9
|
+
* Names the platform asked for that vendor sources state differently, as read
|
|
10
|
+
* on 2026-09-22. Recorded instead of guessed.
|
|
11
|
+
*/
|
|
12
|
+
export const profileKbDiscrepancies = [
|
|
13
|
+
{
|
|
14
|
+
subject: "OpenAI Codex models",
|
|
15
|
+
requested: "gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna as the current Codex models",
|
|
16
|
+
observed: "OpenAI's Codex model page lists GPT-6 Astra, GPT-6 Sol, and GPT-6 Luna as the current recommended models. " +
|
|
17
|
+
"On this box, codex-cli 0.152.1 on a ChatGPT account serves gpt-5.6-sol, gpt-5.6-terra, and gpt-5.6-luna (each returned OK) " +
|
|
18
|
+
"and labels them 'Older'; gpt-6-sol and gpt-6-luna return 'not supported when using Codex with a ChatGPT account', " +
|
|
19
|
+
"and gpt-6-astra returns 'requires a newer version of Codex'. The knowledge base keeps the gpt-5.6 tiers because they are what this box can run.",
|
|
20
|
+
sources: [
|
|
21
|
+
{ url: "https://learn.chatgpt.com/docs/models", checkedAt: CHECKED },
|
|
22
|
+
{
|
|
23
|
+
url: "cli:codex exec -m <model> 'Reply with exactly: OK'",
|
|
24
|
+
checkedAt: CHECKED,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
subject: "DeepSeek V4.1 Pro",
|
|
30
|
+
requested: "DeepSeek V4.1 Pro",
|
|
31
|
+
observed: "DeepSeek has released V4.1 Flash only (2026-09-10). Its changelog says the V4 Pro API continues, its pricing page maps " +
|
|
32
|
+
"deepseek-v4-pro to DeepSeek-V4-Pro-0813, and its V4.1 Flash announcement says deepseek-v4-pro routes to V4.1 Flash from 2026-09-14. " +
|
|
33
|
+
"On the Tangle router, deepseek-v4-pro returned HTTP 503 (provider quota exhausted). No V4.1 Pro entry exists until DeepSeek ships it.",
|
|
34
|
+
sources: [
|
|
35
|
+
{ url: "https://api-docs.deepseek.com/updates/", checkedAt: CHECKED },
|
|
36
|
+
{ url: "https://api-docs.deepseek.com/quick_start/pricing", checkedAt: CHECKED },
|
|
37
|
+
{ url: "https://api-docs.deepseek.com/news/news260910/", checkedAt: CHECKED },
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
subject: "DeepSeek V4.1 Flash router id",
|
|
42
|
+
requested: "deepseek-flash (the vendor id)",
|
|
43
|
+
observed: "On the Tangle router, deepseek-flash returned HTTP 503 (provider_pricing_unavailable); deepseek/deepseek-v4.1-flash returned HTTP 200.",
|
|
44
|
+
sources: [
|
|
45
|
+
{
|
|
46
|
+
url: "https://router.tangle.tools/v1/chat/completions",
|
|
47
|
+
checkedAt: CHECKED,
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
subject: "GPT-6 Pro",
|
|
53
|
+
requested: "GPT-6 Pro in ChatGPT",
|
|
54
|
+
observed: "OpenAI's help center names GPT-6 Pro as a ChatGPT mode powered by GPT-6 Astra; it has no API model id.",
|
|
55
|
+
sources: [
|
|
56
|
+
{
|
|
57
|
+
url: "https://help.openai.com/en/articles/20001354-gpt-56-and-gpt-6-pro-in-chatgpt",
|
|
58
|
+
checkedAt: CHECKED,
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
];
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { HarnessType } from "../harness.js";
|
|
2
|
+
import type { ReasoningEffort } from "../agent-profile.js";
|
|
3
|
+
/** A vendor or measured source, with the date someone read or ran it. */
|
|
4
|
+
export interface ProfileKbSource {
|
|
5
|
+
url: string;
|
|
6
|
+
/** ISO date (YYYY-MM-DD) the source was read or the command was run. */
|
|
7
|
+
checkedAt: string;
|
|
8
|
+
/** What the source is, when the URL alone does not say. */
|
|
9
|
+
note?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* How to get the best from one harness.
|
|
13
|
+
*
|
|
14
|
+
* `prompt` lines are addressed to the agent running inside the harness and
|
|
15
|
+
* are composed into its profile. `operator` lines are for whoever launches
|
|
16
|
+
* the harness; they are never sent to a model.
|
|
17
|
+
*/
|
|
18
|
+
export interface ProfileKbHarness {
|
|
19
|
+
id: HarnessType;
|
|
20
|
+
name: string;
|
|
21
|
+
/** Installed version the guidance was checked against. */
|
|
22
|
+
version: string;
|
|
23
|
+
sources: ProfileKbSource[];
|
|
24
|
+
prompt: string[];
|
|
25
|
+
operator: string[];
|
|
26
|
+
}
|
|
27
|
+
/** Where a model is reached. A model id means different things on each surface. */
|
|
28
|
+
export type ProfileKbSurface = "api" | "codex" | "chatgpt" | "router";
|
|
29
|
+
/**
|
|
30
|
+
* How to get the best from one model.
|
|
31
|
+
*
|
|
32
|
+
* Vendor guidance only, each entry citing its source and date. The guidance is
|
|
33
|
+
* positive and specific to this model; it never ranks the model against
|
|
34
|
+
* another.
|
|
35
|
+
*/
|
|
36
|
+
export interface ProfileKbModel {
|
|
37
|
+
/** Canonical vendor id. */
|
|
38
|
+
id: string;
|
|
39
|
+
name: string;
|
|
40
|
+
vendor: string;
|
|
41
|
+
surfaces: ProfileKbSurface[];
|
|
42
|
+
/** Other spellings that resolve to this model: router ids, harness aliases. */
|
|
43
|
+
aliases: string[];
|
|
44
|
+
/** Vendor default reasoning effort, mapped onto the portable scale. */
|
|
45
|
+
defaultEffort?: ReasoningEffort;
|
|
46
|
+
sources: ProfileKbSource[];
|
|
47
|
+
prompt: string[];
|
|
48
|
+
operator: string[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* A lesson this platform learned itself. It enters the knowledge base only
|
|
52
|
+
* after an agent-eval check reproduced it, and it stays scoped to the
|
|
53
|
+
* harness or model it was measured on.
|
|
54
|
+
*/
|
|
55
|
+
export interface ProfileKbLearning {
|
|
56
|
+
id: string;
|
|
57
|
+
appliesTo: {
|
|
58
|
+
harness?: HarnessType;
|
|
59
|
+
model?: string;
|
|
60
|
+
};
|
|
61
|
+
text: string;
|
|
62
|
+
evidence: {
|
|
63
|
+
/** The agent-eval check that reproduced the lesson. */
|
|
64
|
+
check: string;
|
|
65
|
+
/** Independent reproductions that passed. */
|
|
66
|
+
reproductions: number;
|
|
67
|
+
source: ProfileKbSource;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** A name the platform asked for that a vendor source does not confirm as stated. */
|
|
71
|
+
export interface ProfileKbDiscrepancy {
|
|
72
|
+
subject: string;
|
|
73
|
+
requested: string;
|
|
74
|
+
observed: string;
|
|
75
|
+
sources: ProfileKbSource[];
|
|
76
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/profile-schema.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { type AgentProfile, type AgentProfileMcpServer } from "./agent-profile.js";
|
|
2
|
+
import { type AgentProfile, type AgentProfileMetadata, type AgentTrainingTask, type AgentProfileMcpServer } from "./agent-profile.js";
|
|
3
3
|
import type { AgentProfileDiff } from "./profile-diff.js";
|
|
4
4
|
import { type SandboxSizePreset } from "./sandbox-size.js";
|
|
5
5
|
export declare const agentProfilePermissionValueSchema: z.ZodEnum<{
|
|
@@ -326,6 +326,116 @@ export declare const agentProfileDiffRemovalSchema: z.ZodObject<{
|
|
|
326
326
|
metadata: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodArray<z.ZodString>]>>;
|
|
327
327
|
extensions: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodArray<z.ZodString>]>>;
|
|
328
328
|
}, z.core.$strict>;
|
|
329
|
+
export declare const agentTrainingTaskSchema: z.ZodObject<{
|
|
330
|
+
benchmark: z.ZodString;
|
|
331
|
+
task: z.ZodString;
|
|
332
|
+
contentDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
333
|
+
}, z.core.$strict>;
|
|
334
|
+
/** The same order is used by dataset ingestion, receipt admission and holdout checks. */
|
|
335
|
+
export declare function agentTrainingTaskKey(task: AgentTrainingTask): string;
|
|
336
|
+
export declare const agentTrainingDatasetIdentitySchema: z.ZodObject<{
|
|
337
|
+
digest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
338
|
+
taskSetDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
339
|
+
tasks: z.ZodArray<z.ZodObject<{
|
|
340
|
+
benchmark: z.ZodString;
|
|
341
|
+
task: z.ZodString;
|
|
342
|
+
contentDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
343
|
+
}, z.core.$strict>>;
|
|
344
|
+
}, z.core.$strict>;
|
|
345
|
+
export declare const agentTrainingParametersSchema: z.ZodType<Record<string, string | number | boolean | null>, unknown, z.core.$ZodTypeInternals<Record<string, string | number | boolean | null>, unknown>>;
|
|
346
|
+
export declare const agentTrainingReceiptSchema: z.ZodObject<{
|
|
347
|
+
version: z.ZodLiteral<1>;
|
|
348
|
+
dataset: z.ZodObject<{
|
|
349
|
+
digest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
350
|
+
taskSetDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
351
|
+
tasks: z.ZodArray<z.ZodObject<{
|
|
352
|
+
benchmark: z.ZodString;
|
|
353
|
+
task: z.ZodString;
|
|
354
|
+
contentDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
355
|
+
}, z.core.$strict>>;
|
|
356
|
+
}, z.core.$strict>;
|
|
357
|
+
parentProfileDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
358
|
+
parentReceiptDigest: z.ZodNullable<z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>>;
|
|
359
|
+
executionRef: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
360
|
+
trainer: z.ZodObject<{
|
|
361
|
+
mode: z.ZodEnum<{
|
|
362
|
+
command: "command";
|
|
363
|
+
managed: "managed";
|
|
364
|
+
}>;
|
|
365
|
+
id: z.ZodString;
|
|
366
|
+
revision: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
367
|
+
parameters: z.ZodType<Record<string, string | number | boolean | null>, unknown, z.core.$ZodTypeInternals<Record<string, string | number | boolean | null>, unknown>>;
|
|
368
|
+
}, z.core.$strict>;
|
|
369
|
+
checkpoint: z.ZodObject<{
|
|
370
|
+
artifactDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
371
|
+
artifactBytes: z.ZodNumber;
|
|
372
|
+
routerModelId: z.ZodString;
|
|
373
|
+
servingDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
374
|
+
}, z.core.$strict>;
|
|
375
|
+
}, z.core.$strict>;
|
|
376
|
+
export declare const agentProfileTrainingSchema: z.ZodObject<{
|
|
377
|
+
receipt: z.ZodObject<{
|
|
378
|
+
version: z.ZodLiteral<1>;
|
|
379
|
+
dataset: z.ZodObject<{
|
|
380
|
+
digest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
381
|
+
taskSetDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
382
|
+
tasks: z.ZodArray<z.ZodObject<{
|
|
383
|
+
benchmark: z.ZodString;
|
|
384
|
+
task: z.ZodString;
|
|
385
|
+
contentDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
386
|
+
}, z.core.$strict>>;
|
|
387
|
+
}, z.core.$strict>;
|
|
388
|
+
parentProfileDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
389
|
+
parentReceiptDigest: z.ZodNullable<z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>>;
|
|
390
|
+
executionRef: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
391
|
+
trainer: z.ZodObject<{
|
|
392
|
+
mode: z.ZodEnum<{
|
|
393
|
+
command: "command";
|
|
394
|
+
managed: "managed";
|
|
395
|
+
}>;
|
|
396
|
+
id: z.ZodString;
|
|
397
|
+
revision: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
398
|
+
parameters: z.ZodType<Record<string, string | number | boolean | null>, unknown, z.core.$ZodTypeInternals<Record<string, string | number | boolean | null>, unknown>>;
|
|
399
|
+
}, z.core.$strict>;
|
|
400
|
+
checkpoint: z.ZodObject<{
|
|
401
|
+
artifactDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
402
|
+
artifactBytes: z.ZodNumber;
|
|
403
|
+
routerModelId: z.ZodString;
|
|
404
|
+
servingDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
405
|
+
}, z.core.$strict>;
|
|
406
|
+
}, z.core.$strict>;
|
|
407
|
+
ancestors: z.ZodArray<z.ZodObject<{
|
|
408
|
+
version: z.ZodLiteral<1>;
|
|
409
|
+
dataset: z.ZodObject<{
|
|
410
|
+
digest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
411
|
+
taskSetDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
412
|
+
tasks: z.ZodArray<z.ZodObject<{
|
|
413
|
+
benchmark: z.ZodString;
|
|
414
|
+
task: z.ZodString;
|
|
415
|
+
contentDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
416
|
+
}, z.core.$strict>>;
|
|
417
|
+
}, z.core.$strict>;
|
|
418
|
+
parentProfileDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
419
|
+
parentReceiptDigest: z.ZodNullable<z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>>;
|
|
420
|
+
executionRef: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
421
|
+
trainer: z.ZodObject<{
|
|
422
|
+
mode: z.ZodEnum<{
|
|
423
|
+
command: "command";
|
|
424
|
+
managed: "managed";
|
|
425
|
+
}>;
|
|
426
|
+
id: z.ZodString;
|
|
427
|
+
revision: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
428
|
+
parameters: z.ZodType<Record<string, string | number | boolean | null>, unknown, z.core.$ZodTypeInternals<Record<string, string | number | boolean | null>, unknown>>;
|
|
429
|
+
}, z.core.$strict>;
|
|
430
|
+
checkpoint: z.ZodObject<{
|
|
431
|
+
artifactDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
432
|
+
artifactBytes: z.ZodNumber;
|
|
433
|
+
routerModelId: z.ZodString;
|
|
434
|
+
servingDigest: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
435
|
+
}, z.core.$strict>;
|
|
436
|
+
}, z.core.$strict>>;
|
|
437
|
+
}, z.core.$strict>;
|
|
438
|
+
export declare const agentProfileMetadataSchema: z.ZodType<AgentProfileMetadata>;
|
|
329
439
|
/**
|
|
330
440
|
* The complete provider-neutral agent profile schema — the runtime validator for
|
|
331
441
|
* the canonical {@link AgentProfile} TS contract. Kept structurally in lock-step
|
|
@@ -523,7 +633,7 @@ export declare const agentProfileSchema: z.ZodObject<{
|
|
|
523
633
|
sealed: z.ZodOptional<z.ZodBoolean>;
|
|
524
634
|
attestationRefresh: z.ZodOptional<z.ZodBoolean>;
|
|
525
635
|
}, z.core.$strict>>;
|
|
526
|
-
metadata: z.ZodOptional<z.ZodType<
|
|
636
|
+
metadata: z.ZodOptional<z.ZodType<AgentProfileMetadata, unknown, z.core.$ZodTypeInternals<AgentProfileMetadata, unknown>>>;
|
|
527
637
|
extensions: z.ZodOptional<z.ZodType<Record<string, Record<string, unknown> | undefined>, unknown, z.core.$ZodTypeInternals<Record<string, Record<string, unknown> | undefined>, unknown>>>;
|
|
528
638
|
}, z.core.$strict>;
|
|
529
639
|
/**
|
package/dist/profile-schema.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { REASONING_EFFORTS, } from "./agent-profile.js";
|
|
3
|
-
import { environmentNameSchema, headerNameSchema, isSafeExecutable, isSafeRelativePath, isWellFormedUnicode, looksLikeCredential, } from "./agent-candidate-schema-common.js";
|
|
2
|
+
import { REASONING_EFFORTS, TRAINED_MODEL_PREFIX, trainedModelIdForArtifact, } from "./agent-profile.js";
|
|
3
|
+
import { canonicalCandidateDigest, sha256DigestSchema, environmentNameSchema, headerNameSchema, isSafeExecutable, isSafeRelativePath, isWellFormedUnicode, looksLikeCredential, } from "./agent-candidate-schema-common.js";
|
|
4
4
|
import { harnessTypeSchema } from "./harness.js";
|
|
5
5
|
import { SANDBOX_SIZE_PRESET_NAMES, } from "./sandbox-size.js";
|
|
6
6
|
/**
|
|
@@ -322,6 +322,88 @@ export const agentProfileDiffRemovalSchema = z.strictObject({
|
|
|
322
322
|
metadata: removeListSchema.optional(),
|
|
323
323
|
extensions: removeListSchema.optional(),
|
|
324
324
|
});
|
|
325
|
+
const trainingIdentitySchema = z.string().min(1).max(500).refine((value) => value.trim() === value && isWellFormedUnicode(value) &&
|
|
326
|
+
!controlCharacterPattern.test(value) && !looksLikeCredential(value), "training identity must be canonical public text");
|
|
327
|
+
export const agentTrainingTaskSchema = z.strictObject({
|
|
328
|
+
benchmark: trainingIdentitySchema,
|
|
329
|
+
task: trainingIdentitySchema,
|
|
330
|
+
contentDigest: sha256DigestSchema,
|
|
331
|
+
});
|
|
332
|
+
/** The same order is used by dataset ingestion, receipt admission and holdout checks. */
|
|
333
|
+
export function agentTrainingTaskKey(task) {
|
|
334
|
+
return JSON.stringify([task.benchmark, task.task, task.contentDigest]);
|
|
335
|
+
}
|
|
336
|
+
export const agentTrainingDatasetIdentitySchema = z.strictObject({
|
|
337
|
+
digest: sha256DigestSchema,
|
|
338
|
+
taskSetDigest: sha256DigestSchema,
|
|
339
|
+
tasks: z.array(agentTrainingTaskSchema).min(1).max(10_000),
|
|
340
|
+
}).superRefine((dataset, context) => {
|
|
341
|
+
const keys = dataset.tasks.map(agentTrainingTaskKey);
|
|
342
|
+
if (keys.some((key, index) => index > 0 && key <= keys[index - 1])) {
|
|
343
|
+
context.addIssue({ code: "custom", path: ["tasks"], message: "training tasks must be sorted and unique" });
|
|
344
|
+
}
|
|
345
|
+
if (canonicalCandidateDigest(dataset.tasks) !== dataset.taskSetDigest) {
|
|
346
|
+
context.addIssue({ code: "custom", path: ["taskSetDigest"], message: "training task inventory digest mismatch" });
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
export const agentTrainingParametersSchema = ownPropertyRecordSchema(z.union([z.string().max(2_048).pipe(publicProfileConfigStringSchema), z.number().finite(), z.boolean(), z.null()])).superRefine((parameters, context) => {
|
|
350
|
+
if (Object.keys(parameters).length > 100) {
|
|
351
|
+
context.addIssue({ code: "custom", message: "at most 100 public training parameters are allowed" });
|
|
352
|
+
}
|
|
353
|
+
for (const name of Object.keys(parameters)) {
|
|
354
|
+
if (!trainingIdentitySchema.safeParse(name).success || isCredentialBearingProfileConfigName(name)) {
|
|
355
|
+
context.addIssue({ code: "custom", path: [name], message: "training parameter name must be public and non-credential" });
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
export const agentTrainingReceiptSchema = z.strictObject({
|
|
360
|
+
version: z.literal(1),
|
|
361
|
+
dataset: agentTrainingDatasetIdentitySchema,
|
|
362
|
+
parentProfileDigest: sha256DigestSchema,
|
|
363
|
+
parentReceiptDigest: sha256DigestSchema.nullable(),
|
|
364
|
+
executionRef: sha256DigestSchema,
|
|
365
|
+
trainer: z.strictObject({
|
|
366
|
+
mode: z.enum(["command", "managed"]),
|
|
367
|
+
id: trainingIdentitySchema,
|
|
368
|
+
revision: sha256DigestSchema,
|
|
369
|
+
parameters: agentTrainingParametersSchema,
|
|
370
|
+
}),
|
|
371
|
+
checkpoint: z.strictObject({
|
|
372
|
+
artifactDigest: sha256DigestSchema,
|
|
373
|
+
artifactBytes: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
374
|
+
routerModelId: trainingIdentitySchema,
|
|
375
|
+
servingDigest: sha256DigestSchema,
|
|
376
|
+
}),
|
|
377
|
+
}).superRefine((receipt, context) => {
|
|
378
|
+
if (receipt.checkpoint.routerModelId !== trainedModelIdForArtifact(receipt.checkpoint.artifactDigest)) {
|
|
379
|
+
context.addIssue({ code: "custom", path: ["checkpoint", "routerModelId"], message: "trained Router model must be artifact-addressed" });
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
export const agentProfileTrainingSchema = z.strictObject({
|
|
383
|
+
receipt: agentTrainingReceiptSchema,
|
|
384
|
+
ancestors: z.array(agentTrainingReceiptSchema).max(8),
|
|
385
|
+
}).superRefine((training, context) => {
|
|
386
|
+
const chain = [training.receipt, ...training.ancestors];
|
|
387
|
+
const digests = chain.map(canonicalCandidateDigest);
|
|
388
|
+
if (new Set(digests).size !== digests.length) {
|
|
389
|
+
context.addIssue({ code: "custom", message: "training receipt ancestry must not repeat" });
|
|
390
|
+
}
|
|
391
|
+
for (let index = 0; index < chain.length; index++) {
|
|
392
|
+
if (chain[index].parentReceiptDigest !== (digests[index + 1] ?? null)) {
|
|
393
|
+
context.addIssue({ code: "custom", message: "training receipt ancestry is incomplete or has been altered" });
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
export const agentProfileMetadataSchema = ownPropertyRecordSchema(z.unknown()).superRefine((metadata, context) => {
|
|
398
|
+
if (!Object.hasOwn(metadata, "training"))
|
|
399
|
+
return;
|
|
400
|
+
const result = agentProfileTrainingSchema.safeParse(metadata.training);
|
|
401
|
+
if (!result.success) {
|
|
402
|
+
for (const issue of result.error.issues) {
|
|
403
|
+
context.addIssue({ code: "custom", path: ["training", ...issue.path], message: issue.message });
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
});
|
|
325
407
|
/**
|
|
326
408
|
* The complete provider-neutral agent profile schema — the runtime validator for
|
|
327
409
|
* the canonical {@link AgentProfile} TS contract. Kept structurally in lock-step
|
|
@@ -345,11 +427,27 @@ export const agentProfileSchema = z
|
|
|
345
427
|
hooks: ownPropertyRecordSchema(z.array(agentProfileHookCommandSchema)).optional(),
|
|
346
428
|
modes: ownPropertyRecordSchema(agentProfileModeSchema).optional(),
|
|
347
429
|
confidential: agentProfileConfidentialSchema.optional(),
|
|
348
|
-
metadata:
|
|
430
|
+
metadata: agentProfileMetadataSchema.optional(),
|
|
349
431
|
extensions: ownPropertyRecordSchema(z.union([ownPropertyRecordSchema(z.unknown()), z.undefined()])).optional(),
|
|
350
432
|
})
|
|
351
433
|
.superRefine((profile, context) => {
|
|
352
434
|
validateNestedRecordKeys(profile, context, [], new Set());
|
|
435
|
+
const training = agentProfileTrainingSchema.safeParse(profile.metadata?.training);
|
|
436
|
+
if (profile.model?.default?.startsWith(TRAINED_MODEL_PREFIX) && !training.success) {
|
|
437
|
+
context.addIssue({ code: "custom", path: ["metadata", "training"], message: "trained model requires a checkpoint receipt" });
|
|
438
|
+
}
|
|
439
|
+
const auxiliaryModels = [
|
|
440
|
+
profile.model?.small,
|
|
441
|
+
...Object.values(profile.subagents ?? {}).map((agent) => agent.model),
|
|
442
|
+
...Object.values(profile.modes ?? {}).map((mode) => mode.model),
|
|
443
|
+
];
|
|
444
|
+
if (auxiliaryModels.some((model) => model?.startsWith(TRAINED_MODEL_PREFIX) &&
|
|
445
|
+
(!training.success || model !== training.data.receipt.checkpoint.routerModelId))) {
|
|
446
|
+
context.addIssue({ code: "custom", message: "trained auxiliary models require the same receipted checkpoint" });
|
|
447
|
+
}
|
|
448
|
+
if (training.success && profile.model?.default !== training.data.receipt.checkpoint.routerModelId) {
|
|
449
|
+
context.addIssue({ code: "custom", path: ["model", "default"], message: "trained profile model must equal the receipt's Router model" });
|
|
450
|
+
}
|
|
353
451
|
});
|
|
354
452
|
const encodedRecordKeyPattern = "^u(?:[0-9a-f]{4})*$";
|
|
355
453
|
function isEncodedRecordKeyPropertyNames(value) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-interface",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"license": "MIT",
|
|
@@ -66,6 +66,11 @@
|
|
|
66
66
|
"import": "./dist/interaction.js",
|
|
67
67
|
"types": "./dist/interaction.d.ts",
|
|
68
68
|
"default": "./dist/interaction.js"
|
|
69
|
+
},
|
|
70
|
+
"./profile-kb": {
|
|
71
|
+
"import": "./dist/profile-kb/index.js",
|
|
72
|
+
"types": "./dist/profile-kb/index.d.ts",
|
|
73
|
+
"default": "./dist/profile-kb/index.js"
|
|
69
74
|
}
|
|
70
75
|
},
|
|
71
76
|
"repository": {
|