nexus-ai-pro 0.2.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 (171) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1249 -0
  3. package/assets/nexus-ai-pro-presentation.jpg +0 -0
  4. package/dist/agent/loop.d.ts +12 -0
  5. package/dist/agent/loop.js +89 -0
  6. package/dist/agent/tool.d.ts +16 -0
  7. package/dist/agent/tool.js +43 -0
  8. package/dist/cache/adapters.d.ts +42 -0
  9. package/dist/cache/adapters.js +76 -0
  10. package/dist/cache/memory-cache.d.ts +20 -0
  11. package/dist/cache/memory-cache.js +63 -0
  12. package/dist/cache/semantic-cache.d.ts +19 -0
  13. package/dist/cache/semantic-cache.js +71 -0
  14. package/dist/connectors/web.d.ts +8 -0
  15. package/dist/connectors/web.js +60 -0
  16. package/dist/core/nexus.d.ts +71 -0
  17. package/dist/core/nexus.js +477 -0
  18. package/dist/core/response-format.d.ts +8 -0
  19. package/dist/core/response-format.js +121 -0
  20. package/dist/core/secure-stream.d.ts +3 -0
  21. package/dist/core/secure-stream.js +41 -0
  22. package/dist/core/streaming.d.ts +4 -0
  23. package/dist/core/streaming.js +30 -0
  24. package/dist/embeddings/providers.d.ts +20 -0
  25. package/dist/embeddings/providers.js +60 -0
  26. package/dist/evals/metrics.d.ts +75 -0
  27. package/dist/evals/metrics.js +157 -0
  28. package/dist/evals/runner.d.ts +35 -0
  29. package/dist/evals/runner.js +47 -0
  30. package/dist/hallucination/consistency.d.ts +14 -0
  31. package/dist/hallucination/consistency.js +58 -0
  32. package/dist/hallucination/factual.d.ts +14 -0
  33. package/dist/hallucination/factual.js +35 -0
  34. package/dist/hallucination/knowledge-graph.d.ts +27 -0
  35. package/dist/hallucination/knowledge-graph.js +70 -0
  36. package/dist/hallucination/rag.d.ts +21 -0
  37. package/dist/hallucination/rag.js +46 -0
  38. package/dist/hallucination/retrieval.d.ts +24 -0
  39. package/dist/hallucination/retrieval.js +71 -0
  40. package/dist/hallucination/verification.d.ts +36 -0
  41. package/dist/hallucination/verification.js +110 -0
  42. package/dist/index.d.ts +62 -0
  43. package/dist/index.js +53 -0
  44. package/dist/jobs/batch.d.ts +11 -0
  45. package/dist/jobs/batch.js +32 -0
  46. package/dist/jobs/durable-adapters.d.ts +48 -0
  47. package/dist/jobs/durable-adapters.js +50 -0
  48. package/dist/jobs/queue.d.ts +24 -0
  49. package/dist/jobs/queue.js +57 -0
  50. package/dist/models/registry.d.ts +15 -0
  51. package/dist/models/registry.js +43 -0
  52. package/dist/next/route-handler.d.ts +6 -0
  53. package/dist/next/route-handler.js +35 -0
  54. package/dist/ops/audit-logger.d.ts +6 -0
  55. package/dist/ops/audit-logger.js +19 -0
  56. package/dist/ops/health.d.ts +29 -0
  57. package/dist/ops/health.js +69 -0
  58. package/dist/ops/metrics.d.ts +53 -0
  59. package/dist/ops/metrics.js +122 -0
  60. package/dist/ops/otel-tracing.d.ts +20 -0
  61. package/dist/ops/otel-tracing.js +50 -0
  62. package/dist/ops/rate-limiter.d.ts +11 -0
  63. package/dist/ops/rate-limiter.js +33 -0
  64. package/dist/optimizer/budget.d.ts +19 -0
  65. package/dist/optimizer/budget.js +88 -0
  66. package/dist/optimizer/cost.d.ts +13 -0
  67. package/dist/optimizer/cost.js +31 -0
  68. package/dist/optimizer/densifier.d.ts +10 -0
  69. package/dist/optimizer/densifier.js +77 -0
  70. package/dist/optimizer/index.d.ts +12 -0
  71. package/dist/optimizer/index.js +59 -0
  72. package/dist/pipeline/pipeline.d.ts +14 -0
  73. package/dist/pipeline/pipeline.js +106 -0
  74. package/dist/pipeline/types.d.ts +46 -0
  75. package/dist/pipeline/types.js +1 -0
  76. package/dist/providers/anthropic.d.ts +15 -0
  77. package/dist/providers/anthropic.js +183 -0
  78. package/dist/providers/base.d.ts +19 -0
  79. package/dist/providers/base.js +75 -0
  80. package/dist/providers/cohere.d.ts +16 -0
  81. package/dist/providers/cohere.js +104 -0
  82. package/dist/providers/google.d.ts +22 -0
  83. package/dist/providers/google.js +226 -0
  84. package/dist/providers/groq.d.ts +15 -0
  85. package/dist/providers/groq.js +50 -0
  86. package/dist/providers/mistral.d.ts +15 -0
  87. package/dist/providers/mistral.js +50 -0
  88. package/dist/providers/ollama.d.ts +15 -0
  89. package/dist/providers/ollama.js +108 -0
  90. package/dist/providers/openai.d.ts +21 -0
  91. package/dist/providers/openai.js +304 -0
  92. package/dist/providers/openrouter.d.ts +14 -0
  93. package/dist/providers/openrouter.js +19 -0
  94. package/dist/rag/file-ingestion.d.ts +20 -0
  95. package/dist/rag/file-ingestion.js +55 -0
  96. package/dist/rag/ingestion.d.ts +21 -0
  97. package/dist/rag/ingestion.js +47 -0
  98. package/dist/router/auto-router.d.ts +17 -0
  99. package/dist/router/auto-router.js +228 -0
  100. package/dist/router/failover.d.ts +21 -0
  101. package/dist/router/failover.js +126 -0
  102. package/dist/router/index.d.ts +12 -0
  103. package/dist/router/index.js +31 -0
  104. package/dist/router/rules-router.d.ts +7 -0
  105. package/dist/router/rules-router.js +68 -0
  106. package/dist/router/types.d.ts +19 -0
  107. package/dist/router/types.js +1 -0
  108. package/dist/security/index.d.ts +31 -0
  109. package/dist/security/index.js +173 -0
  110. package/dist/security/injection-calibration.d.ts +17 -0
  111. package/dist/security/injection-calibration.js +48 -0
  112. package/dist/security/injection-detector.d.ts +8 -0
  113. package/dist/security/injection-detector.js +66 -0
  114. package/dist/security/input-guard.d.ts +7 -0
  115. package/dist/security/input-guard.js +109 -0
  116. package/dist/security/output-guard.d.ts +6 -0
  117. package/dist/security/output-guard.js +144 -0
  118. package/dist/security/pii-detector.d.ts +8 -0
  119. package/dist/security/pii-detector.js +66 -0
  120. package/dist/security/policies.d.ts +4 -0
  121. package/dist/security/policies.js +61 -0
  122. package/dist/security/prompt-hardening.d.ts +6 -0
  123. package/dist/security/prompt-hardening.js +18 -0
  124. package/dist/security/schema-validator.d.ts +234 -0
  125. package/dist/security/schema-validator.js +68 -0
  126. package/dist/security/semantic-injection-classifier.d.ts +19 -0
  127. package/dist/security/semantic-injection-classifier.js +75 -0
  128. package/dist/security/upload-scanner.d.ts +29 -0
  129. package/dist/security/upload-scanner.js +72 -0
  130. package/dist/testing/provider-conformance.d.ts +24 -0
  131. package/dist/testing/provider-conformance.js +97 -0
  132. package/dist/types/agent.d.ts +34 -0
  133. package/dist/types/agent.js +1 -0
  134. package/dist/types/config.d.ts +171 -0
  135. package/dist/types/config.js +1 -0
  136. package/dist/types/messages.d.ts +96 -0
  137. package/dist/types/messages.js +1 -0
  138. package/dist/types/optimizer.d.ts +30 -0
  139. package/dist/types/optimizer.js +1 -0
  140. package/dist/types/planning.d.ts +27 -0
  141. package/dist/types/planning.js +1 -0
  142. package/dist/types/providers.d.ts +39 -0
  143. package/dist/types/providers.js +479 -0
  144. package/dist/types/response.d.ts +55 -0
  145. package/dist/types/response.js +1 -0
  146. package/dist/types/security.d.ts +87 -0
  147. package/dist/types/security.js +1 -0
  148. package/dist/utils/ids.d.ts +1 -0
  149. package/dist/utils/ids.js +4 -0
  150. package/dist/utils/logger.d.ts +7 -0
  151. package/dist/utils/logger.js +17 -0
  152. package/dist/utils/tokenizer.d.ts +6 -0
  153. package/dist/utils/tokenizer.js +38 -0
  154. package/dist/workflow/chains.d.ts +53 -0
  155. package/dist/workflow/chains.js +117 -0
  156. package/dist/workflow/domain.d.ts +22 -0
  157. package/dist/workflow/domain.js +96 -0
  158. package/examples/agent.ts +69 -0
  159. package/examples/basic.ts +37 -0
  160. package/examples/bullmq-worker.ts +36 -0
  161. package/examples/classifier-calibration.ts +7 -0
  162. package/examples/domain-workflows.ts +38 -0
  163. package/examples/feature-flags.ts +65 -0
  164. package/examples/minimal.ts +45 -0
  165. package/examples/ocr-pdf-ingestion.ts +42 -0
  166. package/examples/optimizer.ts +43 -0
  167. package/examples/otel-express.ts +47 -0
  168. package/examples/otel-node-http.ts +46 -0
  169. package/examples/persisted-vector-store.ts +42 -0
  170. package/examples/security.ts +69 -0
  171. package/package.json +165 -0
