Skip to content

Commit 54515e1

Browse files
7418claude
andcommitted
feat: stream session manager + always show Claude Code built-in models, bump v0.17.4
Stream Session Manager — 切换会话不中断流: - src/lib/stream-session-manager.ts(新建): 全局单例管理所有 SSE 流, 使用 globalThis 模式(同 conversation-registry.ts)保证 HMR 不丢状态。 管理 AbortController、idle timeout (330s)、tool timeout 自动重试、 5 分钟 GC,所有 SSE 回调写入 snapshot 并 emit 事件给订阅者。 导出 startStream / stopStream / subscribe / getSnapshot / respondToPermission / clearSnapshot 等 API。 - src/types/index.ts: 新增 ToolUseInfo、ToolResultInfo(从 ChatView 提取)、 StreamPhase、SessionStreamSnapshot、StreamEvent、StreamEventListener 类型, 作为管理器与 ChatView 之间的数据契约。 - src/components/chat/ChatView.tsx(重构): 删除 abortControllerRef 及 unmount abort effect(此前切换会话的根因)、整个 fetch/SSE 逻辑约 280 行、 accumulatedRef/toolUsesRef/toolResultsRef/beforeunload handler。 改为 subscribe() + getSnapshot() 订阅模式,unmount 仅 unsubscribe 不 abort,mount 时通过 getSnapshot 恢复进行中的流状态。 sendMessage / stopStreaming / handlePermissionResponse 全部委托管理器。 - src/hooks/usePanel.ts: PanelContextValue 新增 activeStreamingSessions: Set<string> 和 pendingApprovalSessionIds: Set<string>,支持多会话并发流指示。 - src/components/layout/AppShell.tsx: 监听 stream-session-event 窗口事件 更新 activeStreamingSessions / pendingApprovalSessionIds Set 状态; 将 beforeunload handler 从 ChatView 移至此处(全局感知所有流)。 - src/components/layout/ChatListPanel.tsx: 侧栏流指示器改用 activeStreamingSessions.has() / pendingApprovalSessionIds.has(), 支持同时显示多个会话的流/审批状态。 模型选择器始终显示 Claude Code 内置模型: - src/app/api/providers/models/route.ts: 移除 hasEnvKey 环境变量检测条件, 始终显示 "Claude Code" provider 组(Sonnet 4.6 / Opus 4.6 / Haiku 4.5)。 根因:Claude Code CLI 通过 `claude login` 存储凭证在 ~/.claude/ 下, SDK 子进程可以读取,但 Next.js 进程的 process.env 中没有对应变量, 导致之前的 hasEnvKey 检测失败时模型选择器不显示内置模型。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0c379e5 commit 54515e1

File tree

9 files changed

+855
-436
lines changed

9 files changed

+855
-436
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codepilot",
3-
"version": "0.17.3",
3+
"version": "0.17.4",
44
"private": true,
55
"author": {
66
"name": "op7418",

src/app/api/providers/models/route.ts

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -73,16 +73,15 @@ export async function GET() {
7373
const providers = getAllProviders();
7474
const groups: ProviderModelGroup[] = [];
7575

76-
// Check for environment variables
77-
const hasEnvKey = !!(process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_AUTH_TOKEN);
78-
if (hasEnvKey) {
79-
groups.push({
80-
provider_id: 'env',
81-
provider_name: 'Environment',
82-
provider_type: 'anthropic',
83-
models: DEFAULT_MODELS,
84-
});
85-
}
76+
// Always show the built-in Claude Code provider group.
77+
// Claude Code CLI stores credentials in ~/.claude/ (via `claude login`),
78+
// which the SDK subprocess can read — even without ANTHROPIC_API_KEY in env.
79+
groups.push({
80+
provider_id: 'env',
81+
provider_name: 'Claude Code',
82+
provider_type: 'anthropic',
83+
models: DEFAULT_MODELS,
84+
});
8685

8786
// Provider types that are not LLMs (e.g. image generation) — skip in chat model selector
8887
const MEDIA_PROVIDER_TYPES = new Set(['gemini-image']);
@@ -102,16 +101,6 @@ export async function GET() {
102101
});
103102
}
104103

105-
// If no groups at all (no env, no providers), show default Anthropic group
106-
if (groups.length === 0) {
107-
groups.push({
108-
provider_id: 'env',
109-
provider_name: 'Anthropic',
110-
provider_type: 'anthropic',
111-
models: DEFAULT_MODELS,
112-
});
113-
}
114-
115104
// Determine default provider
116105
const defaultProviderId = getDefaultProviderId() || groups[0].provider_id;
117106

0 commit comments

Comments
 (0)