libfx 0.0.7 → 0.0.8-dev.857.gba60fd94fa57

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/skills.js ADDED
@@ -0,0 +1,44 @@
1
+ const maxSkills = 64;
2
+ const maxInstructionsBytes = 64 * 1024;
3
+
4
+ function escapeAttribute(value) {
5
+ return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;");
6
+ }
7
+
8
+ export function createSkillsAdapter(records) {
9
+ if (!Array.isArray(records) || records.length > maxSkills) {
10
+ throw new TypeError("skills must be an array with at most 64 records");
11
+ }
12
+ const names = new Set();
13
+ const sections = [];
14
+ const tools = [];
15
+ for (const [index, record] of records.entries()) {
16
+ if (!record || typeof record.name !== "string" || typeof record.instructions !== "string") {
17
+ throw new TypeError(`skill ${index} requires name and instructions`);
18
+ }
19
+ if (names.has(record.name)) throw new TypeError(`duplicate skill name: ${record.name}`);
20
+ names.add(record.name);
21
+ const resources = (record.resources ?? []).map((resource) => {
22
+ if (typeof resource?.uri !== "string" || typeof resource?.text !== "string") {
23
+ throw new TypeError(`skill ${record.name} has an invalid resource`);
24
+ }
25
+ return `<resource uri="${escapeAttribute(resource.uri)}">\n${resource.text}\n</resource>`;
26
+ }).join("\n");
27
+ sections.push([
28
+ `<skill name="${escapeAttribute(record.name)}">`,
29
+ record.description ? `<description>${record.description}</description>` : "",
30
+ record.instructions,
31
+ resources,
32
+ "</skill>",
33
+ ].filter(Boolean).join("\n"));
34
+ if (record.tools !== undefined) {
35
+ if (!Array.isArray(record.tools)) throw new TypeError(`skill ${record.name} tools must be an array`);
36
+ tools.push(...record.tools);
37
+ }
38
+ }
39
+ const instructions = sections.join("\n\n");
40
+ if (new TextEncoder().encode(instructions).length > maxInstructionsBytes) {
41
+ throw new RangeError(`skill instructions exceed the ${maxInstructionsBytes} byte libfx limit`);
42
+ }
43
+ return { instructions, tools };
44
+ }
package/wasm-module.js ADDED
@@ -0,0 +1,50 @@
1
+ const modulePromisesBySource = new Map();
2
+ const modulePromisesByObject = new WeakMap();
3
+ const moduleFailureSource = Symbol("libfx.moduleFailureSource");
4
+
5
+ export function withModuleFailure(input, onFailure) {
6
+ return { [moduleFailureSource]: { input, onFailure } };
7
+ }
8
+
9
+ async function compileModule(input) {
10
+ const failureSource = input?.[moduleFailureSource];
11
+ if (failureSource) {
12
+ try {
13
+ return await compileModule(failureSource.input);
14
+ } catch (error) {
15
+ failureSource.onFailure();
16
+ throw error;
17
+ }
18
+ }
19
+ if (input instanceof WebAssembly.Module) return input;
20
+ if (typeof input === "string") input = fetch(input);
21
+ if (input instanceof Promise) input = await input;
22
+ if (input instanceof WebAssembly.Module) return input;
23
+ if (input instanceof Response) {
24
+ const contentType = input.headers.get("content-type")?.split(";", 1)[0].trim().toLowerCase();
25
+ if (contentType === "application/wasm" && typeof WebAssembly.compileStreaming === "function") {
26
+ return WebAssembly.compileStreaming(input);
27
+ }
28
+ const bytes = await input.arrayBuffer();
29
+ return WebAssembly.compile(bytes);
30
+ }
31
+ if (input instanceof ArrayBuffer || ArrayBuffer.isView(input)) {
32
+ return WebAssembly.compile(input);
33
+ }
34
+ throw new TypeError("wasm must be a URL, Response, ArrayBuffer, typed array, or WebAssembly.Module");
35
+ }
36
+
37
+ export function loadModule(input) {
38
+ if (input instanceof WebAssembly.Module) return Promise.resolve(input);
39
+ const isString = typeof input === "string";
40
+ if (!isString && (typeof input !== "object" || input === null)) return compileModule(input);
41
+ const cache = isString ? modulePromisesBySource : modulePromisesByObject;
42
+ const cached = cache.get(input);
43
+ if (cached) return cached;
44
+ const pending = compileModule(input);
45
+ cache.set(input, pending);
46
+ pending.catch(() => {
47
+ if (cache.get(input) === pending) cache.delete(input);
48
+ });
49
+ return pending;
50
+ }