@node-llm/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 (74) hide show
  1. package/README.md +215 -0
  2. package/dist/chat/Chat.d.ts +35 -0
  3. package/dist/chat/Chat.d.ts.map +1 -0
  4. package/dist/chat/Chat.js +147 -0
  5. package/dist/chat/ChatOptions.d.ts +10 -0
  6. package/dist/chat/ChatOptions.d.ts.map +1 -0
  7. package/dist/chat/ChatOptions.js +1 -0
  8. package/dist/chat/Content.d.ts +22 -0
  9. package/dist/chat/Content.d.ts.map +1 -0
  10. package/dist/chat/Content.js +1 -0
  11. package/dist/chat/Message.d.ts +11 -0
  12. package/dist/chat/Message.d.ts.map +1 -0
  13. package/dist/chat/Message.js +1 -0
  14. package/dist/chat/Role.d.ts +2 -0
  15. package/dist/chat/Role.d.ts.map +1 -0
  16. package/dist/chat/Role.js +1 -0
  17. package/dist/chat/Tool.d.ts +18 -0
  18. package/dist/chat/Tool.d.ts.map +1 -0
  19. package/dist/chat/Tool.js +1 -0
  20. package/dist/executor/Executor.d.ts +11 -0
  21. package/dist/executor/Executor.d.ts.map +1 -0
  22. package/dist/executor/Executor.js +26 -0
  23. package/dist/index.d.ts +11 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +5 -0
  26. package/dist/llm.d.ts +25 -0
  27. package/dist/llm.d.ts.map +1 -0
  28. package/dist/llm.js +46 -0
  29. package/dist/providers/Provider.d.ts +45 -0
  30. package/dist/providers/Provider.d.ts.map +1 -0
  31. package/dist/providers/Provider.js +1 -0
  32. package/dist/providers/openai/Capabilities.d.ts +25 -0
  33. package/dist/providers/openai/Capabilities.d.ts.map +1 -0
  34. package/dist/providers/openai/Capabilities.js +322 -0
  35. package/dist/providers/openai/Chat.d.ts +8 -0
  36. package/dist/providers/openai/Chat.d.ts.map +1 -0
  37. package/dist/providers/openai/Chat.js +47 -0
  38. package/dist/providers/openai/Models.d.ts +8 -0
  39. package/dist/providers/openai/Models.d.ts.map +1 -0
  40. package/dist/providers/openai/Models.js +35 -0
  41. package/dist/providers/openai/OpenAIProvider.d.ts +23 -0
  42. package/dist/providers/openai/OpenAIProvider.d.ts.map +1 -0
  43. package/dist/providers/openai/OpenAIProvider.js +33 -0
  44. package/dist/providers/openai/Streaming.d.ts +8 -0
  45. package/dist/providers/openai/Streaming.d.ts.map +1 -0
  46. package/dist/providers/openai/Streaming.js +55 -0
  47. package/dist/providers/openai/index.d.ts +2 -0
  48. package/dist/providers/openai/index.d.ts.map +1 -0
  49. package/dist/providers/openai/index.js +11 -0
  50. package/dist/providers/openai/register.d.ts +2 -0
  51. package/dist/providers/openai/register.d.ts.map +1 -0
  52. package/dist/providers/openai/register.js +15 -0
  53. package/dist/providers/openai/types.d.ts +23 -0
  54. package/dist/providers/openai/types.d.ts.map +1 -0
  55. package/dist/providers/openai/types.js +1 -0
  56. package/dist/providers/registry.d.ts +20 -0
  57. package/dist/providers/registry.d.ts.map +1 -0
  58. package/dist/providers/registry.js +29 -0
  59. package/dist/tools/Tool.d.ts +8 -0
  60. package/dist/tools/Tool.d.ts.map +1 -0
  61. package/dist/tools/Tool.js +1 -0
  62. package/dist/tools/ToolSet.d.ts +15 -0
  63. package/dist/tools/ToolSet.d.ts.map +1 -0
  64. package/dist/tools/ToolSet.js +29 -0
  65. package/dist/tools/index.d.ts +2 -0
  66. package/dist/tools/index.d.ts.map +1 -0
  67. package/dist/tools/index.js +1 -0
  68. package/dist/tools/runCommandTool.d.ts +8 -0
  69. package/dist/tools/runCommandTool.d.ts.map +1 -0
  70. package/dist/tools/runCommandTool.js +19 -0
  71. package/dist/utils/FileLoader.d.ts +5 -0
  72. package/dist/utils/FileLoader.d.ts.map +1 -0
  73. package/dist/utils/FileLoader.js +71 -0
  74. package/package.json +29 -0
