The reviewer identified two bugs in the original PR:
1. PATCH /api/config leaves session.dimensions stale: LoadConfig()
derives dimensions from the old dm_scope, and the merge carries
those stale dimensions forward. ApplyDmScope() then exits early
because dimensions is already populated, causing a mismatch between
dm_scope (new) and dimensions (old).
2. Legacy/default configs omit dm_scope in GET response: configs with
explicit dimensions but no dm_scope (including DefaultConfig) return
no dm_scope field, causing the frontend to fall back to its default
('per-channel-peer'), which may not match the actual dimensions.
Fix:
- Add DeriveDmScope() to reverse-map known dimensions arrays to
dm_scope when dm_scope is empty.
- Call it in LoadConfig(), PUT handler, PATCH handler, and
ResetToDefaults() for consistent normalization.
- In PATCH handler, clear stale dimensions from the merge result when
the patch contains session.dm_scope but not session.dimensions,
allowing ApplyDmScope() to re-derive from the new scope.
- Add comprehensive unit tests for DeriveDmScope() and scope
transition scenarios.
* fix(launcher): hide console flashes in all Windows child processes
PR #2654 only applied HideWindow to child processes in gateway.go (powershell, tasklist, ps). Several other files still use exec.Command directly, causing visible console windows on Windows.
- startup.go: reg query/add/delete for autostart registry
- version.go: picoclaw version subcommand
- runtime.go: rundll32 for browser launch
- onboard.go: picoclaw onboard subcommand
Add launcherExecCommand to the utils package (matching the api package pattern) and replace all bare exec.Command calls on Windows paths.
* refactor: consolidate launcherExecCommand into utils package
Export LauncherExecCommand and ApplyLauncherProcAttrs from the utils
package as the single source of truth. The api package now imports
and delegates to these exported functions, eliminating code duplication.
Addresses review feedback from imguoguo on PR #3061.
The dm_scope field was stored in config but never translated into the
dimensions array that the routing layer actually consumes. This meant
changing the session isolation scope in the UI had no effect at runtime.
Add ApplyDmScope() to SessionConfig which maps the user-facing dm_scope
values (per-channel-peer, per-channel, per-peer, global) to the
corresponding dimension arrays. Call it in LoadConfig post-processing
and in both the PATCH and PUT API handlers.
Includes table-driven tests covering all dm_scope values and the
precedence rule (explicit dimensions > derived from dm_scope).
singleflight.Group.Do() returns any, which is type-asserted as bool
without an ok check at model_status.go:211. If a non-bool value is
returned (e.g. nil from shared/cache corruption), this panics.
Add ok check and return false (model probe failed) as a safe default.
Address remaining review feedback: 1) Add HistoryTokens field to ContextUsage/ContextStats, showing history-only token count in /context and frontend UI alongside SummarizeAtTokens so users can see the actual summarization trigger comparison. 2) Remove .codebuddy/github-contribute/ state files accidentally included in the PR.
The /context command previously showed only the hard budget compression
threshold (contextWindow - maxTokens), which confused users who expected
to see the soft summarization trigger from summarize_token_percent.
This commit adds SummarizeAtTokens alongside the existing CompressAtTokens
so that both thresholds are visible:
- Compress at: contextWindow - maxTokens (hard budget, triggers proactive
compression when exceeded)
- Summarize at: contextWindow * summarizeTokenPercent / 100 (soft trigger,
matches maybeSummarize's threshold)
The fix updates the /context command output, the Web UI popover, and the
pico channel WebSocket payload.
Fixes#2968
- Persistence layer (jsonl.go addMsg/SetHistory) normalizes CreatedAt
when missing so the invariant is guaranteed at the storage boundary
- API layer (session.go) exposes created_at on all transcript message
types with session.updated fallback for legacy messages
- Frontend uses per-message timestamps when available
- messagesContentEqual ignores CreatedAt for tail-matching after
JSONL roundtrip
Fixes#2787
* feat: add request-scoped context policies
Add named turn profiles under agents.defaults so callers can opt into
per-request context and tool policies without changing default chat behavior.
Profiles can disable history, system context, skill prompts, or tools, and can
limit skills/tools with allow lists. Wire profile selection through Pico message
payloads, agent turn execution, Web chat selection, and Web visual config.
Reject invalid turn profiles before saving config through Web APIs and document
the new request context policy behavior.
* fix: address turn profile review blockers
* feat: simplify request context policy config
* fix: suppress tool prompt when turn tools are disabled
* fix: enforce turn profile tool restrictions
When editing an existing model, the edit form initializes apiKey as
empty for security. This caused "Fetch Available Models" to reject with
"please enter API Key first" even though the key is saved server-side.
Add model_index support: the frontend passes the model's index to the
backend, which looks up the stored key from config. The key never leaves
the backend. Provider and API base are validated to prevent a stored key
from being sent to an unrelated endpoint.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(chat,seahorse): persist and display model_name across history
* test(seahorse): fix lint regressions in repair coverage
* fix(pico): preserve model_name in live updates
* fix(pico): preserve model_name through live stream wrappers
* feat(models): unify provider metadata around backend catalog
- Move shared provider metadata and alias normalization into backend-owned provider catalog
- Expose display, fetch, auth, and default model metadata through /api/models provider_options
- Replace frontend static provider registry with catalog-driven selection, validation, grouping, and fallback rendering
- Treat provider default api_base as placeholder and effective fetch/test base while keep submitted api_base separate from derived defaults
- Add model page retry handling, touched locale updates, and provider metadata assertions in backend tests
* fix(models): canonicalize backend provider aliases and common models
* fix(models): restore deepseek common model recommendations
* Support streaming
* fix: stream pico reasoning updates
Route Pico reasoning through the active streamer and hide empty thought placeholders.
* fix: harden configured streaming delivery
* fix ci
* fix split issue