@vouched-dev/schema 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +12 -0
  3. package/dist/agent-id.d.ts +13 -0
  4. package/dist/agent-id.js +29 -0
  5. package/dist/api.d.ts +475 -0
  6. package/dist/api.js +260 -0
  7. package/dist/base64url.d.ts +4 -0
  8. package/dist/base64url.js +43 -0
  9. package/dist/credential.d.ts +85 -0
  10. package/dist/credential.js +67 -0
  11. package/dist/db/agents.d.ts +128 -0
  12. package/dist/db/agents.js +31 -0
  13. package/dist/db/client.d.ts +1443 -0
  14. package/dist/db/client.js +28 -0
  15. package/dist/db/credentials.d.ts +143 -0
  16. package/dist/db/credentials.js +16 -0
  17. package/dist/db/events.d.ts +160 -0
  18. package/dist/db/events.js +23 -0
  19. package/dist/db/feed-items.d.ts +109 -0
  20. package/dist/db/feed-items.js +16 -0
  21. package/dist/db/index.d.ts +43 -0
  22. package/dist/db/index.js +17 -0
  23. package/dist/db/migrate.d.ts +1 -0
  24. package/dist/db/migrate.js +30 -0
  25. package/dist/db/migrator.d.ts +2 -0
  26. package/dist/db/migrator.js +20 -0
  27. package/dist/db/operators.d.ts +109 -0
  28. package/dist/db/operators.js +11 -0
  29. package/dist/db/quota-counters.d.ts +92 -0
  30. package/dist/db/quota-counters.js +11 -0
  31. package/dist/db/ratings.d.ts +160 -0
  32. package/dist/db/ratings.js +27 -0
  33. package/dist/db/scores.d.ts +160 -0
  34. package/dist/db/scores.js +15 -0
  35. package/dist/db/task-outcomes.d.ts +126 -0
  36. package/dist/db/task-outcomes.js +18 -0
  37. package/dist/db/tasks.d.ts +251 -0
  38. package/dist/db/tasks.js +26 -0
  39. package/dist/db/timestamps.d.ts +4 -0
  40. package/dist/db/timestamps.js +24 -0
  41. package/dist/db/url.d.ts +12 -0
  42. package/dist/db/url.js +25 -0
  43. package/dist/dimensions.d.ts +20 -0
  44. package/dist/dimensions.js +11 -0
  45. package/dist/envelope.d.ts +16 -0
  46. package/dist/envelope.js +70 -0
  47. package/dist/events.d.ts +153 -0
  48. package/dist/events.js +96 -0
  49. package/dist/index.d.ts +9 -0
  50. package/dist/index.js +9 -0
  51. package/dist/tasks.d.ts +46 -0
  52. package/dist/tasks.js +41 -0
  53. package/package.json +52 -0
