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

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 (73) hide show
  1. package/README.md +439 -10
  2. package/config/function-samples/README.md +1 -0
  3. package/config/function-samples/classify-ticket.ts +73 -0
  4. package/config/function-samples/run-agent.ts +39 -0
  5. package/config/sample.toml +67 -0
  6. package/lib/agent/cli.d.ts +19 -0
  7. package/lib/agent/client.d.ts +66 -0
  8. package/lib/agent/codemode-worker.d.ts +1 -0
  9. package/lib/agent/codemode.d.ts +7 -0
  10. package/lib/agent/config.d.ts +15 -0
  11. package/lib/agent/context.d.ts +11 -0
  12. package/lib/agent/decisions.check.d.ts +1 -0
  13. package/lib/agent/decisions.d.ts +113 -0
  14. package/lib/agent/device-auth.d.ts +3 -0
  15. package/lib/agent/device-tools.d.ts +5 -0
  16. package/lib/agent/loopback.d.ts +21 -0
  17. package/lib/agent/mcp.d.ts +22 -0
  18. package/lib/agent/models.d.ts +22 -0
  19. package/lib/agent/service.d.ts +16 -0
  20. package/lib/agent/sessions.d.ts +30 -0
  21. package/lib/agent/tools.d.ts +35 -0
  22. package/lib/agent/tui.d.ts +17 -0
  23. package/lib/agent/types.d.ts +155 -0
  24. package/lib/cli-KbjOekMI.mjs +22 -0
  25. package/lib/client-qqI-HCOj.mjs +8 -0
  26. package/lib/codemode-C7j8OJ4D.mjs +112 -0
  27. package/lib/codemode-worker.mjs +3 -0
  28. package/lib/command-QjZhpiuj.mjs +38 -0
  29. package/lib/config-DiYweJ2m.mjs +2 -0
  30. package/lib/functions/executor.d.ts +7 -1
  31. package/lib/functions/index.d.ts +3 -1
  32. package/lib/functions/status.d.ts +1 -1
  33. package/lib/functions/templates.d.ts +1 -1
  34. package/lib/functions/types.d.ts +15 -2
  35. package/lib/index.d.ts +12 -5
  36. package/lib/index.mjs +160 -93
  37. package/lib/mcp-DzknURyz.mjs +5 -0
  38. package/lib/mlx-bridge.py +717 -0
  39. package/lib/net-ChIaAlIH.mjs +46 -0
  40. package/lib/protocol-WkPByalT.mjs +468 -0
  41. package/lib/quickjs.wasm +0 -0
  42. package/lib/rolldown-runtime-dTnj95Mm.mjs +2 -0
  43. package/lib/routes/agents.d.ts +66 -0
  44. package/lib/routes/decision-shared.d.ts +28 -0
  45. package/lib/routes/generator-cache.d.ts +3 -1
  46. package/lib/routes/index.d.ts +2 -0
  47. package/lib/routes/llm-shared.d.ts +8 -0
  48. package/lib/routes/openai-compat.d.ts +13 -2
  49. package/lib/routes/openai-decisions.check.d.ts +1 -0
  50. package/lib/routes/openai-decisions.d.ts +97 -0
  51. package/lib/routes/status.d.ts +2 -1
  52. package/lib/routes/tts-shared.d.ts +5 -0
  53. package/lib/routes/typesafe-compat.check.d.ts +1 -0
  54. package/lib/routes/typesafe-compat.d.ts +30 -0
  55. package/lib/services/ggml-decision.d.ts +91 -0
  56. package/lib/services/ggml-llm.d.ts +34 -1
  57. package/lib/services/index.d.ts +3 -0
  58. package/lib/services/register-tts-result.d.ts +4 -0
  59. package/lib/tui-ClNupsCH.mjs +2 -0
  60. package/lib/types.d.ts +56 -2
  61. package/lib/ui/command.d.ts +2 -0
  62. package/lib/ui/host.d.ts +1 -0
  63. package/lib/ui/window-module.d.ts +6 -0
  64. package/lib/utils/SessionFileManager.d.ts +12 -4
  65. package/lib/utils/config.d.ts +3 -3
  66. package/lib/utils/cors.d.ts +1 -0
  67. package/lib/utils/decision-sharing.d.ts +37 -0
  68. package/lib/utils/downloadStatus.d.ts +57 -0
  69. package/lib/utils/hostFacts.d.ts +13 -0
  70. package/lib/utils/workspaceState.d.ts +8 -0
  71. package/lib/wrapper-3PX6qE3t.mjs +7 -0
  72. package/package.json +17 -9
  73. package/public/status.html +219 -1489
