snow-ai 0.2.23 → 0.2.25

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.
Files changed (43) hide show
  1. package/dist/agents/compactAgent.d.ts +55 -0
  2. package/dist/agents/compactAgent.js +301 -0
  3. package/dist/api/chat.d.ts +0 -8
  4. package/dist/api/chat.js +1 -144
  5. package/dist/api/responses.d.ts +0 -11
  6. package/dist/api/responses.js +1 -189
  7. package/dist/api/systemPrompt.d.ts +1 -1
  8. package/dist/api/systemPrompt.js +80 -206
  9. package/dist/app.d.ts +2 -1
  10. package/dist/app.js +11 -13
  11. package/dist/cli.js +23 -3
  12. package/dist/hooks/useConversation.js +51 -7
  13. package/dist/hooks/useGlobalNavigation.d.ts +1 -1
  14. package/dist/hooks/useKeyboardInput.js +14 -8
  15. package/dist/mcp/filesystem.d.ts +49 -6
  16. package/dist/mcp/filesystem.js +243 -86
  17. package/dist/mcp/websearch.d.ts +118 -0
  18. package/dist/mcp/websearch.js +451 -0
  19. package/dist/ui/components/ToolResultPreview.js +60 -1
  20. package/dist/ui/pages/ChatScreen.d.ts +4 -2
  21. package/dist/ui/pages/ChatScreen.js +62 -14
  22. package/dist/ui/pages/{ApiConfigScreen.d.ts → ConfigScreen.d.ts} +1 -1
  23. package/dist/ui/pages/ConfigScreen.js +549 -0
  24. package/dist/ui/pages/{ModelConfigScreen.d.ts → ProxyConfigScreen.d.ts} +1 -1
  25. package/dist/ui/pages/ProxyConfigScreen.js +143 -0
  26. package/dist/ui/pages/WelcomeScreen.js +15 -15
  27. package/dist/utils/apiConfig.d.ts +8 -2
  28. package/dist/utils/apiConfig.js +21 -0
  29. package/dist/utils/commandExecutor.d.ts +1 -1
  30. package/dist/utils/contextCompressor.js +363 -49
  31. package/dist/utils/mcpToolsManager.d.ts +1 -1
  32. package/dist/utils/mcpToolsManager.js +106 -6
  33. package/dist/utils/resourceMonitor.d.ts +65 -0
  34. package/dist/utils/resourceMonitor.js +175 -0
  35. package/dist/utils/retryUtils.js +6 -0
  36. package/dist/utils/sessionManager.d.ts +1 -0
  37. package/dist/utils/sessionManager.js +10 -0
  38. package/dist/utils/textBuffer.js +7 -2
  39. package/dist/utils/toolExecutor.d.ts +2 -2
  40. package/dist/utils/toolExecutor.js +4 -4
  41. package/package.json +5 -1
  42. package/dist/ui/pages/ApiConfigScreen.js +0 -161
  43. package/dist/ui/pages/ModelConfigScreen.js +0 -467
