snow-ai 0.3.1 → 0.3.2
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/dist/api/anthropic.d.ts +13 -9
- package/dist/api/anthropic.js +77 -34
- package/dist/api/chat.d.ts +14 -29
- package/dist/api/chat.js +62 -19
- package/dist/api/gemini.d.ts +1 -10
- package/dist/api/gemini.js +104 -82
- package/dist/api/models.js +6 -7
- package/dist/api/responses.d.ts +2 -17
- package/dist/api/responses.js +59 -17
- package/dist/api/types.d.ts +39 -0
- package/dist/api/types.js +4 -0
- package/dist/ui/pages/ConfigScreen.js +62 -49
- package/dist/ui/pages/WelcomeScreen.js +1 -1
- package/dist/utils/contextCompressor.d.ts +1 -1
- package/dist/utils/contextCompressor.js +193 -81
- package/package.json +1 -4
package/dist/api/models.js
CHANGED
|
@@ -3,7 +3,7 @@ import { getOpenAiConfig, getCustomHeaders } from '../utils/apiConfig.js';
|
|
|
3
3
|
* Fetch models from OpenAI-compatible API
|
|
4
4
|
*/
|
|
5
5
|
async function fetchOpenAIModels(baseUrl, apiKey, customHeaders) {
|
|
6
|
-
const url = `${baseUrl
|
|
6
|
+
const url = `${baseUrl}/models`;
|
|
7
7
|
const headers = {
|
|
8
8
|
'Content-Type': 'application/json',
|
|
9
9
|
...customHeaders,
|
|
@@ -26,7 +26,7 @@ async function fetchOpenAIModels(baseUrl, apiKey, customHeaders) {
|
|
|
26
26
|
*/
|
|
27
27
|
async function fetchGeminiModels(baseUrl, apiKey) {
|
|
28
28
|
// Gemini uses API key as query parameter
|
|
29
|
-
const url = `${baseUrl
|
|
29
|
+
const url = `${baseUrl}/models?key=${apiKey}`;
|
|
30
30
|
const response = await fetch(url, {
|
|
31
31
|
method: 'GET',
|
|
32
32
|
headers: {
|
|
@@ -50,10 +50,9 @@ async function fetchGeminiModels(baseUrl, apiKey) {
|
|
|
50
50
|
* Supports both Anthropic native format and OpenAI-compatible format for backward compatibility
|
|
51
51
|
*/
|
|
52
52
|
async function fetchAnthropicModels(baseUrl, apiKey, customHeaders) {
|
|
53
|
-
const url = `${baseUrl
|
|
53
|
+
const url = `${baseUrl}/models`;
|
|
54
54
|
const headers = {
|
|
55
55
|
'Content-Type': 'application/json',
|
|
56
|
-
'anthropic-version': '2023-06-01',
|
|
57
56
|
...customHeaders,
|
|
58
57
|
};
|
|
59
58
|
if (apiKey) {
|
|
@@ -106,19 +105,19 @@ export async function fetchAvailableModels() {
|
|
|
106
105
|
if (!config.apiKey) {
|
|
107
106
|
throw new Error('API key is required for Gemini API');
|
|
108
107
|
}
|
|
109
|
-
models = await fetchGeminiModels(config.baseUrl.replace(/\/$/, '')
|
|
108
|
+
models = await fetchGeminiModels(config.baseUrl.replace(/\/$/, ''), config.apiKey);
|
|
110
109
|
break;
|
|
111
110
|
case 'anthropic':
|
|
112
111
|
if (!config.apiKey) {
|
|
113
112
|
throw new Error('API key is required for Anthropic API');
|
|
114
113
|
}
|
|
115
|
-
models = await fetchAnthropicModels(config.baseUrl.replace(/\/$/, '')
|
|
114
|
+
models = await fetchAnthropicModels(config.baseUrl.replace(/\/$/, ''), config.apiKey, customHeaders);
|
|
116
115
|
break;
|
|
117
116
|
case 'chat':
|
|
118
117
|
case 'responses':
|
|
119
118
|
default:
|
|
120
119
|
// OpenAI-compatible API
|
|
121
|
-
models = await fetchOpenAIModels(config.baseUrl, config.apiKey, customHeaders);
|
|
120
|
+
models = await fetchOpenAIModels(config.baseUrl.replace(/\/$/, ''), config.apiKey, customHeaders);
|
|
122
121
|
break;
|
|
123
122
|
}
|
|
124
123
|
// Sort models alphabetically by id for better UX
|
package/dist/api/responses.d.ts
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
|
-
import type { ChatMessage, ToolCall } from './
|
|
1
|
+
import type { ChatMessage, ToolCall, ChatCompletionTool, UsageInfo } from './types.js';
|
|
2
2
|
export interface ResponseOptions {
|
|
3
3
|
model: string;
|
|
4
4
|
messages: ChatMessage[];
|
|
5
5
|
stream?: boolean;
|
|
6
6
|
temperature?: number;
|
|
7
7
|
max_tokens?: number;
|
|
8
|
-
tools?:
|
|
9
|
-
type: 'function';
|
|
10
|
-
function: {
|
|
11
|
-
name: string;
|
|
12
|
-
description?: string;
|
|
13
|
-
parameters?: Record<string, any>;
|
|
14
|
-
};
|
|
15
|
-
}>;
|
|
8
|
+
tools?: ChatCompletionTool[];
|
|
16
9
|
tool_choice?: 'auto' | 'none' | 'required';
|
|
17
10
|
reasoning?: {
|
|
18
11
|
summary?: 'auto' | 'none';
|
|
@@ -22,14 +15,6 @@ export interface ResponseOptions {
|
|
|
22
15
|
store?: boolean;
|
|
23
16
|
include?: string[];
|
|
24
17
|
}
|
|
25
|
-
export interface UsageInfo {
|
|
26
|
-
prompt_tokens: number;
|
|
27
|
-
completion_tokens: number;
|
|
28
|
-
total_tokens: number;
|
|
29
|
-
cache_creation_input_tokens?: number;
|
|
30
|
-
cache_read_input_tokens?: number;
|
|
31
|
-
cached_tokens?: number;
|
|
32
|
-
}
|
|
33
18
|
export interface ResponseStreamChunk {
|
|
34
19
|
type: 'content' | 'tool_calls' | 'tool_call_delta' | 'reasoning_delta' | 'reasoning_started' | 'done' | 'usage';
|
|
35
20
|
content?: string;
|
package/dist/api/responses.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import OpenAI from 'openai';
|
|
2
1
|
import { getOpenAiConfig, getCustomSystemPrompt, getCustomHeaders } from '../utils/apiConfig.js';
|
|
3
2
|
import { SYSTEM_PROMPT } from './systemPrompt.js';
|
|
4
3
|
import { withRetryGenerator } from '../utils/retryUtils.js';
|
|
@@ -52,27 +51,24 @@ function convertToolsForResponses(tools) {
|
|
|
52
51
|
strict: false
|
|
53
52
|
}));
|
|
54
53
|
}
|
|
55
|
-
let
|
|
56
|
-
function
|
|
57
|
-
if (!
|
|
54
|
+
let openaiConfig = null;
|
|
55
|
+
function getOpenAIConfig() {
|
|
56
|
+
if (!openaiConfig) {
|
|
58
57
|
const config = getOpenAiConfig();
|
|
59
58
|
if (!config.apiKey || !config.baseUrl) {
|
|
60
59
|
throw new Error('OpenAI API configuration is incomplete. Please configure API settings first.');
|
|
61
60
|
}
|
|
62
|
-
// Get custom headers
|
|
63
61
|
const customHeaders = getCustomHeaders();
|
|
64
|
-
|
|
62
|
+
openaiConfig = {
|
|
65
63
|
apiKey: config.apiKey,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
});
|
|
64
|
+
baseUrl: config.baseUrl,
|
|
65
|
+
customHeaders
|
|
66
|
+
};
|
|
71
67
|
}
|
|
72
|
-
return
|
|
68
|
+
return openaiConfig;
|
|
73
69
|
}
|
|
74
70
|
export function resetOpenAIClient() {
|
|
75
|
-
|
|
71
|
+
openaiConfig = null;
|
|
76
72
|
}
|
|
77
73
|
function convertToResponseInput(messages) {
|
|
78
74
|
const customSystemPrompt = getCustomSystemPrompt();
|
|
@@ -177,11 +173,43 @@ function convertToResponseInput(messages) {
|
|
|
177
173
|
}
|
|
178
174
|
return { input: result, systemInstructions };
|
|
179
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Parse Server-Sent Events (SSE) stream
|
|
178
|
+
*/
|
|
179
|
+
async function* parseSSEStream(reader) {
|
|
180
|
+
const decoder = new TextDecoder();
|
|
181
|
+
let buffer = '';
|
|
182
|
+
while (true) {
|
|
183
|
+
const { done, value } = await reader.read();
|
|
184
|
+
if (done)
|
|
185
|
+
break;
|
|
186
|
+
buffer += decoder.decode(value, { stream: true });
|
|
187
|
+
const lines = buffer.split('\n');
|
|
188
|
+
buffer = lines.pop() || '';
|
|
189
|
+
for (const line of lines) {
|
|
190
|
+
const trimmed = line.trim();
|
|
191
|
+
if (!trimmed || trimmed.startsWith(':'))
|
|
192
|
+
continue;
|
|
193
|
+
if (trimmed === 'data: [DONE]') {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (trimmed.startsWith('data: ')) {
|
|
197
|
+
const data = trimmed.slice(6);
|
|
198
|
+
try {
|
|
199
|
+
yield JSON.parse(data);
|
|
200
|
+
}
|
|
201
|
+
catch (e) {
|
|
202
|
+
console.error('Failed to parse SSE data:', data);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
180
208
|
/**
|
|
181
209
|
* 使用 Responses API 创建流式响应(带自动工具调用)
|
|
182
210
|
*/
|
|
183
211
|
export async function* createStreamingResponse(options, abortSignal, onRetry) {
|
|
184
|
-
const
|
|
212
|
+
const config = getOpenAIConfig();
|
|
185
213
|
// 提取系统提示词和转换后的消息
|
|
186
214
|
const { input: requestInput, systemInstructions } = convertToResponseInput(options.messages);
|
|
187
215
|
// 使用重试包装生成器
|
|
@@ -198,15 +226,29 @@ export async function* createStreamingResponse(options, abortSignal, onRetry) {
|
|
|
198
226
|
include: options.include || ['reasoning.encrypted_content'],
|
|
199
227
|
prompt_cache_key: options.prompt_cache_key,
|
|
200
228
|
};
|
|
201
|
-
const
|
|
202
|
-
|
|
229
|
+
const response = await fetch(`${config.baseUrl}/responses`, {
|
|
230
|
+
method: 'POST',
|
|
231
|
+
headers: {
|
|
232
|
+
'Content-Type': 'application/json',
|
|
233
|
+
'Authorization': `Bearer ${config.apiKey}`,
|
|
234
|
+
...config.customHeaders
|
|
235
|
+
},
|
|
236
|
+
body: JSON.stringify(requestPayload),
|
|
237
|
+
signal: abortSignal
|
|
203
238
|
});
|
|
239
|
+
if (!response.ok) {
|
|
240
|
+
const errorText = await response.text();
|
|
241
|
+
throw new Error(`OpenAI Responses API error: ${response.status} ${response.statusText} - ${errorText}`);
|
|
242
|
+
}
|
|
243
|
+
if (!response.body) {
|
|
244
|
+
throw new Error('No response body from OpenAI Responses API');
|
|
245
|
+
}
|
|
204
246
|
let contentBuffer = '';
|
|
205
247
|
let toolCallsBuffer = {};
|
|
206
248
|
let hasToolCalls = false;
|
|
207
249
|
let currentFunctionCallId = null;
|
|
208
250
|
let usageData;
|
|
209
|
-
for await (const chunk of
|
|
251
|
+
for await (const chunk of parseSSEStream(response.body.getReader())) {
|
|
210
252
|
if (abortSignal?.aborted) {
|
|
211
253
|
return;
|
|
212
254
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared API types for all AI providers
|
|
3
|
+
*/
|
|
4
|
+
export interface ImageContent {
|
|
5
|
+
type: 'image';
|
|
6
|
+
data: string;
|
|
7
|
+
mimeType: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ToolCall {
|
|
10
|
+
id: string;
|
|
11
|
+
type: 'function';
|
|
12
|
+
function: {
|
|
13
|
+
name: string;
|
|
14
|
+
arguments: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export interface ChatMessage {
|
|
18
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
19
|
+
content: string;
|
|
20
|
+
tool_call_id?: string;
|
|
21
|
+
tool_calls?: ToolCall[];
|
|
22
|
+
images?: ImageContent[];
|
|
23
|
+
}
|
|
24
|
+
export interface ChatCompletionTool {
|
|
25
|
+
type: 'function';
|
|
26
|
+
function: {
|
|
27
|
+
name: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
parameters?: Record<string, any>;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export interface UsageInfo {
|
|
33
|
+
prompt_tokens: number;
|
|
34
|
+
completion_tokens: number;
|
|
35
|
+
total_tokens: number;
|
|
36
|
+
cache_creation_input_tokens?: number;
|
|
37
|
+
cache_read_input_tokens?: number;
|
|
38
|
+
cached_tokens?: number;
|
|
39
|
+
}
|
|
@@ -66,6 +66,7 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
66
66
|
const [searchTerm, setSearchTerm] = useState('');
|
|
67
67
|
const [manualInputMode, setManualInputMode] = useState(false);
|
|
68
68
|
const [manualInputValue, setManualInputValue] = useState('');
|
|
69
|
+
const [, forceUpdate] = useState(0);
|
|
69
70
|
const requestMethodOptions = [
|
|
70
71
|
{
|
|
71
72
|
label: 'Chat Completions - Modern chat API (GPT-4, GPT-3.5-turbo)',
|
|
@@ -392,6 +393,8 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
392
393
|
key.escape) {
|
|
393
394
|
setIsEditing(false);
|
|
394
395
|
setSearchTerm('');
|
|
396
|
+
// Force re-render to clear Select component artifacts
|
|
397
|
+
forceUpdate(prev => prev + 1);
|
|
395
398
|
return;
|
|
396
399
|
}
|
|
397
400
|
// Handle editing mode
|
|
@@ -620,26 +623,58 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
620
623
|
activeProfile && (React.createElement(Text, { color: "cyan", dimColor: true },
|
|
621
624
|
"Active Profile: ",
|
|
622
625
|
activeProfile))))),
|
|
623
|
-
|
|
626
|
+
isEditing &&
|
|
627
|
+
(currentField === 'profile' ||
|
|
628
|
+
currentField === 'requestMethod' ||
|
|
629
|
+
currentField === 'advancedModel' ||
|
|
630
|
+
currentField === 'basicModel' ||
|
|
631
|
+
currentField === 'compactModelName') ? (React.createElement(Box, { flexDirection: "column" },
|
|
632
|
+
React.createElement(Text, { color: "green" },
|
|
633
|
+
"\u276F ",
|
|
634
|
+
currentField === 'profile' && 'Profile',
|
|
635
|
+
currentField === 'requestMethod' && 'Request Method',
|
|
636
|
+
currentField === 'advancedModel' && 'Advanced Model',
|
|
637
|
+
currentField === 'basicModel' && 'Basic Model',
|
|
638
|
+
currentField === 'compactModelName' && 'Compact Model',
|
|
639
|
+
":"),
|
|
640
|
+
React.createElement(Box, { marginLeft: 3, marginTop: 1 },
|
|
641
|
+
currentField === 'profile' && (React.createElement(Select, { options: [
|
|
642
|
+
...profiles.map(p => ({
|
|
643
|
+
label: `${p.displayName}${p.isActive ? ' (Active)' : ''}`,
|
|
644
|
+
value: p.name,
|
|
645
|
+
})),
|
|
646
|
+
{
|
|
647
|
+
label: chalk.green('+ New Profile'),
|
|
648
|
+
value: '__CREATE_NEW__',
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
label: chalk.red('🆇 Delete Profile'),
|
|
652
|
+
value: '__DELETE__',
|
|
653
|
+
},
|
|
654
|
+
], defaultValue: activeProfile, onChange: handleProfileChange })),
|
|
655
|
+
currentField === 'requestMethod' && (React.createElement(Select, { options: requestMethodOptions, defaultValue: requestMethod, onChange: value => {
|
|
656
|
+
setRequestMethod(value);
|
|
657
|
+
setIsEditing(false);
|
|
658
|
+
} })),
|
|
659
|
+
(currentField === 'advancedModel' ||
|
|
660
|
+
currentField === 'basicModel' ||
|
|
661
|
+
currentField === 'compactModelName') && (React.createElement(Box, { flexDirection: "column" },
|
|
662
|
+
searchTerm && React.createElement(Text, { color: "cyan" },
|
|
663
|
+
"Filter: ",
|
|
664
|
+
searchTerm),
|
|
665
|
+
React.createElement(Select, { options: getCurrentOptions(), defaultValue: getCurrentValue(), onChange: handleModelChange })))),
|
|
666
|
+
React.createElement(Box, { marginTop: 1 },
|
|
667
|
+
React.createElement(Alert, { variant: "info" },
|
|
668
|
+
(currentField === 'advancedModel' ||
|
|
669
|
+
currentField === 'basicModel' ||
|
|
670
|
+
currentField === 'compactModelName') &&
|
|
671
|
+
'Type to filter, ↑↓ to select, Enter to confirm, Esc to cancel',
|
|
672
|
+
(currentField === 'profile' || currentField === 'requestMethod') &&
|
|
673
|
+
'↑↓ to select, Enter to confirm, Esc to cancel')))) : (React.createElement(Box, { flexDirection: "column" },
|
|
624
674
|
React.createElement(Box, { flexDirection: "column" },
|
|
625
675
|
React.createElement(Text, { color: currentField === 'profile' ? 'green' : 'white' },
|
|
626
676
|
currentField === 'profile' ? '❯ ' : ' ',
|
|
627
677
|
"Profile:"),
|
|
628
|
-
currentField === 'profile' && isEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
629
|
-
React.createElement(Select, { options: [
|
|
630
|
-
...profiles.map(p => ({
|
|
631
|
-
label: `${p.displayName}${p.isActive ? ' (Active)' : ''}`,
|
|
632
|
-
value: p.name,
|
|
633
|
-
})),
|
|
634
|
-
{
|
|
635
|
-
label: chalk.green('+ New Profile'),
|
|
636
|
-
value: '__CREATE_NEW__',
|
|
637
|
-
},
|
|
638
|
-
{
|
|
639
|
-
label: chalk.red('🆇 Delete Profile'),
|
|
640
|
-
value: '__DELETE__',
|
|
641
|
-
},
|
|
642
|
-
], defaultValue: activeProfile, onChange: handleProfileChange }))),
|
|
643
678
|
(!isEditing || currentField !== 'profile') && (React.createElement(Box, { marginLeft: 3 },
|
|
644
679
|
React.createElement(Text, { color: "gray" }, profiles.find(p => p.name === activeProfile)?.displayName ||
|
|
645
680
|
activeProfile)))),
|
|
@@ -663,11 +698,6 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
663
698
|
React.createElement(Text, { color: currentField === 'requestMethod' ? 'green' : 'white' },
|
|
664
699
|
currentField === 'requestMethod' ? '❯ ' : ' ',
|
|
665
700
|
"Request Method:"),
|
|
666
|
-
currentField === 'requestMethod' && isEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
667
|
-
React.createElement(Select, { options: requestMethodOptions, defaultValue: requestMethod, onChange: value => {
|
|
668
|
-
setRequestMethod(value);
|
|
669
|
-
setIsEditing(false);
|
|
670
|
-
} }))),
|
|
671
701
|
(!isEditing || currentField !== 'requestMethod') && (React.createElement(Box, { marginLeft: 3 },
|
|
672
702
|
React.createElement(Text, { color: "gray" }, requestMethodOptions.find(opt => opt.value === requestMethod)
|
|
673
703
|
?.label || 'Not set')))),
|
|
@@ -683,36 +713,18 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
683
713
|
React.createElement(Text, { color: currentField === 'advancedModel' ? 'green' : 'white' },
|
|
684
714
|
currentField === 'advancedModel' ? '❯ ' : ' ',
|
|
685
715
|
"Advanced Model:"),
|
|
686
|
-
currentField === 'advancedModel' && isEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
687
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
688
|
-
searchTerm && React.createElement(Text, { color: "cyan" },
|
|
689
|
-
"Filter: ",
|
|
690
|
-
searchTerm),
|
|
691
|
-
React.createElement(Select, { options: getCurrentOptions(), defaultValue: getCurrentValue(), onChange: handleModelChange })))),
|
|
692
716
|
(!isEditing || currentField !== 'advancedModel') && (React.createElement(Box, { marginLeft: 3 },
|
|
693
717
|
React.createElement(Text, { color: "gray" }, advancedModel || 'Not set')))),
|
|
694
718
|
React.createElement(Box, { flexDirection: "column" },
|
|
695
719
|
React.createElement(Text, { color: currentField === 'basicModel' ? 'green' : 'white' },
|
|
696
720
|
currentField === 'basicModel' ? '❯ ' : ' ',
|
|
697
721
|
"Basic Model:"),
|
|
698
|
-
currentField === 'basicModel' && isEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
699
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
700
|
-
searchTerm && React.createElement(Text, { color: "cyan" },
|
|
701
|
-
"Filter: ",
|
|
702
|
-
searchTerm),
|
|
703
|
-
React.createElement(Select, { options: getCurrentOptions(), defaultValue: getCurrentValue(), onChange: handleModelChange })))),
|
|
704
722
|
(!isEditing || currentField !== 'basicModel') && (React.createElement(Box, { marginLeft: 3 },
|
|
705
723
|
React.createElement(Text, { color: "gray" }, basicModel || 'Not set')))),
|
|
706
724
|
React.createElement(Box, { flexDirection: "column" },
|
|
707
725
|
React.createElement(Text, { color: currentField === 'compactModelName' ? 'green' : 'white' },
|
|
708
726
|
currentField === 'compactModelName' ? '❯ ' : ' ',
|
|
709
727
|
"Compact Model:"),
|
|
710
|
-
currentField === 'compactModelName' && isEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
711
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
712
|
-
searchTerm && React.createElement(Text, { color: "cyan" },
|
|
713
|
-
"Filter: ",
|
|
714
|
-
searchTerm),
|
|
715
|
-
React.createElement(Select, { options: getCurrentOptions(), defaultValue: getCurrentValue(), onChange: handleModelChange })))),
|
|
716
728
|
(!isEditing || currentField !== 'compactModelName') && (React.createElement(Box, { marginLeft: 3 },
|
|
717
729
|
React.createElement(Text, { color: "gray" }, compactModelName || 'Not set')))),
|
|
718
730
|
React.createElement(Box, { flexDirection: "column" },
|
|
@@ -734,20 +746,21 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
734
746
|
"Enter value: ",
|
|
735
747
|
maxTokens))),
|
|
736
748
|
(!isEditing || currentField !== 'maxTokens') && (React.createElement(Box, { marginLeft: 3 },
|
|
737
|
-
React.createElement(Text, { color: "gray" }, maxTokens))))),
|
|
749
|
+
React.createElement(Text, { color: "gray" }, maxTokens)))))),
|
|
738
750
|
errors.length > 0 && (React.createElement(Box, { flexDirection: "column", marginTop: 1 },
|
|
739
751
|
React.createElement(Text, { color: "red", bold: true }, "Errors:"),
|
|
740
752
|
errors.map((error, index) => (React.createElement(Text, { key: index, color: "red" },
|
|
741
753
|
"\u2022 ",
|
|
742
754
|
error))))),
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
' ',
|
|
755
|
+
!(isEditing &&
|
|
756
|
+
(currentField === 'profile' ||
|
|
757
|
+
currentField === 'requestMethod' ||
|
|
747
758
|
currentField === 'advancedModel' ||
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
759
|
+
currentField === 'basicModel' ||
|
|
760
|
+
currentField === 'compactModelName')) && (React.createElement(Box, { flexDirection: "column", marginTop: 1 }, isEditing ? (React.createElement(Alert, { variant: "info" },
|
|
761
|
+
"Editing mode:",
|
|
762
|
+
' ',
|
|
763
|
+
currentField === 'maxContextTokens' || currentField === 'maxTokens'
|
|
764
|
+
? 'Type to edit, Enter to save'
|
|
765
|
+
: 'Press Enter to save and exit editing')) : (React.createElement(Alert, { variant: "info" }, "Use \u2191\u2193 to navigate, Enter to edit, M for manual input, Ctrl+S or Esc to save"))))));
|
|
753
766
|
}
|
|
@@ -92,7 +92,7 @@ export default function WelcomeScreen({ version = '1.0.0', onMenuSelect, }) {
|
|
|
92
92
|
}, [terminalWidth, stdout]);
|
|
93
93
|
return (React.createElement(Box, { flexDirection: "column", width: terminalWidth },
|
|
94
94
|
React.createElement(Static, { key: remountKey, items: [
|
|
95
|
-
React.createElement(Box, { key: "welcome-header", flexDirection: "row", paddingLeft: 2, paddingTop: 1, paddingBottom:
|
|
95
|
+
React.createElement(Box, { key: "welcome-header", flexDirection: "row", paddingLeft: 2, paddingTop: 1, paddingBottom: 0, width: terminalWidth },
|
|
96
96
|
React.createElement(Box, { flexDirection: "column", justifyContent: "center" },
|
|
97
97
|
React.createElement(Text, { bold: true },
|
|
98
98
|
React.createElement(Gradient, { name: "rainbow" }, "\u2746 SNOW AI CLI")),
|