@fugood/buttress-server 2.26.0-beta.3 → 2.26.0-beta.4

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.
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Agent endpoints (EXPERIMENTAL).
3
+ *
4
+ * GET /agents configured agent names
5
+ * POST /agents/:name/run run a prompt; ?stream=1 for SSE events
6
+ * (first a `session` event with the id,
7
+ * then `agent` events, then result/error)
8
+ * GET /agents/:name/sessions newest-first session summaries
9
+ * GET /agents/:name/sessions/:id full transcript (pi messages)
10
+ * POST /agents/:name/sessions/:id/abort abort the active run on a session
11
+ *
12
+ * Configured via [[agents]] tables. These endpoints double as the surface the
13
+ * `bricks-buttress agent` CLI (and future clients) consume.
14
+ *
15
+ * Auth mirrors the functions surface, not the open inference endpoints:
16
+ * agents execute local functions, so an unbound server rejects every call
17
+ * unless `[agents_options] allow_unauthenticated = true`. A bound server
18
+ * accepts workspace JWTs. The server's own ephemeral internal token (also
19
+ * written to the 0600 runtime file for same-host CLIs) is always accepted.
20
+ */
21
+ import { type AgentsService } from '../agent/types';
22
+ /**
23
+ * Slim pi agent events for the wire. `message_update` carries the FULL partial
24
+ * assistant message on every delta — per-token that would dwarf the payload —
25
+ * and tool results can be huge; clients that want the transcript fetch it
26
+ * from the sessions endpoint afterwards.
27
+ */
28
+ export declare const slimAgentEvent: (event: any) => unknown;
29
+ export declare function streamAgentRun(agents: AgentsService, name: string, body: {
30
+ prompt: string;
31
+ sessionId?: string;
32
+ fork?: boolean;
33
+ }, signal: AbortSignal | undefined): AsyncGenerator<{
34
+ readonly event: string;
35
+ readonly data: string;
36
+ }, void, unknown>;
37
+ export default function factory(agents: AgentsService): import("../types").ButtressApp;
@@ -4,3 +4,4 @@ export { default as status } from './status';
4
4
  export { default as openaiCompatFactory } from './openai-compat';
5
5
  export { default as anthropicMessagesFactory } from './anthropic-messages';
6
6
  export { default as functionsFactory } from './functions';
7
+ export { default as agentsFactory } from './agents';
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{i as e}from"./client-Dk7Dx_vo.mjs";import{Container as t,Editor as n,Loader as r,Markdown as i,ProcessTerminal as a,Text as o,TuiMainScreen as s}from"@earendil-works/pi-tui";const c=e=>t=>`\x1b[${e}m${t}\x1b[0m`,l=c(`2`),u=c(`1`),d=c(`36`),f=c(`33`),p=c(`31`),m=c(`32`),h=c(`35`),g={heading:e=>u(d(e)),link:d,linkUrl:e=>l(d(e)),code:f,codeBlock:f,codeBlockBorder:l,quote:l,quoteBorder:l,hr:l,listBullet:d,bold:u,italic:c(`3`),strikethrough:c(`9`),underline:c(`4`)},_={borderColor:l,selectList:{selectedPrefix:d,selectedText:u,description:l,scrollInfo:l,noMatch:l}},v=(e,t)=>e.length>t?`${e.slice(0,t)}…`:e;var y=class{tui;chat;thinking=null;thinkingBuffer=``;answer=null;answerBuffer=``;constructor(e,t){this.tui=e,this.chat=t}touch(){this.tui.requestRender()}appendThinking(e){this.thinking||(this.thinking=new o(``,0,0),this.chat.addChild(this.thinking)),this.thinkingBuffer+=e,this.thinking.setText(l(this.thinkingBuffer.trimEnd())),this.touch()}appendAnswer(e){this.answer||(this.answer=new i(``,0,0,g),this.chat.addChild(this.answer)),this.answerBuffer+=e,this.answer.setText(this.answerBuffer),this.touch()}addLine(e){this.answer=null,this.answerBuffer=``,this.chat.addChild(new o(e,0,0)),this.touch()}};const b=async({connection:i,agentName:c,sessionId:g,fork:b})=>{let x=new a,S=new s(x);x.setTitle(`buttress agent · ${c}`);let C=new t,w=new o(``,0,0),T=new n(S,_);S.addChild(C),S.addChild(w),S.addChild(T),S.setFocus(T);let E=g,D=b,O=null,k=null,A=e=>{w.setText(e),S.requestRender()},j=()=>{k||(k=new r(S,d,l,`thinking…`),C.addChild(k),S.requestRender())},M=()=>{k&&(C.removeChild(k),k=null,S.requestRender())},N=`${u(c)} ${l(`@ ${i.baseUrl}`)}`+(E?` ${l(`(${D?`forking`:`continuing`} ${E})`)}`:``);C.addChild(new o(N,0,0)),A(l(`Enter to send · /new fresh session · /exit or Ctrl+C to quit`));let P=async()=>{S.stop(),await x.drainInput().catch(()=>{}),process.exit(0)};S.addInputListener(e=>{if(e===``)return O?(O.abort(),O=null,{consume:!0}):(P(),{consume:!0})});let F=async t=>{C.addChild(new o(`${d(`>`)} ${t}`,0,0));let n=new y(S,C);O=new AbortController,j(),A(l(`running · Ctrl+C aborts this turn`));let r;try{r=await e(i,c,{prompt:t,sessionId:E??void 0,fork:D},{signal:O.signal,onFrame:({event:e,payload:t})=>{if(e===`session`&&t?.sessionId){t.sessionId!==E&&(E=t.sessionId,C.addChild(new o(l(`session ${E}`),0,0)));return}if(e!==`agent`)return;M();let r=t?.event;if(t?.type===`message_update`&&r)r.type===`thinking_delta`?n.appendThinking(r.delta??``):r.type===`text_delta`&&n.appendAnswer(r.delta??``);else if(t?.type===`tool_execution_start`){let e=JSON.stringify(t.args??{});n.addLine(`${f(`⚙ ${t.toolName}`)}${l(`(${v(e,120)})`)}`)}else t?.type===`tool_execution_end`?n.addLine(t.isError?p(`✗ ${t.toolName} failed`):l(`✓ ${t.toolName}`)):t?.type===`tool_emit`&&n.addLine(l(` ${t.toolName} → ${t.event}`))}})}catch(e){r={kind:`error`,message:e?.message||String(e),sessionId:E}}if(M(),O=null,D=!1,r.kind===`result`){let{result:e}=r;E=e.sessionId??E;let t=e.usage||{};C.addChild(new o(l(`— ${e.stopReason} · ${t.totalTurns??`?`} turn(s) · ${t.input??0} in / ${t.output??0} out · session ${E}`),0,0))}else r.kind===`aborted`?(E=r.sessionId??E,C.addChild(new o(f(`(aborted — session is continuable)`),0,0))):r.kind===`error`?(E=r.sessionId??E,C.addChild(new o(p(`Run failed: ${r.message}`),0,0))):C.addChild(new o(p(`Connection lost mid-run.`),0,0));A(l(`Enter to send · /new fresh session · /exit or Ctrl+C to quit`)),S.requestRender()};T.onSubmit=e=>{let t=e.trim();if(T.setText(``),t){if(O){A(f(`A turn is still running — Ctrl+C aborts it.`));return}if(t===`/exit`||t===`/quit`){P();return}if(t===`/new`){E=null,D=!1,C.addChild(new o(`${m(`•`)} ${l(`started a fresh session`)}`,0,0)),S.requestRender();return}if(t===`/session`){C.addChild(new o(l(E?`session ${E}`:`no session yet`),0,0)),S.requestRender();return}F(t)}},C.addChild(new o(l(h(`ready`)),0,0)),S.start(),await new Promise(()=>{})};export{b as runAgentTui};
package/lib/types.d.ts CHANGED
@@ -53,6 +53,10 @@ export type GlobalConfig = {
53
53
  config?: Record<string, any>;
54
54
  cors_allowed_origins?: string | string[];
55
55
  };
