@agen-ai/agent-runtime 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.
- package/LICENSE +21 -0
- package/README.md +139 -0
- package/dist/adapterValidation.d.ts +4 -0
- package/dist/adapterValidation.js +242 -0
- package/dist/artifacts.d.ts +28 -0
- package/dist/artifacts.js +87 -0
- package/dist/configurationValidation.d.ts +3 -0
- package/dist/configurationValidation.js +35 -0
- package/dist/contractErrors.d.ts +17 -0
- package/dist/contractErrors.js +59 -0
- package/dist/evidence.d.ts +50 -0
- package/dist/evidence.js +368 -0
- package/dist/foundation.d.ts +8 -0
- package/dist/foundation.js +37 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +12 -0
- package/dist/internal/controlCharacters.d.ts +2 -0
- package/dist/internal/controlCharacters.js +7 -0
- package/dist/internal/serializedJsonBytes.d.ts +3 -0
- package/dist/internal/serializedJsonBytes.js +57 -0
- package/dist/outputValidation.d.ts +13 -0
- package/dist/outputValidation.js +174 -0
- package/dist/outputs.d.ts +81 -0
- package/dist/outputs.js +217 -0
- package/dist/providerCatalog.d.ts +13 -0
- package/dist/providerCatalog.js +33 -0
- package/dist/providerDriver.d.ts +41 -0
- package/dist/providerDriver.js +52 -0
- package/dist/providerInstanceRegistry.d.ts +40 -0
- package/dist/providerInstanceRegistry.js +322 -0
- package/dist/readiness.d.ts +22 -0
- package/dist/readiness.js +58 -0
- package/dist/sessionValidation.d.ts +19 -0
- package/dist/sessionValidation.js +767 -0
- package/dist/sessions.d.ts +133 -0
- package/dist/sessions.js +0 -0
- package/dist/steeringValidation.d.ts +4 -0
- package/dist/steeringValidation.js +36 -0
- package/dist/testing/conformance.d.ts +30 -0
- package/dist/testing/conformance.js +379 -0
- package/dist/testing/fakeProvider.d.ts +35 -0
- package/dist/testing/fakeProvider.js +367 -0
- package/dist/testing/index.d.ts +3 -0
- package/dist/testing/index.js +2 -0
- package/dist/text.d.ts +2 -0
- package/dist/text.js +16 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Trevor Nichols
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# `@agen-ai/agent-runtime`
|
|
2
|
+
|
|
3
|
+
`@agen-ai/agent-runtime` is the process-local service-provider interface for coding-agent
|
|
4
|
+
implementations. It preserves a small ownership chain: a driver parses host configuration and
|
|
5
|
+
materializes an instance; the instance owns one opaque ID, technical capabilities, an adapter,
|
|
6
|
+
readiness, and disposal; the adapter opens provider-native sessions; each returned session owns
|
|
7
|
+
its binding and conversation-local operations.
|
|
8
|
+
|
|
9
|
+
The runtime depends only on `@agen-ai/agent-protocol`. It has no concept of tenants, SaaS
|
|
10
|
+
workspaces, assigned users, database rows, persistence sequence, visibility, billing, host boots,
|
|
11
|
+
leases, or storage policy. A host must authorize and select an instance before calling this SPI.
|
|
12
|
+
|
|
13
|
+
## Entrypoints
|
|
14
|
+
|
|
15
|
+
- `@agen-ai/agent-runtime` exports the public driver, instance, adapter, session, output,
|
|
16
|
+
readiness, bounded-evidence, artifact-candidate, and registry APIs.
|
|
17
|
+
- `@agen-ai/agent-runtime/testing` exports the deterministic fake provider and reusable
|
|
18
|
+
conformance runner.
|
|
19
|
+
|
|
20
|
+
## Lifecycle and ownership
|
|
21
|
+
|
|
22
|
+
1. Define an `AgentProviderDriver` with `defineAgentProviderDriver`.
|
|
23
|
+
2. Give caller-owned instance definitions to `createAgentProviderRegistry`.
|
|
24
|
+
3. Select a materialized instance by opaque `instanceId`.
|
|
25
|
+
4. Create, resume, or branch a provider session through its adapter.
|
|
26
|
+
5. Consume each `runTurn` or `resolveRequest` output stream incrementally. Neutral `AgentEvent`
|
|
27
|
+
output carries bounded provider source evidence atomically. A `request.opened` output may also
|
|
28
|
+
carry separately bounded, non-truncated provider request context for continuation; lifecycle,
|
|
29
|
+
authentication, artifact, and standalone diagnostic evidence remain separate output variants.
|
|
30
|
+
Evidence reports an exact truncation reason. `originalDataBytes` is `null` when a structural
|
|
31
|
+
collection, depth, object-key, cycle, accessor, unsupported-value, or inspectability constraint
|
|
32
|
+
prevents honest measurement of the original provider payload.
|
|
33
|
+
6. Close sessions idempotently, then dispose the instance or registry.
|
|
34
|
+
|
|
35
|
+
Instance IDs never repeat in session calls. `workingDirectory` is resolved by the host and is not
|
|
36
|
+
an authorization credential. Create and branch implementations must invoke `onBindingCreated`
|
|
37
|
+
exactly once before returning the matching session. Capability-dependent operations use explicit
|
|
38
|
+
`supported`/`unsupported` discriminants, and the runtime rejects handlers that disagree with the
|
|
39
|
+
instance capability declaration.
|
|
40
|
+
|
|
41
|
+
The host should serialize mutating operations for a given session. Separate session objects may
|
|
42
|
+
run concurrently, so provider implementations must isolate their conversation-local state.
|
|
43
|
+
`runTurn` and `resolveRequest` both preserve consumer backpressure: the provider does not resume
|
|
44
|
+
until the consumer requests the next output. Each stream must end at a completed turn or exactly
|
|
45
|
+
one newly pending request. If a consumer abandons a stream, a provider throws, or either stream
|
|
46
|
+
ends before that stable boundary, the validated session becomes unusable and must be closed rather
|
|
47
|
+
than retried. The validated `runTurn` input may observe `onProviderExecutionStarted`; validation
|
|
48
|
+
invokes it exactly at candidate-port delegation, after runtime prechecks pass, and never forwards it
|
|
49
|
+
to the candidate adapter. A delegated mutating operation that throws or returns an invalid result
|
|
50
|
+
has the same effect. Pre-aborted operations fail with `AbortError`; close and disposal must be safe
|
|
51
|
+
to call repeatedly. An accepted interruption of an already-waiting turn does not prove that the
|
|
52
|
+
turn terminalized; unless the result also carries a terminal event, the validated session becomes
|
|
53
|
+
unusable and must be closed and rematerialized. A close failure makes the session unusable while
|
|
54
|
+
leaving close itself retryable.
|
|
55
|
+
|
|
56
|
+
When `capabilities.turns.steer` is true, the session exposes `steering.steerTurn`. Steering accepts
|
|
57
|
+
the existing turn ID plus the same canonical `parts` and optional `summary` used to start a turn.
|
|
58
|
+
It does not create or own an output stream: model output continues on the original `runTurn`
|
|
59
|
+
iterator. The receipt is exactly `delivered`, `rejected` with a bounded neutral error, or
|
|
60
|
+
`delivery_uncertain` with a bounded neutral error. A provider must use uncertainty when delivery
|
|
61
|
+
may have started but its authoritative acknowledgement was lost; callers cannot safely replay that
|
|
62
|
+
result. The validated runtime preserves pre-delegation validation and abort errors unchanged, while
|
|
63
|
+
provider-delegated steering failures throw `AgentProviderDelegatedOperationError` with the original
|
|
64
|
+
cause and explicit started-execution evidence so a host can retire the unusable session. Platform
|
|
65
|
+
scheduling and provider-native queue modes are intentionally outside this SPI.
|
|
66
|
+
|
|
67
|
+
## Minimal driver
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import {
|
|
71
|
+
defineAgentProviderDriver,
|
|
72
|
+
type MaterializedAgentProviderInstance,
|
|
73
|
+
} from "@agen-ai/agent-runtime";
|
|
74
|
+
import {
|
|
75
|
+
parseAgentInstanceId,
|
|
76
|
+
parseAgentProviderKey,
|
|
77
|
+
} from "@agen-ai/agent-protocol";
|
|
78
|
+
|
|
79
|
+
const providerKey = parseAgentProviderKey("third-party-provider");
|
|
80
|
+
|
|
81
|
+
export const driver = defineAgentProviderDriver({
|
|
82
|
+
providerKey,
|
|
83
|
+
supportsMultipleInstances: true,
|
|
84
|
+
parseConfiguration(input) {
|
|
85
|
+
if (input === null || typeof input !== "object")
|
|
86
|
+
throw new TypeError("Invalid config.");
|
|
87
|
+
return input;
|
|
88
|
+
},
|
|
89
|
+
createInstance({ instanceId }): MaterializedAgentProviderInstance {
|
|
90
|
+
// Construct capabilities, adapter, readiness, and disposal here.
|
|
91
|
+
throw new Error(`Implement ${parseAgentInstanceId(instanceId)}.`);
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Use the `/testing` conformance runner for lifecycle, binding, turn-ordering, live steering and
|
|
97
|
+
interruption, interaction results, capability ports, cancellation, close, and disposal checks.
|
|
98
|
+
Registry publication and provider package discovery are intentionally outside this package.
|
|
99
|
+
|
|
100
|
+
## Errors and cancellation
|
|
101
|
+
|
|
102
|
+
The runtime distinguishes programmer/contract failures from provider failures:
|
|
103
|
+
|
|
104
|
+
- `AgentProviderContractError` reports a stable `code` when an adapter contradicts its declared
|
|
105
|
+
capabilities, emits invalid output, violates turn/request ordering, or returns a mismatched
|
|
106
|
+
binding.
|
|
107
|
+
- `AgentProviderRegistryError` reports stable registry/materialization/disposal codes and retains
|
|
108
|
+
provider/instance correlation when available.
|
|
109
|
+
- `AgentProviderConfigurationError` wraps driver configuration rejection without exposing product
|
|
110
|
+
configuration policy.
|
|
111
|
+
- malformed primitive input may raise `TypeError` or `RangeError`; an aborted operation preserves
|
|
112
|
+
an `AbortError`-named reason.
|
|
113
|
+
|
|
114
|
+
Provider-native exceptions should be normalized or safely wrapped at the provider boundary. Do
|
|
115
|
+
not attach credentials, raw prompts, product identities, or unbounded output to public errors.
|
|
116
|
+
|
|
117
|
+
## Conformance and release
|
|
118
|
+
|
|
119
|
+
Every external driver should run `runAgentProviderConformance` from
|
|
120
|
+
`@agen-ai/agent-runtime/testing`. The deterministic suite exercises duplicate-instance rejection,
|
|
121
|
+
instance identity, capabilities, readiness, create/resume/branch, binding callbacks, abort,
|
|
122
|
+
turn/request ordering, request resolution, steering, interruption, configuration, idempotent
|
|
123
|
+
close, and idempotent disposal. Unsupported operations must remain explicit discriminants and
|
|
124
|
+
must not expose handlers.
|
|
125
|
+
|
|
126
|
+
The package is at `0.1.0` while the public SPI is being proven with external adapters. Minor
|
|
127
|
+
releases may include breaking changes during this beta period, and those changes will be called out
|
|
128
|
+
in the release notes.
|
|
129
|
+
|
|
130
|
+
The current version tuple is Agent Protocol V6, private host V14/catalog V8, and Workspaces event V8.
|
|
131
|
+
The runtime package version remains independent of Agent Protocol V6.
|
|
132
|
+
|
|
133
|
+
Run the clean packed-consumer proof before any release:
|
|
134
|
+
|
|
135
|
+
From the public repository root, run `pnpm check`.
|
|
136
|
+
|
|
137
|
+
It installs tarballs into a temporary project outside the workspace, typechecks every documented
|
|
138
|
+
entrypoint, runs the fake provider and parser flow, and removes the temporary directory. It never
|
|
139
|
+
publishes or accesses release credentials.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type AgentCapabilities } from "@agen-ai/agent-protocol";
|
|
2
|
+
import type { AgentProviderAdapter } from "./sessions.js";
|
|
3
|
+
export declare function validateAgentProviderAdapter(capabilityInput: AgentCapabilities, adapter: AgentProviderAdapter): AgentProviderAdapter;
|
|
4
|
+
//# sourceMappingURL=adapterValidation.d.ts.map
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import {
|
|
3
|
+
parseAgentCapabilities,
|
|
4
|
+
parseAgentIsoDateTime,
|
|
5
|
+
parseAgentSessionOpenInput
|
|
6
|
+
} from "@agen-ai/agent-protocol";
|
|
7
|
+
import {
|
|
8
|
+
assertAgentSessionConfigurationSupported
|
|
9
|
+
} from "./configurationValidation.js";
|
|
10
|
+
import { throwAgentProviderContractError } from "./contractErrors.js";
|
|
11
|
+
import {
|
|
12
|
+
parseAgentProviderTechnicalId,
|
|
13
|
+
throwIfAgentOperationAborted
|
|
14
|
+
} from "./foundation.js";
|
|
15
|
+
import { containsAgentControlCharacter } from "./internal/controlCharacters.js";
|
|
16
|
+
import {
|
|
17
|
+
validateAgentProviderOperationResult,
|
|
18
|
+
validateAgentProviderOutputForContext
|
|
19
|
+
} from "./outputValidation.js";
|
|
20
|
+
import {
|
|
21
|
+
closeRejectedAgentProviderSession,
|
|
22
|
+
openIdentityCreatingAgentProviderSession,
|
|
23
|
+
validateAgentProviderSession
|
|
24
|
+
} from "./sessionValidation.js";
|
|
25
|
+
function parseWorkingDirectory(value) {
|
|
26
|
+
if (value.length < 1 || value.length > 4096 || !path.isAbsolute(value) || path.normalize(value) !== value || containsAgentControlCharacter(value)) {
|
|
27
|
+
throw new TypeError(
|
|
28
|
+
"Provider workingDirectory must be a canonical absolute path."
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
function assertAuthenticationOutputKind(providerKey, output) {
|
|
34
|
+
if (["authentication", "lifecycle", "evidence"].includes(output.kind)) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
throwAgentProviderContractError(
|
|
38
|
+
providerKey,
|
|
39
|
+
"output_capability_mismatch",
|
|
40
|
+
"Authentication may emit only authentication, lifecycle, or evidence output."
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
function validateAgentProviderAdapter(capabilityInput, adapter) {
|
|
44
|
+
const capabilities = parseAgentCapabilities(capabilityInput);
|
|
45
|
+
if (adapter === null || typeof adapter !== "object" || typeof adapter.createSession !== "function" || adapter.resumption === null || typeof adapter.resumption !== "object" || !["supported", "unsupported"].includes(adapter.resumption.kind) || adapter.resumption.kind === "supported" && typeof adapter.resumption.resumeSession !== "function" || adapter.branching === null || typeof adapter.branching !== "object" || !["through_turn", "unsupported"].includes(adapter.branching.kind) || adapter.branching.kind === "through_turn" && typeof adapter.branching.branchSession !== "function" || adapter.authentication === null || typeof adapter.authentication !== "object" || !["supported", "unsupported"].includes(adapter.authentication.kind) || adapter.authentication.kind === "supported" && (typeof adapter.authentication.start !== "function" || typeof adapter.authentication.cancel !== "function")) {
|
|
46
|
+
throwAgentProviderContractError(
|
|
47
|
+
capabilities.providerKey,
|
|
48
|
+
"invalid_adapter",
|
|
49
|
+
`Provider ${capabilities.providerKey} returned an incomplete adapter.`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
if (adapter.resumption.kind === "supported" !== capabilities.sessions.resume || adapter.branching.kind !== capabilities.sessions.branch.kind || adapter.authentication.kind !== capabilities.authentication.kind) {
|
|
53
|
+
throwAgentProviderContractError(
|
|
54
|
+
capabilities.providerKey,
|
|
55
|
+
"capability_port_mismatch",
|
|
56
|
+
`Provider ${capabilities.providerKey} adapter ports do not match its capabilities.`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
const declaredResumption = adapter.resumption;
|
|
60
|
+
const resumption = declaredResumption.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
|
|
61
|
+
kind: "supported",
|
|
62
|
+
resumeSession: async (resumeInput) => {
|
|
63
|
+
throwIfAgentOperationAborted(resumeInput.signal);
|
|
64
|
+
const parsed = parseAgentSessionOpenInput({
|
|
65
|
+
operation: "resume",
|
|
66
|
+
sessionId: resumeInput.sessionId,
|
|
67
|
+
binding: resumeInput.binding,
|
|
68
|
+
configuration: resumeInput.configuration
|
|
69
|
+
});
|
|
70
|
+
if (parsed.operation !== "resume") {
|
|
71
|
+
throw new TypeError("Expected a resume session input.");
|
|
72
|
+
}
|
|
73
|
+
assertAgentSessionConfigurationSupported(
|
|
74
|
+
capabilities,
|
|
75
|
+
parsed.configuration
|
|
76
|
+
);
|
|
77
|
+
const workingDirectory = parseWorkingDirectory(
|
|
78
|
+
resumeInput.workingDirectory
|
|
79
|
+
);
|
|
80
|
+
const binding = parsed.binding;
|
|
81
|
+
const candidate = await declaredResumption.resumeSession({
|
|
82
|
+
sessionId: parsed.sessionId,
|
|
83
|
+
workingDirectory,
|
|
84
|
+
binding,
|
|
85
|
+
configuration: parsed.configuration,
|
|
86
|
+
...resumeInput.signal === void 0 ? {} : { signal: resumeInput.signal }
|
|
87
|
+
});
|
|
88
|
+
try {
|
|
89
|
+
return validateAgentProviderSession({
|
|
90
|
+
capabilities,
|
|
91
|
+
sessionId: parsed.sessionId,
|
|
92
|
+
candidate,
|
|
93
|
+
expectedBinding: binding
|
|
94
|
+
});
|
|
95
|
+
} catch (error) {
|
|
96
|
+
return closeRejectedAgentProviderSession(candidate, error);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
const declaredBranching = adapter.branching;
|
|
101
|
+
const branching = declaredBranching.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
|
|
102
|
+
kind: "through_turn",
|
|
103
|
+
branchSession: async (branchInput) => {
|
|
104
|
+
throwIfAgentOperationAborted(branchInput.signal);
|
|
105
|
+
const parsed = parseAgentSessionOpenInput({
|
|
106
|
+
operation: "branch",
|
|
107
|
+
sessionId: branchInput.sessionId,
|
|
108
|
+
source: branchInput.source,
|
|
109
|
+
configuration: branchInput.configuration
|
|
110
|
+
});
|
|
111
|
+
if (parsed.operation !== "branch") {
|
|
112
|
+
throw new TypeError("Expected a branch session input.");
|
|
113
|
+
}
|
|
114
|
+
assertAgentSessionConfigurationSupported(
|
|
115
|
+
capabilities,
|
|
116
|
+
parsed.configuration
|
|
117
|
+
);
|
|
118
|
+
const workingDirectory = parseWorkingDirectory(
|
|
119
|
+
branchInput.workingDirectory
|
|
120
|
+
);
|
|
121
|
+
const sourceBinding = parsed.source.binding;
|
|
122
|
+
return openIdentityCreatingAgentProviderSession({
|
|
123
|
+
capabilities,
|
|
124
|
+
sessionId: parsed.sessionId,
|
|
125
|
+
observer: branchInput.onBindingCreated,
|
|
126
|
+
sourceBinding,
|
|
127
|
+
open: (observer) => declaredBranching.branchSession({
|
|
128
|
+
sessionId: parsed.sessionId,
|
|
129
|
+
workingDirectory,
|
|
130
|
+
source: parsed.source,
|
|
131
|
+
configuration: parsed.configuration,
|
|
132
|
+
onBindingCreated: observer,
|
|
133
|
+
...branchInput.signal === void 0 ? {} : { signal: branchInput.signal }
|
|
134
|
+
})
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
const declaredAuthentication = adapter.authentication;
|
|
139
|
+
const authenticationFlows = capabilities.authentication.kind === "supported" ? capabilities.authentication.flows : [];
|
|
140
|
+
const authentication = declaredAuthentication.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
|
|
141
|
+
kind: "supported",
|
|
142
|
+
start: async function* (authInput) {
|
|
143
|
+
throwIfAgentOperationAborted(authInput.signal);
|
|
144
|
+
const attemptId = parseAgentProviderTechnicalId(
|
|
145
|
+
authInput.attemptId,
|
|
146
|
+
"authentication attemptId"
|
|
147
|
+
);
|
|
148
|
+
if (!authenticationFlows.includes(authInput.flow)) {
|
|
149
|
+
throwAgentProviderContractError(
|
|
150
|
+
capabilities.providerKey,
|
|
151
|
+
"input_capability_mismatch",
|
|
152
|
+
"Agent authentication flow is not declared by provider capabilities."
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
const deadlineAt = authInput.deadlineAt === void 0 ? void 0 : parseAgentIsoDateTime(authInput.deadlineAt);
|
|
156
|
+
for await (const candidate of declaredAuthentication.start({
|
|
157
|
+
attemptId,
|
|
158
|
+
flow: authInput.flow,
|
|
159
|
+
...deadlineAt === void 0 ? {} : { deadlineAt },
|
|
160
|
+
...authInput.signal === void 0 ? {} : { signal: authInput.signal }
|
|
161
|
+
})) {
|
|
162
|
+
const output = validateAgentProviderOutputForContext(candidate, {
|
|
163
|
+
capabilities,
|
|
164
|
+
providerKey: capabilities.providerKey,
|
|
165
|
+
authenticationAttemptId: attemptId
|
|
166
|
+
});
|
|
167
|
+
assertAuthenticationOutputKind(capabilities.providerKey, output);
|
|
168
|
+
yield output;
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
cancel: async (authInput) => {
|
|
172
|
+
throwIfAgentOperationAborted(authInput.signal);
|
|
173
|
+
const attemptId = parseAgentProviderTechnicalId(
|
|
174
|
+
authInput.attemptId,
|
|
175
|
+
"authentication attemptId"
|
|
176
|
+
);
|
|
177
|
+
const providerLoginId = authInput.providerLoginId === void 0 ? void 0 : parseAgentProviderTechnicalId(
|
|
178
|
+
authInput.providerLoginId,
|
|
179
|
+
"providerLoginId"
|
|
180
|
+
);
|
|
181
|
+
if (authInput.reason !== void 0 && !["user_requested", "timeout", "shutdown", "other"].includes(
|
|
182
|
+
authInput.reason
|
|
183
|
+
)) {
|
|
184
|
+
throw new TypeError(
|
|
185
|
+
"Agent authentication cancel reason is unsupported."
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
const result = validateAgentProviderOperationResult(
|
|
189
|
+
await declaredAuthentication.cancel({
|
|
190
|
+
attemptId,
|
|
191
|
+
...providerLoginId === void 0 ? {} : { providerLoginId },
|
|
192
|
+
...authInput.reason === void 0 ? {} : { reason: authInput.reason },
|
|
193
|
+
...authInput.signal === void 0 ? {} : { signal: authInput.signal }
|
|
194
|
+
}),
|
|
195
|
+
{
|
|
196
|
+
capabilities,
|
|
197
|
+
providerKey: capabilities.providerKey,
|
|
198
|
+
authenticationAttemptId: attemptId
|
|
199
|
+
}
|
|
200
|
+
);
|
|
201
|
+
for (const output of result.outputs ?? []) {
|
|
202
|
+
assertAuthenticationOutputKind(capabilities.providerKey, output);
|
|
203
|
+
}
|
|
204
|
+
return result;
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
return Object.freeze({
|
|
208
|
+
createSession: async (createInput) => {
|
|
209
|
+
throwIfAgentOperationAborted(createInput.signal);
|
|
210
|
+
const parsed = parseAgentSessionOpenInput({
|
|
211
|
+
operation: "create",
|
|
212
|
+
sessionId: createInput.sessionId,
|
|
213
|
+
configuration: createInput.configuration
|
|
214
|
+
});
|
|
215
|
+
assertAgentSessionConfigurationSupported(
|
|
216
|
+
capabilities,
|
|
217
|
+
parsed.configuration
|
|
218
|
+
);
|
|
219
|
+
const workingDirectory = parseWorkingDirectory(
|
|
220
|
+
createInput.workingDirectory
|
|
221
|
+
);
|
|
222
|
+
return openIdentityCreatingAgentProviderSession({
|
|
223
|
+
capabilities,
|
|
224
|
+
sessionId: parsed.sessionId,
|
|
225
|
+
observer: createInput.onBindingCreated,
|
|
226
|
+
open: (observer) => adapter.createSession({
|
|
227
|
+
sessionId: parsed.sessionId,
|
|
228
|
+
workingDirectory,
|
|
229
|
+
configuration: parsed.configuration,
|
|
230
|
+
onBindingCreated: observer,
|
|
231
|
+
...createInput.signal === void 0 ? {} : { signal: createInput.signal }
|
|
232
|
+
})
|
|
233
|
+
});
|
|
234
|
+
},
|
|
235
|
+
resumption,
|
|
236
|
+
branching,
|
|
237
|
+
authentication
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
export {
|
|
241
|
+
validateAgentProviderAdapter
|
|
242
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type AgentArtifactDescriptor } from "@agen-ai/agent-protocol";
|
|
2
|
+
export declare const AGENT_ARTIFACT_CANDIDATE_MAX_BYTES: number;
|
|
3
|
+
export type AgentArtifactDeliveryRequirement = "best_effort" | "required_before_reference";
|
|
4
|
+
export type AgentArtifactCandidateSource = Readonly<{
|
|
5
|
+
kind: "bytes";
|
|
6
|
+
bytes: Uint8Array;
|
|
7
|
+
}> | Readonly<{
|
|
8
|
+
kind: "file";
|
|
9
|
+
filePath: string;
|
|
10
|
+
}>;
|
|
11
|
+
export interface AgentArtifactCandidate {
|
|
12
|
+
readonly descriptor: AgentArtifactDescriptor;
|
|
13
|
+
readonly source: AgentArtifactCandidateSource;
|
|
14
|
+
readonly delivery: AgentArtifactDeliveryRequirement;
|
|
15
|
+
}
|
|
16
|
+
export interface CreateAgentArtifactCandidateInput {
|
|
17
|
+
readonly descriptor: AgentArtifactDescriptor;
|
|
18
|
+
readonly source: AgentArtifactCandidateSource;
|
|
19
|
+
readonly delivery: AgentArtifactDeliveryRequirement;
|
|
20
|
+
}
|
|
21
|
+
export declare const AGENT_ARTIFACT_CANDIDATE_ERROR_CODES: readonly ["invalid_descriptor", "invalid_source", "source_too_large", "byte_size_mismatch", "digest_mismatch", "invalid_delivery"];
|
|
22
|
+
export type AgentArtifactCandidateErrorCode = (typeof AGENT_ARTIFACT_CANDIDATE_ERROR_CODES)[number];
|
|
23
|
+
export declare class AgentArtifactCandidateError extends TypeError {
|
|
24
|
+
readonly code: AgentArtifactCandidateErrorCode;
|
|
25
|
+
constructor(code: AgentArtifactCandidateErrorCode);
|
|
26
|
+
}
|
|
27
|
+
export declare function createAgentArtifactCandidate(input: CreateAgentArtifactCandidateInput): AgentArtifactCandidate;
|
|
28
|
+
//# sourceMappingURL=artifacts.d.ts.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
parseAgentArtifactDescriptor
|
|
4
|
+
} from "@agen-ai/agent-protocol";
|
|
5
|
+
import { containsAgentControlCharacter } from "./internal/controlCharacters.js";
|
|
6
|
+
const AGENT_ARTIFACT_CANDIDATE_MAX_BYTES = 10 * 1024 * 1024;
|
|
7
|
+
const AGENT_ARTIFACT_CANDIDATE_ERROR_CODES = [
|
|
8
|
+
"invalid_descriptor",
|
|
9
|
+
"invalid_source",
|
|
10
|
+
"source_too_large",
|
|
11
|
+
"byte_size_mismatch",
|
|
12
|
+
"digest_mismatch",
|
|
13
|
+
"invalid_delivery"
|
|
14
|
+
];
|
|
15
|
+
class AgentArtifactCandidateError extends TypeError {
|
|
16
|
+
constructor(code) {
|
|
17
|
+
super(`Agent artifact candidate is invalid: ${code}.`);
|
|
18
|
+
this.code = code;
|
|
19
|
+
this.name = "AgentArtifactCandidateError";
|
|
20
|
+
}
|
|
21
|
+
code;
|
|
22
|
+
}
|
|
23
|
+
function candidateError(code) {
|
|
24
|
+
throw new AgentArtifactCandidateError(code);
|
|
25
|
+
}
|
|
26
|
+
function bytesCandidateDescriptor(descriptor, bytes) {
|
|
27
|
+
if (bytes.byteLength > AGENT_ARTIFACT_CANDIDATE_MAX_BYTES) {
|
|
28
|
+
candidateError("source_too_large");
|
|
29
|
+
}
|
|
30
|
+
if (descriptor.byteSize !== void 0 && descriptor.byteSize !== bytes.byteLength) {
|
|
31
|
+
candidateError("byte_size_mismatch");
|
|
32
|
+
}
|
|
33
|
+
const digest = createHash("sha256").update(bytes).digest("hex");
|
|
34
|
+
if (descriptor.digest !== void 0 && descriptor.digest.value !== digest) {
|
|
35
|
+
candidateError("digest_mismatch");
|
|
36
|
+
}
|
|
37
|
+
return parseAgentArtifactDescriptor({
|
|
38
|
+
...descriptor,
|
|
39
|
+
byteSize: bytes.byteLength,
|
|
40
|
+
digest: { algorithm: "sha256", value: digest }
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function fileCandidateSource(filePath) {
|
|
44
|
+
if (filePath.length < 1 || filePath.length > 4096 || filePath !== filePath.trim() || containsAgentControlCharacter(filePath)) {
|
|
45
|
+
candidateError("invalid_source");
|
|
46
|
+
}
|
|
47
|
+
return Object.freeze({ kind: "file", filePath });
|
|
48
|
+
}
|
|
49
|
+
function createAgentArtifactCandidate(input) {
|
|
50
|
+
let descriptor;
|
|
51
|
+
try {
|
|
52
|
+
descriptor = parseAgentArtifactDescriptor(input.descriptor);
|
|
53
|
+
} catch {
|
|
54
|
+
candidateError("invalid_descriptor");
|
|
55
|
+
}
|
|
56
|
+
if (!["best_effort", "required_before_reference"].includes(input.delivery)) {
|
|
57
|
+
candidateError("invalid_delivery");
|
|
58
|
+
}
|
|
59
|
+
if (descriptor.kind === "plan" && input.delivery !== "required_before_reference") {
|
|
60
|
+
candidateError("invalid_delivery");
|
|
61
|
+
}
|
|
62
|
+
if (input.source === null || typeof input.source !== "object") {
|
|
63
|
+
candidateError("invalid_source");
|
|
64
|
+
}
|
|
65
|
+
let source;
|
|
66
|
+
if (input.source.kind === "bytes") {
|
|
67
|
+
if (!(input.source.bytes instanceof Uint8Array))
|
|
68
|
+
candidateError("invalid_source");
|
|
69
|
+
source = Object.freeze({
|
|
70
|
+
kind: "bytes",
|
|
71
|
+
bytes: new Uint8Array(input.source.bytes)
|
|
72
|
+
});
|
|
73
|
+
} else if (input.source.kind === "file") {
|
|
74
|
+
source = fileCandidateSource(input.source.filePath);
|
|
75
|
+
} else {
|
|
76
|
+
candidateError("invalid_source");
|
|
77
|
+
}
|
|
78
|
+
if (source.kind === "bytes")
|
|
79
|
+
descriptor = bytesCandidateDescriptor(descriptor, source.bytes);
|
|
80
|
+
return Object.freeze({ descriptor, source, delivery: input.delivery });
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
AGENT_ARTIFACT_CANDIDATE_ERROR_CODES,
|
|
84
|
+
AGENT_ARTIFACT_CANDIDATE_MAX_BYTES,
|
|
85
|
+
AgentArtifactCandidateError,
|
|
86
|
+
createAgentArtifactCandidate
|
|
87
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { AgentCapabilities, AgentSessionConfiguration } from "@agen-ai/agent-protocol";
|
|
2
|
+
export declare function assertAgentSessionConfigurationSupported(capabilities: AgentCapabilities, configuration: AgentSessionConfiguration): void;
|
|
3
|
+
//# sourceMappingURL=configurationValidation.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { throwAgentProviderContractError } from "./contractErrors.js";
|
|
2
|
+
function assertAgentSessionConfigurationSupported(capabilities, configuration) {
|
|
3
|
+
const entries = Object.entries(configuration.values);
|
|
4
|
+
if (capabilities.configuration.kind === "managed") {
|
|
5
|
+
if (entries.length === 0) return;
|
|
6
|
+
throwAgentProviderContractError(
|
|
7
|
+
capabilities.providerKey,
|
|
8
|
+
"configuration_key_unsupported",
|
|
9
|
+
"Managed provider configuration values must be empty."
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
const fields = new Map(
|
|
13
|
+
capabilities.configuration.fields.map((field) => [field.key, field])
|
|
14
|
+
);
|
|
15
|
+
for (const [key, value] of entries) {
|
|
16
|
+
const field = fields.get(key);
|
|
17
|
+
if (!field) {
|
|
18
|
+
throwAgentProviderContractError(
|
|
19
|
+
capabilities.providerKey,
|
|
20
|
+
"configuration_key_unsupported",
|
|
21
|
+
"Provider configuration contains a key not declared by its capabilities."
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
if (typeof value !== "string" || !field.optionIds.includes(value)) {
|
|
25
|
+
throwAgentProviderContractError(
|
|
26
|
+
capabilities.providerKey,
|
|
27
|
+
"configuration_value_unsupported",
|
|
28
|
+
"Provider configuration contains an option not declared by its capabilities."
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
assertAgentSessionConfigurationSupported
|
|
35
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AgentProviderKey } from "@agen-ai/agent-protocol";
|
|
2
|
+
export declare const AGENT_PROVIDER_CONTRACT_ERROR_CODES: readonly ["capability_port_mismatch", "invalid_adapter", "invalid_session", "invalid_binding", "binding_callback_missing", "binding_callback_repeated", "binding_callback_mismatch", "resume_binding_mismatch", "branch_binding_reused", "session_closed", "session_unusable", "concurrent_turn", "active_turn_mismatch", "invalid_operation_result", "output_session_mismatch", "output_turn_mismatch", "output_authentication_attempt_mismatch", "output_capability_mismatch", "input_capability_mismatch", "invalid_turn_sequence", "request_resolution_mismatch", "configuration_key_unsupported", "configuration_value_unsupported", "request_pending"];
|
|
3
|
+
export type AgentProviderContractErrorCode = (typeof AGENT_PROVIDER_CONTRACT_ERROR_CODES)[number];
|
|
4
|
+
export type AgentProviderDelegatedOperation = "steer_turn";
|
|
5
|
+
export declare class AgentProviderContractError extends Error {
|
|
6
|
+
readonly providerKey: AgentProviderKey;
|
|
7
|
+
readonly code: AgentProviderContractErrorCode;
|
|
8
|
+
constructor(providerKey: AgentProviderKey, code: AgentProviderContractErrorCode, message: string);
|
|
9
|
+
}
|
|
10
|
+
export declare class AgentProviderDelegatedOperationError extends Error {
|
|
11
|
+
readonly providerKey: AgentProviderKey;
|
|
12
|
+
readonly operation: AgentProviderDelegatedOperation;
|
|
13
|
+
readonly providerExecution: "started";
|
|
14
|
+
constructor(providerKey: AgentProviderKey, operation: AgentProviderDelegatedOperation, cause: unknown);
|
|
15
|
+
}
|
|
16
|
+
export declare function throwAgentProviderContractError(providerKey: AgentProviderKey, code: AgentProviderContractErrorCode, message: string): never;
|
|
17
|
+
//# sourceMappingURL=contractErrors.d.ts.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const AGENT_PROVIDER_CONTRACT_ERROR_CODES = [
|
|
2
|
+
"capability_port_mismatch",
|
|
3
|
+
"invalid_adapter",
|
|
4
|
+
"invalid_session",
|
|
5
|
+
"invalid_binding",
|
|
6
|
+
"binding_callback_missing",
|
|
7
|
+
"binding_callback_repeated",
|
|
8
|
+
"binding_callback_mismatch",
|
|
9
|
+
"resume_binding_mismatch",
|
|
10
|
+
"branch_binding_reused",
|
|
11
|
+
"session_closed",
|
|
12
|
+
"session_unusable",
|
|
13
|
+
"concurrent_turn",
|
|
14
|
+
"active_turn_mismatch",
|
|
15
|
+
"invalid_operation_result",
|
|
16
|
+
"output_session_mismatch",
|
|
17
|
+
"output_turn_mismatch",
|
|
18
|
+
"output_authentication_attempt_mismatch",
|
|
19
|
+
"output_capability_mismatch",
|
|
20
|
+
"input_capability_mismatch",
|
|
21
|
+
"invalid_turn_sequence",
|
|
22
|
+
"request_resolution_mismatch",
|
|
23
|
+
"configuration_key_unsupported",
|
|
24
|
+
"configuration_value_unsupported",
|
|
25
|
+
"request_pending"
|
|
26
|
+
];
|
|
27
|
+
class AgentProviderContractError extends Error {
|
|
28
|
+
constructor(providerKey, code, message) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.providerKey = providerKey;
|
|
31
|
+
this.code = code;
|
|
32
|
+
this.name = "AgentProviderContractError";
|
|
33
|
+
}
|
|
34
|
+
providerKey;
|
|
35
|
+
code;
|
|
36
|
+
}
|
|
37
|
+
class AgentProviderDelegatedOperationError extends Error {
|
|
38
|
+
constructor(providerKey, operation, cause) {
|
|
39
|
+
super(
|
|
40
|
+
cause instanceof Error ? cause.message : `Provider ${providerKey} failed after ${operation} delegation.`,
|
|
41
|
+
{ cause }
|
|
42
|
+
);
|
|
43
|
+
this.providerKey = providerKey;
|
|
44
|
+
this.operation = operation;
|
|
45
|
+
this.name = "AgentProviderDelegatedOperationError";
|
|
46
|
+
}
|
|
47
|
+
providerKey;
|
|
48
|
+
operation;
|
|
49
|
+
providerExecution = "started";
|
|
50
|
+
}
|
|
51
|
+
function throwAgentProviderContractError(providerKey, code, message) {
|
|
52
|
+
throw new AgentProviderContractError(providerKey, code, message);
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
AGENT_PROVIDER_CONTRACT_ERROR_CODES,
|
|
56
|
+
AgentProviderContractError,
|
|
57
|
+
AgentProviderDelegatedOperationError,
|
|
58
|
+
throwAgentProviderContractError
|
|
59
|
+
};
|