@symerian/symi 3.0.18 → 3.0.19

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 (116) hide show
  1. package/dist/build-info.json +3 -3
  2. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  3. package/package.json +1 -1
  4. package/extensions/copilot-proxy/README.md +0 -24
  5. package/extensions/copilot-proxy/index.ts +0 -154
  6. package/extensions/copilot-proxy/node_modules/.bin/symi +0 -21
  7. package/extensions/copilot-proxy/package.json +0 -15
  8. package/extensions/copilot-proxy/symi.plugin.json +0 -9
  9. package/extensions/device-pair/index.ts +0 -642
  10. package/extensions/device-pair/symi.plugin.json +0 -20
  11. package/extensions/diagnostics-otel/index.ts +0 -15
  12. package/extensions/diagnostics-otel/node_modules/.bin/acorn +0 -21
  13. package/extensions/diagnostics-otel/node_modules/.bin/symi +0 -21
  14. package/extensions/diagnostics-otel/package.json +0 -27
  15. package/extensions/diagnostics-otel/src/service.test.ts +0 -290
  16. package/extensions/diagnostics-otel/src/service.ts +0 -666
  17. package/extensions/diagnostics-otel/symi.plugin.json +0 -8
  18. package/extensions/google-antigravity-auth/README.md +0 -24
  19. package/extensions/google-antigravity-auth/index.ts +0 -424
  20. package/extensions/google-antigravity-auth/node_modules/.bin/symi +0 -21
  21. package/extensions/google-antigravity-auth/package.json +0 -15
  22. package/extensions/google-antigravity-auth/symi.plugin.json +0 -9
  23. package/extensions/google-gemini-cli-auth/README.md +0 -35
  24. package/extensions/google-gemini-cli-auth/index.ts +0 -75
  25. package/extensions/google-gemini-cli-auth/node_modules/.bin/symi +0 -21
  26. package/extensions/google-gemini-cli-auth/oauth.test.ts +0 -162
  27. package/extensions/google-gemini-cli-auth/oauth.ts +0 -636
  28. package/extensions/google-gemini-cli-auth/package.json +0 -15
  29. package/extensions/google-gemini-cli-auth/symi.plugin.json +0 -9
  30. package/extensions/learning-loop/index.ts +0 -159
  31. package/extensions/learning-loop/node_modules/.bin/symi +0 -21
  32. package/extensions/learning-loop/package.json +0 -18
  33. package/extensions/learning-loop/src/analytics/gateway-methods.ts +0 -230
  34. package/extensions/learning-loop/src/analytics/metrics-aggregator.ts +0 -153
  35. package/extensions/learning-loop/src/capture/run-tracker.ts +0 -181
  36. package/extensions/learning-loop/src/capture/serializer.ts +0 -74
  37. package/extensions/learning-loop/src/db.ts +0 -583
  38. package/extensions/learning-loop/src/feedback/explicit-feedback.ts +0 -58
  39. package/extensions/learning-loop/src/feedback/implicit-signals.ts +0 -89
  40. package/extensions/learning-loop/src/graph/edge-inference.ts +0 -189
  41. package/extensions/learning-loop/src/graph/graph-retrieval.ts +0 -144
  42. package/extensions/learning-loop/src/graph/graph-store.ts +0 -183
  43. package/extensions/learning-loop/src/hooks.ts +0 -244
  44. package/extensions/learning-loop/src/injection/cache.ts +0 -73
  45. package/extensions/learning-loop/src/injection/context-injector.ts +0 -104
  46. package/extensions/learning-loop/src/injection/prompt-builder.ts +0 -43
  47. package/extensions/learning-loop/src/learning/embedding-bridge.ts +0 -54
  48. package/extensions/learning-loop/src/learning/learning-extractor.ts +0 -217
  49. package/extensions/learning-loop/src/learning/learning-store.ts +0 -158
  50. package/extensions/learning-loop/src/learning/retrieval.ts +0 -87
  51. package/extensions/learning-loop/src/math/confidence-intervals.ts +0 -62
  52. package/extensions/learning-loop/src/math/ewma.ts +0 -51
  53. package/extensions/learning-loop/src/math/weighted-scorer.ts +0 -42
  54. package/extensions/learning-loop/src/schema.ts +0 -176
  55. package/extensions/learning-loop/src/scoring/normalization.ts +0 -32
  56. package/extensions/learning-loop/src/scoring/quality-engine.ts +0 -78
  57. package/extensions/learning-loop/src/scoring/signal-extractors.ts +0 -155
  58. package/extensions/learning-loop/src/test/context-injector.test.ts +0 -142
  59. package/extensions/learning-loop/src/test/fixes.test.ts +0 -1286
  60. package/extensions/learning-loop/src/test/graph.test.ts +0 -711
  61. package/extensions/learning-loop/src/test/integration.test.ts +0 -312
  62. package/extensions/learning-loop/src/test/learning-store.test.ts +0 -191
  63. package/extensions/learning-loop/src/test/math.test.ts +0 -148
  64. package/extensions/learning-loop/src/test/quality-engine.test.ts +0 -231
  65. package/extensions/learning-loop/src/test/run-tracker.test.ts +0 -143
  66. package/extensions/learning-loop/src/types.ts +0 -281
  67. package/extensions/learning-loop/symi.plugin.json +0 -46
  68. package/extensions/llm-task/README.md +0 -97
  69. package/extensions/llm-task/index.ts +0 -6
  70. package/extensions/llm-task/package.json +0 -12
  71. package/extensions/llm-task/src/llm-task-tool.test.ts +0 -138
  72. package/extensions/llm-task/src/llm-task-tool.ts +0 -249
  73. package/extensions/llm-task/symi.plugin.json +0 -21
  74. package/extensions/memory-lancedb/config.ts +0 -161
  75. package/extensions/memory-lancedb/index.test.ts +0 -330
  76. package/extensions/memory-lancedb/index.ts +0 -670
  77. package/extensions/memory-lancedb/node_modules/.bin/arrow2csv +0 -21
  78. package/extensions/memory-lancedb/node_modules/.bin/openai +0 -21
  79. package/extensions/memory-lancedb/node_modules/.bin/symi +0 -21
  80. package/extensions/memory-lancedb/package.json +0 -20
  81. package/extensions/memory-lancedb/symi.plugin.json +0 -71
  82. package/extensions/minimax-portal-auth/README.md +0 -33
  83. package/extensions/minimax-portal-auth/index.ts +0 -161
  84. package/extensions/minimax-portal-auth/node_modules/.bin/symi +0 -21
  85. package/extensions/minimax-portal-auth/oauth.ts +0 -247
  86. package/extensions/minimax-portal-auth/package.json +0 -15
  87. package/extensions/minimax-portal-auth/symi.plugin.json +0 -9
  88. package/extensions/model-equalizer/index.ts +0 -80
  89. package/extensions/model-equalizer/skills/model-equalizer/SKILL.md +0 -58
  90. package/extensions/model-equalizer/src/detection.ts +0 -62
  91. package/extensions/model-equalizer/src/enhancer.ts +0 -63
  92. package/extensions/model-equalizer/src/test/detection.test.ts +0 -218
  93. package/extensions/model-equalizer/src/test/enhancer.test.ts +0 -137
  94. package/extensions/model-equalizer/src/test/integration.test.ts +0 -185
  95. package/extensions/model-equalizer/src/types.ts +0 -24
  96. package/extensions/model-equalizer/symi.plugin.json +0 -12
  97. package/extensions/phone-control/index.ts +0 -421
  98. package/extensions/phone-control/symi.plugin.json +0 -10
  99. package/extensions/pipeline/README.md +0 -75
  100. package/extensions/pipeline/SKILL.md +0 -97
  101. package/extensions/pipeline/index.ts +0 -18
  102. package/extensions/pipeline/package.json +0 -11
  103. package/extensions/pipeline/src/pipeline-tool.test.ts +0 -345
  104. package/extensions/pipeline/src/pipeline-tool.ts +0 -266
  105. package/extensions/pipeline/src/windows-spawn.test.ts +0 -148
  106. package/extensions/pipeline/src/windows-spawn.ts +0 -193
  107. package/extensions/pipeline/symi.plugin.json +0 -10
  108. package/extensions/qwen-portal-auth/README.md +0 -24
  109. package/extensions/qwen-portal-auth/index.ts +0 -134
  110. package/extensions/qwen-portal-auth/oauth.ts +0 -190
  111. package/extensions/qwen-portal-auth/symi.plugin.json +0 -9
  112. package/extensions/talk-voice/index.ts +0 -150
  113. package/extensions/talk-voice/symi.plugin.json +0 -10
  114. package/extensions/thread-ownership/index.test.ts +0 -180
  115. package/extensions/thread-ownership/index.ts +0 -133
  116. package/extensions/thread-ownership/symi.plugin.json +0 -28
