@gencode/server 0.3.7 → 0.3.9
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/CHANGELOG.md +25 -0
- package/README.md +35 -0
- package/dist/bin.js +4 -3
- package/dist/index.d.ts +5 -1
- package/dist/index.js +1 -1
- package/dist/server-BWdQz0S2.js +1 -0
- package/package.json +3 -3
- package/dist/server-BMS-TOVR.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @gencode/server
|
|
2
2
|
|
|
3
|
+
## 0.3.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 3dee7d5: `aimax-server` 的 `POST /run` 现在可以在 `run.messages` 中直接接收结构化 Message 输入,格式与 `aimax run --from-file` 一致,支持文本块和 base64 图片块,例如 `content: [{ "type": "text", "text": "/new" }, { "type": "image", "data": "...", "mimeType": "image/png" }]`。这让 server 模式下通过结构化消息发送 `/new` 等 slash command 时能够按会话命令执行;`run.message` 仍保持普通字符串语义,不会被自动当作 JSON 解析。
|
|
8
|
+
- Updated dependencies [b352a92]
|
|
9
|
+
- Updated dependencies [b352a92]
|
|
10
|
+
- Updated dependencies [b352a92]
|
|
11
|
+
- Updated dependencies [b352a92]
|
|
12
|
+
- Updated dependencies [b352a92]
|
|
13
|
+
- Updated dependencies [b352a92]
|
|
14
|
+
- Updated dependencies [3dee7d5]
|
|
15
|
+
- Updated dependencies [02c5263]
|
|
16
|
+
- @gencode/agents@0.17.0
|
|
17
|
+
- @gencode/cli@0.15.0
|
|
18
|
+
|
|
19
|
+
## 0.3.8
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- c96335b: Container prestart deployments can now preload system plugins before the real user request arrives. Start `aimax-server` with `--plugins-config /path/to/plugins.json` or `AIMAX_SERVER_PLUGINS_CONFIG=/path/to/plugins.json`; the server reads that file during warmup and preloads the configured plugins. If a `/run` request does not provide its own `run.pluginsConfig` and does not override `AIMAX_PLUGINS_CONFIG` in request `env`, the run automatically inherits the startup plugins config path, so the CLI execution reuses the preloaded plugin registry. Plugin runtime values such as session env and LLM access remain bound to the actual run request.
|
|
24
|
+
- Updated dependencies [c96335b]
|
|
25
|
+
- @gencode/agents@0.16.4
|
|
26
|
+
- @gencode/cli@0.14.5
|
|
27
|
+
|
|
3
28
|
## 0.3.7
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -5,3 +5,38 @@ One-shot AIMax container prestart server.
|
|
|
5
5
|
This package starts a local HTTP process that warms system-level runtime state,
|
|
6
6
|
accepts exactly one `/run` request, delegates execution to `@gencode/cli`, and
|
|
7
7
|
exits when the agent loop finishes.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
aimax-server --host 127.0.0.1 --port 0 --plugins-config /image/aimax/plugins.json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`--plugins-config` can also be supplied as `AIMAX_SERVER_PLUGINS_CONFIG`. The
|
|
16
|
+
server reads that file during warmup and preloads the configured system plugins.
|
|
17
|
+
If the accepted `/run` request does not provide `run.pluginsConfig` and does not
|
|
18
|
+
override `AIMAX_PLUGINS_CONFIG` in request `env`, the run inherits the startup
|
|
19
|
+
plugins config path so the CLI execution uses the preloaded plugin registry.
|
|
20
|
+
|
|
21
|
+
`POST /run` accepts normal `aimax run` options under `run`. For structured
|
|
22
|
+
message input, pass `run.messages` instead of encoding JSON into `run.message`:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"run": {
|
|
27
|
+
"dataDir": "/data/user1",
|
|
28
|
+
"messages": [
|
|
29
|
+
{
|
|
30
|
+
"role": "user",
|
|
31
|
+
"content": [
|
|
32
|
+
{ "type": "text", "text": "/new" },
|
|
33
|
+
{ "type": "image", "data": "<base64>", "mimeType": "image/png" }
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`run.messages` uses the same structured Message format as `aimax run --from-file`.
|
|
42
|
+
`run.message` remains plain user text and is not JSON-parsed by the server.
|
package/dist/bin.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{t as e}from"./server-
|
|
2
|
+
import{t as e}from"./server-BWdQz0S2.js";function t(e){let t=!1;return()=>{t||(t=!0,n(e))}}async function n(e){let t=e.exit??(e=>process.exit(e)),n=e.onLog??(()=>void 0),a=e.graceMs??3e4,o=e.server.getStatus();if(!r(o)){await e.server.stop().catch(e=>{n(`server shutdown stop failed`,{error:String(e),status:o})}),t(0);return}n(`server shutdown signal received; waiting for active run`,{status:o,graceMs:a}),await e.server.stop().catch(e=>{n(`server shutdown stop failed`,{error:String(e),status:o})});let s=await i(e.server.done,a);if(s.timedOut){n(`server shutdown grace period elapsed before run finished`,{status:o,graceMs:a}),t(1);return}n(`server shutdown completed after active run finished`,{status:o,exitCode:s.exitCode}),t(s.exitCode)}function r(e){return e===`running`||e===`draining`}async function i(e,t){let n,r=new Promise(e=>{n=setTimeout(()=>e({timedOut:!0}),t),n.unref?.()});try{return await Promise.race([e.then(e=>({timedOut:!1,exitCode:e.exitCode})),r])}finally{n&&clearTimeout(n)}}function a(e){let t={};for(let n=0;n<e.length;n+=1){let r=e[n];if(r===`--host`){t.host=e[++n];continue}if(r===`--port`){t.port=o(e[++n],`--port`);continue}if(r===`--plugins-config`){t.pluginsConfig=s(e[++n],`--plugins-config`);continue}if(r===`--request-timeout-ms`){t.requestTimeoutMs=c(e[++n],`--request-timeout-ms`);continue}if(r===`--shutdown-grace-ms`){t.shutdownGraceMs=c(e[++n],`--shutdown-grace-ms`);continue}throw(r===`--help`||r===`-h`)&&(l(),process.exit(0)),Error(`Unknown option: ${r}`)}return t}function o(e,t){let n=c(e,t);if(n>65535)throw Error(`Invalid ${t}: ${e}. Must be between 0 and 65535.`);return n}function s(e,t){if(e===void 0||e.trim()===``)throw Error(`Missing value for ${t}`);return e}function c(e,t){if(e===void 0||e.trim()===``)throw Error(`Missing value for ${t}`);let n=Number(e);if(!Number.isInteger(n)||n<0)throw Error(`Invalid ${t}: ${e}. Must be a non-negative integer.`);return n}function l(){process.stdout.write(`AIMax one-shot prestart server
|
|
3
3
|
|
|
4
4
|
Usage:
|
|
5
|
-
aimax-server [--host 127.0.0.1] [--port 0] [--request-timeout-ms 60000] [--shutdown-grace-ms 30000]
|
|
5
|
+
aimax-server [--host 127.0.0.1] [--port 0] [--plugins-config /image/plugins.json] [--request-timeout-ms 60000] [--shutdown-grace-ms 30000]
|
|
6
6
|
|
|
7
7
|
Environment:
|
|
8
8
|
AIMAX_SERVER_HOST
|
|
9
9
|
AIMAX_SERVER_PORT
|
|
10
|
+
AIMAX_SERVER_PLUGINS_CONFIG
|
|
10
11
|
AIMAX_SERVER_REQUEST_TIMEOUT_MS
|
|
11
12
|
AIMAX_SERVER_SHUTDOWN_GRACE_MS
|
|
12
|
-
`)}async function
|
|
13
|
+
`)}async function u(){let n=a(process.argv.slice(2)),r=e({host:n.host??process.env.AIMAX_SERVER_HOST,port:n.port??(process.env.AIMAX_SERVER_PORT?o(process.env.AIMAX_SERVER_PORT,`AIMAX_SERVER_PORT`):void 0),pluginsConfig:n.pluginsConfig??process.env.AIMAX_SERVER_PLUGINS_CONFIG,requestTimeoutMs:n.requestTimeoutMs??(process.env.AIMAX_SERVER_REQUEST_TIMEOUT_MS?c(process.env.AIMAX_SERVER_REQUEST_TIMEOUT_MS,`AIMAX_SERVER_REQUEST_TIMEOUT_MS`):void 0),onLog:(e,t)=>{process.stderr.write(`${JSON.stringify({level:`info`,message:e,...t})}\n`)}}),i=t({server:r,graceMs:n.shutdownGraceMs??(process.env.AIMAX_SERVER_SHUTDOWN_GRACE_MS?c(process.env.AIMAX_SERVER_SHUTDOWN_GRACE_MS,`AIMAX_SERVER_SHUTDOWN_GRACE_MS`):void 0),onLog:(e,t)=>{process.stderr.write(`${JSON.stringify({level:`info`,message:e,...t})}\n`)}});process.once(`SIGTERM`,i),process.once(`SIGINT`,i),await r.start(),process.stdout.write(`${JSON.stringify({type:`aimax_server_ready`,url:r.getUrl(),status:r.getStatus()})}\n`);let s=await r.done;process.exit(s.exitCode)}u().catch(e=>{process.stderr.write(`${JSON.stringify({level:`error`,message:e.message})}\n`),process.exit(1)});export{};
|
package/dist/index.d.ts
CHANGED
|
@@ -15,12 +15,16 @@ type SystemWarmState = {
|
|
|
15
15
|
type AimaxServerOptions = {
|
|
16
16
|
host?: string;
|
|
17
17
|
port?: number;
|
|
18
|
+
pluginsConfig?: string;
|
|
18
19
|
maxBodyBytes?: number;
|
|
19
20
|
requestTimeoutMs?: number;
|
|
20
21
|
executeRun?: (options: ServerRunOptions) => Promise<void>;
|
|
21
|
-
prepareSystemRuntime?: () => SystemWarmState | Promise<SystemWarmState>;
|
|
22
|
+
prepareSystemRuntime?: (options?: ServerWarmupOptions) => SystemWarmState | Promise<SystemWarmState>;
|
|
22
23
|
onLog?: (message: string, details?: Record<string, unknown>) => void;
|
|
23
24
|
};
|
|
25
|
+
type ServerWarmupOptions = {
|
|
26
|
+
pluginsConfig?: unknown;
|
|
27
|
+
};
|
|
24
28
|
type AimaxServerHandle = {
|
|
25
29
|
start: () => Promise<void>;
|
|
26
30
|
stop: () => Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./server-
|
|
1
|
+
import{t as e}from"./server-BWdQz0S2.js";export{e as createAimaxServer};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import e from"node:http";import t from"node:fs/promises";function n(t={}){let n=t.host??`127.0.0.1`,a=t.port??0,u=t.maxBodyBytes??1048576,p=t.executeRun??s,m=t.prepareSystemRuntime??c,h=t.onLog??(()=>void 0),g=t.pluginsConfig,_=`starting`,v,y,b=null,x=!1,S=()=>void 0,C=new Promise(e=>{S=e});function w(e){x||(x=!0,S(e))}function T(e){_=e,h(`server status changed`,{status:e})}async function E(){let e=b;b=null,!(!e||!e.listening)&&await new Promise((t,n)=>{e.close(e=>{e?n(e):t()})})}async function D(e,t){if(_===`starting`||_===`warming`){f(t,503,{status:_,error:`server is not ready`});return}if(_!==`ready`&&_!==`ready_degraded`){f(t,409,{status:_,error:`server already accepted a run`});return}let n;try{n=i(await d(e,u))}catch(e){f(t,400,{status:_,error:e.message});return}T(`running`),E().catch(e=>{h(`failed to close listener after accepting run`,{error:String(e)})}),f(t,202,{status:_,accepted:!0}),O(n)}async function O(e){let t=0;try{let n=r(e.run,e.env,y);await o(e.env,()=>p(n)),typeof process.exitCode==`number`&&process.exitCode!==0&&(t=process.exitCode),T(`draining`)}catch(e){t=1,h(`run failed`,{error:String(e)}),T(`draining`)}finally{await E().catch(e=>{h(`failed to stop server during drain`,{error:String(e)})}),T(`exiting`),w({exitCode:t})}}async function k(e,t){let r=new URL(e.url??`/`,`http://${n}`);if(e.method===`GET`&&r.pathname===`/healthz`){f(t,200,{status:_});return}if(e.method===`GET`&&r.pathname===`/readyz`){let e=_===`ready`||_===`ready_degraded`;f(t,e?200:503,{status:_,ready:e,degraded:_===`ready_degraded`,warmupError:v});return}if(e.method===`POST`&&r.pathname===`/run`){await D(e,t);return}f(t,404,{status:_,error:`not found`})}async function A(){if(!b){T(`warming`),b=e.createServer((e,t)=>{k(e,t).catch(e=>{f(t,500,{status:_,error:String(e)})})}),await new Promise((e,t)=>{b.once(`error`,t),b.listen(a,n,()=>{b.off(`error`,t),e()})});try{let e=g?await l(g):void 0;e!==void 0&&(y=g),await m({pluginsConfig:e}),_===`warming`&&T(`ready`)}catch(e){v=String(e),h(`system warmup failed; continuing with cold run path`,{error:v}),_===`warming`&&T(`ready_degraded`)}t.requestTimeoutMs&&t.requestTimeoutMs>0&&setTimeout(()=>{(_===`ready`||_===`ready_degraded`)&&E().finally(()=>{T(`exiting`),w({exitCode:1})})},t.requestTimeoutMs).unref()}}function j(){if(!b?.listening)return``;let e=b.address();return`http://${e.address}:${e.port}`}return{start:A,stop:E,done:C,getStatus:()=>_,getUrl:j}}function r(e,t,n){return!n||Object.prototype.hasOwnProperty.call(e,`pluginsConfig`)||t&&Object.prototype.hasOwnProperty.call(t,`AIMAX_PLUGINS_CONFIG`)?e:{...e,pluginsConfig:n}}function i(e){if(!e||typeof e!=`object`)throw Error(`request body must be an object`);let t=e.env;t!==void 0&&a(t);let n=e.run;if(!n||typeof n!=`object`||Array.isArray(n))throw Error(`request body must include run options`);return{env:t,run:n}}function a(e){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`request env must be an object when provided`);for(let[t,n]of Object.entries(e)){if(!t||t.includes(`=`))throw Error(`request env contains invalid key: ${t}`);if(n!==null&&typeof n!=`string`&&typeof n!=`number`&&typeof n!=`boolean`)throw Error(`request env value for ${t} must be string, number, boolean, or null`)}}async function o(e,t){if(!e||Object.keys(e).length===0)return t();let n=new Map;for(let[t,r]of Object.entries(e))n.set(t,process.env[t]),r===null?delete process.env[t]:process.env[t]=String(r);try{return await t()}finally{for(let[e,t]of n)t===void 0?delete process.env[e]:process.env[e]=t}}async function s(e){await(await u(`@gencode/cli`)).executeRun(e)}async function c(e={}){return(await u(`@gencode/agents/system-runtime`)).prepareSystemRuntime({config:e.pluginsConfig})}async function l(e){let n=await t.readFile(e,`utf-8`);return JSON.parse(n)}const u=Function(`specifier`,`return import(specifier)`);async function d(e,t){let n=[],r=0;for await(let i of e){let e=Buffer.isBuffer(i)?i:Buffer.from(i);if(r+=e.byteLength,r>t)throw Error(`request body is too large`);n.push(e)}let i=Buffer.concat(n).toString(`utf-8`);if(!i.trim())throw Error(`request body must not be empty`);try{return JSON.parse(i)}catch{throw Error(`request body must be valid JSON`)}}function f(e,t,n){e.headersSent||(e.writeHead(t,{"content-type":`application/json; charset=utf-8`}),e.end(`${JSON.stringify(n)}\n`))}export{n as t};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gencode/server",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"aimax-server": "./dist/bin.js"
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"access": "public"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@gencode/
|
|
23
|
-
"@gencode/
|
|
22
|
+
"@gencode/cli": "0.15.0",
|
|
23
|
+
"@gencode/agents": "0.17.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/node": "^22.0.0",
|
package/dist/server-BMS-TOVR.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import e from"node:http";function t(t={}){let r=t.host??`127.0.0.1`,s=t.port??0,u=t.maxBodyBytes??1048576,d=t.executeRun??a,f=t.prepareSystemRuntime??o,p=t.onLog??(()=>void 0),m=`starting`,h,g=null,_=!1,v=()=>void 0,y=new Promise(e=>{v=e});function b(e){_||(_=!0,v(e))}function x(e){m=e,p(`server status changed`,{status:e})}async function S(){let e=g;g=null,!(!e||!e.listening)&&await new Promise((t,n)=>{e.close(e=>{e?n(e):t()})})}async function C(e,t){if(m===`starting`||m===`warming`){l(t,503,{status:m,error:`server is not ready`});return}if(m!==`ready`&&m!==`ready_degraded`){l(t,409,{status:m,error:`server already accepted a run`});return}let r;try{r=n(await c(e,u))}catch(e){l(t,400,{status:m,error:e.message});return}x(`running`),S().catch(e=>{p(`failed to close listener after accepting run`,{error:String(e)})}),l(t,202,{status:m,accepted:!0}),w(r)}async function w(e){let t=0;try{await i(e.env,()=>d(e.run)),typeof process.exitCode==`number`&&process.exitCode!==0&&(t=process.exitCode),x(`draining`)}catch(e){t=1,p(`run failed`,{error:String(e)}),x(`draining`)}finally{await S().catch(e=>{p(`failed to stop server during drain`,{error:String(e)})}),x(`exiting`),b({exitCode:t})}}async function T(e,t){let n=new URL(e.url??`/`,`http://${r}`);if(e.method===`GET`&&n.pathname===`/healthz`){l(t,200,{status:m});return}if(e.method===`GET`&&n.pathname===`/readyz`){let e=m===`ready`||m===`ready_degraded`;l(t,e?200:503,{status:m,ready:e,degraded:m===`ready_degraded`,warmupError:h});return}if(e.method===`POST`&&n.pathname===`/run`){await C(e,t);return}l(t,404,{status:m,error:`not found`})}async function E(){if(!g){x(`warming`),g=e.createServer((e,t)=>{T(e,t).catch(e=>{l(t,500,{status:m,error:String(e)})})}),await new Promise((e,t)=>{g.once(`error`,t),g.listen(s,r,()=>{g.off(`error`,t),e()})});try{await f(),m===`warming`&&x(`ready`)}catch(e){h=String(e),p(`system warmup failed; continuing with cold run path`,{error:h}),m===`warming`&&x(`ready_degraded`)}t.requestTimeoutMs&&t.requestTimeoutMs>0&&setTimeout(()=>{(m===`ready`||m===`ready_degraded`)&&S().finally(()=>{x(`exiting`),b({exitCode:1})})},t.requestTimeoutMs).unref()}}function D(){if(!g?.listening)return``;let e=g.address();return`http://${e.address}:${e.port}`}return{start:E,stop:S,done:y,getStatus:()=>m,getUrl:D}}function n(e){if(!e||typeof e!=`object`)throw Error(`request body must be an object`);let t=e.env;t!==void 0&&r(t);let n=e.run;if(!n||typeof n!=`object`||Array.isArray(n))throw Error(`request body must include run options`);return{env:t,run:n}}function r(e){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`request env must be an object when provided`);for(let[t,n]of Object.entries(e)){if(!t||t.includes(`=`))throw Error(`request env contains invalid key: ${t}`);if(n!==null&&typeof n!=`string`&&typeof n!=`number`&&typeof n!=`boolean`)throw Error(`request env value for ${t} must be string, number, boolean, or null`)}}async function i(e,t){if(!e||Object.keys(e).length===0)return t();let n=new Map;for(let[t,r]of Object.entries(e))n.set(t,process.env[t]),r===null?delete process.env[t]:process.env[t]=String(r);try{return await t()}finally{for(let[e,t]of n)t===void 0?delete process.env[e]:process.env[e]=t}}async function a(e){await(await s(`@gencode/cli`)).executeRun(e)}async function o(){return(await s(`@gencode/agents/system-runtime`)).prepareSystemRuntime()}const s=Function(`specifier`,`return import(specifier)`);async function c(e,t){let n=[],r=0;for await(let i of e){let e=Buffer.isBuffer(i)?i:Buffer.from(i);if(r+=e.byteLength,r>t)throw Error(`request body is too large`);n.push(e)}let i=Buffer.concat(n).toString(`utf-8`);if(!i.trim())throw Error(`request body must not be empty`);try{return JSON.parse(i)}catch{throw Error(`request body must be valid JSON`)}}function l(e,t,n){e.headersSent||(e.writeHead(t,{"content-type":`application/json; charset=utf-8`}),e.end(`${JSON.stringify(n)}\n`))}export{t};
|