@agentium/queue 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 +32 -0
- package/dist/index.cjs +306 -0
- package/dist/index.d.cts +171 -0
- package/dist/index.d.ts +171 -0
- package/dist/index.js +284 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# @agentium/queue
|
|
2
|
+
|
|
3
|
+
Background job processing for Agentium agents using BullMQ and Redis.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @agentium/queue bullmq ioredis
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { Agent, openai } from "@agentium/core";
|
|
15
|
+
import { AgentQueue, AgentWorker } from "@agentium/queue";
|
|
16
|
+
|
|
17
|
+
const agent = new Agent({ name: "assistant", model: openai("gpt-4o") });
|
|
18
|
+
const connection = { host: "localhost", port: 6379 };
|
|
19
|
+
|
|
20
|
+
const queue = new AgentQueue({ connection });
|
|
21
|
+
const worker = new AgentWorker({ agents: { assistant: agent }, connection });
|
|
22
|
+
|
|
23
|
+
await queue.enqueueAgentRun({ agentName: "assistant", input: "Hello!" });
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Documentation
|
|
27
|
+
|
|
28
|
+
Full docs at [agentium.mintlify.dev](https://agentium.mintlify.dev)
|
|
29
|
+
|
|
30
|
+
## License
|
|
31
|
+
|
|
32
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AgentQueue: () => AgentQueue,
|
|
24
|
+
AgentWorker: () => AgentWorker,
|
|
25
|
+
bridgeEventBusToJob: () => bridgeEventBusToJob
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
|
|
29
|
+
// src/job-producer.ts
|
|
30
|
+
var AgentQueue = class {
|
|
31
|
+
queue;
|
|
32
|
+
queueEvents;
|
|
33
|
+
queueName;
|
|
34
|
+
constructor(config) {
|
|
35
|
+
this.queueName = config.queueName ?? "agentium:jobs";
|
|
36
|
+
const connection = typeof config.connection === "string" ? { url: config.connection } : config.connection;
|
|
37
|
+
try {
|
|
38
|
+
const { Queue, QueueEvents } = require("bullmq");
|
|
39
|
+
this.queue = new Queue(this.queueName, {
|
|
40
|
+
connection,
|
|
41
|
+
defaultJobOptions: config.defaultJobOptions
|
|
42
|
+
});
|
|
43
|
+
this.queueEvents = new QueueEvents(this.queueName, {
|
|
44
|
+
connection
|
|
45
|
+
});
|
|
46
|
+
} catch (err) {
|
|
47
|
+
if (err?.code === "MODULE_NOT_FOUND" || err?.message?.includes("Cannot find module")) {
|
|
48
|
+
throw new Error("bullmq and ioredis are required for AgentQueue. Install them: npm install bullmq ioredis");
|
|
49
|
+
}
|
|
50
|
+
throw err;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async enqueueAgentRun(opts) {
|
|
54
|
+
const payload = {
|
|
55
|
+
type: "agent",
|
|
56
|
+
agentName: opts.agentName,
|
|
57
|
+
input: opts.input,
|
|
58
|
+
sessionId: opts.sessionId,
|
|
59
|
+
userId: opts.userId
|
|
60
|
+
};
|
|
61
|
+
const jobOpts = {};
|
|
62
|
+
if (opts.priority !== void 0) jobOpts.priority = opts.priority;
|
|
63
|
+
if (opts.delay !== void 0) jobOpts.delay = opts.delay;
|
|
64
|
+
if (opts.attempts !== void 0) jobOpts.attempts = opts.attempts;
|
|
65
|
+
if (opts.backoff) jobOpts.backoff = opts.backoff;
|
|
66
|
+
if (opts.repeat) jobOpts.repeat = opts.repeat;
|
|
67
|
+
const job = await this.queue.add(`agent:${opts.agentName}`, payload, jobOpts);
|
|
68
|
+
return { jobId: job.id };
|
|
69
|
+
}
|
|
70
|
+
async enqueueWorkflow(opts) {
|
|
71
|
+
const payload = {
|
|
72
|
+
type: "workflow",
|
|
73
|
+
workflowName: opts.workflowName,
|
|
74
|
+
initialState: opts.initialState,
|
|
75
|
+
sessionId: opts.sessionId
|
|
76
|
+
};
|
|
77
|
+
const jobOpts = {};
|
|
78
|
+
if (opts.priority !== void 0) jobOpts.priority = opts.priority;
|
|
79
|
+
if (opts.delay !== void 0) jobOpts.delay = opts.delay;
|
|
80
|
+
if (opts.attempts !== void 0) jobOpts.attempts = opts.attempts;
|
|
81
|
+
if (opts.backoff) jobOpts.backoff = opts.backoff;
|
|
82
|
+
if (opts.repeat) jobOpts.repeat = opts.repeat;
|
|
83
|
+
const job = await this.queue.add(`workflow:${opts.workflowName}`, payload, jobOpts);
|
|
84
|
+
return { jobId: job.id };
|
|
85
|
+
}
|
|
86
|
+
async enqueueTeamRun(opts) {
|
|
87
|
+
const payload = {
|
|
88
|
+
type: "team",
|
|
89
|
+
teamName: opts.teamName,
|
|
90
|
+
input: opts.input,
|
|
91
|
+
sessionId: opts.sessionId,
|
|
92
|
+
userId: opts.userId
|
|
93
|
+
};
|
|
94
|
+
const jobOpts = {};
|
|
95
|
+
if (opts.priority !== void 0) jobOpts.priority = opts.priority;
|
|
96
|
+
if (opts.delay !== void 0) jobOpts.delay = opts.delay;
|
|
97
|
+
if (opts.attempts !== void 0) jobOpts.attempts = opts.attempts;
|
|
98
|
+
if (opts.backoff) jobOpts.backoff = opts.backoff;
|
|
99
|
+
if (opts.repeat) jobOpts.repeat = opts.repeat;
|
|
100
|
+
const job = await this.queue.add(`team:${opts.teamName}`, payload, jobOpts);
|
|
101
|
+
return { jobId: job.id };
|
|
102
|
+
}
|
|
103
|
+
async getJobStatus(jobId) {
|
|
104
|
+
const job = await this.queue.getJob(jobId);
|
|
105
|
+
if (!job) {
|
|
106
|
+
throw new Error(`Job ${jobId} not found`);
|
|
107
|
+
}
|
|
108
|
+
const state = await job.getState();
|
|
109
|
+
return {
|
|
110
|
+
jobId: job.id,
|
|
111
|
+
state,
|
|
112
|
+
progress: typeof job.progress === "number" ? job.progress : void 0,
|
|
113
|
+
result: job.returnvalue,
|
|
114
|
+
error: job.failedReason,
|
|
115
|
+
createdAt: new Date(job.timestamp),
|
|
116
|
+
processedAt: job.processedOn ? new Date(job.processedOn) : void 0,
|
|
117
|
+
finishedAt: job.finishedOn ? new Date(job.finishedOn) : void 0
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async cancelJob(jobId) {
|
|
121
|
+
const job = await this.queue.getJob(jobId);
|
|
122
|
+
if (job) {
|
|
123
|
+
await job.remove();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
onCompleted(handler) {
|
|
127
|
+
this.queueEvents.on("completed", ({ jobId, returnvalue }) => {
|
|
128
|
+
handler(jobId, returnvalue);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
onFailed(handler) {
|
|
132
|
+
this.queueEvents.on("failed", ({ jobId, failedReason }) => {
|
|
133
|
+
handler(jobId, new Error(failedReason));
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
async schedule(opts) {
|
|
137
|
+
if (!opts.agent && !opts.workflow) {
|
|
138
|
+
throw new Error("schedule() requires either agent or workflow");
|
|
139
|
+
}
|
|
140
|
+
if (opts.agent && opts.workflow) {
|
|
141
|
+
throw new Error("schedule() accepts either agent or workflow, not both");
|
|
142
|
+
}
|
|
143
|
+
const repeat = { pattern: opts.cron, ...opts.timezone ? { tz: opts.timezone } : {} };
|
|
144
|
+
if (opts.agent) {
|
|
145
|
+
return this.enqueueAgentRun({
|
|
146
|
+
agentName: opts.agent.name,
|
|
147
|
+
input: opts.agent.input,
|
|
148
|
+
sessionId: opts.agent.sessionId,
|
|
149
|
+
userId: opts.agent.userId,
|
|
150
|
+
repeat
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if (opts.team) {
|
|
154
|
+
return this.enqueueTeamRun({
|
|
155
|
+
teamName: opts.team.name,
|
|
156
|
+
input: opts.team.input,
|
|
157
|
+
sessionId: opts.team.sessionId,
|
|
158
|
+
userId: opts.team.userId,
|
|
159
|
+
repeat
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
return this.enqueueWorkflow({
|
|
163
|
+
workflowName: opts.workflow.name,
|
|
164
|
+
initialState: opts.workflow.initialState,
|
|
165
|
+
repeat
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
async unschedule(id) {
|
|
169
|
+
const jobs = await this.queue.getRepeatableJobs();
|
|
170
|
+
const match = jobs.find((j) => j.name === `agent:${id}` || j.name === `workflow:${id}` || j.name === id);
|
|
171
|
+
if (!match) {
|
|
172
|
+
throw new Error(`Schedule "${id}" not found`);
|
|
173
|
+
}
|
|
174
|
+
await this.queue.removeRepeatableByKey(match.key);
|
|
175
|
+
}
|
|
176
|
+
async listSchedules() {
|
|
177
|
+
const jobs = await this.queue.getRepeatableJobs();
|
|
178
|
+
return jobs.map((j) => ({
|
|
179
|
+
id: j.name,
|
|
180
|
+
pattern: j.pattern ?? j.cron,
|
|
181
|
+
timezone: j.tz ?? void 0,
|
|
182
|
+
next: j.next ? new Date(j.next) : /* @__PURE__ */ new Date()
|
|
183
|
+
}));
|
|
184
|
+
}
|
|
185
|
+
async close() {
|
|
186
|
+
const results = await Promise.allSettled([this.queue.close(), this.queueEvents.close()]);
|
|
187
|
+
for (const r of results) {
|
|
188
|
+
if (r.status === "rejected") console.warn("[JobProducer] Error during close:", r.reason);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// src/job-worker.ts
|
|
194
|
+
var AgentWorker = class {
|
|
195
|
+
worker;
|
|
196
|
+
constructor(config) {
|
|
197
|
+
const queueName = config.queueName ?? "agentium:jobs";
|
|
198
|
+
const concurrency = config.concurrency ?? 5;
|
|
199
|
+
const connection = typeof config.connection === "string" ? { url: config.connection } : config.connection;
|
|
200
|
+
const defaultJobOptions = {
|
|
201
|
+
attempts: config.attempts ?? 3,
|
|
202
|
+
backoff: {
|
|
203
|
+
type: "exponential",
|
|
204
|
+
delay: config.backoffDelay ?? 1e3
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
try {
|
|
208
|
+
const { Worker } = require("bullmq");
|
|
209
|
+
this.worker = new Worker(
|
|
210
|
+
queueName,
|
|
211
|
+
async (job) => {
|
|
212
|
+
const payload = job.data;
|
|
213
|
+
if (payload.type === "agent") {
|
|
214
|
+
const agent = config.agentRegistry[payload.agentName];
|
|
215
|
+
if (!agent) {
|
|
216
|
+
throw new Error(`Agent "${payload.agentName}" not found in registry`);
|
|
217
|
+
}
|
|
218
|
+
const onChunk = (_evt) => {
|
|
219
|
+
job.updateProgress(typeof job.progress === "number" ? job.progress + 1 : 1);
|
|
220
|
+
};
|
|
221
|
+
agent.eventBus.on("run.stream.chunk", onChunk);
|
|
222
|
+
try {
|
|
223
|
+
const result = await agent.run(payload.input, {
|
|
224
|
+
sessionId: payload.sessionId,
|
|
225
|
+
userId: payload.userId
|
|
226
|
+
});
|
|
227
|
+
return result;
|
|
228
|
+
} finally {
|
|
229
|
+
agent.eventBus.off("run.stream.chunk", onChunk);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (payload.type === "workflow") {
|
|
233
|
+
const workflow = config.workflowRegistry?.[payload.workflowName];
|
|
234
|
+
if (!workflow) {
|
|
235
|
+
throw new Error(`Workflow "${payload.workflowName}" not found in registry`);
|
|
236
|
+
}
|
|
237
|
+
const result = await workflow.run({
|
|
238
|
+
sessionId: payload.sessionId
|
|
239
|
+
});
|
|
240
|
+
return result;
|
|
241
|
+
}
|
|
242
|
+
if (payload.type === "team") {
|
|
243
|
+
const team = config.teamRegistry?.[payload.teamName];
|
|
244
|
+
if (!team) {
|
|
245
|
+
throw new Error(`Team "${payload.teamName}" not found in registry`);
|
|
246
|
+
}
|
|
247
|
+
const result = await team.run(payload.input, {
|
|
248
|
+
sessionId: payload.sessionId,
|
|
249
|
+
userId: payload.userId
|
|
250
|
+
});
|
|
251
|
+
return result;
|
|
252
|
+
}
|
|
253
|
+
throw new Error(`Unknown job type: ${payload.type}`);
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
connection,
|
|
257
|
+
concurrency,
|
|
258
|
+
defaultJobOptions
|
|
259
|
+
}
|
|
260
|
+
);
|
|
261
|
+
} catch (err) {
|
|
262
|
+
if (err?.code === "MODULE_NOT_FOUND" || err?.message?.includes("Cannot find module")) {
|
|
263
|
+
throw new Error("bullmq and ioredis are required for AgentWorker. Install them: npm install bullmq ioredis");
|
|
264
|
+
}
|
|
265
|
+
throw err;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
start() {
|
|
269
|
+
}
|
|
270
|
+
async stop(timeoutMs = 3e4) {
|
|
271
|
+
await Promise.race([
|
|
272
|
+
this.worker.close(),
|
|
273
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("Worker drain timeout")), timeoutMs))
|
|
274
|
+
]).catch((err) => {
|
|
275
|
+
console.warn("[JobWorker] Error during stop:", err?.message ?? err);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// src/progress.ts
|
|
281
|
+
function bridgeEventBusToJob(eventBus, job, runId) {
|
|
282
|
+
let progressCount = 0;
|
|
283
|
+
const onChunk = (evt) => {
|
|
284
|
+
if (evt.runId !== runId) return;
|
|
285
|
+
progressCount++;
|
|
286
|
+
job.updateProgress(progressCount).catch(() => {
|
|
287
|
+
});
|
|
288
|
+
};
|
|
289
|
+
const onToolCall = (evt) => {
|
|
290
|
+
if (evt.runId !== runId) return;
|
|
291
|
+
job.log(`Tool call: ${evt.toolName}`).catch(() => {
|
|
292
|
+
});
|
|
293
|
+
};
|
|
294
|
+
eventBus.on("run.stream.chunk", onChunk);
|
|
295
|
+
eventBus.on("tool.call", onToolCall);
|
|
296
|
+
return () => {
|
|
297
|
+
eventBus.off("run.stream.chunk", onChunk);
|
|
298
|
+
eventBus.off("tool.call", onToolCall);
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
302
|
+
0 && (module.exports = {
|
|
303
|
+
AgentQueue,
|
|
304
|
+
AgentWorker,
|
|
305
|
+
bridgeEventBusToJob
|
|
306
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import * as _agentium_core from '@agentium/core';
|
|
2
|
+
import { RunOutput, Agent, Workflow, EventBus } from '@agentium/core';
|
|
3
|
+
|
|
4
|
+
type AgentJobPayload = {
|
|
5
|
+
type: "agent";
|
|
6
|
+
agentName: string;
|
|
7
|
+
input: string;
|
|
8
|
+
sessionId?: string;
|
|
9
|
+
userId?: string;
|
|
10
|
+
};
|
|
11
|
+
type WorkflowJobPayload = {
|
|
12
|
+
type: "workflow";
|
|
13
|
+
workflowName: string;
|
|
14
|
+
initialState?: Record<string, unknown>;
|
|
15
|
+
sessionId?: string;
|
|
16
|
+
};
|
|
17
|
+
type TeamJobPayload = {
|
|
18
|
+
type: "team";
|
|
19
|
+
teamName: string;
|
|
20
|
+
input: string;
|
|
21
|
+
sessionId?: string;
|
|
22
|
+
userId?: string;
|
|
23
|
+
};
|
|
24
|
+
type JobPayload = AgentJobPayload | WorkflowJobPayload | TeamJobPayload;
|
|
25
|
+
type ScheduleInfo = {
|
|
26
|
+
id: string;
|
|
27
|
+
pattern: string;
|
|
28
|
+
timezone?: string;
|
|
29
|
+
next: Date;
|
|
30
|
+
};
|
|
31
|
+
type JobStatus = {
|
|
32
|
+
jobId: string;
|
|
33
|
+
state: "waiting" | "active" | "completed" | "failed" | "delayed";
|
|
34
|
+
progress?: number;
|
|
35
|
+
result?: RunOutput;
|
|
36
|
+
error?: string;
|
|
37
|
+
createdAt: Date;
|
|
38
|
+
processedAt?: Date;
|
|
39
|
+
finishedAt?: Date;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
interface QueueConfig {
|
|
43
|
+
connection: {
|
|
44
|
+
host: string;
|
|
45
|
+
port: number;
|
|
46
|
+
password?: string;
|
|
47
|
+
db?: number;
|
|
48
|
+
tls?: boolean;
|
|
49
|
+
} | string;
|
|
50
|
+
queueName?: string;
|
|
51
|
+
defaultJobOptions?: Record<string, unknown>;
|
|
52
|
+
}
|
|
53
|
+
declare class AgentQueue {
|
|
54
|
+
private queue;
|
|
55
|
+
private queueEvents;
|
|
56
|
+
private queueName;
|
|
57
|
+
constructor(config: QueueConfig);
|
|
58
|
+
enqueueAgentRun(opts: {
|
|
59
|
+
agentName: string;
|
|
60
|
+
input: string;
|
|
61
|
+
sessionId?: string;
|
|
62
|
+
userId?: string;
|
|
63
|
+
priority?: number;
|
|
64
|
+
delay?: number;
|
|
65
|
+
attempts?: number;
|
|
66
|
+
backoff?: {
|
|
67
|
+
type: "exponential" | "fixed";
|
|
68
|
+
delay: number;
|
|
69
|
+
};
|
|
70
|
+
repeat?: {
|
|
71
|
+
pattern: string;
|
|
72
|
+
timezone?: string;
|
|
73
|
+
};
|
|
74
|
+
}): Promise<{
|
|
75
|
+
jobId: string;
|
|
76
|
+
}>;
|
|
77
|
+
enqueueWorkflow(opts: {
|
|
78
|
+
workflowName: string;
|
|
79
|
+
initialState?: Record<string, unknown>;
|
|
80
|
+
sessionId?: string;
|
|
81
|
+
priority?: number;
|
|
82
|
+
delay?: number;
|
|
83
|
+
attempts?: number;
|
|
84
|
+
backoff?: {
|
|
85
|
+
type: "exponential" | "fixed";
|
|
86
|
+
delay: number;
|
|
87
|
+
};
|
|
88
|
+
repeat?: {
|
|
89
|
+
pattern: string;
|
|
90
|
+
timezone?: string;
|
|
91
|
+
};
|
|
92
|
+
}): Promise<{
|
|
93
|
+
jobId: string;
|
|
94
|
+
}>;
|
|
95
|
+
enqueueTeamRun(opts: {
|
|
96
|
+
teamName: string;
|
|
97
|
+
input: string;
|
|
98
|
+
sessionId?: string;
|
|
99
|
+
userId?: string;
|
|
100
|
+
priority?: number;
|
|
101
|
+
delay?: number;
|
|
102
|
+
attempts?: number;
|
|
103
|
+
backoff?: {
|
|
104
|
+
type: "exponential" | "fixed";
|
|
105
|
+
delay: number;
|
|
106
|
+
};
|
|
107
|
+
repeat?: {
|
|
108
|
+
pattern: string;
|
|
109
|
+
timezone?: string;
|
|
110
|
+
};
|
|
111
|
+
}): Promise<{
|
|
112
|
+
jobId: string;
|
|
113
|
+
}>;
|
|
114
|
+
getJobStatus(jobId: string): Promise<JobStatus>;
|
|
115
|
+
cancelJob(jobId: string): Promise<void>;
|
|
116
|
+
onCompleted(handler: (jobId: string, result: RunOutput) => void): void;
|
|
117
|
+
onFailed(handler: (jobId: string, error: Error) => void): void;
|
|
118
|
+
schedule(opts: {
|
|
119
|
+
id: string;
|
|
120
|
+
cron: string;
|
|
121
|
+
timezone?: string;
|
|
122
|
+
agent?: {
|
|
123
|
+
name: string;
|
|
124
|
+
input: string;
|
|
125
|
+
sessionId?: string;
|
|
126
|
+
userId?: string;
|
|
127
|
+
};
|
|
128
|
+
workflow?: {
|
|
129
|
+
name: string;
|
|
130
|
+
initialState?: Record<string, unknown>;
|
|
131
|
+
};
|
|
132
|
+
team?: {
|
|
133
|
+
name: string;
|
|
134
|
+
input: string;
|
|
135
|
+
sessionId?: string;
|
|
136
|
+
userId?: string;
|
|
137
|
+
};
|
|
138
|
+
}): Promise<{
|
|
139
|
+
jobId: string;
|
|
140
|
+
}>;
|
|
141
|
+
unschedule(id: string): Promise<void>;
|
|
142
|
+
listSchedules(): Promise<ScheduleInfo[]>;
|
|
143
|
+
close(): Promise<void>;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
interface WorkerConfig {
|
|
147
|
+
connection: {
|
|
148
|
+
host: string;
|
|
149
|
+
port: number;
|
|
150
|
+
password?: string;
|
|
151
|
+
db?: number;
|
|
152
|
+
tls?: boolean;
|
|
153
|
+
} | string;
|
|
154
|
+
queueName?: string;
|
|
155
|
+
concurrency?: number;
|
|
156
|
+
attempts?: number;
|
|
157
|
+
backoffDelay?: number;
|
|
158
|
+
agentRegistry: Record<string, Agent>;
|
|
159
|
+
workflowRegistry?: Record<string, Workflow<any>>;
|
|
160
|
+
teamRegistry?: Record<string, _agentium_core.Team>;
|
|
161
|
+
}
|
|
162
|
+
declare class AgentWorker {
|
|
163
|
+
private worker;
|
|
164
|
+
constructor(config: WorkerConfig);
|
|
165
|
+
start(): void;
|
|
166
|
+
stop(timeoutMs?: number): Promise<void>;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
declare function bridgeEventBusToJob(eventBus: EventBus, job: any, runId: string): () => void;
|
|
170
|
+
|
|
171
|
+
export { type AgentJobPayload, AgentQueue, AgentWorker, type JobPayload, type JobStatus, type QueueConfig, type ScheduleInfo, type TeamJobPayload, type WorkerConfig, type WorkflowJobPayload, bridgeEventBusToJob };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import * as _agentium_core from '@agentium/core';
|
|
2
|
+
import { RunOutput, Agent, Workflow, EventBus } from '@agentium/core';
|
|
3
|
+
|
|
4
|
+
type AgentJobPayload = {
|
|
5
|
+
type: "agent";
|
|
6
|
+
agentName: string;
|
|
7
|
+
input: string;
|
|
8
|
+
sessionId?: string;
|
|
9
|
+
userId?: string;
|
|
10
|
+
};
|
|
11
|
+
type WorkflowJobPayload = {
|
|
12
|
+
type: "workflow";
|
|
13
|
+
workflowName: string;
|
|
14
|
+
initialState?: Record<string, unknown>;
|
|
15
|
+
sessionId?: string;
|
|
16
|
+
};
|
|
17
|
+
type TeamJobPayload = {
|
|
18
|
+
type: "team";
|
|
19
|
+
teamName: string;
|
|
20
|
+
input: string;
|
|
21
|
+
sessionId?: string;
|
|
22
|
+
userId?: string;
|
|
23
|
+
};
|
|
24
|
+
type JobPayload = AgentJobPayload | WorkflowJobPayload | TeamJobPayload;
|
|
25
|
+
type ScheduleInfo = {
|
|
26
|
+
id: string;
|
|
27
|
+
pattern: string;
|
|
28
|
+
timezone?: string;
|
|
29
|
+
next: Date;
|
|
30
|
+
};
|
|
31
|
+
type JobStatus = {
|
|
32
|
+
jobId: string;
|
|
33
|
+
state: "waiting" | "active" | "completed" | "failed" | "delayed";
|
|
34
|
+
progress?: number;
|
|
35
|
+
result?: RunOutput;
|
|
36
|
+
error?: string;
|
|
37
|
+
createdAt: Date;
|
|
38
|
+
processedAt?: Date;
|
|
39
|
+
finishedAt?: Date;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
interface QueueConfig {
|
|
43
|
+
connection: {
|
|
44
|
+
host: string;
|
|
45
|
+
port: number;
|
|
46
|
+
password?: string;
|
|
47
|
+
db?: number;
|
|
48
|
+
tls?: boolean;
|
|
49
|
+
} | string;
|
|
50
|
+
queueName?: string;
|
|
51
|
+
defaultJobOptions?: Record<string, unknown>;
|
|
52
|
+
}
|
|
53
|
+
declare class AgentQueue {
|
|
54
|
+
private queue;
|
|
55
|
+
private queueEvents;
|
|
56
|
+
private queueName;
|
|
57
|
+
constructor(config: QueueConfig);
|
|
58
|
+
enqueueAgentRun(opts: {
|
|
59
|
+
agentName: string;
|
|
60
|
+
input: string;
|
|
61
|
+
sessionId?: string;
|
|
62
|
+
userId?: string;
|
|
63
|
+
priority?: number;
|
|
64
|
+
delay?: number;
|
|
65
|
+
attempts?: number;
|
|
66
|
+
backoff?: {
|
|
67
|
+
type: "exponential" | "fixed";
|
|
68
|
+
delay: number;
|
|
69
|
+
};
|
|
70
|
+
repeat?: {
|
|
71
|
+
pattern: string;
|
|
72
|
+
timezone?: string;
|
|
73
|
+
};
|
|
74
|
+
}): Promise<{
|
|
75
|
+
jobId: string;
|
|
76
|
+
}>;
|
|
77
|
+
enqueueWorkflow(opts: {
|
|
78
|
+
workflowName: string;
|
|
79
|
+
initialState?: Record<string, unknown>;
|
|
80
|
+
sessionId?: string;
|
|
81
|
+
priority?: number;
|
|
82
|
+
delay?: number;
|
|
83
|
+
attempts?: number;
|
|
84
|
+
backoff?: {
|
|
85
|
+
type: "exponential" | "fixed";
|
|
86
|
+
delay: number;
|
|
87
|
+
};
|
|
88
|
+
repeat?: {
|
|
89
|
+
pattern: string;
|
|
90
|
+
timezone?: string;
|
|
91
|
+
};
|
|
92
|
+
}): Promise<{
|
|
93
|
+
jobId: string;
|
|
94
|
+
}>;
|
|
95
|
+
enqueueTeamRun(opts: {
|
|
96
|
+
teamName: string;
|
|
97
|
+
input: string;
|
|
98
|
+
sessionId?: string;
|
|
99
|
+
userId?: string;
|
|
100
|
+
priority?: number;
|
|
101
|
+
delay?: number;
|
|
102
|
+
attempts?: number;
|
|
103
|
+
backoff?: {
|
|
104
|
+
type: "exponential" | "fixed";
|
|
105
|
+
delay: number;
|
|
106
|
+
};
|
|
107
|
+
repeat?: {
|
|
108
|
+
pattern: string;
|
|
109
|
+
timezone?: string;
|
|
110
|
+
};
|
|
111
|
+
}): Promise<{
|
|
112
|
+
jobId: string;
|
|
113
|
+
}>;
|
|
114
|
+
getJobStatus(jobId: string): Promise<JobStatus>;
|
|
115
|
+
cancelJob(jobId: string): Promise<void>;
|
|
116
|
+
onCompleted(handler: (jobId: string, result: RunOutput) => void): void;
|
|
117
|
+
onFailed(handler: (jobId: string, error: Error) => void): void;
|
|
118
|
+
schedule(opts: {
|
|
119
|
+
id: string;
|
|
120
|
+
cron: string;
|
|
121
|
+
timezone?: string;
|
|
122
|
+
agent?: {
|
|
123
|
+
name: string;
|
|
124
|
+
input: string;
|
|
125
|
+
sessionId?: string;
|
|
126
|
+
userId?: string;
|
|
127
|
+
};
|
|
128
|
+
workflow?: {
|
|
129
|
+
name: string;
|
|
130
|
+
initialState?: Record<string, unknown>;
|
|
131
|
+
};
|
|
132
|
+
team?: {
|
|
133
|
+
name: string;
|
|
134
|
+
input: string;
|
|
135
|
+
sessionId?: string;
|
|
136
|
+
userId?: string;
|
|
137
|
+
};
|
|
138
|
+
}): Promise<{
|
|
139
|
+
jobId: string;
|
|
140
|
+
}>;
|
|
141
|
+
unschedule(id: string): Promise<void>;
|
|
142
|
+
listSchedules(): Promise<ScheduleInfo[]>;
|
|
143
|
+
close(): Promise<void>;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
interface WorkerConfig {
|
|
147
|
+
connection: {
|
|
148
|
+
host: string;
|
|
149
|
+
port: number;
|
|
150
|
+
password?: string;
|
|
151
|
+
db?: number;
|
|
152
|
+
tls?: boolean;
|
|
153
|
+
} | string;
|
|
154
|
+
queueName?: string;
|
|
155
|
+
concurrency?: number;
|
|
156
|
+
attempts?: number;
|
|
157
|
+
backoffDelay?: number;
|
|
158
|
+
agentRegistry: Record<string, Agent>;
|
|
159
|
+
workflowRegistry?: Record<string, Workflow<any>>;
|
|
160
|
+
teamRegistry?: Record<string, _agentium_core.Team>;
|
|
161
|
+
}
|
|
162
|
+
declare class AgentWorker {
|
|
163
|
+
private worker;
|
|
164
|
+
constructor(config: WorkerConfig);
|
|
165
|
+
start(): void;
|
|
166
|
+
stop(timeoutMs?: number): Promise<void>;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
declare function bridgeEventBusToJob(eventBus: EventBus, job: any, runId: string): () => void;
|
|
170
|
+
|
|
171
|
+
export { type AgentJobPayload, AgentQueue, AgentWorker, type JobPayload, type JobStatus, type QueueConfig, type ScheduleInfo, type TeamJobPayload, type WorkerConfig, type WorkflowJobPayload, bridgeEventBusToJob };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/job-producer.ts
|
|
9
|
+
var AgentQueue = class {
|
|
10
|
+
queue;
|
|
11
|
+
queueEvents;
|
|
12
|
+
queueName;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.queueName = config.queueName ?? "agentium:jobs";
|
|
15
|
+
const connection = typeof config.connection === "string" ? { url: config.connection } : config.connection;
|
|
16
|
+
try {
|
|
17
|
+
const { Queue, QueueEvents } = __require("bullmq");
|
|
18
|
+
this.queue = new Queue(this.queueName, {
|
|
19
|
+
connection,
|
|
20
|
+
defaultJobOptions: config.defaultJobOptions
|
|
21
|
+
});
|
|
22
|
+
this.queueEvents = new QueueEvents(this.queueName, {
|
|
23
|
+
connection
|
|
24
|
+
});
|
|
25
|
+
} catch (err) {
|
|
26
|
+
if (err?.code === "MODULE_NOT_FOUND" || err?.message?.includes("Cannot find module")) {
|
|
27
|
+
throw new Error("bullmq and ioredis are required for AgentQueue. Install them: npm install bullmq ioredis");
|
|
28
|
+
}
|
|
29
|
+
throw err;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async enqueueAgentRun(opts) {
|
|
33
|
+
const payload = {
|
|
34
|
+
type: "agent",
|
|
35
|
+
agentName: opts.agentName,
|
|
36
|
+
input: opts.input,
|
|
37
|
+
sessionId: opts.sessionId,
|
|
38
|
+
userId: opts.userId
|
|
39
|
+
};
|
|
40
|
+
const jobOpts = {};
|
|
41
|
+
if (opts.priority !== void 0) jobOpts.priority = opts.priority;
|
|
42
|
+
if (opts.delay !== void 0) jobOpts.delay = opts.delay;
|
|
43
|
+
if (opts.attempts !== void 0) jobOpts.attempts = opts.attempts;
|
|
44
|
+
if (opts.backoff) jobOpts.backoff = opts.backoff;
|
|
45
|
+
if (opts.repeat) jobOpts.repeat = opts.repeat;
|
|
46
|
+
const job = await this.queue.add(`agent:${opts.agentName}`, payload, jobOpts);
|
|
47
|
+
return { jobId: job.id };
|
|
48
|
+
}
|
|
49
|
+
async enqueueWorkflow(opts) {
|
|
50
|
+
const payload = {
|
|
51
|
+
type: "workflow",
|
|
52
|
+
workflowName: opts.workflowName,
|
|
53
|
+
initialState: opts.initialState,
|
|
54
|
+
sessionId: opts.sessionId
|
|
55
|
+
};
|
|
56
|
+
const jobOpts = {};
|
|
57
|
+
if (opts.priority !== void 0) jobOpts.priority = opts.priority;
|
|
58
|
+
if (opts.delay !== void 0) jobOpts.delay = opts.delay;
|
|
59
|
+
if (opts.attempts !== void 0) jobOpts.attempts = opts.attempts;
|
|
60
|
+
if (opts.backoff) jobOpts.backoff = opts.backoff;
|
|
61
|
+
if (opts.repeat) jobOpts.repeat = opts.repeat;
|
|
62
|
+
const job = await this.queue.add(`workflow:${opts.workflowName}`, payload, jobOpts);
|
|
63
|
+
return { jobId: job.id };
|
|
64
|
+
}
|
|
65
|
+
async enqueueTeamRun(opts) {
|
|
66
|
+
const payload = {
|
|
67
|
+
type: "team",
|
|
68
|
+
teamName: opts.teamName,
|
|
69
|
+
input: opts.input,
|
|
70
|
+
sessionId: opts.sessionId,
|
|
71
|
+
userId: opts.userId
|
|
72
|
+
};
|
|
73
|
+
const jobOpts = {};
|
|
74
|
+
if (opts.priority !== void 0) jobOpts.priority = opts.priority;
|
|
75
|
+
if (opts.delay !== void 0) jobOpts.delay = opts.delay;
|
|
76
|
+
if (opts.attempts !== void 0) jobOpts.attempts = opts.attempts;
|
|
77
|
+
if (opts.backoff) jobOpts.backoff = opts.backoff;
|
|
78
|
+
if (opts.repeat) jobOpts.repeat = opts.repeat;
|
|
79
|
+
const job = await this.queue.add(`team:${opts.teamName}`, payload, jobOpts);
|
|
80
|
+
return { jobId: job.id };
|
|
81
|
+
}
|
|
82
|
+
async getJobStatus(jobId) {
|
|
83
|
+
const job = await this.queue.getJob(jobId);
|
|
84
|
+
if (!job) {
|
|
85
|
+
throw new Error(`Job ${jobId} not found`);
|
|
86
|
+
}
|
|
87
|
+
const state = await job.getState();
|
|
88
|
+
return {
|
|
89
|
+
jobId: job.id,
|
|
90
|
+
state,
|
|
91
|
+
progress: typeof job.progress === "number" ? job.progress : void 0,
|
|
92
|
+
result: job.returnvalue,
|
|
93
|
+
error: job.failedReason,
|
|
94
|
+
createdAt: new Date(job.timestamp),
|
|
95
|
+
processedAt: job.processedOn ? new Date(job.processedOn) : void 0,
|
|
96
|
+
finishedAt: job.finishedOn ? new Date(job.finishedOn) : void 0
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
async cancelJob(jobId) {
|
|
100
|
+
const job = await this.queue.getJob(jobId);
|
|
101
|
+
if (job) {
|
|
102
|
+
await job.remove();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
onCompleted(handler) {
|
|
106
|
+
this.queueEvents.on("completed", ({ jobId, returnvalue }) => {
|
|
107
|
+
handler(jobId, returnvalue);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
onFailed(handler) {
|
|
111
|
+
this.queueEvents.on("failed", ({ jobId, failedReason }) => {
|
|
112
|
+
handler(jobId, new Error(failedReason));
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
async schedule(opts) {
|
|
116
|
+
if (!opts.agent && !opts.workflow) {
|
|
117
|
+
throw new Error("schedule() requires either agent or workflow");
|
|
118
|
+
}
|
|
119
|
+
if (opts.agent && opts.workflow) {
|
|
120
|
+
throw new Error("schedule() accepts either agent or workflow, not both");
|
|
121
|
+
}
|
|
122
|
+
const repeat = { pattern: opts.cron, ...opts.timezone ? { tz: opts.timezone } : {} };
|
|
123
|
+
if (opts.agent) {
|
|
124
|
+
return this.enqueueAgentRun({
|
|
125
|
+
agentName: opts.agent.name,
|
|
126
|
+
input: opts.agent.input,
|
|
127
|
+
sessionId: opts.agent.sessionId,
|
|
128
|
+
userId: opts.agent.userId,
|
|
129
|
+
repeat
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
if (opts.team) {
|
|
133
|
+
return this.enqueueTeamRun({
|
|
134
|
+
teamName: opts.team.name,
|
|
135
|
+
input: opts.team.input,
|
|
136
|
+
sessionId: opts.team.sessionId,
|
|
137
|
+
userId: opts.team.userId,
|
|
138
|
+
repeat
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return this.enqueueWorkflow({
|
|
142
|
+
workflowName: opts.workflow.name,
|
|
143
|
+
initialState: opts.workflow.initialState,
|
|
144
|
+
repeat
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
async unschedule(id) {
|
|
148
|
+
const jobs = await this.queue.getRepeatableJobs();
|
|
149
|
+
const match = jobs.find((j) => j.name === `agent:${id}` || j.name === `workflow:${id}` || j.name === id);
|
|
150
|
+
if (!match) {
|
|
151
|
+
throw new Error(`Schedule "${id}" not found`);
|
|
152
|
+
}
|
|
153
|
+
await this.queue.removeRepeatableByKey(match.key);
|
|
154
|
+
}
|
|
155
|
+
async listSchedules() {
|
|
156
|
+
const jobs = await this.queue.getRepeatableJobs();
|
|
157
|
+
return jobs.map((j) => ({
|
|
158
|
+
id: j.name,
|
|
159
|
+
pattern: j.pattern ?? j.cron,
|
|
160
|
+
timezone: j.tz ?? void 0,
|
|
161
|
+
next: j.next ? new Date(j.next) : /* @__PURE__ */ new Date()
|
|
162
|
+
}));
|
|
163
|
+
}
|
|
164
|
+
async close() {
|
|
165
|
+
const results = await Promise.allSettled([this.queue.close(), this.queueEvents.close()]);
|
|
166
|
+
for (const r of results) {
|
|
167
|
+
if (r.status === "rejected") console.warn("[JobProducer] Error during close:", r.reason);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// src/job-worker.ts
|
|
173
|
+
var AgentWorker = class {
|
|
174
|
+
worker;
|
|
175
|
+
constructor(config) {
|
|
176
|
+
const queueName = config.queueName ?? "agentium:jobs";
|
|
177
|
+
const concurrency = config.concurrency ?? 5;
|
|
178
|
+
const connection = typeof config.connection === "string" ? { url: config.connection } : config.connection;
|
|
179
|
+
const defaultJobOptions = {
|
|
180
|
+
attempts: config.attempts ?? 3,
|
|
181
|
+
backoff: {
|
|
182
|
+
type: "exponential",
|
|
183
|
+
delay: config.backoffDelay ?? 1e3
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
try {
|
|
187
|
+
const { Worker } = __require("bullmq");
|
|
188
|
+
this.worker = new Worker(
|
|
189
|
+
queueName,
|
|
190
|
+
async (job) => {
|
|
191
|
+
const payload = job.data;
|
|
192
|
+
if (payload.type === "agent") {
|
|
193
|
+
const agent = config.agentRegistry[payload.agentName];
|
|
194
|
+
if (!agent) {
|
|
195
|
+
throw new Error(`Agent "${payload.agentName}" not found in registry`);
|
|
196
|
+
}
|
|
197
|
+
const onChunk = (_evt) => {
|
|
198
|
+
job.updateProgress(typeof job.progress === "number" ? job.progress + 1 : 1);
|
|
199
|
+
};
|
|
200
|
+
agent.eventBus.on("run.stream.chunk", onChunk);
|
|
201
|
+
try {
|
|
202
|
+
const result = await agent.run(payload.input, {
|
|
203
|
+
sessionId: payload.sessionId,
|
|
204
|
+
userId: payload.userId
|
|
205
|
+
});
|
|
206
|
+
return result;
|
|
207
|
+
} finally {
|
|
208
|
+
agent.eventBus.off("run.stream.chunk", onChunk);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (payload.type === "workflow") {
|
|
212
|
+
const workflow = config.workflowRegistry?.[payload.workflowName];
|
|
213
|
+
if (!workflow) {
|
|
214
|
+
throw new Error(`Workflow "${payload.workflowName}" not found in registry`);
|
|
215
|
+
}
|
|
216
|
+
const result = await workflow.run({
|
|
217
|
+
sessionId: payload.sessionId
|
|
218
|
+
});
|
|
219
|
+
return result;
|
|
220
|
+
}
|
|
221
|
+
if (payload.type === "team") {
|
|
222
|
+
const team = config.teamRegistry?.[payload.teamName];
|
|
223
|
+
if (!team) {
|
|
224
|
+
throw new Error(`Team "${payload.teamName}" not found in registry`);
|
|
225
|
+
}
|
|
226
|
+
const result = await team.run(payload.input, {
|
|
227
|
+
sessionId: payload.sessionId,
|
|
228
|
+
userId: payload.userId
|
|
229
|
+
});
|
|
230
|
+
return result;
|
|
231
|
+
}
|
|
232
|
+
throw new Error(`Unknown job type: ${payload.type}`);
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
connection,
|
|
236
|
+
concurrency,
|
|
237
|
+
defaultJobOptions
|
|
238
|
+
}
|
|
239
|
+
);
|
|
240
|
+
} catch (err) {
|
|
241
|
+
if (err?.code === "MODULE_NOT_FOUND" || err?.message?.includes("Cannot find module")) {
|
|
242
|
+
throw new Error("bullmq and ioredis are required for AgentWorker. Install them: npm install bullmq ioredis");
|
|
243
|
+
}
|
|
244
|
+
throw err;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
start() {
|
|
248
|
+
}
|
|
249
|
+
async stop(timeoutMs = 3e4) {
|
|
250
|
+
await Promise.race([
|
|
251
|
+
this.worker.close(),
|
|
252
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("Worker drain timeout")), timeoutMs))
|
|
253
|
+
]).catch((err) => {
|
|
254
|
+
console.warn("[JobWorker] Error during stop:", err?.message ?? err);
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
// src/progress.ts
|
|
260
|
+
function bridgeEventBusToJob(eventBus, job, runId) {
|
|
261
|
+
let progressCount = 0;
|
|
262
|
+
const onChunk = (evt) => {
|
|
263
|
+
if (evt.runId !== runId) return;
|
|
264
|
+
progressCount++;
|
|
265
|
+
job.updateProgress(progressCount).catch(() => {
|
|
266
|
+
});
|
|
267
|
+
};
|
|
268
|
+
const onToolCall = (evt) => {
|
|
269
|
+
if (evt.runId !== runId) return;
|
|
270
|
+
job.log(`Tool call: ${evt.toolName}`).catch(() => {
|
|
271
|
+
});
|
|
272
|
+
};
|
|
273
|
+
eventBus.on("run.stream.chunk", onChunk);
|
|
274
|
+
eventBus.on("tool.call", onToolCall);
|
|
275
|
+
return () => {
|
|
276
|
+
eventBus.off("run.stream.chunk", onChunk);
|
|
277
|
+
eventBus.off("tool.call", onToolCall);
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
export {
|
|
281
|
+
AgentQueue,
|
|
282
|
+
AgentWorker,
|
|
283
|
+
bridgeEventBusToJob
|
|
284
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentium/queue",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Background job processing for Agentium agents using BullMQ",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/agentiumOS/agentium.git",
|
|
9
|
+
"directory": "packages/queue"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"ai",
|
|
13
|
+
"agents",
|
|
14
|
+
"queue",
|
|
15
|
+
"bullmq",
|
|
16
|
+
"redis",
|
|
17
|
+
"background-jobs"
|
|
18
|
+
],
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "./dist/index.cjs",
|
|
21
|
+
"module": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"import": "./dist/index.js",
|
|
27
|
+
"require": "./dist/index.cjs",
|
|
28
|
+
"default": "./dist/index.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsup src/index.ts --format esm,cjs --dts --shims --clean",
|
|
36
|
+
"dev": "tsup src/index.ts --format esm,cjs --dts --shims --watch",
|
|
37
|
+
"prepublishOnly": "npm run build"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^25.3.1",
|
|
41
|
+
"tsup": "^8.0.0",
|
|
42
|
+
"typescript": "^5.6.0"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"@agentium/core": "^1.0.0",
|
|
46
|
+
"bullmq": "^5.0.0",
|
|
47
|
+
"ioredis": "^5.0.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"bullmq": {
|
|
51
|
+
"optional": true
|
|
52
|
+
},
|
|
53
|
+
"ioredis": {
|
|
54
|
+
"optional": true
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|