@runtypelabs/sdk 5.3.1 → 5.5.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,368 @@ 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
+ // Trace checks.
3291
+ "called_tool",
3292
+ "not_called_tool",
3293
+ "used_no_tools",
3294
+ "max_tool_calls",
3295
+ "tool_order",
3296
+ "ran_step",
3297
+ "step_order",
3298
+ "completed",
3299
+ "cost"
3300
+ ]);
3301
+ function contains(value, opts) {
3302
+ return { kind: "contains", value, ...opts?.caseSensitive ? { caseSensitive: true } : {} };
3303
+ }
3304
+ function notContains(value, opts) {
3305
+ return { kind: "not_contains", value, ...opts?.caseSensitive ? { caseSensitive: true } : {} };
3306
+ }
3307
+ function matchesExpected() {
3308
+ return { kind: "matches_expected" };
3309
+ }
3310
+ function regex(pattern, flags) {
3311
+ return { kind: "regex", pattern, ...flags ? { flags } : {} };
3312
+ }
3313
+ function validJson() {
3314
+ return { kind: "valid_json" };
3315
+ }
3316
+ function jsonField(path, opts) {
3317
+ return {
3318
+ kind: "json_field",
3319
+ path,
3320
+ ...opts && "equals" in opts && opts.equals !== void 0 ? { equals: opts.equals } : {},
3321
+ ...opts && typeof opts.exists === "boolean" ? { exists: opts.exists } : {}
3322
+ };
3323
+ }
3324
+ function length(opts) {
3325
+ if (!opts || opts.minChars === void 0 && opts.maxChars === void 0) {
3326
+ throw new Error("length() requires at least one of minChars or maxChars");
3327
+ }
3328
+ return {
3329
+ kind: "length",
3330
+ ...opts.minChars !== void 0 ? { minChars: opts.minChars } : {},
3331
+ ...opts.maxChars !== void 0 ? { maxChars: opts.maxChars } : {}
3332
+ };
3333
+ }
3334
+ function latency(maxMs) {
3335
+ if (!Number.isFinite(maxMs) || maxMs <= 0) {
3336
+ throw new Error("latency() requires a positive maxMs");
3337
+ }
3338
+ return { kind: "latency", maxMs };
3339
+ }
3340
+ function noError() {
3341
+ return { kind: "no_error" };
3342
+ }
3343
+ function calledTool(name, opts) {
3344
+ if (typeof name !== "string" || name.length === 0) {
3345
+ throw new Error("calledTool() requires a non-empty tool name");
3346
+ }
3347
+ if (opts?.times !== void 0 && (!Number.isInteger(opts.times) || opts.times <= 0)) {
3348
+ throw new Error('calledTool() "times" must be a positive integer');
3349
+ }
3350
+ return {
3351
+ kind: "called_tool",
3352
+ name,
3353
+ ...opts && "input" in opts && opts.input !== void 0 ? { input: opts.input } : {},
3354
+ ...opts && "output" in opts && opts.output !== void 0 ? { output: opts.output } : {},
3355
+ ...opts && typeof opts.isError === "boolean" ? { isError: opts.isError } : {},
3356
+ ...opts?.times !== void 0 ? { times: opts.times } : {}
3357
+ };
3358
+ }
3359
+ function notCalledTool(name) {
3360
+ if (typeof name !== "string" || name.length === 0) {
3361
+ throw new Error("notCalledTool() requires a non-empty tool name");
3362
+ }
3363
+ return { kind: "not_called_tool", name };
3364
+ }
3365
+ function usedNoTools() {
3366
+ return { kind: "used_no_tools" };
3367
+ }
3368
+ function maxToolCalls(max) {
3369
+ if (!Number.isInteger(max) || max < 0) {
3370
+ throw new Error("maxToolCalls() requires a non-negative integer");
3371
+ }
3372
+ return { kind: "max_tool_calls", max };
3373
+ }
3374
+ function toolOrder(tools) {
3375
+ if (!Array.isArray(tools) || tools.length === 0) {
3376
+ throw new Error("toolOrder() requires a non-empty array of tool names");
3377
+ }
3378
+ return { kind: "tool_order", tools };
3379
+ }
3380
+ function ranStep(name) {
3381
+ if (typeof name !== "string" || name.length === 0) {
3382
+ throw new Error("ranStep() requires a non-empty step name");
3383
+ }
3384
+ return { kind: "ran_step", name };
3385
+ }
3386
+ function stepOrder(steps) {
3387
+ if (!Array.isArray(steps) || steps.length === 0) {
3388
+ throw new Error("stepOrder() requires a non-empty array of step names");
3389
+ }
3390
+ return { kind: "step_order", steps };
3391
+ }
3392
+ function completed() {
3393
+ return { kind: "completed" };
3394
+ }
3395
+ function cost(maxUsd) {
3396
+ if (!Number.isFinite(maxUsd) || maxUsd <= 0) {
3397
+ throw new Error("cost() requires a positive maxUsd");
3398
+ }
3399
+ return { kind: "cost", maxUsd };
3400
+ }
3401
+ function judge(criteria, opts) {
3402
+ if (typeof criteria !== "string" || criteria.trim().length === 0) {
3403
+ throw new Error("judge() requires non-empty criteria");
3404
+ }
3405
+ return {
3406
+ kind: "ai",
3407
+ criteria,
3408
+ ...opts?.preset ? { preset: opts.preset } : {},
3409
+ ...opts?.useExpected ? { useExpected: true } : {},
3410
+ ...opts?.model ? { model: opts.model } : {},
3411
+ ...opts?.threshold !== void 0 ? { threshold: opts.threshold } : {}
3412
+ };
3413
+ }
3414
+ var judges = {
3415
+ answersQuestion: () => judge(
3416
+ "The response directly addresses what the user asked, without dodging or answering a different question.",
3417
+ { preset: "answersQuestion" }
3418
+ ),
3419
+ matchesExpected: () => judge(
3420
+ "The response conveys the same facts and conclusion as the expected answer. Wording may differ.",
3421
+ { preset: "matchesExpected", useExpected: true }
3422
+ ),
3423
+ followsInstructions: () => judge(
3424
+ "The response obeys every instruction in the system prompt (format, tone, constraints, refusals).",
3425
+ { preset: "followsInstructions" }
3426
+ ),
3427
+ grounded: () => judge(
3428
+ "Every factual claim in the response is supported by the provided context or the expected answer. Flag anything invented.",
3429
+ { preset: "grounded" }
3430
+ ),
3431
+ rightTone: (voice = "{describe the voice you want}") => judge(`The response matches this voice: ${voice}.`, { preset: "rightTone" }),
3432
+ safeToSend: () => judge(
3433
+ "The response contains nothing embarrassing to show a customer: no leaked internals, no hostile tone, no policy violations.",
3434
+ { preset: "safeToSend" }
3435
+ )
3436
+ };
3437
+ var DEFINE_EVAL_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
3438
+ "name",
3439
+ "target",
3440
+ "graders",
3441
+ "cases",
3442
+ "virtual"
3443
+ ]);
3444
+ var DEFINE_EVAL_CASE_KEYS = /* @__PURE__ */ new Set(["name", "input", "expected", "expect"]);
3445
+ function isPlainObject2(value) {
3446
+ return value !== null && typeof value === "object" && !Array.isArray(value);
3447
+ }
3448
+ function normalizeTarget(target) {
3449
+ if (!isPlainObject2(target)) {
3450
+ throw new Error('defineEval requires a "target" object: { flow: name } or { agent: name }');
3451
+ }
3452
+ const hasFlow = typeof target.flow === "string" && target.flow.length > 0;
3453
+ const hasAgent = typeof target.agent === "string" && target.agent.length > 0;
3454
+ if (hasFlow === hasAgent) {
3455
+ throw new Error(
3456
+ 'defineEval "target" must name exactly one of flow or agent: { flow: "name" } XOR { agent: "name" }'
3457
+ );
3458
+ }
3459
+ const extraKeys = Object.keys(target).filter((k) => k !== "flow" && k !== "agent");
3460
+ if (extraKeys.length > 0) {
3461
+ throw new Error(`defineEval "target" has unknown field(s): ${extraKeys.join(", ")}`);
3462
+ }
3463
+ return hasFlow ? { flow: target.flow } : { agent: target.agent };
3464
+ }
3465
+ function validateGrader(grader, where) {
3466
+ if (!isPlainObject2(grader) || typeof grader.kind !== "string") {
3467
+ throw new Error(`defineEval: ${where} must be a grader object with a string "kind"`);
3468
+ }
3469
+ if (grader.kind === "ai") {
3470
+ if (typeof grader.criteria !== "string" || grader.criteria.trim().length === 0) {
3471
+ throw new Error(`defineEval: ${where} is an AI grader and requires non-empty "criteria"`);
3472
+ }
3473
+ return grader;
3474
+ }
3475
+ if (!CHECK_GRADER_KINDS.has(grader.kind)) {
3476
+ throw new Error(
3477
+ `defineEval: ${where} has unknown grader kind "${grader.kind}". Known kinds: ${[...CHECK_GRADER_KINDS].join(", ")}, ai.`
3478
+ );
3479
+ }
3480
+ return grader;
3481
+ }
3482
+ function normalizeCaseInput(input, where) {
3483
+ if (input === void 0) return {};
3484
+ if (!isPlainObject2(input)) {
3485
+ throw new Error(`defineEval: ${where} "input" must be an object`);
3486
+ }
3487
+ const out = {};
3488
+ if (input.variables !== void 0) {
3489
+ if (!isPlainObject2(input.variables)) {
3490
+ throw new Error(`defineEval: ${where} "input.variables" must be an object`);
3491
+ }
3492
+ out.variables = input.variables;
3493
+ }
3494
+ if (input.messages !== void 0) {
3495
+ if (!Array.isArray(input.messages)) {
3496
+ throw new Error(`defineEval: ${where} "input.messages" must be an array`);
3497
+ }
3498
+ out.messages = input.messages.map((m, i) => {
3499
+ if (!isPlainObject2(m) || typeof m.role !== "string" || typeof m.content !== "string") {
3500
+ throw new Error(`defineEval: ${where} "input.messages[${i}]" must be { role, content }`);
3501
+ }
3502
+ return { role: m.role, content: m.content };
3503
+ });
3504
+ }
3505
+ return out;
3506
+ }
3507
+ function defineEval(input) {
3508
+ if (!input || typeof input !== "object") {
3509
+ throw new Error("defineEval requires a definition object");
3510
+ }
3511
+ const unknownKeys = Object.keys(input).filter((k) => !DEFINE_EVAL_TOP_LEVEL_KEYS.has(k));
3512
+ if (unknownKeys.length > 0) {
3513
+ throw new Error(
3514
+ `defineEval: unknown field(s): ${unknownKeys.join(", ")}. Allowed fields are target, graders, cases, virtual.`
3515
+ );
3516
+ }
3517
+ const target = normalizeTarget(input.target);
3518
+ if (input.name !== void 0 && (typeof input.name !== "string" || input.name.length === 0)) {
3519
+ throw new Error('defineEval "name" must be a non-empty string when provided');
3520
+ }
3521
+ const name = input.name ?? ("flow" in target ? `flow:${target.flow}` : `agent:${target.agent}`);
3522
+ const suiteGraders = (input.graders ?? []).map((g, i) => validateGrader(g, `graders[${i}]`));
3523
+ if (!Array.isArray(input.cases) || input.cases.length === 0) {
3524
+ throw new Error('defineEval requires a non-empty "cases" array');
3525
+ }
3526
+ const seenNames = /* @__PURE__ */ new Set();
3527
+ const cases = input.cases.map((c, index) => {
3528
+ if (!isPlainObject2(c)) {
3529
+ throw new Error(`defineEval: cases[${index}] must be an object`);
3530
+ }
3531
+ if (typeof c.name !== "string" || c.name.length === 0) {
3532
+ throw new Error(`defineEval: cases[${index}] requires a non-empty string "name"`);
3533
+ }
3534
+ if (seenNames.has(c.name)) {
3535
+ throw new Error(`defineEval: duplicate case name "${c.name}" (case names are the identity)`);
3536
+ }
3537
+ seenNames.add(c.name);
3538
+ const unknownCaseKeys = Object.keys(c).filter((k) => !DEFINE_EVAL_CASE_KEYS.has(k));
3539
+ if (unknownCaseKeys.length > 0) {
3540
+ throw new Error(
3541
+ `defineEval: cases[${index}] ("${c.name}") has unknown field(s): ${unknownCaseKeys.join(
3542
+ ", "
3543
+ )}. Allowed case fields are name, input, expected, expect.`
3544
+ );
3545
+ }
3546
+ const caseGraders = (c.expect ?? []).map(
3547
+ (g, i) => validateGrader(g, `cases[${index}].expect[${i}]`)
3548
+ );
3549
+ const expect = [...suiteGraders, ...caseGraders];
3550
+ if (expect.length === 0) {
3551
+ throw new Error(
3552
+ `defineEval: cases[${index}] ("${c.name}") has no graders. Add suite-level "graders" or case-level "expect" so there is something to score.`
3553
+ );
3554
+ }
3555
+ if (c.expected !== void 0 && !isPlainObject2(c.expected)) {
3556
+ throw new Error(`defineEval: cases[${index}] ("${c.name}") "expected" must be an object`);
3557
+ }
3558
+ return {
3559
+ name: c.name,
3560
+ input: normalizeCaseInput(c.input, `cases[${index}] ("${c.name}")`),
3561
+ ...c.expected !== void 0 ? { expected: c.expected } : {},
3562
+ expect
3563
+ };
3564
+ });
3565
+ return { name, target, cases, virtual: input.virtual === true };
3566
+ }
3567
+ function normalizeForHash(value) {
3568
+ if (Array.isArray(value)) return value.map(normalizeForHash);
3569
+ if (isPlainObject2(value)) {
3570
+ const out = {};
3571
+ for (const key of Object.keys(value).sort()) {
3572
+ const v = value[key];
3573
+ if (v === void 0) continue;
3574
+ out[key] = normalizeForHash(v);
3575
+ }
3576
+ return out;
3577
+ }
3578
+ return value;
3579
+ }
3580
+ async function computeEvalContentHash(definition) {
3581
+ const canonical = {
3582
+ target: normalizeForHash(definition.target),
3583
+ virtual: definition.virtual,
3584
+ cases: [...definition.cases].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0).map((c) => ({
3585
+ name: c.name,
3586
+ input: normalizeForHash(c.input),
3587
+ ...c.expected !== void 0 ? { expected: normalizeForHash(c.expected) } : {},
3588
+ // Grader order preserved on purpose (it maps to the result index).
3589
+ expect: c.expect.map((g) => normalizeForHash(g))
3590
+ }))
3591
+ };
3592
+ const serialized = JSON.stringify(canonical);
3593
+ const encoded = new TextEncoder().encode(serialized);
3594
+ const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
3595
+ return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
3596
+ }
3597
+ var serverHashMemo2 = /* @__PURE__ */ new WeakMap();
3598
+ function memoFor2(client) {
3599
+ let memo = serverHashMemo2.get(client);
3600
+ if (!memo) {
3601
+ memo = /* @__PURE__ */ new Map();
3602
+ serverHashMemo2.set(client, memo);
3603
+ }
3604
+ return memo;
3605
+ }
3606
+ async function ensureEval(client, definition) {
3607
+ if (definition.virtual) {
3608
+ throw new Error(
3609
+ "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."
3610
+ );
3611
+ }
3612
+ const memo = memoFor2(client);
3613
+ const localHash = await computeEvalContentHash(definition);
3614
+ const memoKey = `${definition.name} ${localHash}`;
3615
+ const contentHash = memo.get(memoKey) ?? localHash;
3616
+ const probe = await client.post(
3617
+ "/eval/ensure",
3618
+ { name: definition.name, contentHash }
3619
+ );
3620
+ if (probe.result !== "definitionRequired") {
3621
+ memo.set(memoKey, probe.contentHash);
3622
+ return probe;
3623
+ }
3624
+ const converged = await client.post(
3625
+ "/eval/ensure",
3626
+ { name: definition.name, definition }
3627
+ );
3628
+ if (converged.result === "definitionRequired") {
3629
+ throw new Error("Server reported definitionRequired for a full-definition request");
3630
+ }
3631
+ memo.set(memoKey, converged.contentHash);
3632
+ return converged;
3633
+ }
3634
+ async function pullEval(client, name) {
3635
+ return client.get("/eval/pull", { name });
3636
+ }
3637
+ async function runEvalSuite(client, input) {
3638
+ return client.post("/eval/run", input);
3639
+ }
3640
+
3279
3641
  // src/evals-namespace.ts
