@agent-surface/core 0.1.0 → 0.3.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/README.md CHANGED
@@ -40,7 +40,8 @@ registry.register(
40
40
 
41
41
  const toolset = createAgentToolset(registry, {
42
42
  consumer: { id: "copilot", kind: "embedded" },
43
- });
43
+ topology: "embedded", // required (D26): embedded → confirmations "wait",
44
+ }); // remote → "two-phase". No global default.
44
45
  ```
45
46
 
46
47
  React apps should use [`@agent-surface/react`](https://www.npmjs.com/package/@agent-surface/react) instead of calling `register` directly. Full specification: [docs](https://github.com/Wiseair-srl/agent-surface/tree/main/docs).
package/dist/index.d.ts CHANGED
@@ -17,6 +17,35 @@ interface AgentRouteInfo {
17
17
  path: string;
18
18
  params?: Record<string, string>;
19
19
  }
20
+ /**
21
+ * Concurrency group for an action or procedure reference (D25). Not
22
+ * model-visible: it is runtime behavior, not planning information.
23
+ *
24
+ * - `instance` (default) — every action on the registration shares one FIFO
25
+ * queue. Safest: two actions on the same component can never interleave.
26
+ * - `capability` — one queue per capability, so a slow export does not block
27
+ * closing a drawer.
28
+ * - `key` — one queue per author-chosen key, for actions that contend over
29
+ * the same resource across capabilities.
30
+ * - `parallel` — bounded parallelism; `max` is required and must be ≥ 1.
31
+ *
32
+ * `queueDepth` overrides `limits.actionQueueDepth` for this group only.
33
+ */
34
+ type AgentConcurrency = {
35
+ mode: "instance";
36
+ queueDepth?: number;
37
+ } | {
38
+ mode: "capability";
39
+ queueDepth?: number;
40
+ } | {
41
+ mode: "key";
42
+ key: string;
43
+ queueDepth?: number;
44
+ } | {
45
+ mode: "parallel";
46
+ max: number;
47
+ queueDepth?: number;
48
+ };
20
49
  interface AgentSurfaceLimits {
21
50
  maxComponentDescription: number;
22
51
  maxCapabilityDescription: number;
@@ -107,13 +136,41 @@ declare function encodeWireName(id: string): string;
107
136
  * Wire name disambiguated per instance: providers require UNIQUE tool names,
108
137
  * so when several live instances expose the same capability the adapter
109
138
  * 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).
139
+ * authoritative).
140
+ *
141
+ * The result is ALWAYS ≤ 64 characters (`AS-WIRE-004`) and deterministic for a
142
+ * given `(id, instanceId, level)` (`AS-WIRE-005`). `level` escalates the hash
143
+ * when a catalog would otherwise emit the same name twice — see
144
+ * {@link assignWireNames}, which owns that check; callers with a whole catalog
145
+ * in hand should use it rather than this function directly.
146
+ */
147
+ declare function encodeWireNameForInstance(id: string, instanceId?: string, level?: number): string;
148
+ interface WireNameEntry {
149
+ /** Canonical capability id. */
150
+ id: string;
151
+ /** Instance disambiguator, when several live instances share the id. */
152
+ instanceId?: string;
153
+ }
154
+ interface WireNameAssignment {
155
+ /** Emitted names, positionally aligned with the input entries. */
156
+ names: string[];
157
+ /** wireName → canonical id. Authoritative; shortened names are not decodable. */
158
+ byName: ReadonlyMap<string, string>;
159
+ }
160
+ /**
161
+ * Assigns wire names to a whole catalog, guaranteeing uniqueness within it
162
+ * (`AS-WIRE-006`). Two distinct entries that collide are BOTH re-encoded at the
163
+ * next hash level, so the outcome depends on the set of entries and not on
164
+ * their order (`AS-WIRE-005`). Escalation is bounded; the last level appends
165
+ * the entry's rank among the colliding keys, which terminates by construction.
112
166
  */
113
- declare function encodeWireNameForInstance(id: string, instanceId?: string): string;
167
+ declare function assignWireNames(entries: readonly WireNameEntry[]): WireNameAssignment;
114
168
  /**
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).
169
+ * Reverses `encodeWireName` for names that were encoded faithfully, and returns
170
+ * `undefined` for every name that was not shortened names and per-instance
171
+ * names among them (`AS-WIRE-007`: consult `toolset.wireNameMap()` instead).
172
+ * Returning a plausible-but-wrong canonical id would take the audit identity
173
+ * with it, so this refuses anything it cannot re-encode byte-identically.
117
174
  */
118
175
  declare function decodeWireName(name: string): string | undefined;
119
176
 
@@ -423,6 +480,9 @@ interface AgentActionDefinition<TIn extends JsonValue, TOut extends JsonValue |
423
480
  policies?: AgentPolicy[];
424
481
  meta?: Record<string, JsonValue>;
425
482
  timeoutMs?: number;
483
+ /** Concurrency group (D25). Default `{mode:"instance"}` — serialize with
484
+ * every other action on this component instance. */
485
+ concurrency?: AgentConcurrency;
426
486
  }
427
487
  /** Identity helpers that fix generics for record-literal authoring. */
428
488
  declare function observation<TOut extends JsonValue>(def: AgentObservationDefinition<TOut>): AgentObservationDefinition<TOut>;
@@ -468,6 +528,10 @@ interface AgentProcedureBindingRuntimeConfig {
468
528
  /** Contextual description appended to the manifest description. */
469
529
  describe?: () => string;
470
530
  meta?: Record<string, JsonValue>;
531
+ /** Concurrency group (D25). Default: one group per procedure identity per
532
+ * referencing registration — conservative, and it never couples a domain
533
+ * call to unrelated view actions. */
534
+ concurrency?: AgentConcurrency;
471
535
  }
472
536
  interface AgentProcedureBinding<TIn extends object = object, TOut = unknown> {
473
537
  readonly kind: "procedure-binding";
@@ -674,7 +738,20 @@ interface AgentActionDescriptor {
674
738
  }
675
739
  interface AgentProcedureDescriptor {
676
740
  procedureId: string;
741
+ /**
742
+ * The manifest description. Stable across snapshots — the contextual
743
+ * `describe()` output is `contextualNote`, not part of this string, unless
744
+ * the registry was created with `snapshotMergesContextualNote: true`
745
+ * (the 0.2 default, removed in a later minor — D28).
746
+ */
677
747
  description: string;
748
+ /**
749
+ * Volatile: this snapshot's contextual `describe()` output, if any. Always
750
+ * populated, in both merge modes, so a host can migrate before the default
751
+ * moves. Use {@link stableDescriptionOf} to recover the note-free
752
+ * description without parsing.
753
+ */
754
+ contextualNote?: string;
678
755
  /** Agent-facing (reduced) input schema per binding rule 1 (docs/05). */
679
756
  inputSchema: JsonSchema;
680
757
  outputSchema?: JsonSchema;
@@ -697,6 +774,15 @@ interface AgentProcedureDescriptor {
697
774
  meta?: Record<string, JsonValue>;
698
775
  }
699
776
  type AgentCapabilityDescriptorUnion = AgentObservationDescriptor | AgentActionDescriptor | AgentProcedureDescriptor;
777
+ /**
778
+ * The note-free description of a descriptor, whichever way the registry was
779
+ * configured to compose it (D28). The merge rule is `${description} ${note}`,
780
+ * so the split is exact — no host ever has to parse a prefix it did not write.
781
+ */
782
+ declare function stableDescriptionOf(descriptor: {
783
+ description: string;
784
+ contextualNote?: string;
785
+ }): string;
700
786
 
701
787
  interface RegistrationCandidate {
702
788
  definition: AgentComponentDefinition;
@@ -720,6 +806,15 @@ interface RegistryOptions {
720
806
  /** Route descriptor for snapshots (host wires its router here). */
721
807
  route?: () => AgentRouteInfo | undefined;
722
808
  limits?: Partial<AgentSurfaceLimits>;
809
+ /**
810
+ * D28 compatibility flag. `true` (default, for one minor) folds a procedure
811
+ * reference's contextual `describe()` output into
812
+ * `AgentProcedureDescriptor.description`, as 0.1 did. `false` keeps the two
813
+ * apart, so `description` is stable across snapshots and the live text is
814
+ * read from `contextualNote`. Populated either way; the default flips in a
815
+ * later minor and the flag is then removed.
816
+ */
817
+ snapshotMergesContextualNote?: boolean;
723
818
  /** Injectable clock (docs/08 determinism); default Date.now. */
724
819
  now?: () => number;
725
820
  }
@@ -755,7 +850,12 @@ declare function createAgentSurfaceRegistry(options?: RegistryOptions): AgentSur
755
850
 
756
851
  interface AgentToolsetOptions {
757
852
  consumer: AgentConsumer;
758
- /** "direct": one tool per capability. "meta": 3 generic tools. [meta: Experimental] */
853
+ /**
854
+ * "direct": one tool per capability — provider-native input typing, catalog
855
+ * size linear in the surface. "meta": three fixed tools with lazy discovery —
856
+ * constant tool-block size, one extra round trip before the first act.
857
+ * Default "direct"; see the selection guide in docs/09 §choosing-a-mode.
858
+ */
759
859
  mode?: "direct" | "meta";
760
860
  /**
761
861
  * Loop topology (D26). Sets the confirmation-mode default: "embedded" →
@@ -771,19 +871,67 @@ interface AgentToolsetOptions {
771
871
  * its transport-timeout story, docs/09 §confirmation-topology).
772
872
  */
773
873
  confirmations?: "wait" | "two-phase";
874
+ /**
875
+ * Component-type prefixes this consumer may discover. D27: this is a
876
+ * **floor** — in "meta" mode a model-supplied `scope` can only narrow it
877
+ * further, never widen it. Not an authority boundary: `invoke` does not
878
+ * check scope in either mode (docs/09 §scope-is-discovery-only).
879
+ */
774
880
  scope?: string[];
881
+ /**
882
+ * [Experimental] Snapshot truncation budget for `surface_discover`.
883
+ * "meta" mode only — there the `truncated` marker rides in the payload the
884
+ * model reads. In "direct" mode a budget would silently drop tools with no
885
+ * signal to anyone, so it is rejected rather than half-honored.
886
+ */
887
+ budget?: {
888
+ maxComponents?: number;
889
+ maxBytes?: number;
890
+ };
891
+ /**
892
+ * D28 compatibility flag. `true` (default, for one minor) composes
893
+ * availability and the contextual note into `description`, as 0.1 did.
894
+ * `false` keeps `description` free of live state, so the provider tool block
895
+ * is byte-stable across steps and prompt-prefix caching survives; the host
896
+ * renders `AgentTool.state` outside the tool definitions (docs/09
897
+ * §rendering-capability-state). `state` is populated either way.
898
+ */
899
+ descriptionIncludesState?: boolean;
775
900
  }
776
901
  interface AgentTool {
777
- /** Wire-safe name (docs/09 §wire-names), ≤ 64 chars. */
902
+ /** Wire-safe name (docs/09 §wire-names), ≤ 64 chars, unique in this catalog. */
778
903
  name: string;
904
+ /**
905
+ * Plane + effect + confirmation prefix, then the authored description.
906
+ * With `descriptionIncludesState: false` this contains NO live state — it is
907
+ * safe in a provider tool block with prompt-prefix caching across steps.
908
+ */
779
909
  description: string;
780
910
  inputSchema: JsonSchema;
911
+ /**
912
+ * Volatile: re-derived on every snapshot. Hosts render this OUTSIDE the tool
913
+ * block (e.g. a trailing system message) so availability stays honest without
914
+ * invalidating the cached prefix (D28).
915
+ */
916
+ state: {
917
+ available: boolean;
918
+ unavailableReason?: string;
919
+ /** Live text contributed by a contextual binding's `describe()`. */
920
+ note?: string;
921
+ };
781
922
  execute(input: JsonValue, call: {
782
923
  toolCallId?: string;
783
924
  }): Promise<AgentInvocationResult>;
784
925
  }
785
926
  interface AgentToolset {
786
927
  tools(): AgentTool[];
928
+ /**
929
+ * wireName → canonical capability id, for the catalog `tools()` last built.
930
+ * Authoritative: shortened names are not decodable by string surgery, so a
931
+ * host MUST consult this rather than reversing names itself (D30). Empty in
932
+ * "meta" mode, whose three tool names are not capability ids.
933
+ */
934
+ wireNameMap(): ReadonlyMap<string, string>;
787
935
  /** Fires when tools() would return a different catalog. */
788
936
  subscribe(listener: (tools: AgentTool[]) => void): Unsubscribe;
789
937
  dispose(): void;
@@ -793,4 +941,4 @@ declare function createAgentToolset(registry: AgentSurfaceRegistry, options: Age
793
941
  /** Deep equality over JsonValue (order-sensitive for arrays, docs/06 rule 2). */
794
942
  declare function jsonDeepEqual(a: JsonValue | undefined, b: JsonValue | undefined): boolean;
795
943
 
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 };
944
+ export { AGENT_CAPABILITY_ERROR_CODES, type AgentActionContext, type AgentActionDefinition, type AgentActionDescriptor, type AgentAuthorizationContext, type AgentCapabilityDescriptorUnion, type AgentCapabilityErrorCode, type AgentCapabilityErrorPayload, type AgentComponentDefinition, type AgentComponentDescriptor, type AgentConcurrency, 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, type WireNameAssignment, type WireNameEntry, action, assignWireNames, 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, stableDescriptionOf, tenantBoundary, validateComponentDefinition, validateJsonSchemaDocument, validateValueAgainstSchema };