@evomap/evolver-proxy 2.0.0-beta.11 → 2.0.0-beta.12

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 (2) hide show
  1. package/dist/llm/server.js +24 -4
  2. package/package.json +3 -3
@@ -5,8 +5,10 @@
5
5
  // host (other local users, container neighbors, postinstall scripts), hence the mandatory token.
6
6
  import { createServer } from 'node:http';
7
7
  import { timingSafeEqual } from 'node:crypto';
8
+ import { util } from '@evomap/evolver-core';
8
9
  export const DEFAULT_LLM_PORT = 19821; // one above the mailbox IPC default — the two daemons co-exist
9
10
  const MAX_PORT_ATTEMPTS = 100;
11
+ const MAX_EPHEMERAL_LLM_LISTEN_ATTEMPTS = 5;
10
12
  /** /v1/messages bodies legitimately reach tens of MiB (long contexts); the 1 MiB IPC-style cap would break
11
13
  * real clients. Still bounded — an unauthenticated local writer must not be able to balloon memory. */
12
14
  export const DEFAULT_LLM_MAX_BODY_BYTES = 32 * 1024 * 1024;
@@ -193,19 +195,35 @@ export class LlmProxyServer {
193
195
  const basePort = this.opts.port ?? Number(this.env['EVOLVER_LLM_PORT'] || DEFAULT_LLM_PORT);
194
196
  const server = createServer((req, res) => { void this.handle(req, res); });
195
197
  const tryListen = (port) => new Promise((resolve, reject) => {
196
- server.once('error', (err) => {
198
+ const onError = (err) => {
197
199
  if (err.code === 'EADDRINUSE')
198
200
  resolve(false);
199
201
  else
200
202
  reject(err);
203
+ };
204
+ server.once('error', onError);
205
+ server.listen(port, host, () => {
206
+ server.removeListener('error', onError);
207
+ resolve(true);
201
208
  });
202
- server.listen(port, host, () => resolve(true));
209
+ });
210
+ const closeListener = () => new Promise((resolve, reject) => {
211
+ server.close((err) => { if (err)
212
+ reject(err);
213
+ else
214
+ resolve(); });
203
215
  });
204
216
  let port = basePort;
205
- for (let i = 0; i < MAX_PORT_ATTEMPTS; i++) {
217
+ const maxAttempts = basePort === 0 ? MAX_EPHEMERAL_LLM_LISTEN_ATTEMPTS : MAX_PORT_ATTEMPTS;
218
+ for (let i = 0; i < maxAttempts; i++) {
206
219
  if (await tryListen(port)) {
207
220
  const addr = server.address();
208
- this.actualPort = typeof addr === 'object' && addr ? addr.port : port;
221
+ const actualPort = typeof addr === 'object' && addr ? addr.port : port;
222
+ if (basePort === 0 && util.isFetchForbiddenPort(actualPort)) {
223
+ await closeListener();
224
+ continue;
225
+ }
226
+ this.actualPort = actualPort;
209
227
  this.server = server;
210
228
  const url = `http://${host}:${this.actualPort}`;
211
229
  this.log.log?.(`[evolver-llm-proxy] listening on ${url}`);
@@ -215,6 +233,8 @@ export class LlmProxyServer {
215
233
  break; // kernel-assigned can't collide; a failure here is real
216
234
  port++;
217
235
  }
236
+ if (basePort === 0)
237
+ throw new Error('llm_proxy_safe_port_unavailable');
218
238
  throw new Error(`LlmProxyServer: no free port after ${MAX_PORT_ATTEMPTS} attempts from ${basePort}`);
219
239
  }
220
240
  async stop() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evomap/evolver-proxy",
3
- "version": "2.0.0-beta.11",
3
+ "version": "2.0.0-beta.12",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "系统级 mailbox/hub 同步 daemon (Node)",
@@ -26,8 +26,8 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "@aws-sdk/client-bedrock-runtime": "^3.1053.0",
29
- "@evomap/evolver-adapter-public": "2.0.0-beta.11",
30
- "@evomap/evolver-core": "2.0.0-beta.11"
29
+ "@evomap/evolver-adapter-public": "2.0.0-beta.12",
30
+ "@evomap/evolver-core": "2.0.0-beta.12"
31
31
  },
32
32
  "repository": {
33
33
  "type": "git",