@streetjs/ai 1.0.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.
package/README.md ADDED
@@ -0,0 +1,107 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/hassanmubiru/StreetJS/main/docs/assets/images/logo-512.png" alt="StreetJS logo" width="100" height="100">
3
+ </p>
4
+
5
+ # @streetjs/ai
6
+
7
+ Official StreetJS Framework AI module: a **provider-agnostic** surface for LLM
8
+ chat, embeddings, retrieval-augmented generation (RAG), and tool calling.
9
+
10
+ - One `AiProvider` contract; swap implementations freely
11
+ - Adapters: `OpenAiProvider`, `AnthropicProvider`, `OllamaProvider`
12
+ - `FakeAiProvider` — deterministic, network-free; default for tests/offline dev
13
+ - `RagPipeline` — embed → store → retrieve → answer (with `InMemoryVectorStore`)
14
+ - `ChatSession` — a tool-calling loop (model requests tools, you run handlers)
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ npm install @streetjs/ai
20
+ ```
21
+
22
+ ## Chat
23
+
24
+ ```ts
25
+ import { OpenAiProvider } from '@streetjs/ai';
26
+
27
+ const ai = new OpenAiProvider({ apiKey: process.env.OPENAI_API_KEY });
28
+ const res = await ai.chat({ messages: [{ role: 'user', content: 'Hello!' }] });
29
+ console.log(res.message.content, res.usage);
30
+ ```
31
+
32
+ Swap providers without touching call sites:
33
+
34
+ ```ts
35
+ import { AnthropicProvider, OllamaProvider } from '@streetjs/ai';
36
+ const claude = new AnthropicProvider({ apiKey: process.env.ANTHROPIC_API_KEY });
37
+ const local = new OllamaProvider({ baseUrl: 'http://127.0.0.1:11434' });
38
+ ```
39
+
40
+ ## Embeddings + RAG
41
+
42
+ ```ts
43
+ import { RagPipeline, OpenAiProvider } from '@streetjs/ai';
44
+
45
+ const rag = new RagPipeline({ provider: new OpenAiProvider({ apiKey }), topK: 4 });
46
+ await rag.index([
47
+ { id: 'd1', text: 'The Eiffel Tower is in Paris.' },
48
+ { id: 'd2', text: 'Mount Everest is the tallest mountain.' },
49
+ ]);
50
+ const { answer, context } = await rag.answer('Where is the Eiffel Tower?');
51
+ ```
52
+
53
+ ## Tool calling
54
+
55
+ ```ts
56
+ import { ChatSession, OpenAiProvider } from '@streetjs/ai';
57
+
58
+ const session = new ChatSession({
59
+ provider: new OpenAiProvider({ apiKey }),
60
+ system: 'You can do arithmetic.',
61
+ tools: [{
62
+ name: 'add',
63
+ description: 'Add two numbers',
64
+ parameters: { type: 'object', properties: { a: { type: 'number' }, b: { type: 'number' } } },
65
+ handler: ({ a, b }) => Number(a) + Number(b),
66
+ }],
67
+ });
68
+
69
+ const { message, toolCallsExecuted } = await session.send('what is 2 + 3?');
70
+ // session runs the tool, feeds the result back, and returns the final answer
71
+ ```
72
+
73
+ ## Testing without network
74
+
75
+ `FakeAiProvider` is deterministic and offline. Its embeddings are hashed
76
+ bag-of-words vectors, so lexically similar text scores higher — enough to
77
+ exercise RAG end-to-end in tests. The HTTP adapters accept an injectable
78
+ `fetch`, so request/response handling is unit-tested without real API calls.
79
+
80
+ ```ts
81
+ import { FakeAiProvider, RagPipeline } from '@streetjs/ai';
82
+ const rag = new RagPipeline({ provider: new FakeAiProvider() });
83
+ ```
84
+
85
+ ## API
86
+
87
+ - Providers: `OpenAiProvider`, `AnthropicProvider`, `OllamaProvider`, `FakeAiProvider`
88
+ - `RagPipeline` (`index`, `retrieve`, `answer`), `InMemoryVectorStore`, `cosineSimilarity`, `hashEmbedding`
89
+ - `ChatSession` (`send`, `messages`)
90
+ - Types: `AiProvider`, `ChatRequest/Response`, `ChatMessage`, `ToolCall`, `ToolDefinition`, `EmbedRequest/Response`
91
+
92
+ ## Notes
93
+
94
+ - `AnthropicProvider` does not support embeddings (use OpenAI or Ollama).
95
+ - Tool-call wiring is implemented for the OpenAI adapter; Anthropic/Ollama
96
+ adapters cover chat + (Ollama) embeddings. Function-calling for those is a
97
+ tracked follow-up.
98
+
99
+ ## Testing
100
+
101
+ ```bash
102
+ npm run test -w packages/ai # unit + property tests, fully offline
103
+ ```
104
+
105
+ ## License
106
+
107
+ MIT
@@ -0,0 +1,183 @@
1
+ export type Role = 'system' | 'user' | 'assistant' | 'tool';
2
+ /** A request from the model to invoke a tool. */
3
+ export interface ToolCall {
4
+ id: string;
5
+ name: string;
6
+ /** Parsed arguments object the tool was called with. */
7
+ arguments: Record<string, unknown>;
8
+ }
9
+ /** A chat message. `toolCalls` is set on assistant turns that request tools; */
10
+ /** `toolCallId` links a `tool` message back to the call it answers. */
11
+ export interface ChatMessage {
12
+ role: Role;
13
+ content: string;
14
+ toolCalls?: ToolCall[];
15
+ toolCallId?: string;
16
+ }
17
+ /** A callable tool exposed to the model. */
18
+ export interface ToolDefinition {
19
+ name: string;
20
+ description: string;
21
+ /** JSON-schema-ish parameter description (passed through to the provider). */
22
+ parameters: Record<string, unknown>;
23
+ }
24
+ export interface TokenUsage {
25
+ promptTokens: number;
26
+ completionTokens: number;
27
+ }
28
+ export interface ChatRequest {
29
+ messages: ChatMessage[];
30
+ tools?: ToolDefinition[];
31
+ model?: string;
32
+ temperature?: number;
33
+ maxTokens?: number;
34
+ }
35
+ export interface ChatResponse {
36
+ message: ChatMessage;
37
+ finishReason: 'stop' | 'tool_calls' | 'length';
38
+ usage?: TokenUsage;
39
+ }
40
+ export interface EmbedRequest {
41
+ input: string[];
42
+ model?: string;
43
+ }
44
+ export interface EmbedResponse {
45
+ /** One embedding vector per input, in order. */
46
+ embeddings: number[][];
47
+ usage?: TokenUsage;
48
+ }
49
+ /** The common provider contract. */
50
+ export interface AiProvider {
51
+ readonly name: string;
52
+ chat(request: ChatRequest): Promise<ChatResponse>;
53
+ embed(request: EmbedRequest): Promise<EmbedResponse>;
54
+ }
55
+ /** Cosine similarity of two equal-length vectors. Returns 0 for zero vectors. */
56
+ export declare function cosineSimilarity(a: number[], b: number[]): number;
57
+ /**
58
+ * Deterministic hashed bag-of-words embedding: lexical overlap → higher cosine
59
+ * similarity. Not semantic, but reproducible and good enough to exercise RAG.
60
+ */
61
+ export declare function hashEmbedding(text: string, dim?: number): number[];
62
+ export interface FakeAiProviderOptions {
63
+ /**
64
+ * Optional scripted chat behaviour. Given the request, return the assistant
65
+ * message and finish reason. Defaults to echoing a summary of the last user
66
+ * message. Use this to script tool-calls in tests.
67
+ */
68
+ chatScript?: (request: ChatRequest) => ChatResponse;
69
+ /** Embedding dimensionality. Default 64. */
70
+ dim?: number;
71
+ }
72
+ /** Deterministic, network-free provider for tests, examples, and offline dev. */
73
+ export declare class FakeAiProvider implements AiProvider {
74
+ readonly name = "fake";
75
+ private readonly dim;
76
+ private readonly chatScript;
77
+ constructor(options?: FakeAiProviderOptions);
78
+ chat(request: ChatRequest): Promise<ChatResponse>;
79
+ embed(request: EmbedRequest): Promise<EmbedResponse>;
80
+ }
81
+ export interface VectorRecord {
82
+ id: string;
83
+ text: string;
84
+ embedding: number[];
85
+ metadata?: Record<string, unknown>;
86
+ }
87
+ export interface ScoredRecord {
88
+ record: VectorRecord;
89
+ score: number;
90
+ }
91
+ /** Pluggable vector store. */
92
+ export interface VectorStore {
93
+ upsert(record: VectorRecord): Promise<void>;
94
+ remove(id: string): Promise<boolean>;
95
+ /** Top-`k` records by cosine similarity to `embedding`, score-desc. */
96
+ query(embedding: number[], k: number): Promise<ScoredRecord[]>;
97
+ size(): Promise<number>;
98
+ }
99
+ /** In-process vector store using exact cosine similarity. */
100
+ export declare class InMemoryVectorStore implements VectorStore {
101
+ private readonly records;
102
+ upsert(record: VectorRecord): Promise<void>;
103
+ remove(id: string): Promise<boolean>;
104
+ query(embedding: number[], k: number): Promise<ScoredRecord[]>;
105
+ size(): Promise<number>;
106
+ }
107
+ /** A document to index into a {@link RagPipeline}. */
108
+ export interface RagDocument {
109
+ id: string;
110
+ text: string;
111
+ metadata?: Record<string, unknown>;
112
+ }
113
+ export interface RagAnswer {
114
+ answer: string;
115
+ /** The records used as context, most relevant first. */
116
+ context: ScoredRecord[];
117
+ usage?: TokenUsage;
118
+ }
119
+ export interface RagPipelineOptions {
120
+ provider: AiProvider;
121
+ store?: VectorStore;
122
+ /** Records to retrieve per query. Default 4. */
123
+ topK?: number;
124
+ /** Embedding model passed to the provider. */
125
+ embedModel?: string;
126
+ /** Chat model passed to the provider. */
127
+ chatModel?: string;
128
+ }
129
+ /** Retrieval-augmented generation: embed → store → retrieve → answer. */
130
+ export declare class RagPipeline {
131
+ private readonly provider;
132
+ private readonly store;
133
+ private readonly topK;
134
+ private readonly embedModel;
135
+ private readonly chatModel;
136
+ constructor(options: RagPipelineOptions);
137
+ /** Embed and store documents for later retrieval. */
138
+ index(docs: RagDocument[]): Promise<void>;
139
+ /** Retrieve the most relevant records for `query`. */
140
+ retrieve(query: string, k?: number): Promise<ScoredRecord[]>;
141
+ /**
142
+ * Answer `query` grounded in retrieved context. Builds a system prompt from
143
+ * the top-`k` records and asks the chat model. With {@link FakeAiProvider}
144
+ * this is deterministic.
145
+ */
146
+ answer(query: string, k?: number): Promise<RagAnswer>;
147
+ }
148
+ /** A tool the model may call, paired with its executor. */
149
+ export interface RegisteredTool extends ToolDefinition {
150
+ handler: (args: Record<string, unknown>) => Promise<unknown> | unknown;
151
+ }
152
+ export interface ChatSessionOptions {
153
+ provider: AiProvider;
154
+ tools?: RegisteredTool[];
155
+ system?: string;
156
+ model?: string;
157
+ /** Max provider round-trips before giving up on a tool loop. Default 5. */
158
+ maxIterations?: number;
159
+ }
160
+ export interface SendResult {
161
+ message: ChatMessage;
162
+ /** Number of tool calls executed while producing this answer. */
163
+ toolCallsExecuted: number;
164
+ }
165
+ /**
166
+ * A stateful chat session that drives the tool-calling loop: when the model
167
+ * returns `tool_calls`, the session runs the matching handlers, appends the
168
+ * results as `tool` messages, and re-queries until the model produces a final
169
+ * answer (or `maxIterations` is reached).
170
+ */
171
+ export declare class ChatSession {
172
+ private readonly provider;
173
+ private readonly tools;
174
+ private readonly toolDefs;
175
+ private readonly model;
176
+ private readonly maxIterations;
177
+ readonly messages: ChatMessage[];
178
+ constructor(options: ChatSessionOptions);
179
+ /** Send a user message and resolve to the final assistant message. */
180
+ send(userMessage: string): Promise<SendResult>;
181
+ }
182
+ export * from './providers.js';
183
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,227 @@
1
+ // packages/ai/src/index.ts
2
+ // Official Street Framework AI module: @streetjs/ai.
3
+ //
4
+ // A provider-agnostic surface for LLM chat, embeddings, retrieval-augmented
5
+ // generation (RAG), and tool calling.
6
+ //
7
+ // * AiProvider — the common contract (chat + embed).
8
+ // * FakeAiProvider — deterministic, dependency-free; default for tests,
9
+ // examples, and offline development. Its embeddings
10
+ // are hashed bag-of-words vectors, so lexical overlap
11
+ // yields higher cosine similarity (RAG is meaningful
12
+ // and reproducible without network access).
13
+ // * OpenAiProvider / AnthropicProvider / OllamaProvider — real HTTP adapters
14
+ // with an injectable `fetch`, so request shaping and
15
+ // response parsing are unit-testable without network.
16
+ // * VectorStore / InMemoryVectorStore + cosineSimilarity — vector search.
17
+ // * RagPipeline — embed → store → retrieve → answer.
18
+ // * ChatSession — a tool-calling loop (model requests tools, we run
19
+ // registered handlers, feed results back, repeat).
20
+ // ── Vector math ───────────────────────────────────────────────────────────────
21
+ /** Cosine similarity of two equal-length vectors. Returns 0 for zero vectors. */
22
+ export function cosineSimilarity(a, b) {
23
+ if (a.length !== b.length) {
24
+ throw new Error(`cosineSimilarity: dimension mismatch (${a.length} vs ${b.length})`);
25
+ }
26
+ let dot = 0;
27
+ let na = 0;
28
+ let nb = 0;
29
+ for (let i = 0; i < a.length; i++) {
30
+ dot += a[i] * b[i];
31
+ na += a[i] * a[i];
32
+ nb += b[i] * b[i];
33
+ }
34
+ if (na === 0 || nb === 0)
35
+ return 0;
36
+ return dot / (Math.sqrt(na) * Math.sqrt(nb));
37
+ }
38
+ // ── Deterministic fake provider ─────────────────────────────────────────────────
39
+ const FAKE_DIM = 64;
40
+ /** Lowercase alphanumeric tokens. */
41
+ function tokenize(text) {
42
+ return text.toLowerCase().match(/[a-z0-9]+/g) ?? [];
43
+ }
44
+ /** Stable 32-bit FNV-1a hash. */
45
+ function fnv1a(s) {
46
+ let h = 0x811c9dc5;
47
+ for (let i = 0; i < s.length; i++) {
48
+ h ^= s.charCodeAt(i);
49
+ h = Math.imul(h, 0x01000193);
50
+ }
51
+ return h >>> 0;
52
+ }
53
+ /**
54
+ * Deterministic hashed bag-of-words embedding: lexical overlap → higher cosine
55
+ * similarity. Not semantic, but reproducible and good enough to exercise RAG.
56
+ */
57
+ export function hashEmbedding(text, dim = FAKE_DIM) {
58
+ const v = new Array(dim).fill(0);
59
+ for (const tok of tokenize(text)) {
60
+ v[fnv1a(tok) % dim] += 1;
61
+ }
62
+ return v;
63
+ }
64
+ /** Deterministic, network-free provider for tests, examples, and offline dev. */
65
+ export class FakeAiProvider {
66
+ name = 'fake';
67
+ dim;
68
+ chatScript;
69
+ constructor(options = {}) {
70
+ this.dim = options.dim ?? FAKE_DIM;
71
+ this.chatScript = options.chatScript;
72
+ }
73
+ async chat(request) {
74
+ if (this.chatScript)
75
+ return this.chatScript(request);
76
+ const lastUser = [...request.messages].reverse().find((m) => m.role === 'user');
77
+ const content = lastUser ? `echo: ${lastUser.content}` : 'echo: (no user message)';
78
+ return {
79
+ message: { role: 'assistant', content },
80
+ finishReason: 'stop',
81
+ usage: { promptTokens: countTokens(request.messages), completionTokens: tokenize(content).length },
82
+ };
83
+ }
84
+ async embed(request) {
85
+ return {
86
+ embeddings: request.input.map((t) => hashEmbedding(t, this.dim)),
87
+ usage: { promptTokens: request.input.reduce((n, t) => n + tokenize(t).length, 0), completionTokens: 0 },
88
+ };
89
+ }
90
+ }
91
+ function countTokens(messages) {
92
+ return messages.reduce((n, m) => n + tokenize(m.content).length, 0);
93
+ }
94
+ /** In-process vector store using exact cosine similarity. */
95
+ export class InMemoryVectorStore {
96
+ records = new Map();
97
+ async upsert(record) {
98
+ this.records.set(record.id, record);
99
+ }
100
+ async remove(id) {
101
+ return this.records.delete(id);
102
+ }
103
+ async query(embedding, k) {
104
+ const scored = [];
105
+ for (const record of this.records.values()) {
106
+ scored.push({ record, score: cosineSimilarity(embedding, record.embedding) });
107
+ }
108
+ scored.sort((a, b) => b.score - a.score || (a.record.id < b.record.id ? -1 : 1));
109
+ return scored.slice(0, Math.max(0, k));
110
+ }
111
+ async size() {
112
+ return this.records.size;
113
+ }
114
+ }
115
+ /** Retrieval-augmented generation: embed → store → retrieve → answer. */
116
+ export class RagPipeline {
117
+ provider;
118
+ store;
119
+ topK;
120
+ embedModel;
121
+ chatModel;
122
+ constructor(options) {
123
+ if (!options?.provider)
124
+ throw new Error('RagPipeline: a provider is required');
125
+ this.provider = options.provider;
126
+ this.store = options.store ?? new InMemoryVectorStore();
127
+ this.topK = options.topK ?? 4;
128
+ this.embedModel = options.embedModel;
129
+ this.chatModel = options.chatModel;
130
+ }
131
+ /** Embed and store documents for later retrieval. */
132
+ async index(docs) {
133
+ if (docs.length === 0)
134
+ return;
135
+ const { embeddings } = await this.provider.embed({ input: docs.map((d) => d.text), model: this.embedModel });
136
+ await Promise.all(docs.map((d, i) => this.store.upsert({ id: d.id, text: d.text, embedding: embeddings[i], metadata: d.metadata })));
137
+ }
138
+ /** Retrieve the most relevant records for `query`. */
139
+ async retrieve(query, k = this.topK) {
140
+ const { embeddings } = await this.provider.embed({ input: [query], model: this.embedModel });
141
+ return this.store.query(embeddings[0], k);
142
+ }
143
+ /**
144
+ * Answer `query` grounded in retrieved context. Builds a system prompt from
145
+ * the top-`k` records and asks the chat model. With {@link FakeAiProvider}
146
+ * this is deterministic.
147
+ */
148
+ async answer(query, k = this.topK) {
149
+ const context = await this.retrieve(query, k);
150
+ const contextBlock = context.map((c, i) => `[${i + 1}] ${c.record.text}`).join('\n');
151
+ const messages = [
152
+ {
153
+ role: 'system',
154
+ content: 'Answer the question using only the provided context. ' +
155
+ 'If the context is insufficient, say so.\n\nContext:\n' + contextBlock,
156
+ },
157
+ { role: 'user', content: query },
158
+ ];
159
+ const res = await this.provider.chat({ messages, model: this.chatModel });
160
+ return { answer: res.message.content, context, usage: res.usage };
161
+ }
162
+ }
163
+ /**
164
+ * A stateful chat session that drives the tool-calling loop: when the model
165
+ * returns `tool_calls`, the session runs the matching handlers, appends the
166
+ * results as `tool` messages, and re-queries until the model produces a final
167
+ * answer (or `maxIterations` is reached).
168
+ */
169
+ export class ChatSession {
170
+ provider;
171
+ tools;
172
+ toolDefs;
173
+ model;
174
+ maxIterations;
175
+ messages = [];
176
+ constructor(options) {
177
+ if (!options?.provider)
178
+ throw new Error('ChatSession: a provider is required');
179
+ this.provider = options.provider;
180
+ this.tools = new Map((options.tools ?? []).map((t) => [t.name, t]));
181
+ this.toolDefs = (options.tools ?? []).map(({ name, description, parameters }) => ({ name, description, parameters }));
182
+ this.model = options.model;
183
+ this.maxIterations = options.maxIterations ?? 5;
184
+ if (options.system)
185
+ this.messages.push({ role: 'system', content: options.system });
186
+ }
187
+ /** Send a user message and resolve to the final assistant message. */
188
+ async send(userMessage) {
189
+ this.messages.push({ role: 'user', content: userMessage });
190
+ let toolCallsExecuted = 0;
191
+ for (let i = 0; i < this.maxIterations; i++) {
192
+ const res = await this.provider.chat({
193
+ messages: this.messages,
194
+ tools: this.toolDefs.length > 0 ? this.toolDefs : undefined,
195
+ model: this.model,
196
+ });
197
+ this.messages.push(res.message);
198
+ if (res.finishReason !== 'tool_calls' || !res.message.toolCalls?.length) {
199
+ return { message: res.message, toolCallsExecuted };
200
+ }
201
+ // Execute each requested tool and append its result.
202
+ for (const call of res.message.toolCalls) {
203
+ toolCallsExecuted++;
204
+ const tool = this.tools.get(call.name);
205
+ let content;
206
+ try {
207
+ if (!tool)
208
+ throw new Error(`unknown tool "${call.name}"`);
209
+ const result = await tool.handler(call.arguments);
210
+ content = typeof result === 'string' ? result : JSON.stringify(result);
211
+ }
212
+ catch (err) {
213
+ content = JSON.stringify({ error: err.message });
214
+ }
215
+ this.messages.push({ role: 'tool', content, toolCallId: call.id });
216
+ }
217
+ }
218
+ // Loop budget exhausted: return the last assistant message we have.
219
+ const lastAssistant = [...this.messages].reverse().find((m) => m.role === 'assistant');
220
+ return {
221
+ message: lastAssistant ?? { role: 'assistant', content: '' },
222
+ toolCallsExecuted,
223
+ };
224
+ }
225
+ }
226
+ export * from './providers.js';
227
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,qDAAqD;AACrD,EAAE;AACF,4EAA4E;AAC5E,sCAAsC;AACtC,EAAE;AACF,gEAAgE;AAChE,+EAA+E;AAC/E,+EAA+E;AAC/E,iFAAiF;AACjF,gFAAgF;AAChF,uEAAuE;AACvE,+EAA+E;AAC/E,gFAAgF;AAChF,iFAAiF;AACjF,4EAA4E;AAC5E,+DAA+D;AAC/D,8EAA8E;AAC9E,8EAA8E;AAoE9E,iFAAiF;AAEjF,iFAAiF;AACjF,MAAM,UAAU,gBAAgB,CAAC,CAAW,EAAE,CAAW;IACvD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC,MAAM,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACvF,CAAC;IACD,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACrB,EAAE,IAAI,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACpB,EAAE,IAAI,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;IACtB,CAAC;IACD,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACnC,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,mFAAmF;AAEnF,MAAM,QAAQ,GAAG,EAAE,CAAC;AAEpB,qCAAqC;AACrC,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;AACtD,CAAC;AAED,iCAAiC;AACjC,SAAS,KAAK,CAAC,CAAS;IACtB,IAAI,CAAC,GAAG,UAAU,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,GAAG,GAAG,QAAQ;IACxD,MAAM,CAAC,GAAG,IAAI,KAAK,CAAS,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACzC,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACjC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,CAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAaD,iFAAiF;AACjF,MAAM,OAAO,cAAc;IAChB,IAAI,GAAG,MAAM,CAAC;IACN,GAAG,CAAS;IACZ,UAAU,CAAuD;IAElF,YAAY,UAAiC,EAAE;QAC7C,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,QAAQ,CAAC;QACnC,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAAoB;QAC7B,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAG,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;QAChF,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,SAAS,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,yBAAyB,CAAC;QACnF,OAAO;YACL,OAAO,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE;YACvC,YAAY,EAAE,MAAM;YACpB,KAAK,EAAE,EAAE,YAAY,EAAE,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,gBAAgB,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE;SACnG,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAAqB;QAC/B,OAAO;YACL,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;YAChE,KAAK,EAAE,EAAE,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE;SACxG,CAAC;IACJ,CAAC;CACF;AAED,SAAS,WAAW,CAAC,QAAuB;IAC1C,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AACtE,CAAC;AAyBD,6DAA6D;AAC7D,MAAM,OAAO,mBAAmB;IACb,OAAO,GAAG,IAAI,GAAG,EAAwB,CAAC;IAE3D,KAAK,CAAC,MAAM,CAAC,MAAoB;QAC/B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,SAAmB,EAAE,CAAS;QACxC,MAAM,MAAM,GAAmB,EAAE,CAAC;QAClC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC3C,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAChF,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjF,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,IAAI;QACR,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;CACF;AA2BD,yEAAyE;AACzE,MAAM,OAAO,WAAW;IACL,QAAQ,CAAa;IACrB,KAAK,CAAc;IACnB,IAAI,CAAS;IACb,UAAU,CAAqB;IAC/B,SAAS,CAAqB;IAE/C,YAAY,OAA2B;QACrC,IAAI,CAAC,OAAO,EAAE,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QAC/E,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,IAAI,mBAAmB,EAAE,CAAC;QACxD,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IACrC,CAAC;IAED,qDAAqD;IACrD,KAAK,CAAC,KAAK,CAAC,IAAmB;QAC7B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC9B,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;QAC7G,MAAM,OAAO,CAAC,GAAG,CACf,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAChB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAC/F,CACF,CAAC;IACJ,CAAC;IAED,sDAAsD;IACtD,KAAK,CAAC,QAAQ,CAAC,KAAa,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI;QACzC,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;QAC7F,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAE,EAAE,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI;QACvC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC9C,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrF,MAAM,QAAQ,GAAkB;YAC9B;gBACE,IAAI,EAAE,QAAQ;gBACd,OAAO,EACL,uDAAuD;oBACvD,uDAAuD,GAAG,YAAY;aACzE;YACD,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE;SACjC,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAC1E,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC;IACpE,CAAC;CACF;AAwBD;;;;;GAKG;AACH,MAAM,OAAO,WAAW;IACL,QAAQ,CAAa;IACrB,KAAK,CAA8B;IACnC,QAAQ,CAAmB;IAC3B,KAAK,CAAqB;IAC1B,aAAa,CAAS;IAC9B,QAAQ,GAAkB,EAAE,CAAC;IAEtC,YAAY,OAA2B;QACrC,IAAI,CAAC,OAAO,EAAE,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QAC/E,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,IAAI,CAAC,QAAQ,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;QACtH,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,CAAC,CAAC;QAChD,IAAI,OAAO,CAAC,MAAM;YAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACtF,CAAC;IAED,sEAAsE;IACtE,KAAK,CAAC,IAAI,CAAC,WAAmB;QAC5B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;QAC3D,IAAI,iBAAiB,GAAG,CAAC,CAAC;QAE1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACnC,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;gBAC3D,KAAK,EAAE,IAAI,CAAC,KAAK;aAClB,CAAC,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAEhC,IAAI,GAAG,CAAC,YAAY,KAAK,YAAY,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;gBACxE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,iBAAiB,EAAE,CAAC;YACrD,CAAC;YAED,qDAAqD;YACrD,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;gBACzC,iBAAiB,EAAE,CAAC;gBACpB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACvC,IAAI,OAAe,CAAC;gBACpB,IAAI,CAAC;oBACH,IAAI,CAAC,IAAI;wBAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;oBAC1D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBAClD,OAAO,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBACzE,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC9D,CAAC;gBACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;YACrE,CAAC;QACH,CAAC;QAED,oEAAoE;QACpE,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;QACvF,OAAO;YACL,OAAO,EAAE,aAAa,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE;YAC5D,iBAAiB;SAClB,CAAC;IACJ,CAAC;CACF;AAED,cAAc,gBAAgB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@streetjs/ai",
3
+ "version": "1.0.0",
4
+ "description": "Official Street Framework AI module: provider-agnostic chat, embeddings, RAG, and tool-calling with OpenAI/Anthropic/Ollama adapters and a deterministic in-memory provider for tests.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist/index.js",
16
+ "dist/index.js.map",
17
+ "dist/index.d.ts",
18
+ "dist/index.d.ts.map",
19
+ "README.md"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsc",
23
+ "lint": "tsc --noEmit",
24
+ "test": "tsc && node --test dist/tests/*.test.js",
25
+ "example": "npm run build && node examples/index.mjs",
26
+ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
27
+ "prepublishOnly": "npm run clean && npm run build"
28
+ },
29
+ "keywords": [
30
+ "street",
31
+ "streetjs",
32
+ "street-framework",
33
+ "ai",
34
+ "llm",
35
+ "embeddings",
36
+ "rag",
37
+ "tool-calling",
38
+ "openai",
39
+ "anthropic",
40
+ "ollama"
41
+ ],
42
+ "author": "street contributors",
43
+ "license": "MIT",
44
+ "homepage": "https://hassanmubiru.github.io/StreetJS/",
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "git+https://github.com/hassanmubiru/StreetJS.git"
48
+ },
49
+ "bugs": {
50
+ "url": "https://github.com/hassanmubiru/StreetJS/issues"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "^25.9.2",
54
+ "fast-check": "^4.8.0",
55
+ "typescript": "^6.0.3"
56
+ },
57
+ "peerDependencies": {
58
+ "typescript": ">=5.0.0"
59
+ },
60
+ "engines": {
61
+ "node": ">=22.0.0"
62
+ },
63
+ "publishConfig": {
64
+ "access": "public"
65
+ }
66
+ }