@wrenai/genbi 0.0.3 → 0.0.5
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 +65 -3
- package/dist/assets/{echarts-LTFC-ysd.js → echarts-DYM4hjvk.js} +2 -2
- package/dist/assets/index-A_Wrq7Ey.css +1 -0
- package/dist/assets/{index-Bo--QMUN.js → index-DsH129tV.js} +18 -17
- package/dist/index.html +2 -2
- package/dist-server/harness/bundle/schema.d.ts +38 -0
- package/dist-server/harness/bundle/schema.js +18 -10
- package/dist-server/harness/bundle/version.js +1 -1
- package/dist-server/harness/cli-args.d.ts +10 -2
- package/dist-server/harness/cli-args.js +24 -8
- package/dist-server/harness/cli.js +75 -9
- package/dist-server/harness/compile/cache.js +4 -4
- package/dist-server/harness/compile/compose-profile.d.ts +51 -14
- package/dist-server/harness/compile/compose-profile.js +85 -19
- package/dist-server/harness/compile/context-loader.d.ts +56 -0
- package/dist-server/harness/compile/context-loader.js +237 -0
- package/dist-server/harness/compile/errors.d.ts +19 -0
- package/dist-server/harness/compile/errors.js +35 -0
- package/dist-server/harness/compile/index.d.ts +4 -3
- package/dist-server/harness/compile/index.js +4 -3
- package/dist-server/harness/compile/pipeline.d.ts +15 -7
- package/dist-server/harness/compile/pipeline.js +62 -14
- package/dist-server/harness/compile/resolve-binary.d.ts +2 -2
- package/dist-server/harness/compile/resolve-binary.js +13 -3
- package/dist-server/harness/compile/types.d.ts +29 -0
- package/dist-server/harness/compile/warble-identity.d.ts +11 -0
- package/dist-server/harness/compile/warble-identity.js +13 -0
- package/dist-server/harness/components/ai-step.d.ts +4 -0
- package/dist-server/harness/components/ai-step.js +40 -0
- package/dist-server/harness/components/broker.d.ts +60 -0
- package/dist-server/harness/components/broker.js +117 -0
- package/dist-server/harness/components/capability-card.d.ts +98 -0
- package/dist-server/harness/components/capability-card.js +169 -0
- package/dist-server/harness/components/context.d.ts +2 -0
- package/dist-server/harness/components/context.js +30 -0
- package/dist-server/harness/components/display.d.ts +6 -0
- package/dist-server/harness/components/display.js +29 -0
- package/dist-server/harness/components/egress-judge.d.ts +12 -0
- package/dist-server/harness/components/egress-judge.js +27 -0
- package/dist-server/harness/components/egress.d.ts +142 -0
- package/dist-server/harness/components/egress.js +469 -0
- package/dist-server/harness/components/in-process.d.ts +7 -0
- package/dist-server/harness/components/in-process.js +245 -0
- package/dist-server/harness/components/normalize.d.ts +35 -0
- package/dist-server/harness/components/normalize.js +245 -0
- package/dist-server/harness/components/plan.d.ts +31 -0
- package/dist-server/harness/components/plan.js +184 -0
- package/dist-server/harness/components/report.d.ts +207 -0
- package/dist-server/harness/components/report.js +309 -0
- package/dist-server/harness/components/runner.d.ts +193 -0
- package/dist-server/harness/components/runner.js +492 -0
- package/dist-server/harness/components/semantic-guards.d.ts +20 -0
- package/dist-server/harness/components/semantic-guards.js +42 -0
- package/dist-server/harness/components/terminal-json.d.ts +18 -0
- package/dist-server/harness/components/terminal-json.js +82 -0
- package/dist-server/harness/components/usage.d.ts +14 -0
- package/dist-server/harness/components/usage.js +19 -0
- package/dist-server/harness/components/wren-access.d.ts +29 -0
- package/dist-server/harness/components/wren-access.js +233 -0
- package/dist-server/harness/components/zone-dry-run.d.ts +43 -0
- package/dist-server/harness/components/zone-dry-run.js +107 -0
- package/dist-server/harness/components/zone-gate.d.ts +76 -0
- package/dist-server/harness/components/zone-gate.js +144 -0
- package/dist-server/harness/events/index.d.ts +1 -1
- package/dist-server/harness/events/types.d.ts +52 -0
- package/dist-server/harness/index.d.ts +9 -2
- package/dist-server/harness/index.js +5 -1
- package/dist-server/harness/loop/executor.d.ts +1 -0
- package/dist-server/harness/loop/executor.js +37 -15
- package/dist-server/harness/npm-package-resolve.d.ts +2 -0
- package/dist-server/harness/npm-package-resolve.js +16 -4
- package/dist-server/harness/providers/adapters/openai-compatible.d.ts +13 -0
- package/dist-server/harness/providers/adapters/openai-compatible.js +17 -0
- package/dist-server/harness/providers/adapters/openai.d.ts +7 -0
- package/dist-server/harness/providers/adapters/openai.js +6 -0
- package/dist-server/harness/providers/adapters/pi-ai.d.ts +48 -0
- package/dist-server/harness/providers/adapters/pi-ai.js +518 -0
- package/dist-server/harness/providers/binding.d.ts +45 -4
- package/dist-server/harness/providers/binding.js +44 -8
- package/dist-server/harness/providers/index.d.ts +9 -3
- package/dist-server/harness/providers/index.js +10 -3
- package/dist-server/harness/providers/zone.d.ts +96 -0
- package/dist-server/harness/providers/zone.js +112 -0
- package/dist-server/harness/render/answering-query.d.ts +29 -0
- package/dist-server/harness/render/answering-query.js +62 -0
- package/dist-server/harness/render/envelope.d.ts +6 -0
- package/dist-server/harness/render/envelope.js +10 -3
- package/dist-server/harness/route/adapter-spec.d.ts +8 -9
- package/dist-server/harness/route/adapter-spec.js +13 -14
- package/dist-server/harness/route/codex-ask-events.js +2 -1
- package/dist-server/harness/route/codex-ask.d.ts +4 -0
- package/dist-server/harness/route/codex-ask.js +69 -30
- package/dist-server/harness/route/codex-host-query.d.ts +52 -0
- package/dist-server/harness/route/codex-host-query.js +191 -0
- package/dist-server/harness/route/codex-local-manifest.d.ts +9 -1
- package/dist-server/harness/route/codex-local-manifest.js +96 -15
- package/dist-server/harness/route/codex-wren-proxy.d.ts +33 -0
- package/dist-server/harness/route/codex-wren-proxy.js +227 -0
- package/dist-server/harness/route/describe.js +45 -6
- package/dist-server/harness/route/in-process.d.ts +22 -1
- package/dist-server/harness/route/in-process.js +54 -4
- package/dist-server/harness/route/route.js +5 -2
- package/dist-server/harness/route/types.d.ts +30 -1
- package/dist-server/harness/session/run.js +30 -10
- package/dist-server/harness/setup/runner.d.ts +2 -0
- package/dist-server/harness/setup/runner.js +38 -17
- package/dist-server/harness/setup/yaml-scalar.d.ts +23 -0
- package/dist-server/harness/setup/yaml-scalar.js +62 -0
- package/dist-server/server/adopt.js +1 -17
- package/dist-server/server/app.d.ts +1 -0
- package/dist-server/server/app.js +163 -14
- package/dist-server/server/auth-choice.d.ts +13 -1
- package/dist-server/server/auth-choice.js +66 -1
- package/dist-server/server/bin.js +197 -26
- package/dist-server/server/codex-local-grounding.d.ts +18 -0
- package/dist-server/server/codex-local-grounding.js +92 -0
- package/dist-server/server/codex-native-session.d.ts +25 -0
- package/dist-server/server/codex-native-session.js +1 -0
- package/dist-server/server/codex-runtime-composition.d.ts +34 -0
- package/dist-server/server/codex-runtime-composition.js +250 -0
- package/dist-server/server/codex-structured-ask.d.ts +23 -0
- package/dist-server/server/codex-structured-ask.js +102 -0
- package/dist-server/server/conn-config.js +4 -16
- package/dist-server/server/conversation-socket.d.ts +16 -0
- package/dist-server/server/conversation-socket.js +65 -0
- package/dist-server/server/db.d.ts +46 -0
- package/dist-server/server/db.js +88 -9
- package/dist-server/server/env-detect.d.ts +6 -0
- package/dist-server/server/env-detect.js +7 -0
- package/dist-server/server/fold.d.ts +22 -4
- package/dist-server/server/fold.js +37 -5
- package/dist-server/server/harness.d.ts +2 -2
- package/dist-server/server/harness.js +33 -7
- package/dist-server/server/interactive-terminal.d.ts +10 -6
- package/dist-server/server/interactive-terminal.js +33 -8
- package/dist-server/server/managed-wren-runtime.d.ts +116 -0
- package/dist-server/server/managed-wren-runtime.js +670 -0
- package/dist-server/server/native-artifacts.d.ts +23 -7
- package/dist-server/server/native-artifacts.js +43 -12
- package/dist-server/server/native-component-context.d.ts +19 -0
- package/dist-server/server/native-component-context.js +76 -0
- package/dist-server/server/native-component-preparation.d.ts +20 -0
- package/dist-server/server/native-component-preparation.js +129 -0
- package/dist-server/server/native-component-runtime.d.ts +36 -0
- package/dist-server/server/native-component-runtime.js +92 -0
- package/dist-server/server/native-components.d.ts +84 -0
- package/dist-server/server/native-components.js +160 -0
- package/dist-server/server/native-dispatch-process.d.ts +8 -0
- package/dist-server/server/native-dispatch-process.js +65 -0
- package/dist-server/server/native-runtime-spec.d.ts +89 -0
- package/dist-server/server/native-runtime-spec.js +169 -0
- package/dist-server/server/native-sessions.d.ts +172 -19
- package/dist-server/server/native-sessions.js +870 -251
- package/dist-server/server/native-shutdown.d.ts +6 -0
- package/dist-server/server/native-shutdown.js +28 -0
- package/dist-server/server/native-wren-home.d.ts +18 -0
- package/dist-server/server/native-wren-home.js +262 -0
- package/dist-server/server/node-pty-host.d.ts +2 -1
- package/dist-server/server/node-pty-host.js +3 -2
- package/dist-server/server/profile-registry.d.ts +139 -0
- package/dist-server/server/profile-registry.js +620 -0
- package/dist-server/server/runtime-binding.d.ts +4 -1
- package/dist-server/server/runtime-binding.js +50 -2
- package/dist-server/server/runtime-host/claude-component-step.d.ts +25 -0
- package/dist-server/server/runtime-host/claude-component-step.js +186 -0
- package/dist-server/server/runtime-host/codex-app-server.d.ts +75 -0
- package/dist-server/server/runtime-host/codex-app-server.js +239 -0
- package/dist-server/server/runtime-host/codex-compatibility.d.ts +110 -0
- package/dist-server/server/runtime-host/codex-compatibility.js +162 -0
- package/dist-server/server/runtime-host/codex-component-step.d.ts +19 -0
- package/dist-server/server/runtime-host/codex-component-step.js +308 -0
- package/dist-server/server/runtime-host/codex-conversation.d.ts +109 -0
- package/dist-server/server/runtime-host/codex-conversation.js +295 -0
- package/dist-server/server/runtime-host/codex-direct-tools.d.ts +23 -0
- package/dist-server/server/runtime-host/codex-direct-tools.js +59 -0
- package/dist-server/server/runtime-host/codex-events.d.ts +647 -0
- package/dist-server/server/runtime-host/codex-events.js +66 -0
- package/dist-server/server/runtime-host/codex-policy.d.ts +16 -0
- package/dist-server/server/runtime-host/codex-policy.js +151 -0
- package/dist-server/server/runtime-host/codex-process.d.ts +8 -0
- package/dist-server/server/runtime-host/codex-process.js +96 -0
- package/dist-server/server/runtime-host/codex-rpc.d.ts +47 -0
- package/dist-server/server/runtime-host/codex-rpc.js +182 -0
- package/dist-server/server/runtime-host/codex-session.d.ts +74 -0
- package/dist-server/server/runtime-host/codex-session.js +492 -0
- package/dist-server/server/runtime-host/codex-terminal-protocol.d.ts +35 -0
- package/dist-server/server/runtime-host/codex-terminal-protocol.js +243 -0
- package/dist-server/server/runtime-host/codex-terminal.d.ts +16 -0
- package/dist-server/server/runtime-host/codex-terminal.js +120 -0
- package/dist-server/server/runtime-host/index.d.ts +5 -0
- package/dist-server/server/runtime-host/index.js +3 -0
- package/dist-server/server/runtime-host/local.d.ts +29 -0
- package/dist-server/server/runtime-host/local.js +90 -0
- package/dist-server/server/runtime-host/policy.d.ts +8 -0
- package/dist-server/server/runtime-host/policy.js +78 -0
- package/dist-server/server/runtime-host/types.d.ts +52 -0
- package/dist-server/server/runtime-host/types.js +62 -0
- package/dist-server/server/structured-query-evidence.d.ts +7 -0
- package/dist-server/server/structured-query-evidence.js +47 -0
- package/dist-server/server/structured-runtime.d.ts +52 -0
- package/dist-server/server/structured-runtime.js +130 -0
- package/dist-server/server/structured-scope.d.ts +4 -0
- package/dist-server/server/structured-scope.js +12 -0
- package/dist-server/server/turn.d.ts +6 -1
- package/dist-server/server/turn.js +82 -25
- package/dist-server/server/wire-types.d.ts +67 -3
- package/dist-server/server/wren-profiles.js +1 -1
- package/managed-wren/README.md +60 -0
- package/managed-wren/dependency-wheels.json +282 -0
- package/managed-wren/manifest.json +373 -0
- package/managed-wren/release-inputs.json +45 -0
- package/managed-wren/runtime-tree.cjs +115 -0
- package/managed-wren/source-inputs.json +40 -0
- package/package.json +15 -6
- package/profiles/genbi-default/context/binding.yml +17 -7
- package/profiles/genbi-default/context/context.json +146 -0
- package/profiles/genbi-default/ir.golden.json +39 -43
- package/profiles/genbi-default/profile.yml +31 -0
- package/profiles/genbi-enrich-context/context/binding.yml +14 -3
- package/profiles/genbi-enrich-context/context/context.json +146 -0
- package/profiles/genbi-enrich-context/ir.golden.json +4 -5
- package/profiles/genbi-monitor/context/binding.yml +13 -5
- package/profiles/genbi-monitor/context/context.json +146 -0
- package/profiles/genbi-monitor/ir.golden.json +13 -7
- package/profiles/genbi-report/context/binding.yml +19 -0
- package/profiles/genbi-report/context/context.json +223 -0
- package/profiles/genbi-report/ir.golden.json +328 -0
- package/profiles/genbi-report/profile.yml +38 -0
- package/profiles/genbi-setup/ir.golden.json +3 -1
- package/dist/assets/index-Xs4q7pNo.css +0 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { RuntimeBackendDiagnostic, RuntimeBackendReadiness } from "./types.js";
|
|
3
|
+
export declare const CODEX_BASELINE_VERSION = "0.156.1";
|
|
4
|
+
export declare const CODEX_REQUIRED_CONTRACTS: readonly ["initialize", "config/read", "thread/start", "turn/start", "turn/interrupt", "permissionProfile/list", "thread/start.permissions", "turn/start.permissions", "command/exec.permissionProfile", "command/exec", "command/exec/write", "command/exec/resize", "command/exec/terminate", "protected_read", "shared_temp_isolation", "network_deny", "timeout_cleanup", "connection_cleanup", "account/read", "thread/start.dynamicTools", "item/tool/call", "component_step_isolation"];
|
|
5
|
+
export declare const codexCertificationSchema: z.ZodObject<{
|
|
6
|
+
state: z.ZodLiteral<"certified_row">;
|
|
7
|
+
platform: z.ZodLiteral<"darwin-arm64">;
|
|
8
|
+
version: z.ZodLiteral<"0.156.1">;
|
|
9
|
+
executableSha256: z.ZodString;
|
|
10
|
+
source: z.ZodString;
|
|
11
|
+
protocolSha256: z.ZodString;
|
|
12
|
+
executionScope: z.ZodObject<{
|
|
13
|
+
models: z.ZodArray<z.ZodString>;
|
|
14
|
+
entries: z.ZodArray<z.ZodEnum<{
|
|
15
|
+
answer_query: "answer_query";
|
|
16
|
+
generate_dashboard: "generate_dashboard";
|
|
17
|
+
}>>;
|
|
18
|
+
}, z.core.$strict>;
|
|
19
|
+
contracts: z.ZodArray<z.ZodEnum<{
|
|
20
|
+
"account/read": "account/read";
|
|
21
|
+
"command/exec": "command/exec";
|
|
22
|
+
"command/exec.permissionProfile": "command/exec.permissionProfile";
|
|
23
|
+
"command/exec/resize": "command/exec/resize";
|
|
24
|
+
"command/exec/terminate": "command/exec/terminate";
|
|
25
|
+
"command/exec/write": "command/exec/write";
|
|
26
|
+
component_step_isolation: "component_step_isolation";
|
|
27
|
+
"config/read": "config/read";
|
|
28
|
+
connection_cleanup: "connection_cleanup";
|
|
29
|
+
initialize: "initialize";
|
|
30
|
+
"item/tool/call": "item/tool/call";
|
|
31
|
+
network_deny: "network_deny";
|
|
32
|
+
"permissionProfile/list": "permissionProfile/list";
|
|
33
|
+
protected_read: "protected_read";
|
|
34
|
+
shared_temp_isolation: "shared_temp_isolation";
|
|
35
|
+
"thread/start": "thread/start";
|
|
36
|
+
"thread/start.dynamicTools": "thread/start.dynamicTools";
|
|
37
|
+
"thread/start.permissions": "thread/start.permissions";
|
|
38
|
+
timeout_cleanup: "timeout_cleanup";
|
|
39
|
+
"turn/interrupt": "turn/interrupt";
|
|
40
|
+
"turn/start": "turn/start";
|
|
41
|
+
"turn/start.permissions": "turn/start.permissions";
|
|
42
|
+
}>>;
|
|
43
|
+
terminal: z.ZodOptional<z.ZodObject<{
|
|
44
|
+
transport: z.ZodLiteral<"remote-tui-v1">;
|
|
45
|
+
deterministicProbesSha256: z.ZodString;
|
|
46
|
+
packedAcceptanceSha256: z.ZodString;
|
|
47
|
+
releaseApprovalSha256: z.ZodString;
|
|
48
|
+
}, z.core.$strict>>;
|
|
49
|
+
evidence: z.ZodObject<{
|
|
50
|
+
deterministicProbesSha256: z.ZodString;
|
|
51
|
+
packedAcceptanceSha256: z.ZodString;
|
|
52
|
+
releaseApprovalSha256: z.ZodString;
|
|
53
|
+
}, z.core.$strict>;
|
|
54
|
+
dependencies: z.ZodObject<{
|
|
55
|
+
warble: z.ZodString;
|
|
56
|
+
ir: z.ZodString;
|
|
57
|
+
"context-loader": z.ZodString;
|
|
58
|
+
}, z.core.$strict>;
|
|
59
|
+
}, z.core.$strict>;
|
|
60
|
+
export type CodexCertification = z.infer<typeof codexCertificationSchema>;
|
|
61
|
+
export declare const CODEX_CERTIFIED_ROWS: readonly CodexCertification[];
|
|
62
|
+
declare const CODEX_DEPENDENCY_PACKAGES: {
|
|
63
|
+
readonly "@warble/cli": "warble";
|
|
64
|
+
readonly "@warble/codex-local": "warble";
|
|
65
|
+
readonly "@warble/claude-agent-sdk": "warble";
|
|
66
|
+
readonly "@warble/ir-spec": "ir";
|
|
67
|
+
readonly "@wrenai/context-loader": "context-loader";
|
|
68
|
+
};
|
|
69
|
+
export type CodexDependencyPackage = keyof typeof CODEX_DEPENDENCY_PACKAGES;
|
|
70
|
+
export type CodexInstalledDependencies = Readonly<Partial<Record<CodexDependencyPackage, string | undefined>>>;
|
|
71
|
+
export interface CodexDependencyReaders {
|
|
72
|
+
/** Manifest path, or undefined only when Node cannot resolve the package at all. */
|
|
73
|
+
readonly resolve?: (name: CodexDependencyPackage) => string | undefined;
|
|
74
|
+
readonly read?: (file: string) => string;
|
|
75
|
+
readonly declared?: (name: CodexDependencyPackage) => string | undefined;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The installed package manifests are authoritative: what Node resolves is what runs, and a
|
|
79
|
+
* consumer's overrides can make it differ from this package's declared pin. Every npm package
|
|
80
|
+
* ships its own package.json and all of these resolve `<name>/package.json`, so a packed install
|
|
81
|
+
* can read them. This package's declared exact pin is the fallback only when a package cannot be
|
|
82
|
+
* resolved at all; a resolved manifest that cannot be read or carries no version is "unreadable"
|
|
83
|
+
* and therefore drifts, as does a dependency found in neither place.
|
|
84
|
+
*/
|
|
85
|
+
export declare function installedCodexDependencies({ resolve, read, declared, }?: CodexDependencyReaders): CodexInstalledDependencies;
|
|
86
|
+
/** Each entry names one drifted package as `name: certified X, installed Y`. */
|
|
87
|
+
export declare function codexDependencyDrift(certified: CodexCertification["dependencies"], installed: CodexInstalledDependencies): readonly string[];
|
|
88
|
+
/** Host-only diagnostic; `drift` details `codex_dependencies_drifted` and never enters readiness text. */
|
|
89
|
+
export type CodexIdentityDiagnostic = RuntimeBackendDiagnostic & {
|
|
90
|
+
readonly drift?: readonly string[];
|
|
91
|
+
};
|
|
92
|
+
export type CodexIdentityVerdict = {
|
|
93
|
+
readonly readiness: RuntimeBackendReadiness<"codex-app-server">;
|
|
94
|
+
readonly diagnostic: CodexIdentityDiagnostic;
|
|
95
|
+
};
|
|
96
|
+
export interface CodexObservedIdentity {
|
|
97
|
+
readonly platform: string;
|
|
98
|
+
readonly versionOutput: string;
|
|
99
|
+
readonly executableSha256: string;
|
|
100
|
+
readonly source: string;
|
|
101
|
+
readonly protocolSha256: string;
|
|
102
|
+
readonly contracts: readonly string[];
|
|
103
|
+
}
|
|
104
|
+
/** Pure comparison for release verification; only the packaged rows grant execution. */
|
|
105
|
+
export declare function evaluateCodexIdentity(observed: CodexObservedIdentity, rows?: readonly unknown[], installed?: CodexInstalledDependencies): CodexIdentityVerdict;
|
|
106
|
+
/** Application admission is narrower than the vendor protocol capability probe. */
|
|
107
|
+
export declare function isCodexExecutionCertified(source: string, executableSha256: string, models: readonly string[], entry: string, rows?: readonly unknown[]): boolean;
|
|
108
|
+
/** A driver certification alone never admits the remote CLI renderer. */
|
|
109
|
+
export declare function isCodexTerminalCertified(source: string, executableSha256: string, models: readonly string[], entry: string, rows?: readonly unknown[]): boolean;
|
|
110
|
+
export {};
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { runtimeNotReady, runtimeReady } from "./policy.js";
|
|
7
|
+
export const CODEX_BASELINE_VERSION = "0.156.1";
|
|
8
|
+
export const CODEX_REQUIRED_CONTRACTS = [
|
|
9
|
+
"initialize", "config/read", "thread/start", "turn/start", "turn/interrupt",
|
|
10
|
+
"permissionProfile/list", "thread/start.permissions", "turn/start.permissions", "command/exec.permissionProfile",
|
|
11
|
+
"command/exec", "command/exec/write", "command/exec/resize", "command/exec/terminate",
|
|
12
|
+
"protected_read", "shared_temp_isolation", "network_deny", "timeout_cleanup", "connection_cleanup",
|
|
13
|
+
"account/read", "thread/start.dynamicTools", "item/tool/call", "component_step_isolation",
|
|
14
|
+
];
|
|
15
|
+
const digest = z.string().regex(/^[a-f0-9]{64}$/);
|
|
16
|
+
const exactVersion = z.string().regex(/^[0-9]+\.[0-9]+\.[0-9]+$/);
|
|
17
|
+
export const codexCertificationSchema = z.object({
|
|
18
|
+
state: z.literal("certified_row"),
|
|
19
|
+
platform: z.literal("darwin-arm64"),
|
|
20
|
+
version: z.literal(CODEX_BASELINE_VERSION),
|
|
21
|
+
executableSha256: digest,
|
|
22
|
+
source: z.string().url().refine((value) => value.startsWith("https://")),
|
|
23
|
+
protocolSha256: digest,
|
|
24
|
+
executionScope: z.object({ models: z.array(z.string().min(1)).min(1), entries: z.array(z.enum(["answer_query", "generate_dashboard"])).min(1) }).strict(),
|
|
25
|
+
contracts: z.array(z.enum(CODEX_REQUIRED_CONTRACTS)).refine((values) => values.length === CODEX_REQUIRED_CONTRACTS.length && new Set(values).size === values.length),
|
|
26
|
+
terminal: z.object({
|
|
27
|
+
transport: z.literal("remote-tui-v1"),
|
|
28
|
+
deterministicProbesSha256: digest,
|
|
29
|
+
packedAcceptanceSha256: digest,
|
|
30
|
+
releaseApprovalSha256: digest,
|
|
31
|
+
}).strict().optional(),
|
|
32
|
+
evidence: z.object({
|
|
33
|
+
deterministicProbesSha256: digest,
|
|
34
|
+
packedAcceptanceSha256: digest,
|
|
35
|
+
releaseApprovalSha256: digest,
|
|
36
|
+
}).strict(),
|
|
37
|
+
/** The component versions the acceptance records were produced with; drift denies the row. */
|
|
38
|
+
dependencies: z.object({ warble: exactVersion, ir: exactVersion, "context-loader": exactVersion }).strict(),
|
|
39
|
+
}).strict();
|
|
40
|
+
// Tested baseline evidence is not a production execution grant. Release
|
|
41
|
+
// engineering must add an exact reviewed row, never a minimum-version range.
|
|
42
|
+
export const CODEX_CERTIFIED_ROWS = Object.freeze([
|
|
43
|
+
{
|
|
44
|
+
"state": "certified_row",
|
|
45
|
+
"platform": "darwin-arm64",
|
|
46
|
+
"version": "0.156.1",
|
|
47
|
+
"executableSha256": "0196e89fe5a7598f816ee54232c3d7c26d75e502ab5cfe2c9240e81d90f7255a",
|
|
48
|
+
"source": "https://registry.npmjs.org/@openai/codex/-/codex-0.156.1-darwin-arm64.tgz",
|
|
49
|
+
"protocolSha256": "655adafa0ccea3d84f30bcbdc74e201fa14511c51e08d0cd024a0280daa8bc60",
|
|
50
|
+
"executionScope": { "models": ["gpt-5.5"], "entries": ["answer_query"] },
|
|
51
|
+
"contracts": [...CODEX_REQUIRED_CONTRACTS],
|
|
52
|
+
"terminal": { "transport": "remote-tui-v1", "deterministicProbesSha256": "9abc4615a9a6020d8d0a2efbeaf36306a48cf3675020e3d43039c6b3505be60f", "packedAcceptanceSha256": "e3a8080db623e4695fba916c1ba4b0da53559ada529de13ba594da7ab5350f71", "releaseApprovalSha256": "322145f63432c3c2751877f30bfc059e7af14af93818c176d50f99182546b0aa" },
|
|
53
|
+
"evidence": { "deterministicProbesSha256": "5ad42e18f831e1688bc76665224c627b3cb25919383717ade7d7107548e1ce90", "packedAcceptanceSha256": "d15692acec5557e41e5b4eed5ced697d5fed5c2aaf8f0c231ac7afca503f7ca0", "releaseApprovalSha256": "c9eb86e98e18fd5ebe6f3f21865facda6bf8b7beb4f2c6f200db9611dbecf88f" },
|
|
54
|
+
"dependencies": { "warble": "0.15.2", "ir": "0.8.0", "context-loader": "0.1.1" }
|
|
55
|
+
}
|
|
56
|
+
]);
|
|
57
|
+
const CODEX_DEPENDENCY_PACKAGES = {
|
|
58
|
+
"@warble/cli": "warble",
|
|
59
|
+
"@warble/codex-local": "warble",
|
|
60
|
+
"@warble/claude-agent-sdk": "warble",
|
|
61
|
+
"@warble/ir-spec": "ir",
|
|
62
|
+
"@wrenai/context-loader": "context-loader",
|
|
63
|
+
};
|
|
64
|
+
function packageRoot() {
|
|
65
|
+
const server = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
66
|
+
const parent = path.resolve(server, "..");
|
|
67
|
+
return path.basename(parent) === "dist-server" ? path.resolve(parent, "..") : parent;
|
|
68
|
+
}
|
|
69
|
+
function declaredPin(name) {
|
|
70
|
+
try {
|
|
71
|
+
const value = JSON.parse(readFileSync(path.join(packageRoot(), "package.json"), "utf8")).dependencies?.[name];
|
|
72
|
+
return typeof value === "string" ? value : undefined;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The installed package manifests are authoritative: what Node resolves is what runs, and a
|
|
80
|
+
* consumer's overrides can make it differ from this package's declared pin. Every npm package
|
|
81
|
+
* ships its own package.json and all of these resolve `<name>/package.json`, so a packed install
|
|
82
|
+
* can read them. This package's declared exact pin is the fallback only when a package cannot be
|
|
83
|
+
* resolved at all; a resolved manifest that cannot be read or carries no version is "unreadable"
|
|
84
|
+
* and therefore drifts, as does a dependency found in neither place.
|
|
85
|
+
*/
|
|
86
|
+
export function installedCodexDependencies({ resolve = (name) => { try {
|
|
87
|
+
return createRequire(import.meta.url).resolve(`${name}/package.json`);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return undefined;
|
|
91
|
+
} }, read = (file) => readFileSync(file, "utf8"), declared = declaredPin, } = {}) {
|
|
92
|
+
const installedVersion = (name) => {
|
|
93
|
+
const manifest = resolve(name);
|
|
94
|
+
if (manifest === undefined)
|
|
95
|
+
return declared(name);
|
|
96
|
+
try {
|
|
97
|
+
const version = JSON.parse(read(manifest)).version;
|
|
98
|
+
return typeof version === "string" ? version : "unreadable";
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return "unreadable";
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
return Object.fromEntries(Object.keys(CODEX_DEPENDENCY_PACKAGES)
|
|
105
|
+
.map((name) => [name, installedVersion(name)]));
|
|
106
|
+
}
|
|
107
|
+
/** Each entry names one drifted package as `name: certified X, installed Y`. */
|
|
108
|
+
export function codexDependencyDrift(certified, installed) {
|
|
109
|
+
return Object.entries(CODEX_DEPENDENCY_PACKAGES)
|
|
110
|
+
.filter(([name, key]) => installed[name] !== certified[key])
|
|
111
|
+
.map(([name, key]) => `${name}: certified ${certified[key]}, installed ${installed[name] ?? "unresolved"}`);
|
|
112
|
+
}
|
|
113
|
+
/** Pure comparison for release verification; only the packaged rows grant execution. */
|
|
114
|
+
export function evaluateCodexIdentity(observed, rows = CODEX_CERTIFIED_ROWS, installed = installedCodexDependencies()) {
|
|
115
|
+
const deny = (code, phase) => ({
|
|
116
|
+
readiness: runtimeNotReady("codex-app-server", "incompatible", code), diagnostic: { phase },
|
|
117
|
+
});
|
|
118
|
+
if (observed.platform !== "darwin-arm64")
|
|
119
|
+
return deny("runtime_platform_unsupported", "platform");
|
|
120
|
+
const match = /^codex-cli ([0-9]+\.[0-9]+\.[0-9]+)\r?\n?$/.exec(observed.versionOutput);
|
|
121
|
+
if (!match)
|
|
122
|
+
return deny("codex_cli_version_malformed", "version");
|
|
123
|
+
if (match[1] !== CODEX_BASELINE_VERSION)
|
|
124
|
+
return deny("codex_cli_version_unsupported", "version");
|
|
125
|
+
const valid = rows.map((row) => codexCertificationSchema.safeParse(row)).filter((row) => row.success).map((row) => row.data);
|
|
126
|
+
const row = valid.find((candidate) => candidate.executableSha256 === observed.executableSha256 && candidate.source === observed.source);
|
|
127
|
+
if (!row)
|
|
128
|
+
return deny("codex_identity_uncertified", "identity");
|
|
129
|
+
if (row.protocolSha256 !== observed.protocolSha256)
|
|
130
|
+
return deny("codex_app_server_protocol_incompatible", "capability");
|
|
131
|
+
if (CODEX_REQUIRED_CONTRACTS.some((name) => !observed.contracts.includes(name))) {
|
|
132
|
+
return deny("codex_sandbox_policy_unavailable", "capability");
|
|
133
|
+
}
|
|
134
|
+
// The row's evidence was accepted with exact component versions; a matching binary running
|
|
135
|
+
// other components is not what was certified, so it stays denied until re-certification.
|
|
136
|
+
const drift = codexDependencyDrift(row.dependencies, installed);
|
|
137
|
+
if (drift.length > 0) {
|
|
138
|
+
const denied = deny("codex_dependencies_drifted", "identity");
|
|
139
|
+
return { ...denied, diagnostic: { ...denied.diagnostic, drift } };
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
readiness: runtimeReady(row.version, ["app_server_rpc", "sandbox_policy", "filesystem_isolation", "network_isolation", "pty", "terminal_resize", "terminal_terminate"]),
|
|
143
|
+
diagnostic: { phase: "capability", observedVersion: row.version },
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/** Application admission is narrower than the vendor protocol capability probe. */
|
|
147
|
+
export function isCodexExecutionCertified(source, executableSha256, models, entry, rows = CODEX_CERTIFIED_ROWS) {
|
|
148
|
+
return models.length > 0 && rows.some((value) => {
|
|
149
|
+
const row = codexCertificationSchema.safeParse(value);
|
|
150
|
+
return row.success && row.data.source === source && row.data.executableSha256 === executableSha256
|
|
151
|
+
&& row.data.executionScope.entries.some((allowed) => allowed === entry)
|
|
152
|
+
&& models.every((model) => row.data.executionScope.models.includes(model));
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
/** A driver certification alone never admits the remote CLI renderer. */
|
|
156
|
+
export function isCodexTerminalCertified(source, executableSha256, models, entry, rows = CODEX_CERTIFIED_ROWS) {
|
|
157
|
+
return rows.some((value) => {
|
|
158
|
+
const row = codexCertificationSchema.safeParse(value);
|
|
159
|
+
return row.success && row.data.terminal?.transport === "remote-tui-v1"
|
|
160
|
+
&& isCodexExecutionCertified(source, executableSha256, models, entry, [row.data]);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { StepRun, StepResponse } from "../../harness/components/runner.js";
|
|
2
|
+
import { type RpcTransport } from "./codex-rpc.js";
|
|
3
|
+
/** Internal driver input from a certified provisioner, never browser configuration. */
|
|
4
|
+
export interface CodexComponentPolicy {
|
|
5
|
+
readonly cwd: string;
|
|
6
|
+
readonly codexHome: string;
|
|
7
|
+
readonly permissionProfile: string;
|
|
8
|
+
readonly model: string;
|
|
9
|
+
readonly accountEmail: string;
|
|
10
|
+
readonly configuration: Readonly<Record<string, unknown>>;
|
|
11
|
+
/** Revalidates approved account, exact executable, environment and generation. */
|
|
12
|
+
assertCurrent(): void;
|
|
13
|
+
/** Cheap revocation check for passive events; full integrity is still checked at every effect boundary. */
|
|
14
|
+
assertLive?(): void;
|
|
15
|
+
}
|
|
16
|
+
/** Explicit feature denylist for the reviewed vendor baseline; new enabled defaults refuse. */
|
|
17
|
+
export declare function codexComponentConfiguration(profile: string): Readonly<Record<string, unknown>>;
|
|
18
|
+
/** Fresh connection/thread per step. No spawn, activation, command RPC or provider fallback. */
|
|
19
|
+
export declare function runCodexComponentStep(transport: RpcTransport, approved: CodexComponentPolicy, run: StepRun): Promise<StepResponse>;
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from "node:util";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { CODEX_BASELINE_VERSION } from "./codex-compatibility.js";
|
|
4
|
+
import { codexAccountUpdatedSchema, codexDisabledCodeModeWarningSchema, codexRateLimitsUpdatedSchema } from "./codex-events.js";
|
|
5
|
+
import { CodexRpcClient, CodexRpcError, object } from "./codex-rpc.js";
|
|
6
|
+
const id = z.string().min(1).max(256);
|
|
7
|
+
const callSchema = z.object({ threadId: id, turnId: id, callId: id, tool: id, arguments: z.unknown(), namespace: z.null().optional() }).strict();
|
|
8
|
+
const turnSchema = z.object({ id, status: z.enum(["inProgress", "completed", "failed", "interrupted"]), items: z.array(z.unknown()).max(512), itemsView: z.enum(["full", "notLoaded", "summary"]).default("full") })
|
|
9
|
+
.refine((turn) => turn.itemsView !== "notLoaded" || turn.items.length === 0);
|
|
10
|
+
const threadSchema = z.object({ id, cwd: z.string(), cliVersion: z.literal(CODEX_BASELINE_VERSION), ephemeral: z.literal(true) });
|
|
11
|
+
function deny() { throw new CodexRpcError("protocol"); }
|
|
12
|
+
function parse(schema, value) { const result = schema.safeParse(value); return result.success ? result.data : deny(); }
|
|
13
|
+
function freeze(value) {
|
|
14
|
+
if (value && typeof value === "object") {
|
|
15
|
+
for (const child of Object.values(value))
|
|
16
|
+
freeze(child);
|
|
17
|
+
Object.freeze(value);
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
function configured(value) {
|
|
22
|
+
if (Array.isArray(value))
|
|
23
|
+
return value.map(configured);
|
|
24
|
+
if (object(value))
|
|
25
|
+
return Object.fromEntries(Object.entries(value).filter(([, v]) => v !== null).map(([k, v]) => [k, configured(v)]));
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
function validatePolicy(policy) {
|
|
29
|
+
const c = policy.configuration;
|
|
30
|
+
if (!policy.model || !policy.accountEmail || !policy.permissionProfile || c.default_permissions !== policy.permissionProfile
|
|
31
|
+
|| c.model_provider !== "openai" || c.approval_policy !== "never" || c.project_doc_max_bytes !== 0 || c.web_search !== "disabled"
|
|
32
|
+
|| !isDeepStrictEqual(c.mcp_servers, {}) || !isDeepStrictEqual(c.project_root_markers, []))
|
|
33
|
+
deny();
|
|
34
|
+
const features = c.features;
|
|
35
|
+
if (!object(features) || ["shell_tool", "unified_exec", "multi_agent", "apps", "plugins", "hooks"].some((name) => features[name] !== false))
|
|
36
|
+
deny();
|
|
37
|
+
const permission = object(c.permissions) ? c.permissions[policy.permissionProfile] : undefined;
|
|
38
|
+
if (!object(permission) || !isDeepStrictEqual(permission.network, { enabled: false }) || !object(permission.filesystem)
|
|
39
|
+
|| !isDeepStrictEqual(permission.filesystem, { "/": "deny" }))
|
|
40
|
+
deny();
|
|
41
|
+
if (!isDeepStrictEqual(c.shell_environment_policy, { inherit: "none", set: {} }))
|
|
42
|
+
deny();
|
|
43
|
+
}
|
|
44
|
+
/** Explicit feature denylist for the reviewed vendor baseline; new enabled defaults refuse. */
|
|
45
|
+
export function codexComponentConfiguration(profile) {
|
|
46
|
+
if (!/^[a-z][a-z0-9_-]{0,63}$/.test(profile))
|
|
47
|
+
deny();
|
|
48
|
+
return {
|
|
49
|
+
default_permissions: profile, model_provider: "openai", approval_policy: "never",
|
|
50
|
+
project_doc_max_bytes: 0, project_root_markers: [], web_search: "disabled", mcp_servers: {},
|
|
51
|
+
permissions: { [profile]: { filesystem: { "/": "deny" }, network: { enabled: false } } },
|
|
52
|
+
shell_environment_policy: { inherit: "none", set: {} },
|
|
53
|
+
features: Object.fromEntries([
|
|
54
|
+
"shell_tool", "unified_exec", "multi_agent", "apps", "plugins", "hooks", "auth_elicitation",
|
|
55
|
+
"mentions_v2", "remote_plugin", "tool_suggest", "memories", "remote_control", "mcp_2026_07_28",
|
|
56
|
+
"browser_use", "browser_use_external", "browser_use_full_cdp_access", "computer_use", "code_mode_host",
|
|
57
|
+
"code_mode", "code_mode_only", "image_generation", "in_app_browser", "multi_agent_v2", "plugin_sharing",
|
|
58
|
+
"skill_mcp_dependency_install", "skill_search", "workspace_dependencies", "request_permissions_tool",
|
|
59
|
+
"exec_permission_approvals", "guardian_approval", "guardianv2", "goals", "external_agent_memory_import",
|
|
60
|
+
"realtime_conversation", "shell_snapshot", "standalone_web_search",
|
|
61
|
+
].map((name) => [name, false])),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** Fresh connection/thread per step. No spawn, activation, command RPC or provider fallback. */
|
|
65
|
+
export async function runCodexComponentStep(transport, approved, run) {
|
|
66
|
+
// Capture authority before callbacks or transport I/O can mutate the supplied object.
|
|
67
|
+
const policy = freeze({ cwd: approved.cwd, codexHome: approved.codexHome,
|
|
68
|
+
permissionProfile: approved.permissionProfile, model: approved.model, accountEmail: approved.accountEmail,
|
|
69
|
+
configuration: structuredClone(approved.configuration), assertCurrent: approved.assertCurrent.bind(approved),
|
|
70
|
+
...(approved.assertLive ? { assertLive: approved.assertLive.bind(approved) } : {}) });
|
|
71
|
+
let phase = "init";
|
|
72
|
+
let threadId;
|
|
73
|
+
let turnId;
|
|
74
|
+
let finalText;
|
|
75
|
+
let usage = { inputTokens: 0, outputTokens: 0 };
|
|
76
|
+
const items = new Map();
|
|
77
|
+
const calls = new Set();
|
|
78
|
+
let failed = false;
|
|
79
|
+
let threadStarted = false;
|
|
80
|
+
let turnStarted = false;
|
|
81
|
+
let accountResponseReceived = false;
|
|
82
|
+
let queued = [];
|
|
83
|
+
let queuedBytes = 0;
|
|
84
|
+
let pendingTools = 0;
|
|
85
|
+
let toolQueue = Promise.resolve();
|
|
86
|
+
let resolveTurn;
|
|
87
|
+
let rejectTurn;
|
|
88
|
+
const completion = new Promise((resolve, reject) => { resolveTurn = resolve; rejectTurn = reject; });
|
|
89
|
+
void completion.catch(() => { });
|
|
90
|
+
let scopeReady;
|
|
91
|
+
const ready = new Promise((resolve) => { scopeReady = resolve; });
|
|
92
|
+
const check = () => { if (failed)
|
|
93
|
+
deny(); run.signal.throwIfAborted(); (policy.assertLive ?? policy.assertCurrent)(); };
|
|
94
|
+
const verify = () => { if (failed)
|
|
95
|
+
deny(); run.signal.throwIfAborted(); policy.assertCurrent(); };
|
|
96
|
+
const scope = (value) => { if (value.threadId !== threadId || value.turnId !== turnId)
|
|
97
|
+
deny(); };
|
|
98
|
+
const receive = (event) => {
|
|
99
|
+
check();
|
|
100
|
+
const p = object(event.params) ? event.params : deny();
|
|
101
|
+
if (event.method === "account/rateLimits/updated") {
|
|
102
|
+
parse(codexRateLimitsUpdatedSchema, p);
|
|
103
|
+
return;
|
|
104
|
+
} // telemetry only, never authority
|
|
105
|
+
if (event.method === "account/updated") {
|
|
106
|
+
if (accountResponseReceived || phase !== "init")
|
|
107
|
+
deny();
|
|
108
|
+
parse(codexAccountUpdatedSchema, p);
|
|
109
|
+
return; // startup only; account/read must still verify the pinned identity
|
|
110
|
+
}
|
|
111
|
+
if (event.method === "remoteControl/status/changed") {
|
|
112
|
+
if (p.status !== "disabled")
|
|
113
|
+
deny();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (phase === "thread" || phase === "starting") {
|
|
117
|
+
queuedBytes += Buffer.byteLength(JSON.stringify(event));
|
|
118
|
+
if (queued.length >= 128 || queuedBytes > 1_048_576)
|
|
119
|
+
deny();
|
|
120
|
+
queued.push(event);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (event.method === "thread/started") {
|
|
124
|
+
const t = parse(threadSchema, p.thread);
|
|
125
|
+
if (threadStarted || t.id !== threadId || t.cwd !== policy.cwd)
|
|
126
|
+
deny();
|
|
127
|
+
threadStarted = true;
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (!threadId || p.threadId !== threadId)
|
|
131
|
+
deny();
|
|
132
|
+
if (event.method === "warning") {
|
|
133
|
+
parse(codexDisabledCodeModeWarningSchema, p);
|
|
134
|
+
const features = policy.configuration.features;
|
|
135
|
+
if (!object(features) || features.code_mode_host !== false || features.code_mode !== false)
|
|
136
|
+
deny();
|
|
137
|
+
return; // exact denial warning only; no tool or permission is enabled
|
|
138
|
+
}
|
|
139
|
+
if (event.method === "thread/status/changed") {
|
|
140
|
+
parse(z.object({ type: z.enum(["notLoaded", "idle", "systemError", "active"]) }), p.status);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (phase !== "running")
|
|
144
|
+
deny();
|
|
145
|
+
if (event.method === "turn/started" || event.method === "turn/completed") {
|
|
146
|
+
const t = parse(turnSchema, p.turn);
|
|
147
|
+
if (t.id !== turnId)
|
|
148
|
+
deny();
|
|
149
|
+
if (event.method === "turn/started") {
|
|
150
|
+
if (turnStarted || t.status !== "inProgress" || t.items.length)
|
|
151
|
+
deny();
|
|
152
|
+
turnStarted = true;
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const completedIds = new Set();
|
|
156
|
+
for (const raw of t.items) {
|
|
157
|
+
const item = parse(z.object({ id, type: z.enum(["userMessage", "agentMessage", "reasoning", "dynamicToolCall"]) }).passthrough(), raw);
|
|
158
|
+
const observed = items.get(item.id);
|
|
159
|
+
if (completedIds.has(item.id) || !observed?.done || observed.type !== item.type || !isDeepStrictEqual(observed.completed, raw))
|
|
160
|
+
deny();
|
|
161
|
+
completedIds.add(item.id);
|
|
162
|
+
}
|
|
163
|
+
// Summary/notLoaded views omit items; the complete streamed lifecycle is
|
|
164
|
+
// authoritative. Every supplied item still matches, and full views cover all.
|
|
165
|
+
if (!threadStarted || !turnStarted || (t.itemsView === "full" && completedIds.size !== items.size) || t.status !== "completed" || pendingTools || [...items.values()].some((item) => !item.done) || finalText === undefined)
|
|
166
|
+
deny();
|
|
167
|
+
phase = "finished";
|
|
168
|
+
resolveTurn();
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
scope(p);
|
|
172
|
+
if (event.method === "thread/tokenUsage/updated") {
|
|
173
|
+
const total = parse(z.object({ total: z.object({ inputTokens: z.number().int().nonnegative(), outputTokens: z.number().int().nonnegative() }) }), p.tokenUsage).total;
|
|
174
|
+
if (total.inputTokens < usage.inputTokens || total.outputTokens < usage.outputTokens)
|
|
175
|
+
deny();
|
|
176
|
+
usage = total;
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (event.method === "item/started" || event.method === "item/completed") {
|
|
180
|
+
parse(z.number().int().nonnegative(), p[event.method === "item/started" ? "startedAtMs" : "completedAtMs"]);
|
|
181
|
+
const item = parse(z.object({ id, type: z.enum(["userMessage", "agentMessage", "reasoning", "dynamicToolCall"]) }).passthrough(), p.item);
|
|
182
|
+
if (item.type === "dynamicToolCall" && (typeof item.tool !== "string" || !Object.hasOwn(run.tools, item.tool) || item.namespace != null))
|
|
183
|
+
deny();
|
|
184
|
+
if (event.method === "item/started") {
|
|
185
|
+
if (items.has(item.id) || items.size >= 512)
|
|
186
|
+
deny();
|
|
187
|
+
items.set(item.id, { type: item.type, done: false });
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
const state = items.get(item.id);
|
|
191
|
+
if (!state || state.done || state.type !== item.type)
|
|
192
|
+
deny();
|
|
193
|
+
state.done = true;
|
|
194
|
+
state.completed = structuredClone(p.item);
|
|
195
|
+
if (item.type === "agentMessage")
|
|
196
|
+
finalText = parse(z.string().max(1_048_576), item.text);
|
|
197
|
+
if (item.type === "dynamicToolCall" && (!calls.has(item.id) || item.status !== "completed" || item.success !== true))
|
|
198
|
+
deny();
|
|
199
|
+
}
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (!["item/agentMessage/delta", "item/reasoning/textDelta", "item/reasoning/summaryTextDelta", "item/reasoning/summaryPartAdded"].includes(event.method)
|
|
203
|
+
|| typeof p.itemId !== "string" || !items.has(p.itemId) || items.get(p.itemId).done)
|
|
204
|
+
deny();
|
|
205
|
+
};
|
|
206
|
+
const rpc = new CodexRpcClient(transport, receive, 1_048_576, async (event) => {
|
|
207
|
+
check();
|
|
208
|
+
if (event.method !== "item/tool/call" || (phase !== "starting" && phase !== "running"))
|
|
209
|
+
deny();
|
|
210
|
+
const call = parse(callSchema, event.params);
|
|
211
|
+
if (calls.has(call.callId) || calls.size >= 32 || !Object.hasOwn(run.tools, call.tool))
|
|
212
|
+
deny();
|
|
213
|
+
calls.add(call.callId);
|
|
214
|
+
pendingTools++;
|
|
215
|
+
const result = toolQueue.then(async () => {
|
|
216
|
+
await Promise.race([ready, completion.then(deny)]);
|
|
217
|
+
check();
|
|
218
|
+
scope(call);
|
|
219
|
+
if (phase !== "running")
|
|
220
|
+
deny();
|
|
221
|
+
if (Buffer.byteLength(JSON.stringify(call.arguments)) > 65_536)
|
|
222
|
+
deny();
|
|
223
|
+
verify();
|
|
224
|
+
const output = await run.tools[call.tool](call.arguments);
|
|
225
|
+
verify();
|
|
226
|
+
if (phase !== "running")
|
|
227
|
+
deny();
|
|
228
|
+
const text = JSON.stringify(output);
|
|
229
|
+
if (text === undefined || Buffer.byteLength(text) > 1_048_000)
|
|
230
|
+
deny();
|
|
231
|
+
return { contentItems: [{ type: "inputText", text }], success: true };
|
|
232
|
+
});
|
|
233
|
+
toolQueue = result.catch(() => { failed = true; rpc.fail("protocol"); });
|
|
234
|
+
try {
|
|
235
|
+
return await result;
|
|
236
|
+
}
|
|
237
|
+
finally {
|
|
238
|
+
pendingTools--;
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
rpc.onFailure((error) => { failed = true; rejectTurn(error); });
|
|
242
|
+
const abort = () => rpc.fail("cancelled");
|
|
243
|
+
run.signal.addEventListener("abort", abort, { once: true });
|
|
244
|
+
const timer = setTimeout(() => rpc.fail("timeout"), 120_000);
|
|
245
|
+
const drain = () => { const events = queued; queued = []; queuedBytes = 0; for (const event of events)
|
|
246
|
+
receive(event); };
|
|
247
|
+
try {
|
|
248
|
+
verify();
|
|
249
|
+
validatePolicy(policy);
|
|
250
|
+
const initialized = parse(z.object({ codexHome: z.literal(policy.codexHome), platformFamily: z.literal("unix"), platformOs: z.literal("macos"), userAgent: z.string() }), await rpc.request("initialize", { clientInfo: { name: "genbi-components", version: "1" }, capabilities: { experimentalApi: true } }));
|
|
251
|
+
if (!initialized.userAgent.includes(`/${CODEX_BASELINE_VERSION} `))
|
|
252
|
+
deny();
|
|
253
|
+
rpc.notify("initialized", {});
|
|
254
|
+
const effective = parse(z.object({ config: z.record(z.string(), z.unknown()) }), await rpc.request("config/read", { cwd: policy.cwd, includeLayers: false }));
|
|
255
|
+
for (const [key, expected] of Object.entries(policy.configuration)) {
|
|
256
|
+
if (key === "features") {
|
|
257
|
+
const features = effective.config.features;
|
|
258
|
+
if (!object(features) || Object.values(configured(features)).some((value) => value !== false) || !object(expected) || Object.keys(expected).some((name) => features[name] !== false))
|
|
259
|
+
deny();
|
|
260
|
+
}
|
|
261
|
+
else if (!isDeepStrictEqual(configured(effective.config[key]), configured(expected)))
|
|
262
|
+
deny();
|
|
263
|
+
}
|
|
264
|
+
parse(z.object({ requiresOpenaiAuth: z.literal(true), account: z.object({ type: z.literal("chatgpt"), email: z.literal(policy.accountEmail) }) }), await rpc.request("account/read", { refreshToken: false }, 10_000, undefined, () => { accountResponseReceived = true; }));
|
|
265
|
+
verify();
|
|
266
|
+
phase = "thread";
|
|
267
|
+
const started = parse(z.object({ thread: threadSchema, model: z.literal(policy.model), modelProvider: z.literal("openai"),
|
|
268
|
+
approvalPolicy: z.literal("never"), cwd: z.literal(policy.cwd),
|
|
269
|
+
activePermissionProfile: z.object({ id: z.literal(policy.permissionProfile), extends: z.null().optional() }).strict(),
|
|
270
|
+
instructionSources: z.array(z.never()).default([]), runtimeWorkspaceRoots: z.array(z.never()).default([]),
|
|
271
|
+
}), await rpc.request("thread/start", {
|
|
272
|
+
cwd: policy.cwd, model: policy.model, modelProvider: "openai", permissions: policy.permissionProfile, approvalPolicy: "never", ephemeral: true,
|
|
273
|
+
runtimeWorkspaceRoots: [], environments: [], allowProviderModelFallback: false,
|
|
274
|
+
baseInstructions: [run.brief, run.prompt].filter(Boolean).join("\n\n"), developerInstructions: "",
|
|
275
|
+
dynamicTools: Object.keys(run.tools).map((name) => ({ name, description: run.toolDescriptions[name] ?? name, inputSchema: run.toolSchemas[name] ?? deny() })),
|
|
276
|
+
}));
|
|
277
|
+
if (started.thread.cwd !== policy.cwd)
|
|
278
|
+
deny();
|
|
279
|
+
threadId = started.thread.id;
|
|
280
|
+
phase = "init";
|
|
281
|
+
drain();
|
|
282
|
+
verify();
|
|
283
|
+
phase = "starting";
|
|
284
|
+
const startedTurn = parse(z.object({ turn: turnSchema }), await rpc.request("turn/start", {
|
|
285
|
+
threadId, model: policy.model, permissions: policy.permissionProfile, approvalPolicy: "never", cwd: policy.cwd, runtimeWorkspaceRoots: [], environments: [],
|
|
286
|
+
input: [{ type: "text", text: JSON.stringify({ request: run.request, input: run.input, consumes: run.consumes }) }],
|
|
287
|
+
}));
|
|
288
|
+
if (startedTurn.turn.status !== "inProgress")
|
|
289
|
+
deny();
|
|
290
|
+
turnId = startedTurn.turn.id;
|
|
291
|
+
phase = "running";
|
|
292
|
+
scopeReady();
|
|
293
|
+
drain();
|
|
294
|
+
await completion;
|
|
295
|
+
verify();
|
|
296
|
+
return { value: finalText, usage };
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
rpc.fail(error instanceof CodexRpcError ? error.reason : "protocol");
|
|
300
|
+
throw new CodexRpcError(error instanceof CodexRpcError ? error.reason : "protocol");
|
|
301
|
+
}
|
|
302
|
+
finally {
|
|
303
|
+
phase = "finished";
|
|
304
|
+
clearTimeout(timer);
|
|
305
|
+
run.signal.removeEventListener("abort", abort);
|
|
306
|
+
await rpc.close();
|
|
307
|
+
}
|
|
308
|
+
}
|