@meistrari/agent-core 0.0.0 → 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 (83) hide show
  1. package/README.md +24 -3
  2. package/bin/supervisor.ts +116 -0
  3. package/package.json +42 -3
  4. package/scripts/build-supervisor-executable.ts +32 -0
  5. package/src/agents/agent-error-serializer.ts +23 -0
  6. package/src/agents/agent-event-stream.ts +81 -0
  7. package/src/agents/agent-id.ts +17 -0
  8. package/src/agents/agent-operation.ts +11 -0
  9. package/src/agents/agent-provider.ts +37 -0
  10. package/src/agents/agent-run.ts +32 -0
  11. package/src/agents/agent-runtime-error.ts +161 -0
  12. package/src/agents/agent-session-events.ts +32 -0
  13. package/src/agents/agent-tool-runner.ts +83 -0
  14. package/src/agents/agent-tool.ts +111 -0
  15. package/src/agents/author-context.ts +36 -0
  16. package/src/agents/claude/claude-command-mapper.ts +234 -0
  17. package/src/agents/claude/claude-event-mapper.ts +736 -0
  18. package/src/agents/claude/claude-provider.ts +191 -0
  19. package/src/agents/claude/claude-run.ts +464 -0
  20. package/src/agents/claude/claude-tool-mapper.ts +186 -0
  21. package/src/agents/claude/index.ts +1 -0
  22. package/src/agents/codex/codex-auth.ts +34 -0
  23. package/src/agents/codex/codex-command-mapper.ts +78 -0
  24. package/src/agents/codex/codex-event-mapper.ts +708 -0
  25. package/src/agents/codex/codex-json-rpc-client.ts +326 -0
  26. package/src/agents/codex/codex-protocol.ts +36 -0
  27. package/src/agents/codex/codex-provider.ts +1050 -0
  28. package/src/agents/codex/codex-run.ts +404 -0
  29. package/src/agents/codex/codex-skill-catalog.ts +158 -0
  30. package/src/agents/codex/codex-skill-roots.ts +19 -0
  31. package/src/agents/codex/codex-tool-mapper.ts +55 -0
  32. package/src/agents/codex/codex.errors.ts +68 -0
  33. package/src/agents/codex/generated/meta.gen.ts +606 -0
  34. package/src/agents/codex/generated/namespaces.gen.ts +311 -0
  35. package/src/agents/codex/generated/schema.gen.ts +34883 -0
  36. package/src/agents/codex/index.ts +2 -0
  37. package/src/agents/index.ts +14 -0
  38. package/src/agents/input-attachment-preparation.ts +86 -0
  39. package/src/agents/input-attachment.errors.ts +16 -0
  40. package/src/agents/instructions.ts +8 -0
  41. package/src/agents/materialized-input-attachment.ts +26 -0
  42. package/src/agents/message-id.ts +23 -0
  43. package/src/agents/normalize.ts +8 -0
  44. package/src/agents/sandbox-environment.ts +1 -0
  45. package/src/agents/tools/ping.tool.ts +13 -0
  46. package/src/agents/user-input-request.ts +470 -0
  47. package/src/provenance.gen.ts +3 -3
  48. package/src/supervisor/agent-provider-factory.ts +189 -0
  49. package/src/supervisor/bootstrap-binder.ts +125 -0
  50. package/src/supervisor/config.ts +49 -0
  51. package/src/supervisor/control-authority-verifier.ts +135 -0
  52. package/src/supervisor/create-supervisor-runtime.ts +25 -0
  53. package/src/supervisor/errors.ts +24 -0
  54. package/src/supervisor/index.ts +34 -0
  55. package/src/supervisor/persistence/json.ts +21 -0
  56. package/src/supervisor/persistence/state-discovery.ts +56 -0
  57. package/src/supervisor/persistence/supervisor-store.ts +364 -0
  58. package/src/supervisor/ports/index.ts +109 -0
  59. package/src/supervisor/provider-factory.ts +37 -0
  60. package/src/supervisor/resident.ts +143 -0
  61. package/src/supervisor/rpc-client.ts +120 -0
  62. package/src/supervisor/runtime-handler.ts +309 -0
  63. package/src/supervisor/websocket-server.ts +434 -0
  64. package/src/supervisor-protocol/bootstrap.ts +1 -1
  65. package/src/template-onboarding.ts +47 -0
  66. package/src/testing/es256-test-keys.ts +73 -0
  67. package/src/testing/in-memory-runtime-control-plane.ts +205 -0
  68. package/src/testing/index.ts +6 -0
  69. package/src/testing/loopback-supervisor-connection.ts +71 -0
  70. package/src/testing/scripted-provider.ts +64 -0
  71. package/src/worker-runtime-client/command-pump.ts +132 -0
  72. package/src/worker-runtime-client/connection-attempt.ts +340 -0
  73. package/src/worker-runtime-client/control-authority-signer.ts +100 -0
  74. package/src/worker-runtime-client/e2b-supervisor-connection.ts +102 -0
  75. package/src/worker-runtime-client/frame-processor.ts +178 -0
  76. package/src/worker-runtime-client/index.ts +27 -0
  77. package/src/worker-runtime-client/lease-reconciler.ts +14 -0
  78. package/src/worker-runtime-client/ports.ts +137 -0
  79. package/src/worker-runtime-client/postgres-notification-listener.ts +91 -0
  80. package/src/worker-runtime-client/rpc-dispatcher.ts +27 -0
  81. package/src/worker-runtime-client/rpc-request-manager.ts +141 -0
  82. package/src/worker-runtime-client/sandbox-connection-runtime.ts +300 -0
  83. package/src/worker-runtime-client/token-crypto.ts +46 -0
