agent-pulse 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 +361 -0
- package/dist/agent.d.ts +8 -0
- package/dist/agent.js +83 -0
- package/dist/chain.d.ts +53 -0
- package/dist/chain.js +91 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +31 -0
- package/dist/providers/google.d.ts +8 -0
- package/dist/providers/google.js +277 -0
- package/dist/providers/grok.d.ts +8 -0
- package/dist/providers/grok.js +148 -0
- package/dist/providers/index.d.ts +5 -0
- package/dist/providers/index.js +28 -0
- package/dist/providers/openai.d.ts +8 -0
- package/dist/providers/openai.js +152 -0
- package/dist/sse.d.ts +15 -0
- package/dist/sse.js +67 -0
- package/dist/types.d.ts +45 -0
- package/dist/types.js +2 -0
- package/dist/utils/file-utils.d.ts +26 -0
- package/dist/utils/file-utils.js +128 -0
- package/dist/utils/image-utils.d.ts +9 -0
- package/dist/utils/image-utils.js +36 -0
- package/package.json +48 -0
package/dist/sse.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setupSSEHeaders = setupSSEHeaders;
|
|
4
|
+
exports.bridgeToSSE = bridgeToSSE;
|
|
5
|
+
/**
|
|
6
|
+
* Sets up standard Server-Sent Events (SSE) headers on the response object.
|
|
7
|
+
* Compatible with Node.js http.ServerResponse and Express Response.
|
|
8
|
+
* @param res The response object
|
|
9
|
+
*/
|
|
10
|
+
function setupSSEHeaders(res) {
|
|
11
|
+
if (typeof res.setHeader === 'function') {
|
|
12
|
+
res.setHeader('Content-Type', 'text/event-stream');
|
|
13
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
14
|
+
res.setHeader('Connection', 'keep-alive');
|
|
15
|
+
// Ensure flushing validation
|
|
16
|
+
if (typeof res.flushHeaders === 'function') {
|
|
17
|
+
res.flushHeaders();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Bridges Agent events to a Server-Sent Events (SSE) stream.
|
|
23
|
+
* Automatically attaches listeners to the agent and writes formatted SSE events to the response.
|
|
24
|
+
*
|
|
25
|
+
* @param res The response object (Node.js or Express)
|
|
26
|
+
* @param agent The Agent instance to listen to
|
|
27
|
+
*/
|
|
28
|
+
function bridgeToSSE(res, agent) {
|
|
29
|
+
const sendEvent = (event, data) => {
|
|
30
|
+
// We use JSON.stringify to safely serialize the data (strings or objects)
|
|
31
|
+
// This handles newlines and special characters correctly in the SSE format.
|
|
32
|
+
res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
|
|
33
|
+
// Optional: Flush if method exists (some environments need explicit flush)
|
|
34
|
+
if (typeof res.flush === 'function') {
|
|
35
|
+
res.flush();
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
// Listen to 'token' events for streaming
|
|
39
|
+
const tokenListener = (token) => {
|
|
40
|
+
sendEvent('token', token);
|
|
41
|
+
};
|
|
42
|
+
// Listen to 'response' event for final completion
|
|
43
|
+
const responseListener = (response) => {
|
|
44
|
+
sendEvent('response', response);
|
|
45
|
+
cleanup();
|
|
46
|
+
res.end();
|
|
47
|
+
};
|
|
48
|
+
// Listen to 'error' event
|
|
49
|
+
const errorListener = (error) => {
|
|
50
|
+
sendEvent('error', error);
|
|
51
|
+
cleanup();
|
|
52
|
+
res.end();
|
|
53
|
+
};
|
|
54
|
+
// Cleanup listeners to avoid memory leaks if the agent is reused (though usually one-off)
|
|
55
|
+
const cleanup = () => {
|
|
56
|
+
agent.off('token', tokenListener);
|
|
57
|
+
agent.off('response', responseListener);
|
|
58
|
+
agent.off('error', errorListener);
|
|
59
|
+
};
|
|
60
|
+
agent.on('token', tokenListener);
|
|
61
|
+
agent.on('response', responseListener);
|
|
62
|
+
agent.on('error', errorListener);
|
|
63
|
+
// Handle client disconnect if possible
|
|
64
|
+
if (res.on) {
|
|
65
|
+
res.on('close', cleanup);
|
|
66
|
+
}
|
|
67
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export interface AgentConfig {
|
|
3
|
+
name: string;
|
|
4
|
+
provider: LLMProvider;
|
|
5
|
+
prompt?: string;
|
|
6
|
+
system?: string;
|
|
7
|
+
files?: string[];
|
|
8
|
+
config?: Record<string, any>;
|
|
9
|
+
tools?: AgentTool[];
|
|
10
|
+
output_schema?: z.ZodType<any>;
|
|
11
|
+
saveFunction?: (message: any) => Promise<void> | void;
|
|
12
|
+
}
|
|
13
|
+
export interface AgentTool {
|
|
14
|
+
name: string;
|
|
15
|
+
description: string;
|
|
16
|
+
parameters: z.ZodType<any>;
|
|
17
|
+
execute: (args: any) => Promise<any>;
|
|
18
|
+
}
|
|
19
|
+
export interface AgentResponse {
|
|
20
|
+
content: string | object;
|
|
21
|
+
tool_calls?: any[];
|
|
22
|
+
usage: {
|
|
23
|
+
input_tokens: number;
|
|
24
|
+
output_tokens: number;
|
|
25
|
+
total_tokens: number;
|
|
26
|
+
reasoning_tokens?: number;
|
|
27
|
+
};
|
|
28
|
+
meta: {
|
|
29
|
+
model: string;
|
|
30
|
+
latency_ms: number;
|
|
31
|
+
[key: string]: any;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export interface AgentEvent {
|
|
35
|
+
type: 'start' | 'token' | 'tool_start' | 'tool_end' | 'response' | 'error' | 'log';
|
|
36
|
+
payload: any;
|
|
37
|
+
}
|
|
38
|
+
export interface AgentError {
|
|
39
|
+
error_key: 'network_error' | 'auth_error' | 'json_error' | 'execution_error' | 'retry_error';
|
|
40
|
+
message: string;
|
|
41
|
+
details?: any;
|
|
42
|
+
}
|
|
43
|
+
export interface LLMProvider {
|
|
44
|
+
generate(system: string | undefined, prompt: string | any[], files: string[] | undefined, tools: AgentTool[] | undefined, config: Record<string, any> | undefined, output_schema: z.ZodType<any> | undefined, onToken: (token: string) => void): Promise<AgentResponse>;
|
|
45
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates if a file has an allowed extension
|
|
3
|
+
*/
|
|
4
|
+
export declare function validateFileExtension(filePath: string, allowedExtensions: string[]): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Reads a markdown file and returns its content
|
|
7
|
+
* @throws Error if file doesn't exist, can't be read, or has wrong extension
|
|
8
|
+
*/
|
|
9
|
+
export declare function readMarkdownFile(filePath: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Checks if a file is a supported image type
|
|
12
|
+
*/
|
|
13
|
+
export declare function isImageFile(filePath: string): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Reads an image file and returns base64 content
|
|
16
|
+
*/
|
|
17
|
+
export declare function readImageFile(filePath: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Reads multiple files (markdown or image) and formats them for provider consumption.
|
|
20
|
+
* Returns an array of file objects to be processed by the provider.
|
|
21
|
+
* Note: This changes the return signature from string to object array, so we'll keep the string return for text-only
|
|
22
|
+
* compatibility for now, but providers should likely use a richer internal format if we were doing a full refactor.
|
|
23
|
+
* For this "Native First" approach, we will keep `readMarkdownFiles` as is for text, and let providers call specific readers.
|
|
24
|
+
* actually, let's keep `readMarkdownFiles` as is for backward compatibility and just export the new helpers.
|
|
25
|
+
*/
|
|
26
|
+
export declare function readMarkdownFiles(filePaths: string[]): string;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.validateFileExtension = validateFileExtension;
|
|
37
|
+
exports.readMarkdownFile = readMarkdownFile;
|
|
38
|
+
exports.isImageFile = isImageFile;
|
|
39
|
+
exports.readImageFile = readImageFile;
|
|
40
|
+
exports.readMarkdownFiles = readMarkdownFiles;
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
/**
|
|
44
|
+
* Validates if a file has an allowed extension
|
|
45
|
+
*/
|
|
46
|
+
function validateFileExtension(filePath, allowedExtensions) {
|
|
47
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
48
|
+
return allowedExtensions.includes(ext);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Reads a markdown file and returns its content
|
|
52
|
+
* @throws Error if file doesn't exist, can't be read, or has wrong extension
|
|
53
|
+
*/
|
|
54
|
+
function readMarkdownFile(filePath) {
|
|
55
|
+
// Validate extension
|
|
56
|
+
if (!validateFileExtension(filePath, ['.md', '.markdown'])) {
|
|
57
|
+
throw new Error(`Invalid file extension for ${filePath}. Only .md and .markdown files are supported.`);
|
|
58
|
+
}
|
|
59
|
+
// Check if file exists
|
|
60
|
+
if (!fs.existsSync(filePath)) {
|
|
61
|
+
throw new Error(`File not found: ${filePath}`);
|
|
62
|
+
}
|
|
63
|
+
// Read file
|
|
64
|
+
try {
|
|
65
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
66
|
+
return content;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
throw new Error(`Failed to read file ${filePath}: ${error.message}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Image extensions supported by Gemini and common web usage
|
|
73
|
+
const IMAGE_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.webp', '.heic', '.heif'];
|
|
74
|
+
/**
|
|
75
|
+
* Checks if a file is a supported image type
|
|
76
|
+
*/
|
|
77
|
+
function isImageFile(filePath) {
|
|
78
|
+
return validateFileExtension(filePath, IMAGE_EXTENSIONS);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Reads an image file and returns base64 content
|
|
82
|
+
*/
|
|
83
|
+
function readImageFile(filePath) {
|
|
84
|
+
if (!isImageFile(filePath)) {
|
|
85
|
+
throw new Error(`Invalid image file extension for ${filePath}`);
|
|
86
|
+
}
|
|
87
|
+
if (!fs.existsSync(filePath)) {
|
|
88
|
+
throw new Error(`File not found: ${filePath}`);
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const fileBuffer = fs.readFileSync(filePath);
|
|
92
|
+
return fileBuffer.toString('base64');
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
throw new Error(`Failed to read image file ${filePath}: ${error.message}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Reads multiple files (markdown or image) and formats them for provider consumption.
|
|
100
|
+
* Returns an array of file objects to be processed by the provider.
|
|
101
|
+
* Note: This changes the return signature from string to object array, so we'll keep the string return for text-only
|
|
102
|
+
* compatibility for now, but providers should likely use a richer internal format if we were doing a full refactor.
|
|
103
|
+
* For this "Native First" approach, we will keep `readMarkdownFiles` as is for text, and let providers call specific readers.
|
|
104
|
+
* actually, let's keep `readMarkdownFiles` as is for backward compatibility and just export the new helpers.
|
|
105
|
+
*/
|
|
106
|
+
function readMarkdownFiles(filePaths) {
|
|
107
|
+
if (!filePaths || filePaths.length === 0) {
|
|
108
|
+
return '';
|
|
109
|
+
}
|
|
110
|
+
const fileContents = [];
|
|
111
|
+
for (const filePath of filePaths) {
|
|
112
|
+
// Skip non-markdown files silently in this specific text-aggregator function
|
|
113
|
+
// so we don't break existing text-only prompts if an image is passed in the mixed list.
|
|
114
|
+
// The provider will handle the image files separately.
|
|
115
|
+
if (validateFileExtension(filePath, ['.md', '.markdown'])) {
|
|
116
|
+
try {
|
|
117
|
+
const content = readMarkdownFile(filePath);
|
|
118
|
+
const fileName = path.basename(filePath);
|
|
119
|
+
fileContents.push(`--- File: ${fileName} ---\n\n${content}\n\n--- End of ${fileName} ---`);
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
// Re-throw to be handled by the provider
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return fileContents.join('\n\n');
|
|
128
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts a base64 encoded image from a text response and saves it to a file.
|
|
3
|
+
*
|
|
4
|
+
* @param content The text content containing the data URL (e.g. "data:image/png;base64,...")
|
|
5
|
+
* @param outputDir The directory where the image should be saved
|
|
6
|
+
* @param filename Optional filename. If not provided, a timestamp-based name will be used.
|
|
7
|
+
* @returns The absolute path to the saved file, or throws an error if no image data is found.
|
|
8
|
+
*/
|
|
9
|
+
export declare function saveImage(content: string, outputDir: string, filename?: string): string;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.saveImage = saveImage;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
/**
|
|
10
|
+
* Extracts a base64 encoded image from a text response and saves it to a file.
|
|
11
|
+
*
|
|
12
|
+
* @param content The text content containing the data URL (e.g. "data:image/png;base64,...")
|
|
13
|
+
* @param outputDir The directory where the image should be saved
|
|
14
|
+
* @param filename Optional filename. If not provided, a timestamp-based name will be used.
|
|
15
|
+
* @returns The absolute path to the saved file, or throws an error if no image data is found.
|
|
16
|
+
*/
|
|
17
|
+
function saveImage(content, outputDir, filename) {
|
|
18
|
+
// Regex to find the data URL pattern and capture the base64 data
|
|
19
|
+
// Matches: data:image/<type>;base64,<data>
|
|
20
|
+
const dataUrlRegex = /data:image\/(\w+);base64,([A-Za-z0-9+/=]+)/;
|
|
21
|
+
const match = content.match(dataUrlRegex);
|
|
22
|
+
if (!match || !match[2]) {
|
|
23
|
+
throw new Error("No base64 image data found in content.");
|
|
24
|
+
}
|
|
25
|
+
const imageType = match[1]; // e.g., 'png', 'jpeg'
|
|
26
|
+
const base64Data = match[2];
|
|
27
|
+
const buffer = Buffer.from(base64Data, 'base64');
|
|
28
|
+
// Ensure output directory exists
|
|
29
|
+
if (!fs_1.default.existsSync(outputDir)) {
|
|
30
|
+
fs_1.default.mkdirSync(outputDir, { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
const finalFilename = filename || `generated_image_${Date.now()}.${imageType}`;
|
|
33
|
+
const outputPath = path_1.default.resolve(outputDir, finalFilename);
|
|
34
|
+
fs_1.default.writeFileSync(outputPath, buffer);
|
|
35
|
+
return outputPath;
|
|
36
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-pulse",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A lightweight, agentic AI framework for JavaScript/TypeScript",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"watch": "tsc --watch",
|
|
14
|
+
"test": "vitest",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"ai",
|
|
19
|
+
"agent",
|
|
20
|
+
"framework",
|
|
21
|
+
"llm",
|
|
22
|
+
"openai",
|
|
23
|
+
"gemini"
|
|
24
|
+
],
|
|
25
|
+
"author": "Mihir Panchal",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/mehere14/Agentic-Framework.git",
|
|
30
|
+
"directory": "agent-pulse"
|
|
31
|
+
},
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/mehere14/Agentic-Framework/issues"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/mehere14/Agentic-Framework/tree/main/agent-pulse#readme",
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@google/genai": "^1.33.0",
|
|
38
|
+
"dotenv": "^16.4.5",
|
|
39
|
+
"openai": "^4.28.0",
|
|
40
|
+
"zod": "^4.0.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^20.19.26",
|
|
44
|
+
"ts-node": "^10.9.2",
|
|
45
|
+
"typescript": "^5.3.3",
|
|
46
|
+
"vitest": "^1.3.1"
|
|
47
|
+
}
|
|
48
|
+
}
|