ds4-context-engine 0.3.0-beta.3 → 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.
@@ -57,6 +57,27 @@ When privacy is enabled, local summary generation may consume allowed local-only
57
57
 
58
58
  Pi 0.84.3 locates the post-compaction entry by summary text, which can surface an older entry when deterministic test summaries are identical. DS4 therefore correlates commit with its pending summary ID and resolves the matching newly appended entry from `SessionManager`, never by text equality.
59
59
 
60
+ ## Dedicated compaction model and thinking
61
+
62
+ By default the active session model generates summaries, exactly as in previous releases. A dedicated model can be opted into:
63
+
64
+ ```json
65
+ {
66
+ "compaction": {
67
+ "model": { "provider": "anthropic", "id": "claude-sonnet-4-5" },
68
+ "summary": { "thinking": "medium" }
69
+ }
70
+ }
71
+ ```
72
+
73
+ Semantics:
74
+
75
+ - when `compaction.model` is absent, the active session model is used for budget, segmentation, requests, and record provenance;
76
+ - when present, the model is resolved once per compaction through the model registry and used uniformly for input budget, segmentation, sanitization, segment/aggregate requests, and `provider`/`model` provenance in summary records;
77
+ - the dedicated model must exist, be configured with auth, and accept text input; otherwise DS4 logs a warning and falls back to the session model — compaction is never blocked by configuration;
78
+ - `compaction.summary.thinking` defaults to `off` and applies only to summary requests: `off` keeps the pre-existing request shape (no thinking fields), while other levels map per API (`thinkingEnabled`/`effort` for `anthropic-messages`, `samplingParams.reasoning_effort` for OpenAI-compatible APIs) and are ignored for unsupported providers;
79
+ - `context.maxSummaryTokens` remains a session-level limit and does not rise for the dedicated model; the minimum with the model's `maxTokens` still applies.
80
+
60
81
  ## Proactive trigger
61
82
 
62
83
  After a settled turn, DS4 computes:
