@runtypelabs/sdk 5.3.1 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -3276,6 +3276,300 @@ var BatchesNamespace = class {
3276
3276
  }
3277
3277
  };
3278
3278
 
3279
+ // src/evals-ensure.ts
3280
+ var CHECK_GRADER_KINDS = /* @__PURE__ */ new Set([
3281
+ "contains",
3282
+ "not_contains",
3283
+ "matches_expected",
3284
+ "regex",
3285
+ "valid_json",
3286
+ "json_field",
3287
+ "length",
3288
+ "latency",
3289
+ "no_error"
3290
+ ]);
3291
+ function contains(value, opts) {
3292
+ return { kind: "contains", value, ...opts?.caseSensitive ? { caseSensitive: true } : {} };
3293
+ }
3294
+ function notContains(value, opts) {
3295
+ return { kind: "not_contains", value, ...opts?.caseSensitive ? { caseSensitive: true } : {} };
3296
+ }
3297
+ function matchesExpected() {
3298
+ return { kind: "matches_expected" };
3299
+ }
3300
+ function regex(pattern, flags) {
3301
+ return { kind: "regex", pattern, ...flags ? { flags } : {} };
3302
+ }
3303
+ function validJson() {
3304
+ return { kind: "valid_json" };
3305
+ }
3306
+ function jsonField(path, opts) {
3307
+ return {
3308
+ kind: "json_field",
3309
+ path,
3310
+ ...opts && "equals" in opts && opts.equals !== void 0 ? { equals: opts.equals } : {},
3311
+ ...opts && typeof opts.exists === "boolean" ? { exists: opts.exists } : {}
3312
+ };
3313
+ }
3314
+ function length(opts) {
3315
+ if (!opts || opts.minChars === void 0 && opts.maxChars === void 0) {
3316
+ throw new Error("length() requires at least one of minChars or maxChars");
3317
+ }
3318
+ return {
3319
+ kind: "length",
3320
+ ...opts.minChars !== void 0 ? { minChars: opts.minChars } : {},
3321
+ ...opts.maxChars !== void 0 ? { maxChars: opts.maxChars } : {}
3322
+ };
3323
+ }
3324
+ function latency(maxMs) {
3325
+ if (!Number.isFinite(maxMs) || maxMs <= 0) {
3326
+ throw new Error("latency() requires a positive maxMs");
3327
+ }
3328
+ return { kind: "latency", maxMs };
3329
+ }
3330
+ function noError() {
3331
+ return { kind: "no_error" };
3332
+ }
3333
+ function judge(criteria, opts) {
3334
+ if (typeof criteria !== "string" || criteria.trim().length === 0) {
3335
+ throw new Error("judge() requires non-empty criteria");
3336
+ }
3337
+ return {
3338
+ kind: "ai",
3339
+ criteria,
3340
+ ...opts?.preset ? { preset: opts.preset } : {},
3341
+ ...opts?.useExpected ? { useExpected: true } : {},
3342
+ ...opts?.model ? { model: opts.model } : {},
3343
+ ...opts?.threshold !== void 0 ? { threshold: opts.threshold } : {}
3344
+ };
3345
+ }
3346
+ var judges = {
3347
+ answersQuestion: () => judge(
3348
+ "The response directly addresses what the user asked, without dodging or answering a different question.",
3349
+ { preset: "answersQuestion" }
3350
+ ),
3351
+ matchesExpected: () => judge(
3352
+ "The response conveys the same facts and conclusion as the expected answer. Wording may differ.",
3353
+ { preset: "matchesExpected", useExpected: true }
3354
+ ),
3355
+ followsInstructions: () => judge(
3356
+ "The response obeys every instruction in the system prompt (format, tone, constraints, refusals).",
3357
+ { preset: "followsInstructions" }
3358
+ ),
3359
+ grounded: () => judge(
3360
+ "Every factual claim in the response is supported by the provided context or the expected answer. Flag anything invented.",
3361
+ { preset: "grounded" }
3362
+ ),
3363
+ rightTone: (voice = "{describe the voice you want}") => judge(`The response matches this voice: ${voice}.`, { preset: "rightTone" }),
3364
+ safeToSend: () => judge(
3365
+ "The response contains nothing embarrassing to show a customer: no leaked internals, no hostile tone, no policy violations.",
3366
+ { preset: "safeToSend" }
3367
+ )
3368
+ };
3369
+ var DEFINE_EVAL_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
3370
+ "name",
3371
+ "target",
3372
+ "graders",
3373
+ "cases",
3374
+ "virtual"
3375
+ ]);
3376
+ var DEFINE_EVAL_CASE_KEYS = /* @__PURE__ */ new Set(["name", "input", "expected", "expect"]);
3377
+ function isPlainObject2(value) {
3378
+ return value !== null && typeof value === "object" && !Array.isArray(value);
3379
+ }
3380
+ function normalizeTarget(target) {
3381
+ if (!isPlainObject2(target)) {
3382
+ throw new Error('defineEval requires a "target" object: { flow: name } or { agent: name }');
3383
+ }
3384
+ const hasFlow = typeof target.flow === "string" && target.flow.length > 0;
3385
+ const hasAgent = typeof target.agent === "string" && target.agent.length > 0;
3386
+ if (hasFlow === hasAgent) {
3387
+ throw new Error(
3388
+ 'defineEval "target" must name exactly one of flow or agent: { flow: "name" } XOR { agent: "name" }'
3389
+ );
3390
+ }
3391
+ const extraKeys = Object.keys(target).filter((k) => k !== "flow" && k !== "agent");
3392
+ if (extraKeys.length > 0) {
3393
+ throw new Error(`defineEval "target" has unknown field(s): ${extraKeys.join(", ")}`);
3394
+ }
3395
+ return hasFlow ? { flow: target.flow } : { agent: target.agent };
3396
+ }
3397
+ function validateGrader(grader, where) {
3398
+ if (!isPlainObject2(grader) || typeof grader.kind !== "string") {
3399
+ throw new Error(`defineEval: ${where} must be a grader object with a string "kind"`);
3400
+ }
3401
+ if (grader.kind === "ai") {
3402
+ if (typeof grader.criteria !== "string" || grader.criteria.trim().length === 0) {
3403
+ throw new Error(`defineEval: ${where} is an AI grader and requires non-empty "criteria"`);
3404
+ }
3405
+ return grader;
3406
+ }
3407
+ if (!CHECK_GRADER_KINDS.has(grader.kind)) {
3408
+ throw new Error(
3409
+ `defineEval: ${where} has unknown grader kind "${grader.kind}". Known kinds: ${[...CHECK_GRADER_KINDS].join(", ")}, ai. (Trace graders such as called_tool/step_order are not available yet.)`
3410
+ );
3411
+ }
3412
+ return grader;
3413
+ }
3414
+ function normalizeCaseInput(input, where) {
3415
+ if (input === void 0) return {};
3416
+ if (!isPlainObject2(input)) {
3417
+ throw new Error(`defineEval: ${where} "input" must be an object`);
3418
+ }
3419
+ const out = {};
3420
+ if (input.variables !== void 0) {
3421
+ if (!isPlainObject2(input.variables)) {
3422
+ throw new Error(`defineEval: ${where} "input.variables" must be an object`);
3423
+ }
3424
+ out.variables = input.variables;
3425
+ }
3426
+ if (input.messages !== void 0) {
3427
+ if (!Array.isArray(input.messages)) {
3428
+ throw new Error(`defineEval: ${where} "input.messages" must be an array`);
3429
+ }
3430
+ out.messages = input.messages.map((m, i) => {
3431
+ if (!isPlainObject2(m) || typeof m.role !== "string" || typeof m.content !== "string") {
3432
+ throw new Error(`defineEval: ${where} "input.messages[${i}]" must be { role, content }`);
3433
+ }
3434
+ return { role: m.role, content: m.content };
3435
+ });
3436
+ }
3437
+ return out;
3438
+ }
3439
+ function defineEval(input) {
3440
+ if (!input || typeof input !== "object") {
3441
+ throw new Error("defineEval requires a definition object");
3442
+ }
3443
+ const unknownKeys = Object.keys(input).filter((k) => !DEFINE_EVAL_TOP_LEVEL_KEYS.has(k));
3444
+ if (unknownKeys.length > 0) {
3445
+ throw new Error(
3446
+ `defineEval: unknown field(s): ${unknownKeys.join(", ")}. Allowed fields are target, graders, cases, virtual.`
3447
+ );
3448
+ }
3449
+ const target = normalizeTarget(input.target);
3450
+ if (input.name !== void 0 && (typeof input.name !== "string" || input.name.length === 0)) {
3451
+ throw new Error('defineEval "name" must be a non-empty string when provided');
3452
+ }
3453
+ const name = input.name ?? ("flow" in target ? `flow:${target.flow}` : `agent:${target.agent}`);
3454
+ const suiteGraders = (input.graders ?? []).map((g, i) => validateGrader(g, `graders[${i}]`));
3455
+ if (!Array.isArray(input.cases) || input.cases.length === 0) {
3456
+ throw new Error('defineEval requires a non-empty "cases" array');
3457
+ }
3458
+ const seenNames = /* @__PURE__ */ new Set();
3459
+ const cases = input.cases.map((c, index) => {
3460
+ if (!isPlainObject2(c)) {
3461
+ throw new Error(`defineEval: cases[${index}] must be an object`);
3462
+ }
3463
+ if (typeof c.name !== "string" || c.name.length === 0) {
3464
+ throw new Error(`defineEval: cases[${index}] requires a non-empty string "name"`);
3465
+ }
3466
+ if (seenNames.has(c.name)) {
3467
+ throw new Error(`defineEval: duplicate case name "${c.name}" (case names are the identity)`);
3468
+ }
3469
+ seenNames.add(c.name);
3470
+ const unknownCaseKeys = Object.keys(c).filter((k) => !DEFINE_EVAL_CASE_KEYS.has(k));
3471
+ if (unknownCaseKeys.length > 0) {
3472
+ throw new Error(
3473
+ `defineEval: cases[${index}] ("${c.name}") has unknown field(s): ${unknownCaseKeys.join(
3474
+ ", "
3475
+ )}. Allowed case fields are name, input, expected, expect.`
3476
+ );
3477
+ }
3478
+ const caseGraders = (c.expect ?? []).map(
3479
+ (g, i) => validateGrader(g, `cases[${index}].expect[${i}]`)
3480
+ );
3481
+ const expect = [...suiteGraders, ...caseGraders];
3482
+ if (expect.length === 0) {
3483
+ throw new Error(
3484
+ `defineEval: cases[${index}] ("${c.name}") has no graders. Add suite-level "graders" or case-level "expect" so there is something to score.`
3485
+ );
3486
+ }
3487
+ if (c.expected !== void 0 && !isPlainObject2(c.expected)) {
3488
+ throw new Error(`defineEval: cases[${index}] ("${c.name}") "expected" must be an object`);
3489
+ }
3490
+ return {
3491
+ name: c.name,
3492
+ input: normalizeCaseInput(c.input, `cases[${index}] ("${c.name}")`),
3493
+ ...c.expected !== void 0 ? { expected: c.expected } : {},
3494
+ expect
3495
+ };
3496
+ });
3497
+ return { name, target, cases, virtual: input.virtual === true };
3498
+ }
3499
+ function normalizeForHash(value) {
3500
+ if (Array.isArray(value)) return value.map(normalizeForHash);
3501
+ if (isPlainObject2(value)) {
3502
+ const out = {};
3503
+ for (const key of Object.keys(value).sort()) {
3504
+ const v = value[key];
3505
+ if (v === void 0) continue;
3506
+ out[key] = normalizeForHash(v);
3507
+ }
3508
+ return out;
3509
+ }
3510
+ return value;
3511
+ }
3512
+ async function computeEvalContentHash(definition) {
3513
+ const canonical = {
3514
+ target: normalizeForHash(definition.target),
3515
+ virtual: definition.virtual,
3516
+ cases: [...definition.cases].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0).map((c) => ({
3517
+ name: c.name,
3518
+ input: normalizeForHash(c.input),
3519
+ ...c.expected !== void 0 ? { expected: normalizeForHash(c.expected) } : {},
3520
+ // Grader order preserved on purpose (it maps to the result index).
3521
+ expect: c.expect.map((g) => normalizeForHash(g))
3522
+ }))
3523
+ };
3524
+ const serialized = JSON.stringify(canonical);
3525
+ const encoded = new TextEncoder().encode(serialized);
3526
+ const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
3527
+ return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
3528
+ }
3529
+ var serverHashMemo2 = /* @__PURE__ */ new WeakMap();
3530
+ function memoFor2(client) {
3531
+ let memo = serverHashMemo2.get(client);
3532
+ if (!memo) {
3533
+ memo = /* @__PURE__ */ new Map();
3534
+ serverHashMemo2.set(client, memo);
3535
+ }
3536
+ return memo;
3537
+ }
3538
+ async function ensureEval(client, definition) {
3539
+ if (definition.virtual) {
3540
+ throw new Error(
3541
+ "Cannot ensure a virtual eval: virtual evals are ephemeral (nothing is persisted to converge). Remove `virtual: true` to converge a durable suite, or run it directly."
3542
+ );
3543
+ }
3544
+ const memo = memoFor2(client);
3545
+ const localHash = await computeEvalContentHash(definition);
3546
+ const memoKey = `${definition.name} ${localHash}`;
3547
+ const contentHash = memo.get(memoKey) ?? localHash;
3548
+ const probe = await client.post(
3549
+ "/eval/ensure",
3550
+ { name: definition.name, contentHash }
3551
+ );
3552
+ if (probe.result !== "definitionRequired") {
3553
+ memo.set(memoKey, probe.contentHash);
3554
+ return probe;
3555
+ }
3556
+ const converged = await client.post(
3557
+ "/eval/ensure",
3558
+ { name: definition.name, definition }
3559
+ );
3560
+ if (converged.result === "definitionRequired") {
3561
+ throw new Error("Server reported definitionRequired for a full-definition request");
3562
+ }
3563
+ memo.set(memoKey, converged.contentHash);
3564
+ return converged;
3565
+ }
3566
+ async function pullEval(client, name) {
3567
+ return client.get("/eval/pull", { name });
3568
+ }
3569
+ async function runEvalSuite(client, input) {
3570
+ return client.post("/eval/run", input);
3571
+ }
3572
+
3279
3573
  // src/evals-namespace.ts
