xiaozuoassistant 0.1.48 → 0.1.50

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/bin/cli.js CHANGED
@@ -22,6 +22,8 @@ const __dirname = path.dirname(__filename);
22
22
  // When installed globally: lib/node_modules/xiaozuoassistant/bin/cli.js -> ../
23
23
  const packageRoot = path.resolve(__dirname, '..');
24
24
 
25
+ const binName = path.basename(process.argv[1] || 'xiaozuoAssistant');
26
+
25
27
  const args = process.argv.slice(2);
26
28
  const command = args[0];
27
29
  const commandArgs = args.slice(1);
@@ -646,7 +648,7 @@ if (command === 'start') {
646
648
  ensureAppHome();
647
649
  stopServer();
648
650
  } else {
649
- console.log('Usage: xiaozuoAssistant <command>');
651
+ console.log(`Usage: ${binName} <command>`);
650
652
  console.log('Commands:');
651
653
  console.log(' start Start the xiaozuoAssistant server');
652
654
  console.log(' stop Stop the xiaozuoAssistant server');
package/config.json CHANGED
@@ -4,10 +4,13 @@
4
4
  "host": "localhost"
5
5
  },
6
6
  "llm": {
7
+ "provider": "qwen",
7
8
  "apiKey": "",
8
9
  "baseURL": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
9
10
  "model": "qwen-plus",
10
- "temperature": 0.7
11
+ "temperature": 0.7,
12
+ "requestTimeoutMs": 600000,
13
+ "maxRetries": 2
11
14
  },
12
15
  "logging": {
13
16
  "level": "info"
@@ -20,12 +20,18 @@ try {
20
20
  apiKey: '',
21
21
  baseURL: 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1',
22
22
  model: 'qwen-plus',
23
- temperature: 0.7
23
+ temperature: 0.7,
24
+ requestTimeoutMs: 600000,
25
+ maxRetries: 2
24
26
  };
25
27
  }
26
28
  else {
27
29
  if (!loadedConfig.llm.apiKey)
28
30
  loadedConfig.llm.apiKey = '';
31
+ if (loadedConfig.llm.requestTimeoutMs === undefined)
32
+ loadedConfig.llm.requestTimeoutMs = 600000;
33
+ if (loadedConfig.llm.maxRetries === undefined)
34
+ loadedConfig.llm.maxRetries = 2;
29
35
  }
30
36
  // Override with env vars if present (optional, but good for security)
31
37
  if (process.env.XIAOZUO_LLM_API_KEY)
@@ -43,7 +49,9 @@ catch (error) {
43
49
  apiKey: '',
44
50
  baseURL: 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1',
45
51
  model: 'qwen-plus',
46
- temperature: 0.7
52
+ temperature: 0.7,
53
+ requestTimeoutMs: 600000,
54
+ maxRetries: 2
47
55
  },
48
56
  logging: { level: 'info' },
49
57
  scheduler: { memoryMaintenanceCron: '0 0 * * *' },
@@ -111,7 +111,7 @@ export class Brain {
111
111
  { role: 'user', content: content }
112
112
  ],
113
113
  temperature: 0.5
114
- });
114
+ }, { timeout: config.llm.requestTimeoutMs ?? 600000 });
115
115
  return response.choices[0].message.content || '';
116
116
  }
117
117
  catch (e) {
@@ -123,12 +123,32 @@ export class Brain {
123
123
  const tools = skillRegistry.getToolsDefinition();
124
124
  // OpenAI SDK expects tools to be undefined if empty array, or valid tools array
125
125
  const toolsParam = tools.length > 0 ? tools : undefined;
126
- return await this.openai.chat.completions.create({
127
- model: config.llm.model,
128
- messages: messages,
129
- tools: toolsParam,
130
- temperature: config.llm.temperature
131
- });
126
+ const maxRetries = config.llm.maxRetries ?? 2;
127
+ const timeout = config.llm.requestTimeoutMs ?? 600000;
128
+ let lastError;
129
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
130
+ try {
131
+ return await this.openai.chat.completions.create({
132
+ model: config.llm.model,
133
+ messages: messages,
134
+ tools: toolsParam,
135
+ temperature: config.llm.temperature
136
+ }, { timeout });
137
+ }
138
+ catch (e) {
139
+ lastError = e;
140
+ const msg = String(e?.message || '').toLowerCase();
141
+ const code = String(e?.code || '').toLowerCase();
142
+ const isTimeout = msg.includes('timeout') || code.includes('etimedout');
143
+ const isConn = msg.includes('econnreset') || msg.includes('network') || code.includes('econnreset');
144
+ const retryable = isTimeout || isConn;
145
+ if (!retryable || attempt === maxRetries)
146
+ break;
147
+ const backoffMs = Math.min(2000 * (attempt + 1), 8000);
148
+ await new Promise(r => setTimeout(r, backoffMs));
149
+ }
150
+ }
151
+ throw lastError;
132
152
  }
133
153
  }
134
154
  export const brain = Brain.getInstance();
@@ -338,6 +338,12 @@ ${context}`;
338
338
  }
339
339
  catch (error) {
340
340
  console.error('Error processing message:', error);
341
+ try {
342
+ await memory.addMessage(sessionId, { role: 'assistant', content: `Error: ${error.message}`, timestamp: Date.now() });
343
+ }
344
+ catch {
345
+ // ignore
346
+ }
341
347
  eventBus.emitEvent({
342
348
  type: 'error',
343
349
  payload: { error: error.message },
@@ -9,8 +9,13 @@ export function createHttpStack() {
9
9
  cors: {
10
10
  origin: '*',
11
11
  methods: ['GET', 'POST']
12
- }
12
+ },
13
+ pingInterval: 25000,
14
+ pingTimeout: 120000
13
15
  });
16
+ httpServer.requestTimeout = 0;
17
+ httpServer.keepAliveTimeout = 70000;
18
+ httpServer.headersTimeout = 75000;
14
19
  app.use(cors());
15
20
  app.use(express.json());
16
21
  return { app, httpServer, io };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "xiaozuoassistant",
3
3
  "private": false,
4
4
  "description": "Your personal, locally-hosted AI assistant for office productivity.",
5
- "version": "0.1.48",
5
+ "version": "0.1.50",
6
6
  "author": "mantle.lau",
7
7
  "license": "MIT",
8
8
  "repository": {
@@ -20,7 +20,8 @@
20
20
  "type": "module",
21
21
  "main": "dist/server/index.js",
22
22
  "bin": {
23
- "xiaozuoAssistant": "bin/cli.js"
23
+ "xiaozuoAssistant": "bin/cli.js",
24
+ "mybot": "bin/cli.js"
24
25
  },
25
26
  "files": [
26
27
  "dist",