@excitedjs/agent-runtime-codex 0.3.4 → 0.3.5-alpha.g1596746f9cad
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 +46 -7
- package/dist/config.d.ts +11 -16
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +7 -9
- package/dist/config.js.map +1 -1
- package/dist/events.d.ts +2 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +28 -5
- package/dist/events.js.map +1 -1
- package/dist/output-schema-codec.d.ts +7 -0
- package/dist/output-schema-codec.d.ts.map +1 -0
- package/dist/output-schema-codec.js +320 -0
- package/dist/output-schema-codec.js.map +1 -0
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +1 -0
- package/dist/provider.js.map +1 -1
- package/dist/rpc.d.ts +1 -1
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +5 -2
- package/dist/rpc.js.map +1 -1
- package/dist/supervisor.d.ts +1 -1
- package/dist/supervisor.d.ts.map +1 -1
- package/dist/supervisor.js +30 -60
- package/dist/supervisor.js.map +1 -1
- package/dist/turn-manager.d.ts +1 -1
- package/dist/turn-manager.d.ts.map +1 -1
- package/dist/turn-manager.js +106 -16
- package/dist/turn-manager.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -12,13 +12,14 @@ completion delivery, and Codex doctor diagnostics.
|
|
|
12
12
|
|
|
13
13
|
## Boundary
|
|
14
14
|
|
|
15
|
-
This package depends on `@excitedjs/dreamux-types`
|
|
16
|
-
`@excitedjs/dreamux
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
This package depends only on the neutral `@excitedjs/dreamux-types` contracts
|
|
16
|
+
and shared `@excitedjs/dreamux-utils`; it never imports `@excitedjs/dreamux`
|
|
17
|
+
core. Everything host-specific — per-dispatcher paths, the volatile
|
|
18
|
+
rendezvous-socket root, the durable state sink, the process `PATH` seeded from
|
|
19
|
+
the host package bins, and bundled-skill installation — is supplied by the
|
|
20
|
+
Dreamux host through the neutral `AgentRuntimeCreateContext` and provider
|
|
21
|
+
factory options. The package owns only Codex-engine mechanics and its own
|
|
22
|
+
`~/.codex` home/config paths.
|
|
22
23
|
|
|
23
24
|
The host resolves `builtin:codex` to this package and wraps it with a
|
|
24
25
|
core-owned adapter that maps its private dispatcher objects onto the neutral
|
|
@@ -42,3 +43,41 @@ import { createCodexAgentRuntimeProvider } from '@excitedjs/agent-runtime-codex'
|
|
|
42
43
|
The factory accepts the neutral create context plus optional host hooks
|
|
43
44
|
(socket allocator, base process env, workspace skill preparation, and test
|
|
44
45
|
factories for the Codex process / WS client / home doctor).
|
|
46
|
+
|
|
47
|
+
## Portable Structured Output
|
|
48
|
+
|
|
49
|
+
The neutral `AgentRuntimeTextInput.outputSchema` contract accepts ordinary
|
|
50
|
+
optional object properties. Codex strict structured output requires every
|
|
51
|
+
declared property to appear in `required`, so this package privately compiles a
|
|
52
|
+
narrow portable subset before `turn/start`:
|
|
53
|
+
|
|
54
|
+
- one closed root object (`additionalProperties: false`);
|
|
55
|
+
- nested closed objects and single-schema arrays;
|
|
56
|
+
- `string`, `number`, `integer`, `boolean`, `null`, and nullable
|
|
57
|
+
`[T, "null"]`;
|
|
58
|
+
- `description`, primitive-value `enum`, and numeric `minimum` / `maximum`.
|
|
59
|
+
|
|
60
|
+
Every wire property is required. An originally optional non-nullable property is
|
|
61
|
+
made nullable for Codex, then a `null` placeholder is removed from the completed
|
|
62
|
+
JSON before Dreamux observes the result. Required nullable values remain
|
|
63
|
+
present as `null`.
|
|
64
|
+
|
|
65
|
+
Open objects, optional fields that already accept `null`, tuples, non-null
|
|
66
|
+
unions, composition/reference keywords, unknown keywords, and other unsupported
|
|
67
|
+
constraints fail before `turn/start` with
|
|
68
|
+
`UnsupportedAgentRuntimeFeatureError(feature = "outputSchema")`. The adapter
|
|
69
|
+
does not drop constraints or fall back to unconstrained text.
|
|
70
|
+
|
|
71
|
+
Concurrent submissions may fold into one active Codex turn only when both are
|
|
72
|
+
structured with the same compiled wire schema and restoration plan, or both are
|
|
73
|
+
unstructured. Structured/unstructured mixing and incompatible schemas fail
|
|
74
|
+
before another `turn/start`.
|
|
75
|
+
|
|
76
|
+
Each turn collector owns one notification subscription. It unsubscribes on
|
|
77
|
+
normal completion, terminal failure, explicit disposal, or runtime stop. A
|
|
78
|
+
rejected `turn/start` therefore cannot leave a stale collector observing or
|
|
79
|
+
buffering notifications from a later turn.
|
|
80
|
+
|
|
81
|
+
See
|
|
82
|
+
[Provider Runtime](../../../.agents/domains/provider-runtime.md#codex-portable-output-schema)
|
|
83
|
+
for the complete current lifecycle and failure contract.
|
package/dist/config.d.ts
CHANGED
|
@@ -19,13 +19,10 @@
|
|
|
19
19
|
* `bin` is the dispatcher's Codex binary path; the `CODEX_HOST_CODEX_BIN`
|
|
20
20
|
* environment variable is a host-level override that takes precedence over it
|
|
21
21
|
* (resolved by the codex builtin's `resolveCodexBinPath`).
|
|
22
|
-
* `initialize_timeout_ms` is that
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* commonly auth, network, or model quota), the worker fails that task instead
|
|
27
|
-
* of leaving it `running` forever. It does not affect the dispatcher's own
|
|
28
|
-
* long-lived runtime, only per-task workers.
|
|
22
|
+
* `initialize_timeout_ms` is that dispatcher's handshake timeout.
|
|
23
|
+
* `turn_timeout_ms` is accepted and defaulted by this config reader, but the
|
|
24
|
+
* current `CodexRuntime` does not consume it. It therefore has no runtime
|
|
25
|
+
* effect; documenting that gap must not be confused with wiring a timeout.
|
|
29
26
|
*/
|
|
30
27
|
export interface DispatcherCodexConfig {
|
|
31
28
|
bin: string;
|
|
@@ -37,24 +34,22 @@ export interface DispatcherCodexConfig {
|
|
|
37
34
|
turn_timeout_ms: number;
|
|
38
35
|
}
|
|
39
36
|
/**
|
|
40
|
-
* Default `
|
|
37
|
+
* Default `agents[].config.bin`. The Codex binary path is
|
|
41
38
|
* dispatcher-local; `CODEX_HOST_CODEX_BIN` is a host-level override above it,
|
|
42
39
|
* not the source.
|
|
43
40
|
*/
|
|
44
41
|
export declare const DEFAULT_CODEX_BIN = "codex";
|
|
45
|
-
/** Default `
|
|
42
|
+
/** Default `agents[].config.initialize_timeout_ms` (handshake timeout, ms). */
|
|
46
43
|
export declare const DEFAULT_INITIALIZE_TIMEOUT_MS = 10000;
|
|
47
44
|
/**
|
|
48
|
-
* Default
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* visible outcome (issue #126). Operators override via
|
|
52
|
-
* `dispatchers[].runtime.config.turn_timeout_ms`.
|
|
45
|
+
* Default accepted value for `agents[].config.turn_timeout_ms` (ms). The reader
|
|
46
|
+
* validates and returns it, but `CodexRuntime` currently does not consume it,
|
|
47
|
+
* so changing this value has no runtime effect.
|
|
53
48
|
*/
|
|
54
49
|
export declare const DEFAULT_CODEX_TURN_TIMEOUT_MS = 600000;
|
|
55
|
-
/** Default `
|
|
50
|
+
/** Default `agents[].config.approval_policy` when omitted. */
|
|
56
51
|
export declare const DEFAULT_APPROVAL_POLICY = "never";
|
|
57
|
-
/** Default `
|
|
52
|
+
/** Default `agents[].config.sandbox_mode` when omitted. */
|
|
58
53
|
export declare const DEFAULT_SANDBOX_MODE = "workspace-write";
|
|
59
54
|
export declare const ALLOWED_APPROVAL_POLICIES: Set<string>;
|
|
60
55
|
export declare const ALLOWED_SANDBOX_MODES: Set<string>;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAWH
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAWH;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,UAAU,CAAC;AAEzC,+EAA+E;AAC/E,eAAO,MAAM,6BAA6B,QAAS,CAAC;AAEpD;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,SAAU,CAAC;AAErD,8DAA8D;AAC9D,eAAO,MAAM,uBAAuB,UAAU,CAAC;AAE/C,2DAA2D;AAC3D,eAAO,MAAM,oBAAoB,oBAAoB,CAAC;AAEtD,eAAO,MAAM,yBAAyB,aAKpC,CAAC;AAEH,eAAO,MAAM,qBAAqB,aAIhC,CAAC;AAEH,wBAAgB,4BAA4B,IAAI,qBAAqB,CAUpE;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,qBAAqB,CA0EvB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE;IAChD,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;CAChD,GAAG,qBAAqB,CAOxB"}
|
package/dist/config.js
CHANGED
|
@@ -12,24 +12,22 @@
|
|
|
12
12
|
import { BUILTIN_CODEX_PROVIDER_REF } from './provider-ref.js';
|
|
13
13
|
import { readOptionalString, rejectUnknownKeys, requirePositiveInt, requireStringArray, requireStringRecord, } from '@excitedjs/dreamux-utils';
|
|
14
14
|
/**
|
|
15
|
-
* Default `
|
|
15
|
+
* Default `agents[].config.bin`. The Codex binary path is
|
|
16
16
|
* dispatcher-local; `CODEX_HOST_CODEX_BIN` is a host-level override above it,
|
|
17
17
|
* not the source.
|
|
18
18
|
*/
|
|
19
19
|
export const DEFAULT_CODEX_BIN = 'codex';
|
|
20
|
-
/** Default `
|
|
20
|
+
/** Default `agents[].config.initialize_timeout_ms` (handshake timeout, ms). */
|
|
21
21
|
export const DEFAULT_INITIALIZE_TIMEOUT_MS = 10_000;
|
|
22
22
|
/**
|
|
23
|
-
* Default
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* visible outcome (issue #126). Operators override via
|
|
27
|
-
* `dispatchers[].runtime.config.turn_timeout_ms`.
|
|
23
|
+
* Default accepted value for `agents[].config.turn_timeout_ms` (ms). The reader
|
|
24
|
+
* validates and returns it, but `CodexRuntime` currently does not consume it,
|
|
25
|
+
* so changing this value has no runtime effect.
|
|
28
26
|
*/
|
|
29
27
|
export const DEFAULT_CODEX_TURN_TIMEOUT_MS = 600_000;
|
|
30
|
-
/** Default `
|
|
28
|
+
/** Default `agents[].config.approval_policy` when omitted. */
|
|
31
29
|
export const DEFAULT_APPROVAL_POLICY = 'never';
|
|
32
|
-
/** Default `
|
|
30
|
+
/** Default `agents[].config.sandbox_mode` when omitted. */
|
|
33
31
|
export const DEFAULT_SANDBOX_MODE = 'workspace-write';
|
|
34
32
|
export const ALLOWED_APPROVAL_POLICIES = new Set([
|
|
35
33
|
'never',
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/events.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export interface CollectedTurn {
|
|
|
15
15
|
}
|
|
16
16
|
export interface TurnCollector {
|
|
17
17
|
awaitTurn(turnId?: string): Promise<CollectedTurn>;
|
|
18
|
+
dispose(): void;
|
|
18
19
|
}
|
|
19
20
|
/**
|
|
20
21
|
* One observed Codex notification, redacted to method + ids + item type — never
|
|
@@ -63,7 +64,7 @@ export declare function subscribeTurnCollection(client: CodexWsClient, threadId:
|
|
|
63
64
|
* This is the production Feishu inbound primitive: it intentionally does not
|
|
64
65
|
* wait for `turn/completed`.
|
|
65
66
|
*/
|
|
66
|
-
export declare function submitTurnStart(client: CodexWsClient, threadId: string, prompt: string, cwd: string | null): Promise<TurnStartResponse>;
|
|
67
|
+
export declare function submitTurnStart(client: CodexWsClient, threadId: string, prompt: string, cwd: string | null, outputSchema?: Record<string, unknown>): Promise<TurnStartResponse>;
|
|
67
68
|
/**
|
|
68
69
|
* Send a `turn/start` request and await `turn/completed`.
|
|
69
70
|
* Returns the collected turn, or throws on RPC failure.
|
package/dist/events.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,KAAK,EAEV,UAAU,EAGV,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,KAAK,EAEV,UAAU,EAGV,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACnD,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,2EAA2E;IAC3E,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,uBAAuB;IACtC;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,0EAA0E;IAC1E,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;CAC3C;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,uBAA4B,GACpC,aAAa,CAqKf;AAaD;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACrC,OAAO,CAAC,iBAAiB,CAAC,CAQ5B;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAC3B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,GAAG,IAAI,GACjB,OAAO,CAAC,aAAa,CAAC,CAQxB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAOvE"}
|
package/dist/events.js
CHANGED
|
@@ -24,10 +24,16 @@ export function subscribeTurnCollection(client, threadId, options = {}) {
|
|
|
24
24
|
let firstFailure = null;
|
|
25
25
|
let unscopedFailure = null;
|
|
26
26
|
let closed = false;
|
|
27
|
+
let unsubscribe = () => { };
|
|
27
28
|
let awaiting = null;
|
|
28
29
|
const closeCollector = () => {
|
|
30
|
+
if (closed)
|
|
31
|
+
return;
|
|
29
32
|
closed = true;
|
|
30
33
|
itemsByTurn.clear();
|
|
34
|
+
completedByTurn.clear();
|
|
35
|
+
failuresByTurn.clear();
|
|
36
|
+
unsubscribe();
|
|
31
37
|
};
|
|
32
38
|
const resolveAwaiting = () => {
|
|
33
39
|
if (awaiting === null)
|
|
@@ -67,7 +73,7 @@ export function subscribeTurnCollection(client, threadId, options = {}) {
|
|
|
67
73
|
closeCollector();
|
|
68
74
|
}
|
|
69
75
|
};
|
|
70
|
-
client.onNotification((notif) => {
|
|
76
|
+
unsubscribe = client.onNotification((notif) => {
|
|
71
77
|
const p = (notif.params ?? {});
|
|
72
78
|
const nThreadId = typeof p['threadId'] === 'string' ? p['threadId'] : null;
|
|
73
79
|
const matches = acceptAnyThread || nThreadId === threadId;
|
|
@@ -164,6 +170,13 @@ export function subscribeTurnCollection(client, threadId, options = {}) {
|
|
|
164
170
|
};
|
|
165
171
|
return promise;
|
|
166
172
|
},
|
|
173
|
+
dispose() {
|
|
174
|
+
if (awaiting !== null) {
|
|
175
|
+
awaiting.reject(new Error('codex turn collector disposed'));
|
|
176
|
+
awaiting = null;
|
|
177
|
+
}
|
|
178
|
+
closeCollector();
|
|
179
|
+
},
|
|
167
180
|
};
|
|
168
181
|
}
|
|
169
182
|
function traceTurnId(params) {
|
|
@@ -181,11 +194,16 @@ function traceItemType(params) {
|
|
|
181
194
|
* This is the production Feishu inbound primitive: it intentionally does not
|
|
182
195
|
* wait for `turn/completed`.
|
|
183
196
|
*/
|
|
184
|
-
export async function submitTurnStart(client, threadId, prompt, cwd) {
|
|
197
|
+
export async function submitTurnStart(client, threadId, prompt, cwd, outputSchema) {
|
|
185
198
|
const input = [
|
|
186
199
|
{ type: 'text', text: prompt, text_elements: [] },
|
|
187
200
|
];
|
|
188
|
-
|
|
201
|
+
const params = { threadId, input };
|
|
202
|
+
if (cwd !== null)
|
|
203
|
+
params.cwd = cwd;
|
|
204
|
+
if (outputSchema !== undefined)
|
|
205
|
+
params.outputSchema = outputSchema;
|
|
206
|
+
return client.request('turn/start', params);
|
|
189
207
|
}
|
|
190
208
|
/**
|
|
191
209
|
* Send a `turn/start` request and await `turn/completed`.
|
|
@@ -193,8 +211,13 @@ export async function submitTurnStart(client, threadId, prompt, cwd) {
|
|
|
193
211
|
*/
|
|
194
212
|
export async function runTurn(client, threadId, prompt, cwd) {
|
|
195
213
|
const collector = subscribeTurnCollection(client, threadId);
|
|
196
|
-
|
|
197
|
-
|
|
214
|
+
try {
|
|
215
|
+
const res = await submitTurnStart(client, threadId, prompt, cwd);
|
|
216
|
+
return await collector.awaitTurn(res.turn.id);
|
|
217
|
+
}
|
|
218
|
+
finally {
|
|
219
|
+
collector.dispose();
|
|
220
|
+
}
|
|
198
221
|
}
|
|
199
222
|
/**
|
|
200
223
|
* Extract the final assistant message text from a collected turn.
|
package/dist/events.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface CodexOutputSchemaCodec {
|
|
2
|
+
wireSchema: Record<string, unknown>;
|
|
3
|
+
fingerprint: string;
|
|
4
|
+
restore(text: string): string;
|
|
5
|
+
}
|
|
6
|
+
export declare function compileCodexOutputSchema(schema: Record<string, unknown>): CodexOutputSchemaCodec;
|
|
7
|
+
//# sourceMappingURL=output-schema-codec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output-schema-codec.d.ts","sourceRoot":"","sources":["../src/output-schema-codec.ts"],"names":[],"mappings":"AA0CA,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CAC/B;AA0BD,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,sBAAsB,CA4BxB"}
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { unsupportedFeatureError } from '@excitedjs/dreamux-utils';
|
|
3
|
+
const SUPPORTED_TYPES = new Set([
|
|
4
|
+
'object',
|
|
5
|
+
'array',
|
|
6
|
+
'string',
|
|
7
|
+
'number',
|
|
8
|
+
'integer',
|
|
9
|
+
'boolean',
|
|
10
|
+
'null',
|
|
11
|
+
]);
|
|
12
|
+
const COMMON_KEYWORDS = new Set(['type', 'description', 'enum']);
|
|
13
|
+
const OBJECT_KEYWORDS = new Set([
|
|
14
|
+
...COMMON_KEYWORDS,
|
|
15
|
+
'properties',
|
|
16
|
+
'required',
|
|
17
|
+
'additionalProperties',
|
|
18
|
+
]);
|
|
19
|
+
const ARRAY_KEYWORDS = new Set([...COMMON_KEYWORDS, 'items']);
|
|
20
|
+
const NUMERIC_KEYWORDS = new Set([
|
|
21
|
+
...COMMON_KEYWORDS,
|
|
22
|
+
'minimum',
|
|
23
|
+
'maximum',
|
|
24
|
+
]);
|
|
25
|
+
export function compileCodexOutputSchema(schema) {
|
|
26
|
+
const root = schemaRecord(schema, '$');
|
|
27
|
+
const rootType = schemaType(root['type'], '$.type');
|
|
28
|
+
if (rootType.type !== 'object' || rootType.nullable) {
|
|
29
|
+
fail('$.type', 'root schema must have type "object"');
|
|
30
|
+
}
|
|
31
|
+
const compiled = compileSchema(schema, '$', false);
|
|
32
|
+
const fingerprint = createHash('sha256')
|
|
33
|
+
.update(canonicalJson({
|
|
34
|
+
wireSchema: compiled.wireSchema,
|
|
35
|
+
restorationPlan: compiled.plan,
|
|
36
|
+
}))
|
|
37
|
+
.digest('hex');
|
|
38
|
+
return {
|
|
39
|
+
wireSchema: compiled.wireSchema,
|
|
40
|
+
fingerprint,
|
|
41
|
+
restore(text) {
|
|
42
|
+
let parsed;
|
|
43
|
+
try {
|
|
44
|
+
parsed = JSON.parse(text);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
throw new Error(`codex outputSchema restoration at $: invalid JSON: ${errorMessage(error)}`);
|
|
48
|
+
}
|
|
49
|
+
return JSON.stringify(restoreValue(parsed, compiled.plan, '$'));
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function compileSchema(value, path, optional) {
|
|
54
|
+
const schema = schemaRecord(value, path);
|
|
55
|
+
const { type, nullable } = schemaType(schema['type'], `${path}.type`);
|
|
56
|
+
const enumValues = schemaEnum(schema['enum'], `${path}.enum`);
|
|
57
|
+
if (enumValues !== undefined) {
|
|
58
|
+
validateEnumTypes(enumValues, type, nullable, `${path}.enum`);
|
|
59
|
+
}
|
|
60
|
+
const acceptsNull = type === 'null' ||
|
|
61
|
+
(nullable && (enumValues === undefined || enumValues.includes(null)));
|
|
62
|
+
if (optional && acceptsNull) {
|
|
63
|
+
fail(path, 'optional property already accepts null');
|
|
64
|
+
}
|
|
65
|
+
const allowed = type === 'object'
|
|
66
|
+
? OBJECT_KEYWORDS
|
|
67
|
+
: type === 'array'
|
|
68
|
+
? ARRAY_KEYWORDS
|
|
69
|
+
: type === 'number' || type === 'integer'
|
|
70
|
+
? NUMERIC_KEYWORDS
|
|
71
|
+
: COMMON_KEYWORDS;
|
|
72
|
+
rejectUnknownKeywords(schema, allowed, path);
|
|
73
|
+
const wireSchema = {
|
|
74
|
+
type: type === 'null'
|
|
75
|
+
? type
|
|
76
|
+
: optional || nullable
|
|
77
|
+
? [type, 'null']
|
|
78
|
+
: type,
|
|
79
|
+
};
|
|
80
|
+
if (schema['description'] !== undefined) {
|
|
81
|
+
if (typeof schema['description'] !== 'string') {
|
|
82
|
+
fail(`${path}.description`, 'description must be a string');
|
|
83
|
+
}
|
|
84
|
+
wireSchema['description'] = schema['description'];
|
|
85
|
+
}
|
|
86
|
+
if (enumValues !== undefined) {
|
|
87
|
+
const wireEnum = optional && !enumValues.includes(null)
|
|
88
|
+
? [...enumValues, null]
|
|
89
|
+
: enumValues;
|
|
90
|
+
wireSchema['enum'] = canonicalEnum(wireEnum);
|
|
91
|
+
}
|
|
92
|
+
if (type === 'object') {
|
|
93
|
+
return compileObject(schema, path, wireSchema, acceptsNull);
|
|
94
|
+
}
|
|
95
|
+
if (type === 'array') {
|
|
96
|
+
return compileArray(schema, path, wireSchema, acceptsNull);
|
|
97
|
+
}
|
|
98
|
+
if (type === 'number' || type === 'integer') {
|
|
99
|
+
compileNumericBounds(schema, path, wireSchema);
|
|
100
|
+
}
|
|
101
|
+
return { wireSchema, plan: { kind: 'value' }, acceptsNull };
|
|
102
|
+
}
|
|
103
|
+
function compileObject(schema, path, wireSchema, acceptsNull) {
|
|
104
|
+
if (schema['additionalProperties'] !== false) {
|
|
105
|
+
fail(`${path}.additionalProperties`, 'object schemas must set additionalProperties to false');
|
|
106
|
+
}
|
|
107
|
+
const properties = schemaRecord(schema['properties'], `${path}.properties`);
|
|
108
|
+
const required = requiredProperties(schema['required'], properties, `${path}.required`);
|
|
109
|
+
const propertyEntries = [];
|
|
110
|
+
const planEntries = [];
|
|
111
|
+
const names = Object.keys(properties).sort();
|
|
112
|
+
for (const name of names) {
|
|
113
|
+
const propertyPath = schemaPropertyPath(path, name);
|
|
114
|
+
const optional = !required.has(name);
|
|
115
|
+
const compiled = compileSchema(properties[name], propertyPath, optional);
|
|
116
|
+
propertyEntries.push([name, compiled.wireSchema]);
|
|
117
|
+
planEntries.push([
|
|
118
|
+
name,
|
|
119
|
+
{ omitNull: optional && !compiled.acceptsNull, plan: compiled.plan },
|
|
120
|
+
]);
|
|
121
|
+
}
|
|
122
|
+
wireSchema['properties'] = Object.fromEntries(propertyEntries);
|
|
123
|
+
wireSchema['required'] = names;
|
|
124
|
+
wireSchema['additionalProperties'] = false;
|
|
125
|
+
return {
|
|
126
|
+
wireSchema,
|
|
127
|
+
plan: {
|
|
128
|
+
kind: 'object',
|
|
129
|
+
acceptsNull,
|
|
130
|
+
properties: Object.fromEntries(planEntries),
|
|
131
|
+
},
|
|
132
|
+
acceptsNull,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function compileArray(schema, path, wireSchema, acceptsNull) {
|
|
136
|
+
if (Array.isArray(schema['items'])) {
|
|
137
|
+
fail(`${path}.items`, 'tuple arrays are not supported');
|
|
138
|
+
}
|
|
139
|
+
if (schema['items'] === undefined) {
|
|
140
|
+
fail(`${path}.items`, 'array schemas require one items schema');
|
|
141
|
+
}
|
|
142
|
+
const items = compileSchema(schema['items'], `${path}.items`, false);
|
|
143
|
+
wireSchema['items'] = items.wireSchema;
|
|
144
|
+
return {
|
|
145
|
+
wireSchema,
|
|
146
|
+
plan: { kind: 'array', acceptsNull, items: items.plan },
|
|
147
|
+
acceptsNull,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function compileNumericBounds(schema, path, wireSchema) {
|
|
151
|
+
for (const keyword of ['minimum', 'maximum']) {
|
|
152
|
+
const value = schema[keyword];
|
|
153
|
+
if (value === undefined)
|
|
154
|
+
continue;
|
|
155
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
156
|
+
fail(`${path}.${keyword}`, `${keyword} must be a finite number`);
|
|
157
|
+
}
|
|
158
|
+
wireSchema[keyword] = value;
|
|
159
|
+
}
|
|
160
|
+
if (typeof wireSchema['minimum'] === 'number' &&
|
|
161
|
+
typeof wireSchema['maximum'] === 'number' &&
|
|
162
|
+
wireSchema['minimum'] > wireSchema['maximum']) {
|
|
163
|
+
fail(path, 'minimum must not exceed maximum');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function schemaType(value, path) {
|
|
167
|
+
if (typeof value === 'string') {
|
|
168
|
+
if (!SUPPORTED_TYPES.has(value)) {
|
|
169
|
+
fail(path, `unsupported type ${JSON.stringify(value)}`);
|
|
170
|
+
}
|
|
171
|
+
return { type: value, nullable: value === 'null' };
|
|
172
|
+
}
|
|
173
|
+
if (!Array.isArray(value)) {
|
|
174
|
+
fail(path, 'type must be one supported type or [T, "null"]');
|
|
175
|
+
}
|
|
176
|
+
if (value.length !== 2 ||
|
|
177
|
+
new Set(value).size !== 2 ||
|
|
178
|
+
!value.includes('null')) {
|
|
179
|
+
fail(path, 'only nullable [T, "null"] unions are supported');
|
|
180
|
+
}
|
|
181
|
+
const nonNull = value.find((entry) => entry !== 'null');
|
|
182
|
+
if (typeof nonNull !== 'string' ||
|
|
183
|
+
!SUPPORTED_TYPES.has(nonNull)) {
|
|
184
|
+
fail(path, 'only nullable [T, "null"] unions are supported');
|
|
185
|
+
}
|
|
186
|
+
return { type: nonNull, nullable: true };
|
|
187
|
+
}
|
|
188
|
+
function schemaEnum(value, path) {
|
|
189
|
+
if (value === undefined)
|
|
190
|
+
return undefined;
|
|
191
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
192
|
+
fail(path, 'enum must be a non-empty array of primitive JSON values');
|
|
193
|
+
}
|
|
194
|
+
const values = value.map((entry, index) => {
|
|
195
|
+
if (entry === null ||
|
|
196
|
+
typeof entry === 'string' ||
|
|
197
|
+
typeof entry === 'boolean')
|
|
198
|
+
return entry;
|
|
199
|
+
if (typeof entry === 'number' && Number.isFinite(entry))
|
|
200
|
+
return entry;
|
|
201
|
+
fail(`${path}[${index}]`, 'enum entries must be primitive JSON values');
|
|
202
|
+
});
|
|
203
|
+
const canonical = values.map(canonicalJson);
|
|
204
|
+
if (new Set(canonical).size !== values.length) {
|
|
205
|
+
fail(path, 'enum values must be unique');
|
|
206
|
+
}
|
|
207
|
+
return values;
|
|
208
|
+
}
|
|
209
|
+
function validateEnumTypes(values, type, nullable, path) {
|
|
210
|
+
if (type === 'object' || type === 'array') {
|
|
211
|
+
fail(path, 'enum is supported only on primitive schemas');
|
|
212
|
+
}
|
|
213
|
+
for (const [index, value] of values.entries()) {
|
|
214
|
+
if (value === null && nullable)
|
|
215
|
+
continue;
|
|
216
|
+
const valid = type === 'null'
|
|
217
|
+
? value === null
|
|
218
|
+
: type === 'integer'
|
|
219
|
+
? typeof value === 'number' && Number.isInteger(value)
|
|
220
|
+
: typeof value === type;
|
|
221
|
+
if (!valid) {
|
|
222
|
+
fail(`${path}[${index}]`, `enum value does not match declared type ${JSON.stringify(type)}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function requiredProperties(value, properties, path) {
|
|
227
|
+
if (value === undefined)
|
|
228
|
+
return new Set();
|
|
229
|
+
if (!Array.isArray(value))
|
|
230
|
+
fail(path, 'required must be an array of strings');
|
|
231
|
+
const required = new Set();
|
|
232
|
+
for (const [index, entry] of value.entries()) {
|
|
233
|
+
if (typeof entry !== 'string') {
|
|
234
|
+
fail(`${path}[${index}]`, 'required entries must be strings');
|
|
235
|
+
}
|
|
236
|
+
if (!Object.hasOwn(properties, entry)) {
|
|
237
|
+
fail(`${path}[${index}]`, `unknown required property ${JSON.stringify(entry)}`);
|
|
238
|
+
}
|
|
239
|
+
if (required.has(entry)) {
|
|
240
|
+
fail(`${path}[${index}]`, `duplicate required property ${JSON.stringify(entry)}`);
|
|
241
|
+
}
|
|
242
|
+
required.add(entry);
|
|
243
|
+
}
|
|
244
|
+
return required;
|
|
245
|
+
}
|
|
246
|
+
function rejectUnknownKeywords(schema, allowed, path) {
|
|
247
|
+
for (const keyword of Object.keys(schema)) {
|
|
248
|
+
if (!allowed.has(keyword)) {
|
|
249
|
+
fail(`${path}.${keyword}`, `unsupported keyword ${JSON.stringify(keyword)}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function restoreValue(value, plan, path) {
|
|
254
|
+
if (plan.kind === 'value')
|
|
255
|
+
return value;
|
|
256
|
+
if (value === null && plan.acceptsNull)
|
|
257
|
+
return null;
|
|
258
|
+
if (plan.kind === 'array') {
|
|
259
|
+
if (!Array.isArray(value)) {
|
|
260
|
+
throw new Error(`codex outputSchema restoration at ${path}: expected array`);
|
|
261
|
+
}
|
|
262
|
+
return value.map((entry, index) => restoreValue(entry, plan.items, `${path}[${index}]`));
|
|
263
|
+
}
|
|
264
|
+
if (!isRecord(value)) {
|
|
265
|
+
throw new Error(`codex outputSchema restoration at ${path}: expected object`);
|
|
266
|
+
}
|
|
267
|
+
const restored = { ...value };
|
|
268
|
+
for (const [name, property] of Object.entries(plan.properties)) {
|
|
269
|
+
if (!Object.hasOwn(restored, name))
|
|
270
|
+
continue;
|
|
271
|
+
if (property.omitNull && restored[name] === null) {
|
|
272
|
+
delete restored[name];
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
restored[name] = restoreValue(restored[name], property.plan, valuePropertyPath(path, name));
|
|
276
|
+
}
|
|
277
|
+
return restored;
|
|
278
|
+
}
|
|
279
|
+
function canonicalEnum(values) {
|
|
280
|
+
return [...values].sort((left, right) => canonicalJson(left).localeCompare(canonicalJson(right)));
|
|
281
|
+
}
|
|
282
|
+
function canonicalJson(value) {
|
|
283
|
+
if (Array.isArray(value)) {
|
|
284
|
+
return `[${value.map(canonicalJson).join(',')}]`;
|
|
285
|
+
}
|
|
286
|
+
if (isRecord(value)) {
|
|
287
|
+
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(',')}}`;
|
|
288
|
+
}
|
|
289
|
+
return JSON.stringify(value);
|
|
290
|
+
}
|
|
291
|
+
function schemaRecord(value, path) {
|
|
292
|
+
if (!isRecord(value))
|
|
293
|
+
fail(path, 'schema must be a plain object');
|
|
294
|
+
return value;
|
|
295
|
+
}
|
|
296
|
+
function isRecord(value) {
|
|
297
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
const prototype = Object.getPrototypeOf(value);
|
|
301
|
+
return prototype === Object.prototype || prototype === null;
|
|
302
|
+
}
|
|
303
|
+
function schemaPropertyPath(path, name) {
|
|
304
|
+
return `${path}.properties${pathSegment(name)}`;
|
|
305
|
+
}
|
|
306
|
+
function valuePropertyPath(path, name) {
|
|
307
|
+
return `${path}${pathSegment(name)}`;
|
|
308
|
+
}
|
|
309
|
+
function pathSegment(name) {
|
|
310
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name)
|
|
311
|
+
? `.${name}`
|
|
312
|
+
: `[${JSON.stringify(name)}]`;
|
|
313
|
+
}
|
|
314
|
+
function fail(path, reason) {
|
|
315
|
+
throw unsupportedFeatureError('outputSchema', `codex outputSchema at ${path}: ${reason}`);
|
|
316
|
+
}
|
|
317
|
+
function errorMessage(error) {
|
|
318
|
+
return error instanceof Error ? error.message : String(error);
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=output-schema-codec.js.map
|