@agent-surface/core 0.1.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.
@@ -0,0 +1,796 @@
1
+ /** JSON value constraint: every agent-crossing payload MUST be a JsonValue. */
2
+ type JsonValue = string | number | boolean | null | JsonValue[] | {
3
+ [key: string]: JsonValue;
4
+ };
5
+ /** A JSON Schema document restricted to the supported subset (docs/03 D19). */
6
+ type JsonSchema = Record<string, unknown>;
7
+ type AgentEnvironment = "development" | "production" | "test";
8
+ type AgentEffect = "read" | "local-state" | "navigation" | "server-query" | "server-mutation" | "external-side-effect" | "destructive";
9
+ type AgentProcedureEffect = "server-query" | "server-mutation" | "external-side-effect" | "destructive";
10
+ interface AgentConsumer {
11
+ id: string;
12
+ kind: "embedded" | "webmcp" | "mcp-bridge" | "test" | "other";
13
+ /** Free-form grant strings interpreted by host policies. */
14
+ grants?: string[];
15
+ }
16
+ interface AgentRouteInfo {
17
+ path: string;
18
+ params?: Record<string, string>;
19
+ }
20
+ interface AgentSurfaceLimits {
21
+ maxComponentDescription: number;
22
+ maxCapabilityDescription: number;
23
+ maxMetaBytes: number;
24
+ maxOutputBytes: number;
25
+ maxSchemaBytes: number;
26
+ maxSchemaDepth: number;
27
+ observationTimeoutMs: number;
28
+ actionTimeoutMs: number;
29
+ procedureTimeoutMs: number;
30
+ actionQueueDepth: number;
31
+ maxConcurrentObservationsPerConsumer: number;
32
+ maxConcurrentObservationsTotal: number;
33
+ maxQueuedObservationsPerConsumer: number;
34
+ dedupeCacheSize: number;
35
+ dedupeCacheTtlMs: number;
36
+ tombstoneSize: number;
37
+ tombstoneTtlMs: number;
38
+ confirmationTtlMs: number;
39
+ maxPendingConfirmations: number;
40
+ }
41
+ declare const DEFAULT_LIMITS: AgentSurfaceLimits;
42
+ type Unsubscribe = () => void;
43
+
44
+ /** The closed agent-facing error enum — one runtime source, cross-validated
45
+ * against spec/error-matrix.json (docs/07 §principles, AS-ERR-001). */
46
+ declare const AGENT_CAPABILITY_ERROR_CODES: readonly ["CAPABILITY_NOT_FOUND", "CAPABILITY_NOT_AVAILABLE", "AMBIGUOUS_INSTANCE", "COMPONENT_UNMOUNTED", "STALE_CAPABILITY", "INVOCATION_CONFLICT", "INVALID_INPUT", "NOT_AUTHENTICATED", "NOT_AUTHORIZED", "PRECONDITION_FAILED", "CONFIRMATION_REQUIRED", "CONFIRMATION_INVALID", "RATE_LIMITED", "TIMEOUT", "CANCELLED", "EXECUTION_FAILED"];
47
+ type AgentCapabilityErrorCode = (typeof AGENT_CAPABILITY_ERROR_CODES)[number];
48
+ type AgentErrorRetry = "no" | "yes" | "after-refresh" | "after-delay" | "with-confirmation" | "with-changes";
49
+ interface AgentCapabilityErrorPayload {
50
+ code: AgentCapabilityErrorCode;
51
+ /** Agent-safe, imperative, ≤ 300 chars. */
52
+ message: string;
53
+ retry: AgentErrorRetry;
54
+ /** Code-specific, agent-safe, JsonValue only. */
55
+ details?: Record<string, JsonValue>;
56
+ }
57
+ /** Thrown form used inside policies/handlers; serialized at the boundary. */
58
+ declare class AgentSurfaceError extends Error {
59
+ readonly payload: AgentCapabilityErrorPayload;
60
+ constructor(payload: AgentCapabilityErrorPayload, opts?: {
61
+ cause?: unknown;
62
+ });
63
+ }
64
+ declare function isAgentSurfaceError(e: unknown): e is AgentSurfaceError;
65
+ type AgentSurfaceDefinitionErrorCode = "INVALID_ID" | "INVALID_DEFINITION" | "UNSUPPORTED_SCHEMA" | "PLANE_VIOLATION" | "DUPLICATE_CAPABILITY" | "LIMIT_EXCEEDED";
66
+ /** Structural defects at registration time. Always thrown, never agent-facing. */
67
+ declare class AgentSurfaceDefinitionError extends Error {
68
+ readonly code: AgentSurfaceDefinitionErrorCode;
69
+ constructor(code: AgentSurfaceDefinitionErrorCode, message: string);
70
+ }
71
+
72
+ /**
73
+ * Canonical ID grammar (docs/01 §identity):
74
+ *
75
+ * capability-id = plane ":" component-type "." capability-name
76
+ * plane = "view" | "domain"
77
+ * component-type = segment *( "." segment )
78
+ * segment = lowercase-letter *( lowercase-letter / digit / "-" )
79
+ * capability-name = lowercase-letter *( letter / digit ) ; camelCase, no dots
80
+ * instance-id = 1*( letter / digit / "-" / "_" )
81
+ *
82
+ * Underscores are reserved for the wire-name encoding (docs/09).
83
+ */
84
+ declare const MAX_ID_LENGTH = 128;
85
+ type AgentPlane = "view" | "domain";
86
+ declare function isValidComponentType(type: string): boolean;
87
+ declare function isValidCapabilityName(name: string): boolean;
88
+ declare function isValidInstanceId(id: string): boolean;
89
+ declare function formatViewCapabilityId(componentType: string, name: string): string;
90
+ declare function formatDomainCapabilityId(path: string): string;
91
+ interface ParsedViewCapabilityId {
92
+ plane: "view";
93
+ componentType: string;
94
+ name: string;
95
+ }
96
+ interface ParsedDomainCapabilityId {
97
+ plane: "domain";
98
+ /** Canonical oRPC procedure path — treated as opaque (docs/01). */
99
+ path: string;
100
+ }
101
+ type ParsedCapabilityId = ParsedViewCapabilityId | ParsedDomainCapabilityId;
102
+ /** Parses a capability id; returns undefined when the grammar is violated. */
103
+ declare function parseCapabilityId(id: string): ParsedCapabilityId | undefined;
104
+ declare const MAX_WIRE_NAME_LENGTH = 64;
105
+ declare function encodeWireName(id: string): string;
106
+ /**
107
+ * Wire name disambiguated per instance: providers require UNIQUE tool names,
108
+ * so when several live instances expose the same capability the adapter
109
+ * appends `_at_<instanceId>` (docs/09 rule 7 — the id↔name map stays
110
+ * authoritative; instance ids never contain "." so decoding stays possible
111
+ * by stripping the suffix).
112
+ */
113
+ declare function encodeWireNameForInstance(id: string, instanceId?: string): string;
114
+ /**
115
+ * Reverses `encodeWireName` for non-truncated names. Truncated names cannot
116
+ * be decoded — the adapter's id↔name map is authoritative (docs/09 rule 7).
117
+ */
118
+ declare function decodeWireName(name: string): string | undefined;
119
+
120
+ interface AgentSchemaIssue {
121
+ path: string;
122
+ message: string;
123
+ }
124
+ /** Thrown by AgentSchema.parse on invalid input; carries safe, structured issues. */
125
+ declare class AgentSchemaError extends Error {
126
+ readonly issues: AgentSchemaIssue[];
127
+ constructor(issues: AgentSchemaIssue[]);
128
+ }
129
+ interface AgentSchema<T> {
130
+ /** Agent-visible JSON Schema (draft 2020-12, restricted subset). */
131
+ readonly jsonSchema: JsonSchema;
132
+ /**
133
+ * Validates and returns a typed value. MUST throw `AgentSchemaError`
134
+ * (with a safe, structured message) on invalid input.
135
+ */
136
+ parse(value: unknown): T;
137
+ }
138
+ /** Minimal Standard Schema mirror (https://standardschema.dev). */
139
+ interface StandardSchemaV1<I = unknown, O = I> {
140
+ readonly "~standard": {
141
+ readonly version: 1;
142
+ readonly vendor: string;
143
+ validate(value: unknown): {
144
+ value: O;
145
+ issues?: undefined;
146
+ } | {
147
+ issues: ReadonlyArray<{
148
+ message: string;
149
+ path?: ReadonlyArray<PropertyKey | {
150
+ key: PropertyKey;
151
+ }>;
152
+ }>;
153
+ } | Promise<unknown>;
154
+ readonly types?: {
155
+ readonly input: I;
156
+ readonly output: O;
157
+ } | undefined;
158
+ };
159
+ }
160
+ /**
161
+ * Wraps any Standard Schema (Zod ≥3.24, Valibot, ArkType) as an AgentSchema.
162
+ * The JSON Schema MUST be supplied explicitly — core does not depend on a
163
+ * converter (docs/03, D20).
164
+ */
165
+ declare function fromStandardSchema<T>(schema: StandardSchemaV1<unknown, T>, options: {
166
+ jsonSchema: JsonSchema;
167
+ }): AgentSchema<T>;
168
+ /**
169
+ * Builds an AgentSchema from a raw JSON Schema, validated by the built-in
170
+ * minimal structural validator covering exactly the supported subset.
171
+ */
172
+ declare function fromJsonSchema<T = JsonValue>(schema: JsonSchema): AgentSchema<T>;
173
+ /** Convenience for actions with no input / observations of constant shape. */
174
+ declare const emptyObjectSchema: AgentSchema<Record<string, never>>;
175
+ interface SchemaSubsetResult {
176
+ ok: boolean;
177
+ reason?: string;
178
+ }
179
+ /**
180
+ * Validates that a JSON Schema document stays inside the D19 subset.
181
+ * Anything outside MUST be rejected at registration with INVALID_DEFINITION /
182
+ * UNSUPPORTED_SCHEMA (docs/03, docs/07).
183
+ */
184
+ declare function validateJsonSchemaDocument(schema: JsonSchema, limits: {
185
+ maxSchemaBytes: number;
186
+ maxSchemaDepth: number;
187
+ }): SchemaSubsetResult;
188
+ /**
189
+ * Validates a value against a subset schema. Returns issues (empty = valid).
190
+ * JSON Schema semantics: `default` is annotation-only and never applied.
191
+ */
192
+ declare function validateValueAgainstSchema(value: unknown, schema: unknown, root: JsonSchema, path: string): AgentSchemaIssue[];
193
+
194
+ interface AgentInvocation {
195
+ /** Idempotency key. Adapters SHOULD pass their tool-call id. Generated if absent. */
196
+ invocationId?: string;
197
+ capabilityId: string;
198
+ /** Required when >1 live instance of the target component exists. */
199
+ instanceId?: string;
200
+ /** Staleness token from discovery. Adapters SHOULD always send it. */
201
+ registrationId?: string;
202
+ /** Version hint; enforced only for destructive/external effects. */
203
+ surfaceVersion?: string;
204
+ input?: JsonValue;
205
+ /** Evidence from a resolved confirmation (docs/06). */
206
+ confirmationId?: string;
207
+ }
208
+ interface InvokeOptions {
209
+ consumer?: AgentConsumer;
210
+ signal?: AbortSignal;
211
+ timeoutMs?: number;
212
+ }
213
+ type AgentInvocationResult = {
214
+ status: "ok";
215
+ invocationId: string;
216
+ capabilityId: string;
217
+ output?: JsonValue;
218
+ surfaceVersion: string;
219
+ /** Set when the surface changed during execution. */
220
+ surfaceChanged?: boolean;
221
+ } | {
222
+ status: "error";
223
+ invocationId: string;
224
+ capabilityId: string;
225
+ error: AgentCapabilityErrorPayload;
226
+ surfaceVersion: string;
227
+ surfaceChanged?: boolean;
228
+ };
229
+
230
+ interface AuditEvent {
231
+ at: string;
232
+ type: "registration" | "unregistration" | "registration-rejected" | "invocation-started" | "invocation-settled" | "confirmation-requested" | "confirmation-approved" | "confirmation-denied" | "confirmation-expired" | "confirmation-consumed" | "late-settlement" | "collision-suspected";
233
+ capabilityId?: string;
234
+ registrationId?: string;
235
+ invocationId?: string;
236
+ consumerId?: string;
237
+ status?: "ok" | "error";
238
+ code?: AgentCapabilityErrorCode;
239
+ durationMs?: number;
240
+ /** Time spent waiting for a concurrency slot (docs/06 §audit; distinct
241
+ * from execution — §7.1 observability). Settled invocations only. */
242
+ queueWaitMs?: number;
243
+ /** Time spent inside the handler/executor guards, excluding queue wait. */
244
+ executionMs?: number;
245
+ /** Present only for capabilities with audit: "full"; size-capped. */
246
+ payload?: {
247
+ input?: JsonValue;
248
+ output?: JsonValue;
249
+ };
250
+ }
251
+ interface AuditSink {
252
+ /** MUST NOT throw; MUST be non-blocking. */
253
+ record(event: AuditEvent): void;
254
+ }
255
+ declare function memoryAuditSink(opts?: {
256
+ capacity?: number;
257
+ }): AuditSink & {
258
+ events(): AuditEvent[];
259
+ };
260
+ declare function consoleAuditSink(): AuditSink;
261
+
262
+ type DiscoveryDecision = {
263
+ decision: "expose";
264
+ } | {
265
+ decision: "disable";
266
+ reason: string;
267
+ } | {
268
+ decision: "hide";
269
+ };
270
+ interface AgentPolicyContext {
271
+ capabilityId: string;
272
+ plane: "view" | "domain";
273
+ kind: "observation" | "action" | "procedure";
274
+ effect: AgentEffect;
275
+ registrationId: string;
276
+ consumer: AgentConsumer;
277
+ host: Readonly<Record<string, unknown>>;
278
+ meta: {
279
+ component?: Record<string, JsonValue>;
280
+ capability?: Record<string, JsonValue>;
281
+ };
282
+ internal: Readonly<Record<string, unknown>>;
283
+ /** Registry environment (additive convenience for built-ins). */
284
+ environment: AgentEnvironment;
285
+ /** Registry's injectable clock — built-ins MUST use this, never Date.now(). */
286
+ now(): number;
287
+ }
288
+ /** Phase-4 context: no agent input is available here, by construction (D21). */
289
+ type AgentAuthorizationContext = AgentPolicyContext;
290
+ /** Phase-6 context: only the validated effective input is visible (D21). */
291
+ interface AgentInvocationPolicyContext extends AgentAuthorizationContext {
292
+ invocationId: string;
293
+ effectiveInput: JsonValue;
294
+ }
295
+ interface AgentPolicy {
296
+ name: string;
297
+ /**
298
+ * Discovery-time filter. MUST be synchronous, cheap, side-effect free.
299
+ * Advisory: hides/disables in catalogs. Default when absent: expose.
300
+ */
301
+ onDiscovery?(ctx: AgentPolicyContext): DiscoveryDecision;
302
+ /**
303
+ * Pre-input authority gate (pipeline phase 4): authn/authz/tenant/
304
+ * environment/input-independent rate. MAY be async. Onion order; call
305
+ * next() to proceed. Throw AgentSurfaceError to deny.
306
+ */
307
+ onAuthorize?(ctx: AgentAuthorizationContext, next: () => Promise<AgentInvocationResult>): Promise<AgentInvocationResult>;
308
+ /**
309
+ * Post-input invocation gate (pipeline phase 6). Receives ONLY the
310
+ * validated effective input — never raw agent input (D21).
311
+ */
312
+ onInvoke?(ctx: AgentInvocationPolicyContext, next: () => Promise<AgentInvocationResult>): Promise<AgentInvocationResult>;
313
+ }
314
+ /**
315
+ * Marker read by the invocation pipeline: policies carrying it escalate the
316
+ * capability's confirmation requirement (docs/06 requireConfirmation).
317
+ */
318
+ declare const CONFIRMATION_ESCALATION: unique symbol;
319
+ interface ConfirmationEscalation {
320
+ /** Evaluated at phase 6 over the validated effective input (D21). */
321
+ if?: (ctx: AgentPolicyContext & {
322
+ effectiveInput: JsonValue;
323
+ }) => boolean;
324
+ summary?: (effectiveInput: JsonValue) => string;
325
+ }
326
+ /** Most-restrictive-wins composition of discovery decisions (docs/06). */
327
+ declare function evaluateDiscovery(policies: ReadonlyArray<AgentPolicy>, ctx: AgentPolicyContext): DiscoveryDecision;
328
+ /** Onion composition of onInvoke handlers (registry outermost, phase 6). */
329
+ declare function composeInvokeChain(policies: ReadonlyArray<AgentPolicy>, ctx: AgentInvocationPolicyContext, core: () => Promise<AgentInvocationResult>): Promise<AgentInvocationResult>;
330
+ /** Requires ctx.host[key] (default "user"). Fails NOT_AUTHENTICATED; hides. */
331
+ declare function authenticated(opts?: {
332
+ key?: string;
333
+ }): AgentPolicy;
334
+ /** Delegates to a host authorizer. Fails NOT_AUTHORIZED; hides at discovery. */
335
+ declare function hasPermission(permission: string, check: (host: Record<string, unknown>, permission: string) => boolean): AgentPolicy;
336
+ /** Tenant boundary: hides unless current(host) === expected(ctx). */
337
+ declare function tenantBoundary(opts: {
338
+ current: (host: Record<string, unknown>) => string | undefined;
339
+ expected: (ctx: AgentPolicyContext) => string | undefined;
340
+ }): AgentPolicy;
341
+ /** Restricts to environments. Others: hidden. */
342
+ declare function environment(allowed: AgentEnvironment[]): AgentPolicy;
343
+ /**
344
+ * Token bucket per (consumer, capability). Advisory, input-independent —
345
+ * runs pre-input (phase 4). Author input-aware rate policies as onInvoke.
346
+ * Fails RATE_LIMITED. Uses the injectable clock (AS-POLICY-001).
347
+ */
348
+ declare function rateLimit(opts: {
349
+ limit: number;
350
+ windowMs: number;
351
+ }): AgentPolicy;
352
+ /** Escalates confirmation to "required" (optionally conditionally).
353
+ * Predicates run at phase 6 over the validated effective input (D21). */
354
+ declare function requireConfirmation(opts?: {
355
+ if?: (ctx: AgentPolicyContext & {
356
+ effectiveInput: JsonValue;
357
+ }) => boolean;
358
+ summary?: (effectiveInput: JsonValue) => string;
359
+ }): AgentPolicy;
360
+ /** Forwards invocation events to a sink at the given detail level.
361
+ * Runs at phase 6 (onInvoke): its enrichment sees the effective input. */
362
+ declare function audit(sink?: AuditSink, level?: "metadata" | "full"): AgentPolicy;
363
+
364
+ interface AgentReadContext {
365
+ capabilityId: string;
366
+ registrationId: string;
367
+ consumer: AgentConsumer;
368
+ /** Host context (user, tenant, env…) from RegistryOptions.context(). */
369
+ host: Readonly<Record<string, unknown>>;
370
+ }
371
+ interface AgentActionContext extends AgentReadContext {
372
+ invocationId: string;
373
+ /** Aborted on timeout, external cancellation, or unmount. Cooperative. */
374
+ signal: AbortSignal;
375
+ /** Present iff this invocation carries approved confirmation evidence. */
376
+ confirmation?: {
377
+ id: string;
378
+ approvedAt: string;
379
+ };
380
+ }
381
+ interface PreconditionFailure {
382
+ message: string;
383
+ details?: Record<string, JsonValue>;
384
+ }
385
+ interface AgentObservationDefinition<TOut extends JsonValue> {
386
+ /** Agent-visible description, ≤ 300 chars. */
387
+ description: string;
388
+ output: AgentSchema<TOut>;
389
+ /**
390
+ * Reads current semantic state. MUST be side-effect free. SHOULD be
391
+ * synchronous; MAY return a promise (subject to observation timeout).
392
+ */
393
+ read(ctx: AgentReadContext): TOut | Promise<TOut>;
394
+ /** Availability predicate, re-evaluated at snapshot and at invocation. */
395
+ when?: () => boolean;
396
+ unavailableReason?: string | (() => string);
397
+ policies?: AgentPolicy[];
398
+ meta?: Record<string, JsonValue>;
399
+ timeoutMs?: number;
400
+ }
401
+ interface AgentActionDefinition<TIn extends JsonValue, TOut extends JsonValue | void = void> {
402
+ description: string;
403
+ input: AgentSchema<TIn>;
404
+ output?: AgentSchema<Exclude<TOut, void>>;
405
+ /** View actions MUST be "local-state" | "navigation" (plane rule, docs/01). */
406
+ effect: "local-state" | "navigation";
407
+ idempotent?: boolean;
408
+ reversible?: boolean;
409
+ confirmation?: "never" | "optional" | "required";
410
+ audit?: "none" | "metadata" | "full";
411
+ when?: () => boolean;
412
+ unavailableReason?: string | (() => string);
413
+ /**
414
+ * Input-aware validation beyond the schema. Return void to pass; return
415
+ * (or throw) a PreconditionFailure to fail with PRECONDITION_FAILED.
416
+ */
417
+ precondition?(input: TIn, ctx: AgentReadContext): void | PreconditionFailure;
418
+ /**
419
+ * TOut is inferred from `output` only (NoInfer): the schema is the source
420
+ * of truth and the handler's return is checked against it.
421
+ */
422
+ execute(input: TIn, ctx: AgentActionContext): NoInfer<TOut> | Promise<NoInfer<TOut>>;
423
+ policies?: AgentPolicy[];
424
+ meta?: Record<string, JsonValue>;
425
+ timeoutMs?: number;
426
+ }
427
+ /** Identity helpers that fix generics for record-literal authoring. */
428
+ declare function observation<TOut extends JsonValue>(def: AgentObservationDefinition<TOut>): AgentObservationDefinition<TOut>;
429
+ declare function action<TIn extends JsonValue, TOut extends JsonValue | void = void>(def: AgentActionDefinition<TIn, TOut>): AgentActionDefinition<TIn, TOut>;
430
+ declare function defineAgentComponent(def: AgentComponentDefinition): AgentComponentDefinition;
431
+ interface ProcedureCallInfo {
432
+ invocationId: string;
433
+ consumer: AgentConsumer;
434
+ signal: AbortSignal;
435
+ confirmation?: {
436
+ id: string;
437
+ approvedAt: string;
438
+ };
439
+ }
440
+ interface AgentProcedureExecutor {
441
+ execute(req: {
442
+ path: string;
443
+ input: JsonValue;
444
+ info: ProcedureCallInfo;
445
+ }): Promise<JsonValue>;
446
+ /** Known exposed procedure paths (manifest), used for suffix-collision lint. */
447
+ paths?: ReadonlyArray<string>;
448
+ }
449
+ interface AgentProcedureRefDescriptor {
450
+ readonly id: string;
451
+ readonly path: string;
452
+ readonly description: string;
453
+ readonly inputSchema: JsonSchema;
454
+ readonly outputSchema?: JsonSchema;
455
+ readonly effect: AgentProcedureEffect;
456
+ /** Server-declared flag the client must respect (approval required). */
457
+ readonly requiresApproval?: boolean;
458
+ }
459
+ interface AgentProcedureBindingRuntimeConfig {
460
+ when?: () => boolean;
461
+ unavailableReason?: string | (() => string);
462
+ /** UI-derived inputs, evaluated at EXECUTION time (docs/05 rule 4). */
463
+ bind?: () => Record<string, JsonValue>;
464
+ overridableFields?: ReadonlyArray<string>;
465
+ /** Escalate (never lower) the manifest's confirmation requirement. */
466
+ confirmation?: "optional" | "required";
467
+ policies?: AgentPolicy[];
468
+ /** Contextual description appended to the manifest description. */
469
+ describe?: () => string;
470
+ meta?: Record<string, JsonValue>;
471
+ }
472
+ interface AgentProcedureBinding<TIn extends object = object, TOut = unknown> {
473
+ readonly kind: "procedure-binding";
474
+ readonly ref: AgentProcedureRefDescriptor;
475
+ readonly config: AgentProcedureBindingRuntimeConfig;
476
+ /** Keys produced by bind(), captured at binding creation. */
477
+ readonly boundKeys: ReadonlyArray<string>;
478
+ /** Bound keys the agent may NOT supply (bound minus overridable). */
479
+ readonly lockedKeys: ReadonlyArray<string>;
480
+ /** Agent-facing (reduced) input schema per D7 rule 1. */
481
+ readonly reducedInputSchema: JsonSchema;
482
+ /** Optional link to the owning view component. */
483
+ contextLink?: {
484
+ type: string;
485
+ instanceId: string;
486
+ };
487
+ /** Phantom fields carrying the generics (never read at runtime). */
488
+ readonly __types?: {
489
+ input: TIn;
490
+ output: TOut;
491
+ };
492
+ }
493
+ interface AgentComponentDefinition {
494
+ /** Component type, e.g. "devices.table". MUST match the id grammar. */
495
+ type: string;
496
+ /** Distinguishes simultaneous mounts. Defaults to "default". Data-derived. */
497
+ instanceId?: string;
498
+ /** Agent-visible description, ≤ 500 chars. Required, non-empty. */
499
+ description: string;
500
+ /** Optional containment link for hierarchy-aware consumers. */
501
+ parent?: {
502
+ type: string;
503
+ instanceId?: string;
504
+ };
505
+ /** Agent-visible metadata. JsonValue, ≤ 2 kB serialized. */
506
+ meta?: Record<string, JsonValue>;
507
+ /** Internal metadata for policies/audit sinks. NEVER serialized. */
508
+ internal?: Record<string, unknown>;
509
+ /** Policies applied to every capability of this component. */
510
+ policies?: AgentPolicy[];
511
+ /** Registrant trust label; default "first-party". */
512
+ origin?: string;
513
+ /** Snapshot ordering/budget priority; higher survives budgets longer. */
514
+ priority?: number;
515
+ /** Master switch; false ⇒ all capabilities visible-disabled. */
516
+ enabled?: boolean;
517
+ observations?: Record<string, AgentObservationDefinition<any>>;
518
+ actions?: Record<string, AgentActionDefinition<any, any>>;
519
+ /** Domain references; normally added via @agent-surface/orpc. */
520
+ procedures?: AgentProcedureBinding<any, any>[];
521
+ }
522
+ /**
523
+ * Validates a component definition structurally. Throws
524
+ * AgentSurfaceDefinitionError in every environment — structural defects are
525
+ * deterministic code bugs (docs/03 §registry).
526
+ */
527
+ declare function validateComponentDefinition(def: AgentComponentDefinition, limits: AgentSurfaceLimits, opts: {
528
+ hasProcedureExecutor: boolean;
529
+ }): void;
530
+
531
+ type AgentSurfaceEvent = {
532
+ type: "surface-changed";
533
+ surfaceVersion: string;
534
+ } | {
535
+ type: "component-registered";
536
+ registrationId: string;
537
+ componentType: string;
538
+ instanceId: string;
539
+ } | {
540
+ type: "component-unregistered";
541
+ registrationId: string;
542
+ componentType: string;
543
+ instanceId: string;
544
+ } | {
545
+ type: "component-rejected";
546
+ componentType: string;
547
+ instanceId: string;
548
+ reason: "duplicate" | "guard";
549
+ } | {
550
+ type: "availability-changed";
551
+ registrationId: string;
552
+ capabilityId: string;
553
+ available: boolean;
554
+ } | {
555
+ type: "collision-suspected";
556
+ viewCapabilityId: string;
557
+ domainProcedureId: string;
558
+ } | {
559
+ type: "invocation-started";
560
+ invocationId: string;
561
+ capabilityId: string;
562
+ consumerId: string;
563
+ } | {
564
+ type: "invocation-settled";
565
+ invocationId: string;
566
+ capabilityId: string;
567
+ status: "ok" | "error";
568
+ code?: AgentCapabilityErrorCode;
569
+ durationMs: number;
570
+ } | {
571
+ type: "confirmation-requested";
572
+ confirmationId: string;
573
+ capabilityId: string;
574
+ expiresAt: string;
575
+ } | {
576
+ type: "confirmation-resolved";
577
+ confirmationId: string;
578
+ outcome: "approved" | "denied" | "expired";
579
+ };
580
+
581
+ interface PendingConfirmation {
582
+ confirmationId: string;
583
+ capabilityId: string;
584
+ registrationId: string;
585
+ /** Normalized consumer identity `kind:id` (D22). */
586
+ consumerKey: string;
587
+ /** Effect of the operation being approved. */
588
+ effect: AgentEffect;
589
+ /** Human-readable summary composed from description + effective input. */
590
+ summary: string;
591
+ /** The exact effective input (bound + agent-supplied) being approved. */
592
+ input: JsonValue;
593
+ requestedAt: string;
594
+ expiresAt: string;
595
+ }
596
+ interface ConfirmationController {
597
+ /** Pending requests, for host UI rendering. */
598
+ pending(): PendingConfirmation[];
599
+ resolve(confirmationId: string, resolution: {
600
+ approved: boolean;
601
+ reason?: string;
602
+ }): void;
603
+ /** Resolves when the given confirmation settles (approved/denied/expired). */
604
+ waitFor(confirmationId: string, opts?: {
605
+ signal?: AbortSignal;
606
+ }): Promise<"approved" | "denied" | "expired">;
607
+ subscribe(listener: (pending: PendingConfirmation[]) => void): Unsubscribe;
608
+ /** Test hook: force-expire a record as if its TTL elapsed (docs/08). */
609
+ forceExpire(confirmationId: string): void;
610
+ }
611
+
612
+ type ConfirmationLevel = "never" | "optional" | "required";
613
+
614
+ interface SnapshotContext {
615
+ consumer?: AgentConsumer;
616
+ /** Component-type prefixes to include, e.g. ["devices"]. Default: all. */
617
+ scope?: string[];
618
+ /** Include visible-disabled capabilities. Default true. */
619
+ includeUnavailable?: boolean;
620
+ /** [Experimental] Truncation budget. */
621
+ budget?: {
622
+ maxComponents?: number;
623
+ maxBytes?: number;
624
+ };
625
+ }
626
+ interface AgentSurfaceSnapshot {
627
+ surfaceId: string;
628
+ surfaceVersion: string;
629
+ capturedAt: string;
630
+ route?: AgentRouteInfo;
631
+ components: AgentComponentDescriptor[];
632
+ /** Domain references, top-level (planes are not nested into each other). */
633
+ procedures: AgentProcedureDescriptor[];
634
+ /** [Experimental] Present iff a budget truncated the snapshot. */
635
+ truncated?: {
636
+ droppedComponents: number;
637
+ };
638
+ }
639
+ interface AgentComponentDescriptor {
640
+ type: string;
641
+ instanceId: string;
642
+ registrationId: string;
643
+ description: string;
644
+ parent?: {
645
+ type: string;
646
+ instanceId: string;
647
+ };
648
+ meta?: Record<string, JsonValue>;
649
+ observations: AgentObservationDescriptor[];
650
+ actions: AgentActionDescriptor[];
651
+ }
652
+ interface AgentObservationDescriptor {
653
+ capabilityId: string;
654
+ name: string;
655
+ description: string;
656
+ outputSchema: JsonSchema;
657
+ available: boolean;
658
+ unavailableReason?: string;
659
+ meta?: Record<string, JsonValue>;
660
+ }
661
+ interface AgentActionDescriptor {
662
+ capabilityId: string;
663
+ name: string;
664
+ description: string;
665
+ inputSchema: JsonSchema;
666
+ outputSchema?: JsonSchema;
667
+ effect: "local-state" | "navigation";
668
+ idempotent: boolean;
669
+ reversible: boolean;
670
+ confirmation: "never" | "optional" | "required";
671
+ available: boolean;
672
+ unavailableReason?: string;
673
+ meta?: Record<string, JsonValue>;
674
+ }
675
+ interface AgentProcedureDescriptor {
676
+ procedureId: string;
677
+ description: string;
678
+ /** Agent-facing (reduced) input schema per binding rule 1 (docs/05). */
679
+ inputSchema: JsonSchema;
680
+ outputSchema?: JsonSchema;
681
+ effect: AgentProcedureEffect;
682
+ confirmation: ConfirmationLevel;
683
+ available: boolean;
684
+ unavailableReason?: string;
685
+ boundFields: Array<{
686
+ path: string;
687
+ locked: boolean;
688
+ source: "ui-state";
689
+ }>;
690
+ /** The registration that contributed this reference (staleness token). */
691
+ registrationId: string;
692
+ /** Optional link to the owning view component. */
693
+ context?: {
694
+ type: string;
695
+ instanceId: string;
696
+ };
697
+ meta?: Record<string, JsonValue>;
698
+ }
699
+ type AgentCapabilityDescriptorUnion = AgentObservationDescriptor | AgentActionDescriptor | AgentProcedureDescriptor;
700
+
701
+ interface RegistrationCandidate {
702
+ definition: AgentComponentDefinition;
703
+ stack?: string;
704
+ }
705
+ interface RegistryOptions {
706
+ /** "development" | "production" | "test". Default: "production". */
707
+ environment?: AgentEnvironment;
708
+ /** Host context provider. MUST be synchronous and cheap. */
709
+ context?: () => Record<string, unknown>;
710
+ /** Global policies, outermost layer of every chain. */
711
+ policies?: AgentPolicy[];
712
+ /** Audit sink; default: bounded in-memory sink (+ console in development). */
713
+ audit?: AuditSink;
714
+ /** Guard invoked before accepting a registration (trust filtering, docs/06). */
715
+ onRegister?: (candidate: RegistrationCandidate) => "accept" | "reject";
716
+ /** Collision handling for duplicate (type, instanceId). Default "reject". */
717
+ onDuplicateInstance?: "reject" | "replace";
718
+ /** Suffix-collision diagnostics vs known domain ids. Default "warn". */
719
+ duplicateSuffixPolicy?: "off" | "warn" | "error";
720
+ /** Route descriptor for snapshots (host wires its router here). */
721
+ route?: () => AgentRouteInfo | undefined;
722
+ limits?: Partial<AgentSurfaceLimits>;
723
+ /** Injectable clock (docs/08 determinism); default Date.now. */
724
+ now?: () => number;
725
+ }
726
+ interface AgentRegistrationHandle {
727
+ readonly registrationId: string;
728
+ readonly status: "active" | "rejected" | "unregistered";
729
+ /** Push dynamic updates; only these fields are updatable (D2). */
730
+ update(patch: {
731
+ enabled?: boolean;
732
+ availability?: Record<string, {
733
+ available: boolean;
734
+ reason?: string;
735
+ }>;
736
+ }): void;
737
+ /** Bumps the surface version without changing anything. */
738
+ invalidate(): void;
739
+ unregister(): void;
740
+ }
741
+ interface AgentSurfaceRegistry {
742
+ readonly surfaceId: string;
743
+ register(definition: AgentComponentDefinition): AgentRegistrationHandle;
744
+ snapshot(context?: SnapshotContext): AgentSurfaceSnapshot;
745
+ invoke(request: AgentInvocation, options?: InvokeOptions): Promise<AgentInvocationResult>;
746
+ subscribe(listener: (event: AgentSurfaceEvent) => void): Unsubscribe;
747
+ confirmations: ConfirmationController;
748
+ /** Register a domain-procedure executor (installed by @agent-surface/orpc). */
749
+ setProcedureExecutor(executor: AgentProcedureExecutor | undefined): void;
750
+ getVersion(): string;
751
+ /** Tears down: aborts in-flight invocations (CANCELLED), clears listeners. */
752
+ dispose(): void;
753
+ }
754
+ declare function createAgentSurfaceRegistry(options?: RegistryOptions): AgentSurfaceRegistry;
755
+
756
+ interface AgentToolsetOptions {
757
+ consumer: AgentConsumer;
758
+ /** "direct": one tool per capability. "meta": 3 generic tools. [meta: Experimental] */
759
+ mode?: "direct" | "meta";
760
+ /**
761
+ * Loop topology (D26). Sets the confirmation-mode default: "embedded" →
762
+ * "wait", "remote" → "two-phase". One of `topology` or `confirmations`
763
+ * MUST be provided — there is no ambiguous global default.
764
+ */
765
+ topology?: "embedded" | "remote";
766
+ /**
767
+ * "wait": on CONFIRMATION_REQUIRED, await user resolution (up to TTL) and
768
+ * auto-retry, so the model sees one tool call → one final result.
769
+ * "two-phase": surface CONFIRMATION_REQUIRED to the model, which retries.
770
+ * Overrides the topology default (a remote loop opting into "wait" owns
771
+ * its transport-timeout story, docs/09 §confirmation-topology).
772
+ */
773
+ confirmations?: "wait" | "two-phase";
774
+ scope?: string[];
775
+ }
776
+ interface AgentTool {
777
+ /** Wire-safe name (docs/09 §wire-names), ≤ 64 chars. */
778
+ name: string;
779
+ description: string;
780
+ inputSchema: JsonSchema;
781
+ execute(input: JsonValue, call: {
782
+ toolCallId?: string;
783
+ }): Promise<AgentInvocationResult>;
784
+ }
785
+ interface AgentToolset {
786
+ tools(): AgentTool[];
787
+ /** Fires when tools() would return a different catalog. */
788
+ subscribe(listener: (tools: AgentTool[]) => void): Unsubscribe;
789
+ dispose(): void;
790
+ }
791
+ declare function createAgentToolset(registry: AgentSurfaceRegistry, options: AgentToolsetOptions): AgentToolset;
792
+
793
+ /** Deep equality over JsonValue (order-sensitive for arrays, docs/06 rule 2). */
794
+ declare function jsonDeepEqual(a: JsonValue | undefined, b: JsonValue | undefined): boolean;
795
+
796
+ export { AGENT_CAPABILITY_ERROR_CODES, type AgentActionContext, type AgentActionDefinition, type AgentActionDescriptor, type AgentAuthorizationContext, type AgentCapabilityDescriptorUnion, type AgentCapabilityErrorCode, type AgentCapabilityErrorPayload, type AgentComponentDefinition, type AgentComponentDescriptor, type AgentConsumer, type AgentEffect, type AgentEnvironment, type AgentErrorRetry, type AgentInvocation, type AgentInvocationPolicyContext, type AgentInvocationResult, type AgentObservationDefinition, type AgentObservationDescriptor, type AgentPlane, type AgentPolicy, type AgentPolicyContext, type AgentProcedureBinding, type AgentProcedureBindingRuntimeConfig, type AgentProcedureDescriptor, type AgentProcedureEffect, type AgentProcedureExecutor, type AgentProcedureRefDescriptor, type AgentReadContext, type AgentRegistrationHandle, type AgentRouteInfo, type AgentSchema, AgentSchemaError, type AgentSchemaIssue, AgentSurfaceDefinitionError, type AgentSurfaceDefinitionErrorCode, AgentSurfaceError, type AgentSurfaceEvent, type AgentSurfaceLimits, type AgentSurfaceRegistry, type AgentSurfaceSnapshot, type AgentTool, type AgentToolset, type AgentToolsetOptions, type AuditEvent, type AuditSink, CONFIRMATION_ESCALATION, type ConfirmationController, type ConfirmationEscalation, DEFAULT_LIMITS, type DiscoveryDecision, type InvokeOptions, type JsonSchema, type JsonValue, MAX_ID_LENGTH, MAX_WIRE_NAME_LENGTH, type ParsedCapabilityId, type PendingConfirmation, type PreconditionFailure, type ProcedureCallInfo, type RegistrationCandidate, type RegistryOptions, type SnapshotContext, type StandardSchemaV1, type Unsubscribe, action, audit, authenticated, composeInvokeChain, consoleAuditSink, createAgentSurfaceRegistry, createAgentToolset, decodeWireName, defineAgentComponent, emptyObjectSchema, encodeWireName, encodeWireNameForInstance, environment, evaluateDiscovery, formatDomainCapabilityId, formatViewCapabilityId, fromJsonSchema, fromStandardSchema, hasPermission, isAgentSurfaceError, isValidCapabilityName, isValidComponentType, isValidInstanceId, jsonDeepEqual, memoryAuditSink, observation, parseCapabilityId, rateLimit, requireConfirmation, tenantBoundary, validateComponentDefinition, validateJsonSchemaDocument, validateValueAgainstSchema };