@sowonai/crewx-cli 0.8.0-rc.1 → 0.8.0-rc.11
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 +2 -2
- package/dist/app.module.js +4 -0
- package/dist/app.module.js.map +1 -1
- package/dist/cli/cli.handler.js +4 -0
- package/dist/cli/cli.handler.js.map +1 -1
- package/dist/cli/init.handler.js +1 -1
- package/dist/cli/skill.handler.d.ts +2 -0
- package/dist/cli/skill.handler.js +143 -0
- package/dist/cli/skill.handler.js.map +1 -0
- package/dist/cli-options.d.ts +4 -0
- package/dist/cli-options.js +19 -0
- package/dist/cli-options.js.map +1 -1
- package/dist/crewx.tool.d.ts +3 -1
- package/dist/crewx.tool.js +42 -2
- package/dist/crewx.tool.js.map +1 -1
- package/dist/main.js +6 -1
- package/dist/main.js.map +1 -1
- package/dist/providers/dynamic-provider.factory.js +2 -0
- package/dist/providers/dynamic-provider.factory.js.map +1 -1
- package/dist/services/skill.service.d.ts +66 -0
- package/dist/services/skill.service.js +584 -0
- package/dist/services/skill.service.js.map +1 -0
- package/dist/services/skill.service.spec.d.ts +1 -0
- package/dist/services/skill.service.spec.js +35 -0
- package/dist/services/skill.service.spec.js.map +1 -0
- package/dist/services/tracing.service.d.ts +77 -73
- package/dist/services/tracing.service.js +250 -338
- package/dist/services/tracing.service.js.map +1 -1
- package/dist/slack/formatters/message.formatter.d.ts +4 -0
- package/dist/slack/formatters/message.formatter.js +93 -49
- package/dist/slack/formatters/message.formatter.js.map +1 -1
- package/dist/utils/template-processor.js +18 -1
- package/dist/utils/template-processor.js.map +1 -1
- package/package.json +4 -2
- package/templates/agents/default.yaml +2 -0
- package/templates/documents/conversation-history-default.hbs +17 -0
- package/dist/services/memory.service.d.ts +0 -102
- package/dist/services/memory.service.js +0 -707
- package/dist/services/memory.service.js.map +0 -1
- package/scripts/migrate-tracing-db.mjs +0 -295
|
@@ -41,470 +41,382 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
41
41
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
42
42
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
43
43
|
};
|
|
44
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
45
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
46
|
+
};
|
|
47
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
48
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
49
|
+
};
|
|
44
50
|
var TracingService_1;
|
|
45
51
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
-
exports.TracingService = exports.
|
|
52
|
+
exports.TracingService = exports.SpanKind = exports.TaskStatus = void 0;
|
|
47
53
|
const common_1 = require("@nestjs/common");
|
|
48
|
-
const path = __importStar(require("path"));
|
|
49
54
|
const fs = __importStar(require("fs"));
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
const path = __importStar(require("path"));
|
|
56
|
+
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
57
|
+
var TaskStatus;
|
|
58
|
+
(function (TaskStatus) {
|
|
59
|
+
TaskStatus["PENDING"] = "pending";
|
|
60
|
+
TaskStatus["RUNNING"] = "running";
|
|
61
|
+
TaskStatus["SUCCESS"] = "success";
|
|
62
|
+
TaskStatus["FAILED"] = "failed";
|
|
63
|
+
})(TaskStatus || (exports.TaskStatus = TaskStatus = {}));
|
|
64
|
+
var SpanKind;
|
|
65
|
+
(function (SpanKind) {
|
|
66
|
+
SpanKind["INTERNAL"] = "internal";
|
|
67
|
+
SpanKind["CLIENT"] = "client";
|
|
68
|
+
SpanKind["SERVER"] = "server";
|
|
69
|
+
SpanKind["PRODUCER"] = "producer";
|
|
70
|
+
SpanKind["CONSUMER"] = "consumer";
|
|
71
|
+
})(SpanKind || (exports.SpanKind = SpanKind = {}));
|
|
58
72
|
let TracingService = TracingService_1 = class TracingService {
|
|
59
|
-
constructor() {
|
|
73
|
+
constructor(options) {
|
|
60
74
|
this.logger = new common_1.Logger(TracingService_1.name);
|
|
61
75
|
this.db = null;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (this.initialized) {
|
|
69
|
-
return true;
|
|
76
|
+
if (options?.dbPath) {
|
|
77
|
+
this.dbPath = options.dbPath;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
const crewxDir = path.join(process.cwd(), '.crewx');
|
|
81
|
+
this.dbPath = path.join(crewxDir, 'traces.db');
|
|
70
82
|
}
|
|
83
|
+
}
|
|
84
|
+
onModuleInit() {
|
|
85
|
+
this.initializeDatabase();
|
|
86
|
+
}
|
|
87
|
+
onModuleDestroy() {
|
|
88
|
+
this.close();
|
|
89
|
+
}
|
|
90
|
+
initializeDatabase() {
|
|
71
91
|
try {
|
|
72
|
-
const Database = await this.loadBetterSqlite3();
|
|
73
|
-
if (!Database) {
|
|
74
|
-
this.logger.warn('better-sqlite3 not available, tracing disabled');
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
92
|
const dir = path.dirname(this.dbPath);
|
|
78
93
|
if (!fs.existsSync(dir)) {
|
|
79
94
|
fs.mkdirSync(dir, { recursive: true });
|
|
80
95
|
}
|
|
81
|
-
this.db = new
|
|
96
|
+
this.db = new better_sqlite3_1.default(this.dbPath);
|
|
82
97
|
this.db.pragma('journal_mode = WAL');
|
|
83
|
-
this.db.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
98
|
+
this.db.exec(`
|
|
99
|
+
CREATE TABLE IF NOT EXISTS tasks (
|
|
100
|
+
id TEXT PRIMARY KEY,
|
|
101
|
+
agent_id TEXT NOT NULL,
|
|
102
|
+
user_id TEXT,
|
|
103
|
+
prompt TEXT NOT NULL,
|
|
104
|
+
mode TEXT NOT NULL CHECK (mode IN ('query', 'execute')),
|
|
105
|
+
status TEXT NOT NULL CHECK (status IN ('pending', 'running', 'success', 'failed')),
|
|
106
|
+
result TEXT,
|
|
107
|
+
error TEXT,
|
|
108
|
+
started_at TEXT NOT NULL,
|
|
109
|
+
completed_at TEXT,
|
|
110
|
+
duration_ms INTEGER,
|
|
111
|
+
metadata TEXT
|
|
112
|
+
)
|
|
113
|
+
`);
|
|
114
|
+
this.db.exec(`
|
|
115
|
+
CREATE TABLE IF NOT EXISTS spans (
|
|
116
|
+
id TEXT PRIMARY KEY,
|
|
117
|
+
task_id TEXT NOT NULL,
|
|
118
|
+
parent_span_id TEXT,
|
|
119
|
+
name TEXT NOT NULL,
|
|
120
|
+
kind TEXT NOT NULL CHECK (kind IN ('internal', 'client', 'server', 'producer', 'consumer')),
|
|
121
|
+
status TEXT NOT NULL CHECK (status IN ('ok', 'error')),
|
|
122
|
+
started_at TEXT NOT NULL,
|
|
123
|
+
completed_at TEXT,
|
|
124
|
+
duration_ms INTEGER,
|
|
125
|
+
input TEXT,
|
|
126
|
+
output TEXT,
|
|
127
|
+
error TEXT,
|
|
128
|
+
attributes TEXT,
|
|
129
|
+
FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,
|
|
130
|
+
FOREIGN KEY (parent_span_id) REFERENCES spans(id) ON DELETE SET NULL
|
|
131
|
+
)
|
|
132
|
+
`);
|
|
133
|
+
this.db.exec(`
|
|
134
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_agent_id ON tasks(agent_id);
|
|
135
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
|
|
136
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_started_at ON tasks(started_at);
|
|
137
|
+
CREATE INDEX IF NOT EXISTS idx_spans_task_id ON spans(task_id);
|
|
138
|
+
CREATE INDEX IF NOT EXISTS idx_spans_parent_span_id ON spans(parent_span_id);
|
|
139
|
+
`);
|
|
88
140
|
this.logger.log(`Tracing database initialized at ${this.dbPath}`);
|
|
89
|
-
return true;
|
|
90
141
|
}
|
|
91
142
|
catch (error) {
|
|
92
|
-
this.logger.
|
|
93
|
-
return false;
|
|
143
|
+
this.logger.error(`Failed to initialize tracing database: ${error instanceof Error ? error.message : String(error)}`);
|
|
94
144
|
}
|
|
95
145
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return null;
|
|
146
|
+
close() {
|
|
147
|
+
if (this.db) {
|
|
148
|
+
this.db.close();
|
|
149
|
+
this.db = null;
|
|
150
|
+
this.logger.log('Tracing database connection closed');
|
|
102
151
|
}
|
|
103
152
|
}
|
|
104
|
-
createTables() {
|
|
105
|
-
this.db.exec(`
|
|
106
|
-
CREATE TABLE IF NOT EXISTS traces (
|
|
107
|
-
id TEXT PRIMARY KEY,
|
|
108
|
-
name TEXT NOT NULL,
|
|
109
|
-
agent_id TEXT,
|
|
110
|
-
session_id TEXT,
|
|
111
|
-
start_time INTEGER NOT NULL,
|
|
112
|
-
end_time INTEGER,
|
|
113
|
-
status TEXT NOT NULL DEFAULT 'pending',
|
|
114
|
-
attributes TEXT,
|
|
115
|
-
metadata TEXT,
|
|
116
|
-
created_at INTEGER DEFAULT (strftime('%s', 'now') * 1000),
|
|
117
|
-
updated_at INTEGER DEFAULT (strftime('%s', 'now') * 1000)
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
CREATE INDEX IF NOT EXISTS idx_traces_agent_id ON traces(agent_id);
|
|
121
|
-
CREATE INDEX IF NOT EXISTS idx_traces_session_id ON traces(session_id);
|
|
122
|
-
CREATE INDEX IF NOT EXISTS idx_traces_status ON traces(status);
|
|
123
|
-
CREATE INDEX IF NOT EXISTS idx_traces_start_time ON traces(start_time);
|
|
124
|
-
`);
|
|
125
|
-
this.db.exec(`
|
|
126
|
-
CREATE TABLE IF NOT EXISTS trace_spans (
|
|
127
|
-
id TEXT PRIMARY KEY,
|
|
128
|
-
trace_id TEXT NOT NULL,
|
|
129
|
-
name TEXT NOT NULL,
|
|
130
|
-
parent_span_id TEXT,
|
|
131
|
-
start_time INTEGER NOT NULL,
|
|
132
|
-
end_time INTEGER,
|
|
133
|
-
status TEXT NOT NULL DEFAULT 'pending',
|
|
134
|
-
attributes TEXT,
|
|
135
|
-
events TEXT,
|
|
136
|
-
created_at INTEGER DEFAULT (strftime('%s', 'now') * 1000),
|
|
137
|
-
FOREIGN KEY (trace_id) REFERENCES traces(id) ON DELETE CASCADE
|
|
138
|
-
);
|
|
139
|
-
|
|
140
|
-
CREATE INDEX IF NOT EXISTS idx_spans_trace_id ON trace_spans(trace_id);
|
|
141
|
-
CREATE INDEX IF NOT EXISTS idx_spans_parent ON trace_spans(parent_span_id);
|
|
142
|
-
`);
|
|
143
|
-
this.db.exec(`
|
|
144
|
-
CREATE TABLE IF NOT EXISTS trace_events (
|
|
145
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
146
|
-
trace_id TEXT NOT NULL,
|
|
147
|
-
span_id TEXT,
|
|
148
|
-
name TEXT NOT NULL,
|
|
149
|
-
timestamp INTEGER NOT NULL,
|
|
150
|
-
attributes TEXT,
|
|
151
|
-
FOREIGN KEY (trace_id) REFERENCES traces(id) ON DELETE CASCADE
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
CREATE INDEX IF NOT EXISTS idx_events_trace_id ON trace_events(trace_id);
|
|
155
|
-
`);
|
|
156
|
-
}
|
|
157
153
|
generateId() {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
154
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
155
|
+
const r = (Math.random() * 16) | 0;
|
|
156
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
157
|
+
return v.toString(16);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
now() {
|
|
161
|
+
return new Date().toISOString();
|
|
161
162
|
}
|
|
162
|
-
|
|
163
|
-
if (!
|
|
163
|
+
createTask(input) {
|
|
164
|
+
if (!this.db) {
|
|
164
165
|
return null;
|
|
165
166
|
}
|
|
166
167
|
const id = this.generateId();
|
|
167
|
-
const now =
|
|
168
|
+
const now = this.now();
|
|
168
169
|
try {
|
|
169
170
|
const stmt = this.db.prepare(`
|
|
170
|
-
INSERT INTO
|
|
171
|
+
INSERT INTO tasks (id, agent_id, user_id, prompt, mode, status, started_at, metadata)
|
|
171
172
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
172
173
|
`);
|
|
173
|
-
stmt.run(id,
|
|
174
|
-
this.logger.debug(`
|
|
174
|
+
stmt.run(id, input.agent_id, input.user_id ?? null, input.prompt, input.mode, TaskStatus.RUNNING, now, input.metadata ? JSON.stringify(input.metadata) : null);
|
|
175
|
+
this.logger.debug(`Task created: ${id} for agent ${input.agent_id}`);
|
|
175
176
|
return id;
|
|
176
177
|
}
|
|
177
178
|
catch (error) {
|
|
178
|
-
this.logger.error(`Failed to
|
|
179
|
+
this.logger.error(`Failed to create task: ${error instanceof Error ? error.message : String(error)}`);
|
|
179
180
|
return null;
|
|
180
181
|
}
|
|
181
182
|
}
|
|
182
|
-
|
|
183
|
-
if (!
|
|
183
|
+
completeTask(taskId, result) {
|
|
184
|
+
if (!this.db) {
|
|
184
185
|
return false;
|
|
185
186
|
}
|
|
186
187
|
try {
|
|
187
|
-
const now =
|
|
188
|
+
const now = this.now();
|
|
188
189
|
const stmt = this.db.prepare(`
|
|
189
|
-
UPDATE
|
|
190
|
-
SET status = ?,
|
|
190
|
+
UPDATE tasks
|
|
191
|
+
SET status = ?, result = ?, completed_at = ?,
|
|
192
|
+
duration_ms = CAST((julianday(?) - julianday(started_at)) * 86400000 AS INTEGER)
|
|
191
193
|
WHERE id = ?
|
|
192
194
|
`);
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
if (changes.changes > 0) {
|
|
196
|
-
this.logger.debug(`Completed trace: ${traceId}`);
|
|
197
|
-
return true;
|
|
198
|
-
}
|
|
199
|
-
return false;
|
|
195
|
+
const info = stmt.run(TaskStatus.SUCCESS, result ?? null, now, now, taskId);
|
|
196
|
+
return info.changes > 0;
|
|
200
197
|
}
|
|
201
198
|
catch (error) {
|
|
202
|
-
this.logger.error(`Failed to complete
|
|
199
|
+
this.logger.error(`Failed to complete task ${taskId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
203
200
|
return false;
|
|
204
201
|
}
|
|
205
202
|
}
|
|
206
|
-
|
|
207
|
-
if (!
|
|
203
|
+
failTask(taskId, error) {
|
|
204
|
+
if (!this.db) {
|
|
208
205
|
return false;
|
|
209
206
|
}
|
|
210
207
|
try {
|
|
211
|
-
const now =
|
|
212
|
-
const errorInfo = {
|
|
213
|
-
error: {
|
|
214
|
-
message: error instanceof Error ? error.message : String(error),
|
|
215
|
-
stack: error instanceof Error ? error.stack : undefined,
|
|
216
|
-
}
|
|
217
|
-
};
|
|
208
|
+
const now = this.now();
|
|
218
209
|
const stmt = this.db.prepare(`
|
|
219
|
-
UPDATE
|
|
220
|
-
SET status = ?,
|
|
210
|
+
UPDATE tasks
|
|
211
|
+
SET status = ?, error = ?, completed_at = ?,
|
|
212
|
+
duration_ms = CAST((julianday(?) - julianday(started_at)) * 86400000 AS INTEGER)
|
|
221
213
|
WHERE id = ?
|
|
222
214
|
`);
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
this.logger.debug(`Failed trace: ${traceId}`);
|
|
226
|
-
return true;
|
|
227
|
-
}
|
|
228
|
-
return false;
|
|
215
|
+
const info = stmt.run(TaskStatus.FAILED, error, now, now, taskId);
|
|
216
|
+
return info.changes > 0;
|
|
229
217
|
}
|
|
230
|
-
catch (
|
|
231
|
-
this.logger.error(`Failed to
|
|
218
|
+
catch (error) {
|
|
219
|
+
this.logger.error(`Failed to fail task ${taskId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
232
220
|
return false;
|
|
233
221
|
}
|
|
234
222
|
}
|
|
235
|
-
|
|
236
|
-
if (!
|
|
223
|
+
getTask(taskId) {
|
|
224
|
+
if (!this.db) {
|
|
237
225
|
return null;
|
|
238
226
|
}
|
|
239
|
-
const id = this.generateId();
|
|
240
|
-
const now = Date.now();
|
|
241
227
|
try {
|
|
242
|
-
const stmt = this.db.prepare(
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
return
|
|
228
|
+
const stmt = this.db.prepare('SELECT * FROM tasks WHERE id = ?');
|
|
229
|
+
const row = stmt.get(taskId);
|
|
230
|
+
if (!row) {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
...row,
|
|
235
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
|
|
236
|
+
};
|
|
248
237
|
}
|
|
249
238
|
catch (error) {
|
|
250
|
-
this.logger.error(`Failed to
|
|
239
|
+
this.logger.error(`Failed to get task ${taskId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
251
240
|
return null;
|
|
252
241
|
}
|
|
253
242
|
}
|
|
254
|
-
|
|
255
|
-
if (!
|
|
256
|
-
return
|
|
243
|
+
listTasks(options) {
|
|
244
|
+
if (!this.db) {
|
|
245
|
+
return [];
|
|
257
246
|
}
|
|
247
|
+
const limit = options?.limit ?? 20;
|
|
248
|
+
const offset = options?.offset ?? 0;
|
|
258
249
|
try {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
UPDATE trace_spans
|
|
265
|
-
SET status = ?, end_time = ?, attributes = json_patch(COALESCE(attributes, '{}'), ?)
|
|
266
|
-
WHERE id = ?
|
|
267
|
-
`);
|
|
268
|
-
changes = stmt.run(status, now, JSON.stringify(attributes), spanId);
|
|
269
|
-
}
|
|
270
|
-
else {
|
|
271
|
-
stmt = this.db.prepare(`
|
|
272
|
-
UPDATE trace_spans
|
|
273
|
-
SET status = ?, end_time = ?
|
|
274
|
-
WHERE id = ?
|
|
275
|
-
`);
|
|
276
|
-
changes = stmt.run(status, now, spanId);
|
|
250
|
+
let query = 'SELECT * FROM tasks';
|
|
251
|
+
const params = [];
|
|
252
|
+
if (options?.agentId) {
|
|
253
|
+
query += ' WHERE agent_id = ?';
|
|
254
|
+
params.push(options.agentId);
|
|
277
255
|
}
|
|
278
|
-
|
|
256
|
+
query += ' ORDER BY started_at DESC LIMIT ? OFFSET ?';
|
|
257
|
+
params.push(limit, offset);
|
|
258
|
+
const stmt = this.db.prepare(query);
|
|
259
|
+
const rows = stmt.all(...params);
|
|
260
|
+
return rows.map((row) => ({
|
|
261
|
+
...row,
|
|
262
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
|
|
263
|
+
}));
|
|
279
264
|
}
|
|
280
265
|
catch (error) {
|
|
281
|
-
this.logger.error(`Failed to
|
|
282
|
-
return
|
|
266
|
+
this.logger.error(`Failed to list tasks: ${error instanceof Error ? error.message : String(error)}`);
|
|
267
|
+
return [];
|
|
283
268
|
}
|
|
284
269
|
}
|
|
285
|
-
|
|
286
|
-
if (!
|
|
287
|
-
return
|
|
270
|
+
createSpan(input) {
|
|
271
|
+
if (!this.db) {
|
|
272
|
+
return null;
|
|
288
273
|
}
|
|
274
|
+
const id = this.generateId();
|
|
275
|
+
const now = this.now();
|
|
289
276
|
try {
|
|
290
|
-
const now = Date.now();
|
|
291
277
|
const stmt = this.db.prepare(`
|
|
292
|
-
INSERT INTO
|
|
293
|
-
VALUES (?, ?, ?, ?, ?)
|
|
278
|
+
INSERT INTO spans (id, task_id, parent_span_id, name, kind, status, started_at, input, attributes)
|
|
279
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
294
280
|
`);
|
|
295
|
-
stmt.run(
|
|
296
|
-
|
|
281
|
+
stmt.run(id, input.task_id, input.parent_span_id ?? null, input.name, input.kind ?? SpanKind.INTERNAL, 'ok', now, input.input ?? null, input.attributes ? JSON.stringify(input.attributes) : null);
|
|
282
|
+
this.logger.debug(`Span created: ${id} for task ${input.task_id}`);
|
|
283
|
+
return id;
|
|
297
284
|
}
|
|
298
285
|
catch (error) {
|
|
299
|
-
this.logger.error(`Failed to
|
|
300
|
-
return
|
|
286
|
+
this.logger.error(`Failed to create span: ${error instanceof Error ? error.message : String(error)}`);
|
|
287
|
+
return null;
|
|
301
288
|
}
|
|
302
289
|
}
|
|
303
|
-
|
|
304
|
-
if (!
|
|
305
|
-
return
|
|
290
|
+
completeSpan(spanId, output) {
|
|
291
|
+
if (!this.db) {
|
|
292
|
+
return false;
|
|
306
293
|
}
|
|
307
294
|
try {
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
}
|
|
315
|
-
const spansStmt = this.db.prepare(`
|
|
316
|
-
SELECT * FROM trace_spans WHERE trace_id = ? ORDER BY start_time
|
|
317
|
-
`);
|
|
318
|
-
const spanRows = spansStmt.all(traceId);
|
|
319
|
-
const eventsStmt = this.db.prepare(`
|
|
320
|
-
SELECT * FROM trace_events WHERE trace_id = ? ORDER BY timestamp
|
|
295
|
+
const now = this.now();
|
|
296
|
+
const stmt = this.db.prepare(`
|
|
297
|
+
UPDATE spans
|
|
298
|
+
SET status = 'ok', output = ?, completed_at = ?,
|
|
299
|
+
duration_ms = CAST((julianday(?) - julianday(started_at)) * 86400000 AS INTEGER)
|
|
300
|
+
WHERE id = ?
|
|
321
301
|
`);
|
|
322
|
-
const
|
|
323
|
-
return
|
|
302
|
+
const info = stmt.run(output ?? null, now, now, spanId);
|
|
303
|
+
return info.changes > 0;
|
|
324
304
|
}
|
|
325
305
|
catch (error) {
|
|
326
|
-
this.logger.error(`Failed to
|
|
327
|
-
return
|
|
306
|
+
this.logger.error(`Failed to complete span ${spanId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
307
|
+
return false;
|
|
328
308
|
}
|
|
329
309
|
}
|
|
330
|
-
|
|
331
|
-
if (!
|
|
332
|
-
return
|
|
310
|
+
failSpan(spanId, error) {
|
|
311
|
+
if (!this.db) {
|
|
312
|
+
return false;
|
|
333
313
|
}
|
|
334
314
|
try {
|
|
335
|
-
const
|
|
336
|
-
const params = [];
|
|
337
|
-
if (options.agentId) {
|
|
338
|
-
conditions.push('agent_id = ?');
|
|
339
|
-
params.push(options.agentId);
|
|
340
|
-
}
|
|
341
|
-
if (options.sessionId) {
|
|
342
|
-
conditions.push('session_id = ?');
|
|
343
|
-
params.push(options.sessionId);
|
|
344
|
-
}
|
|
345
|
-
if (options.status) {
|
|
346
|
-
conditions.push('status = ?');
|
|
347
|
-
params.push(options.status);
|
|
348
|
-
}
|
|
349
|
-
if (options.startTimeFrom) {
|
|
350
|
-
conditions.push('start_time >= ?');
|
|
351
|
-
params.push(options.startTimeFrom);
|
|
352
|
-
}
|
|
353
|
-
if (options.startTimeTo) {
|
|
354
|
-
conditions.push('start_time <= ?');
|
|
355
|
-
params.push(options.startTimeTo);
|
|
356
|
-
}
|
|
357
|
-
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
358
|
-
const limit = options.limit || 100;
|
|
359
|
-
const offset = options.offset || 0;
|
|
315
|
+
const now = this.now();
|
|
360
316
|
const stmt = this.db.prepare(`
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
317
|
+
UPDATE spans
|
|
318
|
+
SET status = 'error', error = ?, completed_at = ?,
|
|
319
|
+
duration_ms = CAST((julianday(?) - julianday(started_at)) * 86400000 AS INTEGER)
|
|
320
|
+
WHERE id = ?
|
|
365
321
|
`);
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
return rows.map((row) => this.rowToTrace(row));
|
|
322
|
+
const info = stmt.run(error, now, now, spanId);
|
|
323
|
+
return info.changes > 0;
|
|
369
324
|
}
|
|
370
325
|
catch (error) {
|
|
371
|
-
this.logger.error(`Failed to
|
|
372
|
-
return
|
|
326
|
+
this.logger.error(`Failed to fail span ${spanId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
327
|
+
return false;
|
|
373
328
|
}
|
|
374
329
|
}
|
|
375
|
-
|
|
376
|
-
if (!
|
|
330
|
+
getSpansForTask(taskId) {
|
|
331
|
+
if (!this.db) {
|
|
377
332
|
return [];
|
|
378
333
|
}
|
|
379
334
|
try {
|
|
380
|
-
const
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
386
|
-
const whereClause = `WHERE ${conditions.join(' AND ')}`;
|
|
387
|
-
const limit = options.limit || 100;
|
|
388
|
-
const stmt = this.db.prepare(`
|
|
389
|
-
SELECT * FROM traces
|
|
390
|
-
${whereClause}
|
|
391
|
-
ORDER BY start_time DESC
|
|
392
|
-
LIMIT ?
|
|
393
|
-
`);
|
|
394
|
-
const rows = stmt.all(...params, limit);
|
|
395
|
-
return rows.map((row) => this.rowToTrace(row));
|
|
335
|
+
const stmt = this.db.prepare('SELECT * FROM spans WHERE task_id = ? ORDER BY started_at ASC');
|
|
336
|
+
const rows = stmt.all(taskId);
|
|
337
|
+
return rows.map((row) => ({
|
|
338
|
+
...row,
|
|
339
|
+
attributes: row.attributes ? JSON.parse(row.attributes) : undefined,
|
|
340
|
+
}));
|
|
396
341
|
}
|
|
397
342
|
catch (error) {
|
|
398
|
-
this.logger.
|
|
343
|
+
this.logger.error(`Failed to get spans for task ${taskId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
399
344
|
return [];
|
|
400
345
|
}
|
|
401
346
|
}
|
|
402
|
-
|
|
403
|
-
if (!
|
|
404
|
-
return
|
|
347
|
+
getSpan(spanId) {
|
|
348
|
+
if (!this.db) {
|
|
349
|
+
return null;
|
|
405
350
|
}
|
|
406
351
|
try {
|
|
407
|
-
const
|
|
408
|
-
const
|
|
409
|
-
if (
|
|
410
|
-
|
|
411
|
-
params.push(options.agentId);
|
|
412
|
-
}
|
|
413
|
-
if (options.since) {
|
|
414
|
-
conditions.push('start_time >= ?');
|
|
415
|
-
params.push(options.since);
|
|
352
|
+
const stmt = this.db.prepare('SELECT * FROM spans WHERE id = ?');
|
|
353
|
+
const row = stmt.get(spanId);
|
|
354
|
+
if (!row) {
|
|
355
|
+
return null;
|
|
416
356
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
SELECT status, COUNT(*) as count
|
|
422
|
-
FROM traces ${whereClause}
|
|
423
|
-
GROUP BY status
|
|
424
|
-
`);
|
|
425
|
-
const statusRows = statusStmt.all(...params);
|
|
426
|
-
const byStatus = statusRows.reduce((acc, row) => {
|
|
427
|
-
acc[row.status] = row.count;
|
|
428
|
-
return acc;
|
|
429
|
-
}, {});
|
|
430
|
-
const durationWhereClause = conditions.length > 0
|
|
431
|
-
? `${whereClause} AND end_time IS NOT NULL`
|
|
432
|
-
: 'WHERE end_time IS NOT NULL';
|
|
433
|
-
const avgStmt = this.db.prepare(`
|
|
434
|
-
SELECT AVG(end_time - start_time) as avg_duration
|
|
435
|
-
FROM traces ${durationWhereClause}
|
|
436
|
-
`);
|
|
437
|
-
const avgDuration = avgStmt.get(...params)?.avg_duration || 0;
|
|
438
|
-
return { total, byStatus, avgDuration };
|
|
357
|
+
return {
|
|
358
|
+
...row,
|
|
359
|
+
attributes: row.attributes ? JSON.parse(row.attributes) : undefined,
|
|
360
|
+
};
|
|
439
361
|
}
|
|
440
362
|
catch (error) {
|
|
441
|
-
this.logger.error(`Failed to get
|
|
442
|
-
return
|
|
363
|
+
this.logger.error(`Failed to get span ${spanId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
364
|
+
return null;
|
|
443
365
|
}
|
|
444
366
|
}
|
|
445
|
-
|
|
446
|
-
if (!
|
|
367
|
+
cleanupOldTasks(daysToKeep = 30) {
|
|
368
|
+
if (!this.db) {
|
|
447
369
|
return 0;
|
|
448
370
|
}
|
|
449
371
|
try {
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
const
|
|
453
|
-
|
|
454
|
-
|
|
372
|
+
const cutoffDate = new Date();
|
|
373
|
+
cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);
|
|
374
|
+
const cutoff = cutoffDate.toISOString();
|
|
375
|
+
const stmt = this.db.prepare('DELETE FROM tasks WHERE started_at < ?');
|
|
376
|
+
const info = stmt.run(cutoff);
|
|
377
|
+
if (info.changes > 0) {
|
|
378
|
+
this.logger.log(`Cleaned up ${info.changes} old tasks`);
|
|
455
379
|
}
|
|
456
|
-
return
|
|
380
|
+
return info.changes;
|
|
457
381
|
}
|
|
458
382
|
catch (error) {
|
|
459
|
-
this.logger.error(`Failed to
|
|
383
|
+
this.logger.error(`Failed to cleanup old tasks: ${error instanceof Error ? error.message : String(error)}`);
|
|
460
384
|
return 0;
|
|
461
385
|
}
|
|
462
386
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
name: row.name,
|
|
467
|
-
agentId: row.agent_id || undefined,
|
|
468
|
-
sessionId: row.session_id || undefined,
|
|
469
|
-
startTime: row.start_time,
|
|
470
|
-
endTime: row.end_time || undefined,
|
|
471
|
-
status: row.status,
|
|
472
|
-
attributes: row.attributes ? JSON.parse(row.attributes) : undefined,
|
|
473
|
-
metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
|
|
474
|
-
};
|
|
475
|
-
if (spanRows && spanRows.length > 0) {
|
|
476
|
-
trace.spans = spanRows.map((spanRow) => ({
|
|
477
|
-
id: spanRow.id,
|
|
478
|
-
traceId: spanRow.trace_id,
|
|
479
|
-
name: spanRow.name,
|
|
480
|
-
parentSpanId: spanRow.parent_span_id || undefined,
|
|
481
|
-
startTime: spanRow.start_time,
|
|
482
|
-
endTime: spanRow.end_time || undefined,
|
|
483
|
-
status: spanRow.status,
|
|
484
|
-
attributes: spanRow.attributes ? JSON.parse(spanRow.attributes) : undefined,
|
|
485
|
-
events: spanRow.events ? JSON.parse(spanRow.events) : undefined,
|
|
486
|
-
}));
|
|
387
|
+
getStats() {
|
|
388
|
+
if (!this.db) {
|
|
389
|
+
return null;
|
|
487
390
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
this.logger.log('Tracing database connection closed');
|
|
498
|
-
}
|
|
499
|
-
catch (error) {
|
|
500
|
-
this.logger.warn(`Error closing database: ${error instanceof Error ? error.message : String(error)}`);
|
|
391
|
+
try {
|
|
392
|
+
const taskCountStmt = this.db.prepare('SELECT COUNT(*) as count FROM tasks');
|
|
393
|
+
const spanCountStmt = this.db.prepare('SELECT COUNT(*) as count FROM spans');
|
|
394
|
+
const taskCount = taskCountStmt.get().count;
|
|
395
|
+
const spanCount = spanCountStmt.get().count;
|
|
396
|
+
let dbSizeBytes = 0;
|
|
397
|
+
if (fs.existsSync(this.dbPath)) {
|
|
398
|
+
const stats = fs.statSync(this.dbPath);
|
|
399
|
+
dbSizeBytes = stats.size;
|
|
501
400
|
}
|
|
401
|
+
return { taskCount, spanCount, dbSizeBytes };
|
|
502
402
|
}
|
|
403
|
+
catch (error) {
|
|
404
|
+
this.logger.error(`Failed to get stats: ${error instanceof Error ? error.message : String(error)}`);
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
isEnabled() {
|
|
409
|
+
return this.db !== null;
|
|
410
|
+
}
|
|
411
|
+
getDbPath() {
|
|
412
|
+
return this.dbPath;
|
|
503
413
|
}
|
|
504
414
|
};
|
|
505
415
|
exports.TracingService = TracingService;
|
|
506
416
|
exports.TracingService = TracingService = TracingService_1 = __decorate([
|
|
507
417
|
(0, common_1.Injectable)(),
|
|
508
|
-
|
|
418
|
+
__param(0, (0, common_1.Optional)()),
|
|
419
|
+
__param(0, (0, common_1.Inject)('TRACING_OPTIONS')),
|
|
420
|
+
__metadata("design:paramtypes", [Object])
|
|
509
421
|
], TracingService);
|
|
510
422
|
//# sourceMappingURL=tracing.service.js.map
|