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/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
+ }
@@ -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,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -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
+ }