@benvargas/pi-openai-verbosity 1.0.1 → 1.1.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/README.md +67 -18
- package/extensions/index.ts +41 -14
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -20,8 +20,9 @@ pi has since shipped an upstream fix: OpenAI Codex Responses requests now defaul
|
|
|
20
20
|
explicit verbosity is provided.
|
|
21
21
|
|
|
22
22
|
That upstream change addresses the original `gpt-5.5` issue, but it also means pi now defaults every
|
|
23
|
-
`openai-codex` model to `low`. That may not be ideal for all model slugs. For example,
|
|
24
|
-
`gpt-5.
|
|
23
|
+
`openai-codex` model to `low`. That may not be ideal for all model slugs. For example, the Codex CLI's own
|
|
24
|
+
default for `gpt-5.4-mini` is `medium`, not `low`, and you may prefer `high` on a model you use for
|
|
25
|
+
long-form writing.
|
|
25
26
|
|
|
26
27
|
This extension now provides the missing user-facing control: per-slug verbosity settings for pi's
|
|
27
28
|
`openai-codex` provider.
|
|
@@ -73,20 +74,27 @@ reloads the config file.
|
|
|
73
74
|
Config files follow pi's project-over-global pattern:
|
|
74
75
|
|
|
75
76
|
- Project: `<repo>/.pi/extensions/pi-openai-verbosity.json`
|
|
76
|
-
- Global:
|
|
77
|
+
- Global: `<agent-dir>/extensions/pi-openai-verbosity.json`
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
The global path uses pi's agent directory — `~/.pi/agent` by default, or wherever `PI_CODING_AGENT_DIR`
|
|
80
|
+
points if you have relocated it.
|
|
81
|
+
|
|
82
|
+
Older versions of this extension always used `~/.pi/agent`, even when `PI_CODING_AGENT_DIR` was set. If you
|
|
83
|
+
have relocated the agent directory and it contains no config, a config left at the legacy
|
|
84
|
+
`~/.pi/agent/extensions/pi-openai-verbosity.json` path is still honored; it is read in place and never
|
|
85
|
+
modified. A config in the relocated directory takes precedence once you create one there.
|
|
86
|
+
|
|
87
|
+
If no config exists at any of these locations, the extension writes a default global config on first run.
|
|
79
88
|
|
|
80
89
|
Example config:
|
|
81
90
|
|
|
82
91
|
```json
|
|
83
92
|
{
|
|
84
93
|
"models": {
|
|
94
|
+
"openai-codex/gpt-5.6-sol": "low",
|
|
85
95
|
"openai-codex/gpt-5.5": "low",
|
|
86
|
-
"openai-codex/gpt-5.4": "
|
|
87
|
-
"openai-codex/gpt-5.3-codex": "medium"
|
|
88
|
-
"openai-codex/gpt-5.3-codex-spark": "medium",
|
|
89
|
-
"openai-codex/gpt-5.2": "medium"
|
|
96
|
+
"openai-codex/gpt-5.4-mini": "medium",
|
|
97
|
+
"openai-codex/gpt-5.3-codex-spark": "medium"
|
|
90
98
|
}
|
|
91
99
|
}
|
|
92
100
|
```
|
|
@@ -100,24 +108,63 @@ native default behavior applies.
|
|
|
100
108
|
|
|
101
109
|
## Default Config
|
|
102
110
|
|
|
103
|
-
By default, the extension
|
|
104
|
-
|
|
111
|
+
By default, the extension mirrors the Codex CLI's own per-model verbosity defaults for every model in pi's
|
|
112
|
+
`openai-codex` catalog. That means `low` everywhere except `gpt-5.4-mini`, whose upstream default is `medium`
|
|
113
|
+
(pi's blanket fallback would otherwise force it to `low`):
|
|
105
114
|
|
|
106
115
|
```json
|
|
107
116
|
{
|
|
108
117
|
"models": {
|
|
118
|
+
"openai-codex/gpt-5.3-codex-spark": "low",
|
|
109
119
|
"openai-codex/gpt-5.4": "low",
|
|
120
|
+
"openai-codex/gpt-5.4-mini": "medium",
|
|
110
121
|
"openai-codex/gpt-5.5": "low",
|
|
111
|
-
"openai-codex/gpt-5.
|
|
112
|
-
"openai-codex/gpt-5.
|
|
113
|
-
"openai-codex/gpt-5.
|
|
114
|
-
"openai-codex/gpt-5.2": "low",
|
|
115
|
-
"openai-codex/codex-auto-review": "low"
|
|
122
|
+
"openai-codex/gpt-5.6-luna": "low",
|
|
123
|
+
"openai-codex/gpt-5.6-sol": "low",
|
|
124
|
+
"openai-codex/gpt-5.6-terra": "low"
|
|
116
125
|
}
|
|
117
126
|
}
|
|
118
127
|
```
|
|
119
128
|
|
|
120
|
-
You can change any value to
|
|
129
|
+
You can change any value to override the default for that model. If you have an existing config file from an
|
|
130
|
+
older version of this extension, your file's entries win over these defaults, and entries for model slugs pi no
|
|
131
|
+
longer exposes are simply ignored.
|
|
132
|
+
|
|
133
|
+
## Why not `samplingParams`?
|
|
134
|
+
|
|
135
|
+
pi 0.84.0 added `samplingParams`, which lets you pass arbitrary OpenAI-compatible parameters through
|
|
136
|
+
`models.json`, model overrides, and extension providers. Reading those release notes, it is natural to assume
|
|
137
|
+
this extension is now redundant and that you can write:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"modelOverrides": {
|
|
142
|
+
"openai-codex/gpt-5.5": {
|
|
143
|
+
"samplingParams": { "text": { "verbosity": "medium" } }
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**On `openai-codex` this silently does nothing.** There is no error and no warning; the setting is simply never
|
|
150
|
+
applied. `samplingParams` is explicitly scoped to OpenAI-*compatible* adapters — pi-ai documents it as "only
|
|
151
|
+
applied by OpenAI-compatible adapters (completions, responses, Azure responses); other APIs ignore it" — and
|
|
152
|
+
the Codex adapter is not one of them. It builds its own request and hardcodes `text: { verbosity: ... }`,
|
|
153
|
+
defaulting to `low`.
|
|
154
|
+
|
|
155
|
+
So for the `openai-codex` provider, this extension remains the only way to set per-model verbosity.
|
|
156
|
+
|
|
157
|
+
### If you use `samplingParams` on the plain `openai` provider
|
|
158
|
+
|
|
159
|
+
There it *is* applied, but the merge is a shallow top-level `Object.assign`. That means:
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{ "samplingParams": { "text": { "verbosity": "medium" } } }
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
replaces the **entire** `text` object rather than merging into it, discarding any other `text` fields pi had
|
|
166
|
+
already set. This extension deliberately does the opposite: it preserves existing `text` fields and replaces
|
|
167
|
+
only `text.verbosity`.
|
|
121
168
|
|
|
122
169
|
## Debugging
|
|
123
170
|
|
|
@@ -131,7 +178,7 @@ matching and rewriting a request, set `PI_OPENAI_VERBOSITY_DEBUG_LOG` to a JSONL
|
|
|
131
178
|
```bash
|
|
132
179
|
PI_OPENAI_VERBOSITY_DEBUG_LOG=/tmp/pi-openai-verbosity.jsonl \
|
|
133
180
|
pi -e npm:@benvargas/pi-openai-verbosity \
|
|
134
|
-
--model openai-codex/gpt-5.
|
|
181
|
+
--model openai-codex/gpt-5.6-sol \
|
|
135
182
|
-p "Reply in one short sentence."
|
|
136
183
|
```
|
|
137
184
|
|
|
@@ -148,7 +195,9 @@ delete it when you are done debugging.
|
|
|
148
195
|
|
|
149
196
|
- This extension only changes outgoing provider request payloads.
|
|
150
197
|
- Existing `text` fields are preserved, and only `text.verbosity` is replaced.
|
|
151
|
-
- Only the `openai-codex` provider is supported.
|
|
198
|
+
- Only the `openai-codex` provider is supported. pi 0.84.0's `samplingParams` does not reach that provider, so
|
|
199
|
+
this extension remains the only per-model verbosity control for it — see
|
|
200
|
+
[Why not `samplingParams`?](#why-not-samplingparams).
|
|
152
201
|
- This extension is most useful if you want different verbosity settings for different OpenAI Codex model slugs.
|
|
153
202
|
|
|
154
203
|
## Uninstall
|
package/extensions/index.ts
CHANGED
|
@@ -4,26 +4,34 @@
|
|
|
4
4
|
* Sets OpenAI Responses `text.verbosity` for configured models via the
|
|
5
5
|
* `before_provider_request` hook. Config precedence is project
|
|
6
6
|
* `.pi/extensions/pi-openai-verbosity.json` over global
|
|
7
|
-
*
|
|
7
|
+
* `<agent-dir>/extensions/pi-openai-verbosity.json`, where the agent
|
|
8
|
+
* directory comes from pi's getAgentDir (honoring PI_CODING_AGENT_DIR).
|
|
9
|
+
* Older versions always used `~/.pi/agent`; when the agent directory is
|
|
10
|
+
* relocated and has no config, a config at that legacy path is still read
|
|
11
|
+
* (in place, never modified) so existing settings keep working.
|
|
8
12
|
*/
|
|
9
13
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
10
14
|
import { homedir } from "node:os";
|
|
11
15
|
import { dirname, join } from "node:path";
|
|
12
16
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
17
|
+
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
13
18
|
|
|
14
19
|
const VERBOSITY_COMMAND = "openai-verbosity";
|
|
15
20
|
const VERBOSITY_CONFIG_BASENAME = "pi-openai-verbosity.json";
|
|
16
21
|
const VERBOSITY_COMMAND_ARGS = ["status"] as const;
|
|
17
22
|
const DEBUG_LOG_ENV = "PI_OPENAI_VERBOSITY_DEBUG_LOG";
|
|
18
23
|
const SUPPORTED_PROVIDERS = ["openai-codex"] as const;
|
|
24
|
+
// Mirrors the Codex CLI upstream defaults for every model in pi's openai-codex
|
|
25
|
+
// catalog. pi itself falls back to `low` for all codex requests, which matches
|
|
26
|
+
// upstream everywhere except gpt-5.4-mini (upstream default: medium).
|
|
19
27
|
const DEFAULT_MODEL_VERBOSITY = {
|
|
28
|
+
"openai-codex/gpt-5.3-codex-spark": "low",
|
|
20
29
|
"openai-codex/gpt-5.4": "low",
|
|
30
|
+
"openai-codex/gpt-5.4-mini": "medium",
|
|
21
31
|
"openai-codex/gpt-5.5": "low",
|
|
22
|
-
"openai-codex/gpt-5.
|
|
23
|
-
"openai-codex/gpt-5.
|
|
24
|
-
"openai-codex/gpt-5.
|
|
25
|
-
"openai-codex/gpt-5.2": "low",
|
|
26
|
-
"openai-codex/codex-auto-review": "low",
|
|
32
|
+
"openai-codex/gpt-5.6-luna": "low",
|
|
33
|
+
"openai-codex/gpt-5.6-sol": "low",
|
|
34
|
+
"openai-codex/gpt-5.6-terra": "low",
|
|
27
35
|
} as const;
|
|
28
36
|
|
|
29
37
|
type TextVerbosity = "low" | "medium" | "high";
|
|
@@ -97,16 +105,23 @@ function getConfigCwd(ctx: ExtensionContext): string {
|
|
|
97
105
|
return ctx.cwd || process.cwd();
|
|
98
106
|
}
|
|
99
107
|
|
|
108
|
+
// The second parameter keeps its pre-0.84 homeDir meaning so existing callers of the
|
|
109
|
+
// exported helpers are unaffected. The agentDir default mirrors pi's getAgentDir():
|
|
110
|
+
// PI_CODING_AGENT_DIR when set, otherwise `<homeDir>/.pi/agent` (which also preserves
|
|
111
|
+
// the old behavior when a caller injects a custom homeDir without setting the env var).
|
|
100
112
|
function getConfigPaths(
|
|
101
113
|
cwd: string,
|
|
102
114
|
homeDir: string = homedir(),
|
|
115
|
+
agentDir: string = process.env.PI_CODING_AGENT_DIR ? getAgentDir() : join(homeDir, ".pi", "agent"),
|
|
103
116
|
): {
|
|
104
117
|
projectConfigPath: string;
|
|
105
118
|
globalConfigPath: string;
|
|
119
|
+
legacyGlobalConfigPath: string;
|
|
106
120
|
} {
|
|
107
121
|
return {
|
|
108
122
|
projectConfigPath: join(cwd, ".pi", "extensions", VERBOSITY_CONFIG_BASENAME),
|
|
109
|
-
globalConfigPath: join(
|
|
123
|
+
globalConfigPath: join(agentDir, "extensions", VERBOSITY_CONFIG_BASENAME),
|
|
124
|
+
legacyGlobalConfigPath: join(homeDir, ".pi", "agent", "extensions", VERBOSITY_CONFIG_BASENAME),
|
|
110
125
|
};
|
|
111
126
|
}
|
|
112
127
|
|
|
@@ -139,20 +154,32 @@ function writeConfigFile(filePath: string, config: VerbosityConfigFile): void {
|
|
|
139
154
|
}
|
|
140
155
|
}
|
|
141
156
|
|
|
142
|
-
function ensureDefaultConfigFile(
|
|
143
|
-
|
|
157
|
+
function ensureDefaultConfigFile(
|
|
158
|
+
projectConfigPath: string,
|
|
159
|
+
globalConfigPath: string,
|
|
160
|
+
legacyGlobalConfigPath: string,
|
|
161
|
+
): void {
|
|
162
|
+
if (existsSync(projectConfigPath) || existsSync(globalConfigPath) || existsSync(legacyGlobalConfigPath)) {
|
|
144
163
|
return;
|
|
145
164
|
}
|
|
146
165
|
writeConfigFile(globalConfigPath, DEFAULT_CONFIG_FILE);
|
|
147
166
|
}
|
|
148
167
|
|
|
149
|
-
function resolveVerbosityConfig(cwd: string, homeDir: string = homedir()): ResolvedVerbosityConfig {
|
|
150
|
-
const { projectConfigPath, globalConfigPath } = getConfigPaths(cwd, homeDir);
|
|
151
|
-
ensureDefaultConfigFile(projectConfigPath, globalConfigPath);
|
|
168
|
+
function resolveVerbosityConfig(cwd: string, homeDir: string = homedir(), agentDir?: string): ResolvedVerbosityConfig {
|
|
169
|
+
const { projectConfigPath, globalConfigPath, legacyGlobalConfigPath } = getConfigPaths(cwd, homeDir, agentDir);
|
|
170
|
+
ensureDefaultConfigFile(projectConfigPath, globalConfigPath, legacyGlobalConfigPath);
|
|
171
|
+
|
|
172
|
+
// Configs written before this extension honored PI_CODING_AGENT_DIR live at the
|
|
173
|
+
// legacy ~/.pi/agent path; fall back to that file (read in place, never migrated)
|
|
174
|
+
// when the relocated agent directory has no config of its own.
|
|
175
|
+
const globalSourcePath =
|
|
176
|
+
!existsSync(globalConfigPath) && globalConfigPath !== legacyGlobalConfigPath && existsSync(legacyGlobalConfigPath)
|
|
177
|
+
? legacyGlobalConfigPath
|
|
178
|
+
: globalConfigPath;
|
|
152
179
|
|
|
153
|
-
const globalConfig = readConfigFile(
|
|
180
|
+
const globalConfig = readConfigFile(globalSourcePath) ?? {};
|
|
154
181
|
const projectConfig = readConfigFile(projectConfigPath) ?? {};
|
|
155
|
-
const selectedConfigPath = existsSync(projectConfigPath) ? projectConfigPath :
|
|
182
|
+
const selectedConfigPath = existsSync(projectConfigPath) ? projectConfigPath : globalSourcePath;
|
|
156
183
|
|
|
157
184
|
return {
|
|
158
185
|
configPath: selectedConfigPath,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@benvargas/pi-openai-verbosity",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Per-model OpenAI Codex text verbosity overrides for pi",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"codex",
|
|
12
12
|
"openai-codex",
|
|
13
13
|
"gpt-5.5",
|
|
14
|
-
"gpt-5.
|
|
14
|
+
"gpt-5.6-sol",
|
|
15
15
|
"verbosity",
|
|
16
16
|
"text-verbosity",
|
|
17
17
|
"per-model"
|