@mjasnikovs/pi-task 0.38.32 → 0.39.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.
Files changed (54) hide show
  1. package/README.md +2 -2
  2. package/dist/config/group-args.d.ts +24 -9
  3. package/dist/config/group-args.js +38 -28
  4. package/dist/config/option-picker.d.ts +39 -11
  5. package/dist/config/option-picker.js +52 -12
  6. package/dist/config/reasoning.d.ts +10 -7
  7. package/dist/config/reasoning.js +19 -32
  8. package/dist/config/register.d.ts +66 -41
  9. package/dist/config/register.js +201 -162
  10. package/dist/shared/child-process.d.ts +34 -32
  11. package/dist/shared/child-process.js +44 -58
  12. package/dist/shared/command-watchdog.d.ts +12 -4
  13. package/dist/shared/command-watchdog.js +6 -7
  14. package/dist/shared/connection-error.d.ts +7 -0
  15. package/dist/shared/connection-error.js +65 -0
  16. package/dist/shared/model-endpoint.d.ts +12 -24
  17. package/dist/shared/model-endpoint.js +32 -82
  18. package/dist/shared/model-resolve.d.ts +105 -0
  19. package/dist/shared/model-resolve.js +97 -0
  20. package/dist/shared/reasoning-capability.d.ts +20 -0
  21. package/dist/shared/reasoning-capability.js +32 -1
  22. package/dist/shared/stall-probe.d.ts +51 -0
  23. package/dist/shared/stall-probe.js +79 -0
  24. package/dist/task/child-runner.d.ts +76 -278
  25. package/dist/task/child-runner.js +186 -722
  26. package/dist/task/context-usage.js +2 -7
  27. package/dist/task/failure-classifier.js +53 -81
  28. package/dist/task/gate-child.js +1 -1
  29. package/dist/task/impl-widget.d.ts +2 -0
  30. package/dist/task/impl-widget.js +4 -0
  31. package/dist/task/implementation-hold.d.ts +11 -0
  32. package/dist/task/implementation-hold.js +20 -0
  33. package/dist/task/implementation-scope.d.ts +24 -0
  34. package/dist/task/implementation-scope.js +34 -0
  35. package/dist/task/loop-detector.d.ts +13 -5
  36. package/dist/task/loop-detector.js +11 -5
  37. package/dist/task/model-hold-stash.js +4 -14
  38. package/dist/task/orchestrator.d.ts +1 -8
  39. package/dist/task/orchestrator.js +11 -34
  40. package/dist/task/phases.js +2 -2
  41. package/dist/task/stall-detector.d.ts +1 -1
  42. package/dist/task/stall-detector.js +1 -1
  43. package/dist/workers/model-warning.d.ts +4 -16
  44. package/dist/workers/model-warning.js +14 -70
  45. package/dist/workers/pi-worker-core.d.ts +65 -20
  46. package/dist/workers/pi-worker-core.js +109 -50
  47. package/dist/workers/reasoning-warning.js +2 -24
  48. package/dist/workers/worker-failure.d.ts +2 -0
  49. package/dist/workers/worker-failure.js +2 -1
  50. package/dist/workers/worker-kill.d.ts +30 -11
  51. package/dist/workers/worker-kill.js +68 -20
  52. package/dist/workers/worker-profiles.d.ts +20 -0
  53. package/dist/workers/worker-profiles.js +22 -9
  54. package/package.json +1 -1
@@ -1,7 +1,8 @@
1
1
  import type { ExtensionAPI, ExtensionCommandContext } from '@earendil-works/pi-coding-agent';
2
2
  import { SettingsList } from '@earendil-works/pi-tui';
3
- import type { Component, SelectItem } from '@earendil-works/pi-tui';
3
+ import type { Component } from '@earendil-works/pi-tui';
4
4
  import { type ReasoningModelFacts } from '../shared/reasoning-capability.js';
5
+ import { type PairOptions } from './option-picker.js';
5
6
  import { type PiTaskConfig } from './config.js';
6
7
  import { type InstalledExtension } from './extension-list.js';
7
8
  import { type GuardableTool } from './tool-list.js';
