@meistrari/agent-core 0.2.0-experimental.2 → 0.2.0-experimental.4
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 +1 -1
- package/package.json +1 -1
- package/src/agents/claude/claude-event-mapper.ts +4 -0
- package/src/agents/claude/claude-provider.ts +12 -1
- package/src/agents/claude/claude-run.ts +30 -7
- package/src/agents/codex/codex-event-mapper.ts +9 -3
- package/src/provenance.gen.ts +3 -3
- package/src/supervisor/agent-provider-factory.ts +8 -3
package/README.md
CHANGED
|
@@ -139,5 +139,5 @@ process lifecycle spec reads `/proc`, so it fails on macOS. Claude Code rejects
|
|
|
139
139
|
bypass-permissions mode as root, so run them as a regular user.
|
|
140
140
|
|
|
141
141
|
Regenerate the experimental Codex wire types with `bun run generate:codex-protocol`.
|
|
142
|
-
The generator pins Codex 0.
|
|
142
|
+
The generator pins Codex 0.156.1 and verifies any `CODEX_EXECUTABLE` override before
|
|
143
143
|
using it. Commit generated files with generator changes; CI checks reproducibility.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meistrari/agent-core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.0-experimental.
|
|
4
|
+
"version": "0.2.0-experimental.4",
|
|
5
5
|
"packageManager": "bun@1.3.12",
|
|
6
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
7
|
"license": "UNLICENSED",
|
|
@@ -400,6 +400,10 @@ function correlateConsumedPrompts({ message, turnId, drafts, state }: {
|
|
|
400
400
|
? message.user_message_uuids.filter((id): id is string => typeof id === 'string')
|
|
401
401
|
: message.user_message_uuid ? [message.user_message_uuid] : []
|
|
402
402
|
for (const inputId of inputIds) {
|
|
403
|
+
// Main-response UUIDs prove consumption even if the started receipt was omitted. This
|
|
404
|
+
// also applies to supervisor inputs, which intentionally have no human-prompt correlation.
|
|
405
|
+
if (state.queuedSteerIds.delete(inputId))
|
|
406
|
+
state.heldTurnEnd = undefined
|
|
403
407
|
const commandId = state.promptCommandByInputId.get(inputId)
|
|
404
408
|
if (!commandId)
|
|
405
409
|
continue
|
|
@@ -512,6 +512,17 @@ function createInputQueue(): AsyncIterable<SDKUserMessage> & { push: (message: S
|
|
|
512
512
|
}
|
|
513
513
|
}
|
|
514
514
|
|
|
515
|
+
// Claude Code 2.1.280 sanitizePath: replace each non-ASCII-alphanumeric UTF-16 unit,
|
|
516
|
+
// then cap the slug at 200 units and suffix a base-36 signed-32-bit hash of the ORIGINAL
|
|
517
|
+
// cwd. The non-Unicode regex is deliberate: an astral character becomes two hyphens.
|
|
518
|
+
// This is needed before input; SessionStart's transcript_path arrives too late for the
|
|
519
|
+
// session-local stores and resume-context lookup. Real-CLI tests pin open and resume.
|
|
515
520
|
function encodeClaudeProjectPath(cwd: string): string {
|
|
516
|
-
|
|
521
|
+
const encoded = cwd.replace(/[^a-z0-9]/gi, '-')
|
|
522
|
+
if (encoded.length <= 200)
|
|
523
|
+
return encoded
|
|
524
|
+
let hash = 0
|
|
525
|
+
for (let index = 0; index < cwd.length; index++)
|
|
526
|
+
hash = ((hash << 5) - hash + cwd.charCodeAt(index)) | 0
|
|
527
|
+
return `${encoded.slice(0, 200)}-${Math.abs(hash).toString(36)}`
|
|
517
528
|
}
|
|
@@ -79,7 +79,7 @@ function isClaudePreInitHookMessage(message: SDKMessage | ClaudeCommandLifecycle
|
|
|
79
79
|
// run in this session". Any other shape or state deviation is provider protocol drift and fails
|
|
80
80
|
// the run closed. Only `queued`/`started`/`completed` are positive. `cancelled` (steered-over,
|
|
81
81
|
// aborted, or user-cancelled) and `discarded` (session ended with the command still queued) are
|
|
82
|
-
//
|
|
82
|
+
// non-positive states that reject an unsettled waiter as delivery-unknown; `refused` is a definite
|
|
83
83
|
// terminal non-acceptance while the session keeps running, so it settles the waiter itself.
|
|
84
84
|
const commandLifecycleFrameSchema = z.strictObject({
|
|
85
85
|
type: z.literal('command_lifecycle'),
|
|
@@ -393,10 +393,11 @@ export class ClaudeRun implements AgentRun {
|
|
|
393
393
|
// Register before the push: the CLI's queued receipt can outrun the local push resolution,
|
|
394
394
|
// and a receipt with no registered waiter would be lost.
|
|
395
395
|
const receipt = this.registerAcceptanceWaiter(clientMessageId)
|
|
396
|
-
if (command.origin === 'user')
|
|
396
|
+
if (command.origin === 'user') {
|
|
397
397
|
this.eventMapperState.promptCommandByInputId.set(clientMessageId, command.commandId)
|
|
398
|
+
this.pendingMessages.set(command.commandId, { messageId: clientMessageId, mode: command.mode, turnId: command.turnId, started: false })
|
|
399
|
+
}
|
|
398
400
|
this.commandByClientMessageId.set(clientMessageId, command.commandId)
|
|
399
|
-
this.pendingMessages.set(command.commandId, { messageId: clientMessageId, mode: command.mode, turnId: command.turnId, started: false })
|
|
400
401
|
if (command.mode === 'steer')
|
|
401
402
|
this.steerInputIds.add(clientMessageId)
|
|
402
403
|
try {
|
|
@@ -740,7 +741,25 @@ export class ClaudeRun implements AgentRun {
|
|
|
740
741
|
// Deliver first: on a prebound resume this is the run's first input, and the resolved
|
|
741
742
|
// event must not precede the lifecycle events the init barrier emits.
|
|
742
743
|
await this.applyProviderSettings(this.current)
|
|
743
|
-
|
|
744
|
+
// The answer opens its turn as the user's input, correlated like a prompt: the turn it
|
|
745
|
+
// starts carries this command, and the answer is accepted as that turn's user message.
|
|
746
|
+
const clientMessageId = deriveMessageId(command.commandId)
|
|
747
|
+
const receipt = this.registerAcceptanceWaiter(clientMessageId)
|
|
748
|
+
this.eventMapperState.promptCommandByInputId.set(clientMessageId, command.commandId)
|
|
749
|
+
this.pendingMessages.set(command.commandId, { messageId: clientMessageId, mode: 'next', turnId: undefined, started: false })
|
|
750
|
+
this.commandByClientMessageId.set(clientMessageId, command.commandId)
|
|
751
|
+
try {
|
|
752
|
+
await this.deliverInput(toClaudeUserMessage({ prompt: resolved.prompt, mode: 'next', commandId: command.commandId }))
|
|
753
|
+
await receipt.promise
|
|
754
|
+
}
|
|
755
|
+
catch (error) {
|
|
756
|
+
if (error instanceof AgentNotAcceptedError)
|
|
757
|
+
this.eventMapperState.promptCommandByInputId.delete(clientMessageId)
|
|
758
|
+
throw error
|
|
759
|
+
}
|
|
760
|
+
finally {
|
|
761
|
+
this.acceptanceWaiters.delete(clientMessageId)
|
|
762
|
+
}
|
|
744
763
|
if (resolved.event)
|
|
745
764
|
this.pushEvent(resolved.event)
|
|
746
765
|
this.userInputRequests.markDelivered(command.requestId)
|
|
@@ -945,9 +964,9 @@ export class ClaudeRun implements AgentRun {
|
|
|
945
964
|
|
|
946
965
|
// Strict pinned-runtime boundary for the undocumented receipt frame: shape/state deviation and
|
|
947
966
|
// session identity mismatch are provider protocol drift and fail the run closed. `cancelled`
|
|
948
|
-
// and `discarded`
|
|
949
|
-
//
|
|
950
|
-
//
|
|
967
|
+
// and `discarded` reject an unsettled waiter as delivery-unknown; a prior positive acceptance
|
|
968
|
+
// cannot be revoked, and later consumed UUIDs remain valid evidence. `refused` is the pinned
|
|
969
|
+
// runtime's definite pre-queue rejection: the input
|
|
951
970
|
// will never run in this session, and the session stays open, so the pending waiter is
|
|
952
971
|
// rejected as a terminal not-accepted outcome instead of waiting for a close that may not
|
|
953
972
|
// come. Valid positive frames without a pending waiter are internal lifecycle for
|
|
@@ -1198,6 +1217,10 @@ export class ClaudeRun implements AgentRun {
|
|
|
1198
1217
|
if (!this.initialized) {
|
|
1199
1218
|
throw new AgentProviderProtocolError({ message: 'Claude SDK ended before emitting system init.' })
|
|
1200
1219
|
}
|
|
1220
|
+
// A queued steer was accepted but never consumed or explicitly dropped. Its preceding
|
|
1221
|
+
// ask's held result cannot stand in for that owed input's completion.
|
|
1222
|
+
if (this.eventMapperState.queuedSteerIds.size > 0)
|
|
1223
|
+
throw new AgentProviderProtocolError({ message: 'Claude SDK ended before queued steering input started.' })
|
|
1201
1224
|
// A superseded ask's held end is final once the stream can deliver no steer to continue it.
|
|
1202
1225
|
await this.emitDrafts(flushHeldTurnEnd(this.eventMapperState), this.eventMapperState.interrupt)
|
|
1203
1226
|
// The SDK reports non-zero exits and signals as errors, but a clean exit mid-turn ends the stream
|
|
@@ -397,10 +397,16 @@ function toolCallCompletion(item: CodexCompletedItem): { toolName: string, statu
|
|
|
397
397
|
if (item.type === 'imageGeneration')
|
|
398
398
|
return { toolName, status: item.status === 'failed' ? 'failed' : 'completed', output: imageGenerationResult(item) }
|
|
399
399
|
if (item.type === 'commandExecution') {
|
|
400
|
-
const status = item.
|
|
400
|
+
const status = item.status === 'declined'
|
|
401
|
+
? 'cancelled'
|
|
402
|
+
: item.status !== 'completed' || (item.exitCode != null && item.exitCode !== 0) ? 'failed' : 'completed'
|
|
401
403
|
const error = 'error' in item && typeof item.error === 'string'
|
|
402
404
|
? { message: item.error }
|
|
403
|
-
: status === 'failed'
|
|
405
|
+
: status === 'failed'
|
|
406
|
+
? { message: item.exitCode != null && item.exitCode !== 0
|
|
407
|
+
? `Command exited with code ${item.exitCode}.`
|
|
408
|
+
: item.status === 'inProgress' ? 'Command completion status was inconsistent.' : 'Command execution failed.' }
|
|
409
|
+
: undefined
|
|
404
410
|
return { toolName, status, output: commandExecutionResult(item, status), error }
|
|
405
411
|
}
|
|
406
412
|
if (item.type === 'dynamicToolCall')
|
|
@@ -503,7 +509,7 @@ function hookPromptText(item: CodexHookPromptItem): string | undefined {
|
|
|
503
509
|
return optionalNonEmpty(item.fragments.map(fragment => fragment.text).join('\n'))
|
|
504
510
|
}
|
|
505
511
|
|
|
506
|
-
function commandExecutionResult(item: Extract<CodexCompletedItem, { type: 'commandExecution' }>, status:
|
|
512
|
+
function commandExecutionResult(item: Extract<CodexCompletedItem, { type: 'commandExecution' }>, status: AgentToolCallStatus): AgentToolResult | undefined {
|
|
507
513
|
// Stdout is content, not a label: whitespace and an explicitly empty
|
|
508
514
|
// successful output must survive normalization into the complete step.
|
|
509
515
|
// Native build_command_execution_end_item encodes empty captured output as
|
package/src/provenance.gen.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Generated by scripts/write-provenance.ts. Do not edit by hand.
|
|
2
2
|
export const generatedProvenance = {
|
|
3
|
-
version: "0.2.0-experimental.
|
|
4
|
-
sha: "
|
|
5
|
-
buildTime: "2026-09-
|
|
3
|
+
version: "0.2.0-experimental.4",
|
|
4
|
+
sha: "432a69b2d7243b7d5c6651229bf2f005e94afad7",
|
|
5
|
+
buildTime: "2026-09-29T14:26:10.056Z",
|
|
6
6
|
} as const
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentProvider, AgentRun } from '../agents'
|
|
2
2
|
import type { AgentInputAttachmentPreparation } from '../agents/materialized-input-attachment'
|
|
3
|
-
import type { AgentEvent, AgentProviderId } from '../protocol'
|
|
3
|
+
import type { AgentEvent, AgentPrompt, AgentProviderId } from '../protocol'
|
|
4
4
|
import type { EphemeralCredentials, SessionBootstrapBody, SessionBootstrapGitToken } from '../supervisor-protocol/bootstrap'
|
|
5
5
|
import type { WireSendPromptCommand } from '../supervisor-protocol/command-body'
|
|
6
6
|
import type { WireEventBody } from '../supervisor-protocol/event-body'
|
|
@@ -62,11 +62,16 @@ export interface AgentSupervisorProviderFactoryOptions {
|
|
|
62
62
|
rpc: SupervisorRpcClient
|
|
63
63
|
}) => AgentProvider<'claude'> | AgentProvider<'codex'>
|
|
64
64
|
bindingStore: AgentProviderBindingStore
|
|
65
|
+
/**
|
|
66
|
+
* Prepares a send-prompt's attachments before the provider sees it. It may also return the
|
|
67
|
+
* prompt the provider receives instead of the command's, for text the command could only
|
|
68
|
+
* reference (a message too long for a wire frame, fetched by the supervisor).
|
|
69
|
+
*/
|
|
65
70
|
prepareInputAttachments?: (input: {
|
|
66
71
|
commandId: string
|
|
67
72
|
command: WireSendPromptCommand
|
|
68
73
|
signal: AbortSignal
|
|
69
|
-
}) => Promise<AgentInputAttachmentPreparation | undefined>
|
|
74
|
+
}) => Promise<(AgentInputAttachmentPreparation & { prompt?: AgentPrompt }) | undefined>
|
|
70
75
|
onSecretsRefreshed?: (input: {
|
|
71
76
|
credentials?: EphemeralCredentials
|
|
72
77
|
gitToken?: SessionBootstrapGitToken
|
|
@@ -194,7 +199,7 @@ class AgentSupervisorRuntime implements SupervisorAgentRuntime {
|
|
|
194
199
|
model: input.body.model,
|
|
195
200
|
reasoningEffort: input.body.reasoningEffort,
|
|
196
201
|
origin: 'user',
|
|
197
|
-
prompt: input.body.prompt,
|
|
202
|
+
prompt: inputAttachmentPreparation?.prompt ?? input.body.prompt,
|
|
198
203
|
author: input.body.user
|
|
199
204
|
? {
|
|
200
205
|
name: input.body.user.name,
|