@meistrari/agent-core 0.0.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 (50) hide show
  1. package/README.md +26 -0
  2. package/package.json +69 -0
  3. package/scripts/write-provenance.ts +74 -0
  4. package/src/errors/app-error.ts +66 -0
  5. package/src/errors/application-error.ts +55 -0
  6. package/src/errors/index.ts +16 -0
  7. package/src/errors/infrastructure-error.ts +13 -0
  8. package/src/errors/provider-error.ts +13 -0
  9. package/src/errors/validation-error.ts +19 -0
  10. package/src/logger/index.ts +75 -0
  11. package/src/protocol/agent-command.ts +65 -0
  12. package/src/protocol/agent-content.ts +73 -0
  13. package/src/protocol/agent-error.ts +81 -0
  14. package/src/protocol/agent-event.ts +391 -0
  15. package/src/protocol/agent-json.ts +30 -0
  16. package/src/protocol/agent-metadata.ts +30 -0
  17. package/src/protocol/agent-model.ts +68 -0
  18. package/src/protocol/agent-overflow.ts +18 -0
  19. package/src/protocol/agent-presentation.ts +98 -0
  20. package/src/protocol/agent-provider.ts +4 -0
  21. package/src/protocol/agent-tool-name.ts +48 -0
  22. package/src/protocol/agent-tool.ts +40 -0
  23. package/src/protocol/agent-usage.ts +14 -0
  24. package/src/protocol/agent-user-input.ts +38 -0
  25. package/src/protocol/agent-work.ts +100 -0
  26. package/src/protocol/index.ts +13 -0
  27. package/src/provenance.gen.ts +6 -0
  28. package/src/provenance.ts +27 -0
  29. package/src/supervisor-protocol/agent-event-wrapper.ts +179 -0
  30. package/src/supervisor-protocol/bootstrap-rejection-receipt.ts +3 -0
  31. package/src/supervisor-protocol/bootstrap.ts +126 -0
  32. package/src/supervisor-protocol/command-body.ts +82 -0
  33. package/src/supervisor-protocol/context-file-content.ts +90 -0
  34. package/src/supervisor-protocol/control-authority.ts +88 -0
  35. package/src/supervisor-protocol/durability.ts +33 -0
  36. package/src/supervisor-protocol/envelope.ts +58 -0
  37. package/src/supervisor-protocol/envelopes/common.ts +7 -0
  38. package/src/supervisor-protocol/envelopes/control-plane-to-supervisor.ts +38 -0
  39. package/src/supervisor-protocol/envelopes/supervisor-to-control-plane.ts +89 -0
  40. package/src/supervisor-protocol/event-body.ts +13 -0
  41. package/src/supervisor-protocol/input-attachment-content.ts +3 -0
  42. package/src/supervisor-protocol/payload-overflow.ts +15 -0
  43. package/src/supervisor-protocol/product-event.ts +27 -0
  44. package/src/supervisor-protocol/profile.ts +22 -0
  45. package/src/supervisor-protocol/rpc.ts +77 -0
  46. package/src/supervisor-protocol/supervisor-agent-run-snapshot.ts +12 -0
  47. package/src/supervisor-protocol/supervisor-event.ts +361 -0
  48. package/src/supervisor-protocol/tela-page-content.ts +6 -0
  49. package/src/supervisor-protocol/wire-codec.ts +71 -0
  50. package/tsconfig.json +24 -0
