@fugood/buttress-server 2.25.5-beta.1 → 2.25.6
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/README.md +164 -4
- package/config/function-samples/README.md +2 -0
- package/config/function-samples/bank-note.ts +47 -0
- package/config/function-samples/bank-watch-daemon.ts +63 -0
- package/config/function-samples/run-agent.ts +39 -0
- package/config/sample.toml +22 -0
- package/lib/agent/cli.d.ts +19 -0
- package/lib/agent/client.d.ts +66 -0
- package/lib/agent/config.d.ts +15 -0
- package/lib/agent/context.d.ts +11 -0
- package/lib/agent/loopback.d.ts +21 -0
- package/lib/agent/mcp.d.ts +23 -0
- package/lib/agent/models.d.ts +20 -0
- package/lib/agent/service.d.ts +16 -0
- package/lib/agent/session-fs.d.ts +42 -0
- package/lib/agent/sessions.d.ts +15 -0
- package/lib/agent/tools.d.ts +32 -0
- package/lib/agent/tui.d.ts +17 -0
- package/lib/agent/types.d.ts +123 -0
- package/lib/cli-DrbWX4ea.mjs +22 -0
- package/lib/client-BCBBen9i.mjs +8 -0
- package/lib/config-lP89VahD.mjs +2 -0
- package/lib/functions/bank-subscribe.d.ts +46 -0
- package/lib/functions/bank.d.ts +21 -0
- package/lib/functions/daemons.d.ts +45 -0
- package/lib/functions/executor.d.ts +31 -4
- package/lib/functions/index.d.ts +17 -7
- package/lib/functions/registry.d.ts +7 -1
- package/lib/functions/status.d.ts +49 -1
- package/lib/functions/templates.d.ts +3 -1
- package/lib/functions/types.d.ts +129 -0
- package/lib/index.d.ts +8 -2
- package/lib/index.mjs +263 -48
- package/lib/mlx-bridge.py +681 -0
- package/lib/routes/agents.d.ts +37 -0
- package/lib/routes/anthropic-messages.d.ts +2 -2
- package/lib/routes/index.d.ts +1 -0
- package/lib/routes/openai-compat.d.ts +2 -2
- package/lib/tui-7B7x6A08.mjs +2 -0
- package/lib/types.d.ts +9 -0
- package/lib/utils/cors.check.d.ts +1 -0
- package/lib/utils/cors.d.ts +72 -0
- package/lib/utils/workspaceState.d.ts +9 -0
- package/package.json +9 -6
- package/public/status.html +77 -1
- package/public/lib/index.d.ts +0 -27
- package/public/lib/index.mjs +0 -110
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
export declare const TYPES_FILE_NAME = "buttress-functions.d.ts";
|
|
10
10
|
export declare const TSCONFIG_FILE_NAME = "tsconfig.json";
|
|
11
11
|
export declare const EXAMPLE_FILE_NAME = "_example.ts";
|
|
12
|
-
export declare const
|
|
12
|
+
export declare const EXAMPLE_DAEMON_FILE_NAME = "_example-daemon.ts";
|
|
13
|
+
export declare const TYPES_TEMPLATE = "// Generated by @fugood/buttress-server \u2014 do not edit.\n// Rewritten on every server start to match the running version.\n//\n// Local functions are EXPERIMENTAL: this contract may change between\n// releases \u2014 after a server upgrade, re-read this file for the current shape.\n\n/** Result of `context.spawn(...)`. */\ntype ButtressSpawnResult = {\n /** Exit code, or null when the process was killed by a signal. */\n code: number | null\n signal: NodeJS.Signals | null\n stdout: string | Buffer\n stderr: string | Buffer\n /** True when output hit `maxBuffer` and capture stopped early. */\n truncated: boolean\n}\n\ntype ButtressSpawnOptions = {\n cwd?: string\n /** Merged over the server's own environment. */\n env?: Record<string, string | undefined>\n /** Written to stdin, which is then closed. */\n input?: string | Uint8Array\n /** 'utf8' (default) yields strings; 'buffer' yields Buffers. */\n encoding?: 'utf8' | 'buffer'\n /** Per-stream capture cap in bytes (default 8MB). */\n maxBuffer?: number\n onStdout?: (chunk: Buffer) => void\n onStderr?: (chunk: Buffer) => void\n}\n\ntype ButtressCompletionResult = {\n content: string\n reasoning_content?: string\n tool_calls?: any[]\n interrupted?: boolean\n usage: { prompt_tokens: number; completion_tokens: number; total_tokens: number }\n}\n\ntype ButtressEmbeddingResult = {\n /** Plain numbers, ready for JSON or conversion into a sqlite-vec float32 BLOB. */\n embedding: number[]\n}\n\n/** 'InSubspace' scopes a property to the space; 'Global' is cross-application. */\ntype ButtressBankPropertyMeta = 'InSubspace' | 'Global'\n\ntype ButtressBankProperty = {\n propertyId: string\n meta: ButtressBankPropertyMeta\n definition: Record<string, any> | null\n value: any\n tags: string[] | null\n lastUpdateHash: string | null\n lastUpdateNote: string | null\n lastUpdateKey: string | null\n createAt: string | null\n updateAt: string | null\n}\n\n/**\n * The Bank replaces `value` unconditionally on update \u2014 an omitted `value`\n * clears the stored one. Read-merge first when a partial update is intended.\n */\ntype ButtressBankPropertyInput = {\n propertyId: string\n /** Defaults to 'InSubspace'. */\n meta?: ButtressBankPropertyMeta\n definition?: Record<string, any>\n newDefinitionFallback?: Record<string, any>\n value?: any\n updateNote?: string\n /** Bank defaults upsert to true; pass false to require an existing property. */\n upsert?: boolean\n tags?: string[]\n}\n\ntype ButtressFunctionContext = {\n /**\n * Run a child process. Resolves once it exits \u2014 a non-zero `code` is a\n * normal resolution, so check it yourself. Rejects only when the process\n * cannot be started. Every process a call spawns is killed when the call\n * ends or times out.\n */\n spawn: (\n command: string,\n args?: string[],\n options?: ButtressSpawnOptions,\n ) => Promise<ButtressSpawnResult>\n\n buttress: {\n /**\n * Run a chat completion on this server's LLM generator. `messages` are\n * rendered with the model's own chat template, and thinking is off unless\n * you pass `enable_thinking: true` (which fills `reasoning_content`).\n */\n completion: (options: {\n /** Configured `[[generators]]` model; defaults to the first one. */\n model?: string\n messages?: { role: string; content: any }[]\n /**\n * Raw prompt sent without the chat template \u2014 the fallback for models\n * whose template the server cannot apply. Use instead of `messages`.\n */\n prompt?: string\n /** Cap on generated tokens. Unbounded when omitted. */\n max_tokens?: number\n temperature?: number\n /** Emit the model's reasoning into `reasoning_content` (default false). */\n enable_thinking?: boolean\n /** Called for every streamed token event. */\n onToken?: (event: { token?: string; content?: string; [key: string]: any }) => void\n /** Any other backend sampling option (`top_p`, `stop`, `tools`, \u2026). */\n [param: string]: any\n }) => Promise<ButtressCompletionResult>\n\n /**\n * Embed text with a GGML generator whose `[generators.model]` table sets\n * `embedding = true`. The vector is returned as plain numbers.\n */\n embedding: (options: {\n model?: string\n text: string\n /** llama.cpp normalization mode; 2 (L2) is the native default. */\n embd_normalize?: number\n }) => Promise<ButtressEmbeddingResult>\n\n /** Tokenize text with a configured GGML or MLX generator. */\n tokenize: (options: {\n model?: string\n text: string\n params?: Record<string, any>\n }) => Promise<Record<string, any> & { tokens: number[] }>\n\n /** Turn model token ids back into text. */\n detokenize: (options: { model?: string; tokens: number[] }) => Promise<string>\n\n /** Transcribe audio with this server's STT generator. */\n transcribe: (options: {\n /** Must match a configured STT model (`repo_id` or `repo_id:filename`). */\n model?: string\n filePath?: string\n audioData?: Uint8Array | Buffer\n options?: Record<string, any>\n }) => Promise<any>\n\n /**\n * Synthesize speech with this server's TTS generator (onnx-tts or\n * ggml-tts). The WAV is written into `tempDir`; return\n * `fileUrl(path)` to let callers download it.\n */\n synthesize: (options: {\n /** Must match a configured TTS model when given. */\n model?: string\n text: string\n /** Backend options; `options.speaker` picks a registered voice. */\n options?: Record<string, any>\n }) => Promise<{ path: string; sampling_rate: number; channels: number }>\n }\n\n /**\n * Daemon functions running on this server (files with `meta.daemon`).\n */\n daemons: {\n /**\n * Deliver an event to the named daemon's `context.onEvent` handlers;\n * it arrives as `{ event, data, source }`. Throws when no daemon of\n * that name is running, or when it registered no handler.\n */\n emit: (name: string, event: string, data?: unknown) => void\n /** Names of the daemons currently running. */\n list: () => string[]\n }\n\n /**\n * The bound workspace's remote Data Bank (read/write; daemon functions can\n * also subscribe to changes via `bank.subscribe`). Every method throws\n * until credentials are stored via `bricks buttress bank-key` (run on\n * this host, then restart the server).\n */\n bank: {\n /** List properties, optionally filtered. */\n list: (options?: {\n /** Match against definition title/description or tags. */\n keyword?: string\n meta?: ButtressBankPropertyMeta\n /** Restrict to these property ids. */\n ids?: string[]\n }) => Promise<ButtressBankProperty[]>\n\n /** One property, or null when it does not exist. */\n get: (propertyId: string) => Promise<ButtressBankProperty | null>\n\n /**\n * Create or update properties (upsert by default). Updates notify\n * subscribed devices unless `dontNotify` is set.\n */\n update: (\n properties: ButtressBankPropertyInput[],\n options?: { dontNotify?: boolean },\n ) => Promise<ButtressBankProperty[]>\n\n /** Delete a property. Resolves false when it did not exist. */\n remove: (propertyId: string) => Promise<boolean>\n\n /**\n * Watch property ids for remote changes. Only available inside daemon\n * functions (throws elsewhere); closed automatically when the daemon\n * stops. The connection is shared and reconnects on its own \u2014 a network\n * drop never stops the daemon.\n */\n subscribe: (\n propertyIds: string[],\n onChange: (properties: ButtressBankProperty[]) => unknown,\n ) => { close: () => void }\n }\n\n fetch: typeof fetch\n /** Server-side log, prefixed with the function name. */\n log: (...args: unknown[]) => void\n /** Emit a progress event. Delivered only to SSE callers; a no-op otherwise. */\n emit: (event: string, data?: unknown) => void\n /** Aborted when the call times out or the caller disconnects. */\n signal: AbortSignal\n env: Record<string, string | undefined>\n /**\n * The `[functions.config]` table from the server config. Read once at\n * server start \u2014 unlike function files, config edits need a restart.\n */\n config: Record<string, any>\n /** Per-call scratch directory, created on first access. */\n tempDir: string\n /**\n * Download URL path (`/functions/files/...`) for a file inside `tempDir`;\n * relative input resolves against it. Callers fetch the URL with the same\n * auth as any function call. Scratch dirs are swept after ~24h.\n */\n fileUrl: (target: string) => string\n /** Absolute path of this functions directory. */\n dir: string\n /** Helper libraries: _, lodash, moment, math, mathjs, voca, chroma, json5, qs, bytes, ms, nanoid, md5. */\n libs: Record<string, any>\n}\n\ntype ButtressFunctionMeta = {\n /** Shown to MCP clients in `tools/list`. */\n description?: string\n /** JSON Schema for the input object, passed to MCP verbatim. */\n parameters?: Record<string, any>\n /**\n * Deadline for this function: ms, or a duration string like \"10m\".\n * Ignored for daemons \u2014 a daemon has no deadline.\n */\n timeout?: number | string\n /**\n * `true` declares this file as a daemon: a long-lived background\n * function. Its default export runs once, with a ButtressDaemonContext as\n * its only argument, and stays alive \u2014 everything registered there\n * (`setInterval` timers, `bank.subscribe` subscriptions, `onEvent`\n * handlers) keeps firing until the file changes or the server stops.\n * A daemon is not an MCP tool and cannot be called over HTTP.\n */\n daemon?: boolean\n}\n\n/** An event another local function sent via `context.daemons.emit`. */\ntype ButtressDaemonEmittedEvent = {\n event: string\n data?: unknown\n /** Name of the local function (or daemon) that emitted it. */\n source: string\n}\n\n/**\n * What a daemon's default export receives: the full function context plus\n * lifetime APIs. `context.signal` aborts when the daemon stops (file\n * changed/removed, or server shutdown); an optional cleanup function\n * *returned* by the handler also runs at that point.\n */\ntype ButtressDaemonContext = ButtressFunctionContext & {\n /**\n * A managed `setInterval`: the callback keeps firing until cleared or\n * the daemon stops. A callback that throws is logged (and shown on\n * /status) \u2014 it never stops the timer or the daemon.\n */\n setInterval: (callback: () => unknown, ms: number) => unknown\n clearInterval: (handle: unknown) => void\n /** Receive events other local functions send via `context.daemons.emit`. */\n onEvent: (handler: (event: ButtressDaemonEmittedEvent) => unknown) => void\n}\n\n// --- Custom auth ------------------------------------------------------------\n// Drop an `_auth.ts` into this directory to gate the /functions endpoints\n// with your own logic. It exports the same shape as a function file:\n//\n// export const meta: ButtressAuthMeta = { mode: 'both' }\n// export default async function (\n// request: ButtressAuthRequest,\n// context: ButtressAuthContext,\n// ): Promise<ButtressAuthResult> { ... }\n//\n// While an `_auth` file exists but fails to load, every call is rejected.\n\ntype ButtressAuthMeta = {\n /**\n * 'both' (default): runs after the built-in workspace auth passes, as an\n * extra gate. 'override': replaces workspace auth \u2014 this function is the\n * only authority (a presented workspace token is still verified into\n * `request.workspaceAuth` so you can choose to honor it).\n */\n mode?: 'override' | 'both'\n}\n\ntype ButtressAuthRequest = {\n method: string\n path: string\n /** Function name for `GET`/`POST /functions/<name>`; undefined for list and MCP. */\n name?: string\n headers: Record<string, string | undefined>\n query: Record<string, string | undefined>\n /** Raw bearer token (Authorization header or `?token=`), if any. */\n token: string | null\n workspaceAuth: {\n /** Whether this server is bound to a workspace. */\n bound: boolean\n /** Whether the caller presented a valid workspace access token. */\n authenticated: boolean\n identity: {\n workspaceId: string\n subjectType: 'ws' | 'dev'\n subjectId: string\n jti?: string\n exp: number\n } | null\n }\n}\n\ntype ButtressAuthContext = {\n /** Server-side log, prefixed with \"_auth\". */\n log: (...args: unknown[]) => void\n fetch: typeof fetch\n env: Record<string, string | undefined>\n /** The `[functions.config]` table, same as `context.config` in functions. */\n config: Record<string, any>\n /** Absolute path of this functions directory. */\n dir: string\n /** Same helper libraries functions get. */\n libs: Record<string, any>\n}\n\n/** Only `true` (or `{ ok: true }`) allows the request; anything else denies. */\ntype ButtressAuthResult =\n | boolean\n | {\n ok: boolean\n /** Response status for a denial, 400-499 (default 403). */\n status?: number\n /** Message returned to the caller on denial. */\n error?: string\n }\n\n// The only non-builtin packages the local-function loader accepts. These\n// declarations keep editor support working when this directory is outside the\n// server package's own node_modules resolution tree.\ndeclare module 'sqlite3' {\n type SqliteCallback = (error: Error | null) => void\n\n class Database {\n constructor(filename: string, callback?: SqliteCallback)\n run(sql: string, ...params: any[]): this\n all<T = Record<string, any>>(\n sql: string,\n ...params: [...any[], (error: Error | null, rows: T[]) => void]\n ): this\n exec(sql: string, callback?: SqliteCallback): this\n loadExtension(filename: string, callback?: SqliteCallback): this\n close(callback?: SqliteCallback): void\n }\n\n const sqlite3: { Database: typeof Database }\n export { Database }\n export default sqlite3\n}\n\ndeclare module 'sqlite-vec' {\n export function getLoadablePath(): string\n export function load(database: { loadExtension(path: string): unknown }): void\n}\n";
|
|
13
14
|
export declare const TSCONFIG_TEMPLATE = "{\n // Editor support for Buttress local functions.\n // Install @types/node here for typings on \"node:*\" imports.\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"lib\": [\"ES2023\"],\n \"strict\": true,\n \"noEmit\": true,\n \"allowJs\": true,\n \"skipLibCheck\": true\n },\n \"include\": [\"**/*.ts\", \"**/*.js\"]\n}\n";
|
|
14
15
|
export declare const EXAMPLE_TEMPLATE = "// Example Buttress local function.\n//\n// Rename (or copy) this file to expose it: files starting with \"_\" are\n// ignored. The tool name is the file name \u2014 \"video-duration.ts\" becomes the\n// tool \"video-duration\", callable over MCP, at POST /functions/video-duration\n// with a JSON body, and at GET /functions/video-duration?path=... with the\n// input in the query string.\n\nexport const meta: ButtressFunctionMeta = {\n description: 'Report the duration of a video file using ffprobe',\n parameters: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Absolute path to a video file' },\n },\n required: ['path'],\n },\n timeout: '2m',\n}\n\nexport default async function (\n { path }: { path: string },\n context: ButtressFunctionContext,\n): Promise<{ seconds: number }> {\n const { code, stdout, stderr } = await context.spawn('ffprobe', [\n '-v',\n 'error',\n '-show_entries',\n 'format=duration',\n '-of',\n 'default=noprint_wrappers=1:nokey=1',\n path,\n ])\n\n if (code !== 0) throw new Error(`ffprobe failed (${code}): ${stderr}`)\n\n return { seconds: Number(String(stdout).trim()) }\n}\n";
|
|
16
|
+
export declare const EXAMPLE_DAEMON_TEMPLATE = "// Example Buttress daemon function.\n//\n// Rename (or copy) this file to activate it: files starting with \"_\" are\n// ignored. A file with `meta.daemon = true` runs as a daemon \u2014 a\n// long-lived background function. It is not exposed as an MCP tool or\n// endpoint; its live status shows on /status.\n//\n// The default export runs ONCE when the daemon starts, and everything it\n// registers on the context keeps running after it returns:\n//\n// context.setInterval(cb, ms) periodic work (cleared on stop;\n// a throwing callback never stops it)\n// context.bank.subscribe(ids, cb) Data Bank change notifications\n// (needs `bricks buttress bank-key`)\n// context.onEvent(cb) events from other local functions:\n// context.daemons.emit(name, event, data)\n//\n// The daemon stops when this file changes or the server shuts down:\n// context.signal aborts, timers and subscriptions are cleaned up, and a\n// cleanup function returned here gets a final (bounded) run.\n\nexport const meta: ButtressFunctionMeta = {\n description: 'Log a heartbeat and react to Data Bank changes',\n daemon: true,\n}\n\nexport default async function (context: ButtressDaemonContext) {\n let ticks = 0\n\n context.setInterval(() => {\n ticks += 1\n context.log(`heartbeat #${ticks}`)\n }, 60_000)\n\n // Requires stored Bank credentials \u2014 uncomment after `bricks buttress bank-key`:\n // context.bank.subscribe(['some-property-id'], (properties) => {\n // for (const property of properties) {\n // context.log(`bank property changed: ${property.propertyId}`)\n // }\n // })\n\n context.onEvent(({ event, data, source }) => {\n context.log(`event \"${event}\" from ${source}`, data)\n })\n\n context.log('daemon started')\n return () => context.log(`stopping after ${ticks} tick(s)`)\n}\n";
|
package/lib/functions/types.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { AgentsFunctionApi, AgentsService } from '../agent/types';
|
|
1
2
|
import type { Backend } from '../index';
|
|
2
3
|
import type { Config } from '../types';
|
|
3
4
|
import type { VerifiedIdentity } from '../utils/buttressAuth';
|
|
5
|
+
import type { WorkspaceState } from '../utils/workspaceState';
|
|
4
6
|
/**
|
|
5
7
|
* Declarative metadata a local function file exports alongside its handler.
|
|
6
8
|
*
|
|
@@ -12,6 +14,23 @@ export type FunctionMeta = {
|
|
|
12
14
|
parameters?: Record<string, any>;
|
|
13
15
|
/** Per-function deadline. Number of ms, or an `ms()` string like "10m". */
|
|
14
16
|
timeout?: number | string;
|
|
17
|
+
/**
|
|
18
|
+
* `true` declares the file as a daemon: a long-lived background function.
|
|
19
|
+
* Its default export runs once, with a `DaemonContext`, and stays alive —
|
|
20
|
+
* timers (`context.setInterval`), Data Bank subscriptions
|
|
21
|
+
* (`context.bank.subscribe`) and event handlers (`context.onEvent`) keep
|
|
22
|
+
* firing until the file changes or the server stops. Daemon files are not
|
|
23
|
+
* exposed as MCP tools or callable endpoints, and `timeout` does not apply
|
|
24
|
+
* to them.
|
|
25
|
+
*/
|
|
26
|
+
daemon?: boolean;
|
|
27
|
+
};
|
|
28
|
+
/** An event another local function sent via `context.daemons.emit`. */
|
|
29
|
+
export type DaemonEmittedEvent = {
|
|
30
|
+
event: string;
|
|
31
|
+
data?: unknown;
|
|
32
|
+
/** Name of the local function (or daemon) that emitted it. */
|
|
33
|
+
source: string;
|
|
15
34
|
};
|
|
16
35
|
export type FunctionEmit = (event: string, data?: unknown) => void;
|
|
17
36
|
export type SpawnOptions = {
|
|
@@ -102,6 +121,72 @@ export type SynthesizeResult = {
|
|
|
102
121
|
sampling_rate: number;
|
|
103
122
|
channels: number;
|
|
104
123
|
};
|
|
124
|
+
/** 'InSubspace' scopes a property to the space; 'Global' is cross-application. */
|
|
125
|
+
export type BankPropertyMeta = 'InSubspace' | 'Global';
|
|
126
|
+
export type BankProperty = {
|
|
127
|
+
propertyId: string;
|
|
128
|
+
meta: BankPropertyMeta;
|
|
129
|
+
definition: Record<string, any> | null;
|
|
130
|
+
value: any;
|
|
131
|
+
tags: string[] | null;
|
|
132
|
+
lastUpdateHash: string | null;
|
|
133
|
+
lastUpdateNote: string | null;
|
|
134
|
+
lastUpdateKey: string | null;
|
|
135
|
+
createAt: string | null;
|
|
136
|
+
updateAt: string | null;
|
|
137
|
+
};
|
|
138
|
+
export type BankListOptions = {
|
|
139
|
+
/** Match against definition title/description or tags. */
|
|
140
|
+
keyword?: string;
|
|
141
|
+
meta?: BankPropertyMeta;
|
|
142
|
+
/** Restrict to these property ids. */
|
|
143
|
+
ids?: string[];
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* The Bank replaces `value` unconditionally on update — an omitted `value`
|
|
147
|
+
* clears the stored one. Read-merge first when a partial update is intended.
|
|
148
|
+
*/
|
|
149
|
+
export type BankPropertyInput = {
|
|
150
|
+
propertyId: string;
|
|
151
|
+
/** Defaults to 'InSubspace'. */
|
|
152
|
+
meta?: BankPropertyMeta;
|
|
153
|
+
definition?: Record<string, any>;
|
|
154
|
+
newDefinitionFallback?: Record<string, any>;
|
|
155
|
+
value?: any;
|
|
156
|
+
updateNote?: string;
|
|
157
|
+
/** Bank defaults upsert to true; pass false to require an existing property. */
|
|
158
|
+
upsert?: boolean;
|
|
159
|
+
tags?: string[];
|
|
160
|
+
};
|
|
161
|
+
export type BankUpdateOptions = {
|
|
162
|
+
/** Skip notifying subscribed devices about this update. */
|
|
163
|
+
dontNotify?: boolean;
|
|
164
|
+
};
|
|
165
|
+
/** A live Data Bank change subscription (daemon functions only). */
|
|
166
|
+
export type BankSubscriptionHandle = {
|
|
167
|
+
close: () => void;
|
|
168
|
+
};
|
|
169
|
+
/** Remote Data Bank access for the bound workspace. */
|
|
170
|
+
export type BankContext = {
|
|
171
|
+
list: (options?: BankListOptions) => Promise<BankProperty[]>;
|
|
172
|
+
/** Null when the property does not exist. */
|
|
173
|
+
get: (propertyId: string) => Promise<BankProperty | null>;
|
|
174
|
+
update: (properties: BankPropertyInput[], options?: BankUpdateOptions) => Promise<BankProperty[]>;
|
|
175
|
+
remove: (propertyId: string) => Promise<boolean>;
|
|
176
|
+
/**
|
|
177
|
+
* Watch property ids for remote changes. Only available inside daemon
|
|
178
|
+
* functions — a call-scoped function has no lifetime to attach it to.
|
|
179
|
+
* Closed automatically when the daemon stops.
|
|
180
|
+
*/
|
|
181
|
+
subscribe: (propertyIds: string[], onChange: (properties: BankProperty[]) => void) => BankSubscriptionHandle;
|
|
182
|
+
};
|
|
183
|
+
/** What the executor needs to route `context.daemons` calls. */
|
|
184
|
+
export type DaemonsHub = {
|
|
185
|
+
/** Enqueue an `event` invocation on a running daemon; throws when unknown. */
|
|
186
|
+
emit: (name: string, event: string, data: unknown, source: string) => void;
|
|
187
|
+
/** Names of the daemons currently running. */
|
|
188
|
+
names: () => string[];
|
|
189
|
+
};
|
|
105
190
|
/** The second argument every local function handler receives. */
|
|
106
191
|
export type FunctionContext = {
|
|
107
192
|
spawn: (command: string, args?: string[], options?: SpawnOptions) => Promise<SpawnResult>;
|
|
@@ -114,6 +199,23 @@ export type FunctionContext = {
|
|
|
114
199
|
transcribe: (options: TranscribeOptions) => Promise<any>;
|
|
115
200
|
synthesize: (options: SynthesizeOptions) => Promise<SynthesizeResult>;
|
|
116
201
|
};
|
|
202
|
+
/**
|
|
203
|
+
* Workspace Data Bank (read/write, v1 — no subscribe). Every method throws
|
|
204
|
+
* until credentials are stored via `bricks buttress bank-key`.
|
|
205
|
+
*/
|
|
206
|
+
bank: BankContext;
|
|
207
|
+
/** Signal running daemon functions from any local function (or daemon). */
|
|
208
|
+
daemons: {
|
|
209
|
+
/** Deliver an event to the named daemon. Throws when it is not running. */
|
|
210
|
+
emit: (name: string, event: string, data?: unknown) => void;
|
|
211
|
+
/** Names of the daemons currently running. */
|
|
212
|
+
list: () => string[];
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* Configured agents (see `[[agents]]`). Every method throws when no agents
|
|
216
|
+
* are configured on this server.
|
|
217
|
+
*/
|
|
218
|
+
agents: AgentsFunctionApi;
|
|
117
219
|
fetch: typeof fetch;
|
|
118
220
|
log: (...args: unknown[]) => void;
|
|
119
221
|
emit: FunctionEmit;
|
|
@@ -131,12 +233,30 @@ export type FunctionContext = {
|
|
|
131
233
|
libs: Record<string, any>;
|
|
132
234
|
};
|
|
133
235
|
export type FunctionHandler = (input: any, context: FunctionContext) => any;
|
|
236
|
+
/**
|
|
237
|
+
* The context a daemon's default export receives (as its only argument):
|
|
238
|
+
* everything a function gets, plus lifetime APIs. Registered timers,
|
|
239
|
+
* subscriptions and event handlers stay live after the invocation returns.
|
|
240
|
+
*/
|
|
241
|
+
export type DaemonContext = FunctionContext & {
|
|
242
|
+
/**
|
|
243
|
+
* A managed `setInterval`: the callback keeps firing until cleared or the
|
|
244
|
+
* daemon stops; a callback that throws is logged and never stops the timer.
|
|
245
|
+
*/
|
|
246
|
+
setInterval: (callback: () => unknown, ms: number) => NodeJS.Timeout;
|
|
247
|
+
clearInterval: (handle: NodeJS.Timeout) => void;
|
|
248
|
+
/** Receive events other local functions send via `context.daemons.emit`. */
|
|
249
|
+
onEvent: (handler: (event: DaemonEmittedEvent) => unknown) => void;
|
|
250
|
+
};
|
|
251
|
+
export type DaemonHandler = (context: DaemonContext) => any;
|
|
134
252
|
export type LoadedFunction = {
|
|
135
253
|
name: string;
|
|
136
254
|
file: string;
|
|
137
255
|
meta: FunctionMeta;
|
|
138
256
|
handler: FunctionHandler;
|
|
139
257
|
timeoutMs: number;
|
|
258
|
+
/** True for daemon files (`meta.daemon = true`). */
|
|
259
|
+
daemon?: boolean;
|
|
140
260
|
/** Every file in this function's module graph → mtimeMs when it was loaded. */
|
|
141
261
|
files: Map<string, number>;
|
|
142
262
|
};
|
|
@@ -145,6 +265,11 @@ export type FunctionSummary = {
|
|
|
145
265
|
description: string;
|
|
146
266
|
parameters: Record<string, any>;
|
|
147
267
|
};
|
|
268
|
+
/** What `GET /functions` and the status page report about a daemon. */
|
|
269
|
+
export type DaemonSummary = {
|
|
270
|
+
name: string;
|
|
271
|
+
description: string;
|
|
272
|
+
};
|
|
148
273
|
export type FunctionsConfig = {
|
|
149
274
|
enabled: boolean;
|
|
150
275
|
dir: string;
|
|
@@ -162,6 +287,10 @@ export type FunctionsConfig = {
|
|
|
162
287
|
export type FunctionRuntime = {
|
|
163
288
|
backend: Backend;
|
|
164
289
|
config: Config;
|
|
290
|
+
/** Carries the Data Bank binding; absent means `context.bank` is unconfigured. */
|
|
291
|
+
workspaceState?: WorkspaceState;
|
|
292
|
+
/** Agents service; absent means `context.agents` throws. */
|
|
293
|
+
agents?: AgentsService;
|
|
165
294
|
};
|
|
166
295
|
/** Metadata an `_auth` file exports alongside its authorize handler. */
|
|
167
296
|
export type AuthMeta = {
|
package/lib/index.d.ts
CHANGED
|
@@ -3,10 +3,12 @@ import * as backendCore from '@fugood/buttress-backend-core';
|
|
|
3
3
|
import { AutodiscoverService } from './autodiscover';
|
|
4
4
|
import type { Config } from './types';
|
|
5
5
|
import { compareVersions } from './utils/update';
|
|
6
|
+
import type { AgentsConfig, AgentsService } from './agent/types';
|
|
6
7
|
import type { FunctionsConfig, FunctionsService } from './functions';
|
|
7
8
|
export { startModelDownload } from '@fugood/buttress-backend-core';
|
|
8
9
|
export { processConfig } from './utils/config';
|
|
9
10
|
export { resolveFunctionsConfig } from './functions';
|
|
11
|
+
export { resolveAgentsConfig } from './agent/config';
|
|
10
12
|
export type { FunctionsConfig, FunctionsService } from './functions';
|
|
11
13
|
export declare const checkForUpdates: () => Promise<string | null>;
|
|
12
14
|
export { compareVersions };
|
|
@@ -21,17 +23,21 @@ export interface StartServerOptions {
|
|
|
21
23
|
enableAnthropicMessages?: boolean;
|
|
22
24
|
/** Resolved `[functions]` config; null/omitted leaves the feature off. */
|
|
23
25
|
functions?: FunctionsConfig | null;
|
|
26
|
+
/** Resolved `[[agents]]` config; null/omitted leaves the feature off. */
|
|
27
|
+
agents?: AgentsConfig | null;
|
|
24
28
|
}
|
|
25
|
-
export declare const createServer: ({ backend, router, config, enableOpenAICompat, enableAnthropicMessages, functions: functionsConfig, }: StartServerOptions) => Promise<{
|
|
29
|
+
export declare const createServer: ({ backend, router, config, enableOpenAICompat, enableAnthropicMessages, functions: functionsConfig, agents: agentsConfig, }: StartServerOptions) => Promise<{
|
|
26
30
|
app: AnyElysia;
|
|
27
31
|
config: Config;
|
|
28
32
|
functions: FunctionsService | null;
|
|
33
|
+
agents: AgentsService | null;
|
|
29
34
|
}>;
|
|
30
|
-
export declare const startServer: ({ backend, router, config, enableOpenAICompat, enableAnthropicMessages, functions: functionsConfig, }: StartServerOptions) => Promise<{
|
|
35
|
+
export declare const startServer: ({ backend, router, config, enableOpenAICompat, enableAnthropicMessages, functions: functionsConfig, agents: agentsConfig, }: StartServerOptions) => Promise<{
|
|
31
36
|
app: AnyElysia;
|
|
32
37
|
port: number;
|
|
33
38
|
openaiEnabled: boolean;
|
|
34
39
|
anthropicMessagesEnabled: boolean;
|
|
35
40
|
functions: FunctionsService | null;
|
|
41
|
+
agents: AgentsService | null;
|
|
36
42
|
autoDiscover: AutodiscoverService | null;
|
|
37
43
|
}>;
|