@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.
- package/README.md +24 -3
- package/bin/supervisor.ts +116 -0
- package/package.json +42 -3
- package/scripts/build-supervisor-executable.ts +32 -0
- package/src/agents/agent-error-serializer.ts +23 -0
- package/src/agents/agent-event-stream.ts +81 -0
- package/src/agents/agent-id.ts +17 -0
- package/src/agents/agent-operation.ts +11 -0
- package/src/agents/agent-provider.ts +37 -0
- package/src/agents/agent-run.ts +32 -0
- package/src/agents/agent-runtime-error.ts +161 -0
- package/src/agents/agent-session-events.ts +32 -0
- package/src/agents/agent-tool-runner.ts +83 -0
- package/src/agents/agent-tool.ts +111 -0
- package/src/agents/author-context.ts +36 -0
- package/src/agents/claude/claude-command-mapper.ts +234 -0
- package/src/agents/claude/claude-event-mapper.ts +736 -0
- package/src/agents/claude/claude-provider.ts +191 -0
- package/src/agents/claude/claude-run.ts +464 -0
- package/src/agents/claude/claude-tool-mapper.ts +186 -0
- package/src/agents/claude/index.ts +1 -0
- package/src/agents/codex/codex-auth.ts +34 -0
- package/src/agents/codex/codex-command-mapper.ts +78 -0
- package/src/agents/codex/codex-event-mapper.ts +708 -0
- package/src/agents/codex/codex-json-rpc-client.ts +326 -0
- package/src/agents/codex/codex-protocol.ts +36 -0
- package/src/agents/codex/codex-provider.ts +1050 -0
- package/src/agents/codex/codex-run.ts +404 -0
- package/src/agents/codex/codex-skill-catalog.ts +158 -0
- package/src/agents/codex/codex-skill-roots.ts +19 -0
- package/src/agents/codex/codex-tool-mapper.ts +55 -0
- package/src/agents/codex/codex.errors.ts +68 -0
- package/src/agents/codex/generated/meta.gen.ts +606 -0
- package/src/agents/codex/generated/namespaces.gen.ts +311 -0
- package/src/agents/codex/generated/schema.gen.ts +34883 -0
- package/src/agents/codex/index.ts +2 -0
- package/src/agents/index.ts +14 -0
- package/src/agents/input-attachment-preparation.ts +86 -0
- package/src/agents/input-attachment.errors.ts +16 -0
- package/src/agents/instructions.ts +8 -0
- package/src/agents/materialized-input-attachment.ts +26 -0
- package/src/agents/message-id.ts +23 -0
- package/src/agents/normalize.ts +8 -0
- package/src/agents/sandbox-environment.ts +1 -0
- package/src/agents/tools/ping.tool.ts +13 -0
- package/src/agents/user-input-request.ts +470 -0
- package/src/provenance.gen.ts +3 -3
- package/src/supervisor/agent-provider-factory.ts +189 -0
- package/src/supervisor/bootstrap-binder.ts +125 -0
- package/src/supervisor/config.ts +49 -0
- package/src/supervisor/control-authority-verifier.ts +135 -0
- package/src/supervisor/create-supervisor-runtime.ts +25 -0
- package/src/supervisor/errors.ts +24 -0
- package/src/supervisor/index.ts +34 -0
- package/src/supervisor/persistence/json.ts +21 -0
- package/src/supervisor/persistence/state-discovery.ts +56 -0
- package/src/supervisor/persistence/supervisor-store.ts +364 -0
- package/src/supervisor/ports/index.ts +109 -0
- package/src/supervisor/provider-factory.ts +37 -0
- package/src/supervisor/resident.ts +143 -0
- package/src/supervisor/rpc-client.ts +120 -0
- package/src/supervisor/runtime-handler.ts +309 -0
- package/src/supervisor/websocket-server.ts +434 -0
- package/src/supervisor-protocol/bootstrap.ts +1 -1
- package/src/template-onboarding.ts +47 -0
- package/src/testing/es256-test-keys.ts +73 -0
- package/src/testing/in-memory-runtime-control-plane.ts +205 -0
- package/src/testing/index.ts +6 -0
- package/src/testing/loopback-supervisor-connection.ts +71 -0
- package/src/testing/scripted-provider.ts +64 -0
- package/src/worker-runtime-client/command-pump.ts +132 -0
- package/src/worker-runtime-client/connection-attempt.ts +340 -0
- package/src/worker-runtime-client/control-authority-signer.ts +100 -0
- package/src/worker-runtime-client/e2b-supervisor-connection.ts +102 -0
- package/src/worker-runtime-client/frame-processor.ts +178 -0
- package/src/worker-runtime-client/index.ts +27 -0
- package/src/worker-runtime-client/lease-reconciler.ts +14 -0
- package/src/worker-runtime-client/ports.ts +137 -0
- package/src/worker-runtime-client/postgres-notification-listener.ts +91 -0
- package/src/worker-runtime-client/rpc-dispatcher.ts +27 -0
- package/src/worker-runtime-client/rpc-request-manager.ts +141 -0
- package/src/worker-runtime-client/sandbox-connection-runtime.ts +300 -0
- 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
|
+
}
|