@tangle-network/agent-interface 0.32.0 → 0.34.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/agent-candidate-code-schema.d.ts +0 -3
- package/dist/agent-candidate-execution-plan-schema.d.ts +11 -17
- package/dist/agent-candidate-lineage-schema.d.ts +2 -2
- package/dist/agent-candidate-outcome-schema.d.ts +4 -4
- package/dist/agent-candidate-profile-schema.d.ts +0 -3
- package/dist/agent-candidate-promotion-schema.d.ts +1411 -885
- package/dist/agent-candidate-promotion-schema.js +46 -346
- package/dist/agent-candidate-receipt-schema.d.ts +8 -11
- package/dist/agent-candidate-schema.d.ts +0 -6
- package/dist/agent-candidate-schema.js +1 -3
- package/dist/agent-candidate.d.ts +14 -7
- package/dist/agent-improvement-measurement-schema.d.ts +198 -0
- package/dist/agent-improvement-measurement-schema.js +349 -0
- package/dist/agent-improvement-source.d.ts +23 -0
- package/dist/agent-improvement-source.js +38 -0
- package/dist/agent-profile-improvement-schema.d.ts +1085 -0
- package/dist/agent-profile-improvement-schema.js +553 -0
- package/dist/agent-profile-improvement.d.ts +139 -0
- package/dist/agent-profile-improvement.js +1 -0
- package/dist/agent-profile.d.ts +2 -2
- package/dist/agent-profile.js +2 -2
- package/dist/certified-context.d.ts +118 -0
- package/dist/certified-context.js +228 -0
- package/dist/harness-capabilities.d.ts +1 -1
- package/dist/harness-capabilities.js +9 -12
- package/dist/harness.d.ts +1 -10
- package/dist/harness.js +0 -13
- package/dist/index.d.ts +6 -1
- package/dist/index.js +5 -0
- package/dist/interaction.d.ts +0 -17
- package/dist/interaction.js +0 -23
- package/dist/number-validation.d.ts +1 -0
- package/dist/number-validation.js +4 -0
- package/dist/profile-schema.d.ts +0 -3
- package/package.json +1 -1
package/dist/agent-profile.d.ts
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* These model portable agent intent at the application boundary. Individual
|
|
5
5
|
* backends translate this shape into their own native profile/configuration
|
|
6
|
-
* formats internally. This is the canonical home
|
|
7
|
-
*
|
|
6
|
+
* formats internally. This package is the canonical public home for these
|
|
7
|
+
* symbols.
|
|
8
8
|
*/
|
|
9
9
|
import type { HarnessType } from "./harness.js";
|
|
10
10
|
/**
|
package/dist/agent-profile.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* These model portable agent intent at the application boundary. Individual
|
|
5
5
|
* backends translate this shape into their own native profile/configuration
|
|
6
|
-
* formats internally. This is the canonical home
|
|
7
|
-
*
|
|
6
|
+
* formats internally. This package is the canonical public home for these
|
|
7
|
+
* symbols.
|
|
8
8
|
*/
|
|
9
9
|
/**
|
|
10
10
|
* Helper for creating typed inline resource refs.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { Sha256Digest } from "./agent-candidate.js";
|
|
3
|
+
export type CertifiedContextKind = "prompt" | "skill" | "instructions";
|
|
4
|
+
export type CertifiedContextDelivery = {
|
|
5
|
+
readonly kind: "inline";
|
|
6
|
+
readonly content: string;
|
|
7
|
+
} | {
|
|
8
|
+
readonly kind: "file";
|
|
9
|
+
readonly path: string;
|
|
10
|
+
readonly content: string;
|
|
11
|
+
};
|
|
12
|
+
export interface CertifiedContextProvenance {
|
|
13
|
+
/** SHA-256 of the entry id, kind, name, and delivery. */
|
|
14
|
+
readonly contentHash: Sha256Digest;
|
|
15
|
+
/** Positive release number, or null when the source has no released version. */
|
|
16
|
+
readonly version: number | null;
|
|
17
|
+
readonly promotedAt: string;
|
|
18
|
+
}
|
|
19
|
+
export interface CertifiedContextEntry {
|
|
20
|
+
readonly id: string;
|
|
21
|
+
readonly kind: CertifiedContextKind;
|
|
22
|
+
readonly name: string;
|
|
23
|
+
readonly delivery: CertifiedContextDelivery;
|
|
24
|
+
readonly provenance: CertifiedContextProvenance;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Tenant-bound context delivered by Intelligence.
|
|
28
|
+
*
|
|
29
|
+
* This contract intentionally excludes tools, credentials, executable files,
|
|
30
|
+
* profile patches, MCP servers, and arbitrary network requests.
|
|
31
|
+
*/
|
|
32
|
+
export interface CertifiedContext {
|
|
33
|
+
readonly tenantId: string;
|
|
34
|
+
readonly target: string;
|
|
35
|
+
readonly state: "active" | "revoked";
|
|
36
|
+
/** Monotonic decimal revision for this tenant and target. */
|
|
37
|
+
readonly revision: string;
|
|
38
|
+
readonly generatedAt: string;
|
|
39
|
+
readonly expiresAt: string;
|
|
40
|
+
readonly entries: readonly CertifiedContextEntry[];
|
|
41
|
+
/** SHA-256 of tenantId, target, state, revision, and entries. */
|
|
42
|
+
readonly contentHash: Sha256Digest;
|
|
43
|
+
}
|
|
44
|
+
export declare const certifiedContextDeliverySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
45
|
+
kind: z.ZodLiteral<"inline">;
|
|
46
|
+
content: z.ZodString;
|
|
47
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
48
|
+
kind: z.ZodLiteral<"file">;
|
|
49
|
+
path: z.ZodString;
|
|
50
|
+
content: z.ZodString;
|
|
51
|
+
}, z.core.$strict>], "kind">;
|
|
52
|
+
export declare const certifiedContextProvenanceSchema: z.ZodObject<{
|
|
53
|
+
contentHash: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
54
|
+
version: z.ZodNullable<z.ZodNumber>;
|
|
55
|
+
promotedAt: z.ZodISODateTime;
|
|
56
|
+
}, z.core.$strict>;
|
|
57
|
+
/** Compute the exact digest stored in an entry's provenance. */
|
|
58
|
+
export declare function certifiedContextEntryContentHash(entry: Pick<CertifiedContextEntry, "id" | "kind" | "name" | "delivery">): Sha256Digest;
|
|
59
|
+
export declare const certifiedContextEntrySchema: z.ZodObject<{
|
|
60
|
+
id: z.ZodString;
|
|
61
|
+
kind: z.ZodEnum<{
|
|
62
|
+
prompt: "prompt";
|
|
63
|
+
instructions: "instructions";
|
|
64
|
+
skill: "skill";
|
|
65
|
+
}>;
|
|
66
|
+
name: z.ZodString;
|
|
67
|
+
delivery: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
68
|
+
kind: z.ZodLiteral<"inline">;
|
|
69
|
+
content: z.ZodString;
|
|
70
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
71
|
+
kind: z.ZodLiteral<"file">;
|
|
72
|
+
path: z.ZodString;
|
|
73
|
+
content: z.ZodString;
|
|
74
|
+
}, z.core.$strict>], "kind">;
|
|
75
|
+
provenance: z.ZodObject<{
|
|
76
|
+
contentHash: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
77
|
+
version: z.ZodNullable<z.ZodNumber>;
|
|
78
|
+
promotedAt: z.ZodISODateTime;
|
|
79
|
+
}, z.core.$strict>;
|
|
80
|
+
}, z.core.$strict>;
|
|
81
|
+
/** Compute the stable hash for one context revision. */
|
|
82
|
+
export declare function certifiedContextContentHash(context: Pick<CertifiedContext, "tenantId" | "target" | "state" | "revision" | "entries">): Sha256Digest;
|
|
83
|
+
export declare const certifiedContextSchema: z.ZodObject<{
|
|
84
|
+
tenantId: z.ZodString;
|
|
85
|
+
target: z.ZodString;
|
|
86
|
+
state: z.ZodEnum<{
|
|
87
|
+
active: "active";
|
|
88
|
+
revoked: "revoked";
|
|
89
|
+
}>;
|
|
90
|
+
revision: z.ZodString;
|
|
91
|
+
generatedAt: z.ZodISODateTime;
|
|
92
|
+
expiresAt: z.ZodISODateTime;
|
|
93
|
+
entries: z.ZodArray<z.ZodObject<{
|
|
94
|
+
id: z.ZodString;
|
|
95
|
+
kind: z.ZodEnum<{
|
|
96
|
+
prompt: "prompt";
|
|
97
|
+
instructions: "instructions";
|
|
98
|
+
skill: "skill";
|
|
99
|
+
}>;
|
|
100
|
+
name: z.ZodString;
|
|
101
|
+
delivery: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
102
|
+
kind: z.ZodLiteral<"inline">;
|
|
103
|
+
content: z.ZodString;
|
|
104
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
105
|
+
kind: z.ZodLiteral<"file">;
|
|
106
|
+
path: z.ZodString;
|
|
107
|
+
content: z.ZodString;
|
|
108
|
+
}, z.core.$strict>], "kind">;
|
|
109
|
+
provenance: z.ZodObject<{
|
|
110
|
+
contentHash: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
111
|
+
version: z.ZodNullable<z.ZodNumber>;
|
|
112
|
+
promotedAt: z.ZodISODateTime;
|
|
113
|
+
}, z.core.$strict>;
|
|
114
|
+
}, z.core.$strict>>;
|
|
115
|
+
contentHash: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
116
|
+
}, z.core.$strict>;
|
|
117
|
+
/** Parse, clone, and recursively freeze one untrusted context response. */
|
|
118
|
+
export declare function parseCertifiedContext(value: unknown): CertifiedContext;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { canonicalCandidateDigest, isSafeRelativePath, sha256DigestSchema, } from "./agent-candidate-schema-common.js";
|
|
3
|
+
const MAX_INLINE_CONTEXT_BYTES = 65_536;
|
|
4
|
+
const MAX_TOTAL_INLINE_CONTEXT_BYTES = 131_072;
|
|
5
|
+
const MAX_FILE_CONTEXT_BYTES = 1_048_576;
|
|
6
|
+
const MAX_CERTIFIED_CONTEXT_BYTES = 16_777_216;
|
|
7
|
+
const MAX_CERTIFIED_CONTEXT_LIFETIME_MS = 900_000;
|
|
8
|
+
const revisionPattern = /^(0|[1-9]\d{0,18})$/;
|
|
9
|
+
const nonBlankStringSchema = z
|
|
10
|
+
.string()
|
|
11
|
+
.refine((value) => value.trim().length > 0, "value cannot be blank");
|
|
12
|
+
const identifierSchema = nonBlankStringSchema.max(256);
|
|
13
|
+
const relativePathSchema = nonBlankStringSchema
|
|
14
|
+
.max(1_024)
|
|
15
|
+
.refine((value) => isSafeRelativePath(value, false), "value must be a canonical relative path");
|
|
16
|
+
const inlineContentSchema = z
|
|
17
|
+
.string()
|
|
18
|
+
.max(MAX_INLINE_CONTEXT_BYTES)
|
|
19
|
+
.refine((value) => new TextEncoder().encode(value).byteLength <= MAX_INLINE_CONTEXT_BYTES, `inline content exceeds ${MAX_INLINE_CONTEXT_BYTES} UTF-8 bytes`);
|
|
20
|
+
const fileContentSchema = z
|
|
21
|
+
.string()
|
|
22
|
+
.max(MAX_FILE_CONTEXT_BYTES)
|
|
23
|
+
.refine((value) => new TextEncoder().encode(value).byteLength <= MAX_FILE_CONTEXT_BYTES, `file content exceeds ${MAX_FILE_CONTEXT_BYTES} UTF-8 bytes`);
|
|
24
|
+
export const certifiedContextDeliverySchema = z.discriminatedUnion("kind", [
|
|
25
|
+
z.strictObject({
|
|
26
|
+
kind: z.literal("inline"),
|
|
27
|
+
content: inlineContentSchema,
|
|
28
|
+
}),
|
|
29
|
+
z.strictObject({
|
|
30
|
+
kind: z.literal("file"),
|
|
31
|
+
path: relativePathSchema,
|
|
32
|
+
content: fileContentSchema,
|
|
33
|
+
}),
|
|
34
|
+
]);
|
|
35
|
+
export const certifiedContextProvenanceSchema = z.strictObject({
|
|
36
|
+
contentHash: sha256DigestSchema,
|
|
37
|
+
version: z.number().int().positive().max(Number.MAX_SAFE_INTEGER).nullable(),
|
|
38
|
+
promotedAt: z.iso.datetime(),
|
|
39
|
+
});
|
|
40
|
+
function jsonMaterial(value) {
|
|
41
|
+
const serialized = JSON.stringify(value);
|
|
42
|
+
if (serialized === undefined) {
|
|
43
|
+
throw new Error("certified context material must be JSON serializable");
|
|
44
|
+
}
|
|
45
|
+
return JSON.parse(serialized);
|
|
46
|
+
}
|
|
47
|
+
/** Compute the exact digest stored in an entry's provenance. */
|
|
48
|
+
export function certifiedContextEntryContentHash(entry) {
|
|
49
|
+
return canonicalCandidateDigest(jsonMaterial({
|
|
50
|
+
id: entry.id,
|
|
51
|
+
kind: entry.kind,
|
|
52
|
+
name: entry.name,
|
|
53
|
+
delivery: entry.delivery,
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
export const certifiedContextEntrySchema = z
|
|
57
|
+
.strictObject({
|
|
58
|
+
id: identifierSchema,
|
|
59
|
+
kind: z.enum(["prompt", "skill", "instructions"]),
|
|
60
|
+
name: identifierSchema,
|
|
61
|
+
delivery: certifiedContextDeliverySchema,
|
|
62
|
+
provenance: certifiedContextProvenanceSchema,
|
|
63
|
+
})
|
|
64
|
+
.superRefine((entry, context) => {
|
|
65
|
+
if (entry.kind === "skill" && entry.delivery.kind !== "file") {
|
|
66
|
+
context.addIssue({
|
|
67
|
+
code: "custom",
|
|
68
|
+
path: ["delivery", "kind"],
|
|
69
|
+
message: "skills must be delivered as files",
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
if (entry.kind !== "skill" && entry.delivery.kind !== "inline") {
|
|
73
|
+
context.addIssue({
|
|
74
|
+
code: "custom",
|
|
75
|
+
path: ["delivery", "kind"],
|
|
76
|
+
message: "prompts and instructions must be delivered inline",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (entry.delivery.kind === "inline" &&
|
|
80
|
+
entry.delivery.content.trim().length === 0) {
|
|
81
|
+
context.addIssue({
|
|
82
|
+
code: "custom",
|
|
83
|
+
path: ["delivery", "content"],
|
|
84
|
+
message: "inline context cannot be blank",
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
if (entry.provenance.contentHash !== certifiedContextEntryContentHash(entry)) {
|
|
88
|
+
context.addIssue({
|
|
89
|
+
code: "custom",
|
|
90
|
+
path: ["provenance", "contentHash"],
|
|
91
|
+
message: "entry content hash does not match the delivered context",
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
/** Compute the stable hash for one context revision. */
|
|
96
|
+
export function certifiedContextContentHash(context) {
|
|
97
|
+
return canonicalCandidateDigest(jsonMaterial(context));
|
|
98
|
+
}
|
|
99
|
+
export const certifiedContextSchema = z
|
|
100
|
+
.strictObject({
|
|
101
|
+
tenantId: identifierSchema,
|
|
102
|
+
target: identifierSchema,
|
|
103
|
+
state: z.enum(["active", "revoked"]),
|
|
104
|
+
revision: z
|
|
105
|
+
.string()
|
|
106
|
+
.regex(revisionPattern)
|
|
107
|
+
.refine((value) => !revisionPattern.test(value) ||
|
|
108
|
+
BigInt(value) <= 9223372036854775807n, "revision exceeds signed 64-bit range"),
|
|
109
|
+
generatedAt: z.iso.datetime(),
|
|
110
|
+
expiresAt: z.iso.datetime(),
|
|
111
|
+
entries: z.array(certifiedContextEntrySchema).max(128),
|
|
112
|
+
contentHash: sha256DigestSchema,
|
|
113
|
+
})
|
|
114
|
+
.superRefine((context, refinement) => {
|
|
115
|
+
const generatedAt = Date.parse(context.generatedAt);
|
|
116
|
+
const expiresAt = Date.parse(context.expiresAt);
|
|
117
|
+
if (expiresAt <= generatedAt) {
|
|
118
|
+
refinement.addIssue({
|
|
119
|
+
code: "custom",
|
|
120
|
+
path: ["expiresAt"],
|
|
121
|
+
message: "expiresAt must be after generatedAt",
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
else if (expiresAt - generatedAt >
|
|
125
|
+
MAX_CERTIFIED_CONTEXT_LIFETIME_MS) {
|
|
126
|
+
refinement.addIssue({
|
|
127
|
+
code: "custom",
|
|
128
|
+
path: ["expiresAt"],
|
|
129
|
+
message: "certified context cannot live longer than 15 minutes",
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const serialized = JSON.stringify(context);
|
|
133
|
+
if (new TextEncoder().encode(serialized).byteLength >
|
|
134
|
+
MAX_CERTIFIED_CONTEXT_BYTES) {
|
|
135
|
+
refinement.addIssue({
|
|
136
|
+
code: "too_big",
|
|
137
|
+
maximum: MAX_CERTIFIED_CONTEXT_BYTES,
|
|
138
|
+
origin: "string",
|
|
139
|
+
inclusive: true,
|
|
140
|
+
message: `serialized context exceeds ${MAX_CERTIFIED_CONTEXT_BYTES} UTF-8 bytes`,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
const ids = new Set();
|
|
144
|
+
const filePaths = new Set();
|
|
145
|
+
let inlineBytes = 0;
|
|
146
|
+
for (const [index, entry] of context.entries.entries()) {
|
|
147
|
+
if (ids.has(entry.id)) {
|
|
148
|
+
refinement.addIssue({
|
|
149
|
+
code: "custom",
|
|
150
|
+
path: ["entries", index, "id"],
|
|
151
|
+
message: `duplicate context id: ${entry.id}`,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
ids.add(entry.id);
|
|
155
|
+
if (entry.delivery.kind === "file") {
|
|
156
|
+
if (filePaths.has(entry.delivery.path)) {
|
|
157
|
+
refinement.addIssue({
|
|
158
|
+
code: "custom",
|
|
159
|
+
path: ["entries", index, "delivery", "path"],
|
|
160
|
+
message: `duplicate file path: ${entry.delivery.path}`,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
filePaths.add(entry.delivery.path);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
inlineBytes += new TextEncoder().encode(entry.delivery.content).byteLength;
|
|
167
|
+
}
|
|
168
|
+
if (Date.parse(entry.provenance.promotedAt) > generatedAt) {
|
|
169
|
+
refinement.addIssue({
|
|
170
|
+
code: "custom",
|
|
171
|
+
path: ["entries", index, "provenance", "promotedAt"],
|
|
172
|
+
message: "context cannot be promoted after bundle generation",
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (inlineBytes > MAX_TOTAL_INLINE_CONTEXT_BYTES) {
|
|
177
|
+
refinement.addIssue({
|
|
178
|
+
code: "custom",
|
|
179
|
+
path: ["entries"],
|
|
180
|
+
message: `inline context exceeds ${MAX_TOTAL_INLINE_CONTEXT_BYTES} UTF-8 bytes`,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
if ((context.state === "active" && context.entries.length === 0) ||
|
|
184
|
+
(context.state === "revoked" && context.entries.length !== 0)) {
|
|
185
|
+
refinement.addIssue({
|
|
186
|
+
code: "custom",
|
|
187
|
+
path: ["entries"],
|
|
188
|
+
message: "active context requires entries and revoked context requires none",
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const material = {
|
|
192
|
+
tenantId: context.tenantId,
|
|
193
|
+
target: context.target,
|
|
194
|
+
state: context.state,
|
|
195
|
+
revision: context.revision,
|
|
196
|
+
entries: context.entries,
|
|
197
|
+
};
|
|
198
|
+
if (context.contentHash !== certifiedContextContentHash(material)) {
|
|
199
|
+
refinement.addIssue({
|
|
200
|
+
code: "custom",
|
|
201
|
+
path: ["contentHash"],
|
|
202
|
+
message: "context content hash does not match the delivered context",
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
function deepFreeze(value) {
|
|
207
|
+
if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
|
|
208
|
+
for (const child of Object.values(value)) {
|
|
209
|
+
deepFreeze(child);
|
|
210
|
+
}
|
|
211
|
+
Object.freeze(value);
|
|
212
|
+
}
|
|
213
|
+
return value;
|
|
214
|
+
}
|
|
215
|
+
const _certifiedContextDeliverySchemaMatches = true;
|
|
216
|
+
const _certifiedContextProvenanceSchemaMatches = true;
|
|
217
|
+
const _certifiedContextEntrySchemaMatches = true;
|
|
218
|
+
const _certifiedContextSchemaMatches = true;
|
|
219
|
+
void [
|
|
220
|
+
_certifiedContextDeliverySchemaMatches,
|
|
221
|
+
_certifiedContextProvenanceSchemaMatches,
|
|
222
|
+
_certifiedContextEntrySchemaMatches,
|
|
223
|
+
_certifiedContextSchemaMatches,
|
|
224
|
+
];
|
|
225
|
+
/** Parse, clone, and recursively freeze one untrusted context response. */
|
|
226
|
+
export function parseCertifiedContext(value) {
|
|
227
|
+
return deepFreeze(certifiedContextSchema.parse(value));
|
|
228
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ReasoningEffort } from "./agent-profile.js";
|
|
2
|
-
import {
|
|
2
|
+
import type { HarnessType } from "./harness.js";
|
|
3
3
|
/**
|
|
4
4
|
* The unified harness capability layer — the single source of truth for:
|
|
5
5
|
* 1. harness ↔ model compatibility (which models a harness can run), and
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { canonicalizeHarness } from "./harness.js";
|
|
2
1
|
/**
|
|
3
2
|
* The unified harness capability layer — the single source of truth for:
|
|
4
3
|
* 1. harness ↔ model compatibility (which models a harness can run), and
|
|
@@ -28,8 +27,7 @@ export const reasoningLadder = [
|
|
|
28
27
|
// ── Harness ↔ model compatibility ────────────────────────────────────────────
|
|
29
28
|
/**
|
|
30
29
|
* Provider prefixes a harness is vendor-locked to (canonical-id prefix, e.g. `anthropic`, `openai`).
|
|
31
|
-
* A harness with no entry is router-backed: it runs any model.
|
|
32
|
-
* (`claude`/`claudish`/`kimi`) resolve through `canonicalizeHarness` first.
|
|
30
|
+
* A harness with no entry is router-backed: it runs any model.
|
|
33
31
|
*
|
|
34
32
|
* `nanoclaw` is deliberately absent despite the "claw" name: its runner routes every provider through
|
|
35
33
|
* the Tangle router (canonical model id straight to the gateway), so it is router-backed like
|
|
@@ -47,7 +45,7 @@ export function modelProvider(modelId) {
|
|
|
47
45
|
}
|
|
48
46
|
/** The providers a harness is locked to, or `null` when it is router-backed (any model). */
|
|
49
47
|
export function harnessProviders(harness) {
|
|
50
|
-
return harnessProviderLock[
|
|
48
|
+
return harnessProviderLock[harness] ?? null;
|
|
51
49
|
}
|
|
52
50
|
/**
|
|
53
51
|
* Whether a harness can run a model. Router-backed harnesses (no provider lock) accept anything;
|
|
@@ -76,7 +74,7 @@ export function preferredHarnessForModel(modelId) {
|
|
|
76
74
|
/**
|
|
77
75
|
* Per-harness ranking patterns for {@link snapModelToHarness}, best first; within one pattern the
|
|
78
76
|
* highest version wins (numeric-aware). Only vendor-locked harnesses need an entry — a router-backed
|
|
79
|
-
* harness never snaps (it runs the model as-is).
|
|
77
|
+
* harness never snaps (it runs the model as-is).
|
|
80
78
|
*/
|
|
81
79
|
const harnessPreferredModelPatterns = {
|
|
82
80
|
"claude-code": [
|
|
@@ -101,7 +99,7 @@ const numericDesc = new Intl.Collator(undefined, {
|
|
|
101
99
|
export function snapModelToHarness(harness, modelId, candidateIds) {
|
|
102
100
|
if (harnessSupportsModel(harness, modelId))
|
|
103
101
|
return modelId;
|
|
104
|
-
const patterns = harnessPreferredModelPatterns[
|
|
102
|
+
const patterns = harnessPreferredModelPatterns[harness] ?? [];
|
|
105
103
|
for (const pattern of patterns) {
|
|
106
104
|
const matches = candidateIds
|
|
107
105
|
.filter((id) => pattern.test(id))
|
|
@@ -164,11 +162,10 @@ const harnessReasoningCeiling = {
|
|
|
164
162
|
/** The reasoning efforts a harness can express, independent of model — its explicit override set, or
|
|
165
163
|
* `none` up to its ceiling (default `ultracode` for router/model-driven harnesses). */
|
|
166
164
|
export function harnessReasoningEfforts(harness) {
|
|
167
|
-
const
|
|
168
|
-
const override = harnessReasoningEffortsOverride[canonical];
|
|
165
|
+
const override = harnessReasoningEffortsOverride[harness];
|
|
169
166
|
if (override)
|
|
170
167
|
return override;
|
|
171
|
-
const ceiling = harnessReasoningCeiling[
|
|
168
|
+
const ceiling = harnessReasoningCeiling[harness] ?? "ultracode";
|
|
172
169
|
return reasoningLadder.slice(0, reasoningLadder.indexOf(ceiling) + 1);
|
|
173
170
|
}
|
|
174
171
|
/**
|
|
@@ -191,7 +188,7 @@ export function reasoningEffortsFor(harness, model) {
|
|
|
191
188
|
/**
|
|
192
189
|
* Harnesses whose runner DROPS a per-turn selector — grounded in the cli-bridge adapter audit, NOT a
|
|
193
190
|
* guess. Most harnesses honor both selectors, so only the exceptions are listed; a harness absent from
|
|
194
|
-
* a set honors that selector.
|
|
191
|
+
* a set honors that selector.
|
|
195
192
|
*
|
|
196
193
|
* - model dropped: `amp` (own agent picks the model), `openclaw` (dispatcher routes by its own
|
|
197
194
|
* config), `nanoclaw` (socket-bridge runner is config/env-driven).
|
|
@@ -215,11 +212,11 @@ const harnessIgnoresEffort = new Set([
|
|
|
215
212
|
]);
|
|
216
213
|
/** Whether the harness's runner honors a per-turn MODEL override (vs. picking the model itself). */
|
|
217
214
|
export function harnessHonorsModel(harness) {
|
|
218
|
-
return !harnessIgnoresModel.has(
|
|
215
|
+
return !harnessIgnoresModel.has(harness);
|
|
219
216
|
}
|
|
220
217
|
/** Whether the harness's runner honors a reasoning-EFFORT override (vs. dropping it). */
|
|
221
218
|
export function harnessHonorsEffort(harness) {
|
|
222
|
-
return !harnessIgnoresEffort.has(
|
|
219
|
+
return !harnessIgnoresEffort.has(harness);
|
|
223
220
|
}
|
|
224
221
|
/** Whether the harness honors BOTH chat selectors — i.e. the model and effort pickers are live. */
|
|
225
222
|
export function harnessHonorsSelectors(harness) {
|
package/dist/harness.d.ts
CHANGED
|
@@ -14,20 +14,15 @@ import { z } from "zod";
|
|
|
14
14
|
* a one-shot) with no full coding-agent harness. The rest are full agentic harnesses run in a
|
|
15
15
|
* sandbox or locally via the CLI bridge.
|
|
16
16
|
*
|
|
17
|
-
* Some values are input aliases that collapse to a base runner (`claude`/`claudish` → `claude-code`,
|
|
18
|
-
* `kimi` → `kimi-code`); normalize with {@link canonicalizeHarness} before keying per-runner config.
|
|
19
17
|
*/
|
|
20
|
-
export type HarnessType = "claude-code" | "
|
|
18
|
+
export type HarnessType = "claude-code" | "nanoclaw" | "codex" | "opencode" | "kimi-code" | "pi" | "gemini" | "hermes" | "openclaw" | "amp" | "factory-droids" | "acp" | "cli-base";
|
|
21
19
|
/** Runtime validator for {@link HarnessType}. Kept in lockstep with the type by the drift guard below. */
|
|
22
20
|
export declare const harnessTypeSchema: z.ZodEnum<{
|
|
23
21
|
"claude-code": "claude-code";
|
|
24
|
-
claude: "claude";
|
|
25
|
-
claudish: "claudish";
|
|
26
22
|
nanoclaw: "nanoclaw";
|
|
27
23
|
codex: "codex";
|
|
28
24
|
opencode: "opencode";
|
|
29
25
|
"kimi-code": "kimi-code";
|
|
30
|
-
kimi: "kimi";
|
|
31
26
|
pi: "pi";
|
|
32
27
|
gemini: "gemini";
|
|
33
28
|
hermes: "hermes";
|
|
@@ -37,7 +32,3 @@ export declare const harnessTypeSchema: z.ZodEnum<{
|
|
|
37
32
|
acp: "acp";
|
|
38
33
|
"cli-base": "cli-base";
|
|
39
34
|
}>;
|
|
40
|
-
/** Input alias → canonical base runner. Aliases accept legacy/shorthand harness names. */
|
|
41
|
-
export declare const harnessAliases: Partial<Record<HarnessType, HarnessType>>;
|
|
42
|
-
/** Collapse an alias to its base runner (idempotent on canonical values). */
|
|
43
|
-
export declare function canonicalizeHarness(harness: HarnessType): HarnessType;
|
package/dist/harness.js
CHANGED
|
@@ -2,13 +2,10 @@ import { z } from "zod";
|
|
|
2
2
|
/** Runtime validator for {@link HarnessType}. Kept in lockstep with the type by the drift guard below. */
|
|
3
3
|
export const harnessTypeSchema = z.enum([
|
|
4
4
|
"claude-code",
|
|
5
|
-
"claude",
|
|
6
|
-
"claudish",
|
|
7
5
|
"nanoclaw",
|
|
8
6
|
"codex",
|
|
9
7
|
"opencode",
|
|
10
8
|
"kimi-code",
|
|
11
|
-
"kimi",
|
|
12
9
|
"pi",
|
|
13
10
|
"gemini",
|
|
14
11
|
"hermes",
|
|
@@ -18,15 +15,5 @@ export const harnessTypeSchema = z.enum([
|
|
|
18
15
|
"acp",
|
|
19
16
|
"cli-base",
|
|
20
17
|
]);
|
|
21
|
-
/** Input alias → canonical base runner. Aliases accept legacy/shorthand harness names. */
|
|
22
|
-
export const harnessAliases = {
|
|
23
|
-
claude: "claude-code",
|
|
24
|
-
claudish: "claude-code",
|
|
25
|
-
kimi: "kimi-code",
|
|
26
|
-
};
|
|
27
|
-
/** Collapse an alias to its base runner (idempotent on canonical values). */
|
|
28
|
-
export function canonicalizeHarness(harness) {
|
|
29
|
-
return harnessAliases[harness] ?? harness;
|
|
30
|
-
}
|
|
31
18
|
const _harnessSchemaMatchesType = true;
|
|
32
19
|
void _harnessSchemaMatchesType;
|
package/dist/index.d.ts
CHANGED
|
@@ -157,7 +157,7 @@ export declare function normalizeInputParts(input: {
|
|
|
157
157
|
export declare function renderInputPartsAsText(parts: InputPart[]): string;
|
|
158
158
|
/**
|
|
159
159
|
* The primary event for all part updates from OpenCode.
|
|
160
|
-
* This is the canonical event
|
|
160
|
+
* This is the canonical event for all part updates.
|
|
161
161
|
*/
|
|
162
162
|
export type MessagePartUpdatedEvent = {
|
|
163
163
|
type: "message.part.updated";
|
|
@@ -614,7 +614,12 @@ export * from "./interaction.js";
|
|
|
614
614
|
export * from "./agent-candidate.js";
|
|
615
615
|
export * from "./agent-candidate-schema.js";
|
|
616
616
|
export * from "./agent-candidate-promotion-schema.js";
|
|
617
|
+
export { agentCandidateEvaluationPolicySchema } from "./agent-improvement-measurement-schema.js";
|
|
618
|
+
export * from "./agent-improvement-source.js";
|
|
619
|
+
export * from "./agent-profile-improvement.js";
|
|
620
|
+
export * from "./agent-profile-improvement-schema.js";
|
|
617
621
|
export * from "./agent-profile.js";
|
|
622
|
+
export * from "./certified-context.js";
|
|
618
623
|
export * from "./profile-diff.js";
|
|
619
624
|
export * from "./harness.js";
|
|
620
625
|
export * from "./harness-capabilities.js";
|
package/dist/index.js
CHANGED
|
@@ -127,7 +127,12 @@ export * from "./interaction.js";
|
|
|
127
127
|
export * from "./agent-candidate.js";
|
|
128
128
|
export * from "./agent-candidate-schema.js";
|
|
129
129
|
export * from "./agent-candidate-promotion-schema.js";
|
|
130
|
+
export { agentCandidateEvaluationPolicySchema } from "./agent-improvement-measurement-schema.js";
|
|
131
|
+
export * from "./agent-improvement-source.js";
|
|
132
|
+
export * from "./agent-profile-improvement.js";
|
|
133
|
+
export * from "./agent-profile-improvement-schema.js";
|
|
130
134
|
export * from "./agent-profile.js";
|
|
135
|
+
export * from "./certified-context.js";
|
|
131
136
|
export * from "./profile-diff.js";
|
|
132
137
|
export * from "./harness.js";
|
|
133
138
|
export * from "./harness-capabilities.js";
|
package/dist/interaction.d.ts
CHANGED
|
@@ -256,23 +256,6 @@ export type PermissionGrant = z.infer<typeof PermissionGrantSchema>;
|
|
|
256
256
|
export declare function permissionAnswerSpec(opts?: {
|
|
257
257
|
allowFeedback?: boolean;
|
|
258
258
|
}): InteractionAnswerSpec;
|
|
259
|
-
/** Shape of one legacy question (kept for the back-compat shim). */
|
|
260
|
-
export type LegacyQuestion = {
|
|
261
|
-
question: string;
|
|
262
|
-
options?: Array<{
|
|
263
|
-
label: string;
|
|
264
|
-
description?: string;
|
|
265
|
-
}>;
|
|
266
|
-
multiSelect?: boolean;
|
|
267
|
-
/** When true the select field accepts write-in answers beyond `options`. */
|
|
268
|
-
allowCustom?: boolean;
|
|
269
|
-
};
|
|
270
|
-
/**
|
|
271
|
-
* Build an answer spec from the legacy `question` event shape. Each question
|
|
272
|
-
* becomes one select field (free text when it declares no options), so the old
|
|
273
|
-
* question/answer path is expressible as a `question` interaction.
|
|
274
|
-
*/
|
|
275
|
-
export declare function questionAnswerSpec(questions: LegacyQuestion[]): InteractionAnswerSpec;
|
|
276
259
|
export type InteractionValidation = {
|
|
277
260
|
ok: true;
|
|
278
261
|
} | {
|
package/dist/interaction.js
CHANGED
|
@@ -176,29 +176,6 @@ export function permissionAnswerSpec(opts) {
|
|
|
176
176
|
}
|
|
177
177
|
return { fields };
|
|
178
178
|
}
|
|
179
|
-
/**
|
|
180
|
-
* Build an answer spec from the legacy `question` event shape. Each question
|
|
181
|
-
* becomes one select field (free text when it declares no options), so the old
|
|
182
|
-
* question/answer path is expressible as a `question` interaction.
|
|
183
|
-
*/
|
|
184
|
-
export function questionAnswerSpec(questions) {
|
|
185
|
-
const fields = questions.map((q, i) => {
|
|
186
|
-
const name = `q${i}`;
|
|
187
|
-
if (q.options && q.options.length > 0) {
|
|
188
|
-
return {
|
|
189
|
-
type: "select",
|
|
190
|
-
name,
|
|
191
|
-
label: q.question,
|
|
192
|
-
required: true,
|
|
193
|
-
multi: q.multiSelect === true,
|
|
194
|
-
...(q.allowCustom === true ? { allowCustom: true } : {}),
|
|
195
|
-
options: q.options.map((o) => ({ value: o.label, label: o.label, description: o.description })),
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
return { type: "text", name, label: q.question, required: true };
|
|
199
|
-
});
|
|
200
|
-
return { fields };
|
|
201
|
-
}
|
|
202
179
|
/**
|
|
203
180
|
* Validate an accepted answer against its spec. Used by the broker before a
|
|
204
181
|
* response reaches the adapter, so malformed answers are rejected centrally.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function numbersApproximatelyEqual(left: number, right: number): boolean;
|
package/dist/profile-schema.d.ts
CHANGED
|
@@ -268,13 +268,10 @@ export declare const agentProfileSchema: z.ZodObject<{
|
|
|
268
268
|
}, z.core.$strict>>;
|
|
269
269
|
harness: z.ZodOptional<z.ZodEnum<{
|
|
270
270
|
"claude-code": "claude-code";
|
|
271
|
-
claude: "claude";
|
|
272
|
-
claudish: "claudish";
|
|
273
271
|
nanoclaw: "nanoclaw";
|
|
274
272
|
codex: "codex";
|
|
275
273
|
opencode: "opencode";
|
|
276
274
|
"kimi-code": "kimi-code";
|
|
277
|
-
kimi: "kimi";
|
|
278
275
|
pi: "pi";
|
|
279
276
|
gemini: "gemini";
|
|
280
277
|
hermes: "hermes";
|