@agent-surface/core 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -699,6 +699,15 @@ interface AgentSurfaceSnapshot {
699
699
  truncated?: {
700
700
  droppedComponents: number;
701
701
  };
702
+ /**
703
+ * [Experimental] Present iff a configured scope floor refused part of a
704
+ * requested scope (D27) — set by the adapter, never by `snapshot()`, which
705
+ * has no floor to intersect against. Empty `components` alongside this marker
706
+ * means the request fell outside the floor, not that the surface is empty.
707
+ */
708
+ scopeRejected?: {
709
+ prefixes: string[];
710
+ };
702
711
  }
703
712
  interface AgentComponentDescriptor {
704
713
  type: string;
package/dist/index.js CHANGED
@@ -3226,7 +3226,16 @@ function createAgentToolset(registry, options) {
3226
3226
  description: "[meta] Discover the current agent surface: components, capabilities, procedures, availability, schemas.",
3227
3227
  inputSchema: {
3228
3228
  type: "object",
3229
- properties: { scope: { type: "array", items: { type: "string" } } },
3229
+ properties: {
3230
+ scope: {
3231
+ type: "array",
3232
+ items: { type: "string" },
3233
+ // No enum: valid tokens are live component types, and inlining
3234
+ // them would make this tool block churn on every mount —
3235
+ // the churn AS-META-005 and D28 exist to prevent.
3236
+ description: 'Component-type prefixes to narrow the result, e.g. ["devices.table"], taken from `components[].type` of an earlier call \u2014 omit on the first. Narrows only: prefixes outside this host\'s configured scope match nothing and come back in `scopeRejected`.'
3237
+ }
3238
+ },
3230
3239
  additionalProperties: false
3231
3240
  },
3232
3241
  async execute(input) {
@@ -3237,7 +3246,14 @@ function createAgentToolset(registry, options) {
3237
3246
  ...effective.scope ? { scope: effective.scope } : {},
3238
3247
  ...options.budget ? { budget: options.budget } : {}
3239
3248
  });
3240
- const projected = effective.empty ? { ...snapshot, components: [], procedures: [] } : snapshot;
3249
+ const projected = {
3250
+ ...snapshot,
3251
+ // A disjoint request is snapshotted unscoped, so any `truncated`
3252
+ // count belongs to a surface this payload does not contain. Keeping
3253
+ // it would claim a budget dropped what scope did.
3254
+ ...effective.empty ? { components: [], procedures: [], truncated: void 0 } : {},
3255
+ ...effective.rejected.length > 0 ? { scopeRejected: { prefixes: effective.rejected } } : {}
3256
+ };
3241
3257
  return {
3242
3258
  status: "ok",
3243
3259
  invocationId: `inv_${randomBase62(12)}`,
@@ -3253,8 +3269,14 @@ function createAgentToolset(registry, options) {
3253
3269
  inputSchema: {
3254
3270
  type: "object",
3255
3271
  properties: {
3256
- capabilityId: { type: "string" },
3257
- instanceId: { type: "string" }
3272
+ capabilityId: {
3273
+ type: "string",
3274
+ description: "Observation id, verbatim from `observations[].capabilityId` in a discover result."
3275
+ },
3276
+ instanceId: {
3277
+ type: "string",
3278
+ description: "Only when several components share a type: `components[].instanceId` picks one."
3279
+ }
3258
3280
  },
3259
3281
  required: ["capabilityId"],
3260
3282
  additionalProperties: false
@@ -3283,12 +3305,27 @@ function createAgentToolset(registry, options) {
3283
3305
  inputSchema: {
3284
3306
  type: "object",
3285
3307
  properties: {
3286
- capabilityId: { type: "string" },
3287
- instanceId: { type: "string" },
3288
- input: {},
3289
- invocationId: { type: "string" },
3290
- confirmationId: { type: "string" },
3291
- surfaceVersion: { type: "string" }
3308
+ capabilityId: {
3309
+ type: "string",
3310
+ description: "Action `capabilityId` or `procedureId`, verbatim from a discover result."
3311
+ },
3312
+ instanceId: {
3313
+ type: "string",
3314
+ description: "Only when several components share a type: `components[].instanceId` picks one."
3315
+ },
3316
+ input: { description: "Arguments matching that capability's `inputSchema`." },
3317
+ invocationId: {
3318
+ type: "string",
3319
+ description: "Reuse a previous call's id to retry without executing twice; required when resuming after CONFIRMATION_REQUIRED."
3320
+ },
3321
+ confirmationId: {
3322
+ type: "string",
3323
+ description: "The id returned with CONFIRMATION_REQUIRED, sent back after the user approves."
3324
+ },
3325
+ surfaceVersion: {
3326
+ type: "string",
3327
+ description: "The `surfaceVersion` you planned against. Send it for destructive or externally-visible calls: a surface that moved underneath the plan then fails instead of executing. Omitted, the call binds to what is live now."
3328
+ }
3292
3329
  },
3293
3330
  required: ["capabilityId"],
3294
3331
  additionalProperties: false
@@ -3379,17 +3416,25 @@ function createAgentToolset(registry, options) {
3379
3416
  function intersectScope(floor, requested) {
3380
3417
  const hasFloor = floor !== void 0 && floor.length > 0;
3381
3418
  if (requested === void 0 || requested.length === 0) {
3382
- return hasFloor ? { scope: floor, empty: false } : { empty: false };
3419
+ return hasFloor ? { scope: floor, empty: false, rejected: [] } : { empty: false, rejected: [] };
3383
3420
  }
3384
- if (!hasFloor) return { scope: requested, empty: false };
3421
+ if (!hasFloor) return { scope: requested, empty: false, rejected: [] };
3385
3422
  const out = /* @__PURE__ */ new Set();
3386
- for (const f of floor) {
3387
- for (const r of requested) {
3388
- if (r === f || r.startsWith(`${f}.`)) out.add(r);
3389
- else if (f.startsWith(`${r}.`)) out.add(f);
3423
+ const rejected = [];
3424
+ for (const r of requested) {
3425
+ let admitted = false;
3426
+ for (const f of floor) {
3427
+ if (r === f || r.startsWith(`${f}.`)) {
3428
+ out.add(r);
3429
+ admitted = true;
3430
+ } else if (f.startsWith(`${r}.`)) {
3431
+ out.add(f);
3432
+ admitted = true;
3433
+ }
3390
3434
  }
3435
+ if (!admitted && !rejected.includes(r)) rejected.push(r);
3391
3436
  }
3392
- return out.size > 0 ? { scope: [...out], empty: false } : { empty: true };
3437
+ return out.size > 0 ? { scope: [...out], empty: false, rejected } : { empty: true, rejected };
3393
3438
  }
3394
3439
  function findRegistrationId(snapshot, capabilityId, instanceId) {
3395
3440
  const matches = [];