oasis_test_v2 2.2.125 → 2.2.127

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.
Files changed (2) hide show
  1. package/dist/index.js +792 -668
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1778,6 +1778,14 @@ var init_overlap = __esm({
1778
1778
  "\u4E4B\u540E",
1779
1779
  "\u4EE5\u524D",
1780
1780
  "\u622A\u6B62",
1781
+ // 任务书里的套话(v2 实测:两份毫不相干的委派因为都写了「交付一个 Markdown 文件 outputs/…」被比成相近)。
1782
+ "\u4EA4\u4ED8",
1783
+ "\u6587\u4EF6",
1784
+ "\u80CC\u666F",
1785
+ "\u7528\u6237",
1786
+ "\u660E\u786E",
1787
+ "\u64B0\u5199",
1788
+ "\u72EC\u7ACB",
1781
1789
  "the",
1782
1790
  "and",
1783
1791
  "for",
@@ -1787,7 +1795,10 @@ var init_overlap = __esm({
1787
1795
  "that",
1788
1796
  "into",
1789
1797
  "todo",
1790
- "task"
1798
+ "task",
1799
+ "markdown",
1800
+ "outputs",
1801
+ "md"
1791
1802
  ]);
1792
1803
  isCjk = (ch) => /[㐀-鿿豈-﫿]/u.test(ch);
1793
1804
  COVER_MIN_SHARED = 3;
@@ -237390,6 +237401,16 @@ async function listSkillMetadataForActor(args) {
237390
237401
  }
237391
237402
  return out;
237392
237403
  }
237404
+ async function skillManifestForActor(args) {
237405
+ const enabledConnectors = args.connectorSkills.length > 0 ? await args.service.effectiveEnabledConnectors(args.actorId) : /* @__PURE__ */ new Set();
237406
+ return listSkillMetadataForActor({
237407
+ service: args.service,
237408
+ actorId: args.actorId,
237409
+ builtins: args.builtins,
237410
+ connectorSkills: args.connectorSkills,
237411
+ enabledConnectors
237412
+ });
237413
+ }
237393
237414
  function builtinSkillToFiles(b6) {
237394
237415
  return Object.entries(b6.files ?? {}).map(([path50, content3]) => ({
237395
237416
  skillId: `builtin:${b6.id}`,
@@ -238897,14 +238918,11 @@ function actorsDomain(opts) {
238897
238918
  const { service } = await resolveCtx(req.auth.companyId);
238898
238919
  const claim = req.auth.dispatch?.chatSessionId ? { chatSessionId: req.auth.dispatch.chatSessionId, companyId: req.auth.companyId } : void 0;
238899
238920
  const builtins = await opts.getBuiltinSkills?.(claim) ?? [];
238900
- const connectorSkills = opts.getConnectorSkills?.() ?? [];
238901
- const enabledConnectors = connectorSkills.length > 0 ? await service.effectiveEnabledConnectors(req.auth.actor) : /* @__PURE__ */ new Set();
238902
- const items = await listSkillMetadataForActor({
238921
+ const items = await skillManifestForActor({
238903
238922
  service,
238904
238923
  actorId: req.auth.actor,
238905
238924
  builtins,
238906
- connectorSkills,
238907
- enabledConnectors
238925
+ connectorSkills: opts.getConnectorSkills?.() ?? []
238908
238926
  });
238909
238927
  return { status: 200, body: { items } };
238910
238928
  });
@@ -255147,6 +255165,562 @@ var init_renderer = __esm({
255147
255165
  }
255148
255166
  });
255149
255167
 
255168
+ // ../server/src/domains/trace/unit-data.ts
255169
+ function keysetBefore(timeExpr, idExpr, before, push2) {
255170
+ return `(date_trunc('milliseconds', ${timeExpr}), ${idExpr}) < (${push2(before.at)}::timestamptz, ${push2(before.id)})`;
255171
+ }
255172
+ function quoteSchema(name) {
255173
+ if (!/^[A-Za-z0-9_][A-Za-z0-9_.-]*$/.test(name)) throw new Error(`invalid schema name: ${name}`);
255174
+ return `"${name}"`;
255175
+ }
255176
+ function dispatchSchemaIdent(name) {
255177
+ const s3 = name.replace(/[^a-zA-Z0-9_]/g, "");
255178
+ if (!s3) throw new Error(`invalid dispatch schema name: ${name}`);
255179
+ return `"${s3}"`;
255180
+ }
255181
+ function replyIssueIdFromWorkId(workId) {
255182
+ const m4 = /^wk:reply:(.+):\d+$/.exec(workId);
255183
+ return m4 ? m4[1] : null;
255184
+ }
255185
+ function toWork(r5) {
255186
+ return {
255187
+ id: String(r5["id"]),
255188
+ workorderId: String(r5["workorder_id"]),
255189
+ nodeId: String(r5["node_id"]),
255190
+ nodeType: str5(r5["node_type"]),
255191
+ nodeTitle: str5(r5["node_title"]),
255192
+ assigneeActorId: String(r5["assignee_actor_id"]),
255193
+ createdAt: isoReq(r5["created_at"]),
255194
+ startedAt: iso4(r5["started_at"]),
255195
+ endedAt: iso4(r5["ended_at"]),
255196
+ deadAt: iso4(r5["dead_at"]),
255197
+ status: str5(r5["status"]),
255198
+ outcome: str5(r5["outcome"]),
255199
+ // 存量 lane 为空时按 work id 前缀兜底(回信轮 id 恒为 `wk:reply:<issueId>:<n>`)。
255200
+ lane: r5["lane"] === "reply" || r5["lane"] == null && String(r5["id"]).startsWith("wk:reply:") ? "reply" : "main",
255201
+ replyIssueId: replyIssueIdFromWorkId(String(r5["id"])),
255202
+ continuesWorkId: str5(r5["continues_work_id"]),
255203
+ acceptanceState: str5(r5["acceptance_state"]) ?? null,
255204
+ acceptedAt: iso4(r5["accepted_at"]),
255205
+ rejectedReason: str5(r5["rejected_reason"]),
255206
+ overrideBy: str5(r5["override_by"]),
255207
+ overrideReason: str5(r5["override_reason"]),
255208
+ frozenIssueIds: strArr(r5["frozen_issue_ids"]),
255209
+ protocolRecovery: r5["protocol_recovery"] ?? null,
255210
+ killSource: str5(r5["kill_source"]),
255211
+ outputVersionNo: num3(r5["output_version_no"])
255212
+ };
255213
+ }
255214
+ function toReview(r5) {
255215
+ const verdict = str5(r5["verdict"]);
255216
+ let status = str5(r5["status"]);
255217
+ if (!status) {
255218
+ if (r5["retry_at"] != null) status = "retry";
255219
+ else if (r5["cancelled_at"] != null) status = "dead";
255220
+ else if (verdict === "approve" && r5["decided_at"] != null) status = "accept";
255221
+ else if (verdict === "request_changes" && r5["decided_at"] != null) status = "reject";
255222
+ else if (r5["ended_at"] != null) status = verdict ? verdict === "approve" ? "accept" : "reject" : "failed";
255223
+ else status = "running";
255224
+ }
255225
+ return {
255226
+ id: String(r5["id"]),
255227
+ workorderId: String(r5["workorder_id"]),
255228
+ nodeId: String(r5["node_id"]),
255229
+ nodeTitle: str5(r5["node_title"]),
255230
+ targetWorkId: String(r5["target_work_id"]),
255231
+ reviewerActorId: String(r5["reviewer_actor_id"]),
255232
+ reviewGroup: String(r5["review_group"] ?? ""),
255233
+ status,
255234
+ verdict: verdict ?? null,
255235
+ note: str5(r5["note"]),
255236
+ createdAt: isoReq(r5["created_at"]),
255237
+ startedAt: iso4(r5["started_at"]),
255238
+ endedAt: iso4(r5["ended_at"]),
255239
+ decidedAt: iso4(r5["decided_at"]),
255240
+ cancelledAt: iso4(r5["cancelled_at"]),
255241
+ killSource: str5(r5["kill_source"])
255242
+ };
255243
+ }
255244
+ function toIssue(r5) {
255245
+ return {
255246
+ id: String(r5["id"]),
255247
+ workorderId: String(r5["workorder_id"]),
255248
+ kind: String(r5["kind"]),
255249
+ body: String(r5["body"] ?? ""),
255250
+ aboutNodeId: str5(r5["about_node_id"]),
255251
+ aboutWorkId: str5(r5["about_work_id"]),
255252
+ raisedByNodeId: str5(r5["raised_by_node_id"]),
255253
+ authorActorId: String(r5["author_actor_id"]),
255254
+ resolvedAt: iso4(r5["resolved_at"]),
255255
+ createdAt: isoReq(r5["created_at"])
255256
+ };
255257
+ }
255258
+ function toDispatch(r5) {
255259
+ return {
255260
+ id: String(r5["id"]),
255261
+ targetKind: String(r5["target_kind"]),
255262
+ targetId: String(r5["target_id"]),
255263
+ actorId: str5(r5["actor_id"]),
255264
+ createdAt: isoReq(r5["created_at"]),
255265
+ startedAt: iso4(r5["started_at"]),
255266
+ endedAt: iso4(r5["ended_at"]),
255267
+ outcome: str5(r5["outcome"]),
255268
+ reason: str5(r5["reason"]),
255269
+ protocolRecoveryRound: num3(r5["protocol_recovery_round"])
255270
+ };
255271
+ }
255272
+ function toDelegation(r5) {
255273
+ return {
255274
+ id: String(r5["id"]),
255275
+ parentSessionId: String(r5["parent_session_id"]),
255276
+ parentMessageId: String(r5["parent_message_id"] ?? ""),
255277
+ childSessionId: String(r5["child_session_id"]),
255278
+ expertActorId: String(r5["expert_actor_id"]),
255279
+ state: String(r5["state"]),
255280
+ failureKind: str5(r5["failure_kind"]),
255281
+ failureReason: str5(r5["failure_reason"]),
255282
+ consecutiveFails: num3(r5["consecutive_fails"]) ?? 0,
255283
+ dispatchSeq: num3(r5["dispatch_seq"]),
255284
+ createdAt: isoReq(r5["created_at"]),
255285
+ settledAt: iso4(r5["settled_at"]),
255286
+ label: str5(r5["label"]),
255287
+ taskDigest: str5(r5["task_digest"])
255288
+ };
255289
+ }
255290
+ function toSession(r5) {
255291
+ return {
255292
+ id: String(r5["id"]),
255293
+ humanActorId: String(r5["human_actor_id"]),
255294
+ aiActorId: String(r5["ai_actor_id"]),
255295
+ title: str5(r5["title"]),
255296
+ analyzedRunId: str5(r5["analyzed_run_id"]),
255297
+ runtimeSessionId: str5(r5["runtime_session_id"]),
255298
+ touchedAt: isoReq(r5["touched_at"]),
255299
+ createdAt: isoReq(r5["created_at"])
255300
+ };
255301
+ }
255302
+ function toTurn(r5) {
255303
+ return {
255304
+ id: String(r5["id"]),
255305
+ chatSessionId: String(r5["chat_session_id"]),
255306
+ source: String(r5["source"]),
255307
+ status: String(r5["status"]),
255308
+ reservedAt: isoReq(r5["reserved_at"]),
255309
+ startedAt: iso4(r5["started_at"]),
255310
+ completedAt: iso4(r5["completed_at"]),
255311
+ cancelledBy: str5(r5["cancelled_by"]),
255312
+ dispatchId: str5(r5["dispatch_id"]),
255313
+ assistantRunId: str5(r5["assistant_run_id"])
255314
+ };
255315
+ }
255316
+ function toMessage(r5) {
255317
+ return {
255318
+ id: String(r5["id"]),
255319
+ sessionId: String(r5["session_id"]),
255320
+ role: String(r5["role"]),
255321
+ content: String(r5["content"] ?? ""),
255322
+ seq: Number(r5["seq"]),
255323
+ createdAt: isoReq(r5["created_at"]),
255324
+ runId: str5(r5["run_id"]),
255325
+ turnId: str5(r5["turn_id"]),
255326
+ source: str5(r5["source"])
255327
+ };
255328
+ }
255329
+ function toLink(r5) {
255330
+ return { sessionId: String(r5["session_id"]), workOrderId: String(r5["work_order_id"]), linkedAt: isoReq(r5["linked_at"]) };
255331
+ }
255332
+ var unitListKey, iso4, isoReq, str5, num3, strArr, WORK_COLS, REVIEW_COLS, MAX_IDS, capIds, PgUnitDataSource;
255333
+ var init_unit_data = __esm({
255334
+ "../server/src/domains/trace/unit-data.ts"() {
255335
+ "use strict";
255336
+ unitListKey = {
255337
+ work: (w2) => ({ at: w2.endedAt ?? w2.deadAt, id: w2.id }),
255338
+ review: (r5) => ({ at: r5.endedAt ?? r5.decidedAt ?? r5.cancelledAt ?? r5.createdAt, id: r5.id }),
255339
+ delegation: (d5) => ({ at: d5.settledAt ?? d5.createdAt, id: d5.id }),
255340
+ session: (s3) => ({ at: s3.touchedAt, id: s3.id })
255341
+ };
255342
+ iso4 = (v2) => v2 == null ? null : v2 instanceof Date ? v2.toISOString() : typeof v2 === "string" ? new Date(v2).toISOString() : null;
255343
+ isoReq = (v2) => iso4(v2) ?? (/* @__PURE__ */ new Date(0)).toISOString();
255344
+ str5 = (v2) => typeof v2 === "string" ? v2 : v2 == null ? null : String(v2);
255345
+ num3 = (v2) => v2 == null ? null : Number.isFinite(Number(v2)) ? Number(v2) : null;
255346
+ strArr = (v2) => Array.isArray(v2) ? v2.filter((x2) => typeof x2 === "string") : [];
255347
+ WORK_COLS = `w.id, w.workorder_id, w.node_id, n.type AS node_type, n.title AS node_title, w.assignee_actor_id,
255348
+ w.created_at, w.started_at, w.ended_at, w.dead_at, w.status, w.outcome, w.lane, w.continues_work_id,
255349
+ w.acceptance_state, w.accepted_at, w.rejected_reason, w.override_by, w.override_reason, w.frozen_issue_ids,
255350
+ w.protocol_recovery, w.kill_source, w.output_version_no`;
255351
+ REVIEW_COLS = `r.id, r.workorder_id, r.node_id, n.title AS node_title, r.target_work_id, r.reviewer_actor_id, r.review_group,
255352
+ r.status, r.verdict, r.note, r.created_at, r.started_at, r.ended_at, r.decided_at, r.cancelled_at, r.retry_at, r.kill_source`;
255353
+ MAX_IDS = 500;
255354
+ capIds = (ids2) => [...new Set(ids2)].slice(0, MAX_IDS);
255355
+ PgUnitDataSource = class {
255356
+ pool;
255357
+ /** 引擎 schema(works / reviews / issues / events / workflow_*)。 */
255358
+ e;
255359
+ /** chat 一族(chat_sessions / chat_messages / chat_session_turns / 委派);缺省与引擎同 schema。 */
255360
+ c;
255361
+ /** 派发台账 schema(按 dispatches store 的口径净化)。 */
255362
+ d;
255363
+ constructor(opts) {
255364
+ this.pool = opts.pool;
255365
+ this.e = quoteSchema(opts.engineSchema);
255366
+ this.c = quoteSchema(opts.chatSchema ?? opts.engineSchema);
255367
+ this.d = dispatchSchemaIdent(opts.dispatchSchema);
255368
+ }
255369
+ async q(text7, values = []) {
255370
+ return (await this.pool.query(text7, values)).rows;
255371
+ }
255372
+ /* ── work / review ── */
255373
+ async getWorks(ids2) {
255374
+ if (ids2.length === 0) return [];
255375
+ const rows = await this.q(
255376
+ `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id WHERE w.id = ANY($1)`,
255377
+ [capIds(ids2)]
255378
+ );
255379
+ return rows.map(toWork);
255380
+ }
255381
+ async getReview(id) {
255382
+ const rows = await this.q(
255383
+ `SELECT ${REVIEW_COLS} FROM ${this.e}.reviews r LEFT JOIN ${this.e}.workflow_nodes n ON n.id = r.node_id WHERE r.id = $1`,
255384
+ [id]
255385
+ );
255386
+ return rows[0] ? toReview(rows[0]) : null;
255387
+ }
255388
+ async reviewsOfWorks(workIds) {
255389
+ if (workIds.length === 0) return [];
255390
+ const rows = await this.q(
255391
+ `SELECT ${REVIEW_COLS} FROM ${this.e}.reviews r LEFT JOIN ${this.e}.workflow_nodes n ON n.id = r.node_id
255392
+ WHERE r.target_work_id = ANY($1) ORDER BY r.created_at ASC, r.id ASC LIMIT 500`,
255393
+ [capIds(workIds)]
255394
+ );
255395
+ return rows.map(toReview);
255396
+ }
255397
+ async worksOfNode(nodeId, limit) {
255398
+ const rows = await this.q(
255399
+ `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
255400
+ WHERE w.node_id = $1 ORDER BY w.created_at DESC, w.id DESC LIMIT $2`,
255401
+ [nodeId, limit]
255402
+ );
255403
+ return rows.map(toWork);
255404
+ }
255405
+ async workInputsOf(workIds) {
255406
+ if (workIds.length === 0) return [];
255407
+ const rows = await this.q(
255408
+ `SELECT work_id, upstream_node_id, upstream_work_id FROM ${this.e}.work_inputs WHERE work_id = ANY($1) LIMIT 2000`,
255409
+ [capIds(workIds)]
255410
+ );
255411
+ return rows.map((r5) => ({
255412
+ workId: String(r5["work_id"]),
255413
+ upstreamNodeId: String(r5["upstream_node_id"]),
255414
+ upstreamWorkId: String(r5["upstream_work_id"])
255415
+ }));
255416
+ }
255417
+ async inputNodesOf(nodeId) {
255418
+ const rows = await this.q(
255419
+ `SELECT from_node_id FROM ${this.e}.workflow_edges WHERE to_node_id = $1 AND kind = 'data' ORDER BY from_node_id LIMIT 100`,
255420
+ [nodeId]
255421
+ );
255422
+ return rows.map((r5) => String(r5["from_node_id"]));
255423
+ }
255424
+ async outputNodesOf(nodeId) {
255425
+ const rows = await this.q(
255426
+ `SELECT to_node_id FROM ${this.e}.workflow_edges WHERE from_node_id = $1 AND kind = 'data' ORDER BY to_node_id LIMIT 100`,
255427
+ [nodeId]
255428
+ );
255429
+ return rows.map((r5) => String(r5["to_node_id"]));
255430
+ }
255431
+ async latestAcceptedWorkOfNodeBefore(nodeId, beforeIso) {
255432
+ const rows = await this.q(
255433
+ `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
255434
+ WHERE w.node_id = $1 AND w.acceptance_state = 'accepted' AND w.accepted_at IS NOT NULL AND w.accepted_at <= $2
255435
+ ORDER BY w.accepted_at DESC, w.id DESC LIMIT 1`,
255436
+ [nodeId, beforeIso]
255437
+ );
255438
+ return rows[0] ? toWork(rows[0]) : null;
255439
+ }
255440
+ async worksAcceptedInWindow(nodeIds, fromIso, toIso2, limit) {
255441
+ if (nodeIds.length === 0) return [];
255442
+ const rows = await this.q(
255443
+ `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
255444
+ WHERE w.node_id = ANY($1) AND w.acceptance_state = 'accepted' AND w.accepted_at >= $2 AND w.accepted_at <= $3
255445
+ ORDER BY w.accepted_at ASC, w.id ASC LIMIT $4`,
255446
+ [capIds(nodeIds), fromIso, toIso2, limit]
255447
+ );
255448
+ return rows.map(toWork);
255449
+ }
255450
+ async reworkSourcesOf(work) {
255451
+ const rows = await this.q(
255452
+ `SELECT DISTINCT x.reason->>'workId' AS src
255453
+ FROM (SELECT payload FROM ${this.e}.events
255454
+ WHERE node_id = $1 AND kind = 'work.create' AND payload->>'workId' = $2
255455
+ ORDER BY seq DESC LIMIT 20) ev,
255456
+ LATERAL jsonb_array_elements(COALESCE(ev.payload->'reasons', '[]'::jsonb)) AS x(reason)
255457
+ WHERE x.reason->>'kind' = 'rework' AND x.reason->>'workId' IS NOT NULL`,
255458
+ [work.nodeId, work.id]
255459
+ );
255460
+ return rows.map((r5) => String(r5["src"]));
255461
+ }
255462
+ async reworkedBy(work) {
255463
+ const viaCol = await this.q(
255464
+ `SELECT id FROM ${this.e}.works WHERE node_id = $1 AND continues_work_id = $2 AND id <> $2 ORDER BY created_at ASC LIMIT 50`,
255465
+ [work.nodeId, work.id]
255466
+ );
255467
+ const viaEvents = await this.q(
255468
+ `SELECT DISTINCT ev.payload->>'workId' AS wid
255469
+ FROM (SELECT payload FROM ${this.e}.events WHERE node_id = $1 AND kind = 'work.create' ORDER BY seq DESC LIMIT 200) ev,
255470
+ LATERAL jsonb_array_elements(COALESCE(ev.payload->'reasons', '[]'::jsonb)) AS x(reason)
255471
+ WHERE x.reason->>'kind' = 'rework' AND x.reason->>'workId' = $2`,
255472
+ [work.nodeId, work.id]
255473
+ );
255474
+ const out = /* @__PURE__ */ new Set();
255475
+ for (const r5 of viaCol) out.add(String(r5["id"]));
255476
+ for (const r5 of viaEvents) if (r5["wid"] != null && r5["wid"] !== work.id) out.add(String(r5["wid"]));
255477
+ return [...out];
255478
+ }
255479
+ async briefNodesOf(workorderId) {
255480
+ const rows = await this.q(
255481
+ `SELECT id FROM ${this.e}.workflow_nodes WHERE workorder_id = $1 AND type = 'brief' ORDER BY created_at ASC LIMIT 10`,
255482
+ [workorderId]
255483
+ );
255484
+ return rows.map((r5) => String(r5["id"]));
255485
+ }
255486
+ /* ── issue ── */
255487
+ async issuesByIds(ids2) {
255488
+ if (ids2.length === 0) return [];
255489
+ const rows = await this.q(`SELECT * FROM ${this.e}.issues WHERE id = ANY($1)`, [capIds(ids2)]);
255490
+ return rows.map(toIssue);
255491
+ }
255492
+ async issuesInWorkorder(workorderId, q4) {
255493
+ const args = [workorderId];
255494
+ const conds = ["workorder_id = $1"];
255495
+ const ors = [];
255496
+ const push2 = (v2) => {
255497
+ args.push(v2);
255498
+ return `$${args.length}`;
255499
+ };
255500
+ if (q4.aboutWorkIds?.length) ors.push(`about_work_id = ANY(${push2(capIds(q4.aboutWorkIds))})`);
255501
+ if (q4.aboutNodeIds?.length) ors.push(`about_node_id = ANY(${push2(capIds(q4.aboutNodeIds))})`);
255502
+ if (q4.raisedByNodeIds?.length) ors.push(`raised_by_node_id = ANY(${push2(capIds(q4.raisedByNodeIds))})`);
255503
+ if (ors.length) conds.push(`(${ors.join(" OR ")})`);
255504
+ if (q4.fromIso) conds.push(`created_at >= ${push2(q4.fromIso)}`);
255505
+ if (q4.toIso) conds.push(`created_at <= ${push2(q4.toIso)}`);
255506
+ const rows = await this.q(
255507
+ `SELECT * FROM ${this.e}.issues WHERE ${conds.join(" AND ")} ORDER BY created_at ASC, id ASC LIMIT ${push2(q4.limit)}`,
255508
+ args
255509
+ );
255510
+ return rows.map(toIssue);
255511
+ }
255512
+ async worksHandlingIssues(workorderId, issueIds, limit) {
255513
+ if (issueIds.length === 0) return [];
255514
+ const ids2 = capIds(issueIds);
255515
+ const rows = await this.q(
255516
+ `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
255517
+ WHERE w.workorder_id = $1
255518
+ AND (w.id LIKE ANY($4::text[]) OR (jsonb_typeof(w.frozen_issue_ids) = 'array' AND w.frozen_issue_ids ?| $2))
255519
+ ORDER BY w.created_at ASC, w.id ASC LIMIT $3`,
255520
+ [workorderId, ids2, limit, ids2.map((i5) => `wk:reply:${i5.replace(/[\\%_]/g, (c5) => `\\${c5}`)}:%`)]
255521
+ );
255522
+ return rows.map(toWork);
255523
+ }
255524
+ /* ── dispatches ── */
255525
+ async dispatchesOf(kind, targetIds) {
255526
+ if (targetIds.length === 0) return [];
255527
+ const rows = await this.q(
255528
+ `SELECT id, target_kind, target_id, actor_id, created_at, started_at, ended_at, outcome, reason, protocol_recovery_round
255529
+ FROM ${this.d}.dispatches WHERE target_kind = $1 AND target_id = ANY($2) ORDER BY created_at ASC, id ASC LIMIT 1000`,
255530
+ [kind, capIds(targetIds)]
255531
+ );
255532
+ return rows.map(toDispatch);
255533
+ }
255534
+ async dispatchTargetOf(runId) {
255535
+ const rows = await this.q(`SELECT target_kind, target_id FROM ${this.d}.dispatches WHERE id = $1`, [runId]);
255536
+ const r5 = rows[0];
255537
+ return r5 ? { targetKind: String(r5["target_kind"]), targetId: String(r5["target_id"]) } : null;
255538
+ }
255539
+ /* ── 委派 ── */
255540
+ async getDelegation(id) {
255541
+ const rows = await this.q(`SELECT * FROM ${this.c}.chat_session_delegations WHERE id = $1`, [id]);
255542
+ return rows[0] ? toDelegation(rows[0]) : null;
255543
+ }
255544
+ async delegationByChildSession(childSessionId) {
255545
+ const rows = await this.q(`SELECT * FROM ${this.c}.chat_session_delegations WHERE child_session_id = $1`, [childSessionId]);
255546
+ return rows[0] ? toDelegation(rows[0]) : null;
255547
+ }
255548
+ async delegationsOfParent(parentSessionId, limit) {
255549
+ const rows = await this.q(
255550
+ `SELECT * FROM ${this.c}.chat_session_delegations WHERE parent_session_id = $1 ORDER BY created_at ASC, id ASC LIMIT $2`,
255551
+ [parentSessionId, limit]
255552
+ );
255553
+ return rows.map(toDelegation);
255554
+ }
255555
+ async touchesOf(delegationId) {
255556
+ const rows = await this.q(
255557
+ `SELECT delegation_id, message_id, kind, at FROM ${this.c}.chat_session_delegation_touches
255558
+ WHERE delegation_id = $1 ORDER BY at ASC LIMIT 500`,
255559
+ [delegationId]
255560
+ );
255561
+ return rows.map((r5) => ({
255562
+ delegationId: String(r5["delegation_id"]),
255563
+ messageId: String(r5["message_id"]),
255564
+ kind: String(r5["kind"]),
255565
+ at: isoReq(r5["at"])
255566
+ }));
255567
+ }
255568
+ /* ── 会话 / 轮次 / 消息 ── */
255569
+ async getSession(id) {
255570
+ const rows = await this.q(`SELECT * FROM ${this.c}.chat_sessions WHERE id = $1`, [id]);
255571
+ return rows[0] ? toSession(rows[0]) : null;
255572
+ }
255573
+ async getTurn(id) {
255574
+ const rows = await this.q(`SELECT * FROM ${this.c}.chat_session_turns WHERE id = $1`, [id]);
255575
+ return rows[0] ? toTurn(rows[0]) : null;
255576
+ }
255577
+ async turnsOfSession(sessionId, limit) {
255578
+ const rows = await this.q(
255579
+ `SELECT * FROM ${this.c}.chat_session_turns WHERE chat_session_id = $1 ORDER BY reserved_at DESC, id DESC LIMIT $2`,
255580
+ [sessionId, limit + 1]
255581
+ );
255582
+ const truncated = rows.length > limit;
255583
+ const turns = (truncated ? rows.slice(0, limit) : rows).map(toTurn).reverse();
255584
+ return { turns, truncated };
255585
+ }
255586
+ async getMessage(id) {
255587
+ const rows = await this.q(`SELECT * FROM ${this.c}.chat_messages WHERE id = $1`, [id]);
255588
+ return rows[0] ? toMessage(rows[0]) : null;
255589
+ }
255590
+ async messagesOf(sessionId, q4) {
255591
+ const args = [sessionId];
255592
+ const push2 = (v2) => {
255593
+ args.push(v2);
255594
+ return `$${args.length}`;
255595
+ };
255596
+ const conds = ["session_id = $1"];
255597
+ if (q4.turnIds) {
255598
+ const window3 = ["turn_id IS NULL"];
255599
+ if (q4.fromIso) window3.push(`created_at >= ${push2(q4.fromIso)}`);
255600
+ if (q4.toIso) window3.push(`created_at <= ${push2(q4.toIso)}`);
255601
+ conds.push(`(turn_id = ANY(${push2(capIds(q4.turnIds))}) OR (${window3.join(" AND ")}))`);
255602
+ } else {
255603
+ if (q4.fromIso) conds.push(`created_at >= ${push2(q4.fromIso)}`);
255604
+ if (q4.toIso) conds.push(`created_at <= ${push2(q4.toIso)}`);
255605
+ }
255606
+ if (q4.roles?.length) conds.push(`role = ANY(${push2(q4.roles)})`);
255607
+ const rows = await this.q(
255608
+ `SELECT id, session_id, role, content, seq, created_at, run_id, turn_id, source FROM ${this.c}.chat_messages
255609
+ WHERE ${conds.join(" AND ")} ORDER BY seq ASC LIMIT ${push2(q4.limit)}`,
255610
+ args
255611
+ );
255612
+ return rows.map(toMessage);
255613
+ }
255614
+ async pendingMessagesOf(sessionId, fromIso, toIso2, limit) {
255615
+ const rows = await this.q(
255616
+ `SELECT id, chat_session_id, text, created_at, state, flavour FROM ${this.c}.chat_pending_messages
255617
+ WHERE chat_session_id = $1 AND created_at >= $2 AND created_at <= $3 ORDER BY seq ASC LIMIT $4`,
255618
+ [sessionId, fromIso, toIso2, limit]
255619
+ );
255620
+ return rows.map((r5) => ({
255621
+ id: String(r5["id"]),
255622
+ chatSessionId: String(r5["chat_session_id"]),
255623
+ text: String(r5["text"] ?? ""),
255624
+ createdAt: isoReq(r5["created_at"]),
255625
+ state: str5(r5["state"]),
255626
+ flavour: str5(r5["flavour"])
255627
+ }));
255628
+ }
255629
+ async originLinksOfWorkorder(workorderId) {
255630
+ const rows = await this.q(
255631
+ `SELECT session_id, work_order_id, linked_at FROM ${this.c}.chat_session_work_orders
255632
+ WHERE work_order_id = $1 AND link_kind = 'origin' ORDER BY linked_at ASC LIMIT 20`,
255633
+ [workorderId]
255634
+ );
255635
+ return rows.map(toLink);
255636
+ }
255637
+ async originLinksOfSession(sessionId) {
255638
+ const rows = await this.q(
255639
+ `SELECT session_id, work_order_id, linked_at FROM ${this.c}.chat_session_work_orders
255640
+ WHERE session_id = $1 AND link_kind = 'origin' ORDER BY linked_at ASC LIMIT 200`,
255641
+ [sessionId]
255642
+ );
255643
+ return rows.map(toLink);
255644
+ }
255645
+ /* ── find / peers 候选 ── */
255646
+ async listEndedWorks(q4) {
255647
+ const args = [];
255648
+ const push2 = (v2) => {
255649
+ args.push(v2);
255650
+ return `$${args.length}`;
255651
+ };
255652
+ const conds = [`(w.ended_at IS NOT NULL OR w.dead_at IS NOT NULL)`, `w.acceptance_state IS DISTINCT FROM 'draft'`];
255653
+ if (q4.sinceIso) conds.push(`COALESCE(w.ended_at, w.dead_at) >= ${push2(q4.sinceIso)}`);
255654
+ if (q4.actorId) conds.push(`w.assignee_actor_id = ${push2(q4.actorId)}`);
255655
+ if (q4.nodeType) conds.push(`n.type = ${push2(q4.nodeType)}`);
255656
+ if (q4.lane) conds.push(`COALESCE(w.lane, CASE WHEN w.id LIKE 'wk:reply:%' THEN 'reply' ELSE 'main' END) = ${push2(q4.lane)}`);
255657
+ const endExpr = `COALESCE(w.ended_at, w.dead_at)`;
255658
+ if (q4.before) conds.push(keysetBefore(endExpr, "w.id", q4.before, push2));
255659
+ const rows = await this.q(
255660
+ `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
255661
+ WHERE ${conds.join(" AND ")} ORDER BY date_trunc('milliseconds', ${endExpr}) DESC, w.id DESC LIMIT ${push2(q4.limit)}`,
255662
+ args
255663
+ );
255664
+ return rows.map(toWork);
255665
+ }
255666
+ async listEndedReviews(q4) {
255667
+ const args = [];
255668
+ const push2 = (v2) => {
255669
+ args.push(v2);
255670
+ return `$${args.length}`;
255671
+ };
255672
+ const endExpr = `COALESCE(r.ended_at, r.decided_at, r.cancelled_at, r.created_at)`;
255673
+ const conds = [`r.status IN ('accept','reject','failed','dead')`];
255674
+ if (q4.sinceIso) conds.push(`${endExpr} >= ${push2(q4.sinceIso)}`);
255675
+ if (q4.actorId) conds.push(`r.reviewer_actor_id = ${push2(q4.actorId)}`);
255676
+ if (q4.before) conds.push(keysetBefore(endExpr, "r.id", q4.before, push2));
255677
+ const rows = await this.q(
255678
+ `SELECT ${REVIEW_COLS} FROM ${this.e}.reviews r LEFT JOIN ${this.e}.workflow_nodes n ON n.id = r.node_id
255679
+ WHERE ${conds.join(" AND ")} ORDER BY date_trunc('milliseconds', ${endExpr}) DESC, r.id DESC LIMIT ${push2(q4.limit)}`,
255680
+ args
255681
+ );
255682
+ return rows.map(toReview);
255683
+ }
255684
+ async listEndedDelegations(q4) {
255685
+ const args = [];
255686
+ const push2 = (v2) => {
255687
+ args.push(v2);
255688
+ return `$${args.length}`;
255689
+ };
255690
+ const conds = [`state IN ('done','failed')`];
255691
+ if (q4.sinceIso) conds.push(`COALESCE(settled_at, created_at) >= ${push2(q4.sinceIso)}`);
255692
+ if (q4.actorId) conds.push(`expert_actor_id = ${push2(q4.actorId)}`);
255693
+ if (q4.before) conds.push(keysetBefore(`COALESCE(settled_at, created_at)`, "id", q4.before, push2));
255694
+ const rows = await this.q(
255695
+ `SELECT * FROM ${this.c}.chat_session_delegations WHERE ${conds.join(" AND ")}
255696
+ ORDER BY date_trunc('milliseconds', COALESCE(settled_at, created_at)) DESC, id DESC LIMIT ${push2(q4.limit)}`,
255697
+ args
255698
+ );
255699
+ return rows.map(toDelegation);
255700
+ }
255701
+ async listRecentSessions(q4) {
255702
+ const args = [];
255703
+ const push2 = (v2) => {
255704
+ args.push(v2);
255705
+ return `$${args.length}`;
255706
+ };
255707
+ const conds = [`NOT EXISTS (SELECT 1 FROM ${this.c}.chat_session_delegations d WHERE d.child_session_id = s.id)`];
255708
+ if (!q4.includeAnalysis) conds.push(`s.analyzed_run_id IS NULL`);
255709
+ if (q4.sinceIso) conds.push(`s.touched_at >= ${push2(q4.sinceIso)}`);
255710
+ if (q4.aiActorId) conds.push(`s.ai_actor_id = ${push2(q4.aiActorId)}`);
255711
+ if (q4.before) conds.push(keysetBefore("s.touched_at", "s.id", q4.before, push2));
255712
+ const rows = await this.q(
255713
+ `SELECT s.id, s.human_actor_id, s.ai_actor_id, s.title, s.analyzed_run_id, s.runtime_session_id, s.touched_at, s.created_at
255714
+ FROM ${this.c}.chat_sessions s WHERE ${conds.join(" AND ")}
255715
+ ORDER BY date_trunc('milliseconds', s.touched_at) DESC, s.id DESC LIMIT ${push2(q4.limit)}`,
255716
+ args
255717
+ );
255718
+ return rows.map(toSession);
255719
+ }
255720
+ };
255721
+ }
255722
+ });
255723
+
255150
255724
  // ../server/src/domains/trace/units.ts
255151
255725
  function splitSegments(turns, gapMs = SEGMENT_IDLE_GAP_MS) {
255152
255726
  const sorted = [...turns].sort((a5, b6) => {
@@ -255241,6 +255815,23 @@ function parseSince(since, nowMs) {
255241
255815
  if (!Number.isFinite(t)) throw new RangeError(`--since \u4E0D\u5408\u6CD5\uFF1A${since}\uFF08\u8981 ISO \u65F6\u95F4\u6216 7d / 12h / 30m\uFF09`);
255242
255816
  return new Date(t).toISOString();
255243
255817
  }
255818
+ function keysetSource(list3, keyOf4, batch, toCandidates) {
255819
+ let before;
255820
+ const src = {
255821
+ watermark: "",
255822
+ async next() {
255823
+ if (src.watermark === null) return [];
255824
+ const rows = await list3(before);
255825
+ const last = rows[rows.length - 1];
255826
+ if (last) before = keyOf4(last);
255827
+ src.watermark = rows.length < batch || !before ? null : before.at;
255828
+ const out = [];
255829
+ for (const r5 of rows) out.push(...await toCandidates(r5));
255830
+ return out;
255831
+ }
255832
+ };
255833
+ return src;
255834
+ }
255244
255835
  function memo(map3, key2, fn) {
255245
255836
  let p4 = map3.get(key2);
255246
255837
  if (!p4) {
@@ -255265,11 +255856,13 @@ function metaString(meta, key2) {
255265
255856
  }
255266
255857
  return null;
255267
255858
  }
255268
- var SEG_TURN_CAP, RUN_PAGE, RUN_CAP, NODE_WORK_CAP, MAX_CHAIN_NODES, MESSAGE_CAP, SIGNAL_TEXT_CAP, FIND_DEFAULT_LIMIT, FIND_MAX_LIMIT, RUN_ROW_CAP, TURN_TERMINAL, REVIEW_ENDED, DELEGATION_ENDED, SYSTEM_CANCEL_REASONS, EXOGENOUS_RUN_STATUS, UnitError, ms, turnStart, turnEnd, UnitService, unitTypeOf, segId, clip4, UnitReader;
255859
+ var SEG_TURN_CAP, RUN_PAGE, RUN_CAP, NODE_WORK_CAP, MAX_CHAIN_NODES, MESSAGE_CAP, SIGNAL_TEXT_CAP, EXOGENOUS_TEXT_CAP, EXOGENOUS_SUMMARY_CAP, FIND_DEFAULT_LIMIT, FIND_BATCH_MAX, FIND_MAX_LIMIT, RUN_ROW_CAP, TURN_TERMINAL, REVIEW_ENDED, DELEGATION_ENDED, SYSTEM_CANCEL_REASONS, EXOGENOUS_RUN_STATUS, UnitError, ms, turnStart, turnEnd, UnitService, unitTypeOf, segId, clipField, outcomeFetchCmd, exogenousFetchCmd, UnitReader;
255269
255860
  var init_units = __esm({
255270
255861
  "../server/src/domains/trace/units.ts"() {
255271
255862
  "use strict";
255272
255863
  init_src();
255864
+ init_unit_data();
255865
+ init_renderer();
255273
255866
  SEG_TURN_CAP = 2e3;
255274
255867
  RUN_PAGE = 200;
255275
255868
  RUN_CAP = 2e3;
@@ -255277,7 +255870,10 @@ var init_units = __esm({
255277
255870
  MAX_CHAIN_NODES = 200;
255278
255871
  MESSAGE_CAP = 1e3;
255279
255872
  SIGNAL_TEXT_CAP = 2e3;
255873
+ EXOGENOUS_TEXT_CAP = 500;
255874
+ EXOGENOUS_SUMMARY_CAP = 120;
255280
255875
  FIND_DEFAULT_LIMIT = 20;
255876
+ FIND_BATCH_MAX = 200;
255281
255877
  FIND_MAX_LIMIT = 200;
255282
255878
  RUN_ROW_CAP = 50;
255283
255879
  TURN_TERMINAL = /* @__PURE__ */ new Set(["succeeded", "failed", "cancelled", "orphaned"]);
@@ -255326,11 +255922,12 @@ var init_units = __esm({
255326
255922
  async evidenceScope(unitId, maxHop) {
255327
255923
  return this.reader().evidenceScope(unitId, maxHop);
255328
255924
  }
255329
- async outcome(unitId) {
255330
- return this.reader().outcome(unitId);
255925
+ /** `full`:长文本不截(`oasis trace outcome <unit> --full`,即截断标记里给的取回命令)。 */
255926
+ async outcome(unitId, opts = {}) {
255927
+ return this.reader().outcome(unitId, opts);
255331
255928
  }
255332
- async exogenous(unitId) {
255333
- return this.reader().exogenous(unitId);
255929
+ async exogenous(unitId, opts = {}) {
255930
+ return this.reader().exogenous(unitId, opts);
255334
255931
  }
255335
255932
  async peers(unitId, limit) {
255336
255933
  return this.reader().peers(unitId, limit);
@@ -255341,7 +255938,9 @@ var init_units = __esm({
255341
255938
  };
255342
255939
  unitTypeOf = (u) => u.kind === "work" || u.kind === "review" ? "work" : u.kind === "delegation" ? "delegation" : "chat";
255343
255940
  segId = (sessionId, firstTurnId) => `seg:${sessionId}:${firstTurnId}`;
255344
- clip4 = (s3, n3 = SIGNAL_TEXT_CAP) => ({ text: s3.length > n3 ? s3.slice(0, n3) : s3, chars: s3.length, clipped: s3.length > n3 });
255941
+ clipField = (s3, fetchCmd, full, n3 = SIGNAL_TEXT_CAP) => full ? { text: s3, truncated: false, fullChars: s3.length, fetchCmd } : { ...truncateText(s3, n3, fetchCmd) };
255942
+ outcomeFetchCmd = (unitId) => `oasis trace outcome ${unitId} --full`;
255943
+ exogenousFetchCmd = (unitId) => `oasis trace exogenous ${unitId} --full`;
255345
255944
  UnitReader = class {
255346
255945
  constructor(deps) {
255347
255946
  this.deps = deps;
@@ -255590,7 +256189,7 @@ var init_units = __esm({
255590
256189
  const ended = reviewEnded(u.review);
255591
256190
  return {
255592
256191
  ended,
255593
- endedAt: ended ? u.review.endedAt ?? u.review.decidedAt ?? u.review.createdAt : null,
256192
+ endedAt: ended ? unitListKey.review(u.review).at : null,
255594
256193
  startedAt: u.review.startedAt ?? u.review.createdAt,
255595
256194
  actorId: u.review.reviewerActorId,
255596
256195
  cursor: u.unitId,
@@ -255646,14 +256245,16 @@ var init_units = __esm({
255646
256245
  async find(q4) {
255647
256246
  const limit = Math.max(1, Math.min(FIND_MAX_LIMIT, Math.floor(q4.limit ?? FIND_DEFAULT_LIMIT)));
255648
256247
  const sinceIso = parseSince(q4.since, this.nowMs);
255649
- const fetchN = limit * 3;
256248
+ const batch = Math.min(FIND_BATCH_MAX, limit * 3);
255650
256249
  const wants = (t) => !q4.type || q4.type === t;
255651
- const cands = [];
256250
+ const base = { ...sinceIso ? { sinceIso } : {}, ...q4.actor ? { actorId: q4.actor } : {} };
256251
+ const sources = [];
255652
256252
  if (wants("work")) {
255653
- const works = await this.data.listEndedWorks({ ...sinceIso ? { sinceIso } : {}, ...q4.actor ? { actorId: q4.actor } : {}, limit: fetchN });
255654
- for (const w2 of works) {
255655
- if (!workEnded(w2)) continue;
255656
- cands.push({
256253
+ sources.push(keysetSource(
256254
+ (before) => this.data.listEndedWorks({ ...base, ...before ? { before } : {}, limit: batch }),
256255
+ unitListKey.work,
256256
+ batch,
256257
+ async (w2) => workEnded(w2) ? [{
255657
256258
  unitId: w2.id,
255658
256259
  type: "work",
255659
256260
  endedAt: w2.endedAt ?? w2.deadAt,
@@ -255661,69 +256262,81 @@ var init_units = __esm({
255661
256262
  sessionId: null,
255662
256263
  cursor: w2.id,
255663
256264
  load: async () => this.cacheUnit({ kind: "work", unitId: w2.id, work: w2 })
255664
- });
255665
- }
255666
- const reviews = await this.data.listEndedReviews({ ...sinceIso ? { sinceIso } : {}, ...q4.actor ? { actorId: q4.actor } : {}, limit: fetchN });
255667
- for (const r5 of reviews) {
255668
- if (!reviewEnded(r5)) continue;
255669
- cands.push({
256265
+ }] : []
256266
+ ));
256267
+ sources.push(keysetSource(
256268
+ (before) => this.data.listEndedReviews({ ...base, ...before ? { before } : {}, limit: batch }),
256269
+ unitListKey.review,
256270
+ batch,
256271
+ async (r5) => reviewEnded(r5) ? [{
255670
256272
  unitId: r5.id,
255671
256273
  type: "work",
255672
- endedAt: r5.endedAt ?? r5.decidedAt ?? r5.createdAt,
256274
+ endedAt: unitListKey.review(r5).at,
255673
256275
  actorId: r5.reviewerActorId,
255674
256276
  sessionId: null,
255675
256277
  cursor: r5.id,
255676
256278
  load: async () => this.cacheUnit({ kind: "review", unitId: r5.id, review: r5 })
255677
- });
255678
- }
256279
+ }] : []
256280
+ ));
255679
256281
  }
255680
256282
  if (wants("delegation")) {
255681
- const dlgs = await this.data.listEndedDelegations({ ...sinceIso ? { sinceIso } : {}, ...q4.actor ? { actorId: q4.actor } : {}, limit: fetchN });
255682
- for (const d5 of dlgs) {
255683
- if (!delegationEnded(d5)) continue;
255684
- const unitId = `dlg:${d5.id}`;
255685
- cands.push({
255686
- unitId,
255687
- type: "delegation",
255688
- endedAt: d5.settledAt ?? d5.createdAt,
255689
- actorId: d5.expertActorId,
255690
- sessionId: null,
255691
- cursor: delegationCursor(d5),
255692
- load: async () => this.cacheUnit({ kind: "delegation", unitId, dlg: d5 })
255693
- });
255694
- }
256283
+ sources.push(keysetSource(
256284
+ (before) => this.data.listEndedDelegations({ ...base, ...before ? { before } : {}, limit: batch }),
256285
+ unitListKey.delegation,
256286
+ batch,
256287
+ async (d5) => {
256288
+ if (!delegationEnded(d5)) return [];
256289
+ const unitId = `dlg:${d5.id}`;
256290
+ return [{
256291
+ unitId,
256292
+ type: "delegation",
256293
+ endedAt: d5.settledAt ?? d5.createdAt,
256294
+ actorId: d5.expertActorId,
256295
+ sessionId: null,
256296
+ cursor: delegationCursor(d5),
256297
+ load: async () => this.cacheUnit({ kind: "delegation", unitId, dlg: d5 })
256298
+ }];
256299
+ }
256300
+ ));
255695
256301
  }
255696
256302
  if (wants("chat")) {
255697
256303
  const excluded = new Set(!q4.includeMeta && this.deps.reflectorSessionIds ? await this.deps.reflectorSessionIds() : []);
255698
- const sessions = await this.data.listRecentSessions({
255699
- ...sinceIso ? { sinceIso } : {},
255700
- ...q4.actor ? { aiActorId: q4.actor } : {},
255701
- includeAnalysis: q4.includeMeta === true,
255702
- limit: fetchN
255703
- });
255704
- for (const s3 of sessions) {
255705
- if (excluded.has(s3.id)) continue;
255706
- const ss = await this.sessionSegments(s3.id);
255707
- if (!ss) continue;
255708
- for (let i5 = 0; i5 < ss.segments.length; i5++) {
255709
- const seg = ss.segments[i5];
255710
- if (!segmentEnded(seg, i5 < ss.segments.length - 1, this.nowMs)) continue;
255711
- const endedAt = turnEnd(seg.turns[seg.turns.length - 1]);
255712
- if (sinceIso && ms(endedAt) < ms(sinceIso)) continue;
255713
- const idx = i5;
255714
- cands.push({
255715
- unitId: segId(s3.id, seg.firstTurnId),
255716
- type: "chat",
255717
- endedAt,
255718
- actorId: s3.aiActorId,
255719
- sessionId: s3.id,
255720
- cursor: seg.lastTurnId,
255721
- load: () => this.segmentUnit(ss, idx)
255722
- });
256304
+ sources.push(keysetSource(
256305
+ (before) => this.data.listRecentSessions({
256306
+ ...sinceIso ? { sinceIso } : {},
256307
+ ...q4.actor ? { aiActorId: q4.actor } : {},
256308
+ includeAnalysis: q4.includeMeta === true,
256309
+ ...before ? { before } : {},
256310
+ limit: batch
256311
+ }),
256312
+ unitListKey.session,
256313
+ batch,
256314
+ // 会话按 touched_at 取:段的结束时间不晚于它,水位照样成立。
256315
+ async (s3) => {
256316
+ if (excluded.has(s3.id)) return [];
256317
+ const ss = await this.sessionSegments(s3.id);
256318
+ if (!ss) return [];
256319
+ const segs = [];
256320
+ for (let i5 = 0; i5 < ss.segments.length; i5++) {
256321
+ const seg = ss.segments[i5];
256322
+ if (!segmentEnded(seg, i5 < ss.segments.length - 1, this.nowMs)) continue;
256323
+ const endedAt = turnEnd(seg.turns[seg.turns.length - 1]);
256324
+ if (sinceIso && ms(endedAt) < ms(sinceIso)) continue;
256325
+ const idx = i5;
256326
+ segs.push({
256327
+ unitId: segId(s3.id, seg.firstTurnId),
256328
+ type: "chat",
256329
+ endedAt,
256330
+ actorId: s3.aiActorId,
256331
+ sessionId: s3.id,
256332
+ cursor: seg.lastTurnId,
256333
+ load: () => this.segmentUnit(ss, idx)
256334
+ });
256335
+ }
256336
+ return segs;
255723
256337
  }
255724
- }
256338
+ ));
255725
256339
  }
255726
- cands.sort((a5, b6) => ms(b6.endedAt) - ms(a5.endedAt) || (a5.unitId < b6.unitId ? 1 : -1));
255727
256340
  const roleCache = /* @__PURE__ */ new Map();
255728
256341
  const roleOk = async (actorId) => {
255729
256342
  if (!q4.role) return true;
@@ -255732,22 +256345,34 @@ var init_units = __esm({
255732
256345
  const roles = await memo(roleCache, actorId, () => fn(actorId)) ?? "";
255733
256346
  return roles.split(",").map((r5) => r5.trim()).includes(q4.role);
255734
256347
  };
255735
- const reflected = this.deps.reflectedCursors ? await this.deps.reflectedCursors(cands.map((c5) => c5.unitId)) : /* @__PURE__ */ new Map();
255736
256348
  const out = [];
255737
- let built = 0;
255738
- for (const c5 of cands) {
255739
- if (out.length >= limit || built >= limit * 5) break;
255740
- if (!await roleOk(c5.actorId)) continue;
255741
- if (q4.unreflected && (reflected.get(c5.unitId) ?? []).some((r5) => cursorCovers(r5, c5.cursor, c5.type))) continue;
255742
- const u = await c5.load();
255743
- if (!u) continue;
255744
- built++;
255745
- const s3 = await this.summary(u, reflected);
255746
- if (!s3.ended) continue;
255747
- if (q4.outcome && s3.outcome !== q4.outcome) continue;
255748
- out.push(s3);
256349
+ const pending = [];
256350
+ for (const src of sources) pending.push(...await src.next());
256351
+ for (; ; ) {
256352
+ const open3 = sources.filter((src) => src.watermark !== null);
256353
+ const mark = open3.length ? Math.max(...open3.map((src) => ms(src.watermark))) : -Infinity;
256354
+ pending.sort((a5, b6) => ms(b6.endedAt) - ms(a5.endedAt) || (a5.unitId < b6.unitId ? 1 : -1));
256355
+ let ready = 0;
256356
+ while (ready < pending.length && ms(pending[ready].endedAt) > mark) ready++;
256357
+ const chunk = pending.splice(0, ready);
256358
+ if (chunk.length > 0) {
256359
+ const reflected = this.deps.reflectedCursors ? await this.deps.reflectedCursors(chunk.map((c5) => c5.unitId)) : /* @__PURE__ */ new Map();
256360
+ for (const c5 of chunk) {
256361
+ if (!await roleOk(c5.actorId)) continue;
256362
+ if (q4.unreflected && (reflected.get(c5.unitId) ?? []).some((r5) => cursorCovers(r5, c5.cursor, c5.type))) continue;
256363
+ const u = await c5.load();
256364
+ if (!u) continue;
256365
+ const s3 = await this.summary(u, reflected);
256366
+ if (!s3.ended) continue;
256367
+ if (q4.outcome && s3.outcome !== q4.outcome) continue;
256368
+ out.push(s3);
256369
+ if (out.length >= limit) return out;
256370
+ }
256371
+ }
256372
+ if (open3.length === 0) return out;
256373
+ const lead = open3.reduce((a5, b6) => ms(b6.watermark) > ms(a5.watermark) ? b6 : a5);
256374
+ pending.push(...await lead.next());
255749
256375
  }
255750
- return out;
255751
256376
  }
255752
256377
  cacheUnit(u) {
255753
256378
  if (!this.units.has(u.unitId)) this.units.set(u.unitId, Promise.resolve(u));
@@ -255948,9 +256573,10 @@ var init_units = __esm({
255948
256573
  return { runHop, nodes: nodes5 };
255949
256574
  }
255950
256575
  /* ── outcome ── */
255951
- async outcome(unitId) {
256576
+ async outcome(unitId, opts = {}) {
255952
256577
  const u = await this.mustLoad(unitId);
255953
256578
  const signals = {};
256579
+ const field = (s3) => clipField(s3, outcomeFetchCmd(u.unitId), opts.full === true);
255954
256580
  switch (u.kind) {
255955
256581
  case "work": {
255956
256582
  const w2 = u.work;
@@ -255977,8 +256603,7 @@ var init_units = __esm({
255977
256603
  decidedAt: r5.decidedAt
255978
256604
  }));
255979
256605
  signals["issues"] = (await this.data.issuesInWorkorder(w2.workorderId, { aboutWorkIds: [w2.id], limit: 100 })).map((i5) => {
255980
- const b6 = clip4(i5.body);
255981
- return { issueId: i5.id, kind: i5.kind, author: i5.authorActorId, resolved: i5.resolvedAt != null, createdAt: i5.createdAt, body: b6.text, bodyChars: b6.chars };
256606
+ return { issueId: i5.id, kind: i5.kind, author: i5.authorActorId, resolved: i5.resolvedAt != null, createdAt: i5.createdAt, body: field(i5.body) };
255982
256607
  });
255983
256608
  signals["reworkedBy"] = await this.data.reworkedBy(w2);
255984
256609
  break;
@@ -256024,16 +256649,16 @@ var init_units = __esm({
256024
256649
  const inter = await this.segmentInterjections(u);
256025
256650
  signals["interjections"] = [...inter].map(([turnId, msgs]) => ({
256026
256651
  turnId,
256027
- messages: msgs.map((m4) => {
256028
- const c5 = clip4(m4.content);
256029
- return { messageId: m4.id, at: m4.at, text: c5.text, chars: c5.chars };
256030
- })
256652
+ messages: msgs.map((m4) => ({ messageId: m4.id, at: m4.at, body: field(m4.content) }))
256031
256653
  }));
256032
256654
  const endIso = new Date(last.completedAt ? ms(last.completedAt) : this.nowMs).toISOString();
256033
- signals["pending"] = (await this.data.pendingMessagesOf(u.session.id, u.seg.turns[0].reservedAt, endIso, 200)).map((p4) => {
256034
- const c5 = clip4(p4.text);
256035
- return { id: p4.id, at: p4.createdAt, state: p4.state, flavour: p4.flavour, text: c5.text, chars: c5.chars };
256036
- });
256655
+ signals["pending"] = (await this.data.pendingMessagesOf(u.session.id, u.seg.turns[0].reservedAt, endIso, 200)).map((p4) => ({
256656
+ id: p4.id,
256657
+ at: p4.createdAt,
256658
+ state: p4.state,
256659
+ flavour: p4.flavour,
256660
+ body: field(p4.text)
256661
+ }));
256037
256662
  break;
256038
256663
  }
256039
256664
  }
@@ -256048,9 +256673,10 @@ var init_units = __esm({
256048
256673
  }
256049
256674
  return out;
256050
256675
  }
256051
- async exogenous(unitId) {
256676
+ async exogenous(unitId, opts = {}) {
256052
256677
  const u = await this.mustLoad(unitId);
256053
256678
  const facts = [];
256679
+ const field = (s3) => clipField(s3, exogenousFetchCmd(u.unitId), opts.full === true, EXOGENOUS_TEXT_CAP);
256054
256680
  const runs = await this.runRows(await this.runIdsOf(u));
256055
256681
  for (const r5 of runs) {
256056
256682
  const abnormal = EXOGENOUS_RUN_STATUS.has(r5.status);
@@ -256060,7 +256686,7 @@ var init_units = __esm({
256060
256686
  at: r5.endedAt ?? r5.startedAt,
256061
256687
  runId: r5.id,
256062
256688
  summary: `run ${r5.id} \u72B6\u6001 ${r5.status}${r5.exitReason ? `\uFF0Cexit_reason=${r5.exitReason}` : ""}${r5.errorCode ? `\uFF0Cerror_code=${r5.errorCode}` : ""}`,
256063
- detail: { status: r5.status, exitReason: r5.exitReason, errorCode: r5.errorCode, errorMessage: r5.errorMessage ? clip4(r5.errorMessage, 500).text : null }
256689
+ detail: { status: r5.status, exitReason: r5.exitReason, errorCode: r5.errorCode, errorMessage: r5.errorMessage ? field(r5.errorMessage) : null }
256064
256690
  });
256065
256691
  }
256066
256692
  const instances = [...new Set(runs.map((r5) => r5.runtimeInstanceId).filter((x2) => !!x2))];
@@ -256103,11 +256729,11 @@ var init_units = __esm({
256103
256729
  });
256104
256730
  }
256105
256731
  }
256106
- if (u.kind === "work") facts.push(...await this.upstreamFacts(u.work));
256732
+ if (u.kind === "work") facts.push(...await this.upstreamFacts(u.work, field));
256107
256733
  return facts;
256108
256734
  }
256109
256735
  /** 单元时间窗里上游(输入节点、brief)收到的 issue、出的新版本。 */
256110
- async upstreamFacts(w2) {
256736
+ async upstreamFacts(w2, field) {
256111
256737
  const out = [];
256112
256738
  const from = w2.startedAt ?? w2.createdAt;
256113
256739
  const to = w2.endedAt ?? w2.deadAt ?? new Date(this.nowMs).toISOString();
@@ -256119,13 +256745,15 @@ var init_units = __esm({
256119
256745
  if (nodes5.size === 0) return out;
256120
256746
  const nodeIds = [...nodes5];
256121
256747
  for (const i5 of await this.data.issuesInWorkorder(w2.workorderId, { aboutNodeIds: nodeIds, fromIso: from, toIso: to, limit: 50 })) {
256122
- const b6 = clip4(i5.body, 500);
256748
+ const b6 = field(i5.body);
256749
+ const head = (i5.body.split("\n")[0] ?? "").slice(0, EXOGENOUS_SUMMARY_CAP);
256750
+ const more = head.length < i5.body.length ? ` \u2026\uFF08\u5168\u6587 ${i5.body.length} \u5B57 \u2192 ${b6.fetchCmd}\uFF09` : "";
256123
256751
  out.push({
256124
256752
  kind: "upstream-issue",
256125
256753
  at: i5.createdAt,
256126
256754
  runId: null,
256127
- summary: `\u6267\u884C\u671F\u95F4\u4E0A\u6E38\u8282\u70B9 ${i5.aboutNodeId} \u6536\u5230 ${i5.kind}\uFF1A${b6.text.split("\n")[0]}`,
256128
- detail: { issueId: i5.id, kind: i5.kind, aboutNodeId: i5.aboutNodeId, author: i5.authorActorId, resolved: i5.resolvedAt != null, body: b6.text, bodyChars: b6.chars }
256755
+ summary: `\u6267\u884C\u671F\u95F4\u4E0A\u6E38\u8282\u70B9 ${i5.aboutNodeId} \u6536\u5230 ${i5.kind}\uFF1A${head}${more}`,
256756
+ detail: { issueId: i5.id, kind: i5.kind, aboutNodeId: i5.aboutNodeId, author: i5.authorActorId, resolved: i5.resolvedAt != null, body: b6 }
256129
256757
  });
256130
256758
  }
256131
256759
  for (const x2 of await this.data.worksAcceptedInWindow(nodeIds, from, to, 50)) {
@@ -256548,12 +257176,13 @@ function reflectionDomain(opts) {
256548
257176
  router.get("/api/traces/units/:unit/outcome", async (req) => {
256549
257177
  const d5 = await deps(req);
256550
257178
  const u = await requireUnit(d5, req.params.unit);
256551
- return { status: 200, body: await d5.units.outcome(u.summary.unitId).catch(unitErr) };
257179
+ return { status: 200, body: await d5.units.outcome(u.summary.unitId, { full: boolParam(req.query, "full") }).catch(unitErr) };
256552
257180
  });
256553
257181
  router.get("/api/traces/units/:unit/exogenous", async (req) => {
256554
257182
  const d5 = await deps(req);
256555
257183
  const u = await requireUnit(d5, req.params.unit);
256556
- return { status: 200, body: { unitId: u.summary.unitId, facts: await d5.units.exogenous(u.summary.unitId).catch(unitErr) } };
257184
+ const facts = await d5.units.exogenous(u.summary.unitId, { full: boolParam(req.query, "full") }).catch(unitErr);
257185
+ return { status: 200, body: { unitId: u.summary.unitId, facts } };
256557
257186
  });
256558
257187
  router.get("/api/traces/units/:unit/runs", async (req) => {
256559
257188
  const d5 = await deps(req);
@@ -257714,546 +258343,6 @@ var init_reflection_service = __esm({
257714
258343
  }
257715
258344
  });
257716
258345
 
257717
- // ../server/src/domains/trace/unit-data.ts
257718
- function quoteSchema(name) {
257719
- if (!/^[A-Za-z0-9_][A-Za-z0-9_.-]*$/.test(name)) throw new Error(`invalid schema name: ${name}`);
257720
- return `"${name}"`;
257721
- }
257722
- function dispatchSchemaIdent(name) {
257723
- const s3 = name.replace(/[^a-zA-Z0-9_]/g, "");
257724
- if (!s3) throw new Error(`invalid dispatch schema name: ${name}`);
257725
- return `"${s3}"`;
257726
- }
257727
- function replyIssueIdFromWorkId(workId) {
257728
- const m4 = /^wk:reply:(.+):\d+$/.exec(workId);
257729
- return m4 ? m4[1] : null;
257730
- }
257731
- function toWork(r5) {
257732
- return {
257733
- id: String(r5["id"]),
257734
- workorderId: String(r5["workorder_id"]),
257735
- nodeId: String(r5["node_id"]),
257736
- nodeType: str5(r5["node_type"]),
257737
- nodeTitle: str5(r5["node_title"]),
257738
- assigneeActorId: String(r5["assignee_actor_id"]),
257739
- createdAt: isoReq(r5["created_at"]),
257740
- startedAt: iso4(r5["started_at"]),
257741
- endedAt: iso4(r5["ended_at"]),
257742
- deadAt: iso4(r5["dead_at"]),
257743
- status: str5(r5["status"]),
257744
- outcome: str5(r5["outcome"]),
257745
- // 存量 lane 为空时按 work id 前缀兜底(回信轮 id 恒为 `wk:reply:<issueId>:<n>`)。
257746
- lane: r5["lane"] === "reply" || r5["lane"] == null && String(r5["id"]).startsWith("wk:reply:") ? "reply" : "main",
257747
- replyIssueId: replyIssueIdFromWorkId(String(r5["id"])),
257748
- continuesWorkId: str5(r5["continues_work_id"]),
257749
- acceptanceState: str5(r5["acceptance_state"]) ?? null,
257750
- acceptedAt: iso4(r5["accepted_at"]),
257751
- rejectedReason: str5(r5["rejected_reason"]),
257752
- overrideBy: str5(r5["override_by"]),
257753
- overrideReason: str5(r5["override_reason"]),
257754
- frozenIssueIds: strArr(r5["frozen_issue_ids"]),
257755
- protocolRecovery: r5["protocol_recovery"] ?? null,
257756
- killSource: str5(r5["kill_source"]),
257757
- outputVersionNo: num3(r5["output_version_no"])
257758
- };
257759
- }
257760
- function toReview(r5) {
257761
- const verdict = str5(r5["verdict"]);
257762
- let status = str5(r5["status"]);
257763
- if (!status) {
257764
- if (r5["retry_at"] != null) status = "retry";
257765
- else if (r5["cancelled_at"] != null) status = "dead";
257766
- else if (verdict === "approve" && r5["decided_at"] != null) status = "accept";
257767
- else if (verdict === "request_changes" && r5["decided_at"] != null) status = "reject";
257768
- else if (r5["ended_at"] != null) status = verdict ? verdict === "approve" ? "accept" : "reject" : "failed";
257769
- else status = "running";
257770
- }
257771
- return {
257772
- id: String(r5["id"]),
257773
- workorderId: String(r5["workorder_id"]),
257774
- nodeId: String(r5["node_id"]),
257775
- nodeTitle: str5(r5["node_title"]),
257776
- targetWorkId: String(r5["target_work_id"]),
257777
- reviewerActorId: String(r5["reviewer_actor_id"]),
257778
- reviewGroup: String(r5["review_group"] ?? ""),
257779
- status,
257780
- verdict: verdict ?? null,
257781
- note: str5(r5["note"]),
257782
- createdAt: isoReq(r5["created_at"]),
257783
- startedAt: iso4(r5["started_at"]),
257784
- endedAt: iso4(r5["ended_at"]),
257785
- decidedAt: iso4(r5["decided_at"]),
257786
- killSource: str5(r5["kill_source"])
257787
- };
257788
- }
257789
- function toIssue(r5) {
257790
- return {
257791
- id: String(r5["id"]),
257792
- workorderId: String(r5["workorder_id"]),
257793
- kind: String(r5["kind"]),
257794
- body: String(r5["body"] ?? ""),
257795
- aboutNodeId: str5(r5["about_node_id"]),
257796
- aboutWorkId: str5(r5["about_work_id"]),
257797
- raisedByNodeId: str5(r5["raised_by_node_id"]),
257798
- authorActorId: String(r5["author_actor_id"]),
257799
- resolvedAt: iso4(r5["resolved_at"]),
257800
- createdAt: isoReq(r5["created_at"])
257801
- };
257802
- }
257803
- function toDispatch(r5) {
257804
- return {
257805
- id: String(r5["id"]),
257806
- targetKind: String(r5["target_kind"]),
257807
- targetId: String(r5["target_id"]),
257808
- actorId: str5(r5["actor_id"]),
257809
- createdAt: isoReq(r5["created_at"]),
257810
- startedAt: iso4(r5["started_at"]),
257811
- endedAt: iso4(r5["ended_at"]),
257812
- outcome: str5(r5["outcome"]),
257813
- reason: str5(r5["reason"]),
257814
- protocolRecoveryRound: num3(r5["protocol_recovery_round"])
257815
- };
257816
- }
257817
- function toDelegation(r5) {
257818
- return {
257819
- id: String(r5["id"]),
257820
- parentSessionId: String(r5["parent_session_id"]),
257821
- parentMessageId: String(r5["parent_message_id"] ?? ""),
257822
- childSessionId: String(r5["child_session_id"]),
257823
- expertActorId: String(r5["expert_actor_id"]),
257824
- state: String(r5["state"]),
257825
- failureKind: str5(r5["failure_kind"]),
257826
- failureReason: str5(r5["failure_reason"]),
257827
- consecutiveFails: num3(r5["consecutive_fails"]) ?? 0,
257828
- dispatchSeq: num3(r5["dispatch_seq"]),
257829
- createdAt: isoReq(r5["created_at"]),
257830
- settledAt: iso4(r5["settled_at"]),
257831
- label: str5(r5["label"]),
257832
- taskDigest: str5(r5["task_digest"])
257833
- };
257834
- }
257835
- function toSession(r5) {
257836
- return {
257837
- id: String(r5["id"]),
257838
- humanActorId: String(r5["human_actor_id"]),
257839
- aiActorId: String(r5["ai_actor_id"]),
257840
- title: str5(r5["title"]),
257841
- analyzedRunId: str5(r5["analyzed_run_id"]),
257842
- runtimeSessionId: str5(r5["runtime_session_id"]),
257843
- touchedAt: isoReq(r5["touched_at"]),
257844
- createdAt: isoReq(r5["created_at"])
257845
- };
257846
- }
257847
- function toTurn(r5) {
257848
- return {
257849
- id: String(r5["id"]),
257850
- chatSessionId: String(r5["chat_session_id"]),
257851
- source: String(r5["source"]),
257852
- status: String(r5["status"]),
257853
- reservedAt: isoReq(r5["reserved_at"]),
257854
- startedAt: iso4(r5["started_at"]),
257855
- completedAt: iso4(r5["completed_at"]),
257856
- cancelledBy: str5(r5["cancelled_by"]),
257857
- dispatchId: str5(r5["dispatch_id"]),
257858
- assistantRunId: str5(r5["assistant_run_id"])
257859
- };
257860
- }
257861
- function toMessage(r5) {
257862
- return {
257863
- id: String(r5["id"]),
257864
- sessionId: String(r5["session_id"]),
257865
- role: String(r5["role"]),
257866
- content: String(r5["content"] ?? ""),
257867
- seq: Number(r5["seq"]),
257868
- createdAt: isoReq(r5["created_at"]),
257869
- runId: str5(r5["run_id"]),
257870
- turnId: str5(r5["turn_id"]),
257871
- source: str5(r5["source"])
257872
- };
257873
- }
257874
- function toLink(r5) {
257875
- return { sessionId: String(r5["session_id"]), workOrderId: String(r5["work_order_id"]), linkedAt: isoReq(r5["linked_at"]) };
257876
- }
257877
- var iso4, isoReq, str5, num3, strArr, WORK_COLS, REVIEW_COLS, MAX_IDS, capIds, PgUnitDataSource;
257878
- var init_unit_data = __esm({
257879
- "../server/src/domains/trace/unit-data.ts"() {
257880
- "use strict";
257881
- iso4 = (v2) => v2 == null ? null : v2 instanceof Date ? v2.toISOString() : typeof v2 === "string" ? new Date(v2).toISOString() : null;
257882
- isoReq = (v2) => iso4(v2) ?? (/* @__PURE__ */ new Date(0)).toISOString();
257883
- str5 = (v2) => typeof v2 === "string" ? v2 : v2 == null ? null : String(v2);
257884
- num3 = (v2) => v2 == null ? null : Number.isFinite(Number(v2)) ? Number(v2) : null;
257885
- strArr = (v2) => Array.isArray(v2) ? v2.filter((x2) => typeof x2 === "string") : [];
257886
- WORK_COLS = `w.id, w.workorder_id, w.node_id, n.type AS node_type, n.title AS node_title, w.assignee_actor_id,
257887
- w.created_at, w.started_at, w.ended_at, w.dead_at, w.status, w.outcome, w.lane, w.continues_work_id,
257888
- w.acceptance_state, w.accepted_at, w.rejected_reason, w.override_by, w.override_reason, w.frozen_issue_ids,
257889
- w.protocol_recovery, w.kill_source, w.output_version_no`;
257890
- REVIEW_COLS = `r.id, r.workorder_id, r.node_id, n.title AS node_title, r.target_work_id, r.reviewer_actor_id, r.review_group,
257891
- r.status, r.verdict, r.note, r.created_at, r.started_at, r.ended_at, r.decided_at, r.cancelled_at, r.retry_at, r.kill_source`;
257892
- MAX_IDS = 500;
257893
- capIds = (ids2) => [...new Set(ids2)].slice(0, MAX_IDS);
257894
- PgUnitDataSource = class {
257895
- pool;
257896
- /** 引擎 schema(works / reviews / issues / events / workflow_*)。 */
257897
- e;
257898
- /** chat 一族(chat_sessions / chat_messages / chat_session_turns / 委派);缺省与引擎同 schema。 */
257899
- c;
257900
- /** 派发台账 schema(按 dispatches store 的口径净化)。 */
257901
- d;
257902
- constructor(opts) {
257903
- this.pool = opts.pool;
257904
- this.e = quoteSchema(opts.engineSchema);
257905
- this.c = quoteSchema(opts.chatSchema ?? opts.engineSchema);
257906
- this.d = dispatchSchemaIdent(opts.dispatchSchema);
257907
- }
257908
- async q(text7, values = []) {
257909
- return (await this.pool.query(text7, values)).rows;
257910
- }
257911
- /* ── work / review ── */
257912
- async getWorks(ids2) {
257913
- if (ids2.length === 0) return [];
257914
- const rows = await this.q(
257915
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id WHERE w.id = ANY($1)`,
257916
- [capIds(ids2)]
257917
- );
257918
- return rows.map(toWork);
257919
- }
257920
- async getReview(id) {
257921
- const rows = await this.q(
257922
- `SELECT ${REVIEW_COLS} FROM ${this.e}.reviews r LEFT JOIN ${this.e}.workflow_nodes n ON n.id = r.node_id WHERE r.id = $1`,
257923
- [id]
257924
- );
257925
- return rows[0] ? toReview(rows[0]) : null;
257926
- }
257927
- async reviewsOfWorks(workIds) {
257928
- if (workIds.length === 0) return [];
257929
- const rows = await this.q(
257930
- `SELECT ${REVIEW_COLS} FROM ${this.e}.reviews r LEFT JOIN ${this.e}.workflow_nodes n ON n.id = r.node_id
257931
- WHERE r.target_work_id = ANY($1) ORDER BY r.created_at ASC, r.id ASC LIMIT 500`,
257932
- [capIds(workIds)]
257933
- );
257934
- return rows.map(toReview);
257935
- }
257936
- async worksOfNode(nodeId, limit) {
257937
- const rows = await this.q(
257938
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
257939
- WHERE w.node_id = $1 ORDER BY w.created_at DESC, w.id DESC LIMIT $2`,
257940
- [nodeId, limit]
257941
- );
257942
- return rows.map(toWork);
257943
- }
257944
- async workInputsOf(workIds) {
257945
- if (workIds.length === 0) return [];
257946
- const rows = await this.q(
257947
- `SELECT work_id, upstream_node_id, upstream_work_id FROM ${this.e}.work_inputs WHERE work_id = ANY($1) LIMIT 2000`,
257948
- [capIds(workIds)]
257949
- );
257950
- return rows.map((r5) => ({
257951
- workId: String(r5["work_id"]),
257952
- upstreamNodeId: String(r5["upstream_node_id"]),
257953
- upstreamWorkId: String(r5["upstream_work_id"])
257954
- }));
257955
- }
257956
- async inputNodesOf(nodeId) {
257957
- const rows = await this.q(
257958
- `SELECT from_node_id FROM ${this.e}.workflow_edges WHERE to_node_id = $1 AND kind = 'data' ORDER BY from_node_id LIMIT 100`,
257959
- [nodeId]
257960
- );
257961
- return rows.map((r5) => String(r5["from_node_id"]));
257962
- }
257963
- async outputNodesOf(nodeId) {
257964
- const rows = await this.q(
257965
- `SELECT to_node_id FROM ${this.e}.workflow_edges WHERE from_node_id = $1 AND kind = 'data' ORDER BY to_node_id LIMIT 100`,
257966
- [nodeId]
257967
- );
257968
- return rows.map((r5) => String(r5["to_node_id"]));
257969
- }
257970
- async latestAcceptedWorkOfNodeBefore(nodeId, beforeIso) {
257971
- const rows = await this.q(
257972
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
257973
- WHERE w.node_id = $1 AND w.acceptance_state = 'accepted' AND w.accepted_at IS NOT NULL AND w.accepted_at <= $2
257974
- ORDER BY w.accepted_at DESC, w.id DESC LIMIT 1`,
257975
- [nodeId, beforeIso]
257976
- );
257977
- return rows[0] ? toWork(rows[0]) : null;
257978
- }
257979
- async worksAcceptedInWindow(nodeIds, fromIso, toIso2, limit) {
257980
- if (nodeIds.length === 0) return [];
257981
- const rows = await this.q(
257982
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
257983
- WHERE w.node_id = ANY($1) AND w.acceptance_state = 'accepted' AND w.accepted_at >= $2 AND w.accepted_at <= $3
257984
- ORDER BY w.accepted_at ASC, w.id ASC LIMIT $4`,
257985
- [capIds(nodeIds), fromIso, toIso2, limit]
257986
- );
257987
- return rows.map(toWork);
257988
- }
257989
- async reworkSourcesOf(work) {
257990
- const rows = await this.q(
257991
- `SELECT DISTINCT x.reason->>'workId' AS src
257992
- FROM (SELECT payload FROM ${this.e}.events
257993
- WHERE node_id = $1 AND kind = 'work.create' AND payload->>'workId' = $2
257994
- ORDER BY seq DESC LIMIT 20) ev,
257995
- LATERAL jsonb_array_elements(COALESCE(ev.payload->'reasons', '[]'::jsonb)) AS x(reason)
257996
- WHERE x.reason->>'kind' = 'rework' AND x.reason->>'workId' IS NOT NULL`,
257997
- [work.nodeId, work.id]
257998
- );
257999
- return rows.map((r5) => String(r5["src"]));
258000
- }
258001
- async reworkedBy(work) {
258002
- const viaCol = await this.q(
258003
- `SELECT id FROM ${this.e}.works WHERE node_id = $1 AND continues_work_id = $2 AND id <> $2 ORDER BY created_at ASC LIMIT 50`,
258004
- [work.nodeId, work.id]
258005
- );
258006
- const viaEvents = await this.q(
258007
- `SELECT DISTINCT ev.payload->>'workId' AS wid
258008
- FROM (SELECT payload FROM ${this.e}.events WHERE node_id = $1 AND kind = 'work.create' ORDER BY seq DESC LIMIT 200) ev,
258009
- LATERAL jsonb_array_elements(COALESCE(ev.payload->'reasons', '[]'::jsonb)) AS x(reason)
258010
- WHERE x.reason->>'kind' = 'rework' AND x.reason->>'workId' = $2`,
258011
- [work.nodeId, work.id]
258012
- );
258013
- const out = /* @__PURE__ */ new Set();
258014
- for (const r5 of viaCol) out.add(String(r5["id"]));
258015
- for (const r5 of viaEvents) if (r5["wid"] != null && r5["wid"] !== work.id) out.add(String(r5["wid"]));
258016
- return [...out];
258017
- }
258018
- async briefNodesOf(workorderId) {
258019
- const rows = await this.q(
258020
- `SELECT id FROM ${this.e}.workflow_nodes WHERE workorder_id = $1 AND type = 'brief' ORDER BY created_at ASC LIMIT 10`,
258021
- [workorderId]
258022
- );
258023
- return rows.map((r5) => String(r5["id"]));
258024
- }
258025
- /* ── issue ── */
258026
- async issuesByIds(ids2) {
258027
- if (ids2.length === 0) return [];
258028
- const rows = await this.q(`SELECT * FROM ${this.e}.issues WHERE id = ANY($1)`, [capIds(ids2)]);
258029
- return rows.map(toIssue);
258030
- }
258031
- async issuesInWorkorder(workorderId, q4) {
258032
- const args = [workorderId];
258033
- const conds = ["workorder_id = $1"];
258034
- const ors = [];
258035
- const push2 = (v2) => {
258036
- args.push(v2);
258037
- return `$${args.length}`;
258038
- };
258039
- if (q4.aboutWorkIds?.length) ors.push(`about_work_id = ANY(${push2(capIds(q4.aboutWorkIds))})`);
258040
- if (q4.aboutNodeIds?.length) ors.push(`about_node_id = ANY(${push2(capIds(q4.aboutNodeIds))})`);
258041
- if (q4.raisedByNodeIds?.length) ors.push(`raised_by_node_id = ANY(${push2(capIds(q4.raisedByNodeIds))})`);
258042
- if (ors.length) conds.push(`(${ors.join(" OR ")})`);
258043
- if (q4.fromIso) conds.push(`created_at >= ${push2(q4.fromIso)}`);
258044
- if (q4.toIso) conds.push(`created_at <= ${push2(q4.toIso)}`);
258045
- const rows = await this.q(
258046
- `SELECT * FROM ${this.e}.issues WHERE ${conds.join(" AND ")} ORDER BY created_at ASC, id ASC LIMIT ${push2(q4.limit)}`,
258047
- args
258048
- );
258049
- return rows.map(toIssue);
258050
- }
258051
- async worksHandlingIssues(workorderId, issueIds, limit) {
258052
- if (issueIds.length === 0) return [];
258053
- const ids2 = capIds(issueIds);
258054
- const rows = await this.q(
258055
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
258056
- WHERE w.workorder_id = $1
258057
- AND (w.id LIKE ANY($4::text[]) OR (jsonb_typeof(w.frozen_issue_ids) = 'array' AND w.frozen_issue_ids ?| $2))
258058
- ORDER BY w.created_at ASC, w.id ASC LIMIT $3`,
258059
- [workorderId, ids2, limit, ids2.map((i5) => `wk:reply:${i5.replace(/[\\%_]/g, (c5) => `\\${c5}`)}:%`)]
258060
- );
258061
- return rows.map(toWork);
258062
- }
258063
- /* ── dispatches ── */
258064
- async dispatchesOf(kind, targetIds) {
258065
- if (targetIds.length === 0) return [];
258066
- const rows = await this.q(
258067
- `SELECT id, target_kind, target_id, actor_id, created_at, started_at, ended_at, outcome, reason, protocol_recovery_round
258068
- FROM ${this.d}.dispatches WHERE target_kind = $1 AND target_id = ANY($2) ORDER BY created_at ASC, id ASC LIMIT 1000`,
258069
- [kind, capIds(targetIds)]
258070
- );
258071
- return rows.map(toDispatch);
258072
- }
258073
- async dispatchTargetOf(runId) {
258074
- const rows = await this.q(`SELECT target_kind, target_id FROM ${this.d}.dispatches WHERE id = $1`, [runId]);
258075
- const r5 = rows[0];
258076
- return r5 ? { targetKind: String(r5["target_kind"]), targetId: String(r5["target_id"]) } : null;
258077
- }
258078
- /* ── 委派 ── */
258079
- async getDelegation(id) {
258080
- const rows = await this.q(`SELECT * FROM ${this.c}.chat_session_delegations WHERE id = $1`, [id]);
258081
- return rows[0] ? toDelegation(rows[0]) : null;
258082
- }
258083
- async delegationByChildSession(childSessionId) {
258084
- const rows = await this.q(`SELECT * FROM ${this.c}.chat_session_delegations WHERE child_session_id = $1`, [childSessionId]);
258085
- return rows[0] ? toDelegation(rows[0]) : null;
258086
- }
258087
- async delegationsOfParent(parentSessionId, limit) {
258088
- const rows = await this.q(
258089
- `SELECT * FROM ${this.c}.chat_session_delegations WHERE parent_session_id = $1 ORDER BY created_at ASC, id ASC LIMIT $2`,
258090
- [parentSessionId, limit]
258091
- );
258092
- return rows.map(toDelegation);
258093
- }
258094
- async touchesOf(delegationId) {
258095
- const rows = await this.q(
258096
- `SELECT delegation_id, message_id, kind, at FROM ${this.c}.chat_session_delegation_touches
258097
- WHERE delegation_id = $1 ORDER BY at ASC LIMIT 500`,
258098
- [delegationId]
258099
- );
258100
- return rows.map((r5) => ({
258101
- delegationId: String(r5["delegation_id"]),
258102
- messageId: String(r5["message_id"]),
258103
- kind: String(r5["kind"]),
258104
- at: isoReq(r5["at"])
258105
- }));
258106
- }
258107
- /* ── 会话 / 轮次 / 消息 ── */
258108
- async getSession(id) {
258109
- const rows = await this.q(`SELECT * FROM ${this.c}.chat_sessions WHERE id = $1`, [id]);
258110
- return rows[0] ? toSession(rows[0]) : null;
258111
- }
258112
- async getTurn(id) {
258113
- const rows = await this.q(`SELECT * FROM ${this.c}.chat_session_turns WHERE id = $1`, [id]);
258114
- return rows[0] ? toTurn(rows[0]) : null;
258115
- }
258116
- async turnsOfSession(sessionId, limit) {
258117
- const rows = await this.q(
258118
- `SELECT * FROM ${this.c}.chat_session_turns WHERE chat_session_id = $1 ORDER BY reserved_at DESC, id DESC LIMIT $2`,
258119
- [sessionId, limit + 1]
258120
- );
258121
- const truncated = rows.length > limit;
258122
- const turns = (truncated ? rows.slice(0, limit) : rows).map(toTurn).reverse();
258123
- return { turns, truncated };
258124
- }
258125
- async getMessage(id) {
258126
- const rows = await this.q(`SELECT * FROM ${this.c}.chat_messages WHERE id = $1`, [id]);
258127
- return rows[0] ? toMessage(rows[0]) : null;
258128
- }
258129
- async messagesOf(sessionId, q4) {
258130
- const args = [sessionId];
258131
- const push2 = (v2) => {
258132
- args.push(v2);
258133
- return `$${args.length}`;
258134
- };
258135
- const conds = ["session_id = $1"];
258136
- if (q4.turnIds) {
258137
- const window3 = ["turn_id IS NULL"];
258138
- if (q4.fromIso) window3.push(`created_at >= ${push2(q4.fromIso)}`);
258139
- if (q4.toIso) window3.push(`created_at <= ${push2(q4.toIso)}`);
258140
- conds.push(`(turn_id = ANY(${push2(capIds(q4.turnIds))}) OR (${window3.join(" AND ")}))`);
258141
- } else {
258142
- if (q4.fromIso) conds.push(`created_at >= ${push2(q4.fromIso)}`);
258143
- if (q4.toIso) conds.push(`created_at <= ${push2(q4.toIso)}`);
258144
- }
258145
- if (q4.roles?.length) conds.push(`role = ANY(${push2(q4.roles)})`);
258146
- const rows = await this.q(
258147
- `SELECT id, session_id, role, content, seq, created_at, run_id, turn_id, source FROM ${this.c}.chat_messages
258148
- WHERE ${conds.join(" AND ")} ORDER BY seq ASC LIMIT ${push2(q4.limit)}`,
258149
- args
258150
- );
258151
- return rows.map(toMessage);
258152
- }
258153
- async pendingMessagesOf(sessionId, fromIso, toIso2, limit) {
258154
- const rows = await this.q(
258155
- `SELECT id, chat_session_id, text, created_at, state, flavour FROM ${this.c}.chat_pending_messages
258156
- WHERE chat_session_id = $1 AND created_at >= $2 AND created_at <= $3 ORDER BY seq ASC LIMIT $4`,
258157
- [sessionId, fromIso, toIso2, limit]
258158
- );
258159
- return rows.map((r5) => ({
258160
- id: String(r5["id"]),
258161
- chatSessionId: String(r5["chat_session_id"]),
258162
- text: String(r5["text"] ?? ""),
258163
- createdAt: isoReq(r5["created_at"]),
258164
- state: str5(r5["state"]),
258165
- flavour: str5(r5["flavour"])
258166
- }));
258167
- }
258168
- async originLinksOfWorkorder(workorderId) {
258169
- const rows = await this.q(
258170
- `SELECT session_id, work_order_id, linked_at FROM ${this.c}.chat_session_work_orders
258171
- WHERE work_order_id = $1 AND link_kind = 'origin' ORDER BY linked_at ASC LIMIT 20`,
258172
- [workorderId]
258173
- );
258174
- return rows.map(toLink);
258175
- }
258176
- async originLinksOfSession(sessionId) {
258177
- const rows = await this.q(
258178
- `SELECT session_id, work_order_id, linked_at FROM ${this.c}.chat_session_work_orders
258179
- WHERE session_id = $1 AND link_kind = 'origin' ORDER BY linked_at ASC LIMIT 200`,
258180
- [sessionId]
258181
- );
258182
- return rows.map(toLink);
258183
- }
258184
- /* ── find / peers 候选 ── */
258185
- async listEndedWorks(q4) {
258186
- const args = [];
258187
- const push2 = (v2) => {
258188
- args.push(v2);
258189
- return `$${args.length}`;
258190
- };
258191
- const conds = [`(w.ended_at IS NOT NULL OR w.dead_at IS NOT NULL)`, `w.acceptance_state IS DISTINCT FROM 'draft'`];
258192
- if (q4.sinceIso) conds.push(`COALESCE(w.ended_at, w.dead_at) >= ${push2(q4.sinceIso)}`);
258193
- if (q4.actorId) conds.push(`w.assignee_actor_id = ${push2(q4.actorId)}`);
258194
- if (q4.nodeType) conds.push(`n.type = ${push2(q4.nodeType)}`);
258195
- if (q4.lane) conds.push(`COALESCE(w.lane, CASE WHEN w.id LIKE 'wk:reply:%' THEN 'reply' ELSE 'main' END) = ${push2(q4.lane)}`);
258196
- const rows = await this.q(
258197
- `SELECT ${WORK_COLS} FROM ${this.e}.works w LEFT JOIN ${this.e}.workflow_nodes n ON n.id = w.node_id
258198
- WHERE ${conds.join(" AND ")} ORDER BY COALESCE(w.ended_at, w.dead_at) DESC, w.id DESC LIMIT ${push2(q4.limit)}`,
258199
- args
258200
- );
258201
- return rows.map(toWork);
258202
- }
258203
- async listEndedReviews(q4) {
258204
- const args = [];
258205
- const push2 = (v2) => {
258206
- args.push(v2);
258207
- return `$${args.length}`;
258208
- };
258209
- const endExpr = `COALESCE(r.ended_at, r.decided_at, r.cancelled_at, r.created_at)`;
258210
- const conds = [`r.status IN ('accept','reject','failed','dead')`];
258211
- if (q4.sinceIso) conds.push(`${endExpr} >= ${push2(q4.sinceIso)}`);
258212
- if (q4.actorId) conds.push(`r.reviewer_actor_id = ${push2(q4.actorId)}`);
258213
- const rows = await this.q(
258214
- `SELECT ${REVIEW_COLS} FROM ${this.e}.reviews r LEFT JOIN ${this.e}.workflow_nodes n ON n.id = r.node_id
258215
- WHERE ${conds.join(" AND ")} ORDER BY ${endExpr} DESC, r.id DESC LIMIT ${push2(q4.limit)}`,
258216
- args
258217
- );
258218
- return rows.map(toReview);
258219
- }
258220
- async listEndedDelegations(q4) {
258221
- const args = [];
258222
- const push2 = (v2) => {
258223
- args.push(v2);
258224
- return `$${args.length}`;
258225
- };
258226
- const conds = [`state IN ('done','failed')`];
258227
- if (q4.sinceIso) conds.push(`COALESCE(settled_at, created_at) >= ${push2(q4.sinceIso)}`);
258228
- if (q4.actorId) conds.push(`expert_actor_id = ${push2(q4.actorId)}`);
258229
- const rows = await this.q(
258230
- `SELECT * FROM ${this.c}.chat_session_delegations WHERE ${conds.join(" AND ")}
258231
- ORDER BY COALESCE(settled_at, created_at) DESC, id DESC LIMIT ${push2(q4.limit)}`,
258232
- args
258233
- );
258234
- return rows.map(toDelegation);
258235
- }
258236
- async listRecentSessions(q4) {
258237
- const args = [];
258238
- const push2 = (v2) => {
258239
- args.push(v2);
258240
- return `$${args.length}`;
258241
- };
258242
- const conds = [`NOT EXISTS (SELECT 1 FROM ${this.c}.chat_session_delegations d WHERE d.child_session_id = s.id)`];
258243
- if (!q4.includeAnalysis) conds.push(`s.analyzed_run_id IS NULL`);
258244
- if (q4.sinceIso) conds.push(`s.touched_at >= ${push2(q4.sinceIso)}`);
258245
- if (q4.aiActorId) conds.push(`s.ai_actor_id = ${push2(q4.aiActorId)}`);
258246
- const rows = await this.q(
258247
- `SELECT s.id, s.human_actor_id, s.ai_actor_id, s.title, s.analyzed_run_id, s.runtime_session_id, s.touched_at, s.created_at
258248
- FROM ${this.c}.chat_sessions s WHERE ${conds.join(" AND ")} ORDER BY s.touched_at DESC, s.id DESC LIMIT ${push2(q4.limit)}`,
258249
- args
258250
- );
258251
- return rows.map(toSession);
258252
- }
258253
- };
258254
- }
258255
- });
258256
-
258257
258346
  // ../server/src/domains/trace/index.ts
258258
258347
  function createTraceDomain(opts) {
258259
258348
  const service = new TraceService({ store: opts.store });
@@ -261512,7 +261601,7 @@ function shown(field, v2, nameOf2) {
261512
261601
  if (v2 === void 0 || v2 === "") return "\uFF08\u7A7A\uFF09";
261513
261602
  if (field === "dueDate" || field === "startDate") return formatTodoDue(v2);
261514
261603
  if (field === "assignee") return nameOf2(v2);
261515
- return clip5(v2);
261604
+ return clip4(v2);
261516
261605
  }
261517
261606
  function assignedTitle(who2, todo) {
261518
261607
  return `${who2} \u6D3E\u7ED9\u4F60\uFF1A${todo.title}\uFF0C${formatTodoSpan(todo)}`;
@@ -261523,13 +261612,13 @@ function unseenTitle(assigneeName, todo) {
261523
261612
  function changedTitle(who2, todo, changes, nameOf2) {
261524
261613
  const parts = changes.map((c5) => `${FIELD_LABEL[c5.field] ?? c5.field} ${shown(c5.field, c5.oldValue, nameOf2)} \u2192 ${shown(c5.field, c5.newValue, nameOf2)}`);
261525
261614
  const reason2 = changes.find((c5) => c5.reason)?.reason;
261526
- return `${who2} \u6539\u4E86\u300C${todo.title}\u300D\uFF1A${parts.join("\uFF1B")}${reason2 ? `\uFF1B\u539F\u56E0\uFF1A${clip5(reason2)}` : ""}`;
261615
+ return `${who2} \u6539\u4E86\u300C${todo.title}\u300D\uFF1A${parts.join("\uFF1B")}${reason2 ? `\uFF1B\u539F\u56E0\uFF1A${clip4(reason2)}` : ""}`;
261527
261616
  }
261528
261617
  function statusTitle(who2, todo, kind, reason2, result) {
261529
261618
  const verb = kind === "todo-done" ? "\u5B8C\u6210\u4E86" : kind === "todo-reopened" ? "\u91CD\u65B0\u6253\u5F00\u4E86" : "\u53D6\u6D88\u4E86";
261530
- return `${who2} ${verb}\u300C${todo.title}\u300D${result ? `\uFF1B\u7ED3\u679C\uFF1A${clip5(result)}` : ""}${reason2 ? `\uFF1B\u539F\u56E0\uFF1A${clip5(reason2)}` : ""}`;
261619
+ return `${who2} ${verb}\u300C${todo.title}\u300D${result ? `\uFF1B\u7ED3\u679C\uFF1A${clip4(result)}` : ""}${reason2 ? `\uFF1B\u539F\u56E0\uFF1A${clip4(reason2)}` : ""}`;
261531
261620
  }
261532
- var VALUE_MAX, FIELD_LABEL, clip5, todoAssignedSourceKey, todoChangeSourceKey, todoUnseenSourceKey;
261621
+ var VALUE_MAX, FIELD_LABEL, clip4, todoAssignedSourceKey, todoChangeSourceKey, todoUnseenSourceKey;
261533
261622
  var init_notices = __esm({
261534
261623
  "../server/src/domains/todos/notices.ts"() {
261535
261624
  "use strict";
@@ -261546,7 +261635,7 @@ var init_notices = __esm({
261546
261635
  assignee: "\u627F\u63A5\u4EBA",
261547
261636
  result: "\u7ED3\u679C\u5728\u54EA"
261548
261637
  };
261549
- clip5 = (v2) => v2.length > VALUE_MAX ? `${v2.slice(0, VALUE_MAX)}\u2026` : v2;
261638
+ clip4 = (v2) => v2.length > VALUE_MAX ? `${v2.slice(0, VALUE_MAX)}\u2026` : v2;
261550
261639
  todoAssignedSourceKey = (todoId) => `todo:${todoId}@assigned`;
261551
261640
  todoChangeSourceKey = (todoId, changeId) => `todo:${todoId}@change:${changeId}`;
261552
261641
  todoUnseenSourceKey = (todo) => `todo:${todo.id}@unseen:${todo.dueDate}`;
@@ -327226,6 +327315,7 @@ __export(src_exports2, {
327226
327315
  shouldInjectResumePack: () => shouldInjectResumePack,
327227
327316
  shouldPush: () => shouldPush,
327228
327317
  singlePushPayload: () => singlePushPayload,
327318
+ skillManifestForActor: () => skillManifestForActor,
327229
327319
  skillsDirForRuntime: () => skillsDirForRuntime,
327230
327320
  splitKnowledgeChunks: () => splitKnowledgeChunks,
327231
327321
  stableChatTraceRunId: () => stableChatTraceRunId,
@@ -331029,6 +331119,18 @@ function skillContentHash(files) {
331029
331119
  }
331030
331120
  return `sha256:${h5.digest("hex")}`;
331031
331121
  }
331122
+ function inMemorySkillFiles(skillId, pools) {
331123
+ const toFiles = (files) => Object.entries(files).map(([path50, content3]) => ({ path: path50, content: content3 }));
331124
+ if (skillId.startsWith("builtin:")) {
331125
+ const b6 = pools.builtins.find((x2) => `builtin:${x2.id}` === skillId);
331126
+ return b6 ? toFiles(b6.files) : null;
331127
+ }
331128
+ if (skillId.startsWith("connector:")) {
331129
+ const c5 = pools.connectorSkills.find((x2) => x2.id === skillId);
331130
+ return c5 ? toFiles(c5.files) : null;
331131
+ }
331132
+ return void 0;
331133
+ }
331032
331134
  function scopedTrace(trace, scope2) {
331033
331135
  if (scope2.companyScoped) return trace;
331034
331136
  const allows = traceReadAllows(scope2);
@@ -331154,7 +331256,10 @@ ${f6.content}`).join("\n\n");
331154
331256
  const svc = await exposureServiceFor(cid, await deps.traceStoreFor(cid), reflection);
331155
331257
  await svc.recordDispatch({
331156
331258
  runId: input.runId,
331157
- skills: await deps.listSkills(cid, input.actorId, { builtins: input.builtins }),
331259
+ skills: await deps.listSkills(cid, input.actorId, {
331260
+ builtins: input.builtins,
331261
+ ...input.chatSessionId !== void 0 ? { chatSessionId: input.chatSessionId } : {}
331262
+ }),
331158
331263
  memories: input.memories ? input.memories.map((m4) => ({ memId: m4.memId, version: m4.version })) : null
331159
331264
  });
331160
331265
  })().catch((e5) => log3(`[reflection] ${cid} chat run ${input.runId} \u57CB\u70B9\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u5BF9\u8BDD\uFF09\uFF1A${String(e5)}`));
@@ -334938,9 +335043,12 @@ async function startServe(opts) {
334938
335043
  traceReadScopeFor: (cid) => traceReadScopeFor(cid),
334939
335044
  blobStoreFor: (cid) => blobStoreFor(cid),
334940
335045
  readBundleFile: (id, rel) => trajReader.readBundleFile(id, rel),
335046
+ // 与 `GET /api/skill-cache/manifest` 同一个函数、同一组参数(ADR 0641 §3.3):内置按会话 claim 投影
335047
+ //(管理者会话不给委派变体),连接器技能按该员工启用的 connector 门禁——节点拿到什么就记什么。
334941
335048
  listSkills: async (cid, actorId, o3) => {
334942
335049
  const { service } = await actors.resolveCtx(cid);
334943
- return listSkillMetadataForActor({ service, actorId, ...o3.builtins ? { builtins: builtinSkills } : {} });
335050
+ const builtins = o3.builtins ? await chatBuiltinSkillsForClaim(o3.chatSessionId ? { chatSessionId: o3.chatSessionId, companyId: cid } : void 0) : [];
335051
+ return skillManifestForActor({ service, actorId, builtins, connectorSkills });
334944
335052
  },
334945
335053
  readMemories: async (cid, actorId, memIds) => {
334946
335054
  const svc = await actorMemoryFor(cid);
@@ -334957,11 +335065,8 @@ async function startServe(opts) {
334957
335065
  return cfg ? { prompt: cfg.prompt ?? "", version: cfg.version } : null;
334958
335066
  },
334959
335067
  readSkillFiles: async (cid, skillId) => {
334960
- if (skillId.startsWith("builtin:")) {
334961
- const b6 = builtinSkills.find((x2) => `builtin:${x2.id}` === skillId);
334962
- return b6 ? Object.entries(b6.files).map(([path50, content3]) => ({ path: path50, content: content3 })) : null;
334963
- }
334964
- if (skillId.startsWith("connector:")) return null;
335068
+ const mem = inMemorySkillFiles(skillId, { builtins: effectiveBuiltinSkills(), connectorSkills });
335069
+ if (mem !== void 0) return mem;
334965
335070
  const files = await (await actors.resolveCtx(cid)).service.listSkillFiles(skillId).catch(() => []);
334966
335071
  return files.length ? files.map((f6) => ({ path: f6.path, content: f6.content })) : null;
334967
335072
  },
@@ -336475,6 +336580,7 @@ async function startServe(opts) {
336475
336580
  actorId,
336476
336581
  turnId: chatTurnId,
336477
336582
  builtins: !isolatedBackground,
336583
+ ...chatSessionId !== void 0 ? { chatSessionId } : {},
336478
336584
  memories: chatInjectedMemories,
336479
336585
  files: { ...files },
336480
336586
  systemPromptFingerprint: null
@@ -343820,18 +343926,24 @@ var COMMAND_DECLS = {
343820
343926
  },
343821
343927
  "trace outcome": {
343822
343928
  group: "\u6267\u884C\u8BB0\u5F55\uFF08trace\uFF09",
343823
- usage: "oasis trace outcome <unit> [--json]",
343824
- description: "\u539F\u59CB\u7ED3\u679C\u4FE1\u53F7\uFF08\u72B6\u6001\u3001\u9A8C\u6536\u3001\u8BC4\u5BA1 verdict \u4E0E note\u3001issue\u3001\u8FD4\u5DE5\u3001\u5F3A\u5236\u901A\u8FC7\u3001\u53EB\u505C\u3001\u63D2\u8BDD\u3001\u8FFD\u95EE\u2026\u2026\uFF09\uFF0C\u5E73\u53F0\u4E0D\u4E0B\u7ED3\u8BBA\uFF0C\u6027\u8D28\u7531\u4F60\u5224\u65AD\u3002",
343929
+ usage: "oasis trace outcome <unit> [--full] [--json]",
343930
+ description: "\u539F\u59CB\u7ED3\u679C\u4FE1\u53F7\uFF08\u72B6\u6001\u3001\u9A8C\u6536\u3001\u8BC4\u5BA1 verdict \u4E0E note\u3001issue\u3001\u8FD4\u5DE5\u3001\u5F3A\u5236\u901A\u8FC7\u3001\u53EB\u505C\u3001\u63D2\u8BDD\u3001\u8FFD\u95EE\u2026\u2026\uFF09\uFF0C\u5E73\u53F0\u4E0D\u4E0B\u7ED3\u8BBA\uFF0C\u6027\u8D28\u7531\u4F60\u5224\u65AD\u3002issue / \u63D2\u8BDD / \u8FFD\u95EE\u539F\u6587\u8FC7\u957F\u65F6\u622A\u65AD\u5E76\u5E26 `[\u5DF2\u7701\u7565 N \u5B57 \u2192 oasis trace outcome <unit> --full]`\u3002",
343825
343931
  positional: [{ name: "<unit>", required: true, desc: "\u5355\u5143 id \u6216 run id" }],
343826
- flags: [{ name: "json", desc: "\u8F93\u51FA\u5951\u7EA6 JSON", boolean: true, own: true }],
343932
+ flags: [
343933
+ { name: "full", desc: "\u957F\u6587\u672C\u4E0D\u622A\u65AD", boolean: true, own: true },
343934
+ { name: "json", desc: "\u8F93\u51FA\u5951\u7EA6 JSON", boolean: true, own: true }
343935
+ ],
343827
343936
  examples: ["oasis trace outcome dlg:7f2c"]
343828
343937
  },
343829
343938
  "trace exogenous": {
343830
343939
  group: "\u6267\u884C\u8BB0\u5F55\uFF08trace\uFF09",
343831
- usage: "oasis trace exogenous <unit> [--json]",
343832
- description: "\u5916\u90E8\u56E0\u7D20\u4E8B\u5B9E\uFF1Arun \u8D85\u65F6 / \u88AB\u6740 / \u5931\u8054\u3001\u767B\u5F55\u5931\u6548\u4E0E\u989D\u5EA6\u4E00\u7C7B\u9519\u8BEF\u7801\u3001\u6362\u673A\u3001\u7CFB\u7EDF\u539F\u56E0\u7684\u53EB\u505C\u3001\u534F\u8BAE\u6062\u590D\u3001\u4E0A\u6E38 issue\u3001\u6267\u884C\u671F\u95F4\u9700\u6C42\u53D8\u4E86\u3002\u53CD\u601D\u65F6\u5148\u770B\u5B83\uFF0C\u5C5E\u4E8E\u5916\u90E8\u539F\u56E0\u7684\u6539\u8FDB\u70B9\u6807 category=external\u3002",
343940
+ usage: "oasis trace exogenous <unit> [--full] [--json]",
343941
+ description: "\u5916\u90E8\u56E0\u7D20\u4E8B\u5B9E\uFF1Arun \u8D85\u65F6 / \u88AB\u6740 / \u5931\u8054\u3001\u767B\u5F55\u5931\u6548\u4E0E\u989D\u5EA6\u4E00\u7C7B\u9519\u8BEF\u7801\u3001\u6362\u673A\u3001\u7CFB\u7EDF\u539F\u56E0\u7684\u53EB\u505C\u3001\u534F\u8BAE\u6062\u590D\u3001\u4E0A\u6E38 issue\u3001\u6267\u884C\u671F\u95F4\u9700\u6C42\u53D8\u4E86\u3002\u53CD\u601D\u65F6\u5148\u770B\u5B83\uFF0C\u5C5E\u4E8E\u5916\u90E8\u539F\u56E0\u7684\u6539\u8FDB\u70B9\u6807 category=external\u3002\u6BCF\u6761\u4E8B\u5B9E\u4E0B\u65B9\u7F29\u8FDB\u6253\u51FA run \u7684\u9519\u8BEF\u4FE1\u606F\u4E0E\u4E0A\u6E38 issue \u6B63\u6587\uFF1B\u8FC7\u957F\u65F6\u622A\u65AD\u5E76\u5E26 `[\u5DF2\u7701\u7565 N \u5B57 \u2192 oasis trace exogenous <unit> --full]`\uFF0C\u52A0 --full \u6253\u51FA\u5168\u6587\u3002",
343833
343942
  positional: [{ name: "<unit>", required: true, desc: "\u5355\u5143 id \u6216 run id" }],
343834
- flags: [{ name: "json", desc: "\u8F93\u51FA\u5951\u7EA6 JSON", boolean: true, own: true }],
343943
+ flags: [
343944
+ { name: "full", desc: "\u957F\u6587\u672C\u4E0D\u622A\u65AD", boolean: true, own: true },
343945
+ { name: "json", desc: "\u8F93\u51FA\u5951\u7EA6 JSON", boolean: true, own: true }
343946
+ ],
343835
343947
  examples: ["oasis trace exogenous wk:n-abc:2"]
343836
343948
  },
343837
343949
  "trace runs": {
@@ -344881,6 +344993,7 @@ function buildTraceRequest(sub, positional, flags, now = Date.now()) {
344881
344993
  return { method: "GET", path: `${unitPath("brief")}${qs({ budget: intFlag(flags, "budget", 6e3, 1) })}` };
344882
344994
  case "outcome":
344883
344995
  case "exogenous":
344996
+ return { method: "GET", path: `${unitPath(sub)}${qs({ full: on(flags, "full") ? 1 : void 0 })}` };
344884
344997
  case "runs":
344885
344998
  return { method: "GET", path: unitPath(sub) };
344886
344999
  case "events": {
@@ -344948,6 +345061,9 @@ var fmtMs = (ms2) => {
344948
345061
  return s3 < 120 ? `${s3}s` : `${Math.round(s3 / 60)}min`;
344949
345062
  };
344950
345063
  var scalar = (v2) => typeof v2 === "string" ? v2 : JSON.stringify(v2);
345064
+ var isTruncatedField = (v2) => typeof v2 === "object" && v2 !== null && typeof v2.text === "string" && typeof v2.truncated === "boolean" && typeof v2.fullChars === "number";
345065
+ var EXOGENOUS_TEXT_LABELS = { errorMessage: "\u9519\u8BEF\u4FE1\u606F", body: "\u6B63\u6587" };
345066
+ var EXOGENOUS_TEXT_INDENT = " ";
344951
345067
  function renderEventPreview(e5, opts = {}) {
344952
345068
  const head = `#${e5.seq} [${e5.eventType}] ${e5.kind}${e5.toolName ? ` ${e5.toolName}` : ""}${e5.level === "error" ? " \u26A0error" : ""}`;
344953
345069
  const tail = e5.ingestTruncated ? " [\u5165\u5E93\u524D\u5DF2\u88AB\u9002\u914D\u5668\u622A\u65AD\uFF0C\u539F\u6837\u7ED9\u51FA]" : "";
@@ -344986,7 +345102,14 @@ function renderTrace(sub, data, flags, println) {
344986
345102
  return;
344987
345103
  }
344988
345104
  println(`${r5.unitId} \u7684\u5916\u90E8\u56E0\u7D20\uFF08${r5.facts.length} \u6761\uFF09\uFF1A`);
344989
- for (const f6 of r5.facts) println(` [${f6.kind}] ${orDash(f6.at)}${f6.runId ? ` ${f6.runId}` : ""} ${oneLine3(f6.summary)}`);
345105
+ for (const f6 of r5.facts) {
345106
+ println(` [${f6.kind}] ${orDash(f6.at)}${f6.runId ? ` ${f6.runId}` : ""} ${oneLine3(f6.summary)}`);
345107
+ for (const [k6, v2] of Object.entries(f6.detail ?? {})) {
345108
+ if (!isTruncatedField(v2)) continue;
345109
+ println(` ${EXOGENOUS_TEXT_LABELS[k6] ?? k6}\uFF08\u5171 ${v2.fullChars} \u5B57${v2.truncated ? `\uFF0C\u5DF2\u622A\u65AD\uFF0C\u53D6\u5168\u6587\uFF1A${v2.fetchCmd}` : ""}\uFF09\uFF1A`);
345110
+ println(v2.text.replace(/^/gm, EXOGENOUS_TEXT_INDENT));
345111
+ }
345112
+ }
344990
345113
  return;
344991
345114
  }
344992
345115
  case "runs": {
@@ -345915,7 +346038,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback2) {
345915
346038
  }
345916
346039
  }
345917
346040
  }
345918
- var CLI_VERSION = "2.2.125" ? "2.2.125" : "dev";
346041
+ var CLI_VERSION = "2.2.127" ? "2.2.127" : "dev";
345919
346042
  function apiHeaders(token2, company) {
345920
346043
  const headers = {
345921
346044
  authorization: `Bearer ${token2}`,
@@ -346721,16 +346844,17 @@ ${round.text}`);
346721
346844
  { to, task, ...flags.get("as") ? { as: flags.get("as") } : {}, ...fileArgs.length ? { files: fileArgs } : {} }
346722
346845
  );
346723
346846
  if (asJson2) {
346724
- const overlap = await overlapLines("delegate", task, started.delegationId);
346725
- println(JSON.stringify({ ...started, ...overlap.length ? { overlap } : {} }, null, 2));
346847
+ const overlap2 = await overlapLines("delegate", task, started.delegationId);
346848
+ println(JSON.stringify({ ...started, ...overlap2.length ? { overlap: overlap2 } : {} }, null, 2));
346726
346849
  break;
346727
346850
  }
346728
346851
  println(`\u5DF2\u4EA4\u7ED9 ${to} \u53BB\u505A\uFF08\u5F02\u6B65\uFF0C\u4E0D\u7528\u7B49\uFF09\u3002`);
346729
346852
  println(` \u77ED\u540D\uFF08--follow-up \u7528\u8FD9\u4E2A\uFF09\uFF1A${started.label}`);
346730
346853
  println(` delegationId\uFF1A${started.delegationId}`);
346731
346854
  if (started.attachedFiles?.length) println(` \u5E26\u8FC7\u53BB\u7684\u6587\u4EF6\uFF1A${started.attachedFiles.join("\u3001")}`);
346732
- println("\u7ED3\u679C\u5E72\u5B8C\u4E86\u4F1A\u81EA\u5DF1\u56DE\u5230\u8FD9\u6761\u5BF9\u8BDD\u3002\u8FD9\u4E00\u8F6E\u5148\u6536\u5C3E\u2014\u2014\u53EF\u4EE5\u987A\u624B\u8DDF\u7528\u6237\u8BF4\u4E00\u53E5\u4F60\u628A\u8FD9\u4EF6\u4E8B\u6D3E\u51FA\u53BB\u4E86\u3002");
346733
- await printOverlap("delegate", task, started.delegationId);
346855
+ const overlap = await overlapLines("delegate", task, started.delegationId);
346856
+ for (const line2 of overlap) println(line2);
346857
+ println(overlap.length ? "\u7ED3\u679C\u5E72\u5B8C\u4E86\u4F1A\u81EA\u5DF1\u56DE\u5230\u8FD9\u6761\u5BF9\u8BDD\u3002\u6536\u5C3E\u524D\u5148\u6309\u4E0A\u9762\u300C\u76F8\u8FD1\u7684\u4E8B\u9879\u300D\u9010\u6761\u67E5\u5B8C\uFF08\u786E\u5B9E\u76F8\u5173\u624D\u987A\u5E26\u544A\u8BC9\u7528\u6237\uFF09\uFF0C\u7136\u540E\u8FD9\u4E00\u8F6E\u5C31\u6536\u5C3E\u2014\u2014\u4E0D\u7528\u7B49\u4E13\u5BB6\u3002" : "\u7ED3\u679C\u5E72\u5B8C\u4E86\u4F1A\u81EA\u5DF1\u56DE\u5230\u8FD9\u6761\u5BF9\u8BDD\u3002\u8FD9\u4E00\u8F6E\u5148\u6536\u5C3E\u2014\u2014\u53EF\u4EE5\u987A\u624B\u8DDF\u7528\u6237\u8BF4\u4E00\u53E5\u4F60\u628A\u8FD9\u4EF6\u4E8B\u6D3E\u51FA\u53BB\u4E86\u3002");
346734
346858
  break;
346735
346859
  }
346736
346860
  case "kb": {
@@ -350228,7 +350352,7 @@ function shimScript() {
350228
350352
  }
350229
350353
 
350230
350354
  // src/index.ts
350231
- var PKG_VERSION = true ? "2.2.125" : "dev";
350355
+ var PKG_VERSION = true ? "2.2.127" : "dev";
350232
350356
  var LOCAL_BIN = localBin();
350233
350357
  var NPM_PREFIX = npmPrefix();
350234
350358
  var INSTANCE = DEFAULT_INSTANCE;