@@ -0,0 +1,83 @@
1
+ # DS4 Context Engine 0.3.0-beta.3
2
+
3
+ Status: published on 2026-09-03 under the npm `beta` dist-tag.
4
+
5
+ This coordinated beta fixes storage maintenance on Windows and carries forward beta.2 without changing canonical records, SQLite schema, runtime contracts, retention limits, privacy policy, compaction validation, or fallback semantics.
6
+
7
+ ## Fixed since beta.2
8
+
9
+ - `compactStorage()` now opens stage/state/source files for the durability flush with write access (`"r+"`). `fsyncPath` previously opened them read-only, which fails on Windows with `EPERM` (`FlushFileBuffers` requires write access), aborting `compact` with `stage=compact; category=maintenance-failed` before the backup could be verified. The failure was confirmed on Windows with a minimal probe:
10
+
11
+ ```text
12
+ fsync-on-readonly-handle: FAIL code=EPERM
13
+ ```
14
+
15
+ - The flush now mirrors `fsyncDirectory`'s best-effort policy for platforms that cannot flush (`EINVAL`, `ENOTSUP`, `EBADF`, `EPERM`, `EACCES`), while still flushing normally on supported platforms. No content is written by the `"r+"` open.
16
+
17
+ - Coordinated package versions moved to `0.3.0-beta.3`.
18
+
19
+ There are no functional storage-format or provider-path changes relative to beta.2.
20
+
21
+ ## Safety and compatibility
22
+
23
+ Unchanged from beta.2: Pi JSONL remains canonical and append-only; SQLite remains disposable and rebuildable; physical maintenance remains explicit, offline, local-TTY-only, and unavailable to model-callable tools; every `context_persistence` write still requires a fresh positive local UI decision.
24
+
25
+ Compatibility remains unchanged:
26
+
27
+ - SQLite schema: `15`;
28
+ - configuration: `ds4-context-config-v1`;
29
+ - runtime adapter: `runtime-adapter-v1`;
30
+ - persistence tool: `ds4-context-persistence-tool-v1`;
31
+ - persistence result: `ds4-context-persistence-result-v1`;
32
+ - Pi: `0.84.3`;
33
+ - Node.js: `>=22.19.0`.
34
+
35
+ ## Package/version policy
36
+
37
+ The coordinated version is `0.3.0-beta.3` for:
38
+
39
+ ```text
40
+ ds4-context-core
41
+ ds4-context-reference-adapter
42
+ ds4-context-engine
43
+ ```
44
+
45
+ Both adapters depend exactly on `ds4-context-core@0.3.0-beta.3`. Publication used the explicit npm `beta` dist-tag for all three packages. npm `latest` remains stable `0.2.0`, and GitHub Actions remains validation-only with OIDC and package-write permissions denied.
46
+
47
+ ## Candidate validation
48
+
49
+ Local candidate verification on Node.js `26.5.1`:
50
+
51
+ - `npm run check`: 69 files and 341 tests passed.
52
+ - `npm run quality:compare`: candidate quality `0.9875` versus baseline `0.808156`.
53
+ - `npm run schema:context-persistence`: 1,266 bytes and 317 estimated tokens; below the 1,500 absolute and 320 relative limits.
54
+ - `npm run pack:check`: verified core (223 files), reference adapter (7 files), and Pi adapter (68 files) in a clean consumer.
55
+ - `npm pack --dry-run --json` for all three packages passed with the same inventories and no forbidden local/session/storage files.
56
+ - `git diff --check` passed; the only pre-existing untracked path is `.serena/`, which is excluded from commits and package inventories.
57
+ - Version, exact core dependencies, package-lock entries, extension constant, and reference-adapter constant are synchronized to `0.3.0-beta.3`.
58
+
59
+ Validation-only CI run [`33771957691`](https://github.com/Alucard24/ds4-context-engine/actions/runs/33771957691) passed on Node.js `22.19.0` and `24.x` for commit `8c4abf6106b675aa1af1ee163f6ca07b5e1c0ef3`.
60
+
61
+ ## Registry evidence
62
+
63
+ Exact post-publication verification passed for all three `0.3.0-beta.3` packages. The clean registry consumer verified exact adapter/core dependencies, public core exports, compiled reference-adapter conformance, packaged quality corpus, packaged Pi extension startup, and the installed `ds4-context-storage` CLI declaration, shim, and usage probe.
64
+
65
+ Published package shasums:
66
+
67
+ ```text
68
+ ds4-context-core: 0428629e03cf2d02a7033fa3e016344dff3af399
69
+ ds4-context-reference-adapter: 53924c98d6c9672709076edb5cf70bf3f98c1915
70
+ ds4-context-engine: d0ae468daae4f4e4970497282fd5c18b86f847d5
71
+ ```
72
+
73
+ For all three packages, npm `beta` resolves to `0.3.0-beta.3`, `alpha` remains `0.3.0-alpha.5`, `rc` remains `0.2.0-rc.1`, and `latest` remains `0.2.0`.
74
+
75
+ Annotated tag `v0.3.0-beta.3` targets `8c4abf6106b675aa1af1ee163f6ca07b5e1c0ef3`. The GitHub prerelease is published at <https://github.com/Alucard24/ds4-context-engine/releases/tag/v0.3.0-beta.3>.
76
+
77
+ ## Documentation
78
+
79
+ - [`../STORAGE_MAINTENANCE.md`](../STORAGE_MAINTENANCE.md)
80
+ - [`../STORAGE.md`](../STORAGE.md)
81
+ - [`../COMPACTION.md`](../COMPACTION.md)
82
+ - [`../RELEASING.md`](../RELEASING.md)
83
+ - [`0.3.0-beta.2.md`](0.3.0-beta.2.md)
@@ -0,0 +1,82 @@
1
+ # DS4 Context Engine 0.3.0
2
+
3
+ Status: promoted 2026-09-04 from beta.3; printed under the npm `latest` dist-tag.
4
+
5
+ This is the first stable release of the 0.3 line. It carries exactly the beta.3 candidate: no canonical record format, SQLite schema, runtime contract, retention limit, privacy policy, compaction validation, or fallback semantics changed during promotion.
6
+
7
+ ## Promoted from
8
+
9
+ - [`0.3.0-beta.3.md`](0.3.0-beta.3.md) is the exact promoted candidate; beta.3 itself fixed Windows storage-maintenance flush handling on top of beta.2.
10
+
11
+ ## Promotion evidence
12
+
13
+ The promotion criteria in [`../DOGFOODING_0.3.0_BETA.md`](../DOGFOODING_0.3.0_BETA.md) are satisfied as follows:
14
+
15
+ - Full mode matrix with synthetic data on 2026-09-03: TUI, RPC (with and without responding UI bridge), print, JSON stream, no-session, canonical append audit, branch switch, restart, projection rebuild, two concurrent client leases, untrusted RPC, isolated offline maintenance with local TTY confirmation, and online retention convergence. Evidence: `/tmp/ds4-beta-dogfood/evidence/`.
16
+ - Configured remote provider (real): the RPC/branch/untrusted matrix ran against `openai-codex` / `gpt-5.4-mini` with real authentication on 2026-09-03; the disposable database records 21 `openai-codex` / `gpt-5.4-mini` context manifests with provider-reported usage. The same matrix covered accepted, cancelled, and provider-policy-denied persistence writes.
17
+ - Additional real-provider TUI soak on 2026-09-04 against `deepseek` / `deepseek-v4-flash-vision-exp` (Pi 0.85.0): normal model call with provider-reported usage, `/context status`, `/context storage`, and a session pin persisted with scope `session`, status `active`, and a canonical source entry. Evidence: `/tmp/ds4-real-dogfood/evidence/` and the disposable database at `/tmp/ds4-real-agent/ds4-context/context.db` (3 real manifests, pin `b5828a50-689b-4c59-8a90-241eca30217c`).
18
+ - Verified local provider: explicitly recorded as unavailable — no local provider (Ollama/LM Studio or equivalent) is configured in the environment; the runbook allows the missing run to remain recorded rather than inferred.
19
+ - Live maintenance authorization: completed 2026-09-03 (2.42 GiB → 377 MiB, `quick_check=ok`, FK `0`, manifests 1,630 → 128); the fixed backup `context.db.precompact.bak` (including `-shm`/`-wal` residues) was removed 2026-09-04 after a post-removal read-only inspection confirmed `quick_check=ok`, FK `0`, 128 manifests, and `Maintenance recommended: no`.
20
+
21
+ ## Safety and compatibility
22
+
23
+ Unchanged from beta.3: Pi JSONL remains canonical and append-only; SQLite remains disposable and rebuildable; physical maintenance remains explicit, offline, local-TTY-only, and unavailable to model-callable tools; every `context_persistence` write still requires a fresh positive local UI decision.
24
+
25
+ Compatibility surface:
26
+
27
+ - SQLite schema: `15`;
28
+ - configuration: `ds4-context-config-v1`;
29
+ - runtime adapter: `runtime-adapter-v1`;
30
+ - persistence tool: `ds4-context-persistence-tool-v1`;
31
+ - persistence result: `ds4-context-persistence-result-v1`;
32
+ - Pi: `0.84.3` (validated; 0.85.0 additionally exercised by the 2026-09-04 TUI soak);
33
+ - Node.js: `>=22.19.0`.
34
+
35
+ ## Package/version policy
36
+
37
+ The coordinated version is `0.3.0` for:
38
+
39
+ ```text
40
+ ds4-context-core
41
+ ds4-context-reference-adapter
42
+ ds4-context-engine
43
+ ```
44
+
45
+ Both adapters depend exactly on `ds4-context-core@0.3.0`. Publication used npm's default `latest` tag for all three packages: `latest` now resolves to `0.3.0` (previously `0.2.0`), `beta` remains `0.3.0-beta.3`, `alpha` remains `0.3.0-alpha.5`, and `rc` remains `0.2.0-rc.1`. GitHub Actions remains validation-only with OIDC and package-write permissions denied.
46
+
47
+ ## Candidate validation
48
+
49
+ Local candidate verification on Node.js `26.5.1`:
50
+
51
+ - `npm run check`: 69 files and 341 tests passed on the promoted tree.
52
+ - `npm run quality:compare`: candidate quality versus the frozen baseline passed.
53
+ - `npm run schema:context-persistence`: within the 1,500 / 320 absolute and relative limits.
54
+ - `npm run pack:check` and `npm pack --dry-run --json` for all three packages passed with no forbidden local/session/storage paths.
55
+ - `git diff --check` passed; the only pre-existing untracked path is `.serena/`, which is excluded from commits and package inventories.
56
+ - Version, exact core dependencies, package-lock entries, extension constant, and reference-adapter constant are synchronized to `0.3.0`.
57
+
58
+ Exact registry verification and the annotated tag are recorded below.
59
+
60
+ ## Registry evidence
61
+
62
+ Exact post-publication verification passed for all three `0.3.0` packages on 2026-09-04. The clean registry consumer verified exact adapter/core dependencies, public core exports, compiled reference-adapter conformance, packaged quality corpus, packaged Pi extension startup, and the installed `ds4-context-storage` CLI declaration, shim, and usage probe.
63
+
64
+ Published package shasums:
65
+
66
+ ```text
67
+ ds4-context-core: 7e3c6407996f263db3f6159e5de8b30de6dfabe8
68
+ ds4-context-reference-adapter: ce133b184b6dbb7ed2a7337d639dca13337d7df1
69
+ ds4-context-engine: 6d265de2a8e6c904482ab0ff89acbadbde862854
70
+ ```
71
+
72
+ For all three packages, npm `latest` now resolves to `0.3.0`, `beta` remains `0.3.0-beta.3`, `alpha` remains `0.3.0-alpha.5`, and `rc` remains `0.2.0-rc.1`.
73
+
74
+ Annotated tag `v0.3.0` targets `608a6238325ed8627dc16c0c32ad10697977e0e0`. The GitHub release is published at <https://github.com/Alucard24/ds4-context-engine/releases/tag/v0.3.0>.
75
+
76
+ ## Documentation
77
+
78
+ - [`../STORAGE_MAINTENANCE.md`](../STORAGE_MAINTENANCE.md)
79
+ - [`../STORAGE.md`](../STORAGE.md)
80
+ - [`../COMPACTION.md`](../COMPACTION.md)
81
+ - [`../RELEASING.md`](../RELEASING.md)
82
+ - [`0.3.0-beta.3.md`](0.3.0-beta.3.md)
@@ -0,0 +1,72 @@
1
+ # DS4 Context Engine 0.3.1
2
+
3
+ Status: published 2026-09-04 as stable, printed under the npm `latest` dist-tag.
4
+
5
+ This release adds the opt-in dedicated compaction model and per-request reasoning control on top of the 0.3.0 stable candidate. It carries forward 0.3.0 without changing canonical records, SQLite schema, runtime contracts, retention limits, privacy policy, compaction validation, or fallback semantics.
6
+
7
+ ## Added since 0.3.0
8
+
9
+ - **Dedicated compaction model** (`compaction.model.provider` / `compaction.model.id`, opt-in):
10
+ - when absent, compaction keeps using the active session model exactly as before, including preflight budget, segmentation, sanitization, and record provenance;
11
+ - when present, the model is resolved once per compaction through Pi's model registry and used uniformly for the input budget, segmentation, sanitization, segment/aggregate requests, and the `provider`/`model` provenance of summary records;
12
+ - automatic fallback with a `compaction.dedicated_model_fallback` warning when the model is not registered, has no configured authentication, or does not accept text input: a configuration mistake can never block compaction, and the hook still returns the session-model path;
13
+ - the resolved model is recorded in diagnostics as `compaction.dedicated_model` at `debug`.
14
+ - **Summary reasoning control** (`compaction.summary.thinking`, default `off`):
15
+ - applies only to summary requests, never to normal session traffic;
16
+ - `off` (default) leaves the request shape unchanged from 0.3.0;
17
+ - levels `minimal`/`low`/`medium`/`high`/`xhigh`/`max` map per API: `thinkingEnabled`/`effort` for `anthropic-messages`, `samplingParams.reasoning_effort` for OpenAI-compatible APIs (`openai-responses`, `openai-completions`, `azure-openai-responses`, `openai-codex-responses`);
18
+ - unsupported APIs ignore the option without errors; `xhigh`/`max` clamp to the highest supported effort where the API has no equivalent.
19
+ - Configuration validation in the loader recognizes the two opt-in object paths and rejects malformed provider/id tokens or unknown thinking levels, generating a `configuration ignored` warning and leaving the default config in force.
20
+ - Coordinated package versions moved to `0.3.1`.
21
+
22
+ There are no functional storage-format or provider-path changes relative to 0.3.0.
23
+
24
+ ## Safety and compatibility
25
+
26
+ Unchanged from 0.3.0: Pi JSONL remains canonical and append-only; SQLite remains disposable and rebuildable; physical maintenance remains explicit, offline, local-TTY-only, and unavailable to model-callable tools; every `context_persistence` write still requires a fresh positive local UI decision.
27
+
28
+ Compatibility remains unchanged:
29
+
30
+ - SQLite schema: `15`;
31
+ - configuration: `ds4-context-config-v1` (two opt-in object keys added; default shape and all existing keys unchanged);
32
+ - runtime adapter: `runtime-adapter-v1`;
33
+ - persistence tool: `ds4-context-persistence-tool-v1`;
34
+ - persistence result: `ds4-context-persistence-result-v1`;
35
+ - Pi: `0.84.3`;
36
+ - Node.js: `>=22.19.0`.
37
+
38
+ ## Package/version policy
39
+
40
+ The coordinated version is `0.3.1` for:
41
+
42
+ ```text
43
+ ds4-context-core
44
+ ds4-context-reference-adapter
45
+ ds4-context-engine
46
+ ```
47
+
48
+ Both adapters depend exactly on `ds4-context-core@0.3.1`. Publication uses npm's default `latest` tag for all three packages: `latest` now resolves to `0.3.1` (previously `0.3.0`), `beta` remains `0.3.0-beta.3`, `alpha` remains `0.3.0-alpha.5`, and `rc` remains `0.2.0-rc.1`. GitHub Actions remains validation-only with OIDC and package-write permissions denied.
49
+
50
+ ## Candidate validation
51
+
52
+ Local candidate verification on Node.js `26.5.1`:
53
+
54
+ - `npm run check`: 70 files and 352 tests passed (including five new dedicated-model/thinking integration tests and the thinking-mapping unit tests).
55
+ - `npm run quality:compare`: candidate quality versus the frozen baseline passed.
56
+ - `npm run schema:context-persistence`: within the 1,500 / 320 absolute and relative limits.
57
+ - `npm run latency:check` against the frozen baseline passed.
58
+ - `npm run pack:check` and `npm pack --dry-run --json` for all three packages passed with no forbidden local/session/storage paths.
59
+ - `git diff --check` passed; the only pre-existing untracked path is `.serena/`, which is excluded from commits and package inventories.
60
+ - Version, exact core dependencies, package-lock entries, extension constant, and reference-adapter constant are synchronized to `0.3.1`.
61
+
62
+ Validation-only CI is recorded below with the release commit. Exact registry verification and the annotated tag are recorded after execution.
63
+
64
+ ## Registry evidence
65
+
66
+ To be completed after publication.
67
+
68
+ ## Documentation
69
+
70
+ - [`../COMPACTION.md`](../COMPACTION.md)
71
+ - [`../RELEASING.md`](../RELEASING.md)
72
+ - [`0.3.0.md`](0.3.0.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ds4-context-engine",
3
- "version": "0.3.0-beta.3",
3
+ "version": "0.3.1",
4
4
  "description": "Non-destructive, provider-independent context management for Pi.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -62,7 +62,7 @@
62
62
  ]
63
63
  },
