@topolo/sdk 0.10.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -44,6 +44,10 @@ __export(index_exports, {
44
44
  auditAllApplicationRequirements: () => auditAllApplicationRequirements,
45
45
  auditApplicationEntries: () => auditApplicationEntries,
46
46
  auditApplicationRequirements: () => auditApplicationRequirements,
47
+ compactActionCatalogEntry: () => compactActionCatalogEntry,
48
+ compactActionPlan: () => compactActionPlan,
49
+ compactActionValidation: () => compactActionValidation,
50
+ compactApplicationAudit: () => compactApplicationAudit,
47
51
  createTopolo: () => createTopolo,
48
52
  createTopoloWidgetError: () => createTopoloWidgetError,
49
53
  createTopoloWidgetResponse: () => createTopoloWidgetResponse,
@@ -3999,6 +4003,54 @@ function mergeSignals(a, b) {
3999
4003
  return controller.signal;
4000
4004
  }
4001
4005
 
4006
+ // src/agent-output.ts
4007
+ function compactActionCatalogEntry(action) {
4008
+ const required = Array.isArray(action.inputSchema["required"]) ? action.inputSchema["required"].filter((value) => typeof value === "string") : [];
4009
+ const examples = action.agentContract?.examples ?? [];
4010
+ return {
4011
+ actionId: action.actionId,
4012
+ title: action.title,
4013
+ description: action.description,
4014
+ method: action.method,
4015
+ readOnly: action.readOnly,
4016
+ requiresConfirmation: action.requiresConfirmation,
4017
+ agentAccess: action.agentAccess ?? (action.requiresConfirmation ? "confirm" : action.readOnly ? "auto" : "confirm"),
4018
+ requiredPermission: action.requiredPermission,
4019
+ requiredInput: required,
4020
+ resourceType: action.agentContract?.resource?.kind ?? null,
4021
+ exampleInput: examples[0]?.input ?? null,
4022
+ docsUrl: action.agentContract?.docsUrl ?? null
4023
+ };
4024
+ }
4025
+ function compactActionValidation(actionId, validation) {
4026
+ return { actionId, valid: validation.valid, errors: validation.errors };
4027
+ }
4028
+ function compactActionPlan(plan) {
4029
+ return {
4030
+ actionId: plan.action.actionId,
4031
+ valid: plan.validation.valid,
4032
+ errors: plan.validation.errors,
4033
+ executable: plan.executable,
4034
+ confirmationRequired: plan.confirmationRequired,
4035
+ confirmationProvided: plan.confirmationProvided,
4036
+ request: plan.request,
4037
+ verification: plan.verification,
4038
+ rollbackActionId: plan.rollbackActionId,
4039
+ nextActionIds: plan.nextActionIds
4040
+ };
4041
+ }
4042
+ function compactApplicationAudit(report) {
4043
+ return {
4044
+ version: report.version,
4045
+ applications: report.applications.map((audit) => ({
4046
+ applicationId: audit.application.id,
4047
+ applicationName: audit.application.name,
4048
+ score: audit.score
4049
+ })),
4050
+ migrationQueueCount: report.migrationQueue.length
4051
+ };
4052
+ }
4053
+
4002
4054
  // src/action-catalog-digest.ts
4003
4055
  var ACTION_CATALOG_DIGEST_ALGORITHM = "sha256-v1";
4004
4056
  function canonicalPermission(value, appId) {
@@ -4212,25 +4264,90 @@ function derivedOutputSchema(action) {
4212
4264
  ...provenance
4213
4265
  };
4214
4266
  }
4215
- function sampleForSchema(schema, depth = 0) {
4216
- if (!isRecord4(schema) || depth > 5) return null;
4267
+ function patternedString(pattern, hint) {
4268
+ const candidates = [
4269
+ hint.toLowerCase().includes("email") ? "agent@topolo.app" : null,
4270
+ hint.toLowerCase().includes("url") || hint.toLowerCase().includes("uri") ? "https://topolo.app" : null,
4271
+ hint.toLowerCase().includes("app") && hint.toLowerCase().includes("id") ? "app_topolo_example" : null,
4272
+ hint.toLowerCase().includes("file") ? "sample.ply" : null,
4273
+ hint.toLowerCase().includes("slug") ? "/sample" : null,
4274
+ hint.toLowerCase().includes("year") ? "2026" : null,
4275
+ hint.toLowerCase().includes("date") || hint.toLowerCase().endsWith("at") ? "2026-01-15T12:00:00Z" : null,
4276
+ hint.toLowerCase().includes("period") || hint.toLowerCase().includes("month") ? "2026-01" : null,
4277
+ hint.toLowerCase().includes("event") || hint.toLowerCase().includes("type") ? "resource.created" : null,
4278
+ "app_topolo_example",
4279
+ "2026-01-15T12:00:00Z",
4280
+ "sample.ply",
4281
+ "/sample",
4282
+ "2026-01-15",
4283
+ "2026-01",
4284
+ "2026",
4285
+ "resource.created",
4286
+ "sample-value",
4287
+ "sample_value",
4288
+ "sample"
4289
+ ].filter(Boolean);
4290
+ try {
4291
+ const expression = new RegExp(pattern);
4292
+ return candidates.find((candidate) => expression.test(candidate)) ?? "sample";
4293
+ } catch {
4294
+ return "sample";
4295
+ }
4296
+ }
4297
+ function sampleString(schema, hint) {
4298
+ if (schema.format === "email") return "agent@topolo.app";
4299
+ if (schema.format === "uri" || schema.format === "url") return "https://topolo.app";
4300
+ if (schema.format === "date-time") return patternedString(schema.pattern || "", hint) || "2026-01-15T12:00:00Z";
4301
+ const words = String(hint || "value").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").toLowerCase();
4302
+ let value = typeof schema.pattern === "string" ? patternedString(schema.pattern, hint) : /(^|\s)id$/.test(words) ? `${slugify(words.replace(/\sid$/, "") || "resource")}_01` : words.includes("date") ? "2026-01-15" : words.includes("period") || words.includes("month") ? "2026-01" : words.includes("year") ? "2026" : `Sample ${words}`;
4303
+ const minimum = Number.isInteger(schema.minLength) ? schema.minLength : 0;
4304
+ const maximum = Number.isInteger(schema.maxLength) ? schema.maxLength : null;
4305
+ if (value.length < minimum) value = value.padEnd(minimum, "x");
4306
+ if (maximum !== null && value.length > maximum) value = value.slice(0, maximum);
4307
+ return value;
4308
+ }
4309
+ function localReference(rootSchema, reference) {
4310
+ if (!isRecord4(rootSchema) || typeof reference !== "string" || !reference.startsWith("#/")) return null;
4311
+ return reference.slice(2).split("/").reduce((value, segment) => {
4312
+ const key = segment.replaceAll("~1", "/").replaceAll("~0", "~");
4313
+ return isRecord4(value) ? value[key] : void 0;
4314
+ }, rootSchema);
4315
+ }
4316
+ function sampleForSchema(schema, depth = 0, hint = "value", rootSchema = schema) {
4317
+ if (!isRecord4(schema) || depth > 20) return null;
4318
+ const referenced = localReference(rootSchema, schema.$ref);
4319
+ if (isRecord4(referenced)) return sampleForSchema(referenced, depth + 1, hint, rootSchema);
4217
4320
  if (schema.const !== void 0) return schema.const;
4218
4321
  if (Array.isArray(schema.enum) && schema.enum.length > 0) return schema.enum[0];
4219
- if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0) return sampleForSchema(schema.oneOf[0], depth + 1);
4220
- if (Array.isArray(schema.anyOf) && schema.anyOf.length > 0) return sampleForSchema(schema.anyOf[0], depth + 1);
4221
- if (schema.type === "array") return [];
4322
+ if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0) return sampleForSchema(schema.oneOf[0], depth + 1, hint, rootSchema);
4323
+ if (Array.isArray(schema.anyOf) && schema.anyOf.length > 0) return sampleForSchema(schema.anyOf[0], depth + 1, hint, rootSchema);
4324
+ if (Array.isArray(schema.type)) {
4325
+ return sampleForSchema({ ...schema, type: schema.type.find((type) => type !== "null") ?? schema.type[0] }, depth + 1, hint, rootSchema);
4326
+ }
4327
+ if (schema.type === "array") {
4328
+ const minimum = Number.isInteger(schema.minItems) ? schema.minItems : 0;
4329
+ const maximum = Number.isInteger(schema.maxItems) ? schema.maxItems : null;
4330
+ const count = maximum === 0 ? 0 : minimum > 0 ? minimum : depth >= 4 ? 0 : 1;
4331
+ return Array.from({ length: count }, () => sampleForSchema(schema.items, depth + 1, singularize(hint), rootSchema));
4332
+ }
4222
4333
  if (schema.type === "boolean") return false;
4223
- if (schema.type === "integer" || schema.type === "number") return schema.minimum ?? 0;
4224
- if (schema.type === "string") {
4225
- if (schema.format === "email") return "agent@example.com";
4226
- if (schema.format === "uri" || schema.format === "url") return "https://example.com";
4227
- return schema.minLength > 1 ? "example".padEnd(schema.minLength, "x") : "example";
4334
+ if (schema.type === "integer" || schema.type === "number") {
4335
+ let value = typeof schema.minimum === "number" ? schema.minimum : 0;
4336
+ if (typeof schema.exclusiveMinimum === "number" && value <= schema.exclusiveMinimum) {
4337
+ value = schema.type === "integer" ? Math.floor(schema.exclusiveMinimum) + 1 : schema.exclusiveMinimum + 0.1;
4338
+ }
4339
+ if (typeof schema.maximum === "number") value = Math.min(value, schema.maximum);
4340
+ if (typeof schema.exclusiveMaximum === "number" && value >= schema.exclusiveMaximum) {
4341
+ value = schema.type === "integer" ? Math.ceil(schema.exclusiveMaximum) - 1 : schema.exclusiveMaximum - 0.1;
4342
+ }
4343
+ return value;
4228
4344
  }
4345
+ if (schema.type === "string") return sampleString(schema, hint);
4229
4346
  if (schema.type === "null") return null;
4230
4347
  if (schema.type === "object" || isRecord4(schema.properties)) {
4231
4348
  const properties = isRecord4(schema.properties) ? schema.properties : {};
4232
4349
  const required = new Set(Array.isArray(schema.required) ? schema.required : []);
4233
- const entries = Object.entries(properties).filter(([key]) => required.has(key)).map(([key, child]) => [key, sampleForSchema(child, depth + 1)]);
4350
+ const entries = Object.entries(properties).filter(([key]) => required.has(key)).map(([key, child]) => [key, sampleForSchema(child, depth + 1, key, rootSchema)]);
4234
4351
  return Object.fromEntries(entries);
4235
4352
  }
4236
4353
  return null;
@@ -4306,7 +4423,11 @@ function enrichActionContract(manifest, action, allActions = manifest.actions ||
4306
4423
  const recovery = isRecord4(existing.recovery) ? existing.recovery : recoveryFor(action, allActions, appId);
4307
4424
  const rollbackActionId = typeof existing.rollbackActionId === "string" && existing.rollbackActionId.trim() ? existing.rollbackActionId.trim() : recovery.mode === "compensating_action" ? recovery.actionId : void 0;
4308
4425
  const inputExample = sampleForSchema(action.inputSchema);
4309
- const examples = Array.isArray(existing.examples) && existing.examples.length > 0 ? existing.examples : [{ input: inputExample ?? {}, expected: `A response matching the published outputSchema for ${action.name}.` }];
4426
+ const expectedExample = readOnly ? `A successful response conforming to outputSchema; verify the returned ${resource.replaceAll("_", " ")} belongs to the selected resource context.` : `A successful response conforming to outputSchema; re-read the affected ${resource.replaceAll("_", " ")} to verify the intended change.`;
4427
+ const examples = Array.isArray(existing.examples) && existing.examples.length > 0 ? existing.examples.map((example) => isRecord4(example) && Object.hasOwn(example, "input") ? { ...example, expected: typeof example.expected === "string" && example.expected.trim() ? example.expected : expectedExample } : { input: example, expected: expectedExample }) : [{
4428
+ input: inputExample ?? {},
4429
+ expected: expectedExample
4430
+ }];
4310
4431
  const docsUrl = `https://docs.topolo.app/reference/actions?service=${encodeURIComponent(service)}&action=${encodeURIComponent(action.name)}`;
4311
4432
  const existingDocsUrl = typeof existing.docsUrl === "string" && existing.docsUrl.trim() ? existing.docsUrl.trim() : void 0;
4312
4433
  return {
@@ -4952,6 +5073,10 @@ function createTopolo(options) {
4952
5073
  auditAllApplicationRequirements,
4953
5074
  auditApplicationEntries,
4954
5075
  auditApplicationRequirements,
5076
+ compactActionCatalogEntry,
5077
+ compactActionPlan,
5078
+ compactActionValidation,
5079
+ compactApplicationAudit,
4955
5080
  createTopolo,
4956
5081
  createTopoloWidgetError,
4957
5082
  createTopoloWidgetResponse,