Skip to content

fix(config): project contextWindow/maxTokens onto flat AppConfig - #326

Open
AmirF194 wants to merge 1 commit into
OpenCoworkAI:mainfrom
AmirF194:fix/262-context-window-config-dropped
Open

fix(config): project contextWindow/maxTokens onto flat AppConfig#326
AmirF194 wants to merge 1 commit into
OpenCoworkAI:mainfrom
AmirF194:fix/262-context-window-config-dropped

Conversation

@AmirF194

@AmirF194 AmirF194 commented Aug 9, 2026

Copy link
Copy Markdown

Summary

normalizeConfig() and composeProjectedConfig() build the flat AppConfig object the
agent runner reads from configStore.getAll(). Both functions read every other projected
field from projectFromConfigSet()'s return value except contextWindow and maxTokens,
so a user's saved context-window/max-tokens override for a custom or Ollama provider profile
is silently dropped: the agent runner falls back to a default or auto-probed value instead of
what the user configured. buildAgentRuntimeSignature() (src/main/index.ts) has the same
gap, so even a user who edits only these two fields will not get the running session reloaded
with the new config, since the signature it hashes never changes.

Fixes #262.

Fix

Project both fields through in normalizeConfig(), composeProjectedConfig(), and
buildAgentRuntimeSignature().

normalizeProfile() (a few lines above normalizeConfig() in the same file) already
establishes the right pattern for this exact situation, with the comment "preserve optional
numeric fields so callers don't silently lose user-set values": assign the field only when it
is a valid positive number, never write it unconditionally. That matters here specifically
because contextWindow/maxTokens are genuinely absent on most profiles (no default profile
sets them), and electron-store's underlying conf package throws on .set() if a key is
present with an explicit undefined value, unlike a plain object or JSON.stringify, which
both drop it silently. A first pass at this fix that assigned the fields unconditionally
(contextWindow: projected.contextWindow) crashed ConfigStore's constructor for any profile
that never set them, which is the common case; composeProjectedConfig() additionally spreads
...base, so switching from a profile with an override to one without needs an explicit
delete, or the old value leaks into the new config set's projection.

Testing

  • tests/config-store-context-window-projection.test.ts (new): fails on main (both the
    drop itself and the constructor crash on a profile with no override), passes on this
    branch. Covers projection, persistence across a config-set switch, and clearing the value
    when switching to a set whose profile has no override.
  • tests/index-agent-runtime-signature.test.ts (new): fails on main, passes on this branch.
  • Full suite: npx vitest run, 154 files / 1108 tests pass. npx tsc --noEmit and
    npx eslint src --ext .ts,.tsx both pass with no new errors or warnings.
  • Not verified: the buildAgentRuntimeSignature() gap as observed through a real running
    session reload (the fix is a one-line addition mirroring the six adjacent fields already
    handled the same way, but I did not drive the actual reload path end to end).

normalizeProfile already preserves a profile's contextWindow/maxTokens
(since 364b0e3), but normalizeConfig() and composeProjectedConfig() both
build the flat AppConfig from projectFromConfigSet()'s projected object
and drop these two fields, so getAll().contextWindow/maxTokens is always
undefined for a custom/Ollama profile. agent-runner.ts reads exactly
those two flat fields to size the synthetic-model fallback, so a
user-configured context window or max-output-tokens override never
reaches the running agent.

buildAgentRuntimeSignature() also omitted both fields, so changing only
contextWindow/maxTokens left a running session on the old runtime config
until an unrelated field changed.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • [Minor] The positive-number guard is repeated in both projection paths and the two paths already behave differently (normalizeConfig leaves the key absent, while composeProjectedConfig explicitly deletes it), so the logic can drift if another optional numeric field is added later. The check also accepts Infinity, despite the valid positive number intent. Centralize it, in src/main/config/config-store.ts:1021-1026 and :1055-1064.

    Suggested fix:

    const setOptionalPositiveNumber = <K extends 'contextWindow' | 'maxTokens'>(
      result: Partial<AppConfig>,
      key: K,
      value: number | undefined,
    ) => {
      if (typeof value === 'number' && Number.isFinite(value) && value > 0) {
        result[key] = value;
      } else {
        delete result[key];
      }
    };

    Then use setOptionalPositiveNumber(result, 'contextWindow', projected.contextWindow) in both methods (the else branch is a safe no-op in normalizeConfig because the fresh object has no stale key).

Questions

None.

Summary

Review mode: initial

Review policy: advisory — the check reflects automation health/completion only; it does not approve the PR or resolve findings.

The change correctly propagates optional contextWindow and maxTokens from the active profile into both normalizeConfig() and composeProjectedConfig(), and adds them to the agent runtime signature. No blockers or major correctness issues found. The one maintainability concern above is minor. Residual risk: the new signature test scans source text rather than exercising the function, and the mocked electron-store does not emulate electron-store's rejection of explicit undefined, so a regression that unconditionally writes contextWindow: undefined would not be caught by the current mock.

Testing

Not run (automation). Suggested additions: make the MockStore.set in src/tests/config-store-context-window-projection.test.ts throw when a value is undefined, and consider a behavioral test for buildAgentRuntimeSignature (for example by exporting it) instead of a source-text scan.

Open Cowork Bot

@AmirF194

Copy link
Copy Markdown
Author

No rush, just checking in after a week. CI is green and the branch is clean against main whenever you get a chance to look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Custom/Ollama contextWindow and maxTokens are not projected into runtime config

1 participant