@@ -0,0 +1,468 @@
1
+ #!/usr/bin/env node
2
+ const e=256*1024,t=1024*1024,n=16*1024*1024,r=1e5,i=`image expects a non-empty image URL string, an object with image_url, or a raw MCP image block`,a=`(function (bridge, toolsJson, globalsJson, storeJson) {
3
+ "use strict";
4
+
5
+ // Freeze every object reachable from the built-in globals, plus the intrinsics that are only
6
+ // reachable from instances (iterator and generator prototypes, %TypedArray%).
7
+ //
8
+ // Freezing alone breaks ordinary code through the "override mistake": a data property that is
9
+ // read-only on a prototype cannot be assigned on an instance either, so
10
+ // this.name = "MyError" in an Error subclass would throw. Commonly overridden properties
11
+ // become accessors whose setter defines an own property on the instance instead.
12
+ (function lockdown() {
13
+ const OVERRIDABLE = new Set(["constructor", "name", "message", "toString", "toLocaleString", "valueOf", "toJSON"]);
14
+ const seen = new Set([globalThis]);
15
+ const queue = [];
16
+ const add = (value) => {
17
+ if ((typeof value === "object" && value !== null) || typeof value === "function") {
18
+ if (!seen.has(value)) {
19
+ seen.add(value);
20
+ queue.push(value);
21
+ }
22
+ }
23
+ };
24
+
25
+ // Accessors from an object literal have no own prototype object, unlike function expressions,
26
+ // whose prototype.constructor would be converted again without end.
27
+ function allowOverride(object, key, value, enumerable) {
28
+ const { get, set } = Object.getOwnPropertyDescriptor(
29
+ {
30
+ get accessor() {
31
+ return value;
32
+ },
33
+ set accessor(next) {
34
+ if (this === object) {
35
+ throw new TypeError("Cannot assign to read only property '" + String(key) + "' of a built-in");
36
+ }
37
+ if ((typeof this !== "object" || this === null) && typeof this !== "function") return;
38
+ Object.defineProperty(this, key, { value: next, writable: true, enumerable: true, configurable: true });
39
+ },
40
+ },
41
+ "accessor",
42
+ );
43
+ Object.defineProperty(object, key, { get, set, enumerable, configurable: false });
44
+ add(get);
45
+ add(set);
46
+ }
47
+
48
+ for (const key of Reflect.ownKeys(globalThis)) {
49
+ const descriptor = Object.getOwnPropertyDescriptor(globalThis, key);
50
+ add(descriptor.value);
51
+ add(descriptor.get);
52
+ add(descriptor.set);
53
+ if ("value" in descriptor && descriptor.configurable) {
54
+ Object.defineProperty(globalThis, key, { writable: false, configurable: false });
55
+ }
56
+ }
57
+ add(Object.getPrototypeOf(function* () {}));
58
+ add(Object.getPrototypeOf(async function () {}));
59
+ add(Object.getPrototypeOf(async function* () {}));
60
+ add(Object.getPrototypeOf(Int8Array));
61
+ add(Object.getPrototypeOf([][Symbol.iterator]()));
62
+ add(Object.getPrototypeOf(new Map()[Symbol.iterator]()));
63
+ add(Object.getPrototypeOf(new Set()[Symbol.iterator]()));
64
+ add(Object.getPrototypeOf(""[Symbol.iterator]()));
65
+ add(Object.getPrototypeOf(/a/[Symbol.matchAll]("")));
66
+ if (typeof Iterator === "function") {
67
+ if (typeof Iterator.prototype.map === "function") add(Object.getPrototypeOf([].values().map((x) => x)));
68
+ if (typeof Iterator.from === "function") add(Object.getPrototypeOf(Iterator.from({ next() {} })));
69
+ }
70
+
71
+ while (queue.length > 0) {
72
+ const object = queue.pop();
73
+ add(Object.getPrototypeOf(object));
74
+ const descriptors = Object.getOwnPropertyDescriptors(object);
75
+ for (const key of Reflect.ownKeys(descriptors)) {
76
+ const descriptor = descriptors[key];
77
+ if ("value" in descriptor) {
78
+ add(descriptor.value);
79
+ if (
80
+ descriptor.writable &&
81
+ descriptor.configurable &&
82
+ (object === Object.prototype || OVERRIDABLE.has(key))
83
+ ) {
84
+ allowOverride(object, key, descriptor.value, descriptor.enumerable);
85
+ }
86
+ } else {
87
+ add(descriptor.get);
88
+ add(descriptor.set);
89
+ }
90
+ }
91
+ Object.freeze(object);
92
+ }
93
+ })();
94
+ const stringify = JSON.stringify;
95
+ const parse = JSON.parse;
96
+ const promiseThen = Promise.prototype.then;
97
+ const ErrorCtor = Error;
98
+ const TypeErrorCtor = TypeError;
99
+ const RangeErrorCtor = RangeError;
100
+ const pending = new Map();
101
+ let nextId = 1;
102
+ let finished = false;
103
+ // Thrown by exit() to unwind the script after it already reported success.
104
+ const EXIT = Object.freeze({});
105
+
106
+ function done(ok, payload, writes) {
107
+ if (finished) return;
108
+ finished = true;
109
+ bridge("done", ok, payload, writes);
110
+ }
111
+
112
+ function serialize(value) {
113
+ return value === undefined ? undefined : stringify(value);
114
+ }
115
+
116
+ // QuickJS stacks list frames only. Prefix "Name: message" like V8 so the
117
+ // text reads the same as a Node error, and drop this prelude's frames.
118
+ function errorText(error) {
119
+ const head = error.message ? error.name + ": " + error.message : String(error.name);
120
+ const frames =
121
+ typeof error.stack === "string"
122
+ ? error.stack.split("\\n").filter((line) => line.trim() && !line.includes("codemode-prelude.js"))
123
+ : [];
124
+ return [head, ...frames].join("\\n");
125
+ }
126
+
127
+ function format(value) {
128
+ if (typeof value === "string") return value;
129
+ if (value instanceof ErrorCtor) return errorText(value);
130
+ try {
131
+ const json = stringify(value);
132
+ return json === undefined ? String(value) : json;
133
+ } catch {
134
+ return String(value);
135
+ }
136
+ }
137
+
138
+ // The host requires string fields. A script can set an error's name or message to anything, so
139
+ // they are coerced, and a value whose coercion throws gets a placeholder.
140
+ function describeError(error) {
141
+ try {
142
+ if (error instanceof ErrorCtor) {
143
+ return stringify({ name: String(error.name), message: String(error.message), stack: errorText(error) });
144
+ }
145
+ return stringify({ message: String(format(error)) });
146
+ } catch {
147
+ return stringify({ message: "The script threw a value that cannot be described" });
148
+ }
149
+ }
150
+
151
+ function caller(kind, name, spread) {
152
+ return (...args) =>
153
+ new Promise((resolve, reject) => {
154
+ let json;
155
+ try {
156
+ json = serialize(spread ? args : args[0]);
157
+ } catch (error) {
158
+ reject(error);
159
+ return;
160
+ }
161
+ const id = nextId++;
162
+ pending.set(id, { resolve, reject });
163
+ bridge(kind, id, name, json);
164
+ });
165
+ }
166
+
167
+ const tools = Object.create(null);
168
+ const allTools = [];
169
+ for (const { name, jsName, description } of parse(toolsJson)) {
170
+ const fn = caller("call", name);
171
+ // The first tool wins when two names normalize to the same identifier.
172
+ if (!(jsName in tools)) {
173
+ tools[jsName] = fn;
174
+ allTools.push(Object.freeze({ name: jsName, description }));
175
+ }
176
+ if (!(name in tools)) tools[name] = fn;
177
+ }
178
+ Object.freeze(tools);
179
+ Object.freeze(allTools);
180
+
181
+ // Reading a member that does not exist throws an error that names the close matches, instead of
182
+ // a later "not a function". \`in\` checks still work.
183
+ const comparable = (name) => name.toLowerCase().replace(/[^a-z0-9]/g, "");
184
+ function guard(target, label, names, hint) {
185
+ return new Proxy(target, {
186
+ get(object, property, receiver) {
187
+ if (typeof property !== "string" || property in object || property in Object.prototype || property === "then" || property === "toJSON") {
188
+ return Reflect.get(object, property, receiver);
189
+ }
190
+ const wanted = comparable(property);
191
+ const exact = names.filter((name) => comparable(name) === wanted);
192
+ const close = exact.length > 0 ? exact : names.filter((name) => wanted && (comparable(name).includes(wanted) || wanted.includes(comparable(name))));
193
+ let message = label + "." + property + " does not exist.";
194
+ if (close.length > 0) message += " Did you mean " + close.slice(0, 5).map((name) => label + "." + name).join(", ") + "?";
195
+ else if (names.length <= 20) message += " Available: " + names.join(", ") + ".";
196
+ if (hint) message += " " + hint;
197
+ message += ' Check for a member with "' + property + '" in ' + label + ".";
198
+ throw new TypeErrorCtor(message);
199
+ },
200
+ });
201
+ }
202
+ const toolsProxy = guard(
203
+ tools,
204
+ "tools",
205
+ allTools.map((tool) => tool.name),
206
+ "ALL_TOOLS lists every tool; searchTools(query) finds tools by topic.",
207
+ );
208
+
209
+ const namespaces = new Map();
210
+ for (const { name, spread } of parse(globalsJson)) {
211
+ const fn = caller("global", name, spread);
212
+ const dot = name.indexOf(".");
213
+ if (dot === -1) {
214
+ Object.defineProperty(globalThis, name, { value: fn, enumerable: true });
215
+ continue;
216
+ }
217
+ const namespace = name.slice(0, dot);
218
+ if (!namespaces.has(namespace)) namespaces.set(namespace, Object.create(null));
219
+ namespaces.get(namespace)[name.slice(dot + 1)] = fn;
220
+ }
221
+ for (const [namespace, members] of namespaces) {
222
+ Object.freeze(members);
223
+ const value = guard(members, namespace, Object.keys(members));
224
+ Object.defineProperty(globalThis, namespace, { value, enumerable: true });
225
+ }
226
+
227
+ // key -> JSON text. Sizes count key and JSON characters.
228
+ const stored = new Map(Object.entries(parse(storeJson)));
229
+ const writes = new Map();
230
+ let storedChars = 0;
231
+ for (const [key, json] of stored) storedChars += key.length + json.length;
232
+
233
+ const STORE_HINT =
234
+ "store() is for small state such as IDs or summaries. Show images with image(), keep large data in variables, or write it to a file with a tool.";
235
+
236
+ function checkKey(name, key) {
237
+ if (typeof key !== "string") throw new TypeError(name + "() key must be a string");
238
+ }
239
+
240
+ function store(key, value) {
241
+ checkKey("store", key);
242
+ const previous = stored.has(key) ? key.length + stored.get(key).length : 0;
243
+ if (value === undefined) {
244
+ stored.delete(key);
245
+ storedChars -= previous;
246
+ writes.set(key, undefined);
247
+ return;
248
+ }
249
+ let json;
250
+ try {
251
+ json = stringify(value);
252
+ } catch (error) {
253
+ throw new TypeError("store(" + stringify(key) + ") value is not JSON-serializable: " + format(error));
254
+ }
255
+ if (json === undefined) {
256
+ throw new TypeError("store(" + stringify(key) + ") value is not JSON-serializable");
257
+ }
258
+ if (json.length > ${e}) {
259
+ throw new RangeError(
260
+ "store(" + stringify(key) + ") value has " + json.length + " characters of JSON, more than the limit of ${e}. " +
261
+ STORE_HINT,
262
+ );
263
+ }
264
+ const next = storedChars - previous + key.length + json.length;
265
+ if (next > ${t}) {
266
+ throw new RangeError(
267
+ "store is full: stored values would exceed ${t} characters of JSON. Delete keys with store(key, undefined). " +
268
+ STORE_HINT,
269
+ );
270
+ }
271
+ stored.set(key, json);
272
+ storedChars = next;
273
+ writes.set(key, json);
274
+ }
275
+
276
+ function load(key) {
277
+ checkKey("load", key);
278
+ const json = stored.get(key);
279
+ return json === undefined ? undefined : parse(json);
280
+ }
281
+
282
+ function serializeWrites() {
283
+ const entries = [];
284
+ for (const [key, json] of writes) entries.push(json === undefined ? [key] : [key, json]);
285
+ return stringify(entries);
286
+ }
287
+
288
+ Object.defineProperty(globalThis, "store", { value: store, enumerable: true });
289
+ Object.defineProperty(globalThis, "load", { value: load, enumerable: true });
290
+
291
+ let outputChars = 0;
292
+ let outputItems = 0;
293
+
294
+ // Past the output limits the script fails: done() reports the error, so catching it does not
295
+ // resume output, and the host ends the script.
296
+ function output(kind, data, mimeType) {
297
+ if (finished) return;
298
+ outputChars += data.length;
299
+ outputItems++;
300
+ if (outputChars > ${n} || outputItems > ${r}) {
301
+ const error = new RangeErrorCtor(
302
+ "script output exceeded the limit of ${n} characters or ${r} text(), image(), and console calls. " +
303
+ "Print a summary instead, or write large data to a file with a tool.",
304
+ );
305
+ done(false, describeError(error));
306
+ throw error;
307
+ }
308
+ bridge("output", kind, data, mimeType);
309
+ }
310
+
311
+ // Primitives become their string form, everything else JSON.
312
+ function outputText(value) {
313
+ if (value === undefined || value === null || typeof value !== "object" && typeof value !== "function") {
314
+ return String(value);
315
+ }
316
+ const json = stringify(value);
317
+ return json === undefined ? String(value) : json;
318
+ }
319
+
320
+ function text(value) {
321
+ let rendered;
322
+ try {
323
+ rendered = outputText(value);
324
+ } catch (error) {
325
+ throw new TypeErrorCtor(error instanceof ErrorCtor ? error.message : String(error));
326
+ }
327
+ output("text", rendered);
328
+ }
329
+
330
+ function imageUrl(value) {
331
+ if (typeof value === "string") return value;
332
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
333
+ throw new TypeErrorCtor(${JSON.stringify(i)});
334
+ }
335
+ if (value.image_url !== undefined) {
336
+ if (typeof value.image_url !== "string") throw new TypeErrorCtor(${JSON.stringify(i)});
337
+ return value.image_url;
338
+ }
339
+ if (typeof value.type !== "string") throw new TypeErrorCtor(${JSON.stringify(i)});
340
+ if (value.type !== "image") {
341
+ throw new TypeErrorCtor('image only accepts MCP image blocks, got "' + value.type + '"');
342
+ }
343
+ if (typeof value.data !== "string" || value.data === "") throw new TypeErrorCtor("image expected MCP image data");
344
+ if (value.data.toLowerCase().startsWith("data:")) return value.data;
345
+ return "data:;base64," + value.data;
346
+ }
347
+
348
+ // Base64 of the signatures of the formats providers accept inline (PNG, JPEG except
349
+ // JPEG-LS, GIF, "RIFF....WEBP"). Signatures start at byte 0, so their encodings are prefixes.
350
+ const IMAGE_SIGNATURES = [
351
+ ["image/png", /^iVBORw0KGg/],
352
+ ["image/jpeg", /^[/]9j[/](?!9)/],
353
+ ["image/gif", /^R0lGOD[dl]h/],
354
+ ["image/webp", /^UklG.{8}RUJQ/],
355
+ ];
356
+
357
+ function image(value) {
358
+ const url = imageUrl(value);
359
+ if (url === "") throw new TypeErrorCtor(${JSON.stringify(i)});
360
+ const colon = url.indexOf(":");
361
+ const scheme = colon === -1 ? "" : url.slice(0, colon).toLowerCase();
362
+ if (scheme === "http" || scheme === "https") {
363
+ throw new TypeErrorCtor("remote image URLs are not supported in tool outputs. Pass a base64 data URI instead");
364
+ }
365
+ const comma = url.indexOf(",");
366
+ const header = comma === -1 ? [] : url.slice(colon + 1, comma).split(";");
367
+ if (scheme !== "data" || comma === -1 || header.slice(1).every((part) => part.toLowerCase() !== "base64")) {
368
+ throw new TypeErrorCtor("invalid image output. Pass a base64 data URI instead");
369
+ }
370
+ // Providers reject the whole request on a bad image, and a persisted image block would be
371
+ // resent on every later turn. Line breaks from wrapped base64 are dropped. The declared type
372
+ // is ignored in favor of the detected one, as providers also reject mismatches.
373
+ const data = url.slice(comma + 1).replace(/\\s+/g, "");
374
+ if (data.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(data)) {
375
+ throw new TypeErrorCtor("invalid image output. The image data is not valid base64 (truncated or corrupted?)");
376
+ }
377
+ const head = data.slice(0, 16);
378
+ const signature = IMAGE_SIGNATURES.find(([, pattern]) => pattern.test(head));
379
+ if (!signature) {
380
+ throw new TypeErrorCtor("invalid image output. The image data is not a PNG, JPEG, GIF, or WebP image");
381
+ }
382
+ output("image", data, signature[0]);
383
+ }
384
+
385
+ function exit() {
386
+ let writesJson;
387
+ try {
388
+ writesJson = serializeWrites();
389
+ } catch (error) {
390
+ done(false, describeError(error));
391
+ throw EXIT;
392
+ }
393
+ done(true, undefined, writesJson);
394
+ throw EXIT;
395
+ }
396
+
397
+ const console = {};
398
+ for (const level of ["log", "info", "warn", "error", "debug"]) {
399
+ console[level] = (...args) => {
400
+ output("console", args.map(format).join(" "));
401
+ };
402
+ }
403
+ Object.freeze(console);
404
+
405
+ Object.defineProperty(globalThis, "tools", { value: toolsProxy, enumerable: true });
406
+ Object.defineProperty(globalThis, "ALL_TOOLS", { value: allTools, enumerable: true });
407
+ Object.defineProperty(globalThis, "console", { value: console, enumerable: true });
408
+ Object.defineProperty(globalThis, "text", { value: text, enumerable: true });
409
+ Object.defineProperty(globalThis, "image", { value: image, enumerable: true });
410
+ Object.defineProperty(globalThis, "exit", { value: exit, enumerable: true });
411
+
412
+ return {
413
+ settle(id, ok, payload) {
414
+ const entry = pending.get(id);
415
+ if (!entry) return;
416
+ pending.delete(id);
417
+ if (!ok) {
418
+ entry.reject(new ErrorCtor(payload));
419
+ return;
420
+ }
421
+ let value;
422
+ try {
423
+ value = payload === undefined ? undefined : parse(payload);
424
+ } catch (error) {
425
+ entry.reject(error);
426
+ return;
427
+ }
428
+ entry.resolve(value);
429
+ },
430
+ run(fn) {
431
+ let promise;
432
+ try {
433
+ promise = fn(toolsProxy, console);
434
+ } catch (error) {
435
+ done(false, describeError(error));
436
+ return;
437
+ }
438
+ promiseThen.call(
439
+ promise,
440
+ (value) => {
441
+ let json;
442
+ try {
443
+ json = serialize(value);
444
+ } catch (error) {
445
+ done(false, describeError(error));
446
+ return;
447
+ }
448
+ done(true, json, serializeWrites());
449
+ },
450
+ (error) => {
451
+ done(false, describeError(error));
452
+ },
453
+ );
454
+ },
455
+ stalled() {
456
+ if (finished || pending.size > 0) return false;
457
+ done(
458
+ false,
459
+ stringify({
460
+ name: "Error",
461
+ message:
462
+ "The script is waiting on a promise that can never settle: no tool call is pending, and timers do not exist here.",
463
+ }),
464
+ );
465
+ return true;
466
+ },
467
+ };
468
+ })`;function o(e){if(typeof e!=`object`||!e)return!1;let t=e.type;return t===`call`||t===`output`||t===`done`||t===`crash`}function s(e){return typeof e==`object`&&!!e&&e.type===`result`}export{o as n,a as r,s as t};
Binary file
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{createRequire as e}from"node:module";var t=Object.create,n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.getPrototypeOf,o=Object.prototype.hasOwnProperty,s=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),c=(e,t)=>{let r={};for(var i in e)n(r,i,{get:e[i],enumerable:!0});return t||n(r,Symbol.toStringTag,{value:`Module`}),r},l=(e,t,a,s)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var c=i(t),l=0,u=c.length,d;l<u;l++)d=c[l],!o.call(e,d)&&d!==a&&n(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(s=r(t,d))||s.enumerable});return e},u=(e,r,i)=>(i=e==null?{}:t(a(e)),l(r||!e||!e.__esModule?n(i,`default`,{value:e,enumerable:!0}):i,e)),d=e(import.meta.url);export{u as i,c as n,d as r,s as t};
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Agent endpoints (EXPERIMENTAL).
3
+ *
4
+ * GET /agents configured agents: names, plus details
5
+ * (model, tools, MCP server names, limits)
6
+ * POST /agents/:name/run run a prompt; ?stream=1 for SSE events
7
+ * (first a `session` event with the id,
8
+ * then `agent` events, then result/error)
9
+ * GET /agents/:name/sessions newest-first session summaries
10
+ * GET /agents/:name/sessions/:id full transcript (pi messages)
11
+ * POST /agents/:name/sessions/:id/abort abort the active run on a session
12
+ *
13
+ * Configured via [[agents]] tables. These endpoints double as the surface the
14
+ * `bricks-buttress agent` CLI (and future clients) consume.
15
+ *
16
+ * Auth mirrors the functions surface, not the open inference endpoints:
17
+ * agents execute local functions, so an unbound server rejects every call
18
+ * unless `[agents_options] allow_unauthenticated = true`. A bound server
19
+ * accepts workspace JWTs. The server's own ephemeral internal token (also
20
+ * written to the 0600 runtime file for same-host CLIs) is always accepted.
21
+ */
22
+ import { type AgentDefinition, type AgentsService } from '../agent/types';
23
+ /**
24
+ * What a client may show about an agent. MCP servers are listed by name only:
25
+ * their urls, headers, commands and env can hold credentials.
26
+ */
27
+ export declare const describeAgent: (agent: AgentDefinition) => {
28
+ name: string;
29
+ model: string;
30
+ tools: string[];
31
+ mcpServers: string[];
32
+ maxTurns: number;
33
+ localDevices: boolean;
34
+ codemode: boolean;
35
+ decisionModel: string | null;
36
+ };
37
+ export type ToolResultSummary = {
38
+ text: string | null;
39
+ images: number;
40
+ truncated: boolean;
41
+ };
42
+ /**
43
+ * A tool result for the wire: its text (bounded) and how many images it holds.
44
+ * Image bytes never go out; the transcript endpoint has the full result.
45
+ *
46
+ * pi passes the tool's own return value: normally `{ content: (text | image)[] }`,
47
+ * but untyped tools may return a bare string or no content at all.
48
+ */
49
+ export declare const summarizeToolResult: (result: unknown) => ToolResultSummary;
50
+ /**
51
+ * Slim pi agent events for the wire. `message_update` carries the FULL partial
52
+ * assistant message on every delta — per-token that would dwarf the payload —
53
+ * and tool results can be huge (`tool_execution_end` carries a bounded text
54
+ * summary); clients that want the full transcript fetch it from the sessions
55
+ * endpoint afterwards.
56
+ */
57
+ export declare const slimAgentEvent: (event: any) => unknown;
58
+ export declare function streamAgentRun(agents: AgentsService, name: string, body: {
59
+ prompt: string;
60
+ sessionId?: string;
61
+ fork?: boolean;
62
+ }, signal: AbortSignal | undefined): AsyncGenerator<{
63
+ readonly event: string;
64
+ readonly data: string;
65
+ }, void, unknown>;
66
+ export default function factory(agents: AgentsService): import("../types").ButtressApp;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Typed decisions on the sessionless paths (local functions, the
3
+ * TypeSafe-compatible endpoint).
4
+ *
5
+ * Mirrors tts-shared: a module-scoped warm-generator cache, reference-counted
6
+ * by in-flight requests. An unmatched model is an error rather than a
7
+ * substitution — another decision model would answer with different
8
+ * calibration, which the caller cannot detect.
9
+ *
10
+ * A decision model that is also configured as a `ggml-llm` runs on that
11
+ * generator's context (see utils/decision-sharing.ts).
12
+ */
13
+ import type { DecisionRequest, DecisionResult } from '../types';
14
+ /** Configured generators that answer decisions, in config order. */
15
+ export declare const isDecisionGenerator: (generator: any) => boolean;
16
+ /**
17
+ * Decision model ids configured more than once. Sessions tell such entries
18
+ * apart (revision, rank pooling, projector), but the sessionless paths select
19
+ * by id and always resolve to the first, so this is a startup warning only.
20
+ */
21
+ export declare const findDuplicateDecisionIds: (config: any) => string[];
22
+ /**
23
+ * Answer typed questions about a state with a warm decision generator,
24
+ * releasing it afterwards. The backend validates the request.
25
+ */
26
+ export declare function decideWith(backend: any, config: any, { model, ...request }: DecisionRequest & {
27
+ model?: string;
28
+ }, logPrefix?: string): Promise<DecisionResult>;
@@ -31,6 +31,8 @@ export type GeneratorCacheOptions = {
31
31
  resolve: (config: any, requestedModel?: string) => ResolvedGeneratorRequest;
32
32
  /** Post-start preparation (typically `initContext`). */
33
33
  prepare: (backend: any, entry: GeneratorCacheEntry) => Promise<void>;
34
+ /** Undo `prepare` before an evicted entry is finalized, when finalizing alone does not. */
35
+ dispose?: (backend: any, entry: GeneratorCacheEntry) => Promise<void>;
34
36
  };