@@ -1,80 +0,0 @@
1
- import type { SymiPluginApi } from "symi/plugin-sdk";
2
- import { buildProviderMap, isLocalProvider, resolveDefaultProvider } from "./src/detection.js";
3
- import { buildEnhancement } from "./src/enhancer.js";
4
- import { resolveConfig } from "./src/types.js";
5
-
6
- const plugin = {
7
- id: "model-equalizer",
8
- name: "Model Equalizer",
9
- description:
10
- "Automatically enhances prompts for local models (Ollama, vLLM, LM Studio, llama.cpp) with chain-of-thought scaffolding and self-verification to close the quality gap with paid API models.",
11
-
12
- register(api: SymiPluginApi) {
13
- const config = resolveConfig(api.pluginConfig);
14
- const logger = api.logger;
15
-
16
- if (!config.enabled) {
17
- logger.debug?.("[model-equalizer] disabled via config");
18
- return;
19
- }
20
-
21
- // Build provider→isLocal map from config at registration time
22
- const providerMap = buildProviderMap(api.config);
23
-
24
- // Cached provider per session (populated by llm_input)
25
- const sessionProviders = new Map<string, string>();
26
-
27
- // -----------------------------------------------------------------------
28
- // llm_input (priority 100) — detect and cache provider per session
29
- // -----------------------------------------------------------------------
30
- api.on(
31
- "llm_input",
32
- (event, ctx) => {
33
- if (ctx.sessionKey) {
34
- sessionProviders.set(ctx.sessionKey, event.provider);
35
- }
36
- },
37
- { priority: 100 },
38
- );
39
-
40
- // -----------------------------------------------------------------------
41
- // before_prompt_build (priority 180) — inject enhancement for local models
42
- // Runs before learning-loop's 200 so learnings are prepended first.
43
- // -----------------------------------------------------------------------
44
- api.on(
45
- "before_prompt_build",
46
- async (event, ctx) => {
47
- try {
48
- const provider =
49
- sessionProviders.get(ctx.sessionKey ?? "") ?? resolveDefaultProvider(api.config);
50
-
51
- if (!provider) return undefined;
52
-
53
- const isLocal =
54
- providerMap.get(provider.trim().toLowerCase()) ?? isLocalProvider(provider);
55
- if (!isLocal) return undefined;
56
-
57
- const enhancement = buildEnhancement(event.prompt, {
58
- intensity: config.intensity,
59
- minPromptLength: config.minPromptLength,
60
- });
61
- if (!enhancement) return undefined;
62
-
63
- logger.debug?.(`[model-equalizer] enhancing prompt for local provider "${provider}"`);
64
- return { prependContext: enhancement };
65
- } catch (err) {
66
- logger.warn(`[model-equalizer] before_prompt_build failed: ${String(err)}`);
67
- return undefined;
68
- }
69
- },
70
- { priority: 180 },
71
- );
72
-
73
- logger.debug?.(
74
- `[model-equalizer] registered (intensity=${config.intensity}, ` +
75
- `${providerMap.size} providers mapped)`,
76
- );
77
- },
78
- };
79
-
80
- export default plugin;
@@ -1,58 +0,0 @@
1
- ---
2
- name: model-equalizer
3
- description: Shows model-equalizer status and whether prompt enhancement is active for the current model.
4
- metadata: { "symi": {} }
5
- ---
6
-
7
- # Model Equalizer Status
8
-
9
- The model-equalizer extension automatically detects local LLM providers (Ollama, vLLM, LM Studio, llama.cpp) and injects prompt enhancement techniques to improve response quality.
10
-
11
- ## When to Activate
12
-
13
- Activate this skill when the user:
14
-
15
- - Asks about model-equalizer status
16
- - Wants to know if prompt enhancement is active
17
- - Asks what enhancement techniques are being applied
18
- - Mentions "equalizer" in the context of model quality
19
-
20
- ## What to Report
21
-
22
- When invoked, check and report:
23
-
24
- 1. **Extension status**: Whether model-equalizer is enabled in the plugin config
25
- 2. **Current provider detection**: Whether the active provider is detected as local
26
- 3. **Enhancement intensity**: The configured intensity level (light / standard / aggressive)
27
- 4. **Techniques applied**: List the specific enhancement techniques being injected
28
-
29
- ## Enhancement Techniques
30
-
31
- Depending on the configured intensity and prompt complexity, these techniques may be applied:
32
-
33
- ### Standard (default for simple prompts)
34
-
35
- - Step-by-step reasoning
36
- - Self-verification after drafting
37
- - Thoroughness anchoring
38
- - Instruction following reinforcement
39
-
40
- ### Complex (auto-detected or aggressive intensity)
41
-
42
- - Problem decomposition into sub-problems
43
- - Step-by-step reasoning per sub-problem
44
- - Accuracy and completeness verification
45
- - Detailed responses with examples
46
- - Instruction following reinforcement
47
- - Structured output formatting
48
-
49
- ### Light
50
-
51
- - Condensed step-by-step + verify + be thorough reminder
52
-
53
- ## Known Local Providers
54
-
55
- The following provider names are recognized as local:
56
- `ollama`, `vllm`, `lmstudio`, `lm-studio`, `lm_studio`, `llama.cpp`, `llama-cpp`, `llamacpp`, `local`
57
-
58
- Any provider with a `baseUrl` containing `localhost`, `127.0.0.1`, or `[::1]` is also treated as local.
@@ -1,62 +0,0 @@
1
- import type { SymiConfig } from "symi/plugin-sdk";
2
-
3
- const LOCAL_PROVIDERS = new Set([
4
- "ollama",
5
- "vllm",
6
- "lmstudio",
7
- "lm-studio",
8
- "lm_studio",
9
- "llama.cpp",
10
- "llama-cpp",
11
- "llamacpp",
12
- "local",
13
- ]);
14
-
15
- /**
16
- * Check whether a provider name is a known local provider.
17
- */
18
- export function isLocalProvider(provider: string): boolean {
19
- return LOCAL_PROVIDERS.has(provider.trim().toLowerCase());
20
- }
21
-
22
- /**
23
- * Check whether a base URL points to a local server.
24
- */
25
- export function isLocalBaseUrl(baseUrl: string | undefined): boolean {
26
- if (!baseUrl) return false;
27
- const url = baseUrl.trim().toLowerCase();
28
- return url.includes("localhost") || url.includes("127.0.0.1") || url.includes("[::1]");
29
- }
30
-
31
- /**
32
- * Build a map of provider-name → isLocal from the full config.
33
- */
34
- export function buildProviderMap(config: SymiConfig): Map<string, boolean> {
35
- const map = new Map<string, boolean>();
36
- const providers = config.models?.providers ?? {};
37
- for (const [name, cfg] of Object.entries(providers)) {
38
- const normalized = name.trim().toLowerCase();
39
- map.set(normalized, isLocalProvider(normalized) || isLocalBaseUrl(cfg.baseUrl));
40
- }
41
- return map;
42
- }
43
-
44
- /**
45
- * Extract the provider name from the default agent's model string.
46
- * Model strings are formatted as "provider/model-id".
47
- * Returns null if no default agent or no model configured.
48
- */
49
- export function resolveDefaultProvider(config: SymiConfig): string | null {
50
- const agents = config.agents?.list ?? [];
51
- const defaultAgent = agents.find((a) => a.default === true) ?? agents[0];
52
- if (!defaultAgent?.model) return null;
53
-
54
- const modelStr =
55
- typeof defaultAgent.model === "string" ? defaultAgent.model : defaultAgent.model.primary;
56
- if (!modelStr) return null;
57
-
58
- const slashIdx = modelStr.indexOf("/");
59
- if (slashIdx <= 0) return null;
60
-
61
- return modelStr.slice(0, slashIdx).trim().toLowerCase();
62
- }
@@ -1,63 +0,0 @@
1
- import type { ModelEqualizerConfig } from "./types.js";
2
-
3
- export type EnhancerOptions = {
4
- intensity?: ModelEqualizerConfig["intensity"];
5
- minPromptLength?: number;
6
- };
7
-
8
- const STANDARD_BLOCK = `<model-equalizer>
9
- You are operating in enhanced reasoning mode. Apply these techniques:
10
- 1. Think step-by-step: break the problem down before answering
11
- 2. Self-verify: after drafting your response, check for errors and correct them
12
- 3. Be thorough: provide complete, detailed, professional-quality responses
13
- 4. Follow instructions precisely: address every part of the user's request
14
- </model-equalizer>`;
15
-
16
- const COMPLEX_BLOCK = `<model-equalizer>
17
- You are operating in enhanced reasoning mode. Apply these techniques:
18
- 1. Decompose: identify all sub-problems before solving
19
- 2. Think step-by-step: reason through each sub-problem carefully
20
- 3. Self-verify: review your complete response for accuracy and completeness
21
- 4. Be thorough: provide detailed, professional-quality responses with examples
22
- 5. Follow instructions precisely: address every part of the user's request
23
- 6. Structure your output: use headers, lists, and code blocks for clarity
24
- </model-equalizer>`;
25
-
26
- const LIGHT_BLOCK = `<model-equalizer>
27
- Think step-by-step. Verify your answer before responding. Be thorough and precise.
28
- </model-equalizer>`;
29
-
30
- /**
31
- * Detect whether a prompt is "complex" based on heuristics:
32
- * - length > 200 chars
33
- * - contains code blocks (```)
34
- * - contains multiple question marks (multi-part question)
35
- */
36
- function isComplexPrompt(prompt: string): boolean {
37
- if (prompt.length > 200) return true;
38
- if (prompt.includes("```")) return true;
39
- const questionMarks = (prompt.match(/\?/g) ?? []).length;
40
- if (questionMarks >= 2) return true;
41
- return false;
42
- }
43
-
44
- /**
45
- * Build a prompt enhancement block for local models.
46
- * Returns null if enhancement should be skipped.
47
- */
48
- export function buildEnhancement(prompt: string, options?: EnhancerOptions): string | null {
49
- const minLen = options?.minPromptLength ?? 10;
50
- if (prompt.trim().length < minLen) return null;
51
-
52
- const intensity = options?.intensity ?? "standard";
53
-
54
- if (intensity === "light") {
55
- return LIGHT_BLOCK;
56
- }
57
-
58
- if (intensity === "aggressive" || isComplexPrompt(prompt)) {
59
- return COMPLEX_BLOCK;
60
- }
61
-
62
- return STANDARD_BLOCK;
63
- }
@@ -1,218 +0,0 @@
1
- import type { SymiConfig } from "symi/plugin-sdk";
2
- import { describe, it, expect } from "vitest";
3
- import {
4
- isLocalProvider,
5
- isLocalBaseUrl,
6
- buildProviderMap,
7
- resolveDefaultProvider,
8
- } from "../detection.js";
9
-
10
- // ---------------------------------------------------------------------------
11
- // isLocalProvider
12
- // ---------------------------------------------------------------------------
13
- describe("isLocalProvider", () => {
14
- it.each([
15
- "ollama",
16
- "vllm",
17
- "lmstudio",
18
- "lm-studio",
19
- "lm_studio",
20
- "llama.cpp",
21
- "llama-cpp",
22
- "llamacpp",
23
- "local",
24
- ])("should detect '%s' as local", (provider) => {
25
- expect(isLocalProvider(provider)).toBe(true);
26
- });
27
-
28
- it("should be case-insensitive", () => {
29
- expect(isLocalProvider("Ollama")).toBe(true);
30
- expect(isLocalProvider("VLLM")).toBe(true);
31
- expect(isLocalProvider("LMStudio")).toBe(true);
32
- });
33
-
34
- it("should trim whitespace", () => {
35
- expect(isLocalProvider(" ollama ")).toBe(true);
36
- });
37
-
38
- it.each(["openai", "anthropic", "google", "azure", "bedrock", "mistral"])(
39
- "should not detect '%s' as local",
40
- (provider) => {
41
- expect(isLocalProvider(provider)).toBe(false);
42
- },
43
- );
44
-
45
- it("should return false for empty string", () => {
46
- expect(isLocalProvider("")).toBe(false);
47
- });
48
- });
49
-
50
- // ---------------------------------------------------------------------------
51
- // isLocalBaseUrl
52
- // ---------------------------------------------------------------------------
53
- describe("isLocalBaseUrl", () => {
54
- it("should detect localhost URLs", () => {
55
- expect(isLocalBaseUrl("http://localhost:11434")).toBe(true);
56
- expect(isLocalBaseUrl("http://localhost:8080/v1")).toBe(true);
57
- expect(isLocalBaseUrl("https://localhost")).toBe(true);
58
- });
59
-
60
- it("should detect 127.0.0.1 URLs", () => {
61
- expect(isLocalBaseUrl("http://127.0.0.1:11434")).toBe(true);
62
- expect(isLocalBaseUrl("http://127.0.0.1:5000/v1")).toBe(true);
63
- });
64
-
65
- it("should detect IPv6 loopback URLs", () => {
66
- expect(isLocalBaseUrl("http://[::1]:11434")).toBe(true);
67
- });
68
-
69
- it("should be case-insensitive", () => {
70
- expect(isLocalBaseUrl("HTTP://LOCALHOST:8080")).toBe(true);
71
- });
72
-
73
- it("should trim whitespace", () => {
74
- expect(isLocalBaseUrl(" http://localhost:11434 ")).toBe(true);
75
- });
76
-
77
- it("should not detect remote URLs", () => {
78
- expect(isLocalBaseUrl("https://api.openai.com/v1")).toBe(false);
79
- expect(isLocalBaseUrl("https://api.anthropic.com")).toBe(false);
80
- });
81
-
82
- it("should return false for undefined", () => {
83
- expect(isLocalBaseUrl(undefined)).toBe(false);
84
- });
85
-
86
- it("should return false for empty string", () => {
87
- expect(isLocalBaseUrl("")).toBe(false);
88
- });
89
- });
90
-
91
- // ---------------------------------------------------------------------------
92
- // buildProviderMap
93
- // ---------------------------------------------------------------------------
94
- describe("buildProviderMap", () => {
95
- it("should map known local providers as local", () => {
96
- const config: SymiConfig = {
97
- models: {
98
- providers: {
99
- ollama: { baseUrl: "http://localhost:11434", models: [] },
100
- openai: { baseUrl: "https://api.openai.com/v1", models: [] },
101
- },
102
- },
103
- };
104
- const map = buildProviderMap(config);
105
- expect(map.get("ollama")).toBe(true);
106
- expect(map.get("openai")).toBe(false);
107
- });
108
-
109
- it("should detect local by baseUrl even with unknown name", () => {
110
- const config: SymiConfig = {
111
- models: {
112
- providers: {
113
- "my-custom-model": { baseUrl: "http://localhost:8080/v1", models: [] },
114
- },
115
- },
116
- };
117
- const map = buildProviderMap(config);
118
- expect(map.get("my-custom-model")).toBe(true);
119
- });
120
-
121
- it("should normalize provider names to lowercase", () => {
122
- const config: SymiConfig = {
123
- models: {
124
- providers: {
125
- Ollama: { baseUrl: "http://remote.example.com", models: [] },
126
- },
127
- },
128
- };
129
- const map = buildProviderMap(config);
130
- expect(map.get("ollama")).toBe(true); // Known local name wins
131
- });
132
-
133
- it("should return empty map when no providers configured", () => {
134
- const config: SymiConfig = {};
135
- const map = buildProviderMap(config);
136
- expect(map.size).toBe(0);
137
- });
138
-
139
- it("should handle providers with no baseUrl using name-only detection", () => {
140
- const config: SymiConfig = {
141
- models: {
142
- providers: {
143
- vllm: { baseUrl: "", models: [] },
144
- },
145
- },
146
- };
147
- const map = buildProviderMap(config);
148
- expect(map.get("vllm")).toBe(true); // Known local name
149
- });
150
- });
151
-
152
- // ---------------------------------------------------------------------------
153
- // resolveDefaultProvider
154
- // ---------------------------------------------------------------------------
155
- describe("resolveDefaultProvider", () => {
156
- it("should extract provider from default agent's model string", () => {
157
- const config: SymiConfig = {
158
- agents: {
159
- list: [{ id: "main", default: true, model: "ollama/llama3.1" }],
160
- },
161
- };
162
- expect(resolveDefaultProvider(config)).toBe("ollama");
163
- });
164
-
165
- it("should extract provider from object-form model config", () => {
166
- const config: SymiConfig = {
167
- agents: {
168
- list: [{ id: "main", default: true, model: { primary: "vllm/mistral-7b" } }],
169
- },
170
- };
171
- expect(resolveDefaultProvider(config)).toBe("vllm");
172
- });
173
-
174
- it("should fall back to the first agent when no default is set", () => {
175
- const config: SymiConfig = {
176
- agents: {
177
- list: [
178
- { id: "first", model: "lmstudio/phi-3" },
179
- { id: "second", model: "openai/gpt-4" },
180
- ],
181
- },
182
- };
183
- expect(resolveDefaultProvider(config)).toBe("lmstudio");
184
- });
185
-
186
- it("should return null when no agents are configured", () => {
187
- const config: SymiConfig = {};
188
- expect(resolveDefaultProvider(config)).toBeNull();
189
- });
190
-
191
- it("should return null when agent has no model", () => {
192
- const config: SymiConfig = {
193
- agents: { list: [{ id: "main", default: true }] },
194
- };
195
- expect(resolveDefaultProvider(config)).toBeNull();
196
- });
197
-
198
- it("should return null for model strings without a slash", () => {
199
- const config: SymiConfig = {
200
- agents: { list: [{ id: "main", default: true, model: "gpt-4" }] },
201
- };
202
- expect(resolveDefaultProvider(config)).toBeNull();
203
- });
204
-
205
- it("should return null for model strings starting with a slash", () => {
206
- const config: SymiConfig = {
207
- agents: { list: [{ id: "main", default: true, model: "/model-only" }] },
208
- };
209
- expect(resolveDefaultProvider(config)).toBeNull();
210
- });
211
-
212
- it("should normalize the provider name to lowercase", () => {
213
- const config: SymiConfig = {
214
- agents: { list: [{ id: "main", default: true, model: "Ollama/Llama3" }] },
215
- };
216
- expect(resolveDefaultProvider(config)).toBe("ollama");
217
- });
218
- });
@@ -1,137 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { buildEnhancement } from "../enhancer.js";
3
-
4
- describe("buildEnhancement", () => {
5
- // ---------------------------------------------------------------------------
6
- // Skip conditions
7
- // ---------------------------------------------------------------------------
8
- describe("skip conditions", () => {
9
- it("should return null for very short prompts", () => {
10
- expect(buildEnhancement("hi")).toBeNull();
11
- expect(buildEnhancement("ok")).toBeNull();
12
- });
13
-
14
- it("should return null for empty prompt", () => {
15
- expect(buildEnhancement("")).toBeNull();
16
- });
17
-
18
- it("should return null for whitespace-only prompt", () => {
19
- expect(buildEnhancement(" ")).toBeNull();
20
- });
21
-
22
- it("should respect custom minPromptLength", () => {
23
- expect(buildEnhancement("hello world", { minPromptLength: 20 })).toBeNull();
24
- expect(buildEnhancement("hello world and more!", { minPromptLength: 20 })).not.toBeNull();
25
- });
26
- });
27
-
28
- // ---------------------------------------------------------------------------
29
- // Standard enhancement
30
- // ---------------------------------------------------------------------------
31
- describe("standard enhancement", () => {
32
- it("should return standard block for normal prompts", () => {
33
- const result = buildEnhancement("What is the capital of France?");
34
- expect(result).not.toBeNull();
35
- expect(result).toContain("<model-equalizer>");
36
- expect(result).toContain("</model-equalizer>");
37
- expect(result).toContain("Think step-by-step");
38
- expect(result).toContain("Self-verify");
39
- });
40
-
41
- it("should not include decompose step for simple prompts", () => {
42
- const result = buildEnhancement("What is 2+2?");
43
- expect(result).not.toBeNull();
44
- expect(result).not.toContain("Decompose");
45
- });
46
- });
47
-
48
- // ---------------------------------------------------------------------------
49
- // Complex prompt detection
50
- // ---------------------------------------------------------------------------
51
- describe("complex prompt detection", () => {
52
- it("should use complex block for long prompts (>200 chars)", () => {
53
- const longPrompt = "a".repeat(201);
54
- const result = buildEnhancement(longPrompt);
55
- expect(result).not.toBeNull();
56
- expect(result).toContain("Decompose");
57
- expect(result).toContain("Structure your output");
58
- });
59
-
60
- it("should use complex block for prompts with code blocks", () => {
61
- const prompt = "Fix this code:\n```\nconst x = 1;\n```";
62
- const result = buildEnhancement(prompt);
63
- expect(result).not.toBeNull();
64
- expect(result).toContain("Decompose");
65
- });
66
-
67
- it("should use complex block for multi-question prompts", () => {
68
- const prompt = "What is X? How does Y work?";
69
- const result = buildEnhancement(prompt);
70
- expect(result).not.toBeNull();
71
- expect(result).toContain("Decompose");
72
- });
73
-
74
- it("should use standard block for single-question prompts", () => {
75
- const prompt = "How does this work?";
76
- const result = buildEnhancement(prompt);
77
- expect(result).not.toBeNull();
78
- expect(result).not.toContain("Decompose");
79
- });
80
- });
81
-
82
- // ---------------------------------------------------------------------------
83
- // Intensity levels
84
- // ---------------------------------------------------------------------------
85
- describe("intensity levels", () => {
86
- it("should use light block for light intensity", () => {
87
- const result = buildEnhancement("Explain this concept please", {
88
- intensity: "light",
89
- });
90
- expect(result).not.toBeNull();
91
- expect(result).toContain("<model-equalizer>");
92
- expect(result).toContain("Think step-by-step");
93
- // Light block is compact, no numbered list
94
- expect(result).not.toContain("1.");
95
- });
96
-
97
- it("should use complex block for aggressive intensity regardless of prompt", () => {
98
- const result = buildEnhancement("Simple question?", {
99
- intensity: "aggressive",
100
- });
101
- expect(result).not.toBeNull();
102
- expect(result).toContain("Decompose");
103
- expect(result).toContain("Structure your output");
104
- });
105
-
106
- it("should use standard block for standard intensity with simple prompt", () => {
107
- const result = buildEnhancement("Explain this concept", {
108
- intensity: "standard",
109
- });
110
- expect(result).not.toBeNull();
111
- expect(result).toContain("Think step-by-step");
112
- expect(result).not.toContain("Decompose");
113
- });
114
- });
115
-
116
- // ---------------------------------------------------------------------------
117
- // Block format
118
- // ---------------------------------------------------------------------------
119
- describe("block format", () => {
120
- it("should wrap content in <model-equalizer> tags", () => {
121
- const result = buildEnhancement("Tell me about something");
122
- expect(result).not.toBeNull();
123
- expect(result!.startsWith("<model-equalizer>")).toBe(true);
124
- expect(result!.endsWith("</model-equalizer>")).toBe(true);
125
- });
126
-
127
- it("should be reasonably sized (under 600 chars)", () => {
128
- const standard = buildEnhancement("Tell me about something");
129
- expect(standard).not.toBeNull();
130
- expect(standard!.length).toBeLessThan(600);
131
-
132
- const complex = buildEnhancement("a".repeat(201));
133
- expect(complex).not.toBeNull();
134
- expect(complex!.length).toBeLessThan(600);
135
- });
136
- });
137
- });