opencode-sidechat 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -3
- package/package.json +1 -1
- package/src/components/SideChat.tsx +348 -348
- package/src/config.ts +194 -189
- package/src/constants.ts +48 -45
- package/src/index.tsx +406 -379
- package/src/session.ts +260 -257
- package/src/types.ts +54 -54
package/src/session.ts
CHANGED
|
@@ -1,257 +1,260 @@
|
|
|
1
|
-
import type { TuiPluginApi, TuiDialogSelectOption } from "@opencode-ai/plugin/tui";
|
|
2
|
-
import type { PermissionRuleset } from "@opencode-ai/sdk/v2";
|
|
3
|
-
import { DEFAULT_ALLOWED_TOOLS, ADDITIONAL_PERMISSION_IDS } from "./constants";
|
|
4
|
-
import type { SideConfig, SessionEntry, ResolvedModel, ModelPreference } from "./types";
|
|
5
|
-
|
|
6
|
-
export type ModelSource = "config" | "session" | "unknown";
|
|
7
|
-
|
|
8
|
-
export type ResolvedModelWithSource = {
|
|
9
|
-
model: ResolvedModel;
|
|
10
|
-
source: ModelSource;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export function resolveModel(
|
|
14
|
-
modelOverride: string | null,
|
|
15
|
-
entries: SessionEntry[],
|
|
16
|
-
api: TuiPluginApi,
|
|
17
|
-
): ResolvedModelWithSource {
|
|
18
|
-
if (modelOverride) {
|
|
19
|
-
const parsed = parseModelOverride(modelOverride);
|
|
20
|
-
if (parsed) return { model: { model: parsed }, source: "config" };
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
let assistantFallback: ResolvedModel | undefined;
|
|
24
|
-
|
|
25
|
-
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
26
|
-
const { info } = entries[index];
|
|
27
|
-
if (info.role === "user") {
|
|
28
|
-
return {
|
|
29
|
-
model: {
|
|
30
|
-
model: {
|
|
31
|
-
providerID: info.model.providerID,
|
|
32
|
-
modelID: info.model.modelID,
|
|
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
|
-
result.data
|
|
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
|
-
permission,
|
|
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
|
-
variant:
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
1
|
+
import type { TuiPluginApi, TuiDialogSelectOption } from "@opencode-ai/plugin/tui";
|
|
2
|
+
import type { PermissionRuleset } from "@opencode-ai/sdk/v2";
|
|
3
|
+
import { DEFAULT_ALLOWED_TOOLS, ADDITIONAL_PERMISSION_IDS, SYSTEM_PROMPT_OVERRIDE } from "./constants";
|
|
4
|
+
import type { SideConfig, SessionEntry, ResolvedModel, ModelPreference } from "./types";
|
|
5
|
+
|
|
6
|
+
export type ModelSource = "config" | "session" | "unknown";
|
|
7
|
+
|
|
8
|
+
export type ResolvedModelWithSource = {
|
|
9
|
+
model: ResolvedModel;
|
|
10
|
+
source: ModelSource;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function resolveModel(
|
|
14
|
+
modelOverride: string | null,
|
|
15
|
+
entries: SessionEntry[],
|
|
16
|
+
api: TuiPluginApi,
|
|
17
|
+
): ResolvedModelWithSource {
|
|
18
|
+
if (modelOverride) {
|
|
19
|
+
const parsed = parseModelOverride(modelOverride);
|
|
20
|
+
if (parsed) return { model: { model: parsed }, source: "config" };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let assistantFallback: ResolvedModel | undefined;
|
|
24
|
+
|
|
25
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
26
|
+
const { info } = entries[index];
|
|
27
|
+
if (info.role === "user" && info.model) {
|
|
28
|
+
return {
|
|
29
|
+
model: {
|
|
30
|
+
model: {
|
|
31
|
+
providerID: info.model.providerID,
|
|
32
|
+
modelID: info.model.modelID,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
source: "session",
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (info.role === "assistant" && info.providerID && info.modelID && !assistantFallback) {
|
|
39
|
+
assistantFallback = {
|
|
40
|
+
model: {
|
|
41
|
+
providerID: info.providerID,
|
|
42
|
+
modelID: info.modelID,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (assistantFallback) return { model: assistantFallback, source: "session" };
|
|
49
|
+
|
|
50
|
+
const sessionModel = api.state.config.model;
|
|
51
|
+
if (sessionModel) {
|
|
52
|
+
const parts = sessionModel.split("/");
|
|
53
|
+
if (parts.length >= 2) {
|
|
54
|
+
return {
|
|
55
|
+
model: { model: { providerID: parts[0], modelID: parts.slice(1).join("/") } },
|
|
56
|
+
source: "session",
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return { model: {}, source: "unknown" };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function parseModelOverride(value: string) {
|
|
65
|
+
const [providerID, ...rest] = value.split("/");
|
|
66
|
+
const modelID = rest.join("/");
|
|
67
|
+
if (!providerID || !modelID) return undefined;
|
|
68
|
+
return { providerID, modelID };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function formatResolvedModel(resolved: ResolvedModel) {
|
|
72
|
+
if (!resolved.model) return "default";
|
|
73
|
+
const base = `${resolved.model.providerID}/${resolved.model.modelID}`;
|
|
74
|
+
return resolved.variant ? `${base} (${resolved.variant})` : base;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function formatPreference(preference: ModelPreference): string {
|
|
78
|
+
if (!preference) return "default";
|
|
79
|
+
return formatResolvedModel(preference);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function getAvailableToolIDs(api: TuiPluginApi): Promise<string[]> {
|
|
83
|
+
try {
|
|
84
|
+
const result = await api.client.tool.ids(
|
|
85
|
+
{ directory: api.state.path.directory },
|
|
86
|
+
{ throwOnError: true },
|
|
87
|
+
);
|
|
88
|
+
if (
|
|
89
|
+
Array.isArray(result.data) &&
|
|
90
|
+
result.data.every((item: unknown) => typeof item === "string")
|
|
91
|
+
) {
|
|
92
|
+
return result.data;
|
|
93
|
+
}
|
|
94
|
+
} catch {}
|
|
95
|
+
|
|
96
|
+
return DEFAULT_ALLOWED_TOOLS;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function resolveAllowedTools(
|
|
100
|
+
allowedTools: string[] | null,
|
|
101
|
+
availableToolIDs: string[],
|
|
102
|
+
): string[] {
|
|
103
|
+
if (allowedTools === null) return DEFAULT_ALLOWED_TOOLS;
|
|
104
|
+
if (allowedTools.includes("*")) return [...availableToolIDs];
|
|
105
|
+
return allowedTools;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function buildToolSelection(toolIDs: string[], allowedTools: string[]) {
|
|
109
|
+
return Object.fromEntries(
|
|
110
|
+
toolIDs.map((toolID) => [toolID, allowedTools.includes(toolID)]),
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function buildPermissionRules(
|
|
115
|
+
toolIDs: string[],
|
|
116
|
+
allowedTools: string[],
|
|
117
|
+
): PermissionRuleset {
|
|
118
|
+
const permissionIDs = [
|
|
119
|
+
...new Set([...toolIDs, ...ADDITIONAL_PERMISSION_IDS]),
|
|
120
|
+
];
|
|
121
|
+
return permissionIDs.map((permission) => ({
|
|
122
|
+
permission,
|
|
123
|
+
pattern: "*",
|
|
124
|
+
action: allowedTools.includes(permission) ? "allow" : "deny",
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function buildSideSystemPrompt(systemPrompt: string, allowedTools: string[]) {
|
|
129
|
+
const toolsNote = allowedTools.length === 0
|
|
130
|
+
? "No tools are available."
|
|
131
|
+
: `Available tools: ${allowedTools.join(", ")}.`;
|
|
132
|
+
return `${SYSTEM_PROMPT_OVERRIDE}\n\n${systemPrompt} ${toolsNote}`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function openModelPicker(
|
|
136
|
+
api: TuiPluginApi,
|
|
137
|
+
config: SideConfig,
|
|
138
|
+
currentPreference: ModelPreference,
|
|
139
|
+
onSelect: (model: ModelPreference) => void,
|
|
140
|
+
) {
|
|
141
|
+
const { model: defaultModel, source: defaultSource } = resolveModel(
|
|
142
|
+
config.model,
|
|
143
|
+
[],
|
|
144
|
+
api,
|
|
145
|
+
);
|
|
146
|
+
const options = buildModelOptions(api, defaultModel, defaultSource);
|
|
147
|
+
|
|
148
|
+
api.ui.dialog.setSize("large");
|
|
149
|
+
api.ui.dialog.replace(() =>
|
|
150
|
+
api.ui.DialogSelect<{ type: "default" } | { type: "model"; model: NonNullable<ResolvedModel["model"]>; variant?: string }>({
|
|
151
|
+
title: "side chat model",
|
|
152
|
+
placeholder: "Select model for side chat",
|
|
153
|
+
options,
|
|
154
|
+
onSelect: (option) => {
|
|
155
|
+
if (option.value.type === "default") {
|
|
156
|
+
onSelect(undefined);
|
|
157
|
+
api.ui.toast({
|
|
158
|
+
variant: "success",
|
|
159
|
+
message: "side chat model reset to default.",
|
|
160
|
+
});
|
|
161
|
+
} else {
|
|
162
|
+
onSelect({
|
|
163
|
+
model: option.value.model,
|
|
164
|
+
variant: option.value.variant,
|
|
165
|
+
});
|
|
166
|
+
api.ui.toast({
|
|
167
|
+
variant: "success",
|
|
168
|
+
message: `side chat model set to ${formatResolvedModel({
|
|
169
|
+
model: option.value.model,
|
|
170
|
+
variant: option.value.variant,
|
|
171
|
+
})}.`,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
api.ui.dialog.clear();
|
|
175
|
+
},
|
|
176
|
+
}),
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function buildModelOptions(
|
|
181
|
+
api: TuiPluginApi,
|
|
182
|
+
defaultModel: ResolvedModel,
|
|
183
|
+
defaultSource: ModelSource,
|
|
184
|
+
): TuiDialogSelectOption<
|
|
185
|
+
{ type: "default" } | { type: "model"; model: NonNullable<ResolvedModel["model"]>; variant?: string }
|
|
186
|
+
>[] {
|
|
187
|
+
const providers = api.state.provider ? [...api.state.provider] : [];
|
|
188
|
+
if (providers.length === 0) {
|
|
189
|
+
api.ui.toast({ variant: "error", message: "No model providers available." });
|
|
190
|
+
api.ui.dialog.clear();
|
|
191
|
+
return [];
|
|
192
|
+
}
|
|
193
|
+
providers.sort((left, right) =>
|
|
194
|
+
left.name.localeCompare(right.name),
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
const defaultModelName = defaultModel.model
|
|
198
|
+
? providers
|
|
199
|
+
.find((p) => p.id === defaultModel.model!.providerID)
|
|
200
|
+
?.models[defaultModel.model!.modelID]?.name ||
|
|
201
|
+
defaultModel.model!.modelID
|
|
202
|
+
: "default";
|
|
203
|
+
|
|
204
|
+
const sourceLabel: Record<ModelSource, string> = {
|
|
205
|
+
config: "config",
|
|
206
|
+
session: "main session",
|
|
207
|
+
unknown: "unknown",
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const options: TuiDialogSelectOption<
|
|
211
|
+
{ type: "default" } | { type: "model"; model: NonNullable<ResolvedModel["model"]>; variant?: string }
|
|
212
|
+
>[] = [
|
|
213
|
+
{
|
|
214
|
+
title: defaultModelName + (defaultModel.variant ? ` (${defaultModel.variant})` : ""),
|
|
215
|
+
value: { type: "default" },
|
|
216
|
+
description: `${formatResolvedModel(defaultModel)}`,
|
|
217
|
+
category: `Default [${sourceLabel[defaultSource]}]`,
|
|
218
|
+
},
|
|
219
|
+
];
|
|
220
|
+
|
|
221
|
+
for (const provider of providers) {
|
|
222
|
+
const models = Object.values(provider.models).sort((left, right) =>
|
|
223
|
+
left.name.localeCompare(right.name),
|
|
224
|
+
);
|
|
225
|
+
for (const model of models) {
|
|
226
|
+
const resolved = {
|
|
227
|
+
providerID: model.providerID,
|
|
228
|
+
modelID: model.id,
|
|
229
|
+
};
|
|
230
|
+
options.push({
|
|
231
|
+
title: model.name || model.id,
|
|
232
|
+
value: { type: "model", model: resolved },
|
|
233
|
+
description: `${provider.id}/${model.id}`,
|
|
234
|
+
category: provider.name,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
for (const variant of Object.keys(model.variants ?? {}).sort()) {
|
|
238
|
+
options.push({
|
|
239
|
+
title: `${model.name || model.id} (${variant})`,
|
|
240
|
+
value: { type: "model", model: resolved, variant },
|
|
241
|
+
description: `${provider.id}/${model.id}`,
|
|
242
|
+
category: provider.name,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return options;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export function getErrorMessage(cause: unknown): string {
|
|
252
|
+
if (cause instanceof Error && cause.message) return cause.message;
|
|
253
|
+
if (cause && typeof cause === "object") {
|
|
254
|
+
const data = "data" in cause
|
|
255
|
+
? (cause as { data?: { message?: unknown } }).data
|
|
256
|
+
: undefined;
|
|
257
|
+
if (data && typeof data.message === "string" && data.message) return data.message;
|
|
258
|
+
}
|
|
259
|
+
return "An error occurred.";
|
|
260
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
import type { TuiPluginApi } from "@opencode-ai/plugin/tui";
|
|
2
|
-
import type { Message, Part } from "@opencode-ai/sdk/v2";
|
|
3
|
-
|
|
4
|
-
export type ThinkConfig = {
|
|
5
|
-
defaultState: "collapsed" | "expanded";
|
|
6
|
-
showSummary: boolean;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export type SideConfig = {
|
|
10
|
-
model: string | null;
|
|
11
|
-
systemPrompt: string;
|
|
12
|
-
tokenLimit: number;
|
|
13
|
-
keybind: string | false;
|
|
14
|
-
clearKeybind: string | false;
|
|
15
|
-
thinkToggleKeybind: string | false;
|
|
16
|
-
allowedTools: string[] | null;
|
|
17
|
-
width: number;
|
|
18
|
-
transcriptHeight: number;
|
|
19
|
-
think: ThinkConfig;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export type SessionEntry = {
|
|
23
|
-
info: Message;
|
|
24
|
-
parts: Part[];
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export type ResolvedModel = {
|
|
28
|
-
model?: {
|
|
29
|
-
providerID: string;
|
|
30
|
-
modelID: string;
|
|
31
|
-
};
|
|
32
|
-
variant?: string;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export type ModelPreference = ResolvedModel | undefined;
|
|
36
|
-
|
|
37
|
-
export type SideDialogState = {
|
|
38
|
-
entries: SessionEntry[];
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
thinkCollapsed: boolean;
|
|
50
|
-
thinkConfig: ThinkConfig;
|
|
51
|
-
onInput?: (input: { focus: () => void } | undefined) => void;
|
|
52
|
-
onChangeModel: () => void;
|
|
53
|
-
onSubmit: (value: string) => boolean;
|
|
54
|
-
};
|
|
1
|
+
import type { TuiPluginApi } from "@opencode-ai/plugin/tui";
|
|
2
|
+
import type { Message, Part } from "@opencode-ai/sdk/v2";
|
|
3
|
+
|
|
4
|
+
export type ThinkConfig = {
|
|
5
|
+
defaultState: "collapsed" | "expanded";
|
|
6
|
+
showSummary: boolean;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type SideConfig = {
|
|
10
|
+
model: string | null;
|
|
11
|
+
systemPrompt: string;
|
|
12
|
+
tokenLimit: number;
|
|
13
|
+
keybind: string | false;
|
|
14
|
+
clearKeybind: string | false;
|
|
15
|
+
thinkToggleKeybind: string | false;
|
|
16
|
+
allowedTools: string[] | null;
|
|
17
|
+
width: number;
|
|
18
|
+
transcriptHeight: number;
|
|
19
|
+
think: ThinkConfig;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type SessionEntry = {
|
|
23
|
+
info: Message;
|
|
24
|
+
parts: Part[];
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type ResolvedModel = {
|
|
28
|
+
model?: {
|
|
29
|
+
providerID: string;
|
|
30
|
+
modelID: string;
|
|
31
|
+
};
|
|
32
|
+
variant?: string;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type ModelPreference = ResolvedModel | undefined;
|
|
36
|
+
|
|
37
|
+
export type SideDialogState = {
|
|
38
|
+
entries: SessionEntry[];
|
|
39
|
+
loading: boolean;
|
|
40
|
+
error?: string;
|
|
41
|
+
tokenCount: number;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type OverlayState = {
|
|
45
|
+
api: TuiPluginApi;
|
|
46
|
+
modelName: string;
|
|
47
|
+
state: SideDialogState;
|
|
48
|
+
streamingAnswer: string;
|
|
49
|
+
thinkCollapsed: boolean;
|
|
50
|
+
thinkConfig: ThinkConfig;
|
|
51
|
+
onInput?: (input: { focus: () => void } | undefined) => void;
|
|
52
|
+
onChangeModel: () => void;
|
|
53
|
+
onSubmit: (value: string) => boolean;
|
|
54
|
+
};
|