fraude-code 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 (127) hide show
  1. package/README.md +68 -0
  2. package/dist/index.js +179297 -0
  3. package/package.json +88 -0
  4. package/src/agent/agent.ts +475 -0
  5. package/src/agent/contextManager.ts +141 -0
  6. package/src/agent/index.ts +14 -0
  7. package/src/agent/pendingChanges.ts +270 -0
  8. package/src/agent/prompts/AskPrompt.txt +10 -0
  9. package/src/agent/prompts/FastPrompt.txt +40 -0
  10. package/src/agent/prompts/PlannerPrompt.txt +51 -0
  11. package/src/agent/prompts/ReviewerPrompt.txt +57 -0
  12. package/src/agent/prompts/WorkerPrompt.txt +33 -0
  13. package/src/agent/subagents/askAgent.ts +37 -0
  14. package/src/agent/subagents/extractionAgent.ts +123 -0
  15. package/src/agent/subagents/fastAgent.ts +45 -0
  16. package/src/agent/subagents/managerAgent.ts +36 -0
  17. package/src/agent/subagents/relationAgent.ts +76 -0
  18. package/src/agent/subagents/researchSubAgent.ts +79 -0
  19. package/src/agent/subagents/reviewerSubAgent.ts +42 -0
  20. package/src/agent/subagents/workerSubAgent.ts +42 -0
  21. package/src/agent/tools/bashTool.ts +94 -0
  22. package/src/agent/tools/descriptions/bash.txt +47 -0
  23. package/src/agent/tools/descriptions/edit.txt +7 -0
  24. package/src/agent/tools/descriptions/glob.txt +4 -0
  25. package/src/agent/tools/descriptions/grep.txt +8 -0
  26. package/src/agent/tools/descriptions/lsp.txt +20 -0
  27. package/src/agent/tools/descriptions/plan.txt +3 -0
  28. package/src/agent/tools/descriptions/read.txt +9 -0
  29. package/src/agent/tools/descriptions/todo.txt +12 -0
  30. package/src/agent/tools/descriptions/write.txt +8 -0
  31. package/src/agent/tools/editTool.ts +44 -0
  32. package/src/agent/tools/globTool.ts +59 -0
  33. package/src/agent/tools/grepTool.ts +343 -0
  34. package/src/agent/tools/lspTool.ts +429 -0
  35. package/src/agent/tools/planTool.ts +118 -0
  36. package/src/agent/tools/readTool.ts +78 -0
  37. package/src/agent/tools/rememberTool.ts +91 -0
  38. package/src/agent/tools/testRunnerTool.ts +77 -0
  39. package/src/agent/tools/testTool.ts +44 -0
  40. package/src/agent/tools/todoTool.ts +224 -0
  41. package/src/agent/tools/writeTool.ts +33 -0
  42. package/src/commands/COMMANDS.ts +38 -0
  43. package/src/commands/cerebras/auth.ts +27 -0
  44. package/src/commands/cerebras/index.ts +31 -0
  45. package/src/commands/forget.ts +29 -0
  46. package/src/commands/google/auth.ts +24 -0
  47. package/src/commands/google/index.ts +31 -0
  48. package/src/commands/groq/add_model.ts +60 -0
  49. package/src/commands/groq/auth.ts +24 -0
  50. package/src/commands/groq/index.ts +33 -0
  51. package/src/commands/index.ts +65 -0
  52. package/src/commands/knowledge.ts +92 -0
  53. package/src/commands/log.ts +32 -0
  54. package/src/commands/mistral/auth.ts +27 -0
  55. package/src/commands/mistral/index.ts +31 -0
  56. package/src/commands/model/index.ts +145 -0
  57. package/src/commands/models/index.ts +16 -0
  58. package/src/commands/ollama/index.ts +29 -0
  59. package/src/commands/openrouter/add_model.ts +64 -0
  60. package/src/commands/openrouter/auth.ts +24 -0
  61. package/src/commands/openrouter/index.ts +33 -0
  62. package/src/commands/remember.ts +48 -0
  63. package/src/commands/serve.ts +31 -0
  64. package/src/commands/session/index.ts +21 -0
  65. package/src/commands/usage.ts +15 -0
  66. package/src/commands/visualize.ts +773 -0
  67. package/src/components/App.tsx +55 -0
  68. package/src/components/IntroComponent.tsx +70 -0
  69. package/src/components/LoaderComponent.tsx +68 -0
  70. package/src/components/OutputRenderer.tsx +88 -0
  71. package/src/components/SettingsRenderer.tsx +23 -0
  72. package/src/components/input/CommandSuggestions.tsx +41 -0
  73. package/src/components/input/FileSuggestions.tsx +61 -0
  74. package/src/components/input/InputBox.tsx +371 -0
  75. package/src/components/output/CheckpointView.tsx +13 -0
  76. package/src/components/output/CommandView.tsx +13 -0
  77. package/src/components/output/CommentView.tsx +12 -0
  78. package/src/components/output/ConfirmationView.tsx +179 -0
  79. package/src/components/output/ContextUsage.tsx +62 -0
  80. package/src/components/output/DiffView.tsx +202 -0
  81. package/src/components/output/ErrorView.tsx +14 -0
  82. package/src/components/output/InteractiveServerView.tsx +69 -0
  83. package/src/components/output/KnowledgeView.tsx +220 -0
  84. package/src/components/output/MarkdownView.tsx +15 -0
  85. package/src/components/output/ModelSelectView.tsx +71 -0
  86. package/src/components/output/ReasoningView.tsx +21 -0
  87. package/src/components/output/ToolCallView.tsx +45 -0
  88. package/src/components/settings/ModelList.tsx +250 -0
  89. package/src/components/settings/TokenUsage.tsx +274 -0
  90. package/src/config/schema.ts +19 -0
  91. package/src/config/settings.ts +229 -0
  92. package/src/index.tsx +100 -0
  93. package/src/parsers/tree-sitter-python.wasm +0 -0
  94. package/src/providers/providers.ts +71 -0
  95. package/src/services/PluginLoader.ts +123 -0
  96. package/src/services/cerebras.ts +69 -0
  97. package/src/services/embeddingService.ts +229 -0
  98. package/src/services/google.ts +65 -0
  99. package/src/services/graphSerializer.ts +248 -0
  100. package/src/services/groq.ts +23 -0
  101. package/src/services/knowledgeOrchestrator.ts +286 -0
  102. package/src/services/mistral.ts +79 -0
  103. package/src/services/ollama.ts +109 -0
  104. package/src/services/openrouter.ts +23 -0
  105. package/src/services/symbolExtractor.ts +277 -0
  106. package/src/store/useFraudeStore.ts +123 -0
  107. package/src/store/useSettingsStore.ts +38 -0
  108. package/src/theme.ts +26 -0
  109. package/src/types/Agent.ts +147 -0
  110. package/src/types/CommandDefinition.ts +8 -0
  111. package/src/types/Model.ts +94 -0
  112. package/src/types/OutputItem.ts +24 -0
  113. package/src/types/PluginContext.ts +55 -0
  114. package/src/types/TokenUsage.ts +5 -0
  115. package/src/types/assets.d.ts +4 -0
  116. package/src/utils/agentCognition.ts +1152 -0
  117. package/src/utils/fileSuggestions.ts +111 -0
  118. package/src/utils/index.ts +17 -0
  119. package/src/utils/initFraude.ts +8 -0
  120. package/src/utils/logger.ts +24 -0
  121. package/src/utils/lspClient.ts +1415 -0
  122. package/src/utils/paths.ts +24 -0
  123. package/src/utils/queryHandler.ts +227 -0
  124. package/src/utils/router.ts +278 -0
  125. package/src/utils/streamHandler.ts +132 -0
  126. package/src/utils/treeSitterQueries.ts +125 -0
  127. package/tsconfig.json +33 -0
