@meistrari/agent-core 0.2.0-experimental.5 → 0.2.0-experimental.6
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
CHANGED
|
@@ -122,6 +122,13 @@ stale managed instruction file.
|
|
|
122
122
|
`resolveInferenceModel`, `pluginsEnabled`, and `browserAuth` (a per-run Browser Use
|
|
123
123
|
credential socket for ChatGPT authentication; off by default).
|
|
124
124
|
|
|
125
|
+
API-key and Bedrock logins stay in the app-server's memory (`cli_auth_credentials_store="ephemeral"`),
|
|
126
|
+
so no `auth.json` under `CODEX_HOME` holds the key for the agent's tools to read. An API-key login
|
|
127
|
+
may name `baseUrl`, the root of another OpenAI Responses API (a gateway, or a loopback proxy that
|
|
128
|
+
holds the real credential and gets a placeholder): Codex then reaches it as a model provider of its
|
|
129
|
+
own, named by `modelProvider` (`api-key-endpoint` by default, never a built-in id), with the key as
|
|
130
|
+
its bearer. `codex-api-key-endpoint.cli.spec.ts` pins that contract against the real CLI.
|
|
131
|
+
|
|
125
132
|
`AgentRun.notify` and `AgentRun.compactContext` are optional on the interface; the Claude and
|
|
126
133
|
Codex runs implement both. `sendPrompt` accepts `submissionOrder`, defaulting to `in-order`.
|
|
127
134
|
|
|
@@ -134,7 +141,8 @@ product instructions/tools, and supervisor integration tests. CI type-checks and
|
|
|
134
141
|
with Remy's Bun 1.3.10 / Claude SDK 0.3.284 and agent-api's Claude SDK 0.3.257 pins.
|
|
135
142
|
|
|
136
143
|
`bun run test` runs the portable suites. `bun run test:cli` runs the `*.cli.spec.ts` suites
|
|
137
|
-
against the real bundled Claude Code CLI and a fake Messages API
|
|
144
|
+
against the real bundled Claude Code CLI and a fake Messages API, and the Codex endpoint spec
|
|
145
|
+
against the pinned Codex CLI (through `bunx`, or `CODEX_EXECUTABLE`) and a fake Responses API. CI runs them on Linux; the
|
|
138
146
|
process lifecycle spec reads `/proc`, so it fails on macOS. Claude Code rejects its
|
|
139
147
|
bypass-permissions mode as root, so run them as a regular user.
|
|
140
148
|
|
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.6",
|
|
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",
|
|
@@ -44,9 +44,23 @@ export interface CodexBedrockAuthProvider {
|
|
|
44
44
|
getCredentials: (input?: CodexAuthTokenRequest) => Promise<CodexBedrockCredentials>
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* An API key login, kept in the app-server's memory only. Without `baseUrl` it reaches the API of the model
|
|
49
|
+
* provider `modelProvider` names (OpenAI's by default). With `baseUrl`, the root of another OpenAI Responses
|
|
50
|
+
* API (`https://gateway.example/v1`, or a loopback proxy that holds the real credential), Codex reaches it as
|
|
51
|
+
* a model provider of its own, named by `modelProvider` (`api-key-endpoint` by default) and given the key as
|
|
52
|
+
* its bearer.
|
|
53
|
+
*/
|
|
54
|
+
export interface CodexApiKeyAuthentication {
|
|
55
|
+
kind: 'api-key'
|
|
56
|
+
provider: CodexApiKeyAuthProvider
|
|
57
|
+
modelProvider?: string
|
|
58
|
+
baseUrl?: string
|
|
59
|
+
}
|
|
60
|
+
|
|
47
61
|
export type CodexAuthentication
|
|
48
62
|
= | { kind: 'chatgpt', provider: CodexAuthProvider }
|
|
49
|
-
|
|
|
63
|
+
| CodexApiKeyAuthentication
|
|
50
64
|
| { kind: 'amazon-bedrock', region: string, provider: CodexBedrockAuthProvider }
|
|
51
65
|
/** Expiry scheduling hint only; this neither authenticates nor verifies a JWT signature. */
|
|
52
66
|
export function codexAuthTokensExpireSoon(tokens: CodexAuthTokens): boolean {
|
|
@@ -5,7 +5,7 @@ import type { AgentRun } from '../agent-run'
|
|
|
5
5
|
import type { AgentTool } from '../agent-tool'
|
|
6
6
|
import type { InstructionComposer } from '../instructions'
|
|
7
7
|
import type { SessionContextComposer } from '../session-context'
|
|
8
|
-
import type { CodexAuthentication, CodexAuthProvider, CodexAuthTokens, CodexBedrockCredentials } from './codex-auth'
|
|
8
|
+
import type { CodexApiKeyAuthentication, CodexAuthentication, CodexAuthProvider, CodexAuthTokens, CodexBedrockCredentials } from './codex-auth'
|
|
9
9
|
import type { CodexEventMapperState, CodexNotification } from './codex-event-mapper'
|
|
10
10
|
import type { CodexJsonRpcMessage, CodexServerRequest } from './codex-json-rpc-client'
|
|
11
11
|
import type { ClientRequestResponsesByMethod } from './codex-protocol'
|
|
@@ -13,7 +13,7 @@ import { realpath } from 'node:fs/promises'
|
|
|
13
13
|
import { resolve } from 'node:path'
|
|
14
14
|
import { codexModelIdSchema } from '../../protocol'
|
|
15
15
|
import { serializeAgentError } from '../agent-error-serializer'
|
|
16
|
-
import { AgentProviderMetadataError, AgentProviderProtocolError, AgentProviderRuntimeError } from '../agent-runtime-error'
|
|
16
|
+
import { AgentProviderMetadataError, AgentProviderProtocolError, AgentProviderRuntimeError, AgentRuntimeValidationError } from '../agent-runtime-error'
|
|
17
17
|
import { sessionConfiguredEvent } from '../agent-session-events'
|
|
18
18
|
import { selectAgentTools, toolByName } from '../agent-tool'
|
|
19
19
|
import { emptyInstructionComposer } from '../instructions'
|
|
@@ -33,6 +33,15 @@ import { CodexRunAuth, CodexRunAuthClosedError } from './codex-run-auth'
|
|
|
33
33
|
import { catalogRepositorySkillRoots, workspaceSkillRoots } from './codex-skill-roots'
|
|
34
34
|
import { runCodexDynamicTool, toCodexDynamicTools } from './codex-tool-mapper'
|
|
35
35
|
|
|
36
|
+
/** The model provider an API key endpoint gets when `modelProvider` names none. */
|
|
37
|
+
const API_KEY_ENDPOINT_PROVIDER = 'api-key-endpoint'
|
|
38
|
+
/** Codex's own provider ids: an endpoint defined under one of these would not be the one Codex uses. */
|
|
39
|
+
const BUILT_IN_MODEL_PROVIDERS = new Set(['openai', 'amazon-bedrock', 'ollama', 'lmstudio', 'oss'])
|
|
40
|
+
/** A bare TOML key, so the id is safe inside the dotted `-c model_providers.<id>.…` overrides. */
|
|
41
|
+
const MODEL_PROVIDER_ID = /^[\w-]+$/
|
|
42
|
+
/** Where plain http keeps the key on the machine. */
|
|
43
|
+
const LOOPBACK_HOSTS = new Set(['127.0.0.1', 'localhost', '[::1]'])
|
|
44
|
+
|
|
36
45
|
export interface CodexStartupStageFact {
|
|
37
46
|
event: 'sandbox.startup-stage'
|
|
38
47
|
stage: 'codex-initialize' | 'auth-acquisition-login' | 'thread-start' | 'thread-resume'
|
|
@@ -103,6 +112,8 @@ export class CodexProvider implements AgentProvider<'codex'> {
|
|
|
103
112
|
private readonly executable: string
|
|
104
113
|
private readonly environment: Record<string, string | undefined>
|
|
105
114
|
private readonly auth: CodexAuthentication
|
|
115
|
+
/** The validated endpoint of an API key login that names one. */
|
|
116
|
+
private readonly apiKeyEndpoint: string | undefined
|
|
106
117
|
private readonly onStartupStage: ((fact: CodexStartupStageFact) => void) | undefined
|
|
107
118
|
private readonly instructions: InstructionComposer
|
|
108
119
|
private readonly sessionContext: SessionContextComposer | undefined
|
|
@@ -115,6 +126,7 @@ export class CodexProvider implements AgentProvider<'codex'> {
|
|
|
115
126
|
|
|
116
127
|
private constructor(config: CodexProviderConfig) {
|
|
117
128
|
this.auth = normalizeCodexAuthentication(config.auth)
|
|
129
|
+
this.apiKeyEndpoint = this.auth.kind === 'api-key' ? apiKeyEndpoint(this.auth) : undefined
|
|
118
130
|
this.tools = config.tools ?? []
|
|
119
131
|
this.executable = config.executable ?? 'codex'
|
|
120
132
|
this.environment = config.environment ?? {}
|
|
@@ -422,7 +434,11 @@ export class CodexProvider implements AgentProvider<'codex'> {
|
|
|
422
434
|
}
|
|
423
435
|
|
|
424
436
|
private modelProvider(): string | undefined {
|
|
425
|
-
|
|
437
|
+
if (this.auth.kind === 'amazon-bedrock')
|
|
438
|
+
return 'amazon-bedrock'
|
|
439
|
+
if (this.auth.kind === 'api-key')
|
|
440
|
+
return this.auth.modelProvider ?? (this.apiKeyEndpoint === undefined ? undefined : API_KEY_ENDPOINT_PROVIDER)
|
|
441
|
+
return undefined
|
|
426
442
|
}
|
|
427
443
|
|
|
428
444
|
private async openConnection(input: {
|
|
@@ -450,6 +466,7 @@ export class CodexProvider implements AgentProvider<'codex'> {
|
|
|
450
466
|
...(this.auth.kind === 'amazon-bedrock'
|
|
451
467
|
? ['cli_auth_credentials_store="ephemeral"', 'model_provider="amazon-bedrock"', `model_providers.amazon-bedrock.aws.region=${JSON.stringify(this.auth.region)}`, 'model_providers.amazon-bedrock.aws.wire_api="responses"']
|
|
452
468
|
: []),
|
|
469
|
+
...(this.auth.kind === 'api-key' ? apiKeyConfigOverrides(this.auth.modelProvider, this.apiKeyEndpoint) : []),
|
|
453
470
|
...(this.pluginsEnabled === undefined ? [] : [`features.plugins=${this.pluginsEnabled}`]),
|
|
454
471
|
],
|
|
455
472
|
onMessage: (message) => {
|
|
@@ -895,6 +912,62 @@ function normalizeCodexAuthentication(auth: CodexAuthProvider | CodexAuthenticat
|
|
|
895
912
|
return 'kind' in auth ? auth : { kind: 'chatgpt', provider: auth }
|
|
896
913
|
}
|
|
897
914
|
|
|
915
|
+
/**
|
|
916
|
+
* The endpoint as Codex is given it, or none: an http(s) URL with no credentials, query or fragment (not even
|
|
917
|
+
* an empty `?` or `#`), plain http only on loopback, where the key never crosses the network. Without a
|
|
918
|
+
* trailing slash, so Codex appends `/responses` to the path it names.
|
|
919
|
+
*/
|
|
920
|
+
function apiKeyEndpoint(auth: CodexApiKeyAuthentication): string | undefined {
|
|
921
|
+
const invalid = (message: string) => new AgentRuntimeValidationError({
|
|
922
|
+
code: 'agents.codex-api-key-endpoint-invalid',
|
|
923
|
+
message,
|
|
924
|
+
publicMessage: 'The Codex API key endpoint is misconfigured.',
|
|
925
|
+
details: { modelProvider: auth.modelProvider },
|
|
926
|
+
})
|
|
927
|
+
// Without an endpoint the provider id only selects a provider configured elsewhere, as it always has.
|
|
928
|
+
if (auth.baseUrl === undefined)
|
|
929
|
+
return undefined
|
|
930
|
+
if (auth.modelProvider !== undefined && !MODEL_PROVIDER_ID.test(auth.modelProvider))
|
|
931
|
+
throw invalid('Codex model provider ids are letters, digits, underscores and hyphens.')
|
|
932
|
+
let url: URL
|
|
933
|
+
try {
|
|
934
|
+
url = new URL(auth.baseUrl)
|
|
935
|
+
}
|
|
936
|
+
catch {
|
|
937
|
+
throw invalid('The Codex API key endpoint is not a URL.')
|
|
938
|
+
}
|
|
939
|
+
if (url.protocol !== 'https:' && url.protocol !== 'http:')
|
|
940
|
+
throw invalid('The Codex API key endpoint must be an http or https URL.')
|
|
941
|
+
if (url.protocol === 'http:' && !LOOPBACK_HOSTS.has(url.hostname))
|
|
942
|
+
throw invalid('The Codex API key endpoint sends the key as its bearer: plain http is accepted on loopback only.')
|
|
943
|
+
if (url.username || url.password || /[?#]/u.test(auth.baseUrl))
|
|
944
|
+
throw invalid('The Codex API key endpoint carries no credentials, query or fragment; the key travels as the bearer.')
|
|
945
|
+
if (BUILT_IN_MODEL_PROVIDERS.has(auth.modelProvider ?? API_KEY_ENDPOINT_PROVIDER))
|
|
946
|
+
throw invalid('An API key endpoint needs a model provider id of its own, not one of Codex\'s built-in providers.')
|
|
947
|
+
return `${url.origin}${url.pathname.replace(/\/+$/u, '')}`
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
/**
|
|
951
|
+
* An API key login is always kept in memory, never written to `auth.json` under CODEX_HOME, where the agent's
|
|
952
|
+
* own tools could read it. With an endpoint, Codex reaches it through a Responses provider of its own that
|
|
953
|
+
* authenticates with that login.
|
|
954
|
+
*/
|
|
955
|
+
function apiKeyConfigOverrides(modelProvider: string | undefined, endpoint: string | undefined): string[] {
|
|
956
|
+
const ephemeral = ['cli_auth_credentials_store="ephemeral"']
|
|
957
|
+
if (endpoint === undefined)
|
|
958
|
+
return ephemeral
|
|
959
|
+
const id = modelProvider ?? API_KEY_ENDPOINT_PROVIDER
|
|
960
|
+
const provider = `model_providers.${id}`
|
|
961
|
+
return [
|
|
962
|
+
...ephemeral,
|
|
963
|
+
`model_provider=${JSON.stringify(id)}`,
|
|
964
|
+
`${provider}.name=${JSON.stringify(id)}`,
|
|
965
|
+
`${provider}.base_url=${JSON.stringify(endpoint)}`,
|
|
966
|
+
`${provider}.wire_api="responses"`,
|
|
967
|
+
`${provider}.requires_openai_auth=true`,
|
|
968
|
+
]
|
|
969
|
+
}
|
|
970
|
+
|
|
898
971
|
async function requireSelectedRepositoryInstructionSource(input: {
|
|
899
972
|
instructionBridgePath: string
|
|
900
973
|
instructionSources?: readonly string[]
|
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-
|
|
3
|
+
version: "0.2.0-experimental.6",
|
|
4
|
+
sha: "1b8f8c0c8cc698990c1b0ed9e03c417216bc0316",
|
|
5
|
+
buildTime: "2026-10-02T20:59:57.760Z",
|
|
6
6
|
} as const
|