@@ -0,0 +1,11 @@
1
+ import { providerRegistry } from "../registry.js";
2
+ import { OpenAIProvider } from "./OpenAIProvider.js";
3
+ export function registerOpenAIProvider() {
4
+ providerRegistry.register("openai", () => {
5
+ const apiKey = process.env.OPENAI_API_KEY;
6
+ if (!apiKey) {
7
+ throw new Error("OPENAI_API_KEY is not set");
8
+ }
9
+ return new OpenAIProvider({ apiKey });
10
+ });
11
+ }
@@ -0,0 +1,2 @@
1
+ export declare function ensureOpenAIRegistered(): void;
2
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/register.ts"],"names":[],"mappings":"AAKA,wBAAgB,sBAAsB,SAcrC"}
@@ -0,0 +1,15 @@
1
+ import { providerRegistry } from "../registry.js";
2
+ import { OpenAIProvider } from "./OpenAIProvider.js";
3
+ let registered = false;
4
+ export function ensureOpenAIRegistered() {
5
+ if (registered)
6
+ return;
7
+ providerRegistry.register("openai", () => {
8
+ const apiKey = process.env.OPENAI_API_KEY;
9
+ if (!apiKey) {
10
+ throw new Error("OPENAI_API_KEY is not set");
11
+ }
12
+ return new OpenAIProvider({ apiKey });
13
+ });
14
+ registered = true;
15
+ }
@@ -0,0 +1,23 @@
1
+ import { Message } from "../../chat/Message.js";
2
+ export interface OpenAIChatRequest {
3
+ model: string;
4
+ messages: Message[];
5
+ }
6
+ export interface OpenAIChatResponse {
7
+ choices: Array<{
8
+ message: {
9
+ role: string;
10
+ content: string | null;
11
+ tool_calls?: Array<{
12
+ id: string;
13
+ type: 'function';
14
+ function: {
15
+ name: string;
16
+ arguments: string;
17
+ };
18
+ }>;
19
+ };
20
+ finish_reason: string;
21
+ }>;
22
+ }
23
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,KAAK,CAAC;QACb,OAAO,EAAE;YACP,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;YACvB,UAAU,CAAC,EAAE,KAAK,CAAC;gBACjB,EAAE,EAAE,MAAM,CAAC;gBACX,IAAI,EAAE,UAAU,CAAC;gBACjB,QAAQ,EAAE;oBACR,IAAI,EAAE,MAAM,CAAC;oBACb,SAAS,EAAE,MAAM,CAAC;iBACnB,CAAC;aACH,CAAC,CAAC;SACJ,CAAC;QACF,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC,CAAC;CACJ"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import { Provider } from "./Provider.js";
2
+ type ProviderFactory = () => Provider;
3
+ declare class ProviderRegistry {
4
+ private providers;
5
+ /**
6
+ * Register a provider factory
7
+ */
8
+ register(name: string, factory: ProviderFactory): void;
9
+ /**
10
+ * Resolve a provider by name
11
+ */
12
+ resolve(name: string): Provider;
13
+ /**
14
+ * Introspection / debugging
15
+ */
16
+ list(): string[];
17
+ }
18
+ export declare const providerRegistry: ProviderRegistry;
19
+ export {};
20
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,KAAK,eAAe,GAAG,MAAM,QAAQ,CAAC;AAEtC,cAAM,gBAAgB;IACpB,OAAO,CAAC,SAAS,CAAsC;IAEvD;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI;IAQtD;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ;IAU/B;;OAEG;IACH,IAAI,IAAI,MAAM,EAAE;CAGjB;AAED,eAAO,MAAM,gBAAgB,kBAAyB,CAAC"}
@@ -0,0 +1,29 @@
1
+ class ProviderRegistry {
2
+ providers = new Map();
3
+ /**
4
+ * Register a provider factory
5
+ */
6
+ register(name, factory) {
7
+ if (this.providers.has(name)) {
8
+ throw new Error(`Provider '${name}' is already registered`);
9
+ }
10
+ this.providers.set(name, factory);
11
+ }
12
+ /**
13
+ * Resolve a provider by name
14
+ */
15
+ resolve(name) {
16
+ const factory = this.providers.get(name);
17
+ if (!factory) {
18
+ throw new Error(`Unknown LLM provider '${name}'`);
19
+ }
20
+ return factory();
21
+ }
22
+ /**
23
+ * Introspection / debugging
24
+ */
25
+ list() {
26
+ return [...this.providers.keys()];
27
+ }
28
+ }
29
+ export const providerRegistry = new ProviderRegistry();
@@ -0,0 +1,8 @@
1
+ export type ToolHandler = (args: any) => any | Promise<any>;
2
+ export interface Tool {
3
+ name: string;
4
+ description?: string;
5
+ parameters?: Record<string, any>;
6
+ handler: ToolHandler;
7
+ }
8
+ //# sourceMappingURL=Tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tool.d.ts","sourceRoot":"","sources":["../../src/tools/Tool.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,GAAG,KAAK,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;AAE5D,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,OAAO,EAAE,WAAW,CAAC;CACtB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,15 @@
1
+ import { Tool, ToolHandler } from "./Tool.js";
2
+ type ToolDefinition = ToolHandler | {
3
+ description?: string;
4
+ parameters?: Record<string, any>;
5
+ handler: ToolHandler;
6
+ };
7
+ export declare class ToolSet {
8
+ private tools;
9
+ constructor(defs?: Record<string, ToolDefinition>);
10
+ register(tool: Tool): void;
11
+ get(name: string): Tool | undefined;
12
+ list(): Tool[];
13
+ }
14
+ export {};
15
+ //# sourceMappingURL=ToolSet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolSet.d.ts","sourceRoot":"","sources":["../../src/tools/ToolSet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE9C,KAAK,cAAc,GACf,WAAW,GACX;IACE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,OAAO,EAAE,WAAW,CAAC;CACtB,CAAC;AAEN,qBAAa,OAAO;IAClB,OAAO,CAAC,KAAK,CAA2B;gBAE5B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC;IAiBjD,QAAQ,CAAC,IAAI,EAAE,IAAI;IAInB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAInC,IAAI,IAAI,IAAI,EAAE;CAGf"}
@@ -0,0 +1,29 @@
1
+ export class ToolSet {
2
+ tools = new Map();
3
+ constructor(defs) {
4
+ if (defs) {
5
+ for (const [name, def] of Object.entries(defs)) {
6
+ if (typeof def === "function") {
7
+ this.register({ name, handler: def });
8
+ }
9
+ else {
10
+ this.register({
11
+ name,
12
+ handler: def.handler,
13
+ description: def.description,
14
+ parameters: def.parameters,
15
+ });
16
+ }
17
+ }
18
+ }
19
+ }
20
+ register(tool) {
21
+ this.tools.set(tool.name, tool);
22
+ }
23
+ get(name) {
24
+ return this.tools.get(name);
25
+ }
26
+ list() {
27
+ return [...this.tools.values()];
28
+ }
29
+ }
@@ -0,0 +1,2 @@
1
+ export { runCommand } from './runCommandTool.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1 @@
1
+ export { runCommand } from './runCommandTool.js';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Executes a shell command and returns its stdout as a string.
3
+ *
4
+ * @param command - The command to execute.
5
+ * @returns A promise that resolves with the command's standard output.
6
+ */
7
+ export declare function runCommand(command: string): Promise<string>;
8
+ //# sourceMappingURL=runCommandTool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runCommandTool.d.ts","sourceRoot":"","sources":["../../src/tools/runCommandTool.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW3D"}
@@ -0,0 +1,19 @@
1
+ import { exec } from 'child_process';
2
+ /**
3
+ * Executes a shell command and returns its stdout as a string.
4
+ *
5
+ * @param command - The command to execute.
6
+ * @returns A promise that resolves with the command's standard output.
7
+ */
8
+ export function runCommand(command) {
9
+ return new Promise((resolve, reject) => {
10
+ exec(command, { maxBuffer: 1024 * 1024 }, (error, stdout, stderr) => {
11
+ if (error) {
12
+ reject(error);
13
+ return;
14
+ }
15
+ // Trim trailing newlines for cleaner output
16
+ resolve(stdout.trim());
17
+ });
18
+ });
19
+ }
@@ -0,0 +1,5 @@
1
+ import { ContentPart } from "../chat/Content.js";
2
+ export declare class FileLoader {
3
+ static load(filePath: string): Promise<ContentPart>;
4
+ }
5
+ //# sourceMappingURL=FileLoader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileLoader.d.ts","sourceRoot":"","sources":["../../src/utils/FileLoader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA+BjD,qBAAa,UAAU;WACR,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CA+C1D"}
@@ -0,0 +1,71 @@
1
+ import { promises as fs } from "fs";
2
+ import * as path from "path";
3
+ const MIME_TYPES = {
4
+ ".jpg": "image/jpeg",
5
+ ".jpeg": "image/jpeg",
6
+ ".png": "image/png",
7
+ ".gif": "image/gif",
8
+ ".webp": "image/webp",
9
+ ".mp4": "video/mp4",
10
+ ".mpeg": "video/mpeg",
11
+ ".mov": "video/quicktime",
12
+ ".wav": "audio/wav",
13
+ ".mp3": "audio/mpeg",
14
+ ".json": "application/json",
15
+ ".js": "text/javascript",
16
+ ".ts": "text/typescript",
17
+ ".rb": "text/x-ruby",
18
+ ".py": "text/x-python",
19
+ ".txt": "text/plain",
20
+ ".md": "text/markdown",
21
+ ".html": "text/html",
22
+ ".css": "text/css",
23
+ ".xml": "text/xml",
24
+ ".yml": "text/yaml",
25
+ ".yaml": "text/yaml",
26
+ };
27
+ const TEXT_EXTENSIONS = new Set([
28
+ ".json", ".js", ".ts", ".rb", ".py", ".txt", ".md", ".html", ".css", ".xml", ".yml", ".yaml", ".env"
29
+ ]);
30
+ export class FileLoader {
31
+ static async load(filePath) {
32
+ if (filePath.startsWith("http") || filePath.startsWith("data:")) {
33
+ // Assume image URL for now if it looks like a URL
34
+ // TODO: Better detection for remote file types
35
+ return { type: "image_url", image_url: { url: filePath } };
36
+ }
37
+ const ext = path.extname(filePath).toLowerCase();
38
+ const mime = MIME_TYPES[ext] ?? "application/octet-stream";
39
+ if (TEXT_EXTENSIONS.has(ext)) {
40
+ const content = await fs.readFile(filePath, "utf-8");
41
+ return {
42
+ type: "text",
43
+ text: `\n\n--- File: ${path.basename(filePath)} ---\n${content}\n--- End of File ---\n`
44
+ };
45
+ }
46
+ // Binary files (Images, Video, Audio)
47
+ const data = await fs.readFile(filePath);
48
+ const base64 = data.toString("base64");
49
+ const dataUri = `data:${mime};base64,${base64}`;
50
+ if (mime.startsWith("image/")) {
51
+ return { type: "image_url", image_url: { url: dataUri } };
52
+ }
53
+ if (mime.startsWith("audio/")) {
54
+ // OpenAI expects 'wav' or 'mp3' as format, not full mime
55
+ const format = mime.split("/")[1];
56
+ return {
57
+ type: "input_audio",
58
+ input_audio: {
59
+ data: base64,
60
+ format: (format === "mpeg" ? "mp3" : format) ?? "wav"
61
+ }
62
+ };
63
+ }
64
+ if (mime.startsWith("video/")) {
65
+ // For now, treat video as a URL (some providers might support data URIs for video)
66
+ return { type: "video_url", video_url: { url: dataUri } };
67
+ }
68
+ // Fallback for unknown binary types
69
+ return { type: "image_url", image_url: { url: dataUri } };
70
+ }
71
+ }
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@node-llm/core",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ }
12
+ },
13
+ "description": "A provider-agnostic LLM core for Node.js, inspired by ruby-llm.",
14
+ "author": "node-llm contributors",
15
+ "license": "MIT",
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsc -p tsconfig.json",
22
+ "dev": "tsc -w",
23
+ "test": "vitest",
24
+ "prepublishOnly": "npm run build"
25
+ },
26
+ "dependencies": {
27
+ "zod": "^3.23.8"
28
+ }
29
+ }