sideagent 0.0.0-stage → 0.1.0
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 +131 -2
- package/dist/index.d.ts +97 -0
- package/dist/index.js +742 -0
- package/dist/protocol.d.ts +87 -0
- package/dist/protocol.js +0 -0
- package/dist/server/browser.d.ts +2 -0
- package/dist/server/browser.js +4 -0
- package/dist/server/index.d.ts +247 -0
- package/dist/server/index.js +1113 -0
- package/dist/testing/mock-llm.d.ts +7 -0
- package/dist/testing/mock-llm.js +84 -0
- package/package.json +66 -4
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
declare function mockLlmHandler(request: Request): Promise<Response>;
|
|
2
|
+
/** Deterministic bag-of-words embedding: texts that share words get similar vectors. */
|
|
3
|
+
declare function mockEmbed(text: string): number[];
|
|
4
|
+
/** Scripted OpenAI-compatible /embeddings endpoint for tests and demos. */
|
|
5
|
+
declare function mockEmbeddingsHandler(request: Request): Promise<Response>;
|
|
6
|
+
|
|
7
|
+
export { mockEmbed, mockEmbeddingsHandler, mockLlmHandler };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// src/testing/mock-llm.ts
|
|
2
|
+
function script(messages, forced) {
|
|
3
|
+
if (forced) return { call: { name: forced, args: {} } };
|
|
4
|
+
const last = messages[messages.length - 1];
|
|
5
|
+
if (!last) return { text: "..." };
|
|
6
|
+
if (last.role === "tool") return { text: `Done. Result: ${String(last.content).slice(0, 120)}` };
|
|
7
|
+
const text = String(last.content ?? "");
|
|
8
|
+
const explicit = /CALL (\S+)\s*(\{.*\})?/s.exec(text);
|
|
9
|
+
if (explicit) return { call: { name: explicit[1], args: explicit[2] ? JSON.parse(explicit[2]) : {} } };
|
|
10
|
+
if (/\b(policy|refunds?|terms|docs|warranty)\b/i.test(text)) return { call: { name: "search_knowledge", args: { query: text } } };
|
|
11
|
+
if (/\blist\b/i.test(text)) return { call: { name: "listInvoices", args: {} } };
|
|
12
|
+
if (/\bcreate\b/i.test(text)) return { call: { name: "createInvoice", args: { body: { customer: "Acme", amount: 100 } } } };
|
|
13
|
+
if (/\bdelete\b/i.test(text)) return { call: { name: "deleteInvoice", args: { id: "1" } } };
|
|
14
|
+
return { text: "Hello from the mock model." };
|
|
15
|
+
}
|
|
16
|
+
async function mockLlmHandler(request) {
|
|
17
|
+
const body = await request.json();
|
|
18
|
+
const { text, call } = script(body.messages, body.tool_choice?.function?.name);
|
|
19
|
+
const id = `chatcmpl-mock-${crypto.randomUUID()}`;
|
|
20
|
+
const base = { id, object: "chat.completion.chunk", created: 0, model: "mock" };
|
|
21
|
+
if (!body.stream) {
|
|
22
|
+
return Response.json({
|
|
23
|
+
id,
|
|
24
|
+
object: "chat.completion",
|
|
25
|
+
created: 0,
|
|
26
|
+
model: "mock",
|
|
27
|
+
choices: [
|
|
28
|
+
{
|
|
29
|
+
index: 0,
|
|
30
|
+
finish_reason: call ? "tool_calls" : "stop",
|
|
31
|
+
message: call ? { role: "assistant", content: null, tool_calls: [{ id: "call_1", type: "function", function: { name: call.name, arguments: JSON.stringify(call.args) } }] } : { role: "assistant", content: text }
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
const chunks = [{ ...base, choices: [{ index: 0, delta: { role: "assistant", content: "" } }] }];
|
|
37
|
+
if (call) {
|
|
38
|
+
chunks.push({
|
|
39
|
+
...base,
|
|
40
|
+
choices: [{ index: 0, delta: { tool_calls: [{ index: 0, id: `call_${Math.random().toString(36).slice(2, 8)}`, type: "function", function: { name: call.name, arguments: JSON.stringify(call.args) } }] } }]
|
|
41
|
+
});
|
|
42
|
+
chunks.push({ ...base, choices: [{ index: 0, delta: {}, finish_reason: "tool_calls" }] });
|
|
43
|
+
} else {
|
|
44
|
+
for (const w of (text ?? "").split(/(?<= )/)) chunks.push({ ...base, choices: [{ index: 0, delta: { content: w } }] });
|
|
45
|
+
chunks.push({ ...base, choices: [{ index: 0, delta: {}, finish_reason: "stop" }] });
|
|
46
|
+
}
|
|
47
|
+
const sse = chunks.map((c) => `data: ${JSON.stringify(c)}
|
|
48
|
+
|
|
49
|
+
`).join("") + "data: [DONE]\n\n";
|
|
50
|
+
return new Response(sse, { headers: { "content-type": "text/event-stream" } });
|
|
51
|
+
}
|
|
52
|
+
var DIM = 128;
|
|
53
|
+
function hashToken(t) {
|
|
54
|
+
let h = 2166136261;
|
|
55
|
+
for (let i = 0; i < t.length; i++) h = Math.imul(h ^ t.charCodeAt(i), 16777619);
|
|
56
|
+
return Math.abs(h) % DIM;
|
|
57
|
+
}
|
|
58
|
+
function mockEmbed(text) {
|
|
59
|
+
const v = new Array(DIM).fill(0);
|
|
60
|
+
for (const w of text.toLowerCase().match(/[a-z0-9]+/g) ?? []) v[hashToken(w)] += 1;
|
|
61
|
+
const n = Math.sqrt(v.reduce((a, b) => a + b * b, 0)) || 1;
|
|
62
|
+
return v.map((x) => x / n);
|
|
63
|
+
}
|
|
64
|
+
async function mockEmbeddingsHandler(request) {
|
|
65
|
+
const body = await request.json();
|
|
66
|
+
const inputs = Array.isArray(body.input) ? body.input : [body.input];
|
|
67
|
+
const toB64 = (v) => {
|
|
68
|
+
const bytes = new Uint8Array(new Float32Array(v).buffer);
|
|
69
|
+
let s = "";
|
|
70
|
+
for (const b of bytes) s += String.fromCharCode(b);
|
|
71
|
+
return btoa(s);
|
|
72
|
+
};
|
|
73
|
+
return Response.json({
|
|
74
|
+
object: "list",
|
|
75
|
+
model: "mock-embedding",
|
|
76
|
+
data: inputs.map((t, index) => ({ object: "embedding", index, embedding: body.encoding_format === "base64" ? toB64(mockEmbed(t)) : mockEmbed(t) })),
|
|
77
|
+
usage: { prompt_tokens: 0, total_tokens: 0 }
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
export {
|
|
81
|
+
mockEmbed,
|
|
82
|
+
mockEmbeddingsHandler,
|
|
83
|
+
mockLlmHandler
|
|
84
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,68 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sideagent",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./server": {
|
|
12
|
+
"types": "./dist/server/index.d.ts",
|
|
13
|
+
"browser": "./dist/server/browser.js",
|
|
14
|
+
"import": "./dist/server/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./protocol": {
|
|
17
|
+
"types": "./dist/protocol.d.ts",
|
|
18
|
+
"import": "./dist/protocol.js"
|
|
19
|
+
},
|
|
20
|
+
"./testing": {
|
|
21
|
+
"types": "./dist/testing/mock-llm.d.ts",
|
|
22
|
+
"import": "./dist/testing/mock-llm.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsup",
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"typecheck": "tsc --noEmit",
|
|
32
|
+
"demo:api": "tsx demo/server.ts",
|
|
33
|
+
"demo": "tsx demo/server.ts & vite demo"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@assistant-ui/react": "^0.15.31",
|
|
37
|
+
"@langchain/core": "^1.0.0",
|
|
38
|
+
"@langchain/langgraph": "^1.5.2",
|
|
39
|
+
"@langchain/openai": "^1.7.0",
|
|
40
|
+
"@radix-ui/react-icons": "^1.3.2",
|
|
41
|
+
"@scalar/openapi-parser": "^0.29.16",
|
|
42
|
+
"zod": "^4.0.0"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"react": ">=18"
|
|
46
|
+
},
|
|
47
|
+
"peerDependenciesMeta": {
|
|
48
|
+
"react": {
|
|
49
|
+
"optional": true
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@hono/node-server": "^1.14.0",
|
|
54
|
+
"@types/node": "^22.0.0",
|
|
55
|
+
"@types/react": "^19.0.0",
|
|
56
|
+
"@types/react-dom": "^19.0.0",
|
|
57
|
+
"@vitejs/plugin-react": "^5.0.0",
|
|
58
|
+
"hono": "^4.9.0",
|
|
59
|
+
"react": "^19.0.0",
|
|
60
|
+
"react-dom": "^19.0.0",
|
|
61
|
+
"tsup": "^8.5.0",
|
|
62
|
+
"tsx": "^4.20.0",
|
|
63
|
+
"typescript": "^5.9.0",
|
|
64
|
+
"vite": "^7.0.0",
|
|
65
|
+
"vitest": "^3.2.0"
|
|
66
|
+
},
|
|
67
|
+
"packageManager": "pnpm@10.30.2"
|
|
68
|
+
}
|