@@ -55,7 +56,7 @@ declare class BorderedBox implements Component {
55
56
  export interface ConfigItem {
56
57
  /**
57
58
  * The row's id. A `keyof PiTaskConfig` for a fixed setting; a prefixed
58
- * string (`reason:`, `tool:`, `ext:`) for a DISCOVERED one.
59
+ * string (`step:`, `tool:`, `ext:`) for a DISCOVERED one.
59
60
  *
60
61
  * It is `string`, not `keyof PiTaskConfig`, and that is what lets the three
61
62
  * dynamic families BE rows instead of bypassing them — so the round-trip
@@ -84,7 +85,7 @@ export interface ConfigItem {
84
85
  * `values` stays the STATIC complete vocabulary, because that is what the
85
86
  * round-trip property in config-items.test.ts quantifies over.
86
87
  */
87
- submenu?: (cfg: PiTaskConfig) => SelectItem[];
88
+ picker?: (cfg: PiTaskConfig) => PairOptions;
88
89
  /** What the panel shows for the current value. */
89
90
  format: (cfg: PiTaskConfig) => string;
90
91
  /** Write the chosen label back. A value it does not recognise is ignored. */
@@ -104,7 +105,7 @@ export interface ConfigItem {
104
105
  * exemptions from it) end up separated by rows that have nothing to do with
105
106
  * them. The headers are inert rows: no `values`, so Enter does nothing on them.
106
107
  */
107
- export type Section = 'session' | 'checks' | 'research' | 'models' | 'reasoning' | 'timeouts' | 'unattended' | 'logging' | 'extensions';
108
+ export type Section = 'session' | 'checks' | 'research' | 'profile' | 'reasoning' | 'timeouts' | 'unattended' | 'logging' | 'extensions';
108
109
  /** Section order, and the label each header renders. */
109
110
  export declare const SECTIONS: ReadonlyArray<{
110
111
  key: Section;
@@ -138,7 +139,7 @@ export declare function toolItems(tools: readonly GuardableTool[]): ConfigItem[]
138
139
  /** Apply a per-tool watchdog toggle to the exemption list (idempotent both ways). */
139
140
  export declare function applyToolToggle(exempt: readonly string[], toolName: string, watched: boolean): string[];
140
141
  /**
141
- * The label for one `think:` row.
142
+ * The label for one step row.
142
143
  *
143
144
  * A group whose name carries a colon is a CHILD of the group before the colon —
144
145
  * `research:files` is one of the four workers `research` fans out to. Rendered
@@ -147,14 +148,18 @@ export declare function applyToolToggle(exempt: readonly string[], toolName: str
147
148
  * parent is also a row.
148
149
  *
149
150
  * So a child is drawn as a tree branch under its parent and loses the repeated
150
- * `think: research:` prefix, the same text at the head of four consecutive
151
- * lines. `└─` on the last child, `├─` on the rest, decided from the group's
152
- * position in {@link CHILD_GROUPS} rather than a hand-kept list — adding a
153
- * fifth worker moves the corner on its own.
151
+ * `research:` prefix, the same text at the head of four consecutive lines. `└─`
152
+ * on the last child, `├─` on the rest, decided from the group's position in
153
+ * {@link CHILD_GROUPS} rather than a hand-kept list — adding a fifth worker
154
+ * moves the corner on its own.
155
+ *
156
+ * A parentless group is its own bare name. It carried a `think: ` prefix while
157
+ * there were two families to tell apart; with one row per step there is nothing
158
+ * to disambiguate, and the prefix was the widest thing in the column.
154
159
  *
155
160
  * Leading spaces survive: SettingsList pads the label right, never trims it.
156
161
  */
157
- export declare function reasoningRowLabel(group: ChildGroup): string;
162
+ export declare function stepRowLabel(group: ChildGroup): string;
158
163
  /**
159
164
  * What this machine can offer a model row, and what each offer can DO.
160
165
  *
@@ -173,36 +178,56 @@ export interface ModelCatalog {
173
178
  }
174
179
  /** No registry reachable. Every row still renders; nothing narrows. */
175
180
  export declare const EMPTY_CATALOG: ModelCatalog;
176
- export declare function modelItems(catalog: ModelCatalog): ConfigItem[];
177
181
  /**
178
- * Write a group's model, and RE-CLAMP its thinking cell in the same write.
182
+ * `level · provider/id`, the one string a step row shows and accepts.
179
183
  *
180
- * Narrowing the picker does nothing about a level already stored from before the
181
- * model was chosen: on its own it would freeze a lie into a cell it has just
182
- * made unconfigurable. `syncRows` re-renders every row, so the user sees the
183
- * level move.
184
+ * THE LEVEL COMES FIRST, and that is a display decision with teeth.
185
+ * `SettingsList` truncates a value from the RIGHT, so whatever is last is what
186
+ * silently disappears and a real local model id (`local/Qwen3.8-27B-UD-Q4_K_XL
187
+ * .gguf`) is wide enough to consume the whole column on its own. Level-first
188
+ * means the half that falls off is the one still identifiable from its head, and
189
+ * the levels line up as a column you can read down.
190
+ */
191
+ export declare function formatStepValue(spec: string, level: GroupSetting): string;
192
+ /**
193
+ * The two halves back out, or `undefined` for anything not of that shape.
184
194
  *
185
- * The clamp reads `resolveReasoning`, NOT `cfg.reasoningLevels[group]`. In mode
186
- * `on` or `off` the stored table is ignored entirely, so a user in `on` who
187
- * picks a non-reasoning model has a stored cell that says nothing and an
188
- * effective `medium` the model will erase — and comparing the stored cell would
189
- * see no clamp and stay silent about a real lie.
195
+ * Split on the FIRST separator, because the level leads and is a closed set,
196
+ * while a `provider/id` could conceivably contain one.
197
+ */
198
+ export declare function parseStepValue(value: string): {
199
+ spec: string;
200
+ level: GroupSetting;
201
+ } | undefined;
202
+ /**
203
+ * One row per step, carrying BOTH dials.
204
+ *
205
+ * They were two parallel blocks of eleven, and the coupling between them was
206
+ * invisible: choosing a model re-clamps that step's thinking level, but the row
207
+ * that moved was eleven rows away from the row you touched. One row shows the
208
+ * pair, and the two-step picker shows the clamp happening.
190
209
  *
191
- * Guarded on the clamp actually MOVING something, because `applyReasoningLevel`
192
- * flips the whole table to `custom`, and picking a fully-capable model must not
193
- * do that as a side effect.
210
+ * `values` is the LEGAL cross product every model against only the levels that
211
+ * model declares. Nothing renders it: the picker offers two short lists, and the
212
+ * round-trip property in config-items.test.ts is its only reader. Building it
213
+ * from `offeredLevels` rather than the full ladder is what makes the property
214
+ * true, because a pair the model cannot honour would be clamped by `apply` and
215
+ * would not round-trip.
194
216
  */
195
- export declare function applyGroupModel(cfg: PiTaskConfig, group: ChildGroup, chosen: string, catalog: ModelCatalog): void;
217
+ export declare function stepItems(catalog?: ModelCatalog): ConfigItem[];
196
218
  /**
197
- * The levels a row may offer, given the model that row's group will run on.
219
+ * Write both halves of a step row, atomically.
220
+ *
221
+ * Atomically matters for the round-trip property, which starts from a FRESH
222
+ * config every iteration: a value that wrote only one half would leave the other
223
+ * at its default and render as something else.
198
224
  *
199
- * The INTERSECTION with `REASONING_SETTINGS`, not `supportedThinkingLevels`
200
- * directly: that returns the whole ladder including `xhigh` and `max`, which
201
- * this menu excludes on purpose (see reasoning.ts) because pi's own UI may not
202
- * offer them. A model declaring `xhigh` must not smuggle it in here.
225
+ * The level is re-clamped even though the picker only ever offers legal pairs.
226
+ * The picker is not the only door `values` is built when the panel opens, and
227
+ * a registry that moved underneath it would otherwise let an unhonourable level
228
+ * through.
203
229
  */
204
- export declare function offeredLevels(facts: ReasoningModelFacts | undefined): GroupSetting[];
205
- export declare function reasoningItems(catalog?: ModelCatalog): ConfigItem[];
230
+ export declare function applyStepValue(cfg: PiTaskConfig, group: ChildGroup, chosen: string, catalog: ModelCatalog): void;
206
231
  /**
207
232
  * Apply one group row's new value.
208
233
  *
@@ -247,13 +272,13 @@ export type PanelItem = {
247
272
  * {@link createSettingsPanel} is where a theme exists, so it is where these
248
273
  * options become a component.
249
274
  */
250
- submenuOptions?: () => SelectItem[];
275
+ pickerOptions?: () => PairOptions;
251
276
  /**
252
277
  * What the headless one-line rendering calls this row, when `label` reads
253
278
  * only in the panel. A tree branch means nothing on a line of `|`-joined
254
- * rows: `├─ files` there names no parent, where `think: research:files`
255
- * does. Set by the reasoning rows; every other row leaves it off and its
256
- * `label` is used.
279
+ * rows: `├─ files` there names no parent, where `step: research:files`
280
+ * does. Set by the step rows; every other row leaves it off and its `label`
281
+ * is used.
257
282
  */
258
283
  headlessLabel?: string;
259
284
  };
@@ -267,10 +292,10 @@ export declare function createSettingsPanel(items: PanelItem[], theme: Theme,
267
292
  * Called with the row's id, its new value, and the LIST ITSELF.
268
293
  *
269
294
  * The list is handed back because some rows change what OTHER rows display:
270
- * flipping `reasoning` to off means every `think:` row now runs at off, and
271
- * a row's `currentValue` is a snapshot taken when the panel was built.
272
- * Without a way to write the others back, the menu would show
273
- * `reasoning off` beside rows still claiming `inherit`.
295
+ * flipping `profile` to off means every `step:` row now runs at off, and a
296
+ * row's `currentValue` is a snapshot taken when the panel was built. Without
297
+ * a way to write the others back, the menu would show `profile off` beside
298
+ * rows still claiming `inherit`.
274
299
  */
275
300
  onChange: (id: string, newValue: string, list: SettingsList) => void, onCancel: () => void): BorderedBox;
276
301
  /**
@@ -294,7 +319,7 @@ export declare function panelItems(cfg: PiTaskConfig, installed: InstalledExtens
294
319
  *
295
320
  * A row's `currentValue` in the live list is a snapshot taken when the panel was
296
321
  * built, and rows describe each other: cycling `reasoning` to `off` changes what
297
- * every `think:` row runs at, and cycling one group row flips the mode, which
322
+ * every `step:` row runs at, and setting one step row flips the profile, which
298
323
  * changes all the others.
299
324
  *
300
325
  * This runs after ANY change, over EVERY row. Re-reading a `format` costs