@tunnlo/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/dist/bus.d.ts +19 -0
- package/dist/bus.d.ts.map +1 -0
- package/dist/bus.js +45 -0
- package/dist/bus.js.map +1 -0
- package/dist/bus.test.d.ts +2 -0
- package/dist/bus.test.d.ts.map +1 -0
- package/dist/bus.test.js +48 -0
- package/dist/bus.test.js.map +1 -0
- package/dist/event.d.ts +16 -0
- package/dist/event.d.ts.map +1 -0
- package/dist/event.js +83 -0
- package/dist/event.js.map +1 -0
- package/dist/event.test.d.ts +2 -0
- package/dist/event.test.d.ts.map +1 -0
- package/dist/event.test.js +40 -0
- package/dist/event.test.js.map +1 -0
- package/dist/fast-bus.d.ts +25 -0
- package/dist/fast-bus.d.ts.map +1 -0
- package/dist/fast-bus.js +114 -0
- package/dist/fast-bus.js.map +1 -0
- package/dist/fast-bus.test.d.ts +2 -0
- package/dist/fast-bus.test.d.ts.map +1 -0
- package/dist/fast-bus.test.js +63 -0
- package/dist/fast-bus.test.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/kafka-bus.d.ts +27 -0
- package/dist/kafka-bus.d.ts.map +1 -0
- package/dist/kafka-bus.js +142 -0
- package/dist/kafka-bus.js.map +1 -0
- package/dist/logger.d.ts +30 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +125 -0
- package/dist/logger.js.map +1 -0
- package/dist/pipeline.d.ts +54 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +209 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/pipeline.test.d.ts +2 -0
- package/dist/pipeline.test.d.ts.map +1 -0
- package/dist/pipeline.test.js +114 -0
- package/dist/pipeline.test.js.map +1 -0
- package/dist/redis-bus.d.ts +25 -0
- package/dist/redis-bus.d.ts.map +1 -0
- package/dist/redis-bus.js +140 -0
- package/dist/redis-bus.js.map +1 -0
- package/dist/state-store.d.ts +12 -0
- package/dist/state-store.d.ts.map +1 -0
- package/dist/state-store.js +36 -0
- package/dist/state-store.js.map +1 -0
- package/dist/types.d.ts +118 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +27 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { Pipeline } from './pipeline.js';
|
|
3
|
+
import { InMemoryBus } from './bus.js';
|
|
4
|
+
import { createEvent } from './event.js';
|
|
5
|
+
function createMockAdapter(events) {
|
|
6
|
+
let connected = false;
|
|
7
|
+
let config;
|
|
8
|
+
return {
|
|
9
|
+
async connect(c) { config = c; connected = true; },
|
|
10
|
+
async *read() {
|
|
11
|
+
for (const e of events)
|
|
12
|
+
yield e;
|
|
13
|
+
},
|
|
14
|
+
transform(raw) {
|
|
15
|
+
return createEvent('mock', 'DATA', { data: raw.data.toString() });
|
|
16
|
+
},
|
|
17
|
+
async disconnect() { connected = false; },
|
|
18
|
+
health() { return { status: connected ? 'connected' : 'disconnected' }; },
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function createMockBridge(response = {}) {
|
|
22
|
+
return {
|
|
23
|
+
async send() {
|
|
24
|
+
return { content: 'ok', tokens_used: 100, ...response };
|
|
25
|
+
},
|
|
26
|
+
async close() { },
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function createPassthroughFilter() {
|
|
30
|
+
return {
|
|
31
|
+
name: 'passthrough',
|
|
32
|
+
process(event) { return event; },
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
describe('Pipeline', () => {
|
|
36
|
+
it('processes events from adapter through filters to bridge', async () => {
|
|
37
|
+
const bus = new InMemoryBus();
|
|
38
|
+
const bridgeSend = vi.fn().mockResolvedValue({ content: 'analyzed', tokens_used: 50 });
|
|
39
|
+
const bridge = { send: bridgeSend, close: vi.fn() };
|
|
40
|
+
const adapter = createMockAdapter([
|
|
41
|
+
{ data: 'event1', received_at: new Date().toISOString() },
|
|
42
|
+
{ data: 'event2', received_at: new Date().toISOString() },
|
|
43
|
+
]);
|
|
44
|
+
const pipeline = new Pipeline({
|
|
45
|
+
bus,
|
|
46
|
+
adapters: new Map([['mock', adapter]]),
|
|
47
|
+
filters: [createPassthroughFilter()],
|
|
48
|
+
bridge,
|
|
49
|
+
agentConfig: {
|
|
50
|
+
runtime: 'direct-llm',
|
|
51
|
+
model: 'test',
|
|
52
|
+
system_prompt: 'test prompt',
|
|
53
|
+
},
|
|
54
|
+
actionHandlers: [],
|
|
55
|
+
});
|
|
56
|
+
await pipeline.start();
|
|
57
|
+
// Give the async pipeline time to process
|
|
58
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
59
|
+
expect(bridgeSend).toHaveBeenCalledTimes(2);
|
|
60
|
+
await pipeline.stop();
|
|
61
|
+
});
|
|
62
|
+
it('respects token budget', async () => {
|
|
63
|
+
const bus = new InMemoryBus();
|
|
64
|
+
const bridgeSend = vi.fn().mockResolvedValue({ content: 'ok', tokens_used: 600 });
|
|
65
|
+
const bridge = { send: bridgeSend, close: vi.fn() };
|
|
66
|
+
const events = Array.from({ length: 5 }, (_, i) => ({
|
|
67
|
+
data: `event${i}`,
|
|
68
|
+
received_at: new Date().toISOString(),
|
|
69
|
+
}));
|
|
70
|
+
const pipeline = new Pipeline({
|
|
71
|
+
bus,
|
|
72
|
+
adapters: new Map([['mock', createMockAdapter(events)]]),
|
|
73
|
+
filters: [createPassthroughFilter()],
|
|
74
|
+
bridge,
|
|
75
|
+
agentConfig: {
|
|
76
|
+
runtime: 'direct-llm',
|
|
77
|
+
model: 'test',
|
|
78
|
+
system_prompt: 'test',
|
|
79
|
+
token_budget: { max_per_hour: 1500, max_per_event: 4000 },
|
|
80
|
+
},
|
|
81
|
+
actionHandlers: [],
|
|
82
|
+
});
|
|
83
|
+
await pipeline.start();
|
|
84
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
85
|
+
// With 600 tokens per call and 1500 budget, should stop after 2 calls
|
|
86
|
+
expect(bridgeSend.mock.calls.length).toBeLessThanOrEqual(3);
|
|
87
|
+
await pipeline.stop();
|
|
88
|
+
});
|
|
89
|
+
it('filters drop events correctly', async () => {
|
|
90
|
+
const bus = new InMemoryBus();
|
|
91
|
+
const bridgeSend = vi.fn().mockResolvedValue({ content: 'ok', tokens_used: 10 });
|
|
92
|
+
const bridge = { send: bridgeSend, close: vi.fn() };
|
|
93
|
+
const dropFilter = {
|
|
94
|
+
name: 'drop-all',
|
|
95
|
+
process() { return null; },
|
|
96
|
+
};
|
|
97
|
+
const adapter = createMockAdapter([
|
|
98
|
+
{ data: 'event1', received_at: new Date().toISOString() },
|
|
99
|
+
]);
|
|
100
|
+
const pipeline = new Pipeline({
|
|
101
|
+
bus,
|
|
102
|
+
adapters: new Map([['mock', adapter]]),
|
|
103
|
+
filters: [dropFilter],
|
|
104
|
+
bridge,
|
|
105
|
+
agentConfig: { runtime: 'direct-llm', model: 'test', system_prompt: 'test' },
|
|
106
|
+
actionHandlers: [],
|
|
107
|
+
});
|
|
108
|
+
await pipeline.start();
|
|
109
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
110
|
+
expect(bridgeSend).not.toHaveBeenCalled();
|
|
111
|
+
await pipeline.stop();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
//# sourceMappingURL=pipeline.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.test.js","sourceRoot":"","sources":["../src/pipeline.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { TunnloEvent } from './types.js';
|
|
2
|
+
import type { EventCallback, MessageBus } from './bus.js';
|
|
3
|
+
export interface RedisBusConfig {
|
|
4
|
+
url?: string;
|
|
5
|
+
maxLen?: number;
|
|
6
|
+
consumerGroup?: string;
|
|
7
|
+
consumerId?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class RedisStreamsBus implements MessageBus {
|
|
10
|
+
private subscribers;
|
|
11
|
+
private pollingTopics;
|
|
12
|
+
private closed;
|
|
13
|
+
private connected;
|
|
14
|
+
private redis;
|
|
15
|
+
private config;
|
|
16
|
+
constructor(config?: RedisBusConfig);
|
|
17
|
+
connect(): Promise<void>;
|
|
18
|
+
private ensureConnected;
|
|
19
|
+
publish(topic: string, event: TunnloEvent): Promise<void>;
|
|
20
|
+
subscribe(topic: string, callback: EventCallback): void;
|
|
21
|
+
unsubscribe(topic: string, callback: EventCallback): void;
|
|
22
|
+
close(): Promise<void>;
|
|
23
|
+
private pollStream;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=redis-bus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-bus.d.ts","sourceRoot":"","sources":["../src/redis-bus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAI1D,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,eAAgB,YAAW,UAAU;IAChD,OAAO,CAAC,WAAW,CAAyC;IAC5D,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,MAAM,CAAiB;gBAEnB,MAAM,GAAE,cAAmB;IASjC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B,OAAO,CAAC,eAAe;IAMjB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAyB/D,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAevD,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAInD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAUd,UAAU;CAqEzB"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { validateEvent } from './event.js';
|
|
2
|
+
import { getLogger } from './logger.js';
|
|
3
|
+
export class RedisStreamsBus {
|
|
4
|
+
subscribers = new Map();
|
|
5
|
+
pollingTopics = new Set();
|
|
6
|
+
closed = false;
|
|
7
|
+
connected = false;
|
|
8
|
+
redis;
|
|
9
|
+
config;
|
|
10
|
+
constructor(config = {}) {
|
|
11
|
+
this.config = {
|
|
12
|
+
url: config.url ?? 'redis://localhost:6379',
|
|
13
|
+
maxLen: config.maxLen ?? 10_000,
|
|
14
|
+
consumerGroup: config.consumerGroup ?? 'tunnlo',
|
|
15
|
+
consumerId: config.consumerId ?? `tunnlo-${Date.now()}`,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
async connect() {
|
|
19
|
+
// Dynamic import to avoid requiring redis as a hard dependency
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
21
|
+
const redis = await Function('return import("redis")')();
|
|
22
|
+
this.redis = redis.createClient({ url: this.config.url });
|
|
23
|
+
await this.redis.connect();
|
|
24
|
+
this.connected = true;
|
|
25
|
+
}
|
|
26
|
+
ensureConnected() {
|
|
27
|
+
if (!this.connected || !this.redis) {
|
|
28
|
+
throw new Error('[tunnlo:redis-bus] Not connected. Call connect() before using the bus.');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async publish(topic, event) {
|
|
32
|
+
if (this.closed)
|
|
33
|
+
return;
|
|
34
|
+
this.ensureConnected();
|
|
35
|
+
const streamKey = `tunnlo:${topic}`;
|
|
36
|
+
await this.redis.xAdd(streamKey, '*', { data: JSON.stringify(event) }, { TRIM: { strategy: 'MAXLEN', strategyModifier: '~', threshold: this.config.maxLen } });
|
|
37
|
+
// Also deliver to local subscribers for hybrid usage
|
|
38
|
+
const subs = this.subscribers.get(topic);
|
|
39
|
+
if (subs) {
|
|
40
|
+
for (const cb of subs) {
|
|
41
|
+
try {
|
|
42
|
+
await cb(event);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
getLogger().error(`[tunnlo:redis-bus] subscriber error on topic "${topic}":`, err);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
subscribe(topic, callback) {
|
|
51
|
+
if (!this.subscribers.has(topic)) {
|
|
52
|
+
this.subscribers.set(topic, new Set());
|
|
53
|
+
}
|
|
54
|
+
this.subscribers.get(topic).add(callback);
|
|
55
|
+
// Start polling this topic from Redis if not already doing so
|
|
56
|
+
if (!this.pollingTopics.has(topic) && this.connected) {
|
|
57
|
+
this.pollingTopics.add(topic);
|
|
58
|
+
this.pollStream(topic).catch((err) => {
|
|
59
|
+
getLogger().error(`[tunnlo:redis-bus] stream poll error for "${topic}":`, err);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
unsubscribe(topic, callback) {
|
|
64
|
+
this.subscribers.get(topic)?.delete(callback);
|
|
65
|
+
}
|
|
66
|
+
async close() {
|
|
67
|
+
this.closed = true;
|
|
68
|
+
this.pollingTopics.clear();
|
|
69
|
+
this.subscribers.clear();
|
|
70
|
+
if (this.redis) {
|
|
71
|
+
await this.redis.quit();
|
|
72
|
+
this.redis = null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async pollStream(topic) {
|
|
76
|
+
const streamKey = `tunnlo:${topic}`;
|
|
77
|
+
const group = this.config.consumerGroup;
|
|
78
|
+
const consumer = this.config.consumerId;
|
|
79
|
+
const maxRetries = 10;
|
|
80
|
+
let retries = 0;
|
|
81
|
+
// Create consumer group if it doesn't exist
|
|
82
|
+
try {
|
|
83
|
+
await this.redis.xGroupCreate(streamKey, group, '0', { MKSTREAM: true });
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// Group may already exist
|
|
87
|
+
}
|
|
88
|
+
while (!this.closed && this.pollingTopics.has(topic)) {
|
|
89
|
+
try {
|
|
90
|
+
const results = await this.redis.xReadGroup(group, consumer, [{ key: streamKey, id: '>' }], { COUNT: 100, BLOCK: 2000 });
|
|
91
|
+
retries = 0; // Reset on success
|
|
92
|
+
if (results) {
|
|
93
|
+
for (const stream of results) {
|
|
94
|
+
for (const message of stream.messages) {
|
|
95
|
+
try {
|
|
96
|
+
const parsed = JSON.parse(message.message.data);
|
|
97
|
+
if (!validateEvent(parsed)) {
|
|
98
|
+
getLogger().error(`[tunnlo:redis-bus] invalid event structure, skipping`);
|
|
99
|
+
await this.redis.xAck(streamKey, group, message.id);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const event = parsed;
|
|
103
|
+
// Events from Redis go directly to callbacks (not re-published to avoid loops)
|
|
104
|
+
const subs = this.subscribers.get(topic);
|
|
105
|
+
if (subs) {
|
|
106
|
+
for (const cb of subs) {
|
|
107
|
+
try {
|
|
108
|
+
await cb(event);
|
|
109
|
+
}
|
|
110
|
+
catch (cbErr) {
|
|
111
|
+
getLogger().error(`[tunnlo:redis-bus] subscriber callback error:`, cbErr);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
await this.redis.xAck(streamKey, group, message.id);
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
getLogger().error(`[tunnlo:redis-bus] message parse error:`, err);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
if (!this.closed) {
|
|
126
|
+
retries++;
|
|
127
|
+
const backoffMs = Math.min(1000 * Math.pow(2, retries - 1), 30_000);
|
|
128
|
+
getLogger().error(`[tunnlo:redis-bus] read error (retry ${retries}/${maxRetries}, backoff ${backoffMs}ms):`, err);
|
|
129
|
+
if (retries >= maxRetries) {
|
|
130
|
+
getLogger().error(`[tunnlo:redis-bus] max retries reached for topic "${topic}", stopping poll`);
|
|
131
|
+
this.pollingTopics.delete(topic);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
await new Promise((r) => setTimeout(r, backoffMs));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=redis-bus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-bus.js","sourceRoot":"","sources":["../src/redis-bus.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CursorState, StateStore } from './types.js';
|
|
2
|
+
export declare class JsonFileStateStore implements StateStore {
|
|
3
|
+
private filePath;
|
|
4
|
+
private state;
|
|
5
|
+
private loaded;
|
|
6
|
+
constructor(filePath: string);
|
|
7
|
+
private load;
|
|
8
|
+
private save;
|
|
9
|
+
get(adapter_id: string): Promise<CursorState | null>;
|
|
10
|
+
commit(adapter_id: string, state: CursorState): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=state-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-store.d.ts","sourceRoot":"","sources":["../src/state-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE1D,qBAAa,kBAAmB,YAAW,UAAU;IAIvC,OAAO,CAAC,QAAQ;IAH5B,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,MAAM,CAAS;gBAEH,QAAQ,EAAE,MAAM;YAEtB,IAAI;YAWJ,IAAI;IAKZ,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAKpD,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAKpE"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
export class JsonFileStateStore {
|
|
4
|
+
filePath;
|
|
5
|
+
state = {};
|
|
6
|
+
loaded = false;
|
|
7
|
+
constructor(filePath) {
|
|
8
|
+
this.filePath = filePath;
|
|
9
|
+
}
|
|
10
|
+
async load() {
|
|
11
|
+
if (this.loaded)
|
|
12
|
+
return;
|
|
13
|
+
try {
|
|
14
|
+
const data = await readFile(this.filePath, 'utf-8');
|
|
15
|
+
this.state = JSON.parse(data);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
this.state = {};
|
|
19
|
+
}
|
|
20
|
+
this.loaded = true;
|
|
21
|
+
}
|
|
22
|
+
async save() {
|
|
23
|
+
await mkdir(dirname(this.filePath), { recursive: true });
|
|
24
|
+
await writeFile(this.filePath, JSON.stringify(this.state, null, 2));
|
|
25
|
+
}
|
|
26
|
+
async get(adapter_id) {
|
|
27
|
+
await this.load();
|
|
28
|
+
return this.state[adapter_id] ?? null;
|
|
29
|
+
}
|
|
30
|
+
async commit(adapter_id, state) {
|
|
31
|
+
await this.load();
|
|
32
|
+
this.state[adapter_id] = state;
|
|
33
|
+
await this.save();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=state-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-store.js","sourceRoot":"","sources":["../src/state-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,MAAM,OAAO,kBAAkB;IAIT;IAHZ,KAAK,GAAgC,EAAE,CAAC;IACxC,MAAM,GAAG,KAAK,CAAC;IAEvB,YAAoB,QAAgB;QAAhB,aAAQ,GAAR,QAAQ,CAAQ;IAAG,CAAC;IAEhC,KAAK,CAAC,IAAI;QAChB,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QACxB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACpD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAClB,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IACrB,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,MAAM,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,UAAkB;QAC1B,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,UAAkB,EAAE,KAAkB;QACjD,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC;QAC/B,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;CACF"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
export type EventType = 'DATA' | 'ALERT' | 'METRIC' | 'HEARTBEAT' | 'ERROR';
|
|
2
|
+
export interface TunnloEvent {
|
|
3
|
+
event_id: string;
|
|
4
|
+
source_id: string;
|
|
5
|
+
timestamp: string;
|
|
6
|
+
event_type: EventType;
|
|
7
|
+
priority?: number;
|
|
8
|
+
payload: Record<string, any>;
|
|
9
|
+
metadata?: Record<string, any>;
|
|
10
|
+
raw?: string | Buffer;
|
|
11
|
+
}
|
|
12
|
+
export type AdapterStatus = 'connected' | 'disconnected' | 'degraded' | 'error';
|
|
13
|
+
export interface AdapterHealth {
|
|
14
|
+
status: AdapterStatus;
|
|
15
|
+
message?: string;
|
|
16
|
+
last_event_at?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface AdapterConfig {
|
|
19
|
+
id: string;
|
|
20
|
+
adapter: string;
|
|
21
|
+
config: Record<string, any>;
|
|
22
|
+
}
|
|
23
|
+
export interface RawEvent {
|
|
24
|
+
data: string | Buffer;
|
|
25
|
+
received_at: string;
|
|
26
|
+
}
|
|
27
|
+
export interface Adapter {
|
|
28
|
+
connect(config: AdapterConfig): Promise<void>;
|
|
29
|
+
read(): AsyncIterable<RawEvent>;
|
|
30
|
+
transform(raw: RawEvent): TunnloEvent;
|
|
31
|
+
disconnect(): Promise<void>;
|
|
32
|
+
health(): AdapterHealth;
|
|
33
|
+
}
|
|
34
|
+
export interface CursorState {
|
|
35
|
+
offset: string | number;
|
|
36
|
+
updated_at: string;
|
|
37
|
+
metadata?: Record<string, any>;
|
|
38
|
+
}
|
|
39
|
+
export interface StateStore {
|
|
40
|
+
get(adapter_id: string): Promise<CursorState | null>;
|
|
41
|
+
commit(adapter_id: string, state: CursorState): Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
export interface Filter {
|
|
44
|
+
name: string;
|
|
45
|
+
process(event: TunnloEvent): TunnloEvent | null;
|
|
46
|
+
flush?(): TunnloEvent | null;
|
|
47
|
+
}
|
|
48
|
+
export interface AgentBridge {
|
|
49
|
+
send(event: TunnloEvent, systemPrompt: string): Promise<AgentResponse>;
|
|
50
|
+
close(): Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
export interface AgentResponse {
|
|
53
|
+
content: string;
|
|
54
|
+
tokens_used: number;
|
|
55
|
+
actions?: ActionRequest[];
|
|
56
|
+
}
|
|
57
|
+
export interface ActionRequest {
|
|
58
|
+
type: string;
|
|
59
|
+
config: Record<string, any>;
|
|
60
|
+
payload: Record<string, any>;
|
|
61
|
+
}
|
|
62
|
+
export interface ActionHandler {
|
|
63
|
+
type: string;
|
|
64
|
+
execute(request: ActionRequest): Promise<ActionResult>;
|
|
65
|
+
}
|
|
66
|
+
export interface ActionResult {
|
|
67
|
+
success: boolean;
|
|
68
|
+
response?: any;
|
|
69
|
+
error?: string;
|
|
70
|
+
}
|
|
71
|
+
export interface TokenBudget {
|
|
72
|
+
max_per_hour: number;
|
|
73
|
+
max_per_event: number;
|
|
74
|
+
}
|
|
75
|
+
export interface AgentConfig {
|
|
76
|
+
runtime: string;
|
|
77
|
+
model: string;
|
|
78
|
+
system_prompt: string;
|
|
79
|
+
token_budget?: TokenBudget;
|
|
80
|
+
actions?: ActionConfig[];
|
|
81
|
+
}
|
|
82
|
+
export interface ActionConfig {
|
|
83
|
+
type: string;
|
|
84
|
+
[key: string]: any;
|
|
85
|
+
}
|
|
86
|
+
export interface BehaviorConfig {
|
|
87
|
+
on_llm_unreachable: 'drop_and_alert' | 'buffer_limited' | 'passthrough';
|
|
88
|
+
log_level?: 'debug' | 'info' | 'warn' | 'error' | 'quiet';
|
|
89
|
+
}
|
|
90
|
+
export interface BusConfig {
|
|
91
|
+
type?: string;
|
|
92
|
+
url?: string;
|
|
93
|
+
max_len?: number;
|
|
94
|
+
[key: string]: any;
|
|
95
|
+
}
|
|
96
|
+
export interface DashboardConfig {
|
|
97
|
+
enabled?: boolean;
|
|
98
|
+
port?: number;
|
|
99
|
+
host?: string;
|
|
100
|
+
}
|
|
101
|
+
export interface OutputConfig {
|
|
102
|
+
log_file?: string;
|
|
103
|
+
log_format?: 'text' | 'json';
|
|
104
|
+
}
|
|
105
|
+
export interface PipelineConfig {
|
|
106
|
+
sources: AdapterConfig[];
|
|
107
|
+
filters: FilterConfig[];
|
|
108
|
+
agent: AgentConfig;
|
|
109
|
+
behavior?: BehaviorConfig;
|
|
110
|
+
bus?: BusConfig;
|
|
111
|
+
dashboard?: DashboardConfig;
|
|
112
|
+
output?: OutputConfig;
|
|
113
|
+
}
|
|
114
|
+
export interface FilterConfig {
|
|
115
|
+
type: string;
|
|
116
|
+
[key: string]: any;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tunnlo/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Core types, interfaces, and runtime for Tunnlo pipelines",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc -b"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"uuid": "^11.0.0",
|
|
20
|
+
"yaml": "^2.7.0",
|
|
21
|
+
"ajv": "^8.17.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/uuid": "^10.0.0"
|
|
25
|
+
},
|
|
26
|
+
"files": ["dist"]
|
|
27
|
+
}
|