@runtypelabs/sdk 4.14.0 → 4.16.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.cjs +1082 -257
- package/dist/index.d.cts +1748 -10
- package/dist/index.d.ts +1748 -10
- package/dist/index.mjs +1064 -257
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -57,6 +57,9 @@ __export(index_exports, {
|
|
|
57
57
|
LEDGER_ARTIFACT_LINE_PREFIX: () => LEDGER_ARTIFACT_LINE_PREFIX,
|
|
58
58
|
LogsEndpoint: () => LogsEndpoint,
|
|
59
59
|
ModelConfigsEndpoint: () => ModelConfigsEndpoint,
|
|
60
|
+
ProductDriftError: () => ProductDriftError,
|
|
61
|
+
ProductEnsureConflictError: () => ProductEnsureConflictError,
|
|
62
|
+
ProductsNamespace: () => ProductsNamespace,
|
|
60
63
|
PromptRunner: () => PromptRunner,
|
|
61
64
|
PromptsEndpoint: () => PromptsEndpoint,
|
|
62
65
|
PromptsNamespace: () => PromptsNamespace,
|
|
@@ -70,9 +73,15 @@ __export(index_exports, {
|
|
|
70
73
|
STEP_TYPE_TO_METHOD: () => STEP_TYPE_TO_METHOD,
|
|
71
74
|
SchedulesEndpoint: () => SchedulesEndpoint,
|
|
72
75
|
SecretsEndpoint: () => SecretsEndpoint,
|
|
76
|
+
SkillDriftError: () => SkillDriftError,
|
|
77
|
+
SkillEnsureConflictError: () => SkillEnsureConflictError,
|
|
73
78
|
SkillProposalsNamespace: () => SkillProposalsNamespace,
|
|
74
79
|
SkillsNamespace: () => SkillsNamespace,
|
|
80
|
+
SurfaceDriftError: () => SurfaceDriftError,
|
|
81
|
+
SurfaceEnsureConflictError: () => SurfaceEnsureConflictError,
|
|
75
82
|
SurfacesEndpoint: () => SurfacesEndpoint,
|
|
83
|
+
SurfacesNamespace: () => SurfacesNamespace,
|
|
84
|
+
ToolApprovalGrantsEndpoint: () => ToolApprovalGrantsEndpoint,
|
|
76
85
|
ToolDriftError: () => ToolDriftError,
|
|
77
86
|
ToolEnsureConflictError: () => ToolEnsureConflictError,
|
|
78
87
|
ToolsEndpoint: () => ToolsEndpoint,
|
|
@@ -88,6 +97,9 @@ __export(index_exports, {
|
|
|
88
97
|
compileWorkflowConfig: () => compileWorkflowConfig,
|
|
89
98
|
computeAgentContentHash: () => computeAgentContentHash,
|
|
90
99
|
computeFlowContentHash: () => computeFlowContentHash,
|
|
100
|
+
computeProductContentHash: () => computeProductContentHash,
|
|
101
|
+
computeSkillContentHash: () => computeSkillContentHash,
|
|
102
|
+
computeSurfaceContentHash: () => computeSurfaceContentHash,
|
|
91
103
|
computeToolContentHash: () => computeToolContentHash,
|
|
92
104
|
createClient: () => createClient,
|
|
93
105
|
createExternalTool: () => createExternalTool,
|
|
@@ -96,6 +108,9 @@ __export(index_exports, {
|
|
|
96
108
|
defineAgent: () => defineAgent,
|
|
97
109
|
defineFlow: () => defineFlow,
|
|
98
110
|
definePlaybook: () => definePlaybook,
|
|
111
|
+
defineProduct: () => defineProduct,
|
|
112
|
+
defineSkill: () => defineSkill,
|
|
113
|
+
defineSurface: () => defineSurface,
|
|
99
114
|
defineTool: () => defineTool,
|
|
100
115
|
deployWorkflow: () => deployWorkflow,
|
|
101
116
|
ensureDefaultWorkflowHooks: () => ensureDefaultWorkflowHooks,
|
|
@@ -112,6 +127,9 @@ __export(index_exports, {
|
|
|
112
127
|
listWorkflowHooks: () => listWorkflowHooks,
|
|
113
128
|
normalizeAgentDefinition: () => normalizeAgentDefinition,
|
|
114
129
|
normalizeCandidatePath: () => normalizeCandidatePath,
|
|
130
|
+
normalizeProductDefinition: () => normalizeProductDefinition,
|
|
131
|
+
normalizeSkillDefinition: () => normalizeSkillDefinition,
|
|
132
|
+
normalizeSurfaceDefinition: () => normalizeSurfaceDefinition,
|
|
115
133
|
normalizeToolDefinition: () => normalizeToolDefinition,
|
|
116
134
|
parseFinalBuffer: () => parseFinalBuffer,
|
|
117
135
|
parseLedgerArtifactRelativePath: () => parseLedgerArtifactRelativePath,
|
|
@@ -1225,20 +1243,20 @@ var FlowBuilder = class {
|
|
|
1225
1243
|
*/
|
|
1226
1244
|
build() {
|
|
1227
1245
|
const flow = this.existingFlowId ? { id: this.existingFlowId } : { name: this.flowConfig.name, steps: this.steps };
|
|
1228
|
-
const
|
|
1246
|
+
const request6 = { flow };
|
|
1229
1247
|
if (this.recordConfig) {
|
|
1230
|
-
|
|
1248
|
+
request6.record = this.recordConfig;
|
|
1231
1249
|
}
|
|
1232
1250
|
if (this.messagesConfig) {
|
|
1233
|
-
|
|
1251
|
+
request6.messages = this.messagesConfig;
|
|
1234
1252
|
}
|
|
1235
1253
|
if (this.inputsConfig) {
|
|
1236
|
-
|
|
1254
|
+
request6.inputs = this.inputsConfig;
|
|
1237
1255
|
}
|
|
1238
1256
|
if (Object.keys(this.optionsConfig).length > 0) {
|
|
1239
|
-
|
|
1257
|
+
request6.options = this.optionsConfig;
|
|
1240
1258
|
}
|
|
1241
|
-
return
|
|
1259
|
+
return request6;
|
|
1242
1260
|
}
|
|
1243
1261
|
/**
|
|
1244
1262
|
* Validate this prospective flow against the public validation endpoint
|
|
@@ -2632,15 +2650,15 @@ var RuntypeFlowBuilder = class {
|
|
|
2632
2650
|
build() {
|
|
2633
2651
|
const flowMode = this.mode === "existing" ? "existing" : this.mode;
|
|
2634
2652
|
const flow = this.existingFlowId ? { id: this.existingFlowId } : { name: this.flowConfig.name, steps: this.steps };
|
|
2635
|
-
const
|
|
2653
|
+
const request6 = { flow };
|
|
2636
2654
|
if (this.recordConfig) {
|
|
2637
|
-
|
|
2655
|
+
request6.record = this.recordConfig;
|
|
2638
2656
|
}
|
|
2639
2657
|
if (this.messagesConfig) {
|
|
2640
|
-
|
|
2658
|
+
request6.messages = this.messagesConfig;
|
|
2641
2659
|
}
|
|
2642
2660
|
if (this.inputsConfig) {
|
|
2643
|
-
|
|
2661
|
+
request6.inputs = this.inputsConfig;
|
|
2644
2662
|
}
|
|
2645
2663
|
const options = {
|
|
2646
2664
|
flowMode,
|
|
@@ -2658,8 +2676,8 @@ var RuntypeFlowBuilder = class {
|
|
|
2658
2676
|
if (this.mode === "upsert" && Object.keys(this.upsertOptions).length > 0) {
|
|
2659
2677
|
options.upsertOptions = this.upsertOptions;
|
|
2660
2678
|
}
|
|
2661
|
-
|
|
2662
|
-
return
|
|
2679
|
+
request6.options = options;
|
|
2680
|
+
return request6;
|
|
2663
2681
|
}
|
|
2664
2682
|
/**
|
|
2665
2683
|
* Validate this prospective flow against the public validation endpoint
|
|
@@ -3253,6 +3271,192 @@ var PromptsNamespace = class {
|
|
|
3253
3271
|
}
|
|
3254
3272
|
};
|
|
3255
3273
|
|
|
3274
|
+
// src/skills-ensure.ts
|
|
3275
|
+
function isPlainObject2(value) {
|
|
3276
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3277
|
+
}
|
|
3278
|
+
function normalizeValue(value) {
|
|
3279
|
+
if (Array.isArray(value)) {
|
|
3280
|
+
return value.map((item) => normalizeValue(item));
|
|
3281
|
+
}
|
|
3282
|
+
if (isPlainObject2(value)) {
|
|
3283
|
+
const normalized = {};
|
|
3284
|
+
for (const key of Object.keys(value).sort()) {
|
|
3285
|
+
const entry = value[key];
|
|
3286
|
+
if (entry === void 0 || entry === null) continue;
|
|
3287
|
+
normalized[key] = normalizeValue(entry);
|
|
3288
|
+
}
|
|
3289
|
+
return normalized;
|
|
3290
|
+
}
|
|
3291
|
+
return value;
|
|
3292
|
+
}
|
|
3293
|
+
function normalizeSkillDefinition(definition) {
|
|
3294
|
+
const manifest = isPlainObject2(definition.manifest) ? definition.manifest : {};
|
|
3295
|
+
const rawFrontmatter = isPlainObject2(manifest.frontmatter) ? manifest.frontmatter : {};
|
|
3296
|
+
const frontmatterWithoutName = {};
|
|
3297
|
+
for (const key of Object.keys(rawFrontmatter)) {
|
|
3298
|
+
if (key === "name") continue;
|
|
3299
|
+
frontmatterWithoutName[key] = rawFrontmatter[key];
|
|
3300
|
+
}
|
|
3301
|
+
const frontmatter = normalizeValue(frontmatterWithoutName);
|
|
3302
|
+
const runtype = isPlainObject2(manifest.runtype) ? normalizeValue(manifest.runtype) : {};
|
|
3303
|
+
const body = typeof manifest.body === "string" ? manifest.body : "";
|
|
3304
|
+
return { frontmatter, runtype, body };
|
|
3305
|
+
}
|
|
3306
|
+
async function computeSkillContentHash(definition) {
|
|
3307
|
+
const serialized = JSON.stringify(normalizeSkillDefinition(definition));
|
|
3308
|
+
const encoded = new TextEncoder().encode(serialized);
|
|
3309
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
|
|
3310
|
+
return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
3311
|
+
}
|
|
3312
|
+
var DEFINE_SKILL_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set(["name", "manifest"]);
|
|
3313
|
+
function defineSkill(input) {
|
|
3314
|
+
if (!input || typeof input !== "object") {
|
|
3315
|
+
throw new Error("defineSkill requires a definition object");
|
|
3316
|
+
}
|
|
3317
|
+
if (typeof input.name !== "string" || input.name.length === 0) {
|
|
3318
|
+
throw new Error('defineSkill requires a non-empty string "name"');
|
|
3319
|
+
}
|
|
3320
|
+
if (!isPlainObject2(input.manifest)) {
|
|
3321
|
+
throw new Error('defineSkill requires a "manifest" object ({ frontmatter, runtype, body })');
|
|
3322
|
+
}
|
|
3323
|
+
const unknownKeys = Object.keys(input).filter((key) => !DEFINE_SKILL_TOP_LEVEL_KEYS.has(key));
|
|
3324
|
+
if (unknownKeys.length > 0) {
|
|
3325
|
+
throw new Error(
|
|
3326
|
+
`defineSkill: unknown field(s): ${unknownKeys.join(", ")}. Allowed fields are name and manifest.`
|
|
3327
|
+
);
|
|
3328
|
+
}
|
|
3329
|
+
const frontmatter = input.manifest.frontmatter;
|
|
3330
|
+
if (!isPlainObject2(frontmatter) || typeof frontmatter.name !== "string") {
|
|
3331
|
+
throw new Error("defineSkill: manifest.frontmatter.name is required");
|
|
3332
|
+
}
|
|
3333
|
+
if (frontmatter.name !== input.name) {
|
|
3334
|
+
throw new Error(
|
|
3335
|
+
`defineSkill: manifest.frontmatter.name ("${frontmatter.name}") must match the identity name ("${input.name}").`
|
|
3336
|
+
);
|
|
3337
|
+
}
|
|
3338
|
+
return { name: input.name, manifest: input.manifest };
|
|
3339
|
+
}
|
|
3340
|
+
var SkillEnsureConflictError = class extends Error {
|
|
3341
|
+
constructor(body) {
|
|
3342
|
+
super(body.error ?? `Skill ensure conflict: ${body.code}`);
|
|
3343
|
+
this.name = "SkillEnsureConflictError";
|
|
3344
|
+
this.code = body.code;
|
|
3345
|
+
this.lastModifiedSource = body.lastModifiedSource;
|
|
3346
|
+
this.modifiedAt = body.modifiedAt;
|
|
3347
|
+
this.currentHash = body.currentHash;
|
|
3348
|
+
}
|
|
3349
|
+
};
|
|
3350
|
+
var SkillDriftError = class extends Error {
|
|
3351
|
+
constructor(plan) {
|
|
3352
|
+
super(
|
|
3353
|
+
`Skill "${plan.skillId ?? "definition"}" drifted: plan is '${plan.changes}' (changed: ${plan.changedKeys.join(", ") || "n/a"}). Run client.skills.pull(name) to absorb the remote edit into your repo, or re-run ensure to converge.`
|
|
3354
|
+
);
|
|
3355
|
+
this.name = "SkillDriftError";
|
|
3356
|
+
this.plan = plan;
|
|
3357
|
+
}
|
|
3358
|
+
};
|
|
3359
|
+
function parseRequestError2(err) {
|
|
3360
|
+
if (!(err instanceof Error)) return { status: null, body: null };
|
|
3361
|
+
const match = err.message.match(/^API request failed: (\d{3}) .*? - ([\s\S]*)$/);
|
|
3362
|
+
if (!match) return { status: null, body: null };
|
|
3363
|
+
try {
|
|
3364
|
+
return { status: Number(match[1]), body: JSON.parse(match[2]) };
|
|
3365
|
+
} catch {
|
|
3366
|
+
return { status: Number(match[1]), body: null };
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
function toConflictError2(err) {
|
|
3370
|
+
const { status, body } = parseRequestError2(err);
|
|
3371
|
+
if (status !== 409 || !isPlainObject2(body)) return null;
|
|
3372
|
+
const code = body.code;
|
|
3373
|
+
if (code !== "external_modification" && code !== "remote_changed") return null;
|
|
3374
|
+
return new SkillEnsureConflictError(
|
|
3375
|
+
body
|
|
3376
|
+
);
|
|
3377
|
+
}
|
|
3378
|
+
var serverHashMemo2 = /* @__PURE__ */ new WeakMap();
|
|
3379
|
+
function memoFor2(client) {
|
|
3380
|
+
let memo = serverHashMemo2.get(client);
|
|
3381
|
+
if (!memo) {
|
|
3382
|
+
memo = /* @__PURE__ */ new Map();
|
|
3383
|
+
serverHashMemo2.set(client, memo);
|
|
3384
|
+
}
|
|
3385
|
+
return memo;
|
|
3386
|
+
}
|
|
3387
|
+
function memoize2(memo, memoKey, result) {
|
|
3388
|
+
if (result.result !== "plan") memo.set(memoKey, result.contentHash);
|
|
3389
|
+
}
|
|
3390
|
+
async function request2(client, body) {
|
|
3391
|
+
try {
|
|
3392
|
+
return await client.post(
|
|
3393
|
+
"/skills/ensure",
|
|
3394
|
+
body
|
|
3395
|
+
);
|
|
3396
|
+
} catch (err) {
|
|
3397
|
+
const conflict = toConflictError2(err);
|
|
3398
|
+
if (conflict) throw conflict;
|
|
3399
|
+
throw err;
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3402
|
+
async function ensureSkill(client, definition, options = {}) {
|
|
3403
|
+
const { dryRun, onConflict, release, expectedRemoteHash, expectNoChanges } = options;
|
|
3404
|
+
const passthrough = {
|
|
3405
|
+
...onConflict ? { onConflict } : {},
|
|
3406
|
+
...release ? { release } : {},
|
|
3407
|
+
...expectedRemoteHash ? { expectedRemoteHash } : {}
|
|
3408
|
+
};
|
|
3409
|
+
if (dryRun || expectNoChanges) {
|
|
3410
|
+
const plan = await request2(client, {
|
|
3411
|
+
name: definition.name,
|
|
3412
|
+
definition: manifestToWire(definition),
|
|
3413
|
+
dryRun: true,
|
|
3414
|
+
...passthrough
|
|
3415
|
+
});
|
|
3416
|
+
if (plan.result !== "plan") {
|
|
3417
|
+
throw new Error(`Expected a plan result from dryRun, got '${plan.result}'`);
|
|
3418
|
+
}
|
|
3419
|
+
if (expectNoChanges && plan.changes !== "none") {
|
|
3420
|
+
throw new SkillDriftError(plan);
|
|
3421
|
+
}
|
|
3422
|
+
return plan;
|
|
3423
|
+
}
|
|
3424
|
+
const memo = memoFor2(client);
|
|
3425
|
+
const localHash = await computeSkillContentHash(definition);
|
|
3426
|
+
const memoKey = `${definition.name} ${localHash}`;
|
|
3427
|
+
const contentHash = memo.get(memoKey) ?? localHash;
|
|
3428
|
+
const probe = await request2(client, {
|
|
3429
|
+
name: definition.name,
|
|
3430
|
+
contentHash,
|
|
3431
|
+
...passthrough
|
|
3432
|
+
});
|
|
3433
|
+
if (probe.result !== "definitionRequired") {
|
|
3434
|
+
memoize2(memo, memoKey, probe);
|
|
3435
|
+
return probe;
|
|
3436
|
+
}
|
|
3437
|
+
const converged = await request2(client, {
|
|
3438
|
+
name: definition.name,
|
|
3439
|
+
definition: manifestToWire(definition),
|
|
3440
|
+
...passthrough
|
|
3441
|
+
});
|
|
3442
|
+
if (converged.result === "definitionRequired") {
|
|
3443
|
+
throw new Error("Server reported definitionRequired for a full-definition request");
|
|
3444
|
+
}
|
|
3445
|
+
memoize2(memo, memoKey, converged);
|
|
3446
|
+
return converged;
|
|
3447
|
+
}
|
|
3448
|
+
function manifestToWire(definition) {
|
|
3449
|
+
const manifest = definition.manifest;
|
|
3450
|
+
const frontmatter = { ...manifest.frontmatter };
|
|
3451
|
+
if (manifest.runtype && Object.keys(manifest.runtype).length > 0) {
|
|
3452
|
+
frontmatter.runtype = manifest.runtype;
|
|
3453
|
+
}
|
|
3454
|
+
return { frontmatter, body: manifest.body ?? "" };
|
|
3455
|
+
}
|
|
3456
|
+
async function pullSkill(client, name) {
|
|
3457
|
+
return client.get("/skills/pull", { name });
|
|
3458
|
+
}
|
|
3459
|
+
|
|
3256
3460
|
// src/skills-namespace.ts
|
|
3257
3461
|
var SkillProposalsNamespace = class {
|
|
3258
3462
|
constructor(getClient) {
|
|
@@ -3393,6 +3597,22 @@ var SkillsNamespace = class {
|
|
|
3393
3597
|
const client = this.getClient();
|
|
3394
3598
|
await client.post(`/skills/${skillId}/versions/${versionId}/publish`);
|
|
3395
3599
|
}
|
|
3600
|
+
/**
|
|
3601
|
+
* Statically scan a SKILL.md document for malicious patterns and return a
|
|
3602
|
+
* two-tier verdict — `warning` when a skill appears suspicious (low–medium
|
|
3603
|
+
* confidence), `error` when high-confidence malicious. Does not persist or
|
|
3604
|
+
* gate; use it as a "scan before save" affordance.
|
|
3605
|
+
*
|
|
3606
|
+
* @example
|
|
3607
|
+
* ```typescript
|
|
3608
|
+
* const { verdict } = await Runtype.skills.scan(skillMarkdown)
|
|
3609
|
+
* if (verdict.tier === 'error') console.warn(verdict.summary)
|
|
3610
|
+
* ```
|
|
3611
|
+
*/
|
|
3612
|
+
async scan(markdown) {
|
|
3613
|
+
const client = this.getClient();
|
|
3614
|
+
return client.post("/skills/scan", { markdown });
|
|
3615
|
+
}
|
|
3396
3616
|
/**
|
|
3397
3617
|
* Import a single SKILL.md document. The imported skill lands with
|
|
3398
3618
|
* `trustLevel: 'imported'` and a draft version.
|
|
@@ -3435,6 +3655,40 @@ var SkillsNamespace = class {
|
|
|
3435
3655
|
const res = await client.get("/skills/bindings", { agentId });
|
|
3436
3656
|
return res.data;
|
|
3437
3657
|
}
|
|
3658
|
+
/**
|
|
3659
|
+
* Idempotently converge a `defineSkill` definition onto the platform.
|
|
3660
|
+
* Hash-first: the steady state is one tiny probe request. Creates or appends a
|
|
3661
|
+
* new version; never deletes. Identity is name + account scope. Pass
|
|
3662
|
+
* `release: 'publish'` to publish the converged version.
|
|
3663
|
+
*
|
|
3664
|
+
* @example
|
|
3665
|
+
* ```typescript
|
|
3666
|
+
* const reviewer = defineSkill({
|
|
3667
|
+
* name: 'code_reviewer',
|
|
3668
|
+
* manifest: {
|
|
3669
|
+
* frontmatter: { name: 'code_reviewer', description: 'Reviews pull requests' },
|
|
3670
|
+
* runtype: { trustLevel: 'org' },
|
|
3671
|
+
* body: '# Code Reviewer\n\nReview the diff...',
|
|
3672
|
+
* },
|
|
3673
|
+
* })
|
|
3674
|
+
*
|
|
3675
|
+
* // Converge + publish (CI/deploy).
|
|
3676
|
+
* const result = await Runtype.skills.ensure(reviewer, { release: 'publish' })
|
|
3677
|
+
*
|
|
3678
|
+
* // PR drift gate.
|
|
3679
|
+
* await Runtype.skills.ensure(reviewer, { expectNoChanges: true })
|
|
3680
|
+
* ```
|
|
3681
|
+
*/
|
|
3682
|
+
async ensure(definition, options = {}) {
|
|
3683
|
+
return ensureSkill(this.getClient(), definition, options);
|
|
3684
|
+
}
|
|
3685
|
+
/**
|
|
3686
|
+
* Pull the canonical definition + provenance for a skill by name — the
|
|
3687
|
+
* absorb-drift direction of the ensure protocol.
|
|
3688
|
+
*/
|
|
3689
|
+
async pull(name) {
|
|
3690
|
+
return pullSkill(this.getClient(), name);
|
|
3691
|
+
}
|
|
3438
3692
|
};
|
|
3439
3693
|
|
|
3440
3694
|
// src/agents-namespace.ts
|
|
@@ -3460,19 +3714,19 @@ var AGENT_CONFIG_KEYS = [
|
|
|
3460
3714
|
"memory"
|
|
3461
3715
|
];
|
|
3462
3716
|
var AGENT_CONFIG_KEY_LIST = [...AGENT_CONFIG_KEYS].sort();
|
|
3463
|
-
function
|
|
3717
|
+
function isPlainObject3(value) {
|
|
3464
3718
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3465
3719
|
}
|
|
3466
|
-
function
|
|
3720
|
+
function normalizeValue2(value) {
|
|
3467
3721
|
if (Array.isArray(value)) {
|
|
3468
|
-
return value.map((item) =>
|
|
3722
|
+
return value.map((item) => normalizeValue2(item));
|
|
3469
3723
|
}
|
|
3470
|
-
if (
|
|
3724
|
+
if (isPlainObject3(value)) {
|
|
3471
3725
|
const normalized = {};
|
|
3472
3726
|
for (const key of Object.keys(value).sort()) {
|
|
3473
3727
|
const entry = value[key];
|
|
3474
3728
|
if (entry === void 0 || entry === null) continue;
|
|
3475
|
-
normalized[key] =
|
|
3729
|
+
normalized[key] = normalizeValue2(entry);
|
|
3476
3730
|
}
|
|
3477
3731
|
return normalized;
|
|
3478
3732
|
}
|
|
@@ -3480,11 +3734,11 @@ function normalizeValue(value) {
|
|
|
3480
3734
|
}
|
|
3481
3735
|
function normalizeAgentDefinition(definition) {
|
|
3482
3736
|
const config = {};
|
|
3483
|
-
const rawConfig =
|
|
3737
|
+
const rawConfig = isPlainObject3(definition.config) ? definition.config : {};
|
|
3484
3738
|
for (const key of AGENT_CONFIG_KEY_LIST) {
|
|
3485
3739
|
const value = rawConfig[key];
|
|
3486
3740
|
if (value === void 0 || value === null) continue;
|
|
3487
|
-
config[key] =
|
|
3741
|
+
config[key] = normalizeValue2(value);
|
|
3488
3742
|
}
|
|
3489
3743
|
return {
|
|
3490
3744
|
name: definition.name,
|
|
@@ -3502,7 +3756,7 @@ async function computeAgentContentHash(definition) {
|
|
|
3502
3756
|
var DEFINE_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set(["name", "description", "icon", ...AGENT_CONFIG_KEYS]);
|
|
3503
3757
|
function collectNonPortableToolRefs(config) {
|
|
3504
3758
|
const tools = config.tools;
|
|
3505
|
-
if (!
|
|
3759
|
+
if (!isPlainObject3(tools)) return [];
|
|
3506
3760
|
const found = [];
|
|
3507
3761
|
const isAccountScoped = (ref) => typeof ref === "string" && ref.startsWith("tool_");
|
|
3508
3762
|
const scanArray = (value, path) => {
|
|
@@ -3512,7 +3766,7 @@ function collectNonPortableToolRefs(config) {
|
|
|
3512
3766
|
});
|
|
3513
3767
|
};
|
|
3514
3768
|
const scanKeys = (value, path) => {
|
|
3515
|
-
if (!
|
|
3769
|
+
if (!isPlainObject3(value)) return;
|
|
3516
3770
|
for (const key of Object.keys(value)) {
|
|
3517
3771
|
if (isAccountScoped(key)) found.push(`${path}.${key}`);
|
|
3518
3772
|
}
|
|
@@ -3520,16 +3774,16 @@ function collectNonPortableToolRefs(config) {
|
|
|
3520
3774
|
scanArray(tools.toolIds, "tools.toolIds");
|
|
3521
3775
|
scanKeys(tools.toolConfigs, "tools.toolConfigs");
|
|
3522
3776
|
scanKeys(tools.perToolLimits, "tools.perToolLimits");
|
|
3523
|
-
if (
|
|
3524
|
-
if (
|
|
3777
|
+
if (isPlainObject3(tools.approval)) scanArray(tools.approval.require, "tools.approval.require");
|
|
3778
|
+
if (isPlainObject3(tools.subagentConfig)) {
|
|
3525
3779
|
scanArray(tools.subagentConfig.toolPool, "tools.subagentConfig.toolPool");
|
|
3526
3780
|
}
|
|
3527
|
-
if (
|
|
3781
|
+
if (isPlainObject3(tools.codeModeConfig)) {
|
|
3528
3782
|
scanArray(tools.codeModeConfig.toolPool, "tools.codeModeConfig.toolPool");
|
|
3529
3783
|
}
|
|
3530
3784
|
if (Array.isArray(tools.runtimeTools)) {
|
|
3531
3785
|
tools.runtimeTools.forEach((runtimeTool, i) => {
|
|
3532
|
-
if (!
|
|
3786
|
+
if (!isPlainObject3(runtimeTool) || !isPlainObject3(runtimeTool.config)) return;
|
|
3533
3787
|
const base = `tools.runtimeTools[${i}].config`;
|
|
3534
3788
|
const rtConfig = runtimeTool.config;
|
|
3535
3789
|
if (runtimeTool.toolType === "subagent" && typeof rtConfig.agentId === "string" && rtConfig.agentId.startsWith("agent_")) {
|
|
@@ -3590,226 +3844,693 @@ var AgentDriftError = class extends Error {
|
|
|
3590
3844
|
this.name = "AgentDriftError";
|
|
3591
3845
|
this.plan = plan;
|
|
3592
3846
|
}
|
|
3593
|
-
};
|
|
3594
|
-
function
|
|
3595
|
-
if (!(err instanceof Error)) return { status: null, body: null };
|
|
3596
|
-
const match = err.message.match(/^API request failed: (\d{3}) .*? - ([\s\S]*)$/);
|
|
3597
|
-
if (!match) return { status: null, body: null };
|
|
3598
|
-
try {
|
|
3599
|
-
return { status: Number(match[1]), body: JSON.parse(match[2]) };
|
|
3600
|
-
} catch {
|
|
3601
|
-
return { status: Number(match[1]), body: null };
|
|
3847
|
+
};
|
|
3848
|
+
function parseRequestError3(err) {
|
|
3849
|
+
if (!(err instanceof Error)) return { status: null, body: null };
|
|
3850
|
+
const match = err.message.match(/^API request failed: (\d{3}) .*? - ([\s\S]*)$/);
|
|
3851
|
+
if (!match) return { status: null, body: null };
|
|
3852
|
+
try {
|
|
3853
|
+
return { status: Number(match[1]), body: JSON.parse(match[2]) };
|
|
3854
|
+
} catch {
|
|
3855
|
+
return { status: Number(match[1]), body: null };
|
|
3856
|
+
}
|
|
3857
|
+
}
|
|
3858
|
+
function toConflictError3(err) {
|
|
3859
|
+
const { status, body } = parseRequestError3(err);
|
|
3860
|
+
if (status !== 409 || !isPlainObject3(body)) return null;
|
|
3861
|
+
const code = body.code;
|
|
3862
|
+
if (code !== "external_modification" && code !== "remote_changed") return null;
|
|
3863
|
+
return new AgentEnsureConflictError(
|
|
3864
|
+
body
|
|
3865
|
+
);
|
|
3866
|
+
}
|
|
3867
|
+
var serverHashMemo3 = /* @__PURE__ */ new WeakMap();
|
|
3868
|
+
function memoFor3(client) {
|
|
3869
|
+
let memo = serverHashMemo3.get(client);
|
|
3870
|
+
if (!memo) {
|
|
3871
|
+
memo = /* @__PURE__ */ new Map();
|
|
3872
|
+
serverHashMemo3.set(client, memo);
|
|
3873
|
+
}
|
|
3874
|
+
return memo;
|
|
3875
|
+
}
|
|
3876
|
+
var AgentsNamespace = class {
|
|
3877
|
+
constructor(getClient) {
|
|
3878
|
+
this.getClient = getClient;
|
|
3879
|
+
}
|
|
3880
|
+
/**
|
|
3881
|
+
* Idempotently converge a definition onto the platform. Hash-first: probes
|
|
3882
|
+
* with a content hash, and only ships the full definition when the server
|
|
3883
|
+
* reports a miss (`definitionRequired`). Creates an immutable version
|
|
3884
|
+
* snapshot on every change; never deletes.
|
|
3885
|
+
*/
|
|
3886
|
+
async ensure(definition, options = {}) {
|
|
3887
|
+
const client = this.getClient();
|
|
3888
|
+
const { dryRun, onConflict, release, expectedRemoteHash, expectNoChanges } = options;
|
|
3889
|
+
const passthrough = {
|
|
3890
|
+
...onConflict ? { onConflict } : {},
|
|
3891
|
+
...release ? { release } : {},
|
|
3892
|
+
...expectedRemoteHash ? { expectedRemoteHash } : {}
|
|
3893
|
+
};
|
|
3894
|
+
if (dryRun || expectNoChanges) {
|
|
3895
|
+
const plan = await this.request(client, {
|
|
3896
|
+
name: definition.name,
|
|
3897
|
+
definition,
|
|
3898
|
+
dryRun: true,
|
|
3899
|
+
...passthrough
|
|
3900
|
+
});
|
|
3901
|
+
if (plan.result !== "plan") {
|
|
3902
|
+
throw new Error(`Expected a plan result from dryRun, got '${plan.result}'`);
|
|
3903
|
+
}
|
|
3904
|
+
if (expectNoChanges && plan.changes !== "none") {
|
|
3905
|
+
throw new AgentDriftError(plan);
|
|
3906
|
+
}
|
|
3907
|
+
return plan;
|
|
3908
|
+
}
|
|
3909
|
+
const memo = memoFor3(client);
|
|
3910
|
+
const localHash = await computeAgentContentHash({
|
|
3911
|
+
...definition,
|
|
3912
|
+
config: definition.config
|
|
3913
|
+
});
|
|
3914
|
+
const memoKey = `${definition.name}\0${localHash}`;
|
|
3915
|
+
const contentHash = memo.get(memoKey) ?? localHash;
|
|
3916
|
+
const probe = await this.request(client, {
|
|
3917
|
+
name: definition.name,
|
|
3918
|
+
contentHash,
|
|
3919
|
+
...passthrough
|
|
3920
|
+
});
|
|
3921
|
+
if (probe.result !== "definitionRequired") {
|
|
3922
|
+
this.memoize(memo, memoKey, probe);
|
|
3923
|
+
return probe;
|
|
3924
|
+
}
|
|
3925
|
+
const converged = await this.request(client, {
|
|
3926
|
+
name: definition.name,
|
|
3927
|
+
definition,
|
|
3928
|
+
...passthrough
|
|
3929
|
+
});
|
|
3930
|
+
if (converged.result === "definitionRequired") {
|
|
3931
|
+
throw new Error("Server reported definitionRequired for a full-definition request");
|
|
3932
|
+
}
|
|
3933
|
+
this.memoize(memo, memoKey, converged);
|
|
3934
|
+
return converged;
|
|
3935
|
+
}
|
|
3936
|
+
/**
|
|
3937
|
+
* Pull the canonical definition + provenance for an agent by name — the
|
|
3938
|
+
* absorb-drift direction. The contentHash reflects the live agent state.
|
|
3939
|
+
*/
|
|
3940
|
+
async pull(name) {
|
|
3941
|
+
const client = this.getClient();
|
|
3942
|
+
return client.get("/agents/pull", { name });
|
|
3943
|
+
}
|
|
3944
|
+
memoize(memo, memoKey, result) {
|
|
3945
|
+
if (result.result !== "plan") memo.set(memoKey, result.contentHash);
|
|
3946
|
+
}
|
|
3947
|
+
async request(client, body) {
|
|
3948
|
+
try {
|
|
3949
|
+
return await client.post(
|
|
3950
|
+
"/agents/ensure",
|
|
3951
|
+
body
|
|
3952
|
+
);
|
|
3953
|
+
} catch (err) {
|
|
3954
|
+
const conflict = toConflictError3(err);
|
|
3955
|
+
if (conflict) throw conflict;
|
|
3956
|
+
throw err;
|
|
3957
|
+
}
|
|
3958
|
+
}
|
|
3959
|
+
};
|
|
3960
|
+
|
|
3961
|
+
// src/tools-ensure.ts
|
|
3962
|
+
function isPlainObject4(value) {
|
|
3963
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3964
|
+
}
|
|
3965
|
+
function normalizeValue3(value) {
|
|
3966
|
+
if (Array.isArray(value)) {
|
|
3967
|
+
return value.map((item) => normalizeValue3(item));
|
|
3968
|
+
}
|
|
3969
|
+
if (isPlainObject4(value)) {
|
|
3970
|
+
const normalized = {};
|
|
3971
|
+
for (const key of Object.keys(value).sort()) {
|
|
3972
|
+
const entry = value[key];
|
|
3973
|
+
if (entry === void 0 || entry === null) continue;
|
|
3974
|
+
normalized[key] = normalizeValue3(entry);
|
|
3975
|
+
}
|
|
3976
|
+
return normalized;
|
|
3977
|
+
}
|
|
3978
|
+
return value;
|
|
3979
|
+
}
|
|
3980
|
+
function normalizeToolDefinition(definition) {
|
|
3981
|
+
const parametersSchema = isPlainObject4(definition.parametersSchema) ? normalizeValue3(definition.parametersSchema) : {};
|
|
3982
|
+
const config = isPlainObject4(definition.config) ? normalizeValue3(definition.config) : {};
|
|
3983
|
+
return {
|
|
3984
|
+
toolType: definition.toolType,
|
|
3985
|
+
...definition.description ? { description: definition.description } : {},
|
|
3986
|
+
parametersSchema,
|
|
3987
|
+
config
|
|
3988
|
+
};
|
|
3989
|
+
}
|
|
3990
|
+
async function computeToolContentHash(definition) {
|
|
3991
|
+
const serialized = JSON.stringify(normalizeToolDefinition(definition));
|
|
3992
|
+
const encoded = new TextEncoder().encode(serialized);
|
|
3993
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
|
|
3994
|
+
return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
3995
|
+
}
|
|
3996
|
+
var DEFINE_TOOL_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
3997
|
+
"name",
|
|
3998
|
+
"description",
|
|
3999
|
+
"toolType",
|
|
4000
|
+
"parametersSchema",
|
|
4001
|
+
"config"
|
|
4002
|
+
]);
|
|
4003
|
+
var TOOL_DEFINITION_TYPES = /* @__PURE__ */ new Set([
|
|
4004
|
+
"flow",
|
|
4005
|
+
"custom",
|
|
4006
|
+
"external",
|
|
4007
|
+
"graphql",
|
|
4008
|
+
"mcp",
|
|
4009
|
+
"local",
|
|
4010
|
+
"subagent"
|
|
4011
|
+
]);
|
|
4012
|
+
function defineTool(input) {
|
|
4013
|
+
if (!input || typeof input !== "object") {
|
|
4014
|
+
throw new Error("defineTool requires a definition object");
|
|
4015
|
+
}
|
|
4016
|
+
if (typeof input.name !== "string" || input.name.length === 0) {
|
|
4017
|
+
throw new Error('defineTool requires a non-empty string "name"');
|
|
4018
|
+
}
|
|
4019
|
+
if (typeof input.description !== "string" || input.description.length === 0) {
|
|
4020
|
+
throw new Error('defineTool requires a non-empty string "description"');
|
|
4021
|
+
}
|
|
4022
|
+
if (typeof input.toolType !== "string" || !TOOL_DEFINITION_TYPES.has(input.toolType)) {
|
|
4023
|
+
throw new Error(
|
|
4024
|
+
`defineTool requires "toolType" to be one of: ${[...TOOL_DEFINITION_TYPES].join(", ")}`
|
|
4025
|
+
);
|
|
4026
|
+
}
|
|
4027
|
+
if (!isPlainObject4(input.parametersSchema)) {
|
|
4028
|
+
throw new Error('defineTool requires a "parametersSchema" object (a JSON Schema)');
|
|
4029
|
+
}
|
|
4030
|
+
if (!isPlainObject4(input.config)) {
|
|
4031
|
+
throw new Error('defineTool requires a "config" object');
|
|
4032
|
+
}
|
|
4033
|
+
const unknownKeys = Object.keys(input).filter((key) => !DEFINE_TOOL_TOP_LEVEL_KEYS.has(key));
|
|
4034
|
+
if (unknownKeys.length > 0) {
|
|
4035
|
+
throw new Error(
|
|
4036
|
+
`defineTool: unknown field(s): ${unknownKeys.join(", ")}. Allowed fields are name, description, toolType, parametersSchema, config.`
|
|
4037
|
+
);
|
|
4038
|
+
}
|
|
4039
|
+
return {
|
|
4040
|
+
name: input.name,
|
|
4041
|
+
description: input.description,
|
|
4042
|
+
toolType: input.toolType,
|
|
4043
|
+
parametersSchema: input.parametersSchema,
|
|
4044
|
+
config: input.config
|
|
4045
|
+
};
|
|
4046
|
+
}
|
|
4047
|
+
var ToolEnsureConflictError = class extends Error {
|
|
4048
|
+
constructor(body) {
|
|
4049
|
+
super(body.error ?? `Tool ensure conflict: ${body.code}`);
|
|
4050
|
+
this.name = "ToolEnsureConflictError";
|
|
4051
|
+
this.code = body.code;
|
|
4052
|
+
this.lastModifiedSource = body.lastModifiedSource;
|
|
4053
|
+
this.modifiedAt = body.modifiedAt;
|
|
4054
|
+
this.currentHash = body.currentHash;
|
|
4055
|
+
}
|
|
4056
|
+
};
|
|
4057
|
+
var ToolDriftError = class extends Error {
|
|
4058
|
+
constructor(plan) {
|
|
4059
|
+
super(
|
|
4060
|
+
`Tool "${plan.toolId ?? "definition"}" drifted: plan is '${plan.changes}' (changed: ${plan.changedKeys.join(", ") || "n/a"}). Run client.tools.pull(name) to absorb the remote edit into your repo, or re-run ensure to converge.`
|
|
4061
|
+
);
|
|
4062
|
+
this.name = "ToolDriftError";
|
|
4063
|
+
this.plan = plan;
|
|
4064
|
+
}
|
|
4065
|
+
};
|
|
4066
|
+
function parseRequestError4(err) {
|
|
4067
|
+
if (!(err instanceof Error)) return { status: null, body: null };
|
|
4068
|
+
const match = err.message.match(/^API request failed: (\d{3}) .*? - ([\s\S]*)$/);
|
|
4069
|
+
if (!match) return { status: null, body: null };
|
|
4070
|
+
try {
|
|
4071
|
+
return { status: Number(match[1]), body: JSON.parse(match[2]) };
|
|
4072
|
+
} catch {
|
|
4073
|
+
return { status: Number(match[1]), body: null };
|
|
4074
|
+
}
|
|
4075
|
+
}
|
|
4076
|
+
function toConflictError4(err) {
|
|
4077
|
+
const { status, body } = parseRequestError4(err);
|
|
4078
|
+
if (status !== 409 || !isPlainObject4(body)) return null;
|
|
4079
|
+
const code = body.code;
|
|
4080
|
+
if (code !== "external_modification" && code !== "remote_changed") return null;
|
|
4081
|
+
return new ToolEnsureConflictError(
|
|
4082
|
+
body
|
|
4083
|
+
);
|
|
4084
|
+
}
|
|
4085
|
+
var serverHashMemo4 = /* @__PURE__ */ new WeakMap();
|
|
4086
|
+
function memoFor4(client) {
|
|
4087
|
+
let memo = serverHashMemo4.get(client);
|
|
4088
|
+
if (!memo) {
|
|
4089
|
+
memo = /* @__PURE__ */ new Map();
|
|
4090
|
+
serverHashMemo4.set(client, memo);
|
|
4091
|
+
}
|
|
4092
|
+
return memo;
|
|
4093
|
+
}
|
|
4094
|
+
function memoize3(memo, memoKey, result) {
|
|
4095
|
+
if (result.result !== "plan") memo.set(memoKey, result.contentHash);
|
|
4096
|
+
}
|
|
4097
|
+
async function request3(client, body) {
|
|
4098
|
+
try {
|
|
4099
|
+
return await client.post(
|
|
4100
|
+
"/tools/ensure",
|
|
4101
|
+
body
|
|
4102
|
+
);
|
|
4103
|
+
} catch (err) {
|
|
4104
|
+
const conflict = toConflictError4(err);
|
|
4105
|
+
if (conflict) throw conflict;
|
|
4106
|
+
throw err;
|
|
4107
|
+
}
|
|
4108
|
+
}
|
|
4109
|
+
async function ensureTool(client, definition, options = {}) {
|
|
4110
|
+
const { dryRun, onConflict, expectedRemoteHash, expectNoChanges } = options;
|
|
4111
|
+
const passthrough = {
|
|
4112
|
+
...onConflict ? { onConflict } : {},
|
|
4113
|
+
...expectedRemoteHash ? { expectedRemoteHash } : {}
|
|
4114
|
+
};
|
|
4115
|
+
if (dryRun || expectNoChanges) {
|
|
4116
|
+
const plan = await request3(client, {
|
|
4117
|
+
name: definition.name,
|
|
4118
|
+
definition,
|
|
4119
|
+
dryRun: true,
|
|
4120
|
+
...passthrough
|
|
4121
|
+
});
|
|
4122
|
+
if (plan.result !== "plan") {
|
|
4123
|
+
throw new Error(`Expected a plan result from dryRun, got '${plan.result}'`);
|
|
4124
|
+
}
|
|
4125
|
+
if (expectNoChanges && plan.changes !== "none") {
|
|
4126
|
+
throw new ToolDriftError(plan);
|
|
4127
|
+
}
|
|
4128
|
+
return plan;
|
|
4129
|
+
}
|
|
4130
|
+
const memo = memoFor4(client);
|
|
4131
|
+
const localHash = await computeToolContentHash(definition);
|
|
4132
|
+
const memoKey = `${definition.name} ${localHash}`;
|
|
4133
|
+
const contentHash = memo.get(memoKey) ?? localHash;
|
|
4134
|
+
const probe = await request3(client, {
|
|
4135
|
+
name: definition.name,
|
|
4136
|
+
contentHash,
|
|
4137
|
+
...passthrough
|
|
4138
|
+
});
|
|
4139
|
+
if (probe.result !== "definitionRequired") {
|
|
4140
|
+
memoize3(memo, memoKey, probe);
|
|
4141
|
+
return probe;
|
|
4142
|
+
}
|
|
4143
|
+
const converged = await request3(client, {
|
|
4144
|
+
name: definition.name,
|
|
4145
|
+
definition,
|
|
4146
|
+
...passthrough
|
|
4147
|
+
});
|
|
4148
|
+
if (converged.result === "definitionRequired") {
|
|
4149
|
+
throw new Error("Server reported definitionRequired for a full-definition request");
|
|
4150
|
+
}
|
|
4151
|
+
memoize3(memo, memoKey, converged);
|
|
4152
|
+
return converged;
|
|
4153
|
+
}
|
|
4154
|
+
async function pullTool(client, name) {
|
|
4155
|
+
return client.get("/tools/pull", { name });
|
|
4156
|
+
}
|
|
4157
|
+
|
|
4158
|
+
// src/tools-namespace.ts
|
|
4159
|
+
var ToolsNamespace = class {
|
|
4160
|
+
constructor(getClient) {
|
|
4161
|
+
this.getClient = getClient;
|
|
4162
|
+
}
|
|
4163
|
+
/**
|
|
4164
|
+
* Idempotently converge a `defineTool` definition onto the platform.
|
|
4165
|
+
* Hash-first: the steady state is one tiny probe request. Creates or updates
|
|
4166
|
+
* the saved tool; never deletes. Identity is name + account scope.
|
|
4167
|
+
*
|
|
4168
|
+
* @example
|
|
4169
|
+
* ```typescript
|
|
4170
|
+
* const weather = defineTool({
|
|
4171
|
+
* name: 'Weather Lookup',
|
|
4172
|
+
* description: 'Fetch the current weather for a city',
|
|
4173
|
+
* toolType: 'external',
|
|
4174
|
+
* parametersSchema: { type: 'object', properties: { city: { type: 'string' } } },
|
|
4175
|
+
* config: { url: 'https://api.example.com/weather', method: 'GET' },
|
|
4176
|
+
* })
|
|
4177
|
+
*
|
|
4178
|
+
* // Converge (CI/deploy).
|
|
4179
|
+
* const result = await Runtype.tools.ensure(weather)
|
|
4180
|
+
*
|
|
4181
|
+
* // PR drift gate.
|
|
4182
|
+
* await Runtype.tools.ensure(weather, { expectNoChanges: true })
|
|
4183
|
+
* ```
|
|
4184
|
+
*/
|
|
4185
|
+
async ensure(definition, options = {}) {
|
|
4186
|
+
return ensureTool(this.getClient(), definition, options);
|
|
4187
|
+
}
|
|
4188
|
+
/**
|
|
4189
|
+
* Pull the canonical definition + provenance for a tool by name — the
|
|
4190
|
+
* absorb-drift direction of the ensure protocol.
|
|
4191
|
+
*/
|
|
4192
|
+
async pull(name) {
|
|
4193
|
+
return pullTool(this.getClient(), name);
|
|
4194
|
+
}
|
|
4195
|
+
};
|
|
4196
|
+
|
|
4197
|
+
// src/products-ensure.ts
|
|
4198
|
+
function isPlainObject5(value) {
|
|
4199
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4200
|
+
}
|
|
4201
|
+
function normalizeValue4(value) {
|
|
4202
|
+
if (Array.isArray(value)) {
|
|
4203
|
+
return value.map((item) => normalizeValue4(item));
|
|
4204
|
+
}
|
|
4205
|
+
if (isPlainObject5(value)) {
|
|
4206
|
+
const normalized = {};
|
|
4207
|
+
for (const key of Object.keys(value).sort()) {
|
|
4208
|
+
const entry = value[key];
|
|
4209
|
+
if (entry === void 0 || entry === null) continue;
|
|
4210
|
+
normalized[key] = normalizeValue4(entry);
|
|
4211
|
+
}
|
|
4212
|
+
return normalized;
|
|
4213
|
+
}
|
|
4214
|
+
return value;
|
|
4215
|
+
}
|
|
4216
|
+
function normalizeProductDefinition(definition) {
|
|
4217
|
+
const spec = isPlainObject5(definition.spec) ? normalizeValue4(definition.spec) : {};
|
|
4218
|
+
return {
|
|
4219
|
+
...definition.description ? { description: definition.description } : {},
|
|
4220
|
+
...definition.icon ? { icon: definition.icon } : {},
|
|
4221
|
+
spec
|
|
4222
|
+
};
|
|
4223
|
+
}
|
|
4224
|
+
async function computeProductContentHash(definition) {
|
|
4225
|
+
const serialized = JSON.stringify(normalizeProductDefinition(definition));
|
|
4226
|
+
const encoded = new TextEncoder().encode(serialized);
|
|
4227
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
|
|
4228
|
+
return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
4229
|
+
}
|
|
4230
|
+
var DEFINE_PRODUCT_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set(["name", "description", "icon", "spec"]);
|
|
4231
|
+
function defineProduct(input) {
|
|
4232
|
+
if (!input || typeof input !== "object") {
|
|
4233
|
+
throw new Error("defineProduct requires a definition object");
|
|
4234
|
+
}
|
|
4235
|
+
if (typeof input.name !== "string" || input.name.length === 0) {
|
|
4236
|
+
throw new Error('defineProduct requires a non-empty string "name"');
|
|
4237
|
+
}
|
|
4238
|
+
if (input.description != null && typeof input.description !== "string") {
|
|
4239
|
+
throw new Error('defineProduct "description" must be a string when provided');
|
|
4240
|
+
}
|
|
4241
|
+
if (input.icon != null && typeof input.icon !== "string") {
|
|
4242
|
+
throw new Error('defineProduct "icon" must be a string when provided');
|
|
4243
|
+
}
|
|
4244
|
+
if (input.spec != null && !isPlainObject5(input.spec)) {
|
|
4245
|
+
throw new Error('defineProduct "spec" must be an object when provided');
|
|
4246
|
+
}
|
|
4247
|
+
const unknownKeys = Object.keys(input).filter((key) => !DEFINE_PRODUCT_TOP_LEVEL_KEYS.has(key));
|
|
4248
|
+
if (unknownKeys.length > 0) {
|
|
4249
|
+
throw new Error(
|
|
4250
|
+
`defineProduct: unknown field(s): ${unknownKeys.join(", ")}. Allowed fields are name, description, icon, spec. (canvas / nested capabilities and surfaces are not converged by ensure.)`
|
|
4251
|
+
);
|
|
4252
|
+
}
|
|
4253
|
+
return {
|
|
4254
|
+
name: input.name,
|
|
4255
|
+
...input.description !== void 0 ? { description: input.description } : {},
|
|
4256
|
+
...input.icon !== void 0 ? { icon: input.icon } : {},
|
|
4257
|
+
...input.spec !== void 0 ? { spec: input.spec } : {}
|
|
4258
|
+
};
|
|
4259
|
+
}
|
|
4260
|
+
var ProductEnsureConflictError = class extends Error {
|
|
4261
|
+
constructor(body) {
|
|
4262
|
+
super(body.error ?? `Product ensure conflict: ${body.code}`);
|
|
4263
|
+
this.name = "ProductEnsureConflictError";
|
|
4264
|
+
this.code = body.code;
|
|
4265
|
+
this.lastModifiedSource = body.lastModifiedSource;
|
|
4266
|
+
this.modifiedAt = body.modifiedAt;
|
|
4267
|
+
this.currentHash = body.currentHash;
|
|
4268
|
+
}
|
|
4269
|
+
};
|
|
4270
|
+
var ProductDriftError = class extends Error {
|
|
4271
|
+
constructor(plan) {
|
|
4272
|
+
super(
|
|
4273
|
+
`Product "${plan.productId ?? "definition"}" drifted: plan is '${plan.changes}' (changed: ${plan.changedKeys.join(", ") || "n/a"}). Run client.products.pull(name) to absorb the remote edit into your repo, or re-run ensure to converge.`
|
|
4274
|
+
);
|
|
4275
|
+
this.name = "ProductDriftError";
|
|
4276
|
+
this.plan = plan;
|
|
4277
|
+
}
|
|
4278
|
+
};
|
|
4279
|
+
function parseRequestError5(err) {
|
|
4280
|
+
if (!(err instanceof Error)) return { status: null, body: null };
|
|
4281
|
+
const match = err.message.match(/^API request failed: (\d{3}) .*? - ([\s\S]*)$/);
|
|
4282
|
+
if (!match) return { status: null, body: null };
|
|
4283
|
+
try {
|
|
4284
|
+
return { status: Number(match[1]), body: JSON.parse(match[2]) };
|
|
4285
|
+
} catch {
|
|
4286
|
+
return { status: Number(match[1]), body: null };
|
|
4287
|
+
}
|
|
4288
|
+
}
|
|
4289
|
+
function toConflictError5(err) {
|
|
4290
|
+
const { status, body } = parseRequestError5(err);
|
|
4291
|
+
if (status !== 409 || !isPlainObject5(body)) return null;
|
|
4292
|
+
const code = body.code;
|
|
4293
|
+
if (code !== "external_modification" && code !== "remote_changed") return null;
|
|
4294
|
+
return new ProductEnsureConflictError(
|
|
4295
|
+
body
|
|
4296
|
+
);
|
|
4297
|
+
}
|
|
4298
|
+
var serverHashMemo5 = /* @__PURE__ */ new WeakMap();
|
|
4299
|
+
function memoFor5(client) {
|
|
4300
|
+
let memo = serverHashMemo5.get(client);
|
|
4301
|
+
if (!memo) {
|
|
4302
|
+
memo = /* @__PURE__ */ new Map();
|
|
4303
|
+
serverHashMemo5.set(client, memo);
|
|
4304
|
+
}
|
|
4305
|
+
return memo;
|
|
4306
|
+
}
|
|
4307
|
+
function memoize4(memo, memoKey, result) {
|
|
4308
|
+
if (result.result !== "plan") memo.set(memoKey, result.contentHash);
|
|
4309
|
+
}
|
|
4310
|
+
async function request4(client, body) {
|
|
4311
|
+
try {
|
|
4312
|
+
return await client.post(
|
|
4313
|
+
"/products/ensure",
|
|
4314
|
+
body
|
|
4315
|
+
);
|
|
4316
|
+
} catch (err) {
|
|
4317
|
+
const conflict = toConflictError5(err);
|
|
4318
|
+
if (conflict) throw conflict;
|
|
4319
|
+
throw err;
|
|
4320
|
+
}
|
|
4321
|
+
}
|
|
4322
|
+
async function ensureProduct(client, definition, options = {}) {
|
|
4323
|
+
const { dryRun, onConflict, expectedRemoteHash, expectNoChanges } = options;
|
|
4324
|
+
const passthrough = {
|
|
4325
|
+
...onConflict ? { onConflict } : {},
|
|
4326
|
+
...expectedRemoteHash ? { expectedRemoteHash } : {}
|
|
4327
|
+
};
|
|
4328
|
+
if (dryRun || expectNoChanges) {
|
|
4329
|
+
const plan = await request4(client, {
|
|
4330
|
+
name: definition.name,
|
|
4331
|
+
definition,
|
|
4332
|
+
dryRun: true,
|
|
4333
|
+
...passthrough
|
|
4334
|
+
});
|
|
4335
|
+
if (plan.result !== "plan") {
|
|
4336
|
+
throw new Error(`Expected a plan result from dryRun, got '${plan.result}'`);
|
|
4337
|
+
}
|
|
4338
|
+
if (expectNoChanges && plan.changes !== "none") {
|
|
4339
|
+
throw new ProductDriftError(plan);
|
|
4340
|
+
}
|
|
4341
|
+
return plan;
|
|
4342
|
+
}
|
|
4343
|
+
const memo = memoFor5(client);
|
|
4344
|
+
const localHash = await computeProductContentHash(definition);
|
|
4345
|
+
const memoKey = `${definition.name} ${localHash}`;
|
|
4346
|
+
const contentHash = memo.get(memoKey) ?? localHash;
|
|
4347
|
+
const probe = await request4(client, {
|
|
4348
|
+
name: definition.name,
|
|
4349
|
+
contentHash,
|
|
4350
|
+
...passthrough
|
|
4351
|
+
});
|
|
4352
|
+
if (probe.result !== "definitionRequired") {
|
|
4353
|
+
memoize4(memo, memoKey, probe);
|
|
4354
|
+
return probe;
|
|
4355
|
+
}
|
|
4356
|
+
const converged = await request4(client, {
|
|
4357
|
+
name: definition.name,
|
|
4358
|
+
definition,
|
|
4359
|
+
...passthrough
|
|
4360
|
+
});
|
|
4361
|
+
if (converged.result === "definitionRequired") {
|
|
4362
|
+
throw new Error("Server reported definitionRequired for a full-definition request");
|
|
3602
4363
|
}
|
|
4364
|
+
memoize4(memo, memoKey, converged);
|
|
4365
|
+
return converged;
|
|
3603
4366
|
}
|
|
3604
|
-
function
|
|
3605
|
-
|
|
3606
|
-
if (status !== 409 || !isPlainObject2(body)) return null;
|
|
3607
|
-
const code = body.code;
|
|
3608
|
-
if (code !== "external_modification" && code !== "remote_changed") return null;
|
|
3609
|
-
return new AgentEnsureConflictError(
|
|
3610
|
-
body
|
|
3611
|
-
);
|
|
3612
|
-
}
|
|
3613
|
-
var serverHashMemo2 = /* @__PURE__ */ new WeakMap();
|
|
3614
|
-
function memoFor2(client) {
|
|
3615
|
-
let memo = serverHashMemo2.get(client);
|
|
3616
|
-
if (!memo) {
|
|
3617
|
-
memo = /* @__PURE__ */ new Map();
|
|
3618
|
-
serverHashMemo2.set(client, memo);
|
|
3619
|
-
}
|
|
3620
|
-
return memo;
|
|
4367
|
+
async function pullProduct(client, name) {
|
|
4368
|
+
return client.get("/products/pull", { name });
|
|
3621
4369
|
}
|
|
3622
|
-
|
|
4370
|
+
|
|
4371
|
+
// src/products-namespace.ts
|
|
4372
|
+
var ProductsNamespace = class {
|
|
3623
4373
|
constructor(getClient) {
|
|
3624
4374
|
this.getClient = getClient;
|
|
3625
4375
|
}
|
|
3626
4376
|
/**
|
|
3627
|
-
* Idempotently converge a definition onto the platform.
|
|
3628
|
-
*
|
|
3629
|
-
*
|
|
3630
|
-
*
|
|
4377
|
+
* Idempotently converge a `defineProduct` definition onto the platform.
|
|
4378
|
+
* Hash-first: the steady state is one tiny probe request. Creates or updates
|
|
4379
|
+
* the top-level product record; never deletes. Identity is name + account
|
|
4380
|
+
* scope.
|
|
4381
|
+
*
|
|
4382
|
+
* @example
|
|
4383
|
+
* ```typescript
|
|
4384
|
+
* const product = defineProduct({
|
|
4385
|
+
* name: 'Support Copilot',
|
|
4386
|
+
* description: 'An AI support assistant',
|
|
4387
|
+
* icon: '🤖',
|
|
4388
|
+
* spec: { productGoal: 'Deflect tier-1 tickets', productStage: 'beta' },
|
|
4389
|
+
* })
|
|
4390
|
+
*
|
|
4391
|
+
* // Converge (CI/deploy).
|
|
4392
|
+
* const result = await Runtype.products.ensure(product)
|
|
4393
|
+
*
|
|
4394
|
+
* // PR drift gate.
|
|
4395
|
+
* await Runtype.products.ensure(product, { expectNoChanges: true })
|
|
4396
|
+
* ```
|
|
3631
4397
|
*/
|
|
3632
4398
|
async ensure(definition, options = {}) {
|
|
3633
|
-
|
|
3634
|
-
const { dryRun, onConflict, release, expectedRemoteHash, expectNoChanges } = options;
|
|
3635
|
-
const passthrough = {
|
|
3636
|
-
...onConflict ? { onConflict } : {},
|
|
3637
|
-
...release ? { release } : {},
|
|
3638
|
-
...expectedRemoteHash ? { expectedRemoteHash } : {}
|
|
3639
|
-
};
|
|
3640
|
-
if (dryRun || expectNoChanges) {
|
|
3641
|
-
const plan = await this.request(client, {
|
|
3642
|
-
name: definition.name,
|
|
3643
|
-
definition,
|
|
3644
|
-
dryRun: true,
|
|
3645
|
-
...passthrough
|
|
3646
|
-
});
|
|
3647
|
-
if (plan.result !== "plan") {
|
|
3648
|
-
throw new Error(`Expected a plan result from dryRun, got '${plan.result}'`);
|
|
3649
|
-
}
|
|
3650
|
-
if (expectNoChanges && plan.changes !== "none") {
|
|
3651
|
-
throw new AgentDriftError(plan);
|
|
3652
|
-
}
|
|
3653
|
-
return plan;
|
|
3654
|
-
}
|
|
3655
|
-
const memo = memoFor2(client);
|
|
3656
|
-
const localHash = await computeAgentContentHash({
|
|
3657
|
-
...definition,
|
|
3658
|
-
config: definition.config
|
|
3659
|
-
});
|
|
3660
|
-
const memoKey = `${definition.name}\0${localHash}`;
|
|
3661
|
-
const contentHash = memo.get(memoKey) ?? localHash;
|
|
3662
|
-
const probe = await this.request(client, {
|
|
3663
|
-
name: definition.name,
|
|
3664
|
-
contentHash,
|
|
3665
|
-
...passthrough
|
|
3666
|
-
});
|
|
3667
|
-
if (probe.result !== "definitionRequired") {
|
|
3668
|
-
this.memoize(memo, memoKey, probe);
|
|
3669
|
-
return probe;
|
|
3670
|
-
}
|
|
3671
|
-
const converged = await this.request(client, {
|
|
3672
|
-
name: definition.name,
|
|
3673
|
-
definition,
|
|
3674
|
-
...passthrough
|
|
3675
|
-
});
|
|
3676
|
-
if (converged.result === "definitionRequired") {
|
|
3677
|
-
throw new Error("Server reported definitionRequired for a full-definition request");
|
|
3678
|
-
}
|
|
3679
|
-
this.memoize(memo, memoKey, converged);
|
|
3680
|
-
return converged;
|
|
4399
|
+
return ensureProduct(this.getClient(), definition, options);
|
|
3681
4400
|
}
|
|
3682
4401
|
/**
|
|
3683
|
-
* Pull the canonical definition + provenance for
|
|
3684
|
-
* absorb-drift direction
|
|
4402
|
+
* Pull the canonical definition + provenance for a product by name — the
|
|
4403
|
+
* absorb-drift direction of the ensure protocol.
|
|
3685
4404
|
*/
|
|
3686
4405
|
async pull(name) {
|
|
3687
|
-
|
|
3688
|
-
return client.get("/agents/pull", { name });
|
|
3689
|
-
}
|
|
3690
|
-
memoize(memo, memoKey, result) {
|
|
3691
|
-
if (result.result !== "plan") memo.set(memoKey, result.contentHash);
|
|
3692
|
-
}
|
|
3693
|
-
async request(client, body) {
|
|
3694
|
-
try {
|
|
3695
|
-
return await client.post(
|
|
3696
|
-
"/agents/ensure",
|
|
3697
|
-
body
|
|
3698
|
-
);
|
|
3699
|
-
} catch (err) {
|
|
3700
|
-
const conflict = toConflictError2(err);
|
|
3701
|
-
if (conflict) throw conflict;
|
|
3702
|
-
throw err;
|
|
3703
|
-
}
|
|
4406
|
+
return pullProduct(this.getClient(), name);
|
|
3704
4407
|
}
|
|
3705
4408
|
};
|
|
3706
4409
|
|
|
3707
|
-
// src/
|
|
3708
|
-
function
|
|
4410
|
+
// src/surfaces-ensure.ts
|
|
4411
|
+
function isPlainObject6(value) {
|
|
3709
4412
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3710
4413
|
}
|
|
3711
|
-
function
|
|
4414
|
+
function normalizeValue5(value) {
|
|
3712
4415
|
if (Array.isArray(value)) {
|
|
3713
|
-
return value.map((item) =>
|
|
4416
|
+
return value.map((item) => normalizeValue5(item));
|
|
3714
4417
|
}
|
|
3715
|
-
if (
|
|
4418
|
+
if (isPlainObject6(value)) {
|
|
3716
4419
|
const normalized = {};
|
|
3717
4420
|
for (const key of Object.keys(value).sort()) {
|
|
3718
4421
|
const entry = value[key];
|
|
3719
4422
|
if (entry === void 0 || entry === null) continue;
|
|
3720
|
-
normalized[key] =
|
|
4423
|
+
normalized[key] = normalizeValue5(entry);
|
|
3721
4424
|
}
|
|
3722
4425
|
return normalized;
|
|
3723
4426
|
}
|
|
3724
4427
|
return value;
|
|
3725
4428
|
}
|
|
3726
|
-
function
|
|
3727
|
-
const
|
|
3728
|
-
const config = isPlainObject3(definition.config) ? normalizeValue2(definition.config) : {};
|
|
4429
|
+
function normalizeSurfaceDefinition(definition) {
|
|
4430
|
+
const behavior = isPlainObject6(definition.behavior) ? normalizeValue5(definition.behavior) : { type: definition.type };
|
|
3729
4431
|
return {
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
4432
|
+
type: definition.type,
|
|
4433
|
+
behavior,
|
|
4434
|
+
status: definition.status || "draft",
|
|
4435
|
+
environment: definition.environment || "development"
|
|
3734
4436
|
};
|
|
3735
4437
|
}
|
|
3736
|
-
async function
|
|
3737
|
-
const serialized = JSON.stringify(
|
|
4438
|
+
async function computeSurfaceContentHash(definition) {
|
|
4439
|
+
const serialized = JSON.stringify(normalizeSurfaceDefinition(definition));
|
|
3738
4440
|
const encoded = new TextEncoder().encode(serialized);
|
|
3739
4441
|
const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
|
|
3740
4442
|
return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
3741
4443
|
}
|
|
3742
|
-
var
|
|
4444
|
+
var DEFINE_SURFACE_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
3743
4445
|
"name",
|
|
3744
|
-
"
|
|
3745
|
-
"
|
|
3746
|
-
"
|
|
3747
|
-
"
|
|
4446
|
+
"type",
|
|
4447
|
+
"behavior",
|
|
4448
|
+
"inbound",
|
|
4449
|
+
"outbound",
|
|
4450
|
+
"status",
|
|
4451
|
+
"environment"
|
|
3748
4452
|
]);
|
|
3749
|
-
var
|
|
3750
|
-
"
|
|
3751
|
-
"custom",
|
|
3752
|
-
"external",
|
|
3753
|
-
"graphql",
|
|
4453
|
+
var SURFACE_DEFINITION_TYPES = /* @__PURE__ */ new Set([
|
|
4454
|
+
"chat",
|
|
3754
4455
|
"mcp",
|
|
3755
|
-
"
|
|
3756
|
-
"
|
|
4456
|
+
"mcp_code",
|
|
4457
|
+
"api",
|
|
4458
|
+
"webhook",
|
|
4459
|
+
"schedule",
|
|
4460
|
+
"a2a",
|
|
4461
|
+
"email",
|
|
4462
|
+
"slack",
|
|
4463
|
+
"sms",
|
|
4464
|
+
"imessage",
|
|
4465
|
+
"discord",
|
|
4466
|
+
"whatsapp",
|
|
4467
|
+
"telegram",
|
|
4468
|
+
"hosted-page",
|
|
4469
|
+
"chrome_extension"
|
|
3757
4470
|
]);
|
|
3758
|
-
function
|
|
4471
|
+
function defineSurface(input) {
|
|
3759
4472
|
if (!input || typeof input !== "object") {
|
|
3760
|
-
throw new Error("
|
|
4473
|
+
throw new Error("defineSurface requires a definition object");
|
|
3761
4474
|
}
|
|
3762
4475
|
if (typeof input.name !== "string" || input.name.length === 0) {
|
|
3763
|
-
throw new Error('
|
|
4476
|
+
throw new Error('defineSurface requires a non-empty string "name"');
|
|
3764
4477
|
}
|
|
3765
|
-
if (typeof input.
|
|
3766
|
-
throw new Error('defineTool requires a non-empty string "description"');
|
|
3767
|
-
}
|
|
3768
|
-
if (typeof input.toolType !== "string" || !TOOL_DEFINITION_TYPES.has(input.toolType)) {
|
|
4478
|
+
if (typeof input.type !== "string" || !SURFACE_DEFINITION_TYPES.has(input.type)) {
|
|
3769
4479
|
throw new Error(
|
|
3770
|
-
`
|
|
4480
|
+
`defineSurface requires "type" to be one of: ${[...SURFACE_DEFINITION_TYPES].join(", ")}`
|
|
3771
4481
|
);
|
|
3772
4482
|
}
|
|
3773
|
-
if (!
|
|
3774
|
-
throw new Error('
|
|
4483
|
+
if (input.behavior !== void 0 && !isPlainObject6(input.behavior)) {
|
|
4484
|
+
throw new Error('defineSurface "behavior" must be an object when provided');
|
|
3775
4485
|
}
|
|
3776
|
-
if (!
|
|
3777
|
-
throw new Error('
|
|
4486
|
+
if (input.inbound !== void 0 && !isPlainObject6(input.inbound)) {
|
|
4487
|
+
throw new Error('defineSurface "inbound" must be an object when provided');
|
|
3778
4488
|
}
|
|
3779
|
-
|
|
4489
|
+
if (input.outbound !== void 0 && !isPlainObject6(input.outbound)) {
|
|
4490
|
+
throw new Error('defineSurface "outbound" must be an object when provided');
|
|
4491
|
+
}
|
|
4492
|
+
if (input.status !== void 0 && !["draft", "active", "paused"].includes(input.status)) {
|
|
4493
|
+
throw new Error('defineSurface "status" must be one of: draft, active, paused');
|
|
4494
|
+
}
|
|
4495
|
+
if (input.environment !== void 0 && !["production", "development"].includes(input.environment)) {
|
|
4496
|
+
throw new Error('defineSurface "environment" must be one of: production, development');
|
|
4497
|
+
}
|
|
4498
|
+
const unknownKeys = Object.keys(input).filter((key) => !DEFINE_SURFACE_TOP_LEVEL_KEYS.has(key));
|
|
3780
4499
|
if (unknownKeys.length > 0) {
|
|
3781
4500
|
throw new Error(
|
|
3782
|
-
`
|
|
4501
|
+
`defineSurface: unknown field(s): ${unknownKeys.join(", ")}. Allowed fields are name, type, behavior, inbound, outbound, status, environment.`
|
|
3783
4502
|
);
|
|
3784
4503
|
}
|
|
3785
4504
|
return {
|
|
3786
4505
|
name: input.name,
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
4506
|
+
type: input.type,
|
|
4507
|
+
...input.behavior !== void 0 ? { behavior: input.behavior } : {},
|
|
4508
|
+
...input.inbound !== void 0 ? { inbound: input.inbound } : {},
|
|
4509
|
+
...input.outbound !== void 0 ? { outbound: input.outbound } : {},
|
|
4510
|
+
...input.status !== void 0 ? { status: input.status } : {},
|
|
4511
|
+
...input.environment !== void 0 ? { environment: input.environment } : {}
|
|
3791
4512
|
};
|
|
3792
4513
|
}
|
|
3793
|
-
var
|
|
4514
|
+
var SurfaceEnsureConflictError = class extends Error {
|
|
3794
4515
|
constructor(body) {
|
|
3795
|
-
super(body.error ?? `
|
|
3796
|
-
this.name = "
|
|
4516
|
+
super(body.error ?? `Surface ensure conflict: ${body.code}`);
|
|
4517
|
+
this.name = "SurfaceEnsureConflictError";
|
|
3797
4518
|
this.code = body.code;
|
|
3798
4519
|
this.lastModifiedSource = body.lastModifiedSource;
|
|
3799
4520
|
this.modifiedAt = body.modifiedAt;
|
|
3800
4521
|
this.currentHash = body.currentHash;
|
|
3801
4522
|
}
|
|
3802
4523
|
};
|
|
3803
|
-
var
|
|
4524
|
+
var SurfaceDriftError = class extends Error {
|
|
3804
4525
|
constructor(plan) {
|
|
3805
4526
|
super(
|
|
3806
|
-
`
|
|
4527
|
+
`Surface "${plan.surfaceId ?? "definition"}" drifted: plan is '${plan.changes}' (changed: ${plan.changedKeys.join(", ") || "n/a"}). Run client.surfaces.pull(productId, name) to absorb the remote edit into your repo, or re-run ensure to converge.`
|
|
3807
4528
|
);
|
|
3808
|
-
this.name = "
|
|
4529
|
+
this.name = "SurfaceDriftError";
|
|
3809
4530
|
this.plan = plan;
|
|
3810
4531
|
}
|
|
3811
4532
|
};
|
|
3812
|
-
function
|
|
4533
|
+
function parseRequestError6(err) {
|
|
3813
4534
|
if (!(err instanceof Error)) return { status: null, body: null };
|
|
3814
4535
|
const match = err.message.match(/^API request failed: (\d{3}) .*? - ([\s\S]*)$/);
|
|
3815
4536
|
if (!match) return { status: null, body: null };
|
|
@@ -3819,47 +4540,47 @@ function parseRequestError3(err) {
|
|
|
3819
4540
|
return { status: Number(match[1]), body: null };
|
|
3820
4541
|
}
|
|
3821
4542
|
}
|
|
3822
|
-
function
|
|
3823
|
-
const { status, body } =
|
|
3824
|
-
if (status !== 409 || !
|
|
4543
|
+
function toConflictError6(err) {
|
|
4544
|
+
const { status, body } = parseRequestError6(err);
|
|
4545
|
+
if (status !== 409 || !isPlainObject6(body)) return null;
|
|
3825
4546
|
const code = body.code;
|
|
3826
4547
|
if (code !== "external_modification" && code !== "remote_changed") return null;
|
|
3827
|
-
return new
|
|
4548
|
+
return new SurfaceEnsureConflictError(
|
|
3828
4549
|
body
|
|
3829
4550
|
);
|
|
3830
4551
|
}
|
|
3831
|
-
var
|
|
3832
|
-
function
|
|
3833
|
-
let memo =
|
|
4552
|
+
var serverHashMemo6 = /* @__PURE__ */ new WeakMap();
|
|
4553
|
+
function memoFor6(client) {
|
|
4554
|
+
let memo = serverHashMemo6.get(client);
|
|
3834
4555
|
if (!memo) {
|
|
3835
4556
|
memo = /* @__PURE__ */ new Map();
|
|
3836
|
-
|
|
4557
|
+
serverHashMemo6.set(client, memo);
|
|
3837
4558
|
}
|
|
3838
4559
|
return memo;
|
|
3839
4560
|
}
|
|
3840
|
-
function
|
|
4561
|
+
function memoize5(memo, memoKey, result) {
|
|
3841
4562
|
if (result.result !== "plan") memo.set(memoKey, result.contentHash);
|
|
3842
4563
|
}
|
|
3843
|
-
async function
|
|
4564
|
+
async function request5(client, productId, body) {
|
|
3844
4565
|
try {
|
|
3845
4566
|
return await client.post(
|
|
3846
|
-
|
|
4567
|
+
`/products/${encodeURIComponent(productId)}/surfaces/ensure`,
|
|
3847
4568
|
body
|
|
3848
4569
|
);
|
|
3849
4570
|
} catch (err) {
|
|
3850
|
-
const conflict =
|
|
4571
|
+
const conflict = toConflictError6(err);
|
|
3851
4572
|
if (conflict) throw conflict;
|
|
3852
4573
|
throw err;
|
|
3853
4574
|
}
|
|
3854
4575
|
}
|
|
3855
|
-
async function
|
|
4576
|
+
async function ensureSurface(client, productId, definition, options = {}) {
|
|
3856
4577
|
const { dryRun, onConflict, expectedRemoteHash, expectNoChanges } = options;
|
|
3857
4578
|
const passthrough = {
|
|
3858
4579
|
...onConflict ? { onConflict } : {},
|
|
3859
4580
|
...expectedRemoteHash ? { expectedRemoteHash } : {}
|
|
3860
4581
|
};
|
|
3861
4582
|
if (dryRun || expectNoChanges) {
|
|
3862
|
-
const plan = await
|
|
4583
|
+
const plan = await request5(client, productId, {
|
|
3863
4584
|
name: definition.name,
|
|
3864
4585
|
definition,
|
|
3865
4586
|
dryRun: true,
|
|
@@ -3869,24 +4590,24 @@ async function ensureTool(client, definition, options = {}) {
|
|
|
3869
4590
|
throw new Error(`Expected a plan result from dryRun, got '${plan.result}'`);
|
|
3870
4591
|
}
|
|
3871
4592
|
if (expectNoChanges && plan.changes !== "none") {
|
|
3872
|
-
throw new
|
|
4593
|
+
throw new SurfaceDriftError(plan);
|
|
3873
4594
|
}
|
|
3874
4595
|
return plan;
|
|
3875
4596
|
}
|
|
3876
|
-
const memo =
|
|
3877
|
-
const localHash = await
|
|
3878
|
-
const memoKey = `${definition.name} ${localHash}`;
|
|
4597
|
+
const memo = memoFor6(client);
|
|
4598
|
+
const localHash = await computeSurfaceContentHash(definition);
|
|
4599
|
+
const memoKey = `${productId} ${definition.name} ${localHash}`;
|
|
3879
4600
|
const contentHash = memo.get(memoKey) ?? localHash;
|
|
3880
|
-
const probe = await
|
|
4601
|
+
const probe = await request5(client, productId, {
|
|
3881
4602
|
name: definition.name,
|
|
3882
4603
|
contentHash,
|
|
3883
4604
|
...passthrough
|
|
3884
4605
|
});
|
|
3885
4606
|
if (probe.result !== "definitionRequired") {
|
|
3886
|
-
|
|
4607
|
+
memoize5(memo, memoKey, probe);
|
|
3887
4608
|
return probe;
|
|
3888
4609
|
}
|
|
3889
|
-
const converged = await
|
|
4610
|
+
const converged = await request5(client, productId, {
|
|
3890
4611
|
name: definition.name,
|
|
3891
4612
|
definition,
|
|
3892
4613
|
...passthrough
|
|
@@ -3894,49 +4615,51 @@ async function ensureTool(client, definition, options = {}) {
|
|
|
3894
4615
|
if (converged.result === "definitionRequired") {
|
|
3895
4616
|
throw new Error("Server reported definitionRequired for a full-definition request");
|
|
3896
4617
|
}
|
|
3897
|
-
|
|
4618
|
+
memoize5(memo, memoKey, converged);
|
|
3898
4619
|
return converged;
|
|
3899
4620
|
}
|
|
3900
|
-
async function
|
|
3901
|
-
return client.get(
|
|
4621
|
+
async function pullSurface(client, productId, name) {
|
|
4622
|
+
return client.get(
|
|
4623
|
+
`/products/${encodeURIComponent(productId)}/surfaces/pull`,
|
|
4624
|
+
{ name }
|
|
4625
|
+
);
|
|
3902
4626
|
}
|
|
3903
4627
|
|
|
3904
|
-
// src/
|
|
3905
|
-
var
|
|
4628
|
+
// src/surfaces-namespace.ts
|
|
4629
|
+
var SurfacesNamespace = class {
|
|
3906
4630
|
constructor(getClient) {
|
|
3907
4631
|
this.getClient = getClient;
|
|
3908
4632
|
}
|
|
3909
4633
|
/**
|
|
3910
|
-
* Idempotently converge a `
|
|
4634
|
+
* Idempotently converge a `defineSurface` definition onto a product.
|
|
3911
4635
|
* Hash-first: the steady state is one tiny probe request. Creates or updates
|
|
3912
|
-
* the
|
|
4636
|
+
* the surface; never deletes. Identity is name + product.
|
|
3913
4637
|
*
|
|
3914
4638
|
* @example
|
|
3915
4639
|
* ```typescript
|
|
3916
|
-
* const
|
|
3917
|
-
* name: '
|
|
3918
|
-
*
|
|
3919
|
-
*
|
|
3920
|
-
*
|
|
3921
|
-
* config: { url: 'https://api.example.com/weather', method: 'GET' },
|
|
4640
|
+
* const chat = defineSurface({
|
|
4641
|
+
* name: 'Support Chat',
|
|
4642
|
+
* type: 'chat',
|
|
4643
|
+
* behavior: { type: 'chat', greeting: 'Hi there!' },
|
|
4644
|
+
* status: 'active',
|
|
3922
4645
|
* })
|
|
3923
4646
|
*
|
|
3924
4647
|
* // Converge (CI/deploy).
|
|
3925
|
-
* const result = await Runtype.
|
|
4648
|
+
* const result = await Runtype.surfaces.ensure('product_abc', chat)
|
|
3926
4649
|
*
|
|
3927
4650
|
* // PR drift gate.
|
|
3928
|
-
* await Runtype.
|
|
4651
|
+
* await Runtype.surfaces.ensure('product_abc', chat, { expectNoChanges: true })
|
|
3929
4652
|
* ```
|
|
3930
4653
|
*/
|
|
3931
|
-
async ensure(definition, options = {}) {
|
|
3932
|
-
return
|
|
4654
|
+
async ensure(productId, definition, options = {}) {
|
|
4655
|
+
return ensureSurface(this.getClient(), productId, definition, options);
|
|
3933
4656
|
}
|
|
3934
4657
|
/**
|
|
3935
|
-
* Pull the canonical definition + provenance for a
|
|
3936
|
-
* absorb-drift direction of the ensure protocol.
|
|
4658
|
+
* Pull the canonical definition + provenance for a surface by name within a
|
|
4659
|
+
* product — the absorb-drift direction of the ensure protocol.
|
|
3937
4660
|
*/
|
|
3938
|
-
async pull(name) {
|
|
3939
|
-
return
|
|
4661
|
+
async pull(productId, name) {
|
|
4662
|
+
return pullSurface(this.getClient(), productId, name);
|
|
3940
4663
|
}
|
|
3941
4664
|
};
|
|
3942
4665
|
|
|
@@ -4356,6 +5079,66 @@ var Runtype = class {
|
|
|
4356
5079
|
static get tools() {
|
|
4357
5080
|
return new ToolsNamespace(() => this.getClient());
|
|
4358
5081
|
}
|
|
5082
|
+
/**
|
|
5083
|
+
* Products namespace - Product config-as-code (define / ensure / pull)
|
|
5084
|
+
*
|
|
5085
|
+
* Converges the top-level product record (description, icon, spec). Nested
|
|
5086
|
+
* capabilities/surfaces/tools and the canvas UI layout state are not
|
|
5087
|
+
* converged by ensure.
|
|
5088
|
+
*
|
|
5089
|
+
* @example
|
|
5090
|
+
* ```typescript
|
|
5091
|
+
* import { defineProduct, Runtype } from '@runtypelabs/sdk'
|
|
5092
|
+
*
|
|
5093
|
+
* const product = defineProduct({
|
|
5094
|
+
* name: 'Support Copilot',
|
|
5095
|
+
* description: 'An AI support assistant',
|
|
5096
|
+
* icon: '🤖',
|
|
5097
|
+
* spec: { productGoal: 'Deflect tier-1 tickets', productStage: 'beta' },
|
|
5098
|
+
* })
|
|
5099
|
+
*
|
|
5100
|
+
* // Converge at deploy time (idempotent; one tiny probe in steady state)
|
|
5101
|
+
* await Runtype.products.ensure(product)
|
|
5102
|
+
*
|
|
5103
|
+
* // CI drift gate
|
|
5104
|
+
* await Runtype.products.ensure(product, { expectNoChanges: true })
|
|
5105
|
+
*
|
|
5106
|
+
* // Absorb a dashboard edit back into the repo
|
|
5107
|
+
* const { definition } = await Runtype.products.pull('Support Copilot')
|
|
5108
|
+
* ```
|
|
5109
|
+
*/
|
|
5110
|
+
static get products() {
|
|
5111
|
+
return new ProductsNamespace(() => this.getClient());
|
|
5112
|
+
}
|
|
5113
|
+
/**
|
|
5114
|
+
* Config-as-code operations for product surfaces. `surfaces.ensure` is the
|
|
5115
|
+
* deploy-time, non-executing converge (create-or-update a surface by name
|
|
5116
|
+
* within a product); `surfaces.pull` is the absorb-drift direction.
|
|
5117
|
+
*
|
|
5118
|
+
* @example
|
|
5119
|
+
* ```typescript
|
|
5120
|
+
* import { Runtype, defineSurface } from '@runtypelabs/sdk'
|
|
5121
|
+
*
|
|
5122
|
+
* const chat = defineSurface({
|
|
5123
|
+
* name: 'Support Chat',
|
|
5124
|
+
* type: 'chat',
|
|
5125
|
+
* behavior: { type: 'chat', greeting: 'Hi there!' },
|
|
5126
|
+
* status: 'active',
|
|
5127
|
+
* })
|
|
5128
|
+
*
|
|
5129
|
+
* // Converge at deploy time (idempotent; one tiny probe in steady state)
|
|
5130
|
+
* await Runtype.surfaces.ensure('product_abc', chat)
|
|
5131
|
+
*
|
|
5132
|
+
* // CI drift gate
|
|
5133
|
+
* await Runtype.surfaces.ensure('product_abc', chat, { expectNoChanges: true })
|
|
5134
|
+
*
|
|
5135
|
+
* // Absorb a dashboard edit back into the repo
|
|
5136
|
+
* const { definition } = await Runtype.surfaces.pull('product_abc', 'Support Chat')
|
|
5137
|
+
* ```
|
|
5138
|
+
*/
|
|
5139
|
+
static get surfaces() {
|
|
5140
|
+
return new SurfacesNamespace(() => this.getClient());
|
|
5141
|
+
}
|
|
4359
5142
|
};
|
|
4360
5143
|
|
|
4361
5144
|
// src/generated-tool-gate.ts
|
|
@@ -4578,8 +5361,8 @@ function buildGeneratedRuntimeToolGateOutput(proposal, options = {}) {
|
|
|
4578
5361
|
...decision.tool ? { tool: decision.tool } : {}
|
|
4579
5362
|
};
|
|
4580
5363
|
}
|
|
4581
|
-
function attachRuntimeToolsToDispatchRequest(
|
|
4582
|
-
const stepList =
|
|
5364
|
+
function attachRuntimeToolsToDispatchRequest(request6, runtimeTools, options = {}) {
|
|
5365
|
+
const stepList = request6.flow.steps;
|
|
4583
5366
|
if (!stepList || !Array.isArray(stepList) || stepList.length === 0) {
|
|
4584
5367
|
throw new Error("Cannot attach runtime tools: dispatch request must include flow.steps");
|
|
4585
5368
|
}
|
|
@@ -4622,9 +5405,9 @@ function attachRuntimeToolsToDispatchRequest(request3, runtimeTools, options = {
|
|
|
4622
5405
|
}
|
|
4623
5406
|
};
|
|
4624
5407
|
return {
|
|
4625
|
-
...
|
|
5408
|
+
...request6,
|
|
4626
5409
|
flow: {
|
|
4627
|
-
...
|
|
5410
|
+
...request6.flow,
|
|
4628
5411
|
// `clonedSteps` is a structural clone of `request.flow.steps` (already
|
|
4629
5412
|
// `FlowStepDefinition[]`); only the prompt step's `config.tools` was
|
|
4630
5413
|
// merged, so every step's `type` discriminant is preserved. The clone is
|
|
@@ -4634,12 +5417,12 @@ function attachRuntimeToolsToDispatchRequest(request3, runtimeTools, options = {
|
|
|
4634
5417
|
}
|
|
4635
5418
|
};
|
|
4636
5419
|
}
|
|
4637
|
-
function applyGeneratedRuntimeToolProposalToDispatchRequest(
|
|
5420
|
+
function applyGeneratedRuntimeToolProposalToDispatchRequest(request6, proposal, options = {}) {
|
|
4638
5421
|
const decision = evaluateGeneratedRuntimeToolProposal(proposal, options.gate);
|
|
4639
5422
|
if (!decision.approved || !decision.tool) {
|
|
4640
|
-
return { decision, request:
|
|
5423
|
+
return { decision, request: request6 };
|
|
4641
5424
|
}
|
|
4642
|
-
const nextRequest = attachRuntimeToolsToDispatchRequest(
|
|
5425
|
+
const nextRequest = attachRuntimeToolsToDispatchRequest(request6, [decision.tool], options.attach);
|
|
4643
5426
|
return {
|
|
4644
5427
|
decision,
|
|
4645
5428
|
request: nextRequest
|
|
@@ -6889,15 +7672,15 @@ var DispatchEndpoint = class {
|
|
|
6889
7672
|
* Attach approved runtime tools to a prompt step in a redispatch request.
|
|
6890
7673
|
* Returns a new request object and does not mutate the original.
|
|
6891
7674
|
*/
|
|
6892
|
-
attachApprovedRuntimeTools(
|
|
6893
|
-
return attachRuntimeToolsToDispatchRequest(
|
|
7675
|
+
attachApprovedRuntimeTools(request6, runtimeTools, options) {
|
|
7676
|
+
return attachRuntimeToolsToDispatchRequest(request6, runtimeTools, options);
|
|
6894
7677
|
}
|
|
6895
7678
|
/**
|
|
6896
7679
|
* Validate a generated runtime tool proposal and attach it to the redispatch
|
|
6897
7680
|
* request if approved, in one call.
|
|
6898
7681
|
*/
|
|
6899
|
-
applyGeneratedRuntimeToolProposal(
|
|
6900
|
-
return applyGeneratedRuntimeToolProposalToDispatchRequest(
|
|
7682
|
+
applyGeneratedRuntimeToolProposal(request6, proposal, options) {
|
|
7683
|
+
return applyGeneratedRuntimeToolProposalToDispatchRequest(request6, proposal, options);
|
|
6901
7684
|
}
|
|
6902
7685
|
};
|
|
6903
7686
|
var ChatEndpoint = class {
|
|
@@ -7449,8 +8232,8 @@ var GENERATED_RUNTIME_TOOL_PROPOSAL_SCHEMA = {
|
|
|
7449
8232
|
},
|
|
7450
8233
|
required: ["name", "description", "toolType", "parametersSchema", "config"]
|
|
7451
8234
|
};
|
|
7452
|
-
function appendRuntimeToolsToAgentRequest(
|
|
7453
|
-
const existing =
|
|
8235
|
+
function appendRuntimeToolsToAgentRequest(request6, runtimeTools) {
|
|
8236
|
+
const existing = request6.tools?.runtimeTools || [];
|
|
7454
8237
|
const existingNames = new Set(existing.map((tool) => tool.name));
|
|
7455
8238
|
const converted = runtimeTools.filter((tool) => !existingNames.has(tool.name)).map((tool) => ({
|
|
7456
8239
|
name: tool.name,
|
|
@@ -7460,9 +8243,9 @@ function appendRuntimeToolsToAgentRequest(request3, runtimeTools) {
|
|
|
7460
8243
|
...tool.config ? { config: tool.config } : {}
|
|
7461
8244
|
}));
|
|
7462
8245
|
return {
|
|
7463
|
-
...
|
|
8246
|
+
...request6,
|
|
7464
8247
|
tools: {
|
|
7465
|
-
...
|
|
8248
|
+
...request6.tools,
|
|
7466
8249
|
runtimeTools: [...existing, ...converted]
|
|
7467
8250
|
}
|
|
7468
8251
|
};
|
|
@@ -7538,21 +8321,21 @@ var _AgentsEndpoint = class _AgentsEndpoint {
|
|
|
7538
8321
|
* Attach approved runtime tools to an agent execute request.
|
|
7539
8322
|
* Returns a new request object and does not mutate the original.
|
|
7540
8323
|
*/
|
|
7541
|
-
attachApprovedRuntimeTools(
|
|
7542
|
-
return appendRuntimeToolsToAgentRequest(
|
|
8324
|
+
attachApprovedRuntimeTools(request6, runtimeTools) {
|
|
8325
|
+
return appendRuntimeToolsToAgentRequest(request6, runtimeTools);
|
|
7543
8326
|
}
|
|
7544
8327
|
/**
|
|
7545
8328
|
* Validate a generated runtime tool proposal and append it to an agent execute
|
|
7546
8329
|
* request if approved, in one call.
|
|
7547
8330
|
*/
|
|
7548
|
-
applyGeneratedRuntimeToolProposal(
|
|
8331
|
+
applyGeneratedRuntimeToolProposal(request6, proposal, options) {
|
|
7549
8332
|
const decision = evaluateGeneratedRuntimeToolProposal(proposal, options);
|
|
7550
8333
|
if (!decision.approved || !decision.tool) {
|
|
7551
|
-
return { decision, request:
|
|
8334
|
+
return { decision, request: request6 };
|
|
7552
8335
|
}
|
|
7553
8336
|
return {
|
|
7554
8337
|
decision,
|
|
7555
|
-
request: appendRuntimeToolsToAgentRequest(
|
|
8338
|
+
request: appendRuntimeToolsToAgentRequest(request6, [decision.tool])
|
|
7556
8339
|
};
|
|
7557
8340
|
}
|
|
7558
8341
|
/**
|
|
@@ -10653,6 +11436,29 @@ var BillingEndpoint = class {
|
|
|
10653
11436
|
return this.client.get("/billing/spend-analytics", params);
|
|
10654
11437
|
}
|
|
10655
11438
|
};
|
|
11439
|
+
var ToolApprovalGrantsEndpoint = class {
|
|
11440
|
+
constructor(client) {
|
|
11441
|
+
this.client = client;
|
|
11442
|
+
}
|
|
11443
|
+
/**
|
|
11444
|
+
* List active remembered tool-approval grants for the authenticated owner,
|
|
11445
|
+
* optionally filtered to a single agent.
|
|
11446
|
+
*/
|
|
11447
|
+
async list(agentId) {
|
|
11448
|
+
const query = agentId ? `?agentId=${encodeURIComponent(agentId)}` : "";
|
|
11449
|
+
const response = await this.client.get(
|
|
11450
|
+
`/tool-approval-grants${query}`
|
|
11451
|
+
);
|
|
11452
|
+
return response.data;
|
|
11453
|
+
}
|
|
11454
|
+
/**
|
|
11455
|
+
* Revoke (soft-delete) a remembered grant so the tool prompts for approval
|
|
11456
|
+
* again on future dispatches.
|
|
11457
|
+
*/
|
|
11458
|
+
async revoke(id) {
|
|
11459
|
+
return this.client.delete(`/tool-approval-grants/${id}`);
|
|
11460
|
+
}
|
|
11461
|
+
};
|
|
10656
11462
|
var AppsEndpoint = class {
|
|
10657
11463
|
constructor(client) {
|
|
10658
11464
|
this.client = client;
|
|
@@ -10750,6 +11556,7 @@ var RuntypeClient2 = class {
|
|
|
10750
11556
|
this.flowVersions = new FlowVersionsEndpoint(this);
|
|
10751
11557
|
this.integrations = new IntegrationsEndpoint(this);
|
|
10752
11558
|
this.billing = new BillingEndpoint(this);
|
|
11559
|
+
this.toolApprovalGrants = new ToolApprovalGrantsEndpoint(this);
|
|
10753
11560
|
}
|
|
10754
11561
|
/**
|
|
10755
11562
|
* Set the API key for authentication
|
|
@@ -10788,7 +11595,7 @@ var RuntypeClient2 = class {
|
|
|
10788
11595
|
clearApiKey() {
|
|
10789
11596
|
delete this.headers.Authorization;
|
|
10790
11597
|
}
|
|
10791
|
-
async runWithLocalTools(
|
|
11598
|
+
async runWithLocalTools(request6, localTools, arg3, arg4) {
|
|
10792
11599
|
const isOptionsObject = (val) => typeof val === "object" && val !== null && "scope" in val;
|
|
10793
11600
|
const callbacks = isOptionsObject(arg3) ? void 0 : arg3;
|
|
10794
11601
|
const options = (isOptionsObject(arg3) ? arg3 : arg4) ?? {};
|
|
@@ -10802,12 +11609,12 @@ var RuntypeClient2 = class {
|
|
|
10802
11609
|
...entry.pageOrigin ? { pageOrigin: entry.pageOrigin } : {}
|
|
10803
11610
|
})) : [];
|
|
10804
11611
|
const modifiedRequest = {
|
|
10805
|
-
...
|
|
11612
|
+
...request6,
|
|
10806
11613
|
...derivedClientTools.length > 0 ? {
|
|
10807
|
-
clientTools: [...
|
|
11614
|
+
clientTools: [...request6.clientTools ?? [], ...derivedClientTools]
|
|
10808
11615
|
} : {},
|
|
10809
11616
|
options: {
|
|
10810
|
-
...
|
|
11617
|
+
...request6.options || {},
|
|
10811
11618
|
streamResponse: isStreaming
|
|
10812
11619
|
}
|
|
10813
11620
|
};
|
|
@@ -11245,20 +12052,20 @@ var BatchBuilder = class {
|
|
|
11245
12052
|
if (!this.recordType) {
|
|
11246
12053
|
throw new Error("BatchBuilder: recordType is required. Call .forRecordType(type) first.");
|
|
11247
12054
|
}
|
|
11248
|
-
const
|
|
12055
|
+
const request6 = {
|
|
11249
12056
|
flowId: this.flowId,
|
|
11250
12057
|
recordType: this.recordType
|
|
11251
12058
|
};
|
|
11252
12059
|
if (Object.keys(this.batchOptions).length > 0) {
|
|
11253
|
-
|
|
12060
|
+
request6.options = this.batchOptions;
|
|
11254
12061
|
}
|
|
11255
12062
|
if (this.filterConfig) {
|
|
11256
|
-
|
|
12063
|
+
request6.filter = this.filterConfig;
|
|
11257
12064
|
}
|
|
11258
12065
|
if (this.limitConfig !== void 0) {
|
|
11259
|
-
|
|
12066
|
+
request6.limit = this.limitConfig;
|
|
11260
12067
|
}
|
|
11261
|
-
return
|
|
12068
|
+
return request6;
|
|
11262
12069
|
}
|
|
11263
12070
|
/**
|
|
11264
12071
|
* Execute the batch operation
|
|
@@ -11415,32 +12222,32 @@ var EvalBuilder = class {
|
|
|
11415
12222
|
"EvalBuilder: records are required. Call .forRecordType(type) or .withRecords([...]) first."
|
|
11416
12223
|
);
|
|
11417
12224
|
}
|
|
11418
|
-
const
|
|
12225
|
+
const request6 = {};
|
|
11419
12226
|
if (this.flowId) {
|
|
11420
|
-
|
|
12227
|
+
request6.flowId = this.flowId;
|
|
11421
12228
|
} else if (this.virtualFlow) {
|
|
11422
|
-
|
|
12229
|
+
request6.flow = this.virtualFlow;
|
|
11423
12230
|
}
|
|
11424
12231
|
if (this.recordType) {
|
|
11425
|
-
|
|
12232
|
+
request6.recordType = this.recordType;
|
|
11426
12233
|
} else if (this.inlineRecords) {
|
|
11427
|
-
|
|
12234
|
+
request6.records = this.inlineRecords;
|
|
11428
12235
|
}
|
|
11429
12236
|
if (this.modelOverrides) {
|
|
11430
|
-
|
|
12237
|
+
request6.modelOverrides = this.modelOverrides;
|
|
11431
12238
|
} else if (this.modelConfigs) {
|
|
11432
|
-
|
|
12239
|
+
request6.modelConfigs = this.modelConfigs;
|
|
11433
12240
|
}
|
|
11434
12241
|
if (Object.keys(this.evalOptions).length > 0) {
|
|
11435
|
-
|
|
12242
|
+
request6.options = this.evalOptions;
|
|
11436
12243
|
}
|
|
11437
12244
|
if (this.filterConfig) {
|
|
11438
|
-
|
|
12245
|
+
request6.filter = this.filterConfig;
|
|
11439
12246
|
}
|
|
11440
12247
|
if (this.limitConfig !== void 0) {
|
|
11441
|
-
|
|
12248
|
+
request6.limit = this.limitConfig;
|
|
11442
12249
|
}
|
|
11443
|
-
return
|
|
12250
|
+
return request6;
|
|
11444
12251
|
}
|
|
11445
12252
|
/**
|
|
11446
12253
|
* Execute the evaluation
|
|
@@ -11944,6 +12751,9 @@ var STEP_TYPE_TO_METHOD = {
|
|
|
11944
12751
|
LEDGER_ARTIFACT_LINE_PREFIX,
|
|
11945
12752
|
LogsEndpoint,
|
|
11946
12753
|
ModelConfigsEndpoint,
|
|
12754
|
+
ProductDriftError,
|
|
12755
|
+
ProductEnsureConflictError,
|
|
12756
|
+
ProductsNamespace,
|
|
11947
12757
|
PromptRunner,
|
|
11948
12758
|
PromptsEndpoint,
|
|
11949
12759
|
PromptsNamespace,
|
|
@@ -11957,9 +12767,15 @@ var STEP_TYPE_TO_METHOD = {
|
|
|
11957
12767
|
STEP_TYPE_TO_METHOD,
|
|
11958
12768
|
SchedulesEndpoint,
|
|
11959
12769
|
SecretsEndpoint,
|
|
12770
|
+
SkillDriftError,
|
|
12771
|
+
SkillEnsureConflictError,
|
|
11960
12772
|
SkillProposalsNamespace,
|
|
11961
12773
|
SkillsNamespace,
|
|
12774
|
+
SurfaceDriftError,
|
|
12775
|
+
SurfaceEnsureConflictError,
|
|
11962
12776
|
SurfacesEndpoint,
|
|
12777
|
+
SurfacesNamespace,
|
|
12778
|
+
ToolApprovalGrantsEndpoint,
|
|
11963
12779
|
ToolDriftError,
|
|
11964
12780
|
ToolEnsureConflictError,
|
|
11965
12781
|
ToolsEndpoint,
|
|
@@ -11975,6 +12791,9 @@ var STEP_TYPE_TO_METHOD = {
|
|
|
11975
12791
|
compileWorkflowConfig,
|
|
11976
12792
|
computeAgentContentHash,
|
|
11977
12793
|
computeFlowContentHash,
|
|
12794
|
+
computeProductContentHash,
|
|
12795
|
+
computeSkillContentHash,
|
|
12796
|
+
computeSurfaceContentHash,
|
|
11978
12797
|
computeToolContentHash,
|
|
11979
12798
|
createClient,
|
|
11980
12799
|
createExternalTool,
|
|
@@ -11983,6 +12802,9 @@ var STEP_TYPE_TO_METHOD = {
|
|
|
11983
12802
|
defineAgent,
|
|
11984
12803
|
defineFlow,
|
|
11985
12804
|
definePlaybook,
|
|
12805
|
+
defineProduct,
|
|
12806
|
+
defineSkill,
|
|
12807
|
+
defineSurface,
|
|
11986
12808
|
defineTool,
|
|
11987
12809
|
deployWorkflow,
|
|
11988
12810
|
ensureDefaultWorkflowHooks,
|
|
@@ -11999,6 +12821,9 @@ var STEP_TYPE_TO_METHOD = {
|
|
|
11999
12821
|
listWorkflowHooks,
|
|
12000
12822
|
normalizeAgentDefinition,
|
|
12001
12823
|
normalizeCandidatePath,
|
|
12824
|
+
normalizeProductDefinition,
|
|
12825
|
+
normalizeSkillDefinition,
|
|
12826
|
+
normalizeSurfaceDefinition,
|
|
12002
12827
|
normalizeToolDefinition,
|
|
12003
12828
|
parseFinalBuffer,
|
|
12004
12829
|
parseLedgerArtifactRelativePath,
|