@@ -0,0 +1,229 @@
1
+ import { pipeline, type FeatureExtractionPipeline } from "@xenova/transformers";
2
+ import { connect, type Connection, type Table } from "@lancedb/lancedb";
3
+ import path from "path";
4
+
5
+ // ============================================================================
6
+ // Embedding Service - Local embeddings with transformers.js + LanceDB storage
7
+ // ============================================================================
8
+
9
+ class EmbeddingService {
10
+ private static instance: EmbeddingService;
11
+ private extractor: FeatureExtractionPipeline | null = null;
12
+ private db: Connection | null = null;
13
+ private table: Table | null = null;
14
+ private initPromise: Promise<void> | null = null;
15
+
16
+ // Model: all-MiniLM-L6-v2 produces 384-dim embeddings
17
+ private static MODEL_ID = "Xenova/all-MiniLM-L6-v2";
18
+ private static TABLE_NAME = "facts";
19
+
20
+ private constructor() {}
21
+
22
+ static getInstance(): EmbeddingService {
23
+ if (!EmbeddingService.instance) {
24
+ EmbeddingService.instance = new EmbeddingService();
25
+ }
26
+ return EmbeddingService.instance;
27
+ }
28
+
29
+ async init(): Promise<void> {
30
+ if (this.initPromise) return this.initPromise;
31
+ this.initPromise = this.doInit();
32
+ return this.initPromise;
33
+ }
34
+
35
+ private async doInit(): Promise<void> {
36
+ // Initialize transformers.js pipeline
37
+ this.extractor = await pipeline(
38
+ "feature-extraction",
39
+ EmbeddingService.MODEL_ID,
40
+ {
41
+ // Use ONNX runtime for Bun compatibility
42
+ revision: "main",
43
+ },
44
+ );
45
+
46
+ // Initialize LanceDB
47
+ const dbPath = path.join(process.cwd(), ".fraude", "lancedb");
48
+ this.db = await connect(dbPath);
49
+
50
+ // Try to open existing table, or we'll create on first insert
51
+ try {
52
+ this.table = await this.db.openTable(EmbeddingService.TABLE_NAME);
53
+ } catch {
54
+ // Table doesn't exist yet, will create on first insert
55
+ this.table = null;
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Generate embedding for text
61
+ */
62
+ async embed(text: string): Promise<number[]> {
63
+ await this.init();
64
+ if (!this.extractor) throw new Error("Extractor not initialized");
65
+
66
+ const output = await this.extractor(text, {
67
+ pooling: "mean",
68
+ normalize: true,
69
+ });
70
+
71
+ // Convert to regular array
72
+ return Array.from(output.data as Float32Array);
73
+ }
74
+
75
+ /**
76
+ * Store a fact with its embedding
77
+ */
78
+ async store(fact: {
79
+ id: string;
80
+ type: string;
81
+ content: string;
82
+ data?: string;
83
+ timestamp: number;
84
+ sessionId: string;
85
+ confidence: number;
86
+ }): Promise<void> {
87
+ await this.init();
88
+ if (!this.db) throw new Error("Database not initialized");
89
+
90
+ const embedding = await this.embed(fact.content);
91
+
92
+ const record = {
93
+ id: fact.id,
94
+ type: fact.type,
95
+ content: fact.content,
96
+ data: fact.data || "",
97
+ timestamp: fact.timestamp,
98
+ sessionId: fact.sessionId,
99
+ confidence: fact.confidence,
100
+ vector: embedding,
101
+ };
102
+
103
+ if (!this.table) {
104
+ // Create table with first record
105
+ this.table = await this.db.createTable(EmbeddingService.TABLE_NAME, [
106
+ record,
107
+ ]);
108
+ } else {
109
+ // Upsert: delete existing record with same ID before adding
110
+ try {
111
+ await this.table.delete(`id = '${fact.id}'`);
112
+ } catch {
113
+ // Record might not exist, continue with insert
114
+ }
115
+ await this.table.add([record]);
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Search for similar facts using vector similarity
121
+ */
122
+ async search(
123
+ query: string,
124
+ limit: number = 5,
125
+ threshold: number = 0.5,
126
+ ): Promise<
127
+ Array<{
128
+ id: string;
129
+ type: string;
130
+ content: string;
131
+ data: string;
132
+ timestamp: number;
133
+ sessionId: string;
134
+ confidence: number;
135
+ score: number;
136
+ }>
137
+ > {
138
+ await this.init();
139
+ if (!this.table) return [];
140
+
141
+ const queryEmbedding = await this.embed(query);
142
+
143
+ const results = await this.table
144
+ .search(queryEmbedding)
145
+ .limit(limit)
146
+ .toArray();
147
+
148
+ // Filter by threshold and map results
149
+ return results
150
+ .filter((r) => {
151
+ // LanceDB returns _distance (lower is better) or _relevance (higher is better)
152
+ const score = 1 - (r._distance || 0);
153
+ return score >= threshold;
154
+ })
155
+ .map((r) => ({
156
+ id: r.id as string,
157
+ type: r.type as string,
158
+ content: r.content as string,
159
+ data: r.data as string,
160
+ timestamp: r.timestamp as number,
161
+ sessionId: r.sessionId as string,
162
+ confidence: r.confidence as number,
163
+ score: 1 - (r._distance || 0),
164
+ }));
165
+ }
166
+
167
+ /**
168
+ * Delete a fact by ID
169
+ */
170
+ async delete(id: string): Promise<void> {
171
+ await this.init();
172
+ if (!this.table) return;
173
+
174
+ await this.table.delete(`id = '${id}'`);
175
+ }
176
+
177
+ /**
178
+ * Clear all data (drops table)
179
+ */
180
+ async clear(): Promise<void> {
181
+ await this.init();
182
+ if (!this.db) return;
183
+
184
+ try {
185
+ await this.db.dropTable(EmbeddingService.TABLE_NAME);
186
+ this.table = null;
187
+ } catch {
188
+ // Table might not exist
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Get all facts (for migration/debugging)
194
+ */
195
+ async getAll(): Promise<
196
+ Array<{
197
+ id: string;
198
+ type: string;
199
+ content: string;
200
+ data: string;
201
+ timestamp: number;
202
+ }>
203
+ > {
204
+ await this.init();
205
+ if (!this.table) return [];
206
+
207
+ const results = await this.table.query().toArray();
208
+ return results.map((r) => ({
209
+ id: r.id as string,
210
+ type: r.type as string,
211
+ content: r.content as string,
212
+ data: r.data as string,
213
+ timestamp: r.timestamp as number,
214
+ }));
215
+ }
216
+
217
+ /**
218
+ * Close connections
219
+ */
220
+ async close(): Promise<void> {
221
+ // LanceDB doesn't require explicit close, but reset state
222
+ this.table = null;
223
+ this.db = null;
224
+ this.extractor = null;
225
+ this.initPromise = null;
226
+ }
227
+ }
228
+
229
+ export default EmbeddingService;
@@ -0,0 +1,65 @@
1
+ import { UpdateSettings } from "@/config/settings";
2
+ import useSettingsStore from "../store/useSettingsStore";
3
+ import type { Model } from "../types/Model";
4
+
5
+ const getSettings = () => useSettingsStore.getState();
6
+
7
+ class GoogleClient {
8
+ async syncGoogleModels() {
9
+ if (!getSettings().google_api_key && !process.env.GOOGLE_API_KEY) {
10
+ return;
11
+ }
12
+ const savedModels = getSettings().models;
13
+ const existingGoogleModels = savedModels.filter((m) => m.type === "google");
14
+ const otherModels = savedModels.filter((m) => m.type !== "google");
15
+
16
+ const models: Model[] = [
17
+ {
18
+ type: "google",
19
+ name: "gemini-3-flash-preview",
20
+ modified_at: new Date().toISOString(),
21
+ digest: "",
22
+ usage: {
23
+ promptTokens: 0,
24
+ completionTokens: 0,
25
+ totalTokens: 0,
26
+ },
27
+ details: {
28
+ provider: "google",
29
+ context_length: 100000,
30
+ },
31
+ } as Model,
32
+ {
33
+ type: "google",
34
+ name: "gemini-2.5-flash-lite",
35
+ modified_at: new Date().toISOString(),
36
+ digest: "",
37
+ usage: {
38
+ promptTokens: 0,
39
+ completionTokens: 0,
40
+ totalTokens: 0,
41
+ },
42
+ details: {
43
+ provider: "google",
44
+ context_length: 100000,
45
+ },
46
+ } as Model,
47
+ ].map((model) => {
48
+ const existing = existingGoogleModels.find((m) => m.name === model.name);
49
+ if (existing) {
50
+ return {
51
+ ...model,
52
+ digest: existing.digest || "",
53
+ usage: existing.usage || model.usage,
54
+ details: { ...model.details, ...existing.details },
55
+ };
56
+ }
57
+ return model;
58
+ });
59
+
60
+ const mergedModels = [...otherModels, ...models];
61
+ await UpdateSettings({ models: mergedModels });
62
+ }
63
+ }
64
+
65
+ export default new GoogleClient();
@@ -0,0 +1,248 @@
1
+ /**
2
+ * GraphSerializer - Optimized serialization of knowledge graph subsets for LLM context.
3
+ *
4
+ * Converts graph data into concise, LLM-friendly markdown format that maximizes
5
+ * information density while staying within context window limits.
6
+ */
7
+
8
+ import type { Fact } from "@/utils/agentCognition";
9
+ import path from "path";
10
+
11
+ export interface SerializationOptions {
12
+ maxSymbols?: number;
13
+ maxDecisions?: number;
14
+ maxFacts?: number;
15
+ includeRelations?: boolean;
16
+ format?: "markdown" | "compact";
17
+ }
18
+
19
+ const DEFAULT_OPTIONS: SerializationOptions = {
20
+ maxSymbols: 10,
21
+ maxDecisions: 5,
22
+ maxFacts: 5,
23
+ includeRelations: true,
24
+ format: "markdown",
25
+ };
26
+
27
+ export class GraphSerializer {
28
+ /**
29
+ * Serialize a collection of facts into LLM-friendly context.
30
+ */
31
+ static serialize(
32
+ facts: Fact[],
33
+ relations?: Array<{ source: string; target: string; type: string }>,
34
+ options: SerializationOptions = {},
35
+ ): string {
36
+ const opts = { ...DEFAULT_OPTIONS, ...options };
37
+
38
+ if (opts.format === "compact") {
39
+ return GraphSerializer.serializeCompact(facts, relations, opts);
40
+ }
41
+
42
+ return GraphSerializer.serializeMarkdown(facts, relations, opts);
43
+ }
44
+
45
+ /**
46
+ * Markdown format - human-readable, good for general context.
47
+ */
48
+ private static serializeMarkdown(
49
+ facts: Fact[],
50
+ relations?: Array<{ source: string; target: string; type: string }>,
51
+ opts: SerializationOptions = DEFAULT_OPTIONS,
52
+ ): string {
53
+ if (facts.length === 0) return "";
54
+
55
+ const parts: string[] = [];
56
+
57
+ // Group facts by type
58
+ const byType = GraphSerializer.groupByType(facts);
59
+
60
+ // Code entities (new types: file, module, function, class, interface, variable, symbol)
61
+ const codeTypes = [
62
+ "file",
63
+ "module",
64
+ "function",
65
+ "class",
66
+ "interface",
67
+ "variable",
68
+ "symbol",
69
+ "concept",
70
+ ];
71
+ const codeEntities = facts.filter((f) => codeTypes.includes(f.type));
72
+ if (codeEntities.length > 0) {
73
+ parts.push("## Code Context\n");
74
+
75
+ // Group by file
76
+ const byFile = new Map<string, Fact[]>();
77
+ for (const c of codeEntities.slice(0, opts.maxSymbols!)) {
78
+ const file = (c.data?.file as string) || "unknown";
79
+ const list = byFile.get(file) || [];
80
+ list.push(c);
81
+ byFile.set(file, list);
82
+ }
83
+
84
+ for (const [file, symbols] of byFile) {
85
+ const fileName = path.basename(file);
86
+ parts.push(`### ${fileName}\n`);
87
+ for (const sym of symbols) {
88
+ const sig = sym.data?.signature ? ` ${sym.data.signature}` : "";
89
+ const exp = sym.data?.exported ? "export " : "";
90
+ parts.push(
91
+ `- \`${exp}${sym.data?.kind || "Symbol"}: ${sym.data?.symbol}${sig}\``,
92
+ );
93
+ if (sym.data?.docstring) {
94
+ const doc = (sym.data.docstring as string).slice(0, 80);
95
+ parts.push(` - ${doc}${doc.length >= 80 ? "..." : ""}`);
96
+ }
97
+ }
98
+ parts.push("");
99
+ }
100
+ }
101
+
102
+ // Decisions
103
+ const decisions = byType.get("decision") || [];
104
+ if (decisions.length > 0) {
105
+ parts.push("## Project Decisions\n");
106
+ for (const d of decisions.slice(0, opts.maxDecisions!)) {
107
+ parts.push(`- ${d.content}`);
108
+ }
109
+ parts.push("");
110
+ }
111
+
112
+ // Facts
113
+ const factItems = byType.get("fact") || [];
114
+ if (factItems.length > 0) {
115
+ parts.push("## Known Facts\n");
116
+ for (const f of factItems.slice(0, opts.maxFacts!)) {
117
+ parts.push(`- ${f.content}`);
118
+ }
119
+ parts.push("");
120
+ }
121
+
122
+ // Relations (optional)
123
+ if (opts.includeRelations && relations && relations.length > 0) {
124
+ parts.push("## Relationships\n");
125
+ const relationsByType = new Map<string, number>();
126
+ for (const r of relations) {
127
+ relationsByType.set(r.type, (relationsByType.get(r.type) || 0) + 1);
128
+ }
129
+ for (const [type, count] of relationsByType) {
130
+ parts.push(`- ${type}: ${count} connections`);
131
+ }
132
+ parts.push("");
133
+ }
134
+
135
+ return parts.join("\n").trim();
136
+ }
137
+
138
+ /**
139
+ * Compact format - minimal tokens, maximum information density.
140
+ */
141
+ private static serializeCompact(
142
+ facts: Fact[],
143
+ relations?: Array<{ source: string; target: string; type: string }>,
144
+ opts: SerializationOptions = DEFAULT_OPTIONS,
145
+ ): string {
146
+ if (facts.length === 0) return "";
147
+
148
+ const lines: string[] = [];
149
+ const byType = GraphSerializer.groupByType(facts);
150
+
151
+ // Code entities
152
+ const codeTypes = [
153
+ "file",
154
+ "module",
155
+ "function",
156
+ "class",
157
+ "interface",
158
+ "variable",
159
+ "symbol",
160
+ "concept",
161
+ ];
162
+ const codeEntities = facts.filter((f) => codeTypes.includes(f.type));
163
+ if (codeEntities.length > 0) {
164
+ lines.push("[code]");
165
+ for (const c of codeEntities.slice(0, opts.maxSymbols!)) {
166
+ const kind =
167
+ (c.data?.kind as string)?.charAt(0) || c.type.charAt(0).toUpperCase();
168
+ const name = c.data?.symbol || "?";
169
+ const sig = c.data?.signature || "";
170
+ const file = c.data?.file
171
+ ? `@${path.basename(c.data.file as string)}`
172
+ : "";
173
+ lines.push(`${kind}:${name}${sig}${file}`);
174
+ }
175
+ }
176
+
177
+ // Decisions: brief
178
+ const decisions = byType.get("decision") || [];
179
+ if (decisions.length > 0) {
180
+ lines.push("[dec]");
181
+ for (const d of decisions.slice(0, opts.maxDecisions!)) {
182
+ lines.push(d.content.slice(0, 100));
183
+ }
184
+ }
185
+
186
+ return lines.join("\n");
187
+ }
188
+
189
+ /**
190
+ * Create a focused context for a specific file.
191
+ */
192
+ static serializeFileContext(
193
+ filePath: string,
194
+ symbols: Fact[],
195
+ relatedFacts: Fact[],
196
+ ): string {
197
+ const parts: string[] = [
198
+ `## File: ${path.basename(filePath)}\n`,
199
+ `Path: \`${filePath}\`\n`,
200
+ ];
201
+
202
+ if (symbols.length > 0) {
203
+ parts.push("### Symbols\n");
204
+ for (const sym of symbols) {
205
+ const sig = sym.data?.signature ? `: ${sym.data.signature}` : "";
206
+ parts.push(`- **${sym.data?.kind}** \`${sym.data?.symbol}\`${sig}`);
207
+ }
208
+ parts.push("");
209
+ }
210
+
211
+ if (relatedFacts.length > 0) {
212
+ parts.push("### Related Knowledge\n");
213
+ for (const f of relatedFacts.slice(0, 5)) {
214
+ parts.push(`- [${f.type}] ${f.content}`);
215
+ }
216
+ }
217
+
218
+ return parts.join("\n").trim();
219
+ }
220
+
221
+ /**
222
+ * Create summary statistics for a graph subset.
223
+ */
224
+ static summarize(
225
+ facts: Fact[],
226
+ relations?: Array<{ source: string; target: string; type: string }>,
227
+ ): string {
228
+ const byType = GraphSerializer.groupByType(facts);
229
+ const counts = Array.from(byType.entries())
230
+ .map(([type, list]) => `${type}:${list.length}`)
231
+ .join(" ");
232
+
233
+ const relCount = relations?.length || 0;
234
+ return `[${facts.length} facts (${counts}), ${relCount} relations]`;
235
+ }
236
+
237
+ private static groupByType(facts: Fact[]): Map<string, Fact[]> {
238
+ const byType = new Map<string, Fact[]>();
239
+ for (const fact of facts) {
240
+ const list = byType.get(fact.type) || [];
241
+ list.push(fact);
242
+ byType.set(fact.type, list);
243
+ }
244
+ return byType;
245
+ }
246
+ }
247
+
248
+ export default GraphSerializer;
@@ -0,0 +1,23 @@
1
+ import useSettingsStore from "../store/useSettingsStore";
2
+
3
+ const getSettings = () => useSettingsStore.getState();
4
+
5
+ class GroqClient {
6
+ async getModelData(model: string) {
7
+ const url = `https://api.groq.com/openai/v1/models/${model}`;
8
+ const options = {
9
+ method: "GET",
10
+ headers: { Authorization: `Bearer ${getSettings().groq_api_key}` },
11
+ };
12
+ const response = await fetch(url, options);
13
+ if (!response.ok) {
14
+ throw new Error(
15
+ `Failed to fetch Groq model ${model}: ${response.status}`
16
+ );
17
+ }
18
+ const data: any = await response.json();
19
+ return data;
20
+ }
21
+ }
22
+
23
+ export default new GroqClient();