@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.
- package/README.md +215 -0
- package/dist/chat/Chat.d.ts +35 -0
- package/dist/chat/Chat.d.ts.map +1 -0
- package/dist/chat/Chat.js +147 -0
- package/dist/chat/ChatOptions.d.ts +10 -0
- package/dist/chat/ChatOptions.d.ts.map +1 -0
- package/dist/chat/ChatOptions.js +1 -0
- package/dist/chat/Content.d.ts +22 -0
- package/dist/chat/Content.d.ts.map +1 -0
- package/dist/chat/Content.js +1 -0
- package/dist/chat/Message.d.ts +11 -0
- package/dist/chat/Message.d.ts.map +1 -0
- package/dist/chat/Message.js +1 -0
- package/dist/chat/Role.d.ts +2 -0
- package/dist/chat/Role.d.ts.map +1 -0
- package/dist/chat/Role.js +1 -0
- package/dist/chat/Tool.d.ts +18 -0
- package/dist/chat/Tool.d.ts.map +1 -0
- package/dist/chat/Tool.js +1 -0
- package/dist/executor/Executor.d.ts +11 -0
- package/dist/executor/Executor.d.ts.map +1 -0
- package/dist/executor/Executor.js +26 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/llm.d.ts +25 -0
- package/dist/llm.d.ts.map +1 -0
- package/dist/llm.js +46 -0
- package/dist/providers/Provider.d.ts +45 -0
- package/dist/providers/Provider.d.ts.map +1 -0
- package/dist/providers/Provider.js +1 -0
- package/dist/providers/openai/Capabilities.d.ts +25 -0
- package/dist/providers/openai/Capabilities.d.ts.map +1 -0
- package/dist/providers/openai/Capabilities.js +322 -0
- package/dist/providers/openai/Chat.d.ts +8 -0
- package/dist/providers/openai/Chat.d.ts.map +1 -0
- package/dist/providers/openai/Chat.js +47 -0
- package/dist/providers/openai/Models.d.ts +8 -0
- package/dist/providers/openai/Models.d.ts.map +1 -0
- package/dist/providers/openai/Models.js +35 -0
- package/dist/providers/openai/OpenAIProvider.d.ts +23 -0
- package/dist/providers/openai/OpenAIProvider.d.ts.map +1 -0
- package/dist/providers/openai/OpenAIProvider.js +33 -0
- package/dist/providers/openai/Streaming.d.ts +8 -0
- package/dist/providers/openai/Streaming.d.ts.map +1 -0
- package/dist/providers/openai/Streaming.js +55 -0
- package/dist/providers/openai/index.d.ts +2 -0
- package/dist/providers/openai/index.d.ts.map +1 -0
- package/dist/providers/openai/index.js +11 -0
- package/dist/providers/openai/register.d.ts +2 -0
- package/dist/providers/openai/register.d.ts.map +1 -0
- package/dist/providers/openai/register.js +15 -0
- package/dist/providers/openai/types.d.ts +23 -0
- package/dist/providers/openai/types.d.ts.map +1 -0
- package/dist/providers/openai/types.js +1 -0
- package/dist/providers/registry.d.ts +20 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +29 -0
- package/dist/tools/Tool.d.ts +8 -0
- package/dist/tools/Tool.d.ts.map +1 -0
- package/dist/tools/Tool.js +1 -0
- package/dist/tools/ToolSet.d.ts +15 -0
- package/dist/tools/ToolSet.d.ts.map +1 -0
- package/dist/tools/ToolSet.js +29 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +1 -0
- package/dist/tools/runCommandTool.d.ts +8 -0
- package/dist/tools/runCommandTool.d.ts.map +1 -0
- package/dist/tools/runCommandTool.js +19 -0
- package/dist/utils/FileLoader.d.ts +5 -0
- package/dist/utils/FileLoader.d.ts.map +1 -0
- package/dist/utils/FileLoader.js +71 -0
- 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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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
|
+
}
|