8 Commits

Author SHA1 Message Date
程序员阿江(Relakkes)
a159ee3511 fix: stream ChatGPT OAuth title requests
ChatGPT Codex requires streamed Responses API requests, including hidden non-chat paths such as title generation. Keep the OAuth adapter streaming upstream while preserving JSON responses for non-streaming Anthropic callers, and route ChatGPT Official titles through the OAuth Codex endpoint.

Constraint: ChatGPT Codex rejects non-streaming requests with HTTP 400
Rejected: Disable AI title generation for ChatGPT OAuth | would leave first-session metadata degraded
Confidence: high
Scope-risk: narrow
Tested: bun test src/services/openaiAuth/fetch.test.ts
Tested: bun test src/server/__tests__/title-service.test.ts
Tested: bun run check:server
Tested: git diff --check
Not-tested: Live ChatGPT OAuth account round trip after remote build
2026-05-21 15:31:56 +08:00
程序员阿江(Relakkes)
c866adc951 Honor desktop thinking controls for provider streams
Desktop sessions must treat the global Thinking toggle as the source of truth across active CLI sessions, title generation, and provider-compatible request bodies. DeepSeek-style streams can start with reasoning blocks before text, so the WebSocket bridge now keeps the UI in thinking state until text content actually starts.

Constraint: DeepSeek and MiniMax use Anthropic-compatible surfaces but expose thinking behavior through provider-specific request and stream shapes
Rejected: Keep provider-specific disabled-thinking env defaults | stale defaults kept overriding the user's global Thinking setting
Rejected: Treat every non-tool stream block as text | reasoning-only startup blocks created a blank streaming gap before the visible thinking bubble
Confidence: high
Scope-risk: moderate
Directive: Do not change thinking stream state transitions without replaying reasoning-before-text provider events
Tested: bun test src/server/__tests__/ws-memory-events.test.ts
Tested: bun run check:server
Tested: bun run verify
Not-tested: Live DeepSeek provider smoke with real quota
2026-05-15 19:35:12 +08:00
程序员阿江(Relakkes)
179f79b794 fix: sanitize generated session titles
Slash-command and skill prompts can enter the title-generation path as internal XML breadcrumbs. The async title request previously treated that transport metadata as user prose, so a generated ai-title could persist raw command tags and override the normal session title.

This routes title sources and generated title output through a shared sanitizer, preserving user-visible command names and arguments while dropping unrelated internal XML metadata. Desktop fallback title rendering now applies the same cleanup so existing transcripts with bad ai-title entries recover on read.

Constraint: Session titles can be produced by both desktop server logic and the SDK generate_session_title control request.
Rejected: Only clean desktop session display | leaves CLI and remote title generation able to persist bad titles again
Confidence: high
Scope-risk: moderate
Directive: Keep generated-title input and persisted-title readback on the shared sanitizer; do not add a title path that reads command XML directly.
Tested: bun test src/utils/__tests__/sessionTitle.test.ts src/utils/__tests__/sessionTitleText.test.ts
Tested: bun run check:server
Tested: bun run check:desktop
Tested: bun run verify (7 passed, 1 failed on existing aggregate agent-utils coverage baseline)
Not-tested: live model title-generation smoke
2026-05-09 22:34:27 +08:00
程序员阿江(Relakkes)
7fbce35be6 fix: prevent malformed generated session titles
Session titles need to appear immediately, but the async AI title pass can return fenced or escaped JSON fragments. Keep the first-message title path fast, preserve optimistic client titles during background refresh, and only accept structured title responses that parse cleanly.

Constraint: Desktop sessions should stop showing Untitled/New Session after the first user turn.
Rejected: Accept short raw model output as a fallback | malformed JSON fragments are short enough to leak into the UI.
Confidence: high
Scope-risk: moderate
Directive: Do not loosen generated title parsing without regression coverage for fenced, escaped, and truncated JSON responses.
Tested: bun test src/server/__tests__/title-service.test.ts
Tested: bun run check:server
Tested: cd desktop && bun run test -- --run src/stores/chatStore.test.ts src/stores/sessionStore.test.ts src/pages/EmptySession.test.tsx
Tested: agent-browser smoke on http://127.0.0.1:1420/ confirmed sidebar and tab titles update without JSON fragments.
2026-05-07 16:28:08 +08:00
程序员阿江(Relakkes)
d50268c07c fix: prevent session sidebar stalls and title churn
Large desktop histories were making session discovery parse every JSONL
before pagination, while automatic title updates could still overwrite
manual names during resumed sessions. This keeps listing bounded to the
requested page, preserves custom titles, and blocks deleted placeholder
sessions from being recreated by prewarm startup.

