ex-brain 0.2.3 → 0.2.4

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 CHANGED
@@ -14,7 +14,7 @@ CLI personal knowledge base built on [seekdb](https://docs.seekdb.ai/), featurin
14
14
  - **Hybrid Search** - Full-text search + vector semantic queries
15
15
  - **Entity Linking** - Auto-detect entities and create linked pages
16
16
 
17
- <img src="https://mdn.alipayobjects.com/huamei_ytl0i7/afts/img/A*TqdfTZ-yCPwAAAAAgBAAAAgAejCYAQ/original" width="800">
17
+ <img src="https://mdn.alipayobjects.com/huamei_ytl0i7/afts/img/A*jyPOT4CzwL0AAAAAgBAAAAgAejCYAQ/original" width="800">
18
18
 
19
19
  ## Data Collection
20
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ex-brain",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "CLI personal knowledge base powered by seekdb",
5
5
  "module": "src/cli.ts",
6
6
  "type": "module",
@@ -24,6 +24,7 @@
24
24
  "typescript": "^5"
25
25
  },
26
26
  "dependencies": {
27
+ "@ax-llm/ax": "^19.0.43",
27
28
  "@modelcontextprotocol/sdk": "^1.29.0",
28
29
  "@seekdb/js-bindings": "^1.2.0",
29
30
  "@seekdb/openai": "1.2.0",
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Ax Adapter — bridges ex-brain settings to @ax-llm/ax AI instances.
3
+ *
4
+ * Provides a single factory to create Ax AI clients from ex-brain's
5
+ * ResolvedLLM configuration, supporting any OpenAI-compatible endpoint.
6
+ *
7
+ * Fix: Injects enable_thinking: false for DashScope/qwen compatibility.
8
+ * qwen3.5-plus has thinking mode enabled by default, which doesn't support
9
+ * the tool_choice format Ax uses for complex object outputs.
10
+ */
11
+
12
+ import { ai, AxAIOpenAI, type AxAIServiceOptions } from "@ax-llm/ax";
13
+ import type { ResolvedLLM } from "../settings";
14
+
15
+ // ---------------------------------------------------------------------------
16
+ // Custom fetch wrapper: inject enable_thinking: false
17
+ // ---------------------------------------------------------------------------
18
+
19
+ function createThinkingDisabledFetch(originalFetch: typeof fetch): typeof fetch {
20
+ return async function (input: RequestInfo | URL, init?: RequestInit) {
21
+ if (init?.body && typeof init.body === "string") {
22
+ try {
23
+ const body = JSON.parse(init.body);
24
+ // Disable thinking mode for DashScope/qwen compatibility
25
+ // qwen3.5-plus thinking mode doesn't support tool_choice with object format
26
+ body.enable_thinking = false;
27
+ init.body = JSON.stringify(body);
28
+ } catch {
29
+ // Not JSON, leave as-is
30
+ }
31
+ }
32
+ return originalFetch(input, init);
33
+ };
34
+ }
35
+
36
+ // ---------------------------------------------------------------------------
37
+ // Public API
38
+ // ---------------------------------------------------------------------------
39
+
40
+ /**
41
+ * Create an Ax AI instance from ex-brain LLM settings.
42
+ * Returns null if no API key is configured.
43
+ */
44
+ export function createAxAI(llm: ResolvedLLM): AxAIOpenAI<string> | null {
45
+ const apiKey = resolveApiKey(llm);
46
+ if (!apiKey) return null;
47
+
48
+ // Wrap fetch to inject enable_thinking: false for DashScope compatibility
49
+ const wrappedFetch = createThinkingDisabledFetch(fetch);
50
+
51
+ const options: AxAIServiceOptions = {
52
+ fetch: wrappedFetch,
53
+ };
54
+
55
+ // ex-brain uses OpenAI-compatible endpoints (DashScope, etc.)
56
+ // AxAIOpenAI supports custom apiURL for any compatible endpoint.
57
+ return ai({
58
+ name: "openai",
59
+ apiKey,
60
+ ...(llm.baseURL ? { apiURL: llm.baseURL } : {}),
61
+ ...(llm.model ? { config: { model: llm.model } } : {}),
62
+ options,
63
+ });
64
+ }
65
+
66
+ /**
67
+ * Resolve API key from LLM config (direct key or env var).
68
+ */
69
+ export function resolveApiKey(llm: ResolvedLLM): string {
70
+ if (llm.apiKey) return llm.apiKey;
71
+ if (llm.apiKeyEnv) return process.env[llm.apiKeyEnv] ?? "";
72
+ return "";
73
+ }
74
+
75
+ /**
76
+ * Check if LLM is properly configured with an API key.
77
+ */
78
+ export function isConfigured(llm: ResolvedLLM): boolean {
79
+ return !!resolveApiKey(llm);
80
+ }