pikiclaw 0.3.70 → 0.3.72

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.
@@ -189,9 +189,9 @@ export function claudeContextWindowFromModel(model) {
189
189
  return null;
190
190
  if (id === 'haiku' || /^claude-haiku-/.test(id))
191
191
  return 200_000;
192
- if (id === 'opus' || id === 'sonnet')
192
+ if (id === 'opus' || id === 'sonnet' || id === 'fable')
193
193
  return 1_000_000;
194
- if (/^claude-(opus|sonnet)-/.test(id))
194
+ if (/^claude-(opus|sonnet)-/.test(id) || /^claude-fable-/.test(id))
195
195
  return 1_000_000;
196
196
  return null;
197
197
  }
@@ -2064,6 +2064,7 @@ function hydrateSubAgentBlocksFromSidecar(richMsgs, subAgentsDir) {
2064
2064
  // Models
2065
2065
  // ---------------------------------------------------------------------------
2066
2066
  const CLAUDE_MODELS = [
2067
+ { id: 'claude-fable-5', alias: 'fable' },
2067
2068
  { id: 'claude-opus-4-8', alias: 'opus' },
2068
2069
  { id: 'claude-sonnet-4-6', alias: 'sonnet' },
2069
2070
  { id: 'claude-haiku-4-5-20251001', alias: 'haiku' },
@@ -509,6 +509,8 @@ export function modelFamily(model) {
509
509
  const lower = model?.toLowerCase() || '';
510
510
  if (!lower)
511
511
  return null;
512
+ if (lower.includes('fable'))
513
+ return 'fable';
512
514
  if (lower.includes('opus'))
513
515
  return 'opus';
514
516
  if (lower.includes('sonnet'))
package/dist/bot/bot.js CHANGED
@@ -1886,12 +1886,40 @@ export class Bot {
1886
1886
  }
1887
1887
  switchEffortForChat(chatId, effort) {
1888
1888
  const cs = this.chat(chatId);
1889
- this.setEffortForAgent(cs.agent, effort);
1889
+ // "ultra" is a synthetic top rung in the effort picker, NOT a real --effort
1890
+ // value (the claude CLI rejects anything outside low|medium|high|xhigh|max).
1891
+ // It bundles "max reasoning depth + permit multi-agent Workflow
1892
+ // orchestration" — the same pairing as Claude's own `ultracode` mode. Decode
1893
+ // it here, the single apply choke point, so the rest of the pipeline only
1894
+ // ever sees a concrete effort value plus the orthogonal workflow flag.
1895
+ // Because the rungs are mutually exclusive, picking any concrete level also
1896
+ // clears the workflow opt-in (capability-gated — only claude advertises it).
1897
+ const ultra = effort === 'ultra';
1898
+ const realEffort = ultra ? 'max' : effort;
1899
+ this.setEffortForAgent(cs.agent, realEffort);
1890
1900
  const session = this.getSelectedSession(cs);
1891
1901
  if (session)
1892
- session.thinkingEffort = effort;
1893
- this.persistAgentPreference(cs.agent, 'effort', effort);
1894
- this.log(`effort switched to ${effort} for ${cs.agent} chat=${chatId}`);
1902
+ session.thinkingEffort = realEffort;
1903
+ this.persistAgentPreference(cs.agent, 'effort', realEffort);
1904
+ if (getDriverCapabilities(cs.agent).workflow) {
1905
+ this.setWorkflowEnabledForAgent(cs.agent, ultra);
1906
+ this.persistAgentPreference(cs.agent, 'workflow', ultra ? '1' : '0');
1907
+ }
1908
+ this.log(`effort switched to ${effort} (effort=${realEffort}, workflow=${ultra}) for ${cs.agent} chat=${chatId}`);
1909
+ }
1910
+ /**
1911
+ * Effort value to *display* in the picker. Workflow is orthogonal under the
1912
+ * hood, but the UI folds "max depth + workflow on" into the single synthetic
1913
+ * `ultra` rung (see {@link switchEffortForChat}), so report it as current when
1914
+ * the agent has orchestration enabled. Mirrors the decomposition above.
1915
+ */
1916
+ effortSelectionForAgent(agent) {
1917
+ const effort = this.effortForAgent(agent);
1918
+ if (!effort)
1919
+ return null;
1920
+ if (getDriverCapabilities(agent).workflow && this.workflowEnabledForAgent(agent))
1921
+ return 'ultra';
1922
+ return effort;
1895
1923
  }
1896
1924
  switchPermissionModeForChat(chatId, mode) {
1897
1925
  const cs = this.chat(chatId);
@@ -387,22 +387,20 @@ export function buildModeCommandView(bot, chatId) {
387
387
  ],
388
388
  ];
389
389
  const metaLines = [];
390
- if (!isClaude && !supportsWorkflow)
390
+ if (!isClaude)
391
391
  metaLines.push('Permission mode is only available for Claude.');
392
+ // Workflow orchestration is no longer a standalone toggle here — it folded
393
+ // into the effort picker as the top "Ultra" rung (max depth + multi-agent
394
+ // fan-out). Surface its state and point users to /models so the capability
395
+ // stays discoverable.
392
396
  if (supportsWorkflow) {
393
- metaLines.push(`Workflow orchestration: ${workflowOn ? 'On' : 'Off'} — multi-agent fan-out for large tasks.`);
394
- rows.push([
395
- { label: 'Workflow On', action: { kind: 'workflow.toggle', enabled: true },
396
- state: workflowOn ? 'current' : 'default', primary: workflowOn },
397
- { label: 'Workflow Off', action: { kind: 'workflow.toggle', enabled: false },
398
- state: workflowOn ? 'default' : 'current', primary: !workflowOn },
399
- ]);
397
+ metaLines.push(`Workflow orchestration: ${workflowOn ? 'On (Ultra effort)' : 'Off'} — pick the Ultra rung in /models to toggle.`);
400
398
  }
401
399
  return {
402
400
  kind: 'mode',
403
401
  title: 'Agent Mode',
404
402
  detail: `Current: ${isPlanMode ? 'Plan (read-only)' : 'Code (full access)'}`
405
- + (supportsWorkflow ? ` · Workflow ${workflowOn ? 'On' : 'Off'}` : ''),
403
+ + (supportsWorkflow && workflowOn ? ' · Ultra (workflow)' : ''),
406
404
  metaLines,
407
405
  items: [],
408
406
  rows,
@@ -515,7 +513,7 @@ export async function executeCommandAction(bot, chatId, action, opts = {}) {
515
513
  }
516
514
  case 'effort.set': {
517
515
  const chat = bot.chat(chatId);
518
- const currentEffort = bot.effortForAgent(chat.agent);
516
+ const currentEffort = bot.effortSelectionForAgent(chat.agent);
519
517
  if (action.effort === currentEffort) {
520
518
  return { kind: 'noop', message: `Already using ${action.effort} effort` };
521
519
  }
@@ -552,7 +550,7 @@ export async function executeCommandAction(bot, chatId, action, opts = {}) {
552
550
  if (!draft)
553
551
  return { kind: 'noop', message: 'No changes' };
554
552
  const currentModel = bot.modelForAgent(chat.agent);
555
- const currentEffort = bot.effortForAgent(chat.agent);
553
+ const currentEffort = bot.effortSelectionForAgent(chat.agent);
556
554
  const currentProfileId = bot.activeProfileIdForAgent(chat.agent);
557
555
  const profileChanged = (draft.profileId || null) !== (currentProfileId || null);
558
556
  const modelChanged = profileChanged
@@ -30,7 +30,7 @@ export function getStartData(bot, chatId) {
30
30
  .map(a => ({
31
31
  agent: a.agent,
32
32
  model: bot.modelForAgent(a.agent) || '(default)',
33
- effort: bot.effortForAgent(a.agent),
33
+ effort: bot.effortSelectionForAgent(a.agent),
34
34
  }));
35
35
  return {
36
36
  ...intro,
@@ -343,6 +343,8 @@ function claudeModelFamily(modelId) {
343
343
  const value = normalizeClaudeModelId(modelId).toLowerCase();
344
344
  if (!value)
345
345
  return null;
346
+ if (value === 'fable' || value.startsWith('claude-fable-'))
347
+ return 'fable';
346
348
  if (value === 'opus' || value.startsWith('claude-opus-'))
347
349
  return 'opus';
348
350
  if (value === 'sonnet' || value.startsWith('claude-sonnet-'))
@@ -353,7 +355,7 @@ function claudeModelFamily(modelId) {
353
355
  }
354
356
  function isClaudeFamilyAlias(modelId) {
355
357
  const v = modelId.trim().toLowerCase();
356
- return v === 'opus' || v === 'sonnet' || v === 'haiku';
358
+ return v === 'fable' || v === 'opus' || v === 'sonnet' || v === 'haiku';
357
359
  }
358
360
  export function modelMatchesSelection(agent, selection, currentModel) {
359
361
  if (selection === currentModel)
@@ -373,6 +375,10 @@ const EFFORT_LEVELS = {
373
375
  { id: 'high', label: 'High' },
374
376
  { id: 'xhigh', label: 'Very High' },
375
377
  { id: 'max', label: 'Max' },
378
+ // Synthetic top rung: "max depth + multi-agent Workflow orchestration", the
379
+ // same bundle as Claude's `ultracode` mode. Not a real --effort value — the
380
+ // bot decomposes it into (effort=max, workflow=on) at apply time.
381
+ { id: 'ultra', label: 'Ultra' },
376
382
  ],
377
383
  codex: [
378
384
  { id: 'low', label: 'Low' },
@@ -389,7 +395,9 @@ const EFFORT_LEVELS = {
389
395
  ],
390
396
  };
391
397
  function buildEffortData(bot, agent) {
392
- const currentEffort = bot.effortForAgent(agent);
398
+ // Display value folds workflow into the synthetic `ultra` rung — see
399
+ // Bot.effortSelectionForAgent.
400
+ const currentEffort = bot.effortSelectionForAgent(agent);
393
401
  if (!currentEffort)
394
402
  return null;
395
403
  const levels = EFFORT_LEVELS[agent];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pikiclaw",
3
- "version": "0.3.70",
3
+ "version": "0.3.72",
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": {