3280
3574
  var EvalRunner = class {
3281
3575
  constructor(getClient, config) {
@@ -3420,6 +3714,49 @@ var EvalsNamespace = class {
3420
3714
  run(config) {
3421
3715
  return new EvalRunner(this.getClient, config);
3422
3716
  }
3717
+ /**
3718
+ * Idempotently converge a `defineEval` suite definition onto the platform —
3719
+ * the deploy-time, non-executing converge for code-colocated evals. Hash-first:
3720
+ * the steady state is one tiny probe request. Upserts the eval suite + replaces
3721
+ * its cases; never runs the eval.
3722
+ *
3723
+ * @example
3724
+ * ```typescript
3725
+ * const suite = defineEval({
3726
+ * target: { flow: 'support-triage' },
3727
+ * graders: [noError()],
3728
+ * cases: [{ name: 'billing', input: { variables: { message: 'I was double charged' } }, expect: [contains('finance')] }],
3729
+ * })
3730
+ * const result = await Runtype.evals.ensure(suite)
3731
+ * ```
3732
+ */
3733
+ async ensure(definition) {
3734
+ return ensureEval(this.getClient(), definition);
3735
+ }
3736
+ /**
3737
+ * Pull the canonical definition + provenance for an eval suite by name — the
3738
+ * absorb-drift direction of the ensure protocol.
3739
+ */
3740
+ async pull(name) {
3741
+ return pullEval(this.getClient(), name);
3742
+ }
3743
+ /**
3744
+ * Run an eval suite synchronously and return the suite score + per-case grader
3745
+ * outcomes — the executing counterpart of `ensure`, powering the `runtype
3746
+ * eval` CI gate. Run a saved suite by id (`{ suiteId }`, the post-`ensure`
3747
+ * path) or an inline definition without persisting (`{ definition }`, the
3748
+ * virtual path).
3749
+ *
3750
+ * @example
3751
+ * ```typescript
3752
+ * const { suiteId } = await Runtype.evals.ensure(suite)
3753
+ * const result = await Runtype.evals.runSuite({ suiteId })
3754
+ * if (!result.passed) process.exit(1)
3755
+ * ```
3756
+ */
3757
+ async runSuite(input) {
3758
+ return runEvalSuite(this.getClient(), input);
3759
+ }
3423
3760
  /**
3424
3761
  * Get evaluation status by ID
3425
3762
  *
@@ -3538,14 +3875,14 @@ var PromptsNamespace = class {
3538
3875
  };
3539
3876
 
3540
3877
  // src/skills-ensure.ts
3541
- function isPlainObject2(value) {
3878
+ function isPlainObject3(value) {
3542
3879
  return value !== null && typeof value === "object" && !Array.isArray(value);
3543
3880
  }
3544
3881
  function normalizeValue(value) {
3545
3882
  if (Array.isArray(value)) {
3546
3883
  return value.map((item) => normalizeValue(item));
3547
3884
  }
3548
- if (isPlainObject2(value)) {
3885
+ if (isPlainObject3(value)) {
3549
3886
  const normalized = {};
3550
3887
  for (const key of Object.keys(value).sort()) {
3551
3888
  const entry = value[key];
@@ -3557,15 +3894,15 @@ function normalizeValue(value) {
3557
3894
  return value;
3558
3895
  }
3559
3896
  function normalizeSkillDefinition(definition) {
3560
- const manifest = isPlainObject2(definition.manifest) ? definition.manifest : {};
3561
- const rawFrontmatter = isPlainObject2(manifest.frontmatter) ? manifest.frontmatter : {};
3897
+ const manifest = isPlainObject3(definition.manifest) ? definition.manifest : {};
3898
+ const rawFrontmatter = isPlainObject3(manifest.frontmatter) ? manifest.frontmatter : {};
3562
3899
  const frontmatterWithoutName = {};
3563
3900
  for (const key of Object.keys(rawFrontmatter)) {
3564
3901
  if (key === "name") continue;
3565
3902
  frontmatterWithoutName[key] = rawFrontmatter[key];
3566
3903
  }
3567
3904
  const frontmatter = normalizeValue(frontmatterWithoutName);
3568
- const runtype = isPlainObject2(manifest.runtype) ? normalizeValue(manifest.runtype) : {};
3905
+ const runtype = isPlainObject3(manifest.runtype) ? normalizeValue(manifest.runtype) : {};
3569
3906
  const body = typeof manifest.body === "string" ? manifest.body : "";
3570
3907
  return { frontmatter, runtype, body };
3571
3908
  }
@@ -3583,7 +3920,7 @@ function defineSkill(input) {
3583
3920
  if (typeof input.name !== "string" || input.name.length === 0) {
3584
3921
  throw new Error('defineSkill requires a non-empty string "name"');
3585
3922
  }
3586
- if (!isPlainObject2(input.manifest)) {
3923
+ if (!isPlainObject3(input.manifest)) {
3587
3924
  throw new Error('defineSkill requires a "manifest" object ({ frontmatter, runtype, body })');
3588
3925
  }
3589
3926
  const unknownKeys = Object.keys(input).filter((key) => !DEFINE_SKILL_TOP_LEVEL_KEYS.has(key));
@@ -3593,7 +3930,7 @@ function defineSkill(input) {
3593
3930
  );
3594
3931
  }
3595
3932
  const frontmatter = input.manifest.frontmatter;
3596
- if (!isPlainObject2(frontmatter) || typeof frontmatter.name !== "string") {
3933
+ if (!isPlainObject3(frontmatter) || typeof frontmatter.name !== "string") {
3597
3934
  throw new Error("defineSkill: manifest.frontmatter.name is required");
3598
3935
  }
3599
3936
  if (frontmatter.name !== input.name) {
@@ -3634,19 +3971,19 @@ function parseRequestError2(err) {
3634
3971
  }
3635
3972
  function toConflictError2(err) {
3636
3973
  const { status, body } = parseRequestError2(err);
3637
- if (status !== 409 || !isPlainObject2(body)) return null;
3974
+ if (status !== 409 || !isPlainObject3(body)) return null;
3638
3975
  const code = body.code;
3639
3976
  if (code !== "external_modification" && code !== "remote_changed") return null;
3640
3977
  return new SkillEnsureConflictError(
3641
3978
  body
3642
3979
  );
3643
3980
  }
3644
- var serverHashMemo2 = /* @__PURE__ */ new WeakMap();
3645
- function memoFor2(client) {
3646
- let memo = serverHashMemo2.get(client);
3981
+ var serverHashMemo3 = /* @__PURE__ */ new WeakMap();
3982
+ function memoFor3(client) {
3983
+ let memo = serverHashMemo3.get(client);
3647
3984
  if (!memo) {
3648
3985
  memo = /* @__PURE__ */ new Map();
3649
- serverHashMemo2.set(client, memo);
3986
+ serverHashMemo3.set(client, memo);
3650
3987
  }
3651
3988
  return memo;
3652
3989
  }
@@ -3687,7 +4024,7 @@ async function ensureSkill(client, definition, options = {}) {
3687
4024
  }
3688
4025
  return plan;
3689
4026
  }
3690
- const memo = memoFor2(client);
4027
+ const memo = memoFor3(client);
3691
4028
  const localHash = await computeSkillContentHash(definition);
3692
4029
  const memoKey = `${definition.name} ${localHash}`;
3693
4030
  const contentHash = memo.get(memoKey) ?? localHash;
@@ -3982,14 +4319,14 @@ var AGENT_CONFIG_KEYS = [
3982
4319
  "tenancyStrategy"
3983
4320
  ];
3984
4321
  var AGENT_CONFIG_KEY_LIST = [...AGENT_CONFIG_KEYS].sort();
3985
- function isPlainObject3(value) {
4322
+ function isPlainObject4(value) {
3986
4323
  return value !== null && typeof value === "object" && !Array.isArray(value);
3987
4324
  }
3988
4325
  function normalizeValue2(value) {
3989
4326
  if (Array.isArray(value)) {
3990
4327
  return value.map((item) => normalizeValue2(item));
3991
4328
  }
3992
- if (isPlainObject3(value)) {
4329
+ if (isPlainObject4(value)) {
3993
4330
  const normalized = {};
3994
4331
  for (const key of Object.keys(value).sort()) {
3995
4332
  const entry = value[key];
@@ -4002,7 +4339,7 @@ function normalizeValue2(value) {
4002
4339
  }
4003
4340
  function normalizeAgentDefinition(definition) {
4004
4341
  const config = {};
4005
- const rawConfig = isPlainObject3(definition.config) ? definition.config : {};
4342
+ const rawConfig = isPlainObject4(definition.config) ? definition.config : {};
4006
4343
  for (const key of AGENT_CONFIG_KEY_LIST) {
4007
4344
  const value = rawConfig[key];
4008
4345
  if (value === void 0 || value === null) continue;
@@ -4024,7 +4361,7 @@ async function computeAgentContentHash(definition) {
4024
4361
  var DEFINE_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set(["name", "description", "icon", ...AGENT_CONFIG_KEYS]);
4025
4362
  function collectNonPortableToolRefs(config) {
4026
4363
  const tools = config.tools;
4027
- if (!isPlainObject3(tools)) return [];
4364
+ if (!isPlainObject4(tools)) return [];
4028
4365
  const found = [];
4029
4366
  const isAccountScoped = (ref) => typeof ref === "string" && ref.startsWith("tool_");
4030
4367
  const scanArray = (value, path) => {
@@ -4034,7 +4371,7 @@ function collectNonPortableToolRefs(config) {
4034
4371
  });
4035
4372
  };
4036
4373
  const scanKeys = (value, path) => {
4037
- if (!isPlainObject3(value)) return;
4374
+ if (!isPlainObject4(value)) return;
4038
4375
  for (const key of Object.keys(value)) {
4039
4376
  if (isAccountScoped(key)) found.push(`${path}.${key}`);
4040
4377
  }
@@ -4042,16 +4379,16 @@ function collectNonPortableToolRefs(config) {
4042
4379
  scanArray(tools.toolIds, "tools.toolIds");
4043
4380
  scanKeys(tools.toolConfigs, "tools.toolConfigs");
4044
4381
  scanKeys(tools.perToolLimits, "tools.perToolLimits");
4045
- if (isPlainObject3(tools.approval)) scanArray(tools.approval.require, "tools.approval.require");
4046
- if (isPlainObject3(tools.subagentConfig)) {
4382
+ if (isPlainObject4(tools.approval)) scanArray(tools.approval.require, "tools.approval.require");
4383
+ if (isPlainObject4(tools.subagentConfig)) {
4047
4384
  scanArray(tools.subagentConfig.toolPool, "tools.subagentConfig.toolPool");
4048
4385
  }
4049
- if (isPlainObject3(tools.codeModeConfig)) {
4386
+ if (isPlainObject4(tools.codeModeConfig)) {
4050
4387
  scanArray(tools.codeModeConfig.toolPool, "tools.codeModeConfig.toolPool");
4051
4388
  }
4052
4389
  if (Array.isArray(tools.runtimeTools)) {
4053
4390
  tools.runtimeTools.forEach((runtimeTool, i) => {
4054
- if (!isPlainObject3(runtimeTool) || !isPlainObject3(runtimeTool.config)) return;
4391
+ if (!isPlainObject4(runtimeTool) || !isPlainObject4(runtimeTool.config)) return;
4055
4392
  const base = `tools.runtimeTools[${i}].config`;
4056
4393
  const rtConfig = runtimeTool.config;
4057
4394
  if (runtimeTool.toolType === "subagent" && typeof rtConfig.agentId === "string" && rtConfig.agentId.startsWith("agent_")) {
@@ -4125,19 +4462,19 @@ function parseRequestError3(err) {
4125
4462
  }
4126
4463
  function toConflictError3(err) {
4127
4464
  const { status, body } = parseRequestError3(err);
4128
- if (status !== 409 || !isPlainObject3(body)) return null;
4465
+ if (status !== 409 || !isPlainObject4(body)) return null;
4129
4466
  const code = body.code;
4130
4467
  if (code !== "external_modification" && code !== "remote_changed") return null;
4131
4468
  return new AgentEnsureConflictError(
4132
4469
  body
4133
4470
  );
4134
4471
  }
4135
- var serverHashMemo3 = /* @__PURE__ */ new WeakMap();
4136
- function memoFor3(client) {
4137
- let memo = serverHashMemo3.get(client);
4472
+ var serverHashMemo4 = /* @__PURE__ */ new WeakMap();
4473
+ function memoFor4(client) {
4474
+ let memo = serverHashMemo4.get(client);
4138
4475
  if (!memo) {
4139
4476
  memo = /* @__PURE__ */ new Map();
4140
- serverHashMemo3.set(client, memo);
4477
+ serverHashMemo4.set(client, memo);
4141
4478
  }
4142
4479
  return memo;
4143
4480
  }
@@ -4174,7 +4511,7 @@ var AgentsNamespace = class {
4174
4511
  }
4175
4512
  return plan;
4176
4513
  }
4177
- const memo = memoFor3(client);
4514
+ const memo = memoFor4(client);
4178
4515
  const localHash = await computeAgentContentHash({
4179
4516
  ...definition,
4180
4517
  config: definition.config
@@ -4227,14 +4564,14 @@ var AgentsNamespace = class {
4227
4564
  };
4228
4565
 
4229
4566
  // src/tools-ensure.ts
4230
- function isPlainObject4(value) {
4567
+ function isPlainObject5(value) {
4231
4568
  return value !== null && typeof value === "object" && !Array.isArray(value);
4232
4569
  }
4233
4570
  function normalizeValue3(value) {
4234
4571
  if (Array.isArray(value)) {
4235
4572
  return value.map((item) => normalizeValue3(item));
4236
4573
  }
4237
- if (isPlainObject4(value)) {
4574
+ if (isPlainObject5(value)) {
4238
4575
  const normalized = {};
4239
4576
  for (const key of Object.keys(value).sort()) {
4240
4577
  const entry = value[key];
@@ -4246,8 +4583,8 @@ function normalizeValue3(value) {
4246
4583
  return value;
4247
4584
  }
4248
4585
  function normalizeToolDefinition(definition) {
4249
- const parametersSchema = isPlainObject4(definition.parametersSchema) ? normalizeValue3(definition.parametersSchema) : {};
4250
- const config = isPlainObject4(definition.config) ? normalizeValue3(definition.config) : {};
4586
+ const parametersSchema = isPlainObject5(definition.parametersSchema) ? normalizeValue3(definition.parametersSchema) : {};
4587
+ const config = isPlainObject5(definition.config) ? normalizeValue3(definition.config) : {};
4251
4588
  return {
4252
4589
  toolType: definition.toolType,
4253
4590
  ...definition.description ? { description: definition.description } : {},
@@ -4292,10 +4629,10 @@ function defineTool(input) {
4292
4629
  `defineTool requires "toolType" to be one of: ${[...TOOL_DEFINITION_TYPES].join(", ")}`
4293
4630
  );
4294
4631
  }
4295
- if (!isPlainObject4(input.parametersSchema)) {
4632
+ if (!isPlainObject5(input.parametersSchema)) {
4296
4633
  throw new Error('defineTool requires a "parametersSchema" object (a JSON Schema)');
4297
4634
  }
4298
- if (!isPlainObject4(input.config)) {
4635
+ if (!isPlainObject5(input.config)) {
4299
4636
  throw new Error('defineTool requires a "config" object');
4300
4637
  }
4301
4638
  const unknownKeys = Object.keys(input).filter((key) => !DEFINE_TOOL_TOP_LEVEL_KEYS.has(key));
@@ -4343,19 +4680,19 @@ function parseRequestError4(err) {
4343
4680
  }
4344
4681
  function toConflictError4(err) {
4345
4682
  const { status, body } = parseRequestError4(err);
4346
- if (status !== 409 || !isPlainObject4(body)) return null;
4683
+ if (status !== 409 || !isPlainObject5(body)) return null;
4347
4684
  const code = body.code;
4348
4685
  if (code !== "external_modification" && code !== "remote_changed") return null;
4349
4686
  return new ToolEnsureConflictError(
4350
4687
  body
4351
4688
  );
4352
4689
  }
4353
- var serverHashMemo4 = /* @__PURE__ */ new WeakMap();
4354
- function memoFor4(client) {
4355
- let memo = serverHashMemo4.get(client);
4690
+ var serverHashMemo5 = /* @__PURE__ */ new WeakMap();
4691
+ function memoFor5(client) {
4692
+ let memo = serverHashMemo5.get(client);
4356
4693
  if (!memo) {
4357
4694
  memo = /* @__PURE__ */ new Map();
4358
- serverHashMemo4.set(client, memo);
4695
+ serverHashMemo5.set(client, memo);
4359
4696
  }
4360
4697
  return memo;
4361
4698
  }
@@ -4395,7 +4732,7 @@ async function ensureTool(client, definition, options = {}) {
4395
4732
  }
4396
4733
  return plan;
4397
4734
  }
4398
- const memo = memoFor4(client);
4735
+ const memo = memoFor5(client);
4399
4736
  const localHash = await computeToolContentHash(definition);
4400
4737
  const memoKey = `${definition.name} ${localHash}`;
4401
4738
  const contentHash = memo.get(memoKey) ?? localHash;
@@ -4463,14 +4800,14 @@ var ToolsNamespace = class {
4463
4800
  };
4464
4801
 
4465
4802
  // src/products-ensure.ts
4466
- function isPlainObject5(value) {
4803
+ function isPlainObject6(value) {
4467
4804
  return value !== null && typeof value === "object" && !Array.isArray(value);
4468
4805
  }
4469
4806
  function normalizeValue4(value) {
4470
4807
  if (Array.isArray(value)) {
4471
4808
  return value.map((item) => normalizeValue4(item));
4472
4809
  }
4473
- if (isPlainObject5(value)) {
4810
+ if (isPlainObject6(value)) {
4474
4811
  const normalized = {};
4475
4812
  for (const key of Object.keys(value).sort()) {
4476
4813
  const entry = value[key];
@@ -4482,7 +4819,7 @@ function normalizeValue4(value) {
4482
4819
  return value;
4483
4820
  }
4484
4821
  function normalizeProductDefinition(definition) {
4485
- const spec = isPlainObject5(definition.spec) ? normalizeValue4(definition.spec) : {};
4822
+ const spec = isPlainObject6(definition.spec) ? normalizeValue4(definition.spec) : {};
4486
4823
  return {
4487
4824
  ...definition.description ? { description: definition.description } : {},
4488
4825
  ...definition.icon ? { icon: definition.icon } : {},
@@ -4509,7 +4846,7 @@ function defineProduct(input) {
4509
4846
  if (input.icon != null && typeof input.icon !== "string") {
4510
4847
  throw new Error('defineProduct "icon" must be a string when provided');
4511
4848
  }
4512
- if (input.spec != null && !isPlainObject5(input.spec)) {
4849
+ if (input.spec != null && !isPlainObject6(input.spec)) {
4513
4850
  throw new Error('defineProduct "spec" must be an object when provided');
4514
4851
  }
4515
4852
  const unknownKeys = Object.keys(input).filter((key) => !DEFINE_PRODUCT_TOP_LEVEL_KEYS.has(key));
@@ -4556,19 +4893,19 @@ function parseRequestError5(err) {
4556
4893
  }
4557
4894
  function toConflictError5(err) {
4558
4895
  const { status, body } = parseRequestError5(err);
4559
- if (status !== 409 || !isPlainObject5(body)) return null;
4896
+ if (status !== 409 || !isPlainObject6(body)) return null;
4560
4897
  const code = body.code;
4561
4898
  if (code !== "external_modification" && code !== "remote_changed") return null;
4562
4899
  return new ProductEnsureConflictError(
4563
4900
  body
4564
4901
  );
4565
4902
  }
4566
- var serverHashMemo5 = /* @__PURE__ */ new WeakMap();
4567
- function memoFor5(client) {
4568
- let memo = serverHashMemo5.get(client);
4903
+ var serverHashMemo6 = /* @__PURE__ */ new WeakMap();
4904
+ function memoFor6(client) {
4905
+ let memo = serverHashMemo6.get(client);
4569
4906
  if (!memo) {
4570
4907
  memo = /* @__PURE__ */ new Map();
4571
- serverHashMemo5.set(client, memo);
4908
+ serverHashMemo6.set(client, memo);
4572
4909
  }
4573
4910
  return memo;
4574
4911
  }
@@ -4608,7 +4945,7 @@ async function ensureProduct(client, definition, options = {}) {
4608
4945
  }
4609
4946
  return plan;
4610
4947
  }
4611
- const memo = memoFor5(client);
4948
+ const memo = memoFor6(client);
4612
4949
  const localHash = await computeProductContentHash(definition);
4613
4950
  const memoKey = `${definition.name} ${localHash}`;
4614
4951
  const contentHash = memo.get(memoKey) ?? localHash;
@@ -4637,14 +4974,14 @@ async function pullProduct(client, name) {
4637
4974
  }
4638
4975
 
4639
4976
  // src/products-ensure-fpo.ts
4640
- function isPlainObject6(value) {
4977
+ function isPlainObject7(value) {
4641
4978
  return value !== null && typeof value === "object" && !Array.isArray(value);
4642
4979
  }
4643
4980
  function normalizeValue5(value) {
4644
4981
  if (Array.isArray(value)) {
4645
4982
  return value.map((item) => normalizeValue5(item));
4646
4983
  }
4647
- if (isPlainObject6(value)) {
4984
+ if (isPlainObject7(value)) {
4648
4985
  const normalized = {};
4649
4986
  for (const key of Object.keys(value).sort()) {
4650
4987
  const entry = value[key];
@@ -4656,7 +4993,7 @@ function normalizeValue5(value) {
4656
4993
  return value;
4657
4994
  }
4658
4995
  function normalizeFpoDefinition(fpo) {
4659
- const productInput = isPlainObject6(fpo.product) ? fpo.product : {};
4996
+ const productInput = isPlainObject7(fpo.product) ? fpo.product : {};
4660
4997
  const { name: _identityName, ...productRest } = productInput;
4661
4998
  const product = normalizeValue5(productRest);
4662
4999
  return {
@@ -4677,10 +5014,10 @@ async function computeFpoContentHash(fpo) {
4677
5014
  return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
4678
5015
  }
4679
5016
  function defineFpo(fpo) {
4680
- if (!isPlainObject6(fpo)) {
5017
+ if (!isPlainObject7(fpo)) {
4681
5018
  throw new Error("defineFpo requires an FPO object");
4682
5019
  }
4683
- const product = isPlainObject6(fpo.product) ? fpo.product : void 0;
5020
+ const product = isPlainObject7(fpo.product) ? fpo.product : void 0;
4684
5021
  if (!product || typeof product.name !== "string" || product.name.length === 0) {
4685
5022
  throw new Error('defineFpo requires a non-empty "product.name" (the converge identity)');
4686
5023
  }
@@ -4776,14 +5113,14 @@ var ProductsNamespace = class {
4776
5113
  };
4777
5114
 
4778
5115
  // src/surfaces-ensure.ts
4779
- function isPlainObject7(value) {
5116
+ function isPlainObject8(value) {
4780
5117
  return value !== null && typeof value === "object" && !Array.isArray(value);
4781
5118
  }
4782
5119
  function normalizeValue6(value) {
4783
5120
  if (Array.isArray(value)) {
4784
5121
  return value.map((item) => normalizeValue6(item));
4785
5122
  }
4786
- if (isPlainObject7(value)) {
5123
+ if (isPlainObject8(value)) {
4787
5124
  const normalized = {};
4788
5125
  for (const key of Object.keys(value).sort()) {
4789
5126
  const entry = value[key];
@@ -4795,7 +5132,7 @@ function normalizeValue6(value) {
4795
5132
  return value;
4796
5133
  }
4797
5134
  function normalizeSurfaceDefinition(definition) {
4798
- const behavior = isPlainObject7(definition.behavior) ? normalizeValue6(definition.behavior) : { type: definition.type };
5135
+ const behavior = isPlainObject8(definition.behavior) ? normalizeValue6(definition.behavior) : { type: definition.type };
4799
5136
  return {
4800
5137
  type: definition.type,
4801
5138
  behavior,
@@ -4848,13 +5185,13 @@ function defineSurface(input) {
4848
5185
  `defineSurface requires "type" to be one of: ${[...SURFACE_DEFINITION_TYPES].join(", ")}`
4849
5186
  );
4850
5187
  }
4851
- if (input.behavior !== void 0 && !isPlainObject7(input.behavior)) {
5188
+ if (input.behavior !== void 0 && !isPlainObject8(input.behavior)) {
4852
5189
  throw new Error('defineSurface "behavior" must be an object when provided');
4853
5190
  }
4854
- if (input.inbound !== void 0 && !isPlainObject7(input.inbound)) {
5191
+ if (input.inbound !== void 0 && !isPlainObject8(input.inbound)) {
4855
5192
  throw new Error('defineSurface "inbound" must be an object when provided');
4856
5193
  }
4857
- if (input.outbound !== void 0 && !isPlainObject7(input.outbound)) {
5194
+ if (input.outbound !== void 0 && !isPlainObject8(input.outbound)) {
4858
5195
  throw new Error('defineSurface "outbound" must be an object when provided');
4859
5196
  }
4860
5197
  if (input.status !== void 0 && !["draft", "active", "paused"].includes(input.status)) {
@@ -4910,19 +5247,19 @@ function parseRequestError6(err) {
4910
5247
  }
4911
5248
  function toConflictError6(err) {
4912
5249
  const { status, body } = parseRequestError6(err);
4913
- if (status !== 409 || !isPlainObject7(body)) return null;
5250
+ if (status !== 409 || !isPlainObject8(body)) return null;
4914
5251
  const code = body.code;
4915
5252
  if (code !== "external_modification" && code !== "remote_changed") return null;
4916
5253
  return new SurfaceEnsureConflictError(
4917
5254
  body
4918
5255
  );
4919
5256
  }
4920
- var serverHashMemo6 = /* @__PURE__ */ new WeakMap();
4921
- function memoFor6(client) {
4922
- let memo = serverHashMemo6.get(client);
5257
+ var serverHashMemo7 = /* @__PURE__ */ new WeakMap();
5258
+ function memoFor7(client) {
5259
+ let memo = serverHashMemo7.get(client);
4923
5260
  if (!memo) {
4924
5261
  memo = /* @__PURE__ */ new Map();
4925
- serverHashMemo6.set(client, memo);
5262
+ serverHashMemo7.set(client, memo);
4926
5263
  }
4927
5264
  return memo;
4928
5265
  }
@@ -4962,7 +5299,7 @@ async function ensureSurface(client, productId, definition, options = {}) {
4962
5299
  }
4963
5300
  return plan;
4964
5301
  }
4965
- const memo = memoFor6(client);
5302
+ const memo = memoFor7(client);
4966
5303
  const localHash = await computeSurfaceContentHash(definition);
4967
5304
  const memoKey = `${productId} ${definition.name} ${localHash}`;
4968
5305
  const contentHash = memo.get(memoKey) ?? localHash;
@@ -5511,7 +5848,7 @@ var Runtype = class {
5511
5848
 
5512
5849
  // src/version.ts
5513
5850
  var FALLBACK_VERSION = "0.0.0";
5514
- var SDK_VERSION = "5.3.1".length > 0 ? "5.3.1" : FALLBACK_VERSION;
5851
+ var SDK_VERSION = "5.4.0".length > 0 ? "5.4.0" : FALLBACK_VERSION;
5515
5852
  var RUNTYPE_CLIENT_KIND = "sdk";
5516
5853
  var SDK_USER_AGENT = `runtype-sdk/${SDK_VERSION} (typescript)`;
5517
5854
 
@@ -13223,12 +13560,14 @@ export {
13223
13560
  buildSendViewOffloadMarker,
13224
13561
  compileWorkflowConfig,
13225
13562
  computeAgentContentHash,
13563
+ computeEvalContentHash,
13226
13564
  computeFlowContentHash,
13227
13565
  computeFpoContentHash,
13228
13566
  computeProductContentHash,
13229
13567
  computeSkillContentHash,
13230
13568
  computeSurfaceContentHash,
13231
13569
  computeToolContentHash,
13570
+ contains,
13232
13571
  createAgentEventTranslator,
13233
13572
  createClient,
13234
13573
  createExternalTool,
@@ -13236,6 +13575,7 @@ export {
13236
13575
  defaultWorkflow,
13237
13576
  defaultWorkflowConfig,
13238
13577
  defineAgent,
13578
+ defineEval,
13239
13579
  defineFlow,
13240
13580
  defineFpo,
13241
13581
  definePlaybook,
@@ -13245,6 +13585,7 @@ export {
13245
13585
  defineTool,
13246
13586
  deployWorkflow,
13247
13587
  ensureDefaultWorkflowHooks,
13588
+ ensureEval,
13248
13589
  ensureFpo,
13249
13590
  evaluateGeneratedRuntimeToolProposal,
13250
13591
  extractDeclaredToolResultChars,
@@ -13257,7 +13598,14 @@ export {
13257
13598
  isPreservationSensitiveTask,
13258
13599
  isUnifiedEventType,
13259
13600
  isWorkflowHookRef,
13601
+ jsonField,
13602
+ judge,
13603
+ judges,
13604
+ latency,
13605
+ length,
13260
13606
  listWorkflowHooks,
13607
+ matchesExpected,
13608
+ noError,
13261
13609
  normalizeAgentDefinition,
13262
13610
  normalizeCandidatePath,
13263
13611
  normalizeFpoDefinition,
@@ -13265,19 +13613,24 @@ export {
13265
13613
  normalizeSkillDefinition,
13266
13614
  normalizeSurfaceDefinition,
13267
13615
  normalizeToolDefinition,
13616
+ notContains,
13268
13617
  parseFinalBuffer,
13269
13618
  parseLedgerArtifactRelativePath,
13270
13619
  parseOffloadedOutputId,
13271
13620
  parseSSEChunk,
13272
13621
  processStream,
13622
+ pullEval,
13273
13623
  pullFpo,
13624
+ regex,
13274
13625
  registerWorkflowHook,
13275
13626
  resolveStallStopAfter,
13276
13627
  resolveWorkflowHook,
13628
+ runEvalSuite,
13277
13629
  sanitizeTaskSlug,
13278
13630
  shouldInjectEmptySessionNudge,
13279
13631
  shouldRequestModelEscalation,
13280
13632
  streamEvents,
13281
13633
  unregisterWorkflowHook,
13634
+ validJson,
13282
13635
  withUnifiedEvents
13283
13636
  };