@@ -0,0 +1,186 @@
1
+ import type { Options } from '@anthropic-ai/claude-agent-sdk'
2
+ import type { AgentRunMetadata, AgentUserInputQuestion, JsonValue } from '../../protocol'
3
+ import type { AgentTool } from '../agent-tool'
4
+ import { tool as claudeTool, createSdkMcpServer } from '@anthropic-ai/claude-agent-sdk'
5
+ import { isAppError } from '../../errors'
6
+ import { AgentProviderProtocolError } from '../agent-runtime-error'
7
+ import { agentToolActorDenialMessage, agentToolAllowsActor } from '../agent-tool'
8
+ import { runAgentTool } from '../agent-tool-runner'
9
+
10
+ export const CLAUDE_AGENT_TOOL_SERVER = 'coding_agent'
11
+ export const CLAUDE_CODE_TOOL_USE_ID_META_KEY = 'claudecode/toolUseId'
12
+
13
+ const UNEXPECTED_TOOL_FAILURE_MESSAGE = 'The tool could not be executed.'
14
+
15
+ interface ClaudeMcpToolExtra {
16
+ _meta?: {
17
+ [CLAUDE_CODE_TOOL_USE_ID_META_KEY]?: unknown
18
+ }
19
+ }
20
+
21
+ interface ClaudeToolUserInputRequest {
22
+ turnId: string
23
+ toolCallId: string
24
+ prompt: string
25
+ questions: AgentUserInputQuestion[]
26
+ }
27
+
28
+ interface ClaudeToolRuntimeAttachment {
29
+ metadata: AgentRunMetadata
30
+ requestUserInput: (input: ClaudeToolUserInputRequest) => Promise<{ requestId: string }>
31
+ }
32
+
33
+ interface ClaudeToolRuntimeRef {
34
+ metadata: () => AgentRunMetadata
35
+ turnId: () => string
36
+ requestUserInput: (input: ClaudeToolUserInputRequest) => Promise<{ requestId: string }>
37
+ }
38
+
39
+ type AttachableClaudeToolRuntimeRef = ClaudeToolRuntimeRef & {
40
+ attach: (runtime: ClaudeToolRuntimeAttachment) => void
41
+ }
42
+
43
+ export function createClaudeToolRuntimeRef(input: { turnId: () => string | undefined }): AttachableClaudeToolRuntimeRef {
44
+ let runtime: ClaudeToolRuntimeAttachment | undefined
45
+
46
+ return {
47
+ attach: attached => runtime = attached,
48
+ metadata: () => requireAttachedRuntime(runtime).metadata,
49
+ turnId: () => {
50
+ const turnId = input.turnId()
51
+ if (turnId)
52
+ return turnId
53
+ throw new AgentProviderProtocolError({ message: 'Claude invoked a runtime tool without an active turn id.' })
54
+ },
55
+ requestUserInput: async request => await requireAttachedRuntime(runtime).requestUserInput(request),
56
+ }
57
+ }
58
+
59
+ export function toClaudeMcpServers(input: {
60
+ tools: readonly AgentTool[]
61
+ runtime: ClaudeToolRuntimeRef
62
+ signal: AbortSignal
63
+ }): NonNullable<Options['mcpServers']> | undefined {
64
+ if (input.tools.length === 0)
65
+ return undefined
66
+
67
+ return {
68
+ [CLAUDE_AGENT_TOOL_SERVER]: createSdkMcpServer({
69
+ name: CLAUDE_AGENT_TOOL_SERVER,
70
+ version: '0.1.0',
71
+ tools: input.tools.map(runtimeTool => claudeTool(
72
+ runtimeTool.name,
73
+ runtimeTool.description,
74
+ runtimeTool.inputShape,
75
+ async (args: JsonValue, extra: unknown) => {
76
+ const metadata = input.runtime.metadata()
77
+ const turnId = input.runtime.turnId()
78
+ const toolCallId = requiredToolCallId(extra)
79
+ try {
80
+ const result = await runAgentTool({
81
+ tool: runtimeTool,
82
+ // The PreToolUse hook is the actor gate because MCP handler metadata has no actor identity.
83
+ actor: 'main',
84
+ rawInput: args,
85
+ context: {
86
+ provider: 'claude',
87
+ sessionId: metadata.sessionId,
88
+ providerSessionId: metadata.providerSessionId,
89
+ turnId,
90
+ cwd: metadata.cwd,
91
+ toolCallId,
92
+ signal: input.signal,
93
+ requestUserInput: async request => await input.runtime.requestUserInput({ ...request, turnId, toolCallId }),
94
+ },
95
+ })
96
+ return {
97
+ isError: !result.success,
98
+ content: result.content,
99
+ }
100
+ }
101
+ catch (error) {
102
+ if (isAppError(error))
103
+ throw error
104
+ return unexpectedToolFailure()
105
+ }
106
+ },
107
+ )),
108
+ }),
109
+ }
110
+ }
111
+
112
+ export function claudeAllowedToolNames(tools: readonly AgentTool[]): string[] {
113
+ return tools.map(runtimeTool => claudeToolName(runtimeTool.name))
114
+ }
115
+
116
+ export function claudeToolActorHooks(tools: readonly AgentTool[]): Options['hooks'] {
117
+ const toolsByName = new Map(
118
+ tools
119
+ .filter(runtimeTool => runtimeTool.actorScope === 'main')
120
+ .map(runtimeTool => [claudeToolName(runtimeTool.name), runtimeTool] as const),
121
+ )
122
+ if (toolsByName.size === 0)
123
+ return undefined
124
+
125
+ return {
126
+ PreToolUse: [{
127
+ hooks: [async (hookInput) => {
128
+ if (hookInput.hook_event_name !== 'PreToolUse')
129
+ return {}
130
+
131
+ const runtimeTool = toolsByName.get(hookInput.tool_name)
132
+ const actor = hookInput.agent_id === undefined ? 'main' : 'subagent'
133
+ if (!runtimeTool || agentToolAllowsActor(runtimeTool, actor))
134
+ return {}
135
+
136
+ return {
137
+ hookSpecificOutput: {
138
+ hookEventName: 'PreToolUse',
139
+ permissionDecision: 'deny',
140
+ permissionDecisionReason: agentToolActorDenialMessage(runtimeTool),
141
+ },
142
+ }
143
+ }],
144
+ }],
145
+ }
146
+ }
147
+
148
+ function claudeToolName(toolName: string): string {
149
+ return `mcp__${CLAUDE_AGENT_TOOL_SERVER}__${toolName}`
150
+ }
151
+
152
+ function unexpectedToolFailure(): { isError: true, content: [{ type: 'text', text: string }] } {
153
+ return {
154
+ isError: true,
155
+ content: [{ type: 'text', text: UNEXPECTED_TOOL_FAILURE_MESSAGE }],
156
+ }
157
+ }
158
+
159
+ function requireAttachedRuntime(runtime: ClaudeToolRuntimeAttachment | undefined): ClaudeToolRuntimeAttachment {
160
+ if (runtime)
161
+ return runtime
162
+ throw new AgentProviderProtocolError({ message: 'Claude invoked a runtime tool before run metadata was available.' })
163
+ }
164
+
165
+ function requiredToolCallId(extra: unknown): string {
166
+ const toolCallId = toolCallIdFromExtra(extra)
167
+ if (toolCallId)
168
+ return toolCallId
169
+ throw new AgentProviderProtocolError({ message: 'Claude invoked a runtime tool without a provider tool call id.' })
170
+ }
171
+
172
+ function toolCallIdFromExtra(extra: unknown): string | undefined {
173
+ if (!isClaudeMcpToolExtra(extra))
174
+ return undefined
175
+
176
+ const value = extra._meta?.[CLAUDE_CODE_TOOL_USE_ID_META_KEY]
177
+ return typeof value === 'string' && value.trim() ? value : undefined
178
+ }
179
+
180
+ function isClaudeMcpToolExtra(value: unknown): value is ClaudeMcpToolExtra {
181
+ if (typeof value !== 'object' || value === null)
182
+ return false
183
+
184
+ const meta = (value as { _meta?: unknown })._meta
185
+ return meta === undefined || (typeof meta === 'object' && meta !== null)
186
+ }
@@ -0,0 +1 @@
1
+ export * from './claude-provider'
@@ -0,0 +1,34 @@
1
+ export interface CodexAuthTokens {
2
+ accessToken: string
3
+ accessTokenGeneration: number
4
+ accessTokenFingerprint: string
5
+ chatgptAccountId: string
6
+ chatgptPlanType?: string | null
7
+ }
8
+
9
+ export interface CodexAuthRefreshInput {
10
+ reason: 'unauthorized'
11
+ rejectedTokenGeneration: number
12
+ rejectedTokenFingerprint: string
13
+ }
14
+
15
+ export type CodexAuthTokenRequest = Readonly<{
16
+ signal?: AbortSignal
17
+ }>
18
+
19
+ export interface CodexAuthProvider {
20
+ getAuthTokens: (input?: CodexAuthTokenRequest) => Promise<CodexAuthTokens>
21
+ refreshAuthTokens: (input: CodexAuthRefreshInput) => Promise<CodexAuthTokens>
22
+ }
23
+
24
+ export interface CodexApiKeyCredentials {
25
+ apiKey: string
26
+ }
27
+
28
+ export interface CodexApiKeyAuthProvider {
29
+ getApiKey: (input?: CodexAuthTokenRequest) => Promise<CodexApiKeyCredentials>
30
+ }
31
+
32
+ export type CodexAuthentication
33
+ = | { kind: 'chatgpt', provider: CodexAuthProvider }
34
+ | { kind: 'api-key', provider: CodexApiKeyAuthProvider, modelProvider?: string }
@@ -0,0 +1,78 @@
1
+ import type { AgentAuthor, AgentInputBlock, AgentPrompt, AgentReasoningEffort } from '../../protocol'
2
+ import type { AgentSenderContext } from '../agent-operation'
3
+ import type { AgentInputAttachmentPreparation, AgentInputAttachmentProjection } from '../materialized-input-attachment'
4
+ import type { CodexTurnStartParams, CodexUserInput } from './codex-protocol'
5
+ import { AgentUnsupportedPromptBlockError } from '../agent-runtime-error'
6
+ import { renderAuthorContext } from '../author-context'
7
+ import { filesystemFallbackLabel, nativeAttachmentLabel, nativeImageMimeType, readAttachmentBytes } from '../input-attachment-preparation'
8
+
9
+ interface CodexUserInputMapperInput {
10
+ prompt: AgentPrompt
11
+ origin?: 'user' | 'supervisor'
12
+ author?: AgentAuthor
13
+ senderContext?: AgentSenderContext
14
+ }
15
+
16
+ export function toCodexUserInput(input: CodexUserInputMapperInput): CodexUserInput[] {
17
+ const { prompt, origin = 'user', author, senderContext } = input
18
+ const blocks = prompt.blocks.map(toCodexInputBlock)
19
+ return origin === 'user' && author
20
+ ? [{ type: 'text', text: renderAuthorContext(author, senderContext), text_elements: [] }, ...blocks]
21
+ : blocks
22
+ }
23
+
24
+ export async function prepareCodexUserInput(input: CodexUserInputMapperInput & { preparation: AgentInputAttachmentPreparation }): Promise<CodexUserInput[]> {
25
+ input.preparation.signal.throwIfAborted()
26
+ const userInput = toCodexUserInput(input)
27
+ const records: AgentInputAttachmentProjection[] = []
28
+
29
+ for (const attachment of input.preparation.attachments) {
30
+ const bytes = await readAttachmentBytes(attachment, input.preparation.signal)
31
+ const imageMimeType = nativeImageMimeType(attachment.mediaType, bytes)
32
+ if (imageMimeType) {
33
+ userInput.push(
34
+ { type: 'text', text: nativeAttachmentLabel(attachment), text_elements: [] },
35
+ { type: 'localImage', path: attachment.localPath },
36
+ )
37
+ records.push({
38
+ attachmentId: attachment.attachmentId,
39
+ ordinal: attachment.ordinal,
40
+ sha256: attachment.sha256,
41
+ route: 'native',
42
+ nativeKind: 'image',
43
+ })
44
+ continue
45
+ }
46
+
47
+ userInput.push({ type: 'text', text: filesystemFallbackLabel(attachment), text_elements: [] })
48
+ records.push({
49
+ attachmentId: attachment.attachmentId,
50
+ ordinal: attachment.ordinal,
51
+ sha256: attachment.sha256,
52
+ route: 'filesystem_fallback',
53
+ })
54
+ }
55
+
56
+ input.preparation.recordInputAttachmentProjections(records)
57
+ return userInput
58
+ }
59
+
60
+ export function codexEffort(effort: AgentReasoningEffort | undefined): CodexTurnStartParams['effort'] | undefined {
61
+ if (effort === undefined)
62
+ return undefined
63
+ if (effort === 'max')
64
+ return 'xhigh'
65
+ return effort
66
+ }
67
+
68
+ function toCodexInputBlock(block: AgentInputBlock): CodexUserInput {
69
+ if (block.type === 'text') {
70
+ return { type: 'text', text: block.text, text_elements: [] }
71
+ }
72
+
73
+ if (block.type === 'image' && block.source.kind === 'url') {
74
+ return { type: 'image', url: block.source.url }
75
+ }
76
+
77
+ throw new AgentUnsupportedPromptBlockError({ provider: 'codex', blockType: block.type })
78
+ }