@musnows/scriverse 0.5.0 → 0.5.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.
package/dist/ai.js CHANGED
@@ -33,6 +33,66 @@ function thinkingParameters(provider, model) {
33
33
  return { thinking: { type: boolValue(model, "thinking_enabled") ? "enabled" : "disabled" } };
34
34
  }
35
35
  const AGENT_TOOL_IDS = ["story_index", "read_chapters", "grep", "search_story_entities", "read_character_sections"];
36
+ const TASK_TRACE_PREVIEW_CHARACTER_LIMIT = 3_000;
37
+ function traceRecord(value) {
38
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
39
+ }
40
+ function previewTaskTraceMessages(messages) {
41
+ const records = messages.map(traceRecord);
42
+ const contents = records.map((message) => message.content === null ? "" : String(message.content ?? ""));
43
+ const allocations = contents.map(() => 0);
44
+ let remaining = TASK_TRACE_PREVIEW_CHARACTER_LIMIT;
45
+ let active = contents.map((_, index) => index).filter((index) => contents[index].length > 0);
46
+ while (remaining > 0 && active.length > 0) {
47
+ const share = Math.max(1, Math.floor(remaining / active.length));
48
+ const next = [];
49
+ for (const index of active) {
50
+ if (remaining <= 0)
51
+ break;
52
+ const available = contents[index].length - allocations[index];
53
+ const granted = Math.min(available, share, remaining);
54
+ allocations[index] = allocations[index] + granted;
55
+ remaining -= granted;
56
+ if (allocations[index] < contents[index].length)
57
+ next.push(index);
58
+ }
59
+ active = next;
60
+ }
61
+ return {
62
+ messages: records.map((message, index) => {
63
+ const content = contents[index];
64
+ const toolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : [];
65
+ return {
66
+ role: typeof message.role === "string" ? message.role : "user",
67
+ content: content.slice(0, allocations[index]),
68
+ contentChars: content.length,
69
+ contentTruncated: allocations[index] < content.length,
70
+ toolCallCount: toolCalls.length,
71
+ ...(typeof message.tool_call_id === "string" ? { tool_call_id: message.tool_call_id } : {})
72
+ };
73
+ }),
74
+ totalChars: contents.reduce((total, content) => total + content.length, 0),
75
+ truncated: contents.some((content, index) => allocations[index] < content.length)
76
+ };
77
+ }
78
+ function summarizeTaskTraceRound(value) {
79
+ const round = traceRecord(value);
80
+ const request = traceRecord(round.request);
81
+ const messages = Array.isArray(request.messages) ? request.messages : [];
82
+ const attempts = Array.isArray(round.attempts) ? round.attempts : [];
83
+ const toolExecutions = Array.isArray(round.toolExecutions) ? round.toolExecutions : [];
84
+ return {
85
+ round: typeof round.round === "number" ? round.round : 1,
86
+ requestedAt: typeof round.requestedAt === "string" ? round.requestedAt : "",
87
+ messageCount: messages.length,
88
+ promptChars: messages.reduce((total, message) => {
89
+ const content = traceRecord(message).content;
90
+ return total + (content === null ? 0 : String(content ?? "").length);
91
+ }, 0),
92
+ attemptCount: attempts.length,
93
+ toolExecutionCount: toolExecutions.length
94
+ };
95
+ }
36
96
  function redactProviderSecret(value, apiKey) {
37
97
  if (!apiKey)
38
98
  return value;
@@ -1313,8 +1373,12 @@ export class AiManager {
1313
1373
  }
1314
1374
  getTaskTrace(taskId) {
1315
1375
  this.store.getTask(taskId);
1316
- const rows = this.store.db.all(`SELECT call.*, trace.initial_messages_json, trace.rounds_json, trace.created_at AS trace_created_at,
1317
- trace.updated_at AS trace_updated_at, provider.name AS provider_name,
1376
+ const rows = this.store.db.all(`SELECT call.id, call.task_type, call.provider_id, call.model_id, call.status, call.failure,
1377
+ call.input_chars, call.output_chars, call.created_at, call.completed_at, trace.call_id AS trace_call_id,
1378
+ CASE WHEN trace.call_id IS NULL THEN 0 ELSE json_array_length(trace.initial_messages_json) END AS initial_message_count,
1379
+ CASE WHEN trace.call_id IS NULL THEN 0 ELSE json_array_length(trace.rounds_json) END AS round_count,
1380
+ CASE WHEN trace.call_id IS NULL THEN 0 ELSE length(trace.initial_messages_json) + length(trace.rounds_json) END AS trace_chars,
1381
+ trace.created_at AS trace_created_at, trace.updated_at AS trace_updated_at, provider.name AS provider_name,
1318
1382
  model.display_name AS model_display_name, model.model_id AS external_model_id
1319
1383
  FROM ai_calls call
1320
1384
  LEFT JOIN ai_call_traces trace ON trace.call_id = call.id
@@ -1323,7 +1387,8 @@ export class AiManager {
1323
1387
  WHERE call.task_id = ?
1324
1388
  ORDER BY call.created_at ASC, call.id ASC`, taskId);
1325
1389
  const calls = rows.map((row) => {
1326
- const hasTrace = row.initial_messages_json !== null && row.initial_messages_json !== undefined;
1390
+ const hasTrace = row.trace_call_id !== null && row.trace_call_id !== undefined;
1391
+ const failure = row.failure === null ? null : stringValue(row, "failure");
1327
1392
  return {
1328
1393
  id: stringValue(row, "id"),
1329
1394
  taskType: stringValue(row, "task_type"),
@@ -1338,17 +1403,18 @@ export class AiManager {
1338
1403
  modelId: row.external_model_id === null ? null : stringValue(row, "external_model_id"),
1339
1404
  deleted: row.model_display_name === null
1340
1405
  },
1341
- contextScope: json(stringValue(row, "context_scope_json"), {}),
1342
- parameters: json(stringValue(row, "parameters_json"), {}),
1343
1406
  status: stringValue(row, "status"),
1344
- failure: row.failure === null ? null : stringValue(row, "failure"),
1407
+ failure: failure === null ? null : failure.slice(0, 1_000),
1408
+ failureTruncated: failure !== null && failure.length > 1_000,
1345
1409
  inputChars: numberValue(row, "input_chars"),
1346
1410
  outputChars: numberValue(row, "output_chars"),
1347
1411
  createdAt: stringValue(row, "created_at"),
1348
1412
  completedAt: row.completed_at === null ? null : stringValue(row, "completed_at"),
1349
1413
  trace: hasTrace ? {
1350
- initialMessages: json(stringValue(row, "initial_messages_json"), []),
1351
- rounds: json(stringValue(row, "rounds_json"), []),
1414
+ available: true,
1415
+ initialMessageCount: numberValue(row, "initial_message_count"),
1416
+ roundCount: numberValue(row, "round_count"),
1417
+ serializedChars: numberValue(row, "trace_chars"),
1352
1418
  createdAt: stringValue(row, "trace_created_at"),
1353
1419
  updatedAt: stringValue(row, "trace_updated_at")
1354
1420
  } : null
@@ -1360,6 +1426,44 @@ export class AiManager {
1360
1426
  calls
1361
1427
  };
1362
1428
  }
1429
+ getTaskTraceCall(taskId, callId, full = false) {
1430
+ this.store.getTask(taskId);
1431
+ const row = this.store.db.get(`SELECT trace.initial_messages_json, trace.rounds_json, trace.created_at, trace.updated_at
1432
+ FROM ai_calls call JOIN ai_call_traces trace ON trace.call_id = call.id AND trace.task_id = call.task_id
1433
+ WHERE call.id = ? AND call.task_id = ?`, callId, taskId);
1434
+ if (!row)
1435
+ throw notFound("AI 调用追踪");
1436
+ const initialMessages = json(stringValue(row, "initial_messages_json"), []);
1437
+ const rounds = json(stringValue(row, "rounds_json"), []);
1438
+ if (full) {
1439
+ return {
1440
+ taskId,
1441
+ callId,
1442
+ mode: "full",
1443
+ trace: {
1444
+ initialMessages,
1445
+ rounds,
1446
+ createdAt: stringValue(row, "created_at"),
1447
+ updatedAt: stringValue(row, "updated_at")
1448
+ }
1449
+ };
1450
+ }
1451
+ const preview = previewTaskTraceMessages(initialMessages);
1452
+ return {
1453
+ taskId,
1454
+ callId,
1455
+ mode: "preview",
1456
+ previewLimit: TASK_TRACE_PREVIEW_CHARACTER_LIMIT,
1457
+ truncated: preview.truncated,
1458
+ totalPromptChars: preview.totalChars,
1459
+ trace: {
1460
+ initialMessages: preview.messages,
1461
+ rounds: rounds.map(summarizeTaskTraceRound),
1462
+ createdAt: stringValue(row, "created_at"),
1463
+ updatedAt: stringValue(row, "updated_at")
1464
+ }
1465
+ };
1466
+ }
1363
1467
  async runTask(taskId, modelId) {
1364
1468
  const task = this.store.getTask(taskId);
1365
1469
  const workId = String(task.workId);