@tangle-network/agent-interface 3.0.0 → 3.1.1

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.
@@ -166,6 +166,37 @@ export declare const agentProfileModelHintsSchema: z.ZodObject<{
166
166
  maxTotalOutputTokens: z.ZodOptional<z.ZodNumber>;
167
167
  metadata: z.ZodOptional<z.ZodType<Record<string, unknown>, unknown, z.core.$ZodTypeInternals<Record<string, unknown>, unknown>>>;
168
168
  }, z.core.$strict>;
169
+ /** Ordered account selection policy, without credentials or ambient model defaults. */
170
+ export declare const agentProfileSeatSchema: z.ZodObject<{
171
+ harness: z.ZodEnum<{
172
+ acp: "acp";
173
+ amp: "amp";
174
+ "claude-code": "claude-code";
175
+ "cli-base": "cli-base";
176
+ codex: "codex";
177
+ cursor: "cursor";
178
+ "factory-droids": "factory-droids";
179
+ forge: "forge";
180
+ gemini: "gemini";
181
+ hermes: "hermes";
182
+ "kimi-code": "kimi-code";
183
+ nanoclaw: "nanoclaw";
184
+ openclaw: "openclaw";
185
+ opencode: "opencode";
186
+ pi: "pi";
187
+ prime: "prime";
188
+ }>;
189
+ provider: z.ZodString;
190
+ model: z.ZodString;
191
+ selector: z.ZodUnion<readonly [z.ZodObject<{
192
+ kind: z.ZodLiteral<"all-eligible">;
193
+ }, z.core.$strict>, z.ZodObject<{
194
+ kind: z.ZodLiteral<"seat">;
195
+ id: z.ZodString;
196
+ }, z.core.$strict>]>;
197
+ tools: z.ZodOptional<z.ZodType<Record<string, boolean>, unknown, z.core.$ZodTypeInternals<Record<string, boolean>, unknown>>>;
198
+ permissions: z.ZodOptional<z.ZodType<Record<string, "allow" | "ask" | "deny" | Record<string, "allow" | "ask" | "deny">>, unknown, z.core.$ZodTypeInternals<Record<string, "allow" | "ask" | "deny" | Record<string, "allow" | "ask" | "deny">>, unknown>>>;
199
+ }, z.core.$strict>;
169
200
  /**
170
201
  * Replacement and addition are separate, independently optional fields, and the
171
202
  * pair is admitted on purpose: the effective prompt is `systemPrompt` followed
@@ -306,6 +337,7 @@ export declare const agentProfileDiffRemovalSchema: z.ZodObject<{
306
337
  }, z.core.$strict>]>>;
307
338
  model: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodArray<z.ZodString>]>>;
308
339
  harness: z.ZodOptional<z.ZodLiteral<true>>;
340
+ seats: z.ZodOptional<z.ZodLiteral<true>>;
309
341
  permissions: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodArray<z.ZodString>]>>;
310
342
  tools: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodArray<z.ZodString>]>>;
311
343
  mcp: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodArray<z.ZodString>]>>;
@@ -487,6 +519,36 @@ export declare const agentProfileSchema: z.ZodObject<{
487
519
  pi: "pi";
488
520
  prime: "prime";
489
521
  }>>;
522
+ seats: z.ZodOptional<z.ZodArray<z.ZodObject<{
523
+ harness: z.ZodEnum<{
524
+ acp: "acp";
525
+ amp: "amp";
526
+ "claude-code": "claude-code";
527
+ "cli-base": "cli-base";
528
+ codex: "codex";
529
+ cursor: "cursor";
530
+ "factory-droids": "factory-droids";
531
+ forge: "forge";
532
+ gemini: "gemini";
533
+ hermes: "hermes";
534
+ "kimi-code": "kimi-code";
535
+ nanoclaw: "nanoclaw";
536
+ openclaw: "openclaw";
537
+ opencode: "opencode";
538
+ pi: "pi";
539
+ prime: "prime";
540
+ }>;
541
+ provider: z.ZodString;
542
+ model: z.ZodString;
543
+ selector: z.ZodUnion<readonly [z.ZodObject<{
544
+ kind: z.ZodLiteral<"all-eligible">;
545
+ }, z.core.$strict>, z.ZodObject<{
546
+ kind: z.ZodLiteral<"seat">;
547
+ id: z.ZodString;
548
+ }, z.core.$strict>]>;
549
+ tools: z.ZodOptional<z.ZodType<Record<string, boolean>, unknown, z.core.$ZodTypeInternals<Record<string, boolean>, unknown>>>;
550
+ permissions: z.ZodOptional<z.ZodType<Record<string, "allow" | "ask" | "deny" | Record<string, "allow" | "ask" | "deny">>, unknown, z.core.$ZodTypeInternals<Record<string, "allow" | "ask" | "deny" | Record<string, "allow" | "ask" | "deny">>, unknown>>>;
551
+ }, z.core.$strict>>>;
490
552
  permissions: z.ZodOptional<z.ZodType<Record<string, "allow" | "ask" | "deny" | Record<string, "allow" | "ask" | "deny">>, unknown, z.core.$ZodTypeInternals<Record<string, "allow" | "ask" | "deny" | Record<string, "allow" | "ask" | "deny">>, unknown>>>;
491
553
  tools: z.ZodOptional<z.ZodType<Record<string, boolean>, unknown, z.core.$ZodTypeInternals<Record<string, boolean>, unknown>>>;
492
554
  mcp: z.ZodOptional<z.ZodType<Record<string, AgentProfileMcpServer>, unknown, z.core.$ZodTypeInternals<Record<string, AgentProfileMcpServer>, unknown>>>;
@@ -2,6 +2,8 @@ import { z } from "zod";
2
2
  import { REASONING_EFFORTS, TRAINED_MODEL_PREFIX, trainedModelIdForArtifact, } from "./agent-profile.js";
3
3
  import { canonicalCandidateDigest, sha256DigestSchema, environmentNameSchema, headerNameSchema, isSafeExecutable, isSafeRelativePath, isWellFormedUnicode, looksLikeCredential, } from "./agent-candidate-schema-common.js";
4
4
  import { harnessTypeSchema } from "./harness.js";
5
+ import { canonicalAgentProfileJson } from "./agent-profile-canonical.js";
6
+ import { harnessHonorsEffort, harnessHonorsModel, harnessModelSupport, harnessReasoningEfforts, harnessSystemPromptIntents, resolveModelProvider, } from "./harness-capabilities.js";
5
7
  import { SANDBOX_SIZE_PRESET_NAMES, } from "./sandbox-size.js";
6
8
  /**
7
9
  * Zod records currently assign parsed values onto an ordinary object. The
@@ -130,6 +132,18 @@ export const agentProfileModelHintsBaseSchema = z.strictObject({
130
132
  metadata: ownPropertyRecordSchema(z.unknown()).optional(),
131
133
  });
132
134
  export const agentProfileModelHintsSchema = agentProfileModelHintsBaseSchema.superRefine(enforceModelTokenBounds);
135
+ /** Ordered account selection policy, without credentials or ambient model defaults. */
136
+ export const agentProfileSeatSchema = z.strictObject({
137
+ harness: harnessTypeSchema,
138
+ provider: z.string().regex(/^[a-z][a-z0-9-]*$/),
139
+ model: z.string().min(1).refine((value) => value.trim() === value, "model must be canonical"),
140
+ selector: z.union([
141
+ z.strictObject({ kind: z.literal("all-eligible") }),
142
+ z.strictObject({ kind: z.literal("seat"), id: z.string().min(1).refine((value) => value.trim() === value, "seat id must be canonical") }),
143
+ ]),
144
+ tools: ownPropertyRecordSchema(z.boolean()).optional(),
145
+ permissions: ownPropertyRecordSchema(agentProfilePermissionSchema).optional(),
146
+ });
133
147
  /**
134
148
  * Replacement and addition are separate, independently optional fields, and the
135
149
  * pair is admitted on purpose: the effective prompt is `systemPrompt` followed
@@ -308,6 +322,7 @@ export const agentProfileDiffRemovalSchema = z.strictObject({
308
322
  .optional(),
309
323
  model: removeListSchema.optional(),
310
324
  harness: z.literal(true).optional(),
325
+ seats: z.literal(true).optional(),
311
326
  permissions: removeListSchema.optional(),
312
327
  tools: removeListSchema.optional(),
313
328
  mcp: removeListSchema.optional(),
@@ -418,6 +433,7 @@ export const agentProfileSchema = z
418
433
  prompt: agentProfilePromptSchema.optional(),
419
434
  model: agentProfileModelHintsSchema.optional(),
420
435
  harness: harnessTypeSchema.optional(),
436
+ seats: z.array(agentProfileSeatSchema).nonempty().optional(),
421
437
  permissions: ownPropertyRecordSchema(agentProfilePermissionSchema).optional(),
422
438
  tools: ownPropertyRecordSchema(z.boolean()).optional(),
423
439
  mcp: ownPropertyRecordSchema(agentProfileMcpServerSchema).optional(),
@@ -432,6 +448,46 @@ export const agentProfileSchema = z
432
448
  })
433
449
  .superRefine((profile, context) => {
434
450
  validateNestedRecordKeys(profile, context, [], new Set());
451
+ if (profile.seats?.length) {
452
+ const first = profile.seats[0];
453
+ if (first.harness !== profile.harness || first.provider !== profile.model?.provider ||
454
+ first.model !== profile.model?.default) {
455
+ context.addIssue({ code: "custom", path: ["seats", 0], message: "first seat must match profile harness, model.provider, and model.default" });
456
+ }
457
+ if (first.tools !== undefined &&
458
+ canonicalAgentProfileJson(first.tools) !== canonicalAgentProfileJson(profile.tools)) {
459
+ context.addIssue({ code: "custom", path: ["seats", 0, "tools"], message: "first seat tools must match profile tools" });
460
+ }
461
+ if (first.permissions !== undefined &&
462
+ canonicalAgentProfileJson(first.permissions) !== canonicalAgentProfileJson(profile.permissions)) {
463
+ context.addIssue({ code: "custom", path: ["seats", 0, "permissions"], message: "first seat permissions must match profile permissions" });
464
+ }
465
+ for (const [index, seat] of profile.seats.entries()) {
466
+ const provider = resolveModelProvider(seat.model);
467
+ if (provider !== seat.provider) {
468
+ context.addIssue({ code: "custom", path: ["seats", index, "provider"], message: "seat provider must match the model provider" });
469
+ }
470
+ if (!harnessHonorsModel(seat.harness)) {
471
+ context.addIssue({ code: "custom", path: ["seats", index, "harness"], message: "seat harness does not honor an exact model choice" });
472
+ }
473
+ const support = harnessModelSupport(seat.harness, seat.model, { reasoningEffort: profile.model?.reasoningEffort });
474
+ if (!support.supported) {
475
+ context.addIssue({ code: "custom", path: ["seats", index, "model"], message: support.message });
476
+ }
477
+ const effort = profile.model?.reasoningEffort;
478
+ if (effort !== undefined && (!harnessHonorsEffort(seat.harness) ||
479
+ !harnessReasoningEfforts(seat.harness).includes(effort))) {
480
+ context.addIssue({ code: "custom", path: ["seats", index, "harness"], message: "seat harness cannot honor profile reasoning effort" });
481
+ }
482
+ const prompt = harnessSystemPromptIntents(seat.harness);
483
+ if (profile.prompt?.systemPrompt !== undefined && !prompt.replace) {
484
+ context.addIssue({ code: "custom", path: ["seats", index, "harness"], message: "seat harness cannot replace the system prompt" });
485
+ }
486
+ if (profile.prompt?.appendSystemPrompt !== undefined && !prompt.append) {
487
+ context.addIssue({ code: "custom", path: ["seats", index, "harness"], message: "seat harness cannot append the system prompt" });
488
+ }
489
+ }
490
+ }
435
491
  const training = agentProfileTrainingSchema.safeParse(profile.metadata?.training);
436
492
  if (profile.model?.default?.startsWith(TRAINED_MODEL_PREFIX) && !training.success) {
437
493
  context.addIssue({ code: "custom", path: ["metadata", "training"], message: "trained model requires a checkpoint receipt" });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-interface",
3
- "version": "3.0.0",
3
+ "version": "3.1.1",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "license": "MIT",