pikiloom 0.4.70 → 0.4.71

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.
@@ -276,9 +276,11 @@ export async function pauseCodexGoal(threadId) {
276
276
  export async function resumeCodexGoal(threadId) {
277
277
  return setCodexGoal({ threadId, status: 'active' });
278
278
  }
279
- const EFFORT_MAP = {
280
- low: 'low', medium: 'medium', high: 'high', min: 'minimal', max: 'xhigh',
281
- };
279
+ // Codex (GPT-5.6+) accepts low / medium / high / xhigh / max / ultra as native reasoning levels,
280
+ // so the effort token is forwarded to the app-server verbatim. Only `min` is an alias for the
281
+ // CLI's `minimal`. (Historically `max` was folded to `xhigh` because older Codex had no `max`
282
+ // rung — that clamp is gone now that 5.6 exposes `max`/`ultra` directly.)
283
+ const EFFORT_MAP = { min: 'minimal' };
282
284
  function mapEffort(effort) { return EFFORT_MAP[effort] ?? effort; }
283
285
  function isCodexToolCallItem(item) {
284
286
  return item?.type === 'dynamicToolCall' || item?.type === 'mcpToolCall' || item?.type === 'collabAgentToolCall';
@@ -808,7 +810,7 @@ export function humanizeCodexError(raw) {
808
810
  const model = match[1];
809
811
  return `Codex 正在使用 ChatGPT 账号登录,无法运行第三方模型「${model}」。`
810
812
  + `请在「智能体配置」页接入该模型的供应商(填入 Base URL 与 API Key),添加对应模型档案并绑定到 Codex,`
811
- + `或改用 Codex 原生模型(如 gpt-5.5)。`;
813
+ + `或改用 Codex 原生模型(如 gpt-5.6-sol)。`;
812
814
  }
813
815
  return raw;
814
816
  }
@@ -17,7 +17,11 @@ import { resolveAgentInjection } from '../model/injector.js';
17
17
  // queue, wire) is live here.
18
18
  const DEMO_MODELS = {
19
19
  claude: [{ id: 'claude-opus-4-8', label: 'Opus 4.8', providerName: 'anthropic', contextWindow: 200000 }],
20
- codex: [{ id: 'gpt-5.5-codex', label: 'GPT-5.5 Codex', providerName: 'openai', contextWindow: 400000 }],
20
+ codex: [
21
+ { id: 'gpt-5.6-sol', label: 'GPT-5.6-Sol', providerName: 'openai', contextWindow: 372000 },
22
+ { id: 'gpt-5.6-terra', label: 'GPT-5.6-Terra', providerName: 'openai', contextWindow: 372000 },
23
+ { id: 'gpt-5.6-luna', label: 'GPT-5.6-Luna', providerName: 'openai', contextWindow: 372000 },
24
+ ],
21
25
  gemini: [{ id: 'gemini-2.5-pro', label: 'Gemini 2.5 Pro', providerName: 'google', contextWindow: 1000000 }],
22
26
  opencode: [{ id: 'claude-sonnet-4-6', label: 'OpenCode · Sonnet 4.6 (ACP)', providerName: 'opencode', contextWindow: 200000 }],
23
27
  echo: [{ id: 'echo-1', label: 'Echo (hermetic)', providerName: 'local', contextWindow: 8192 }],
@@ -1,7 +1,13 @@
1
1
  import { normalizeClaudeModelId } from '../../agent/index.js';
2
+ /** Account-scoped GPT-5.6 variants the Codex model catalog currently advertises. */
3
+ export const CODEX_56_MODEL_IDS = [
4
+ 'gpt-5.6-sol',
5
+ 'gpt-5.6-terra',
6
+ 'gpt-5.6-luna',
7
+ ];
2
8
  export const DEFAULT_AGENT_MODELS = {
3
9
  claude: 'claude-opus-4-8',
4
- codex: 'gpt-5.5',
10
+ codex: CODEX_56_MODEL_IDS[0],
5
11
  gemini: 'gemini-3.1-pro-preview',
6
12
  hermes: 'anthropic/claude-sonnet-4',
7
13
  };
@@ -178,16 +184,39 @@ export function effortLabel(id) {
178
184
  // so per-model/provider rules stay in one place. Labels come from effortLabel() so the picker
179
185
  // and the live status row can never diverge.
180
186
  const effortLevels = (...ids) => ids.map(id => ({ id, label: effortLabel(id) }));
187
+ const CODEX_BASE_EFFORTS = ['low', 'medium', 'high', 'xhigh'];
188
+ // Per-model Codex reasoning ladders. GPT-5.6 adds the native `max` rung (sol/terra also expose
189
+ // `ultra`), which older Codex models (5.5/5.4) do not support — so the picker must vary by model,
190
+ // never a single flat list. For codex, `max`/`ultra` are REAL CLI reasoning levels (not the
191
+ // claude display alias): they are dispatched verbatim (see splitEffortForAgent / the codex driver).
192
+ const CODEX_56_EFFORTS = {
193
+ 'gpt-5.6-sol': [...CODEX_BASE_EFFORTS, 'max', ULTRA_EFFORT],
194
+ 'gpt-5.6-terra': [...CODEX_BASE_EFFORTS, 'max', ULTRA_EFFORT],
195
+ 'gpt-5.6-luna': [...CODEX_BASE_EFFORTS, 'max'],
196
+ };
181
197
  const AGENT_EFFORT_LEVELS = {
182
198
  claude: effortLevels('low', 'medium', 'high', 'xhigh', 'max', ULTRA_EFFORT),
183
- codex: effortLevels('low', 'medium', 'high', 'xhigh'),
199
+ codex: effortLevels(...CODEX_BASE_EFFORTS),
184
200
  // gemini intentionally has no UI-exposed effort levels: pikiloom sends it no reasoning-effort
185
201
  // (see the gemini→null guards in InputComposer). Add a gemini entry here to surface low/high.
186
202
  hermes: effortLevels('minimal', 'low', 'medium', 'high', 'xhigh'),
187
203
  };
188
204
  // Valid effort levels for a given (agent, model, providerKind). Returns [] when reasoning
189
205
  // effort does not apply (the UI then hides the selector entirely). model/providerKind are the
190
- // seam for per-model rules — add them here and nowhere else.
191
- export function effortOptionsFor(agent, _model, _providerKind) {
206
+ // seam for per-model rules — add them here and nowhere else. A known GPT-5.6 codex model unlocks
207
+ // its `max`/`ultra` rungs; every other codex model (incl. BYOK) keeps the base low→xhigh ladder.
208
+ export function effortOptionsFor(agent, model, _providerKind) {
209
+ if (agent === 'codex' && model && model in CODEX_56_EFFORTS) {
210
+ return effortLevels(...CODEX_56_EFFORTS[model]);
211
+ }
192
212
  return AGENT_EFFORT_LEVELS[agent] ?? [];
193
213
  }
214
+ // Reconcile the two meanings of the effort token before dispatch. Codex (GPT-5.6+) treats
215
+ // `max`/`ultra` as NATIVE reasoning levels, so its token must reach the CLI verbatim — never fold
216
+ // `ultra` into `max`, and never turn on the (claude-only) workflow orchestration. For every other
217
+ // agent `ultra` stays a display alias that decomposes to `max` effort + workflow (decomposeEffortSelection).
218
+ export function splitEffortForAgent(agent, raw) {
219
+ if (agent === 'codex')
220
+ return { effort: trimmed(raw).toLowerCase(), workflow: false };
221
+ return decomposeEffortSelection(raw);
222
+ }
@@ -7,7 +7,7 @@ import { loadUserConfig, saveUserConfig, applyUserConfig } from '../../core/conf
7
7
  import { setAgentBoundModelId } from '../../agent/index.js';
8
8
  import { getAgentUpdateState, checkAgentLatestVersion, manualAgentUpdate } from '../../agent/auto-update.js';
9
9
  import { getDriver, getDriverCapabilities } from '../../agent/driver.js';
10
- import { decomposeEffortSelection, effortOptionsFor } from '../../core/config/runtime-config.js';
10
+ import { splitEffortForAgent, effortOptionsFor } from '../../core/config/runtime-config.js';
11
11
  import { getActiveProfile, getProvider, peekProviderModelList, prefetchProviderModels, } from '../../model/index.js';
12
12
  import { DASHBOARD_TIMEOUTS } from '../../core/constants.js';
13
13
  import { withTimeoutFallback } from '../../core/utils.js';
@@ -326,7 +326,6 @@ app.post('/api/runtime-agent', async (c) => {
326
326
  const targetAgent = body?.agent;
327
327
  const model = typeof body?.model === 'string' ? body.model.trim() : '';
328
328
  const rawEffort = typeof body?.effort === 'string' ? body.effort.trim().toLowerCase() : '';
329
- const { effort, workflow: effortWorkflow } = decomposeEffortSelection(rawEffort);
330
329
  const hasEffort = rawEffort !== '';
331
330
  const botRef = runtime.getBotRef();
332
331
  if (defaultAgent != null) {
@@ -358,6 +357,9 @@ app.post('/api/runtime-agent', async (c) => {
358
357
  botRef.setModelForAgent(targetAgent, model);
359
358
  }
360
359
  if (hasEffort) {
360
+ // Codex keeps `max`/`ultra` as native reasoning levels; claude decomposes `ultra` into
361
+ // `max` effort + workflow. splitEffortForAgent reconciles both before we persist the default.
362
+ const { effort, workflow: effortWorkflow } = splitEffortForAgent(targetAgent, rawEffort);
361
363
  runtime.runtimePrefs.efforts[targetAgent] = effort;
362
364
  runtime.setEffortEnv(targetAgent, effort);
363
365
  if (targetAgent === 'claude')
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import { getProjectSkillPaths, listSkills, stageSessionFiles, ensureManagedSession, findPikiloomSession, getDriverCapabilities, isPendingSessionId } from '../agent/index.js';
3
3
  import { loadUserConfig } from '../core/config/user-config.js';
4
- import { decomposeEffortSelection } from '../core/config/runtime-config.js';
4
+ import { splitEffortForAgent } from '../core/config/runtime-config.js';
5
5
  import { runtime } from './runtime.js';
6
6
  const KNOWN_AGENTS = new Set(['claude', 'codex', 'gemini', 'hermes']);
7
7
  function parseGoalSlash(prompt) {
@@ -78,7 +78,7 @@ export async function queueDashboardSessionTask(request) {
78
78
  : runtime.getRuntimeDefaultAgent(config);
79
79
  const modelId = typeof request.model === 'string' ? request.model.trim() : '';
80
80
  const profileId = resolveProfileIdOverride(request.profileId);
81
- const { effort: splitEffort, workflow: ultraWorkflow } = decomposeEffortSelection(typeof request.effort === 'string' ? request.effort : '');
81
+ const { effort: splitEffort, workflow: ultraWorkflow } = splitEffortForAgent(resolvedAgent, typeof request.effort === 'string' ? request.effort : '');
82
82
  const thinkingEffort = resolvedAgent === 'gemini' ? '' : splitEffort;
83
83
  const workflowEnabled = ultraWorkflow || request.workflow === true;
84
84
  const goalCmd = parseGoalSlash(request.prompt || '');
@@ -171,7 +171,7 @@ export function forkDashboardSessionTask(request) {
171
171
  }
172
172
  const modelId = typeof request.model === 'string' ? request.model.trim() : '';
173
173
  const profileId = resolveProfileIdOverride(request.profileId);
174
- const { effort: splitEffort, workflow: ultraWorkflow } = decomposeEffortSelection(typeof request.effort === 'string' ? request.effort : '');
174
+ const { effort: splitEffort, workflow: ultraWorkflow } = splitEffortForAgent(agent, typeof request.effort === 'string' ? request.effort : '');
175
175
  const thinkingEffort = agent === 'gemini' ? '' : splitEffort;
176
176
  let prompt = request.prompt;
177
177
  const skillResult = prompt ? resolveSkillFromPrompt(request.workdir, prompt) : null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pikiloom",
3
- "version": "0.4.70",
3
+ "version": "0.4.71",
4
4
  "description": "Put the world's smartest AI agents in your pocket. Command local Claude & Gemini via IM. | 让最好用的 IM 变成你电脑上的顶级 Agent 控制台",
5
5
  "type": "module",
6
6
  "bin": {