bikky 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.
Files changed (124) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +323 -0
  3. package/bin/bikky.js +6 -0
  4. package/dist/cli.d.ts +12 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +51 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/config.d.ts +59 -0
  9. package/dist/config.d.ts.map +1 -0
  10. package/dist/config.js +141 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/config.test.d.ts +8 -0
  13. package/dist/config.test.d.ts.map +1 -0
  14. package/dist/config.test.js +449 -0
  15. package/dist/config.test.js.map +1 -0
  16. package/dist/daemon/consolidation.d.ts +60 -0
  17. package/dist/daemon/consolidation.d.ts.map +1 -0
  18. package/dist/daemon/consolidation.js +448 -0
  19. package/dist/daemon/consolidation.js.map +1 -0
  20. package/dist/daemon/extraction.d.ts +17 -0
  21. package/dist/daemon/extraction.d.ts.map +1 -0
  22. package/dist/daemon/extraction.js +465 -0
  23. package/dist/daemon/extraction.js.map +1 -0
  24. package/dist/daemon/index.d.ts +3 -0
  25. package/dist/daemon/index.d.ts.map +1 -0
  26. package/dist/daemon/index.js +3 -0
  27. package/dist/daemon/index.js.map +1 -0
  28. package/dist/daemon/loop.d.ts +3 -0
  29. package/dist/daemon/loop.d.ts.map +1 -0
  30. package/dist/daemon/loop.js +93 -0
  31. package/dist/daemon/loop.js.map +1 -0
  32. package/dist/daemon/qdrant.d.ts +103 -0
  33. package/dist/daemon/qdrant.d.ts.map +1 -0
  34. package/dist/daemon/qdrant.js +273 -0
  35. package/dist/daemon/qdrant.js.map +1 -0
  36. package/dist/daemon/qdrant.test.d.ts +8 -0
  37. package/dist/daemon/qdrant.test.d.ts.map +1 -0
  38. package/dist/daemon/qdrant.test.js +209 -0
  39. package/dist/daemon/qdrant.test.js.map +1 -0
  40. package/dist/daemon/relations.d.ts +54 -0
  41. package/dist/daemon/relations.d.ts.map +1 -0
  42. package/dist/daemon/relations.js +290 -0
  43. package/dist/daemon/relations.js.map +1 -0
  44. package/dist/daemon/staleness.d.ts +24 -0
  45. package/dist/daemon/staleness.d.ts.map +1 -0
  46. package/dist/daemon/staleness.js +63 -0
  47. package/dist/daemon/staleness.js.map +1 -0
  48. package/dist/daemon/watcher.d.ts +11 -0
  49. package/dist/daemon/watcher.d.ts.map +1 -0
  50. package/dist/daemon/watcher.js +38 -0
  51. package/dist/daemon/watcher.js.map +1 -0
  52. package/dist/daemon/watcher.test.d.ts +8 -0
  53. package/dist/daemon/watcher.test.d.ts.map +1 -0
  54. package/dist/daemon/watcher.test.js +214 -0
  55. package/dist/daemon/watcher.test.js.map +1 -0
  56. package/dist/install.d.ts +5 -0
  57. package/dist/install.d.ts.map +1 -0
  58. package/dist/install.js +49 -0
  59. package/dist/install.js.map +1 -0
  60. package/dist/install.test.d.ts +9 -0
  61. package/dist/install.test.d.ts.map +1 -0
  62. package/dist/install.test.js +126 -0
  63. package/dist/install.test.js.map +1 -0
  64. package/dist/llm/embedding.d.ts +13 -0
  65. package/dist/llm/embedding.d.ts.map +1 -0
  66. package/dist/llm/embedding.js +127 -0
  67. package/dist/llm/embedding.js.map +1 -0
  68. package/dist/llm/embedding.test.d.ts +8 -0
  69. package/dist/llm/embedding.test.d.ts.map +1 -0
  70. package/dist/llm/embedding.test.js +117 -0
  71. package/dist/llm/embedding.test.js.map +1 -0
  72. package/dist/llm/index.d.ts +4 -0
  73. package/dist/llm/index.d.ts.map +1 -0
  74. package/dist/llm/index.js +3 -0
  75. package/dist/llm/index.js.map +1 -0
  76. package/dist/llm/inference.d.ts +12 -0
  77. package/dist/llm/inference.d.ts.map +1 -0
  78. package/dist/llm/inference.js +146 -0
  79. package/dist/llm/inference.js.map +1 -0
  80. package/dist/llm/inference.test.d.ts +8 -0
  81. package/dist/llm/inference.test.d.ts.map +1 -0
  82. package/dist/llm/inference.test.js +117 -0
  83. package/dist/llm/inference.test.js.map +1 -0
  84. package/dist/llm/types.d.ts +41 -0
  85. package/dist/llm/types.d.ts.map +1 -0
  86. package/dist/llm/types.js +5 -0
  87. package/dist/llm/types.js.map +1 -0
  88. package/dist/logger.d.ts +13 -0
  89. package/dist/logger.d.ts.map +1 -0
  90. package/dist/logger.js +41 -0
  91. package/dist/logger.js.map +1 -0
  92. package/dist/mcp/api.d.ts +30 -0
  93. package/dist/mcp/api.d.ts.map +1 -0
  94. package/dist/mcp/api.js +150 -0
  95. package/dist/mcp/api.js.map +1 -0
  96. package/dist/mcp/helpers.d.ts +35 -0
  97. package/dist/mcp/helpers.d.ts.map +1 -0
  98. package/dist/mcp/helpers.js +152 -0
  99. package/dist/mcp/helpers.js.map +1 -0
  100. package/dist/mcp/helpers.test.d.ts +5 -0
  101. package/dist/mcp/helpers.test.d.ts.map +1 -0
  102. package/dist/mcp/helpers.test.js +487 -0
  103. package/dist/mcp/helpers.test.js.map +1 -0
  104. package/dist/mcp/index.d.ts +9 -0
  105. package/dist/mcp/index.d.ts.map +1 -0
  106. package/dist/mcp/index.js +67 -0
  107. package/dist/mcp/index.js.map +1 -0
  108. package/dist/mcp/taxonomy.d.ts +38 -0
  109. package/dist/mcp/taxonomy.d.ts.map +1 -0
  110. package/dist/mcp/taxonomy.js +223 -0
  111. package/dist/mcp/taxonomy.js.map +1 -0
  112. package/dist/mcp/taxonomy.test.d.ts +5 -0
  113. package/dist/mcp/taxonomy.test.d.ts.map +1 -0
  114. package/dist/mcp/taxonomy.test.js +341 -0
  115. package/dist/mcp/taxonomy.test.js.map +1 -0
  116. package/dist/mcp/tools.d.ts +6 -0
  117. package/dist/mcp/tools.d.ts.map +1 -0
  118. package/dist/mcp/tools.js +958 -0
  119. package/dist/mcp/tools.js.map +1 -0
  120. package/dist/mcp/types.d.ts +118 -0
  121. package/dist/mcp/types.d.ts.map +1 -0
  122. package/dist/mcp/types.js +5 -0
  123. package/dist/mcp/types.js.map +1 -0
  124. package/package.json +56 -0
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Tests for the embedding module.
3
+ *
4
+ * These tests verify initialization and config, NOT actual embedding calls
5
+ * (which require a live Ollama/OpenAI/Bedrock service).
6
+ */
7
+ import { describe, it, beforeEach } from "node:test";
8
+ import assert from "node:assert/strict";
9
+ import { initEmbedding, getEmbeddingConfig, getEmbeddingDimensions, embed, } from "./embedding.js";
10
+ // ---------------------------------------------------------------------------
11
+ // initEmbedding
12
+ // ---------------------------------------------------------------------------
13
+ describe("initEmbedding", () => {
14
+ it("returns config with ollama defaults when called with no args", () => {
15
+ const cfg = initEmbedding();
16
+ assert.strictEqual(cfg.provider, "ollama");
17
+ assert.strictEqual(cfg.model, "qwen3-embedding:0.6b");
18
+ assert.strictEqual(cfg.dimensions, 1024);
19
+ assert.strictEqual(cfg.baseUrl, "http://localhost:11434");
20
+ assert.strictEqual(cfg.apiKey, null);
21
+ });
22
+ it("accepts ollama provider with overrides", () => {
23
+ const cfg = initEmbedding({
24
+ provider: "ollama",
25
+ model: "nomic-embed-text",
26
+ dimensions: 768,
27
+ baseUrl: "http://custom:11434",
28
+ });
29
+ assert.strictEqual(cfg.provider, "ollama");
30
+ assert.strictEqual(cfg.model, "nomic-embed-text");
31
+ assert.strictEqual(cfg.dimensions, 768);
32
+ assert.strictEqual(cfg.baseUrl, "http://custom:11434");
33
+ });
34
+ it("accepts openai provider", () => {
35
+ const cfg = initEmbedding({
36
+ provider: "openai",
37
+ apiKey: "sk-test-key",
38
+ });
39
+ assert.strictEqual(cfg.provider, "openai");
40
+ assert.strictEqual(cfg.model, "text-embedding-3-small");
41
+ assert.strictEqual(cfg.dimensions, 1536);
42
+ assert.strictEqual(cfg.baseUrl, "https://api.openai.com");
43
+ assert.strictEqual(cfg.apiKey, "sk-test-key");
44
+ });
45
+ it("accepts bedrock provider", () => {
46
+ const cfg = initEmbedding({ provider: "bedrock" });
47
+ assert.strictEqual(cfg.provider, "bedrock");
48
+ assert.strictEqual(cfg.model, "amazon.titan-embed-text-v2:0");
49
+ assert.strictEqual(cfg.dimensions, 1024);
50
+ });
51
+ it("strips trailing slashes from baseUrl", () => {
52
+ const cfg = initEmbedding({
53
+ provider: "ollama",
54
+ baseUrl: "http://localhost:11434///",
55
+ });
56
+ assert.strictEqual(cfg.baseUrl, "http://localhost:11434");
57
+ });
58
+ it("defaults apiKey to null when not provided", () => {
59
+ const cfg = initEmbedding({ provider: "ollama" });
60
+ assert.strictEqual(cfg.apiKey, null);
61
+ });
62
+ });
63
+ // ---------------------------------------------------------------------------
64
+ // getEmbeddingConfig
65
+ // ---------------------------------------------------------------------------
66
+ describe("getEmbeddingConfig", () => {
67
+ it("returns the initialized config", () => {
68
+ const init = initEmbedding({ provider: "openai", apiKey: "key-123" });
69
+ const retrieved = getEmbeddingConfig();
70
+ assert.deepStrictEqual(retrieved, init);
71
+ });
72
+ it("returns same object after init", () => {
73
+ initEmbedding({ provider: "ollama" });
74
+ const cfg = getEmbeddingConfig();
75
+ assert.strictEqual(cfg.provider, "ollama");
76
+ });
77
+ });
78
+ // ---------------------------------------------------------------------------
79
+ // getEmbeddingDimensions
80
+ // ---------------------------------------------------------------------------
81
+ describe("getEmbeddingDimensions", () => {
82
+ it("returns dimensions from initialized config", () => {
83
+ initEmbedding({ provider: "ollama", dimensions: 512 });
84
+ assert.strictEqual(getEmbeddingDimensions(), 512);
85
+ });
86
+ it("returns openai default dimensions", () => {
87
+ initEmbedding({ provider: "openai" });
88
+ assert.strictEqual(getEmbeddingDimensions(), 1536);
89
+ });
90
+ });
91
+ // ---------------------------------------------------------------------------
92
+ // embed — error cases only (no live service calls)
93
+ // ---------------------------------------------------------------------------
94
+ describe("embed", () => {
95
+ beforeEach(() => {
96
+ // Ensure we're initialized but pointing to a non-existent server
97
+ initEmbedding({
98
+ provider: "ollama",
99
+ baseUrl: "http://localhost:99999", // nothing listening
100
+ });
101
+ });
102
+ it("throws on empty text", async () => {
103
+ await assert.rejects(() => embed(""), {
104
+ message: /empty text/,
105
+ });
106
+ });
107
+ it("throws on whitespace-only text", async () => {
108
+ await assert.rejects(() => embed(" "), {
109
+ message: /empty text/,
110
+ });
111
+ });
112
+ it("throws/rejects when service is unreachable", async () => {
113
+ // This will fail to connect — we just verify it throws, not the exact message
114
+ await assert.rejects(() => embed("test content"));
115
+ });
116
+ });
117
+ //# sourceMappingURL=embedding.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedding.test.js","sourceRoot":"","sources":["../../src/llm/embedding.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export type { EmbeddingProviderConfig, InferenceProviderConfig, ChatCompletionOpts, ResponseFormat, LogFn } from "./types.js";
2
+ export { initEmbedding, embed, getEmbeddingConfig, getEmbeddingDimensions } from "./embedding.js";
3
+ export { initLLM, chatCompletion } from "./inference.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/llm/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC9H,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAClG,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { initEmbedding, embed, getEmbeddingConfig, getEmbeddingDimensions } from "./embedding.js";
2
+ export { initLLM, chatCompletion } from "./inference.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/llm/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAClG,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Unified LLM chat-completion client.
3
+ * Routes to Ollama (default), OpenAI, or Bedrock based on config.
4
+ * Ollama → Bedrock fallback when Ollama is primary and fails.
5
+ */
6
+ import type { InferenceProviderConfig, ChatCompletionOpts, LogFn } from "./types.js";
7
+ export declare function initLLM(opts: {
8
+ config: InferenceProviderConfig;
9
+ logger?: LogFn;
10
+ }): void;
11
+ export declare function chatCompletion(opts: ChatCompletionOpts): Promise<string | null>;
12
+ //# sourceMappingURL=inference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inference.d.ts","sourceRoot":"","sources":["../../src/llm/inference.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,OAAO,KAAK,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAQrF,wBAAgB,OAAO,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,uBAAuB,CAAC;IAAC,MAAM,CAAC,EAAE,KAAK,CAAA;CAAE,GAAG,IAAI,CAKvF;AAWD,wBAAsB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAarF"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Unified LLM chat-completion client.
3
+ * Routes to Ollama (default), OpenAI, or Bedrock based on config.
4
+ * Ollama → Bedrock fallback when Ollama is primary and fails.
5
+ */
6
+ import { BedrockRuntimeClient, ConverseCommand, } from "@aws-sdk/client-bedrock-runtime";
7
+ // ── Module state ─────────────────────────────────────────────────────────────
8
+ let cfg = null;
9
+ let log = () => { };
10
+ let bedrockClient = null;
11
+ export function initLLM(opts) {
12
+ cfg = opts.config;
13
+ if (opts.logger)
14
+ log = opts.logger;
15
+ if (cfg.provider === "bedrock")
16
+ initBedrockClient();
17
+ }
18
+ function initBedrockClient() {
19
+ const region = cfg?.bedrock_region ?? process.env.AWS_BEDROCK_REGION ?? process.env.AWS_REGION ?? "us-east-1";
20
+ // Let the AWS SDK resolve credentials via its default chain:
21
+ // env vars → shared credentials file → SSO → IAM role
22
+ bedrockClient = new BedrockRuntimeClient({ region });
23
+ }
24
+ // ── Core function ────────────────────────────────────────────────────────────
25
+ export async function chatCompletion(opts) {
26
+ const provider = cfg?.provider ?? "ollama";
27
+ if (provider === "openai")
28
+ return openaiCompletion(opts);
29
+ if (provider === "ollama") {
30
+ const result = await ollamaCompletion(opts);
31
+ if (result !== null)
32
+ return result;
33
+ log("INFO", "LLM: Ollama failed, falling back to Bedrock");
34
+ return bedrockCompletion(opts);
35
+ }
36
+ return bedrockCompletion(opts);
37
+ }
38
+ // ── Provider implementations ─────────────────────────────────────────────────
39
+ async function ollamaCompletion(opts) {
40
+ const baseUrl = cfg?.ollama_url ?? "http://localhost:11434";
41
+ const model = cfg?.ollama_model ?? "qwen2.5:7b";
42
+ const body = {
43
+ model,
44
+ messages: opts.messages,
45
+ temperature: opts.temperature ?? 0.2,
46
+ max_tokens: opts.max_tokens ?? 500,
47
+ };
48
+ if (opts.response_format) {
49
+ body.response_format = opts.response_format.type === "json_schema"
50
+ ? { type: "json_object" }
51
+ : opts.response_format;
52
+ }
53
+ try {
54
+ const resp = await fetch(`${baseUrl}/v1/chat/completions`, {
55
+ method: "POST",
56
+ headers: { "Content-Type": "application/json" },
57
+ body: JSON.stringify(body),
58
+ });
59
+ if (!resp.ok) {
60
+ const err = await resp.text().catch(() => "");
61
+ log("WARN", `LLM Ollama error (${resp.status}): ${err.slice(0, 200)}`);
62
+ return null;
63
+ }
64
+ const data = (await resp.json());
65
+ return data.choices?.[0]?.message?.content?.trim() ?? null;
66
+ }
67
+ catch (e) {
68
+ log("WARN", `LLM Ollama unreachable: ${e.message}`);
69
+ return null;
70
+ }
71
+ }
72
+ async function openaiCompletion(opts) {
73
+ const apiKey = cfg?.openai_api_key;
74
+ if (!apiKey) {
75
+ log("WARN", "LLM OpenAI: no API key");
76
+ return null;
77
+ }
78
+ const model = cfg?.openai_model ?? "gpt-4.1-mini";
79
+ const body = {
80
+ model,
81
+ messages: opts.messages,
82
+ temperature: opts.temperature ?? 0.2,
83
+ max_tokens: opts.max_tokens ?? 500,
84
+ };
85
+ if (opts.response_format)
86
+ body.response_format = opts.response_format;
87
+ try {
88
+ const resp = await fetch("https://api.openai.com/v1/chat/completions", {
89
+ method: "POST",
90
+ headers: {
91
+ "Content-Type": "application/json",
92
+ "Authorization": `Bearer ${apiKey}`,
93
+ },
94
+ body: JSON.stringify(body),
95
+ });
96
+ if (!resp.ok) {
97
+ const err = await resp.text().catch(() => "");
98
+ log("WARN", `LLM OpenAI error (${resp.status}): ${err.slice(0, 200)}`);
99
+ return null;
100
+ }
101
+ const data = (await resp.json());
102
+ return data.choices?.[0]?.message?.content?.trim() ?? null;
103
+ }
104
+ catch (e) {
105
+ log("WARN", `LLM OpenAI error: ${e.message}`);
106
+ return null;
107
+ }
108
+ }
109
+ async function bedrockCompletion(opts) {
110
+ if (!bedrockClient)
111
+ initBedrockClient();
112
+ const modelId = cfg?.bedrock_model ?? "us.anthropic.claude-sonnet-4-20250514";
113
+ const systemBlocks = [];
114
+ const messages = [];
115
+ for (const m of opts.messages) {
116
+ if (m.role === "system") {
117
+ systemBlocks.push({ text: m.content });
118
+ }
119
+ else {
120
+ messages.push({
121
+ role: m.role,
122
+ content: [{ text: m.content }],
123
+ });
124
+ }
125
+ }
126
+ try {
127
+ const command = new ConverseCommand({
128
+ modelId,
129
+ messages,
130
+ ...(systemBlocks.length > 0 ? { system: systemBlocks } : {}),
131
+ inferenceConfig: {
132
+ maxTokens: opts.max_tokens ?? 500,
133
+ temperature: opts.temperature ?? 0.2,
134
+ },
135
+ });
136
+ const resp = await bedrockClient.send(command);
137
+ const content = resp.output?.message?.content;
138
+ const textBlock = content?.find(c => "text" in c);
139
+ return textBlock?.text?.trim() ?? null;
140
+ }
141
+ catch (e) {
142
+ log("WARN", `LLM Bedrock error: ${e.message}`);
143
+ return null;
144
+ }
145
+ }
146
+ //# sourceMappingURL=inference.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inference.js","sourceRoot":"","sources":["../../src/llm/inference.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Tests for the inference (LLM) module.
3
+ *
4
+ * These tests verify initialization and config, NOT actual LLM calls
5
+ * (which require a live Ollama/OpenAI/Bedrock service).
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=inference.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inference.test.d.ts","sourceRoot":"","sources":["../../src/llm/inference.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Tests for the inference (LLM) module.
3
+ *
4
+ * These tests verify initialization and config, NOT actual LLM calls
5
+ * (which require a live Ollama/OpenAI/Bedrock service).
6
+ */
7
+ import { describe, it } from "node:test";
8
+ import assert from "node:assert/strict";
9
+ import { initLLM, chatCompletion } from "./inference.js";
10
+ // ---------------------------------------------------------------------------
11
+ // Helpers
12
+ // ---------------------------------------------------------------------------
13
+ function makeOllamaConfig(overrides = {}) {
14
+ return {
15
+ provider: "ollama",
16
+ ollama_url: "http://localhost:11434",
17
+ ollama_model: "qwen2.5:7b",
18
+ openai_api_key: null,
19
+ openai_model: "gpt-4.1-mini",
20
+ bedrock_region: "us-east-1",
21
+ bedrock_model: "us.anthropic.claude-sonnet-4-20250514",
22
+ ...overrides,
23
+ };
24
+ }
25
+ function makeOpenaiConfig() {
26
+ return {
27
+ provider: "openai",
28
+ ollama_url: "http://localhost:11434",
29
+ ollama_model: "qwen2.5:7b",
30
+ openai_api_key: "sk-test-key",
31
+ openai_model: "gpt-4.1-mini",
32
+ bedrock_region: "us-east-1",
33
+ bedrock_model: "us.anthropic.claude-sonnet-4-20250514",
34
+ };
35
+ }
36
+ function makeBedrockConfig() {
37
+ return {
38
+ provider: "bedrock",
39
+ ollama_url: "http://localhost:11434",
40
+ ollama_model: "qwen2.5:7b",
41
+ openai_api_key: null,
42
+ openai_model: "gpt-4.1-mini",
43
+ bedrock_region: "us-east-1",
44
+ bedrock_model: "us.anthropic.claude-sonnet-4-20250514",
45
+ };
46
+ }
47
+ // ---------------------------------------------------------------------------
48
+ // initLLM
49
+ // ---------------------------------------------------------------------------
50
+ describe("initLLM", () => {
51
+ it("does not throw with ollama config", () => {
52
+ assert.doesNotThrow(() => {
53
+ initLLM({ config: makeOllamaConfig() });
54
+ });
55
+ });
56
+ it("does not throw with openai config", () => {
57
+ assert.doesNotThrow(() => {
58
+ initLLM({ config: makeOpenaiConfig() });
59
+ });
60
+ });
61
+ it("does not throw with bedrock config", () => {
62
+ assert.doesNotThrow(() => {
63
+ initLLM({ config: makeBedrockConfig() });
64
+ });
65
+ });
66
+ it("accepts optional logger", () => {
67
+ const logs = [];
68
+ initLLM({
69
+ config: makeOllamaConfig(),
70
+ logger: (level, ...args) => logs.push(`${level}: ${args.join(" ")}`),
71
+ });
72
+ // Logger is stored — we can't verify it directly, but it shouldn't throw
73
+ assert.ok(true);
74
+ });
75
+ });
76
+ // ---------------------------------------------------------------------------
77
+ // chatCompletion — error/fallback behavior (no live calls)
78
+ // ---------------------------------------------------------------------------
79
+ describe("chatCompletion", () => {
80
+ it("returns null when ollama is unreachable (falls back to bedrock which also fails)", async () => {
81
+ initLLM({
82
+ config: makeOllamaConfig({ ollama_url: "http://localhost:99999" }),
83
+ });
84
+ const result = await chatCompletion({
85
+ messages: [{ role: "user", content: "hello" }],
86
+ });
87
+ // Ollama fails → falls back to bedrock → which also fails → returns null
88
+ assert.strictEqual(result, null);
89
+ });
90
+ it("returns null when openai has no API key", async () => {
91
+ initLLM({
92
+ config: makeOpenaiConfig(),
93
+ });
94
+ // Override to remove API key
95
+ initLLM({
96
+ config: { ...makeOpenaiConfig(), openai_api_key: null },
97
+ });
98
+ const result = await chatCompletion({
99
+ messages: [{ role: "user", content: "hello" }],
100
+ });
101
+ assert.strictEqual(result, null);
102
+ });
103
+ it("respects temperature and max_tokens options", async () => {
104
+ // Verify the function at least accepts these options without throwing
105
+ initLLM({
106
+ config: makeOllamaConfig({ ollama_url: "http://localhost:99999" }),
107
+ });
108
+ const result = await chatCompletion({
109
+ messages: [{ role: "user", content: "test" }],
110
+ temperature: 0.5,
111
+ max_tokens: 100,
112
+ });
113
+ // Will fail due to unreachable server, but should not throw on options parsing
114
+ assert.strictEqual(result, null);
115
+ });
116
+ });
117
+ //# sourceMappingURL=inference.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inference.test.js","sourceRoot":"","sources":["../../src/llm/inference.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Shared types for embedding and inference providers.
3
+ */
4
+ export type LogFn = (level: string, ...args: unknown[]) => void;
5
+ export interface EmbeddingProviderConfig {
6
+ provider: "ollama" | "openai" | "bedrock";
7
+ baseUrl: string;
8
+ model: string;
9
+ dimensions: number;
10
+ apiKey: string | null;
11
+ }
12
+ export interface InferenceProviderConfig {
13
+ provider: "ollama" | "openai" | "bedrock";
14
+ ollama_url: string;
15
+ ollama_model: string;
16
+ openai_api_key: string | null;
17
+ openai_model: string;
18
+ bedrock_region: string;
19
+ bedrock_model: string;
20
+ }
21
+ export interface ChatCompletionOpts {
22
+ messages: Array<{
23
+ role: string;
24
+ content: string;
25
+ }>;
26
+ temperature?: number;
27
+ max_tokens?: number;
28
+ response_format?: ResponseFormat;
29
+ }
30
+ export type ResponseFormat = {
31
+ type: "json_object";
32
+ } | {
33
+ type: "json_schema";
34
+ json_schema: JsonSchemaSpec;
35
+ };
36
+ export interface JsonSchemaSpec {
37
+ name: string;
38
+ strict?: boolean;
39
+ schema: Record<string, unknown>;
40
+ }
41
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/llm/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;AAIhE,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAID,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,cAAc,CAAC;CAClC;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,WAAW,EAAE,cAAc,CAAA;CAAE,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Shared types for embedding and inference providers.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/llm/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Simple rotating file logger.
3
+ * Writes to file only — stdout/stderr are reserved for MCP stdio transport.
4
+ */
5
+ export type LogLevel = "DEBUG" | "INFO" | "WARN" | "ERROR";
6
+ export type LogFn = (level: LogLevel, ...args: unknown[]) => void;
7
+ interface LoggerOpts {
8
+ maxSize?: number;
9
+ maxFiles?: number;
10
+ }
11
+ export declare function createLogger(name: string, filePath: string, opts?: LoggerOpts): LogFn;
12
+ export {};
13
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAC3D,MAAM,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;AAElE,UAAU,UAAU;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,UAAe,GACpB,KAAK,CAgCP"}
package/dist/logger.js ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Simple rotating file logger.
3
+ * Writes to file only — stdout/stderr are reserved for MCP stdio transport.
4
+ */
5
+ import fs from "node:fs";
6
+ import path from "node:path";
7
+ export function createLogger(name, filePath, opts = {}) {
8
+ const maxSize = opts.maxSize ?? 2 * 1024 * 1024;
9
+ const maxFiles = opts.maxFiles ?? 3;
10
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
11
+ let fd = fs.openSync(filePath, "a");
12
+ let currentSize = 0;
13
+ try {
14
+ currentSize = fs.fstatSync(fd).size;
15
+ }
16
+ catch { /* new file */ }
17
+ function rotate() {
18
+ fs.closeSync(fd);
19
+ for (let i = maxFiles - 1; i >= 1; i--) {
20
+ const from = i === 1 ? filePath : `${filePath}.${i - 1}`;
21
+ const to = `${filePath}.${i}`;
22
+ try {
23
+ fs.renameSync(from, to);
24
+ }
25
+ catch { /* missing file is fine */ }
26
+ }
27
+ fd = fs.openSync(filePath, "w");
28
+ currentSize = 0;
29
+ }
30
+ return (level, ...args) => {
31
+ const ts = new Date().toISOString().replace("T", " ").slice(0, 19);
32
+ const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
33
+ const line = `[${ts}] [${name}] ${level}: ${msg}\n`;
34
+ const buf = Buffer.from(line);
35
+ fs.writeSync(fd, buf);
36
+ currentSize += buf.length;
37
+ if (currentSize > maxSize)
38
+ rotate();
39
+ };
40
+ }
41
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAU7B,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,QAAgB,EAChB,OAAmB,EAAE;IAErB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;IAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;IAEpC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1D,IAAI,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IACpC,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,CAAC;QAAC,WAAW,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,cAAc,CAAC,CAAC;IAErE,SAAS,MAAM;QACb,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACjB,KAAK,IAAI,CAAC,GAAG,QAAQ,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACzD,MAAM,EAAE,GAAG,GAAG,QAAQ,IAAI,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC;gBAAC,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,0BAA0B,CAAC,CAAC;QACvE,CAAC;QACD,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QAChC,WAAW,GAAG,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,KAAe,EAAE,GAAG,IAAe,EAAQ,EAAE;QACnD,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACnE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACzB,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAC9C,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACZ,MAAM,IAAI,GAAG,IAAI,EAAE,MAAM,IAAI,KAAK,KAAK,KAAK,GAAG,IAAI,CAAC;QACpD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9B,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QACtB,WAAW,IAAI,GAAG,CAAC,MAAM,CAAC;QAC1B,IAAI,WAAW,GAAG,OAAO;YAAE,MAAM,EAAE,CAAC;IACtC,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * External API helpers — Qdrant REST client, LLM chat, logging.
3
+ * Credentials come from config (~/.bikky/config.json) or env vars.
4
+ */
5
+ import type { QdrantFilter, QdrantGetResult, QdrantScrollResult, QdrantSearchResult } from "./types.js";
6
+ import { embed, getEmbeddingDimensions, getEmbeddingConfig, initEmbedding } from "../llm/index.js";
7
+ export type { EmbeddingProviderConfig } from "../llm/index.js";
8
+ export { embed, getEmbeddingDimensions, getEmbeddingConfig, initEmbedding };
9
+ export declare const MEMORY_DIR: string;
10
+ export declare function getCollection(): string;
11
+ export declare function setCollection(name: string): void;
12
+ export declare let qdrantUrl: string | null;
13
+ export declare let qdrantApiKey: string | null;
14
+ export declare let ready: boolean;
15
+ export declare function setQdrantUrl(v: string | null): void;
16
+ export declare function setQdrantApiKey(v: string | null): void;
17
+ export declare function setReady(v: boolean): void;
18
+ export declare const log: import("../logger.js").LogFn;
19
+ export declare function chatComplete(systemPrompt: string, userPrompt: string): Promise<string>;
20
+ export declare function qdrantReq<T>(method: string, urlPath: string, body?: unknown): Promise<T>;
21
+ export declare function ensureCollection(indexes: Array<{
22
+ field_name: string;
23
+ field_schema: string;
24
+ }>): Promise<void>;
25
+ export declare function qdrantUpsert(id: string, vector: number[], payload: Record<string, unknown>): Promise<unknown>;
26
+ export declare function qdrantSearch(vector: number[], filter: QdrantFilter | undefined, limit?: number): Promise<QdrantSearchResult>;
27
+ export declare function qdrantScroll(filter: QdrantFilter, limit?: number): Promise<QdrantScrollResult>;
28
+ export declare function qdrantSetPayload(ids: string[], payload: Record<string, unknown>): Promise<unknown>;
29
+ export declare function qdrantGetPoints(ids: string[]): Promise<QdrantGetResult>;
30
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/mcp/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACxG,OAAO,EAAE,KAAK,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,aAAa,EAA2B,MAAM,iBAAiB,CAAC;AAC5H,YAAY,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,KAAK,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,aAAa,EAAE,CAAC;AAS5E,eAAO,MAAM,UAAU,QAAY,CAAC;AAGpC,wBAAgB,aAAa,IAAI,MAAM,CAA2B;AAClE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAA2B;AAW5E,eAAO,IAAI,SAAS,EAAE,MAAM,GAAG,IAAW,CAAC;AAC3C,eAAO,IAAI,YAAY,EAAE,MAAM,GAAG,IAAW,CAAC;AAC9C,eAAO,IAAI,KAAK,SAAQ,CAAC;AAEzB,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAmB;AACvE,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAsB;AAC7E,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAe;AAMzD,eAAO,MAAM,GAAG,8BAGd,CAAC;AAMH,wBAAsB,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA6B5F;AAaD,wBAAsB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAU9F;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BlH;AAED,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAInH;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,YAAY,GAAG,SAAS,EAAE,KAAK,SAAI,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAO7H;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAMhG;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAKxG;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAK7E"}