ai-workflow-logic 0.1.11 → 0.2.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.
- package/package.json +8 -6
- package/src/agent-code-brand.ts +14 -0
- package/src/agent-code-execution.ts +98 -0
- package/src/agent-code-projection.ts +98 -0
- package/src/agent-definition-selection.ts +274 -24
- package/src/agent-execution-resources.ts +160 -0
- package/src/agent-resources.ts +3 -0
- package/src/browser.ts +1 -1
- package/src/core.ts +563 -0
- package/src/filesystem.ts +22 -2
- package/src/index.ts +6 -563
- package/src/resource-resolution.ts +145 -0
- package/src/run-freeze.ts +90 -6
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import Ajv, { type ValidateFunction } from 'ajv';
|
|
2
|
+
import {
|
|
3
|
+
DEPA_AI_RESOURCE_KIND_OWNERS,
|
|
4
|
+
DEPA_AI_RESOURCE_KIND_READER_REGISTRATIONS,
|
|
5
|
+
DEPA_AI_RESOURCE_KIND_SPEC_REVISIONS,
|
|
6
|
+
DEPA_AI_RESOURCE_KIND_SPEC_RESOLUTIONS,
|
|
7
|
+
} from 'ai-workflow-contract';
|
|
8
|
+
import type {
|
|
9
|
+
AuthoredResourceTree,
|
|
10
|
+
JsonSchemaValidator,
|
|
11
|
+
KindSpecRevision,
|
|
12
|
+
PortableSpec,
|
|
13
|
+
ResolvedResourceTree,
|
|
14
|
+
ResourceContentIdentity,
|
|
15
|
+
} from 'halfcode-compiler.xnl/resource-core';
|
|
16
|
+
import { createResourceContentIdentity, digestCanonical } from 'halfcode-compiler.xnl/resource-core';
|
|
17
|
+
import {
|
|
18
|
+
CORE_KIND_READER_REGISTRATIONS,
|
|
19
|
+
CORE_KIND_SPEC_REVISIONS,
|
|
20
|
+
CORE_KIND_SUBJECT_OWNERS,
|
|
21
|
+
KindContractRegistry,
|
|
22
|
+
KindReaderRegistry,
|
|
23
|
+
SpecResolutionRegistry,
|
|
24
|
+
createReaderProfile,
|
|
25
|
+
resolveResourceTree,
|
|
26
|
+
type ReaderProfile,
|
|
27
|
+
} from 'halfcode-compiler.xnl/kind-definition';
|
|
28
|
+
|
|
29
|
+
export const DEPA_AI_RESOURCE_READER_PROFILE_ID = 'depa.flows.ai-resources.v1' as const;
|
|
30
|
+
|
|
31
|
+
export interface AIWorkflowResourceResolutionContext {
|
|
32
|
+
readonly contracts: KindContractRegistry;
|
|
33
|
+
readonly readers: KindReaderRegistry;
|
|
34
|
+
readonly readerProfile: ReaderProfile;
|
|
35
|
+
readonly resolutions: SpecResolutionRegistry;
|
|
36
|
+
readonly validator: JsonSchemaValidator;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const ajv = new Ajv({ allErrors: true, strict: false, validateFormats: false });
|
|
40
|
+
const compiledSchemas = new Map<string, ValidateFunction>();
|
|
41
|
+
|
|
42
|
+
export const AI_WORKFLOW_RESOURCE_SCHEMA_VALIDATOR: JsonSchemaValidator = Object.freeze({
|
|
43
|
+
validate(revision: KindSpecRevision, value: PortableSpec): readonly string[] {
|
|
44
|
+
let validate = compiledSchemas.get(revision.contractFingerprint);
|
|
45
|
+
if (!validate) {
|
|
46
|
+
validate = ajv.compile(revision.specSchema);
|
|
47
|
+
compiledSchemas.set(revision.contractFingerprint, validate);
|
|
48
|
+
}
|
|
49
|
+
return validate(value)
|
|
50
|
+
? Object.freeze([])
|
|
51
|
+
: Object.freeze((validate.errors ?? []).map((error) =>
|
|
52
|
+
`${error.instancePath || '/'} ${error.message ?? 'invalid'}`));
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export function createAIWorkflowResourceResolutionContext(
|
|
57
|
+
validator: JsonSchemaValidator = AI_WORKFLOW_RESOURCE_SCHEMA_VALIDATOR,
|
|
58
|
+
tree?: AuthoredResourceTree,
|
|
59
|
+
): AIWorkflowResourceResolutionContext {
|
|
60
|
+
const contracts = new KindContractRegistry();
|
|
61
|
+
for (const owner of [...CORE_KIND_SUBJECT_OWNERS, ...DEPA_AI_RESOURCE_KIND_OWNERS]) {
|
|
62
|
+
contracts.registerOwner(owner);
|
|
63
|
+
}
|
|
64
|
+
// A package's declared revision set is an exact Halfcode admission boundary.
|
|
65
|
+
// Old packages keep their original v1 profile; new packages declare v1+v2.
|
|
66
|
+
const revisions = [...CORE_KIND_SPEC_REVISIONS, ...DEPA_AI_RESOURCE_KIND_SPEC_REVISIONS].filter(revision => {
|
|
67
|
+
const definition = tree && [...tree.registry.kindDefinitions.values()].find(item => item.subjectFqn === revision.subjectFqn);
|
|
68
|
+
return definition
|
|
69
|
+
? definition.specRevisions.some(item => item.specVersion === revision.specVersion)
|
|
70
|
+
: revision.specVersion === 1;
|
|
71
|
+
});
|
|
72
|
+
for (const revision of revisions) {
|
|
73
|
+
contracts.registerRevision(revision);
|
|
74
|
+
}
|
|
75
|
+
const hasRevision = (subjectFqn: string, specVersion: number): boolean => revisions.some(revision =>
|
|
76
|
+
revision.subjectFqn === subjectFqn && revision.specVersion === specVersion);
|
|
77
|
+
|
|
78
|
+
const readerRegistrations = [
|
|
79
|
+
...CORE_KIND_READER_REGISTRATIONS,
|
|
80
|
+
...DEPA_AI_RESOURCE_KIND_READER_REGISTRATIONS,
|
|
81
|
+
].filter(reader => hasRevision(reader.subjectFqn, reader.readerSpecVersion));
|
|
82
|
+
const readers = new KindReaderRegistry();
|
|
83
|
+
for (const reader of readerRegistrations) readers.register(reader);
|
|
84
|
+
const selectedReaders = readerRegistrations.filter(reader => !readerRegistrations.some(other =>
|
|
85
|
+
other.subjectFqn === reader.subjectFqn && other.readerSpecVersion > reader.readerSpecVersion));
|
|
86
|
+
const targets = selectedReaders.map((reader) => ({
|
|
87
|
+
readerId: reader.readerId,
|
|
88
|
+
subjectFqn: reader.subjectFqn,
|
|
89
|
+
readerSpecVersion: reader.readerSpecVersion,
|
|
90
|
+
contractFingerprint: reader.contractFingerprint,
|
|
91
|
+
readerImplementationFingerprint: reader.readerImplementationFingerprint,
|
|
92
|
+
}));
|
|
93
|
+
const readerProfile = createReaderProfile(
|
|
94
|
+
targets.some(target => target.readerSpecVersion !== 1)
|
|
95
|
+
? `${DEPA_AI_RESOURCE_READER_PROFILE_ID}/${digestCanonical(targets)}`
|
|
96
|
+
: DEPA_AI_RESOURCE_READER_PROFILE_ID,
|
|
97
|
+
targets,
|
|
98
|
+
);
|
|
99
|
+
const resolutions = new SpecResolutionRegistry(contracts);
|
|
100
|
+
for (const resolution of DEPA_AI_RESOURCE_KIND_SPEC_RESOLUTIONS) {
|
|
101
|
+
if (hasRevision(resolution.subjectFqn, resolution.writerSpecVersion)
|
|
102
|
+
&& hasRevision(resolution.subjectFqn, resolution.readerSpecVersion)) {
|
|
103
|
+
resolutions.register(resolution);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return Object.freeze({
|
|
107
|
+
contracts,
|
|
108
|
+
readers,
|
|
109
|
+
readerProfile,
|
|
110
|
+
resolutions,
|
|
111
|
+
validator,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function resolveAIWorkflowResourceTree(
|
|
116
|
+
tree: AuthoredResourceTree,
|
|
117
|
+
context?: AIWorkflowResourceResolutionContext,
|
|
118
|
+
): ResolvedResourceTree {
|
|
119
|
+
return resolveResourceTree({ tree, ...(context ?? createAIWorkflowResourceResolutionContext(undefined, tree)) });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Projects Halfcode's exact resolved content identity into the public dependency
|
|
124
|
+
* snapshot shape. The digest is still constructed by Halfcode; depa-flows only
|
|
125
|
+
* chooses the resolved receipt identity as the authority input.
|
|
126
|
+
*/
|
|
127
|
+
export function createResolvedAIWorkflowContentIdentityIndex(
|
|
128
|
+
tree: ResolvedResourceTree,
|
|
129
|
+
): ReadonlyMap<string, ResourceContentIdentity> {
|
|
130
|
+
const entries: Array<readonly [string, ResourceContentIdentity]> = [];
|
|
131
|
+
for (const records of tree.registry.byKind.values()) {
|
|
132
|
+
for (const record of records) {
|
|
133
|
+
entries.push([record.resourceId, createResourceContentIdentity({
|
|
134
|
+
resourceId: record.resourceId,
|
|
135
|
+
authorityDigest: record.effectiveContentDigest,
|
|
136
|
+
})]);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
entries.sort(([left], [right]) => compareCodeUnits(left, right));
|
|
140
|
+
return new Map(entries);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function compareCodeUnits(left: string, right: string): number {
|
|
144
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
145
|
+
}
|
package/src/run-freeze.ts
CHANGED
|
@@ -7,6 +7,8 @@ import type {
|
|
|
7
7
|
AIWorkflowRunResourceFreezeReceipt,
|
|
8
8
|
MaterialBindingProjection,
|
|
9
9
|
MaterialPortProjection,
|
|
10
|
+
CompiledAIAgentCodeExecution,
|
|
11
|
+
AIAgentCodeExecutionIdentity,
|
|
10
12
|
} from 'ai-workflow-contract';
|
|
11
13
|
import {
|
|
12
14
|
normalizeHolonTaskTarget,
|
|
@@ -18,16 +20,25 @@ import {
|
|
|
18
20
|
buildResourceDependencySnapshot,
|
|
19
21
|
composeLayeredResourceRegistry,
|
|
20
22
|
loadResourceTree,
|
|
21
|
-
resolveEffectiveResourceContentIdentities,
|
|
22
23
|
sha256Digest,
|
|
24
|
+
digestCanonical,
|
|
23
25
|
type EffectiveResourceRegistry,
|
|
24
26
|
type ResourceContentIdentity,
|
|
25
27
|
type ResourceDependencyEdge,
|
|
28
|
+
type Sha256Digest,
|
|
26
29
|
} from 'halfcode-compiler.xnl/resource-core';
|
|
27
30
|
import { projectAIWorkflowAgentResources } from './agent-resources.js';
|
|
28
31
|
import { sourceRegistryForAIWorkflowAgentResourceProjection } from './agent-resource-brand.js';
|
|
32
|
+
import { authorityForAIAgentCodeExecution } from './agent-code-brand.js';
|
|
33
|
+
import { assertAIAgentExecutionResources, assertAIAgentFreezeRegistry, type AIAgentExecutionResourceObservation } from './agent-execution-resources.js';
|
|
34
|
+
import {
|
|
35
|
+
createResolvedAIWorkflowContentIdentityIndex,
|
|
36
|
+
resolveAIWorkflowResourceTree,
|
|
37
|
+
} from './resource-resolution.js';
|
|
29
38
|
|
|
30
39
|
export interface FreezeAIWorkflowRunResourcesInput {
|
|
40
|
+
readonly executionResources?: AIAgentExecutionResourceObservation;
|
|
41
|
+
readonly codeExecutions?: readonly CompiledAIAgentCodeExecution[];
|
|
31
42
|
readonly registry: EffectiveResourceRegistry;
|
|
32
43
|
readonly projection: AIWorkflowAgentResourceProjection;
|
|
33
44
|
readonly task: AIWorkflowAgentTaskRef;
|
|
@@ -39,14 +50,15 @@ export async function freezeAIWorkflowRunResourcesFromDirectory(
|
|
|
39
50
|
rootDir: string,
|
|
40
51
|
task: AIWorkflowAgentTaskRef,
|
|
41
52
|
): Promise<AIWorkflowRunResourceFreezeReceipt> {
|
|
42
|
-
const
|
|
53
|
+
const authoredTree = await loadResourceTree({ rootDir });
|
|
54
|
+
const tree = resolveAIWorkflowResourceTree(authoredTree);
|
|
43
55
|
const layers = [{ id: 'workspace', tree }] as const;
|
|
44
56
|
const registry = composeLayeredResourceRegistry({ layers });
|
|
45
57
|
return freezeAIWorkflowRunResources({
|
|
46
58
|
registry,
|
|
47
59
|
projection: projectAIWorkflowAgentResources(registry),
|
|
48
60
|
task,
|
|
49
|
-
contentIdentities:
|
|
61
|
+
contentIdentities: createResolvedAIWorkflowContentIdentityIndex(tree),
|
|
50
62
|
});
|
|
51
63
|
}
|
|
52
64
|
|
|
@@ -59,6 +71,7 @@ export class AIWorkflowRunResourceFreezeError extends Error {
|
|
|
59
71
|
|
|
60
72
|
const authenticFreezeReceipts = new WeakSet<object>();
|
|
61
73
|
const authenticTaskBindings = new WeakSet<object>();
|
|
74
|
+
const receiptByTaskBinding = new WeakMap<object, AIWorkflowRunResourceFreezeReceipt>();
|
|
62
75
|
const authenticHolonTargetFreezeReceipts = new WeakSet<object>();
|
|
63
76
|
const authenticFrozenHolonTargets = new WeakSet<object>();
|
|
64
77
|
|
|
@@ -72,13 +85,14 @@ export async function freezeAIWorkflowHolonTaskTargetFromDirectory(
|
|
|
72
85
|
rootDir: string,
|
|
73
86
|
target: HolonTaskTarget,
|
|
74
87
|
): Promise<AIWorkflowHolonTaskTargetFreezeReceipt> {
|
|
75
|
-
const
|
|
88
|
+
const authoredTree = await loadResourceTree({ rootDir });
|
|
89
|
+
const tree = resolveAIWorkflowResourceTree(authoredTree);
|
|
76
90
|
const layers = [{ id: 'workspace', tree }] as const;
|
|
77
91
|
const registry = composeLayeredResourceRegistry({ layers });
|
|
78
92
|
return freezeAIWorkflowHolonTaskTarget({
|
|
79
93
|
registry,
|
|
80
94
|
target,
|
|
81
|
-
contentIdentities:
|
|
95
|
+
contentIdentities: createResolvedAIWorkflowContentIdentityIndex(tree),
|
|
82
96
|
});
|
|
83
97
|
}
|
|
84
98
|
|
|
@@ -180,6 +194,7 @@ export function assertFrozenHolonTaskTarget(value: FrozenHolonTaskTarget): Froze
|
|
|
180
194
|
export function freezeAIWorkflowRunResources(
|
|
181
195
|
input: FreezeAIWorkflowRunResourcesInput,
|
|
182
196
|
): AIWorkflowRunResourceFreezeReceipt {
|
|
197
|
+
assertAIAgentFreezeRegistry(input.registry);
|
|
183
198
|
const diagnostics: AIWorkflowResourceProjectionDiagnostic[] = [];
|
|
184
199
|
if (sourceRegistryForAIWorkflowAgentResourceProjection(input.projection) !== input.registry) {
|
|
185
200
|
diagnostics.push(diagnostic(
|
|
@@ -189,6 +204,19 @@ export function freezeAIWorkflowRunResources(
|
|
|
189
204
|
));
|
|
190
205
|
throwFreezeError(diagnostics);
|
|
191
206
|
}
|
|
207
|
+
const executionResources = input.executionResources === undefined ? undefined
|
|
208
|
+
: assertAIAgentExecutionResources(input.executionResources, input.registry);
|
|
209
|
+
if (executionResources) {
|
|
210
|
+
if (input.contentIdentities.size !== executionResources.contentIdentities.size
|
|
211
|
+
|| [...executionResources.contentIdentities].some(([id, identity]) =>
|
|
212
|
+
digestCanonical(input.contentIdentities.get(id) ?? null) !== digestCanonical(identity))) {
|
|
213
|
+
throw new AIWorkflowRunResourceFreezeError(Object.freeze([
|
|
214
|
+
diagnostic('AI_RUN_EXECUTION_CONTENT_IDENTITY_MISMATCH', 'run-freeze:identities', 'Execution observation requires its exact authored content identity facts.'),
|
|
215
|
+
]));
|
|
216
|
+
}
|
|
217
|
+
input = { ...input, registry: executionResources.registry, projection: executionResources.projection,
|
|
218
|
+
contentIdentities: executionResources.contentIdentities };
|
|
219
|
+
}
|
|
192
220
|
const task = normalizeTask(input.task, diagnostics);
|
|
193
221
|
if (!task) throwFreezeError(diagnostics);
|
|
194
222
|
const workflowId = resourceIdFromRef(task.workflowRef)!;
|
|
@@ -225,19 +253,34 @@ export function freezeAIWorkflowRunResources(
|
|
|
225
253
|
agentDefinitionRef: task.agentDefinitionRef,
|
|
226
254
|
});
|
|
227
255
|
const bindingResourceIds = Object.freeze(orderedBindings.map((binding) => binding.resource.resourceId));
|
|
228
|
-
const
|
|
256
|
+
const resourceFingerprint = semanticResourceFingerprint(
|
|
229
257
|
frozenTask,
|
|
230
258
|
agent,
|
|
231
259
|
orderedBindings,
|
|
232
260
|
dependencySnapshot.closure,
|
|
233
261
|
dependencySnapshot.edges,
|
|
234
262
|
);
|
|
263
|
+
const codeExecutions = selectedCodeExecutions(input, dependencySnapshot.closure.map(item => item.resourceId));
|
|
264
|
+
const resourceResolutions = executionResources && Object.freeze(dependencySnapshot.closure
|
|
265
|
+
.map(item => {
|
|
266
|
+
const resolution = executionResources.resolutionIdentities.get(item.resourceId);
|
|
267
|
+
if (!resolution) throw new Error(`AI_RUN_RESOURCE_RESOLUTION_MISSING: ${item.resourceId}`);
|
|
268
|
+
return resolution;
|
|
269
|
+
}).sort((a, b) => a.resourceId < b.resourceId ? -1 : a.resourceId > b.resourceId ? 1 : 0));
|
|
270
|
+
const codeFingerprint = codeExecutions.length
|
|
271
|
+
? sha256Digest(JSON.stringify({ schemaVersion: 'ai-workflow.code-bound-semantic/v1', resourceFingerprint, codeExecutions }))
|
|
272
|
+
: resourceFingerprint;
|
|
273
|
+
const semanticFingerprint = resourceResolutions
|
|
274
|
+
? sha256Digest(JSON.stringify({ schemaVersion: 'ai-workflow.reader-bound-semantic/v1', resourceFingerprint: codeFingerprint, resourceResolutions }))
|
|
275
|
+
: codeFingerprint;
|
|
235
276
|
const receipt = Object.freeze({
|
|
236
277
|
schemaVersion: 'ai-workflow.run-resource-freeze/v1',
|
|
237
278
|
task: frozenTask,
|
|
238
279
|
bindingResourceIds,
|
|
239
280
|
dependencySnapshot,
|
|
240
281
|
semanticFingerprint,
|
|
282
|
+
...(codeExecutions.length ? { codeExecutions } : {}),
|
|
283
|
+
...(resourceResolutions ? { resourceResolutions } : {}),
|
|
241
284
|
});
|
|
242
285
|
authenticFreezeReceipts.add(receipt);
|
|
243
286
|
return receipt;
|
|
@@ -258,11 +301,52 @@ export function projectFrozenAIAgentTaskBinding(
|
|
|
258
301
|
semanticFingerprint: receipt.semanticFingerprint,
|
|
259
302
|
snapshotRevision: receipt.dependencySnapshot.snapshotRevision,
|
|
260
303
|
closureResourceIds: Object.freeze(receipt.dependencySnapshot.closure.map((item) => item.resourceId)),
|
|
304
|
+
...(receipt.codeExecutions ? { codeExecutions: receipt.codeExecutions } : {}),
|
|
305
|
+
...(receipt.resourceResolutions ? { resourceResolutions: receipt.resourceResolutions } : {}),
|
|
261
306
|
});
|
|
262
307
|
authenticTaskBindings.add(binding);
|
|
308
|
+
receiptByTaskBinding.set(binding, receipt);
|
|
263
309
|
return binding;
|
|
264
310
|
}
|
|
265
311
|
|
|
312
|
+
/** Retrieves the old Agent identity from the authentic freeze, not caller feedback. */
|
|
313
|
+
export function frozenAIAgentTaskAgentContentDigest(binding: FrozenAIAgentTaskBinding): Sha256Digest {
|
|
314
|
+
assertFrozenAIAgentTaskBinding(binding);
|
|
315
|
+
const receipt = receiptByTaskBinding.get(binding)!;
|
|
316
|
+
const agentId = resourceIdFromRef(receipt.task.agentDefinitionRef)!;
|
|
317
|
+
const identity = receipt.dependencySnapshot.closure.find(({ resourceId }) => resourceId === agentId);
|
|
318
|
+
if (!identity) throw new AIWorkflowRunResourceFreezeError(Object.freeze([
|
|
319
|
+
diagnostic('AI_RUN_AGENT_IDENTITY_MISSING', binding.task.agentDefinitionRef, 'Frozen Agent identity is absent.'),
|
|
320
|
+
]));
|
|
321
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(identity.contentDigest)) throw new Error('Invalid frozen Agent content digest');
|
|
322
|
+
return identity.contentDigest as Sha256Digest;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function selectedCodeExecutions(input: FreezeAIWorkflowRunResourcesInput, closureIds: readonly string[]): readonly AIAgentCodeExecutionIdentity[] {
|
|
326
|
+
const selected = new Set(closureIds);
|
|
327
|
+
const identities = new Map<string, AIAgentCodeExecutionIdentity>();
|
|
328
|
+
for (const execution of input.codeExecutions ?? []) {
|
|
329
|
+
const authority = authorityForAIAgentCodeExecution(execution);
|
|
330
|
+
if (!authority || !selected.has(authority.identity.resourceId)
|
|
331
|
+
|| input.registry.byId.get(authority.identity.resourceId)?.resource !== authority.projection.resource
|
|
332
|
+
|| !(input.projection.codeResources ?? []).includes(authority.projection)
|
|
333
|
+
|| identities.has(authority.identity.resourceId)) {
|
|
334
|
+
throw new AIWorkflowRunResourceFreezeError(Object.freeze([
|
|
335
|
+
diagnostic('AI_RUN_CODE_EXECUTION_UNTRUSTED', 'run-freeze:code', 'Code execution must be authentic, selected and belong to the exact registry projection.'),
|
|
336
|
+
]));
|
|
337
|
+
}
|
|
338
|
+
identities.set(authority.identity.resourceId, authority.identity);
|
|
339
|
+
}
|
|
340
|
+
for (const code of input.projection.codeResources ?? []) {
|
|
341
|
+
if (code.mode === 'native' && selected.has(code.resource.resourceId) && !identities.has(code.resource.resourceId)) {
|
|
342
|
+
throw new AIWorkflowRunResourceFreezeError(Object.freeze([
|
|
343
|
+
diagnostic('AI_RUN_CODE_EXECUTION_MISSING', `resource://${code.resource.resourceId}`, 'Native code must be compiled or restored before task freeze.'),
|
|
344
|
+
]));
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return Object.freeze([...identities.values()].sort((a, b) => a.resourceId < b.resourceId ? -1 : a.resourceId > b.resourceId ? 1 : 0));
|
|
348
|
+
}
|
|
349
|
+
|
|
266
350
|
/** Runtime assertion; a structurally similar literal is not an admitted authority. */
|
|
267
351
|
export function assertFrozenAIAgentTaskBinding(value: FrozenAIAgentTaskBinding): FrozenAIAgentTaskBinding {
|
|
268
352
|
if (!authenticTaskBindings.has(value as object)) {
|