@agent-surface/core 0.1.0 → 0.2.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 +53 -1
- package/dist/index.js +160 -80
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
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;
|
|
@@ -423,6 +452,9 @@ interface AgentActionDefinition<TIn extends JsonValue, TOut extends JsonValue |
|
|
|
423
452
|
policies?: AgentPolicy[];
|
|
424
453
|
meta?: Record<string, JsonValue>;
|
|
425
454
|
timeoutMs?: number;
|
|
455
|
+
/** Concurrency group (D25). Default `{mode:"instance"}` — serialize with
|
|
456
|
+
* every other action on this component instance. */
|
|
457
|
+
concurrency?: AgentConcurrency;
|
|
426
458
|
}
|
|
427
459
|
/** Identity helpers that fix generics for record-literal authoring. */
|
|
428
460
|
declare function observation<TOut extends JsonValue>(def: AgentObservationDefinition<TOut>): AgentObservationDefinition<TOut>;
|
|
@@ -468,6 +500,10 @@ interface AgentProcedureBindingRuntimeConfig {
|
|
|
468
500
|
/** Contextual description appended to the manifest description. */
|
|
469
501
|
describe?: () => string;
|
|
470
502
|
meta?: Record<string, JsonValue>;
|
|
503
|
+
/** Concurrency group (D25). Default: one group per procedure identity per
|
|
504
|
+
* referencing registration — conservative, and it never couples a domain
|
|
505
|
+
* call to unrelated view actions. */
|
|
506
|
+
concurrency?: AgentConcurrency;
|
|
471
507
|
}
|
|
472
508
|
interface AgentProcedureBinding<TIn extends object = object, TOut = unknown> {
|
|
473
509
|
readonly kind: "procedure-binding";
|
|
@@ -771,7 +807,23 @@ interface AgentToolsetOptions {
|
|
|
771
807
|
* its transport-timeout story, docs/09 §confirmation-topology).
|
|
772
808
|
*/
|
|
773
809
|
confirmations?: "wait" | "two-phase";
|
|
810
|
+
/**
|
|
811
|
+
* Component-type prefixes this consumer may discover. D27: this is a
|
|
812
|
+
* **floor** — in "meta" mode a model-supplied `scope` can only narrow it
|
|
813
|
+
* further, never widen it. Not an authority boundary: `invoke` does not
|
|
814
|
+
* check scope in either mode (docs/09 §scope-is-discovery-only).
|
|
815
|
+
*/
|
|
774
816
|
scope?: string[];
|
|
817
|
+
/**
|
|
818
|
+
* [Experimental] Snapshot truncation budget for `surface_discover`.
|
|
819
|
+
* "meta" mode only — there the `truncated` marker rides in the payload the
|
|
820
|
+
* model reads. In "direct" mode a budget would silently drop tools with no
|
|
821
|
+
* signal to anyone, so it is rejected rather than half-honored.
|
|
822
|
+
*/
|
|
823
|
+
budget?: {
|
|
824
|
+
maxComponents?: number;
|
|
825
|
+
maxBytes?: number;
|
|
826
|
+
};
|
|
775
827
|
}
|
|
776
828
|
interface AgentTool {
|
|
777
829
|
/** Wire-safe name (docs/09 §wire-names), ≤ 64 chars. */
|
|
@@ -793,4 +845,4 @@ declare function createAgentToolset(registry: AgentSurfaceRegistry, options: Age
|
|
|
793
845
|
/** Deep equality over JsonValue (order-sensitive for arrays, docs/06 rule 2). */
|
|
794
846
|
declare function jsonDeepEqual(a: JsonValue | undefined, b: JsonValue | undefined): boolean;
|
|
795
847
|
|
|
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 };
|
|
848
|
+
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, 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 };
|
package/dist/index.js
CHANGED
|
@@ -645,7 +645,8 @@ var ACTION_KEYS = /* @__PURE__ */ new Set([
|
|
|
645
645
|
"execute",
|
|
646
646
|
"policies",
|
|
647
647
|
"meta",
|
|
648
|
-
"timeoutMs"
|
|
648
|
+
"timeoutMs",
|
|
649
|
+
"concurrency"
|
|
649
650
|
]);
|
|
650
651
|
var VIEW_EFFECTS = /* @__PURE__ */ new Set(["local-state", "navigation"]);
|
|
651
652
|
var SERVER_EFFECTS = /* @__PURE__ */ new Set([
|
|
@@ -666,6 +667,29 @@ function checkMeta(meta, where, limits) {
|
|
|
666
667
|
fail("LIMIT_EXCEEDED", `${where}: meta exceeds ${limits.maxMetaBytes} bytes`);
|
|
667
668
|
}
|
|
668
669
|
}
|
|
670
|
+
function checkConcurrency(concurrency, where) {
|
|
671
|
+
if (concurrency === void 0) return;
|
|
672
|
+
if (typeof concurrency !== "object" || concurrency === null) {
|
|
673
|
+
fail("INVALID_DEFINITION", `${where}: concurrency must be an object`);
|
|
674
|
+
}
|
|
675
|
+
const { mode } = concurrency;
|
|
676
|
+
if (!["instance", "capability", "key", "parallel"].includes(mode)) {
|
|
677
|
+
fail("INVALID_DEFINITION", `${where}: invalid concurrency mode "${String(mode)}"`);
|
|
678
|
+
}
|
|
679
|
+
if (mode === "key" && (typeof concurrency.key !== "string" || concurrency.key.length === 0)) {
|
|
680
|
+
fail("INVALID_DEFINITION", `${where}: concurrency mode "key" requires a non-empty key`);
|
|
681
|
+
}
|
|
682
|
+
if (mode === "parallel" && (typeof concurrency.max !== "number" || !Number.isInteger(concurrency.max) || concurrency.max < 1)) {
|
|
683
|
+
fail(
|
|
684
|
+
"INVALID_DEFINITION",
|
|
685
|
+
`${where}: concurrency mode "parallel" requires an integer max \u2265 1 (unbounded parallelism is not offered)`
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
const depth = concurrency.queueDepth;
|
|
689
|
+
if (depth !== void 0 && (!Number.isInteger(depth) || depth < 0)) {
|
|
690
|
+
fail("INVALID_DEFINITION", `${where}: concurrency queueDepth must be a non-negative integer`);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
669
693
|
function checkSchema(schema, where, limits) {
|
|
670
694
|
if (schema === void 0) return;
|
|
671
695
|
if (typeof schema !== "object" || schema === null || typeof schema.parse !== "function" || typeof schema.jsonSchema !== "object") {
|
|
@@ -774,6 +798,7 @@ function validateComponentDefinition(def, limits, opts) {
|
|
|
774
798
|
checkSchema(act.input, `${where} input`, limits);
|
|
775
799
|
checkSchema(act.output, `${where} output`, limits);
|
|
776
800
|
checkMeta(act.meta, where, limits);
|
|
801
|
+
checkConcurrency(act.concurrency, where);
|
|
777
802
|
}
|
|
778
803
|
const procedures = def.procedures ?? [];
|
|
779
804
|
if (procedures.length > 0 && !opts.hasProcedureExecutor) {
|
|
@@ -803,6 +828,7 @@ function validateComponentDefinition(def, limits, opts) {
|
|
|
803
828
|
fail("INVALID_DEFINITION", `procedure "${ref.path}": invalid confirmation escalation`);
|
|
804
829
|
}
|
|
805
830
|
checkMeta(binding.config.meta, `procedure "${ref.path}"`, limits);
|
|
831
|
+
checkConcurrency(binding.config.concurrency, `procedure "${ref.path}"`);
|
|
806
832
|
}
|
|
807
833
|
}
|
|
808
834
|
|
|
@@ -1354,7 +1380,8 @@ function normalizeRegistration(def, id) {
|
|
|
1354
1380
|
auditLevel: act.audit ?? "metadata",
|
|
1355
1381
|
meta: act.meta ? jsonClone(act.meta) : void 0,
|
|
1356
1382
|
timeoutMs: act.timeoutMs,
|
|
1357
|
-
policies: [...act.policies ?? []]
|
|
1383
|
+
policies: [...act.policies ?? []],
|
|
1384
|
+
concurrency: act.concurrency
|
|
1358
1385
|
});
|
|
1359
1386
|
}
|
|
1360
1387
|
const hasView = observations.size > 0 || actions.size > 0;
|
|
@@ -1386,7 +1413,8 @@ function normalizeRegistration(def, id) {
|
|
|
1386
1413
|
auditLevel: defaultAuditFor(effect),
|
|
1387
1414
|
meta: binding.config.meta ? jsonClone(binding.config.meta) : void 0,
|
|
1388
1415
|
policies: [...binding.config.policies ?? []],
|
|
1389
|
-
contextLink: binding.contextLink ?? (hasView ? { type: def.type, instanceId } : void 0)
|
|
1416
|
+
contextLink: binding.contextLink ?? (hasView ? { type: def.type, instanceId } : void 0),
|
|
1417
|
+
concurrency: binding.config.concurrency
|
|
1390
1418
|
};
|
|
1391
1419
|
});
|
|
1392
1420
|
return {
|
|
@@ -1410,9 +1438,27 @@ function normalizeRegistration(def, id) {
|
|
|
1410
1438
|
enabled: def.enabled !== false,
|
|
1411
1439
|
availabilityOverrides: /* @__PURE__ */ new Map(),
|
|
1412
1440
|
inFlight: /* @__PURE__ */ new Set(),
|
|
1413
|
-
|
|
1441
|
+
concurrencyGroups: /* @__PURE__ */ new Map()
|
|
1414
1442
|
};
|
|
1415
1443
|
}
|
|
1444
|
+
function concurrencyGroupFor(cap, limits) {
|
|
1445
|
+
const declared = cap.kind === "action" ? cap.concurrency : cap.concurrency;
|
|
1446
|
+
const fallbackDepth = limits.actionQueueDepth;
|
|
1447
|
+
if (declared === void 0) {
|
|
1448
|
+
return cap.kind === "action" ? { key: "instance", max: 1, depth: fallbackDepth } : { key: `proc:${cap.capabilityId}`, max: 1, depth: fallbackDepth };
|
|
1449
|
+
}
|
|
1450
|
+
const depth = declared.queueDepth ?? fallbackDepth;
|
|
1451
|
+
switch (declared.mode) {
|
|
1452
|
+
case "instance":
|
|
1453
|
+
return { key: "instance", max: 1, depth };
|
|
1454
|
+
case "capability":
|
|
1455
|
+
return { key: `cap:${cap.capabilityId}`, max: 1, depth };
|
|
1456
|
+
case "key":
|
|
1457
|
+
return { key: `key:${declared.key}`, max: 1, depth };
|
|
1458
|
+
case "parallel":
|
|
1459
|
+
return { key: `par:${cap.capabilityId}`, max: declared.max, depth };
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1416
1462
|
function liveAvailabilityHooks(reg, cap) {
|
|
1417
1463
|
if (cap.kind === "observation") {
|
|
1418
1464
|
const live = reg.definition.observations?.[cap.name];
|
|
@@ -2000,7 +2046,7 @@ async function executeAction(internals, args, cap) {
|
|
|
2000
2046
|
}
|
|
2001
2047
|
}
|
|
2002
2048
|
const queueStart = internals.now();
|
|
2003
|
-
const slot = await acquireActionSlot(internals, reg);
|
|
2049
|
+
const slot = await acquireActionSlot(internals, reg, cap);
|
|
2004
2050
|
args.setTimings({ queueWaitMs: internals.now() - queueStart });
|
|
2005
2051
|
if (slot === "overflow") {
|
|
2006
2052
|
return finalize({ status: "error", error: queueFull(250) });
|
|
@@ -2034,7 +2080,7 @@ async function executeAction(internals, args, cap) {
|
|
|
2034
2080
|
args.setAuditPayload(void 0, output.value);
|
|
2035
2081
|
return finalize({ status: "ok", output: output.value });
|
|
2036
2082
|
} finally {
|
|
2037
|
-
releaseActionSlot(reg);
|
|
2083
|
+
releaseActionSlot(internals, reg, cap);
|
|
2038
2084
|
}
|
|
2039
2085
|
};
|
|
2040
2086
|
return runInvokePolicies(args, parsedInput, run);
|
|
@@ -2102,40 +2148,50 @@ async function executeProcedure(internals, args, cap) {
|
|
|
2102
2148
|
effect: cap.effect
|
|
2103
2149
|
});
|
|
2104
2150
|
if ("error" in confirmation) return finalize({ status: "error", error: confirmation.error });
|
|
2105
|
-
const
|
|
2106
|
-
|
|
2107
|
-
|
|
2151
|
+
const queueStart = internals.now();
|
|
2152
|
+
const slot = await acquireActionSlot(internals, reg, cap);
|
|
2153
|
+
args.setTimings({ queueWaitMs: internals.now() - queueStart });
|
|
2154
|
+
if (slot === "overflow") {
|
|
2155
|
+
return finalize({ status: "error", error: queueFull(250) });
|
|
2156
|
+
}
|
|
2157
|
+
try {
|
|
2158
|
+
const executor = internals.executor;
|
|
2159
|
+
if (!executor) {
|
|
2160
|
+
return finalize({ status: "error", error: executionFailed("transport") });
|
|
2161
|
+
}
|
|
2162
|
+
const timeoutMs = options?.timeoutMs ?? internals.limits.procedureTimeoutMs;
|
|
2163
|
+
const executeStart = internals.now();
|
|
2164
|
+
const outcome = await executeWithGuards(internals, reg, {
|
|
2165
|
+
invocationId,
|
|
2166
|
+
capabilityId: cap.capabilityId,
|
|
2167
|
+
timeoutMs,
|
|
2168
|
+
externalSignal: options?.signal,
|
|
2169
|
+
idempotent: cap.idempotent,
|
|
2170
|
+
run: (signal) => executor.execute({
|
|
2171
|
+
path: cap.path,
|
|
2172
|
+
input: effective,
|
|
2173
|
+
info: {
|
|
2174
|
+
invocationId,
|
|
2175
|
+
consumer,
|
|
2176
|
+
signal,
|
|
2177
|
+
...confirmation.evidence ? { confirmation: confirmation.evidence } : {}
|
|
2178
|
+
}
|
|
2179
|
+
}),
|
|
2180
|
+
procedureErrors: true
|
|
2181
|
+
});
|
|
2182
|
+
args.setTimings({ executionMs: internals.now() - executeStart });
|
|
2183
|
+
if (!outcome.ok) return finalize({ status: "error", error: outcome.payload });
|
|
2184
|
+
const output = settleOutput(
|
|
2185
|
+
internals,
|
|
2186
|
+
outcome.value,
|
|
2187
|
+
cap.outputJsonSchema ? fromJsonSchema(cap.outputJsonSchema) : void 0
|
|
2188
|
+
);
|
|
2189
|
+
if ("error" in output) return finalize({ status: "error", error: output.error });
|
|
2190
|
+
args.setAuditPayload(void 0, output.value);
|
|
2191
|
+
return finalize({ status: "ok", output: output.value });
|
|
2192
|
+
} finally {
|
|
2193
|
+
releaseActionSlot(internals, reg, cap);
|
|
2108
2194
|
}
|
|
2109
|
-
const timeoutMs = options?.timeoutMs ?? internals.limits.procedureTimeoutMs;
|
|
2110
|
-
const executeStart = internals.now();
|
|
2111
|
-
const outcome = await executeWithGuards(internals, reg, {
|
|
2112
|
-
invocationId,
|
|
2113
|
-
capabilityId: cap.capabilityId,
|
|
2114
|
-
timeoutMs,
|
|
2115
|
-
externalSignal: options?.signal,
|
|
2116
|
-
idempotent: cap.idempotent,
|
|
2117
|
-
run: (signal) => executor.execute({
|
|
2118
|
-
path: cap.path,
|
|
2119
|
-
input: effective,
|
|
2120
|
-
info: {
|
|
2121
|
-
invocationId,
|
|
2122
|
-
consumer,
|
|
2123
|
-
signal,
|
|
2124
|
-
...confirmation.evidence ? { confirmation: confirmation.evidence } : {}
|
|
2125
|
-
}
|
|
2126
|
-
}),
|
|
2127
|
-
procedureErrors: true
|
|
2128
|
-
});
|
|
2129
|
-
args.setTimings({ executionMs: internals.now() - executeStart });
|
|
2130
|
-
if (!outcome.ok) return finalize({ status: "error", error: outcome.payload });
|
|
2131
|
-
const output = settleOutput(
|
|
2132
|
-
internals,
|
|
2133
|
-
outcome.value,
|
|
2134
|
-
cap.outputJsonSchema ? fromJsonSchema(cap.outputJsonSchema) : void 0
|
|
2135
|
-
);
|
|
2136
|
-
if ("error" in output) return finalize({ status: "error", error: output.error });
|
|
2137
|
-
args.setAuditPayload(void 0, output.value);
|
|
2138
|
-
return finalize({ status: "ok", output: output.value });
|
|
2139
2195
|
};
|
|
2140
2196
|
return runInvokePolicies(args, effective, run);
|
|
2141
2197
|
}
|
|
@@ -2384,21 +2440,32 @@ function executeWithGuards(internals, reg, opts) {
|
|
|
2384
2440
|
}
|
|
2385
2441
|
});
|
|
2386
2442
|
}
|
|
2387
|
-
async function acquireActionSlot(internals, reg) {
|
|
2388
|
-
|
|
2389
|
-
|
|
2443
|
+
async function acquireActionSlot(internals, reg, cap) {
|
|
2444
|
+
const { key, max, depth } = concurrencyGroupFor(cap, internals.limits);
|
|
2445
|
+
let group = reg.concurrencyGroups.get(key);
|
|
2446
|
+
if (!group) {
|
|
2447
|
+
group = { running: 0, max, depth, waiting: [] };
|
|
2448
|
+
reg.concurrencyGroups.set(key, group);
|
|
2449
|
+
}
|
|
2450
|
+
if (group.running < group.max) {
|
|
2451
|
+
group.running += 1;
|
|
2390
2452
|
return "ok";
|
|
2391
2453
|
}
|
|
2392
|
-
if (
|
|
2454
|
+
if (group.waiting.length >= group.depth) {
|
|
2455
|
+
if (group.running === 0 && group.waiting.length === 0) reg.concurrencyGroups.delete(key);
|
|
2393
2456
|
return "overflow";
|
|
2394
2457
|
}
|
|
2395
|
-
await new Promise((resolve) =>
|
|
2458
|
+
await new Promise((resolve) => group.waiting.push(resolve));
|
|
2396
2459
|
return "ok";
|
|
2397
2460
|
}
|
|
2398
|
-
function releaseActionSlot(reg) {
|
|
2399
|
-
const
|
|
2400
|
-
|
|
2401
|
-
|
|
2461
|
+
function releaseActionSlot(internals, reg, cap) {
|
|
2462
|
+
const { key } = concurrencyGroupFor(cap, internals.limits);
|
|
2463
|
+
const group = reg.concurrencyGroups.get(key);
|
|
2464
|
+
if (!group) return;
|
|
2465
|
+
const next = group.waiting.shift();
|
|
2466
|
+
if (!next) group.running -= 1;
|
|
2467
|
+
else next();
|
|
2468
|
+
if (group.running === 0 && group.waiting.length === 0) reg.concurrencyGroups.delete(key);
|
|
2402
2469
|
}
|
|
2403
2470
|
function acquireObservationSlot(internals, consumerKey) {
|
|
2404
2471
|
const adm = internals.observationAdmission;
|
|
@@ -2943,6 +3010,11 @@ function createAgentToolset(registry, options) {
|
|
|
2943
3010
|
"createAgentToolset: declare a topology ('embedded' | 'remote') or an explicit confirmations mode ('wait' | 'two-phase'). Embedded loops default to 'wait', remote loops to 'two-phase' (docs/09 \xA7confirmation-topology)."
|
|
2944
3011
|
);
|
|
2945
3012
|
}
|
|
3013
|
+
if (options.budget !== void 0 && mode !== "meta") {
|
|
3014
|
+
throw new Error(
|
|
3015
|
+
"createAgentToolset: `budget` applies to mode 'meta' only \u2014 in 'direct' mode it would silently drop tools. Pass a `scope` to bound a direct catalog instead (docs/09 \xA7meta-tools-mode)."
|
|
3016
|
+
);
|
|
3017
|
+
}
|
|
2946
3018
|
const confirmationsMode = options.confirmations ?? (options.topology === "remote" ? "two-phase" : "wait");
|
|
2947
3019
|
const listeners = /* @__PURE__ */ new Set();
|
|
2948
3020
|
const pendingWaits = /* @__PURE__ */ new Set();
|
|
@@ -2960,15 +3032,16 @@ function createAgentToolset(registry, options) {
|
|
|
2960
3032
|
pendingWaits.delete(controller);
|
|
2961
3033
|
}
|
|
2962
3034
|
}
|
|
2963
|
-
async function invokeThroughSurface(entry, input, toolCallId) {
|
|
2964
|
-
const invocationId = toolCallId ?? `inv_${randomBase62(12)}`;
|
|
3035
|
+
async function invokeThroughSurface(entry, input, toolCallId, overrides) {
|
|
3036
|
+
const invocationId = overrides?.invocationId ?? toolCallId ?? `inv_${randomBase62(12)}`;
|
|
2965
3037
|
const base = {
|
|
2966
3038
|
invocationId,
|
|
2967
3039
|
capabilityId: entry.capabilityId,
|
|
2968
3040
|
...entry.instanceId !== void 0 ? { instanceId: entry.instanceId } : {},
|
|
2969
|
-
registrationId: entry.registrationId,
|
|
3041
|
+
...entry.registrationId !== void 0 ? { registrationId: entry.registrationId } : {},
|
|
2970
3042
|
surfaceVersion: entry.surfaceVersion,
|
|
2971
|
-
...input !== void 0 ? { input } : {}
|
|
3043
|
+
...input !== void 0 ? { input } : {},
|
|
3044
|
+
...overrides?.confirmationId !== void 0 ? { confirmationId: overrides.confirmationId } : {}
|
|
2972
3045
|
};
|
|
2973
3046
|
let result = await registry.invoke(base, { consumer: options.consumer });
|
|
2974
3047
|
if (confirmationsMode === "wait" && result.status === "error" && result.error.code === "CONFIRMATION_REQUIRED") {
|
|
@@ -3065,16 +3138,19 @@ function createAgentToolset(registry, options) {
|
|
|
3065
3138
|
additionalProperties: false
|
|
3066
3139
|
},
|
|
3067
3140
|
async execute(input) {
|
|
3068
|
-
const
|
|
3141
|
+
const requested = input?.scope;
|
|
3142
|
+
const effective = intersectScope(options.scope, requested);
|
|
3069
3143
|
const snapshot = registry.snapshot({
|
|
3070
3144
|
consumer: options.consumer,
|
|
3071
|
-
...
|
|
3145
|
+
...effective.scope ? { scope: effective.scope } : {},
|
|
3146
|
+
...options.budget ? { budget: options.budget } : {}
|
|
3072
3147
|
});
|
|
3148
|
+
const projected = effective.empty ? { ...snapshot, components: [], procedures: [] } : snapshot;
|
|
3073
3149
|
return {
|
|
3074
3150
|
status: "ok",
|
|
3075
3151
|
invocationId: `inv_${randomBase62(12)}`,
|
|
3076
3152
|
capabilityId: "meta:surface.discover",
|
|
3077
|
-
output: JSON.parse(JSON.stringify(
|
|
3153
|
+
output: JSON.parse(JSON.stringify(projected)),
|
|
3078
3154
|
surfaceVersion: snapshot.surfaceVersion
|
|
3079
3155
|
};
|
|
3080
3156
|
}
|
|
@@ -3094,10 +3170,12 @@ function createAgentToolset(registry, options) {
|
|
|
3094
3170
|
async execute(input, call) {
|
|
3095
3171
|
const req = input;
|
|
3096
3172
|
const snapshot = snapshotFor();
|
|
3173
|
+
const registrationId = findRegistrationId(snapshot, req.capabilityId, req.instanceId);
|
|
3097
3174
|
return invokeThroughSurface(
|
|
3098
3175
|
{
|
|
3099
3176
|
capabilityId: req.capabilityId,
|
|
3100
|
-
|
|
3177
|
+
// Unresolved → let the registry answer (AS-ADAPTER-003).
|
|
3178
|
+
...registrationId !== void 0 ? { registrationId } : {},
|
|
3101
3179
|
...req.instanceId !== void 0 ? { instanceId: req.instanceId } : {},
|
|
3102
3180
|
surfaceVersion: snapshot.surfaceVersion,
|
|
3103
3181
|
kind: "observation"
|
|
@@ -3125,36 +3203,22 @@ function createAgentToolset(registry, options) {
|
|
|
3125
3203
|
async execute(input, call) {
|
|
3126
3204
|
const req = input;
|
|
3127
3205
|
const snapshot = snapshotFor();
|
|
3128
|
-
const
|
|
3129
|
-
|
|
3206
|
+
const registrationId = findRegistrationId(snapshot, req.capabilityId, req.instanceId);
|
|
3207
|
+
return invokeThroughSurface(
|
|
3130
3208
|
{
|
|
3131
|
-
invocationId,
|
|
3132
3209
|
capabilityId: req.capabilityId,
|
|
3210
|
+
...registrationId !== void 0 ? { registrationId } : {},
|
|
3133
3211
|
...req.instanceId !== void 0 ? { instanceId: req.instanceId } : {},
|
|
3134
|
-
...findRegistrationId(snapshot, req.capabilityId, req.instanceId) ? { registrationId: findRegistrationId(snapshot, req.capabilityId, req.instanceId) } : {},
|
|
3135
3212
|
surfaceVersion: snapshot.surfaceVersion,
|
|
3136
|
-
|
|
3137
|
-
...req.confirmationId !== void 0 ? { confirmationId: req.confirmationId } : {}
|
|
3213
|
+
kind: "action"
|
|
3138
3214
|
},
|
|
3139
|
-
|
|
3215
|
+
req.input,
|
|
3216
|
+
call.toolCallId,
|
|
3217
|
+
{
|
|
3218
|
+
...req.invocationId !== void 0 ? { invocationId: req.invocationId } : {},
|
|
3219
|
+
...req.confirmationId !== void 0 ? { confirmationId: req.confirmationId } : {}
|
|
3220
|
+
}
|
|
3140
3221
|
);
|
|
3141
|
-
if (confirmationsMode === "wait" && result.status === "error" && result.error.code === "CONFIRMATION_REQUIRED" && typeof result.error.details?.confirmationId === "string") {
|
|
3142
|
-
const confirmationId = result.error.details.confirmationId;
|
|
3143
|
-
await waitForConfirmation(confirmationId);
|
|
3144
|
-
if (disposed) return result;
|
|
3145
|
-
result = await registry.invoke(
|
|
3146
|
-
{
|
|
3147
|
-
invocationId,
|
|
3148
|
-
capabilityId: req.capabilityId,
|
|
3149
|
-
...req.instanceId !== void 0 ? { instanceId: req.instanceId } : {},
|
|
3150
|
-
surfaceVersion: snapshot.surfaceVersion,
|
|
3151
|
-
...req.input !== void 0 ? { input: req.input } : {},
|
|
3152
|
-
confirmationId
|
|
3153
|
-
},
|
|
3154
|
-
{ consumer: options.consumer }
|
|
3155
|
-
);
|
|
3156
|
-
}
|
|
3157
|
-
return result;
|
|
3158
3222
|
}
|
|
3159
3223
|
}
|
|
3160
3224
|
];
|
|
@@ -3178,6 +3242,7 @@ function createAgentToolset(registry, options) {
|
|
|
3178
3242
|
const unsubscribe = registry.subscribe((event) => {
|
|
3179
3243
|
if (disposed || event.type !== "surface-changed") return;
|
|
3180
3244
|
cachedVersion = void 0;
|
|
3245
|
+
if (mode === "meta") return;
|
|
3181
3246
|
const tools = computeTools();
|
|
3182
3247
|
const signature = signatureOf(tools);
|
|
3183
3248
|
if (signature === cachedSignature) return;
|
|
@@ -3210,6 +3275,21 @@ function createAgentToolset(registry, options) {
|
|
|
3210
3275
|
}
|
|
3211
3276
|
};
|
|
3212
3277
|
}
|
|
3278
|
+
function intersectScope(floor, requested) {
|
|
3279
|
+
const hasFloor = floor !== void 0 && floor.length > 0;
|
|
3280
|
+
if (requested === void 0 || requested.length === 0) {
|
|
3281
|
+
return hasFloor ? { scope: floor, empty: false } : { empty: false };
|
|
3282
|
+
}
|
|
3283
|
+
if (!hasFloor) return { scope: requested, empty: false };
|
|
3284
|
+
const out = /* @__PURE__ */ new Set();
|
|
3285
|
+
for (const f of floor) {
|
|
3286
|
+
for (const r of requested) {
|
|
3287
|
+
if (r === f || r.startsWith(`${f}.`)) out.add(r);
|
|
3288
|
+
else if (f.startsWith(`${r}.`)) out.add(f);
|
|
3289
|
+
}
|
|
3290
|
+
}
|
|
3291
|
+
return out.size > 0 ? { scope: [...out], empty: false } : { empty: true };
|
|
3292
|
+
}
|
|
3213
3293
|
function findRegistrationId(snapshot, capabilityId, instanceId) {
|
|
3214
3294
|
const matches = [];
|
|
3215
3295
|
for (const component of snapshot.components) {
|