-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtypes.ts
More file actions
191 lines (179 loc) · 5.46 KB
/
types.ts
File metadata and controls
191 lines (179 loc) · 5.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
export interface FallbackPluginConfig {
enabled?: boolean
retry_on_errors?: number[]
/** Additional regex patterns (strings) that mark an error as retryable.
* These supplement the built-in patterns. Each string is compiled as
* a case-insensitive regex and matched against the error message. */
retryable_error_patterns?: string[]
max_fallback_attempts?: number
cooldown_seconds?: number
/** Time-to-first-token timeout in seconds. If the fallback model does not
* produce its first token within this window, it is aborted and the next
* fallback is tried. Once streaming begins the timeout is cancelled.
* Set to 0 to disable. */
timeout_seconds?: number
notify_on_fallback?: boolean
fallback_models?: string | string[]
}
export interface FallbackState {
originalModel: string
currentModel: string
fallbackIndex: number
failedModels: Map<string, number>
attemptCount: number
pendingFallbackModel?: string
}
export interface FallbackResult {
success: boolean
newModel?: string
error?: string
maxAttemptsReached?: boolean
}
/** Returned by planFallback — describes what to do but does NOT mutate state. */
export interface FallbackPlan {
success: true
newModel: string
failedModel: string
newFallbackIndex: number
}
export interface FallbackPlanFailure {
success: false
error: string
maxAttemptsReached?: boolean
}
export type MessagePart = { type: string } & Record<string, unknown>
export type ReplayTier = 1 | 2 | 3
export interface ReplayResult {
success: boolean
tier?: ReplayTier
sentParts?: MessagePart[]
droppedTypes?: string[]
error?: string
}
export interface ChatMessageInput {
sessionID: string
agent?: string
model?: {
providerID: string
modelID: string
}
}
export interface ChatMessageOutput {
message: {
model?: {
providerID: string
modelID: string
}
}
parts?: Array<{
type: string
text?: string
}>
}
export interface FallbackPluginHook {
event: (input: {
event: { type: string; properties?: unknown }
}) => Promise<void>
"chat.message"?: (
input: ChatMessageInput,
output: ChatMessageOutput
) => Promise<void>
}
export interface PluginContext {
directory: string
client: {
session: {
abort: (args: { path: { id: string } }) => Promise<void>
messages: (args: {
path: { id: string }
query: { directory: string }
}) => Promise<{
data?: Array<{
info?: Record<string, unknown>
parts?: Array<{ type?: string; text?: string }>
}>
}>
promptAsync: (args: {
path: { id: string }
body: {
agent?: string
model: { providerID: string; modelID: string }
parts: MessagePart[]
}
query: { directory: string }
}) => Promise<void>
/** Re-dispatch a command (e.g. compaction) on a specific model.
* Uses the SDK's path/body/query format. */
command: (args: {
path: { id: string }
body: {
command: string
arguments: string
model?: string
agent?: string
messageID?: string
}
query?: { directory?: string }
}) => Promise<void>
/** Revert a specific message, undoing its effects and restoring
* the previous session state. Used to remove failed compaction
* messages so OpenCode doesn't re-queue them. */
revert: (args: {
path: { id: string }
body: { messageID: string; partID?: string }
query?: { directory?: string }
}) => Promise<void>
/** Re-run compaction/summarization with a specific model.
* This is the actual compaction API — "compact" is not a
* user-facing command. */
summarize: (args: {
path: { id: string }
body: { providerID: string; modelID: string }
query?: { directory?: string }
}) => Promise<unknown>
get: (args: {
path: { id: string }
}) => Promise<{ data?: Record<string, unknown> }>
}
tui: {
showToast: (args: {
body: {
title: string
message: string
variant: string
duration: number
}
}) => Promise<void>
}
}
}
export interface HookDeps {
ctx: PluginContext
config: Required<FallbackPluginConfig>
agentConfigs: Record<string, unknown> | undefined
globalFallbackModels: string[]
sessionStates: Map<string, FallbackState>
sessionLastAccess: Map<string, number>
sessionRetryInFlight: Set<string>
sessionAwaitingFallbackResult: Set<string>
sessionFallbackTimeouts: Map<string, ReturnType<typeof setTimeout>>
sessionFirstTokenReceived: Map<string, boolean>
/** Timestamp of the last plugin-initiated abort per session.
* Used to distinguish self-inflicted MessageAbortedError from user cancellation. */
sessionSelfAbortTimestamp: Map<string, number>
/** Cached parentID for child sessions. `undefined` value means "looked up,
* no parent" so we distinguish from "never looked up" (key absent). */
sessionParentID: Map<string, string | null>
/** Resolvers for code awaiting a session to go idle (e.g. subagent-sync
* waiting for a child session's fallback response to complete). */
sessionIdleResolvers: Map<string, Array<() => void>>
/** Timestamp of the last message.updated event per session.
* Used by subagent-sync to detect child activity and reset timeouts. */
sessionLastMessageTime: Map<string, number>
/** Sessions with an in-flight compaction fallback via session.command.
* Compaction commands produce no message.updated events, only a final
* session.compacted signal. While this flag is set, stale errors from
* the pre-compaction model are suppressed and session.idle does not
* treat the silence as a "silent model failure". */
sessionCompactionInFlight: Set<string>
}