Constraint: Desktop session storage remains JSONL-compatible with the CLI
Rejected: Virtualize the sidebar in this patch | does not fix backend JSONL parsing cost
Rejected: Disable title generation globally | would regress useful titles for unnamed sessions
Confidence: high
Scope-risk: moderate
Directive: Do not reintroduce all-file JSONL parsing on /api/sessions list paths without a heavy-session benchmark
Tested: ANTHROPIC_API_KEY=test-key bun test src/server/__tests__/title-service.test.ts src/server/__tests__/sessions.test.ts
Tested: ANTHROPIC_API_KEY=test-key bun test src/server/__tests__/conversations.test.ts
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: heavy local preview with 240 sessions, 320 messages each, and 40 restored tabs
Not-tested: native packaged desktop runtime under Windows with the same heavy fixture
Related: https://github.com/NanmiCoder/cc-haha/issues/237
Related: https://github.com/NanmiCoder/cc-haha/issues/248
2026-05-02 12:04:51 +08:00
程序员阿江(Relakkes)
9ecc178c7a fix: prevent third-party thinking mode mismatches
Desktop users can now disable thinking for new sessions, and Anthropic-compatible providers that opt in receive explicit disabled-thinking requests across main turns, side queries, and AI title generation.

Constraint: DeepSeek/Kimi/GLM Anthropic-compatible endpoints need a non-thinking path without scattering provider-specific logic through the CLI.
Rejected: Per-model if/else branches | centralized provider preset env keeps the native CLI surface smaller and easier to audit.
Confidence: high
Scope-risk: moderate
Tested: bun test src/utils/__tests__/thinking.test.ts src/server/__tests__/title-service.test.ts src/server/__tests__/provider-presets.test.ts src/server/__tests__/conversations.test.ts
Tested: cd desktop && bun run test -- generalSettings.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: agent-browser DeepSeek desktop E2E with transparent proxy captured main and title requests with thinking.type=disabled
2026-05-01 10:13:10 +08:00
程序员阿江(Relakkes)
773a8a703f Keep desktop chats on the selected provider/model
The desktop model picker now stores a session-scoped provider/model selection instead of relying on the global active provider. That selection is replayed on connect, passed into the CLI startup path, and preserved across turns until the user changes it again.

To make that true end-to-end, the server now restarts the session process when runtime selection changes, injects provider-scoped env for third-party providers, and routes proxy traffic by provider id. The selector UI was also tightened so provider grouping stays visible while the actual model choice remains readable.

Constraint: Different providers can expose the same model id, so chat runtime selection cannot be derived from model id alone
Constraint: A desktop session reuses one CLI subprocess across turns, so runtime changes must restart that process to take effect
Rejected: Keep using Settings active provider as the chat selector | conflates defaults with live session state and breaks overlapping models
Rejected: UI-only runtime switching without server restart | later turns would continue using the old CLI subprocess configuration
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep provider defaults and session runtime overrides separate, and preserve provider-scoped proxy routing when extending model selection surfaces
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run test src/stores/chatStore.test.ts
Tested: cd desktop && bun run test src/__tests__/generalSettings.test.tsx
Tested: bun test src/server/__tests__/conversation-service.test.ts
Tested: bun test src/server/__tests__/conversations.test.ts
Tested: bun -e "await import('./src/server/services/titleService.ts'); await import('./src/server/ws/handler.ts')"
Not-tested: Real third-party provider round-trip from the desktop UI against a live upstream account
2026-04-23 13:41:27 +08:00
程序员阿江(Relakkes)
12cc872150 feat: auto-generate session titles using AI (Haiku model)
After the first assistant response, derive a quick placeholder title from
the user message, then asynchronously call the provider's Haiku model to
generate a polished 3-7 word title. Titles update again at message 3 with
fuller conversation context. Updates push to frontend in real-time via
WebSocket `session_title_updated` event.

- extractTitle now reads `ai-title` JSONL entries (priority: custom > ai > first message)
- New titleService with deriveTitle + generateTitle using active provider config
- Handler tracks per-session message count and triggers generation on result
- Frontend sessionStore receives live title updates for sidebar + header

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 20:48:48 +08:00