返回 DeepSeek-Reasonix
port.go
根目录 / internal / control / port.go
1 package control
2
3 import (
4 "context"
5
6 "reasonix/internal/agent"
7 "reasonix/internal/billing"
8 "reasonix/internal/checkpoint"
9 "reasonix/internal/command"
10 "reasonix/internal/config"
11 "reasonix/internal/event"
12 "reasonix/internal/evidence"
13 "reasonix/internal/hook"
14 "reasonix/internal/jobs"
15 "reasonix/internal/memory"
16 "reasonix/internal/plugin"
17 "reasonix/internal/provider"
18 "reasonix/internal/sandbox"
19 "reasonix/internal/session"
20 "reasonix/internal/skill"
21 )
22
23 // This file defines the driving port: the typed, segregated interface surface
24 // that frontends (cli, desktop, bot, acp, serve) consume instead of coupling to
25 // the concrete *Controller and its ~99 methods. Each frontend depends only on
26 // the sub-ports it actually uses (interface segregation), so e.g. the bot never
27 // sees checkpoint or memory methods.
28 //
29 // The sub-ports are also the intended decomposition boundary for Controller
30 // itself: the port comes first and gives the later collaborator splits a spec to
31 // follow. *Controller implements every sub-port (asserted below). The full
32 // SessionAPI composition will accrete here as the remaining frontends migrate.
33
34 // Lifecycle covers a session's identity and lifecycle: minting, resuming,
35 // clearing, and locating the active session.
36 type Lifecycle interface {
37 NewSession() error
38 ClearSession() error
39 Resume(s *agent.Session, path string)
40 SetSessionPath(p string)
41 SessionPath() string
42 SessionDir() string
43 Label() string
44 ModelRef() string
45 WorkspaceRoot() string
46 Close()
47 }
48
49 // IdentityLifecycle is the final session-id based lifecycle. Frontends may
50 // type-assert it while legacy read/import DTOs remain available; new execution
51 // commands must use this surface instead of manufacturing transcript paths.
52 type IdentityLifecycle interface {
53 SessionRef() (session.SessionRef, bool)
54 SessionService() *session.Service
55 UsesExclusiveSession() bool
56 BindFreshSession(context.Context, string) (session.SessionRef, error)
57 OpenSession(context.Context, session.SessionRef) (session.SessionRef, error)
58 ContinueLegacySession(context.Context, string, string) (session.SessionRef, error)
59 ContinuePrototypeSession(context.Context, string) (session.SessionRef, error)
60 }
61
62 // IdentityCreateLifecycle is the header-aware creation extension used by the
63 // Desktop Workspace registry. Other frontends may continue using
64 // IdentityLifecycle.BindFreshSession while they do not own Workspace metadata.
65 type IdentityCreateLifecycle interface {
66 BindFreshSessionWithOptions(context.Context, session.CreateOptions) (session.SessionRef, error)
67 ContinueLegacySessionWithOptions(context.Context, string, string, session.CreateOptions) (session.SessionRef, error)
68 }
69
70 // TurnControl covers driving a model turn and observing its run state: the
71 // various submit/run entry points, cancellation, steering, and status reads.
72 type TurnControl interface {
73 Submit(input string)
74 SubmitDisplay(display, input string)
75 SubmitFinalReadinessRecovery(display, input string)
76 SubmitDeliveryRecovery(display, input string)
77 SubmitInvocationDisplay(display, input string, invocations []InvocationRequest)
78 SubmitEditedDisplay(display, input, original string)
79 SubmitHTTP(input string)
80 SubmitHTTPFormat(input, format string)
81 SubmitUserTurn(input, display string)
82 Send(input string)
83 SendWithRaw(input, raw string)
84 Run(ctx context.Context, input string) error
85 RunTurn(ctx context.Context, input string) error
86 RunFinalReadinessRecovery(ctx context.Context, input string) error
87 RunShell(command string)
88 Cancel()
89 Steer(text string)
90 SteerConsumed() bool
91 Running() bool
92 CancelRequested() bool
93 RuntimeStatus() RuntimeStatus
94 Turn() int
95 History() []provider.Message
96 ToolResult(toolID string) *ToolResultData
97 }
98
99 // Approvals covers tool-approval and ask prompts plus the runtime approval
100 // posture (ask/auto/yolo). It mirrors the approvalManager surface.
101 type Approvals interface {
102 Approve(id string, allow, session, persist bool)
103 ResolveApproval(id string, allow bool, scope sandbox.ApprovalScope) error
104 ResolvePlanDecision(id string, action PlanDecisionAction) error
105 ResolvePlanDecisionWithFeedback(id string, action PlanDecisionAction, feedback string) error
106 // ResolveRecovery rejects retired Auto Guard actions with recovery_retired.
107 ResolveRecovery(id string, action agent.RecoveryAction, feedback string) error
108 AnswerMCPInteraction(id, action string, content map[string]any)
109 AnswerQuestion(id string, answers []event.AskAnswer)
110 AnswerQuestionChecked(id string, answers []event.AskAnswer) error
111 // AnswerMCPInteractionChecked resolves an mcp_interaction prompt after its
112 // durable transition (serve /mcp-interaction, desktop bridge).
113 AnswerMCPInteractionChecked(id, action string, content map[string]any) error
114 Ask(ctx context.Context, questions []event.AskQuestion) ([]event.AskAnswer, error)
115 ReplayPendingPrompts()
116 ReplayPendingPromptsTo(sink event.Sink)
117 ReplayPendingPromptsWith(sinkFactory func() event.Sink)
118 PendingPrompt() bool
119 EnableInteractiveApproval()
120 ToolApprovalMode() string
121 SetToolApprovalMode(mode string)
122 AutoApproveTools() bool
123 SetAutoApproveTools(on bool)
124 Bypass() bool
125 SetBypass(on bool)
126 SetMode(plan, autoApproveTools bool)
127 }
128
129 // Goals covers the active-goal FSM and plan mode.
130 type Goals interface {
131 Goal() string
132 GoalStatus() string
133 SetGoal(goal string)
134 // SetGoalDurable updates the Goal only after its backing session accepts
135 // the lifecycle mutation. Hosts must use this method before publishing UI
136 // metadata or starting a provider turn.
137 SetGoalDurable(goal string) error
138 // EditGoalDurable changes an existing Goal in place. It preserves the Goal
139 // identity and admitted round count while advancing its CAS revision.
140 EditGoalDurable(objective string, maxGoalRounds *uint64) error
141 // SetGoalWithResearchMode is retained for deprecated CLI budget flags. The
142 // mode is translated at the boundary and is not stored in the Goal runtime.
143 SetGoalWithResearchMode(goal string, researchMode GoalResearchMode)
144 ResumeGoal() bool
145 PauseGoal() bool
146 GoalRuntime() GoalRuntimeView
147 GoalStrict(strict bool)
148 ClearGoal()
149 ResetPlannerSession()
150 PlanMode() bool
151 SetPlanMode(v bool)
152 // AgentPreset is the session role setting (standard|delivery), derived
153 // from the quality floor.
154 AgentPreset() string
155 // SetAgentPreset updates the role setting for subsequent turns without
156 // rebuilding the controller.
157 SetAgentPreset(preset string)
158 // QualityFloor is the session delivery floor (standard|delivery).
159 QualityFloor() string
160 // SetQualityFloor updates the session delivery floor for subsequent
161 // turns without rebuilding the controller.
162 SetQualityFloor(floor string) error
163 }
164
165 // SessionHistory covers checkpoint/rewind, branch/fork, and the log-restructuring
166 // operations (compact, summarize).
167 type SessionHistory interface {
168 Checkpoints() []checkpoint.Meta
169 CheckpointFileState(path string) (checkpoint.FileState, bool)
170 CheckpointTurnChanges(turn int) *checkpoint.TurnChanges
171 CheckpointTurnsByMessageIndex() map[int]int
172 CheckpointHasBoundary(turn int) bool
173 Rewind(turn int, scope RewindScope) error
174 PrepareRewind(turn int, scope RewindScope) (checkpoint.RewindPlan, error)
175 CommitRewind(planID string) (checkpoint.RewindResult, error)
176 CommitRewindInPlace(planID string) (checkpoint.RewindResult, error)
177 SessionHead() (agent.HeadRef, bool)
178 UndoRewind(transactionID string) (checkpoint.RewindResult, error)
179 PrepareFileRevert(path string) (checkpoint.RewindPlan, error)
180 CommitFileRevert(planID string, resolution checkpoint.ConflictResolution) (checkpoint.RewindResult, error)
181 Fork(turn int) (string, error)
182 ForkNamed(turn int, name string) (string, error)
183 ForkSession(turn int, name string) (string, error)
184 Branch(name string) (string, error)
185 Branches() ([]agent.BranchInfo, error)
186 BranchTreeText() string
187 CurrentBranchID() string
188 SwitchBranch(ref string) (agent.BranchInfo, error)
189 Compact(ctx context.Context, instructions string) error
190 CompactRatio() float64
191 ContextReport() (summary, detail string)
192 SummarizeFrom(ctx context.Context, turn int) error
193 SummarizeUpTo(ctx context.Context, turn int) error
194 }
195
196 // MemoryControl covers session/project memory reads and mutations.
197 type MemoryControl interface {
198 Memory() *memory.Set
199 QuickAdd(scope memory.Scope, note string) (string, error)
200 SaveDoc(path, body string) (string, error)
201 SaveMemory(m memory.Memory) (string, error)
202 ForgetMemory(name string) error
203 QueueMemory(note string)
204 MemoryRevisions(ref string) []memory.Memory
205 RestoreMemory(ref string, revision int) (memory.Memory, error)
206 RestoreArchivedMemory(archivePath string) (memory.Memory, error)
207 LastMemoryRecall() memory.RecallResult
208 }
209
210 // Capabilities covers the session's pluggable surface — MCP servers, skills,
211 // slash commands, hooks — and resolving prompt/command/skill inputs.
212 type Capabilities interface {
213 Host() *plugin.Host
214 Commands() []command.Command
215 ReloadCommands(ctx context.Context) error
216 Skills() []skill.Skill
217 SlashSkills() []skill.Skill
218 AllSkills() []skill.Skill
219 LoadSkill(name string) (skill.Skill, bool)
220 DisabledSkills() []skill.Skill
221 SkillEnabled(name string) bool
222 SetSkillEnabled(name string, enabled bool) error
223 CreateSkill(name string, scope skill.Scope, content string) (string, error)
224 UpdateSkill(name string, scope skill.Scope, content string) error
225 DeleteSkill(name string, scope skill.Scope) error
226 HookRunner() *hook.Runner
227 CustomCommand(input string) (sent string, found bool)
228 MCPPrompt(ctx context.Context, input string) (sent string, found bool, err error)
229 // MCPCapabilityViews returns the host's four-layer capability matrix
230 // (Protocol Connection, Core Host, Interactive Host, Apps Host) as
231 // read-only diagnostics for MCP status surfaces.
232 MCPCapabilityViews() []plugin.CapabilityView
233 RunSkill(input string) (sent string, found bool)
234 AddMCPServer(e config.PluginEntry) (int, error)
235 ConnectMCPServer(e config.PluginEntry) (int, error)
236 RegisterMCPServerOnDemand(e config.PluginEntry) (int, error)
237 ConnectConfiguredMCPServer(name string) (int, error)
238 DisconnectMCPServer(name string) bool
239 RemoveMCPServer(name string) (disconnected bool, err error)
240 ConfiguredMCPNames() []string
241 DisconnectedMCPNames() []string
242 UnregisterMCPServerTools(name string) bool
243 ImportMCPEntries(entries []config.PluginEntry) (total, added, updated, connected, failed, skipped int, err error)
244 // Extension UI (stage 8a): enumerate handshake-declared extension actions
245 // and invoke one by its public /<plugin>:<action> name. Nil hub → empty /
246 // error; the stage-8b slash dispatch resolves these.
247 ExtensionActions() []ExtensionActionView
248 InvokeExtensionAction(ctx context.Context, name string, args map[string]string) (string, error)
249 // ProviderCatalog is the session's merged provider catalog — config/broker
250 // base plus sidecar-declared extension providers (plugin/... refs). Nil
251 // when no extension declared providers; frontends merge it into their
252 // model pickers and skip nil.
253 ProviderCatalog() []provider.Descriptor
254 }
255
256 // Status covers read-only run/usage/billing telemetry and task list state.
257 type Status interface {
258 ContextSnapshot() (int, int)
259 ContextMaintenanceSnapshot() agent.ContextMaintenanceSnapshot
260 LastUsage() *provider.Usage
261 Balance(ctx context.Context) (*billing.Balance, error)
262 Jobs() []jobs.View
263 Todos() []evidence.TodoItem
264 // BoundShell reports the interpreter this controller generation bound at
265 // build time, so hosts can distinguish the live session's shell from what
266 // a reload would resolve now.
267 BoundShell() sandbox.Shell
268 }
269
270 // SessionPersistence covers snapshotting a session and tearing down its on-disk
271 // state.
272 type SessionPersistence interface {
273 Snapshot() error
274 SnapshotForShutdown() error
275 SnapshotActivity() error
276 // SessionHasUnsavedChanges reports whether the in-memory transcript is
277 // newer than the durable session file. Frontends use this to avoid
278 // replacing a failed/contended save with stale disk history.
279 SessionHasUnsavedChanges() bool
280 SessionCache() (hit, miss int)
281 BeginDestroySession(sessionPath string) SessionDestroyHandle
282 CloseAfterDestroy()
283 IsDestroyingSession(sessionPath string) bool
284 ReleaseResources()
285 }
286
287 // Input covers composing a turn's text (plan/goal/memory injection) and
288 // resolving @-references before submission.
289 type Input interface {
290 Compose(text string) string
291 ComposeSynthetic(text string) string
292 ResolveRefs(ctx context.Context, line string) (block string, errs []string)
293 HasRefs(line string) bool
294 ImageInputEnabled() bool
295 RegisterExternalFolderRef(path string) (token, displayPath string, err error)
296 }
297
298 // Settings covers runtime session settings that don't fit a richer domain.
299 type Settings interface {
300 SetResponseLanguage(lang string)
301 SetReasoningLanguage(lang string)
302 SetDisplayRecorder(fn func(content, display string))
303 ApplyComposerProfile(plan bool, toolApprovalMode, goal string) ([]string, error)
304 SystemPrompt() string
305 }
306
307 // SessionAPI is the full driving port — the composition of every sub-port. A
308 // rich frontend (the HTTP server, the desktop app, the TUI) depends on this;
309 // leaner frontends (bot, acp) depend on just the sub-ports they use.
310 type SessionAPI interface {
311 Lifecycle
312 TurnControl
313 Approvals
314 Goals
315 SessionHistory
316 MemoryControl
317 Capabilities
318 Status
319 SessionPersistence
320 Input
321 Settings
322 Inbox
323 }
324
325 // Compile-time proof that the concrete controller satisfies each sub-port and
326 // the full port, so frontend migrations to the interfaces are mechanical and can
327 // never silently drift from the implementation.
328 var (
329 _ Lifecycle = (*Controller)(nil)
330 _ IdentityLifecycle = (*Controller)(nil)
331 _ TurnControl = (*Controller)(nil)
332 _ Approvals = (*Controller)(nil)
333 _ Goals = (*Controller)(nil)
334 _ SessionHistory = (*Controller)(nil)
335 _ MemoryControl = (*Controller)(nil)
336 _ Capabilities = (*Controller)(nil)
337 _ Status = (*Controller)(nil)
338 _ SessionPersistence = (*Controller)(nil)
339 _ Input = (*Controller)(nil)
340 _ Settings = (*Controller)(nil)
341 _ Inbox = (*Controller)(nil)
342 _ SessionAPI = (*Controller)(nil)
343 )
344
344 lines GO