@@ -0,0 +1,143 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Box, Newline, Text, useInput } from 'ink';
3
+ import Gradient from 'ink-gradient';
4
+ import { Alert } from '@inkjs/ui';
5
+ import TextInput from 'ink-text-input';
6
+ import { getProxyConfig, updateProxyConfig, } from '../../utils/apiConfig.js';
7
+ export default function ProxyConfigScreen({ onBack, onSave, inlineMode = false }) {
8
+ const [enabled, setEnabled] = useState(false);
9
+ const [port, setPort] = useState('7890');
10
+ const [browserPath, setBrowserPath] = useState('');
11
+ const [currentField, setCurrentField] = useState('enabled');
12
+ const [errors, setErrors] = useState([]);
13
+ const [isEditing, setIsEditing] = useState(false);
14
+ useEffect(() => {
15
+ const config = getProxyConfig();
16
+ setEnabled(config.enabled);
17
+ setPort(config.port.toString());
18
+ setBrowserPath(config.browserPath || '');
19
+ }, []);
20
+ const validateConfig = () => {
21
+ const validationErrors = [];
22
+ const portNum = parseInt(port, 10);
23
+ if (isNaN(portNum) || portNum < 1 || portNum > 65535) {
24
+ validationErrors.push('Port must be a number between 1 and 65535');
25
+ }
26
+ return validationErrors;
27
+ };
28
+ const saveConfig = () => {
29
+ const validationErrors = validateConfig();
30
+ if (validationErrors.length === 0) {
31
+ const config = {
32
+ enabled,
33
+ port: parseInt(port, 10),
34
+ browserPath: browserPath.trim() || undefined,
35
+ };
36
+ updateProxyConfig(config);
37
+ setErrors([]);
38
+ return true;
39
+ }
40
+ else {
41
+ setErrors(validationErrors);
42
+ return false;
43
+ }
44
+ };
45
+ useInput((input, key) => {
46
+ // Handle save/exit globally
47
+ if (input === 's' && (key.ctrl || key.meta)) {
48
+ if (saveConfig()) {
49
+ onSave();
50
+ }
51
+ }
52
+ else if (key.escape) {
53
+ saveConfig(); // Try to save even on escape
54
+ onBack();
55
+ }
56
+ else if (key.return) {
57
+ if (isEditing) {
58
+ // Exit edit mode, return to navigation
59
+ setIsEditing(false);
60
+ }
61
+ else {
62
+ // Enter edit mode for current field (toggle for checkbox)
63
+ if (currentField === 'enabled') {
64
+ setEnabled(!enabled);
65
+ }
66
+ else {
67
+ setIsEditing(true);
68
+ }
69
+ }
70
+ }
71
+ else if (!isEditing && key.upArrow) {
72
+ if (currentField === 'port') {
73
+ setCurrentField('enabled');
74
+ }
75
+ else if (currentField === 'browserPath') {
76
+ setCurrentField('port');
77
+ }
78
+ }
79
+ else if (!isEditing && key.downArrow) {
80
+ if (currentField === 'enabled') {
81
+ setCurrentField('port');
82
+ }
83
+ else if (currentField === 'port') {
84
+ setCurrentField('browserPath');
85
+ }
86
+ }
87
+ });
88
+ return (React.createElement(Box, { flexDirection: "column", padding: 1 },
89
+ !inlineMode && (React.createElement(Box, { marginBottom: 1, borderStyle: "double", borderColor: "cyan", paddingX: 2, paddingY: 1 },
90
+ React.createElement(Box, { flexDirection: "column" },
91
+ React.createElement(Gradient, { name: "rainbow" }, "Proxy Configuration"),
92
+ React.createElement(Text, { color: "gray", dimColor: true }, "Configure system proxy for web search and fetch")))),
93
+ React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
94
+ React.createElement(Box, { marginBottom: 1 },
95
+ React.createElement(Box, { flexDirection: "column" },
96
+ React.createElement(Text, { color: currentField === 'enabled' ? 'green' : 'white' },
97
+ currentField === 'enabled' ? '❯ ' : ' ',
98
+ "Enable Proxy:"),
99
+ React.createElement(Box, { marginLeft: 3 },
100
+ React.createElement(Text, { color: "gray" },
101
+ enabled ? '☑ Enabled' : '☐ Disabled',
102
+ " (Press Enter to toggle)")))),
103
+ React.createElement(Box, { marginBottom: 1 },
104
+ React.createElement(Box, { flexDirection: "column" },
105
+ React.createElement(Text, { color: currentField === 'port' ? 'green' : 'white' },
106
+ currentField === 'port' ? '❯ ' : ' ',
107
+ "Proxy Port:"),
108
+ currentField === 'port' && isEditing && (React.createElement(Box, { marginLeft: 3 },
109
+ React.createElement(TextInput, { value: port, onChange: setPort, placeholder: "7890" }))),
110
+ (!isEditing || currentField !== 'port') && (React.createElement(Box, { marginLeft: 3 },
111
+ React.createElement(Text, { color: "gray" }, port || 'Not set'))))),
112
+ React.createElement(Box, { marginBottom: 1 },
113
+ React.createElement(Box, { flexDirection: "column" },
114
+ React.createElement(Text, { color: currentField === 'browserPath' ? 'green' : 'white' },
115
+ currentField === 'browserPath' ? '❯ ' : ' ',
116
+ "Browser Path (Optional):"),
117
+ currentField === 'browserPath' && isEditing && (React.createElement(Box, { marginLeft: 3 },
118
+ React.createElement(TextInput, { value: browserPath, onChange: setBrowserPath, placeholder: "Leave empty for auto-detect" }))),
119
+ (!isEditing || currentField !== 'browserPath') && (React.createElement(Box, { marginLeft: 3 },
120
+ React.createElement(Text, { color: "gray" }, browserPath || 'Auto-detect')))))),
121
+ errors.length > 0 && (React.createElement(Box, { flexDirection: "column", marginBottom: 2 },
122
+ React.createElement(Text, { color: "red", bold: true }, "Errors:"),
123
+ errors.map((error, index) => (React.createElement(Text, { key: index, color: "red" },
124
+ "\u2022 ",
125
+ error))))),
126
+ React.createElement(Box, { flexDirection: "column" }, isEditing ? (React.createElement(React.Fragment, null,
127
+ React.createElement(Alert, { variant: "info" }, "Editing mode: Press Enter to save and exit editing (Make your changes and press Enter when done)"))) : (React.createElement(React.Fragment, null,
128
+ React.createElement(Alert, { variant: "info" }, "Use \u2191\u2193 to navigate between fields, press Enter to edit/toggle, and press Ctrl+S or Esc to save and return")))),
129
+ React.createElement(Box, { flexDirection: "column", marginTop: 1 },
130
+ React.createElement(Alert, { variant: "info" },
131
+ "Browser Path Examples: ",
132
+ React.createElement(Newline, null),
133
+ React.createElement(Text, { color: 'blue' }, "\u2022 Windows: C:\\Program Files(x86)\\Microsoft\\Edge\\Application\\msedge.exe"),
134
+ " ",
135
+ React.createElement(Newline, null),
136
+ React.createElement(Text, { color: 'green' }, "\u2022 macOS: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome"),
137
+ " ",
138
+ React.createElement(Newline, null),
139
+ React.createElement(Text, { color: 'yellow' }, "\u2022 Linux: /usr/bin/chromium-browser"),
140
+ " ",
141
+ React.createElement(Newline, null),
142
+ "Leave empty to auto-detect system browser (Edge/Chrome)"))));
143
+ }
@@ -5,8 +5,8 @@ import Gradient from 'ink-gradient';
5
5
  import ansiEscapes from 'ansi-escapes';
