@eggjs/agent-runtime 0.0.0 → 3.73.0-beta.1

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.
@@ -0,0 +1,104 @@
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.FileAgentStore = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const promises_1 = __importDefault(require("node:fs/promises"));
9
+ const node_crypto_1 = __importDefault(require("node:crypto"));
10
+ class FileAgentStore {
11
+ constructor(options) {
12
+ this.dataDir = options.dataDir;
13
+ this.threadsDir = node_path_1.default.join(this.dataDir, 'threads');
14
+ this.runsDir = node_path_1.default.join(this.dataDir, 'runs');
15
+ }
16
+ safePath(baseDir, id) {
17
+ if (!id) {
18
+ throw new Error('Invalid id: id must not be empty');
19
+ }
20
+ const filePath = node_path_1.default.join(baseDir, `${id}.json`);
21
+ if (!filePath.startsWith(baseDir + node_path_1.default.sep)) {
22
+ throw new Error(`Invalid id: ${id}`);
23
+ }
24
+ return filePath;
25
+ }
26
+ async init() {
27
+ await promises_1.default.mkdir(this.threadsDir, { recursive: true });
28
+ await promises_1.default.mkdir(this.runsDir, { recursive: true });
29
+ }
30
+ async createThread(metadata) {
31
+ const threadId = `thread_${node_crypto_1.default.randomUUID()}`;
32
+ const record = {
33
+ id: threadId,
34
+ object: 'thread',
35
+ messages: [],
36
+ metadata: metadata !== null && metadata !== void 0 ? metadata : {},
37
+ created_at: Math.floor(Date.now() / 1000),
38
+ };
39
+ await this.writeFile(this.safePath(this.threadsDir, threadId), record);
40
+ return record;
41
+ }
42
+ async getThread(threadId) {
43
+ const filePath = this.safePath(this.threadsDir, threadId);
44
+ const data = await this.readFile(filePath);
45
+ if (!data) {
46
+ throw new Error(`Thread ${threadId} not found`);
47
+ }
48
+ return data;
49
+ }
50
+ // Note: read-modify-write without locking. Concurrent appends to the same thread may lose messages.
51
+ // This is acceptable for a default file-based store; production stores should implement proper locking.
52
+ async appendMessages(threadId, messages) {
53
+ const thread = await this.getThread(threadId);
54
+ thread.messages.push(...messages);
55
+ await this.writeFile(this.safePath(this.threadsDir, threadId), thread);
56
+ }
57
+ async createRun(input, threadId, config, metadata) {
58
+ const runId = `run_${node_crypto_1.default.randomUUID()}`;
59
+ const record = {
60
+ id: runId,
61
+ object: 'thread.run',
62
+ thread_id: threadId,
63
+ status: 'queued',
64
+ input,
65
+ config,
66
+ metadata,
67
+ created_at: Math.floor(Date.now() / 1000),
68
+ };
69
+ await this.writeFile(this.safePath(this.runsDir, runId), record);
70
+ return record;
71
+ }
72
+ async getRun(runId) {
73
+ const filePath = this.safePath(this.runsDir, runId);
74
+ const data = await this.readFile(filePath);
75
+ if (!data) {
76
+ throw new Error(`Run ${runId} not found`);
77
+ }
78
+ return data;
79
+ }
80
+ async updateRun(runId, updates) {
81
+ const run = await this.getRun(runId);
82
+ Object.assign(run, updates);
83
+ await this.writeFile(this.safePath(this.runsDir, runId), run);
84
+ }
85
+ async writeFile(filePath, data) {
86
+ const tmpPath = `${filePath}.${node_crypto_1.default.randomUUID()}.tmp`;
87
+ await promises_1.default.writeFile(tmpPath, JSON.stringify(data), 'utf-8');
88
+ await promises_1.default.rename(tmpPath, filePath);
89
+ }
90
+ async readFile(filePath) {
91
+ try {
92
+ const content = await promises_1.default.readFile(filePath, 'utf-8');
93
+ return JSON.parse(content);
94
+ }
95
+ catch (err) {
96
+ if (err.code === 'ENOENT') {
97
+ return null;
98
+ }
99
+ throw err;
100
+ }
101
+ }
102
+ }
103
+ exports.FileAgentStore = FileAgentStore;
104
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRmlsZUFnZW50U3RvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvRmlsZUFnZW50U3RvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsMERBQTZCO0FBQzdCLGdFQUFrQztBQUNsQyw4REFBaUM7QUFRakMsTUFBYSxjQUFjO0lBS3pCLFlBQVksT0FBOEI7UUFDeEMsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDO1FBQy9CLElBQUksQ0FBQyxVQUFVLEdBQUcsbUJBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUMsQ0FBQztRQUNyRCxJQUFJLENBQUMsT0FBTyxHQUFHLG1CQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDakQsQ0FBQztJQUVPLFFBQVEsQ0FBQyxPQUFlLEVBQUUsRUFBVTtRQUMxQyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDUixNQUFNLElBQUksS0FBSyxDQUFDLGtDQUFrQyxDQUFDLENBQUM7UUFDdEQsQ0FBQztRQUNELE1BQU0sUUFBUSxHQUFHLG1CQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxHQUFHLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDbEQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsT0FBTyxHQUFHLG1CQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUM3QyxNQUFNLElBQUksS0FBSyxDQUFDLGVBQWUsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUN2QyxDQUFDO1FBQ0QsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztJQUVELEtBQUssQ0FBQyxJQUFJO1FBQ1IsTUFBTSxrQkFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFDckQsTUFBTSxrQkFB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
@@ -0,0 +1,16 @@
1
+ import type { ServerResponse } from 'node:http';
2
+ import type { SSEWriter } from './SSEWriter';
3
+ export declare class HttpSSEWriter implements SSEWriter {
4
+ private res;
5
+ private _closed;
6
+ private closeCallbacks;
7
+ private headersSent;
8
+ private readonly onResClose;
9
+ constructor(res: ServerResponse);
10
+ /** Lazily write headers on first event — avoids sending corrupt headers if constructor throws. */
11
+ private ensureHeaders;
12
+ writeEvent(event: string, data: unknown): void;
13
+ get closed(): boolean;
14
+ end(): void;
15
+ onClose(callback: () => void): void;
16
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpSSEWriter = void 0;
4
+ class HttpSSEWriter {
5
+ constructor(res) {
6
+ this._closed = false;
7
+ this.closeCallbacks = [];
8
+ this.headersSent = false;
9
+ this.res = res;
10
+ this.onResClose = () => {
11
+ this._closed = true;
12
+ for (const cb of this.closeCallbacks)
13
+ cb();
14
+ this.closeCallbacks.length = 0;
15
+ };
16
+ res.on('close', this.onResClose);
17
+ }
18
+ /** Lazily write headers on first event — avoids sending corrupt headers if constructor throws. */
19
+ ensureHeaders() {
20
+ if (this.headersSent)
21
+ return;
22
+ this.headersSent = true;
23
+ this.res.writeHead(200, {
24
+ 'content-type': 'text/event-stream',
25
+ 'cache-control': 'no-cache',
26
+ connection: 'keep-alive',
27
+ });
28
+ }
29
+ writeEvent(event, data) {
30
+ if (this._closed)
31
+ return;
32
+ this.ensureHeaders();
33
+ this.res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
34
+ }
35
+ get closed() {
36
+ return this._closed;
37
+ }
38
+ end() {
39
+ if (!this._closed) {
40
+ this._closed = true;
41
+ this.res.off('close', this.onResClose);
42
+ this.closeCallbacks.length = 0;
43
+ this.res.end();
44
+ }
45
+ }
46
+ onClose(callback) {
47
+ this.closeCallbacks.push(callback);
48
+ }
49
+ }
50
+ exports.HttpSSEWriter = HttpSSEWriter;
51
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSHR0cFNTRVdyaXRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9IdHRwU1NFV3JpdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUlBLE1BQWEsYUFBYTtJQU94QixZQUFZLEdBQW1CO1FBTHZCLFlBQU8sR0FBRyxLQUFLLENBQUM7UUFDaEIsbUJBQWMsR0FBc0IsRUFBRSxDQUFDO1FBQ3ZDLGdCQUFXLEdBQUcsS0FBSyxDQUFDO1FBSTFCLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDO1FBQ2YsSUFBSSxDQUFDLFVBQVUsR0FBRyxHQUFHLEVBQUU7WUFDckIsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7WUFDcEIsS0FBSyxNQUFNLEVBQUUsSUFBSSxJQUFJLENBQUMsY0FBYztnQkFBRSxFQUFFLEVBQUUsQ0FBQztZQUMzQyxJQUFJLENBQUMsY0FBYyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7UUFDakMsQ0FBQyxDQUFDO1FBQ0YsR0FBRyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ25DLENBQUM7SUFFRCxrR0FBa0c7SUFDMUYsYUFBYTtRQUNuQixJQUFJLElBQUksQ0FBQyxXQUFXO1lBQUUsT0FBTztRQUM3QixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztRQUN4QixJQUFJLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUU7WUFDdEIsY0FBYyxFQUFFLG1CQUFtQjtZQUNuQyxlQUFlLEVBQUUsVUFBVTtZQUMzQixVQUFVLEVBQUUsWUFBWTtTQUN6QixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsVUFBVSxDQUFDLEtBQWEsRUFBRSxJQUFhO1FBQ3JDLElBQUksSUFBSSxDQUFDLE9BQU87WUFBRSxPQUFPO1FBQ3pCLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUNyQixJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxVQUFVLEtBQUssV0FBVyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN2RSxDQUFDO0lBRUQsSUFBSSxNQUFNO1FBQ1IsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDO0lBQ3RCLENBQUM7SUFFRCxHQUFHO1FBQ0QsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNsQixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQztZQUNwQixJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztZQUMvQixJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ2pCLENBQUM7SUFDSCxDQUFDO0lBRUQsT0FBTyxDQUFDLFFBQW9CO1FBQzFCLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ3JDLENBQUM7Q0FDRjtBQWxERCxzQ0FrREMifQ==
@@ -0,0 +1,32 @@
1
+ import type { CreateRunInput, MessageObject, MessageContentBlock, AgentStreamMessage, AgentStreamMessagePayload } from '@eggjs/tegg-types/agent-runtime';
2
+ import type { RunUsage } from './RunBuilder';
3
+ export declare class MessageConverter {
4
+ /**
5
+ * Convert an AgentStreamMessage's message payload into OpenAI MessageContentBlock[].
6
+ */
7
+ static toContentBlocks(msg: AgentStreamMessagePayload): MessageContentBlock[];
8
+ /**
9
+ * Build a completed MessageObject from an AgentStreamMessage payload.
10
+ */
11
+ static toMessageObject(msg: AgentStreamMessagePayload, runId?: string): MessageObject;
12
+ /**
13
+ * Extract MessageObjects and accumulated usage from AgentStreamMessage objects.
14
+ */
15
+ static extractFromStreamMessages(messages: AgentStreamMessage[], runId?: string): {
16
+ output: MessageObject[];
17
+ usage?: RunUsage;
18
+ };
19
+ /**
20
+ * Produce a completed copy of a streaming MessageObject with final content.
21
+ */
22
+ static completeMessage(msg: MessageObject, content: MessageContentBlock[]): MessageObject;
23
+ /**
24
+ * Create an in-progress MessageObject for streaming (before content is known).
25
+ */
26
+ static createStreamMessage(msgId: string, runId: string): MessageObject;
27
+ /**
28
+ * Convert input messages to MessageObjects for thread history.
29
+ * System messages are filtered out — they are transient instructions, not conversation history.
30
+ */
31
+ static toInputMessageObjects(messages: CreateRunInput['input']['messages'], threadId?: string): MessageObject[];
32
+ }
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MessageConverter = void 0;
4
+ const agent_runtime_1 = require("@eggjs/tegg-types/agent-runtime");
5
+ const AgentStoreUtils_1 = require("./AgentStoreUtils");
6
+ class MessageConverter {
7
+ /**
8
+ * Convert an AgentStreamMessage's message payload into OpenAI MessageContentBlock[].
9
+ */
10
+ static toContentBlocks(msg) {
11
+ if (!msg)
12
+ return [];
13
+ const content = msg.content;
14
+ if (typeof content === 'string') {
15
+ return [{ type: agent_runtime_1.ContentBlockType.Text, text: { value: content, annotations: [] } }];
16
+ }
17
+ if (Array.isArray(content)) {
18
+ return content
19
+ .filter(part => part.type === agent_runtime_1.ContentBlockType.Text)
20
+ .map(part => ({ type: agent_runtime_1.ContentBlockType.Text, text: { value: part.text, annotations: [] } }));
21
+ }
22
+ return [];
23
+ }
24
+ /**
25
+ * Build a completed MessageObject from an AgentStreamMessage payload.
26
+ */
27
+ static toMessageObject(msg, runId) {
28
+ return {
29
+ id: (0, AgentStoreUtils_1.newMsgId)(),
30
+ object: agent_runtime_1.AgentObjectType.ThreadMessage,
31
+ createdAt: (0, AgentStoreUtils_1.nowUnix)(),
32
+ runId,
33
+ role: agent_runtime_1.MessageRole.Assistant,
34
+ status: agent_runtime_1.MessageStatus.Completed,
35
+ content: MessageConverter.toContentBlocks(msg),
36
+ };
37
+ }
38
+ /**
39
+ * Extract MessageObjects and accumulated usage from AgentStreamMessage objects.
40
+ */
41
+ static extractFromStreamMessages(messages, runId) {
42
+ var _a, _b;
43
+ const output = [];
44
+ let promptTokens = 0;
45
+ let completionTokens = 0;
46
+ let hasUsage = false;
47
+ for (const msg of messages) {
48
+ if (msg.message) {
49
+ output.push(MessageConverter.toMessageObject(msg.message, runId));
50
+ }
51
+ if (msg.usage) {
52
+ hasUsage = true;
53
+ promptTokens += (_a = msg.usage.promptTokens) !== null && _a !== void 0 ? _a : 0;
54
+ completionTokens += (_b = msg.usage.completionTokens) !== null && _b !== void 0 ? _b : 0;
55
+ }
56
+ }
57
+ let usage;
58
+ if (hasUsage) {
59
+ usage = {
60
+ promptTokens,
61
+ completionTokens,
62
+ totalTokens: promptTokens + completionTokens,
63
+ };
64
+ }
65
+ return { output, usage };
66
+ }
67
+ /**
68
+ * Produce a completed copy of a streaming MessageObject with final content.
69
+ */
70
+ static completeMessage(msg, content) {
71
+ return { ...msg, status: agent_runtime_1.MessageStatus.Completed, content };
72
+ }
73
+ /**
74
+ * Create an in-progress MessageObject for streaming (before content is known).
75
+ */
76
+ static createStreamMessage(msgId, runId) {
77
+ return {
78
+ id: msgId,
79
+ object: agent_runtime_1.AgentObjectType.ThreadMessage,
80
+ createdAt: (0, AgentStoreUtils_1.nowUnix)(),
81
+ runId,
82
+ role: agent_runtime_1.MessageRole.Assistant,
83
+ status: agent_runtime_1.MessageStatus.InProgress,
84
+ content: [],
85
+ };
86
+ }
87
+ /**
88
+ * Convert input messages to MessageObjects for thread history.
89
+ * System messages are filtered out — they are transient instructions, not conversation history.
90
+ */
91
+ static toInputMessageObjects(messages, threadId) {
92
+ return messages
93
+ .filter((m) => m.role !== agent_runtime_1.MessageRole.System)
94
+ .map(m => ({
95
+ id: (0, AgentStoreUtils_1.newMsgId)(),
96
+ object: agent_runtime_1.AgentObjectType.ThreadMessage,
97
+ createdAt: (0, AgentStoreUtils_1.nowUnix)(),
98
+ threadId,
99
+ role: m.role,
100
+ status: agent_runtime_1.MessageStatus.Completed,
101
+ content: typeof m.content === 'string'
102
+ ? [{ type: agent_runtime_1.ContentBlockType.Text, text: { value: m.content, annotations: [] } }]
103
+ : m.content.map(p => ({ type: agent_runtime_1.ContentBlockType.Text, text: { value: p.text, annotations: [] } })),
104
+ }));
105
+ }
106
+ }
107
+ exports.MessageConverter = MessageConverter;
108
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWVzc2FnZUNvbnZlcnRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9NZXNzYWdlQ29udmVydGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQU9BLG1FQUFnSDtBQUVoSCx1REFBc0Q7QUFHdEQsTUFBYSxnQkFBZ0I7SUFDM0I7O09BRUc7SUFDSCxNQUFNLENBQUMsZUFBZSxDQUFDLEdBQThCO1FBQ25ELElBQUksQ0FBQyxHQUFHO1lBQUUsT0FBTyxFQUFFLENBQUM7UUFDcEIsTUFBTSxPQUFPLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQztRQUM1QixJQUFJLE9BQU8sT0FBTyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ2hDLE9BQU8sQ0FBQyxFQUFFLElBQUksRUFBRSxnQ0FBZ0IsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxXQUFXLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3RGLENBQUM7UUFDRCxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUMzQixPQUFPLE9BQU87aUJBQ1gsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksS0FBSyxnQ0FBZ0IsQ0FBQyxJQUFJLENBQUM7aUJBQ25ELEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsZ0NBQWdCLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsSUFBSSxFQUFFLFdBQVcsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUNqRyxDQUFDO1FBQ0QsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsZUFBZSxDQUFDLEdBQThCLEVBQUUsS0FBYztRQUNuRSxPQUFPO1lBQ0wsRUFBRSxFQUFFLElB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
@@ -0,0 +1,62 @@
1
+ import type { AgentRunConfig, AgentStore, InputMessage, MessageObject, RunRecord, ThreadRecord, ObjectStorageClient } from '@eggjs/tegg-types/agent-runtime';
2
+ export interface OSSAgentStoreOptions {
3
+ client: ObjectStorageClient;
4
+ prefix?: string;
5
+ }
6
+ /**
7
+ * AgentStore implementation backed by an ObjectStorageClient (OSS, S3, etc.).
8
+ *
9
+ * ## Storage layout
10
+ *
11
+ * ```
12
+ * {prefix}threads/{id}/meta.json — Thread metadata (JSON)
13
+ * {prefix}threads/{id}/messages.jsonl — Messages (JSONL, one JSON object per line)
14
+ * {prefix}runs/{id}.json — Run record (JSON)
15
+ * ```
16
+ *
17
+ * ### Why split threads into two keys?
18
+ *
19
+ * Thread messages are append-only: new messages are added at the end but never
20
+ * modified or deleted. Storing them as a JSONL file allows us to leverage the
21
+ * OSS AppendObject API (or similar) to write new messages without reading the
22
+ * entire thread first. This is much more efficient than read-modify-write for
23
+ * long conversations.
24
+ *
25
+ * If the underlying ObjectStorageClient provides an `append()` method, it will
26
+ * be used for O(1) message writes. Otherwise, the store falls back to
27
+ * get-concat-put (which is NOT atomic and may lose data under concurrent
28
+ * writers — acceptable for single-writer scenarios).
29
+ *
30
+ * ### Atomicity note
31
+ *
32
+ * Run updates still use read-modify-write because run fields are mutated
33
+ * (status, timestamps, output, etc.) — they cannot be modelled as append-only.
34
+ * For multi-writer safety, consider a database-backed AgentStore or ETag-based
35
+ * conditional writes with retry.
36
+ */
37
+ export declare class OSSAgentStore implements AgentStore {
38
+ private readonly client;
39
+ private readonly prefix;
40
+ constructor(options: OSSAgentStoreOptions);
41
+ /** Key for thread metadata (JSON). */
42
+ private threadMetaKey;
43
+ /** Key for thread messages (JSONL, one message per line). */
44
+ private threadMessagesKey;
45
+ /** Key for run record (JSON). */
46
+ private runKey;
47
+ init(): Promise<void>;
48
+ destroy(): Promise<void>;
49
+ createThread(metadata?: Record<string, unknown>): Promise<ThreadRecord>;
50
+ getThread(threadId: string): Promise<ThreadRecord>;
51
+ /**
52
+ * Append messages to a thread.
53
+ *
54
+ * Each message is serialized as a single JSON line (JSONL format).
55
+ * When the underlying client supports `append()`, this is a single
56
+ * O(1) write — no need to read the existing messages first.
57
+ */
58
+ appendMessages(threadId: string, messages: MessageObject[]): Promise<void>;
59
+ createRun(input: InputMessage[], threadId?: string, config?: AgentRunConfig, metadata?: Record<string, unknown>): Promise<RunRecord>;
60
+ getRun(runId: string): Promise<RunRecord>;
61
+ updateRun(runId: string, updates: Partial<RunRecord>): Promise<void>;
62
+ }
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OSSAgentStore = void 0;
4
+ const agent_runtime_1 = require("@eggjs/tegg-types/agent-runtime");
5
+ const AgentStoreUtils_1 = require("./AgentStoreUtils");
6
+ /**
7
+ * AgentStore implementation backed by an ObjectStorageClient (OSS, S3, etc.).
8
+ *
9
+ * ## Storage layout
10
+ *
11
+ * ```
12
+ * {prefix}threads/{id}/meta.json — Thread metadata (JSON)
13
+ * {prefix}threads/{id}/messages.jsonl — Messages (JSONL, one JSON object per line)
14
+ * {prefix}runs/{id}.json — Run record (JSON)
15
+ * ```
16
+ *
17
+ * ### Why split threads into two keys?
18
+ *
19
+ * Thread messages are append-only: new messages are added at the end but never
20
+ * modified or deleted. Storing them as a JSONL file allows us to leverage the
21
+ * OSS AppendObject API (or similar) to write new messages without reading the
22
+ * entire thread first. This is much more efficient than read-modify-write for
23
+ * long conversations.
24
+ *
25
+ * If the underlying ObjectStorageClient provides an `append()` method, it will
26
+ * be used for O(1) message writes. Otherwise, the store falls back to
27
+ * get-concat-put (which is NOT atomic and may lose data under concurrent
28
+ * writers — acceptable for single-writer scenarios).
29
+ *
30
+ * ### Atomicity note
31
+ *
32
+ * Run updates still use read-modify-write because run fields are mutated
33
+ * (status, timestamps, output, etc.) — they cannot be modelled as append-only.
34
+ * For multi-writer safety, consider a database-backed AgentStore or ETag-based
35
+ * conditional writes with retry.
36
+ */
37
+ class OSSAgentStore {
38
+ constructor(options) {
39
+ var _a;
40
+ this.client = options.client;
41
+ // Normalize: ensure non-empty prefix ends with '/'
42
+ const raw = (_a = options.prefix) !== null && _a !== void 0 ? _a : '';
43
+ this.prefix = raw && !raw.endsWith('/') ? raw + '/' : raw;
44
+ }
45
+ // ── Key helpers ──────────────────────────────────────────────────────
46
+ /** Key for thread metadata (JSON). */
47
+ threadMetaKey(threadId) {
48
+ return `${this.prefix}threads/${threadId}/meta.json`;
49
+ }
50
+ /** Key for thread messages (JSONL, one message per line). */
51
+ threadMessagesKey(threadId) {
52
+ return `${this.prefix}threads/${threadId}/messages.jsonl`;
53
+ }
54
+ /** Key for run record (JSON). */
55
+ runKey(runId) {
56
+ return `${this.prefix}runs/${runId}.json`;
57
+ }
58
+ // ── Lifecycle ────────────────────────────────────────────────────────
59
+ async init() {
60
+ var _a, _b;
61
+ await ((_b = (_a = this.client).init) === null || _b === void 0 ? void 0 : _b.call(_a));
62
+ }
63
+ async destroy() {
64
+ var _a, _b;
65
+ await ((_b = (_a = this.client).destroy) === null || _b === void 0 ? void 0 : _b.call(_a));
66
+ }
67
+ // ── Thread operations ────────────────────────────────────────────────
68
+ async createThread(metadata) {
69
+ const threadId = (0, AgentStoreUtils_1.newThreadId)();
70
+ const meta = {
71
+ id: threadId,
72
+ object: agent_runtime_1.AgentObjectType.Thread,
73
+ metadata: metadata !== null && metadata !== void 0 ? metadata : {},
74
+ createdAt: (0, AgentStoreUtils_1.nowUnix)(),
75
+ };
76
+ await this.client.put(this.threadMetaKey(threadId), JSON.stringify(meta));
77
+ // Messages file is created lazily on first appendMessages call.
78
+ return { ...meta, messages: [] };
79
+ }
80
+ async getThread(threadId) {
81
+ const [metaData, messagesData] = await Promise.all([
82
+ this.client.get(this.threadMetaKey(threadId)),
83
+ this.client.get(this.threadMessagesKey(threadId)),
84
+ ]);
85
+ if (!metaData) {
86
+ throw new agent_runtime_1.AgentNotFoundError(`Thread ${threadId} not found`);
87
+ }
88
+ const meta = JSON.parse(metaData);
89
+ // Parse messages JSONL — may not exist yet if no messages were appended.
90
+ const messages = messagesData
91
+ ? messagesData
92
+ .trim()
93
+ .split('\n')
94
+ .filter(line => line.length > 0)
95
+ .map(line => JSON.parse(line))
96
+ : [];
97
+ return { ...meta, messages };
98
+ }
99
+ /**
100
+ * Append messages to a thread.
101
+ *
102
+ * Each message is serialized as a single JSON line (JSONL format).
103
+ * When the underlying client supports `append()`, this is a single
104
+ * O(1) write — no need to read the existing messages first.
105
+ */
106
+ async appendMessages(threadId, messages) {
107
+ var _a;
108
+ // Verify the thread exists before writing messages (or returning early),
109
+ // so callers always get AgentNotFoundError for invalid threadIds.
110
+ const metaData = await this.client.get(this.threadMetaKey(threadId));
111
+ if (!metaData) {
112
+ throw new agent_runtime_1.AgentNotFoundError(`Thread ${threadId} not found`);
113
+ }
114
+ if (messages.length === 0)
115
+ return;
116
+ const lines = messages.map(m => JSON.stringify(m)).join('\n') + '\n';
117
+ const messagesKey = this.threadMessagesKey(threadId);
118
+ if (this.client.append) {
119
+ // Fast path: use the native append API (e.g., OSS AppendObject).
120
+ await this.client.append(messagesKey, lines);
121
+ }
122
+ else {
123
+ // Slow path: read-modify-write fallback.
124
+ // NOTE: Not atomic — concurrent appends may lose data.
125
+ const existing = (_a = (await this.client.get(messagesKey))) !== null && _a !== void 0 ? _a : '';
126
+ await this.client.put(messagesKey, existing + lines);
127
+ }
128
+ }
129
+ // ── Run operations ───────────────────────────────────────────────────
130
+ async createRun(input, threadId, config, metadata) {
131
+ const runId = (0, AgentStoreUtils_1.newRunId)();
132
+ const record = {
133
+ id: runId,
134
+ object: agent_runtime_1.AgentObjectType.ThreadRun,
135
+ threadId,
136
+ status: agent_runtime_1.RunStatus.Queued,
137
+ input,
138
+ config,
139
+ metadata,
140
+ createdAt: (0, AgentStoreUtils_1.nowUnix)(),
141
+ };
142
+ await this.client.put(this.runKey(runId), JSON.stringify(record));
143
+ return record;
144
+ }
145
+ async getRun(runId) {
146
+ const data = await this.client.get(this.runKey(runId));
147
+ if (!data) {
148
+ throw new agent_runtime_1.AgentNotFoundError(`Run ${runId} not found`);
149
+ }
150
+ return JSON.parse(data);
151
+ }
152
+ // TODO: read-modify-write is NOT atomic. Concurrent updates may lose data.
153
+ // Acceptable for single-writer scenarios; for multi-writer, consider ETag-based
154
+ // conditional writes with retry, or use a database-backed AgentStore instead.
155
+ async updateRun(runId, updates) {
156
+ const run = await this.getRun(runId);
157
+ const safeUpdates = { ...updates };
158
+ delete safeUpdates.id;
159
+ delete safeUpdates.object;
160
+ Object.assign(run, safeUpdates);
161
+ await this.client.put(this.runKey(runId), JSON.stringify(run));
162
+ }
163
+ }
164
+ exports.OSSAgentStore = OSSAgentStore;
165
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiT1NTQWdlbnRTdG9yZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9PU1NBZ2VudFN0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQVFBLG1FQUFpRztBQUVqRyx1REFBbUU7QUFhbkU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQThCRztBQUNILE1BQWEsYUFBYTtJQUl4QixZQUFZLE9BQTZCOztRQUN2QyxJQUFJLENBQUMsTUFBTSxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUM7UUFDN0IsbURBQW1EO1FBQ25ELE1BQU0sR0FBRyxHQUFHLE1BQUEsT0FBTyxDQUFDLE1BQU0sbUNBQUksRUFBRSxDQUFDO1FBQ2pDLElBQUksQ0FBQyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0lBQzVELENBQUM7SUFFRCx3RUFBd0U7SUFFeEUsc0NBQXNDO0lBQzlCLGFBQWEsQ0FBQyxRQUFnQjtRQUNwQyxPQUFPLEdBQUcsSUFBSSxDQUFDLE1BQU0sV0FBVyxRQUFRLFlBQVksQ0FBQztJQUN2RCxDQUFDO0lBRUQsNkRBQTZEO0lBQ3JELGlCQUFpQixDQUFDLFFBQWdCO1FBQ3hDLE9BQU8sR0FBRyxJQUFJLENBQUMsTUFBTSxXQUFXLFFBQVEsaUJBQWlCLENBQUM7SUFDNUQsQ0FBQztJQUVELGlDQUFpQztJQUN6QixNQUFNLENBQUMsS0FBYTtRQUMxQixPQUFPLEdBQUcsSUFBSSxDQUFDLE1BQU0sUUFBUSxLQUFLLE9BQU8sQ0FBQztJQUM1QyxDQUFDO0lBRUQsd0VBQXdFO0lBRXhFLEtBQUssQ0FBQyxJQUFJOztRQUNSLE1BQU0sQ0FBQSxNQUFBLE1BQUEsSUFBSSxDQUFDLE1BQU0sRUFBQyxJQUFJLGtEQUFJLENBQUEsQ0FBQztJQUM3QixDQUFDO0lBRUQsS0FBSyxD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
@@ -0,0 +1,46 @@
1
+ import type { ObjectStorageClient } from '@eggjs/tegg-types/agent-runtime';
2
+ import type { OSSObject } from 'oss-client';
3
+ /**
4
+ * ObjectStorageClient backed by Alibaba Cloud OSS (via oss-client).
5
+ *
6
+ * Supports both `put`/`get` for normal objects and `append` for
7
+ * OSS Appendable Objects. The append path uses a local position cache
8
+ * to avoid extra HEAD requests; on position mismatch it falls back to
9
+ * HEAD + retry automatically.
10
+ *
11
+ * The OSSObject instance should be constructed and injected by the caller,
12
+ * following the IoC/DI principle.
13
+ */
14
+ export declare class OSSObjectStorageClient implements ObjectStorageClient {
15
+ private readonly client;
16
+ /**
17
+ * In-memory cache of next-append positions.
18
+ *
19
+ * After each successful `append()`, OSS returns `nextAppendPosition`.
20
+ * We cache it here so the next append can skip a HEAD round-trip.
21
+ * If the cached position is stale (e.g., process restarted or another
22
+ * writer appended), the append will fail with PositionNotEqualToLength
23
+ * and we fall back to HEAD + retry.
24
+ */
25
+ private readonly appendPositions;
26
+ constructor(client: OSSObject);
27
+ put(key: string, value: string): Promise<void>;
28
+ get(key: string): Promise<string | null>;
29
+ /**
30
+ * Append data to an OSS Appendable Object.
31
+ *
32
+ * OSS AppendObject requires a `position` parameter that must equal the
33
+ * current object size. We use a three-step strategy:
34
+ *
35
+ * 1. Use the cached position (0 for new objects, or the value from the
36
+ * last successful append).
37
+ * 2. If OSS returns PositionNotEqualToLength (cache is stale), issue a
38
+ * HEAD request to learn the current object size, then retry once.
39
+ * 3. Update the cache with `nextAppendPosition` from the response.
40
+ *
41
+ * This gives us single-round-trip performance in the common case (single
42
+ * writer, no restarts) while still being self-healing when the cache is
43
+ * stale.
44
+ */
45
+ append(key: string, value: string): Promise<void>;
46
+ }