64
64
  "dependencies": {
65
- "ds4-context-core": "0.3.0-beta.3"
65
+ "ds4-context-core": "0.3.1"
66
66
  },
67
67
  "peerDependencies": {
68
68
  "@earendil-works/pi-ai": "0.84.3",
@@ -5,7 +5,8 @@ import type {
5
5
  SessionCompactEvent,
6
6
  SessionEntry,
7
7
  } from "@earendil-works/pi-coding-agent";
8
- import type { Ds4ContextConfig } from "ds4-context-core/config/config";
8
+ import type { Api, Model } from "@earendil-works/pi-ai";
9
+ import type { CompactionThinkingLevel, Ds4ContextConfig } from "ds4-context-core/config/config";
9
10
  import { calculateContextBudget, type ContextBudget } from "ds4-context-core/core/budget-manager";
10
11
  import { createModelProfile, type ModelDescriptor } from "ds4-context-core/core/model-profile";
11
12
  import type { ContextManifest } from "ds4-context-core/manifest/context-manifest";
@@ -212,7 +213,7 @@ export class CompactionCoordinator {
212
213
  ctx: ExtensionContext,
213
214
  ): Promise<{ compaction?: CompactionResult } | undefined> {
214
215
  const config = this.dependencies.config;
215
- const model = ctx.model;
216
+ const model = this.resolveCompactionModel(ctx) ?? ctx.model;
216
217
  if (!config.compaction.enabled || !config.enabled || !model || config.context.maxSummaryTokens <= 0) {
217
218
  return undefined;
218
219
  }
@@ -278,6 +279,8 @@ export class CompactionCoordinator {
278
279
  modifiedFiles: plan.modifiedFiles,
279
280
  event,
280
281
  ctx,
282
+ model,
283
+ thinking: this.dependencies.config.compaction.summary?.thinking,
281
284
  });
282
285
  usages.push(generated.usage);
283
286
  segmentNodes.push({
@@ -324,6 +327,7 @@ export class CompactionCoordinator {
324
327
  nextId,
325
328
  createdNodes,
326
329
  usages,
330
+ modelObject: model,
327
331
  });
328
332
  const activeNode = aggregated.activeNode;
329
333
  const embeddedNodes = createdNodes.filter((node) => node.id !== activeNode.id);
@@ -664,6 +668,45 @@ export class CompactionCoordinator {
664
668
  };
665
669
  }
666
670
 
671
+ private resolveCompactionModel(ctx: ExtensionContext): Model<Api> | undefined {
672
+ const configured = this.dependencies.config.compaction.model;
673
+ if (!configured || !ctx.model || !ctx.modelRegistry) return undefined;
674
+ const dedicated = ctx.modelRegistry.find(configured.provider, configured.id);
675
+ if (!dedicated) {
676
+ this.dependencies.logger.warn("compaction.dedicated_model_fallback", {
677
+ provider: configured.provider,
678
+ id: configured.id,
679
+ reason: "not-found",
680
+ sessionModel: ctx.model.id,
681
+ });
682
+ return undefined;
683
+ }
684
+ if (!ctx.modelRegistry.hasConfiguredAuth(dedicated)) {
685
+ this.dependencies.logger.warn("compaction.dedicated_model_fallback", {
686
+ provider: configured.provider,
687
+ id: configured.id,
688
+ reason: "no-auth",
689
+ sessionModel: ctx.model.id,
690
+ });
691
+ return undefined;
692
+ }
693
+ if (!dedicated.input?.includes("text")) {
694
+ this.dependencies.logger.warn("compaction.dedicated_model_fallback", {
695
+ provider: configured.provider,
696
+ id: configured.id,
697
+ reason: "no-text-input",
698
+ sessionModel: ctx.model.id,
699
+ });
700
+ return undefined;
701
+ }
702
+ this.dependencies.logger.debug("compaction.dedicated_model", {
703
+ provider: dedicated.provider,
704
+ id: dedicated.id,
705
+ sessionModel: ctx.model.id,
706
+ });
707
+ return dedicated;
708
+ }
709
+
667
710
  private inputBudgetTokens(model: ModelDescriptor): number {
668
711
  const config = this.dependencies.config;
669
712
  const resolved = this.dependencies.resolveModelBudget?.(model)
@@ -841,6 +884,7 @@ export class CompactionCoordinator {
841
884
  ctx: ExtensionContext;
842
885
  provider: string;
843
886
  model: string;
887
+ modelObject: Model<Api>;
844
888
  readFiles: readonly string[];
845
889
  modifiedFiles: readonly string[];
846
890
  inputBudgetTokens: number;
@@ -914,6 +958,8 @@ export class CompactionCoordinator {
914
958
  modifiedFiles: plan.modifiedFiles,
915
959
  event: input.event,
916
960
  ctx: input.ctx,
961
+ model: input.modelObject,
962
+ thinking: this.dependencies.config.compaction.summary?.thinking,
917
963
  });
918
964
  input.usages.push(generated.usage);
919
965
  const aggregateNode: EmbeddedSummaryNode = {
@@ -952,6 +998,8 @@ export class CompactionCoordinator {
952
998
  modifiedFiles: readonly string[];
953
999
  event: SessionBeforeCompactEvent;
954
1000
  ctx: ExtensionContext;
1001
+ model: Model<Api>;
1002
+ thinking?: CompactionThinkingLevel;
955
1003
  }): Promise<GeneratedSummary> {
956
1004
  return generateValidatedSummary({
957
1005
  ...input,
@@ -1,9 +1,10 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import type { Usage } from "@earendil-works/pi-ai";
2
+ import type { Api, Model, Usage } from "@earendil-works/pi-ai";
3
3
  import type {
4
4
  ExtensionContext,
5
5
  SessionBeforeCompactEvent,
6
6
  } from "@earendil-works/pi-coding-agent";
7
+ import type { CompactionThinkingLevel } from "ds4-context-core/config/config";
7
8
  import {
8
9
  analyzeUnsupportedExactValueBullets,
9
10
  groundSummaryFileSections,
@@ -33,6 +34,10 @@ export interface GenerateValidatedSummaryInput {
33
34
  maxSummaryTokens: number;
34
35
  event: SessionBeforeCompactEvent;
35
36
  ctx: ExtensionContext;
37
+ /** Dedicated compaction model; falls back to `ctx.model` when absent. */
38
+ model?: Model<Api>;
39
+ /** Reasoning level for the summary request; `off` (default) keeps the pre-existing request shape. */
40
+ thinking?: CompactionThinkingLevel;
36
41
  now: () => number;
37
42
  onTransportRetry?: (diagnostic: CompactionTransportRetryDiagnostic) => void;
38
43
  }
@@ -47,6 +52,36 @@ function unique(values: readonly string[]): string[] {
47
52
  return [...new Set(values)];
48
53
  }
49
54
 
55
+ /**
56
+ * Maps a compaction thinking level to provider-specific request options.
57
+ * Unknown/unsupported APIs return an empty object so the request keeps the
58
+ * pre-existing shape (no thinking fields). `off` also returns an empty object.
59
+ */
60
+ export function compactionThinkingOptions(
61
+ api: string,
62
+ level: CompactionThinkingLevel | undefined,
63
+ ): Record<string, unknown> {
64
+ if (!level || level === "off") return {};
65
+ if (api === "anthropic-messages") {
66
+ const effort = level === "minimal" || level === "low" ? "low" : level;
67
+ return { thinkingEnabled: true, effort };
68
+ }
69
+ if ([
70
+ "openai-completions",
71
+ "openai-responses",
72
+ "azure-openai-responses",
73
+ "openai-codex-responses",
74
+ ].includes(api)) {
75
+ const effort = level === "minimal" || level === "low"
76
+ ? "low"
77
+ : level === "xhigh" || level === "max"
78
+ ? "high"
79
+ : level;
80
+ return { samplingParams: { reasoning_effort: effort } };
81
+ }
82
+ return {};
83
+ }
84
+
50
85
  function responseText(response: unknown): string {
51
86
  if (!response || typeof response !== "object" || !("content" in response)) return "";
52
87
  const content = (response as { content?: unknown }).content;
@@ -124,7 +159,7 @@ function transportFailureSuffix(category: ProviderFailureCategory, attempts: num
124
159
  export async function generateValidatedSummary(
125
160
  input: GenerateValidatedSummaryInput,
126
161
  ): Promise<GeneratedSummary> {
127
- const model = input.ctx.model;
162
+ const model = input.model ?? input.ctx.model;
128
163
  if (!model) throw new Error("Compaction summary generation requires an active model");
129
164
  const maxTokens = Math.max(1, Math.min(input.maxSummaryTokens, model.maxTokens ?? input.maxSummaryTokens));
130
165
  const retryUsages: Usage[] = [];
@@ -148,7 +183,8 @@ export async function generateValidatedSummary(
148
183
  signal: input.event.signal,
149
184
  cacheRetention: "none",
150
185
  sessionId: randomUUID(),
151
- },
186
+ ...compactionThinkingOptions(model.api, input.thinking),
187
+ } as NonNullable<Parameters<typeof input.ctx.modelRegistry.complete>[2]>,
152
188
  );
153
189
  } catch (error) {
154
190
  if (input.event.signal.aborted) throw abortedError();
@@ -1,4 +1,4 @@
1
- export const EXTENSION_VERSION = "0.3.0-beta.3";
1
+ export const EXTENSION_VERSION = "0.3.1";
2
2
  export const SUPPORTED_PI_VERSION = "0.84.3";
3
3
  export const OBSERVER_PLANNER_VERSION = "observer-model-aware-v1";
4
4
  export const PLANNER_VERSION = "managed-learned-ranking-v1";