6
6
  import Menu from '../components/Menu.js';
7
7
  import { useTerminalSize } from '../../hooks/useTerminalSize.js';
8
- import ApiConfigScreen from './ApiConfigScreen.js';
9
- import ModelConfigScreen from './ModelConfigScreen.js';
8
+ import ConfigScreen from './ConfigScreen.js';
9
+ import ProxyConfigScreen from './ProxyConfigScreen.js';
10
10
  export default function WelcomeScreen({ version = '1.0.0', onMenuSelect, }) {
11
11
  const [infoText, setInfoText] = useState('Start a new chat conversation');
12
12
  const [inlineView, setInlineView] = useState('menu');
@@ -22,14 +22,14 @@ export default function WelcomeScreen({ version = '1.0.0', onMenuSelect, }) {
22
22
  clearTerminal: true,
23
23
  },
24
24
  {
25
- label: 'API Settings',
25
+ label: 'API & Model Settings',
26
26
  value: 'config',
27
- infoText: 'Configure OpenAI API settings',
27
+ infoText: 'Configure API settings and AI models',
28
28
  },
29
29
  {
30
- label: 'Model Settings',
31
- value: 'models',
32
- infoText: 'Configure AI models for different tasks',
30
+ label: 'Proxy & Browser Settings',
31
+ value: 'proxy',
32
+ infoText: 'Configure system proxy and browser for web search and fetch',
33
33
  },
34
34
  {
35
35
  label: 'System Prompt Settings',
@@ -57,12 +57,12 @@ export default function WelcomeScreen({ version = '1.0.0', onMenuSelect, }) {
57
57
  setInfoText(newInfoText);
58
58
  }, []);
59
59
  const handleInlineMenuSelect = useCallback((value) => {
60
- // Handle inline views (config, models) or pass through to parent
60
+ // Handle inline views (config, proxy) or pass through to parent
61
61
  if (value === 'config') {
62
- setInlineView('api-config');
62
+ setInlineView('config');
63
63
  }
64
- else if (value === 'models') {
65
- setInlineView('model-config');
64
+ else if (value === 'proxy') {
65
+ setInlineView('proxy-config');
66
66
  }
67
67
  else {
68
68
  // Pass through to parent for other actions (chat, exit, etc.)
@@ -106,8 +106,8 @@ export default function WelcomeScreen({ version = '1.0.0', onMenuSelect, }) {
106
106
  React.createElement(Menu, { options: menuOptions, onSelect: handleInlineMenuSelect, onSelectionChange: handleSelectionChange })))),
107
107
  inlineView === 'menu' && (React.createElement(Box, { paddingX: 1 },
108
108
  React.createElement(Alert, { variant: "info" }, infoText))),
109
- inlineView === 'api-config' && (React.createElement(Box, { paddingX: 1 },
110
- React.createElement(ApiConfigScreen, { onBack: handleBackToMenu, onSave: handleConfigSave, inlineMode: true }))),
111
- inlineView === 'model-config' && (React.createElement(Box, { paddingX: 1 },
112
- React.createElement(ModelConfigScreen, { onBack: handleBackToMenu, onSave: handleConfigSave, inlineMode: true })))));
109
+ inlineView === 'config' && (React.createElement(Box, { paddingX: 1 },
110
+ React.createElement(ConfigScreen, { onBack: handleBackToMenu, onSave: handleConfigSave, inlineMode: true }))),
111
+ inlineView === 'proxy-config' && (React.createElement(Box, { paddingX: 1 },
112
+ React.createElement(ProxyConfigScreen, { onBack: handleBackToMenu, onSave: handleConfigSave, inlineMode: true })))));
113
113
  }
