@radaros/core 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 (48) hide show
  1. package/dist/index.d.ts +887 -0
  2. package/dist/index.js +3462 -0
  3. package/package.json +64 -0
  4. package/src/agent/agent.ts +314 -0
  5. package/src/agent/llm-loop.ts +263 -0
  6. package/src/agent/run-context.ts +35 -0
  7. package/src/agent/types.ts +77 -0
  8. package/src/events/event-bus.ts +45 -0
  9. package/src/events/types.ts +16 -0
  10. package/src/guardrails/types.ts +5 -0
  11. package/src/hooks/types.ts +6 -0
  12. package/src/index.ts +111 -0
  13. package/src/knowledge/knowledge-base.ts +146 -0
  14. package/src/logger/logger.ts +232 -0
  15. package/src/memory/memory.ts +87 -0
  16. package/src/memory/types.ts +13 -0
  17. package/src/models/provider.ts +22 -0
  18. package/src/models/providers/anthropic.ts +330 -0
  19. package/src/models/providers/google.ts +361 -0
  20. package/src/models/providers/ollama.ts +211 -0
  21. package/src/models/providers/openai.ts +323 -0
  22. package/src/models/registry.ts +90 -0
  23. package/src/models/types.ts +112 -0
  24. package/src/session/session-manager.ts +75 -0
  25. package/src/session/types.ts +10 -0
  26. package/src/storage/driver.ts +10 -0
  27. package/src/storage/in-memory.ts +44 -0
  28. package/src/storage/mongodb.ts +70 -0
  29. package/src/storage/postgres.ts +81 -0
  30. package/src/storage/sqlite.ts +81 -0
  31. package/src/team/modes.ts +1 -0
  32. package/src/team/team.ts +323 -0
  33. package/src/team/types.ts +26 -0
  34. package/src/tools/define-tool.ts +20 -0
  35. package/src/tools/tool-executor.ts +131 -0
  36. package/src/tools/types.ts +27 -0
  37. package/src/vector/base.ts +44 -0
  38. package/src/vector/embeddings/google.ts +64 -0
  39. package/src/vector/embeddings/openai.ts +66 -0
  40. package/src/vector/in-memory.ts +115 -0
  41. package/src/vector/mongodb.ts +241 -0
  42. package/src/vector/pgvector.ts +169 -0
  43. package/src/vector/qdrant.ts +203 -0
  44. package/src/vector/types.ts +55 -0
  45. package/src/workflow/step-runner.ts +303 -0
  46. package/src/workflow/types.ts +55 -0
  47. package/src/workflow/workflow.ts +68 -0
  48. package/tsconfig.json +8 -0
