@copilotkit/aimock 1.7.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/.claude-plugin/marketplace.json +17 -0
- package/.claude-plugin/plugin.json +12 -0
- package/LICENSE +21 -0
- package/README.md +82 -0
- package/dist/_virtual/_rolldown/runtime.cjs +29 -0
- package/dist/a2a-handler.cjs +203 -0
- package/dist/a2a-handler.cjs.map +1 -0
- package/dist/a2a-handler.js +199 -0
- package/dist/a2a-handler.js.map +1 -0
- package/dist/a2a-mock.cjs +292 -0
- package/dist/a2a-mock.cjs.map +1 -0
- package/dist/a2a-mock.d.cts +41 -0
- package/dist/a2a-mock.d.cts.map +1 -0
- package/dist/a2a-mock.d.ts +41 -0
- package/dist/a2a-mock.d.ts.map +1 -0
- package/dist/a2a-mock.js +290 -0
- package/dist/a2a-mock.js.map +1 -0
- package/dist/a2a-stub.cjs +4 -0
- package/dist/a2a-stub.d.cts +3 -0
- package/dist/a2a-stub.d.ts +3 -0
- package/dist/a2a-stub.js +3 -0
- package/dist/a2a-types.d.cts +68 -0
- package/dist/a2a-types.d.cts.map +1 -0
- package/dist/a2a-types.d.ts +68 -0
- package/dist/a2a-types.d.ts.map +1 -0
- package/dist/aimock-cli.cjs +112 -0
- package/dist/aimock-cli.cjs.map +1 -0
- package/dist/aimock-cli.d.cts +19 -0
- package/dist/aimock-cli.d.cts.map +1 -0
- package/dist/aimock-cli.d.ts +19 -0
- package/dist/aimock-cli.d.ts.map +1 -0
- package/dist/aimock-cli.js +110 -0
- package/dist/aimock-cli.js.map +1 -0
- package/dist/aws-event-stream.cjs +117 -0
- package/dist/aws-event-stream.cjs.map +1 -0
- package/dist/aws-event-stream.d.cts +38 -0
- package/dist/aws-event-stream.d.cts.map +1 -0
- package/dist/aws-event-stream.d.ts +38 -0
- package/dist/aws-event-stream.d.ts.map +1 -0
- package/dist/aws-event-stream.js +114 -0
- package/dist/aws-event-stream.js.map +1 -0
- package/dist/bedrock-converse.cjs +445 -0
- package/dist/bedrock-converse.cjs.map +1 -0
- package/dist/bedrock-converse.d.cts +50 -0
- package/dist/bedrock-converse.d.cts.map +1 -0
- package/dist/bedrock-converse.d.ts +50 -0
- package/dist/bedrock-converse.d.ts.map +1 -0
- package/dist/bedrock-converse.js +443 -0
- package/dist/bedrock-converse.js.map +1 -0
- package/dist/bedrock.cjs +557 -0
- package/dist/bedrock.cjs.map +1 -0
- package/dist/bedrock.d.cts +41 -0
- package/dist/bedrock.d.cts.map +1 -0
- package/dist/bedrock.d.ts +41 -0
- package/dist/bedrock.d.ts.map +1 -0
- package/dist/bedrock.js +553 -0
- package/dist/bedrock.js.map +1 -0
- package/dist/chaos.cjs +114 -0
- package/dist/chaos.cjs.map +1 -0
- package/dist/chaos.d.cts +27 -0
- package/dist/chaos.d.cts.map +1 -0
- package/dist/chaos.d.ts +27 -0
- package/dist/chaos.d.ts.map +1 -0
- package/dist/chaos.js +113 -0
- package/dist/chaos.js.map +1 -0
- package/dist/cli.cjs +268 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +268 -0
- package/dist/cli.js.map +1 -0
- package/dist/cohere.cjs +434 -0
- package/dist/cohere.cjs.map +1 -0
- package/dist/cohere.d.cts +34 -0
- package/dist/cohere.d.cts.map +1 -0
- package/dist/cohere.d.ts +34 -0
- package/dist/cohere.d.ts.map +1 -0
- package/dist/cohere.js +433 -0
- package/dist/cohere.js.map +1 -0
- package/dist/config-loader.cjs +111 -0
- package/dist/config-loader.cjs.map +1 -0
- package/dist/config-loader.d.cts +100 -0
- package/dist/config-loader.d.cts.map +1 -0
- package/dist/config-loader.d.ts +100 -0
- package/dist/config-loader.d.ts.map +1 -0
- package/dist/config-loader.js +107 -0
- package/dist/config-loader.js.map +1 -0
- package/dist/embeddings.cjs +150 -0
- package/dist/embeddings.cjs.map +1 -0
- package/dist/embeddings.d.cts +12 -0
- package/dist/embeddings.d.cts.map +1 -0
- package/dist/embeddings.d.ts +12 -0
- package/dist/embeddings.d.ts.map +1 -0
- package/dist/embeddings.js +150 -0
- package/dist/embeddings.js.map +1 -0
- package/dist/fixture-loader.cjs +269 -0
- package/dist/fixture-loader.cjs.map +1 -0
- package/dist/fixture-loader.d.cts +17 -0
- package/dist/fixture-loader.d.cts.map +1 -0
- package/dist/fixture-loader.d.ts +17 -0
- package/dist/fixture-loader.d.ts.map +1 -0
- package/dist/fixture-loader.js +265 -0
- package/dist/fixture-loader.js.map +1 -0
- package/dist/gemini.cjs +403 -0
- package/dist/gemini.cjs.map +1 -0
- package/dist/gemini.d.cts +10 -0
- package/dist/gemini.d.cts.map +1 -0
- package/dist/gemini.d.ts +10 -0
- package/dist/gemini.d.ts.map +1 -0
- package/dist/gemini.js +403 -0
- package/dist/gemini.js.map +1 -0
- package/dist/helpers.cjs +276 -0
- package/dist/helpers.cjs.map +1 -0
- package/dist/helpers.d.cts +39 -0
- package/dist/helpers.d.cts.map +1 -0
- package/dist/helpers.d.ts +39 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +259 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.cjs +113 -0
- package/dist/index.d.cts +42 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +39 -0
- package/dist/interruption.cjs +40 -0
- package/dist/interruption.cjs.map +1 -0
- package/dist/interruption.d.cts +15 -0
- package/dist/interruption.d.cts.map +1 -0
- package/dist/interruption.d.ts +15 -0
- package/dist/interruption.d.ts.map +1 -0
- package/dist/interruption.js +39 -0
- package/dist/interruption.js.map +1 -0
- package/dist/journal.cjs +65 -0
- package/dist/journal.cjs.map +1 -0
- package/dist/journal.d.cts +23 -0
- package/dist/journal.d.cts.map +1 -0
- package/dist/journal.d.ts +23 -0
- package/dist/journal.d.ts.map +1 -0
- package/dist/journal.js +65 -0
- package/dist/journal.js.map +1 -0
- package/dist/jsonrpc.cjs +91 -0
- package/dist/jsonrpc.cjs.map +1 -0
- package/dist/jsonrpc.d.cts +24 -0
- package/dist/jsonrpc.d.cts.map +1 -0
- package/dist/jsonrpc.d.ts +24 -0
- package/dist/jsonrpc.d.ts.map +1 -0
- package/dist/jsonrpc.js +90 -0
- package/dist/jsonrpc.js.map +1 -0
- package/dist/llmock.cjs +223 -0
- package/dist/llmock.cjs.map +1 -0
- package/dist/llmock.d.cts +70 -0
- package/dist/llmock.d.cts.map +1 -0
- package/dist/llmock.d.ts +70 -0
- package/dist/llmock.d.ts.map +1 -0
- package/dist/llmock.js +223 -0
- package/dist/llmock.js.map +1 -0
- package/dist/logger.cjs +29 -0
- package/dist/logger.cjs.map +1 -0
- package/dist/logger.d.cts +14 -0
- package/dist/logger.d.cts.map +1 -0
- package/dist/logger.d.ts +14 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +28 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp-handler.cjs +189 -0
- package/dist/mcp-handler.cjs.map +1 -0
- package/dist/mcp-handler.js +188 -0
- package/dist/mcp-handler.js.map +1 -0
- package/dist/mcp-mock.cjs +169 -0
- package/dist/mcp-mock.cjs.map +1 -0
- package/dist/mcp-mock.d.cts +40 -0
- package/dist/mcp-mock.d.cts.map +1 -0
- package/dist/mcp-mock.d.ts +40 -0
- package/dist/mcp-mock.d.ts.map +1 -0
- package/dist/mcp-mock.js +167 -0
- package/dist/mcp-mock.js.map +1 -0
- package/dist/mcp-stub.cjs +4 -0
- package/dist/mcp-stub.d.cts +3 -0
- package/dist/mcp-stub.d.ts +3 -0
- package/dist/mcp-stub.js +3 -0
- package/dist/mcp-types.d.cts +65 -0
- package/dist/mcp-types.d.cts.map +1 -0
- package/dist/mcp-types.d.ts +65 -0
- package/dist/mcp-types.d.ts.map +1 -0
- package/dist/messages.cjs +489 -0
- package/dist/messages.cjs.map +1 -0
- package/dist/messages.d.cts +10 -0
- package/dist/messages.d.cts.map +1 -0
- package/dist/messages.d.ts +10 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +489 -0
- package/dist/messages.js.map +1 -0
- package/dist/metrics.cjs +160 -0
- package/dist/metrics.cjs.map +1 -0
- package/dist/metrics.d.cts +24 -0
- package/dist/metrics.d.cts.map +1 -0
- package/dist/metrics.d.ts +24 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +158 -0
- package/dist/metrics.js.map +1 -0
- package/dist/moderation.cjs +91 -0
- package/dist/moderation.cjs.map +1 -0
- package/dist/moderation.d.cts +23 -0
- package/dist/moderation.d.cts.map +1 -0
- package/dist/moderation.d.ts +23 -0
- package/dist/moderation.d.ts.map +1 -0
- package/dist/moderation.js +91 -0
- package/dist/moderation.js.map +1 -0
- package/dist/ndjson-writer.cjs +31 -0
- package/dist/ndjson-writer.cjs.map +1 -0
- package/dist/ndjson-writer.d.cts +17 -0
- package/dist/ndjson-writer.d.cts.map +1 -0
- package/dist/ndjson-writer.d.ts +17 -0
- package/dist/ndjson-writer.d.ts.map +1 -0
- package/dist/ndjson-writer.js +31 -0
- package/dist/ndjson-writer.js.map +1 -0
- package/dist/ollama.cjs +519 -0
- package/dist/ollama.cjs.map +1 -0
- package/dist/ollama.d.cts +34 -0
- package/dist/ollama.d.cts.map +1 -0
- package/dist/ollama.d.ts +34 -0
- package/dist/ollama.d.ts.map +1 -0
- package/dist/ollama.js +517 -0
- package/dist/ollama.js.map +1 -0
- package/dist/recorder.cjs +311 -0
- package/dist/recorder.cjs.map +1 -0
- package/dist/recorder.d.cts +23 -0
- package/dist/recorder.d.cts.map +1 -0
- package/dist/recorder.d.ts +23 -0
- package/dist/recorder.d.ts.map +1 -0
- package/dist/recorder.js +305 -0
- package/dist/recorder.js.map +1 -0
- package/dist/rerank.cjs +71 -0
- package/dist/rerank.cjs.map +1 -0
- package/dist/rerank.d.cts +22 -0
- package/dist/rerank.d.cts.map +1 -0
- package/dist/rerank.d.ts +22 -0
- package/dist/rerank.d.ts.map +1 -0
- package/dist/rerank.js +71 -0
- package/dist/rerank.js.map +1 -0
- package/dist/responses.cjs +637 -0
- package/dist/responses.cjs.map +1 -0
- package/dist/responses.d.cts +16 -0
- package/dist/responses.d.cts.map +1 -0
- package/dist/responses.d.ts +16 -0
- package/dist/responses.d.ts.map +1 -0
- package/dist/responses.js +634 -0
- package/dist/responses.js.map +1 -0
- package/dist/router.cjs +68 -0
- package/dist/router.cjs.map +1 -0
- package/dist/router.d.cts +16 -0
- package/dist/router.d.cts.map +1 -0
- package/dist/router.d.ts +16 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +65 -0
- package/dist/router.js.map +1 -0
- package/dist/search.cjs +59 -0
- package/dist/search.cjs.map +1 -0
- package/dist/search.d.cts +23 -0
- package/dist/search.d.cts.map +1 -0
- package/dist/search.d.ts +23 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +59 -0
- package/dist/search.js.map +1 -0
- package/dist/server.cjs +935 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +28 -0
- package/dist/server.d.cts.map +1 -0
- package/dist/server.d.ts +28 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +933 -0
- package/dist/server.js.map +1 -0
- package/dist/sse-writer.cjs +59 -0
- package/dist/sse-writer.cjs.map +1 -0
- package/dist/sse-writer.d.cts +19 -0
- package/dist/sse-writer.d.cts.map +1 -0
- package/dist/sse-writer.d.ts +19 -0
- package/dist/sse-writer.d.ts.map +1 -0
- package/dist/sse-writer.js +55 -0
- package/dist/sse-writer.js.map +1 -0
- package/dist/stream-collapse.cjs +496 -0
- package/dist/stream-collapse.cjs.map +1 -0
- package/dist/stream-collapse.d.cts +70 -0
- package/dist/stream-collapse.d.cts.map +1 -0
- package/dist/stream-collapse.d.ts +70 -0
- package/dist/stream-collapse.d.ts.map +1 -0
- package/dist/stream-collapse.js +489 -0
- package/dist/stream-collapse.js.map +1 -0
- package/dist/suite.cjs +46 -0
- package/dist/suite.cjs.map +1 -0
- package/dist/suite.d.cts +31 -0
- package/dist/suite.d.cts.map +1 -0
- package/dist/suite.d.ts +31 -0
- package/dist/suite.d.ts.map +1 -0
- package/dist/suite.js +46 -0
- package/dist/suite.js.map +1 -0
- package/dist/types.d.cts +243 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.ts +243 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/url.cjs +21 -0
- package/dist/url.cjs.map +1 -0
- package/dist/url.d.cts +16 -0
- package/dist/url.d.cts.map +1 -0
- package/dist/url.d.ts +16 -0
- package/dist/url.d.ts.map +1 -0
- package/dist/url.js +20 -0
- package/dist/url.js.map +1 -0
- package/dist/vector-handler.cjs +239 -0
- package/dist/vector-handler.cjs.map +1 -0
- package/dist/vector-handler.js +238 -0
- package/dist/vector-handler.js.map +1 -0
- package/dist/vector-mock.cjs +229 -0
- package/dist/vector-mock.cjs.map +1 -0
- package/dist/vector-mock.d.cts +39 -0
- package/dist/vector-mock.d.cts.map +1 -0
- package/dist/vector-mock.d.ts +39 -0
- package/dist/vector-mock.d.ts.map +1 -0
- package/dist/vector-mock.js +227 -0
- package/dist/vector-mock.js.map +1 -0
- package/dist/vector-stub.cjs +4 -0
- package/dist/vector-stub.d.cts +3 -0
- package/dist/vector-stub.d.ts +3 -0
- package/dist/vector-stub.js +3 -0
- package/dist/vector-types.d.cts +32 -0
- package/dist/vector-types.d.cts.map +1 -0
- package/dist/vector-types.d.ts +32 -0
- package/dist/vector-types.d.ts.map +1 -0
- package/dist/watcher.cjs +59 -0
- package/dist/watcher.cjs.map +1 -0
- package/dist/watcher.js +58 -0
- package/dist/watcher.js.map +1 -0
- package/dist/ws-framing.cjs +187 -0
- package/dist/ws-framing.cjs.map +1 -0
- package/dist/ws-framing.d.cts +26 -0
- package/dist/ws-framing.d.cts.map +1 -0
- package/dist/ws-framing.d.ts +26 -0
- package/dist/ws-framing.d.ts.map +1 -0
- package/dist/ws-framing.js +184 -0
- package/dist/ws-framing.js.map +1 -0
- package/dist/ws-gemini-live.cjs +364 -0
- package/dist/ws-gemini-live.cjs.map +1 -0
- package/dist/ws-gemini-live.d.cts +18 -0
- package/dist/ws-gemini-live.d.cts.map +1 -0
- package/dist/ws-gemini-live.d.ts +18 -0
- package/dist/ws-gemini-live.d.ts.map +1 -0
- package/dist/ws-gemini-live.js +364 -0
- package/dist/ws-gemini-live.js.map +1 -0
- package/dist/ws-realtime.cjs +435 -0
- package/dist/ws-realtime.cjs.map +1 -0
- package/dist/ws-realtime.d.cts +17 -0
- package/dist/ws-realtime.d.cts.map +1 -0
- package/dist/ws-realtime.d.ts +17 -0
- package/dist/ws-realtime.d.ts.map +1 -0
- package/dist/ws-realtime.js +435 -0
- package/dist/ws-realtime.js.map +1 -0
- package/dist/ws-responses.cjs +164 -0
- package/dist/ws-responses.cjs.map +1 -0
- package/dist/ws-responses.d.cts +18 -0
- package/dist/ws-responses.d.cts.map +1 -0
- package/dist/ws-responses.d.ts +18 -0
- package/dist/ws-responses.d.ts.map +1 -0
- package/dist/ws-responses.js +164 -0
- package/dist/ws-responses.js.map +1 -0
- package/fixtures/example-greeting.json +12 -0
- package/fixtures/example-multi-turn.json +14 -0
- package/fixtures/example-tool-call.json +15 -0
- package/package.json +118 -0
- package/skills/write-fixtures/SKILL.md +625 -0
package/dist/helpers.cjs
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
2
|
+
let node_crypto = require("node:crypto");
|
|
3
|
+
|
|
4
|
+
//#region src/helpers.ts
|
|
5
|
+
const REDACTED_HEADERS = new Set([
|
|
6
|
+
"authorization",
|
|
7
|
+
"x-api-key",
|
|
8
|
+
"api-key"
|
|
9
|
+
]);
|
|
10
|
+
function flattenHeaders(headers) {
|
|
11
|
+
const flat = {};
|
|
12
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
13
|
+
if (value === void 0) continue;
|
|
14
|
+
if (REDACTED_HEADERS.has(key.toLowerCase())) flat[key] = "[REDACTED]";
|
|
15
|
+
else flat[key] = Array.isArray(value) ? value.join(", ") : value;
|
|
16
|
+
}
|
|
17
|
+
return flat;
|
|
18
|
+
}
|
|
19
|
+
function generateId(prefix = "chatcmpl") {
|
|
20
|
+
return `${prefix}-${(0, node_crypto.randomBytes)(12).toString("base64url")}`;
|
|
21
|
+
}
|
|
22
|
+
function generateToolCallId() {
|
|
23
|
+
return `call_${(0, node_crypto.randomBytes)(12).toString("base64url")}`;
|
|
24
|
+
}
|
|
25
|
+
function generateMessageId() {
|
|
26
|
+
return `msg_${(0, node_crypto.randomBytes)(12).toString("base64url")}`;
|
|
27
|
+
}
|
|
28
|
+
function generateToolUseId() {
|
|
29
|
+
return `toolu_${(0, node_crypto.randomBytes)(12).toString("base64url")}`;
|
|
30
|
+
}
|
|
31
|
+
function isTextResponse(r) {
|
|
32
|
+
return "content" in r && typeof r.content === "string";
|
|
33
|
+
}
|
|
34
|
+
function isToolCallResponse(r) {
|
|
35
|
+
return "toolCalls" in r && Array.isArray(r.toolCalls);
|
|
36
|
+
}
|
|
37
|
+
function isErrorResponse(r) {
|
|
38
|
+
return "error" in r && r.error !== null && typeof r.error === "object";
|
|
39
|
+
}
|
|
40
|
+
function isEmbeddingResponse(r) {
|
|
41
|
+
return "embedding" in r && Array.isArray(r.embedding);
|
|
42
|
+
}
|
|
43
|
+
function buildTextChunks(content, model, chunkSize) {
|
|
44
|
+
const id = generateId();
|
|
45
|
+
const created = Math.floor(Date.now() / 1e3);
|
|
46
|
+
const chunks = [];
|
|
47
|
+
chunks.push({
|
|
48
|
+
id,
|
|
49
|
+
object: "chat.completion.chunk",
|
|
50
|
+
created,
|
|
51
|
+
model,
|
|
52
|
+
choices: [{
|
|
53
|
+
index: 0,
|
|
54
|
+
delta: {
|
|
55
|
+
role: "assistant",
|
|
56
|
+
content: ""
|
|
57
|
+
},
|
|
58
|
+
finish_reason: null
|
|
59
|
+
}]
|
|
60
|
+
});
|
|
61
|
+
for (let i = 0; i < content.length; i += chunkSize) {
|
|
62
|
+
const slice = content.slice(i, i + chunkSize);
|
|
63
|
+
chunks.push({
|
|
64
|
+
id,
|
|
65
|
+
object: "chat.completion.chunk",
|
|
66
|
+
created,
|
|
67
|
+
model,
|
|
68
|
+
choices: [{
|
|
69
|
+
index: 0,
|
|
70
|
+
delta: { content: slice },
|
|
71
|
+
finish_reason: null
|
|
72
|
+
}]
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
chunks.push({
|
|
76
|
+
id,
|
|
77
|
+
object: "chat.completion.chunk",
|
|
78
|
+
created,
|
|
79
|
+
model,
|
|
80
|
+
choices: [{
|
|
81
|
+
index: 0,
|
|
82
|
+
delta: {},
|
|
83
|
+
finish_reason: "stop"
|
|
84
|
+
}]
|
|
85
|
+
});
|
|
86
|
+
return chunks;
|
|
87
|
+
}
|
|
88
|
+
function buildToolCallChunks(toolCalls, model, chunkSize) {
|
|
89
|
+
const id = generateId();
|
|
90
|
+
const created = Math.floor(Date.now() / 1e3);
|
|
91
|
+
const chunks = [];
|
|
92
|
+
chunks.push({
|
|
93
|
+
id,
|
|
94
|
+
object: "chat.completion.chunk",
|
|
95
|
+
created,
|
|
96
|
+
model,
|
|
97
|
+
choices: [{
|
|
98
|
+
index: 0,
|
|
99
|
+
delta: {
|
|
100
|
+
role: "assistant",
|
|
101
|
+
content: null
|
|
102
|
+
},
|
|
103
|
+
finish_reason: null
|
|
104
|
+
}]
|
|
105
|
+
});
|
|
106
|
+
for (let tcIdx = 0; tcIdx < toolCalls.length; tcIdx++) {
|
|
107
|
+
const tc = toolCalls[tcIdx];
|
|
108
|
+
const tcId = tc.id || generateToolCallId();
|
|
109
|
+
chunks.push({
|
|
110
|
+
id,
|
|
111
|
+
object: "chat.completion.chunk",
|
|
112
|
+
created,
|
|
113
|
+
model,
|
|
114
|
+
choices: [{
|
|
115
|
+
index: 0,
|
|
116
|
+
delta: { tool_calls: [{
|
|
117
|
+
index: tcIdx,
|
|
118
|
+
id: tcId,
|
|
119
|
+
type: "function",
|
|
120
|
+
function: {
|
|
121
|
+
name: tc.name,
|
|
122
|
+
arguments: ""
|
|
123
|
+
}
|
|
124
|
+
}] },
|
|
125
|
+
finish_reason: null
|
|
126
|
+
}]
|
|
127
|
+
});
|
|
128
|
+
const args = tc.arguments;
|
|
129
|
+
for (let i = 0; i < args.length; i += chunkSize) {
|
|
130
|
+
const slice = args.slice(i, i + chunkSize);
|
|
131
|
+
chunks.push({
|
|
132
|
+
id,
|
|
133
|
+
object: "chat.completion.chunk",
|
|
134
|
+
created,
|
|
135
|
+
model,
|
|
136
|
+
choices: [{
|
|
137
|
+
index: 0,
|
|
138
|
+
delta: { tool_calls: [{
|
|
139
|
+
index: tcIdx,
|
|
140
|
+
function: { arguments: slice }
|
|
141
|
+
}] },
|
|
142
|
+
finish_reason: null
|
|
143
|
+
}]
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
chunks.push({
|
|
148
|
+
id,
|
|
149
|
+
object: "chat.completion.chunk",
|
|
150
|
+
created,
|
|
151
|
+
model,
|
|
152
|
+
choices: [{
|
|
153
|
+
index: 0,
|
|
154
|
+
delta: {},
|
|
155
|
+
finish_reason: "tool_calls"
|
|
156
|
+
}]
|
|
157
|
+
});
|
|
158
|
+
return chunks;
|
|
159
|
+
}
|
|
160
|
+
function buildTextCompletion(content, model) {
|
|
161
|
+
return {
|
|
162
|
+
id: generateId(),
|
|
163
|
+
object: "chat.completion",
|
|
164
|
+
created: Math.floor(Date.now() / 1e3),
|
|
165
|
+
model,
|
|
166
|
+
choices: [{
|
|
167
|
+
index: 0,
|
|
168
|
+
message: {
|
|
169
|
+
role: "assistant",
|
|
170
|
+
content,
|
|
171
|
+
refusal: null
|
|
172
|
+
},
|
|
173
|
+
finish_reason: "stop"
|
|
174
|
+
}],
|
|
175
|
+
usage: {
|
|
176
|
+
prompt_tokens: 0,
|
|
177
|
+
completion_tokens: 0,
|
|
178
|
+
total_tokens: 0
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function buildToolCallCompletion(toolCalls, model) {
|
|
183
|
+
return {
|
|
184
|
+
id: generateId(),
|
|
185
|
+
object: "chat.completion",
|
|
186
|
+
created: Math.floor(Date.now() / 1e3),
|
|
187
|
+
model,
|
|
188
|
+
choices: [{
|
|
189
|
+
index: 0,
|
|
190
|
+
message: {
|
|
191
|
+
role: "assistant",
|
|
192
|
+
content: null,
|
|
193
|
+
refusal: null,
|
|
194
|
+
tool_calls: toolCalls.map((tc) => ({
|
|
195
|
+
id: tc.id || generateToolCallId(),
|
|
196
|
+
type: "function",
|
|
197
|
+
function: {
|
|
198
|
+
name: tc.name,
|
|
199
|
+
arguments: tc.arguments
|
|
200
|
+
}
|
|
201
|
+
}))
|
|
202
|
+
},
|
|
203
|
+
finish_reason: "tool_calls"
|
|
204
|
+
}],
|
|
205
|
+
usage: {
|
|
206
|
+
prompt_tokens: 0,
|
|
207
|
+
completion_tokens: 0,
|
|
208
|
+
total_tokens: 0
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function readBody(req) {
|
|
213
|
+
return new Promise((resolve, reject) => {
|
|
214
|
+
const chunks = [];
|
|
215
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
216
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString()));
|
|
217
|
+
req.on("error", reject);
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
function matchesPattern(text, pattern) {
|
|
221
|
+
if (typeof pattern === "string") return text.toLowerCase().includes(pattern.toLowerCase());
|
|
222
|
+
return pattern.test(text);
|
|
223
|
+
}
|
|
224
|
+
const DEFAULT_EMBEDDING_DIMENSIONS = 1536;
|
|
225
|
+
/**
|
|
226
|
+
* Generate a deterministic embedding vector from input text.
|
|
227
|
+
* Hashes the input with SHA-256 and spreads the hash bytes across
|
|
228
|
+
* the requested number of dimensions, producing values in [-1, 1].
|
|
229
|
+
*/
|
|
230
|
+
function generateDeterministicEmbedding(input, dimensions = DEFAULT_EMBEDDING_DIMENSIONS) {
|
|
231
|
+
let currentHash = (0, node_crypto.createHash)("sha256").update(input).digest();
|
|
232
|
+
const embedding = new Array(dimensions);
|
|
233
|
+
for (let i = 0; i < dimensions; i++) {
|
|
234
|
+
if (i > 0 && i % 32 === 0) currentHash = (0, node_crypto.createHash)("sha256").update(currentHash).digest();
|
|
235
|
+
embedding[i] = currentHash[i % 32] / 127.5 - 1;
|
|
236
|
+
}
|
|
237
|
+
return embedding;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Build an OpenAI-format embeddings API response for one or more inputs.
|
|
241
|
+
*/
|
|
242
|
+
function buildEmbeddingResponse(embeddings, model) {
|
|
243
|
+
return {
|
|
244
|
+
object: "list",
|
|
245
|
+
data: embeddings.map((embedding, index) => ({
|
|
246
|
+
object: "embedding",
|
|
247
|
+
index,
|
|
248
|
+
embedding
|
|
249
|
+
})),
|
|
250
|
+
model,
|
|
251
|
+
usage: {
|
|
252
|
+
prompt_tokens: 0,
|
|
253
|
+
total_tokens: 0
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
//#endregion
|
|
259
|
+
exports.buildEmbeddingResponse = buildEmbeddingResponse;
|
|
260
|
+
exports.buildTextChunks = buildTextChunks;
|
|
261
|
+
exports.buildTextCompletion = buildTextCompletion;
|
|
262
|
+
exports.buildToolCallChunks = buildToolCallChunks;
|
|
263
|
+
exports.buildToolCallCompletion = buildToolCallCompletion;
|
|
264
|
+
exports.flattenHeaders = flattenHeaders;
|
|
265
|
+
exports.generateDeterministicEmbedding = generateDeterministicEmbedding;
|
|
266
|
+
exports.generateId = generateId;
|
|
267
|
+
exports.generateMessageId = generateMessageId;
|
|
268
|
+
exports.generateToolCallId = generateToolCallId;
|
|
269
|
+
exports.generateToolUseId = generateToolUseId;
|
|
270
|
+
exports.isEmbeddingResponse = isEmbeddingResponse;
|
|
271
|
+
exports.isErrorResponse = isErrorResponse;
|
|
272
|
+
exports.isTextResponse = isTextResponse;
|
|
273
|
+
exports.isToolCallResponse = isToolCallResponse;
|
|
274
|
+
exports.matchesPattern = matchesPattern;
|
|
275
|
+
exports.readBody = readBody;
|
|
276
|
+
//# sourceMappingURL=helpers.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.cjs","names":[],"sources":["../src/helpers.ts"],"sourcesContent":["import { createHash, randomBytes } from \"node:crypto\";\nimport type * as http from \"node:http\";\nimport type {\n FixtureResponse,\n TextResponse,\n ToolCallResponse,\n ErrorResponse,\n EmbeddingResponse,\n SSEChunk,\n ToolCall,\n ChatCompletion,\n} from \"./types.js\";\n\nconst REDACTED_HEADERS = new Set([\"authorization\", \"x-api-key\", \"api-key\"]);\n\nexport function flattenHeaders(headers: http.IncomingHttpHeaders): Record<string, string> {\n const flat: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (value === undefined) continue;\n if (REDACTED_HEADERS.has(key.toLowerCase())) {\n flat[key] = \"[REDACTED]\";\n } else {\n flat[key] = Array.isArray(value) ? value.join(\", \") : value;\n }\n }\n return flat;\n}\n\nexport function generateId(prefix = \"chatcmpl\"): string {\n return `${prefix}-${randomBytes(12).toString(\"base64url\")}`;\n}\n\nexport function generateToolCallId(): string {\n return `call_${randomBytes(12).toString(\"base64url\")}`;\n}\n\nexport function generateMessageId(): string {\n return `msg_${randomBytes(12).toString(\"base64url\")}`;\n}\n\nexport function generateToolUseId(): string {\n return `toolu_${randomBytes(12).toString(\"base64url\")}`;\n}\n\nexport function isTextResponse(r: FixtureResponse): r is TextResponse {\n return \"content\" in r && typeof (r as TextResponse).content === \"string\";\n}\n\nexport function isToolCallResponse(r: FixtureResponse): r is ToolCallResponse {\n return \"toolCalls\" in r && Array.isArray((r as ToolCallResponse).toolCalls);\n}\n\nexport function isErrorResponse(r: FixtureResponse): r is ErrorResponse {\n return (\n \"error\" in r &&\n (r as ErrorResponse).error !== null &&\n typeof (r as ErrorResponse).error === \"object\"\n );\n}\n\nexport function isEmbeddingResponse(r: FixtureResponse): r is EmbeddingResponse {\n return \"embedding\" in r && Array.isArray((r as EmbeddingResponse).embedding);\n}\n\nexport function buildTextChunks(content: string, model: string, chunkSize: number): SSEChunk[] {\n const id = generateId();\n const created = Math.floor(Date.now() / 1000);\n const chunks: SSEChunk[] = [];\n\n // Role chunk\n chunks.push({\n id,\n object: \"chat.completion.chunk\",\n created,\n model,\n choices: [{ index: 0, delta: { role: \"assistant\", content: \"\" }, finish_reason: null }],\n });\n\n // Content chunks\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n chunks.push({\n id,\n object: \"chat.completion.chunk\",\n created,\n model,\n choices: [{ index: 0, delta: { content: slice }, finish_reason: null }],\n });\n }\n\n // Finish chunk\n chunks.push({\n id,\n object: \"chat.completion.chunk\",\n created,\n model,\n choices: [{ index: 0, delta: {}, finish_reason: \"stop\" }],\n });\n\n return chunks;\n}\n\nexport function buildToolCallChunks(\n toolCalls: ToolCall[],\n model: string,\n chunkSize: number,\n): SSEChunk[] {\n const id = generateId();\n const created = Math.floor(Date.now() / 1000);\n const chunks: SSEChunk[] = [];\n\n // Role chunk\n chunks.push({\n id,\n object: \"chat.completion.chunk\",\n created,\n model,\n choices: [{ index: 0, delta: { role: \"assistant\", content: null }, finish_reason: null }],\n });\n\n // Tool call chunks — one initial chunk per tool call, then argument chunks\n for (let tcIdx = 0; tcIdx < toolCalls.length; tcIdx++) {\n const tc = toolCalls[tcIdx];\n const tcId = tc.id || generateToolCallId();\n\n // Initial tool call chunk (id + function name)\n chunks.push({\n id,\n object: \"chat.completion.chunk\",\n created,\n model,\n choices: [\n {\n index: 0,\n delta: {\n tool_calls: [\n {\n index: tcIdx,\n id: tcId,\n type: \"function\",\n function: { name: tc.name, arguments: \"\" },\n },\n ],\n },\n finish_reason: null,\n },\n ],\n });\n\n // Argument streaming chunks\n const args = tc.arguments;\n for (let i = 0; i < args.length; i += chunkSize) {\n const slice = args.slice(i, i + chunkSize);\n chunks.push({\n id,\n object: \"chat.completion.chunk\",\n created,\n model,\n choices: [\n {\n index: 0,\n delta: {\n tool_calls: [{ index: tcIdx, function: { arguments: slice } }],\n },\n finish_reason: null,\n },\n ],\n });\n }\n }\n\n // Finish chunk\n chunks.push({\n id,\n object: \"chat.completion.chunk\",\n created,\n model,\n choices: [{ index: 0, delta: {}, finish_reason: \"tool_calls\" }],\n });\n\n return chunks;\n}\n\n// Non-streaming response builders\n\nexport function buildTextCompletion(content: string, model: string): ChatCompletion {\n return {\n id: generateId(),\n object: \"chat.completion\",\n created: Math.floor(Date.now() / 1000),\n model,\n choices: [\n {\n index: 0,\n message: { role: \"assistant\", content, refusal: null },\n finish_reason: \"stop\",\n },\n ],\n usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n };\n}\n\nexport function buildToolCallCompletion(toolCalls: ToolCall[], model: string): ChatCompletion {\n return {\n id: generateId(),\n object: \"chat.completion\",\n created: Math.floor(Date.now() / 1000),\n model,\n choices: [\n {\n index: 0,\n message: {\n role: \"assistant\",\n content: null,\n refusal: null,\n tool_calls: toolCalls.map((tc) => ({\n id: tc.id || generateToolCallId(),\n type: \"function\" as const,\n function: { name: tc.name, arguments: tc.arguments },\n })),\n },\n finish_reason: \"tool_calls\",\n },\n ],\n usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n };\n}\n\n// ─── HTTP helpers ─────────────────────────────────────────────────────────\n\nexport function readBody(req: http.IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n req.on(\"end\", () => resolve(Buffer.concat(chunks).toString()));\n req.on(\"error\", reject);\n });\n}\n\n// ─── Pattern matching ─────────────────────────────────────────────────────\n\nexport function matchesPattern(text: string, pattern: string | RegExp): boolean {\n if (typeof pattern === \"string\") {\n return text.toLowerCase().includes(pattern.toLowerCase());\n }\n return pattern.test(text);\n}\n\n// ─── Embedding helpers ─────────────────────────────────────────────────────\n\nconst DEFAULT_EMBEDDING_DIMENSIONS = 1536;\n\n/**\n * Generate a deterministic embedding vector from input text.\n * Hashes the input with SHA-256 and spreads the hash bytes across\n * the requested number of dimensions, producing values in [-1, 1].\n */\nexport function generateDeterministicEmbedding(\n input: string,\n dimensions: number = DEFAULT_EMBEDDING_DIMENSIONS,\n): number[] {\n let currentHash = createHash(\"sha256\").update(input).digest();\n const embedding: number[] = new Array(dimensions);\n for (let i = 0; i < dimensions; i++) {\n if (i > 0 && i % 32 === 0) {\n currentHash = createHash(\"sha256\").update(currentHash).digest();\n }\n // Map 0-255 → -1.0 to 1.0\n embedding[i] = currentHash[i % 32] / 127.5 - 1;\n }\n return embedding;\n}\n\nexport interface EmbeddingAPIResponse {\n object: \"list\";\n data: { object: \"embedding\"; index: number; embedding: number[] }[];\n model: string;\n usage: { prompt_tokens: number; total_tokens: number };\n}\n\n/**\n * Build an OpenAI-format embeddings API response for one or more inputs.\n */\nexport function buildEmbeddingResponse(\n embeddings: number[][],\n model: string,\n): EmbeddingAPIResponse {\n return {\n object: \"list\",\n data: embeddings.map((embedding, index) => ({\n object: \"embedding\" as const,\n index,\n embedding,\n })),\n model,\n usage: { prompt_tokens: 0, total_tokens: 0 },\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { EmbeddingResponse, FixtureResponse, SSEChunk, ToolCall } from "./types.cjs";
|
|
2
|
+
import * as http from "node:http";
|
|
3
|
+
|
|
4
|
+
//#region src/helpers.d.ts
|
|
5
|
+
declare function flattenHeaders(headers: http.IncomingHttpHeaders): Record<string, string>;
|
|
6
|
+
declare function generateId(prefix?: string): string;
|
|
7
|
+
declare function generateToolCallId(): string;
|
|
8
|
+
declare function generateMessageId(): string;
|
|
9
|
+
declare function generateToolUseId(): string;
|
|
10
|
+
declare function isEmbeddingResponse(r: FixtureResponse): r is EmbeddingResponse;
|
|
11
|
+
declare function buildTextChunks(content: string, model: string, chunkSize: number): SSEChunk[];
|
|
12
|
+
declare function buildToolCallChunks(toolCalls: ToolCall[], model: string, chunkSize: number): SSEChunk[];
|
|
13
|
+
/**
|
|
14
|
+
* Generate a deterministic embedding vector from input text.
|
|
15
|
+
* Hashes the input with SHA-256 and spreads the hash bytes across
|
|
16
|
+
* the requested number of dimensions, producing values in [-1, 1].
|
|
17
|
+
*/
|
|
18
|
+
declare function generateDeterministicEmbedding(input: string, dimensions?: number): number[];
|
|
19
|
+
interface EmbeddingAPIResponse {
|
|
20
|
+
object: "list";
|
|
21
|
+
data: {
|
|
22
|
+
object: "embedding";
|
|
23
|
+
index: number;
|
|
24
|
+
embedding: number[];
|
|
25
|
+
}[];
|
|
26
|
+
model: string;
|
|
27
|
+
usage: {
|
|
28
|
+
prompt_tokens: number;
|
|
29
|
+
total_tokens: number;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build an OpenAI-format embeddings API response for one or more inputs.
|
|
34
|
+
*/
|
|
35
|
+
declare function buildEmbeddingResponse(embeddings: number[][], model: string): EmbeddingAPIResponse;
|
|
36
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
37
|
+
//#endregion
|
|
38
|
+
export { EmbeddingAPIResponse, buildEmbeddingResponse, buildTextChunks, buildToolCallChunks, flattenHeaders, generateDeterministicEmbedding, generateId, generateMessageId, generateToolCallId, generateToolUseId, isEmbeddingResponse };
|
|
39
|
+
//# sourceMappingURL=helpers.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.cts","names":[],"sources":["../src/helpers.ts"],"sourcesContent":[],"mappings":";;;;iBAegB,cAAA,UAAwB,IAAA,CAAK,sBAAsB;iBAanD,UAAA;AAbA,iBAiBA,kBAAA,CAAA,CAjBc,EAAA,MAAA;AAAA,iBAqBd,iBAAA,CAAA,CArBc,EAAA,MAAA;AAAU,iBAyBxB,iBAAA,CAAA,CAzB6B,EAAA,MAAA;AAiB7B,iBA4BA,mBAAA,CA5BkB,CAAA,EA4BK,eA5BL,CAAA,EAAA,CAAA,IA4B4B,iBA5B5B;AAIlB,iBA4BA,eAAA,CA5BiB,OAAA,EAAA,MAAA,EAAA,KAAA,EAAA,MAAA,EAAA,SAAA,EAAA,MAAA,CAAA,EA4BmD,QA5BnD,EAAA;AAIjB,iBA8DA,mBAAA,CA9DiB,SAAA,EA+DpB,QA/DoB,EAAA,EAAA,KAAA,EAAA,MAAA,EAAA,SAAA,EAAA,MAAA,CAAA,EAkE9B,QAlE8B,EAAA;;AAwBjC;AAsCA;;;AAIG,iBAuJa,8BAAA,CAvJb,KAAA,EAAA,MAAA,EAAA,UAAA,CAAA,EAAA,MAAA,CAAA,EAAA,MAAA,EAAA;AAAQ,UAuKM,oBAAA,CAvKN;EAuJK,MAAA,EAAA,MAAA;EAgBC,IAAA,EAAA;IAUD,MAAA,EAAA,WAAA;;;;;;;;;;;;;iBAAA,sBAAA,yCAGb"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { EmbeddingResponse, FixtureResponse, SSEChunk, ToolCall } from "./types.js";
|
|
2
|
+
import * as http from "node:http";
|
|
3
|
+
|
|
4
|
+
//#region src/helpers.d.ts
|
|
5
|
+
declare function flattenHeaders(headers: http.IncomingHttpHeaders): Record<string, string>;
|
|
6
|
+
declare function generateId(prefix?: string): string;
|
|
7
|
+
declare function generateToolCallId(): string;
|
|
8
|
+
declare function generateMessageId(): string;
|
|
9
|
+
declare function generateToolUseId(): string;
|
|
10
|
+
declare function isEmbeddingResponse(r: FixtureResponse): r is EmbeddingResponse;
|
|
11
|
+
declare function buildTextChunks(content: string, model: string, chunkSize: number): SSEChunk[];
|
|
12
|
+
declare function buildToolCallChunks(toolCalls: ToolCall[], model: string, chunkSize: number): SSEChunk[];
|
|
13
|
+
/**
|
|
14
|
+
* Generate a deterministic embedding vector from input text.
|
|
15
|
+
* Hashes the input with SHA-256 and spreads the hash bytes across
|
|
16
|
+
* the requested number of dimensions, producing values in [-1, 1].
|
|
17
|
+
*/
|
|
18
|
+
declare function generateDeterministicEmbedding(input: string, dimensions?: number): number[];
|
|
19
|
+
interface EmbeddingAPIResponse {
|
|
20
|
+
object: "list";
|
|
21
|
+
data: {
|
|
22
|
+
object: "embedding";
|
|
23
|
+
index: number;
|
|
24
|
+
embedding: number[];
|
|
25
|
+
}[];
|
|
26
|
+
model: string;
|
|
27
|
+
usage: {
|
|
28
|
+
prompt_tokens: number;
|
|
29
|
+
total_tokens: number;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build an OpenAI-format embeddings API response for one or more inputs.
|
|
34
|
+
*/
|
|
35
|
+
declare function buildEmbeddingResponse(embeddings: number[][], model: string): EmbeddingAPIResponse;
|
|
36
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
37
|
+
//#endregion
|
|
38
|
+
export { EmbeddingAPIResponse, buildEmbeddingResponse, buildTextChunks, buildToolCallChunks, flattenHeaders, generateDeterministicEmbedding, generateId, generateMessageId, generateToolCallId, generateToolUseId, isEmbeddingResponse };
|
|
39
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","names":[],"sources":["../src/helpers.ts"],"sourcesContent":[],"mappings":";;;;iBAegB,cAAA,UAAwB,IAAA,CAAK,sBAAsB;iBAanD,UAAA;AAbA,iBAiBA,kBAAA,CAAA,CAjBc,EAAA,MAAA;AAAA,iBAqBd,iBAAA,CAAA,CArBc,EAAA,MAAA;AAAU,iBAyBxB,iBAAA,CAAA,CAzB6B,EAAA,MAAA;AAiB7B,iBA4BA,mBAAA,CA5BkB,CAAA,EA4BK,eA5BL,CAAA,EAAA,CAAA,IA4B4B,iBA5B5B;AAIlB,iBA4BA,eAAA,CA5BiB,OAAA,EAAA,MAAA,EAAA,KAAA,EAAA,MAAA,EAAA,SAAA,EAAA,MAAA,CAAA,EA4BmD,QA5BnD,EAAA;AAIjB,iBA8DA,mBAAA,CA9DiB,SAAA,EA+DpB,QA/DoB,EAAA,EAAA,KAAA,EAAA,MAAA,EAAA,SAAA,EAAA,MAAA,CAAA,EAkE9B,QAlE8B,EAAA;;AAwBjC;AAsCA;;;AAIG,iBAuJa,8BAAA,CAvJb,KAAA,EAAA,MAAA,EAAA,UAAA,CAAA,EAAA,MAAA,CAAA,EAAA,MAAA,EAAA;AAAQ,UAuKM,oBAAA,CAvKN;EAuJK,MAAA,EAAA,MAAA;EAgBC,IAAA,EAAA;IAUD,MAAA,EAAA,WAAA;;;;;;;;;;;;;iBAAA,sBAAA,yCAGb"}
|
package/dist/helpers.js
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
//#region src/helpers.ts
|
|
4
|
+
const REDACTED_HEADERS = new Set([
|
|
5
|
+
"authorization",
|
|
6
|
+
"x-api-key",
|
|
7
|
+
"api-key"
|
|
8
|
+
]);
|
|
9
|
+
function flattenHeaders(headers) {
|
|
10
|
+
const flat = {};
|
|
11
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
12
|
+
if (value === void 0) continue;
|
|
13
|
+
if (REDACTED_HEADERS.has(key.toLowerCase())) flat[key] = "[REDACTED]";
|
|
14
|
+
else flat[key] = Array.isArray(value) ? value.join(", ") : value;
|
|
15
|
+
}
|
|
16
|
+
return flat;
|
|
17
|
+
}
|
|
18
|
+
function generateId(prefix = "chatcmpl") {
|
|
19
|
+
return `${prefix}-${randomBytes(12).toString("base64url")}`;
|
|
20
|
+
}
|
|
21
|
+
function generateToolCallId() {
|
|
22
|
+
return `call_${randomBytes(12).toString("base64url")}`;
|
|
23
|
+
}
|
|
24
|
+
function generateMessageId() {
|
|
25
|
+
return `msg_${randomBytes(12).toString("base64url")}`;
|
|
26
|
+
}
|
|
27
|
+
function generateToolUseId() {
|
|
28
|
+
return `toolu_${randomBytes(12).toString("base64url")}`;
|
|
29
|
+
}
|
|
30
|
+
function isTextResponse(r) {
|
|
31
|
+
return "content" in r && typeof r.content === "string";
|
|
32
|
+
}
|
|
33
|
+
function isToolCallResponse(r) {
|
|
34
|
+
return "toolCalls" in r && Array.isArray(r.toolCalls);
|
|
35
|
+
}
|
|
36
|
+
function isErrorResponse(r) {
|
|
37
|
+
return "error" in r && r.error !== null && typeof r.error === "object";
|
|
38
|
+
}
|
|
39
|
+
function isEmbeddingResponse(r) {
|
|
40
|
+
return "embedding" in r && Array.isArray(r.embedding);
|
|
41
|
+
}
|
|
42
|
+
function buildTextChunks(content, model, chunkSize) {
|
|
43
|
+
const id = generateId();
|
|
44
|
+
const created = Math.floor(Date.now() / 1e3);
|
|
45
|
+
const chunks = [];
|
|
46
|
+
chunks.push({
|
|
47
|
+
id,
|
|
48
|
+
object: "chat.completion.chunk",
|
|
49
|
+
created,
|
|
50
|
+
model,
|
|
51
|
+
choices: [{
|
|
52
|
+
index: 0,
|
|
53
|
+
delta: {
|
|
54
|
+
role: "assistant",
|
|
55
|
+
content: ""
|
|
56
|
+
},
|
|
57
|
+
finish_reason: null
|
|
58
|
+
}]
|
|
59
|
+
});
|
|
60
|
+
for (let i = 0; i < content.length; i += chunkSize) {
|
|
61
|
+
const slice = content.slice(i, i + chunkSize);
|
|
62
|
+
chunks.push({
|
|
63
|
+
id,
|
|
64
|
+
object: "chat.completion.chunk",
|
|
65
|
+
created,
|
|
66
|
+
model,
|
|
67
|
+
choices: [{
|
|
68
|
+
index: 0,
|
|
69
|
+
delta: { content: slice },
|
|
70
|
+
finish_reason: null
|
|
71
|
+
}]
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
chunks.push({
|
|
75
|
+
id,
|
|
76
|
+
object: "chat.completion.chunk",
|
|
77
|
+
created,
|
|
78
|
+
model,
|
|
79
|
+
choices: [{
|
|
80
|
+
index: 0,
|
|
81
|
+
delta: {},
|
|
82
|
+
finish_reason: "stop"
|
|
83
|
+
}]
|
|
84
|
+
});
|
|
85
|
+
return chunks;
|
|
86
|
+
}
|
|
87
|
+
function buildToolCallChunks(toolCalls, model, chunkSize) {
|
|
88
|
+
const id = generateId();
|
|
89
|
+
const created = Math.floor(Date.now() / 1e3);
|
|
90
|
+
const chunks = [];
|
|
91
|
+
chunks.push({
|
|
92
|
+
id,
|
|
93
|
+
object: "chat.completion.chunk",
|
|
94
|
+
created,
|
|
95
|
+
model,
|
|
96
|
+
choices: [{
|
|
97
|
+
index: 0,
|
|
98
|
+
delta: {
|
|
99
|
+
role: "assistant",
|
|
100
|
+
content: null
|
|
101
|
+
},
|
|
102
|
+
finish_reason: null
|
|
103
|
+
}]
|
|
104
|
+
});
|
|
105
|
+
for (let tcIdx = 0; tcIdx < toolCalls.length; tcIdx++) {
|
|
106
|
+
const tc = toolCalls[tcIdx];
|
|
107
|
+
const tcId = tc.id || generateToolCallId();
|
|
108
|
+
chunks.push({
|
|
109
|
+
id,
|
|
110
|
+
object: "chat.completion.chunk",
|
|
111
|
+
created,
|
|
112
|
+
model,
|
|
113
|
+
choices: [{
|
|
114
|
+
index: 0,
|
|
115
|
+
delta: { tool_calls: [{
|
|
116
|
+
index: tcIdx,
|
|
117
|
+
id: tcId,
|
|
118
|
+
type: "function",
|
|
119
|
+
function: {
|
|
120
|
+
name: tc.name,
|
|
121
|
+
arguments: ""
|
|
122
|
+
}
|
|
123
|
+
}] },
|
|
124
|
+
finish_reason: null
|
|
125
|
+
}]
|
|
126
|
+
});
|
|
127
|
+
const args = tc.arguments;
|
|
128
|
+
for (let i = 0; i < args.length; i += chunkSize) {
|
|
129
|
+
const slice = args.slice(i, i + chunkSize);
|
|
130
|
+
chunks.push({
|
|
131
|
+
id,
|
|
132
|
+
object: "chat.completion.chunk",
|
|
133
|
+
created,
|
|
134
|
+
model,
|
|
135
|
+
choices: [{
|
|
136
|
+
index: 0,
|
|
137
|
+
delta: { tool_calls: [{
|
|
138
|
+
index: tcIdx,
|
|
139
|
+
function: { arguments: slice }
|
|
140
|
+
}] },
|
|
141
|
+
finish_reason: null
|
|
142
|
+
}]
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
chunks.push({
|
|
147
|
+
id,
|
|
148
|
+
object: "chat.completion.chunk",
|
|
149
|
+
created,
|
|
150
|
+
model,
|
|
151
|
+
choices: [{
|
|
152
|
+
index: 0,
|
|
153
|
+
delta: {},
|
|
154
|
+
finish_reason: "tool_calls"
|
|
155
|
+
}]
|
|
156
|
+
});
|
|
157
|
+
return chunks;
|
|
158
|
+
}
|
|
159
|
+
function buildTextCompletion(content, model) {
|
|
160
|
+
return {
|
|
161
|
+
id: generateId(),
|
|
162
|
+
object: "chat.completion",
|
|
163
|
+
created: Math.floor(Date.now() / 1e3),
|
|
164
|
+
model,
|
|
165
|
+
choices: [{
|
|
166
|
+
index: 0,
|
|
167
|
+
message: {
|
|
168
|
+
role: "assistant",
|
|
169
|
+
content,
|
|
170
|
+
refusal: null
|
|
171
|
+
},
|
|
172
|
+
finish_reason: "stop"
|
|
173
|
+
}],
|
|
174
|
+
usage: {
|
|
175
|
+
prompt_tokens: 0,
|
|
176
|
+
completion_tokens: 0,
|
|
177
|
+
total_tokens: 0
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function buildToolCallCompletion(toolCalls, model) {
|
|
182
|
+
return {
|
|
183
|
+
id: generateId(),
|
|
184
|
+
object: "chat.completion",
|
|
185
|
+
created: Math.floor(Date.now() / 1e3),
|
|
186
|
+
model,
|
|
187
|
+
choices: [{
|
|
188
|
+
index: 0,
|
|
189
|
+
message: {
|
|
190
|
+
role: "assistant",
|
|
191
|
+
content: null,
|
|
192
|
+
refusal: null,
|
|
193
|
+
tool_calls: toolCalls.map((tc) => ({
|
|
194
|
+
id: tc.id || generateToolCallId(),
|
|
195
|
+
type: "function",
|
|
196
|
+
function: {
|
|
197
|
+
name: tc.name,
|
|
198
|
+
arguments: tc.arguments
|
|
199
|
+
}
|
|
200
|
+
}))
|
|
201
|
+
},
|
|
202
|
+
finish_reason: "tool_calls"
|
|
203
|
+
}],
|
|
204
|
+
usage: {
|
|
205
|
+
prompt_tokens: 0,
|
|
206
|
+
completion_tokens: 0,
|
|
207
|
+
total_tokens: 0
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function readBody(req) {
|
|
212
|
+
return new Promise((resolve, reject) => {
|
|
213
|
+
const chunks = [];
|
|
214
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
215
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString()));
|
|
216
|
+
req.on("error", reject);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
function matchesPattern(text, pattern) {
|
|
220
|
+
if (typeof pattern === "string") return text.toLowerCase().includes(pattern.toLowerCase());
|
|
221
|
+
return pattern.test(text);
|
|
222
|
+
}
|
|
223
|
+
const DEFAULT_EMBEDDING_DIMENSIONS = 1536;
|
|
224
|
+
/**
|
|
225
|
+
* Generate a deterministic embedding vector from input text.
|
|
226
|
+
* Hashes the input with SHA-256 and spreads the hash bytes across
|
|
227
|
+
* the requested number of dimensions, producing values in [-1, 1].
|
|
228
|
+
*/
|
|
229
|
+
function generateDeterministicEmbedding(input, dimensions = DEFAULT_EMBEDDING_DIMENSIONS) {
|
|
230
|
+
let currentHash = createHash("sha256").update(input).digest();
|
|
231
|
+
const embedding = new Array(dimensions);
|
|
232
|
+
for (let i = 0; i < dimensions; i++) {
|
|
233
|
+
if (i > 0 && i % 32 === 0) currentHash = createHash("sha256").update(currentHash).digest();
|
|
234
|
+
embedding[i] = currentHash[i % 32] / 127.5 - 1;
|
|
235
|
+
}
|
|
236
|
+
return embedding;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Build an OpenAI-format embeddings API response for one or more inputs.
|
|
240
|
+
*/
|
|
241
|
+
function buildEmbeddingResponse(embeddings, model) {
|
|
242
|
+
return {
|
|
243
|
+
object: "list",
|
|
244
|
+
data: embeddings.map((embedding, index) => ({
|
|
245
|
+
object: "embedding",
|
|
246
|
+
index,
|
|
247
|
+
embedding
|
|
248
|
+
})),
|
|
249
|
+
model,
|
|
250
|
+
usage: {
|
|
251
|
+
prompt_tokens: 0,
|
|
252
|
+
total_tokens: 0
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
//#endregion
|
|
258
|
+
export { buildEmbeddingResponse, buildTextChunks, buildTextCompletion, buildToolCallChunks, buildToolCallCompletion, flattenHeaders, generateDeterministicEmbedding, generateId, generateMessageId, generateToolCallId, generateToolUseId, isEmbeddingResponse, isErrorResponse, isTextResponse, isToolCallResponse, matchesPattern, readBody };
|
|
259
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","names":[],"sources":["../src/helpers.ts"],"sourcesContent":["import { createHash, randomBytes } from \"node:crypto\";\nimport type * as http from \"node:http\";\nimport type {\n FixtureResponse,\n TextResponse,\n ToolCallResponse,\n ErrorResponse,\n EmbeddingResponse,\n SSEChunk,\n ToolCall,\n ChatCompletion,\n} from \"./types.js\";\n\nconst REDACTED_HEADERS = new Set([\"authorization\", \"x-api-key\", \"api-key\"]);\n\nexport function flattenHeaders(headers: http.IncomingHttpHeaders): Record<string, string> {\n const flat: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (value === undefined) continue;\n if (REDACTED_HEADERS.has(key.toLowerCase())) {\n flat[key] = \"[REDACTED]\";\n } else {\n flat[key] = Array.isArray(value) ? value.join(\", \") : value;\n }\n }\n return flat;\n}\n\nexport function generateId(prefix = \"chatcmpl\"): string {\n return `${prefix}-${randomBytes(12).toString(\"base64url\")}`;\n}\n\nexport function generateToolCallId(): string {\n return `call_${randomBytes(12).toString(\"base64url\")}`;\n}\n\nexport function generateMessageId(): string {\n return `msg_${randomBytes(12).toString(\"base64url\")}`;\n}\n\nexport function generateToolUseId(): string {\n return `toolu_${randomBytes(12).toString(\"base64url\")}`;\n}\n\nexport function isTextResponse(r: FixtureResponse): r is TextResponse {\n return \"content\" in r && typeof (r as TextResponse).content === \"string\";\n}\n\nexport function isToolCallResponse(r: FixtureResponse): r is ToolCallResponse {\n return \"toolCalls\" in r && Array.isArray((r as ToolCallResponse).toolCalls);\n}\n\nexport function isErrorResponse(r: FixtureResponse): r is ErrorResponse {\n return (\n \"error\" in r &&\n (r as ErrorResponse).error !== null &&\n typeof (r as ErrorResponse).error === \"object\"\n );\n}\n\nexport function isEmbeddingResponse(r: FixtureResponse): r is EmbeddingResponse {\n return \"embedding\" in r && Array.isArray((r as EmbeddingResponse).embedding);\n}\n\nexport function buildTextChunks(content: string, model: string, chunkSize: number): SSEChunk[] {\n const id = generateId();\n const created = Math.floor(Date.now() / 1000);\n const chunks: SSEChunk[] = [];\n\n // Role chunk\n chunks.push({\n id,\n object: \"chat.completion.chunk\",\n created,\n model,\n choices: [{ index: 0, delta: { role: \"assistant\", content: \"\" }, finish_reason: null }],\n });\n\n // Content chunks\n for (let i = 0; i < content.length; i += chunkSize) {\n const slice = content.slice(i, i + chunkSize);\n chunks.push({\n id,\n object: \"chat.completion.chunk\",\n created,\n model,\n choices: [{ index: 0, delta: { content: slice }, finish_reason: null }],\n });\n }\n\n // Finish chunk\n chunks.push({\n id,\n object: \"chat.completion.chunk\",\n created,\n model,\n choices: [{ index: 0, delta: {}, finish_reason: \"stop\" }],\n });\n\n return chunks;\n}\n\nexport function buildToolCallChunks(\n toolCalls: ToolCall[],\n model: string,\n chunkSize: number,\n): SSEChunk[] {\n const id = generateId();\n const created = Math.floor(Date.now() / 1000);\n const chunks: SSEChunk[] = [];\n\n // Role chunk\n chunks.push({\n id,\n object: \"chat.completion.chunk\",\n created,\n model,\n choices: [{ index: 0, delta: { role: \"assistant\", content: null }, finish_reason: null }],\n });\n\n // Tool call chunks — one initial chunk per tool call, then argument chunks\n for (let tcIdx = 0; tcIdx < toolCalls.length; tcIdx++) {\n const tc = toolCalls[tcIdx];\n const tcId = tc.id || generateToolCallId();\n\n // Initial tool call chunk (id + function name)\n chunks.push({\n id,\n object: \"chat.completion.chunk\",\n created,\n model,\n choices: [\n {\n index: 0,\n delta: {\n tool_calls: [\n {\n index: tcIdx,\n id: tcId,\n type: \"function\",\n function: { name: tc.name, arguments: \"\" },\n },\n ],\n },\n finish_reason: null,\n },\n ],\n });\n\n // Argument streaming chunks\n const args = tc.arguments;\n for (let i = 0; i < args.length; i += chunkSize) {\n const slice = args.slice(i, i + chunkSize);\n chunks.push({\n id,\n object: \"chat.completion.chunk\",\n created,\n model,\n choices: [\n {\n index: 0,\n delta: {\n tool_calls: [{ index: tcIdx, function: { arguments: slice } }],\n },\n finish_reason: null,\n },\n ],\n });\n }\n }\n\n // Finish chunk\n chunks.push({\n id,\n object: \"chat.completion.chunk\",\n created,\n model,\n choices: [{ index: 0, delta: {}, finish_reason: \"tool_calls\" }],\n });\n\n return chunks;\n}\n\n// Non-streaming response builders\n\nexport function buildTextCompletion(content: string, model: string): ChatCompletion {\n return {\n id: generateId(),\n object: \"chat.completion\",\n created: Math.floor(Date.now() / 1000),\n model,\n choices: [\n {\n index: 0,\n message: { role: \"assistant\", content, refusal: null },\n finish_reason: \"stop\",\n },\n ],\n usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n };\n}\n\nexport function buildToolCallCompletion(toolCalls: ToolCall[], model: string): ChatCompletion {\n return {\n id: generateId(),\n object: \"chat.completion\",\n created: Math.floor(Date.now() / 1000),\n model,\n choices: [\n {\n index: 0,\n message: {\n role: \"assistant\",\n content: null,\n refusal: null,\n tool_calls: toolCalls.map((tc) => ({\n id: tc.id || generateToolCallId(),\n type: \"function\" as const,\n function: { name: tc.name, arguments: tc.arguments },\n })),\n },\n finish_reason: \"tool_calls\",\n },\n ],\n usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },\n };\n}\n\n// ─── HTTP helpers ─────────────────────────────────────────────────────────\n\nexport function readBody(req: http.IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n req.on(\"end\", () => resolve(Buffer.concat(chunks).toString()));\n req.on(\"error\", reject);\n });\n}\n\n// ─── Pattern matching ─────────────────────────────────────────────────────\n\nexport function matchesPattern(text: string, pattern: string | RegExp): boolean {\n if (typeof pattern === \"string\") {\n return text.toLowerCase().includes(pattern.toLowerCase());\n }\n return pattern.test(text);\n}\n\n// ─── Embedding helpers ─────────────────────────────────────────────────────\n\nconst DEFAULT_EMBEDDING_DIMENSIONS = 1536;\n\n/**\n * Generate a deterministic embedding vector from input text.\n * Hashes the input with SHA-256 and spreads the hash bytes across\n * the requested number of dimensions, producing values in [-1, 1].\n */\nexport function generateDeterministicEmbedding(\n input: string,\n dimensions: number = DEFAULT_EMBEDDING_DIMENSIONS,\n): number[] {\n let currentHash = createHash(\"sha256\").update(input).digest();\n const embedding: number[] = new Array(dimensions);\n for (let i = 0; i < dimensions; i++) {\n if (i > 0 && i % 32 === 0) {\n currentHash = createHash(\"sha256\").update(currentHash).digest();\n }\n // Map 0-255 → -1.0 to 1.0\n embedding[i] = currentHash[i % 32] / 127.5 - 1;\n }\n return embedding;\n}\n\nexport interface EmbeddingAPIResponse {\n object: \"list\";\n data: { object: \"embedding\"; index: number; embedding: number[] }[];\n model: string;\n usage: { prompt_tokens: number; total_tokens: number };\n}\n\n/**\n * Build an OpenAI-format embeddings API response for one or more inputs.\n */\nexport function buildEmbeddingResponse(\n embeddings: number[][],\n model: string,\n): EmbeddingAPIResponse {\n return {\n object: \"list\",\n data: embeddings.map((embedding, index) => ({\n object: \"embedding\" as const,\n index,\n embedding,\n })),\n model,\n usage: { prompt_tokens: 0, total_tokens: 0 },\n };\n}\n"],"mappings":"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"}
|