pi-oracle 0.7.11 → 0.7.13
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/CHANGELOG.md +26 -0
- package/README.md +22 -11
- package/docs/ORACLE_DESIGN.md +7 -6
- package/docs/ORACLE_ISOLATED_PI_VALIDATION.md +21 -2
- package/docs/platform-smoke.md +3 -2
- package/extensions/oracle/lib/archive.ts +725 -0
- package/extensions/oracle/lib/config.ts +14 -5
- package/extensions/oracle/lib/jobs.ts +49 -3
- package/extensions/oracle/lib/provider-capabilities.ts +41 -0
- package/extensions/oracle/lib/runtime.ts +9 -5
- package/extensions/oracle/lib/tools.ts +10 -576
- package/extensions/oracle/worker/chatgpt-ui-helpers.d.mts +2 -0
- package/extensions/oracle/worker/chatgpt-ui-helpers.mjs +23 -3
- package/extensions/oracle/worker/run-job.mjs +65 -16
- package/package.json +8 -5
- package/platform-smoke.config.mjs +1 -1
- package/scripts/oracle-chatgpt-preset-proof.mjs +352 -0
- package/scripts/oracle-real-smoke.mjs +3 -1
- package/scripts/platform-smoke/invariants.mjs +1 -1
|
@@ -22,6 +22,9 @@ import { getProjectId } from "./runtime.js";
|
|
|
22
22
|
export const ORACLE_PROVIDERS = ["chatgpt", "grok"] as const;
|
|
23
23
|
export type OracleProvider = (typeof ORACLE_PROVIDERS)[number];
|
|
24
24
|
|
|
25
|
+
export { resolveOracleArchiveFormat, resolveOracleProviderArchivePlan } from "./provider-capabilities.js";
|
|
26
|
+
export type { OracleArchiveFormat, OracleProviderArchivePlan } from "./provider-capabilities.js";
|
|
27
|
+
|
|
25
28
|
export const MODEL_FAMILIES = ["instant", "thinking", "pro", "grok"] as const;
|
|
26
29
|
export type OracleModelFamily = (typeof MODEL_FAMILIES)[number];
|
|
27
30
|
|
|
@@ -209,13 +212,19 @@ export function getProviderAuthSeedProfileDir(config: OracleConfig, provider: Or
|
|
|
209
212
|
}
|
|
210
213
|
|
|
211
214
|
export function resolveOracleConfigForProvider(config: OracleConfig, provider: OracleProvider): OracleConfig {
|
|
212
|
-
|
|
215
|
+
const defaults = {
|
|
216
|
+
...config.defaults,
|
|
217
|
+
provider,
|
|
218
|
+
};
|
|
219
|
+
if (provider === "chatgpt") {
|
|
220
|
+
return {
|
|
221
|
+
...config,
|
|
222
|
+
defaults,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
213
225
|
return {
|
|
214
226
|
...config,
|
|
215
|
-
defaults
|
|
216
|
-
...config.defaults,
|
|
217
|
-
provider,
|
|
218
|
-
},
|
|
227
|
+
defaults,
|
|
219
228
|
browser: {
|
|
220
229
|
...config.browser,
|
|
221
230
|
authSeedProfileDir: getProviderAuthSeedProfileDir(config, provider),
|
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
// Usage: Imported by oracle commands, tools, queue logic, poller flows, and runtime cleanup/reconciliation paths.
|
|
5
5
|
// Invariants/Assumptions: Job mutations happen under per-job locks, worker identity checks defend against PID reuse, and persisted jobs remain the source of truth.
|
|
6
6
|
import { createHash, randomUUID } from "node:crypto";
|
|
7
|
+
import { execFileSync } from "node:child_process";
|
|
7
8
|
import { existsSync, readdirSync, readFileSync, realpathSync } from "node:fs";
|
|
8
9
|
import { chmod, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
9
10
|
import { isAbsolute, join, relative as relativePath, resolve, sep } from "node:path";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
10
12
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
11
13
|
import {
|
|
12
14
|
ACTIVE_ORACLE_JOB_STATUSES,
|
|
@@ -28,6 +30,7 @@ import type { OracleJobLifecycleEvent as SharedOracleJobLifecycleEvent, OracleJo
|
|
|
28
30
|
import { hasDurableWorkerHandoff as sharedHasDurableWorkerHandoff } from "../shared/job-coordination-helpers.mjs";
|
|
29
31
|
import { isTrackedProcessAlive, readProcessStartedAt, spawnDetachedNodeProcess, terminateTrackedProcess } from "../shared/process-helpers.mjs";
|
|
30
32
|
import type { OracleConfig, OracleResolvedSelection } from "./config.js";
|
|
33
|
+
import { resolveOracleProviderArchivePlan } from "./provider-capabilities.js";
|
|
31
34
|
import { withJobLock, withLock } from "./locks.js";
|
|
32
35
|
import { cleanupRuntimeArtifacts, getProjectId, getSessionId, parseConversationId, requirePersistedSessionFile, type OracleCleanupReport } from "./runtime.js";
|
|
33
36
|
|
|
@@ -116,6 +119,14 @@ export interface OracleArtifactRecord {
|
|
|
116
119
|
matchesUploadedArchive?: boolean;
|
|
117
120
|
}
|
|
118
121
|
|
|
122
|
+
export interface OracleExtensionProvenance {
|
|
123
|
+
schemaVersion: 1;
|
|
124
|
+
packageName: string;
|
|
125
|
+
packageVersion: string;
|
|
126
|
+
sourcePath: string;
|
|
127
|
+
gitHead?: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
119
130
|
export interface OracleJob {
|
|
120
131
|
id: string;
|
|
121
132
|
status: OracleJobStatus;
|
|
@@ -134,6 +145,7 @@ export interface OracleJob {
|
|
|
134
145
|
originSessionFile?: string;
|
|
135
146
|
requestSource: "command" | "tool";
|
|
136
147
|
selection: OracleResolvedSelection;
|
|
148
|
+
extensionProvenance?: OracleExtensionProvenance;
|
|
137
149
|
followUpToJobId?: string;
|
|
138
150
|
chatUrl?: string;
|
|
139
151
|
conversationId?: string;
|
|
@@ -451,8 +463,8 @@ export async function cleanupJobResources(
|
|
|
451
463
|
|
|
452
464
|
function getCleanupRetentionMs(job: OracleJob): { complete: number; failed: number } {
|
|
453
465
|
return {
|
|
454
|
-
complete: job.config
|
|
455
|
-
failed: job.config
|
|
466
|
+
complete: job.config?.cleanup?.completeJobRetentionMs ?? ORACLE_COMPLETE_JOB_RETENTION_MS,
|
|
467
|
+
failed: job.config?.cleanup?.failedJobRetentionMs ?? ORACLE_FAILED_JOB_RETENTION_MS,
|
|
456
468
|
};
|
|
457
469
|
}
|
|
458
470
|
|
|
@@ -898,6 +910,39 @@ export async function cancelOracleJob(id: string, reason = "Cancelled by user"):
|
|
|
898
910
|
});
|
|
899
911
|
}
|
|
900
912
|
|
|
913
|
+
function readExtensionProvenance(cwd: string): OracleExtensionProvenance {
|
|
914
|
+
const sourcePath = resolve(fileURLToPath(new URL("../../../", import.meta.url)));
|
|
915
|
+
let packageName = "pi-oracle";
|
|
916
|
+
let packageVersion = "unknown";
|
|
917
|
+
try {
|
|
918
|
+
const packageJson = JSON.parse(readFileSync(join(sourcePath, "package.json"), "utf8")) as { name?: string; version?: string };
|
|
919
|
+
packageName = packageJson.name || packageName;
|
|
920
|
+
packageVersion = packageJson.version || packageVersion;
|
|
921
|
+
} catch {
|
|
922
|
+
// Keep provenance present even when package metadata is unavailable in an
|
|
923
|
+
// unusual loader; release proof rejects unknown versions.
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
let gitHead: string | undefined;
|
|
927
|
+
try {
|
|
928
|
+
gitHead = execFileSync("git", ["rev-parse", "HEAD"], { cwd: sourcePath, encoding: "utf8" }).trim();
|
|
929
|
+
} catch {
|
|
930
|
+
try {
|
|
931
|
+
gitHead = execFileSync("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8" }).trim();
|
|
932
|
+
} catch {
|
|
933
|
+
gitHead = undefined;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
return {
|
|
938
|
+
schemaVersion: 1,
|
|
939
|
+
packageName,
|
|
940
|
+
packageVersion,
|
|
941
|
+
sourcePath,
|
|
942
|
+
gitHead,
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
|
|
901
946
|
export async function createJob(
|
|
902
947
|
id: string,
|
|
903
948
|
input: OracleSubmitInput,
|
|
@@ -911,7 +956,7 @@ export async function createJob(
|
|
|
911
956
|
const logsDir = join(jobDir, "logs");
|
|
912
957
|
const workerLogPath = join(logsDir, "worker.log");
|
|
913
958
|
const promptPath = join(jobDir, "prompt.md");
|
|
914
|
-
const archivePath = join(jobDir, `context-${id}.
|
|
959
|
+
const archivePath = join(jobDir, `context-${id}.${resolveOracleProviderArchivePlan(input.selection.provider).archiveExtension}`);
|
|
915
960
|
const responsePath = join(jobDir, "response.md");
|
|
916
961
|
const reasoningPath = join(jobDir, "reasoning.md");
|
|
917
962
|
const artifactsManifestPath = join(jobDir, "artifacts.json");
|
|
@@ -945,6 +990,7 @@ export async function createJob(
|
|
|
945
990
|
originSessionFile: sessionFile,
|
|
946
991
|
requestSource: input.requestSource,
|
|
947
992
|
selection: input.selection,
|
|
993
|
+
extensionProvenance: readExtensionProvenance(cwd),
|
|
948
994
|
followUpToJobId: input.followUpToJobId,
|
|
949
995
|
chatUrl: input.chatUrl,
|
|
950
996
|
conversationId,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Purpose: Centralize provider-specific archive capabilities for oracle submissions.
|
|
2
|
+
// Responsibilities: Map each supported provider to archive format, file extension, upload ceiling, and local compression dependencies.
|
|
3
|
+
// Scope: Static provider capability data only; config loading, archive writing, and runtime preflight live in sibling modules.
|
|
4
|
+
// Usage: Imported by config, jobs, tools, runtime, and archive code so provider policy stays in one canonical place.
|
|
5
|
+
// Invariants/Assumptions: Provider ids are defined by config.ts, while this module must not import config values to avoid runtime/config cycles.
|
|
6
|
+
import type { OracleProvider } from "./config.js";
|
|
7
|
+
|
|
8
|
+
export type OracleArchiveFormat = "tar.zst" | "tar.gz";
|
|
9
|
+
|
|
10
|
+
export interface OracleProviderArchivePlan {
|
|
11
|
+
provider: OracleProvider;
|
|
12
|
+
archiveFormat: OracleArchiveFormat;
|
|
13
|
+
archiveExtension: OracleArchiveFormat;
|
|
14
|
+
maxArchiveBytes: number;
|
|
15
|
+
requiresZstd: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const ORACLE_PROVIDER_ARCHIVE_PLANS: Record<OracleProvider, OracleProviderArchivePlan> = {
|
|
19
|
+
chatgpt: {
|
|
20
|
+
provider: "chatgpt",
|
|
21
|
+
archiveFormat: "tar.zst",
|
|
22
|
+
archiveExtension: "tar.zst",
|
|
23
|
+
maxArchiveBytes: 250 * 1024 * 1024,
|
|
24
|
+
requiresZstd: true,
|
|
25
|
+
},
|
|
26
|
+
grok: {
|
|
27
|
+
provider: "grok",
|
|
28
|
+
archiveFormat: "tar.gz",
|
|
29
|
+
archiveExtension: "tar.gz",
|
|
30
|
+
maxArchiveBytes: 200 * 1024 * 1024,
|
|
31
|
+
requiresZstd: false,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export function resolveOracleProviderArchivePlan(provider: OracleProvider): OracleProviderArchivePlan {
|
|
36
|
+
return ORACLE_PROVIDER_ARCHIVE_PLANS[provider];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function resolveOracleArchiveFormat(provider: OracleProvider): OracleArchiveFormat {
|
|
40
|
+
return resolveOracleProviderArchivePlan(provider).archiveFormat;
|
|
41
|
+
}
|
|
@@ -11,7 +11,8 @@ import { delimiter, dirname, join } from "node:path";
|
|
|
11
11
|
import { assertNotKnownBrowserUserDataPath, sweetCookieSafeStoragePasswordScrubbedEnv } from "../shared/browser-profile-helpers.mjs";
|
|
12
12
|
import { jobBlocksAdmission } from "../shared/job-coordination-helpers.mjs";
|
|
13
13
|
import { isTrackedProcessAlive } from "../shared/process-helpers.mjs";
|
|
14
|
-
import type { OracleConfig } from "./config.js";
|
|
14
|
+
import type { OracleConfig, OracleProvider } from "./config.js";
|
|
15
|
+
import { resolveOracleProviderArchivePlan } from "./provider-capabilities.js";
|
|
15
16
|
import { createLease, listLeaseMetadata, readLeaseMetadata, releaseLease, withAuthLock } from "./locks.js";
|
|
16
17
|
|
|
17
18
|
const SEED_GENERATION_FILE = ".oracle-seed-generation";
|
|
@@ -49,12 +50,15 @@ function cpCommand(): string {
|
|
|
49
50
|
return process.env.PI_ORACLE_CP_PATH?.trim() || "cp";
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
function requiredOracleDependencies(config: OracleConfig): Array<{ name: string; command: string }> {
|
|
53
|
+
function requiredOracleDependencies(config: OracleConfig, provider = config.defaults.provider): Array<{ name: string; command: string }> {
|
|
54
|
+
const archivePlan = resolveOracleProviderArchivePlan(provider);
|
|
53
55
|
const dependencies = [
|
|
54
56
|
{ name: "agent-browser", command: AGENT_BROWSER_BIN },
|
|
55
57
|
{ name: "tar", command: "tar" },
|
|
56
|
-
{ name: "zstd", command: "zstd" },
|
|
57
58
|
];
|
|
59
|
+
if (archivePlan.requiresZstd) {
|
|
60
|
+
dependencies.push({ name: "zstd", command: "zstd" });
|
|
61
|
+
}
|
|
58
62
|
if (config.browser.cloneStrategy === "apfs-clone" && process.platform === "darwin") {
|
|
59
63
|
dependencies.push({ name: "cp", command: cpCommand() });
|
|
60
64
|
}
|
|
@@ -325,11 +329,11 @@ export async function assertOracleAuthSeedProfileReady(config: OracleConfig): Pr
|
|
|
325
329
|
}
|
|
326
330
|
}
|
|
327
331
|
|
|
328
|
-
export async function assertOracleSubmitPrerequisites(config: OracleConfig): Promise<void> {
|
|
332
|
+
export async function assertOracleSubmitPrerequisites(config: OracleConfig, provider: OracleProvider = config.defaults.provider): Promise<void> {
|
|
329
333
|
assertSafeOracleProfilePath(config.browser.runtimeProfilesDir, "runtime profiles", config);
|
|
330
334
|
await assertOracleAuthSeedProfileReady(config);
|
|
331
335
|
await assertConfiguredBrowserExecutableReady(config.browser.executablePath);
|
|
332
|
-
for (const dependency of requiredOracleDependencies(config)) {
|
|
336
|
+
for (const dependency of requiredOracleDependencies(config, provider)) {
|
|
333
337
|
await assertRequiredLocalDependencyReady(dependency.name, dependency.command);
|
|
334
338
|
}
|
|
335
339
|
await assertWritableDirectory(config.browser.runtimeProfilesDir, "runtime profiles");
|