35
37
  type ConfiguredGeneratorResolverOptions = {
36
38
  family: string;
@@ -47,7 +49,7 @@ export declare const configuredGeneratorModelId: (generatorConfig: any) => strin
47
49
  * of silently loading different weights or voices.
48
50
  */
49
51
  export declare const createConfiguredGeneratorResolver: ({ family, types }: ConfiguredGeneratorResolverOptions) => (config: any, requestedModel?: string) => ResolvedGeneratorRequest;
50
- export declare const createGeneratorCache: ({ max, resolve, prepare }: GeneratorCacheOptions) => {
52
+ export declare const createGeneratorCache: ({ max, resolve, prepare, dispose }: GeneratorCacheOptions) => {
51
53
  getOrCreate: (backend: any, config: any, requestedModel: string | undefined, logPrefix: string) => Promise<GeneratorCacheEntry>;
52
54
  release: (backend: any, entry: GeneratorCacheEntry | null | undefined, logPrefix: string) => Promise<void>;
53
55
  };
@@ -3,4 +3,6 @@ export { default as file } from './file';
3
3
  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
+ export { default as typesafeCompatFactory } from './typesafe-compat';
6
7
  export { default as functionsFactory } from './functions';
8
+ export { default as agentsFactory } from './agents';
@@ -9,6 +9,7 @@ import type { GeneratorCacheEntry } from './generator-cache';
9
9
  export type { GeneratorCacheEntry };
10
10
  export { cancelReaderBestEffort } from './generator-cache';
11
11
  export declare const LLM_TYPES: string[];
12
+ export declare const resolveConfiguredLlm: (config: any, requestedModel?: string) => import("./generator-cache").ResolvedGeneratorRequest;
12
13
  /**
13
14
  * Backend options every `messages`-shaped completion needs.
14
15
  *
@@ -47,6 +48,13 @@ export declare function extractTokenCounts(eventData: Record<string, any>): {
47
48
  cachedTokens: number;
48
49
  completionTokens: number;
49
50
  };
51
+ /**
52
+ * Whether generation stopped because it ran out of room: the max-token budget
53
+ * or a full context. llama.node reports the budget as `stopped_limit` from
54
+ * parallel completion (what ggml-llm uses) and `stopped_limited` from a single
55
+ * completion.
56
+ */
57
+ export declare function stoppedAtLimit(eventData: Record<string, any>): boolean;
50
58
  /**
51
59
  * Extract token usage in OpenAI format from backend event data.
52
60
  */
@@ -1,6 +1,7 @@
1
1
  /**
2
- * OpenAI-compatible API endpoints for ggml-llm (EXPERIMENTAL)
3
- * Provides /oai-compat/v1/chat/completions and /oai-compat/v1/models endpoints
2
+ * OpenAI-compatible API endpoints for ggml-llm and ggml-decision (EXPERIMENTAL)
3
+ * Provides /oai-compat/v1/chat/completions, /oai-compat/v1/decisions and
4
+ * /oai-compat/v1/models endpoints
4
5
  *
5
6
  * Enable via TOML config: [openai_compat] enabled = true
6
7
  *
@@ -14,4 +15,14 @@ import type { EventStream } from '../types';
14
15
  export declare function streamChatCompletion(completionStream: ReadableStream<EventStream>, completionId: string, created: number, modelId: string, includeUsage: boolean): AsyncGenerator<{
15
16
  readonly data: string;
16
17
  }, void, unknown>;
18
+ /**
19
+ * Model id -> what this server can do with it, from the config alone (no model
20
+ * load), in the `architecture` shape that llama.cpp server and OpenRouter
21
+ * publish: `text` output means chat completions, `decisions` means
22
+ * `/v1/decisions`. Clients should test membership and ignore unknown values.
23
+ */
24
+ export declare const collectModelArchitectures: (generators: any[]) => Map<string, {
25
+ input_modalities: string[];
26
+ output_modalities: string[];
27
+ }>;
17
28
  export default function factory(): import("../types").ButtressApp;
@@ -0,0 +1 @@
1
+ export {};