@@ -1,7 +1,5 @@
1
1
  export type RequestMethod = 'chat' | 'responses' | 'gemini' | 'anthropic';
2
2
  export interface CompactModelConfig {
3
- baseUrl: string;
4
- apiKey: string;
5
3
  modelName: string;
6
4
  }
7
5
  export interface ApiConfig {
@@ -24,9 +22,15 @@ export interface MCPServer {
24
22
  export interface MCPConfig {
25
23
  mcpServers: Record<string, MCPServer>;
26
24
  }
25
+ export interface ProxyConfig {
26
+ enabled: boolean;
27
+ port: number;
28
+ browserPath?: string;
29
+ }
27
30
  export interface AppConfig {
28
31
  snowcfg: ApiConfig;
29
32
  openai?: ApiConfig;
33
+ proxy?: ProxyConfig;
30
34
  }
31
35
  export declare function loadConfig(): AppConfig;
32
36
  export declare function saveConfig(config: AppConfig): void;
@@ -35,6 +39,8 @@ export declare function getOpenAiConfig(): ApiConfig;
35
39
  export declare function validateApiConfig(config: Partial<ApiConfig>): string[];
36
40
  export declare function updateMCPConfig(mcpConfig: MCPConfig): void;
37
41
  export declare function getMCPConfig(): MCPConfig;
42
+ export declare function getProxyConfig(): ProxyConfig;
43
+ export declare function updateProxyConfig(proxyConfig: ProxyConfig): void;
38
44
  export declare function validateMCPConfig(config: Partial<MCPConfig>): string[];
39
45
  /**
40
46
  * 读取自定义系统提示词
@@ -12,6 +12,10 @@ const DEFAULT_CONFIG = {
12
12
  maxTokens: 4096,
13
13
  anthropicBeta: false,
14
14
  },
15
+ proxy: {
16
+ enabled: false,
17
+ port: 7890,
18
+ },
15
19
  };
16
20
  const DEFAULT_MCP_CONFIG = {
17
21
  mcpServers: {},
@@ -160,6 +164,23 @@ export function getMCPConfig() {
160
164
  return defaultMCPConfig;
161
165
  }
162
166
  }
167
+ export function getProxyConfig() {
168
+ const fullConfig = loadConfig();
169
+ return fullConfig.proxy || DEFAULT_CONFIG.proxy;
170
+ }
171
+ export function updateProxyConfig(proxyConfig) {
172
+ ensureConfigDirectory();
173
+ try {
174
+ const fullConfig = loadConfig();
175
+ fullConfig.proxy = proxyConfig;
176
+ const { openai, ...configWithoutOpenai } = fullConfig;
177
+ const configData = JSON.stringify(configWithoutOpenai, null, 2);
178
+ writeFileSync(CONFIG_FILE, configData, 'utf8');
179
+ }
180
+ catch (error) {
181
+ throw new Error(`Failed to save proxy configuration: ${error}`);
182
+ }
183
+ }
163
184
  export function validateMCPConfig(config) {
164
185
  const errors = [];
165
186
  if (config.mcpServers) {
@@ -1,7 +1,7 @@
1
1
  export interface CommandResult {
2
2
  success: boolean;
3
3
  message?: string;
4
- action?: 'clear' | 'resume' | 'info' | 'showMcpInfo' | 'goHome' | 'toggleYolo' | 'initProject' | 'compact' | 'showSessionPanel' | 'showMcpPanel';
4
+ action?: 'clear' | 'resume' | 'info' | 'showMcpInfo' | 'toggleYolo' | 'initProject' | 'compact' | 'showSessionPanel' | 'showMcpPanel';
5
5
  prompt?: string;
6
6
  alreadyConnected?: boolean;
7
7
  }