56
+ /** `[[agents]]` tables; validated by `agent/config.ts` at startup. */
57
+ agents?: Record<string, any>[];
58
+ /** `[agents_options]`: sessions_dir, retention, max_depth, allow_unauthenticated. */
59
+ agents_options?: Record<string, any>;
56
60
  } & Record<string, any>;
57
61
  export type AutodiscoverConfig = {
58
62
  udp: {
@@ -135,6 +139,11 @@ export type ServerInfo = {
135
139
  enabled: boolean;
136
140
  count: number;
137
141
  };
142
+ /** Agent surface: a flag and a count, for the same ANNOUNCE-size reason. */
143
+ agents?: {
144
+ enabled: boolean;
145
+ count: number;
146
+ };
138
147
  };
139
148
  export type EventStream = {
140
149
  event: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fugood/buttress-server",
3
- "version": "2.26.0-beta.3",
3
+ "version": "2.26.0-beta.4",
4
4
  "main": "lib/index.mjs",
5
5
  "types": "lib/index.d.ts",
6
6
  "type": "module",
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "scripts": {
21
21
  "typecheck": "tsc --noEmit",
22
- "build": "tsdown -c rolldown.config.js --config-loader native && tsc --noCheck --emitDeclarationOnly",
22
+ "build": "tsdown -c rolldown.config.js --config-loader native && tsc --noCheck --emitDeclarationOnly && cp ../buttress-backend-core/src/backends/mlx-bridge.py lib/mlx-bridge.py",
23
23
  "build:dist": "$npm_execpath scripts/build-distribution.js",
24
24
  "release": "$npm_execpath scripts/build-distribution.js",
25
25
  "release-beta": "$npm_execpath scripts/build-distribution.js --beta",
@@ -37,9 +37,12 @@
37
37
  ],
38
38
  "license": "MIT",
39
39
  "dependencies": {
40
+ "@earendil-works/pi-agent-core": "^0.84.3",
41
+ "@earendil-works/pi-ai": "0.84.3",
42
+ "@earendil-works/pi-tui": "^0.84.4",
40
43
  "@elysiajs/cors": "^1.1.1",
41
44
  "@elysiajs/node": "^1.4.2",
42
- "@fugood/llama.node": "^1.8.0-rc.4",
45
+ "@fugood/llama.node": "^1.8.0-rc.5",
43
46
  "@fugood/whisper.node": "^1.1.3",
44
47
  "@huggingface/gguf": "^0.3.2",
45
48
  "@iarna/toml": "^3.0.0",
@@ -69,5 +72,5 @@
69
72
  "tsdown": "^0.22.4",
70
73
  "typescript": "^7.0.2"
71
74
  },
72
- "gitHead": "5fb0097f14368552386fb4f3ebd4c53ab9de89e2"
75
+ "gitHead": "13b0d97e181e2d090b6df915b446c4f7673af04f"
73
76
  }