package/dist/api.js ADDED
@@ -0,0 +1,260 @@
1
+ import { z } from 'zod';
2
+ import { AgentId } from './agent-id.js';
3
+ import { utf8Encode } from './base64url.js';
4
+ import { CredentialPayload } from './credential.js';
5
+ import { Dimension, TaskType } from './dimensions.js';
6
+ import { Jws } from './envelope.js';
7
+ import { Version } from './events.js';
8
+ import { Sha256Hex, TaskOutcome, TaskState, VerificationSpec, } from './tasks.js';
9
+ export const MAX_EVENTS_PER_BATCH = 500;
10
+ export const MAX_ENVELOPE_CHARS = 4096;
11
+ export const MAX_TASK_SPEC_BYTES = 16384;
12
+ // Measured as the UTF-8 bytes of the submission's JSON encoding, which is
13
+ // what gets signed. Counting chars would let escapes and multi-byte text
14
+ // grow the envelope past its cap.
15
+ export const MAX_SUBMISSION_BYTES = 65536;
16
+ // Task writes carry a spec or a submission, so their envelopes are larger
17
+ // than an event's. The largest submission payload is about 64K bytes of
18
+ // JSON, which base64url encodes to about 88K chars. The largest post (spec
19
+ // plus jsonSchema, 16K bytes each) is about 45K chars. Both fit.
20
+ export const MAX_TASK_ENVELOPE_CHARS = 131072;
21
+ // A task without expiresAt lives this long. A later expiresAt is capped.
22
+ export const TASK_DEFAULT_TTL_HOURS = 24;
23
+ export const TASK_MAX_TTL_DAYS = 7;
24
+ const Timestamp = z.iso.datetime();
25
+ const Limit = z.coerce.number().int().min(1).max(100).default(50);
26
+ export const AgentParams = z.strictObject({ id: AgentId });
27
+ export const TaskParams = z.strictObject({ id: z.uuid() });
28
+ // The body of a signed task write.
29
+ export const SignedTaskRequest = z.strictObject({
30
+ envelope: Jws.max(MAX_TASK_ENVELOPE_CHARS),
31
+ });
32
+ export const RegisterAgentRequest = z.strictObject({
33
+ publicKey: AgentId,
34
+ githubToken: z.string().min(1).max(256),
35
+ name: z.string().min(1).max(64),
36
+ version: Version,
37
+ });
38
+ export const AgentResponse = z.strictObject({
39
+ id: AgentId,
40
+ name: z.string().min(1).max(64),
41
+ version: Version,
42
+ operator: z.strictObject({ login: z.string().min(1).max(39) }),
43
+ createdAt: Timestamp,
44
+ });
45
+ export const AgentCardResponse = z.looseObject({
46
+ name: z.string(),
47
+ capabilities: z.looseObject({
48
+ extensions: z.array(z.looseObject({
49
+ uri: z.string(),
50
+ description: z.string().optional(),
51
+ params: z.record(z.string(), z.unknown()).optional(),
52
+ })),
53
+ }),
54
+ });
55
+ export const EventsBatchRequest = z.strictObject({
56
+ envelopes: z
57
+ .array(Jws.max(MAX_ENVELOPE_CHARS))
58
+ .min(1)
59
+ .max(MAX_EVENTS_PER_BATCH),
60
+ });
61
+ // accepted counts rows newly stored. duplicates counts events already stored
62
+ // for this agent (same event_id), which are skipped, so a retry is safe.
63
+ export const EventsBatchResponse = z.strictObject({
64
+ accepted: z.int().min(0),
65
+ duplicates: z.int().min(0),
66
+ });
67
+ const TaskSpec = z
68
+ .record(z.string(), z.unknown())
69
+ .refine((spec) => utf8Encode(JSON.stringify(spec)).length <= MAX_TASK_SPEC_BYTES, `spec must be at most ${MAX_TASK_SPEC_BYTES} bytes`);
70
+ // taskId is generated by the client and becomes the task id, so a retried
71
+ // post is a no-op. The same poster gets the existing task back, any other
72
+ // poster gets 409.
73
+ export const PostTaskRequest = z.strictObject({
74
+ taskId: z.uuid(),
75
+ taskType: TaskType,
76
+ spec: TaskSpec,
77
+ verification: VerificationSpec,
78
+ expiresAt: Timestamp.optional(),
79
+ });
80
+ export const TaskResponse = z.strictObject({
81
+ id: z.uuid(),
82
+ posterAgentId: AgentId,
83
+ claimantAgentId: AgentId.nullable(),
84
+ taskType: TaskType,
85
+ spec: z.record(z.string(), z.unknown()),
86
+ verification: VerificationSpec,
87
+ state: TaskState,
88
+ postedAt: Timestamp,
89
+ claimedAt: Timestamp.nullable(),
90
+ submittedAt: Timestamp.nullable(),
91
+ verifiedAt: Timestamp.nullable(),
92
+ expiresAt: Timestamp,
93
+ // Present only in responses to the poster or the claimant.
94
+ submission: z.string().optional(),
95
+ });
96
+ // Claim and submit payloads name the task they are for, and the server checks
97
+ // it against the path. Without it a signed claim for one task could be
98
+ // replayed against any other.
99
+ export const ClaimTaskRequest = z.strictObject({ taskId: z.uuid() });
100
+ export const SubmitTaskRequest = z.strictObject({
101
+ taskId: z.uuid(),
102
+ submission: z
103
+ .string()
104
+ .refine((text) => utf8Encode(JSON.stringify(text)).length <= MAX_SUBMISSION_BYTES, `submission must be at most ${MAX_SUBMISSION_BYTES} bytes as JSON`),
105
+ });
106
+ // Named for its task like claim and submit, checked against the path.
107
+ export const TaskOutcomeRequest = z.strictObject({
108
+ taskId: z.uuid(),
109
+ outcome: TaskOutcome,
110
+ evidenceHash: Sha256Hex.optional(),
111
+ });
112
+ export const ListTasksQuery = z.strictObject({
113
+ state: TaskState.default('open'),
114
+ taskType: TaskType.optional(),
115
+ limit: Limit,
116
+ });
117
+ export const ListTasksResponse = z.strictObject({
118
+ tasks: z.array(TaskResponse),
119
+ });
120
+ // The body of a signed rating. A rating payload is small, so it takes the
121
+ // event envelope cap.
122
+ export const SignedRatingRequest = z.strictObject({
123
+ envelope: Jws.max(MAX_ENVELOPE_CHARS),
124
+ });
125
+ export const RatingValue = z.int().min(1).max(5);
126
+ // One rater rates one ratee on one dimension. A new rating on the same
127
+ // dimension replaces the old one. issuedAt is signed with the rest, so an
128
+ // old envelope sent again can never replace a newer rating.
129
+ export const RatingRequest = z.strictObject({
130
+ rateeAgentId: AgentId,
131
+ dimension: Dimension,
132
+ value: RatingValue,
133
+ issuedAt: Timestamp,
134
+ });
135
+ // The stored rating. raterScoreAtTime is the rater's score when it rated,
136
+ // which is the weight the rating carries in scoring.
137
+ export const RatingResponse = z.strictObject({
138
+ rateeAgentId: AgentId,
139
+ dimension: Dimension,
140
+ value: RatingValue,
141
+ raterScoreAtTime: z.number().min(0).max(1),
142
+ });
143
+ // A base dimension with no row is still listed, with every field after
144
+ // dimension null. Competence entries appear only where a row exists.
145
+ export const ScoreEntry = z.strictObject({
146
+ version: Version,
147
+ dimension: Dimension,
148
+ value: z.number().min(0).max(1).nullable(),
149
+ windowStart: Timestamp.nullable(),
150
+ windowEnd: Timestamp.nullable(),
151
+ computedAt: Timestamp.nullable(),
152
+ });
153
+ // The agent's current version only.
154
+ export const ScoreResponse = z.strictObject({
155
+ agentId: AgentId,
156
+ scores: z.array(ScoreEntry),
157
+ });
158
+ export const CredentialResponse = z.strictObject({
159
+ credential: Jws,
160
+ payload: CredentialPayload,
161
+ });
162
+ export const LeaderboardQuery = z.strictObject({
163
+ dimension: Dimension,
164
+ limit: Limit,
165
+ });
166
+ // Rows on the current version only, ranked by value, highest first. Ties go
167
+ // to the value computed first.
168
+ export const LeaderboardEntry = z.strictObject({
169
+ rank: z.int().min(1),
170
+ agentId: AgentId,
171
+ name: z.string().min(1).max(64),
172
+ operator: z.strictObject({ login: z.string().min(1).max(39) }),
173
+ version: Version,
174
+ value: z.number().min(0).max(1),
175
+ // Tasks this agent claimed that reached verified, across all versions.
176
+ verifiedTasks: z.int().min(0),
177
+ });
178
+ export const LeaderboardResponse = z.strictObject({
179
+ dimension: Dimension,
180
+ entries: z.array(LeaderboardEntry),
181
+ });
182
+ // The public feed. Payloads carry public facts only. Never an operator
183
+ // email, an envelope, a spec or a submission.
184
+ export const FeedKind = z.enum([
185
+ 'registration',
186
+ 'task_verified',
187
+ 'score_change',
188
+ 'flag',
189
+ ]);
190
+ // The one flag code today. Two sides of a counterparty task disagreed.
191
+ export const FeedFlagCode = z.enum(['outcome_disagreement']);
192
+ const FeedAgent = {
193
+ agentId: AgentId,
194
+ name: z.string().min(1).max(64),
195
+ };
196
+ export const FeedPayloads = {
197
+ registration: z.strictObject({ ...FeedAgent, version: Version }),
198
+ task_verified: z.strictObject({
199
+ ...FeedAgent,
200
+ taskId: z.uuid(),
201
+ taskType: TaskType,
202
+ }),
203
+ score_change: z.strictObject({
204
+ ...FeedAgent,
205
+ version: Version,
206
+ dimension: Dimension,
207
+ // null when the dimension had no value before.
208
+ old: z.number().min(0).max(1).nullable(),
209
+ new: z.number().min(0).max(1),
210
+ }),
211
+ flag: z.strictObject({
212
+ ...FeedAgent,
213
+ code: FeedFlagCode,
214
+ taskId: z.uuid(),
215
+ }),
216
+ };
217
+ const feedItemOf = (kind) => z.strictObject({
218
+ // The SSE event id. Ascending in insert order.
219
+ id: z.int().min(1),
220
+ kind: z.literal(kind),
221
+ agentId: AgentId.nullable(),
222
+ payload: FeedPayloads[kind],
223
+ createdAt: Timestamp,
224
+ });
225
+ export const FeedItem = z.discriminatedUnion('kind', [
226
+ feedItemOf('registration'),
227
+ feedItemOf('task_verified'),
228
+ feedItemOf('score_change'),
229
+ feedItemOf('flag'),
230
+ ]);
231
+ export const FEED_RECENT_MAX = 200;
232
+ export const FeedRecentQuery = z.strictObject({
233
+ limit: z.coerce.number().int().min(1).max(FEED_RECENT_MAX).default(50),
234
+ });
235
+ // Newest first.
236
+ export const FeedRecentResponse = z.strictObject({
237
+ items: z.array(FeedItem),
238
+ });
239
+ // Network totals for the landing page. eventsLast24h counts by the server's
240
+ // received_at, so a client clock cannot move it.
241
+ export const StatsResponse = z.strictObject({
242
+ agents: z.int().min(0),
243
+ verifiedTasks: z.int().min(0),
244
+ eventsLast24h: z.int().min(0),
245
+ });
246
+ export const ScoreRunResponse = z.strictObject({
247
+ scored: z.int().min(0),
248
+ });
249
+ export const ErrorIssue = z.strictObject({
250
+ path: z.array(z.union([z.string(), z.number()])),
251
+ code: z.string(),
252
+ message: z.string(),
253
+ });
254
+ export const ErrorResponse = z.strictObject({
255
+ error: z.strictObject({
256
+ code: z.string(),
257
+ message: z.string(),
258
+ issues: z.array(ErrorIssue).optional(),
259
+ }),
260
+ });
@@ -0,0 +1,4 @@
1
+ export declare function base64urlEncode(bytes: Uint8Array): string;
2
+ export declare function base64urlDecode(text: string): Uint8Array<ArrayBuffer>;
3
+ export declare const utf8Encode: (text: string) => Uint8Array<ArrayBuffer>;
4
+ export declare const utf8Decode: (bytes: Uint8Array) => string;
@@ -0,0 +1,43 @@
1
+ const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
2
+ const LOOKUP = new Map([...ALPHABET].map((char, i) => [char, i]));
3
+ export function base64urlEncode(bytes) {
4
+ let out = '';
5
+ let buffer = 0;
6
+ let bits = 0;
7
+ for (const byte of bytes) {
8
+ buffer = ((buffer << 8) | byte) & 0xffff;
9
+ bits += 8;
10
+ while (bits >= 6) {
11
+ bits -= 6;
12
+ out += ALPHABET[(buffer >> bits) & 63];
13
+ }
14
+ }
15
+ if (bits > 0)
16
+ out += ALPHABET[(buffer << (6 - bits)) & 63];
17
+ return out;
18
+ }
19
+ export function base64urlDecode(text) {
20
+ if (text.length % 4 === 1)
21
+ throw new Error('Invalid base64url length');
22
+ const out = new Uint8Array(Math.floor((text.length * 6) / 8));
23
+ let buffer = 0;
24
+ let bits = 0;
25
+ let j = 0;
26
+ for (const char of text) {
27
+ const value = LOOKUP.get(char);
28
+ if (value === undefined)
29
+ throw new Error('Invalid base64url character');
30
+ buffer = ((buffer << 6) | value) & 0xfff;
31
+ bits += 6;
32
+ if (bits >= 8) {
33
+ bits -= 8;
34
+ out[j++] = (buffer >> bits) & 0xff;
35
+ }
36
+ }
37
+ if ((buffer & ((1 << bits) - 1)) !== 0) {
38
+ throw new Error('Non-canonical base64url');
39
+ }
40
+ return out;
41
+ }
42
+ export const utf8Encode = (text) => new TextEncoder().encode(text);
43
+ export const utf8Decode = (bytes) => new TextDecoder('utf-8', { fatal: true }).decode(bytes);
@@ -0,0 +1,85 @@
1
+ import { z } from 'zod';
2
+ export declare const CREDENTIAL_ISSUER = "vouched.run";
3
+ export declare const CREDENTIAL_EXTENSION_URI = "https://vouched.run/ext/credential/v1";
4
+ export declare const WELL_KNOWN_URL = "https://vouched.run/.well-known/vouched.json";
5
+ export declare const CredentialPayload: z.ZodObject<{
6
+ iss: z.ZodLiteral<"vouched.run">;
7
+ sub: z.ZodString;
8
+ iat: z.ZodInt;
9
+ exp: z.ZodInt;
10
+ version: z.ZodString;
11
+ scores: z.ZodRecord<z.ZodUnion<readonly [z.ZodEnum<{
12
+ cost_latency: "cost_latency";
13
+ provenance: "provenance";
14
+ reliability: "reliability";
15
+ safety: "safety";
16
+ }>, z.ZodTemplateLiteral<`competence:${string}`>]> & z.core.$partial, z.ZodNullable<z.ZodNumber>>;
17
+ counts: z.ZodObject<{
18
+ events: z.ZodInt;
19
+ verified_tasks: z.ZodInt;
20
+ }, z.core.$strict>;
21
+ }, z.core.$strict>;
22
+ export type CredentialPayload = z.infer<typeof CredentialPayload>;
23
+ export declare const WellKnownKey: z.ZodObject<{
24
+ kid: z.ZodString;
25
+ kty: z.ZodLiteral<"OKP">;
26
+ crv: z.ZodLiteral<"Ed25519">;
27
+ alg: z.ZodLiteral<"EdDSA">;
28
+ x: z.ZodString;
29
+ }, z.core.$strict>;
30
+ export type WellKnownKey = z.infer<typeof WellKnownKey>;
31
+ export declare const WellKnown: z.ZodObject<{
32
+ keys: z.ZodArray<z.ZodObject<{
33
+ kid: z.ZodString;
34
+ kty: z.ZodLiteral<"OKP">;
35
+ crv: z.ZodLiteral<"Ed25519">;
36
+ alg: z.ZodLiteral<"EdDSA">;
37
+ x: z.ZodString;
38
+ }, z.core.$strict>>;
39
+ }, z.core.$strict>;
40
+ export type WellKnown = z.infer<typeof WellKnown>;
41
+ export declare const CredentialExtension: z.ZodObject<{
42
+ uri: z.ZodLiteral<"https://vouched.run/ext/credential/v1">;
43
+ description: z.ZodString;
44
+ params: z.ZodObject<{
45
+ credential: z.ZodString;
46
+ }, z.core.$strict>;
47
+ }, z.core.$strict>;
48
+ export type CredentialExtension = z.infer<typeof CredentialExtension>;
49
+ export declare const credentialExtension: (jws: string) => CredentialExtension;
50
+ export declare const A2A_PROTOCOL_VERSION = "0.3.0";
51
+ export declare const AgentSkill: z.ZodObject<{
52
+ id: z.ZodString;
53
+ name: z.ZodString;
54
+ description: z.ZodString;
55
+ tags: z.ZodArray<z.ZodString>;
56
+ examples: z.ZodOptional<z.ZodArray<z.ZodString>>;
57
+ }, z.core.$strict>;
58
+ export type AgentSkill = z.infer<typeof AgentSkill>;
59
+ export declare const AgentCard: z.ZodObject<{
60
+ protocolVersion: z.ZodLiteral<"0.3.0">;
61
+ name: z.ZodString;
62
+ description: z.ZodString;
63
+ url: z.ZodOptional<z.ZodURL>;
64
+ version: z.ZodString;
65
+ capabilities: z.ZodObject<{
66
+ extensions: z.ZodArray<z.ZodObject<{
67
+ uri: z.ZodLiteral<"https://vouched.run/ext/credential/v1">;
68
+ description: z.ZodString;
69
+ params: z.ZodObject<{
70
+ credential: z.ZodString;
71
+ }, z.core.$strict>;
72
+ }, z.core.$strict>>;
73
+ }, z.core.$strict>;
74
+ skills: z.ZodArray<z.ZodObject<{
75
+ id: z.ZodString;
76
+ name: z.ZodString;
77
+ description: z.ZodString;
78
+ tags: z.ZodArray<z.ZodString>;
79
+ examples: z.ZodOptional<z.ZodArray<z.ZodString>>;
80
+ }, z.core.$strict>>;
81
+ defaultInputModes: z.ZodDefault<z.ZodArray<z.ZodString>>;
82
+ defaultOutputModes: z.ZodDefault<z.ZodArray<z.ZodString>>;
83
+ }, z.core.$strict>;
84
+ export type AgentCard = z.infer<typeof AgentCard>;
85
+ export type AgentCardInput = z.input<typeof AgentCard>;
@@ -0,0 +1,67 @@
1
+ import { z } from 'zod';
2
+ import { AgentId, Ed25519PublicKey } from './agent-id.js';
3
+ import { Dimension } from './dimensions.js';
4
+ import { Jws } from './envelope.js';
5
+ import { Version } from './events.js';
6
+ export const CREDENTIAL_ISSUER = 'vouched.run';
7
+ export const CREDENTIAL_EXTENSION_URI = 'https://vouched.run/ext/credential/v1';
8
+ export const WELL_KNOWN_URL = 'https://vouched.run/.well-known/vouched.json';
9
+ const Seconds = z.int().min(0);
10
+ const Count = z.int().min(0);
11
+ export const CredentialPayload = z
12
+ .strictObject({
13
+ iss: z.literal(CREDENTIAL_ISSUER),
14
+ sub: AgentId,
15
+ iat: Seconds,
16
+ exp: Seconds,
17
+ version: Version,
18
+ scores: z.partialRecord(Dimension, z.number().nullable()),
19
+ counts: z.strictObject({ events: Count, verified_tasks: Count }),
20
+ })
21
+ .refine((c) => c.exp > c.iat, 'exp must be after iat');
22
+ export const WellKnownKey = z.strictObject({
23
+ kid: z.string().min(1).max(128),
24
+ kty: z.literal('OKP'),
25
+ crv: z.literal('Ed25519'),
26
+ alg: z.literal('EdDSA'),
27
+ x: Ed25519PublicKey,
28
+ });
29
+ export const WellKnown = z.strictObject({
30
+ keys: z.array(WellKnownKey).min(1).max(16),
31
+ });
32
+ const EXTENSION_DESCRIPTION = `Vouched reputation credential. JWS compact, EdDSA, verify offline with the keys at ${WELL_KNOWN_URL}`;
33
+ export const CredentialExtension = z.strictObject({
34
+ uri: z.literal(CREDENTIAL_EXTENSION_URI),
35
+ description: z.string().min(1).max(512),
36
+ params: z.strictObject({ credential: Jws }),
37
+ });
38
+ export const credentialExtension = (jws) => ({
39
+ uri: CREDENTIAL_EXTENSION_URI,
40
+ description: EXTENSION_DESCRIPTION,
41
+ params: { credential: jws },
42
+ });
43
+ export const A2A_PROTOCOL_VERSION = '0.3.0';
44
+ export const AgentSkill = z.strictObject({
45
+ id: z.string().min(1).max(128),
46
+ name: z.string().min(1).max(128),
47
+ description: z.string().min(1).max(1024),
48
+ tags: z.array(z.string().min(1).max(64)).max(32),
49
+ examples: z.array(z.string().min(1).max(1024)).max(32).optional(),
50
+ });
51
+ const Modes = z.array(z.string().min(1).max(128)).max(32).default(['text']);
52
+ // The subset of the A2A agent card that Vouched emits, strict so the CLI
53
+ // never writes a field it did not mean to. Reading someone else's card uses
54
+ // the loose AgentCardResponse instead.
55
+ export const AgentCard = z.strictObject({
56
+ protocolVersion: z.literal(A2A_PROTOCOL_VERSION),
57
+ name: z.string().min(1).max(128),
58
+ description: z.string().min(1).max(1024),
59
+ url: z.url({ protocol: /^https$/ }).optional(),
60
+ version: z.string().min(1).max(64),
61
+ capabilities: z.strictObject({
62
+ extensions: z.array(CredentialExtension).max(8),
63
+ }),
64
+ skills: z.array(AgentSkill).max(64),
65
+ defaultInputModes: Modes,
66
+ defaultOutputModes: Modes,
67
+ });
@@ -0,0 +1,128 @@
1
+ export declare const agents: import("drizzle-orm/pg-core").PgTableWithColumns<{
2
+ name: "agents";
3
+ schema: undefined;
4
+ columns: {
5
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
6
+ name: "created_at";
7
+ tableName: "agents";
8
+ dataType: "date";
9
+ columnType: "PgTimestamp";
10
+ data: Date;
11
+ driverParam: string;
12
+ notNull: true;
13
+ hasDefault: true;
14
+ isPrimaryKey: false;
15
+ isAutoincrement: false;
16
+ hasRuntimeDefault: false;
17
+ enumValues: undefined;
18
+ baseColumn: never;
19
+ identity: undefined;
20
+ generated: undefined;
21
+ }, {}, {}>;
22
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
23
+ name: "updated_at";
24
+ tableName: "agents";
25
+ dataType: "date";
26
+ columnType: "PgTimestamp";
27
+ data: Date;
28
+ driverParam: string;
29
+ notNull: true;
30
+ hasDefault: true;
31
+ isPrimaryKey: false;
32
+ isAutoincrement: false;
33
+ hasRuntimeDefault: false;
34
+ enumValues: undefined;
35
+ baseColumn: never;
36
+ identity: undefined;
37
+ generated: undefined;
38
+ }, {}, {}>;
39
+ id: import("drizzle-orm/pg-core").PgColumn<{
40
+ name: "id";
41
+ tableName: "agents";
42
+ dataType: "string";
43
+ columnType: "PgText";
44
+ data: string;
45
+ driverParam: string;
46
+ notNull: true;
47
+ hasDefault: false;
48
+ isPrimaryKey: true;
49
+ isAutoincrement: false;
50
+ hasRuntimeDefault: false;
51
+ enumValues: [string, ...string[]];
52
+ baseColumn: never;
53
+ identity: undefined;
54
+ generated: undefined;
55
+ }, {}, {}>;
56
+ operatorId: import("drizzle-orm/pg-core").PgColumn<{
57
+ name: "operator_id";
58
+ tableName: "agents";
59
+ dataType: "string";
60
+ columnType: "PgUUID";
61
+ data: string;
62
+ driverParam: string;
63
+ notNull: true;
64
+ hasDefault: false;
65
+ isPrimaryKey: false;
66
+ isAutoincrement: false;
67
+ hasRuntimeDefault: false;
68
+ enumValues: undefined;
69
+ baseColumn: never;
70
+ identity: undefined;
71
+ generated: undefined;
72
+ }, {}, {}>;
73
+ name: import("drizzle-orm/pg-core").PgColumn<{
74
+ name: "name";
75
+ tableName: "agents";
76
+ dataType: "string";
77
+ columnType: "PgText";
78
+ data: string;
79
+ driverParam: string;
80
+ notNull: true;
81
+ hasDefault: false;
82
+ isPrimaryKey: false;
83
+ isAutoincrement: false;
84
+ hasRuntimeDefault: false;
85
+ enumValues: [string, ...string[]];
86
+ baseColumn: never;
87
+ identity: undefined;
88
+ generated: undefined;
89
+ }, {}, {}>;
90
+ version: import("drizzle-orm/pg-core").PgColumn<{
91
+ name: "version";
92
+ tableName: "agents";
93
+ dataType: "string";
94
+ columnType: "PgText";
95
+ data: string;
96
+ driverParam: string;
97
+ notNull: true;
98
+ hasDefault: false;
99
+ isPrimaryKey: false;
100
+ isAutoincrement: false;
101
+ hasRuntimeDefault: false;
102
+ enumValues: [string, ...string[]];
103
+ baseColumn: never;
104
+ identity: undefined;
105
+ generated: undefined;
106
+ }, {}, {}>;
107
+ card: import("drizzle-orm/pg-core").PgColumn<{
108
+ name: "card";
109
+ tableName: "agents";
110
+ dataType: "json";
111
+ columnType: "PgJsonb";
112
+ data: unknown;
113
+ driverParam: unknown;
114
+ notNull: false;
115
+ hasDefault: false;
116
+ isPrimaryKey: false;
117
+ isAutoincrement: false;
118
+ hasRuntimeDefault: false;
119
+ enumValues: undefined;
120
+ baseColumn: never;
121
+ identity: undefined;
122
+ generated: undefined;
123
+ }, {}, {}>;
124
+ };
125
+ dialect: 'pg';
126
+ }>;
127
+ export type Agent = typeof agents.$inferSelect;
128
+ export type NewAgent = typeof agents.$inferInsert;
@@ -0,0 +1,31 @@
1
+ import { sql } from 'drizzle-orm';
2
+ import { check, jsonb, pgTable, text, uuid } from 'drizzle-orm/pg-core';
3
+ import { operators } from './operators.js';
4
+ import { timestamps } from './timestamps.js';
5
+ // How a Drizzle table is declared.
6
+ //
7
+ // pgTable(sqlName, columns, extras) returns a table object. Queries use it,
8
+ // as in db.select().from(agents), and drizzle-kit diffs it to write
9
+ // migrations.
10
+ //
11
+ // columns maps a TypeScript property to a column builder. The first argument
12
+ // of each builder is the SQL column name, so the property is camelCase in
13
+ // code and snake_case in the database. Builders chain constraints such as
14
+ // .notNull(), .primaryKey() and .references(() => operators.id). The arrow in
15
+ // references() lets tables point at each other regardless of file order.
16
+ //
17
+ // ...timestamps spreads the shared created_at and updated_at columns in.
18
+ //
19
+ // extras receives the built columns and returns table level constraints and
20
+ // indexes. Here it is a check constraint written as raw SQL. The agent id is
21
+ // the ed25519 public key, 32 bytes, base64url without padding, so 43 chars.
22
+ export const agents = pgTable('agents', {
23
+ id: text('id').primaryKey(),
24
+ operatorId: uuid('operator_id')
25
+ .notNull()
26
+ .references(() => operators.id),
27
+ name: text('name').notNull(),
28
+ version: text('version').notNull(),
29
+ card: jsonb('card'),
30
+ ...timestamps,
31
+ }, (t) => [check('agents_id_length', sql `length(${t.id}) = 43`)]);