@hivemagnus/ardent 0.0.0-stage → 1.0.2
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 +202 -0
- package/README.md +274 -2
- package/dist/a2a-client.d.ts +35 -0
- package/dist/a2a-client.js +172 -0
- package/dist/a2a-hermes-alias.d.ts +3 -0
- package/dist/a2a-hermes-alias.js +57 -0
- package/dist/a2a-idempotency.d.ts +13 -0
- package/dist/a2a-idempotency.js +86 -0
- package/dist/a2a-peers.d.ts +28 -0
- package/dist/a2a-peers.js +108 -0
- package/dist/a2a-push-inbox.d.ts +22 -0
- package/dist/a2a-push-inbox.js +84 -0
- package/dist/a2a-push.d.ts +27 -0
- package/dist/a2a-push.js +188 -0
- package/dist/a2a-server.d.ts +37 -0
- package/dist/a2a-server.js +186 -0
- package/dist/a2a-store.d.ts +10 -0
- package/dist/a2a-store.js +122 -0
- package/dist/a2a.d.ts +19 -0
- package/dist/a2a.js +466 -0
- package/dist/api.d.ts +6 -0
- package/dist/api.js +381 -0
- package/dist/artifacts.d.ts +15 -0
- package/dist/artifacts.js +41 -0
- package/dist/backend-events.d.ts +49 -0
- package/dist/backend-events.js +8 -0
- package/dist/channels.d.ts +52 -0
- package/dist/channels.js +184 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +845 -0
- package/dist/codex-output-budget.d.ts +17 -0
- package/dist/codex-output-budget.js +31 -0
- package/dist/codex-output-budget.test.d.ts +1 -0
- package/dist/codex-output-budget.test.js +29 -0
- package/dist/codex.d.ts +82 -0
- package/dist/codex.js +431 -0
- package/dist/config.d.ts +171 -0
- package/dist/config.js +244 -0
- package/dist/context-checkpoints.d.ts +49 -0
- package/dist/context-checkpoints.js +248 -0
- package/dist/context.d.ts +16 -0
- package/dist/context.js +101 -0
- package/dist/gateway-lock.d.ts +18 -0
- package/dist/gateway-lock.js +104 -0
- package/dist/hermes-compat.d.ts +15 -0
- package/dist/hermes-compat.js +62 -0
- package/dist/identity.d.ts +15 -0
- package/dist/identity.js +52 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +8 -0
- package/dist/job-engine.d.ts +222 -0
- package/dist/job-engine.js +497 -0
- package/dist/job-news-handlers.d.ts +54 -0
- package/dist/job-news-handlers.js +153 -0
- package/dist/job-ownership.d.ts +9 -0
- package/dist/job-ownership.js +17 -0
- package/dist/json-schema.d.ts +9 -0
- package/dist/json-schema.js +20 -0
- package/dist/llamacpp.d.ts +49 -0
- package/dist/llamacpp.js +216 -0
- package/dist/magnus-control.d.ts +3 -0
- package/dist/magnus-control.js +99 -0
- package/dist/magnus-node-dependency-impact.d.ts +1 -0
- package/dist/magnus-node-dependency-impact.js +126 -0
- package/dist/magnus-owner-reads.d.ts +4 -0
- package/dist/magnus-owner-reads.js +99 -0
- package/dist/magnus-readiness.d.ts +1 -0
- package/dist/magnus-readiness.js +108 -0
- package/dist/mattermost.d.ts +18 -0
- package/dist/mattermost.js +303 -0
- package/dist/memory-tools.d.ts +5 -0
- package/dist/memory-tools.js +49 -0
- package/dist/memory.d.ts +40 -0
- package/dist/memory.js +128 -0
- package/dist/model-policy.d.ts +64 -0
- package/dist/model-policy.js +56 -0
- package/dist/news.d.ts +10 -0
- package/dist/news.js +291 -0
- package/dist/owner-read.d.ts +32 -0
- package/dist/owner-read.js +130 -0
- package/dist/plugins.d.ts +74 -0
- package/dist/plugins.js +115 -0
- package/dist/research.d.ts +110 -0
- package/dist/research.js +164 -0
- package/dist/runtime.d.ts +33 -0
- package/dist/runtime.js +665 -0
- package/dist/skills.d.ts +13 -0
- package/dist/skills.js +87 -0
- package/dist/store.d.ts +142 -0
- package/dist/store.js +322 -0
- package/dist/team-artifacts.d.ts +138 -0
- package/dist/team-artifacts.js +241 -0
- package/dist/team-child.d.ts +21 -0
- package/dist/team-child.js +130 -0
- package/dist/team-contract.d.ts +116 -0
- package/dist/team-contract.js +84 -0
- package/dist/team-control.d.ts +8 -0
- package/dist/team-control.js +152 -0
- package/dist/telegram.d.ts +35 -0
- package/dist/telegram.js +284 -0
- package/dist/tools.d.ts +48 -0
- package/dist/tools.js +58 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +5 -0
- package/model-policy.default.json +20 -0
- package/package.json +84 -4
- package/profiles/assistant/IDENTITY.md +9 -0
- package/profiles/assistant/SOUL.md +8 -0
- package/profiles/assistant/config.yaml +88 -0
- package/profiles/assistant/peers.yaml +12 -0
- package/profiles/assistant/skills/grounded-answers/SKILL.md +18 -0
- package/protocol/LICENSE-A2A.txt +202 -0
- package/protocol/README.md +12 -0
- package/protocol/a2a.proto +811 -0
- package/protocol/lock.json +9 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ArdentRuntime } from './runtime.js';
|
|
3
|
+
import type { ArdentConfig } from './config.js';
|
|
4
|
+
declare const Manifest: z.ZodObject<{
|
|
5
|
+
schema_version: z.ZodLiteral<"1.0">;
|
|
6
|
+
revision: z.ZodNumber;
|
|
7
|
+
source_revision: z.ZodString;
|
|
8
|
+
visibility: z.ZodEnum<{
|
|
9
|
+
private: "private";
|
|
10
|
+
gm: "gm";
|
|
11
|
+
player: "player";
|
|
12
|
+
}>;
|
|
13
|
+
license: z.ZodString;
|
|
14
|
+
preview: z.ZodObject<{
|
|
15
|
+
mode: z.ZodEnum<{
|
|
16
|
+
none: "none";
|
|
17
|
+
inline: "inline";
|
|
18
|
+
thumbnail: "thumbnail";
|
|
19
|
+
download_only: "download_only";
|
|
20
|
+
}>;
|
|
21
|
+
mime: z.ZodString;
|
|
22
|
+
}, z.core.$strict>;
|
|
23
|
+
supersedes_sha256: z.ZodNullable<z.ZodString>;
|
|
24
|
+
acceptance_status: z.ZodEnum<{
|
|
25
|
+
rejected: "rejected";
|
|
26
|
+
partial: "partial";
|
|
27
|
+
unreviewed: "unreviewed";
|
|
28
|
+
approved: "approved";
|
|
29
|
+
}>;
|
|
30
|
+
name: z.ZodString;
|
|
31
|
+
mime: z.ZodString;
|
|
32
|
+
sha256: z.ZodString;
|
|
33
|
+
size: z.ZodNumber;
|
|
34
|
+
created_at: z.ZodNumber;
|
|
35
|
+
expires_at: z.ZodNumber;
|
|
36
|
+
provenance: z.ZodObject<{
|
|
37
|
+
producer: z.ZodString;
|
|
38
|
+
source_id: z.ZodString;
|
|
39
|
+
producer_task_id: z.ZodString;
|
|
40
|
+
lineage: z.ZodArray<z.ZodObject<{
|
|
41
|
+
producer: z.ZodString;
|
|
42
|
+
source_id: z.ZodString;
|
|
43
|
+
}, z.core.$strict>>;
|
|
44
|
+
}, z.core.$strict>;
|
|
45
|
+
recovery: z.ZodObject<{
|
|
46
|
+
on_expiry: z.ZodLiteral<"request_verified_reexport">;
|
|
47
|
+
}, z.core.$strict>;
|
|
48
|
+
artifact_id: z.ZodString;
|
|
49
|
+
}, z.core.$strict>;
|
|
50
|
+
export type TeamArtifactManifest = z.infer<typeof Manifest>;
|
|
51
|
+
export declare const TeamArtifactDescriptorSchema: z.ZodObject<{
|
|
52
|
+
artifact_id: z.ZodString;
|
|
53
|
+
name: z.ZodString;
|
|
54
|
+
mime: z.ZodString;
|
|
55
|
+
sha256: z.ZodString;
|
|
56
|
+
size: z.ZodNumber;
|
|
57
|
+
producer_task_id: z.ZodString;
|
|
58
|
+
artifact_manifest: z.ZodObject<{
|
|
59
|
+
schema_version: z.ZodLiteral<"1.0">;
|
|
60
|
+
revision: z.ZodNumber;
|
|
61
|
+
source_revision: z.ZodString;
|
|
62
|
+
visibility: z.ZodEnum<{
|
|
63
|
+
private: "private";
|
|
64
|
+
gm: "gm";
|
|
65
|
+
player: "player";
|
|
66
|
+
}>;
|
|
67
|
+
license: z.ZodString;
|
|
68
|
+
preview: z.ZodObject<{
|
|
69
|
+
mode: z.ZodEnum<{
|
|
70
|
+
none: "none";
|
|
71
|
+
inline: "inline";
|
|
72
|
+
thumbnail: "thumbnail";
|
|
73
|
+
download_only: "download_only";
|
|
74
|
+
}>;
|
|
75
|
+
mime: z.ZodString;
|
|
76
|
+
}, z.core.$strict>;
|
|
77
|
+
supersedes_sha256: z.ZodNullable<z.ZodString>;
|
|
78
|
+
acceptance_status: z.ZodEnum<{
|
|
79
|
+
rejected: "rejected";
|
|
80
|
+
partial: "partial";
|
|
81
|
+
unreviewed: "unreviewed";
|
|
82
|
+
approved: "approved";
|
|
83
|
+
}>;
|
|
84
|
+
name: z.ZodString;
|
|
85
|
+
mime: z.ZodString;
|
|
86
|
+
sha256: z.ZodString;
|
|
87
|
+
size: z.ZodNumber;
|
|
88
|
+
created_at: z.ZodNumber;
|
|
89
|
+
expires_at: z.ZodNumber;
|
|
90
|
+
provenance: z.ZodObject<{
|
|
91
|
+
producer: z.ZodString;
|
|
92
|
+
source_id: z.ZodString;
|
|
93
|
+
producer_task_id: z.ZodString;
|
|
94
|
+
lineage: z.ZodArray<z.ZodObject<{
|
|
95
|
+
producer: z.ZodString;
|
|
96
|
+
source_id: z.ZodString;
|
|
97
|
+
}, z.core.$strict>>;
|
|
98
|
+
}, z.core.$strict>;
|
|
99
|
+
recovery: z.ZodObject<{
|
|
100
|
+
on_expiry: z.ZodLiteral<"request_verified_reexport">;
|
|
101
|
+
}, z.core.$strict>;
|
|
102
|
+
artifact_id: z.ZodString;
|
|
103
|
+
}, z.core.$strict>;
|
|
104
|
+
}, z.core.$strict>;
|
|
105
|
+
export type TeamArtifactDescriptor = z.infer<typeof TeamArtifactDescriptorSchema>;
|
|
106
|
+
/** Peer artifact receipts. A transfer is retained evidence, never a delivery claim. */
|
|
107
|
+
export declare class TeamArtifacts {
|
|
108
|
+
readonly runtime: ArdentRuntime;
|
|
109
|
+
readonly config: ArdentConfig;
|
|
110
|
+
readonly env: NodeJS.ProcessEnv;
|
|
111
|
+
constructor(runtime: ArdentRuntime, config?: ArdentConfig, env?: NodeJS.ProcessEnv);
|
|
112
|
+
registerResearch(a2aTaskId: string): Promise<TeamArtifactDescriptor[]>;
|
|
113
|
+
serve(peer: string, id: string, contextId: string): Promise<{
|
|
114
|
+
status: number;
|
|
115
|
+
bytes?: Uint8Array;
|
|
116
|
+
descriptor?: TeamArtifactDescriptor;
|
|
117
|
+
}>;
|
|
118
|
+
revokeLocal(peer: string, a2aTaskId: string, id: string): void;
|
|
119
|
+
fetchHermes(input: {
|
|
120
|
+
owner: string;
|
|
121
|
+
localTaskId: string;
|
|
122
|
+
peer: string;
|
|
123
|
+
remoteTaskId: string;
|
|
124
|
+
remoteContextId: string;
|
|
125
|
+
artifactId: string;
|
|
126
|
+
sha256: string;
|
|
127
|
+
}): Promise<TeamArtifactDescriptor & {
|
|
128
|
+
local_artifact_id: string;
|
|
129
|
+
}>;
|
|
130
|
+
project(owner: string, localTaskId: string): Array<{
|
|
131
|
+
local_artifact_id: string;
|
|
132
|
+
peer: string;
|
|
133
|
+
remote_task_id: string;
|
|
134
|
+
artifact_manifest: TeamArtifactManifest;
|
|
135
|
+
delivery: 'unverified';
|
|
136
|
+
}>;
|
|
137
|
+
}
|
|
138
|
+
export {};
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { TaskState } from '@a2a-js/sdk';
|
|
4
|
+
import { ArdentA2AClient } from './a2a-client.js';
|
|
5
|
+
import { TeamEnvelope } from './team-contract.js';
|
|
6
|
+
const digest = z.string().regex(/^[a-f0-9]{64}$/);
|
|
7
|
+
const identifier = z.string().regex(/^[a-f0-9]{32}$/);
|
|
8
|
+
const safeName = z.string().regex(/^[A-Za-z0-9._-]{1,128}$/);
|
|
9
|
+
const Manifest = z.object({
|
|
10
|
+
schema_version: z.literal('1.0'), revision: z.number().int().min(1), source_revision: z.string().min(1),
|
|
11
|
+
visibility: z.enum(['private', 'gm', 'player']), license: z.string().min(1),
|
|
12
|
+
preview: z.object({ mode: z.enum(['inline', 'thumbnail', 'download_only', 'none']), mime: z.string().min(1) }).strict(),
|
|
13
|
+
supersedes_sha256: digest.nullable(), acceptance_status: z.enum(['unreviewed', 'approved', 'partial', 'rejected']),
|
|
14
|
+
name: safeName, mime: z.string().min(1), sha256: digest, size: z.number().int().min(0).max(2 * 1024 * 1024),
|
|
15
|
+
created_at: z.number().finite(), expires_at: z.number().finite(),
|
|
16
|
+
provenance: z.object({ producer: z.string().min(1), source_id: z.string(), producer_task_id: z.string().min(1),
|
|
17
|
+
lineage: z.array(z.object({ producer: z.string().min(1), source_id: z.string() }).strict()).min(1).max(4) }).strict(),
|
|
18
|
+
recovery: z.object({ on_expiry: z.literal('request_verified_reexport') }).strict(), artifact_id: identifier
|
|
19
|
+
}).strict();
|
|
20
|
+
export const TeamArtifactDescriptorSchema = z.object({ artifact_id: identifier, name: safeName, mime: z.string().min(1), sha256: digest,
|
|
21
|
+
size: z.number().int().min(0).max(2 * 1024 * 1024), producer_task_id: z.string().min(1), artifact_manifest: Manifest }).strict();
|
|
22
|
+
const LocalRow = z.object({ id: identifier, peer: z.string(), context_id: z.string(), a2a_task_id: z.string(),
|
|
23
|
+
digest, name: safeName, mime: z.string(), size: z.number(), manifest_json: z.string(), status: z.string(), expires: z.number() });
|
|
24
|
+
const TransferRow = z.object({ id: digest, owner: z.string(), local_task_id: z.string(), peer: z.string(),
|
|
25
|
+
remote_task_id: z.string(), remote_context_id: z.string(), remote_artifact_id: identifier,
|
|
26
|
+
digest, manifest_json: z.string(), status: z.string() });
|
|
27
|
+
const MAX_BYTES = 2 * 1024 * 1024;
|
|
28
|
+
const TTL_SECONDS = 7 * 24 * 3600;
|
|
29
|
+
function sha(bytes) { return createHash('sha256').update(bytes).digest('hex'); }
|
|
30
|
+
function textParts(task) {
|
|
31
|
+
return task.artifacts.flatMap(artifact => artifact.parts.flatMap(part => part.content?.$case === 'text' && typeof part.content.value === 'string' ? [part.content.value] : []));
|
|
32
|
+
}
|
|
33
|
+
/** Peer artifact receipts. A transfer is retained evidence, never a delivery claim. */
|
|
34
|
+
export class TeamArtifacts {
|
|
35
|
+
runtime;
|
|
36
|
+
config;
|
|
37
|
+
env;
|
|
38
|
+
constructor(runtime, config = runtime.config, env = process.env) {
|
|
39
|
+
this.runtime = runtime;
|
|
40
|
+
this.config = config;
|
|
41
|
+
this.env = env;
|
|
42
|
+
runtime.store.db.exec(`CREATE TABLE IF NOT EXISTS a2a_team_artifacts (
|
|
43
|
+
id TEXT PRIMARY KEY, peer TEXT NOT NULL, context_id TEXT NOT NULL, a2a_task_id TEXT NOT NULL,
|
|
44
|
+
digest TEXT NOT NULL, name TEXT NOT NULL, mime TEXT NOT NULL, size INTEGER NOT NULL,
|
|
45
|
+
manifest_json TEXT NOT NULL, status TEXT NOT NULL, expires REAL NOT NULL);
|
|
46
|
+
CREATE TABLE IF NOT EXISTS a2a_team_artifact_transfers (
|
|
47
|
+
id TEXT PRIMARY KEY, owner TEXT NOT NULL, local_task_id TEXT NOT NULL, peer TEXT NOT NULL,
|
|
48
|
+
remote_task_id TEXT NOT NULL, remote_context_id TEXT NOT NULL, remote_artifact_id TEXT NOT NULL,
|
|
49
|
+
digest TEXT NOT NULL, manifest_json TEXT NOT NULL, status TEXT NOT NULL);`);
|
|
50
|
+
}
|
|
51
|
+
async registerResearch(a2aTaskId) {
|
|
52
|
+
const db = this.runtime.store.db;
|
|
53
|
+
const row = db.prepare(`SELECT t.caller,t.context_id,o.tenant,o.operation_id,m.envelope_json FROM a2a_tasks t
|
|
54
|
+
JOIN a2a_operation_map o ON o.a2a_task_id=t.id JOIN a2a_team_missions m ON m.a2a_task_id=t.id
|
|
55
|
+
WHERE t.id=? AND t.caller=o.caller AND t.caller=m.caller`)
|
|
56
|
+
.get(a2aTaskId);
|
|
57
|
+
const bound = z.object({ caller: z.string(), context_id: z.string(), tenant: z.string(),
|
|
58
|
+
operation_id: z.string(), envelope_json: z.string() }).parse(row);
|
|
59
|
+
const operation = this.runtime.store.get(bound.operation_id);
|
|
60
|
+
if (operation?.state !== 'completed' || operation.context !== 'peer' ||
|
|
61
|
+
operation.caller !== `a2a:${bound.tenant}:${bound.caller}`)
|
|
62
|
+
return [];
|
|
63
|
+
const envelope = TeamEnvelope.parse(JSON.parse(bound.envelope_json));
|
|
64
|
+
if (!envelope.mission.allowed_actions.includes('create_artifact'))
|
|
65
|
+
return [];
|
|
66
|
+
const events = this.runtime.store.events(bound.operation_id, 0, 500);
|
|
67
|
+
const event = events.find(item => item.kind === 'research_artifacts');
|
|
68
|
+
const actual = z.object({ report: z.object({ id: digest }), markdown: z.object({ id: digest }) }).safeParse(event?.detail);
|
|
69
|
+
const entries = actual.success ? [
|
|
70
|
+
{ name: 'research-brief.json', mime: 'application/json', digest: actual.data.report.id, producer: 'ardent-research', sourceId: '' },
|
|
71
|
+
{ name: 'research-brief.md', mime: 'text/markdown', digest: actual.data.markdown.id, producer: 'ardent-research', sourceId: '' }
|
|
72
|
+
] : [];
|
|
73
|
+
const result = [];
|
|
74
|
+
for (const entry of entries) {
|
|
75
|
+
const bytes = await this.runtime.artifacts.get(entry.digest);
|
|
76
|
+
const size = bytes.byteLength;
|
|
77
|
+
if (size > MAX_BYTES)
|
|
78
|
+
throw new Error('Team artifact exceeds the byte limit');
|
|
79
|
+
const previous = db.prepare(`SELECT * FROM a2a_team_artifacts WHERE a2a_task_id=? AND digest=? AND name=? AND status='available' AND expires>?`)
|
|
80
|
+
.get(a2aTaskId, entry.digest, entry.name, Date.now() / 1000);
|
|
81
|
+
if (previous) {
|
|
82
|
+
const old = LocalRow.parse(previous);
|
|
83
|
+
result.push({ artifact_id: old.id, name: old.name, mime: old.mime, sha256: old.digest, size: old.size,
|
|
84
|
+
producer_task_id: a2aTaskId, artifact_manifest: Manifest.parse(JSON.parse(old.manifest_json)) });
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const id = randomBytes(16).toString('hex');
|
|
88
|
+
const created = Date.now() / 1000;
|
|
89
|
+
const manifest = {
|
|
90
|
+
schema_version: '1.0', revision: 1, source_revision: entry.digest,
|
|
91
|
+
visibility: 'private', license: 'NOASSERTION', preview: { mode: 'download_only', mime: entry.mime },
|
|
92
|
+
supersedes_sha256: null, acceptance_status: 'unreviewed', name: entry.name, mime: entry.mime,
|
|
93
|
+
sha256: entry.digest, size, created_at: created, expires_at: created + TTL_SECONDS,
|
|
94
|
+
provenance: { producer: entry.producer, source_id: entry.sourceId, producer_task_id: a2aTaskId,
|
|
95
|
+
lineage: [{ producer: entry.producer, source_id: entry.sourceId }] },
|
|
96
|
+
recovery: { on_expiry: 'request_verified_reexport' }, artifact_id: id
|
|
97
|
+
};
|
|
98
|
+
db.prepare(`INSERT INTO a2a_team_artifacts(id,peer,context_id,a2a_task_id,digest,name,mime,size,manifest_json,status,expires)
|
|
99
|
+
VALUES (?,?,?,?,?,?,?,?,?,'available',?)`).run(id, bound.caller, bound.context_id, a2aTaskId, entry.digest, entry.name, entry.mime, size, JSON.stringify(manifest), manifest.expires_at);
|
|
100
|
+
result.push({ artifact_id: id, name: entry.name, mime: entry.mime, sha256: entry.digest, size,
|
|
101
|
+
producer_task_id: a2aTaskId, artifact_manifest: manifest });
|
|
102
|
+
}
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
async serve(peer, id, contextId) {
|
|
106
|
+
if (!identifier.safeParse(id).success || !contextId || contextId.length > 128)
|
|
107
|
+
return { status: 404 };
|
|
108
|
+
const raw = this.runtime.store.db.prepare('SELECT * FROM a2a_team_artifacts WHERE id=? AND peer=? AND context_id=?').get(id, peer, contextId);
|
|
109
|
+
if (!raw)
|
|
110
|
+
return { status: 404 };
|
|
111
|
+
const row = LocalRow.parse(raw);
|
|
112
|
+
if (row.status !== 'available' || row.expires <= Date.now() / 1000)
|
|
113
|
+
return { status: 410 };
|
|
114
|
+
try {
|
|
115
|
+
const bytes = await this.runtime.artifacts.get(row.digest);
|
|
116
|
+
if (bytes.byteLength !== row.size)
|
|
117
|
+
return { status: 409 };
|
|
118
|
+
const manifest = Manifest.parse(JSON.parse(row.manifest_json));
|
|
119
|
+
if (manifest.artifact_id !== id || manifest.sha256 !== row.digest || manifest.expires_at !== row.expires ||
|
|
120
|
+
manifest.name !== row.name || manifest.mime !== row.mime || manifest.size !== row.size ||
|
|
121
|
+
manifest.provenance.producer_task_id !== row.a2a_task_id)
|
|
122
|
+
return { status: 410 };
|
|
123
|
+
return { status: 200, bytes, descriptor: { artifact_id: id, name: row.name, mime: row.mime,
|
|
124
|
+
sha256: row.digest, size: row.size, producer_task_id: row.a2a_task_id, artifact_manifest: manifest } };
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return { status: 409 };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
revokeLocal(peer, a2aTaskId, id) {
|
|
131
|
+
const changed = this.runtime.store.db.prepare(`UPDATE a2a_team_artifacts SET status='revoked'
|
|
132
|
+
WHERE id=? AND peer=? AND a2a_task_id=? AND status='available'`).run(id, peer, a2aTaskId).changes;
|
|
133
|
+
if (changed !== 1)
|
|
134
|
+
throw new Error('Owned artifact export is unavailable');
|
|
135
|
+
}
|
|
136
|
+
async fetchHermes(input) {
|
|
137
|
+
const owned = this.runtime.store.get(input.localTaskId);
|
|
138
|
+
if (!owned || owned.caller !== input.owner || !['direct', 'peer'].includes(owned.context))
|
|
139
|
+
throw new Error('Local recipient task is not owned');
|
|
140
|
+
const id = identifier.parse(input.artifactId);
|
|
141
|
+
const expected = digest.parse(input.sha256);
|
|
142
|
+
if (!input.remoteTaskId || !input.remoteContextId)
|
|
143
|
+
throw new Error('Remote task receipt is incomplete');
|
|
144
|
+
const transferId = sha(Buffer.from(JSON.stringify([input.owner, input.localTaskId, input.peer,
|
|
145
|
+
input.remoteTaskId, input.remoteContextId, id, expected])));
|
|
146
|
+
const priorRaw = this.runtime.store.db.prepare('SELECT * FROM a2a_team_artifact_transfers WHERE id=?').get(transferId);
|
|
147
|
+
if (priorRaw) {
|
|
148
|
+
const prior = TransferRow.parse(priorRaw);
|
|
149
|
+
if (prior.status !== 'complete')
|
|
150
|
+
throw new Error('Artifact transfer requires reconciliation');
|
|
151
|
+
await this.runtime.artifacts.get(prior.digest);
|
|
152
|
+
const manifest = Manifest.parse(JSON.parse(prior.manifest_json));
|
|
153
|
+
return { artifact_id: id, name: manifest.name, mime: manifest.mime, sha256: expected, size: manifest.size,
|
|
154
|
+
producer_task_id: input.remoteTaskId, artifact_manifest: manifest, local_artifact_id: prior.digest };
|
|
155
|
+
}
|
|
156
|
+
const { card, client, authorization } = await new ArdentA2AClient(this.runtime.profileDir, this.config, this.env).open(input.peer);
|
|
157
|
+
const remote = await client.getTask({ tenant: '', id: input.remoteTaskId }, { serviceParameters: { Authorization: authorization, 'A2A-Version': '1.0' } });
|
|
158
|
+
if (remote.id !== input.remoteTaskId || remote.contextId !== input.remoteContextId ||
|
|
159
|
+
remote.status?.state !== TaskState.TASK_STATE_COMPLETED)
|
|
160
|
+
throw new Error('Remote task receipt is not complete or bound');
|
|
161
|
+
const descriptors = textParts(remote).flatMap(value => {
|
|
162
|
+
try {
|
|
163
|
+
return [TeamArtifactDescriptorSchema.parse(JSON.parse(value))];
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return [];
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
const declared = descriptors.find(item => item.artifact_id === id && item.sha256 === expected &&
|
|
170
|
+
item.producer_task_id === input.remoteTaskId);
|
|
171
|
+
if (!declared)
|
|
172
|
+
throw new Error('Remote task did not declare this exact artifact');
|
|
173
|
+
const interfaceUrl = card.supportedInterfaces.find(item => item.protocolBinding.toUpperCase() === 'JSONRPC' &&
|
|
174
|
+
item.protocolVersion === '1.0')?.url;
|
|
175
|
+
if (!interfaceUrl)
|
|
176
|
+
throw new Error('Remote peer has no pinned JSON-RPC origin');
|
|
177
|
+
const url = new URL(`/team/artifacts/${id}`, interfaceUrl);
|
|
178
|
+
url.searchParams.set('context', input.remoteContextId);
|
|
179
|
+
const response = await fetch(url, { redirect: 'manual', signal: AbortSignal.timeout(30_000),
|
|
180
|
+
headers: { Authorization: authorization } });
|
|
181
|
+
if (!response.ok)
|
|
182
|
+
throw new Error(`Artifact fetch HTTP ${response.status}`);
|
|
183
|
+
const lengthHeader = response.headers.get('content-length');
|
|
184
|
+
const length = lengthHeader === null ? NaN : Number(lengthHeader);
|
|
185
|
+
if (!Number.isInteger(length) || length < 0 || length > MAX_BYTES || length !== declared.size)
|
|
186
|
+
throw new Error('Artifact size differs from task receipt');
|
|
187
|
+
if (response.headers.get('x-hermes-task-id') !== input.remoteTaskId ||
|
|
188
|
+
decodeURIComponent(response.headers.get('x-artifact-name') ?? '') !== declared.name ||
|
|
189
|
+
response.headers.get('content-type')?.split(';')[0] !== declared.mime)
|
|
190
|
+
throw new Error('Artifact response differs from task receipt');
|
|
191
|
+
const encoded = response.headers.get('x-hermes-artifact-manifest');
|
|
192
|
+
if (!encoded || encoded.length > 8192)
|
|
193
|
+
throw new Error('Artifact manifest is missing or oversized');
|
|
194
|
+
const manifest = Manifest.parse(JSON.parse(Buffer.from(encoded, 'base64url').toString('utf8')));
|
|
195
|
+
if (JSON.stringify(manifest) !== JSON.stringify(declared.artifact_manifest) ||
|
|
196
|
+
manifest.expires_at <= Date.now() / 1000 || manifest.provenance.producer_task_id !== input.remoteTaskId)
|
|
197
|
+
throw new Error('Artifact manifest differs from task receipt');
|
|
198
|
+
if (!response.body)
|
|
199
|
+
throw new Error('Artifact response has no body');
|
|
200
|
+
const reader = response.body.getReader();
|
|
201
|
+
const chunks = [];
|
|
202
|
+
let total = 0;
|
|
203
|
+
try {
|
|
204
|
+
while (true) {
|
|
205
|
+
const { done, value } = await reader.read();
|
|
206
|
+
if (done)
|
|
207
|
+
break;
|
|
208
|
+
total += value.byteLength;
|
|
209
|
+
if (total > MAX_BYTES || total > length)
|
|
210
|
+
throw new Error('Artifact response exceeds declared size');
|
|
211
|
+
chunks.push(value);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
await reader.cancel().catch(() => { });
|
|
216
|
+
throw error;
|
|
217
|
+
}
|
|
218
|
+
finally {
|
|
219
|
+
reader.releaseLock();
|
|
220
|
+
}
|
|
221
|
+
const bytes = Buffer.concat(chunks, total);
|
|
222
|
+
if (bytes.byteLength !== length || sha(bytes) !== expected)
|
|
223
|
+
throw new Error('Artifact bytes differ from task receipt');
|
|
224
|
+
const local = await this.runtime.artifacts.put(manifest.name, manifest.mime, bytes);
|
|
225
|
+
this.runtime.store.db.prepare(`INSERT INTO a2a_team_artifact_transfers(id,owner,local_task_id,peer,remote_task_id,
|
|
226
|
+
remote_context_id,remote_artifact_id,digest,manifest_json,status) VALUES (?,?,?,?,?,?,?,?,?,'complete')`)
|
|
227
|
+
.run(transferId, input.owner, input.localTaskId, input.peer, input.remoteTaskId, input.remoteContextId, id, local.id, JSON.stringify(manifest));
|
|
228
|
+
return { ...declared, local_artifact_id: local.id };
|
|
229
|
+
}
|
|
230
|
+
project(owner, localTaskId) {
|
|
231
|
+
const task = this.runtime.store.get(localTaskId);
|
|
232
|
+
if (!task || task.caller !== owner)
|
|
233
|
+
throw new Error('Recipient task owner differs');
|
|
234
|
+
return this.runtime.store.db.prepare(`SELECT * FROM a2a_team_artifact_transfers
|
|
235
|
+
WHERE owner=? AND local_task_id=? AND status='complete'`).all(owner, localTaskId).map(raw => {
|
|
236
|
+
const row = TransferRow.parse(raw);
|
|
237
|
+
return { local_artifact_id: row.digest, peer: row.peer, remote_task_id: row.remote_task_id,
|
|
238
|
+
artifact_manifest: Manifest.parse(JSON.parse(row.manifest_json)), delivery: 'unverified' };
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ArdentRuntime } from './runtime.js';
|
|
3
|
+
import { TeamEnvelope, type TeamResult } from './team-contract.js';
|
|
4
|
+
export declare const TeamChildReference: z.ZodObject<{
|
|
5
|
+
version: z.ZodLiteral<"1.0">;
|
|
6
|
+
root: z.ZodString;
|
|
7
|
+
child_id: z.ZodString;
|
|
8
|
+
sha256: z.ZodString;
|
|
9
|
+
}, z.core.$strict>;
|
|
10
|
+
export type TeamChildReference = z.infer<typeof TeamChildReference>;
|
|
11
|
+
/** A child is admitted only after the retained Hermes root grants its exact scope. */
|
|
12
|
+
export declare class TeamChildService {
|
|
13
|
+
#private;
|
|
14
|
+
readonly runtime: ArdentRuntime;
|
|
15
|
+
constructor(runtime: ArdentRuntime, env: NodeJS.ProcessEnv);
|
|
16
|
+
claim(raw: unknown, envelope: z.infer<typeof TeamEnvelope>, a2aTaskId: string, contextId: string, authenticatedCaller: string, requestFingerprint: string): Promise<TeamChildReference>;
|
|
17
|
+
attach(ref: TeamChildReference, operationId: string): void;
|
|
18
|
+
deadline(ref: TeamChildReference): number;
|
|
19
|
+
settle(ref: TeamChildReference, outcome: TeamResult['outcome'], result: string): Promise<void>;
|
|
20
|
+
flush(): Promise<void>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { ArdentA2AClient } from './a2a-client.js';
|
|
4
|
+
import { TeamEnvelope } from './team-contract.js';
|
|
5
|
+
const id = z.string().regex(/^[A-Za-z0-9._:-]{1,128}$/);
|
|
6
|
+
const sha = z.string().regex(/^[a-f0-9]{64}$/);
|
|
7
|
+
export const TeamChildReference = z.object({ version: z.literal('1.0'), root: id, child_id: id, sha256: sha }).strict();
|
|
8
|
+
const Grant = z.object({ version: z.literal('1.0'), root: id, child_id: id, target: z.string().regex(/^[A-Za-z0-9_-]{1,64}$/), parent_task: id,
|
|
9
|
+
context: id, envelope: TeamEnvelope, budget_id: id, depth: z.number().int().min(1).max(4), deadline: z.number().int().positive(), sha256: sha }).strict();
|
|
10
|
+
const ClaimResponse = z.object({ grant: Grant, state: z.literal('claimed'), claim_id: id }).passthrough();
|
|
11
|
+
const SettlementResponse = z.object({ native_id: id, status: z.string() }).passthrough();
|
|
12
|
+
const Row = z.object({ child_id: id, a2a_task_id: z.string(), fingerprint: sha, claim_id: id, root: id, grant_json: z.string(),
|
|
13
|
+
operation_id: z.string().nullable(), settlement_json: z.string().nullable(), acknowledged: z.number().int() });
|
|
14
|
+
function stable(value) {
|
|
15
|
+
const sort = (item) => {
|
|
16
|
+
if (Array.isArray(item))
|
|
17
|
+
return item.map(sort);
|
|
18
|
+
if (item && typeof item === 'object')
|
|
19
|
+
return Object.fromEntries(Object.entries(item)
|
|
20
|
+
.sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, nested]) => [key, sort(nested)]));
|
|
21
|
+
return item;
|
|
22
|
+
};
|
|
23
|
+
return JSON.stringify(sort(value));
|
|
24
|
+
}
|
|
25
|
+
function digest(value) { return createHash('sha256').update(stable(value)).digest('hex'); }
|
|
26
|
+
/** A child is admitted only after the retained Hermes root grants its exact scope. */
|
|
27
|
+
export class TeamChildService {
|
|
28
|
+
runtime;
|
|
29
|
+
#client;
|
|
30
|
+
constructor(runtime, env) {
|
|
31
|
+
this.runtime = runtime;
|
|
32
|
+
this.#client = new ArdentA2AClient(runtime.profileDir, runtime.config, env);
|
|
33
|
+
runtime.store.db.exec(`CREATE TABLE IF NOT EXISTS a2a_team_child_claims (
|
|
34
|
+
child_id TEXT PRIMARY KEY, a2a_task_id TEXT NOT NULL, fingerprint TEXT NOT NULL,
|
|
35
|
+
claim_id TEXT NOT NULL, root TEXT NOT NULL, grant_json TEXT NOT NULL,
|
|
36
|
+
operation_id TEXT, settlement_json TEXT, acknowledged INTEGER NOT NULL DEFAULT 0);`);
|
|
37
|
+
}
|
|
38
|
+
#row(childId) {
|
|
39
|
+
const raw = this.runtime.store.db.prepare('SELECT * FROM a2a_team_child_claims WHERE child_id=?').get(childId);
|
|
40
|
+
return raw ? Row.parse(raw) : undefined;
|
|
41
|
+
}
|
|
42
|
+
async #call(root, action, payload, key) {
|
|
43
|
+
const control = { version: '1.0', action, key, payload };
|
|
44
|
+
const receipt = await this.#client.teamControl(root, control);
|
|
45
|
+
if (receipt['request_digest'] !== digest(control))
|
|
46
|
+
throw new Error('Root coordination receipt digest differs');
|
|
47
|
+
return z.record(z.string(), z.unknown()).parse(receipt['data']);
|
|
48
|
+
}
|
|
49
|
+
async claim(raw, envelope, a2aTaskId, contextId, authenticatedCaller, requestFingerprint) {
|
|
50
|
+
const ref = TeamChildReference.parse(raw);
|
|
51
|
+
if (ref.child_id !== envelope.task_id || envelope.mission.parent_task === null ||
|
|
52
|
+
authenticatedCaller !== envelope.caller || !envelope.mission.allowed_actions.every(action => action === 'observe' || action === 'analyze'))
|
|
53
|
+
throw new Error('Child reference is outside the authenticated read-only mission');
|
|
54
|
+
const fingerprint = digest({ reference: ref, envelope, contextId, caller: authenticatedCaller, requestFingerprint });
|
|
55
|
+
const db = this.runtime.store.db;
|
|
56
|
+
let row = this.#row(ref.child_id);
|
|
57
|
+
if (row && (row.fingerprint !== fingerprint || row.root !== ref.root || row.a2a_task_id !== a2aTaskId))
|
|
58
|
+
throw new Error('Child receipt already binds different work');
|
|
59
|
+
if (!row) {
|
|
60
|
+
const claimId = `claim-${randomUUID().replaceAll('-', '')}`;
|
|
61
|
+
db.prepare('INSERT INTO a2a_team_child_claims(child_id,a2a_task_id,fingerprint,claim_id,root,grant_json) VALUES (?,?,?,?,?,?)')
|
|
62
|
+
.run(ref.child_id, a2aTaskId, fingerprint, claimId, ref.root, '{}');
|
|
63
|
+
row = this.#row(ref.child_id);
|
|
64
|
+
}
|
|
65
|
+
if (!row)
|
|
66
|
+
throw new Error('Child claim was not retained');
|
|
67
|
+
if (row.operation_id)
|
|
68
|
+
throw new Error('Child already has a native execution receipt; reconcile without replay');
|
|
69
|
+
if (row.grant_json !== '{}') {
|
|
70
|
+
if (Grant.parse(JSON.parse(row.grant_json)).deadline <= Date.now() / 1000)
|
|
71
|
+
throw new Error('Retained child grant has expired');
|
|
72
|
+
return ref;
|
|
73
|
+
}
|
|
74
|
+
const response = ClaimResponse.parse(await this.#call(ref.root, 'claim_child', { child_id: ref.child_id, grant_sha256: ref.sha256, claim_id: row.claim_id }, `claim-${digest([ref.child_id, row.claim_id])}`));
|
|
75
|
+
const grant = response.grant;
|
|
76
|
+
const { sha256, ...unsigned } = grant;
|
|
77
|
+
if (response.claim_id !== row.claim_id || sha256 !== ref.sha256 || digest(unsigned) !== sha256 ||
|
|
78
|
+
grant.target !== this.runtime.config.profile || grant.root !== ref.root || grant.child_id !== ref.child_id || grant.context !== contextId ||
|
|
79
|
+
stable(grant.envelope) !== stable(envelope) || grant.deadline <= Date.now() / 1000 ||
|
|
80
|
+
grant.deadline > envelope.mission.deadline || grant.parent_task !== envelope.mission.parent_task)
|
|
81
|
+
throw new Error('Root child grant does not authorize these exact parameters');
|
|
82
|
+
db.prepare('UPDATE a2a_team_child_claims SET grant_json=? WHERE child_id=?').run(stable(grant), ref.child_id);
|
|
83
|
+
return ref;
|
|
84
|
+
}
|
|
85
|
+
attach(ref, operationId) {
|
|
86
|
+
const row = this.#row(ref.child_id);
|
|
87
|
+
if (!row || row.grant_json === '{}')
|
|
88
|
+
throw new Error('Child execution has no retained root claim');
|
|
89
|
+
if (row.operation_id && row.operation_id !== operationId)
|
|
90
|
+
throw new Error('Child native execution identity changed');
|
|
91
|
+
this.runtime.store.db.prepare('UPDATE a2a_team_child_claims SET operation_id=? WHERE child_id=?').run(operationId, ref.child_id);
|
|
92
|
+
}
|
|
93
|
+
deadline(ref) {
|
|
94
|
+
const row = this.#row(ref.child_id);
|
|
95
|
+
if (!row || row.grant_json === '{}')
|
|
96
|
+
throw new Error('Child has no retained root budget');
|
|
97
|
+
return Grant.parse(JSON.parse(row.grant_json)).deadline;
|
|
98
|
+
}
|
|
99
|
+
async settle(ref, outcome, result) {
|
|
100
|
+
const row = this.#row(ref.child_id);
|
|
101
|
+
if (!row?.operation_id)
|
|
102
|
+
throw new Error('Child settlement has no native execution');
|
|
103
|
+
const value = { child_id: ref.child_id, claim_id: row.claim_id, native_id: row.a2a_task_id,
|
|
104
|
+
result: Buffer.byteLength(result, 'utf8') > 40_000 ? 'Child result exceeds root settlement limit; inspect retained Ardent task' : result,
|
|
105
|
+
outcome: Buffer.byteLength(result, 'utf8') > 40_000 ? 'unknown' : outcome };
|
|
106
|
+
const serialized = stable(value);
|
|
107
|
+
if (row.settlement_json && row.settlement_json !== serialized)
|
|
108
|
+
throw new Error('Child settlement cannot change after first publication');
|
|
109
|
+
if (!row.settlement_json)
|
|
110
|
+
this.runtime.store.db.prepare('UPDATE a2a_team_child_claims SET settlement_json=? WHERE child_id=?').run(serialized, ref.child_id);
|
|
111
|
+
if (row.acknowledged)
|
|
112
|
+
return;
|
|
113
|
+
const response = SettlementResponse.parse(await this.#call(row.root, 'settle_child', value, `settle-${digest(value)}`));
|
|
114
|
+
if (response.native_id !== row.a2a_task_id || response.status !== value.outcome)
|
|
115
|
+
throw new Error('Root child settlement binding differs');
|
|
116
|
+
this.runtime.store.db.prepare('UPDATE a2a_team_child_claims SET acknowledged=1 WHERE child_id=?').run(ref.child_id);
|
|
117
|
+
}
|
|
118
|
+
async flush() {
|
|
119
|
+
const rows = this.runtime.store.db.prepare('SELECT * FROM a2a_team_child_claims WHERE settlement_json IS NOT NULL AND acknowledged=0 LIMIT 16').all();
|
|
120
|
+
for (const raw of rows) {
|
|
121
|
+
try {
|
|
122
|
+
const row = Row.parse(raw);
|
|
123
|
+
const value = JSON.parse(row.settlement_json ?? '');
|
|
124
|
+
const settlement = z.object({ outcome: z.enum(['completed', 'partial', 'failed', 'blocked', 'input_required', 'cancelled', 'unknown']), result: z.string() }).passthrough().parse(value);
|
|
125
|
+
await this.settle({ version: '1.0', root: row.root, child_id: row.child_id, sha256: Grant.parse(JSON.parse(row.grant_json)).sha256 }, settlement.outcome, settlement.result);
|
|
126
|
+
}
|
|
127
|
+
catch { /* Retained settlement is retried later; native work is never replayed. */ }
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const TEAM_VERSION = "1.0";
|
|
3
|
+
export declare const TEAM_TASK_METADATA_KEY = "hermesTeamTask";
|
|
4
|
+
export declare const TEAM_CLARIFICATION_METADATA_KEY = "hermesTeamClarification";
|
|
5
|
+
/** The mission shape without its cross-field rules (Zod 4 cannot omit fields from a refined object). */
|
|
6
|
+
export declare const TeamMissionShape: z.ZodObject<{
|
|
7
|
+
id: z.ZodString;
|
|
8
|
+
revision: z.ZodNumber;
|
|
9
|
+
parent_task: z.ZodNullable<z.ZodString>;
|
|
10
|
+
constraints: z.ZodArray<z.ZodString>;
|
|
11
|
+
allowed_actions: z.ZodArray<z.ZodEnum<{
|
|
12
|
+
observe: "observe";
|
|
13
|
+
analyze: "analyze";
|
|
14
|
+
create_artifact: "create_artifact";
|
|
15
|
+
create_draft: "create_draft";
|
|
16
|
+
reversible_change: "reversible_change";
|
|
17
|
+
deploy: "deploy";
|
|
18
|
+
external_publish: "external_publish";
|
|
19
|
+
destructive_response: "destructive_response";
|
|
20
|
+
}>>;
|
|
21
|
+
resources: z.ZodArray<z.ZodString>;
|
|
22
|
+
deadline: z.ZodNumber;
|
|
23
|
+
acceptance_criteria: z.ZodArray<z.ZodString>;
|
|
24
|
+
expected_artifacts: z.ZodArray<z.ZodString>;
|
|
25
|
+
}, z.core.$strict>;
|
|
26
|
+
export declare const TeamMission: z.ZodObject<{
|
|
27
|
+
id: z.ZodString;
|
|
28
|
+
revision: z.ZodNumber;
|
|
29
|
+
parent_task: z.ZodNullable<z.ZodString>;
|
|
30
|
+
constraints: z.ZodArray<z.ZodString>;
|
|
31
|
+
allowed_actions: z.ZodArray<z.ZodEnum<{
|
|
32
|
+
observe: "observe";
|
|
33
|
+
analyze: "analyze";
|
|
34
|
+
create_artifact: "create_artifact";
|
|
35
|
+
create_draft: "create_draft";
|
|
36
|
+
reversible_change: "reversible_change";
|
|
37
|
+
deploy: "deploy";
|
|
38
|
+
external_publish: "external_publish";
|
|
39
|
+
destructive_response: "destructive_response";
|
|
40
|
+
}>>;
|
|
41
|
+
resources: z.ZodArray<z.ZodString>;
|
|
42
|
+
deadline: z.ZodNumber;
|
|
43
|
+
acceptance_criteria: z.ZodArray<z.ZodString>;
|
|
44
|
+
expected_artifacts: z.ZodArray<z.ZodString>;
|
|
45
|
+
}, z.core.$strict>;
|
|
46
|
+
export type TeamMission = z.infer<typeof TeamMission>;
|
|
47
|
+
export declare const TeamEnvelope: z.ZodObject<{
|
|
48
|
+
version: z.ZodLiteral<"1.0">;
|
|
49
|
+
caller: z.ZodString;
|
|
50
|
+
task_id: z.ZodString;
|
|
51
|
+
objective: z.ZodString;
|
|
52
|
+
mission: z.ZodObject<{
|
|
53
|
+
id: z.ZodString;
|
|
54
|
+
revision: z.ZodNumber;
|
|
55
|
+
parent_task: z.ZodNullable<z.ZodString>;
|
|
56
|
+
constraints: z.ZodArray<z.ZodString>;
|
|
57
|
+
allowed_actions: z.ZodArray<z.ZodEnum<{
|
|
58
|
+
observe: "observe";
|
|
59
|
+
analyze: "analyze";
|
|
60
|
+
create_artifact: "create_artifact";
|
|
61
|
+
create_draft: "create_draft";
|
|
62
|
+
reversible_change: "reversible_change";
|
|
63
|
+
deploy: "deploy";
|
|
64
|
+
external_publish: "external_publish";
|
|
65
|
+
destructive_response: "destructive_response";
|
|
66
|
+
}>>;
|
|
67
|
+
resources: z.ZodArray<z.ZodString>;
|
|
68
|
+
deadline: z.ZodNumber;
|
|
69
|
+
acceptance_criteria: z.ZodArray<z.ZodString>;
|
|
70
|
+
expected_artifacts: z.ZodArray<z.ZodString>;
|
|
71
|
+
}, z.core.$strict>;
|
|
72
|
+
}, z.core.$strict>;
|
|
73
|
+
export type TeamEnvelope = z.infer<typeof TeamEnvelope>;
|
|
74
|
+
export declare const TeamResult: z.ZodObject<{
|
|
75
|
+
version: z.ZodLiteral<"1.0">;
|
|
76
|
+
mission_id: z.ZodString;
|
|
77
|
+
mission_revision: z.ZodNumber;
|
|
78
|
+
task_id: z.ZodString;
|
|
79
|
+
outcome: z.ZodEnum<{
|
|
80
|
+
unknown: "unknown";
|
|
81
|
+
failed: "failed";
|
|
82
|
+
completed: "completed";
|
|
83
|
+
input_required: "input_required";
|
|
84
|
+
partial: "partial";
|
|
85
|
+
cancelled: "cancelled";
|
|
86
|
+
blocked: "blocked";
|
|
87
|
+
}>;
|
|
88
|
+
summary: z.ZodString;
|
|
89
|
+
checks: z.ZodArray<z.ZodObject<{
|
|
90
|
+
criterion: z.ZodString;
|
|
91
|
+
status: z.ZodEnum<{
|
|
92
|
+
unknown: "unknown";
|
|
93
|
+
pass: "pass";
|
|
94
|
+
fail: "fail";
|
|
95
|
+
}>;
|
|
96
|
+
evidence: z.ZodArray<z.ZodString>;
|
|
97
|
+
}, z.core.$strict>>;
|
|
98
|
+
artifacts: z.ZodArray<z.ZodObject<{
|
|
99
|
+
name: z.ZodString;
|
|
100
|
+
reference: z.ZodString;
|
|
101
|
+
sha256: z.ZodString;
|
|
102
|
+
}, z.core.$strict>>;
|
|
103
|
+
uncertain_effects: z.ZodArray<z.ZodString>;
|
|
104
|
+
clarification: z.ZodOptional<z.ZodObject<{
|
|
105
|
+
missing_fact: z.ZodString;
|
|
106
|
+
choices: z.ZodArray<z.ZodObject<{
|
|
107
|
+
id: z.ZodString;
|
|
108
|
+
label: z.ZodString;
|
|
109
|
+
}, z.core.$strict>>;
|
|
110
|
+
blocked_task: z.ZodString;
|
|
111
|
+
intended_respondent: z.ZodUnion<readonly [z.ZodString, z.ZodLiteral<"operator">]>;
|
|
112
|
+
}, z.core.$strict>>;
|
|
113
|
+
}, z.core.$strict>;
|
|
114
|
+
export type TeamResult = z.infer<typeof TeamResult>;
|
|
115
|
+
export declare function validateTeamEnvelope(value: unknown, authenticatedPeer: string, messageId: string, objective: string, nowSeconds?: number, child?: boolean): TeamEnvelope;
|
|
116
|
+
export declare function validateTeamResult(raw: string, envelope: TeamEnvelope, knownReferences?: ReadonlySet<string>): TeamResult;
|