@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.mjs
CHANGED
|
@@ -1094,20 +1094,20 @@ var FlowBuilder = class {
|
|
|
1094
1094
|
*/
|
|
1095
1095
|
build() {
|
|
1096
1096
|
const flow = this.existingFlowId ? { id: this.existingFlowId } : { name: this.flowConfig.name, steps: this.steps };
|
|
1097
|
-
const
|
|
1097
|
+
const request6 = { flow };
|
|
1098
1098
|
if (this.recordConfig) {
|
|
1099
|
-
|
|
1099
|
+
request6.record = this.recordConfig;
|
|
1100
1100
|
}
|
|
1101
1101
|
if (this.messagesConfig) {
|
|
1102
|
-
|
|
1102
|
+
request6.messages = this.messagesConfig;
|
|
1103
1103
|
}
|
|
1104
1104
|
if (this.inputsConfig) {
|
|
1105
|
-
|
|
1105
|
+
request6.inputs = this.inputsConfig;
|
|
1106
1106
|
}
|
|
1107
1107
|
if (Object.keys(this.optionsConfig).length > 0) {
|
|
1108
|
-
|
|
1108
|
+
request6.options = this.optionsConfig;
|
|
1109
1109
|
}
|
|
1110
|
-
return
|
|
1110
|
+
return request6;
|
|
1111
1111
|
}
|
|
1112
1112
|
/**
|
|
1113
1113
|
* Validate this prospective flow against the public validation endpoint
|
|
@@ -2501,15 +2501,15 @@ var RuntypeFlowBuilder = class {
|
|
|
2501
2501
|
build() {
|
|
2502
2502
|
const flowMode = this.mode === "existing" ? "existing" : this.mode;
|
|
2503
2503
|
const flow = this.existingFlowId ? { id: this.existingFlowId } : { name: this.flowConfig.name, steps: this.steps };
|
|
2504
|
-
const
|
|
2504
|
+
const request6 = { flow };
|
|
2505
2505
|
if (this.recordConfig) {
|
|
2506
|
-
|
|
2506
|
+
request6.record = this.recordConfig;
|
|
2507
2507
|
}
|
|
2508
2508
|
if (this.messagesConfig) {
|
|
2509
|
-
|
|
2509
|
+
request6.messages = this.messagesConfig;
|
|
2510
2510
|
}
|
|
2511
2511
|
if (this.inputsConfig) {
|
|
2512
|
-
|
|
2512
|
+
request6.inputs = this.inputsConfig;
|
|
2513
2513
|
}
|
|
2514
2514
|
const options = {
|
|
2515
2515
|
flowMode,
|
|
@@ -2527,8 +2527,8 @@ var RuntypeFlowBuilder = class {
|
|
|
2527
2527
|
if (this.mode === "upsert" && Object.keys(this.upsertOptions).length > 0) {
|
|
2528
2528
|
options.upsertOptions = this.upsertOptions;
|
|
2529
2529
|
}
|
|
2530
|
-
|
|
2531
|
-
return
|
|
2530
|
+
request6.options = options;
|
|
2531
|
+
return request6;
|
|
2532
2532
|
}
|
|
2533
2533
|
/**
|
|
2534
2534
|
* Validate this prospective flow against the public validation endpoint
|
|
@@ -3122,6 +3122,192 @@ var PromptsNamespace = class {
|
|
|
3122
3122
|
}
|
|
3123
3123
|
};
|
|
3124
3124
|
|
|
3125
|
+
// src/skills-ensure.ts
|
|
3126
|
+
function isPlainObject2(value) {
|
|
3127
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3128
|
+
}
|
|
3129
|
+
function normalizeValue(value) {
|
|
3130
|
+
if (Array.isArray(value)) {
|
|
3131
|
+
return value.map((item) => normalizeValue(item));
|
|
3132
|
+
}
|
|
3133
|
+
if (isPlainObject2(value)) {
|
|
3134
|
+
const normalized = {};
|
|
3135
|
+
for (const key of Object.keys(value).sort()) {
|
|
3136
|
+
const entry = value[key];
|
|
3137
|
+
if (entry === void 0 || entry === null) continue;
|
|
3138
|
+
normalized[key] = normalizeValue(entry);
|
|
3139
|
+
}
|
|
3140
|
+
return normalized;
|
|
3141
|
+
}
|
|
3142
|
+
return value;
|
|
3143
|
+
}
|
|
3144
|
+
function normalizeSkillDefinition(definition) {
|
|
3145
|
+
const manifest = isPlainObject2(definition.manifest) ? definition.manifest : {};
|
|
3146
|
+
const rawFrontmatter = isPlainObject2(manifest.frontmatter) ? manifest.frontmatter : {};
|
|
3147
|
+
const frontmatterWithoutName = {};
|
|
3148
|
+
for (const key of Object.keys(rawFrontmatter)) {
|
|
3149
|
+
if (key === "name") continue;
|
|
3150
|
+
frontmatterWithoutName[key] = rawFrontmatter[key];
|
|
3151
|
+
}
|
|
3152
|
+
const frontmatter = normalizeValue(frontmatterWithoutName);
|
|
3153
|
+
const runtype = isPlainObject2(manifest.runtype) ? normalizeValue(manifest.runtype) : {};
|
|
3154
|
+
const body = typeof manifest.body === "string" ? manifest.body : "";
|
|
3155
|
+
return { frontmatter, runtype, body };
|
|
3156
|
+
}
|
|
3157
|
+
async function computeSkillContentHash(definition) {
|
|
3158
|
+
const serialized = JSON.stringify(normalizeSkillDefinition(definition));
|
|
3159
|
+
const encoded = new TextEncoder().encode(serialized);
|
|
3160
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
|
|
3161
|
+
return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
3162
|
+
}
|
|
3163
|
+
var DEFINE_SKILL_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set(["name", "manifest"]);
|
|
3164
|
+
function defineSkill(input) {
|
|
3165
|
+
if (!input || typeof input !== "object") {
|
|
3166
|
+
throw new Error("defineSkill requires a definition object");
|
|
3167
|
+
}
|
|
3168
|
+
if (typeof input.name !== "string" || input.name.length === 0) {
|
|
3169
|
+
throw new Error('defineSkill requires a non-empty string "name"');
|
|
3170
|
+
}
|
|
3171
|
+
if (!isPlainObject2(input.manifest)) {
|
|
3172
|
+
throw new Error('defineSkill requires a "manifest" object ({ frontmatter, runtype, body })');
|
|
3173
|
+
}
|
|
3174
|
+
const unknownKeys = Object.keys(input).filter((key) => !DEFINE_SKILL_TOP_LEVEL_KEYS.has(key));
|
|
3175
|
+
if (unknownKeys.length > 0) {
|
|
3176
|
+
throw new Error(
|
|
3177
|
+
`defineSkill: unknown field(s): ${unknownKeys.join(", ")}. Allowed fields are name and manifest.`
|
|
3178
|
+
);
|
|
3179
|
+
}
|
|
3180
|
+
const frontmatter = input.manifest.frontmatter;
|
|
3181
|
+
if (!isPlainObject2(frontmatter) || typeof frontmatter.name !== "string") {
|
|
3182
|
+
throw new Error("defineSkill: manifest.frontmatter.name is required");
|
|
3183
|
+
}
|
|
3184
|
+
if (frontmatter.name !== input.name) {
|
|
3185
|
+
throw new Error(
|
|
3186
|
+
`defineSkill: manifest.frontmatter.name ("${frontmatter.name}") must match the identity name ("${input.name}").`
|
|
3187
|
+
);
|
|
3188
|
+
}
|
|
3189
|
+
return { name: input.name, manifest: input.manifest };
|
|
3190
|
+
}
|
|
3191
|
+
var SkillEnsureConflictError = class extends Error {
|
|
3192
|
+
constructor(body) {
|
|
3193
|
+
super(body.error ?? `Skill ensure conflict: ${body.code}`);
|
|
3194
|
+
this.name = "SkillEnsureConflictError";
|
|
3195
|
+
this.code = body.code;
|
|
3196
|
+
this.lastModifiedSource = body.lastModifiedSource;
|
|
3197
|
+
this.modifiedAt = body.modifiedAt;
|
|
3198
|
+
this.currentHash = body.currentHash;
|
|
3199
|
+
}
|
|
3200
|
+
};
|
|
3201
|
+
var SkillDriftError = class extends Error {
|
|
3202
|
+
constructor(plan) {
|
|
3203
|
+
super(
|
|
3204
|
+
`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.`
|
|
3205
|
+
);
|
|
3206
|
+
this.name = "SkillDriftError";
|
|
3207
|
+
this.plan = plan;
|
|
3208
|
+
}
|
|
3209
|
+
};
|
|
3210
|
+
function parseRequestError2(err) {
|
|
3211
|
+
if (!(err instanceof Error)) return { status: null, body: null };
|
|
3212
|
+
const match = err.message.match(/^API request failed: (\d{3}) .*? - ([\s\S]*)$/);
|
|
3213
|
+
if (!match) return { status: null, body: null };
|
|
3214
|
+
try {
|
|
3215
|
+
return { status: Number(match[1]), body: JSON.parse(match[2]) };
|
|
3216
|
+
} catch {
|
|
3217
|
+
return { status: Number(match[1]), body: null };
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
function toConflictError2(err) {
|
|
3221
|
+
const { status, body } = parseRequestError2(err);
|
|
3222
|
+
if (status !== 409 || !isPlainObject2(body)) return null;
|
|
3223
|
+
const code = body.code;
|
|
3224
|
+
if (code !== "external_modification" && code !== "remote_changed") return null;
|
|
3225
|
+
return new SkillEnsureConflictError(
|
|
3226
|
+
body
|
|
3227
|
+
);
|
|
3228
|
+
}
|
|
3229
|
+
var serverHashMemo2 = /* @__PURE__ */ new WeakMap();
|
|
3230
|
+
function memoFor2(client) {
|
|
3231
|
+
let memo = serverHashMemo2.get(client);
|
|
3232
|
+
if (!memo) {
|
|
3233
|
+
memo = /* @__PURE__ */ new Map();
|
|
3234
|
+
serverHashMemo2.set(client, memo);
|
|
3235
|
+
}
|
|
3236
|
+
return memo;
|
|
3237
|
+
}
|
|
3238
|
+
function memoize2(memo, memoKey, result) {
|
|
3239
|
+
if (result.result !== "plan") memo.set(memoKey, result.contentHash);
|
|
3240
|
+
}
|
|
3241
|
+
async function request2(client, body) {
|
|
3242
|
+
try {
|
|
3243
|
+
return await client.post(
|
|
3244
|
+
"/skills/ensure",
|
|
3245
|
+
body
|
|
3246
|
+
);
|
|
3247
|
+
} catch (err) {
|
|
3248
|
+
const conflict = toConflictError2(err);
|
|
3249
|
+
if (conflict) throw conflict;
|
|
3250
|
+
throw err;
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
async function ensureSkill(client, definition, options = {}) {
|
|
3254
|
+
const { dryRun, onConflict, release, expectedRemoteHash, expectNoChanges } = options;
|
|
3255
|
+
const passthrough = {
|
|
3256
|
+
...onConflict ? { onConflict } : {},
|
|
3257
|
+
...release ? { release } : {},
|
|
3258
|
+
...expectedRemoteHash ? { expectedRemoteHash } : {}
|
|
3259
|
+
};
|
|
3260
|
+
if (dryRun || expectNoChanges) {
|
|
3261
|
+
const plan = await request2(client, {
|
|
3262
|
+
name: definition.name,
|
|
3263
|
+
definition: manifestToWire(definition),
|
|
3264
|
+
dryRun: true,
|
|
3265
|
+
...passthrough
|
|
3266
|
+
});
|
|
3267
|
+
if (plan.result !== "plan") {
|
|
3268
|
+
throw new Error(`Expected a plan result from dryRun, got '${plan.result}'`);
|
|
3269
|
+
}
|
|
3270
|
+
if (expectNoChanges && plan.changes !== "none") {
|
|
3271
|
+
throw new SkillDriftError(plan);
|
|
3272
|
+
}
|
|
3273
|
+
return plan;
|
|
3274
|
+
}
|
|
3275
|
+
const memo = memoFor2(client);
|
|
3276
|
+
const localHash = await computeSkillContentHash(definition);
|
|
3277
|
+
const memoKey = `${definition.name} ${localHash}`;
|
|
3278
|
+
const contentHash = memo.get(memoKey) ?? localHash;
|
|
3279
|
+
const probe = await request2(client, {
|
|
3280
|
+
name: definition.name,
|
|
3281
|
+
contentHash,
|
|
3282
|
+
...passthrough
|
|
3283
|
+
});
|
|
3284
|
+
if (probe.result !== "definitionRequired") {
|
|
3285
|
+
memoize2(memo, memoKey, probe);
|
|
3286
|
+
return probe;
|
|
3287
|
+
}
|
|
3288
|
+
const converged = await request2(client, {
|
|
3289
|
+
name: definition.name,
|
|
3290
|
+
definition: manifestToWire(definition),
|
|
3291
|
+
...passthrough
|
|
3292
|
+
});
|
|
3293
|
+
if (converged.result === "definitionRequired") {
|
|
3294
|
+
throw new Error("Server reported definitionRequired for a full-definition request");
|
|
3295
|
+
}
|
|
3296
|
+
memoize2(memo, memoKey, converged);
|
|
3297
|
+
return converged;
|
|
3298
|
+
}
|
|
3299
|
+
function manifestToWire(definition) {
|
|
3300
|
+
const manifest = definition.manifest;
|
|
3301
|
+
const frontmatter = { ...manifest.frontmatter };
|
|
3302
|
+
if (manifest.runtype && Object.keys(manifest.runtype).length > 0) {
|
|
3303
|
+
frontmatter.runtype = manifest.runtype;
|
|
3304
|
+
}
|
|
3305
|
+
return { frontmatter, body: manifest.body ?? "" };
|
|
3306
|
+
}
|
|
3307
|
+
async function pullSkill(client, name) {
|
|
3308
|
+
return client.get("/skills/pull", { name });
|
|
3309
|
+
}
|
|
3310
|
+
|
|
3125
3311
|
// src/skills-namespace.ts
|
|
3126
3312
|
var SkillProposalsNamespace = class {
|
|
3127
3313
|
constructor(getClient) {
|
|
@@ -3262,6 +3448,22 @@ var SkillsNamespace = class {
|
|
|
3262
3448
|
const client = this.getClient();
|
|
3263
3449
|
await client.post(`/skills/${skillId}/versions/${versionId}/publish`);
|
|
3264
3450
|
}
|
|
3451
|
+
/**
|
|
3452
|
+
* Statically scan a SKILL.md document for malicious patterns and return a
|
|
3453
|
+
* two-tier verdict — `warning` when a skill appears suspicious (low–medium
|
|
3454
|
+
* confidence), `error` when high-confidence malicious. Does not persist or
|
|
3455
|
+
* gate; use it as a "scan before save" affordance.
|
|
3456
|
+
*
|
|
3457
|
+
* @example
|
|
3458
|
+
* ```typescript
|
|
3459
|
+
* const { verdict } = await Runtype.skills.scan(skillMarkdown)
|
|
3460
|
+
* if (verdict.tier === 'error') console.warn(verdict.summary)
|
|
3461
|
+
* ```
|
|
3462
|
+
*/
|
|
3463
|
+
async scan(markdown) {
|
|
3464
|
+
const client = this.getClient();
|
|
3465
|
+
return client.post("/skills/scan", { markdown });
|
|
3466
|
+
}
|
|
3265
3467
|
/**
|
|
3266
3468
|
* Import a single SKILL.md document. The imported skill lands with
|
|
3267
3469
|
* `trustLevel: 'imported'` and a draft version.
|
|
@@ -3304,6 +3506,40 @@ var SkillsNamespace = class {
|
|
|
3304
3506
|
const res = await client.get("/skills/bindings", { agentId });
|
|
3305
3507
|
return res.data;
|
|
3306
3508
|
}
|
|
3509
|
+
/**
|
|
3510
|
+
* Idempotently converge a `defineSkill` definition onto the platform.
|
|
3511
|
+
* Hash-first: the steady state is one tiny probe request. Creates or appends a
|
|
3512
|
+
* new version; never deletes. Identity is name + account scope. Pass
|
|
3513
|
+
* `release: 'publish'` to publish the converged version.
|
|
3514
|
+
*
|
|
3515
|
+
* @example
|
|
3516
|
+
* ```typescript
|
|
3517
|
+
* const reviewer = defineSkill({
|
|
3518
|
+
* name: 'code_reviewer',
|
|
3519
|
+
* manifest: {
|
|
3520
|
+
* frontmatter: { name: 'code_reviewer', description: 'Reviews pull requests' },
|
|
3521
|
+
* runtype: { trustLevel: 'org' },
|
|
3522
|
+
* body: '# Code Reviewer\n\nReview the diff...',
|
|
3523
|
+
* },
|
|
3524
|
+
* })
|
|
3525
|
+
*
|
|
3526
|
+
* // Converge + publish (CI/deploy).
|
|
3527
|
+
* const result = await Runtype.skills.ensure(reviewer, { release: 'publish' })
|
|
3528
|
+
*
|
|
3529
|
+
* // PR drift gate.
|
|
3530
|
+
* await Runtype.skills.ensure(reviewer, { expectNoChanges: true })
|
|
3531
|
+
* ```
|
|
3532
|
+
*/
|
|
3533
|
+
async ensure(definition, options = {}) {
|
|
3534
|
+
return ensureSkill(this.getClient(), definition, options);
|
|
3535
|
+
}
|
|
3536
|
+
/**
|
|
3537
|
+
* Pull the canonical definition + provenance for a skill by name — the
|
|
3538
|
+
* absorb-drift direction of the ensure protocol.
|
|
3539
|
+
*/
|
|
3540
|
+
async pull(name) {
|
|
3541
|
+
return pullSkill(this.getClient(), name);
|
|
3542
|
+
}
|
|
3307
3543
|
};
|
|
3308
3544
|
|
|
3309
3545
|
// src/agents-namespace.ts
|
|
@@ -3329,19 +3565,19 @@ var AGENT_CONFIG_KEYS = [
|
|
|
3329
3565
|
"memory"
|
|
3330
3566
|
];
|
|
3331
3567
|
var AGENT_CONFIG_KEY_LIST = [...AGENT_CONFIG_KEYS].sort();
|
|
3332
|
-
function
|
|
3568
|
+
function isPlainObject3(value) {
|
|
3333
3569
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3334
3570
|
}
|
|
3335
|
-
function
|
|
3571
|
+
function normalizeValue2(value) {
|
|
3336
3572
|
if (Array.isArray(value)) {
|
|
3337
|
-
return value.map((item) =>
|
|
3573
|
+
return value.map((item) => normalizeValue2(item));
|
|
3338
3574
|
}
|
|
3339
|
-
if (
|
|
3575
|
+
if (isPlainObject3(value)) {
|
|
3340
3576
|
const normalized = {};
|
|
3341
3577
|
for (const key of Object.keys(value).sort()) {
|
|
3342
3578
|
const entry = value[key];
|
|
3343
3579
|
if (entry === void 0 || entry === null) continue;
|
|
3344
|
-
normalized[key] =
|
|
3580
|
+
normalized[key] = normalizeValue2(entry);
|
|
3345
3581
|
}
|
|
3346
3582
|
return normalized;
|
|
3347
3583
|
}
|
|
@@ -3349,11 +3585,11 @@ function normalizeValue(value) {
|
|
|
3349
3585
|
}
|
|
3350
3586
|
function normalizeAgentDefinition(definition) {
|
|
3351
3587
|
const config = {};
|
|
3352
|
-
const rawConfig =
|
|
3588
|
+
const rawConfig = isPlainObject3(definition.config) ? definition.config : {};
|
|
3353
3589
|
for (const key of AGENT_CONFIG_KEY_LIST) {
|
|
3354
3590
|
const value = rawConfig[key];
|
|
3355
3591
|
if (value === void 0 || value === null) continue;
|
|
3356
|
-
config[key] =
|
|
3592
|
+
config[key] = normalizeValue2(value);
|
|
3357
3593
|
}
|
|
3358
3594
|
return {
|
|
3359
3595
|
name: definition.name,
|
|
@@ -3371,7 +3607,7 @@ async function computeAgentContentHash(definition) {
|
|
|
3371
3607
|
var DEFINE_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set(["name", "description", "icon", ...AGENT_CONFIG_KEYS]);
|
|
3372
3608
|
function collectNonPortableToolRefs(config) {
|
|
3373
3609
|
const tools = config.tools;
|
|
3374
|
-
if (!
|
|
3610
|
+
if (!isPlainObject3(tools)) return [];
|
|
3375
3611
|
const found = [];
|
|
3376
3612
|
const isAccountScoped = (ref) => typeof ref === "string" && ref.startsWith("tool_");
|
|
3377
3613
|
const scanArray = (value, path) => {
|
|
@@ -3381,7 +3617,7 @@ function collectNonPortableToolRefs(config) {
|
|
|
3381
3617
|
});
|
|
3382
3618
|
};
|
|
3383
3619
|
const scanKeys = (value, path) => {
|
|
3384
|
-
if (!
|
|
3620
|
+
if (!isPlainObject3(value)) return;
|
|
3385
3621
|
for (const key of Object.keys(value)) {
|
|
3386
3622
|
if (isAccountScoped(key)) found.push(`${path}.${key}`);
|
|
3387
3623
|
}
|
|
@@ -3389,16 +3625,16 @@ function collectNonPortableToolRefs(config) {
|
|
|
3389
3625
|
scanArray(tools.toolIds, "tools.toolIds");
|
|
3390
3626
|
scanKeys(tools.toolConfigs, "tools.toolConfigs");
|
|
3391
3627
|
scanKeys(tools.perToolLimits, "tools.perToolLimits");
|
|
3392
|
-
if (
|
|
3393
|
-
if (
|
|
3628
|
+
if (isPlainObject3(tools.approval)) scanArray(tools.approval.require, "tools.approval.require");
|
|
3629
|
+
if (isPlainObject3(tools.subagentConfig)) {
|
|
3394
3630
|
scanArray(tools.subagentConfig.toolPool, "tools.subagentConfig.toolPool");
|
|
3395
3631
|
}
|
|
3396
|
-
if (
|
|
3632
|
+
if (isPlainObject3(tools.codeModeConfig)) {
|
|
3397
3633
|
scanArray(tools.codeModeConfig.toolPool, "tools.codeModeConfig.toolPool");
|
|
3398
3634
|
}
|
|
3399
3635
|
if (Array.isArray(tools.runtimeTools)) {
|
|
3400
3636
|
tools.runtimeTools.forEach((runtimeTool, i) => {
|
|
3401
|
-
if (!
|
|
3637
|
+
if (!isPlainObject3(runtimeTool) || !isPlainObject3(runtimeTool.config)) return;
|
|
3402
3638
|
const base = `tools.runtimeTools[${i}].config`;
|
|
3403
3639
|
const rtConfig = runtimeTool.config;
|
|
3404
3640
|
if (runtimeTool.toolType === "subagent" && typeof rtConfig.agentId === "string" && rtConfig.agentId.startsWith("agent_")) {
|
|
@@ -3459,226 +3695,693 @@ var AgentDriftError = class extends Error {
|
|
|
3459
3695
|
this.name = "AgentDriftError";
|
|
3460
3696
|
this.plan = plan;
|
|
3461
3697
|
}
|
|
3462
|
-
};
|
|
3463
|
-
function
|
|
3464
|
-
if (!(err instanceof Error)) return { status: null, body: null };
|
|
3465
|
-
const match = err.message.match(/^API request failed: (\d{3}) .*? - ([\s\S]*)$/);
|
|
3466
|
-
if (!match) return { status: null, body: null };
|
|
3467
|
-
try {
|
|
3468
|
-
return { status: Number(match[1]), body: JSON.parse(match[2]) };
|
|
3469
|
-
} catch {
|
|
3470
|
-
return { status: Number(match[1]), body: null };
|
|
3698
|
+
};
|
|
3699
|
+
function parseRequestError3(err) {
|
|
3700
|
+
if (!(err instanceof Error)) return { status: null, body: null };
|
|
3701
|
+
const match = err.message.match(/^API request failed: (\d{3}) .*? - ([\s\S]*)$/);
|
|
3702
|
+
if (!match) return { status: null, body: null };
|
|
3703
|
+
try {
|
|
3704
|
+
return { status: Number(match[1]), body: JSON.parse(match[2]) };
|
|
3705
|
+
} catch {
|
|
3706
|
+
return { status: Number(match[1]), body: null };
|
|
3707
|
+
}
|
|
3708
|
+
}
|
|
3709
|
+
function toConflictError3(err) {
|
|
3710
|
+
const { status, body } = parseRequestError3(err);
|
|
3711
|
+
if (status !== 409 || !isPlainObject3(body)) return null;
|
|
3712
|
+
const code = body.code;
|
|
3713
|
+
if (code !== "external_modification" && code !== "remote_changed") return null;
|
|
3714
|
+
return new AgentEnsureConflictError(
|
|
3715
|
+
body
|
|
3716
|
+
);
|
|
3717
|
+
}
|
|
3718
|
+
var serverHashMemo3 = /* @__PURE__ */ new WeakMap();
|
|
3719
|
+
function memoFor3(client) {
|
|
3720
|
+
let memo = serverHashMemo3.get(client);
|
|
3721
|
+
if (!memo) {
|
|
3722
|
+
memo = /* @__PURE__ */ new Map();
|
|
3723
|
+
serverHashMemo3.set(client, memo);
|
|
3724
|
+
}
|
|
3725
|
+
return memo;
|
|
3726
|
+
}
|
|
3727
|
+
var AgentsNamespace = class {
|
|
3728
|
+
constructor(getClient) {
|
|
3729
|
+
this.getClient = getClient;
|
|
3730
|
+
}
|
|
3731
|
+
/**
|
|
3732
|
+
* Idempotently converge a definition onto the platform. Hash-first: probes
|
|
3733
|
+
* with a content hash, and only ships the full definition when the server
|
|
3734
|
+
* reports a miss (`definitionRequired`). Creates an immutable version
|
|
3735
|
+
* snapshot on every change; never deletes.
|
|
3736
|
+
*/
|
|
3737
|
+
async ensure(definition, options = {}) {
|
|
3738
|
+
const client = this.getClient();
|
|
3739
|
+
const { dryRun, onConflict, release, expectedRemoteHash, expectNoChanges } = options;
|
|
3740
|
+
const passthrough = {
|
|
3741
|
+
...onConflict ? { onConflict } : {},
|
|
3742
|
+
...release ? { release } : {},
|
|
3743
|
+
...expectedRemoteHash ? { expectedRemoteHash } : {}
|
|
3744
|
+
};
|
|
3745
|
+
if (dryRun || expectNoChanges) {
|
|
3746
|
+
const plan = await this.request(client, {
|
|
3747
|
+
name: definition.name,
|
|
3748
|
+
definition,
|
|
3749
|
+
dryRun: true,
|
|
3750
|
+
...passthrough
|
|
3751
|
+
});
|
|
3752
|
+
if (plan.result !== "plan") {
|
|
3753
|
+
throw new Error(`Expected a plan result from dryRun, got '${plan.result}'`);
|
|
3754
|
+
}
|
|
3755
|
+
if (expectNoChanges && plan.changes !== "none") {
|
|
3756
|
+
throw new AgentDriftError(plan);
|
|
3757
|
+
}
|
|
3758
|
+
return plan;
|
|
3759
|
+
}
|
|
3760
|
+
const memo = memoFor3(client);
|
|
3761
|
+
const localHash = await computeAgentContentHash({
|
|
3762
|
+
...definition,
|
|
3763
|
+
config: definition.config
|
|
3764
|
+
});
|
|
3765
|
+
const memoKey = `${definition.name}\0${localHash}`;
|
|
3766
|
+
const contentHash = memo.get(memoKey) ?? localHash;
|
|
3767
|
+
const probe = await this.request(client, {
|
|
3768
|
+
name: definition.name,
|
|
3769
|
+
contentHash,
|
|
3770
|
+
...passthrough
|
|
3771
|
+
});
|
|
3772
|
+
if (probe.result !== "definitionRequired") {
|
|
3773
|
+
this.memoize(memo, memoKey, probe);
|
|
3774
|
+
return probe;
|
|
3775
|
+
}
|
|
3776
|
+
const converged = await this.request(client, {
|
|
3777
|
+
name: definition.name,
|
|
3778
|
+
definition,
|
|
3779
|
+
...passthrough
|
|
3780
|
+
});
|
|
3781
|
+
if (converged.result === "definitionRequired") {
|
|
3782
|
+
throw new Error("Server reported definitionRequired for a full-definition request");
|
|
3783
|
+
}
|
|
3784
|
+
this.memoize(memo, memoKey, converged);
|
|
3785
|
+
return converged;
|
|
3786
|
+
}
|
|
3787
|
+
/**
|
|
3788
|
+
* Pull the canonical definition + provenance for an agent by name — the
|
|
3789
|
+
* absorb-drift direction. The contentHash reflects the live agent state.
|
|
3790
|
+
*/
|
|
3791
|
+
async pull(name) {
|
|
3792
|
+
const client = this.getClient();
|
|
3793
|
+
return client.get("/agents/pull", { name });
|
|
3794
|
+
}
|
|
3795
|
+
memoize(memo, memoKey, result) {
|
|
3796
|
+
if (result.result !== "plan") memo.set(memoKey, result.contentHash);
|
|
3797
|
+
}
|
|
3798
|
+
async request(client, body) {
|
|
3799
|
+
try {
|
|
3800
|
+
return await client.post(
|
|
3801
|
+
"/agents/ensure",
|
|
3802
|
+
body
|
|
3803
|
+
);
|
|
3804
|
+
} catch (err) {
|
|
3805
|
+
const conflict = toConflictError3(err);
|
|
3806
|
+
if (conflict) throw conflict;
|
|
3807
|
+
throw err;
|
|
3808
|
+
}
|
|
3809
|
+
}
|
|
3810
|
+
};
|
|
3811
|
+
|
|
3812
|
+
// src/tools-ensure.ts
|
|
3813
|
+
function isPlainObject4(value) {
|
|
3814
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3815
|
+
}
|
|
3816
|
+
function normalizeValue3(value) {
|
|
3817
|
+
if (Array.isArray(value)) {
|
|
3818
|
+
return value.map((item) => normalizeValue3(item));
|
|
3819
|
+
}
|
|
3820
|
+
if (isPlainObject4(value)) {
|
|
3821
|
+
const normalized = {};
|
|
3822
|
+
for (const key of Object.keys(value).sort()) {
|
|
3823
|
+
const entry = value[key];
|
|
3824
|
+
if (entry === void 0 || entry === null) continue;
|
|
3825
|
+
normalized[key] = normalizeValue3(entry);
|
|
3826
|
+
}
|
|
3827
|
+
return normalized;
|
|
3828
|
+
}
|
|
3829
|
+
return value;
|
|
3830
|
+
}
|
|
3831
|
+
function normalizeToolDefinition(definition) {
|
|
3832
|
+
const parametersSchema = isPlainObject4(definition.parametersSchema) ? normalizeValue3(definition.parametersSchema) : {};
|
|
3833
|
+
const config = isPlainObject4(definition.config) ? normalizeValue3(definition.config) : {};
|
|
3834
|
+
return {
|
|
3835
|
+
toolType: definition.toolType,
|
|
3836
|
+
...definition.description ? { description: definition.description } : {},
|
|
3837
|
+
parametersSchema,
|
|
3838
|
+
config
|
|
3839
|
+
};
|
|
3840
|
+
}
|
|
3841
|
+
async function computeToolContentHash(definition) {
|
|
3842
|
+
const serialized = JSON.stringify(normalizeToolDefinition(definition));
|
|
3843
|
+
const encoded = new TextEncoder().encode(serialized);
|
|
3844
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
|
|
3845
|
+
return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
3846
|
+
}
|
|
3847
|
+
var DEFINE_TOOL_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
3848
|
+
"name",
|
|
3849
|
+
"description",
|
|
3850
|
+
"toolType",
|
|
3851
|
+
"parametersSchema",
|
|
3852
|
+
"config"
|
|
3853
|
+
]);
|
|
3854
|
+
var TOOL_DEFINITION_TYPES = /* @__PURE__ */ new Set([
|
|
3855
|
+
"flow",
|
|
3856
|
+
"custom",
|
|
3857
|
+
"external",
|
|
3858
|
+
"graphql",
|
|
3859
|
+
"mcp",
|
|
3860
|
+
"local",
|
|
3861
|
+
"subagent"
|
|
3862
|
+
]);
|
|
3863
|
+
function defineTool(input) {
|
|
3864
|
+
if (!input || typeof input !== "object") {
|
|
3865
|
+
throw new Error("defineTool requires a definition object");
|
|
3866
|
+
}
|
|
3867
|
+
if (typeof input.name !== "string" || input.name.length === 0) {
|
|
3868
|
+
throw new Error('defineTool requires a non-empty string "name"');
|
|
3869
|
+
}
|
|
3870
|
+
if (typeof input.description !== "string" || input.description.length === 0) {
|
|
3871
|
+
throw new Error('defineTool requires a non-empty string "description"');
|
|
3872
|
+
}
|
|
3873
|
+
if (typeof input.toolType !== "string" || !TOOL_DEFINITION_TYPES.has(input.toolType)) {
|
|
3874
|
+
throw new Error(
|
|
3875
|
+
`defineTool requires "toolType" to be one of: ${[...TOOL_DEFINITION_TYPES].join(", ")}`
|
|
3876
|
+
);
|
|
3877
|
+
}
|
|
3878
|
+
if (!isPlainObject4(input.parametersSchema)) {
|
|
3879
|
+
throw new Error('defineTool requires a "parametersSchema" object (a JSON Schema)');
|
|
3880
|
+
}
|
|
3881
|
+
if (!isPlainObject4(input.config)) {
|
|
3882
|
+
throw new Error('defineTool requires a "config" object');
|
|
3883
|
+
}
|
|
3884
|
+
const unknownKeys = Object.keys(input).filter((key) => !DEFINE_TOOL_TOP_LEVEL_KEYS.has(key));
|
|
3885
|
+
if (unknownKeys.length > 0) {
|
|
3886
|
+
throw new Error(
|
|
3887
|
+
`defineTool: unknown field(s): ${unknownKeys.join(", ")}. Allowed fields are name, description, toolType, parametersSchema, config.`
|
|
3888
|
+
);
|
|
3889
|
+
}
|
|
3890
|
+
return {
|
|
3891
|
+
name: input.name,
|
|
3892
|
+
description: input.description,
|
|
3893
|
+
toolType: input.toolType,
|
|
3894
|
+
parametersSchema: input.parametersSchema,
|
|
3895
|
+
config: input.config
|
|
3896
|
+
};
|
|
3897
|
+
}
|
|
3898
|
+
var ToolEnsureConflictError = class extends Error {
|
|
3899
|
+
constructor(body) {
|
|
3900
|
+
super(body.error ?? `Tool ensure conflict: ${body.code}`);
|
|
3901
|
+
this.name = "ToolEnsureConflictError";
|
|
3902
|
+
this.code = body.code;
|
|
3903
|
+
this.lastModifiedSource = body.lastModifiedSource;
|
|
3904
|
+
this.modifiedAt = body.modifiedAt;
|
|
3905
|
+
this.currentHash = body.currentHash;
|
|
3906
|
+
}
|
|
3907
|
+
};
|
|
3908
|
+
var ToolDriftError = class extends Error {
|
|
3909
|
+
constructor(plan) {
|
|
3910
|
+
super(
|
|
3911
|
+
`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.`
|
|
3912
|
+
);
|
|
3913
|
+
this.name = "ToolDriftError";
|
|
3914
|
+
this.plan = plan;
|
|
3915
|
+
}
|
|
3916
|
+
};
|
|
3917
|
+
function parseRequestError4(err) {
|
|
3918
|
+
if (!(err instanceof Error)) return { status: null, body: null };
|
|
3919
|
+
const match = err.message.match(/^API request failed: (\d{3}) .*? - ([\s\S]*)$/);
|
|
3920
|
+
if (!match) return { status: null, body: null };
|
|
3921
|
+
try {
|
|
3922
|
+
return { status: Number(match[1]), body: JSON.parse(match[2]) };
|
|
3923
|
+
} catch {
|
|
3924
|
+
return { status: Number(match[1]), body: null };
|
|
3925
|
+
}
|
|
3926
|
+
}
|
|
3927
|
+
function toConflictError4(err) {
|
|
3928
|
+
const { status, body } = parseRequestError4(err);
|
|
3929
|
+
if (status !== 409 || !isPlainObject4(body)) return null;
|
|
3930
|
+
const code = body.code;
|
|
3931
|
+
if (code !== "external_modification" && code !== "remote_changed") return null;
|
|
3932
|
+
return new ToolEnsureConflictError(
|
|
3933
|
+
body
|
|
3934
|
+
);
|
|
3935
|
+
}
|
|
3936
|
+
var serverHashMemo4 = /* @__PURE__ */ new WeakMap();
|
|
3937
|
+
function memoFor4(client) {
|
|
3938
|
+
let memo = serverHashMemo4.get(client);
|
|
3939
|
+
if (!memo) {
|
|
3940
|
+
memo = /* @__PURE__ */ new Map();
|
|
3941
|
+
serverHashMemo4.set(client, memo);
|
|
3942
|
+
}
|
|
3943
|
+
return memo;
|
|
3944
|
+
}
|
|
3945
|
+
function memoize3(memo, memoKey, result) {
|
|
3946
|
+
if (result.result !== "plan") memo.set(memoKey, result.contentHash);
|
|
3947
|
+
}
|
|
3948
|
+
async function request3(client, body) {
|
|
3949
|
+
try {
|
|
3950
|
+
return await client.post(
|
|
3951
|
+
"/tools/ensure",
|
|
3952
|
+
body
|
|
3953
|
+
);
|
|
3954
|
+
} catch (err) {
|
|
3955
|
+
const conflict = toConflictError4(err);
|
|
3956
|
+
if (conflict) throw conflict;
|
|
3957
|
+
throw err;
|
|
3958
|
+
}
|
|
3959
|
+
}
|
|
3960
|
+
async function ensureTool(client, definition, options = {}) {
|
|
3961
|
+
const { dryRun, onConflict, expectedRemoteHash, expectNoChanges } = options;
|
|
3962
|
+
const passthrough = {
|
|
3963
|
+
...onConflict ? { onConflict } : {},
|
|
3964
|
+
...expectedRemoteHash ? { expectedRemoteHash } : {}
|
|
3965
|
+
};
|
|
3966
|
+
if (dryRun || expectNoChanges) {
|
|
3967
|
+
const plan = await request3(client, {
|
|
3968
|
+
name: definition.name,
|
|
3969
|
+
definition,
|
|
3970
|
+
dryRun: true,
|
|
3971
|
+
...passthrough
|
|
3972
|
+
});
|
|
3973
|
+
if (plan.result !== "plan") {
|
|
3974
|
+
throw new Error(`Expected a plan result from dryRun, got '${plan.result}'`);
|
|
3975
|
+
}
|
|
3976
|
+
if (expectNoChanges && plan.changes !== "none") {
|
|
3977
|
+
throw new ToolDriftError(plan);
|
|
3978
|
+
}
|
|
3979
|
+
return plan;
|
|
3980
|
+
}
|
|
3981
|
+
const memo = memoFor4(client);
|
|
3982
|
+
const localHash = await computeToolContentHash(definition);
|
|
3983
|
+
const memoKey = `${definition.name} ${localHash}`;
|
|
3984
|
+
const contentHash = memo.get(memoKey) ?? localHash;
|
|
3985
|
+
const probe = await request3(client, {
|
|
3986
|
+
name: definition.name,
|
|
3987
|
+
contentHash,
|
|
3988
|
+
...passthrough
|
|
3989
|
+
});
|
|
3990
|
+
if (probe.result !== "definitionRequired") {
|
|
3991
|
+
memoize3(memo, memoKey, probe);
|
|
3992
|
+
return probe;
|
|
3993
|
+
}
|
|
3994
|
+
const converged = await request3(client, {
|
|
3995
|
+
name: definition.name,
|
|
3996
|
+
definition,
|
|
3997
|
+
...passthrough
|
|
3998
|
+
});
|
|
3999
|
+
if (converged.result === "definitionRequired") {
|
|
4000
|
+
throw new Error("Server reported definitionRequired for a full-definition request");
|
|
4001
|
+
}
|
|
4002
|
+
memoize3(memo, memoKey, converged);
|
|
4003
|
+
return converged;
|
|
4004
|
+
}
|
|
4005
|
+
async function pullTool(client, name) {
|
|
4006
|
+
return client.get("/tools/pull", { name });
|
|
4007
|
+
}
|
|
4008
|
+
|
|
4009
|
+
// src/tools-namespace.ts
|
|
4010
|
+
var ToolsNamespace = class {
|
|
4011
|
+
constructor(getClient) {
|
|
4012
|
+
this.getClient = getClient;
|
|
4013
|
+
}
|
|
4014
|
+
/**
|
|
4015
|
+
* Idempotently converge a `defineTool` definition onto the platform.
|
|
4016
|
+
* Hash-first: the steady state is one tiny probe request. Creates or updates
|
|
4017
|
+
* the saved tool; never deletes. Identity is name + account scope.
|
|
4018
|
+
*
|
|
4019
|
+
* @example
|
|
4020
|
+
* ```typescript
|
|
4021
|
+
* const weather = defineTool({
|
|
4022
|
+
* name: 'Weather Lookup',
|
|
4023
|
+
* description: 'Fetch the current weather for a city',
|
|
4024
|
+
* toolType: 'external',
|
|
4025
|
+
* parametersSchema: { type: 'object', properties: { city: { type: 'string' } } },
|
|
4026
|
+
* config: { url: 'https://api.example.com/weather', method: 'GET' },
|
|
4027
|
+
* })
|
|
4028
|
+
*
|
|
4029
|
+
* // Converge (CI/deploy).
|
|
4030
|
+
* const result = await Runtype.tools.ensure(weather)
|
|
4031
|
+
*
|
|
4032
|
+
* // PR drift gate.
|
|
4033
|
+
* await Runtype.tools.ensure(weather, { expectNoChanges: true })
|
|
4034
|
+
* ```
|
|
4035
|
+
*/
|
|
4036
|
+
async ensure(definition, options = {}) {
|
|
4037
|
+
return ensureTool(this.getClient(), definition, options);
|
|
4038
|
+
}
|
|
4039
|
+
/**
|
|
4040
|
+
* Pull the canonical definition + provenance for a tool by name — the
|
|
4041
|
+
* absorb-drift direction of the ensure protocol.
|
|
4042
|
+
*/
|
|
4043
|
+
async pull(name) {
|
|
4044
|
+
return pullTool(this.getClient(), name);
|
|
4045
|
+
}
|
|
4046
|
+
};
|
|
4047
|
+
|
|
4048
|
+
// src/products-ensure.ts
|
|
4049
|
+
function isPlainObject5(value) {
|
|
4050
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4051
|
+
}
|
|
4052
|
+
function normalizeValue4(value) {
|
|
4053
|
+
if (Array.isArray(value)) {
|
|
4054
|
+
return value.map((item) => normalizeValue4(item));
|
|
4055
|
+
}
|
|
4056
|
+
if (isPlainObject5(value)) {
|
|
4057
|
+
const normalized = {};
|
|
4058
|
+
for (const key of Object.keys(value).sort()) {
|
|
4059
|
+
const entry = value[key];
|
|
4060
|
+
if (entry === void 0 || entry === null) continue;
|
|
4061
|
+
normalized[key] = normalizeValue4(entry);
|
|
4062
|
+
}
|
|
4063
|
+
return normalized;
|
|
4064
|
+
}
|
|
4065
|
+
return value;
|
|
4066
|
+
}
|
|
4067
|
+
function normalizeProductDefinition(definition) {
|
|
4068
|
+
const spec = isPlainObject5(definition.spec) ? normalizeValue4(definition.spec) : {};
|
|
4069
|
+
return {
|
|
4070
|
+
...definition.description ? { description: definition.description } : {},
|
|
4071
|
+
...definition.icon ? { icon: definition.icon } : {},
|
|
4072
|
+
spec
|
|
4073
|
+
};
|
|
4074
|
+
}
|
|
4075
|
+
async function computeProductContentHash(definition) {
|
|
4076
|
+
const serialized = JSON.stringify(normalizeProductDefinition(definition));
|
|
4077
|
+
const encoded = new TextEncoder().encode(serialized);
|
|
4078
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
|
|
4079
|
+
return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
4080
|
+
}
|
|
4081
|
+
var DEFINE_PRODUCT_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set(["name", "description", "icon", "spec"]);
|
|
4082
|
+
function defineProduct(input) {
|
|
4083
|
+
if (!input || typeof input !== "object") {
|
|
4084
|
+
throw new Error("defineProduct requires a definition object");
|
|
4085
|
+
}
|
|
4086
|
+
if (typeof input.name !== "string" || input.name.length === 0) {
|
|
4087
|
+
throw new Error('defineProduct requires a non-empty string "name"');
|
|
4088
|
+
}
|
|
4089
|
+
if (input.description != null && typeof input.description !== "string") {
|
|
4090
|
+
throw new Error('defineProduct "description" must be a string when provided');
|
|
4091
|
+
}
|
|
4092
|
+
if (input.icon != null && typeof input.icon !== "string") {
|
|
4093
|
+
throw new Error('defineProduct "icon" must be a string when provided');
|
|
4094
|
+
}
|
|
4095
|
+
if (input.spec != null && !isPlainObject5(input.spec)) {
|
|
4096
|
+
throw new Error('defineProduct "spec" must be an object when provided');
|
|
4097
|
+
}
|
|
4098
|
+
const unknownKeys = Object.keys(input).filter((key) => !DEFINE_PRODUCT_TOP_LEVEL_KEYS.has(key));
|
|
4099
|
+
if (unknownKeys.length > 0) {
|
|
4100
|
+
throw new Error(
|
|
4101
|
+
`defineProduct: unknown field(s): ${unknownKeys.join(", ")}. Allowed fields are name, description, icon, spec. (canvas / nested capabilities and surfaces are not converged by ensure.)`
|
|
4102
|
+
);
|
|
4103
|
+
}
|
|
4104
|
+
return {
|
|
4105
|
+
name: input.name,
|
|
4106
|
+
...input.description !== void 0 ? { description: input.description } : {},
|
|
4107
|
+
...input.icon !== void 0 ? { icon: input.icon } : {},
|
|
4108
|
+
...input.spec !== void 0 ? { spec: input.spec } : {}
|
|
4109
|
+
};
|
|
4110
|
+
}
|
|
4111
|
+
var ProductEnsureConflictError = class extends Error {
|
|
4112
|
+
constructor(body) {
|
|
4113
|
+
super(body.error ?? `Product ensure conflict: ${body.code}`);
|
|
4114
|
+
this.name = "ProductEnsureConflictError";
|
|
4115
|
+
this.code = body.code;
|
|
4116
|
+
this.lastModifiedSource = body.lastModifiedSource;
|
|
4117
|
+
this.modifiedAt = body.modifiedAt;
|
|
4118
|
+
this.currentHash = body.currentHash;
|
|
4119
|
+
}
|
|
4120
|
+
};
|
|
4121
|
+
var ProductDriftError = class extends Error {
|
|
4122
|
+
constructor(plan) {
|
|
4123
|
+
super(
|
|
4124
|
+
`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.`
|
|
4125
|
+
);
|
|
4126
|
+
this.name = "ProductDriftError";
|
|
4127
|
+
this.plan = plan;
|
|
4128
|
+
}
|
|
4129
|
+
};
|
|
4130
|
+
function parseRequestError5(err) {
|
|
4131
|
+
if (!(err instanceof Error)) return { status: null, body: null };
|
|
4132
|
+
const match = err.message.match(/^API request failed: (\d{3}) .*? - ([\s\S]*)$/);
|
|
4133
|
+
if (!match) return { status: null, body: null };
|
|
4134
|
+
try {
|
|
4135
|
+
return { status: Number(match[1]), body: JSON.parse(match[2]) };
|
|
4136
|
+
} catch {
|
|
4137
|
+
return { status: Number(match[1]), body: null };
|
|
4138
|
+
}
|
|
4139
|
+
}
|
|
4140
|
+
function toConflictError5(err) {
|
|
4141
|
+
const { status, body } = parseRequestError5(err);
|
|
4142
|
+
if (status !== 409 || !isPlainObject5(body)) return null;
|
|
4143
|
+
const code = body.code;
|
|
4144
|
+
if (code !== "external_modification" && code !== "remote_changed") return null;
|
|
4145
|
+
return new ProductEnsureConflictError(
|
|
4146
|
+
body
|
|
4147
|
+
);
|
|
4148
|
+
}
|
|
4149
|
+
var serverHashMemo5 = /* @__PURE__ */ new WeakMap();
|
|
4150
|
+
function memoFor5(client) {
|
|
4151
|
+
let memo = serverHashMemo5.get(client);
|
|
4152
|
+
if (!memo) {
|
|
4153
|
+
memo = /* @__PURE__ */ new Map();
|
|
4154
|
+
serverHashMemo5.set(client, memo);
|
|
4155
|
+
}
|
|
4156
|
+
return memo;
|
|
4157
|
+
}
|
|
4158
|
+
function memoize4(memo, memoKey, result) {
|
|
4159
|
+
if (result.result !== "plan") memo.set(memoKey, result.contentHash);
|
|
4160
|
+
}
|
|
4161
|
+
async function request4(client, body) {
|
|
4162
|
+
try {
|
|
4163
|
+
return await client.post(
|
|
4164
|
+
"/products/ensure",
|
|
4165
|
+
body
|
|
4166
|
+
);
|
|
4167
|
+
} catch (err) {
|
|
4168
|
+
const conflict = toConflictError5(err);
|
|
4169
|
+
if (conflict) throw conflict;
|
|
4170
|
+
throw err;
|
|
4171
|
+
}
|
|
4172
|
+
}
|
|
4173
|
+
async function ensureProduct(client, definition, options = {}) {
|
|
4174
|
+
const { dryRun, onConflict, expectedRemoteHash, expectNoChanges } = options;
|
|
4175
|
+
const passthrough = {
|
|
4176
|
+
...onConflict ? { onConflict } : {},
|
|
4177
|
+
...expectedRemoteHash ? { expectedRemoteHash } : {}
|
|
4178
|
+
};
|
|
4179
|
+
if (dryRun || expectNoChanges) {
|
|
4180
|
+
const plan = await request4(client, {
|
|
4181
|
+
name: definition.name,
|
|
4182
|
+
definition,
|
|
4183
|
+
dryRun: true,
|
|
4184
|
+
...passthrough
|
|
4185
|
+
});
|
|
4186
|
+
if (plan.result !== "plan") {
|
|
4187
|
+
throw new Error(`Expected a plan result from dryRun, got '${plan.result}'`);
|
|
4188
|
+
}
|
|
4189
|
+
if (expectNoChanges && plan.changes !== "none") {
|
|
4190
|
+
throw new ProductDriftError(plan);
|
|
4191
|
+
}
|
|
4192
|
+
return plan;
|
|
4193
|
+
}
|
|
4194
|
+
const memo = memoFor5(client);
|
|
4195
|
+
const localHash = await computeProductContentHash(definition);
|
|
4196
|
+
const memoKey = `${definition.name} ${localHash}`;
|
|
4197
|
+
const contentHash = memo.get(memoKey) ?? localHash;
|
|
4198
|
+
const probe = await request4(client, {
|
|
4199
|
+
name: definition.name,
|
|
4200
|
+
contentHash,
|
|
4201
|
+
...passthrough
|
|
4202
|
+
});
|
|
4203
|
+
if (probe.result !== "definitionRequired") {
|
|
4204
|
+
memoize4(memo, memoKey, probe);
|
|
4205
|
+
return probe;
|
|
4206
|
+
}
|
|
4207
|
+
const converged = await request4(client, {
|
|
4208
|
+
name: definition.name,
|
|
4209
|
+
definition,
|
|
4210
|
+
...passthrough
|
|
4211
|
+
});
|
|
4212
|
+
if (converged.result === "definitionRequired") {
|
|
4213
|
+
throw new Error("Server reported definitionRequired for a full-definition request");
|
|
3471
4214
|
}
|
|
4215
|
+
memoize4(memo, memoKey, converged);
|
|
4216
|
+
return converged;
|
|
3472
4217
|
}
|
|
3473
|
-
function
|
|
3474
|
-
|
|
3475
|
-
if (status !== 409 || !isPlainObject2(body)) return null;
|
|
3476
|
-
const code = body.code;
|
|
3477
|
-
if (code !== "external_modification" && code !== "remote_changed") return null;
|
|
3478
|
-
return new AgentEnsureConflictError(
|
|
3479
|
-
body
|
|
3480
|
-
);
|
|
3481
|
-
}
|
|
3482
|
-
var serverHashMemo2 = /* @__PURE__ */ new WeakMap();
|
|
3483
|
-
function memoFor2(client) {
|
|
3484
|
-
let memo = serverHashMemo2.get(client);
|
|
3485
|
-
if (!memo) {
|
|
3486
|
-
memo = /* @__PURE__ */ new Map();
|
|
3487
|
-
serverHashMemo2.set(client, memo);
|
|
3488
|
-
}
|
|
3489
|
-
return memo;
|
|
4218
|
+
async function pullProduct(client, name) {
|
|
4219
|
+
return client.get("/products/pull", { name });
|
|
3490
4220
|
}
|
|
3491
|
-
|
|
4221
|
+
|
|
4222
|
+
// src/products-namespace.ts
|
|
4223
|
+
var ProductsNamespace = class {
|
|
3492
4224
|
constructor(getClient) {
|
|
3493
4225
|
this.getClient = getClient;
|
|
3494
4226
|
}
|
|
3495
4227
|
/**
|
|
3496
|
-
* Idempotently converge a definition onto the platform.
|
|
3497
|
-
*
|
|
3498
|
-
*
|
|
3499
|
-
*
|
|
4228
|
+
* Idempotently converge a `defineProduct` definition onto the platform.
|
|
4229
|
+
* Hash-first: the steady state is one tiny probe request. Creates or updates
|
|
4230
|
+
* the top-level product record; never deletes. Identity is name + account
|
|
4231
|
+
* scope.
|
|
4232
|
+
*
|
|
4233
|
+
* @example
|
|
4234
|
+
* ```typescript
|
|
4235
|
+
* const product = defineProduct({
|
|
4236
|
+
* name: 'Support Copilot',
|
|
4237
|
+
* description: 'An AI support assistant',
|
|
4238
|
+
* icon: '🤖',
|
|
4239
|
+
* spec: { productGoal: 'Deflect tier-1 tickets', productStage: 'beta' },
|
|
4240
|
+
* })
|
|
4241
|
+
*
|
|
4242
|
+
* // Converge (CI/deploy).
|
|
4243
|
+
* const result = await Runtype.products.ensure(product)
|
|
4244
|
+
*
|
|
4245
|
+
* // PR drift gate.
|
|
4246
|
+
* await Runtype.products.ensure(product, { expectNoChanges: true })
|
|
4247
|
+
* ```
|
|
3500
4248
|
*/
|
|
3501
4249
|
async ensure(definition, options = {}) {
|
|
3502
|
-
|
|
3503
|
-
const { dryRun, onConflict, release, expectedRemoteHash, expectNoChanges } = options;
|
|
3504
|
-
const passthrough = {
|
|
3505
|
-
...onConflict ? { onConflict } : {},
|
|
3506
|
-
...release ? { release } : {},
|
|
3507
|
-
...expectedRemoteHash ? { expectedRemoteHash } : {}
|
|
3508
|
-
};
|
|
3509
|
-
if (dryRun || expectNoChanges) {
|
|
3510
|
-
const plan = await this.request(client, {
|
|
3511
|
-
name: definition.name,
|
|
3512
|
-
definition,
|
|
3513
|
-
dryRun: true,
|
|
3514
|
-
...passthrough
|
|
3515
|
-
});
|
|
3516
|
-
if (plan.result !== "plan") {
|
|
3517
|
-
throw new Error(`Expected a plan result from dryRun, got '${plan.result}'`);
|
|
3518
|
-
}
|
|
3519
|
-
if (expectNoChanges && plan.changes !== "none") {
|
|
3520
|
-
throw new AgentDriftError(plan);
|
|
3521
|
-
}
|
|
3522
|
-
return plan;
|
|
3523
|
-
}
|
|
3524
|
-
const memo = memoFor2(client);
|
|
3525
|
-
const localHash = await computeAgentContentHash({
|
|
3526
|
-
...definition,
|
|
3527
|
-
config: definition.config
|
|
3528
|
-
});
|
|
3529
|
-
const memoKey = `${definition.name}\0${localHash}`;
|
|
3530
|
-
const contentHash = memo.get(memoKey) ?? localHash;
|
|
3531
|
-
const probe = await this.request(client, {
|
|
3532
|
-
name: definition.name,
|
|
3533
|
-
contentHash,
|
|
3534
|
-
...passthrough
|
|
3535
|
-
});
|
|
3536
|
-
if (probe.result !== "definitionRequired") {
|
|
3537
|
-
this.memoize(memo, memoKey, probe);
|
|
3538
|
-
return probe;
|
|
3539
|
-
}
|
|
3540
|
-
const converged = await this.request(client, {
|
|
3541
|
-
name: definition.name,
|
|
3542
|
-
definition,
|
|
3543
|
-
...passthrough
|
|
3544
|
-
});
|
|
3545
|
-
if (converged.result === "definitionRequired") {
|
|
3546
|
-
throw new Error("Server reported definitionRequired for a full-definition request");
|
|
3547
|
-
}
|
|
3548
|
-
this.memoize(memo, memoKey, converged);
|
|
3549
|
-
return converged;
|
|
4250
|
+
return ensureProduct(this.getClient(), definition, options);
|
|
3550
4251
|
}
|
|
3551
4252
|
/**
|
|
3552
|
-
* Pull the canonical definition + provenance for
|
|
3553
|
-
* absorb-drift direction
|
|
4253
|
+
* Pull the canonical definition + provenance for a product by name — the
|
|
4254
|
+
* absorb-drift direction of the ensure protocol.
|
|
3554
4255
|
*/
|
|
3555
4256
|
async pull(name) {
|
|
3556
|
-
|
|
3557
|
-
return client.get("/agents/pull", { name });
|
|
3558
|
-
}
|
|
3559
|
-
memoize(memo, memoKey, result) {
|
|
3560
|
-
if (result.result !== "plan") memo.set(memoKey, result.contentHash);
|
|
3561
|
-
}
|
|
3562
|
-
async request(client, body) {
|
|
3563
|
-
try {
|
|
3564
|
-
return await client.post(
|
|
3565
|
-
"/agents/ensure",
|
|
3566
|
-
body
|
|
3567
|
-
);
|
|
3568
|
-
} catch (err) {
|
|
3569
|
-
const conflict = toConflictError2(err);
|
|
3570
|
-
if (conflict) throw conflict;
|
|
3571
|
-
throw err;
|
|
3572
|
-
}
|
|
4257
|
+
return pullProduct(this.getClient(), name);
|
|
3573
4258
|
}
|
|
3574
4259
|
};
|
|
3575
4260
|
|
|
3576
|
-
// src/
|
|
3577
|
-
function
|
|
4261
|
+
// src/surfaces-ensure.ts
|
|
4262
|
+
function isPlainObject6(value) {
|
|
3578
4263
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3579
4264
|
}
|
|
3580
|
-
function
|
|
4265
|
+
function normalizeValue5(value) {
|
|
3581
4266
|
if (Array.isArray(value)) {
|
|
3582
|
-
return value.map((item) =>
|
|
4267
|
+
return value.map((item) => normalizeValue5(item));
|
|
3583
4268
|
}
|
|
3584
|
-
if (
|
|
4269
|
+
if (isPlainObject6(value)) {
|
|
3585
4270
|
const normalized = {};
|
|
3586
4271
|
for (const key of Object.keys(value).sort()) {
|
|
3587
4272
|
const entry = value[key];
|
|
3588
4273
|
if (entry === void 0 || entry === null) continue;
|
|
3589
|
-
normalized[key] =
|
|
4274
|
+
normalized[key] = normalizeValue5(entry);
|
|
3590
4275
|
}
|
|
3591
4276
|
return normalized;
|
|
3592
4277
|
}
|
|
3593
4278
|
return value;
|
|
3594
4279
|
}
|
|
3595
|
-
function
|
|
3596
|
-
const
|
|
3597
|
-
const config = isPlainObject3(definition.config) ? normalizeValue2(definition.config) : {};
|
|
4280
|
+
function normalizeSurfaceDefinition(definition) {
|
|
4281
|
+
const behavior = isPlainObject6(definition.behavior) ? normalizeValue5(definition.behavior) : { type: definition.type };
|
|
3598
4282
|
return {
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
4283
|
+
type: definition.type,
|
|
4284
|
+
behavior,
|
|
4285
|
+
status: definition.status || "draft",
|
|
4286
|
+
environment: definition.environment || "development"
|
|
3603
4287
|
};
|
|
3604
4288
|
}
|
|
3605
|
-
async function
|
|
3606
|
-
const serialized = JSON.stringify(
|
|
4289
|
+
async function computeSurfaceContentHash(definition) {
|
|
4290
|
+
const serialized = JSON.stringify(normalizeSurfaceDefinition(definition));
|
|
3607
4291
|
const encoded = new TextEncoder().encode(serialized);
|
|
3608
4292
|
const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
|
|
3609
4293
|
return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
3610
4294
|
}
|
|
3611
|
-
var
|
|
4295
|
+
var DEFINE_SURFACE_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
3612
4296
|
"name",
|
|
3613
|
-
"
|
|
3614
|
-
"
|
|
3615
|
-
"
|
|
3616
|
-
"
|
|
4297
|
+
"type",
|
|
4298
|
+
"behavior",
|
|
4299
|
+
"inbound",
|
|
4300
|
+
"outbound",
|
|
4301
|
+
"status",
|
|
4302
|
+
"environment"
|
|
3617
4303
|
]);
|
|
3618
|
-
var
|
|
3619
|
-
"
|
|
3620
|
-
"custom",
|
|
3621
|
-
"external",
|
|
3622
|
-
"graphql",
|
|
4304
|
+
var SURFACE_DEFINITION_TYPES = /* @__PURE__ */ new Set([
|
|
4305
|
+
"chat",
|
|
3623
4306
|
"mcp",
|
|
3624
|
-
"
|
|
3625
|
-
"
|
|
4307
|
+
"mcp_code",
|
|
4308
|
+
"api",
|
|
4309
|
+
"webhook",
|
|
4310
|
+
"schedule",
|
|
4311
|
+
"a2a",
|
|
4312
|
+
"email",
|
|
4313
|
+
"slack",
|
|
4314
|
+
"sms",
|
|
4315
|
+
"imessage",
|
|
4316
|
+
"discord",
|
|
4317
|
+
"whatsapp",
|
|
4318
|
+
"telegram",
|
|
4319
|
+
"hosted-page",
|
|
4320
|
+
"chrome_extension"
|
|
3626
4321
|
]);
|
|
3627
|
-
function
|
|
4322
|
+
function defineSurface(input) {
|
|
3628
4323
|
if (!input || typeof input !== "object") {
|
|
3629
|
-
throw new Error("
|
|
4324
|
+
throw new Error("defineSurface requires a definition object");
|
|
3630
4325
|
}
|
|
3631
4326
|
if (typeof input.name !== "string" || input.name.length === 0) {
|
|
3632
|
-
throw new Error('
|
|
4327
|
+
throw new Error('defineSurface requires a non-empty string "name"');
|
|
3633
4328
|
}
|
|
3634
|
-
if (typeof input.
|
|
3635
|
-
throw new Error('defineTool requires a non-empty string "description"');
|
|
3636
|
-
}
|
|
3637
|
-
if (typeof input.toolType !== "string" || !TOOL_DEFINITION_TYPES.has(input.toolType)) {
|
|
4329
|
+
if (typeof input.type !== "string" || !SURFACE_DEFINITION_TYPES.has(input.type)) {
|
|
3638
4330
|
throw new Error(
|
|
3639
|
-
`
|
|
4331
|
+
`defineSurface requires "type" to be one of: ${[...SURFACE_DEFINITION_TYPES].join(", ")}`
|
|
3640
4332
|
);
|
|
3641
4333
|
}
|
|
3642
|
-
if (!
|
|
3643
|
-
throw new Error('
|
|
4334
|
+
if (input.behavior !== void 0 && !isPlainObject6(input.behavior)) {
|
|
4335
|
+
throw new Error('defineSurface "behavior" must be an object when provided');
|
|
3644
4336
|
}
|
|
3645
|
-
if (!
|
|
3646
|
-
throw new Error('
|
|
4337
|
+
if (input.inbound !== void 0 && !isPlainObject6(input.inbound)) {
|
|
4338
|
+
throw new Error('defineSurface "inbound" must be an object when provided');
|
|
3647
4339
|
}
|
|
3648
|
-
|
|
4340
|
+
if (input.outbound !== void 0 && !isPlainObject6(input.outbound)) {
|
|
4341
|
+
throw new Error('defineSurface "outbound" must be an object when provided');
|
|
4342
|
+
}
|
|
4343
|
+
if (input.status !== void 0 && !["draft", "active", "paused"].includes(input.status)) {
|
|
4344
|
+
throw new Error('defineSurface "status" must be one of: draft, active, paused');
|
|
4345
|
+
}
|
|
4346
|
+
if (input.environment !== void 0 && !["production", "development"].includes(input.environment)) {
|
|
4347
|
+
throw new Error('defineSurface "environment" must be one of: production, development');
|
|
4348
|
+
}
|
|
4349
|
+
const unknownKeys = Object.keys(input).filter((key) => !DEFINE_SURFACE_TOP_LEVEL_KEYS.has(key));
|
|
3649
4350
|
if (unknownKeys.length > 0) {
|
|
3650
4351
|
throw new Error(
|
|
3651
|
-
`
|
|
4352
|
+
`defineSurface: unknown field(s): ${unknownKeys.join(", ")}. Allowed fields are name, type, behavior, inbound, outbound, status, environment.`
|
|
3652
4353
|
);
|
|
3653
4354
|
}
|
|
3654
4355
|
return {
|
|
3655
4356
|
name: input.name,
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
4357
|
+
type: input.type,
|
|
4358
|
+
...input.behavior !== void 0 ? { behavior: input.behavior } : {},
|
|
4359
|
+
...input.inbound !== void 0 ? { inbound: input.inbound } : {},
|
|
4360
|
+
...input.outbound !== void 0 ? { outbound: input.outbound } : {},
|
|
4361
|
+
...input.status !== void 0 ? { status: input.status } : {},
|
|
4362
|
+
...input.environment !== void 0 ? { environment: input.environment } : {}
|
|
3660
4363
|
};
|
|
3661
4364
|
}
|
|
3662
|
-
var
|
|
4365
|
+
var SurfaceEnsureConflictError = class extends Error {
|
|
3663
4366
|
constructor(body) {
|
|
3664
|
-
super(body.error ?? `
|
|
3665
|
-
this.name = "
|
|
4367
|
+
super(body.error ?? `Surface ensure conflict: ${body.code}`);
|
|
4368
|
+
this.name = "SurfaceEnsureConflictError";
|
|
3666
4369
|
this.code = body.code;
|
|
3667
4370
|
this.lastModifiedSource = body.lastModifiedSource;
|
|
3668
4371
|
this.modifiedAt = body.modifiedAt;
|
|
3669
4372
|
this.currentHash = body.currentHash;
|
|
3670
4373
|
}
|
|
3671
4374
|
};
|
|
3672
|
-
var
|
|
4375
|
+
var SurfaceDriftError = class extends Error {
|
|
3673
4376
|
constructor(plan) {
|
|
3674
4377
|
super(
|
|
3675
|
-
`
|
|
4378
|
+
`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.`
|
|
3676
4379
|
);
|
|
3677
|
-
this.name = "
|
|
4380
|
+
this.name = "SurfaceDriftError";
|
|
3678
4381
|
this.plan = plan;
|
|
3679
4382
|
}
|
|
3680
4383
|
};
|
|
3681
|
-
function
|
|
4384
|
+
function parseRequestError6(err) {
|
|
3682
4385
|
if (!(err instanceof Error)) return { status: null, body: null };
|
|
3683
4386
|
const match = err.message.match(/^API request failed: (\d{3}) .*? - ([\s\S]*)$/);
|
|
3684
4387
|
if (!match) return { status: null, body: null };
|
|
@@ -3688,47 +4391,47 @@ function parseRequestError3(err) {
|
|
|
3688
4391
|
return { status: Number(match[1]), body: null };
|
|
3689
4392
|
}
|
|
3690
4393
|
}
|
|
3691
|
-
function
|
|
3692
|
-
const { status, body } =
|
|
3693
|
-
if (status !== 409 || !
|
|
4394
|
+
function toConflictError6(err) {
|
|
4395
|
+
const { status, body } = parseRequestError6(err);
|
|
4396
|
+
if (status !== 409 || !isPlainObject6(body)) return null;
|
|
3694
4397
|
const code = body.code;
|
|
3695
4398
|
if (code !== "external_modification" && code !== "remote_changed") return null;
|
|
3696
|
-
return new
|
|
4399
|
+
return new SurfaceEnsureConflictError(
|
|
3697
4400
|
body
|
|
3698
4401
|
);
|
|
3699
4402
|
}
|
|
3700
|
-
var
|
|
3701
|
-
function
|
|
3702
|
-
let memo =
|
|
4403
|
+
var serverHashMemo6 = /* @__PURE__ */ new WeakMap();
|
|
4404
|
+
function memoFor6(client) {
|
|
4405
|
+
let memo = serverHashMemo6.get(client);
|
|
3703
4406
|
if (!memo) {
|
|
3704
4407
|
memo = /* @__PURE__ */ new Map();
|
|
3705
|
-
|
|
4408
|
+
serverHashMemo6.set(client, memo);
|
|
3706
4409
|
}
|
|
3707
4410
|
return memo;
|
|
3708
4411
|
}
|
|
3709
|
-
function
|
|
4412
|
+
function memoize5(memo, memoKey, result) {
|
|
3710
4413
|
if (result.result !== "plan") memo.set(memoKey, result.contentHash);
|
|
3711
4414
|
}
|
|
3712
|
-
async function
|
|
4415
|
+
async function request5(client, productId, body) {
|
|
3713
4416
|
try {
|
|
3714
4417
|
return await client.post(
|
|
3715
|
-
|
|
4418
|
+
`/products/${encodeURIComponent(productId)}/surfaces/ensure`,
|
|
3716
4419
|
body
|
|
3717
4420
|
);
|
|
3718
4421
|
} catch (err) {
|
|
3719
|
-
const conflict =
|
|
4422
|
+
const conflict = toConflictError6(err);
|
|
3720
4423
|
if (conflict) throw conflict;
|
|
3721
4424
|
throw err;
|
|
3722
4425
|
}
|
|
3723
4426
|
}
|
|
3724
|
-
async function
|
|
4427
|
+
async function ensureSurface(client, productId, definition, options = {}) {
|
|
3725
4428
|
const { dryRun, onConflict, expectedRemoteHash, expectNoChanges } = options;
|
|
3726
4429
|
const passthrough = {
|
|
3727
4430
|
...onConflict ? { onConflict } : {},
|
|
3728
4431
|
...expectedRemoteHash ? { expectedRemoteHash } : {}
|
|
3729
4432
|
};
|
|
3730
4433
|
if (dryRun || expectNoChanges) {
|
|
3731
|
-
const plan = await
|
|
4434
|
+
const plan = await request5(client, productId, {
|
|
3732
4435
|
name: definition.name,
|
|
3733
4436
|
definition,
|
|
3734
4437
|
dryRun: true,
|
|
@@ -3738,24 +4441,24 @@ async function ensureTool(client, definition, options = {}) {
|
|
|
3738
4441
|
throw new Error(`Expected a plan result from dryRun, got '${plan.result}'`);
|
|
3739
4442
|
}
|
|
3740
4443
|
if (expectNoChanges && plan.changes !== "none") {
|
|
3741
|
-
throw new
|
|
4444
|
+
throw new SurfaceDriftError(plan);
|
|
3742
4445
|
}
|
|
3743
4446
|
return plan;
|
|
3744
4447
|
}
|
|
3745
|
-
const memo =
|
|
3746
|
-
const localHash = await
|
|
3747
|
-
const memoKey = `${definition.name} ${localHash}`;
|
|
4448
|
+
const memo = memoFor6(client);
|
|
4449
|
+
const localHash = await computeSurfaceContentHash(definition);
|
|
4450
|
+
const memoKey = `${productId} ${definition.name} ${localHash}`;
|
|
3748
4451
|
const contentHash = memo.get(memoKey) ?? localHash;
|
|
3749
|
-
const probe = await
|
|
4452
|
+
const probe = await request5(client, productId, {
|
|
3750
4453
|
name: definition.name,
|
|
3751
4454
|
contentHash,
|
|
3752
4455
|
...passthrough
|
|
3753
4456
|
});
|
|
3754
4457
|
if (probe.result !== "definitionRequired") {
|
|
3755
|
-
|
|
4458
|
+
memoize5(memo, memoKey, probe);
|
|
3756
4459
|
return probe;
|
|
3757
4460
|
}
|
|
3758
|
-
const converged = await
|
|
4461
|
+
const converged = await request5(client, productId, {
|
|
3759
4462
|
name: definition.name,
|
|
3760
4463
|
definition,
|
|
3761
4464
|
...passthrough
|
|
@@ -3763,49 +4466,51 @@ async function ensureTool(client, definition, options = {}) {
|
|
|
3763
4466
|
if (converged.result === "definitionRequired") {
|
|
3764
4467
|
throw new Error("Server reported definitionRequired for a full-definition request");
|
|
3765
4468
|
}
|
|
3766
|
-
|
|
4469
|
+
memoize5(memo, memoKey, converged);
|
|
3767
4470
|
return converged;
|
|
3768
4471
|
}
|
|
3769
|
-
async function
|
|
3770
|
-
return client.get(
|
|
4472
|
+
async function pullSurface(client, productId, name) {
|
|
4473
|
+
return client.get(
|
|
4474
|
+
`/products/${encodeURIComponent(productId)}/surfaces/pull`,
|
|
4475
|
+
{ name }
|
|
4476
|
+
);
|
|
3771
4477
|
}
|
|
3772
4478
|
|
|
3773
|
-
// src/
|
|
3774
|
-
var
|
|
4479
|
+
// src/surfaces-namespace.ts
|
|
4480
|
+
var SurfacesNamespace = class {
|
|
3775
4481
|
constructor(getClient) {
|
|
3776
4482
|
this.getClient = getClient;
|
|
3777
4483
|
}
|
|
3778
4484
|
/**
|
|
3779
|
-
* Idempotently converge a `
|
|
4485
|
+
* Idempotently converge a `defineSurface` definition onto a product.
|
|
3780
4486
|
* Hash-first: the steady state is one tiny probe request. Creates or updates
|
|
3781
|
-
* the
|
|
4487
|
+
* the surface; never deletes. Identity is name + product.
|
|
3782
4488
|
*
|
|
3783
4489
|
* @example
|
|
3784
4490
|
* ```typescript
|
|
3785
|
-
* const
|
|
3786
|
-
* name: '
|
|
3787
|
-
*
|
|
3788
|
-
*
|
|
3789
|
-
*
|
|
3790
|
-
* config: { url: 'https://api.example.com/weather', method: 'GET' },
|
|
4491
|
+
* const chat = defineSurface({
|
|
4492
|
+
* name: 'Support Chat',
|
|
4493
|
+
* type: 'chat',
|
|
4494
|
+
* behavior: { type: 'chat', greeting: 'Hi there!' },
|
|
4495
|
+
* status: 'active',
|
|
3791
4496
|
* })
|
|
3792
4497
|
*
|
|
3793
4498
|
* // Converge (CI/deploy).
|
|
3794
|
-
* const result = await Runtype.
|
|
4499
|
+
* const result = await Runtype.surfaces.ensure('product_abc', chat)
|
|
3795
4500
|
*
|
|
3796
4501
|
* // PR drift gate.
|
|
3797
|
-
* await Runtype.
|
|
4502
|
+
* await Runtype.surfaces.ensure('product_abc', chat, { expectNoChanges: true })
|
|
3798
4503
|
* ```
|
|
3799
4504
|
*/
|
|
3800
|
-
async ensure(definition, options = {}) {
|
|
3801
|
-
return
|
|
4505
|
+
async ensure(productId, definition, options = {}) {
|
|
4506
|
+
return ensureSurface(this.getClient(), productId, definition, options);
|
|
3802
4507
|
}
|
|
3803
4508
|
/**
|
|
3804
|
-
* Pull the canonical definition + provenance for a
|
|
3805
|
-
* absorb-drift direction of the ensure protocol.
|
|
4509
|
+
* Pull the canonical definition + provenance for a surface by name within a
|
|
4510
|
+
* product — the absorb-drift direction of the ensure protocol.
|
|
3806
4511
|
*/
|
|
3807
|
-
async pull(name) {
|
|
3808
|
-
return
|
|
4512
|
+
async pull(productId, name) {
|
|
4513
|
+
return pullSurface(this.getClient(), productId, name);
|
|
3809
4514
|
}
|
|
3810
4515
|
};
|
|
3811
4516
|
|
|
@@ -4225,6 +4930,66 @@ var Runtype = class {
|
|
|
4225
4930
|
static get tools() {
|
|
4226
4931
|
return new ToolsNamespace(() => this.getClient());
|
|
4227
4932
|
}
|
|
4933
|
+
/**
|
|
4934
|
+
* Products namespace - Product config-as-code (define / ensure / pull)
|
|
4935
|
+
*
|
|
4936
|
+
* Converges the top-level product record (description, icon, spec). Nested
|
|
4937
|
+
* capabilities/surfaces/tools and the canvas UI layout state are not
|
|
4938
|
+
* converged by ensure.
|
|
4939
|
+
*
|
|
4940
|
+
* @example
|
|
4941
|
+
* ```typescript
|
|
4942
|
+
* import { defineProduct, Runtype } from '@runtypelabs/sdk'
|
|
4943
|
+
*
|
|
4944
|
+
* const product = defineProduct({
|
|
4945
|
+
* name: 'Support Copilot',
|
|
4946
|
+
* description: 'An AI support assistant',
|
|
4947
|
+
* icon: '🤖',
|
|
4948
|
+
* spec: { productGoal: 'Deflect tier-1 tickets', productStage: 'beta' },
|
|
4949
|
+
* })
|
|
4950
|
+
*
|
|
4951
|
+
* // Converge at deploy time (idempotent; one tiny probe in steady state)
|
|
4952
|
+
* await Runtype.products.ensure(product)
|
|
4953
|
+
*
|
|
4954
|
+
* // CI drift gate
|
|
4955
|
+
* await Runtype.products.ensure(product, { expectNoChanges: true })
|
|
4956
|
+
*
|
|
4957
|
+
* // Absorb a dashboard edit back into the repo
|
|
4958
|
+
* const { definition } = await Runtype.products.pull('Support Copilot')
|
|
4959
|
+
* ```
|
|
4960
|
+
*/
|
|
4961
|
+
static get products() {
|
|
4962
|
+
return new ProductsNamespace(() => this.getClient());
|
|
4963
|
+
}
|
|
4964
|
+
/**
|
|
4965
|
+
* Config-as-code operations for product surfaces. `surfaces.ensure` is the
|
|
4966
|
+
* deploy-time, non-executing converge (create-or-update a surface by name
|
|
4967
|
+
* within a product); `surfaces.pull` is the absorb-drift direction.
|
|
4968
|
+
*
|
|
4969
|
+
* @example
|
|
4970
|
+
* ```typescript
|
|
4971
|
+
* import { Runtype, defineSurface } from '@runtypelabs/sdk'
|
|
4972
|
+
*
|
|
4973
|
+
* const chat = defineSurface({
|
|
4974
|
+
* name: 'Support Chat',
|
|
4975
|
+
* type: 'chat',
|
|
4976
|
+
* behavior: { type: 'chat', greeting: 'Hi there!' },
|
|
4977
|
+
* status: 'active',
|
|
4978
|
+
* })
|
|
4979
|
+
*
|
|
4980
|
+
* // Converge at deploy time (idempotent; one tiny probe in steady state)
|
|
4981
|
+
* await Runtype.surfaces.ensure('product_abc', chat)
|
|
4982
|
+
*
|
|
4983
|
+
* // CI drift gate
|
|
4984
|
+
* await Runtype.surfaces.ensure('product_abc', chat, { expectNoChanges: true })
|
|
4985
|
+
*
|
|
4986
|
+
* // Absorb a dashboard edit back into the repo
|
|
4987
|
+
* const { definition } = await Runtype.surfaces.pull('product_abc', 'Support Chat')
|
|
4988
|
+
* ```
|
|
4989
|
+
*/
|
|
4990
|
+
static get surfaces() {
|
|
4991
|
+
return new SurfacesNamespace(() => this.getClient());
|
|
4992
|
+
}
|
|
4228
4993
|
};
|
|
4229
4994
|
|
|
4230
4995
|
// src/generated-tool-gate.ts
|
|
@@ -4447,8 +5212,8 @@ function buildGeneratedRuntimeToolGateOutput(proposal, options = {}) {
|
|
|
4447
5212
|
...decision.tool ? { tool: decision.tool } : {}
|
|
4448
5213
|
};
|
|
4449
5214
|
}
|
|
4450
|
-
function attachRuntimeToolsToDispatchRequest(
|
|
4451
|
-
const stepList =
|
|
5215
|
+
function attachRuntimeToolsToDispatchRequest(request6, runtimeTools, options = {}) {
|
|
5216
|
+
const stepList = request6.flow.steps;
|
|
4452
5217
|
if (!stepList || !Array.isArray(stepList) || stepList.length === 0) {
|
|
4453
5218
|
throw new Error("Cannot attach runtime tools: dispatch request must include flow.steps");
|
|
4454
5219
|
}
|
|
@@ -4491,9 +5256,9 @@ function attachRuntimeToolsToDispatchRequest(request3, runtimeTools, options = {
|
|
|
4491
5256
|
}
|
|
4492
5257
|
};
|
|
4493
5258
|
return {
|
|
4494
|
-
...
|
|
5259
|
+
...request6,
|
|
4495
5260
|
flow: {
|
|
4496
|
-
...
|
|
5261
|
+
...request6.flow,
|
|
4497
5262
|
// `clonedSteps` is a structural clone of `request.flow.steps` (already
|
|
4498
5263
|
// `FlowStepDefinition[]`); only the prompt step's `config.tools` was
|
|
4499
5264
|
// merged, so every step's `type` discriminant is preserved. The clone is
|
|
@@ -4503,12 +5268,12 @@ function attachRuntimeToolsToDispatchRequest(request3, runtimeTools, options = {
|
|
|
4503
5268
|
}
|
|
4504
5269
|
};
|
|
4505
5270
|
}
|
|
4506
|
-
function applyGeneratedRuntimeToolProposalToDispatchRequest(
|
|
5271
|
+
function applyGeneratedRuntimeToolProposalToDispatchRequest(request6, proposal, options = {}) {
|
|
4507
5272
|
const decision = evaluateGeneratedRuntimeToolProposal(proposal, options.gate);
|
|
4508
5273
|
if (!decision.approved || !decision.tool) {
|
|
4509
|
-
return { decision, request:
|
|
5274
|
+
return { decision, request: request6 };
|
|
4510
5275
|
}
|
|
4511
|
-
const nextRequest = attachRuntimeToolsToDispatchRequest(
|
|
5276
|
+
const nextRequest = attachRuntimeToolsToDispatchRequest(request6, [decision.tool], options.attach);
|
|
4512
5277
|
return {
|
|
4513
5278
|
decision,
|
|
4514
5279
|
request: nextRequest
|
|
@@ -6758,15 +7523,15 @@ var DispatchEndpoint = class {
|
|
|
6758
7523
|
* Attach approved runtime tools to a prompt step in a redispatch request.
|
|
6759
7524
|
* Returns a new request object and does not mutate the original.
|
|
6760
7525
|
*/
|
|
6761
|
-
attachApprovedRuntimeTools(
|
|
6762
|
-
return attachRuntimeToolsToDispatchRequest(
|
|
7526
|
+
attachApprovedRuntimeTools(request6, runtimeTools, options) {
|
|
7527
|
+
return attachRuntimeToolsToDispatchRequest(request6, runtimeTools, options);
|
|
6763
7528
|
}
|
|
6764
7529
|
/**
|
|
6765
7530
|
* Validate a generated runtime tool proposal and attach it to the redispatch
|
|
6766
7531
|
* request if approved, in one call.
|
|
6767
7532
|
*/
|
|
6768
|
-
applyGeneratedRuntimeToolProposal(
|
|
6769
|
-
return applyGeneratedRuntimeToolProposalToDispatchRequest(
|
|
7533
|
+
applyGeneratedRuntimeToolProposal(request6, proposal, options) {
|
|
7534
|
+
return applyGeneratedRuntimeToolProposalToDispatchRequest(request6, proposal, options);
|
|
6770
7535
|
}
|
|
6771
7536
|
};
|
|
6772
7537
|
var ChatEndpoint = class {
|
|
@@ -7318,8 +8083,8 @@ var GENERATED_RUNTIME_TOOL_PROPOSAL_SCHEMA = {
|
|
|
7318
8083
|
},
|
|
7319
8084
|
required: ["name", "description", "toolType", "parametersSchema", "config"]
|
|
7320
8085
|
};
|
|
7321
|
-
function appendRuntimeToolsToAgentRequest(
|
|
7322
|
-
const existing =
|
|
8086
|
+
function appendRuntimeToolsToAgentRequest(request6, runtimeTools) {
|
|
8087
|
+
const existing = request6.tools?.runtimeTools || [];
|
|
7323
8088
|
const existingNames = new Set(existing.map((tool) => tool.name));
|
|
7324
8089
|
const converted = runtimeTools.filter((tool) => !existingNames.has(tool.name)).map((tool) => ({
|
|
7325
8090
|
name: tool.name,
|
|
@@ -7329,9 +8094,9 @@ function appendRuntimeToolsToAgentRequest(request3, runtimeTools) {
|
|
|
7329
8094
|
...tool.config ? { config: tool.config } : {}
|
|
7330
8095
|
}));
|
|
7331
8096
|
return {
|
|
7332
|
-
...
|
|
8097
|
+
...request6,
|
|
7333
8098
|
tools: {
|
|
7334
|
-
...
|
|
8099
|
+
...request6.tools,
|
|
7335
8100
|
runtimeTools: [...existing, ...converted]
|
|
7336
8101
|
}
|
|
7337
8102
|
};
|
|
@@ -7407,21 +8172,21 @@ var _AgentsEndpoint = class _AgentsEndpoint {
|
|
|
7407
8172
|
* Attach approved runtime tools to an agent execute request.
|
|
7408
8173
|
* Returns a new request object and does not mutate the original.
|
|
7409
8174
|
*/
|
|
7410
|
-
attachApprovedRuntimeTools(
|
|
7411
|
-
return appendRuntimeToolsToAgentRequest(
|
|
8175
|
+
attachApprovedRuntimeTools(request6, runtimeTools) {
|
|
8176
|
+
return appendRuntimeToolsToAgentRequest(request6, runtimeTools);
|
|
7412
8177
|
}
|
|
7413
8178
|
/**
|
|
7414
8179
|
* Validate a generated runtime tool proposal and append it to an agent execute
|
|
7415
8180
|
* request if approved, in one call.
|
|
7416
8181
|
*/
|
|
7417
|
-
applyGeneratedRuntimeToolProposal(
|
|
8182
|
+
applyGeneratedRuntimeToolProposal(request6, proposal, options) {
|
|
7418
8183
|
const decision = evaluateGeneratedRuntimeToolProposal(proposal, options);
|
|
7419
8184
|
if (!decision.approved || !decision.tool) {
|
|
7420
|
-
return { decision, request:
|
|
8185
|
+
return { decision, request: request6 };
|
|
7421
8186
|
}
|
|
7422
8187
|
return {
|
|
7423
8188
|
decision,
|
|
7424
|
-
request: appendRuntimeToolsToAgentRequest(
|
|
8189
|
+
request: appendRuntimeToolsToAgentRequest(request6, [decision.tool])
|
|
7425
8190
|
};
|
|
7426
8191
|
}
|
|
7427
8192
|
/**
|
|
@@ -10522,6 +11287,29 @@ var BillingEndpoint = class {
|
|
|
10522
11287
|
return this.client.get("/billing/spend-analytics", params);
|
|
10523
11288
|
}
|
|
10524
11289
|
};
|
|
11290
|
+
var ToolApprovalGrantsEndpoint = class {
|
|
11291
|
+
constructor(client) {
|
|
11292
|
+
this.client = client;
|
|
11293
|
+
}
|
|
11294
|
+
/**
|
|
11295
|
+
* List active remembered tool-approval grants for the authenticated owner,
|
|
11296
|
+
* optionally filtered to a single agent.
|
|
11297
|
+
*/
|
|
11298
|
+
async list(agentId) {
|
|
11299
|
+
const query = agentId ? `?agentId=${encodeURIComponent(agentId)}` : "";
|
|
11300
|
+
const response = await this.client.get(
|
|
11301
|
+
`/tool-approval-grants${query}`
|
|
11302
|
+
);
|
|
11303
|
+
return response.data;
|
|
11304
|
+
}
|
|
11305
|
+
/**
|
|
11306
|
+
* Revoke (soft-delete) a remembered grant so the tool prompts for approval
|
|
11307
|
+
* again on future dispatches.
|
|
11308
|
+
*/
|
|
11309
|
+
async revoke(id) {
|
|
11310
|
+
return this.client.delete(`/tool-approval-grants/${id}`);
|
|
11311
|
+
}
|
|
11312
|
+
};
|
|
10525
11313
|
var AppsEndpoint = class {
|
|
10526
11314
|
constructor(client) {
|
|
10527
11315
|
this.client = client;
|
|
@@ -10619,6 +11407,7 @@ var RuntypeClient2 = class {
|
|
|
10619
11407
|
this.flowVersions = new FlowVersionsEndpoint(this);
|
|
10620
11408
|
this.integrations = new IntegrationsEndpoint(this);
|
|
10621
11409
|
this.billing = new BillingEndpoint(this);
|
|
11410
|
+
this.toolApprovalGrants = new ToolApprovalGrantsEndpoint(this);
|
|
10622
11411
|
}
|
|
10623
11412
|
/**
|
|
10624
11413
|
* Set the API key for authentication
|
|
@@ -10657,7 +11446,7 @@ var RuntypeClient2 = class {
|
|
|
10657
11446
|
clearApiKey() {
|
|
10658
11447
|
delete this.headers.Authorization;
|
|
10659
11448
|
}
|
|
10660
|
-
async runWithLocalTools(
|
|
11449
|
+
async runWithLocalTools(request6, localTools, arg3, arg4) {
|
|
10661
11450
|
const isOptionsObject = (val) => typeof val === "object" && val !== null && "scope" in val;
|
|
10662
11451
|
const callbacks = isOptionsObject(arg3) ? void 0 : arg3;
|
|
10663
11452
|
const options = (isOptionsObject(arg3) ? arg3 : arg4) ?? {};
|
|
@@ -10671,12 +11460,12 @@ var RuntypeClient2 = class {
|
|
|
10671
11460
|
...entry.pageOrigin ? { pageOrigin: entry.pageOrigin } : {}
|
|
10672
11461
|
})) : [];
|
|
10673
11462
|
const modifiedRequest = {
|
|
10674
|
-
...
|
|
11463
|
+
...request6,
|
|
10675
11464
|
...derivedClientTools.length > 0 ? {
|
|
10676
|
-
clientTools: [...
|
|
11465
|
+
clientTools: [...request6.clientTools ?? [], ...derivedClientTools]
|
|
10677
11466
|
} : {},
|
|
10678
11467
|
options: {
|
|
10679
|
-
...
|
|
11468
|
+
...request6.options || {},
|
|
10680
11469
|
streamResponse: isStreaming
|
|
10681
11470
|
}
|
|
10682
11471
|
};
|
|
@@ -11114,20 +11903,20 @@ var BatchBuilder = class {
|
|
|
11114
11903
|
if (!this.recordType) {
|
|
11115
11904
|
throw new Error("BatchBuilder: recordType is required. Call .forRecordType(type) first.");
|
|
11116
11905
|
}
|
|
11117
|
-
const
|
|
11906
|
+
const request6 = {
|
|
11118
11907
|
flowId: this.flowId,
|
|
11119
11908
|
recordType: this.recordType
|
|
11120
11909
|
};
|
|
11121
11910
|
if (Object.keys(this.batchOptions).length > 0) {
|
|
11122
|
-
|
|
11911
|
+
request6.options = this.batchOptions;
|
|
11123
11912
|
}
|
|
11124
11913
|
if (this.filterConfig) {
|
|
11125
|
-
|
|
11914
|
+
request6.filter = this.filterConfig;
|
|
11126
11915
|
}
|
|
11127
11916
|
if (this.limitConfig !== void 0) {
|
|
11128
|
-
|
|
11917
|
+
request6.limit = this.limitConfig;
|
|
11129
11918
|
}
|
|
11130
|
-
return
|
|
11919
|
+
return request6;
|
|
11131
11920
|
}
|
|
11132
11921
|
/**
|
|
11133
11922
|
* Execute the batch operation
|
|
@@ -11284,32 +12073,32 @@ var EvalBuilder = class {
|
|
|
11284
12073
|
"EvalBuilder: records are required. Call .forRecordType(type) or .withRecords([...]) first."
|
|
11285
12074
|
);
|
|
11286
12075
|
}
|
|
11287
|
-
const
|
|
12076
|
+
const request6 = {};
|
|
11288
12077
|
if (this.flowId) {
|
|
11289
|
-
|
|
12078
|
+
request6.flowId = this.flowId;
|
|
11290
12079
|
} else if (this.virtualFlow) {
|
|
11291
|
-
|
|
12080
|
+
request6.flow = this.virtualFlow;
|
|
11292
12081
|
}
|
|
11293
12082
|
if (this.recordType) {
|
|
11294
|
-
|
|
12083
|
+
request6.recordType = this.recordType;
|
|
11295
12084
|
} else if (this.inlineRecords) {
|
|
11296
|
-
|
|
12085
|
+
request6.records = this.inlineRecords;
|
|
11297
12086
|
}
|
|
11298
12087
|
if (this.modelOverrides) {
|
|
11299
|
-
|
|
12088
|
+
request6.modelOverrides = this.modelOverrides;
|
|
11300
12089
|
} else if (this.modelConfigs) {
|
|
11301
|
-
|
|
12090
|
+
request6.modelConfigs = this.modelConfigs;
|
|
11302
12091
|
}
|
|
11303
12092
|
if (Object.keys(this.evalOptions).length > 0) {
|
|
11304
|
-
|
|
12093
|
+
request6.options = this.evalOptions;
|
|
11305
12094
|
}
|
|
11306
12095
|
if (this.filterConfig) {
|
|
11307
|
-
|
|
12096
|
+
request6.filter = this.filterConfig;
|
|
11308
12097
|
}
|
|
11309
12098
|
if (this.limitConfig !== void 0) {
|
|
11310
|
-
|
|
12099
|
+
request6.limit = this.limitConfig;
|
|
11311
12100
|
}
|
|
11312
|
-
return
|
|
12101
|
+
return request6;
|
|
11313
12102
|
}
|
|
11314
12103
|
/**
|
|
11315
12104
|
* Execute the evaluation
|
|
@@ -11812,6 +12601,9 @@ export {
|
|
|
11812
12601
|
LEDGER_ARTIFACT_LINE_PREFIX,
|
|
11813
12602
|
LogsEndpoint,
|
|
11814
12603
|
ModelConfigsEndpoint,
|
|
12604
|
+
ProductDriftError,
|
|
12605
|
+
ProductEnsureConflictError,
|
|
12606
|
+
ProductsNamespace,
|
|
11815
12607
|
PromptRunner,
|
|
11816
12608
|
PromptsEndpoint,
|
|
11817
12609
|
PromptsNamespace,
|
|
@@ -11825,9 +12617,15 @@ export {
|
|
|
11825
12617
|
STEP_TYPE_TO_METHOD,
|
|
11826
12618
|
SchedulesEndpoint,
|
|
11827
12619
|
SecretsEndpoint,
|
|
12620
|
+
SkillDriftError,
|
|
12621
|
+
SkillEnsureConflictError,
|
|
11828
12622
|
SkillProposalsNamespace,
|
|
11829
12623
|
SkillsNamespace,
|
|
12624
|
+
SurfaceDriftError,
|
|
12625
|
+
SurfaceEnsureConflictError,
|
|
11830
12626
|
SurfacesEndpoint,
|
|
12627
|
+
SurfacesNamespace,
|
|
12628
|
+
ToolApprovalGrantsEndpoint,
|
|
11831
12629
|
ToolDriftError,
|
|
11832
12630
|
ToolEnsureConflictError,
|
|
11833
12631
|
ToolsEndpoint,
|
|
@@ -11843,6 +12641,9 @@ export {
|
|
|
11843
12641
|
compileWorkflowConfig,
|
|
11844
12642
|
computeAgentContentHash,
|
|
11845
12643
|
computeFlowContentHash,
|
|
12644
|
+
computeProductContentHash,
|
|
12645
|
+
computeSkillContentHash,
|
|
12646
|
+
computeSurfaceContentHash,
|
|
11846
12647
|
computeToolContentHash,
|
|
11847
12648
|
createClient,
|
|
11848
12649
|
createExternalTool,
|
|
@@ -11851,6 +12652,9 @@ export {
|
|
|
11851
12652
|
defineAgent,
|
|
11852
12653
|
defineFlow,
|
|
11853
12654
|
definePlaybook,
|
|
12655
|
+
defineProduct,
|
|
12656
|
+
defineSkill,
|
|
12657
|
+
defineSurface,
|
|
11854
12658
|
defineTool,
|
|
11855
12659
|
deployWorkflow,
|
|
11856
12660
|
ensureDefaultWorkflowHooks,
|
|
@@ -11867,6 +12671,9 @@ export {
|
|
|
11867
12671
|
listWorkflowHooks,
|
|
11868
12672
|
normalizeAgentDefinition,
|
|
11869
12673
|
normalizeCandidatePath,
|
|
12674
|
+
normalizeProductDefinition,
|
|
12675
|
+
normalizeSkillDefinition,
|
|
12676
|
+
normalizeSurfaceDefinition,
|
|
11870
12677
|
normalizeToolDefinition,
|
|
11871
12678
|
parseFinalBuffer,
|
|
11872
12679
|
parseLedgerArtifactRelativePath,
|