@agen-ai/agent-runtime 0.2.4 → 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 +48 -16
- package/dist/accountQuota/index.d.ts +3 -0
- package/dist/accountQuota/index.js +2 -0
- package/dist/accountQuota/types.d.ts +26 -0
- package/dist/accountQuota/types.js +0 -0
- package/dist/accountQuota/validation.d.ts +5 -0
- package/dist/accountQuota/validation.js +278 -0
- package/dist/environment/index.d.ts +3 -0
- package/dist/environment/index.js +2 -0
- package/dist/environment/types.d.ts +59 -0
- package/dist/environment/types.js +0 -0
- package/dist/environment/validation.d.ts +17 -0
- package/dist/environment/validation.js +533 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/interactionValidation.js +1 -3
- package/dist/providerDriver.d.ts +4 -0
- package/dist/providerInstanceRegistry.js +17 -0
- package/dist/sessionValidation.js +75 -50
- package/dist/sessions.d.ts +3 -8
- package/dist/testing/conformance.d.ts +2 -1
- package/dist/testing/conformance.js +113 -15
- package/dist/testing/fakeProvider.d.ts +4 -0
- package/dist/testing/fakeProvider.js +104 -13
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -3,20 +3,22 @@
|
|
|
3
3
|
`@agen-ai/agent-runtime` is the process-local service-provider interface for coding-agent
|
|
4
4
|
implementations. It preserves a small ownership chain: a driver parses host configuration and
|
|
5
5
|
materializes an instance; the instance owns one opaque ID, technical capabilities, an adapter,
|
|
6
|
-
readiness, and disposal; the adapter opens provider-native
|
|
7
|
-
its binding and conversation-local operations.
|
|
6
|
+
account-quota and environment discovery ports, readiness, and disposal; the adapter opens provider-native
|
|
7
|
+
sessions; each returned session owns its binding and conversation-local operations.
|
|
8
8
|
|
|
9
9
|
The runtime depends only on `@agen-ai/agent-protocol`. It has no concept of tenants, SaaS
|
|
10
10
|
workspaces, assigned users, database rows, persistence sequence, visibility, billing, host boots,
|
|
11
11
|
leases, or storage policy. A host must authorize and select an instance before calling this SPI.
|
|
12
|
-
This source package implements Agent Protocol
|
|
13
|
-
|
|
12
|
+
This source package implements Agent Protocol V9 as part of the coordinated SDK `0.3.0` contract.
|
|
13
|
+
The SDK contract version is independent of private transport and product persistence versions. This
|
|
14
|
+
is intentionally one coordinated tuple rather than a deployable mixed-version graph.
|
|
14
15
|
|
|
15
16
|
## Entrypoints
|
|
16
17
|
|
|
17
18
|
- `@agen-ai/agent-runtime` exports the public driver, instance, adapter, session, output,
|
|
18
|
-
readiness, bounded-evidence, artifact-candidate,
|
|
19
|
-
and registry APIs.
|
|
19
|
+
readiness, account-quota port validation, bounded-evidence, artifact-candidate,
|
|
20
|
+
capability-bound interaction validation, and registry APIs.
|
|
21
|
+
- `@agen-ai/agent-runtime/environment` exports the instance discovery and session observation ports.
|
|
20
22
|
- `@agen-ai/agent-runtime/testing` exports the deterministic fake provider and reusable
|
|
21
23
|
conformance runner.
|
|
22
24
|
|
|
@@ -41,13 +43,24 @@ exactly once before returning the matching session. Capability-dependent operati
|
|
|
41
43
|
`supported`/`unsupported` discriminants, and the runtime rejects handlers that disagree with the
|
|
42
44
|
instance capability declaration.
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
Sessions expose cohesive capability-matched ports:
|
|
45
47
|
configuration inventory and selection, typed operation inventory and invocation, managed-content
|
|
46
|
-
inventory,
|
|
48
|
+
inventory, environment observation, collaboration spawn/control, and generated-resource access.
|
|
47
49
|
An unsupported declaration exposes exactly `{ kind: "unsupported" }`; a supported declaration must
|
|
48
50
|
expose exactly its typed handlers. Catalogs and results are parsed again at the runtime boundary,
|
|
49
51
|
bounded by the declaration, and correlated to the offered revision and caller-owned identity.
|
|
50
52
|
|
|
53
|
+
Account-quota observation is an instance port beside the session adapter. Its four exact variants
|
|
54
|
+
are `unsupported`, `query`, `observe`, and `query_and_observe`; supported variants must expose all
|
|
55
|
+
methods named by their kind. Every operation receives an `AbortSignal`. The registry combines that
|
|
56
|
+
caller signal with the materialized-instance lifetime, parses every returned snapshot, closes an
|
|
57
|
+
observation iterator on cancellation or disposal, and preserves provider errors. Quota reads are
|
|
58
|
+
replaceable account state and never become model prompts, conversation events, turn output, or
|
|
59
|
+
execution authorization. A malformed or unavailable quota result cannot invalidate an otherwise
|
|
60
|
+
usable session.
|
|
61
|
+
|
|
62
|
+
Explicit iterator return and normal end join native cleanup for at most 1,000 ms; cleanup failure or timeout is observable. Cancellation or an existing provider failure keeps its original error while cleanup is still attempted. Iterator closure aborts its producer and removes listeners, and late native rejections remain observed.
|
|
63
|
+
|
|
51
64
|
Approval continuations are refusal-first. Before delegating to the candidate adapter, the
|
|
52
65
|
validated session proves that the request is still pending and unexpired and that a selected
|
|
53
66
|
`optionId` was offered by that exact request. Provider-emitted approval requests must correlate to
|
|
@@ -132,7 +145,7 @@ export const driver = defineAgentProviderDriver({
|
|
|
132
145
|
return input;
|
|
133
146
|
},
|
|
134
147
|
createInstance({ instanceId }): MaterializedAgentProviderInstance {
|
|
135
|
-
// Construct capabilities, adapter, readiness, and disposal here.
|
|
148
|
+
// Construct capabilities, adapter, accountQuota, readiness, and disposal here.
|
|
136
149
|
throw new Error(`Implement ${parseAgentInstanceId(instanceId)}.`);
|
|
137
150
|
},
|
|
138
151
|
});
|
|
@@ -159,6 +172,26 @@ The runtime distinguishes programmer/contract failures from provider failures:
|
|
|
159
172
|
Provider-native exceptions should be normalized or safely wrapped at the provider boundary. Do
|
|
160
173
|
not attach credentials, raw prompts, product identities, or unbounded output to public errors.
|
|
161
174
|
|
|
175
|
+
## Scoped environment observation
|
|
176
|
+
|
|
177
|
+
`MaterializedAgentProviderInstance.environment` discovers a caller-selected workspace and
|
|
178
|
+
configuration. `AgentProviderSession.environment` observes the already bound session. Both ports
|
|
179
|
+
use exact `unsupported`, `read`, or `read_and_watch` variants and declare their observed domains.
|
|
180
|
+
Unsupported domains cannot expose methods or be returned as available observations.
|
|
181
|
+
|
|
182
|
+
Every read and watch receives an `AbortSignal` and a caller-supplied `environmentId`; snapshots and
|
|
183
|
+
invalidations must echo that identity. Discovery also requires a canonical absolute working directory
|
|
184
|
+
and validated session configuration. The runtime preserves method receivers and provider exceptions,
|
|
185
|
+
combines caller cancellation with instance/session lifetime, rejects operations after disposal, and
|
|
186
|
+
closes watch iterators with bounded cleanup. It does not accept late yields or concurrent pulls.
|
|
187
|
+
The optional read execution observer runs after prechecks immediately before native delegation.
|
|
188
|
+
An environment metadata error alone does not invalidate an otherwise healthy turn session.
|
|
189
|
+
|
|
190
|
+
Inventory observation never authorizes invocation. The host owns account/workspace scope, freshness,
|
|
191
|
+
visibility, immutable content admission, and durable mutation authority. Providers should obtain
|
|
192
|
+
registered facts from their native harness and report gaps explicitly; a successful empty inventory
|
|
193
|
+
must not stand in for a failed read. No provider is required to start a model turn for discovery.
|
|
194
|
+
|
|
162
195
|
## Conformance and release
|
|
163
196
|
|
|
164
197
|
Every external driver should run `runAgentProviderConformance` from
|
|
@@ -168,13 +201,12 @@ turn/request ordering, request resolution, steering, interruption, configuration
|
|
|
168
201
|
close, and idempotent disposal. Unsupported operations must remain explicit discriminants and
|
|
169
202
|
must not expose handlers.
|
|
170
203
|
|
|
171
|
-
The
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
runtime shim or dual-protocol session surface.
|
|
204
|
+
The coordinated SDK version for this source is `0.3.0`, and the source implements Agent Protocol
|
|
205
|
+
V9. The earlier public `0.2.5` release is historical. Upgrade all three SDK packages together. Every materialized instance requires `environment` and
|
|
206
|
+
`accountQuota`; every session requires `environment`. The former standalone `integrations`
|
|
207
|
+
observation port is removed. The public runtime implements Agent Protocol V9 with one current
|
|
208
|
+
adapter/session surface. Package versions remain independent of private transport and product
|
|
209
|
+
persistence versions.
|
|
178
210
|
|
|
179
211
|
Run the clean packed-consumer proof before any release:
|
|
180
212
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { AgentAccountQuotaSnapshot, AgentProviderKey } from "@agen-ai/agent-protocol";
|
|
2
|
+
import type { MaybePromise } from "../foundation.js";
|
|
3
|
+
export interface AgentAccountQuotaQueryInput {
|
|
4
|
+
readonly signal: AbortSignal;
|
|
5
|
+
}
|
|
6
|
+
export type AgentAccountQuotaQuery = (input: AgentAccountQuotaQueryInput) => MaybePromise<AgentAccountQuotaSnapshot>;
|
|
7
|
+
export type AgentAccountQuotaObserve = (input: AgentAccountQuotaQueryInput) => AsyncIterable<AgentAccountQuotaSnapshot>;
|
|
8
|
+
export type AgentAccountQuotaPort = Readonly<{
|
|
9
|
+
kind: "unsupported";
|
|
10
|
+
}> | Readonly<{
|
|
11
|
+
kind: "query";
|
|
12
|
+
query: AgentAccountQuotaQuery;
|
|
13
|
+
}> | Readonly<{
|
|
14
|
+
kind: "observe";
|
|
15
|
+
observe: AgentAccountQuotaObserve;
|
|
16
|
+
}> | Readonly<{
|
|
17
|
+
kind: "query_and_observe";
|
|
18
|
+
query: AgentAccountQuotaQuery;
|
|
19
|
+
observe: AgentAccountQuotaObserve;
|
|
20
|
+
}>;
|
|
21
|
+
export interface ValidateAgentAccountQuotaPortInput {
|
|
22
|
+
readonly providerKey: AgentProviderKey;
|
|
23
|
+
readonly port: unknown;
|
|
24
|
+
readonly signal: AbortSignal;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=types.d.ts.map
|
|
File without changes
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AgentAccountQuotaPort, ValidateAgentAccountQuotaPortInput } from "./types.js";
|
|
2
|
+
/** Maximum time the runtime waits for a provider's native iterator cleanup. */
|
|
3
|
+
export declare const AGENT_ACCOUNT_QUOTA_ITERATOR_CLEANUP_TIMEOUT_MS = 1000;
|
|
4
|
+
export declare function validateAgentAccountQuotaPort(input: ValidateAgentAccountQuotaPortInput): AgentAccountQuotaPort;
|
|
5
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseAgentAccountQuotaSnapshot
|
|
3
|
+
} from "@agen-ai/agent-protocol";
|
|
4
|
+
import { throwAgentProviderContractError } from "../contractErrors.js";
|
|
5
|
+
import { throwIfAgentOperationAborted } from "../foundation.js";
|
|
6
|
+
const AGENT_ACCOUNT_QUOTA_ITERATOR_CLEANUP_TIMEOUT_MS = 1e3;
|
|
7
|
+
function isObject(value) {
|
|
8
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
9
|
+
}
|
|
10
|
+
function assertSignal(value, field) {
|
|
11
|
+
if (!(value instanceof AbortSignal)) {
|
|
12
|
+
throw new TypeError(`Account quota ${field} must be an AbortSignal.`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function exactKeys(value, expected) {
|
|
16
|
+
const actual = Reflect.ownKeys(value);
|
|
17
|
+
return actual.length === expected.length && actual.every((key) => typeof key === "string" && expected.includes(key)) && expected.every((key) => Object.prototype.hasOwnProperty.call(value, key));
|
|
18
|
+
}
|
|
19
|
+
function contractError(providerKey, detail) {
|
|
20
|
+
return throwAgentProviderContractError(
|
|
21
|
+
providerKey,
|
|
22
|
+
"capability_port_mismatch",
|
|
23
|
+
`Provider ${providerKey} returned an invalid account quota ${detail}.`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
function abortReason(signal) {
|
|
27
|
+
return signal.reason instanceof Error ? signal.reason : new DOMException("The agent operation was aborted.", "AbortError");
|
|
28
|
+
}
|
|
29
|
+
function awaitCancellable(candidate, signal) {
|
|
30
|
+
const providerResult = Promise.resolve(candidate);
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
let settled = false;
|
|
33
|
+
const remove = () => signal.removeEventListener("abort", onAbort);
|
|
34
|
+
const onAbort = () => {
|
|
35
|
+
if (settled) return;
|
|
36
|
+
settled = true;
|
|
37
|
+
remove();
|
|
38
|
+
reject(abortReason(signal));
|
|
39
|
+
};
|
|
40
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
41
|
+
providerResult.then(
|
|
42
|
+
(value) => {
|
|
43
|
+
if (settled) return;
|
|
44
|
+
settled = true;
|
|
45
|
+
remove();
|
|
46
|
+
resolve(value);
|
|
47
|
+
},
|
|
48
|
+
(error) => {
|
|
49
|
+
if (settled) return;
|
|
50
|
+
settled = true;
|
|
51
|
+
remove();
|
|
52
|
+
reject(error);
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
if (signal.aborted) onAbort();
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function operationSignal(input) {
|
|
59
|
+
if (!isObject(input)) {
|
|
60
|
+
throw new TypeError("Account quota operation input must be an object.");
|
|
61
|
+
}
|
|
62
|
+
assertSignal(input.signal, "operation signal");
|
|
63
|
+
return input.signal;
|
|
64
|
+
}
|
|
65
|
+
function providerIterator(providerKey, iterable) {
|
|
66
|
+
if (!isObject(iterable)) return contractError(providerKey, "observation");
|
|
67
|
+
const factory = iterable[Symbol.asyncIterator];
|
|
68
|
+
if (typeof factory !== "function") return contractError(providerKey, "observation");
|
|
69
|
+
const iterator = factory.call(iterable);
|
|
70
|
+
if (!isObject(iterator)) return contractError(providerKey, "observation iterator");
|
|
71
|
+
const next = iterator.next;
|
|
72
|
+
if (typeof next !== "function") return contractError(providerKey, "observation iterator");
|
|
73
|
+
const returnMethod = iterator.return;
|
|
74
|
+
if (returnMethod !== void 0 && typeof returnMethod !== "function") {
|
|
75
|
+
return contractError(providerKey, "observation iterator");
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
iterator,
|
|
79
|
+
next,
|
|
80
|
+
returnMethod
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function iteratorResult(value) {
|
|
84
|
+
if (!isObject(value)) return false;
|
|
85
|
+
const done = value.done;
|
|
86
|
+
return done === void 0 || typeof done === "boolean";
|
|
87
|
+
}
|
|
88
|
+
function boundedCleanup(result, providerKey) {
|
|
89
|
+
let timer;
|
|
90
|
+
const timeout = new Promise((_, reject) => {
|
|
91
|
+
timer = setTimeout(() => reject(new Error(
|
|
92
|
+
`Provider ${providerKey} account quota iterator cleanup exceeded ${AGENT_ACCOUNT_QUOTA_ITERATOR_CLEANUP_TIMEOUT_MS}ms.`
|
|
93
|
+
)), AGENT_ACCOUNT_QUOTA_ITERATOR_CLEANUP_TIMEOUT_MS);
|
|
94
|
+
});
|
|
95
|
+
return Promise.race([Promise.resolve(result), timeout]).then(() => void 0).finally(() => {
|
|
96
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
function beginCleanup(state) {
|
|
100
|
+
if (state.cleanupPromise !== void 0) return state.cleanupPromise;
|
|
101
|
+
const source = state.source;
|
|
102
|
+
if (source === void 0) return Promise.resolve();
|
|
103
|
+
if (source.returnMethod === void 0) {
|
|
104
|
+
state.cleanupPromise = Promise.resolve();
|
|
105
|
+
} else {
|
|
106
|
+
try {
|
|
107
|
+
state.cleanupPromise = boundedCleanup(
|
|
108
|
+
source.returnMethod.call(source.iterator),
|
|
109
|
+
state.providerKey
|
|
110
|
+
);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
state.cleanupPromise = Promise.reject(error);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
state.cleanupPromise.catch(() => void 0);
|
|
116
|
+
return state.cleanupPromise;
|
|
117
|
+
}
|
|
118
|
+
function closeState(state) {
|
|
119
|
+
if (state.closed) {
|
|
120
|
+
void beginCleanup(state);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
state.closed = true;
|
|
124
|
+
state.signal.removeEventListener("abort", state.onAbort);
|
|
125
|
+
if (!state.controller.signal.aborted) state.controller.abort();
|
|
126
|
+
void beginCleanup(state);
|
|
127
|
+
}
|
|
128
|
+
function createIterator(providerKey, declaredObserve, receiver, lifetimeSignal, operationSignalValue) {
|
|
129
|
+
const controller = new AbortController();
|
|
130
|
+
const signal = AbortSignal.any([
|
|
131
|
+
lifetimeSignal,
|
|
132
|
+
operationSignalValue,
|
|
133
|
+
controller.signal
|
|
134
|
+
]);
|
|
135
|
+
const state = {
|
|
136
|
+
providerKey,
|
|
137
|
+
controller,
|
|
138
|
+
signal,
|
|
139
|
+
onAbort: () => closeState(state),
|
|
140
|
+
closed: false,
|
|
141
|
+
closedNormally: false,
|
|
142
|
+
pendingNext: false
|
|
143
|
+
};
|
|
144
|
+
if (signal.aborted) closeState(state);
|
|
145
|
+
else signal.addEventListener("abort", state.onAbort, { once: true });
|
|
146
|
+
const source = () => {
|
|
147
|
+
if (state.source !== void 0) return state.source;
|
|
148
|
+
throwIfAgentOperationAborted(signal);
|
|
149
|
+
const iterable = declaredObserve.call(receiver, { signal });
|
|
150
|
+
state.source = providerIterator(providerKey, iterable);
|
|
151
|
+
if (signal.aborted) closeState(state);
|
|
152
|
+
return state.source;
|
|
153
|
+
};
|
|
154
|
+
const next = async () => {
|
|
155
|
+
if (state.pendingNext) {
|
|
156
|
+
throw new TypeError("Concurrent account quota observation next calls are not supported.");
|
|
157
|
+
}
|
|
158
|
+
if (state.closed) {
|
|
159
|
+
if (state.closedNormally || !signal.aborted) return { done: true, value: void 0 };
|
|
160
|
+
throwIfAgentOperationAborted(signal);
|
|
161
|
+
}
|
|
162
|
+
throwIfAgentOperationAborted(signal);
|
|
163
|
+
state.pendingNext = true;
|
|
164
|
+
try {
|
|
165
|
+
const iterator = source();
|
|
166
|
+
throwIfAgentOperationAborted(signal);
|
|
167
|
+
const result = await awaitCancellable(iterator.next.call(iterator.iterator), signal);
|
|
168
|
+
throwIfAgentOperationAborted(signal);
|
|
169
|
+
if (!iteratorResult(result)) return contractError(providerKey, "observation");
|
|
170
|
+
if (result.done === true) {
|
|
171
|
+
state.closedNormally = true;
|
|
172
|
+
closeState(state);
|
|
173
|
+
await beginCleanup(state);
|
|
174
|
+
return { done: true, value: void 0 };
|
|
175
|
+
}
|
|
176
|
+
return { done: false, value: parseAgentAccountQuotaSnapshot(result.value) };
|
|
177
|
+
} catch (error) {
|
|
178
|
+
closeState(state);
|
|
179
|
+
throw error;
|
|
180
|
+
} finally {
|
|
181
|
+
state.pendingNext = false;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
const returnIterator = async (value) => {
|
|
185
|
+
state.closedNormally = true;
|
|
186
|
+
state.controller.abort();
|
|
187
|
+
closeState(state);
|
|
188
|
+
await beginCleanup(state);
|
|
189
|
+
return { done: true, value };
|
|
190
|
+
};
|
|
191
|
+
return { next, return: returnIterator };
|
|
192
|
+
}
|
|
193
|
+
function wrapQuery(declaredQuery, receiver, lifetimeSignal) {
|
|
194
|
+
return async (input) => {
|
|
195
|
+
const signal = AbortSignal.any([lifetimeSignal, operationSignal(input)]);
|
|
196
|
+
throwIfAgentOperationAborted(signal);
|
|
197
|
+
const candidate = declaredQuery.call(receiver, { signal });
|
|
198
|
+
const snapshot = await awaitCancellable(candidate, signal);
|
|
199
|
+
throwIfAgentOperationAborted(signal);
|
|
200
|
+
return parseAgentAccountQuotaSnapshot(snapshot);
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function wrapObserve(providerKey, declaredObserve, receiver, lifetimeSignal) {
|
|
204
|
+
return (input) => {
|
|
205
|
+
const operationSignalValue = operationSignal(input);
|
|
206
|
+
return {
|
|
207
|
+
[Symbol.asyncIterator]() {
|
|
208
|
+
return createIterator(
|
|
209
|
+
providerKey,
|
|
210
|
+
declaredObserve,
|
|
211
|
+
receiver,
|
|
212
|
+
lifetimeSignal,
|
|
213
|
+
operationSignalValue
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function validateShape(providerKey, candidate) {
|
|
220
|
+
if (!isObject(candidate)) return contractError(providerKey, "port");
|
|
221
|
+
const kind = candidate.kind;
|
|
222
|
+
const query = candidate.query;
|
|
223
|
+
const observe = candidate.observe;
|
|
224
|
+
if (kind === "unsupported") {
|
|
225
|
+
if (!exactKeys(candidate, ["kind"]) || "query" in candidate || "observe" in candidate) {
|
|
226
|
+
return contractError(providerKey, "port");
|
|
227
|
+
}
|
|
228
|
+
return Object.freeze({ kind: "unsupported" });
|
|
229
|
+
}
|
|
230
|
+
if (kind === "query") {
|
|
231
|
+
if (!exactKeys(candidate, ["kind", "query"]) || typeof query !== "function" || "observe" in candidate) {
|
|
232
|
+
return contractError(providerKey, "port");
|
|
233
|
+
}
|
|
234
|
+
return candidate;
|
|
235
|
+
}
|
|
236
|
+
if (kind === "observe") {
|
|
237
|
+
if (!exactKeys(candidate, ["kind", "observe"]) || typeof observe !== "function" || "query" in candidate) {
|
|
238
|
+
return contractError(providerKey, "port");
|
|
239
|
+
}
|
|
240
|
+
return candidate;
|
|
241
|
+
}
|
|
242
|
+
if (kind === "query_and_observe") {
|
|
243
|
+
if (!exactKeys(candidate, ["kind", "query", "observe"]) || typeof query !== "function" || typeof observe !== "function") {
|
|
244
|
+
return contractError(providerKey, "port");
|
|
245
|
+
}
|
|
246
|
+
return candidate;
|
|
247
|
+
}
|
|
248
|
+
return contractError(providerKey, "port");
|
|
249
|
+
}
|
|
250
|
+
function validateAgentAccountQuotaPort(input) {
|
|
251
|
+
if (!isObject(input)) {
|
|
252
|
+
throw new TypeError("Account quota port validation input must be an object.");
|
|
253
|
+
}
|
|
254
|
+
assertSignal(input.signal, "instance signal");
|
|
255
|
+
const declared = validateShape(input.providerKey, input.port);
|
|
256
|
+
if (declared.kind === "unsupported") return declared;
|
|
257
|
+
if (declared.kind === "query") {
|
|
258
|
+
return Object.freeze({
|
|
259
|
+
kind: "query",
|
|
260
|
+
query: wrapQuery(declared.query, declared, input.signal)
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
if (declared.kind === "observe") {
|
|
264
|
+
return Object.freeze({
|
|
265
|
+
kind: "observe",
|
|
266
|
+
observe: wrapObserve(input.providerKey, declared.observe, declared, input.signal)
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
return Object.freeze({
|
|
270
|
+
kind: "query_and_observe",
|
|
271
|
+
query: wrapQuery(declared.query, declared, input.signal),
|
|
272
|
+
observe: wrapObserve(input.providerKey, declared.observe, declared, input.signal)
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
export {
|
|
276
|
+
AGENT_ACCOUNT_QUOTA_ITERATOR_CLEANUP_TIMEOUT_MS,
|
|
277
|
+
validateAgentAccountQuotaPort
|
|
278
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { AgentEnvironmentDomain, AgentEnvironmentId, AgentEnvironmentInvalidation, AgentEnvironmentSnapshot, AgentSessionConfiguration } from "@agen-ai/agent-protocol";
|
|
2
|
+
import type { AgentProviderExecutionStartedObserver } from "../sessions.js";
|
|
3
|
+
/** Input supplied when a materialized instance discovers its host-scoped environment. */
|
|
4
|
+
export interface AgentEnvironmentDiscoveryInput {
|
|
5
|
+
readonly signal: AbortSignal;
|
|
6
|
+
readonly environmentId: AgentEnvironmentId;
|
|
7
|
+
readonly workingDirectory: string;
|
|
8
|
+
readonly configuration: AgentSessionConfiguration;
|
|
9
|
+
/** Runtime receipt invoked immediately before the provider read candidate. */
|
|
10
|
+
readonly onProviderExecutionStarted?: AgentProviderExecutionStartedObserver;
|
|
11
|
+
}
|
|
12
|
+
/** Input supplied to a discovery watch. Watches have no provider-start receipt. */
|
|
13
|
+
export interface AgentEnvironmentDiscoveryWatchInput {
|
|
14
|
+
readonly signal: AbortSignal;
|
|
15
|
+
readonly environmentId: AgentEnvironmentId;
|
|
16
|
+
readonly workingDirectory: string;
|
|
17
|
+
readonly configuration: AgentSessionConfiguration;
|
|
18
|
+
}
|
|
19
|
+
/** Input supplied when an opened provider session observes its bound environment. */
|
|
20
|
+
export interface AgentEnvironmentObservationInput {
|
|
21
|
+
readonly signal: AbortSignal;
|
|
22
|
+
readonly environmentId: AgentEnvironmentId;
|
|
23
|
+
/** Runtime receipt invoked immediately before the provider read candidate. */
|
|
24
|
+
readonly onProviderExecutionStarted?: AgentProviderExecutionStartedObserver;
|
|
25
|
+
}
|
|
26
|
+
/** Input supplied to an observation watch. Watches have no provider-start receipt. */
|
|
27
|
+
export interface AgentEnvironmentObservationWatchInput {
|
|
28
|
+
readonly signal: AbortSignal;
|
|
29
|
+
readonly environmentId: AgentEnvironmentId;
|
|
30
|
+
}
|
|
31
|
+
export type AgentEnvironmentDiscovery = (input: AgentEnvironmentDiscoveryInput) => Promise<AgentEnvironmentSnapshot>;
|
|
32
|
+
export type AgentEnvironmentObservation = (input: AgentEnvironmentObservationInput) => Promise<AgentEnvironmentSnapshot>;
|
|
33
|
+
export type AgentEnvironmentDiscoveryWatch = (input: AgentEnvironmentDiscoveryWatchInput) => AsyncIterable<AgentEnvironmentInvalidation>;
|
|
34
|
+
export type AgentEnvironmentObservationWatch = (input: AgentEnvironmentObservationWatchInput) => AsyncIterable<AgentEnvironmentInvalidation>;
|
|
35
|
+
export type AgentEnvironmentDiscoveryPort = Readonly<{
|
|
36
|
+
kind: "unsupported";
|
|
37
|
+
}> | Readonly<{
|
|
38
|
+
kind: "read";
|
|
39
|
+
domains: readonly AgentEnvironmentDomain[];
|
|
40
|
+
readEnvironment: AgentEnvironmentDiscovery;
|
|
41
|
+
}> | Readonly<{
|
|
42
|
+
kind: "read_and_watch";
|
|
43
|
+
domains: readonly AgentEnvironmentDomain[];
|
|
44
|
+
readEnvironment: AgentEnvironmentDiscovery;
|
|
45
|
+
watchEnvironment: AgentEnvironmentDiscoveryWatch;
|
|
46
|
+
}>;
|
|
47
|
+
export type AgentEnvironmentObservationPort = Readonly<{
|
|
48
|
+
kind: "unsupported";
|
|
49
|
+
}> | Readonly<{
|
|
50
|
+
kind: "read";
|
|
51
|
+
domains: readonly AgentEnvironmentDomain[];
|
|
52
|
+
readEnvironment: AgentEnvironmentObservation;
|
|
53
|
+
}> | Readonly<{
|
|
54
|
+
kind: "read_and_watch";
|
|
55
|
+
domains: readonly AgentEnvironmentDomain[];
|
|
56
|
+
readEnvironment: AgentEnvironmentObservation;
|
|
57
|
+
watchEnvironment: AgentEnvironmentObservationWatch;
|
|
58
|
+
}>;
|
|
59
|
+
//# sourceMappingURL=types.d.ts.map
|
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type AgentCapabilities, type AgentProviderKey } from "@agen-ai/agent-protocol";
|
|
2
|
+
import type { AgentEnvironmentDiscoveryPort, AgentEnvironmentObservationPort } from "./types.js";
|
|
3
|
+
/** Maximum time allowed for a native watch iterator's return method to settle. */
|
|
4
|
+
export declare const AGENT_ENVIRONMENT_ITERATOR_CLEANUP_TIMEOUT_MS = 1000;
|
|
5
|
+
export declare function validateAgentEnvironmentDiscoveryPort(input: Readonly<{
|
|
6
|
+
readonly providerKey: AgentProviderKey;
|
|
7
|
+
readonly capability: AgentCapabilities["environment"]["instance"];
|
|
8
|
+
readonly port: unknown;
|
|
9
|
+
readonly signal: AbortSignal;
|
|
10
|
+
}>): AgentEnvironmentDiscoveryPort;
|
|
11
|
+
export declare function validateAgentEnvironmentObservationPort(input: Readonly<{
|
|
12
|
+
readonly providerKey: AgentProviderKey;
|
|
13
|
+
readonly capability: AgentCapabilities["environment"]["session"];
|
|
14
|
+
readonly port: unknown;
|
|
15
|
+
readonly signal: AbortSignal;
|
|
16
|
+
}>): AgentEnvironmentObservationPort;
|
|
17
|
+
//# sourceMappingURL=validation.d.ts.map
|