@@ -0,0 +1,12 @@
1
+ import type { AgentConfig, AgentResult } from '../types/agent.js';
2
+ import type { CompletionRequest } from '../types/messages.js';
3
+ import type { NexusResponse } from '../types/response.js';
4
+ export interface AgentModelClient {
5
+ complete(request: CompletionRequest): Promise<NexusResponse>;
6
+ }
7
+ export declare class AgentLoop {
8
+ private client;
9
+ constructor(client: AgentModelClient);
10
+ run(config: AgentConfig): Promise<AgentResult>;
11
+ private parseToolArgs;
12
+ }
@@ -0,0 +1,89 @@
1
+ import { ToolExecutor } from './tool.js';
2
+ export class AgentLoop {
3
+ client;
4
+ constructor(client) {
5
+ this.client = client;
6
+ }
7
+ async run(config) {
8
+ const maxIterations = config.maxIterations ?? 8;
9
+ const executor = new ToolExecutor(config.tools || []);
10
+ const steps = [];
11
+ const messages = [];
12
+ if (config.systemPrompt) {
13
+ messages.push({ role: 'system', content: config.systemPrompt });
14
+ }
15
+ messages.push({ role: 'user', content: config.goal });
16
+ let lastResponse = null;
17
+ for (let iteration = 1; iteration <= maxIterations; iteration++) {
18
+ const response = await this.client.complete({
19
+ model: config.model,
20
+ messages,
21
+ tools: executor.list(),
22
+ temperature: config.temperature,
23
+ maxTokens: config.maxTokens,
24
+ metadata: config.metadata,
25
+ });
26
+ lastResponse = response;
27
+ const modelStep = {
28
+ iteration,
29
+ type: response.toolCalls?.length ? 'model' : 'final',
30
+ message: response.content || (response.toolCalls?.length ? 'Model requested tool calls' : ''),
31
+ };
32
+ steps.push(modelStep);
33
+ await config.onStep?.(modelStep);
34
+ messages.push({
35
+ role: 'assistant',
36
+ content: response.content,
37
+ toolCalls: response.toolCalls,
38
+ });
39
+ if (!response.toolCalls || response.toolCalls.length === 0) {
40
+ return {
41
+ content: response.content,
42
+ steps,
43
+ iterations: iteration,
44
+ response,
45
+ messages,
46
+ };
47
+ }
48
+ for (const toolCall of response.toolCalls) {
49
+ const args = this.parseToolArgs(toolCall.function.arguments);
50
+ const result = await executor.execute(toolCall.function.name, args);
51
+ const toolStep = {
52
+ iteration,
53
+ type: 'tool',
54
+ message: result.ok ? 'Tool executed successfully' : `Tool failed: ${result.error}`,
55
+ toolName: toolCall.function.name,
56
+ toolArgs: args,
57
+ toolResult: result.ok ? result.result : { error: result.error },
58
+ };
59
+ steps.push(toolStep);
60
+ await config.onToolCall?.(toolStep);
61
+ await config.onStep?.(toolStep);
62
+ messages.push({
63
+ role: 'tool',
64
+ toolCallId: toolCall.id,
65
+ content: JSON.stringify(result.ok ? result.result : { error: result.error }),
66
+ });
67
+ }
68
+ }
69
+ if (!lastResponse) {
70
+ throw new Error('Agent loop failed before receiving a model response');
71
+ }
72
+ return {
73
+ content: lastResponse.content,
74
+ steps,
75
+ iterations: maxIterations,
76
+ response: lastResponse,
77
+ messages,
78
+ };
79
+ }
80
+ parseToolArgs(raw) {
81
+ try {
82
+ const parsed = JSON.parse(raw || '{}');
83
+ return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed) ? parsed : {};
84
+ }
85
+ catch {
86
+ return {};
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,16 @@
1
+ import type { ToolDefinition } from '../types/messages.js';
2
+ import type { ToolExecutionResult } from '../types/agent.js';
3
+ export declare function tool<TArgs extends Record<string, unknown> = Record<string, unknown>>(definition: {
4
+ name: string;
5
+ description: string;
6
+ parameters: Record<string, unknown>;
7
+ execute: (args: TArgs) => Promise<unknown> | unknown;
8
+ }): ToolDefinition;
9
+ export declare class ToolExecutor {
10
+ private tools;
11
+ constructor(tools?: ToolDefinition[]);
12
+ register(toolDefinition: ToolDefinition): this;
13
+ has(name: string): boolean;
14
+ list(): ToolDefinition[];
15
+ execute(name: string, args: Record<string, unknown>): Promise<ToolExecutionResult>;
16
+ }
@@ -0,0 +1,43 @@
1
+ export function tool(definition) {
2
+ return {
3
+ name: definition.name,
4
+ description: definition.description,
5
+ parameters: definition.parameters,
6
+ execute: async (args) => definition.execute(args),
7
+ };
8
+ }
9
+ export class ToolExecutor {
10
+ tools = new Map();
11
+ constructor(tools = []) {
12
+ tools.forEach((toolDefinition) => this.register(toolDefinition));
13
+ }
14
+ register(toolDefinition) {
15
+ this.tools.set(toolDefinition.name, toolDefinition);
16
+ return this;
17
+ }
18
+ has(name) {
19
+ return this.tools.has(name);
20
+ }
21
+ list() {
22
+ return [...this.tools.values()];
23
+ }
24
+ async execute(name, args) {
25
+ const toolDefinition = this.tools.get(name);
26
+ if (!toolDefinition) {
27
+ return { ok: false, error: `Tool "${name}" is not registered` };
28
+ }
29
+ if (!toolDefinition.execute) {
30
+ return { ok: false, error: `Tool "${name}" does not have an execute function` };
31
+ }
32
+ try {
33
+ const result = await toolDefinition.execute(args);
34
+ return { ok: true, result };
35
+ }
36
+ catch (err) {
37
+ return {
38
+ ok: false,
39
+ error: err instanceof Error ? err.message : String(err),
40
+ };
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,42 @@
1
+ export interface CacheAdapter<T = unknown> {
2
+ get(key: string): Promise<T | undefined> | T | undefined;
3
+ set(key: string, value: T, ttlSeconds?: number): Promise<void> | void;
4
+ delete?(key: string): Promise<boolean> | boolean;
5
+ clear?(): Promise<void> | void;
6
+ }
7
+ export declare class MemoryCacheAdapter<T = unknown> implements CacheAdapter<T> {
8
+ private entries;
9
+ get(key: string): T | undefined;
10
+ set(key: string, value: T, ttlSeconds?: number): void;
11
+ delete(key: string): boolean;
12
+ clear(): void;
13
+ }
14
+ export interface RedisLikeClient {
15
+ get(key: string): Promise<string | null> | string | null;
16
+ set(key: string, value: string, mode?: string, ttlSeconds?: number): Promise<unknown> | unknown;
17
+ del?(key: string): Promise<number> | number;
18
+ }
19
+ export declare class RedisCacheAdapter<T = unknown> implements CacheAdapter<T> {
20
+ private client;
21
+ private prefix;
22
+ constructor(client: RedisLikeClient, prefix?: string);
23
+ get(key: string): Promise<T | undefined>;
24
+ set(key: string, value: T, ttlSeconds?: number): Promise<void>;
25
+ delete(key: string): Promise<boolean>;
26
+ }
27
+ export interface SQLiteLikeDatabase {
28
+ prepare(sql: string): {
29
+ get?: (...args: unknown[]) => unknown;
30
+ run?: (...args: unknown[]) => unknown;
31
+ };
32
+ exec?(sql: string): unknown;
33
+ }
34
+ export declare class SQLiteCacheAdapter<T = unknown> implements CacheAdapter<T> {
35
+ private db;
36
+ private table;
37
+ constructor(db: SQLiteLikeDatabase, table?: string);
38
+ get(key: string): T | undefined;
39
+ set(key: string, value: T, ttlSeconds?: number): void;
40
+ delete(key: string): boolean;
41
+ clear(): void;
42
+ }
@@ -0,0 +1,76 @@
1
+ export class MemoryCacheAdapter {
2
+ entries = new Map();
3
+ get(key) {
4
+ const entry = this.entries.get(key);
5
+ if (!entry)
6
+ return undefined;
7
+ if (entry.expiresAt < Date.now()) {
8
+ this.entries.delete(key);
9
+ return undefined;
10
+ }
11
+ return entry.value;
12
+ }
13
+ set(key, value, ttlSeconds = 300) {
14
+ this.entries.set(key, {
15
+ value,
16
+ expiresAt: Date.now() + ttlSeconds * 1000,
17
+ });
18
+ }
19
+ delete(key) {
20
+ return this.entries.delete(key);
21
+ }
22
+ clear() {
23
+ this.entries.clear();
24
+ }
25
+ }
26
+ export class RedisCacheAdapter {
27
+ client;
28
+ prefix;
29
+ constructor(client, prefix = 'nexus-ai-pro:cache:') {
30
+ this.client = client;
31
+ this.prefix = prefix;
32
+ }
33
+ async get(key) {
34
+ const raw = await this.client.get(this.prefix + key);
35
+ if (!raw)
36
+ return undefined;
37
+ return JSON.parse(raw);
38
+ }
39
+ async set(key, value, ttlSeconds = 300) {
40
+ await this.client.set(this.prefix + key, JSON.stringify(value), 'EX', ttlSeconds);
41
+ }
42
+ async delete(key) {
43
+ if (!this.client.del)
44
+ return false;
45
+ return (await this.client.del(this.prefix + key)) > 0;
46
+ }
47
+ }
48
+ export class SQLiteCacheAdapter {
49
+ db;
50
+ table;
51
+ constructor(db, table = 'nexus_cache') {
52
+ this.db = db;
53
+ this.table = table;
54
+ this.db.exec?.(`CREATE TABLE IF NOT EXISTS ${table} (key TEXT PRIMARY KEY, value TEXT NOT NULL, expires_at INTEGER NOT NULL)`);
55
+ }
56
+ get(key) {
57
+ const row = this.db.prepare(`SELECT value, expires_at FROM ${this.table} WHERE key = ?`).get?.(key);
58
+ if (!row)
59
+ return undefined;
60
+ if (row.expires_at < Date.now()) {
61
+ this.delete(key);
62
+ return undefined;
63
+ }
64
+ return JSON.parse(row.value);
65
+ }
66
+ set(key, value, ttlSeconds = 300) {
67
+ this.db.prepare(`INSERT OR REPLACE INTO ${this.table} (key, value, expires_at) VALUES (?, ?, ?)`).run?.(key, JSON.stringify(value), Date.now() + ttlSeconds * 1000);
68
+ }
69
+ delete(key) {
70
+ this.db.prepare(`DELETE FROM ${this.table} WHERE key = ?`).run?.(key);
71
+ return true;
72
+ }
73
+ clear() {
74
+ this.db.prepare(`DELETE FROM ${this.table}`).run?.();
75
+ }
76
+ }
@@ -0,0 +1,20 @@
1
+ export interface CacheEntry<T> {
2
+ value: T;
3
+ expiresAt: number;
4
+ }
5
+ export declare class MemoryCache<T> {
6
+ private maxEntries;
7
+ private entries;
8
+ constructor(maxEntries?: number);
9
+ get(key: string): T | undefined;
10
+ set(key: string, value: T, ttlSeconds?: number): void;
11
+ clear(): void;
12
+ delete(key: string): boolean;
13
+ clearExpired(): number;
14
+ stats(): {
15
+ size: number;
16
+ maxEntries: number;
17
+ expiredEntries: number;
18
+ };
19
+ }
20
+ export declare function createCacheKey(value: unknown): string;
@@ -0,0 +1,63 @@
1
+ export class MemoryCache {
2
+ maxEntries;
3
+ entries = new Map();
4
+ constructor(maxEntries = 500) {
5
+ this.maxEntries = maxEntries;
6
+ }
7
+ get(key) {
8
+ const entry = this.entries.get(key);
9
+ if (!entry)
10
+ return undefined;
11
+ if (entry.expiresAt < Date.now()) {
12
+ this.entries.delete(key);
13
+ return undefined;
14
+ }
15
+ this.entries.delete(key);
16
+ this.entries.set(key, entry);
17
+ return entry.value;
18
+ }
19
+ set(key, value, ttlSeconds = 300) {
20
+ if (this.entries.size >= this.maxEntries) {
21
+ const oldest = this.entries.keys().next().value;
22
+ if (oldest)
23
+ this.entries.delete(oldest);
24
+ }
25
+ this.entries.set(key, {
26
+ value,
27
+ expiresAt: Date.now() + ttlSeconds * 1000,
28
+ });
29
+ }
30
+ clear() {
31
+ this.entries.clear();
32
+ }
33
+ delete(key) {
34
+ return this.entries.delete(key);
35
+ }
36
+ clearExpired() {
37
+ const now = Date.now();
38
+ let removed = 0;
39
+ for (const [key, entry] of this.entries) {
40
+ if (entry.expiresAt < now) {
41
+ this.entries.delete(key);
42
+ removed += 1;
43
+ }
44
+ }
45
+ return removed;
46
+ }
47
+ stats() {
48
+ const now = Date.now();
49
+ let expiredEntries = 0;
50
+ for (const entry of this.entries.values()) {
51
+ if (entry.expiresAt < now)
52
+ expiredEntries += 1;
53
+ }
54
+ return {
55
+ size: this.entries.size,
56
+ maxEntries: this.maxEntries,
57
+ expiredEntries,
58
+ };
59
+ }
60
+ }
61
+ export function createCacheKey(value) {
62
+ return JSON.stringify(value, Object.keys(value).sort());
63
+ }
@@ -0,0 +1,19 @@
1
+ import type { CompletionRequest } from '../types/messages.js';
2
+ import type { NexusResponse } from '../types/response.js';
3
+ import { type EmbeddingProvider } from '../hallucination/retrieval.js';
4
+ export interface SemanticCacheOptions {
5
+ enabled?: boolean;
6
+ similarityThreshold?: number;
7
+ maxEntries?: number;
8
+ ttlSeconds?: number;
9
+ embed?: EmbeddingProvider;
10
+ }
11
+ export declare class SemanticCache {
12
+ private options;
13
+ private entries;
14
+ private embed;
15
+ constructor(options?: SemanticCacheOptions);
16
+ get(request: CompletionRequest): Promise<NexusResponse | undefined>;
17
+ set(key: string, request: CompletionRequest, response: NexusResponse): Promise<void>;
18
+ clear(): void;
19
+ }
@@ -0,0 +1,71 @@
1
+ import { createHashEmbeddings, cosineSimilarity } from '../hallucination/retrieval.js';
2
+ export class SemanticCache {
3
+ options;
4
+ entries = [];
5
+ embed;
6
+ constructor(options = {}) {
7
+ this.options = options;
8
+ this.embed = options.embed || createHashEmbeddings;
9
+ }
10
+ async get(request) {
11
+ if (!this.options.enabled)
12
+ return undefined;
13
+ const text = requestToSearchText(request);
14
+ const [embedding] = await this.embed([text]);
15
+ const threshold = this.options.similarityThreshold ?? 0.88;
16
+ const now = Date.now();
17
+ let best;
18
+ this.entries = this.entries.filter((entry) => entry.expiresAt > now);
19
+ for (const entry of this.entries) {
20
+ const score = cosineSimilarity(embedding, entry.embedding);
21
+ if (score >= threshold && (!best || score > best.score)) {
22
+ best = { entry, score };
23
+ }
24
+ }
25
+ if (!best)
26
+ return undefined;
27
+ return {
28
+ ...best.entry.response,
29
+ meta: {
30
+ ...best.entry.response.meta,
31
+ cacheHit: true,
32
+ semanticCache: {
33
+ hit: true,
34
+ score: best.score,
35
+ key: best.entry.key,
36
+ },
37
+ },
38
+ };
39
+ }
40
+ async set(key, request, response) {
41
+ if (!this.options.enabled)
42
+ return;
43
+ const text = requestToSearchText(request);
44
+ const [embedding] = await this.embed([text]);
45
+ const maxEntries = this.options.maxEntries || 500;
46
+ if (this.entries.length >= maxEntries)
47
+ this.entries.shift();
48
+ this.entries.push({
49
+ key,
50
+ text,
51
+ embedding,
52
+ response,
53
+ expiresAt: Date.now() + (this.options.ttlSeconds || 300) * 1000,
54
+ });
55
+ }
56
+ clear() {
57
+ this.entries = [];
58
+ }
59
+ }
60
+ function requestToSearchText(request) {
61
+ return request.messages
62
+ .map((message) => {
63
+ if (typeof message.content === 'string')
64
+ return `${message.role}: ${message.content}`;
65
+ return `${message.role}: ${message.content
66
+ .filter((part) => part.type === 'text')
67
+ .map((part) => part.text)
68
+ .join('\n')}`;
69
+ })
70
+ .join('\n');
71
+ }
@@ -0,0 +1,8 @@
1
+ import type { ToolDefinition } from '../types/messages.js';
2
+ export interface WebConnectorOptions {
3
+ allowedDomains?: string[];
4
+ timeoutMs?: number;
5
+ userAgent?: string;
6
+ }
7
+ export declare function createFetchUrlTool(options?: WebConnectorOptions): ToolDefinition;
8
+ export declare function createSearchTool(search: (query: string) => Promise<unknown>, name?: string): ToolDefinition;
@@ -0,0 +1,60 @@
1
+ import { tool } from '../agent/tool.js';
2
+ export function createFetchUrlTool(options = {}) {
3
+ return tool({
4
+ name: 'fetch_url',
5
+ description: 'Fetch text content from an allowed URL.',
6
+ parameters: {
7
+ type: 'object',
8
+ required: ['url'],
9
+ properties: {
10
+ url: { type: 'string' },
11
+ },
12
+ },
13
+ execute: async (args) => {
14
+ const url = String(args.url || '');
15
+ assertAllowedUrl(url, options.allowedDomains);
16
+ const controller = new AbortController();
17
+ const timeout = setTimeout(() => controller.abort(), options.timeoutMs || 10_000);
18
+ try {
19
+ const response = await fetch(url, {
20
+ signal: controller.signal,
21
+ headers: { 'user-agent': options.userAgent || 'nexus-ai-pro/0.1' },
22
+ });
23
+ return {
24
+ url,
25
+ ok: response.ok,
26
+ status: response.status,
27
+ text: (await response.text()).slice(0, 20_000),
28
+ };
29
+ }
30
+ finally {
31
+ clearTimeout(timeout);
32
+ }
33
+ },
34
+ });
35
+ }
36
+ export function createSearchTool(search, name = 'web_search') {
37
+ return tool({
38
+ name,
39
+ description: 'Search the web or an external search index.',
40
+ parameters: {
41
+ type: 'object',
42
+ required: ['query'],
43
+ properties: {
44
+ query: { type: 'string' },
45
+ },
46
+ },
47
+ execute: async (args) => search(String(args.query || '')),
48
+ });
49
+ }
50
+ function assertAllowedUrl(url, allowedDomains) {
51
+ const parsed = new URL(url);
52
+ if (!['http:', 'https:'].includes(parsed.protocol)) {
53
+ throw new Error('Only http and https URLs are allowed');
54
+ }
55
+ if (!allowedDomains?.length)
56
+ return;
57
+ const allowed = allowedDomains.some((domain) => parsed.hostname === domain || parsed.hostname.endsWith(`.${domain}`));
58
+ if (!allowed)
59
+ throw new Error(`URL domain ${parsed.hostname} is not allowed`);
60
+ }
@@ -0,0 +1,71 @@
1
+ import type { NexusAIConfig } from '../types/config.js';
2
+ import type { CompletionRequest } from '../types/messages.js';
3
+ import type { NexusPlan } from '../types/planning.js';
4
+ import type { NexusResponse, NexusStream } from '../types/response.js';
5
+ import type { AgentConfig, AgentResult } from '../types/agent.js';
6
+ import type { PipelineStep } from '../pipeline/types.js';
7
+ import { BaseProvider } from '../providers/base.js';
8
+ import { type VerificationOptions } from '../hallucination/verification.js';
9
+ import { type SelfConsistencyOptions } from '../hallucination/consistency.js';
10
+ import { type BatchOptions, type BatchItemResult } from '../jobs/batch.js';
11
+ import { JobQueue, type QueueOptions } from '../jobs/queue.js';
12
+ import { type EvalCase, type EvalRunResult } from '../evals/runner.js';
13
+ import { type SummarizeVerifyFormatOptions, type WorkflowResult } from '../workflow/chains.js';
14
+ export declare class NexusAI {
15
+ private config;
16
+ private providers;
17
+ private router;
18
+ private failover;
19
+ private logger;
20
+ private security;
21
+ private optimizer;
22
+ private cache;
23
+ private auditLogger;
24
+ private rateLimiter;
25
+ private pipeline;
26
+ private metrics;
27
+ private health;
28
+ private semanticCache;
29
+ constructor(config: NexusAIConfig);
30
+ complete(request: CompletionRequest): Promise<NexusResponse>;
31
+ completeVerified(request: CompletionRequest, options: VerificationOptions): Promise<NexusResponse>;
32
+ completeConsistent(request: CompletionRequest, options?: SelfConsistencyOptions): Promise<NexusResponse>;
33
+ plan(request: CompletionRequest): NexusPlan;
34
+ stream(request: CompletionRequest): NexusStream;
35
+ agent(config: AgentConfig): Promise<AgentResult>;
36
+ registerProvider(name: string, provider: BaseProvider): this;
37
+ hasProvider(name: string): boolean;
38
+ listProviders(): string[];
39
+ use(step: PipelineStep): this;
40
+ batchComplete(requests: CompletionRequest[], options?: BatchOptions): Promise<Array<BatchItemResult<NexusResponse>>>;
41
+ createQueue(options?: QueueOptions): JobQueue<CompletionRequest, NexusResponse>;
42
+ runEvals(cases: EvalCase<NexusResponse>[]): Promise<EvalRunResult<NexusResponse>>;
43
+ summarizeVerifyFormat(options: SummarizeVerifyFormatOptions): Promise<WorkflowResult>;
44
+ getProviderHealth(): import("../ops/health.js").ProviderHealthSnapshot[];
45
+ checkProviders(): Promise<Array<{
46
+ providerName: string;
47
+ ok: boolean;
48
+ error?: string;
49
+ }>>;
50
+ getMetricsSnapshot(): Record<string, unknown>;
51
+ getPrometheusMetrics(): string;
52
+ clearCache(): void;
53
+ clearExpiredCache(): number;
54
+ getCacheStats(): {
55
+ size: number;
56
+ maxEntries: number;
57
+ expiredEntries: number;
58
+ };
59
+ private isAuditLogEnabled;
60
+ private isCacheEnabled;
61
+ private isCostBudgetEnabled;
62
+ private isSecurityEnabled;
63
+ private isTokenOptimizerEnabled;
64
+ private hasResponseFormat;
65
+ private registerConfiguredProviders;
66
+ private attachTrace;
67
+ private getCachedResponse;
68
+ private setCachedResponse;
69
+ private enforceCostBudget;
70
+ private estimatedOutputTokens;
71
+ }