@pasko70/pibo 1.16.6 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-runtime/auth.js +28 -0
- package/dist/agent-runtime/capabilities.js +221 -0
- package/dist/agent-runtime/context-build.js +313 -0
- package/dist/agent-runtime/contract.js +45 -0
- package/dist/agent-runtime/errors.js +57 -0
- package/dist/agent-runtime/events.js +1 -0
- package/dist/agent-runtime/history.js +1 -0
- package/dist/agent-runtime/profile-validation.js +109 -0
- package/dist/agent-runtime/registry.js +608 -0
- package/dist/agent-runtime/resource-files.js +87 -0
- package/dist/agent-runtime/resource-service.js +635 -0
- package/dist/agent-runtime/resources.js +1 -0
- package/dist/agent-runtime/routed-session.js +931 -0
- package/dist/agent-runtime/testing/contract.js +51 -0
- package/dist/agent-runtime/testing/fake-adapter.js +192 -0
- package/dist/agent-runtime/types.js +3 -0
- package/dist/agent-runtimes/codex-native/adapter.js +905 -0
- package/dist/agent-runtimes/codex-native/auth.js +476 -0
- package/dist/agent-runtimes/codex-native/client.js +734 -0
- package/dist/agent-runtimes/codex-native/config.js +152 -0
- package/dist/agent-runtimes/codex-native/history.js +283 -0
- package/dist/agent-runtimes/codex-native/mcp-stdio-launcher.js +89 -0
- package/dist/agent-runtimes/codex-native/models.js +581 -0
- package/dist/agent-runtimes/codex-native/process.js +459 -0
- package/dist/agent-runtimes/codex-native/protocol-types.js +1 -0
- package/dist/agent-runtimes/codex-native/protocol-version.js +7 -0
- package/dist/agent-runtimes/codex-native/redaction.js +31 -0
- package/dist/agent-runtimes/codex-native/requests.js +378 -0
- package/dist/agent-runtimes/codex-native/resource-delivery.js +445 -0
- package/dist/agent-runtimes/codex-native/thread.js +388 -0
- package/dist/agent-runtimes/codex-native/turn.js +849 -0
- package/dist/agent-runtimes/pi/adapter.js +653 -0
- package/dist/agent-runtimes/pi/auth.js +455 -0
- package/dist/agent-runtimes/pi/history.js +640 -0
- package/dist/agent-runtimes/pi/model-catalog.js +87 -0
- package/dist/agent-runtimes/pi/routed-session.js +1464 -0
- package/dist/agent-runtimes/pi/runtime.js +534 -0
- package/dist/agent-runtimes/pi/tool-compiler.js +69 -0
- package/dist/apps/chat/agent-profiles.js +40 -23
- package/dist/apps/chat/agent-store.js +111 -64
- package/dist/apps/chat/chat-api-routes.js +1 -1
- package/dist/apps/chat/chat-request-normalizers.js +47 -0
- package/dist/apps/chat/data/chat-data-mappers.js +25 -9
- package/dist/apps/chat/data/history-query-service.js +108 -0
- package/dist/apps/chat/data/session-query-service.js +24 -3
- package/dist/apps/chat/data/timeline-query-service.js +3 -3
- package/dist/apps/chat/model-catalog.js +1 -55
- package/dist/apps/chat/provider-auth-actions.js +171 -23
- package/dist/apps/chat/stream.js +12 -0
- package/dist/apps/chat/trace-v2.js +1 -0
- package/dist/apps/chat/trace.js +126 -415
- package/dist/apps/chat/web-app.js +582 -157
- package/dist/apps/chat-ui/assets/{dist-BTLtT_Vf.js → dist-9v2ZXT6V.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CMk1aPug.js → dist-B1LVAytl.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CcwA_IWN.js → dist-C6LPDFXU.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DKOthbxr.js → dist-DVtXxfHc.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-ls2I6BIw.js → dist-DW4Qrfbd.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-D1rAtRWs.js → dist-DmbsHdMC.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-C1JQRskW.js → dist-DyvwuSFO.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DfpaylQ-.js → dist-I26VB0QO.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-D10bTFD5.js → dist-RtHbJRPV.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-5KpmmBBZ.js → dist-sZgJkWZb.js} +1 -1
- package/dist/apps/chat-ui/assets/index-BPbNvcZe.css +1 -0
- package/dist/apps/chat-ui/assets/index-CIOf2uL2.js +237 -0
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/chat-vscode-web/assets/index-1ivRyjFs.js +41 -0
- package/dist/apps/chat-vscode-web/index.html +1 -1
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-2.0.0.vsix +0 -0
- package/dist/auth/login-actions.js +5 -251
- package/dist/cli-session/localSessionSource.js +8 -1
- package/dist/core/context-build.js +124 -20
- package/dist/core/default-profile.js +8 -0
- package/dist/core/profiles.js +30 -3
- package/dist/core/routed-session.js +5 -1446
- package/dist/core/runtime.js +5 -561
- package/dist/core/session-router.js +637 -83
- package/dist/data/cli.js +20 -3
- package/dist/data/schema.js +104 -1
- package/dist/data/session-store.js +24 -1
- package/dist/debug/events.js +25 -10
- package/dist/debug/failures.js +23 -3
- package/dist/debug/index.js +24 -6
- package/dist/debug/messages.js +87 -7
- package/dist/debug/persisted-payloads.js +31 -0
- package/dist/debug/pty.js +7 -6
- package/dist/debug/runtime-binding.js +29 -0
- package/dist/debug/session.js +137 -0
- package/dist/debug/summary.js +12 -0
- package/dist/debug/telemetry.js +28 -0
- package/dist/debug/tools.js +12 -2
- package/dist/debug/trace.js +154 -76
- package/dist/gateway/server.js +87 -2
- package/dist/gateway/tool.js +5 -5
- package/dist/index.js +21 -2
- package/dist/loops/tools.js +13 -12
- package/dist/mcp/agent-context.js +13 -4
- package/dist/mcp/client.js +10 -6
- package/dist/mcp/config.js +5 -2
- package/dist/mcp/runtime-session.js +166 -0
- package/dist/plugins/builtin.js +191 -53
- package/dist/plugins/codex-native.js +29 -0
- package/dist/plugins/registry.js +66 -2
- package/dist/runs/tools.js +26 -25
- package/dist/session-ui/terminalRows.js +2 -2
- package/dist/sessions/pibo-data-store.js +125 -16
- package/dist/sessions/runtime-binding.js +107 -0
- package/dist/sessions/sqlite-store.js +239 -18
- package/dist/sessions/store.js +86 -7
- package/dist/shared/trace-engine.js +18 -9
- package/dist/shared/trace-event-projection.js +29 -11
- package/dist/shared/{trace-transcript.js → trace-history.js} +193 -195
- package/dist/shared/trace-order.js +9 -4
- package/dist/shared/trace-page-merge.js +1 -1
- package/dist/signals/projector.js +20 -2
- package/dist/signals/registry.js +11 -0
- package/dist/subagents/tool.js +8 -6
- package/dist/tools/codex-browser.js +20 -19
- package/dist/tools/codex-compat.js +10 -9
- package/dist/tools/codex-image-generation.js +8 -6
- package/dist/tools/contract.js +45 -0
- package/dist/tools/credential-registry.js +182 -0
- package/dist/tools/mcp-bridge.js +511 -0
- package/dist/tools/payload-writer.js +17 -0
- package/dist/tools/runtime/tool.js +10 -9
- package/dist/tools/schema.js +9 -0
- package/dist/tools/session-service.js +193 -0
- package/dist/tools/session-tool-set.js +85 -0
- package/dist/web-annotations/tools.js +17 -16
- package/docs/README.md +11 -0
- package/package.json +3 -2
- package/skills/builtin/pibo-agent-runtime-adapter/SKILL.md +183 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/README.md +10 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/evals.json +45 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/fixtures/orion-full-harness.md +60 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/fixtures/relay-partial-harness.md +52 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/capabilities-and-designer.md +194 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/history-debug-and-security.md +213 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/interfaces-and-registration.md +214 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/lifecycle-bindings-and-events.md +193 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/portable-delivery-and-native-behavior.md +226 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/testing-migration-and-validation.md +256 -0
- package/dist/apps/chat-ui/assets/index-C2YI0xfw.js +0 -237
- package/dist/apps/chat-ui/assets/index-E0RmuCkY.css +0 -1
- package/dist/apps/chat-vscode-web/assets/index-D-tSsXLG.js +0 -41
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { isAbsolute, resolve } from "node:path";
|
|
2
|
+
import { piboHomePath } from "../../core/pibo-home.js";
|
|
3
|
+
const MAX_TIMEOUT_MS = 10 * 60 * 1_000;
|
|
4
|
+
const MAX_AUTH_LOGIN_TIMEOUT_MS = 30 * 60 * 1_000;
|
|
5
|
+
const ENVIRONMENT_KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
6
|
+
const RESERVED_ENVIRONMENT_KEYS = new Set([
|
|
7
|
+
"CODEX_HOME",
|
|
8
|
+
"HOME",
|
|
9
|
+
"USERPROFILE",
|
|
10
|
+
"XDG_CACHE_HOME",
|
|
11
|
+
"XDG_CONFIG_HOME",
|
|
12
|
+
"XDG_DATA_HOME",
|
|
13
|
+
"XDG_STATE_HOME",
|
|
14
|
+
"TMP",
|
|
15
|
+
"TEMP",
|
|
16
|
+
"TMPDIR",
|
|
17
|
+
"NODE_OPTIONS",
|
|
18
|
+
"LD_PRELOAD",
|
|
19
|
+
"BASH_ENV",
|
|
20
|
+
"ENV",
|
|
21
|
+
"PYTHONHOME",
|
|
22
|
+
"PYTHONPATH",
|
|
23
|
+
"RUBYOPT",
|
|
24
|
+
"PERL5OPT",
|
|
25
|
+
"JAVA_TOOL_OPTIONS",
|
|
26
|
+
"_JAVA_OPTIONS",
|
|
27
|
+
]);
|
|
28
|
+
export const DEFAULT_CODEX_NATIVE_ENVIRONMENT_ALLOWLIST = [
|
|
29
|
+
"PATH",
|
|
30
|
+
"PATHEXT",
|
|
31
|
+
"SystemRoot",
|
|
32
|
+
"WINDIR",
|
|
33
|
+
"COMSPEC",
|
|
34
|
+
"LANG",
|
|
35
|
+
"LC_ALL",
|
|
36
|
+
"LC_CTYPE",
|
|
37
|
+
"TZ",
|
|
38
|
+
"HTTP_PROXY",
|
|
39
|
+
"HTTPS_PROXY",
|
|
40
|
+
"NO_PROXY",
|
|
41
|
+
"ALL_PROXY",
|
|
42
|
+
"SSL_CERT_FILE",
|
|
43
|
+
"SSL_CERT_DIR",
|
|
44
|
+
];
|
|
45
|
+
export const CODEX_NATIVE_RUNTIME_CONFIG_SCHEMA = {
|
|
46
|
+
type: "object",
|
|
47
|
+
additionalProperties: false,
|
|
48
|
+
properties: {
|
|
49
|
+
executable: { type: "string", minLength: 1, default: "codex" },
|
|
50
|
+
homeRoot: { type: "string", minLength: 1 },
|
|
51
|
+
environmentAllowlist: {
|
|
52
|
+
type: "array",
|
|
53
|
+
items: { type: "string", pattern: ENVIRONMENT_KEY_PATTERN.source },
|
|
54
|
+
uniqueItems: true,
|
|
55
|
+
},
|
|
56
|
+
experimentalUserInput: { type: "boolean", default: false },
|
|
57
|
+
diagnosticTimeoutMs: { type: "integer", minimum: 1, maximum: MAX_TIMEOUT_MS, default: 5_000 },
|
|
58
|
+
startupTimeoutMs: { type: "integer", minimum: 1, maximum: MAX_TIMEOUT_MS, default: 10_000 },
|
|
59
|
+
requestTimeoutMs: { type: "integer", minimum: 1, maximum: MAX_TIMEOUT_MS, default: 120_000 },
|
|
60
|
+
authLoginTimeoutMs: { type: "integer", minimum: 1, maximum: MAX_AUTH_LOGIN_TIMEOUT_MS, default: 15 * 60 * 1_000 },
|
|
61
|
+
shutdownTimeoutMs: { type: "integer", minimum: 1, maximum: MAX_TIMEOUT_MS, default: 2_000 },
|
|
62
|
+
killTimeoutMs: { type: "integer", minimum: 1, maximum: MAX_TIMEOUT_MS, default: 500 },
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
export function defaultCodexNativeRuntimeConfig() {
|
|
66
|
+
return {
|
|
67
|
+
executable: "codex",
|
|
68
|
+
homeRoot: piboHomePath("agent-runtimes", "codex-native"),
|
|
69
|
+
environmentAllowlist: [...DEFAULT_CODEX_NATIVE_ENVIRONMENT_ALLOWLIST],
|
|
70
|
+
experimentalUserInput: false,
|
|
71
|
+
diagnosticTimeoutMs: 5_000,
|
|
72
|
+
startupTimeoutMs: 10_000,
|
|
73
|
+
requestTimeoutMs: 120_000,
|
|
74
|
+
authLoginTimeoutMs: 15 * 60 * 1_000,
|
|
75
|
+
shutdownTimeoutMs: 2_000,
|
|
76
|
+
killTimeoutMs: 500,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function timeout(value, fallback, label, maximum = MAX_TIMEOUT_MS) {
|
|
80
|
+
const selected = value ?? fallback;
|
|
81
|
+
if (!Number.isSafeInteger(selected) || Number(selected) <= 0 || Number(selected) > maximum) {
|
|
82
|
+
throw new Error(`${label} must be a positive integer no greater than ${maximum}`);
|
|
83
|
+
}
|
|
84
|
+
return Number(selected);
|
|
85
|
+
}
|
|
86
|
+
function environmentAllowlist(value, fallback) {
|
|
87
|
+
const selected = value ?? fallback;
|
|
88
|
+
if (!Array.isArray(selected))
|
|
89
|
+
throw new Error("environmentAllowlist must be an array of environment variable names");
|
|
90
|
+
const result = [];
|
|
91
|
+
const seen = new Set();
|
|
92
|
+
for (const entry of selected) {
|
|
93
|
+
if (typeof entry !== "string" || !ENVIRONMENT_KEY_PATTERN.test(entry)) {
|
|
94
|
+
throw new Error("environmentAllowlist entries must be valid environment variable names");
|
|
95
|
+
}
|
|
96
|
+
const canonical = entry.toUpperCase();
|
|
97
|
+
if (RESERVED_ENVIRONMENT_KEYS.has(canonical) || canonical.startsWith("DYLD_")) {
|
|
98
|
+
throw new Error(`environmentAllowlist may not include reserved key "${entry}"`);
|
|
99
|
+
}
|
|
100
|
+
if (seen.has(canonical))
|
|
101
|
+
throw new Error(`environmentAllowlist contains duplicate key "${entry}"`);
|
|
102
|
+
seen.add(canonical);
|
|
103
|
+
result.push(entry);
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
export function parseCodexNativeRuntimeConfig(value) {
|
|
108
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
109
|
+
throw new Error("config must be an object");
|
|
110
|
+
const supported = new Set([
|
|
111
|
+
"executable",
|
|
112
|
+
"homeRoot",
|
|
113
|
+
"environmentAllowlist",
|
|
114
|
+
"experimentalUserInput",
|
|
115
|
+
"diagnosticTimeoutMs",
|
|
116
|
+
"startupTimeoutMs",
|
|
117
|
+
"requestTimeoutMs",
|
|
118
|
+
"authLoginTimeoutMs",
|
|
119
|
+
"shutdownTimeoutMs",
|
|
120
|
+
"killTimeoutMs",
|
|
121
|
+
]);
|
|
122
|
+
const unknown = Object.keys(value).find((key) => !supported.has(key));
|
|
123
|
+
if (unknown)
|
|
124
|
+
throw new Error(`unsupported config field "${unknown}"`);
|
|
125
|
+
const defaults = defaultCodexNativeRuntimeConfig();
|
|
126
|
+
const executable = value.executable ?? defaults.executable;
|
|
127
|
+
if (typeof executable !== "string" || !executable.trim())
|
|
128
|
+
throw new Error("executable must be a non-empty string");
|
|
129
|
+
const homeRoot = value.homeRoot ?? defaults.homeRoot;
|
|
130
|
+
if (typeof homeRoot !== "string" || !homeRoot.trim())
|
|
131
|
+
throw new Error("homeRoot must be a non-empty absolute path");
|
|
132
|
+
if (!isAbsolute(homeRoot))
|
|
133
|
+
throw new Error("homeRoot must be an absolute path");
|
|
134
|
+
return {
|
|
135
|
+
executable: executable.trim(),
|
|
136
|
+
homeRoot: resolve(homeRoot),
|
|
137
|
+
environmentAllowlist: environmentAllowlist(value.environmentAllowlist, defaults.environmentAllowlist),
|
|
138
|
+
experimentalUserInput: value.experimentalUserInput === undefined
|
|
139
|
+
? defaults.experimentalUserInput
|
|
140
|
+
: (() => {
|
|
141
|
+
if (typeof value.experimentalUserInput !== "boolean")
|
|
142
|
+
throw new Error("experimentalUserInput must be boolean");
|
|
143
|
+
return value.experimentalUserInput;
|
|
144
|
+
})(),
|
|
145
|
+
diagnosticTimeoutMs: timeout(value.diagnosticTimeoutMs, defaults.diagnosticTimeoutMs, "diagnosticTimeoutMs"),
|
|
146
|
+
startupTimeoutMs: timeout(value.startupTimeoutMs, defaults.startupTimeoutMs, "startupTimeoutMs"),
|
|
147
|
+
requestTimeoutMs: timeout(value.requestTimeoutMs, defaults.requestTimeoutMs, "requestTimeoutMs"),
|
|
148
|
+
authLoginTimeoutMs: timeout(value.authLoginTimeoutMs, defaults.authLoginTimeoutMs, "authLoginTimeoutMs", MAX_AUTH_LOGIN_TIMEOUT_MS),
|
|
149
|
+
shutdownTimeoutMs: timeout(value.shutdownTimeoutMs, defaults.shutdownTimeoutMs, "shutdownTimeoutMs"),
|
|
150
|
+
killTimeoutMs: timeout(value.killTimeoutMs, defaults.killTimeoutMs, "killTimeoutMs"),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { redactCodexNativeSensitiveText } from "./redaction.js";
|
|
2
|
+
import { CODEX_NATIVE_ADAPTER_ID } from "./thread.js";
|
|
3
|
+
const CODEX_HISTORY_CURSOR_PREFIX = "codex-history:";
|
|
4
|
+
const DEFAULT_HISTORY_LIMIT = 100;
|
|
5
|
+
const MAX_HISTORY_LIMIT = 200;
|
|
6
|
+
function isRecord(value) {
|
|
7
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
function isoFromSeconds(seconds, fallback) {
|
|
10
|
+
const selected = Number.isSafeInteger(seconds) ? Number(seconds) : fallback;
|
|
11
|
+
const date = new Date(selected * 1_000);
|
|
12
|
+
return Number.isNaN(date.getTime()) ? new Date(0).toISOString() : date.toISOString();
|
|
13
|
+
}
|
|
14
|
+
function jsonValue(value, depth = 0) {
|
|
15
|
+
if (depth > 32)
|
|
16
|
+
return "[maximum depth reached]";
|
|
17
|
+
if (value === null || typeof value === "boolean")
|
|
18
|
+
return value;
|
|
19
|
+
if (typeof value === "string")
|
|
20
|
+
return redactCodexNativeSensitiveText(value);
|
|
21
|
+
if (typeof value === "number")
|
|
22
|
+
return Number.isFinite(value) ? value : String(value);
|
|
23
|
+
if (Array.isArray(value))
|
|
24
|
+
return value.map((entry) => jsonValue(entry, depth + 1));
|
|
25
|
+
if (isRecord(value)) {
|
|
26
|
+
const result = {};
|
|
27
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
28
|
+
if (entry !== undefined)
|
|
29
|
+
result[key] = jsonValue(entry, depth + 1);
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
return String(value);
|
|
34
|
+
}
|
|
35
|
+
function turnStatus(turn) {
|
|
36
|
+
if (turn.status === "inProgress")
|
|
37
|
+
return "running";
|
|
38
|
+
if (turn.status === "failed")
|
|
39
|
+
return "error";
|
|
40
|
+
return "complete";
|
|
41
|
+
}
|
|
42
|
+
function textUserInput(item) {
|
|
43
|
+
if (!Array.isArray(item.content))
|
|
44
|
+
return "";
|
|
45
|
+
const text = [];
|
|
46
|
+
for (const part of item.content) {
|
|
47
|
+
if (!isRecord(part) || typeof part.type !== "string")
|
|
48
|
+
continue;
|
|
49
|
+
if (part.type === "text" && typeof part.text === "string")
|
|
50
|
+
text.push(redactCodexNativeSensitiveText(part.text));
|
|
51
|
+
else if (part.type === "image" || part.type === "localImage")
|
|
52
|
+
text.push("[image]");
|
|
53
|
+
else if (part.type === "audio" || part.type === "localAudio")
|
|
54
|
+
text.push("[audio]");
|
|
55
|
+
else if (part.type === "skill" && typeof part.name === "string")
|
|
56
|
+
text.push(`[skill: ${part.name}]`);
|
|
57
|
+
else if (part.type === "mention" && typeof part.name === "string")
|
|
58
|
+
text.push(`[mention: ${part.name}]`);
|
|
59
|
+
}
|
|
60
|
+
return text.join("\n");
|
|
61
|
+
}
|
|
62
|
+
function reasoningParts(item) {
|
|
63
|
+
const values = [
|
|
64
|
+
...(Array.isArray(item.summary) ? item.summary : []),
|
|
65
|
+
...(Array.isArray(item.content) ? item.content : []),
|
|
66
|
+
].filter((value) => typeof value === "string" && value.length > 0)
|
|
67
|
+
.map(redactCodexNativeSensitiveText);
|
|
68
|
+
return values.length > 0 ? [{ type: "reasoning", text: values.join("\n") }] : [];
|
|
69
|
+
}
|
|
70
|
+
function itemEntry(thread, turn, item, sequence) {
|
|
71
|
+
const createdAt = isoFromSeconds(turn.startedAt ?? turn.completedAt, thread.updatedAt);
|
|
72
|
+
const base = {
|
|
73
|
+
id: `codex:${thread.id}:${turn.id}:${item.id}`,
|
|
74
|
+
type: "message",
|
|
75
|
+
source: "native",
|
|
76
|
+
createdAt,
|
|
77
|
+
sequence,
|
|
78
|
+
turnId: turn.id,
|
|
79
|
+
nativeTurnId: turn.id,
|
|
80
|
+
nativeEntryId: item.id,
|
|
81
|
+
status: turnStatus(turn),
|
|
82
|
+
};
|
|
83
|
+
if (item.type === "userMessage") {
|
|
84
|
+
return { ...base, role: "user", content: textUserInput(item) };
|
|
85
|
+
}
|
|
86
|
+
if (item.type === "agentMessage" && typeof item.text === "string") {
|
|
87
|
+
return { ...base, role: "assistant", content: redactCodexNativeSensitiveText(item.text) };
|
|
88
|
+
}
|
|
89
|
+
if (item.type === "reasoning") {
|
|
90
|
+
const content = reasoningParts(item);
|
|
91
|
+
if (content.length === 0)
|
|
92
|
+
return undefined;
|
|
93
|
+
return { ...base, role: "assistant", content };
|
|
94
|
+
}
|
|
95
|
+
if (item.type === "commandExecution") {
|
|
96
|
+
const command = typeof item.command === "string" ? redactCodexNativeSensitiveText(item.command) : "Codex command";
|
|
97
|
+
const output = typeof item.aggregatedOutput === "string" ? redactCodexNativeSensitiveText(item.aggregatedOutput) : "";
|
|
98
|
+
const status = typeof item.status === "string" ? item.status : "completed";
|
|
99
|
+
return {
|
|
100
|
+
...base,
|
|
101
|
+
role: "tool",
|
|
102
|
+
content: output || "Codex command execution",
|
|
103
|
+
toolCallId: item.id,
|
|
104
|
+
toolName: "codex_command",
|
|
105
|
+
result: output,
|
|
106
|
+
isError: status === "failed" || status === "declined",
|
|
107
|
+
metadata: { command },
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (item.type === "fileChange") {
|
|
111
|
+
const status = typeof item.status === "string" ? item.status : "completed";
|
|
112
|
+
return {
|
|
113
|
+
...base,
|
|
114
|
+
role: "tool",
|
|
115
|
+
content: "Codex file change",
|
|
116
|
+
toolCallId: item.id,
|
|
117
|
+
toolName: "codex_file_change",
|
|
118
|
+
result: jsonValue(item.changes),
|
|
119
|
+
isError: status === "failed" || status === "declined",
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (item.type === "mcpToolCall") {
|
|
123
|
+
const server = typeof item.server === "string" ? item.server : "mcp";
|
|
124
|
+
const tool = typeof item.tool === "string" ? item.tool : "tool";
|
|
125
|
+
const status = typeof item.status === "string" ? item.status : "completed";
|
|
126
|
+
return {
|
|
127
|
+
...base,
|
|
128
|
+
role: "tool",
|
|
129
|
+
content: status === "failed" ? "Codex MCP tool failed" : "Codex MCP tool result",
|
|
130
|
+
toolCallId: item.id,
|
|
131
|
+
toolName: `${server}/${tool}`,
|
|
132
|
+
result: jsonValue(item.result ?? item.error ?? null),
|
|
133
|
+
isError: status === "failed",
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (item.type === "dynamicToolCall") {
|
|
137
|
+
const tool = typeof item.tool === "string" ? item.tool : "dynamic_tool";
|
|
138
|
+
const status = typeof item.status === "string" ? item.status : "completed";
|
|
139
|
+
return {
|
|
140
|
+
...base,
|
|
141
|
+
role: "tool",
|
|
142
|
+
content: status === "failed" ? "Codex dynamic tool failed" : "Codex dynamic tool result",
|
|
143
|
+
toolCallId: item.id,
|
|
144
|
+
toolName: tool,
|
|
145
|
+
result: jsonValue(item.contentItems ?? item.success ?? null),
|
|
146
|
+
isError: status === "failed" || item.success === false,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
if (item.type === "webSearch") {
|
|
150
|
+
return {
|
|
151
|
+
...base,
|
|
152
|
+
role: "tool",
|
|
153
|
+
content: typeof item.query === "string" ? item.query : "Codex web search",
|
|
154
|
+
toolCallId: item.id,
|
|
155
|
+
toolName: "codex_web_search",
|
|
156
|
+
result: jsonValue(item.results ?? null),
|
|
157
|
+
isError: false,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
162
|
+
export function codexThreadHistoryEntries(thread) {
|
|
163
|
+
const entries = [];
|
|
164
|
+
let sequence = 0;
|
|
165
|
+
if (thread.name) {
|
|
166
|
+
entries.push({
|
|
167
|
+
id: `codex:${thread.id}:session-info`,
|
|
168
|
+
type: "session_info",
|
|
169
|
+
source: "native",
|
|
170
|
+
createdAt: isoFromSeconds(thread.createdAt, thread.createdAt),
|
|
171
|
+
sequence: sequence++,
|
|
172
|
+
nativeEntryId: thread.id,
|
|
173
|
+
name: redactCodexNativeSensitiveText(thread.name),
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
for (const turn of thread.turns) {
|
|
177
|
+
for (const item of turn.items) {
|
|
178
|
+
const entry = itemEntry(thread, turn, item, sequence);
|
|
179
|
+
if (!entry)
|
|
180
|
+
continue;
|
|
181
|
+
entries.push(entry);
|
|
182
|
+
sequence += 1;
|
|
183
|
+
}
|
|
184
|
+
if (turn.status === "failed" && turn.error !== undefined) {
|
|
185
|
+
entries.push({
|
|
186
|
+
id: `codex:${thread.id}:${turn.id}:error`,
|
|
187
|
+
type: "message",
|
|
188
|
+
source: "native",
|
|
189
|
+
createdAt: isoFromSeconds(turn.completedAt ?? turn.startedAt, thread.updatedAt),
|
|
190
|
+
sequence: sequence++,
|
|
191
|
+
turnId: turn.id,
|
|
192
|
+
nativeTurnId: turn.id,
|
|
193
|
+
nativeEntryId: `${turn.id}:error`,
|
|
194
|
+
role: "assistant",
|
|
195
|
+
content: "Codex turn failed.",
|
|
196
|
+
status: "error",
|
|
197
|
+
error: "Codex turn failed.",
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return entries;
|
|
202
|
+
}
|
|
203
|
+
export function inspectCodexThreadHistory(runtimeInstanceId, binding, thread) {
|
|
204
|
+
return {
|
|
205
|
+
runtimeInstanceId,
|
|
206
|
+
adapterId: CODEX_NATIVE_ADAPTER_ID,
|
|
207
|
+
bindingState: binding.state,
|
|
208
|
+
available: true,
|
|
209
|
+
locator: { kind: "adapter-resolved" },
|
|
210
|
+
title: thread.name ? redactCodexNativeSensitiveText(thread.name) : undefined,
|
|
211
|
+
firstMessage: thread.preview ? redactCodexNativeSensitiveText(thread.preview) : undefined,
|
|
212
|
+
createdAt: isoFromSeconds(thread.createdAt, thread.createdAt),
|
|
213
|
+
updatedAt: isoFromSeconds(thread.updatedAt, thread.updatedAt),
|
|
214
|
+
entryCount: thread.turns.length > 0 ? codexThreadHistoryEntries(thread).length : undefined,
|
|
215
|
+
version: thread.cliVersion,
|
|
216
|
+
diagnostics: [],
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
export function unavailableCodexThreadHistoryInspection(runtimeInstanceId, binding, code, message) {
|
|
220
|
+
return {
|
|
221
|
+
runtimeInstanceId,
|
|
222
|
+
adapterId: CODEX_NATIVE_ADAPTER_ID,
|
|
223
|
+
bindingState: binding.state,
|
|
224
|
+
available: false,
|
|
225
|
+
diagnostics: [{
|
|
226
|
+
severity: binding.state === "missing" ? "error" : "warning",
|
|
227
|
+
code,
|
|
228
|
+
message,
|
|
229
|
+
}],
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
function encodeCursor(cursor) {
|
|
233
|
+
return `${CODEX_HISTORY_CURSOR_PREFIX}${Buffer.from(JSON.stringify(cursor), "utf8").toString("base64url")}`;
|
|
234
|
+
}
|
|
235
|
+
function decodeCursor(value, threadId) {
|
|
236
|
+
if (!value)
|
|
237
|
+
return undefined;
|
|
238
|
+
if (!value.startsWith(CODEX_HISTORY_CURSOR_PREFIX))
|
|
239
|
+
throw new Error("Invalid Codex native history cursor.");
|
|
240
|
+
try {
|
|
241
|
+
const parsed = JSON.parse(Buffer.from(value.slice(CODEX_HISTORY_CURSOR_PREFIX.length), "base64url").toString("utf8"));
|
|
242
|
+
if (parsed.v !== 1 || parsed.threadId !== threadId || !Number.isSafeInteger(parsed.beforeIndex) || Number(parsed.beforeIndex) < 0) {
|
|
243
|
+
throw new Error("invalid cursor");
|
|
244
|
+
}
|
|
245
|
+
return parsed;
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
throw new Error("Invalid Codex native history cursor.");
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function selectedLimit(value) {
|
|
252
|
+
if (value === undefined)
|
|
253
|
+
return DEFAULT_HISTORY_LIMIT;
|
|
254
|
+
if (!Number.isSafeInteger(value) || value <= 0)
|
|
255
|
+
throw new Error("Codex native history limit must be a positive integer.");
|
|
256
|
+
return Math.min(value, MAX_HISTORY_LIMIT);
|
|
257
|
+
}
|
|
258
|
+
export function pageCodexThreadHistory(input) {
|
|
259
|
+
const allEntries = codexThreadHistoryEntries(input.thread);
|
|
260
|
+
const beforeTimestampMs = input.beforeTimestamp === undefined ? undefined : Date.parse(input.beforeTimestamp);
|
|
261
|
+
if (beforeTimestampMs !== undefined && Number.isNaN(beforeTimestampMs)) {
|
|
262
|
+
throw new Error("Codex native history beforeTimestamp is invalid.");
|
|
263
|
+
}
|
|
264
|
+
const filtered = beforeTimestampMs === undefined
|
|
265
|
+
? allEntries
|
|
266
|
+
: allEntries.filter((entry) => Date.parse(entry.createdAt) < beforeTimestampMs);
|
|
267
|
+
const cursor = decodeCursor(input.cursor, input.thread.id);
|
|
268
|
+
const end = Math.min(cursor?.beforeIndex ?? filtered.length, filtered.length);
|
|
269
|
+
const limit = selectedLimit(input.limit);
|
|
270
|
+
const start = Math.max(0, end - limit);
|
|
271
|
+
const entries = filtered.slice(start, end);
|
|
272
|
+
const hasMore = start > 0;
|
|
273
|
+
return {
|
|
274
|
+
runtimeInstanceId: input.runtimeInstanceId,
|
|
275
|
+
adapterId: CODEX_NATIVE_ADAPTER_ID,
|
|
276
|
+
source: "native",
|
|
277
|
+
entries,
|
|
278
|
+
orderOffset: start,
|
|
279
|
+
...(hasMore ? { nextCursor: encodeCursor({ v: 1, threadId: input.thread.id, beforeIndex: start }) } : {}),
|
|
280
|
+
hasMore,
|
|
281
|
+
inspection: inspectCodexThreadHistory(input.runtimeInstanceId, input.binding, input.thread),
|
|
282
|
+
};
|
|
283
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
const ENVIRONMENT_KEY_PATTERN = /^PIBO_CODEX_MCP_STDIO_[A-F0-9]{16}_(COMMAND|ARGS|ENV|CWD)$/;
|
|
3
|
+
const MAX_COMMAND_BYTES = 16 * 1024;
|
|
4
|
+
const MAX_ARGS = 512;
|
|
5
|
+
const MAX_ARGS_BYTES = 256 * 1024;
|
|
6
|
+
const MAX_ENVIRONMENT_ENTRIES = 512;
|
|
7
|
+
const MAX_ENVIRONMENT_BYTES = 512 * 1024;
|
|
8
|
+
function fail() {
|
|
9
|
+
process.stderr.write("Pibo native Codex MCP stdio launcher configuration is invalid.\n");
|
|
10
|
+
process.exit(125);
|
|
11
|
+
}
|
|
12
|
+
function takeEnvironment(name) {
|
|
13
|
+
if (!name || !ENVIRONMENT_KEY_PATTERN.test(name))
|
|
14
|
+
fail();
|
|
15
|
+
const value = process.env[name];
|
|
16
|
+
delete process.env[name];
|
|
17
|
+
if (value === undefined)
|
|
18
|
+
fail();
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
function parseStringArray(value) {
|
|
22
|
+
if (Buffer.byteLength(value, "utf8") > MAX_ARGS_BYTES)
|
|
23
|
+
fail();
|
|
24
|
+
let parsed;
|
|
25
|
+
try {
|
|
26
|
+
parsed = JSON.parse(value);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
fail();
|
|
30
|
+
}
|
|
31
|
+
if (!Array.isArray(parsed) || parsed.length > MAX_ARGS || parsed.some((entry) => typeof entry !== "string"))
|
|
32
|
+
fail();
|
|
33
|
+
return parsed;
|
|
34
|
+
}
|
|
35
|
+
function parseEnvironment(value) {
|
|
36
|
+
if (Buffer.byteLength(value, "utf8") > MAX_ENVIRONMENT_BYTES)
|
|
37
|
+
fail();
|
|
38
|
+
let parsed;
|
|
39
|
+
try {
|
|
40
|
+
parsed = JSON.parse(value);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
fail();
|
|
44
|
+
}
|
|
45
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
46
|
+
fail();
|
|
47
|
+
const entries = Object.entries(parsed);
|
|
48
|
+
if (entries.length > MAX_ENVIRONMENT_ENTRIES)
|
|
49
|
+
fail();
|
|
50
|
+
const environment = Object.create(null);
|
|
51
|
+
for (const [name, entry] of entries) {
|
|
52
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name) || typeof entry !== "string")
|
|
53
|
+
fail();
|
|
54
|
+
environment[name] = entry;
|
|
55
|
+
}
|
|
56
|
+
return environment;
|
|
57
|
+
}
|
|
58
|
+
const [commandEnvironment, argsEnvironment, childEnvironment, cwdEnvironment] = process.argv.slice(2);
|
|
59
|
+
const command = takeEnvironment(commandEnvironment);
|
|
60
|
+
if (!command.trim() || Buffer.byteLength(command, "utf8") > MAX_COMMAND_BYTES)
|
|
61
|
+
fail();
|
|
62
|
+
const args = parseStringArray(takeEnvironment(argsEnvironment));
|
|
63
|
+
const configuredEnvironment = parseEnvironment(takeEnvironment(childEnvironment));
|
|
64
|
+
const cwdValue = takeEnvironment(cwdEnvironment);
|
|
65
|
+
const cwd = cwdValue || undefined;
|
|
66
|
+
const environment = {
|
|
67
|
+
...process.env,
|
|
68
|
+
...configuredEnvironment,
|
|
69
|
+
};
|
|
70
|
+
const child = spawn(command, args, {
|
|
71
|
+
cwd,
|
|
72
|
+
env: environment,
|
|
73
|
+
stdio: "inherit",
|
|
74
|
+
});
|
|
75
|
+
let terminal = false;
|
|
76
|
+
const finish = (code) => {
|
|
77
|
+
if (terminal)
|
|
78
|
+
return;
|
|
79
|
+
terminal = true;
|
|
80
|
+
process.exit(code);
|
|
81
|
+
};
|
|
82
|
+
child.once("error", () => finish(126));
|
|
83
|
+
child.once("exit", (code, signal) => finish(code ?? (signal ? 128 : 1)));
|
|
84
|
+
for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
|
|
85
|
+
process.once(signal, () => {
|
|
86
|
+
if (!terminal)
|
|
87
|
+
child.kill(signal);
|
|
88
|
+
});
|
|
89
|
+
}
|