pi-oracle 0.2.2 → 0.3.1
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 +21 -0
- package/README.md +143 -104
- package/docs/ORACLE_DESIGN.md +5 -7
- package/extensions/oracle/lib/config.ts +55 -19
- package/extensions/oracle/lib/jobs.ts +4 -14
- package/extensions/oracle/lib/tools.ts +18 -51
- package/extensions/oracle/worker/run-job.mjs +18 -18
- package/package.json +1 -1
- package/prompts/oracle.md +7 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.1 - 2026-04-08
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- rewrote the GitHub-facing README to work better as a landing page, with a sharper value prop, clearer install guidance, a real quickstart, example requests, a minimal config example, troubleshooting, and a high-level flow diagram
|
|
7
|
+
- README now explains when to use `pi-oracle`, when not to use it first, where outputs live, and what to do if a wake-up is missed
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- removed the stale legacy model wording from the README example flow and aligned user-facing setup docs with the preset-based configuration model
|
|
11
|
+
|
|
12
|
+
## 0.3.0 - 2026-04-08
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- breaking: `oracle_submit` and oracle config defaults now use preset-only model selection; legacy `modelFamily` / `effort` / `autoSwitchToThinking` submit inputs and default config fields were removed in favor of canonical preset ids
|
|
16
|
+
- oracle jobs now persist a resolved `selection` snapshot and the worker configures ChatGPT from that persisted selection instead of re-deriving model settings from legacy job fields
|
|
17
|
+
- oracle model preset definitions now come from a single canonical registry in `extensions/oracle/lib/config.ts`
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- removed duplicate hand-maintained preset-id examples from agent-facing prompt and design docs so callers are directed to the tool schema / canonical registry instead of stale inline lists
|
|
21
|
+
- oracle sanity coverage now validates the preset-only contract from the registered tool schema and canonical registry instead of brittle prose-only assertions
|
|
22
|
+
- worker model configuration now consistently uses the explicit `configureModel(job)` parameter instead of hidden coupling through the module-global current job
|
|
23
|
+
|
|
3
24
|
## 0.2.2 - 2026-04-07
|
|
4
25
|
|
|
5
26
|
### Fixed
|
package/README.md
CHANGED
|
@@ -1,152 +1,191 @@
|
|
|
1
1
|
# pi-oracle
|
|
2
2
|
|
|
3
|
-
`pi-oracle` is a `pi`
|
|
3
|
+
`pi-oracle` is a `pi` package that lets the agent hand off difficult, long-running tasks to ChatGPT.com through the web app instead of the API.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
-
|
|
5
|
+
Use it when you want:
|
|
6
|
+
- your real ChatGPT account
|
|
7
7
|
- web-model behavior instead of API usage
|
|
8
|
-
- large
|
|
9
|
-
- async background execution
|
|
10
|
-
-
|
|
11
|
-
- legacy project-scoped jobs created before that change remain readable via project status/read commands, but skip best-effort wake-up routing after upgrade
|
|
8
|
+
- large repo/context uploads
|
|
9
|
+
- async background execution
|
|
10
|
+
- durable saved responses/artifacts plus best-effort wake-ups back into `pi`
|
|
12
11
|
|
|
13
|
-
Normal oracle jobs run in an isolated browser profile, not
|
|
12
|
+
Normal oracle jobs run in an isolated browser profile, not your active Chrome window.
|
|
14
13
|
|
|
15
|
-
Status: experimental public beta
|
|
14
|
+
> Status: experimental public beta. Validated primarily on macOS with Google Chrome and `pi` 0.65.0+.
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
This package intentionally uses the current `session_start`-based session lifecycle and does not ship backward-compatibility shims for removed extension events.
|
|
16
|
+
## When to use it
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
Use `pi-oracle` for:
|
|
19
|
+
- big code reviews of a repo or pending changes
|
|
20
|
+
- architectural or migration analysis that benefits from a large uploaded archive
|
|
21
|
+
- long-running prompts that may take minutes to finish
|
|
22
|
+
- follow-up questions in the same ChatGPT thread later
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
Do not reach for it first for:
|
|
25
|
+
- normal short coding tasks that `pi` can handle directly
|
|
26
|
+
- workflows that must never upload project archives to ChatGPT.com
|
|
27
|
+
- environments outside the current supported setup
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
npm:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pi install npm:pi-oracle
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
GitHub:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pi install https://github.com/fitchmultz/pi-oracle
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Quickstart
|
|
44
|
+
|
|
45
|
+
1. Make sure ChatGPT already works in your local Chrome profile.
|
|
46
|
+
2. Make sure these are installed: Google Chrome, `agent-browser`, `tar`, and `zstd`.
|
|
47
|
+
3. Optional: create `~/.pi/agent/extensions/oracle.json` if you want non-default settings.
|
|
48
|
+
4. Run `/oracle-auth`.
|
|
49
|
+
5. Run `/oracle Review the current pending changes. Include the whole repo unless a narrower archive is clearly better.`
|
|
50
|
+
6. Wait for a best-effort wake-up, or check `/oracle-status`.
|
|
51
|
+
|
|
52
|
+
If you miss the wake-up, the result is still saved durably in the oracle job directory and can be read later.
|
|
53
|
+
|
|
54
|
+
## Example requests
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
/oracle Review the current pending changes. Include the whole repo unless a narrower archive is clearly better. Give me a prioritized code review with concrete fixes.
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
/oracle Read the codebase and explain the highest-risk auth/session failure modes, including what to test before shipping.
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## High-level flow
|
|
65
|
+
|
|
66
|
+
```mermaid
|
|
67
|
+
flowchart LR
|
|
68
|
+
A["/oracle request"] --> B["Agent gathers repo context"]
|
|
69
|
+
B --> C["oracle_submit builds archive"]
|
|
70
|
+
C --> D["Detached worker starts isolated ChatGPT runtime"]
|
|
71
|
+
D --> E["Archive + prompt sent to ChatGPT.com"]
|
|
72
|
+
E --> F["Response/artifacts saved under oracle job dir"]
|
|
73
|
+
F --> G["Best-effort wake-up to matching pi session"]
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
If concurrency is full, the job is queued and starts automatically later.
|
|
77
|
+
|
|
78
|
+
## What the package adds
|
|
79
|
+
|
|
80
|
+
User-facing commands:
|
|
81
|
+
- `/oracle <request>` — prompt template that tells the agent to gather context and dispatch an oracle job
|
|
82
|
+
- `/oracle-auth` — sync ChatGPT cookies from your real Chrome profile into the isolated oracle auth profile
|
|
83
|
+
- `/oracle-status [job-id]` — inspect job status
|
|
84
|
+
- `/oracle-cancel [job-id]` — cancel queued or active job
|
|
85
|
+
- `/oracle-clean <job-id|all>` — remove temp files for terminal jobs
|
|
86
|
+
|
|
87
|
+
Agent-facing tools:
|
|
29
88
|
- `oracle_submit`
|
|
30
89
|
- `oracle_read`
|
|
31
90
|
- `oracle_cancel`
|
|
32
91
|
|
|
33
|
-
|
|
34
|
-
1. gathers a project archive
|
|
35
|
-
2. if runtime capacity is full, persists as `queued` and starts automatically later
|
|
36
|
-
3. otherwise opens ChatGPT in an isolated runtime profile
|
|
37
|
-
4. uploads the archive and sends the prompt
|
|
38
|
-
5. waits in the background
|
|
39
|
-
6. persists the response and any artifacts under the oracle job directory (`${PI_ORACLE_JOBS_DIR:-/tmp}/oracle-<job-id>/` by default)
|
|
40
|
-
- old terminal jobs are later pruned according to cleanup retention settings
|
|
41
|
-
- when directory inputs are expanded, project archives automatically skip common bulky generated caches and top-level build outputs such as `node_modules/`, `target/`, virtualenv caches, coverage outputs, and `dist/`/`build/`/`out/`, unless you explicitly pass those directories
|
|
42
|
-
- whole-repo archive defaults also skip obvious credentials/private data such as `.env` files, key material, credential dotfiles, local database files, and root `secrets/` directories unless you explicitly pass them
|
|
43
|
-
- if a whole-repo archive is still too large after default exclusions, submit automatically prunes the largest nested directories with generic generated-output names like `build/`, `dist/`, `out/`, `coverage/`, and `tmp/` outside obvious source roots like `src/` and `lib/`, and successful submissions report what was pruned
|
|
44
|
-
7. persists the response/artifacts durably in oracle job state and issues best-effort wake-ups to whichever matching `pi` session is currently live
|
|
45
|
-
|
|
46
|
-
## Example
|
|
92
|
+
## Minimal config
|
|
47
93
|
|
|
48
|
-
|
|
49
|
-
|
|
94
|
+
Most users can start with the packaged defaults and only set the Chrome profile if needed.
|
|
95
|
+
|
|
96
|
+
`~/.pi/agent/extensions/oracle.json`
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"defaults": {
|
|
101
|
+
"preset": "<preset id from ORACLE_SUBMIT_PRESETS>"
|
|
102
|
+
},
|
|
103
|
+
"auth": {
|
|
104
|
+
"chromeProfile": "Default"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
50
107
|
```
|
|
51
108
|
|
|
52
|
-
|
|
109
|
+
Notes:
|
|
110
|
+
- `defaults.preset` is the default ChatGPT model preset for oracle jobs.
|
|
111
|
+
- The canonical preset ids live in `extensions/oracle/lib/config.ts`.
|
|
112
|
+
- If the packaged default is fine, you can omit `defaults.preset` entirely.
|
|
113
|
+
- You usually do not need to set browser paths unless auto-detection fails.
|
|
114
|
+
|
|
115
|
+
Other useful settings:
|
|
116
|
+
- `browser.runMode`
|
|
117
|
+
- `browser.args`
|
|
118
|
+
- `browser.authSeedProfileDir`
|
|
119
|
+
- `browser.runtimeProfilesDir`
|
|
120
|
+
- `cleanup.completeJobRetentionMs`
|
|
121
|
+
- `cleanup.failedJobRetentionMs`
|
|
53
122
|
|
|
54
|
-
|
|
55
|
-
- paying API costs for every long review
|
|
56
|
-
- blocking the agent for 10–90 minutes
|
|
57
|
-
- stealing focus from the user’s active browser session
|
|
123
|
+
Project config should only override safe, non-privileged settings.
|
|
58
124
|
|
|
59
|
-
##
|
|
125
|
+
## What happens to outputs
|
|
60
126
|
|
|
61
|
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
- isolated auth seed profile + per-job runtime profile clones
|
|
66
|
-
- concurrent jobs across different projects/sessions
|
|
67
|
-
- workerless queued jobs when the global concurrency limit is full
|
|
68
|
-
- same-conversation exclusion for follow-ups
|
|
69
|
-
- plain-text responses
|
|
70
|
-
- artifact capture, including multi-artifact runs
|
|
71
|
-
|
|
72
|
-
Not promised yet:
|
|
73
|
-
- cross-platform support
|
|
74
|
-
- immunity to future ChatGPT UI changes
|
|
75
|
-
- fully polished partial-artifact terminal semantics
|
|
127
|
+
- Jobs persist their response and any artifacts under `${PI_ORACLE_JOBS_DIR:-/tmp}/oracle-<job-id>/` by default.
|
|
128
|
+
- Jobs can queue automatically if runtime capacity is full.
|
|
129
|
+
- Completion delivery into `pi` is best-effort wake-up based.
|
|
130
|
+
- If you miss the wake-up, use `oracle_read(jobId)` or `/oracle-status`.
|
|
76
131
|
|
|
77
132
|
## Requirements
|
|
78
133
|
|
|
79
134
|
- macOS
|
|
80
135
|
- Google Chrome installed
|
|
81
136
|
- ChatGPT already signed into a local Chrome profile
|
|
82
|
-
- `pi` 0.65.0 or newer
|
|
137
|
+
- `pi` 0.65.0 or newer
|
|
83
138
|
- `agent-browser` available on the machine
|
|
84
139
|
- `tar` and `zstd` available
|
|
85
140
|
|
|
86
|
-
##
|
|
141
|
+
## Troubleshooting
|
|
87
142
|
|
|
88
|
-
|
|
143
|
+
### `/oracle-auth` fails or says login is required
|
|
89
144
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
145
|
+
- Make sure ChatGPT works in the same local Chrome profile you configured.
|
|
146
|
+
- Re-run `/oracle-auth`.
|
|
147
|
+
- If ChatGPT is half-logged-in or challenge flow state looks weird, finish the login/challenge in the headed auth browser and retry.
|
|
93
148
|
|
|
94
|
-
|
|
149
|
+
### You hit a challenge / verification page
|
|
95
150
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
```
|
|
151
|
+
- Solve it in the auth/bootstrap browser if prompted.
|
|
152
|
+
- Then re-run `/oracle-auth` before submitting jobs again.
|
|
99
153
|
|
|
100
|
-
|
|
154
|
+
### You see "Oracle requires a persisted pi session"
|
|
101
155
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
3. Run `/oracle-auth`.
|
|
105
|
-
4. Run a tiny `/oracle` smoke test.
|
|
156
|
+
- Do not run oracle from `pi --no-session`.
|
|
157
|
+
- Start a normal persisted `pi` session, then use `/oracle` again.
|
|
106
158
|
|
|
107
|
-
|
|
159
|
+
### A job finished but no wake-up arrived
|
|
108
160
|
|
|
109
|
-
|
|
110
|
-
-
|
|
111
|
-
- project: `.pi/extensions/oracle.json`
|
|
161
|
+
- Use `/oracle-status [job-id]` or `oracle_read(jobId)`.
|
|
162
|
+
- Results are still saved on disk even if the reminder turn does not land.
|
|
112
163
|
|
|
113
|
-
|
|
114
|
-
- `browser.args`
|
|
115
|
-
- `browser.executablePath`
|
|
116
|
-
- `browser.authSeedProfileDir`
|
|
117
|
-
- `browser.runtimeProfilesDir`
|
|
118
|
-
- `auth.chromeProfile`
|
|
119
|
-
- `auth.chromeCookiePath`
|
|
120
|
-
- `cleanup.completeJobRetentionMs`
|
|
121
|
-
- `cleanup.failedJobRetentionMs`
|
|
164
|
+
### `agent-browser`, `tar`, or `zstd` is missing
|
|
122
165
|
|
|
123
|
-
|
|
166
|
+
- Install the missing local dependency and rerun the command.
|
|
167
|
+
|
|
168
|
+
### Auto-detection picked the wrong Chrome profile
|
|
169
|
+
|
|
170
|
+
- Set `auth.chromeProfile` in `~/.pi/agent/extensions/oracle.json`.
|
|
171
|
+
- Re-run `/oracle-auth`.
|
|
172
|
+
|
|
173
|
+
### You want more details about a failed run
|
|
174
|
+
|
|
175
|
+
- Inspect the job directory under `${PI_ORACLE_JOBS_DIR:-/tmp}/oracle-<job-id>/`.
|
|
176
|
+
- The worker log and captured diagnostics are stored there.
|
|
177
|
+
|
|
178
|
+
## Detailed docs
|
|
124
179
|
|
|
125
|
-
|
|
126
|
-
-
|
|
127
|
-
- completed/cancelled jobs are pruned after `cleanup.completeJobRetentionMs` based on terminal-job age, but recent wake-up sends keep response/artifact files retained briefly so follow-up turns do not point at deleted paths
|
|
128
|
-
- failed jobs are pruned after `cleanup.failedJobRetentionMs`
|
|
129
|
-
- `/oracle-cancel` can cancel queued or active jobs
|
|
130
|
-
- `/oracle-clean` refuses non-terminal jobs, including queued ones, refuses terminal jobs whose worker is still live, also refuses recently woken jobs during a short post-send retention grace window, performs runtime cleanup before removing terminal job directories, and reports cleanup warnings if any residual cleanup step fails
|
|
131
|
-
|
|
132
|
-
Detailed design and maintainer docs:
|
|
133
|
-
- `docs/ORACLE_DESIGN.md`
|
|
134
|
-
- `docs/ORACLE_RECOVERY_DRILL.md`
|
|
135
|
-
|
|
136
|
-
Completion notification semantics:
|
|
137
|
-
- oracle responses and artifacts are always persisted durably in oracle job state under the configured oracle jobs dir (`${PI_ORACLE_JOBS_DIR:-/tmp}/oracle-<job-id>/` by default)
|
|
138
|
-
- completion delivery into pi sessions is best-effort wake-up based; the extension no longer appends synthetic assistant completion messages into session history
|
|
139
|
-
- wake-up content tells the receiving assistant to call `oracle_read(jobId)` as the canonical completion-consumption path, with saved file paths included as secondary context
|
|
140
|
-
- manual `oracle_read` or `/oracle-status` inspection settles further reminder retries once the terminal job has been opened, and now persists settlement provenance for postmortems
|
|
141
|
-
- manual inspection before the first wake-up attempt is recorded as observation only and does not suppress the first reminder send
|
|
142
|
-
- if a wake-up does not land, the job remains available via its saved response/artifacts and status commands
|
|
180
|
+
- `docs/ORACLE_DESIGN.md` — architecture, lifecycle, queueing, persistence, presets, and recovery behavior
|
|
181
|
+
- `docs/ORACLE_RECOVERY_DRILL.md` — safe expired-auth recovery validation drill
|
|
143
182
|
|
|
144
183
|
## Privacy / local data
|
|
145
184
|
|
|
146
185
|
This extension is local-first, but it does read and persist local data:
|
|
147
186
|
- `/oracle-auth` reads ChatGPT cookies from a local Chrome profile
|
|
148
187
|
- job archives are uploaded to ChatGPT.com
|
|
149
|
-
- responses and artifacts are written under the configured oracle jobs dir
|
|
188
|
+
- responses and artifacts are written under the configured oracle jobs dir
|
|
150
189
|
|
|
151
190
|
Review the code and design docs before using it with sensitive material.
|
|
152
191
|
|
package/docs/ORACLE_DESIGN.md
CHANGED
|
@@ -133,7 +133,9 @@ The authenticated seed profile remains the source of truth for future oracle run
|
|
|
133
133
|
|
|
134
134
|
### `oracle_submit`
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
Agent-facing submissions use **`preset`**; the canonical registry is `ORACLE_SUBMIT_PRESETS` in `extensions/oracle/lib/config.ts`. **`preset` is the only model-selection parameter** on `oracle_submit`. There are no `modelFamily`, `effort`, or `autoSwitchToThinking` fields.
|
|
137
|
+
|
|
138
|
+
1. resolve the preset (submit-time or config default) into an execution snapshot
|
|
137
139
|
2. resolve optional `followUpJobId` into a prior `chatUrl` and `conversationId`
|
|
138
140
|
3. build the archive first into a temporary path
|
|
139
141
|
4. allocate a unique runtime:
|
|
@@ -216,9 +218,7 @@ Browser/auth settings are global-only because they control local privileged brow
|
|
|
216
218
|
```json
|
|
217
219
|
{
|
|
218
220
|
"defaults": {
|
|
219
|
-
"
|
|
220
|
-
"effort": "extended",
|
|
221
|
-
"autoSwitchToThinking": false
|
|
221
|
+
"preset": "<preset id from ORACLE_SUBMIT_PRESETS>"
|
|
222
222
|
},
|
|
223
223
|
"browser": {
|
|
224
224
|
"sessionPrefix": "oracle",
|
|
@@ -317,9 +317,7 @@ Important fields include:
|
|
|
317
317
|
- `sessionId`
|
|
318
318
|
- `originSessionFile`
|
|
319
319
|
- `requestSource`
|
|
320
|
-
- `
|
|
321
|
-
- `effort`
|
|
322
|
-
- `autoSwitchToThinking`
|
|
320
|
+
- `selection`: resolved execution snapshot with `{ preset, modelFamily, effort?, autoSwitchToThinking }`
|
|
323
321
|
- `followUpToJobId`
|
|
324
322
|
- `chatUrl`
|
|
325
323
|
- `conversationId`
|
|
@@ -10,13 +10,61 @@ export type OracleModelFamily = (typeof MODEL_FAMILIES)[number];
|
|
|
10
10
|
export const EFFORTS = ["light", "standard", "extended", "heavy"] as const;
|
|
11
11
|
export type OracleEffort = (typeof EFFORTS)[number];
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Canonical preset registry for `oracle_submit` preset selection.
|
|
15
|
+
* This is the single authored source of truth — all derived lists come from `Object.keys(...)`.
|
|
16
|
+
*/
|
|
17
|
+
export const ORACLE_SUBMIT_PRESETS = {
|
|
18
|
+
pro_standard: { label: "Pro - Standard", modelFamily: "pro" as const, effort: "standard" as const, autoSwitchToThinking: false },
|
|
19
|
+
pro_extended: { label: "Pro - Extended", modelFamily: "pro" as const, effort: "extended" as const, autoSwitchToThinking: false },
|
|
20
|
+
thinking_light: { label: "Thinking - Light", modelFamily: "thinking" as const, effort: "light" as const, autoSwitchToThinking: false },
|
|
21
|
+
thinking_standard: { label: "Thinking - Standard", modelFamily: "thinking" as const, effort: "standard" as const, autoSwitchToThinking: false },
|
|
22
|
+
thinking_extended: { label: "Thinking - Extended", modelFamily: "thinking" as const, effort: "extended" as const, autoSwitchToThinking: false },
|
|
23
|
+
thinking_heavy: { label: "Thinking - Heavy", modelFamily: "thinking" as const, effort: "heavy" as const, autoSwitchToThinking: false },
|
|
24
|
+
instant: { label: "Instant", modelFamily: "instant" as const, autoSwitchToThinking: false },
|
|
25
|
+
instant_auto_switch: { label: "Instant - Auto-switch to Thinking Enabled", modelFamily: "instant" as const, autoSwitchToThinking: true },
|
|
26
|
+
} as const;
|
|
27
|
+
|
|
28
|
+
export type OracleSubmitPresetId = keyof typeof ORACLE_SUBMIT_PRESETS;
|
|
29
|
+
|
|
30
|
+
export type OracleSubmitPreset = typeof ORACLE_SUBMIT_PRESETS[OracleSubmitPresetId];
|
|
31
|
+
|
|
32
|
+
export function getOracleSubmitPresetById(id: OracleSubmitPresetId): OracleSubmitPreset {
|
|
33
|
+
const found = ORACLE_SUBMIT_PRESETS[id];
|
|
34
|
+
if (!found) {
|
|
35
|
+
throw new Error(`Unknown oracle_submit preset: ${id}`);
|
|
36
|
+
}
|
|
37
|
+
return found;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Resolved execution snapshot generated from a preset at submit time. */
|
|
41
|
+
export type OracleResolvedSelection = {
|
|
42
|
+
preset: OracleSubmitPresetId;
|
|
43
|
+
modelFamily: OracleModelFamily;
|
|
44
|
+
effort?: OracleEffort;
|
|
45
|
+
autoSwitchToThinking: boolean;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Resolve a preset id into the execution snapshot that gets persisted on the job.
|
|
50
|
+
* @throws if the preset id is unknown.
|
|
51
|
+
*/
|
|
52
|
+
export function resolveOracleSubmitPreset(presetId: OracleSubmitPresetId): OracleResolvedSelection {
|
|
53
|
+
const def = getOracleSubmitPresetById(presetId);
|
|
54
|
+
return {
|
|
55
|
+
preset: presetId,
|
|
56
|
+
modelFamily: def.modelFamily,
|
|
57
|
+
effort: def.modelFamily === "instant" ? undefined : def.effort,
|
|
58
|
+
autoSwitchToThinking: def.modelFamily === "instant" ? def.autoSwitchToThinking : false,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
13
62
|
export const BROWSER_RUN_MODES = ["headless", "headed"] as const;
|
|
14
63
|
export type OracleBrowserRunMode = (typeof BROWSER_RUN_MODES)[number];
|
|
15
64
|
|
|
16
65
|
export const CLONE_STRATEGIES = ["apfs-clone", "copy"] as const;
|
|
17
66
|
export type OracleCloneStrategy = (typeof CLONE_STRATEGIES)[number];
|
|
18
67
|
|
|
19
|
-
const PRO_EFFORTS = ["standard", "extended"] as const satisfies readonly OracleEffort[];
|
|
20
68
|
const ALLOWED_CHATGPT_ORIGINS = new Set(["https://chatgpt.com", "https://chat.openai.com"]);
|
|
21
69
|
const PROJECT_OVERRIDE_KEYS = new Set(["defaults", "worker", "poller", "artifacts", "cleanup"]);
|
|
22
70
|
const DEFAULT_MAC_CHROME_EXECUTABLE = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
|
|
@@ -24,9 +72,7 @@ const DEFAULT_MAC_CHROME_USER_DATA_DIR = join(homedir(), "Library", "Application
|
|
|
24
72
|
|
|
25
73
|
export interface OracleConfig {
|
|
26
74
|
defaults: {
|
|
27
|
-
|
|
28
|
-
effort: OracleEffort;
|
|
29
|
-
autoSwitchToThinking: boolean;
|
|
75
|
+
preset: OracleSubmitPresetId;
|
|
30
76
|
};
|
|
31
77
|
browser: {
|
|
32
78
|
sessionPrefix: string;
|
|
@@ -98,9 +144,7 @@ const detectedChromeProfileName = detectDefaultChromeProfileName();
|
|
|
98
144
|
|
|
99
145
|
export const DEFAULT_CONFIG: OracleConfig = {
|
|
100
146
|
defaults: {
|
|
101
|
-
|
|
102
|
-
effort: "extended",
|
|
103
|
-
autoSwitchToThinking: false,
|
|
147
|
+
preset: "pro_extended",
|
|
104
148
|
},
|
|
105
149
|
browser: {
|
|
106
150
|
sessionPrefix: "oracle",
|
|
@@ -292,19 +336,13 @@ function normalizeLegacyBrowserConfig(root: Record<string, unknown>): Record<str
|
|
|
292
336
|
return root;
|
|
293
337
|
}
|
|
294
338
|
|
|
339
|
+
const PRESET_IDS = Object.keys(ORACLE_SUBMIT_PRESETS) as unknown as readonly OracleSubmitPresetId[];
|
|
340
|
+
|
|
295
341
|
function validateOracleConfig(value: unknown): OracleConfig {
|
|
296
342
|
const root = normalizeLegacyBrowserConfig(expectObject(value, "root"));
|
|
297
343
|
|
|
298
344
|
const defaults = expectObject(root.defaults, "defaults");
|
|
299
|
-
const
|
|
300
|
-
const effort = expectEnum(defaults.effort, "defaults.effort", EFFORTS);
|
|
301
|
-
const autoSwitchToThinking = expectBoolean(defaults.autoSwitchToThinking, "defaults.autoSwitchToThinking");
|
|
302
|
-
if (modelFamily === "pro" && effort !== "standard" && effort !== "extended") {
|
|
303
|
-
throw new Error(`Invalid oracle config: defaults.effort must be one of ${PRO_EFFORTS.join(", ")} for pro`);
|
|
304
|
-
}
|
|
305
|
-
if (modelFamily !== "instant" && autoSwitchToThinking) {
|
|
306
|
-
throw new Error("Invalid oracle config: defaults.autoSwitchToThinking is only valid for instant");
|
|
307
|
-
}
|
|
345
|
+
const preset = expectEnum(defaults.preset, "defaults.preset", PRESET_IDS);
|
|
308
346
|
|
|
309
347
|
const browser = expectObject(root.browser, "browser");
|
|
310
348
|
const auth = expectObject(root.auth, "auth");
|
|
@@ -321,9 +359,7 @@ function validateOracleConfig(value: unknown): OracleConfig {
|
|
|
321
359
|
|
|
322
360
|
return {
|
|
323
361
|
defaults: {
|
|
324
|
-
|
|
325
|
-
effort,
|
|
326
|
-
autoSwitchToThinking,
|
|
362
|
+
preset,
|
|
327
363
|
},
|
|
328
364
|
browser: {
|
|
329
365
|
sessionPrefix: expectString(browser.sessionPrefix, "browser.sessionPrefix"),
|
|
@@ -4,7 +4,7 @@ import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
|
4
4
|
import { chmod, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
5
5
|
import { join, resolve } from "node:path";
|
|
6
6
|
import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
7
|
-
import type { OracleConfig,
|
|
7
|
+
import type { OracleConfig, OracleResolvedSelection } from "./config.js";
|
|
8
8
|
import { withJobLock, withLock } from "./locks.js";
|
|
9
9
|
import { cleanupRuntimeArtifacts, getProjectId, getSessionId, parseConversationId, requirePersistedSessionFile, type OracleCleanupReport } from "./runtime.js";
|
|
10
10
|
|
|
@@ -133,9 +133,7 @@ export interface OracleJob {
|
|
|
133
133
|
sessionId: string;
|
|
134
134
|
originSessionFile?: string;
|
|
135
135
|
requestSource: "command" | "tool";
|
|
136
|
-
|
|
137
|
-
effort?: OracleEffort;
|
|
138
|
-
autoSwitchToThinking?: boolean;
|
|
136
|
+
selection: OracleResolvedSelection;
|
|
139
137
|
followUpToJobId?: string;
|
|
140
138
|
chatUrl?: string;
|
|
141
139
|
conversationId?: string;
|
|
@@ -185,9 +183,7 @@ export interface OracleJob {
|
|
|
185
183
|
export interface OracleSubmitInput {
|
|
186
184
|
prompt: string;
|
|
187
185
|
files: string[];
|
|
188
|
-
|
|
189
|
-
effort?: OracleEffort;
|
|
190
|
-
autoSwitchToThinking?: boolean;
|
|
186
|
+
selection: OracleResolvedSelection;
|
|
191
187
|
followUpToJobId?: string;
|
|
192
188
|
chatUrl?: string;
|
|
193
189
|
requestSource: "command" | "tool";
|
|
@@ -971,10 +967,6 @@ export async function createJob(
|
|
|
971
967
|
|
|
972
968
|
const createdAt = options?.createdAt ?? new Date().toISOString();
|
|
973
969
|
const initialState = options?.initialState ?? "submitted";
|
|
974
|
-
const normalizedEffort = input.modelFamily === "instant" ? undefined : (input.effort ?? config.defaults.effort);
|
|
975
|
-
const normalizedAutoSwitchToThinking = input.modelFamily === "instant"
|
|
976
|
-
? (input.autoSwitchToThinking ?? config.defaults.autoSwitchToThinking)
|
|
977
|
-
: false;
|
|
978
970
|
const job: OracleJob = {
|
|
979
971
|
id,
|
|
980
972
|
status: initialState,
|
|
@@ -988,9 +980,7 @@ export async function createJob(
|
|
|
988
980
|
sessionId,
|
|
989
981
|
originSessionFile: sessionFile,
|
|
990
982
|
requestSource: input.requestSource,
|
|
991
|
-
|
|
992
|
-
effort: normalizedEffort,
|
|
993
|
-
autoSwitchToThinking: normalizedAutoSwitchToThinking,
|
|
983
|
+
selection: input.selection,
|
|
994
984
|
followUpToJobId: input.followUpToJobId,
|
|
995
985
|
chatUrl: input.followUpToJobId ? input.chatUrl : undefined,
|
|
996
986
|
conversationId,
|
|
@@ -5,7 +5,12 @@ import { basename, join, posix } from "node:path";
|
|
|
5
5
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
6
6
|
import { Type } from "@sinclair/typebox";
|
|
7
7
|
import { isLockTimeoutError, withGlobalReconcileLock, withLock } from "./locks.js";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
loadOracleConfig,
|
|
10
|
+
ORACLE_SUBMIT_PRESETS,
|
|
11
|
+
resolveOracleSubmitPreset,
|
|
12
|
+
type OracleSubmitPresetId,
|
|
13
|
+
} from "./config.js";
|
|
9
14
|
import {
|
|
10
15
|
appendCleanupWarnings,
|
|
11
16
|
cancelOracleJob,
|
|
@@ -53,10 +58,11 @@ const ORACLE_SUBMIT_PARAMS = Type.Object({
|
|
|
53
58
|
description: "Exact project-relative files/directories to include in the oracle archive.",
|
|
54
59
|
minItems: 1,
|
|
55
60
|
}),
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
preset: Type.Optional(
|
|
62
|
+
stringEnum(
|
|
63
|
+
[...Object.keys(ORACLE_SUBMIT_PRESETS)] as const,
|
|
64
|
+
"ChatGPT model preset. Omit to use the configured default preset.",
|
|
65
|
+
),
|
|
60
66
|
),
|
|
61
67
|
followUpJobId: Type.Optional(Type.String({ description: "Earlier oracle job id whose chat thread should be continued." })),
|
|
62
68
|
});
|
|
@@ -69,12 +75,6 @@ const ORACLE_CANCEL_PARAMS = Type.Object({
|
|
|
69
75
|
jobId: Type.String({ description: "Oracle job id." }),
|
|
70
76
|
});
|
|
71
77
|
|
|
72
|
-
const VALID_EFFORTS: Record<OracleModelFamily, readonly OracleEffort[]> = {
|
|
73
|
-
instant: [],
|
|
74
|
-
thinking: ["light", "standard", "extended", "heavy"],
|
|
75
|
-
pro: ["standard", "extended"],
|
|
76
|
-
};
|
|
77
|
-
|
|
78
78
|
const MAX_ARCHIVE_BYTES = 250 * 1024 * 1024;
|
|
79
79
|
const MAX_QUEUED_JOBS_PER_ACTIVE_RUNTIME = 1;
|
|
80
80
|
const MAX_QUEUED_ARCHIVE_BYTES_PER_ACTIVE_RUNTIME = MAX_ARCHIVE_BYTES;
|
|
@@ -491,29 +491,6 @@ export function getQueueAdmissionFailure(args: {
|
|
|
491
491
|
return undefined;
|
|
492
492
|
}
|
|
493
493
|
|
|
494
|
-
function validateSubmissionOptions(
|
|
495
|
-
params: { effort?: OracleEffort; autoSwitchToThinking?: boolean },
|
|
496
|
-
modelFamily: OracleModelFamily,
|
|
497
|
-
effort: OracleEffort | undefined,
|
|
498
|
-
autoSwitchToThinking: boolean,
|
|
499
|
-
): void {
|
|
500
|
-
if (modelFamily === "instant" && params.effort !== undefined) {
|
|
501
|
-
throw new Error("Instant model family does not support effort selection");
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
if (effort && !VALID_EFFORTS[modelFamily].includes(effort)) {
|
|
505
|
-
throw new Error(`Invalid effort for ${modelFamily}: ${effort}`);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
if (modelFamily !== "instant" && params.autoSwitchToThinking === true) {
|
|
509
|
-
throw new Error("autoSwitchToThinking is only valid for the instant model family");
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
if (modelFamily !== "instant" && autoSwitchToThinking) {
|
|
513
|
-
throw new Error(`autoSwitchToThinking cannot be enabled for ${modelFamily}`);
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
494
|
function resolveFollowUp(previousJobId: string | undefined, cwd: string): {
|
|
518
495
|
followUpToJobId?: string;
|
|
519
496
|
chatUrl?: string;
|
|
@@ -601,7 +578,8 @@ export function registerOracleTools(pi: ExtensionAPI, workerPath: string): void
|
|
|
601
578
|
name: "oracle_submit",
|
|
602
579
|
label: "Oracle Submit",
|
|
603
580
|
description:
|
|
604
|
-
"Dispatch a background ChatGPT web oracle job after gathering context. Always pass a prompt and exact project-relative archive inputs."
|
|
581
|
+
"Dispatch a background ChatGPT web oracle job after gathering context. Always pass a prompt and exact project-relative archive inputs. " +
|
|
582
|
+
"Optional ChatGPT model: set parameter `preset`, or omit it for configured defaults (see `preset` field for allowed ids).",
|
|
605
583
|
promptSnippet: "Dispatch a background ChatGPT web oracle job after gathering repo context.",
|
|
606
584
|
promptGuidelines: [
|
|
607
585
|
"Gather context before calling oracle_submit.",
|
|
@@ -613,7 +591,7 @@ export function registerOracleTools(pi: ExtensionAPI, workerPath: string): void
|
|
|
613
591
|
"If oracle_submit itself fails because the local archive still exceeds the upload limit after default exclusions and automatic generic generated-output-dir pruning, or for any other submit-time error, stop and report the error instead of retrying automatically.",
|
|
614
592
|
"If oracle_submit returns a queued job instead of an immediately dispatched one, treat that as success and stop exactly the same way.",
|
|
615
593
|
"Stop after dispatching oracle_submit; do not continue the task while the oracle job is running.",
|
|
616
|
-
"
|
|
594
|
+
"Use `preset` as the only model-selection parameter on oracle_submit. Allowed values come from the tool schema enum. Omit preset to use the configured default.",
|
|
617
595
|
],
|
|
618
596
|
parameters: ORACLE_SUBMIT_PARAMS,
|
|
619
597
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
@@ -621,16 +599,9 @@ export function registerOracleTools(pi: ExtensionAPI, workerPath: string): void
|
|
|
621
599
|
const originSessionFile = requirePersistedSessionFile(getSessionFile(ctx), "submit oracle jobs");
|
|
622
600
|
const projectId = getProjectId(ctx.cwd);
|
|
623
601
|
const sessionId = getSessionId(originSessionFile, projectId);
|
|
624
|
-
const
|
|
625
|
-
const
|
|
626
|
-
const modelFamily: OracleModelFamily = submittedModelFamily ?? config.defaults.modelFamily;
|
|
627
|
-
const requestedEffort: OracleEffort = submittedEffort ?? config.defaults.effort;
|
|
628
|
-
const effort: OracleEffort | undefined = modelFamily === "instant" ? undefined : requestedEffort;
|
|
629
|
-
const rawAutoSwitchToThinking = params.autoSwitchToThinking ?? config.defaults.autoSwitchToThinking;
|
|
630
|
-
const autoSwitchToThinking = modelFamily === "instant" ? rawAutoSwitchToThinking : false;
|
|
602
|
+
const presetId = (params.preset as OracleSubmitPresetId | undefined) ?? config.defaults.preset;
|
|
603
|
+
const selection = resolveOracleSubmitPreset(presetId);
|
|
631
604
|
const followUp = resolveFollowUp(params.followUpJobId, ctx.cwd);
|
|
632
|
-
|
|
633
|
-
validateSubmissionOptions({ effort: submittedEffort, autoSwitchToThinking: params.autoSwitchToThinking }, modelFamily, effort, autoSwitchToThinking);
|
|
634
605
|
try {
|
|
635
606
|
await withGlobalReconcileLock({ processPid: process.pid, source: "oracle_submit", cwd: ctx.cwd }, async () => {
|
|
636
607
|
await reconcileStaleOracleJobs();
|
|
@@ -691,9 +662,7 @@ export function registerOracleTools(pi: ExtensionAPI, workerPath: string): void
|
|
|
691
662
|
{
|
|
692
663
|
prompt: params.prompt,
|
|
693
664
|
files: params.files,
|
|
694
|
-
|
|
695
|
-
effort,
|
|
696
|
-
autoSwitchToThinking,
|
|
665
|
+
selection,
|
|
697
666
|
followUpToJobId: followUp.followUpToJobId,
|
|
698
667
|
chatUrl: followUp.chatUrl,
|
|
699
668
|
requestSource: "tool",
|
|
@@ -736,9 +705,7 @@ export function registerOracleTools(pi: ExtensionAPI, workerPath: string): void
|
|
|
736
705
|
{
|
|
737
706
|
prompt: params.prompt,
|
|
738
707
|
files: params.files,
|
|
739
|
-
|
|
740
|
-
effort,
|
|
741
|
-
autoSwitchToThinking,
|
|
708
|
+
selection,
|
|
742
709
|
followUpToJobId: followUp.followUpToJobId,
|
|
743
710
|
chatUrl: followUp.chatUrl,
|
|
744
711
|
requestSource: "tool",
|
|
@@ -807,7 +807,7 @@ function matchesModelFamilyButton(candidate, family) {
|
|
|
807
807
|
}
|
|
808
808
|
|
|
809
809
|
function requestedEffortLabel(job) {
|
|
810
|
-
return job.effort ? titleCase(job.effort) : undefined;
|
|
810
|
+
return job.selection?.effort ? titleCase(job.selection.effort) : undefined;
|
|
811
811
|
}
|
|
812
812
|
|
|
813
813
|
function effortSelectionVisible(snapshot, effortLabel) {
|
|
@@ -852,12 +852,12 @@ function snapshotHasModelConfigurationUi(snapshot) {
|
|
|
852
852
|
|
|
853
853
|
function snapshotStronglyMatchesRequestedModel(snapshot, job) {
|
|
854
854
|
const entries = parseSnapshotEntries(snapshot);
|
|
855
|
-
const familyMatched = entries.some((entry) => matchesModelFamilyButton(entry, job.
|
|
855
|
+
const familyMatched = entries.some((entry) => matchesModelFamilyButton(entry, job.selection.modelFamily));
|
|
856
856
|
const effortLabel = requestedEffortLabel(job);
|
|
857
|
-
if (job.
|
|
857
|
+
if (job.selection.modelFamily === "thinking") {
|
|
858
858
|
return familyMatched || effortSelectionVisible(snapshot, effortLabel);
|
|
859
859
|
}
|
|
860
|
-
if (job.
|
|
860
|
+
if (job.selection.modelFamily === "pro") {
|
|
861
861
|
return effortLabel ? familyMatched && effortSelectionVisible(snapshot, effortLabel) : familyMatched;
|
|
862
862
|
}
|
|
863
863
|
return familyMatched;
|
|
@@ -880,13 +880,13 @@ function composerControlsVisible(snapshot) {
|
|
|
880
880
|
}
|
|
881
881
|
|
|
882
882
|
function snapshotWeaklyMatchesRequestedModel(snapshot, job) {
|
|
883
|
-
if (job.
|
|
883
|
+
if (job.selection.modelFamily === "thinking") {
|
|
884
884
|
return effortSelectionVisible(snapshot, requestedEffortLabel(job)) || thinkingSelectionVisible(snapshot);
|
|
885
885
|
}
|
|
886
|
-
if (job.
|
|
886
|
+
if (job.selection.modelFamily === "pro") {
|
|
887
887
|
return !thinkingChipVisible(snapshot);
|
|
888
888
|
}
|
|
889
|
-
if (job.
|
|
889
|
+
if (job.selection.modelFamily === "instant") {
|
|
890
890
|
return !thinkingChipVisible(snapshot);
|
|
891
891
|
}
|
|
892
892
|
return false;
|
|
@@ -1214,7 +1214,7 @@ async function waitForModelConfigurationToSettle(job, options = {}) {
|
|
|
1214
1214
|
if (options.stronglyVerified) {
|
|
1215
1215
|
if (!fallbackLogged) {
|
|
1216
1216
|
fallbackLogged = true;
|
|
1217
|
-
await log(`Model configuration closed after strong in-dialog verification for family=${job.
|
|
1217
|
+
await log(`Model configuration closed after strong in-dialog verification for family=${job.selection.modelFamily} effort=${job.selection?.effort || "(none)"}`);
|
|
1218
1218
|
}
|
|
1219
1219
|
return;
|
|
1220
1220
|
}
|
|
@@ -1223,7 +1223,7 @@ async function waitForModelConfigurationToSettle(job, options = {}) {
|
|
|
1223
1223
|
if (!configurationUiVisible && composerControlsVisible(snapshot) && options.stronglyVerified) {
|
|
1224
1224
|
if (!fallbackLogged) {
|
|
1225
1225
|
fallbackLogged = true;
|
|
1226
|
-
await log(`Composer became usable after strong in-dialog verification for family=${job.
|
|
1226
|
+
await log(`Composer became usable after strong in-dialog verification for family=${job.selection.modelFamily} effort=${job.selection?.effort || "(none)"}`);
|
|
1227
1227
|
}
|
|
1228
1228
|
return;
|
|
1229
1229
|
}
|
|
@@ -1239,30 +1239,30 @@ async function waitForModelConfigurationToSettle(job, options = {}) {
|
|
|
1239
1239
|
}
|
|
1240
1240
|
|
|
1241
1241
|
if (options.stronglyVerified && lastSnapshot && !snapshotHasModelConfigurationUi(lastSnapshot)) {
|
|
1242
|
-
await log(`Model configuration closed only after settle-timeout for family=${job.
|
|
1242
|
+
await log(`Model configuration closed only after settle-timeout for family=${job.selection.modelFamily} effort=${job.selection?.effort || "(none)"}`);
|
|
1243
1243
|
return;
|
|
1244
1244
|
}
|
|
1245
1245
|
|
|
1246
|
-
throw new Error(`Could not verify requested model settings after configuration for ${job.
|
|
1246
|
+
throw new Error(`Could not verify requested model settings after configuration for ${job.selection.modelFamily}`);
|
|
1247
1247
|
}
|
|
1248
1248
|
|
|
1249
1249
|
async function configureModel(job) {
|
|
1250
1250
|
const initialSnapshot = await snapshotText(job);
|
|
1251
1251
|
if (snapshotStronglyMatchesRequestedModel(initialSnapshot, job)) {
|
|
1252
|
-
await log(`Model already appears configured for family=${job.
|
|
1252
|
+
await log(`Model already appears configured for family=${job.selection.modelFamily} effort=${job.selection?.effort || "(none)"}; skipping reconfiguration`);
|
|
1253
1253
|
return;
|
|
1254
1254
|
}
|
|
1255
1255
|
|
|
1256
|
-
await log(`Configuring model family=${job.
|
|
1256
|
+
await log(`Configuring model family=${job.selection.modelFamily} effort=${job.selection?.effort || "(none)"}`);
|
|
1257
1257
|
let familySnapshot = await openModelConfiguration(job);
|
|
1258
1258
|
let verificationSnapshot = familySnapshot;
|
|
1259
1259
|
|
|
1260
|
-
let familyEntry = findEntry(familySnapshot, (candidate) => matchesModelFamilyButton(candidate, job.
|
|
1260
|
+
let familyEntry = findEntry(familySnapshot, (candidate) => matchesModelFamilyButton(candidate, job.selection.modelFamily));
|
|
1261
1261
|
if (!familyEntry && snapshotStronglyMatchesRequestedModel(familySnapshot, job)) {
|
|
1262
1262
|
await log("Model configuration UI opened with requested settings already selected");
|
|
1263
1263
|
}
|
|
1264
1264
|
if (!familyEntry && !snapshotStronglyMatchesRequestedModel(familySnapshot, job)) {
|
|
1265
|
-
throw new Error(`Could not find model family button for ${job.
|
|
1265
|
+
throw new Error(`Could not find model family button for ${job.selection.modelFamily}`);
|
|
1266
1266
|
}
|
|
1267
1267
|
|
|
1268
1268
|
if (familyEntry) {
|
|
@@ -1272,7 +1272,7 @@ async function configureModel(job) {
|
|
|
1272
1272
|
verificationSnapshot = familySnapshot;
|
|
1273
1273
|
}
|
|
1274
1274
|
|
|
1275
|
-
if (job.
|
|
1275
|
+
if (job.selection.modelFamily === "thinking" || job.selection.modelFamily === "pro") {
|
|
1276
1276
|
const effortLabel = requestedEffortLabel(job);
|
|
1277
1277
|
if (effortLabel && !effortSelectionVisible(familySnapshot, effortLabel)) {
|
|
1278
1278
|
const opened = await openEffortDropdown(job);
|
|
@@ -1294,14 +1294,14 @@ async function configureModel(job) {
|
|
|
1294
1294
|
}
|
|
1295
1295
|
}
|
|
1296
1296
|
|
|
1297
|
-
if (job.
|
|
1297
|
+
if (job.selection.modelFamily === "instant" && job.selection.autoSwitchToThinking) {
|
|
1298
1298
|
await maybeClickLabeledEntry(job, CHATGPT_LABELS.autoSwitchToThinking);
|
|
1299
1299
|
verificationSnapshot = await snapshotText(job);
|
|
1300
1300
|
}
|
|
1301
1301
|
|
|
1302
1302
|
const stronglyVerified = snapshotStronglyMatchesRequestedModel(verificationSnapshot, job);
|
|
1303
1303
|
if (!stronglyVerified) {
|
|
1304
|
-
throw new Error(`Could not verify requested model settings in configuration UI for ${job.
|
|
1304
|
+
throw new Error(`Could not verify requested model settings in configuration UI for ${job.selection.modelFamily}`);
|
|
1305
1305
|
}
|
|
1306
1306
|
|
|
1307
1307
|
if (!(await maybeClickLabeledEntry(job, CHATGPT_LABELS.close, { kind: "button" }))) {
|
package/package.json
CHANGED
package/prompts/oracle.md
CHANGED
|
@@ -13,6 +13,12 @@ Required workflow:
|
|
|
13
13
|
5. Call oracle_submit with the prompt and exact archive inputs.
|
|
14
14
|
6. Stop immediately after dispatching the oracle job.
|
|
15
15
|
|
|
16
|
+
Oracle model (`oracle_submit`):
|
|
17
|
+
- To choose a specific ChatGPT model, pass **`preset`** with one of the allowed ids from the tool schema enum / canonical preset registry.
|
|
18
|
+
- **Or** omit **`preset`** entirely to use the configured default model (from oracle config).
|
|
19
|
+
- **`preset`** is the only model-selection parameter on `oracle_submit`. Do not pass `modelFamily`, `effort`, or `autoSwitchToThinking`.
|
|
20
|
+
- If unsure which preset fits the task, ask the user.
|
|
21
|
+
|
|
16
22
|
Rules:
|
|
17
23
|
- Always include an archive. Do not submit without context files.
|
|
18
24
|
- By default, include the whole repository by passing `.`. Default archive exclusions apply automatically, including common bulky outputs and obvious credentials/private data like `.env` files, key material, credential dotfiles, local database files, and root `secrets/` directories.
|
|
@@ -21,8 +27,7 @@ Rules:
|
|
|
21
27
|
- If the request depends on git state or pending changes (for example code review, ship readiness, or release approval), create a tracked diff bundle file inside the repo (for example under `.pi/`) containing `git status` plus `git diff` output, include that file in the archive, and tell the oracle to use it because the `.git` directory is not included in oracle exports.
|
|
22
28
|
- When `files=["."]` and the post-exclusion archive is still too large, submit automatically prunes the largest nested directories matching generic generated-output names like `build/`, `dist/`, `out/`, `coverage/`, and `tmp/` outside obvious source roots like `src/` and `lib/` until the archive fits or no candidate remains. Successful submissions report what was pruned.
|
|
23
29
|
- If a submitted oracle job later fails because upload is rejected, retry with a smaller archive in this order: (1) remove the largest obviously irrelevant/generated content, (2) if still too large, include modified files plus adjacent files plus directly relevant subtrees, (3) if still too large, explain the cut or ask the user.
|
|
24
|
-
- Prefer the configured default
|
|
25
|
-
- Only use autoSwitchToThinking with the instant model family.
|
|
30
|
+
- Prefer the configured default (omit **`preset`**) unless the task clearly needs a different model; then choose a **`preset`** id from the tool schema enum.
|
|
26
31
|
- If `oracle_submit` itself fails because the local archive still exceeds the upload limit after default exclusions and automatic generic generated-output-dir pruning, or for any other submit-time error, stop and report the error. Do not retry automatically.
|
|
27
32
|
- If `oracle_submit` returns a queued job instead of an immediately dispatched one, treat that as success and end your turn exactly the same way.
|
|
28
33
|
- After oracle_submit returns, end your turn. Do not keep working while the oracle runs.
|