package/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # @meistrari/agent-core
2
+
3
+ Shared contracts and runtime modules for Tela coding-agent sandboxes.
4
+
5
+ | Subpath | What it is |
6
+ | --- | --- |
7
+ | `@meistrari/agent-core/protocol` | Provider-neutral agent commands, events, content, tools, usage, work items (Claude and Codex share it). |
8
+ | `@meistrari/agent-core/supervisor-protocol/*` | Strict wire contracts between a worker runtime and the resident sandbox supervisor: bootstrap, commands, events, reverse RPC, control authority. |
9
+ | `@meistrari/agent-core/errors`, `/logger`, `/provenance` | Shared primitives. |
10
+ | `@meistrari/agent-core/supervisor` | Sandbox-resident supervisor runtime (Bun, SQLite). |
11
+ | `@meistrari/agent-core/worker-runtime-client` | Control-plane WSS client: leases, generation fencing, command pump, durable event acking, reverse RPC dispatch. |
12
+ | `@meistrari/agent-core/claude`, `/codex` | Harness adapters. |
13
+
14
+ The package ships TypeScript source and targets Bun `>=1.3.10`. There is no wire protocol version: a sandbox keeps the exact agent-core build it was created with for its lifetime (immutable sandbox invariant). Incompatible wire changes require reprovisioning sandboxes, never in-place upgrades.
15
+
16
+ ## Development
17
+
18
+ ```bash
19
+ bun install
20
+ bun run lint
21
+ bun run typecheck
22
+ bun run test # unit tests (src/**/*.test.ts)
23
+ bun run test:e2e # loopback worker <-> supervisor e2e
24
+ ```
25
+
26
+ Publishing runs from `main` through `.github/workflows/publish.yml` (conventional commits decide the bump).
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@meistrari/agent-core",
3
+ "type": "module",
4
+ "version": "0.0.0",
5
+ "packageManager": "bun@1.3.12",
6
+ "description": "Shared contracts and runtime modules for Tela coding-agent sandboxes: agent protocol, supervisor wire protocol, resident supervisor, worker runtime client, and Claude/Codex harness adapters.",
7
+ "license": "UNLICENSED",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/meistrari/agent-core.git"
11
+ },
12
+ "publishConfig": {
13
+ "access": "public",
14
+ "registry": "https://registry.npmjs.org"
15
+ },
16
+ "exports": {
17
+ "./errors": "./src/errors/index.ts",
18
+ "./errors/application-error": "./src/errors/application-error.ts",
19
+ "./logger": "./src/logger/index.ts",
20
+ "./provenance": "./src/provenance.ts",
21
+ "./protocol": "./src/protocol/index.ts",
22
+ "./protocol/agent-content": "./src/protocol/agent-content.ts",
23
+ "./protocol/agent-tool-name": "./src/protocol/agent-tool-name.ts",
24
+ "./protocol/agent-work": "./src/protocol/agent-work.ts",
25
+ "./supervisor-protocol/agent-event-wrapper": "./src/supervisor-protocol/agent-event-wrapper.ts",
26
+ "./supervisor-protocol/bootstrap": "./src/supervisor-protocol/bootstrap.ts",
27
+ "./supervisor-protocol/bootstrap-rejection-receipt": "./src/supervisor-protocol/bootstrap-rejection-receipt.ts",
28
+ "./supervisor-protocol/command-body": "./src/supervisor-protocol/command-body.ts",
29
+ "./supervisor-protocol/control-authority": "./src/supervisor-protocol/control-authority.ts",
30
+ "./supervisor-protocol/context-file-content": "./src/supervisor-protocol/context-file-content.ts",
31
+ "./supervisor-protocol/durability": "./src/supervisor-protocol/durability.ts",
32
+ "./supervisor-protocol/envelope": "./src/supervisor-protocol/envelope.ts",
33
+ "./supervisor-protocol/envelopes/common": "./src/supervisor-protocol/envelopes/common.ts",
34
+ "./supervisor-protocol/envelopes/control-plane-to-supervisor": "./src/supervisor-protocol/envelopes/control-plane-to-supervisor.ts",
35
+ "./supervisor-protocol/envelopes/supervisor-to-control-plane": "./src/supervisor-protocol/envelopes/supervisor-to-control-plane.ts",
36
+ "./supervisor-protocol/event-body": "./src/supervisor-protocol/event-body.ts",
37
+ "./supervisor-protocol/input-attachment-content": "./src/supervisor-protocol/input-attachment-content.ts",
38
+ "./supervisor-protocol/payload-overflow": "./src/supervisor-protocol/payload-overflow.ts",
39
+ "./supervisor-protocol/profile": "./src/supervisor-protocol/profile.ts",
40
+ "./supervisor-protocol/product-event": "./src/supervisor-protocol/product-event.ts",
41
+ "./supervisor-protocol/rpc": "./src/supervisor-protocol/rpc.ts",
42
+ "./supervisor-protocol/supervisor-agent-run-snapshot": "./src/supervisor-protocol/supervisor-agent-run-snapshot.ts",
43
+ "./supervisor-protocol/supervisor-event": "./src/supervisor-protocol/supervisor-event.ts",
44
+ "./supervisor-protocol/tela-page-content": "./src/supervisor-protocol/tela-page-content.ts",
45
+ "./supervisor-protocol/wire-codec": "./src/supervisor-protocol/wire-codec.ts"
46
+ },
47
+ "engines": {
48
+ "bun": ">=1.3.10"
49
+ },
50
+ "scripts": {
51
+ "lint": "eslint .",
52
+ "lint:fix": "eslint . --fix",
53
+ "typecheck": "tsc --noEmit",
54
+ "test": "bun test src/",
55
+ "test:e2e": "bun test --pass-with-no-tests e2e/",
56
+ "provenance": "bun scripts/write-provenance.ts",
57
+ "build": "bun scripts/write-provenance.ts"
58
+ },
59
+ "dependencies": {
60
+ "pino": "^9.7.0",
61
+ "zod": "^4.1.12"
62
+ },
63
+ "devDependencies": {
64
+ "@antfu/eslint-config": "4.16.2",
65
+ "@types/bun": "1.3.12",
66
+ "eslint": "^9.30.0",
67
+ "typescript": "5.9.3"
68
+ }
69
+ }
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Writes `src/provenance.gen.ts` with the published version and source sha.
4
+ *
5
+ * The publish workflow runs this before packing so every consumer (the sandbox
6
+ * supervisor, the worker runtime, image builds) can record exactly which
7
+ * agent-core build it embeds. In development the committed placeholder wins.
8
+ */
9
+ import { readFile, writeFile } from 'node:fs/promises'
10
+ import { join } from 'node:path'
11
+
12
+ interface Options { version?: string, sha?: string, dryRun: boolean }
13
+
14
+ function parseArguments(argv: readonly string[]): Options {
15
+ const options: Options = { dryRun: false }
16
+ for (let index = 0; index < argv.length; index += 1) {
17
+ const argument = argv[index]
18
+ if (argument === '--version') {
19
+ options.version = argv[index + 1]
20
+ index += 1
21
+ }
22
+ else if (argument === '--sha') {
23
+ options.sha = argv[index + 1]
24
+ index += 1
25
+ }
26
+ else if (argument === '--dry-run') {
27
+ options.dryRun = true
28
+ }
29
+ else {
30
+ throw new Error(`Unknown argument: ${argument}`)
31
+ }
32
+ }
33
+ return options
34
+ }
35
+
36
+ async function resolveGitSha(): Promise<string> {
37
+ const process = Bun.spawn(['git', 'rev-parse', 'HEAD'], { stdout: 'pipe', stderr: 'pipe' })
38
+ const output = (await new Response(process.stdout).text()).trim()
39
+ const exitCode = await process.exited
40
+ if (exitCode !== 0 || !/^[0-9a-f]{40}$/u.test(output))
41
+ throw new Error('Unable to resolve the git HEAD sha; pass --sha explicitly.')
42
+ return output
43
+ }
44
+
45
+ async function main(): Promise<void> {
46
+ const options = parseArguments(Bun.argv.slice(2))
47
+ const rootDir = join(import.meta.dir, '..')
48
+ const packageJson = JSON.parse(await readFile(join(rootDir, 'package.json'), 'utf8')) as { version: string }
49
+ const version = options.version ?? packageJson.version
50
+ const sha = options.sha ?? await resolveGitSha()
51
+ if (!/^[0-9a-f]{40}$/u.test(sha))
52
+ throw new Error(`Invalid source sha: ${sha}`)
53
+ if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u.test(version))
54
+ throw new Error(`Invalid version: ${version}`)
55
+
56
+ const content = [
57
+ '// Generated by scripts/write-provenance.ts. Do not edit by hand.',
58
+ 'export const generatedProvenance = {',
59
+ ` version: ${JSON.stringify(version)},`,
60
+ ` sha: ${JSON.stringify(sha)},`,
61
+ ` buildTime: ${JSON.stringify(new Date().toISOString())},`,
62
+ '} as const',
63
+ '',
64
+ ].join('\n')
65
+
66
+ if (options.dryRun) {
67
+ console.log(content)
68
+ return
69
+ }
70
+ await writeFile(join(rootDir, 'src', 'provenance.gen.ts'), content)
71
+ console.log(`Wrote src/provenance.gen.ts for ${version}@${sha.slice(0, 12)}`)
72
+ }
73
+
74
+ await main()
@@ -0,0 +1,66 @@
1
+ export type AppErrorCategory = 'application' | 'provider' | 'infrastructure' | 'validation'
2
+
3
+ export interface AppErrorInput {
4
+ category: AppErrorCategory
5
+ code: string
6
+ message: string
7
+ publicMessage?: string
8
+ details?: Record<string, unknown>
9
+ retryable?: boolean
10
+ cause?: unknown
11
+ }
12
+
13
+ export class AppError extends Error {
14
+ readonly category: AppErrorCategory
15
+ readonly code: string
16
+ readonly publicMessage: string
17
+ readonly details?: Record<string, unknown>
18
+ readonly retryable: boolean
19
+ override readonly cause?: unknown
20
+
21
+ constructor(input: AppErrorInput) {
22
+ if (input.cause === undefined)
23
+ super(input.message)
24
+ else
25
+ super(input.message, { cause: input.cause })
26
+
27
+ this.name = new.target.name
28
+ this.category = input.category
29
+ this.code = input.code
30
+ this.publicMessage = input.publicMessage ?? input.message
31
+ this.retryable = input.retryable ?? false
32
+
33
+ if (input.details) {
34
+ this.details = input.details
35
+ }
36
+
37
+ if (input.cause !== undefined) {
38
+ this.cause = input.cause
39
+ }
40
+
41
+ Error.captureStackTrace?.(this, new.target)
42
+ }
43
+
44
+ toJSON() {
45
+ return {
46
+ name: this.name,
47
+ category: this.category,
48
+ code: this.code,
49
+ message: this.message,
50
+ publicMessage: this.publicMessage,
51
+ details: this.details,
52
+ retryable: this.retryable,
53
+ }
54
+ }
55
+
56
+ getPublicResponseBody() {
57
+ return {
58
+ message: this.publicMessage,
59
+ details: this.details,
60
+ }
61
+ }
62
+ }
63
+
64
+ export function isAppError(error: unknown): error is AppError {
65
+ return error instanceof AppError
66
+ }
@@ -0,0 +1,55 @@
1
+ import type { AppErrorInput } from './app-error'
2
+ import { AppError } from './app-error'
3
+
4
+ export type ApplicationErrorInput = Omit<AppErrorInput, 'category'>
5
+
6
+ export class ApplicationError extends AppError {
7
+ constructor(input: ApplicationErrorInput) {
8
+ super({
9
+ ...input,
10
+ category: 'application',
11
+ })
12
+ }
13
+ }
14
+
15
+ export class RateLimitExceededError extends ApplicationError {
16
+ readonly retryAfterSeconds: number
17
+
18
+ constructor({ retryAfterSeconds, ...input }: Omit<ApplicationErrorInput, 'retryable' | 'details'> & {
19
+ retryAfterSeconds: number
20
+ }) {
21
+ if (!Number.isSafeInteger(retryAfterSeconds) || retryAfterSeconds <= 0)
22
+ throw new RangeError('retryAfterSeconds must be a positive safe integer')
23
+
24
+ super({
25
+ ...input,
26
+ retryable: false,
27
+ details: { retry_after_seconds: retryAfterSeconds },
28
+ })
29
+ this.retryAfterSeconds = retryAfterSeconds
30
+ }
31
+ }
32
+
33
+ export class NotFoundError extends ApplicationError {
34
+ constructor(input: ApplicationErrorInput) {
35
+ super(input)
36
+ }
37
+ }
38
+
39
+ export class ConflictError extends ApplicationError {
40
+ constructor(input: ApplicationErrorInput) {
41
+ super(input)
42
+ }
43
+ }
44
+
45
+ export class ForbiddenError extends ApplicationError {
46
+ constructor(input: ApplicationErrorInput) {
47
+ super(input)
48
+ }
49
+ }
50
+
51
+ export class UnauthorizedError extends ApplicationError {
52
+ constructor(input: ApplicationErrorInput) {
53
+ super(input)
54
+ }
55
+ }
@@ -0,0 +1,16 @@
1
+ export { AppError, isAppError } from './app-error'
2
+ export type { AppErrorCategory, AppErrorInput } from './app-error'
3
+ export {
4
+ ApplicationError,
5
+ ConflictError,
6
+ ForbiddenError,
7
+ NotFoundError,
8
+ UnauthorizedError,
9
+ } from './application-error'
10
+ export type { ApplicationErrorInput } from './application-error'
11
+ export { InfrastructureError } from './infrastructure-error'
12
+ export type { InfrastructureErrorInput } from './infrastructure-error'
13
+ export { ProviderError } from './provider-error'
14
+ export type { ProviderErrorInput } from './provider-error'
15
+ export { UnprocessableEntityError, ValidationError } from './validation-error'
16
+ export type { ValidationErrorInput } from './validation-error'
@@ -0,0 +1,13 @@
1
+ import type { AppErrorInput } from './app-error'
2
+ import { AppError } from './app-error'
3
+
4
+ export type InfrastructureErrorInput = Omit<AppErrorInput, 'category'>
5
+
6
+ export class InfrastructureError extends AppError {
7
+ constructor(input: InfrastructureErrorInput) {
8
+ super({
9
+ ...input,
10
+ category: 'infrastructure',
11
+ })
12
+ }
13
+ }
@@ -0,0 +1,13 @@
1
+ import type { AppErrorInput } from './app-error'
2
+ import { AppError } from './app-error'
3
+
4
+ export type ProviderErrorInput = Omit<AppErrorInput, 'category'>
5
+
6
+ export class ProviderError extends AppError {
7
+ constructor(input: ProviderErrorInput) {
8
+ super({
9
+ ...input,
10
+ category: 'provider',
11
+ })
12
+ }
13
+ }
@@ -0,0 +1,19 @@
1
+ import type { AppErrorInput } from './app-error'
2
+ import { AppError } from './app-error'
3
+
4
+ export type ValidationErrorInput = Omit<AppErrorInput, 'category'>
5
+
6
+ export class ValidationError extends AppError {
7
+ constructor(input: ValidationErrorInput) {
8
+ super({
9
+ ...input,
10
+ category: 'validation',
11
+ })
12
+ }
13
+ }
14
+
15
+ export class UnprocessableEntityError extends ValidationError {
16
+ constructor(input: ValidationErrorInput) {
17
+ super(input)
18
+ }
19
+ }
@@ -0,0 +1,75 @@
1
+ import type { LoggerOptions, Logger as PinoLogger } from 'pino'
2
+ import pino from 'pino'
3
+
4
+ /**
5
+ * Structural logger contract used across agent-core. Pino satisfies it, and so
6
+ * does any product logger (Datadog-flavoured pino wrappers included), so hosts
7
+ * inject their own instance and agent-core never owns process-wide logging.
8
+ */
9
+ export type Logger = PinoLogger<never>
10
+
11
+ export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'
12
+
13
+ interface LoggerBaseFields {
14
+ readonly [key: string]: string | number | boolean | null | undefined
15
+ }
16
+
17
+ export interface CreateLoggerInput {
18
+ level?: LogLevel
19
+ base?: LoggerBaseFields
20
+ /** Redirect output (tests, supervisor stderr). Defaults to stdout. */
21
+ destination?: pino.DestinationStream
22
+ }
23
+
24
+ type SafeErrorField = 'category' | 'code' | 'publicMessage' | 'retryable' | 'details'
25
+
26
+ function readErrorField(error: Error, field: SafeErrorField): unknown {
27
+ return Reflect.get(error, field) as unknown
28
+ }
29
+
30
+ // Keeps only safe outer fields and never traverses error causes, so a wrapped
31
+ // provider error cannot leak credentials through its cause chain.
32
+ export function serializeError(error: Error) {
33
+ const category = readErrorField(error, 'category')
34
+ const code = readErrorField(error, 'code')
35
+ const publicMessage = readErrorField(error, 'publicMessage')
36
+ const retryable = readErrorField(error, 'retryable')
37
+ const details = readErrorField(error, 'details')
38
+
39
+ return {
40
+ type: error.name || error.constructor.name,
41
+ message: error.message,
42
+ ...(error.stack ? { stack: error.stack } : {}),
43
+ ...(typeof category === 'string' ? { category } : {}),
44
+ ...(typeof code === 'string' ? { code } : {}),
45
+ ...(typeof publicMessage === 'string' ? { publicMessage } : {}),
46
+ ...(typeof retryable === 'boolean' ? { retryable } : {}),
47
+ ...(details ? { details } : {}),
48
+ }
49
+ }
50
+
51
+ export function readLogLevelFromEnvironment(environment: Record<string, string | undefined> = process.env): LogLevel {
52
+ const level = environment.LOG_LEVEL
53
+ if (level === 'trace' || level === 'debug' || level === 'info' || level === 'warn' || level === 'error' || level === 'fatal')
54
+ return level
55
+ return 'info'
56
+ }
57
+
58
+ export function createLogger(input: CreateLoggerInput = {}): Logger {
59
+ const options: LoggerOptions<never> = {
60
+ level: input.level ?? readLogLevelFromEnvironment(),
61
+ errorKey: 'err',
62
+ messageKey: 'message',
63
+ timestamp: pino.stdTimeFunctions.isoTime,
64
+ serializers: { err: serializeError },
65
+ formatters: {
66
+ level: (label: string) => ({ level: label.toUpperCase() }),
67
+ },
68
+ ...(input.base ? { base: input.base } : {}),
69
+ }
70
+ return input.destination ? pino(options, input.destination) : pino(options)
71
+ }
72
+
73
+ export function createSilentLogger(): Logger {
74
+ return pino({ level: 'silent' })
75
+ }
@@ -0,0 +1,65 @@
1
+ import z from 'zod'
2
+ import { agentPromptSchema } from './agent-content'
3
+ import { agentProviderIdSchema } from './agent-provider'
4
+ import { agentUserInputAnswersSchema } from './agent-user-input'
5
+
6
+ export const agentReasoningEffortSchema = z.enum(['low', 'medium', 'high', 'xhigh', 'max'])
7
+ export const agentPromptModeSchema = z.enum(['next', 'steer'])
8
+
9
+ export const agentAuthorSchema = z.object({
10
+ name: z.string().min(1),
11
+ email: z.string().min(1).optional(),
12
+ gitEmail: z.string().min(1).optional(),
13
+ }).strict()
14
+
15
+ const commandIdSchema = z.string().min(1)
16
+
17
+ const runningCommandBaseSchema = z.object({
18
+ provider: agentProviderIdSchema,
19
+ sessionId: z.string().min(1),
20
+ providerSessionId: z.string().min(1),
21
+ }).strict()
22
+
23
+ export const sendPromptCommandSchema = runningCommandBaseSchema.extend({
24
+ type: z.literal('agent.send-prompt'),
25
+ mode: agentPromptModeSchema,
26
+ origin: z.enum(['user', 'supervisor']).default('user'),
27
+ prompt: agentPromptSchema,
28
+ commandId: commandIdSchema,
29
+ author: agentAuthorSchema.optional(),
30
+ }).strict()
31
+
32
+ export const interruptAgentCommandSchema = runningCommandBaseSchema.extend({
33
+ type: z.literal('agent.interrupt'),
34
+ commandId: commandIdSchema,
35
+ turnId: z.string().min(1).optional(),
36
+ reason: z.string().min(1).optional(),
37
+ }).strict()
38
+
39
+ export const stopAgentCommandSchema = runningCommandBaseSchema.extend({
40
+ type: z.literal('agent.stop'),
41
+ reason: z.string().min(1).optional(),
42
+ }).strict()
43
+
44
+ export const respondUserInputAgentCommandSchema = runningCommandBaseSchema.extend({
45
+ type: z.literal('agent.respond-user-input'),
46
+ commandId: commandIdSchema,
47
+ requestId: z.string().min(1),
48
+ answers: agentUserInputAnswersSchema,
49
+ }).strict()
50
+
51
+ export const agentCommandSchema = z.union([
52
+ sendPromptCommandSchema,
53
+ interruptAgentCommandSchema,
54
+ stopAgentCommandSchema,
55
+ respondUserInputAgentCommandSchema,
56
+ ])
57
+
58
+ export type AgentReasoningEffort = z.infer<typeof agentReasoningEffortSchema>
59
+ export type AgentPromptMode = z.infer<typeof agentPromptModeSchema>
60
+ export type AgentAuthor = z.infer<typeof agentAuthorSchema>
61
+ export type SendPromptCommand = z.infer<typeof sendPromptCommandSchema>
62
+ export type InterruptAgentCommand = z.infer<typeof interruptAgentCommandSchema>
63
+ export type StopAgentCommand = z.infer<typeof stopAgentCommandSchema>
64
+ export type RespondUserInputAgentCommand = z.infer<typeof respondUserInputAgentCommandSchema>
65
+ export type AgentCommand = z.infer<typeof agentCommandSchema>
@@ -0,0 +1,73 @@
1
+ import z from 'zod'
2
+
3
+ export const textAgentInputBlockSchema = z.object({
4
+ type: z.literal('text'),
5
+ text: z.string(),
6
+ }).strict()
7
+
8
+ export const urlAgentImageSourceSchema = z.object({
9
+ kind: z.literal('url'),
10
+ url: z.url(),
11
+ }).strict()
12
+
13
+ export const base64AgentImageSourceSchema = z.object({
14
+ kind: z.literal('base64'),
15
+ data: z.string().min(1),
16
+ mimeType: z.string().min(1),
17
+ }).strict()
18
+
19
+ export const agentImageSourceSchema = z.discriminatedUnion('kind', [
20
+ urlAgentImageSourceSchema,
21
+ base64AgentImageSourceSchema,
22
+ ])
23
+
24
+ export const imageAgentInputBlockSchema = z.object({
25
+ type: z.literal('image'),
26
+ source: agentImageSourceSchema,
27
+ }).strict()
28
+
29
+ export const textAgentFileSourceSchema = z.object({
30
+ kind: z.literal('text'),
31
+ name: z.string().min(1).optional(),
32
+ text: z.string(),
33
+ mimeType: z.string().min(1).optional(),
34
+ }).strict()
35
+
36
+ export const urlAgentFileSourceSchema = z.object({
37
+ kind: z.literal('url'),
38
+ url: z.url(),
39
+ name: z.string().min(1).optional(),
40
+ mimeType: z.string().min(1).optional(),
41
+ }).strict()
42
+
43
+ export const agentFileSourceSchema = z.discriminatedUnion('kind', [
44
+ textAgentFileSourceSchema,
45
+ urlAgentFileSourceSchema,
46
+ ])
47
+
48
+ export const fileAgentInputBlockSchema = z.object({
49
+ type: z.literal('file'),
50
+ source: agentFileSourceSchema,
51
+ }).strict()
52
+
53
+ export const agentInputBlockSchema = z.discriminatedUnion('type', [
54
+ textAgentInputBlockSchema,
55
+ imageAgentInputBlockSchema,
56
+ fileAgentInputBlockSchema,
57
+ ])
58
+
59
+ export const agentPromptSchema = z.object({
60
+ blocks: z.array(agentInputBlockSchema).min(1),
61
+ }).strict()
62
+
63
+ export type TextAgentInputBlock = z.infer<typeof textAgentInputBlockSchema>
64
+ export type UrlAgentImageSource = z.infer<typeof urlAgentImageSourceSchema>
65
+ export type Base64AgentImageSource = z.infer<typeof base64AgentImageSourceSchema>
66
+ export type AgentImageSource = z.infer<typeof agentImageSourceSchema>
67
+ export type ImageAgentInputBlock = z.infer<typeof imageAgentInputBlockSchema>
68
+ export type TextAgentFileSource = z.infer<typeof textAgentFileSourceSchema>
69
+ export type UrlAgentFileSource = z.infer<typeof urlAgentFileSourceSchema>
70
+ export type AgentFileSource = z.infer<typeof agentFileSourceSchema>
71
+ export type FileAgentInputBlock = z.infer<typeof fileAgentInputBlockSchema>
72
+ export type AgentInputBlock = z.infer<typeof agentInputBlockSchema>
73
+ export type AgentPrompt = z.infer<typeof agentPromptSchema>
@@ -0,0 +1,81 @@
1
+ import type { ApplicationErrorInput, ValidationErrorInput } from '../errors'
2
+ import { ApplicationError, ValidationError } from '../errors'
3
+
4
+ type AgentProtocolErrorInput = Omit<ApplicationErrorInput, 'code'> & {
5
+ code?: string
6
+ }
7
+
8
+ type AgentProtocolValidationErrorInput = Omit<ValidationErrorInput, 'code'> & {
9
+ code?: string
10
+ }
11
+
12
+ type AgentProtocolDetails = ValidationErrorInput['details']
13
+
14
+ interface InvalidAgentCommandErrorInput {
15
+ message?: string
16
+ details?: AgentProtocolDetails
17
+ cause?: unknown
18
+ }
19
+
20
+ interface InvalidAgentEventErrorInput {
21
+ message?: string
22
+ details?: AgentProtocolDetails
23
+ cause?: unknown
24
+ }
25
+
26
+ export class AgentProtocolError extends ApplicationError {
27
+ constructor(input: AgentProtocolErrorInput) {
28
+ const { code = 'agents-protocol.error', ...rest } = input
29
+
30
+ super({
31
+ ...rest,
32
+ code,
33
+ })
34
+ }
35
+ }
36
+
37
+ export class AgentProtocolValidationError extends ValidationError {
38
+ constructor(input: AgentProtocolValidationErrorInput) {
39
+ const { code = 'agents-protocol.validation-failed', ...rest } = input
40
+
41
+ super({
42
+ ...rest,
43
+ code,
44
+ })
45
+ }
46
+ }
47
+
48
+ export class UnsupportedAgentProviderError extends AgentProtocolValidationError {
49
+ constructor({ provider }: { provider: string }) {
50
+ super({
51
+ code: 'agents-protocol.unsupported-provider',
52
+ message: `Unsupported agent provider: ${provider}`,
53
+ publicMessage: 'Unsupported agent provider.',
54
+ details: { provider },
55
+ })
56
+ }
57
+ }
58
+
59
+ export class InvalidAgentCommandError extends AgentProtocolValidationError {
60
+ constructor(input: InvalidAgentCommandErrorInput = {}) {
61
+ super({
62
+ code: 'agents-protocol.invalid-command',
63
+ message: input.message ?? 'Agent command is invalid.',
64
+ publicMessage: 'Agent command is invalid.',
65
+ details: input.details,
66
+ cause: input.cause,
67
+ })
68
+ }
69
+ }
70
+
71
+ export class InvalidAgentEventError extends AgentProtocolValidationError {
72
+ constructor(input: InvalidAgentEventErrorInput = {}) {
73
+ super({
74
+ code: 'agents-protocol.invalid-event',
75
+ message: input.message ?? 'Agent event is invalid.',
76
+ publicMessage: 'Agent event is invalid.',
77
+ details: input.details,
78
+ cause: input.cause,
79
+ })
80
+ }
81
+ }