返回 DeepSeek-Reasonix
model_settings.go
根目录 / internal / bot / model_settings.go
1 package bot
2
3 import (
4 "context"
5 "fmt"
6 "strings"
7
8 "reasonix/internal/boot"
9 "reasonix/internal/config"
10 "reasonix/internal/control"
11 "reasonix/internal/event"
12 "reasonix/internal/secrets"
13 )
14
15 // The session queue owns this new turn. Approval replies and child work never
16 // enter here. Keep the previous state and lease until the complete replacement
17 // is ready, then fence publication against retirement and a newer disk save.
18 func (gw *BotGateway) applySessionModelSettings(ctx context.Context, key string, msg InboundMessage, previous *sessionState) (*sessionState, error) {
19 old, ok := previous.ctrl.(*control.Controller)
20 if !ok {
21 return previous, nil
22 }
23 previous.lifecycleMu.Lock()
24 defer previous.lifecycleMu.Unlock()
25 for {
26 if err := ctx.Err(); err != nil {
27 return nil, err
28 }
29 if previous.retired {
30 return nil, errBotSessionRetired
31 }
32 applied, desired, err := old.ModelSettingsState()
33 if err != nil {
34 return nil, err
35 }
36 if applied == desired {
37 return previous, nil
38 }
39 if botSessionHasActiveWork(previous) {
40 return nil, fmt.Errorf("saved model settings are pending until current work finishes")
41 }
42 cfg, err := config.LoadModelRuntimeSnapshot(previous.workspaceRoot, old.ModelRef())
43 if err != nil {
44 return nil, err
45 }
46 model := old.ModelRef()
47 if entry, ok := cfg.ResolveModel(model); !ok || !entry.Configured() {
48 var available bool
49 model, _, available = cfg.ResolveNewSessionChatModel()
50 if !available || strings.TrimSpace(model) == "" {
51 return nil, fmt.Errorf("choose a configured model before starting another bot request")
52 }
53 }
54 next := &sessionState{
55 sink: &sessionEventSink{}, leases: previous.leases,
56 platform: previous.platform, connectionID: previous.connectionID,
57 model: previous.model, workspaceRoot: previous.workspaceRoot,
58 toolApprovalMode: previous.toolApprovalMode, sessionPath: previous.sessionPath,
59 mappingDegraded: previous.mappingDegraded, createdAt: previous.createdAt, lastActive: previous.lastActive,
60 pendingApprovals: map[string]event.Approval{}, pendingAsks: map[string][]event.AskQuestion{},
61 }
62 next.onSessionTransition = gw.botSessionTransitionHandler(key, msg, next)
63 result, err := boot.Rebuild(ctx, old, boot.Options{
64 Model: model, RequireKey: true, RuntimeReload: boot.RuntimeReload{ForceFullRebuild: true},
65 MaxSteps: gw.cfg.MaxSteps, MaxStepsKey: "bot.max_steps", Sink: next.sink,
66 StatsSource: "bot", WorkspaceRoot: next.workspaceRoot, SessionDir: botSessionDir(next.workspaceRoot),
67 ApprovalTimeout: gw.approvalTimeout(),
68 OnSessionRecovered: gw.botSessionRecoveredHandler(key, msg, next), OnSessionTransition: next.onSessionTransition,
69 })
70 if err != nil {
71 return nil, err
72 }
73 next.ctrl = result.Controller
74 result.Controller.EnableInteractiveApproval()
75 a, d, err := result.Controller.ModelSettingsState()
76 if err != nil || a != d {
77 result.Controller.Close()
78 if err != nil {
79 return nil, err
80 }
81 continue
82 }
83 if err := bindBotSessionWriteAuthority(next); err != nil {
84 result.Controller.Close()
85 _ = bindBotSessionWriteAuthority(previous)
86 return nil, err
87 }
88 gw.mu.Lock()
89 if gw.controllers[key] != previous {
90 gw.mu.Unlock()
91 result.Controller.Close()
92 _ = bindBotSessionWriteAuthority(previous)
93 return nil, fmt.Errorf("bot session changed while applying saved model settings")
94 }
95 if err := control.ActivateControllerReplacement(old, result.Controller); err != nil {
96 gw.mu.Unlock()
97 result.Controller.ReleaseResources()
98 _ = bindBotSessionWriteAuthority(previous)
99 return nil, fmt.Errorf("activate replacement bot runtime: %w", err)
100 }
101 gw.controllers[key] = next
102 previous.leases = nil
103 previous.retired = true
104 gw.mu.Unlock()
105 result.Controller.ActivateGoalDriverAfterRebuild()
106 old.Close()
107 return next, nil
108 }
109 }
110
111 func (gw *BotGateway) sessionForNewTurn(ctx context.Context, adapter Adapter, key string, msg InboundMessage) *sessionState {
112 // 获取或创建 Controller
113 state := gw.getOrCreateSession(ctx, key, msg)
114 if state == nil || state.ctrl == nil {
115 _ = gw.sendText(ctx, adapter, msg, "内部错误:无法创建会话。")
116 return nil
117 }
118 var settingsErr error
119 state, settingsErr = gw.applySessionModelSettings(ctx, key, msg, state)
120 if settingsErr != nil {
121 gw.logger.Warn("bot model settings application failed", "err", secrets.RedactError(settingsErr))
122 _ = gw.sendText(ctx, adapter, msg, "模型设置已保存,但当前会话尚未成功应用。请检查可用模型后重试;原会话仍保留。")
123 return nil
124 }
125 return state
126 }
127
127 lines GO