3280
3642
  var EvalRunner = class {
3281
3643
  constructor(getClient, config) {
@@ -3420,6 +3782,49 @@ var EvalsNamespace = class {
3420
3782
  run(config) {
3421
3783
  return new EvalRunner(this.getClient, config);
3422
3784
  }
3785
+ /**
3786
+ * Idempotently converge a `defineEval` suite definition onto the platform —
3787
+ * the deploy-time, non-executing converge for code-colocated evals. Hash-first:
3788
+ * the steady state is one tiny probe request. Upserts the eval suite + replaces
3789
+ * its cases; never runs the eval.
3790
+ *
3791
+ * @example
3792
+ * ```typescript
3793
+ * const suite = defineEval({
3794
+ * target: { flow: 'support-triage' },
3795
+ * graders: [noError()],
3796
+ * cases: [{ name: 'billing', input: { variables: { message: 'I was double charged' } }, expect: [contains('finance')] }],
3797
+ * })
3798
+ * const result = await Runtype.evals.ensure(suite)
3799
+ * ```
3800
+ */
3801
+ async ensure(definition) {
3802
+ return ensureEval(this.getClient(), definition);
3803
+ }
3804
+ /**
3805
+ * Pull the canonical definition + provenance for an eval suite by name — the
3806
+ * absorb-drift direction of the ensure protocol.
3807
+ */
3808
+ async pull(name) {
3809
+ return pullEval(this.getClient(), name);
3810
+ }
3811
+ /**
3812
+ * Run an eval suite synchronously and return the suite score + per-case grader
3813
+ * outcomes — the executing counterpart of `ensure`, powering the `runtype
3814
+ * eval` CI gate. Run a saved suite by id (`{ suiteId }`, the post-`ensure`
3815
+ * path) or an inline definition without persisting (`{ definition }`, the
3816
+ * virtual path).
3817
+ *
3818
+ * @example
3819
+ * ```typescript
3820
+ * const { suiteId } = await Runtype.evals.ensure(suite)
3821
+ * const result = await Runtype.evals.runSuite({ suiteId })
3822
+ * if (!result.passed) process.exit(1)
3823
+ * ```
3824
+ */
3825
+ async runSuite(input) {
3826
+ return runEvalSuite(this.getClient(), input);
3827
+ }
3423
3828
  /**
3424
3829
  * Get evaluation status by ID
3425
3830
  *
@@ -3538,14 +3943,14 @@ var PromptsNamespace = class {
3538
3943
  };
3539
3944
 
3540
3945
  // src/skills-ensure.ts
3541
- function isPlainObject2(value) {
3946
+ function isPlainObject3(value) {
3542
3947
  return value !== null && typeof value === "object" && !Array.isArray(value);
3543
3948
  }
3544
3949
  function normalizeValue(value) {
3545
3950
  if (Array.isArray(value)) {
3546
3951
  return value.map((item) => normalizeValue(item));
3547
3952
  }
3548
- if (isPlainObject2(value)) {
3953
+ if (isPlainObject3(value)) {
3549
3954
  const normalized = {};
3550
3955
  for (const key of Object.keys(value).sort()) {
3551
3956
  const entry = value[key];
@@ -3557,15 +3962,15 @@ function normalizeValue(value) {
3557
3962
  return value;
3558
3963
  }
3559
3964
  function normalizeSkillDefinition(definition) {
3560
- const manifest = isPlainObject2(definition.manifest) ? definition.manifest : {};
3561
- const rawFrontmatter = isPlainObject2(manifest.frontmatter) ? manifest.frontmatter : {};
3965
+ const manifest = isPlainObject3(definition.manifest) ? definition.manifest : {};
3966
+ const rawFrontmatter = isPlainObject3(manifest.frontmatter) ? manifest.frontmatter : {};
3562
3967
  const frontmatterWithoutName = {};
3563
3968
  for (const key of Object.keys(rawFrontmatter)) {
3564
3969
  if (key === "name") continue;
3565
3970
  frontmatterWithoutName[key] = rawFrontmatter[key];
3566
3971
  }
3567
3972
  const frontmatter = normalizeValue(frontmatterWithoutName);
3568
- const runtype = isPlainObject2(manifest.runtype) ? normalizeValue(manifest.runtype) : {};
3973
+ const runtype = isPlainObject3(manifest.runtype) ? normalizeValue(manifest.runtype) : {};
3569
3974
  const body = typeof manifest.body === "string" ? manifest.body : "";
3570
3975
  return { frontmatter, runtype, body };
3571
3976
  }
@@ -3583,7 +3988,7 @@ function defineSkill(input) {
3583
3988
  if (typeof input.name !== "string" || input.name.length === 0) {
3584
3989
  throw new Error('defineSkill requires a non-empty string "name"');
3585
3990
  }
3586
- if (!isPlainObject2(input.manifest)) {
3991
+ if (!isPlainObject3(input.manifest)) {
3587
3992
  throw new Error('defineSkill requires a "manifest" object ({ frontmatter, runtype, body })');
3588
3993
  }
3589
3994
  const unknownKeys = Object.keys(input).filter((key) => !DEFINE_SKILL_TOP_LEVEL_KEYS.has(key));
@@ -3593,7 +3998,7 @@ function defineSkill(input) {
3593
3998
  );
3594
3999
  }
3595
4000
  const frontmatter = input.manifest.frontmatter;
3596
- if (!isPlainObject2(frontmatter) || typeof frontmatter.name !== "string") {
4001
+ if (!isPlainObject3(frontmatter) || typeof frontmatter.name !== "string") {
3597
4002
  throw new Error("defineSkill: manifest.frontmatter.name is required");
3598
4003
  }
3599
4004
  if (frontmatter.name !== input.name) {
@@ -3634,19 +4039,19 @@ function parseRequestError2(err) {
3634
4039
  }
3635
4040
  function toConflictError2(err) {
3636
4041
  const { status, body } = parseRequestError2(err);
3637
- if (status !== 409 || !isPlainObject2(body)) return null;
4042
+ if (status !== 409 || !isPlainObject3(body)) return null;
3638
4043
  const code = body.code;
3639
4044
  if (code !== "external_modification" && code !== "remote_changed") return null;
3640
4045
  return new SkillEnsureConflictError(
3641
4046
  body
3642
4047
  );
3643
4048
  }
3644
- var serverHashMemo2 = /* @__PURE__ */ new WeakMap();
3645
- function memoFor2(client) {
3646
- let memo = serverHashMemo2.get(client);
4049
+ var serverHashMemo3 = /* @__PURE__ */ new WeakMap();
4050
+ function memoFor3(client) {
4051
+ let memo = serverHashMemo3.get(client);
3647
4052
  if (!memo) {
3648
4053
  memo = /* @__PURE__ */ new Map();
3649
- serverHashMemo2.set(client, memo);
4054
+ serverHashMemo3.set(client, memo);
3650
4055
  }
3651
4056
  return memo;
3652
4057
  }
@@ -3687,7 +4092,7 @@ async function ensureSkill(client, definition, options = {}) {
3687
4092
  }
3688
4093
  return plan;
3689
4094
  }
3690
- const memo = memoFor2(client);
4095
+ const memo = memoFor3(client);
3691
4096
  const localHash = await computeSkillContentHash(definition);
3692
4097
  const memoKey = `${definition.name} ${localHash}`;
3693
4098
  const contentHash = memo.get(memoKey) ?? localHash;
@@ -3982,14 +4387,14 @@ var AGENT_CONFIG_KEYS = [
3982
4387
  "tenancyStrategy"
3983
4388
  ];
3984
4389
  var AGENT_CONFIG_KEY_LIST = [...AGENT_CONFIG_KEYS].sort();
3985
- function isPlainObject3(value) {
4390
+ function isPlainObject4(value) {
3986
4391
  return value !== null && typeof value === "object" && !Array.isArray(value);
3987
4392
  }
3988
4393
  function normalizeValue2(value) {
3989
4394
  if (Array.isArray(value)) {
3990
4395
  return value.map((item) => normalizeValue2(item));
3991
4396
  }
3992
- if (isPlainObject3(value)) {
4397
+ if (isPlainObject4(value)) {
3993
4398
  const normalized = {};
3994
4399
  for (const key of Object.keys(value).sort()) {
3995
4400
  const entry = value[key];
@@ -4002,7 +4407,7 @@ function normalizeValue2(value) {
4002
4407
  }
4003
4408
  function normalizeAgentDefinition(definition) {
4004
4409
  const config = {};
4005
- const rawConfig = isPlainObject3(definition.config) ? definition.config : {};
4410
+ const rawConfig = isPlainObject4(definition.config) ? definition.config : {};
4006
4411
  for (const key of AGENT_CONFIG_KEY_LIST) {
4007
4412
  const value = rawConfig[key];
4008
4413
  if (value === void 0 || value === null) continue;
@@ -4024,7 +4429,7 @@ async function computeAgentContentHash(definition) {
4024
4429
  var DEFINE_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set(["name", "description", "icon", ...AGENT_CONFIG_KEYS]);
4025
4430
  function collectNonPortableToolRefs(config) {
4026
4431
  const tools = config.tools;
4027
- if (!isPlainObject3(tools)) return [];
4432
+ if (!isPlainObject4(tools)) return [];
4028
4433
  const found = [];
4029
4434
  const isAccountScoped = (ref) => typeof ref === "string" && ref.startsWith("tool_");
4030
4435
  const scanArray = (value, path) => {
@@ -4034,7 +4439,7 @@ function collectNonPortableToolRefs(config) {
4034
4439
  });
4035
4440
  };
4036
4441
  const scanKeys = (value, path) => {
4037
- if (!isPlainObject3(value)) return;
4442
+ if (!isPlainObject4(value)) return;
4038
4443
  for (const key of Object.keys(value)) {
4039
4444
  if (isAccountScoped(key)) found.push(`${path}.${key}`);
4040
4445
  }
@@ -4042,16 +4447,16 @@ function collectNonPortableToolRefs(config) {
4042
4447
  scanArray(tools.toolIds, "tools.toolIds");
4043
4448
  scanKeys(tools.toolConfigs, "tools.toolConfigs");
4044
4449
  scanKeys(tools.perToolLimits, "tools.perToolLimits");
4045
- if (isPlainObject3(tools.approval)) scanArray(tools.approval.require, "tools.approval.require");
4046
- if (isPlainObject3(tools.subagentConfig)) {
4450
+ if (isPlainObject4(tools.approval)) scanArray(tools.approval.require, "tools.approval.require");
4451
+ if (isPlainObject4(tools.subagentConfig)) {
4047
4452
  scanArray(tools.subagentConfig.toolPool, "tools.subagentConfig.toolPool");
4048
4453
  }
4049
- if (isPlainObject3(tools.codeModeConfig)) {
4454
+ if (isPlainObject4(tools.codeModeConfig)) {
4050
4455
  scanArray(tools.codeModeConfig.toolPool, "tools.codeModeConfig.toolPool");
4051
4456
  }
4052
4457
  if (Array.isArray(tools.runtimeTools)) {
4053
4458
  tools.runtimeTools.forEach((runtimeTool, i) => {
4054
- if (!isPlainObject3(runtimeTool) || !isPlainObject3(runtimeTool.config)) return;
4459
+ if (!isPlainObject4(runtimeTool) || !isPlainObject4(runtimeTool.config)) return;
4055
4460
  const base = `tools.runtimeTools[${i}].config`;
4056
4461
  const rtConfig = runtimeTool.config;
4057
4462
  if (runtimeTool.toolType === "subagent" && typeof rtConfig.agentId === "string" && rtConfig.agentId.startsWith("agent_")) {
@@ -4125,19 +4530,19 @@ function parseRequestError3(err) {
4125
4530
  }
4126
4531
  function toConflictError3(err) {
4127
4532
  const { status, body } = parseRequestError3(err);
4128
- if (status !== 409 || !isPlainObject3(body)) return null;
4533
+ if (status !== 409 || !isPlainObject4(body)) return null;
4129
4534
  const code = body.code;
4130
4535
  if (code !== "external_modification" && code !== "remote_changed") return null;
4131
4536
  return new AgentEnsureConflictError(
4132
4537
  body
4133
4538
  );
4134
4539
  }
4135
- var serverHashMemo3 = /* @__PURE__ */ new WeakMap();
4136
- function memoFor3(client) {
4137
- let memo = serverHashMemo3.get(client);
4540
+ var serverHashMemo4 = /* @__PURE__ */ new WeakMap();
4541
+ function memoFor4(client) {
4542
+ let memo = serverHashMemo4.get(client);
4138
4543
  if (!memo) {
4139
4544
  memo = /* @__PURE__ */ new Map();
4140
- serverHashMemo3.set(client, memo);
4545
+ serverHashMemo4.set(client, memo);
4141
4546
  }
4142
4547
  return memo;
4143
4548
  }
@@ -4174,7 +4579,7 @@ var AgentsNamespace = class {
4174
4579
  }
4175
4580
  return plan;
4176
4581
  }
4177
- const memo = memoFor3(client);
4582
+ const memo = memoFor4(client);
4178
4583
  const localHash = await computeAgentContentHash({
4179
4584
  ...definition,
4180
4585
  config: definition.config
@@ -4227,14 +4632,14 @@ var AgentsNamespace = class {
4227
4632
  };
4228
4633
 
4229
4634
  // src/tools-ensure.ts
4230
- function isPlainObject4(value) {
4635
+ function isPlainObject5(value) {
4231
4636
  return value !== null && typeof value === "object" && !Array.isArray(value);
4232
4637
  }
4233
4638
  function normalizeValue3(value) {
4234
4639
  if (Array.isArray(value)) {
4235
4640
  return value.map((item) => normalizeValue3(item));
4236
4641
  }
4237
- if (isPlainObject4(value)) {
4642
+ if (isPlainObject5(value)) {
4238
4643
  const normalized = {};
4239
4644
  for (const key of Object.keys(value).sort()) {
4240
4645
  const entry = value[key];
@@ -4246,8 +4651,8 @@ function normalizeValue3(value) {
4246
4651
  return value;
4247
4652
  }
4248
4653
  function normalizeToolDefinition(definition) {
4249
- const parametersSchema = isPlainObject4(definition.parametersSchema) ? normalizeValue3(definition.parametersSchema) : {};
4250
- const config = isPlainObject4(definition.config) ? normalizeValue3(definition.config) : {};
4654
+ const parametersSchema = isPlainObject5(definition.parametersSchema) ? normalizeValue3(definition.parametersSchema) : {};
4655
+ const config = isPlainObject5(definition.config) ? normalizeValue3(definition.config) : {};
4251
4656
  return {
4252
4657
  toolType: definition.toolType,
4253
4658
  ...definition.description ? { description: definition.description } : {},
@@ -4292,10 +4697,10 @@ function defineTool(input) {
4292
4697
  `defineTool requires "toolType" to be one of: ${[...TOOL_DEFINITION_TYPES].join(", ")}`
4293
4698
  );
4294
4699
  }
4295
- if (!isPlainObject4(input.parametersSchema)) {
4700
+ if (!isPlainObject5(input.parametersSchema)) {
4296
4701
  throw new Error('defineTool requires a "parametersSchema" object (a JSON Schema)');
4297
4702
  }
4298
- if (!isPlainObject4(input.config)) {
4703
+ if (!isPlainObject5(input.config)) {
4299
4704
  throw new Error('defineTool requires a "config" object');
4300
4705
  }
4301
4706
  const unknownKeys = Object.keys(input).filter((key) => !DEFINE_TOOL_TOP_LEVEL_KEYS.has(key));
@@ -4343,19 +4748,19 @@ function parseRequestError4(err) {
4343
4748
  }
4344
4749
  function toConflictError4(err) {
4345
4750
  const { status, body } = parseRequestError4(err);
4346
- if (status !== 409 || !isPlainObject4(body)) return null;
4751
+ if (status !== 409 || !isPlainObject5(body)) return null;
4347
4752
  const code = body.code;
4348
4753
  if (code !== "external_modification" && code !== "remote_changed") return null;
4349
4754
  return new ToolEnsureConflictError(
4350
4755
  body
4351
4756
  );
4352
4757
  }
4353
- var serverHashMemo4 = /* @__PURE__ */ new WeakMap();
4354
- function memoFor4(client) {
4355
- let memo = serverHashMemo4.get(client);
4758
+ var serverHashMemo5 = /* @__PURE__ */ new WeakMap();
4759
+ function memoFor5(client) {
4760
+ let memo = serverHashMemo5.get(client);
4356
4761
  if (!memo) {
4357
4762
  memo = /* @__PURE__ */ new Map();
4358
- serverHashMemo4.set(client, memo);
4763
+ serverHashMemo5.set(client, memo);
4359
4764
  }
4360
4765
  return memo;
4361
4766
  }
@@ -4395,7 +4800,7 @@ async function ensureTool(client, definition, options = {}) {
4395
4800
  }
4396
4801
  return plan;
4397
4802
  }
4398
- const memo = memoFor4(client);
4803
+ const memo = memoFor5(client);
4399
4804
  const localHash = await computeToolContentHash(definition);
4400
4805
  const memoKey = `${definition.name} ${localHash}`;
4401
4806
  const contentHash = memo.get(memoKey) ?? localHash;
@@ -4463,14 +4868,14 @@ var ToolsNamespace = class {
4463
4868
  };
4464
4869
 
4465
4870
  // src/products-ensure.ts
4466
- function isPlainObject5(value) {
4871
+ function isPlainObject6(value) {
4467
4872
  return value !== null && typeof value === "object" && !Array.isArray(value);
4468
4873
  }
4469
4874
  function normalizeValue4(value) {
4470
4875
  if (Array.isArray(value)) {
4471
4876
  return value.map((item) => normalizeValue4(item));
4472
4877
  }
4473
- if (isPlainObject5(value)) {
4878
+ if (isPlainObject6(value)) {
4474
4879
  const normalized = {};
4475
4880
  for (const key of Object.keys(value).sort()) {
4476
4881
  const entry = value[key];
@@ -4482,7 +4887,7 @@ function normalizeValue4(value) {
4482
4887
  return value;
4483
4888
  }
4484
4889
  function normalizeProductDefinition(definition) {
4485
- const spec = isPlainObject5(definition.spec) ? normalizeValue4(definition.spec) : {};
4890
+ const spec = isPlainObject6(definition.spec) ? normalizeValue4(definition.spec) : {};
4486
4891
  return {
4487
4892
  ...definition.description ? { description: definition.description } : {},
4488
4893
  ...definition.icon ? { icon: definition.icon } : {},
@@ -4509,7 +4914,7 @@ function defineProduct(input) {
4509
4914
  if (input.icon != null && typeof input.icon !== "string") {
4510
4915
  throw new Error('defineProduct "icon" must be a string when provided');
4511
4916
  }
4512
- if (input.spec != null && !isPlainObject5(input.spec)) {
4917
+ if (input.spec != null && !isPlainObject6(input.spec)) {
4513
4918
  throw new Error('defineProduct "spec" must be an object when provided');
4514
4919
  }
4515
4920
  const unknownKeys = Object.keys(input).filter((key) => !DEFINE_PRODUCT_TOP_LEVEL_KEYS.has(key));
@@ -4556,19 +4961,19 @@ function parseRequestError5(err) {
4556
4961
  }
4557
4962
  function toConflictError5(err) {
4558
4963
  const { status, body } = parseRequestError5(err);
4559
- if (status !== 409 || !isPlainObject5(body)) return null;
4964
+ if (status !== 409 || !isPlainObject6(body)) return null;
4560
4965
  const code = body.code;
4561
4966
  if (code !== "external_modification" && code !== "remote_changed") return null;
4562
4967
  return new ProductEnsureConflictError(
4563
4968
  body
4564
4969
  );
4565
4970
  }
4566
- var serverHashMemo5 = /* @__PURE__ */ new WeakMap();
4567
- function memoFor5(client) {
4568
- let memo = serverHashMemo5.get(client);
4971
+ var serverHashMemo6 = /* @__PURE__ */ new WeakMap();
4972
+ function memoFor6(client) {
4973
+ let memo = serverHashMemo6.get(client);
4569
4974
  if (!memo) {
4570
4975
  memo = /* @__PURE__ */ new Map();
4571
- serverHashMemo5.set(client, memo);
4976
+ serverHashMemo6.set(client, memo);
4572
4977
  }
4573
4978
  return memo;
4574
4979
  }
@@ -4608,7 +5013,7 @@ async function ensureProduct(client, definition, options = {}) {
4608
5013
  }
4609
5014
  return plan;
4610
5015
  }
4611
- const memo = memoFor5(client);
5016
+ const memo = memoFor6(client);
4612
5017
  const localHash = await computeProductContentHash(definition);
4613
5018
  const memoKey = `${definition.name} ${localHash}`;
4614
5019
  const contentHash = memo.get(memoKey) ?? localHash;
@@ -4637,14 +5042,14 @@ async function pullProduct(client, name) {
4637
5042
  }
4638
5043
 
4639
5044
  // src/products-ensure-fpo.ts
4640
- function isPlainObject6(value) {
5045
+ function isPlainObject7(value) {
4641
5046
  return value !== null && typeof value === "object" && !Array.isArray(value);
4642
5047
  }
4643
5048
  function normalizeValue5(value) {
4644
5049
  if (Array.isArray(value)) {
4645
5050
  return value.map((item) => normalizeValue5(item));
4646
5051
  }
4647
- if (isPlainObject6(value)) {
5052
+ if (isPlainObject7(value)) {
4648
5053
  const normalized = {};
4649
5054
  for (const key of Object.keys(value).sort()) {
4650
5055
  const entry = value[key];
@@ -4656,7 +5061,7 @@ function normalizeValue5(value) {
4656
5061
  return value;
4657
5062
  }
4658
5063
  function normalizeFpoDefinition(fpo) {
4659
- const productInput = isPlainObject6(fpo.product) ? fpo.product : {};
5064
+ const productInput = isPlainObject7(fpo.product) ? fpo.product : {};
4660
5065
  const { name: _identityName, ...productRest } = productInput;
4661
5066
  const product = normalizeValue5(productRest);
4662
5067
  return {
@@ -4677,10 +5082,10 @@ async function computeFpoContentHash(fpo) {
4677
5082
  return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
4678
5083
  }
4679
5084
  function defineFpo(fpo) {
4680
- if (!isPlainObject6(fpo)) {
5085
+ if (!isPlainObject7(fpo)) {
4681
5086
  throw new Error("defineFpo requires an FPO object");
4682
5087
  }
4683
- const product = isPlainObject6(fpo.product) ? fpo.product : void 0;
5088
+ const product = isPlainObject7(fpo.product) ? fpo.product : void 0;
4684
5089
  if (!product || typeof product.name !== "string" || product.name.length === 0) {
4685
5090
  throw new Error('defineFpo requires a non-empty "product.name" (the converge identity)');
4686
5091
  }
@@ -4776,14 +5181,14 @@ var ProductsNamespace = class {
4776
5181
  };
4777
5182
 
4778
5183
  // src/surfaces-ensure.ts
4779
- function isPlainObject7(value) {
5184
+ function isPlainObject8(value) {
4780
5185
  return value !== null && typeof value === "object" && !Array.isArray(value);
4781
5186
  }
4782
5187
  function normalizeValue6(value) {
4783
5188
  if (Array.isArray(value)) {
4784
5189
  return value.map((item) => normalizeValue6(item));
4785
5190
  }
4786
- if (isPlainObject7(value)) {
5191
+ if (isPlainObject8(value)) {
4787
5192
  const normalized = {};
4788
5193
  for (const key of Object.keys(value).sort()) {
4789
5194
  const entry = value[key];
@@ -4795,7 +5200,7 @@ function normalizeValue6(value) {
4795
5200
  return value;
4796
5201
  }
4797
5202
  function normalizeSurfaceDefinition(definition) {
4798
- const behavior = isPlainObject7(definition.behavior) ? normalizeValue6(definition.behavior) : { type: definition.type };
5203
+ const behavior = isPlainObject8(definition.behavior) ? normalizeValue6(definition.behavior) : { type: definition.type };
4799
5204
  return {
4800
5205
  type: definition.type,
4801
5206
  behavior,
@@ -4848,13 +5253,13 @@ function defineSurface(input) {
4848
5253
  `defineSurface requires "type" to be one of: ${[...SURFACE_DEFINITION_TYPES].join(", ")}`
4849
5254
  );
4850
5255
  }
4851
- if (input.behavior !== void 0 && !isPlainObject7(input.behavior)) {
5256
+ if (input.behavior !== void 0 && !isPlainObject8(input.behavior)) {
4852
5257
  throw new Error('defineSurface "behavior" must be an object when provided');
4853
5258
  }
4854
- if (input.inbound !== void 0 && !isPlainObject7(input.inbound)) {
5259
+ if (input.inbound !== void 0 && !isPlainObject8(input.inbound)) {
4855
5260
  throw new Error('defineSurface "inbound" must be an object when provided');
4856
5261
  }
4857
- if (input.outbound !== void 0 && !isPlainObject7(input.outbound)) {
5262
+ if (input.outbound !== void 0 && !isPlainObject8(input.outbound)) {
4858
5263
  throw new Error('defineSurface "outbound" must be an object when provided');
4859
5264
  }
4860
5265
  if (input.status !== void 0 && !["draft", "active", "paused"].includes(input.status)) {
@@ -4910,19 +5315,19 @@ function parseRequestError6(err) {
4910
5315
  }
4911
5316
  function toConflictError6(err) {
4912
5317
  const { status, body } = parseRequestError6(err);
4913
- if (status !== 409 || !isPlainObject7(body)) return null;
5318
+ if (status !== 409 || !isPlainObject8(body)) return null;
4914
5319
  const code = body.code;
4915
5320
  if (code !== "external_modification" && code !== "remote_changed") return null;
4916
5321
  return new SurfaceEnsureConflictError(
4917
5322
  body
4918
5323
  );
4919
5324
  }
4920
- var serverHashMemo6 = /* @__PURE__ */ new WeakMap();
4921
- function memoFor6(client) {
4922
- let memo = serverHashMemo6.get(client);
5325
+ var serverHashMemo7 = /* @__PURE__ */ new WeakMap();
5326
+ function memoFor7(client) {
5327
+ let memo = serverHashMemo7.get(client);
4923
5328
  if (!memo) {
4924
5329
  memo = /* @__PURE__ */ new Map();
4925
- serverHashMemo6.set(client, memo);
5330
+ serverHashMemo7.set(client, memo);
4926
5331
  }
4927
5332
  return memo;
4928
5333
  }
@@ -4962,7 +5367,7 @@ async function ensureSurface(client, productId, definition, options = {}) {
4962
5367
  }
4963
5368
  return plan;
4964
5369
  }
4965
- const memo = memoFor6(client);
5370
+ const memo = memoFor7(client);
4966
5371
  const localHash = await computeSurfaceContentHash(definition);
4967
5372
  const memoKey = `${productId} ${definition.name} ${localHash}`;
4968
5373
  const contentHash = memo.get(memoKey) ?? localHash;
@@ -5511,7 +5916,7 @@ var Runtype = class {
5511
5916
 
5512
5917
  // src/version.ts
5513
5918
  var FALLBACK_VERSION = "0.0.0";
5514
- var SDK_VERSION = "5.3.1".length > 0 ? "5.3.1" : FALLBACK_VERSION;
5919
+ var SDK_VERSION = "5.5.0".length > 0 ? "5.5.0" : FALLBACK_VERSION;
5515
5920
  var RUNTYPE_CLIENT_KIND = "sdk";
5516
5921
  var SDK_USER_AGENT = `runtype-sdk/${SDK_VERSION} (typescript)`;
5517
5922
 
@@ -13221,14 +13626,19 @@ export {
13221
13626
  buildLedgerOffloadReference,
13222
13627
  buildPolicyGuidance,
13223
13628
  buildSendViewOffloadMarker,
13629
+ calledTool,
13224
13630
  compileWorkflowConfig,
13631
+ completed,
13225
13632
  computeAgentContentHash,
13633
+ computeEvalContentHash,
13226
13634
  computeFlowContentHash,
13227
13635
  computeFpoContentHash,
13228
13636
  computeProductContentHash,
13229
13637
  computeSkillContentHash,
13230
13638
  computeSurfaceContentHash,
13231
13639
  computeToolContentHash,
13640
+ contains,
13641
+ cost,
13232
13642
  createAgentEventTranslator,
13233
13643
  createClient,
13234
13644
  createExternalTool,
@@ -13236,6 +13646,7 @@ export {
13236
13646
  defaultWorkflow,
13237
13647
  defaultWorkflowConfig,
13238
13648
  defineAgent,
13649
+ defineEval,
13239
13650
  defineFlow,
13240
13651
  defineFpo,
13241
13652
  definePlaybook,
@@ -13245,6 +13656,7 @@ export {
13245
13656
  defineTool,
13246
13657
  deployWorkflow,
13247
13658
  ensureDefaultWorkflowHooks,
13659
+ ensureEval,
13248
13660
  ensureFpo,
13249
13661
  evaluateGeneratedRuntimeToolProposal,
13250
13662
  extractDeclaredToolResultChars,
@@ -13257,7 +13669,15 @@ export {
13257
13669
  isPreservationSensitiveTask,
13258
13670
  isUnifiedEventType,
13259
13671
  isWorkflowHookRef,
13672
+ jsonField,
13673
+ judge,
13674
+ judges,
13675
+ latency,
13676
+ length,
13260
13677
  listWorkflowHooks,
13678
+ matchesExpected,
13679
+ maxToolCalls,
13680
+ noError,
13261
13681
  normalizeAgentDefinition,
13262
13682
  normalizeCandidatePath,
13263
13683
  normalizeFpoDefinition,
@@ -13265,19 +13685,29 @@ export {
13265
13685
  normalizeSkillDefinition,
13266
13686
  normalizeSurfaceDefinition,
13267
13687
  normalizeToolDefinition,
13688
+ notCalledTool,
13689
+ notContains,
13268
13690
  parseFinalBuffer,
13269
13691
  parseLedgerArtifactRelativePath,
13270
13692
  parseOffloadedOutputId,
13271
13693
  parseSSEChunk,
13272
13694
  processStream,
13695
+ pullEval,
13273
13696
  pullFpo,
13697
+ ranStep,
13698
+ regex,
13274
13699
  registerWorkflowHook,
13275
13700
  resolveStallStopAfter,
13276
13701
  resolveWorkflowHook,
13702
+ runEvalSuite,
13277
13703
  sanitizeTaskSlug,
13278
13704
  shouldInjectEmptySessionNudge,
13279
13705
  shouldRequestModelEscalation,
13706
+ stepOrder,
13280
13707
  streamEvents,
13708
+ toolOrder,
13281
13709
  unregisterWorkflowHook,
13710
+ usedNoTools,
13711
+ validJson,
13282
13712
  withUnifiedEvents
13283
13713
  };