@tangle-network/agent-interface 2.2.0 → 2.3.1
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.
|
@@ -827,6 +827,8 @@ export interface AgentEnvironmentCapabilities {
|
|
|
827
827
|
branching: {
|
|
828
828
|
checkpoint: boolean;
|
|
829
829
|
fork: boolean;
|
|
830
|
+
/** True only when a fork can preserve and prove confidential requirements. */
|
|
831
|
+
confidential?: boolean;
|
|
830
832
|
/** True only when key + canonical request digest semantics are implemented. */
|
|
831
833
|
retrySafe?: boolean;
|
|
832
834
|
/** True only when operations can be recovered by idempotency key. */
|
|
@@ -984,6 +986,7 @@ export declare const AgentEnvironmentCapabilitiesSchema: z.ZodObject<{
|
|
|
984
986
|
branching: z.ZodObject<{
|
|
985
987
|
checkpoint: z.ZodBoolean;
|
|
986
988
|
fork: z.ZodBoolean;
|
|
989
|
+
confidential: z.ZodOptional<z.ZodBoolean>;
|
|
987
990
|
retrySafe: z.ZodOptional<z.ZodBoolean>;
|
|
988
991
|
lookup: z.ZodOptional<z.ZodBoolean>;
|
|
989
992
|
cleanup: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -1084,6 +1087,8 @@ export interface CreateAgentEnvironmentInput {
|
|
|
1084
1087
|
* The operation key names the request and the abort signal controls one
|
|
1085
1088
|
* attempt, so neither belongs in the input identity. Every other field is
|
|
1086
1089
|
* canonicalized with the shared RFC 8785 JSON representation.
|
|
1090
|
+
* A keyed create therefore accepts only canonical JSON material.
|
|
1091
|
+
* Unkeyed creates can retain opaque provider-native mapper values.
|
|
1087
1092
|
* @internal
|
|
1088
1093
|
*/
|
|
1089
1094
|
export declare function agentEnvironmentCreateInputDigest(input: CreateAgentEnvironmentInput): Sha256Digest;
|
|
@@ -1115,9 +1120,15 @@ export declare function replayedAgentEnvironmentView<T extends object>(environme
|
|
|
1115
1120
|
* with the creation verdict the provider could prove. Every same-key call
|
|
1116
1121
|
* after it, including one that awaited the same pending create, receives
|
|
1117
1122
|
* {@link replayedAgentEnvironmentView} of that environment.
|
|
1123
|
+
*
|
|
1124
|
+
* A keyed create callback receives one immutable canonical JSON snapshot.
|
|
1125
|
+
* Its digest and provider therefore read identical request bytes even when
|
|
1126
|
+
* the caller mutates its original object after this function returns.
|
|
1127
|
+
* An unkeyed create retains its original input so opaque provider-native
|
|
1128
|
+
* mapper values retain their public identity.
|
|
1118
1129
|
* @internal
|
|
1119
1130
|
*/
|
|
1120
|
-
export declare function createAgentEnvironmentWithIdempotency<T extends object>(records: Map<string, AgentEnvironmentCreateIdempotencyRecord<T>>, input: CreateAgentEnvironmentInput, create: () => Promise<T>): Promise<T>;
|
|
1131
|
+
export declare function createAgentEnvironmentWithIdempotency<T extends object>(records: Map<string, AgentEnvironmentCreateIdempotencyRecord<T>>, input: CreateAgentEnvironmentInput, create: (input: CreateAgentEnvironmentInput) => Promise<T>): Promise<T>;
|
|
1121
1132
|
export interface AgentEnvironmentProvider {
|
|
1122
1133
|
readonly name: string;
|
|
1123
1134
|
readonly exactProcess?: AgentExactProcessProvider;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { canonicalCandidateDigest } from "./agent-candidate-schema-common.js";
|
|
2
|
+
import { canonicalCandidateDigest, canonicalCandidateJson, } from "./agent-candidate-schema-common.js";
|
|
3
3
|
import { InteractionCapabilitiesSchema, RequestedInteractionsSchema } from "./interaction.js";
|
|
4
4
|
import { ContextTransferReceiptSchema, ContextTransferRequestSchema, NativeContextBoundaryProofSchema, NativeContextContinuationAcknowledgementSchema, NativeContextContinuationRequestSchema, nativeContextContinuationAcknowledgementMatches } from "./portable-context.js";
|
|
5
5
|
import { AgentExactRunControlRefSchema, AgentRunControlRefSchema, CanonicalStreamEventSchema } from "./runtime-control.js";
|
|
6
6
|
import { AgentProfileCapabilitiesSchema } from "./environment-profile-capabilities.js";
|
|
7
7
|
import { boundedIdentifierSchema, boundedJsonRecordSchema, boundedJsonSchema, boundedStringSchema, CONTRACT_MAX_ARRAY_LENGTH } from "./contract-limits.js";
|
|
8
8
|
import { InputPartSchema } from "./portable-context-shared.js";
|
|
9
|
+
import { deepFreeze } from "./deep-freeze.js";
|
|
9
10
|
export const AgentTurnInputSchema = z.strictObject({
|
|
10
11
|
prompt: boundedStringSchema.optional(),
|
|
11
12
|
parts: z.array(InputPartSchema).max(CONTRACT_MAX_ARRAY_LENGTH).optional(),
|
|
@@ -215,6 +216,7 @@ export const AgentEnvironmentCapabilitiesSchema = z
|
|
|
215
216
|
branching: z.strictObject({
|
|
216
217
|
checkpoint: z.boolean(),
|
|
217
218
|
fork: z.boolean(),
|
|
219
|
+
confidential: z.boolean().optional(),
|
|
218
220
|
retrySafe: z.boolean().optional(),
|
|
219
221
|
lookup: z.boolean().optional(),
|
|
220
222
|
cleanup: z.boolean().optional(),
|
|
@@ -422,6 +424,8 @@ export const AgentEnvironmentCapabilitiesSchema = z
|
|
|
422
424
|
* The operation key names the request and the abort signal controls one
|
|
423
425
|
* attempt, so neither belongs in the input identity. Every other field is
|
|
424
426
|
* canonicalized with the shared RFC 8785 JSON representation.
|
|
427
|
+
* A keyed create therefore accepts only canonical JSON material.
|
|
428
|
+
* Unkeyed creates can retain opaque provider-native mapper values.
|
|
425
429
|
* @internal
|
|
426
430
|
*/
|
|
427
431
|
export function agentEnvironmentCreateInputDigest(input) {
|
|
@@ -459,14 +463,26 @@ export function replayedAgentEnvironmentView(environment) {
|
|
|
459
463
|
* with the creation verdict the provider could prove. Every same-key call
|
|
460
464
|
* after it, including one that awaited the same pending create, receives
|
|
461
465
|
* {@link replayedAgentEnvironmentView} of that environment.
|
|
466
|
+
*
|
|
467
|
+
* A keyed create callback receives one immutable canonical JSON snapshot.
|
|
468
|
+
* Its digest and provider therefore read identical request bytes even when
|
|
469
|
+
* the caller mutates its original object after this function returns.
|
|
470
|
+
* An unkeyed create retains its original input so opaque provider-native
|
|
471
|
+
* mapper values retain their public identity.
|
|
462
472
|
* @internal
|
|
463
473
|
*/
|
|
464
474
|
export async function createAgentEnvironmentWithIdempotency(records, input, create) {
|
|
465
|
-
input
|
|
466
|
-
|
|
475
|
+
const { idempotencyKey: key, signal, ...material } = input;
|
|
476
|
+
signal?.throwIfAborted();
|
|
467
477
|
if (key === undefined)
|
|
468
|
-
return create();
|
|
469
|
-
const
|
|
478
|
+
return create(input);
|
|
479
|
+
const snapshot = deepFreeze(JSON.parse(canonicalCandidateJson(material)));
|
|
480
|
+
const acceptedInput = Object.freeze({
|
|
481
|
+
...snapshot,
|
|
482
|
+
idempotencyKey: key,
|
|
483
|
+
...(signal === undefined ? {} : { signal }),
|
|
484
|
+
});
|
|
485
|
+
const digest = agentEnvironmentCreateInputDigest(acceptedInput);
|
|
470
486
|
const existing = records.get(key);
|
|
471
487
|
if (existing !== undefined) {
|
|
472
488
|
if (existing.digest !== digest) {
|
|
@@ -474,7 +490,7 @@ export async function createAgentEnvironmentWithIdempotency(records, input, crea
|
|
|
474
490
|
}
|
|
475
491
|
return replayedAgentEnvironmentView(existing.environment ?? (await existing.pending));
|
|
476
492
|
}
|
|
477
|
-
const pending = Promise.resolve().then(create);
|
|
493
|
+
const pending = Promise.resolve().then(() => create(acceptedInput));
|
|
478
494
|
const record = {
|
|
479
495
|
digest,
|
|
480
496
|
pending,
|
|
@@ -9,6 +9,8 @@ import { type AgentExactRunControlRef } from "./runtime-control.js";
|
|
|
9
9
|
export declare const ConfidentialAttestationSchema: z.ZodObject<{
|
|
10
10
|
provider: z.ZodString;
|
|
11
11
|
requested: z.ZodLiteral<true>;
|
|
12
|
+
tee: z.ZodOptional<z.ZodString>;
|
|
13
|
+
sealed: z.ZodOptional<z.ZodBoolean>;
|
|
12
14
|
nonce: z.ZodString;
|
|
13
15
|
measurement: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
14
16
|
environmentId: z.ZodString;
|
|
@@ -32,11 +34,15 @@ export type ConfidentialAttestation = z.infer<typeof ConfidentialAttestationSche
|
|
|
32
34
|
/** What the caller asked for, separate from what the provider proved. */
|
|
33
35
|
export declare const ConfidentialExecutionRequestSchema: z.ZodObject<{
|
|
34
36
|
requested: z.ZodBoolean;
|
|
37
|
+
tee: z.ZodOptional<z.ZodString>;
|
|
38
|
+
sealed: z.ZodOptional<z.ZodBoolean>;
|
|
35
39
|
nonce: z.ZodOptional<z.ZodString>;
|
|
36
40
|
policy: z.ZodOptional<z.ZodString>;
|
|
37
41
|
profileDigest: z.ZodOptional<z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>>;
|
|
38
42
|
}, z.core.$strict>;
|
|
39
43
|
export type ConfidentialExecutionRequest = z.infer<typeof ConfidentialExecutionRequestSchema>;
|
|
44
|
+
/** Match one requested TEE against a provider-reported TEE identifier. */
|
|
45
|
+
export declare function confidentialTeeMatchesRequest(requested: string | undefined, attested: string | undefined): boolean;
|
|
40
46
|
export interface ConfidentialExecutionEnvironment {
|
|
41
47
|
provider: string;
|
|
42
48
|
environmentId: string;
|
|
@@ -11,6 +11,10 @@ export const ConfidentialAttestationSchema = z
|
|
|
11
11
|
.strictObject({
|
|
12
12
|
provider: idSchema,
|
|
13
13
|
requested: z.literal(true),
|
|
14
|
+
/** Provider-reported TEE type after external evidence verification. */
|
|
15
|
+
tee: idSchema.optional(),
|
|
16
|
+
/** Verified no-persistence posture, when the provider can prove it. */
|
|
17
|
+
sealed: z.boolean().optional(),
|
|
14
18
|
nonce: idSchema,
|
|
15
19
|
measurement: sha256DigestSchema,
|
|
16
20
|
environmentId: idSchema,
|
|
@@ -43,11 +47,18 @@ export const ConfidentialAttestationSchema = z
|
|
|
43
47
|
export const ConfidentialExecutionRequestSchema = z
|
|
44
48
|
.strictObject({
|
|
45
49
|
requested: z.boolean(),
|
|
50
|
+
/** Requested TEE. Omit it to accept any provider-supported TEE. */
|
|
51
|
+
tee: idSchema.optional(),
|
|
52
|
+
/** Require the provider to avoid persistence after the environment ends. */
|
|
53
|
+
sealed: z.boolean().optional(),
|
|
46
54
|
nonce: idSchema.optional(),
|
|
47
55
|
policy: idSchema.optional(),
|
|
48
56
|
profileDigest: sha256DigestSchema.optional(),
|
|
49
57
|
})
|
|
50
58
|
.superRefine((request, refinement) => {
|
|
59
|
+
const carriesAdmissionField = request.nonce !== undefined ||
|
|
60
|
+
request.policy !== undefined ||
|
|
61
|
+
request.profileDigest !== undefined;
|
|
51
62
|
const complete = request.nonce !== undefined &&
|
|
52
63
|
request.policy !== undefined &&
|
|
53
64
|
request.profileDigest !== undefined;
|
|
@@ -58,14 +69,48 @@ export const ConfidentialExecutionRequestSchema = z
|
|
|
58
69
|
message: "a confidential execution request must bind nonce, policy, and profile digest",
|
|
59
70
|
});
|
|
60
71
|
}
|
|
61
|
-
if (!request.requested &&
|
|
72
|
+
if (!request.requested &&
|
|
73
|
+
(carriesAdmissionField ||
|
|
74
|
+
request.tee !== undefined ||
|
|
75
|
+
request.sealed !== undefined)) {
|
|
62
76
|
refinement.addIssue({
|
|
63
77
|
code: "custom",
|
|
64
78
|
path: ["requested"],
|
|
65
|
-
message: "a non-confidential execution request cannot carry confidential admission fields",
|
|
79
|
+
message: "a non-confidential execution request cannot carry confidential requirements or admission fields",
|
|
66
80
|
});
|
|
67
81
|
}
|
|
68
82
|
});
|
|
83
|
+
function normalizedTeeId(value) {
|
|
84
|
+
const normalized = value.trim().toLowerCase().replaceAll("_", "-");
|
|
85
|
+
switch (normalized) {
|
|
86
|
+
case "aws-nitro":
|
|
87
|
+
case "aws-nitro-enclave":
|
|
88
|
+
case "aws-nitro-enclaves":
|
|
89
|
+
return "nitro";
|
|
90
|
+
case "intel-tdx":
|
|
91
|
+
return "tdx";
|
|
92
|
+
case "amd-sev":
|
|
93
|
+
case "amd-sev-snp":
|
|
94
|
+
case "sev":
|
|
95
|
+
return "sev-snp";
|
|
96
|
+
case "dstack":
|
|
97
|
+
case "phala":
|
|
98
|
+
return "phala-dstack";
|
|
99
|
+
default:
|
|
100
|
+
return normalized;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** Match one requested TEE against a provider-reported TEE identifier. */
|
|
104
|
+
export function confidentialTeeMatchesRequest(requested, attested) {
|
|
105
|
+
if (attested === undefined)
|
|
106
|
+
return requested === undefined;
|
|
107
|
+
const normalizedAttested = normalizedTeeId(attested);
|
|
108
|
+
if (normalizedAttested === "none")
|
|
109
|
+
return false;
|
|
110
|
+
if (requested === undefined || normalizedTeeId(requested) === "any")
|
|
111
|
+
return true;
|
|
112
|
+
return (normalizedAttested === normalizedTeeId(requested));
|
|
113
|
+
}
|
|
69
114
|
/**
|
|
70
115
|
* Verify every request/result binding and require an external provider-key
|
|
71
116
|
* check before exposing a positive confidentiality result.
|
|
@@ -104,6 +149,8 @@ export function confidentialExecutionVerified(input) {
|
|
|
104
149
|
attestation.nonce !== request.nonce ||
|
|
105
150
|
attestation.policy !== request.policy ||
|
|
106
151
|
attestation.profileDigest !== request.profileDigest ||
|
|
152
|
+
!confidentialTeeMatchesRequest(request.tee, attestation.tee) ||
|
|
153
|
+
(request.sealed === true && attestation.sealed !== true) ||
|
|
107
154
|
environment.confidentialRequested !== request.requested) {
|
|
108
155
|
return false;
|
|
109
156
|
}
|
|
@@ -114,6 +161,8 @@ export function confidentialExecutionRequestDigest(request) {
|
|
|
114
161
|
const parsed = ConfidentialExecutionRequestSchema.parse(request);
|
|
115
162
|
return wireDigest({
|
|
116
163
|
requested: parsed.requested,
|
|
164
|
+
...(parsed.tee === undefined ? {} : { tee: parsed.tee }),
|
|
165
|
+
...(parsed.sealed === undefined ? {} : { sealed: parsed.sealed }),
|
|
117
166
|
...(parsed.nonce === undefined ? {} : { nonce: parsed.nonce }),
|
|
118
167
|
...(parsed.policy === undefined ? {} : { policy: parsed.policy }),
|
|
119
168
|
...(parsed.profileDigest === undefined
|
package/dist/workspace-fork.d.ts
CHANGED
|
@@ -52,6 +52,8 @@ export declare const WorkspaceForkRequestSchema: z.ZodObject<{
|
|
|
52
52
|
}, z.core.$strict>;
|
|
53
53
|
confidential: z.ZodOptional<z.ZodObject<{
|
|
54
54
|
requested: z.ZodBoolean;
|
|
55
|
+
tee: z.ZodOptional<z.ZodString>;
|
|
56
|
+
sealed: z.ZodOptional<z.ZodBoolean>;
|
|
55
57
|
nonce: z.ZodOptional<z.ZodString>;
|
|
56
58
|
policy: z.ZodOptional<z.ZodString>;
|
|
57
59
|
profileDigest: z.ZodOptional<z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>>;
|
|
@@ -115,6 +117,8 @@ export declare const ForkedEnvironmentRefSchema: z.ZodObject<{
|
|
|
115
117
|
confidentialAttestation: z.ZodOptional<z.ZodObject<{
|
|
116
118
|
provider: z.ZodString;
|
|
117
119
|
requested: z.ZodLiteral<true>;
|
|
120
|
+
tee: z.ZodOptional<z.ZodString>;
|
|
121
|
+
sealed: z.ZodOptional<z.ZodBoolean>;
|
|
118
122
|
nonce: z.ZodString;
|
|
119
123
|
measurement: z.ZodType<`sha256:${string}`, unknown, z.core.$ZodTypeInternals<`sha256:${string}`, unknown>>;
|
|
120
124
|
environmentId: z.ZodString;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-interface",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"license": "MIT",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"zod": "4.5.4"
|
|
89
89
|
},
|
|
90
90
|
"devDependencies": {
|
|
91
|
-
"@types/node": "26.4.
|
|
91
|
+
"@types/node": "26.4.1",
|
|
92
92
|
"@types/spdx-expression-parse": "4.0.0",
|
|
93
93
|
"typescript": "7.0.2",
|
|
94
94
|
"vitest": "4.1.11"
|