@@ -0,0 +1,169 @@
1
+ import { createRequire } from "node:module";
2
+ import { BaseVectorStore } from "./base.js";
3
+ import type {
4
+ VectorDocument,
5
+ VectorSearchResult,
6
+ VectorSearchOptions,
7
+ EmbeddingProvider,
8
+ } from "./types.js";
9
+
10
+ const _require = createRequire(import.meta.url);
11
+
12
+ export interface PgVectorConfig {
13
+ connectionString: string;
14
+ dimensions?: number;
15
+ }
16
+
17
+ export class PgVectorStore extends BaseVectorStore {
18
+ private pool: any;
19
+ private dimensions: number;
20
+ private initializedCollections = new Set<string>();
21
+
22
+ constructor(config: PgVectorConfig, embedder?: EmbeddingProvider) {
23
+ super(embedder);
24
+ this.dimensions = config.dimensions ?? embedder?.dimensions ?? 1536;
25
+ try {
26
+ const { Pool } = _require("pg");
27
+ this.pool = new Pool({ connectionString: config.connectionString });
28
+ } catch {
29
+ throw new Error(
30
+ "pg is required for PgVectorStore. Install it: npm install pg"
31
+ );
32
+ }
33
+ }
34
+
35
+ async initialize(): Promise<void> {
36
+ await this.pool.query("CREATE EXTENSION IF NOT EXISTS vector");
37
+ }
38
+
39
+ private async ensureCollection(collection: string): Promise<void> {
40
+ if (this.initializedCollections.has(collection)) return;
41
+ const table = this.sanitize(collection);
42
+ await this.pool.query(`
43
+ CREATE TABLE IF NOT EXISTS ${table} (
44
+ id TEXT PRIMARY KEY,
45
+ content TEXT NOT NULL,
46
+ embedding vector(${this.dimensions}),
47
+ metadata JSONB DEFAULT '{}'::jsonb,
48
+ created_at TIMESTAMPTZ DEFAULT NOW()
49
+ )
50
+ `);
51
+ await this.pool.query(`
52
+ CREATE INDEX IF NOT EXISTS ${table}_embedding_idx
53
+ ON ${table} USING ivfflat (embedding vector_cosine_ops)
54
+ WITH (lists = 100)
55
+ `).catch(() => {
56
+ // IVFFlat index needs enough rows; hnsw fallback
57
+ });
58
+ this.initializedCollections.add(collection);
59
+ }
60
+
61
+ private sanitize(name: string): string {
62
+ return name.replace(/[^a-zA-Z0-9_]/g, "_");
63
+ }
64
+
65
+ private toSql(vec: number[]): string {
66
+ return `[${vec.join(",")}]`;
67
+ }
68
+
69
+ async upsert(collection: string, doc: VectorDocument): Promise<void> {
70
+ await this.ensureCollection(collection);
71
+ const embedding = await this.ensureEmbedding(doc);
72
+ const table = this.sanitize(collection);
73
+ await this.pool.query(
74
+ `INSERT INTO ${table} (id, content, embedding, metadata)
75
+ VALUES ($1, $2, $3::vector, $4::jsonb)
76
+ ON CONFLICT (id)
77
+ DO UPDATE SET content = EXCLUDED.content,
78
+ embedding = EXCLUDED.embedding,
79
+ metadata = EXCLUDED.metadata`,
80
+ [doc.id, doc.content, this.toSql(embedding), JSON.stringify(doc.metadata ?? {})]
81
+ );
82
+ }
83
+
84
+ async upsertBatch(collection: string, docs: VectorDocument[]): Promise<void> {
85
+ for (const doc of docs) {
86
+ await this.upsert(collection, doc);
87
+ }
88
+ }
89
+
90
+ async search(
91
+ collection: string,
92
+ query: number[] | string,
93
+ options?: VectorSearchOptions
94
+ ): Promise<VectorSearchResult[]> {
95
+ await this.ensureCollection(collection);
96
+ const vec = await this.ensureQueryVector(query);
97
+ const topK = options?.topK ?? 10;
98
+ const table = this.sanitize(collection);
99
+
100
+ let filterClause = "";
101
+ const params: unknown[] = [this.toSql(vec), topK];
102
+
103
+ if (options?.filter) {
104
+ const conditions = Object.entries(options.filter).map(([k, v], i) => {
105
+ params.push(JSON.stringify(v));
106
+ return `metadata->>'${k.replace(/'/g, "''")}' = $${i + 3}`;
107
+ });
108
+ if (conditions.length > 0) {
109
+ filterClause = `WHERE ${conditions.join(" AND ")}`;
110
+ }
111
+ }
112
+
113
+ const result = await this.pool.query(
114
+ `SELECT id, content, metadata,
115
+ 1 - (embedding <=> $1::vector) AS score
116
+ FROM ${table}
117
+ ${filterClause}
118
+ ORDER BY embedding <=> $1::vector
119
+ LIMIT $2`,
120
+ params
121
+ );
122
+
123
+ let rows = result.rows as Array<{
124
+ id: string;
125
+ content: string;
126
+ score: number;
127
+ metadata: Record<string, unknown>;
128
+ }>;
129
+
130
+ if (options?.minScore != null) {
131
+ rows = rows.filter((r) => r.score >= options.minScore!);
132
+ }
133
+
134
+ return rows.map((r) => ({
135
+ id: r.id,
136
+ content: r.content,
137
+ score: r.score,
138
+ metadata: r.metadata,
139
+ }));
140
+ }
141
+
142
+ async delete(collection: string, id: string): Promise<void> {
143
+ await this.ensureCollection(collection);
144
+ const table = this.sanitize(collection);
145
+ await this.pool.query(`DELETE FROM ${table} WHERE id = $1`, [id]);
146
+ }
147
+
148
+ async get(collection: string, id: string): Promise<VectorDocument | null> {
149
+ await this.ensureCollection(collection);
150
+ const table = this.sanitize(collection);
151
+ const result = await this.pool.query(
152
+ `SELECT id, content, metadata FROM ${table} WHERE id = $1`,
153
+ [id]
154
+ );
155
+ if (result.rows.length === 0) return null;
156
+ const row = result.rows[0];
157
+ return { id: row.id, content: row.content, metadata: row.metadata };
158
+ }
159
+
160
+ async dropCollection(collection: string): Promise<void> {
161
+ const table = this.sanitize(collection);
162
+ await this.pool.query(`DROP TABLE IF EXISTS ${table}`);
163
+ this.initializedCollections.delete(collection);
164
+ }
165
+
166
+ async close(): Promise<void> {
167
+ await this.pool.end();
168
+ }
169
+ }
@@ -0,0 +1,203 @@
1
+ import { createRequire } from "node:module";
2
+ import { createHash } from "node:crypto";
3
+ import { BaseVectorStore } from "./base.js";
4
+ import type {
5
+ VectorDocument,
6
+ VectorSearchResult,
7
+ VectorSearchOptions,
8
+ EmbeddingProvider,
9
+ } from "./types.js";
10
+
11
+ const _require = createRequire(import.meta.url);
12
+
13
+ export interface QdrantConfig {
14
+ url?: string;
15
+ apiKey?: string;
16
+ dimensions?: number;
17
+ checkCompatibility?: boolean;
18
+ }
19
+
20
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
21
+
22
+ /**
23
+ * Deterministic UUID from an arbitrary string.
24
+ * Qdrant only accepts UUIDs or unsigned ints as point IDs,
25
+ * so we hash arbitrary strings into valid UUID v4 format
26
+ * and store the original ID in the payload under `_originalId`.
27
+ */
28
+ function stringToUUID(str: string): string {
29
+ const hex = createHash("md5").update(str).digest("hex");
30
+ return [
31
+ hex.slice(0, 8),
32
+ hex.slice(8, 12),
33
+ "4" + hex.slice(13, 16),
34
+ "8" + hex.slice(17, 20),
35
+ hex.slice(20, 32),
36
+ ].join("-");
37
+ }
38
+
39
+ function toQdrantId(id: string): string | number {
40
+ if (/^\d+$/.test(id)) return Number(id);
41
+ if (UUID_RE.test(id)) return id;
42
+ return stringToUUID(id);
43
+ }
44
+
45
+ export class QdrantVectorStore extends BaseVectorStore {
46
+ private client: any;
47
+ private dimensions: number;
48
+ private initializedCollections = new Set<string>();
49
+
50
+ constructor(config: QdrantConfig = {}, embedder?: EmbeddingProvider) {
51
+ super(embedder);
52
+ this.dimensions = config.dimensions ?? embedder?.dimensions ?? 1536;
53
+ try {
54
+ const { QdrantClient } = _require("@qdrant/js-client-rest");
55
+ this.client = new QdrantClient({
56
+ url: config.url ?? "http://localhost:6333",
57
+ apiKey: config.apiKey,
58
+ checkCompatibility: config.checkCompatibility ?? false,
59
+ });
60
+ } catch {
61
+ throw new Error(
62
+ "@qdrant/js-client-rest is required for QdrantVectorStore. Install it: npm install @qdrant/js-client-rest"
63
+ );
64
+ }
65
+ }
66
+
67
+ async initialize(): Promise<void> {}
68
+
69
+ private async ensureCollection(collection: string): Promise<void> {
70
+ if (this.initializedCollections.has(collection)) return;
71
+ try {
72
+ await this.client.getCollection(collection);
73
+ } catch {
74
+ await this.client.createCollection(collection, {
75
+ vectors: {
76
+ size: this.dimensions,
77
+ distance: "Cosine",
78
+ },
79
+ });
80
+ }
81
+ this.initializedCollections.add(collection);
82
+ }
83
+
84
+ async upsert(collection: string, doc: VectorDocument): Promise<void> {
85
+ await this.ensureCollection(collection);
86
+ const embedding = await this.ensureEmbedding(doc);
87
+ await this.client.upsert(collection, {
88
+ wait: true,
89
+ points: [
90
+ {
91
+ id: toQdrantId(doc.id),
92
+ vector: embedding,
93
+ payload: {
94
+ _originalId: doc.id,
95
+ content: doc.content,
96
+ ...(doc.metadata ?? {}),
97
+ },
98
+ },
99
+ ],
100
+ });
101
+ }
102
+
103
+ async upsertBatch(collection: string, docs: VectorDocument[]): Promise<void> {
104
+ await this.ensureCollection(collection);
105
+ const points = await Promise.all(
106
+ docs.map(async (doc) => {
107
+ const embedding = await this.ensureEmbedding(doc);
108
+ return {
109
+ id: toQdrantId(doc.id),
110
+ vector: embedding,
111
+ payload: {
112
+ _originalId: doc.id,
113
+ content: doc.content,
114
+ ...(doc.metadata ?? {}),
115
+ },
116
+ };
117
+ })
118
+ );
119
+ await this.client.upsert(collection, { wait: true, points });
120
+ }
121
+
122
+ async search(
123
+ collection: string,
124
+ query: number[] | string,
125
+ options?: VectorSearchOptions
126
+ ): Promise<VectorSearchResult[]> {
127
+ await this.ensureCollection(collection);
128
+ const vec = await this.ensureQueryVector(query);
129
+ const topK = options?.topK ?? 10;
130
+
131
+ const searchParams: Record<string, unknown> = {
132
+ vector: vec,
133
+ limit: topK,
134
+ with_payload: true,
135
+ };
136
+
137
+ if (options?.filter) {
138
+ searchParams.filter = {
139
+ must: Object.entries(options.filter).map(([key, value]) => ({
140
+ key,
141
+ match: { value },
142
+ })),
143
+ };
144
+ }
145
+
146
+ if (options?.minScore != null) {
147
+ searchParams.score_threshold = options.minScore;
148
+ }
149
+
150
+ const results = await this.client.search(collection, searchParams);
151
+
152
+ return results.map((r: any) => {
153
+ const { _originalId, content, ...rest } = r.payload ?? {};
154
+ return {
155
+ id: _originalId ?? String(r.id),
156
+ content: content ?? "",
157
+ score: r.score,
158
+ metadata: rest,
159
+ };
160
+ });
161
+ }
162
+
163
+ async delete(collection: string, id: string): Promise<void> {
164
+ await this.ensureCollection(collection);
165
+ await this.client.delete(collection, {
166
+ wait: true,
167
+ points: [toQdrantId(id)],
168
+ });
169
+ }
170
+
171
+ async get(collection: string, id: string): Promise<VectorDocument | null> {
172
+ await this.ensureCollection(collection);
173
+ try {
174
+ const results = await this.client.retrieve(collection, {
175
+ ids: [toQdrantId(id)],
176
+ with_payload: true,
177
+ });
178
+ if (!results || results.length === 0) return null;
179
+ const point = results[0];
180
+ const { _originalId, content, ...rest } = point.payload ?? {};
181
+ return {
182
+ id: _originalId ?? String(point.id),
183
+ content: content ?? "",
184
+ metadata: rest,
185
+ };
186
+ } catch {
187
+ return null;
188
+ }
189
+ }
190
+
191
+ async dropCollection(collection: string): Promise<void> {
192
+ try {
193
+ await this.client.deleteCollection(collection);
194
+ } catch {
195
+ // collection may not exist
196
+ }
197
+ this.initializedCollections.delete(collection);
198
+ }
199
+
200
+ async close(): Promise<void> {
201
+ // Qdrant JS client doesn't require explicit close
202
+ }
203
+ }
@@ -0,0 +1,55 @@
1
+ export interface VectorDocument {
2
+ id: string;
3
+ content: string;
4
+ embedding?: number[];
5
+ metadata?: Record<string, unknown>;
6
+ }
7
+
8
+ export interface VectorSearchResult {
9
+ id: string;
10
+ content: string;
11
+ score: number;
12
+ metadata?: Record<string, unknown>;
13
+ }
14
+
15
+ export interface VectorSearchOptions {
16
+ topK?: number;
17
+ filter?: Record<string, unknown>;
18
+ minScore?: number;
19
+ }
20
+
21
+ export interface EmbeddingProvider {
22
+ readonly dimensions: number;
23
+ embed(text: string): Promise<number[]>;
24
+ embedBatch(texts: string[]): Promise<number[][]>;
25
+ }
26
+
27
+ export interface VectorStore {
28
+ /** Initialize collections/indexes. Call once before use. */
29
+ initialize(): Promise<void>;
30
+
31
+ /** Upsert a single document (embedding computed if not provided). */
32
+ upsert(collection: string, doc: VectorDocument): Promise<void>;
33
+
34
+ /** Upsert multiple documents in batch. */
35
+ upsertBatch(collection: string, docs: VectorDocument[]): Promise<void>;
36
+
37
+ /** Similarity search by vector or text query. */
38
+ search(
39
+ collection: string,
40
+ query: number[] | string,
41
+ options?: VectorSearchOptions
42
+ ): Promise<VectorSearchResult[]>;
43
+
44
+ /** Delete a document by ID. */
45
+ delete(collection: string, id: string): Promise<void>;
46
+
47
+ /** Get a document by ID. */
48
+ get(collection: string, id: string): Promise<VectorDocument | null>;
49
+
50
+ /** Drop an entire collection. */
51
+ dropCollection(collection: string): Promise<void>;
52
+
53
+ /** Close connections. */
54
+ close(): Promise<void>;
55
+ }