@ottocode/sdk 0.1.237 → 0.1.243
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/package.json +1 -1
- package/src/config/src/index.ts +1 -0
- package/src/config/src/manager.ts +2 -1
- package/src/core/src/tools/builtin/bash.txt +9 -4
- package/src/core/src/tools/builtin/finish.txt +12 -7
- package/src/core/src/tools/builtin/glob.txt +9 -6
- package/src/core/src/tools/builtin/patch.txt +120 -11
- package/src/core/src/tools/builtin/progress.txt +20 -3
- package/src/core/src/tools/builtin/ripgrep.txt +8 -3
- package/src/core/src/tools/builtin/terminal.txt +1 -1
- package/src/core/src/tools/builtin/todos.txt +44 -4
- package/src/prompts/src/agents/build.txt +23 -211
- package/src/prompts/src/agents/init.txt +24 -0
- package/src/prompts/src/base.txt +33 -32
- package/src/prompts/src/providers/anthropic.txt +58 -210
- package/src/prompts/src/providers/default.txt +36 -472
- package/src/prompts/src/providers/glm.txt +43 -342
- package/src/prompts/src/providers/google.txt +55 -178
- package/src/prompts/src/providers/moonshot.txt +43 -396
- package/src/prompts/src/providers/openai.txt +95 -359
- package/src/providers/src/catalog.ts +977 -1225
- package/src/providers/src/oauth-models.ts +2 -0
- package/src/providers/src/utils.ts +1 -1
- package/src/skills/loader.ts +1 -1
- package/src/skills/parser.ts +215 -24
- package/src/skills/tool.ts +91 -13
- package/src/types/src/config.ts +2 -1
|
@@ -5,6 +5,7 @@ const OAUTH_MODEL_PREFIXES: Partial<Record<ProviderId, string[]>> = {
|
|
|
5
5
|
'claude-haiku-4-5',
|
|
6
6
|
'claude-opus-4-5',
|
|
7
7
|
'claude-opus-4-6',
|
|
8
|
+
'claude-opus-4-7',
|
|
8
9
|
'claude-sonnet-4-5',
|
|
9
10
|
'claude-sonnet-4-6',
|
|
10
11
|
],
|
|
@@ -19,6 +20,7 @@ const OAUTH_MODEL_IDS: Partial<Record<ProviderId, string[]>> = {
|
|
|
19
20
|
'gpt-5.2-codex',
|
|
20
21
|
'gpt-5.3-codex',
|
|
21
22
|
'gpt-5.4',
|
|
23
|
+
'gpt-5.4-mini',
|
|
22
24
|
],
|
|
23
25
|
};
|
|
24
26
|
|
|
@@ -40,7 +40,7 @@ const PREFERRED_FAST_MODELS: Partial<Record<ProviderId, string[]>> = {
|
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
const PREFERRED_FAST_MODELS_OAUTH: Partial<Record<ProviderId, string[]>> = {
|
|
43
|
-
openai: ['gpt-5.
|
|
43
|
+
openai: ['gpt-5.4-mini'],
|
|
44
44
|
anthropic: ['claude-haiku-4-5'],
|
|
45
45
|
};
|
|
46
46
|
|
package/src/skills/loader.ts
CHANGED
|
@@ -74,6 +74,7 @@ export async function discoverSkills(
|
|
|
74
74
|
let current = cwd;
|
|
75
75
|
const visited = new Set<string>();
|
|
76
76
|
while (current && !visited.has(current)) {
|
|
77
|
+
if (repoRoot && !current.startsWith(repoRoot)) break;
|
|
77
78
|
visited.add(current);
|
|
78
79
|
const scope: SkillScope =
|
|
79
80
|
current === cwd ? 'cwd' : current === repoRoot ? 'repo' : 'parent';
|
|
@@ -82,7 +83,6 @@ export async function discoverSkills(
|
|
|
82
83
|
}
|
|
83
84
|
const parent = dirname(current);
|
|
84
85
|
if (parent === current) break;
|
|
85
|
-
if (repoRoot && !current.startsWith(repoRoot)) break;
|
|
86
86
|
current = parent;
|
|
87
87
|
}
|
|
88
88
|
|
package/src/skills/parser.ts
CHANGED
|
@@ -35,50 +35,225 @@ function parseYamlFrontmatter(
|
|
|
35
35
|
): Record<string, unknown> {
|
|
36
36
|
const result: Record<string, unknown> = {};
|
|
37
37
|
const lines = yaml.split('\n');
|
|
38
|
-
let
|
|
39
|
-
let currentIndent = 0;
|
|
40
|
-
let nestedObject: Record<string, string> | null = null;
|
|
38
|
+
let index = 0;
|
|
41
39
|
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
while (index < lines.length) {
|
|
41
|
+
const line = lines[index];
|
|
42
|
+
if (!line || !line.trim()) {
|
|
43
|
+
index += 1;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
44
46
|
|
|
45
47
|
const indent = line.search(/\S/);
|
|
48
|
+
if (indent > 0) {
|
|
49
|
+
index += 1;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
46
53
|
const trimmed = line.trim();
|
|
54
|
+
const colonIdx = trimmed.indexOf(':');
|
|
55
|
+
if (colonIdx === -1) {
|
|
56
|
+
index += 1;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
47
59
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
60
|
+
const key = normalizeKey(trimmed.slice(0, colonIdx).trim());
|
|
61
|
+
const value = trimmed.slice(colonIdx + 1).trim();
|
|
62
|
+
|
|
63
|
+
// Handle YAML block scalars with optional chomping/indentation indicators:
|
|
64
|
+
// `|`, `>`, `|-`, `>-`, `|+`, `>+`, `|2`, `>2-`, etc.
|
|
65
|
+
const blockScalarMatch = value.match(/^([|>])[-+]?\d*[-+]?$/);
|
|
66
|
+
if (blockScalarMatch) {
|
|
67
|
+
const style = blockScalarMatch[1] as '|' | '>';
|
|
68
|
+
const { content, nextIndex } = readBlockScalar(
|
|
69
|
+
lines,
|
|
70
|
+
index + 1,
|
|
71
|
+
indent,
|
|
72
|
+
style,
|
|
73
|
+
);
|
|
74
|
+
result[key] = content;
|
|
75
|
+
index = nextIndex;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!value) {
|
|
80
|
+
const { content, nextIndex } = readIndentedValue(
|
|
81
|
+
lines,
|
|
82
|
+
index + 1,
|
|
83
|
+
indent,
|
|
84
|
+
);
|
|
85
|
+
result[key] = content;
|
|
86
|
+
index = nextIndex;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
result[key] = parseYamlValue(value);
|
|
91
|
+
index += 1;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function readIndentedValue(
|
|
98
|
+
lines: string[],
|
|
99
|
+
startIndex: number,
|
|
100
|
+
parentIndent: number,
|
|
101
|
+
): { content: Record<string, string> | string; nextIndex: number } {
|
|
102
|
+
for (let index = startIndex; index < lines.length; index += 1) {
|
|
103
|
+
const line = lines[index];
|
|
104
|
+
if (!line || !line.trim()) continue;
|
|
105
|
+
|
|
106
|
+
const indent = line.search(/\S/);
|
|
107
|
+
if (indent <= parentIndent) {
|
|
108
|
+
return { content: '', nextIndex: index };
|
|
54
109
|
}
|
|
55
110
|
|
|
111
|
+
if (isNestedObjectLine(line.trim())) {
|
|
112
|
+
return readNestedObject(lines, startIndex, parentIndent);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return readIndentedScalar(lines, startIndex, parentIndent);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return { content: '', nextIndex: lines.length };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function readNestedObject(
|
|
122
|
+
lines: string[],
|
|
123
|
+
startIndex: number,
|
|
124
|
+
parentIndent: number,
|
|
125
|
+
): { content: Record<string, string>; nextIndex: number } {
|
|
126
|
+
const result: Record<string, string> = {};
|
|
127
|
+
let index = startIndex;
|
|
128
|
+
|
|
129
|
+
while (index < lines.length) {
|
|
130
|
+
const line = lines[index];
|
|
131
|
+
if (!line || !line.trim()) {
|
|
132
|
+
index += 1;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const indent = line.search(/\S/);
|
|
137
|
+
if (indent <= parentIndent) break;
|
|
138
|
+
|
|
139
|
+
const trimmed = line.trim();
|
|
56
140
|
const colonIdx = trimmed.indexOf(':');
|
|
57
|
-
if (colonIdx === -1)
|
|
141
|
+
if (colonIdx === -1) {
|
|
142
|
+
index += 1;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
58
145
|
|
|
59
|
-
const key = trimmed.slice(0, colonIdx).trim();
|
|
146
|
+
const key = normalizeKey(trimmed.slice(0, colonIdx).trim());
|
|
60
147
|
const value = trimmed.slice(colonIdx + 1).trim();
|
|
61
148
|
|
|
62
|
-
|
|
63
|
-
|
|
149
|
+
const blockScalarMatch = value.match(/^([|>])[-+]?\d*[-+]?$/);
|
|
150
|
+
if (blockScalarMatch) {
|
|
151
|
+
const style = blockScalarMatch[1] as '|' | '>';
|
|
152
|
+
const block = readBlockScalar(lines, index + 1, indent, style);
|
|
153
|
+
result[key] = block.content;
|
|
154
|
+
index = block.nextIndex;
|
|
64
155
|
continue;
|
|
65
156
|
}
|
|
66
157
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
158
|
+
result[key] = String(parseYamlValue(value));
|
|
159
|
+
index += 1;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return { content: result, nextIndex: index };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function readIndentedScalar(
|
|
166
|
+
lines: string[],
|
|
167
|
+
startIndex: number,
|
|
168
|
+
parentIndent: number,
|
|
169
|
+
): { content: string; nextIndex: number } {
|
|
170
|
+
const scalarLines: string[] = [];
|
|
171
|
+
let index = startIndex;
|
|
172
|
+
let contentIndent: number | null = null;
|
|
173
|
+
|
|
174
|
+
while (index < lines.length) {
|
|
175
|
+
const line = lines[index];
|
|
176
|
+
if (!line) {
|
|
177
|
+
scalarLines.push('');
|
|
178
|
+
index += 1;
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (!line.trim()) {
|
|
183
|
+
scalarLines.push('');
|
|
184
|
+
index += 1;
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const indent = line.search(/\S/);
|
|
189
|
+
if (indent <= parentIndent) break;
|
|
190
|
+
|
|
191
|
+
contentIndent ??= indent;
|
|
192
|
+
scalarLines.push(line.slice(contentIndent));
|
|
193
|
+
index += 1;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return { content: foldBlockScalar(scalarLines), nextIndex: index };
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function readBlockScalar(
|
|
200
|
+
lines: string[],
|
|
201
|
+
startIndex: number,
|
|
202
|
+
parentIndent: number,
|
|
203
|
+
style: '|' | '>',
|
|
204
|
+
): { content: string; nextIndex: number } {
|
|
205
|
+
const blockLines: string[] = [];
|
|
206
|
+
let index = startIndex;
|
|
207
|
+
let contentIndent: number | null = null;
|
|
208
|
+
|
|
209
|
+
while (index < lines.length) {
|
|
210
|
+
const line = lines[index];
|
|
211
|
+
if (!line) {
|
|
212
|
+
blockLines.push('');
|
|
213
|
+
index += 1;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (!line.trim()) {
|
|
218
|
+
blockLines.push('');
|
|
219
|
+
index += 1;
|
|
71
220
|
continue;
|
|
72
221
|
}
|
|
73
222
|
|
|
74
|
-
|
|
223
|
+
const indent = line.search(/\S/);
|
|
224
|
+
if (indent <= parentIndent) break;
|
|
225
|
+
|
|
226
|
+
contentIndent ??= indent;
|
|
227
|
+
blockLines.push(line.slice(contentIndent));
|
|
228
|
+
index += 1;
|
|
75
229
|
}
|
|
76
230
|
|
|
77
|
-
|
|
78
|
-
|
|
231
|
+
const content =
|
|
232
|
+
style === '>' ? foldBlockScalar(blockLines) : blockLines.join('\n').trim();
|
|
233
|
+
return { content, nextIndex: index };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function foldBlockScalar(lines: string[]): string {
|
|
237
|
+
const segments: string[] = [];
|
|
238
|
+
let current = '';
|
|
239
|
+
|
|
240
|
+
for (const line of lines) {
|
|
241
|
+
if (!line.trim()) {
|
|
242
|
+
if (current) {
|
|
243
|
+
segments.push(current.trim());
|
|
244
|
+
current = '';
|
|
245
|
+
}
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
current = current ? `${current} ${line.trim()}` : line.trim();
|
|
79
250
|
}
|
|
80
251
|
|
|
81
|
-
|
|
252
|
+
if (current) {
|
|
253
|
+
segments.push(current.trim());
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return segments.join('\n');
|
|
82
257
|
}
|
|
83
258
|
|
|
84
259
|
function normalizeKey(key: string): string {
|
|
@@ -86,13 +261,29 @@ function normalizeKey(key: string): string {
|
|
|
86
261
|
return key.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
87
262
|
}
|
|
88
263
|
|
|
89
|
-
function
|
|
264
|
+
function isNestedObjectLine(line: string): boolean {
|
|
265
|
+
return /^[A-Za-z0-9_-]+\s*:/.test(line);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function parseYamlValue(value: string): unknown {
|
|
90
269
|
if (
|
|
91
270
|
(value.startsWith('"') && value.endsWith('"')) ||
|
|
92
271
|
(value.startsWith("'") && value.endsWith("'"))
|
|
93
272
|
) {
|
|
94
273
|
return value.slice(1, -1);
|
|
95
274
|
}
|
|
275
|
+
|
|
276
|
+
if (
|
|
277
|
+
(value.startsWith('{') && value.endsWith('}')) ||
|
|
278
|
+
(value.startsWith('[') && value.endsWith(']'))
|
|
279
|
+
) {
|
|
280
|
+
try {
|
|
281
|
+
return JSON.parse(value) as unknown;
|
|
282
|
+
} catch {
|
|
283
|
+
return value;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
96
287
|
return value;
|
|
97
288
|
}
|
|
98
289
|
|
package/src/skills/tool.ts
CHANGED
|
@@ -120,32 +120,53 @@ async function loadSubFile(
|
|
|
120
120
|
|
|
121
121
|
function buildSkillDescription(): string {
|
|
122
122
|
if (cachedSkillList.length === 0) {
|
|
123
|
-
return 'Load a skill by name. No skills are currently available.';
|
|
123
|
+
return 'Load a skill by name to get detailed, task-specific instructions. No skills are currently available.';
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
// Dedupe by name — later scopes (cwd > repo > user) have already overwritten
|
|
127
|
+
// earlier ones in the loader, so the cached list is deduplicated. We re-dedupe
|
|
128
|
+
// defensively here in case the same name slipped through from different dirs.
|
|
129
|
+
const seen = new Set<string>();
|
|
130
|
+
const unique: DiscoveredSkill[] = [];
|
|
131
|
+
for (const s of cachedSkillList) {
|
|
132
|
+
const key = s.name.trim();
|
|
133
|
+
if (!key || seen.has(key)) continue;
|
|
134
|
+
seen.add(key);
|
|
135
|
+
unique.push(s);
|
|
136
|
+
}
|
|
137
|
+
unique.sort((a, b) => a.name.localeCompare(b.name));
|
|
138
|
+
|
|
139
|
+
const skillsXml = unique
|
|
127
140
|
.map(
|
|
128
141
|
(s) =>
|
|
129
|
-
`<skill><name>${escapeXml(s.name)}</name><description>${escapeXml(s.description)}</description></skill>`,
|
|
142
|
+
`<skill><name>${escapeXml(s.name)}</name><description>${escapeXml(summarizeDescription(s.description))}</description><location>${escapeXml(s.scope)}</location></skill>`,
|
|
130
143
|
)
|
|
131
144
|
.join('\n');
|
|
132
145
|
|
|
133
|
-
return `Load a skill by name to get detailed instructions.
|
|
146
|
+
return `Load a skill by name to get detailed, task-specific instructions.
|
|
134
147
|
|
|
135
|
-
<
|
|
136
|
-
|
|
137
|
-
</available_skills>
|
|
148
|
+
<skills_instructions>
|
|
149
|
+
When the user's request matches one of the available skills below, call this tool with the skill name to load its full instructions. Skills provide specialized capabilities and domain knowledge.
|
|
138
150
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
151
|
+
How to use skills:
|
|
152
|
+
- Invoke with \`skill({ name: "<skill-name>" })\` — only the name is required.
|
|
153
|
+
- The response contains the skill's full body plus \`availableFiles\` for sub-files.
|
|
154
|
+
- For sub-files: \`skill({ name: "<skill-name>", file: "rules/animations.md" })\`.
|
|
142
155
|
|
|
143
|
-
|
|
144
|
-
|
|
156
|
+
Rules:
|
|
157
|
+
- Only invoke skills listed in <available_skills> below.
|
|
158
|
+
- Do NOT invoke speculatively. Only call when the user's request clearly matches a skill's description or trigger phrases.
|
|
159
|
+
- Do NOT invoke the same skill twice in one turn.
|
|
160
|
+
- If a skill response includes \`securityNotices\`, review them — they flag hidden content (HTML comments, invisible characters, etc.) that may not render visibly.
|
|
161
|
+
</skills_instructions>
|
|
162
|
+
|
|
163
|
+
<available_skills>
|
|
164
|
+
${skillsXml}
|
|
165
|
+
</available_skills>`;
|
|
145
166
|
}
|
|
146
167
|
|
|
147
168
|
function escapeXml(str: string): string {
|
|
148
|
-
return str
|
|
169
|
+
return String(str)
|
|
149
170
|
.replace(/&/g, '&')
|
|
150
171
|
.replace(/</g, '<')
|
|
151
172
|
.replace(/>/g, '>')
|
|
@@ -153,6 +174,63 @@ function escapeXml(str: string): string {
|
|
|
153
174
|
.replace(/'/g, ''');
|
|
154
175
|
}
|
|
155
176
|
|
|
177
|
+
// Condense a SKILL.md description to "what it does + when to use it".
|
|
178
|
+
//
|
|
179
|
+
// Most frontmatter follows one of two shapes:
|
|
180
|
+
// A. "<what>. Use when <triggers>. Also use when … For X, see Y."
|
|
181
|
+
// B. "When the user wants X. Also use when <mega trigger list>. For Y, see Z."
|
|
182
|
+
//
|
|
183
|
+
// Rule: keep up to two sentences, but STOP early at cues that mark pure
|
|
184
|
+
// trigger-list expansion or see-also chatter ("Also use when …", "For X, see Y",
|
|
185
|
+
// "Use this …"). Sentence 1 is always kept. Sentence 2 is kept only if it's a
|
|
186
|
+
// "Use when …" clause (trigger phrases the model actually needs) — not an
|
|
187
|
+
// "Also use when" balloon.
|
|
188
|
+
const SENTENCE_END = /[.!?]\s/g;
|
|
189
|
+
const SKIP_PREFIXES = [
|
|
190
|
+
/^also use when\b/i,
|
|
191
|
+
/^for [^.]*?,?\s*see\b/i,
|
|
192
|
+
/^see\s+/i,
|
|
193
|
+
/^use this\b/i,
|
|
194
|
+
/^use proactively\b/i,
|
|
195
|
+
/^distinct from\b/i,
|
|
196
|
+
/^different from\b/i,
|
|
197
|
+
/^not for\b/i,
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
function shouldSkipSentence(sentence: string): boolean {
|
|
201
|
+
const s = sentence.trim();
|
|
202
|
+
return SKIP_PREFIXES.some((re) => re.test(s));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function summarizeDescription(raw: string): string {
|
|
206
|
+
const text = String(raw ?? '')
|
|
207
|
+
.replace(/\s+/g, ' ')
|
|
208
|
+
.trim();
|
|
209
|
+
if (!text) return '';
|
|
210
|
+
|
|
211
|
+
// Split into sentences, keeping terminal punctuation.
|
|
212
|
+
const sentences: string[] = [];
|
|
213
|
+
SENTENCE_END.lastIndex = 0;
|
|
214
|
+
let lastIndex = 0;
|
|
215
|
+
let match: RegExpExecArray | null;
|
|
216
|
+
// biome-ignore lint/suspicious/noAssignInExpressions: standard regex iteration
|
|
217
|
+
while ((match = SENTENCE_END.exec(text)) !== null) {
|
|
218
|
+
sentences.push(text.slice(lastIndex, match.index + 1).trim());
|
|
219
|
+
lastIndex = match.index + match[0].length;
|
|
220
|
+
}
|
|
221
|
+
if (lastIndex < text.length) sentences.push(text.slice(lastIndex).trim());
|
|
222
|
+
|
|
223
|
+
if (sentences.length === 0) return text;
|
|
224
|
+
|
|
225
|
+
const kept: string[] = [sentences[0]]; // always keep sentence 1 (what)
|
|
226
|
+
// Keep sentence 2 only if it adds routing signal (e.g. starts with "Use when").
|
|
227
|
+
if (sentences[1] && !shouldSkipSentence(sentences[1])) {
|
|
228
|
+
kept.push(sentences[1]);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return kept.join(' ');
|
|
232
|
+
}
|
|
233
|
+
|
|
156
234
|
export function rebuildSkillDescription(): string {
|
|
157
235
|
return buildSkillDescription();
|
|
158
236
|
}
|
package/src/types/src/config.ts
CHANGED
|
@@ -8,7 +8,7 @@ export type Scope = 'global' | 'local';
|
|
|
8
8
|
/**
|
|
9
9
|
* Default settings for the CLI
|
|
10
10
|
*/
|
|
11
|
-
export type ToolApprovalMode = 'auto' | 'dangerous' | 'all';
|
|
11
|
+
export type ToolApprovalMode = 'auto' | 'dangerous' | 'all' | 'yolo';
|
|
12
12
|
export type ReasoningLevel =
|
|
13
13
|
| 'minimal'
|
|
14
14
|
| 'low'
|
|
@@ -27,6 +27,7 @@ export type DefaultConfig = {
|
|
|
27
27
|
reasoningLevel?: ReasoningLevel;
|
|
28
28
|
theme?: string;
|
|
29
29
|
fullWidthContent?: boolean;
|
|
30
|
+
autoCompactThresholdTokens?: number | null;
|
|
30
31
|
};
|
|
31
32
|
|
|
32
33
|
export type ProviderSettings = Record<
|