@agen-ai/agent-runtime 0.2.5 → 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 +33 -14
- 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 +1 -0
- package/dist/index.js +1 -0
- package/dist/interactionValidation.js +1 -3
- package/dist/providerDriver.d.ts +2 -0
- package/dist/providerInstanceRegistry.js +9 -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 +93 -15
- package/dist/testing/fakeProvider.d.ts +2 -0
- package/dist/testing/fakeProvider.js +103 -13
- package/package.json +7 -3
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AGENT_COLLABORATION_GRAPH_LIMITS,
|
|
3
|
+
AGENT_CONTENT_REFERENCES_MAX_LENGTH,
|
|
4
|
+
findAgentContentReferenceTextIssue,
|
|
3
5
|
matchesAgentSessionBinding,
|
|
4
6
|
parseAgentCollaborationControlInput,
|
|
5
7
|
parseAgentCollaborationSpawnInput,
|
|
@@ -18,11 +20,11 @@ import {
|
|
|
18
20
|
import {
|
|
19
21
|
createAgentArtifactCandidate
|
|
20
22
|
} from "./artifacts.js";
|
|
23
|
+
import { validateAgentEnvironmentObservationPort } from "./environment/validation.js";
|
|
21
24
|
import {
|
|
22
25
|
validateAgentCollaborationNodeForCapabilities,
|
|
23
26
|
validateAgentConfigurationCatalogForCapabilities,
|
|
24
27
|
validateAgentGeneratedResourceForCapabilities,
|
|
25
|
-
validateAgentIntegrationCatalogForCapabilities,
|
|
26
28
|
validateAgentManagedContentCatalogForCapabilities,
|
|
27
29
|
validateAgentOperationCatalogForCapabilities,
|
|
28
30
|
validateAgentOperationResultForInvocation,
|
|
@@ -57,11 +59,11 @@ function validateSessionPorts(capabilities, session) {
|
|
|
57
59
|
"configuration",
|
|
58
60
|
"operations",
|
|
59
61
|
"managedContent",
|
|
60
|
-
"
|
|
62
|
+
"environment",
|
|
61
63
|
"collaboration",
|
|
62
64
|
"generatedResources",
|
|
63
65
|
"close"
|
|
64
|
-
]) || typeof session.runTurn !== "function" || typeof session.resolveRequest !== "function" || typeof session.close !== "function" || session.interruption === null || typeof session.interruption !== "object" || !["supported", "unsupported"].includes(session.interruption.kind) || session.steering === null || typeof session.steering !== "object" || !["supported", "unsupported"].includes(session.steering.kind) || session.configuration === null || typeof session.configuration !== "object" || !["managed", "selectable"].includes(session.configuration.kind) || session.operations === null || typeof session.operations !== "object" || !["supported", "unsupported"].includes(session.operations.kind) || session.managedContent === null || typeof session.managedContent !== "object" || !["supported", "unsupported"].includes(session.managedContent.kind) || session.
|
|
66
|
+
]) || typeof session.runTurn !== "function" || typeof session.resolveRequest !== "function" || typeof session.close !== "function" || session.interruption === null || typeof session.interruption !== "object" || !["supported", "unsupported"].includes(session.interruption.kind) || session.steering === null || typeof session.steering !== "object" || !["supported", "unsupported"].includes(session.steering.kind) || session.configuration === null || typeof session.configuration !== "object" || !["managed", "selectable"].includes(session.configuration.kind) || session.operations === null || typeof session.operations !== "object" || !["supported", "unsupported"].includes(session.operations.kind) || session.managedContent === null || typeof session.managedContent !== "object" || !["supported", "unsupported"].includes(session.managedContent.kind) || session.environment === null || typeof session.environment !== "object" || !["read", "read_and_watch", "unsupported"].includes(session.environment.kind) || session.collaboration === null || typeof session.collaboration !== "object" || !["supported", "unsupported"].includes(session.collaboration.kind) || session.generatedResources === null || typeof session.generatedResources !== "object" || !["supported", "unsupported"].includes(session.generatedResources.kind)) {
|
|
65
67
|
throwAgentProviderContractError(
|
|
66
68
|
capabilities.providerKey,
|
|
67
69
|
"invalid_session",
|
|
@@ -84,15 +86,15 @@ function validateSessionPorts(capabilities, session) {
|
|
|
84
86
|
session.managedContent,
|
|
85
87
|
session.managedContent.kind === "supported" ? ["kind", "listManagedContent"] : ["kind"]
|
|
86
88
|
) || !hasExactOwnKeys(
|
|
87
|
-
session.
|
|
88
|
-
session.
|
|
89
|
+
session.environment,
|
|
90
|
+
session.environment.kind === "unsupported" ? ["kind"] : session.environment.kind === "read" ? ["kind", "domains", "readEnvironment"] : ["kind", "domains", "readEnvironment", "watchEnvironment"]
|
|
89
91
|
) || !hasExactOwnKeys(
|
|
90
92
|
session.collaboration,
|
|
91
93
|
session.collaboration.kind === "supported" ? ["kind", "spawnCollaboration", "controlCollaboration"] : ["kind"]
|
|
92
94
|
) || !hasExactOwnKeys(
|
|
93
95
|
session.generatedResources,
|
|
94
96
|
session.generatedResources.kind === "supported" ? ["kind", "getGeneratedResource"] : ["kind"]
|
|
95
|
-
) || session.interruption.kind === "supported" !== capabilities.turns.interrupt || session.steering.kind === "supported" !== (capabilities.turns.steer.kind === "supported") || session.configuration.kind !== capabilities.configuration.kind || session.interruption.kind === "supported" && typeof session.interruption.interruptTurn !== "function" || session.steering.kind === "supported" && typeof session.steering.steerTurn !== "function" || session.configuration.kind === "selectable" && (typeof session.configuration.listConfiguration !== "function" || typeof session.configuration.applyConfigurationSelection !== "function") || session.operations.kind === "supported" !== (capabilities.operations.kind === "supported") || session.operations.kind === "supported" && (typeof session.operations.listOperations !== "function" || typeof session.operations.invokeOperation !== "function") || session.managedContent.kind === "supported" !== (capabilities.managedContent.kind === "supported") || session.managedContent.kind === "supported" && typeof session.managedContent.listManagedContent !== "function" || session.
|
|
97
|
+
) || session.interruption.kind === "supported" !== capabilities.turns.interrupt || session.steering.kind === "supported" !== (capabilities.turns.steer.kind === "supported") || session.configuration.kind !== capabilities.configuration.kind || session.interruption.kind === "supported" && typeof session.interruption.interruptTurn !== "function" || session.steering.kind === "supported" && typeof session.steering.steerTurn !== "function" || session.configuration.kind === "selectable" && (typeof session.configuration.listConfiguration !== "function" || typeof session.configuration.applyConfigurationSelection !== "function") || session.operations.kind === "supported" !== (capabilities.operations.kind === "supported") || session.operations.kind === "supported" && (typeof session.operations.listOperations !== "function" || typeof session.operations.invokeOperation !== "function") || session.managedContent.kind === "supported" !== (capabilities.managedContent.kind === "supported") || session.managedContent.kind === "supported" && typeof session.managedContent.listManagedContent !== "function" || session.environment.kind !== capabilities.environment.session.kind || session.environment.kind !== "unsupported" && (typeof session.environment.readEnvironment !== "function" || session.environment.kind === "read_and_watch" && typeof session.environment.watchEnvironment !== "function") || session.collaboration.kind === "supported" !== (capabilities.collaboration.kind === "supported") || session.collaboration.kind === "supported" && (typeof session.collaboration.spawnCollaboration !== "function" || typeof session.collaboration.controlCollaboration !== "function") || session.generatedResources.kind === "supported" !== (capabilities.generatedResources.kind === "supported") || session.generatedResources.kind === "supported" && typeof session.generatedResources.getGeneratedResource !== "function") {
|
|
96
98
|
throwAgentProviderContractError(
|
|
97
99
|
capabilities.providerKey,
|
|
98
100
|
"capability_port_mismatch",
|
|
@@ -612,46 +614,75 @@ function clearPendingRequestsForTurn(pendingRequests, turnId) {
|
|
|
612
614
|
}
|
|
613
615
|
function assertAgentTurnInputCapability(input) {
|
|
614
616
|
const imageParts = input.parts.filter((part) => part.type === "image");
|
|
615
|
-
if (imageParts.length
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
617
|
+
if (imageParts.length > 0) {
|
|
618
|
+
const imageCapability = input.capability.images;
|
|
619
|
+
if (imageCapability.kind === "unsupported") {
|
|
620
|
+
throwAgentProviderContractError(
|
|
621
|
+
input.providerKey,
|
|
622
|
+
"input_capability_mismatch",
|
|
623
|
+
`Provider ${input.providerKey} does not accept image input.`
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
const reject = (reason) => throwAgentProviderContractError(
|
|
619
627
|
input.providerKey,
|
|
620
628
|
"input_capability_mismatch",
|
|
621
|
-
`Provider ${input.providerKey}
|
|
629
|
+
`Provider ${input.providerKey} cannot accept this image input: ${reason}.`
|
|
622
630
|
);
|
|
631
|
+
if (imageParts.length > imageCapability.maxImages) {
|
|
632
|
+
reject("image count exceeds the declared limit");
|
|
633
|
+
}
|
|
634
|
+
if (!imageCapability.supportsImageOnly && !input.parts.some((part) => part.type === "text" && part.text.trim().length > 0)) {
|
|
635
|
+
reject("image-only input is unsupported");
|
|
636
|
+
}
|
|
637
|
+
let totalBytes = 0;
|
|
638
|
+
for (const part of imageParts) {
|
|
639
|
+
const { source } = part;
|
|
640
|
+
if (!imageCapability.sourceKinds.includes(source.type)) {
|
|
641
|
+
reject(`source kind ${source.type} is unsupported`);
|
|
642
|
+
}
|
|
643
|
+
if (!imageCapability.mediaTypes.includes(source.mediaType)) {
|
|
644
|
+
reject(`media type ${source.mediaType} is unsupported`);
|
|
645
|
+
}
|
|
646
|
+
if (source.byteSize > imageCapability.maxBytesPerImage) {
|
|
647
|
+
reject("an image exceeds the declared byte limit");
|
|
648
|
+
}
|
|
649
|
+
if (source.widthPixels > imageCapability.maxWidthPixels || source.heightPixels > imageCapability.maxHeightPixels || source.widthPixels * source.heightPixels > imageCapability.maxPixelsPerImage) {
|
|
650
|
+
reject("an image exceeds the declared dimension or pixel limit");
|
|
651
|
+
}
|
|
652
|
+
totalBytes += source.byteSize;
|
|
653
|
+
}
|
|
654
|
+
if (totalBytes > imageCapability.maxTotalBytes) {
|
|
655
|
+
reject("aggregate image bytes exceed the declared limit");
|
|
656
|
+
}
|
|
623
657
|
}
|
|
624
|
-
const
|
|
658
|
+
const contentReferenceParts = input.parts.filter(
|
|
659
|
+
(part) => part.type === "content_reference"
|
|
660
|
+
);
|
|
661
|
+
if (contentReferenceParts.length === 0) return;
|
|
662
|
+
const contentReferenceCapability = input.capability.contentReferences;
|
|
663
|
+
const rejectReference = (reason) => throwAgentProviderContractError(
|
|
625
664
|
input.providerKey,
|
|
626
665
|
"input_capability_mismatch",
|
|
627
|
-
`Provider ${input.providerKey} cannot accept this
|
|
666
|
+
`Provider ${input.providerKey} cannot accept this content reference input: ${reason}.`
|
|
628
667
|
);
|
|
629
|
-
if (
|
|
630
|
-
|
|
668
|
+
if (contentReferenceParts.length > AGENT_CONTENT_REFERENCES_MAX_LENGTH) {
|
|
669
|
+
rejectReference("content reference count exceeds the protocol limit");
|
|
631
670
|
}
|
|
632
|
-
if (
|
|
633
|
-
|
|
671
|
+
if (contentReferenceCapability.kind === "unsupported") {
|
|
672
|
+
return rejectReference("content references are unsupported");
|
|
634
673
|
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
const { source } = part;
|
|
638
|
-
if (!imageCapability.sourceKinds.includes(source.type)) {
|
|
639
|
-
reject(`source kind ${source.type} is unsupported`);
|
|
640
|
-
}
|
|
641
|
-
if (!imageCapability.mediaTypes.includes(source.mediaType)) {
|
|
642
|
-
reject(`media type ${source.mediaType} is unsupported`);
|
|
643
|
-
}
|
|
644
|
-
if (source.byteSize > imageCapability.maxBytesPerImage) {
|
|
645
|
-
reject("an image exceeds the declared byte limit");
|
|
646
|
-
}
|
|
647
|
-
if (source.widthPixels > imageCapability.maxWidthPixels || source.heightPixels > imageCapability.maxHeightPixels || source.widthPixels * source.heightPixels > imageCapability.maxPixelsPerImage) {
|
|
648
|
-
reject("an image exceeds the declared dimension or pixel limit");
|
|
649
|
-
}
|
|
650
|
-
totalBytes += source.byteSize;
|
|
674
|
+
if (contentReferenceParts.length > contentReferenceCapability.maxReferences) {
|
|
675
|
+
rejectReference("content reference count exceeds the declared limit");
|
|
651
676
|
}
|
|
652
|
-
if (
|
|
653
|
-
|
|
677
|
+
if (!contentReferenceCapability.arguments && contentReferenceParts.some((part) => part.arguments !== void 0)) {
|
|
678
|
+
rejectReference("reference arguments are unsupported");
|
|
654
679
|
}
|
|
680
|
+
const textIssue = findAgentContentReferenceTextIssue({
|
|
681
|
+
prompt: input.parts.filter((part) => part.type === "text").map((part) => part.text).join("\n"),
|
|
682
|
+
arguments: contentReferenceParts.map((part) => part.arguments ?? ""),
|
|
683
|
+
textFormats: contentReferenceCapability.textFormats
|
|
684
|
+
});
|
|
685
|
+
if (textIssue) rejectReference(`${textIssue.target} must use ${textIssue.format} text`);
|
|
655
686
|
}
|
|
656
687
|
function validateAgentProviderSession(input) {
|
|
657
688
|
const { capabilities, sessionId } = input;
|
|
@@ -688,6 +719,13 @@ function validateAgentProviderSession(input) {
|
|
|
688
719
|
);
|
|
689
720
|
}
|
|
690
721
|
validateSessionPorts(capabilities, input.candidate);
|
|
722
|
+
const sessionLifetime = new AbortController();
|
|
723
|
+
const environment = validateAgentEnvironmentObservationPort({
|
|
724
|
+
providerKey,
|
|
725
|
+
capability: capabilities.environment.session,
|
|
726
|
+
port: input.candidate.environment,
|
|
727
|
+
signal: sessionLifetime.signal
|
|
728
|
+
});
|
|
691
729
|
const pendingRequests = /* @__PURE__ */ new Map();
|
|
692
730
|
const waitingTurnStates = /* @__PURE__ */ new Map();
|
|
693
731
|
const openedRequestIds = /* @__PURE__ */ new Set();
|
|
@@ -1331,20 +1369,6 @@ function validateAgentProviderSession(input) {
|
|
|
1331
1369
|
);
|
|
1332
1370
|
}
|
|
1333
1371
|
});
|
|
1334
|
-
const declaredIntegrations = input.candidate.integrations;
|
|
1335
|
-
const integrations = declaredIntegrations.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
|
|
1336
|
-
kind: "supported",
|
|
1337
|
-
observeIntegrations: async (listInput = {}) => {
|
|
1338
|
-
requireUsable();
|
|
1339
|
-
throwIfAgentOperationAborted(listInput.signal);
|
|
1340
|
-
return validateAgentIntegrationCatalogForCapabilities(
|
|
1341
|
-
capabilities,
|
|
1342
|
-
await declaredIntegrations.observeIntegrations(
|
|
1343
|
-
listInput.signal === void 0 ? {} : { signal: listInput.signal }
|
|
1344
|
-
)
|
|
1345
|
-
);
|
|
1346
|
-
}
|
|
1347
|
-
});
|
|
1348
1372
|
const declaredCollaboration = input.candidate.collaboration;
|
|
1349
1373
|
const collaboration = declaredCollaboration.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
|
|
1350
1374
|
kind: "supported",
|
|
@@ -1592,6 +1616,7 @@ function validateAgentProviderSession(input) {
|
|
|
1592
1616
|
throw new TypeError("Provider session close reason is unsupported.");
|
|
1593
1617
|
}
|
|
1594
1618
|
unusable = true;
|
|
1619
|
+
sessionLifetime.abort(new DOMException("The provider session was closed.", "AbortError"));
|
|
1595
1620
|
closePromise = Promise.resolve().then(() => input.candidate.close(closeInput)).then(() => {
|
|
1596
1621
|
closed = true;
|
|
1597
1622
|
}).finally(() => {
|
|
@@ -1608,7 +1633,7 @@ function validateAgentProviderSession(input) {
|
|
|
1608
1633
|
configuration,
|
|
1609
1634
|
operations,
|
|
1610
1635
|
managedContent,
|
|
1611
|
-
|
|
1636
|
+
environment,
|
|
1612
1637
|
collaboration,
|
|
1613
1638
|
generatedResources,
|
|
1614
1639
|
close
|
package/dist/sessions.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import type { AgentAuthenticationFlow, AgentCollaborationControlInput, AgentCollaborationNode, AgentCollaborationSpawnInput, AgentConfigurationCatalog, AgentConfigurationSelectionInput, AgentError, AgentGeneratedResourceDescriptor, AgentGeneratedResourceId,
|
|
1
|
+
import type { AgentAuthenticationFlow, AgentCollaborationControlInput, AgentCollaborationNode, AgentCollaborationSpawnInput, AgentConfigurationCatalog, AgentConfigurationSelectionInput, AgentError, AgentGeneratedResourceDescriptor, AgentGeneratedResourceId, AgentManagedContentCatalog, AgentOperationCatalog, AgentOperationInvocation, AgentOperationResult, AgentRequestResolution, AgentSessionBinding, AgentSessionBranchSource, AgentSessionConfiguration, AgentSessionId, AgentTurnId, AgentTurnInputContent, AgentTurnInteractionMode, AgentTurnInputPart, AgentTurnInterruptionReason } from "@agen-ai/agent-protocol";
|
|
2
2
|
import type { MaybePromise } from "./foundation.js";
|
|
3
3
|
import type { AgentProviderOutput } from "./outputs.js";
|
|
4
4
|
import type { AgentArtifactCandidate } from "./artifacts.js";
|
|
5
|
+
import type { AgentEnvironmentObservationPort } from "./environment/types.js";
|
|
5
6
|
export interface AgentProviderSessionContext {
|
|
6
7
|
readonly sessionId: AgentSessionId;
|
|
7
8
|
readonly workingDirectory: string;
|
|
@@ -129,12 +130,6 @@ export type AgentManagedContentInventory = Readonly<{
|
|
|
129
130
|
kind: "supported";
|
|
130
131
|
listManagedContent: (input?: AgentProviderListInput) => MaybePromise<AgentManagedContentCatalog>;
|
|
131
132
|
}>;
|
|
132
|
-
export type AgentIntegrationObservation = Readonly<{
|
|
133
|
-
kind: "unsupported";
|
|
134
|
-
}> | Readonly<{
|
|
135
|
-
kind: "supported";
|
|
136
|
-
observeIntegrations: (input?: AgentProviderListInput) => MaybePromise<AgentIntegrationCatalog>;
|
|
137
|
-
}>;
|
|
138
133
|
export type AgentCollaborationControl = Readonly<{
|
|
139
134
|
kind: "unsupported";
|
|
140
135
|
}> | Readonly<{
|
|
@@ -157,7 +152,7 @@ export interface AgentProviderSession {
|
|
|
157
152
|
readonly configuration: AgentSessionConfigurationControl;
|
|
158
153
|
readonly operations: AgentOperationControl;
|
|
159
154
|
readonly managedContent: AgentManagedContentInventory;
|
|
160
|
-
readonly
|
|
155
|
+
readonly environment: AgentEnvironmentObservationPort;
|
|
161
156
|
readonly collaboration: AgentCollaborationControl;
|
|
162
157
|
readonly generatedResources: AgentGeneratedResourceAccess;
|
|
163
158
|
readonly close: (input: AgentProviderCloseSessionInput) => MaybePromise<void>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AgentCollaborationSpawnInput, type AgentConfigurationSelectionInput, type AgentGeneratedResourceId, type AgentOperationInvocation, type AgentRequest, type AgentRequestResolution, type AgentSessionBinding, type AgentSessionBranchSource, type AgentSessionConfiguration, type AgentSessionId, type AgentTurnId, type AgentTurnInputContent } from "@agen-ai/agent-protocol";
|
|
1
|
+
import { type AgentCollaborationSpawnInput, type AgentConfigurationSelectionInput, type AgentEnvironmentId, type AgentGeneratedResourceId, type AgentOperationInvocation, type AgentRequest, type AgentRequestResolution, type AgentSessionBinding, type AgentSessionBranchSource, type AgentSessionConfiguration, type AgentSessionId, type AgentTurnId, type AgentTurnInputContent } from "@agen-ai/agent-protocol";
|
|
2
2
|
import type { AgentProviderDriver, AgentProviderInstanceDefinition } from "../providerDriver.js";
|
|
3
3
|
import type { AgentProviderRunTurnInput } from "../sessions.js";
|
|
4
4
|
export interface AgentProviderConformanceScenario {
|
|
@@ -10,6 +10,7 @@ export interface AgentProviderConformanceScenario {
|
|
|
10
10
|
readonly operationInvocation?: AgentOperationInvocation;
|
|
11
11
|
readonly collaborationSpawn?: AgentCollaborationSpawnInput;
|
|
12
12
|
readonly generatedResourceId?: AgentGeneratedResourceId;
|
|
13
|
+
readonly environmentId?: AgentEnvironmentId;
|
|
13
14
|
readonly createSessionId: AgentSessionId;
|
|
14
15
|
readonly resumeSessionId: AgentSessionId;
|
|
15
16
|
readonly branchSessionId?: AgentSessionId;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
matchesAgentSessionBinding,
|
|
3
|
+
parseAgentEnvironmentId,
|
|
3
4
|
parseAgentRequestResolutionFor,
|
|
4
5
|
parseAgentTurnId
|
|
5
6
|
} from "@agen-ai/agent-protocol";
|
|
@@ -19,6 +20,23 @@ class AgentProviderConformanceError extends Error {
|
|
|
19
20
|
function requireCheck(condition, check, message) {
|
|
20
21
|
if (!condition) throw new AgentProviderConformanceError(check, message);
|
|
21
22
|
}
|
|
23
|
+
async function checkEnvironmentWatch(input) {
|
|
24
|
+
const pending = input.iterator.next();
|
|
25
|
+
await Promise.resolve();
|
|
26
|
+
input.controller.abort(new DOMException("Conformance watch complete.", "AbortError"));
|
|
27
|
+
try {
|
|
28
|
+
const next = await pending;
|
|
29
|
+
requireCheck(
|
|
30
|
+
next.done || next.value.environmentId === input.environmentId,
|
|
31
|
+
input.check,
|
|
32
|
+
"Environment watch returned a different identity."
|
|
33
|
+
);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
if (!isAgentOperationAbortError(error)) throw error;
|
|
36
|
+
} finally {
|
|
37
|
+
await input.iterator.return?.();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
22
40
|
async function advanceToStartedTurn(session, input) {
|
|
23
41
|
const iterator = session.runTurn(input)[Symbol.asyncIterator]();
|
|
24
42
|
const outputs = [];
|
|
@@ -142,6 +160,46 @@ async function runAgentProviderConformance(scenario) {
|
|
|
142
160
|
requireCheck(aborted2, "account_quota", "Pre-aborted quota work must fail with AbortError.");
|
|
143
161
|
}
|
|
144
162
|
checks.push("account_quota");
|
|
163
|
+
const environmentId = scenario.environmentId ?? parseAgentEnvironmentId("conformance-environment:instance");
|
|
164
|
+
if (instance.capabilities.environment.instance.kind === "unsupported") {
|
|
165
|
+
requireCheck(
|
|
166
|
+
instance.environment.kind === "unsupported",
|
|
167
|
+
"environment_instance",
|
|
168
|
+
"Unsupported instance environment exposed a discovery port."
|
|
169
|
+
);
|
|
170
|
+
} else {
|
|
171
|
+
requireCheck(
|
|
172
|
+
instance.environment.kind === instance.capabilities.environment.instance.kind,
|
|
173
|
+
"environment_instance",
|
|
174
|
+
"Instance environment capability has no matching discovery port."
|
|
175
|
+
);
|
|
176
|
+
const readSignal = new AbortController();
|
|
177
|
+
let executionStarted = 0;
|
|
178
|
+
const snapshot = await instance.environment.readEnvironment({
|
|
179
|
+
signal: readSignal.signal,
|
|
180
|
+
environmentId,
|
|
181
|
+
workingDirectory: scenario.workingDirectory,
|
|
182
|
+
configuration: scenario.configuration,
|
|
183
|
+
onProviderExecutionStarted: () => {
|
|
184
|
+
executionStarted += 1;
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
requireCheck(
|
|
188
|
+
snapshot.environmentId === environmentId && executionStarted === 1,
|
|
189
|
+
"environment_instance",
|
|
190
|
+
"Instance environment discovery did not echo its identity and start receipt."
|
|
191
|
+
);
|
|
192
|
+
if (instance.environment.kind === "read_and_watch") {
|
|
193
|
+
const iterator = instance.environment.watchEnvironment({
|
|
194
|
+
signal: readSignal.signal,
|
|
195
|
+
environmentId,
|
|
196
|
+
workingDirectory: scenario.workingDirectory,
|
|
197
|
+
configuration: scenario.configuration
|
|
198
|
+
})[Symbol.asyncIterator]();
|
|
199
|
+
await checkEnvironmentWatch({ iterator, controller: readSignal, environmentId, check: "environment_instance" });
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
checks.push("environment_instance");
|
|
145
203
|
let createdBindingCount = 0;
|
|
146
204
|
const created = await instance.adapter.createSession({
|
|
147
205
|
sessionId: scenario.createSessionId,
|
|
@@ -158,6 +216,41 @@ async function runAgentProviderConformance(scenario) {
|
|
|
158
216
|
"Create session did not report exactly one binding."
|
|
159
217
|
);
|
|
160
218
|
checks.push("create_session", "binding_callback");
|
|
219
|
+
if (instance.capabilities.environment.session.kind === "unsupported") {
|
|
220
|
+
requireCheck(
|
|
221
|
+
created.environment.kind === "unsupported",
|
|
222
|
+
"environment_session",
|
|
223
|
+
"Unsupported session environment exposed an observation port."
|
|
224
|
+
);
|
|
225
|
+
} else {
|
|
226
|
+
requireCheck(
|
|
227
|
+
created.environment.kind === instance.capabilities.environment.session.kind,
|
|
228
|
+
"environment_session",
|
|
229
|
+
"Session environment capability has no matching observation port."
|
|
230
|
+
);
|
|
231
|
+
const readSignal = new AbortController();
|
|
232
|
+
let executionStarted = 0;
|
|
233
|
+
const snapshot = await created.environment.readEnvironment({
|
|
234
|
+
signal: readSignal.signal,
|
|
235
|
+
environmentId,
|
|
236
|
+
onProviderExecutionStarted: () => {
|
|
237
|
+
executionStarted += 1;
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
requireCheck(
|
|
241
|
+
snapshot.environmentId === environmentId && executionStarted === 1,
|
|
242
|
+
"environment_session",
|
|
243
|
+
"Session environment observation did not echo its identity and start receipt."
|
|
244
|
+
);
|
|
245
|
+
if (created.environment.kind === "read_and_watch") {
|
|
246
|
+
const iterator = created.environment.watchEnvironment({
|
|
247
|
+
signal: readSignal.signal,
|
|
248
|
+
environmentId
|
|
249
|
+
})[Symbol.asyncIterator]();
|
|
250
|
+
await checkEnvironmentWatch({ iterator, controller: readSignal, environmentId, check: "environment_session" });
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
checks.push("environment_session");
|
|
161
254
|
const aborted = new AbortController();
|
|
162
255
|
aborted.abort(new DOMException("Conformance abort.", "AbortError"));
|
|
163
256
|
try {
|
|
@@ -386,21 +479,6 @@ async function runAgentProviderConformance(scenario) {
|
|
|
386
479
|
);
|
|
387
480
|
}
|
|
388
481
|
checks.push("managed_content");
|
|
389
|
-
if (instance.capabilities.integrations.kind === "supported") {
|
|
390
|
-
requireCheck(
|
|
391
|
-
created.integrations.kind === "supported",
|
|
392
|
-
"integrations",
|
|
393
|
-
"Supported integrations have no observation port."
|
|
394
|
-
);
|
|
395
|
-
await created.integrations.observeIntegrations();
|
|
396
|
-
} else {
|
|
397
|
-
requireCheck(
|
|
398
|
-
created.integrations.kind === "unsupported",
|
|
399
|
-
"integrations",
|
|
400
|
-
"Unsupported integrations exposed an observation port."
|
|
401
|
-
);
|
|
402
|
-
}
|
|
403
|
-
checks.push("integrations");
|
|
404
482
|
if (instance.capabilities.collaboration.kind === "supported") {
|
|
405
483
|
requireCheck(
|
|
406
484
|
created.collaboration.kind === "supported" && scenario.collaborationSpawn !== void 0,
|
|
@@ -22,6 +22,8 @@ export interface FakeAgentProviderSnapshot {
|
|
|
22
22
|
readonly interruptedTurnIds: readonly AgentTurnId[];
|
|
23
23
|
readonly steeringInputs: readonly FakeAgentSteeringInput[];
|
|
24
24
|
readonly configurationRevisions: readonly string[];
|
|
25
|
+
readonly environmentReadIds: readonly string[];
|
|
26
|
+
readonly environmentInvalidationIds: readonly string[];
|
|
25
27
|
readonly closeCounts: Readonly<Record<string, number>>;
|
|
26
28
|
}
|
|
27
29
|
export interface FakeAgentProvider {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
+
AGENT_ENVIRONMENT_DOMAINS,
|
|
3
|
+
parseAgentEnvironmentSnapshot,
|
|
2
4
|
parseAgentCapabilities,
|
|
3
5
|
parseAgentInstanceId,
|
|
4
6
|
parseAgentIsoDateTime,
|
|
@@ -33,10 +35,16 @@ function defaultCapabilities(providerKey) {
|
|
|
33
35
|
maxHeightPixels: 6e3,
|
|
34
36
|
maxPixelsPerImage: 36e6,
|
|
35
37
|
supportsImageOnly: true
|
|
38
|
+
},
|
|
39
|
+
contentReferences: {
|
|
40
|
+
kind: "supported",
|
|
41
|
+
maxReferences: 16,
|
|
42
|
+
arguments: true,
|
|
43
|
+
textFormats: { prompt: "unrestricted", arguments: "unrestricted" }
|
|
36
44
|
}
|
|
37
45
|
};
|
|
38
46
|
return parseAgentCapabilities({
|
|
39
|
-
protocolVersion:
|
|
47
|
+
protocolVersion: 9,
|
|
40
48
|
providerKey,
|
|
41
49
|
sessions: { create: true, resume: true, branch: { kind: "through_turn" } },
|
|
42
50
|
turns: {
|
|
@@ -117,6 +125,16 @@ function defaultCapabilities(providerKey) {
|
|
|
117
125
|
maxToolsPerServer: 100,
|
|
118
126
|
maxResourcesPerServer: 100
|
|
119
127
|
},
|
|
128
|
+
environment: {
|
|
129
|
+
instance: {
|
|
130
|
+
kind: "read_and_watch",
|
|
131
|
+
domains: [...AGENT_ENVIRONMENT_DOMAINS]
|
|
132
|
+
},
|
|
133
|
+
session: {
|
|
134
|
+
kind: "read_and_watch",
|
|
135
|
+
domains: [...AGENT_ENVIRONMENT_DOMAINS]
|
|
136
|
+
}
|
|
137
|
+
},
|
|
120
138
|
collaboration: {
|
|
121
139
|
kind: "supported",
|
|
122
140
|
roles: ["delegate", "reviewer", "researcher", "specialist"],
|
|
@@ -147,7 +165,76 @@ function sessionBinding(state, sessionId) {
|
|
|
147
165
|
};
|
|
148
166
|
}
|
|
149
167
|
function eventBase(sessionId, turnId, occurredAt) {
|
|
150
|
-
return { protocolVersion:
|
|
168
|
+
return { protocolVersion: 9, sessionId, turnId, occurredAt };
|
|
169
|
+
}
|
|
170
|
+
function fakeEnvironmentSnapshot(environmentId) {
|
|
171
|
+
return parseAgentEnvironmentSnapshot({
|
|
172
|
+
schemaVersion: 1,
|
|
173
|
+
environmentId,
|
|
174
|
+
revision: 1,
|
|
175
|
+
content: { kind: "unavailable", reasons: ["transient_failure"] },
|
|
176
|
+
commands: { kind: "unavailable", reasons: ["transient_failure"] },
|
|
177
|
+
extensions: { kind: "unavailable", reasons: ["transient_failure"] },
|
|
178
|
+
integrations: { kind: "unavailable", reasons: ["transient_failure"] }
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
function fakeDiscoveryEnvironment(state, capability) {
|
|
182
|
+
if (capability.kind === "unsupported") return { kind: "unsupported" };
|
|
183
|
+
const domains = Object.freeze([
|
|
184
|
+
...capability.domains
|
|
185
|
+
]);
|
|
186
|
+
const readEnvironment = async ({ signal, environmentId }) => {
|
|
187
|
+
throwIfAgentOperationAborted(signal);
|
|
188
|
+
state.environmentReadIds.push(environmentId);
|
|
189
|
+
return fakeEnvironmentSnapshot(environmentId);
|
|
190
|
+
};
|
|
191
|
+
const watchEnvironment = async function* ({ signal, environmentId }) {
|
|
192
|
+
throwIfAgentOperationAborted(signal);
|
|
193
|
+
state.environmentInvalidationIds.push(environmentId);
|
|
194
|
+
yield { environmentId, domains: ["content"] };
|
|
195
|
+
};
|
|
196
|
+
if (capability.kind === "read") {
|
|
197
|
+
return {
|
|
198
|
+
kind: "read",
|
|
199
|
+
domains,
|
|
200
|
+
readEnvironment
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
kind: "read_and_watch",
|
|
205
|
+
domains,
|
|
206
|
+
readEnvironment,
|
|
207
|
+
watchEnvironment
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function fakeObservationEnvironment(state, capability) {
|
|
211
|
+
if (capability.kind === "unsupported") return { kind: "unsupported" };
|
|
212
|
+
const domains = Object.freeze([
|
|
213
|
+
...capability.domains
|
|
214
|
+
]);
|
|
215
|
+
const readEnvironment = async ({ signal, environmentId }) => {
|
|
216
|
+
throwIfAgentOperationAborted(signal);
|
|
217
|
+
state.environmentReadIds.push(environmentId);
|
|
218
|
+
return fakeEnvironmentSnapshot(environmentId);
|
|
219
|
+
};
|
|
220
|
+
const watchEnvironment = async function* ({ signal, environmentId }) {
|
|
221
|
+
throwIfAgentOperationAborted(signal);
|
|
222
|
+
state.environmentInvalidationIds.push(environmentId);
|
|
223
|
+
yield { environmentId, domains: ["content"] };
|
|
224
|
+
};
|
|
225
|
+
if (capability.kind === "read") {
|
|
226
|
+
return {
|
|
227
|
+
kind: "read",
|
|
228
|
+
domains,
|
|
229
|
+
readEnvironment
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
kind: "read_and_watch",
|
|
234
|
+
domains,
|
|
235
|
+
readEnvironment,
|
|
236
|
+
watchEnvironment
|
|
237
|
+
};
|
|
151
238
|
}
|
|
152
239
|
function requestForTurn(turnId) {
|
|
153
240
|
return {
|
|
@@ -383,17 +470,10 @@ function fakeSession(input) {
|
|
|
383
470
|
return { revision: 1, entries: [] };
|
|
384
471
|
}
|
|
385
472
|
} : { kind: "unsupported" },
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
return {
|
|
391
|
-
revision: 1,
|
|
392
|
-
observedAt: input.now(),
|
|
393
|
-
integrations: []
|
|
394
|
-
};
|
|
395
|
-
}
|
|
396
|
-
} : { kind: "unsupported" },
|
|
473
|
+
environment: fakeObservationEnvironment(
|
|
474
|
+
input.state,
|
|
475
|
+
input.capabilities.environment.session
|
|
476
|
+
),
|
|
397
477
|
collaboration: input.capabilities.collaboration.kind === "supported" ? {
|
|
398
478
|
kind: "supported",
|
|
399
479
|
spawnCollaboration: async (collaborationInput) => {
|
|
@@ -537,6 +617,8 @@ function createFakeAgentProvider(options = {}) {
|
|
|
537
617
|
interruptedTurnIds: [],
|
|
538
618
|
steeringInputs: [],
|
|
539
619
|
configurationRevisions: [],
|
|
620
|
+
environmentReadIds: [],
|
|
621
|
+
environmentInvalidationIds: [],
|
|
540
622
|
closeCounts: /* @__PURE__ */ new Map()
|
|
541
623
|
};
|
|
542
624
|
const driver = defineAgentProviderDriver({
|
|
@@ -555,6 +637,10 @@ function createFakeAgentProvider(options = {}) {
|
|
|
555
637
|
instanceId: createdInstanceId,
|
|
556
638
|
capabilities,
|
|
557
639
|
adapter: fakeAdapter({ state, capabilities, now, steeringResult }),
|
|
640
|
+
environment: fakeDiscoveryEnvironment(
|
|
641
|
+
state,
|
|
642
|
+
capabilities.environment.instance
|
|
643
|
+
),
|
|
558
644
|
accountQuota: options.accountQuota ?? { kind: "unsupported" },
|
|
559
645
|
checkReadiness: () => createAgentProviderReadiness({
|
|
560
646
|
status: "ready",
|
|
@@ -591,6 +677,10 @@ function createFakeAgentProvider(options = {}) {
|
|
|
591
677
|
configurationRevisions: Object.freeze([
|
|
592
678
|
...state.configurationRevisions
|
|
593
679
|
]),
|
|
680
|
+
environmentReadIds: Object.freeze([...state.environmentReadIds]),
|
|
681
|
+
environmentInvalidationIds: Object.freeze([
|
|
682
|
+
...state.environmentInvalidationIds
|
|
683
|
+
]),
|
|
594
684
|
closeCounts: Object.freeze(Object.fromEntries(state.closeCounts))
|
|
595
685
|
})
|
|
596
686
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agen-ai/agent-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Provider-neutral driver, instance, adapter, session, output, and conformance contracts for coding-agent runtimes.",
|
|
6
6
|
"type": "module",
|
|
@@ -24,10 +24,14 @@
|
|
|
24
24
|
"types": "./dist/testing/index.d.ts",
|
|
25
25
|
"import": "./dist/testing/index.js"
|
|
26
26
|
},
|
|
27
|
-
"./package.json": "./package.json"
|
|
27
|
+
"./package.json": "./package.json",
|
|
28
|
+
"./environment": {
|
|
29
|
+
"types": "./dist/environment/index.d.ts",
|
|
30
|
+
"import": "./dist/environment/index.js"
|
|
31
|
+
}
|
|
28
32
|
},
|
|
29
33
|
"dependencies": {
|
|
30
|
-
"@agen-ai/agent-protocol": "^0.
|
|
34
|
+
"@agen-ai/agent-protocol": "^0.3.0"
|
|
31
35
|
},
|
|
32
36
|
"devDependencies": {
|
|
33
37
|
"tsup": "^8.5.0"
|