oasis_test_v2 2.2.67 → 2.2.68

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 +247 -16
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1303,6 +1303,15 @@ var init_telemetry = __esm({
1303
1303
  });
1304
1304
 
1305
1305
  // ../contract/src/trace.ts
1306
+ function legacyScopeIsEmpty(scope2) {
1307
+ return scope2.artifactIds.length === 0 && scope2.chatSessionIds.length === 0 && (scope2.runtimeInstanceIds?.length ?? 0) === 0;
1308
+ }
1309
+ function legacyScopeMatcher(scope2) {
1310
+ const artifacts = new Set(scope2.artifactIds);
1311
+ const sessions = new Set(scope2.chatSessionIds);
1312
+ const runtimes = new Set(scope2.runtimeInstanceIds ?? []);
1313
+ return (run) => run.artifactId != null && artifacts.has(run.artifactId) || run.chatSessionId != null && sessions.has(run.chatSessionId) || run.runtimeInstanceId != null && runtimes.has(run.runtimeInstanceId);
1314
+ }
1306
1315
  var DISPLAY_CNY_PER_USD, USAGE_POINT_FINAL_SEQ;
1307
1316
  var init_trace = __esm({
1308
1317
  "../contract/src/trace.ts"() {
@@ -215505,6 +215514,7 @@ var init_memory_trace_store = __esm({
215505
215514
  return run ? this.decorate(structuredClone(run)) : null;
215506
215515
  }
215507
215516
  async listRuns(filter) {
215517
+ const inScope2 = filter.legacyScope ? legacyScopeMatcher(filter.legacyScope) : null;
215508
215518
  let items = [...this.runs.values()].filter((r) => {
215509
215519
  if (filter.actorId && r.actorId !== filter.actorId) return false;
215510
215520
  if (filter.artifactId && r.artifactId !== filter.artifactId) return false;
@@ -215512,6 +215522,7 @@ var init_memory_trace_store = __esm({
215512
215522
  if (filter.runtimeKind && r.runtimeKind !== filter.runtimeKind) return false;
215513
215523
  if (filter.status && r.status !== filter.status) return false;
215514
215524
  if (filter.rootRunId && r.rootRunId !== filter.rootRunId) return false;
215525
+ if (inScope2 && !inScope2(r)) return false;
215515
215526
  if (filter.from && r.startedAt < filter.from) return false;
215516
215527
  if (filter.to && r.startedAt > filter.to) return false;
215517
215528
  if (filter.excludeAnalysis) {
@@ -216223,6 +216234,7 @@ var init_memory_trace_store = __esm({
216223
216234
  }
216224
216235
  /** 按维度查聚合用量。 */
216225
216236
  async queryUsageStats(filter) {
216237
+ if (filter.legacyScope) return this.queryUsageStatsScoped(filter, filter.legacyScope);
216226
216238
  const gran = filter.granularity ?? "hour";
216227
216239
  const out = [];
216228
216240
  for (const row of this.usageAggregates.values()) {
@@ -216250,6 +216262,59 @@ var init_memory_trace_store = __esm({
216250
216262
  }
216251
216263
  return out.sort((a, b2) => a.bucket < b2.bucket ? 1 : a.bucket > b2.bucket ? -1 : a.actorId.localeCompare(b2.actorId));
216252
216264
  }
216265
+ /**
216266
+ * legacy 共享账本上的按维度用量:绕开聚合行、按租户谓词从 runs 现算
216267
+ * (与 PostgresTraceStore.queryUsageStatsScoped 同口径——聚合行里没有 artifact / chat_session,
216268
+ * 表达不了归属;共用同一份 run 才能对上数)。
216269
+ */
216270
+ async queryUsageStatsScoped(filter, scope2) {
216271
+ if (legacyScopeIsEmpty(scope2)) return [];
216272
+ const inScope2 = legacyScopeMatcher(scope2);
216273
+ const gran = filter.granularity ?? "hour";
216274
+ const acc = /* @__PURE__ */ new Map();
216275
+ for (const run of this.runs.values()) {
216276
+ if (run.usage == null) continue;
216277
+ if (!inScope2(run)) continue;
216278
+ if (filter.actorIds?.length && !filter.actorIds.includes(run.actorId)) continue;
216279
+ if (filter.runtimeInstanceIds?.length && !filter.runtimeInstanceIds.includes(run.runtimeInstanceId ?? "")) continue;
216280
+ if (filter.runtimeKinds?.length && !filter.runtimeKinds.includes(run.runtimeKind)) continue;
216281
+ if (filter.effectiveModels?.length && !filter.effectiveModels.includes(run.effectiveModel ?? "")) continue;
216282
+ const started = new Date(run.startedAt);
216283
+ const bucket2 = gran === "day" ? this.truncDayISO(started) : this.truncHourISO(started);
216284
+ if (filter.from && bucket2 < (gran === "day" ? this.truncDayISO(new Date(filter.from)) : this.truncHourISO(new Date(filter.from)))) continue;
216285
+ if (filter.to && bucket2 > filter.to) continue;
216286
+ const u = run.usage;
216287
+ const input = u.inputTokens ?? 0;
216288
+ const output = u.outputTokens ?? 0;
216289
+ const key2 = `${run.actorId}|${run.runtimeInstanceId ?? ""}|${run.effectiveModel ?? ""}|${bucket2}`;
216290
+ const row = acc.get(key2);
216291
+ if (row) {
216292
+ row.runCount += 1;
216293
+ row.inputTokens += input;
216294
+ row.outputTokens += output;
216295
+ row.totalTokens += u.totalTokens ?? input + output;
216296
+ row.cacheReadTokens += u.cacheReadTokens ?? 0;
216297
+ row.cacheCreationTokens += u.cacheCreationTokens ?? 0;
216298
+ row.costUsdMicros += u.costUsdMicros ?? 0;
216299
+ } else {
216300
+ acc.set(key2, {
216301
+ actorId: run.actorId,
216302
+ runtimeInstanceId: run.runtimeInstanceId ?? null,
216303
+ runtimeKind: run.runtimeKind,
216304
+ effectiveModel: run.effectiveModel ?? null,
216305
+ bucket: bucket2,
216306
+ runCount: 1,
216307
+ inputTokens: input,
216308
+ outputTokens: output,
216309
+ totalTokens: u.totalTokens ?? input + output,
216310
+ cacheReadTokens: u.cacheReadTokens ?? 0,
216311
+ cacheCreationTokens: u.cacheCreationTokens ?? 0,
216312
+ costUsdMicros: u.costUsdMicros ?? 0
216313
+ });
216314
+ }
216315
+ }
216316
+ return [...acc.values()].sort((a, b2) => a.bucket < b2.bucket ? 1 : a.bucket > b2.bucket ? -1 : a.actorId.localeCompare(b2.actorId));
216317
+ }
216253
216318
  };
216254
216319
  }
216255
216320
  });
@@ -244209,8 +244274,14 @@ var init_service7 = __esm({
244209
244274
  listRunLinks(runId) {
244210
244275
  return this.store.listRunLinks(runId);
244211
244276
  }
244212
- /** run 详情聚合(§4.3):run + links + toolCalls + children + 派生 stats。 */
244213
- async getRunDetail(id) {
244277
+ /**
244278
+ * run 详情聚合(§4.3):run + links + toolCalls + children + 派生 stats。
244279
+ *
244280
+ * `scopeFilters` 由调用方给(HTTP 读面传租户闸门,内部调用不给):子 run 是用
244281
+ * `listRuns({ rootRunId })` 捞的,共享 legacy 账本上这一步必须带同一条归属谓词,
244282
+ * 否则详情页的「子运行」会成为列表谓词之外的第二个出口。
244283
+ */
244284
+ async getRunDetail(id, scopeFilters = (f2) => f2) {
244214
244285
  const run = await this.store.getRun(id);
244215
244286
  if (!run) return null;
244216
244287
  const [links, toolCalls, events] = await Promise.all([
@@ -244218,7 +244289,7 @@ var init_service7 = __esm({
244218
244289
  this.store.listToolCalls(id),
244219
244290
  this.store.listEvents(id, {})
244220
244291
  ]);
244221
- const sameRoot = await this.store.listRuns({ rootRunId: run.rootRunId, limit: 1e3 });
244292
+ const sameRoot = await this.store.listRuns(scopeFilters({ rootRunId: run.rootRunId, limit: 1e3 }));
244222
244293
  const children = sameRoot.items.filter((r) => r.parentRunId === id).map((r) => this.withDisplayCost(r));
244223
244294
  const stats = {
244224
244295
  eventCount: events.length,
@@ -244229,9 +244300,14 @@ var init_service7 = __esm({
244229
244300
  };
244230
244301
  return { run: this.withDisplayCost(run), links, toolCalls, children, stats };
244231
244302
  }
244232
- /** 聚合统计(§4.1 /api/traces/summary)。v1 全量扫描,量大后改投影表。 */
244233
- async summary() {
244234
- const { items } = await this.store.listRuns({ limit: 1e3 });
244303
+ /**
244304
+ * 聚合统计(§4.1 /api/traces/summary)。v1 全量扫描,量大后改投影表。
244305
+ *
244306
+ * `filter` 由调用方给:这几个计数是 `listRuns` 扫出来的,共享 legacy 账本上必须带同一条
244307
+ * 归属谓词——轨迹页页头的「共 N 条运行」就是它,不带谓词就是把别家的运行数报给本公司。
244308
+ */
244309
+ async summary(filter = {}) {
244310
+ const { items } = await this.store.listRuns({ ...filter, limit: 1e3 });
244235
244311
  const byStatus = /* @__PURE__ */ new Map();
244236
244312
  const byKind = /* @__PURE__ */ new Map();
244237
244313
  for (const r of items) {
@@ -244499,6 +244575,26 @@ var init_map2 = __esm({
244499
244575
  }
244500
244576
  });
244501
244577
 
244578
+ // ../server/src/domains/trace/read-scope.ts
244579
+ function scopedTraceFilters(filter, scope2) {
244580
+ return scope2.companyScoped ? filter : { ...filter, legacyScope: scope2.legacyScope };
244581
+ }
244582
+ function traceReadAllows(scope2) {
244583
+ return scope2.companyScoped ? () => true : legacyScopeMatcher(scope2.legacyScope);
244584
+ }
244585
+ var COMPANY_SCOPED_TRACE_READ, DENY_ALL_TRACE_READ;
244586
+ var init_read_scope = __esm({
244587
+ "../server/src/domains/trace/read-scope.ts"() {
244588
+ "use strict";
244589
+ init_src();
244590
+ COMPANY_SCOPED_TRACE_READ = { companyScoped: true };
244591
+ DENY_ALL_TRACE_READ = {
244592
+ companyScoped: false,
244593
+ legacyScope: { artifactIds: [], chatSessionIds: [], runtimeInstanceIds: [] }
244594
+ };
244595
+ }
244596
+ });
244597
+
244502
244598
  // ../server/src/domains/trace/routes.ts
244503
244599
  function parseFilters(q2) {
244504
244600
  const f2 = {};
@@ -244527,36 +244623,53 @@ function parseFilters(q2) {
244527
244623
  }
244528
244624
  function traceDomain(opts) {
244529
244625
  const svc = async (req) => opts.resolveService ? await opts.resolveService(req.auth?.companyId) : opts.service;
244626
+ const scopeOf = async (req) => opts.resolveReadScope ? await opts.resolveReadScope(req.auth?.companyId) : COMPANY_SCOPED_TRACE_READ;
244627
+ const requireRun = async (req) => {
244628
+ const id = req.params.id;
244629
+ const service = await svc(req);
244630
+ const run = await service.getRun(id);
244631
+ if (!run || !traceReadAllows(await scopeOf(req))(run)) {
244632
+ throw new ApiError(404, "NOT_FOUND", `\u6CA1\u6709\u8FD9\u4E2A run\uFF1A${id}`);
244633
+ }
244634
+ return { service, id };
244635
+ };
244530
244636
  return (router) => {
244531
244637
  router.get("/api/traces/runs", async (req) => {
244532
- return { status: 200, body: await (await svc(req)).listRuns(parseFilters(req.query)) };
244638
+ const filter = scopedTraceFilters(parseFilters(req.query), await scopeOf(req));
244639
+ return { status: 200, body: await (await svc(req)).listRuns(filter) };
244533
244640
  });
244534
244641
  router.get("/api/traces/summary", async (req) => {
244535
- return { status: 200, body: await (await svc(req)).summary() };
244642
+ return { status: 200, body: await (await svc(req)).summary(scopedTraceFilters({}, await scopeOf(req))) };
244536
244643
  });
244537
244644
  router.get("/api/traces/runs/:id", async (req) => {
244538
- const detail = await (await svc(req)).getRunDetail(req.params.id);
244539
- if (!detail) throw new ApiError(404, "NOT_FOUND", `\u6CA1\u6709\u8FD9\u4E2A run\uFF1A${req.params.id}`);
244645
+ const scope2 = await scopeOf(req);
244646
+ const detail = await (await svc(req)).getRunDetail(req.params.id, (f2) => scopedTraceFilters(f2, scope2));
244647
+ if (!detail || !traceReadAllows(scope2)(detail.run)) {
244648
+ throw new ApiError(404, "NOT_FOUND", `\u6CA1\u6709\u8FD9\u4E2A run\uFF1A${req.params.id}`);
244649
+ }
244540
244650
  return { status: 200, body: detail };
244541
244651
  });
244542
244652
  router.get("/api/traces/runs/:id/events", async (req) => {
244653
+ const { service, id } = await requireRun(req);
244543
244654
  const afterSeq = req.query.get("afterSeq") ?? req.query.get("cursor");
244544
244655
  const limit = req.query.get("limit");
244545
244656
  return {
244546
244657
  status: 200,
244547
- body: await (await svc(req)).listEvents(req.params.id, {
244658
+ body: await service.listEvents(id, {
244548
244659
  ...afterSeq !== null && Number.isFinite(Number(afterSeq)) ? { afterSeq: Number(afterSeq) } : {},
244549
244660
  ...limit !== null && Number.isFinite(Number(limit)) ? { limit: Number(limit) } : {}
244550
244661
  })
244551
244662
  };
244552
244663
  });
244553
244664
  router.get("/api/traces/runs/:id/tool-calls", async (req) => {
244554
- return { status: 200, body: { items: await (await svc(req)).listToolCalls(req.params.id) } };
244665
+ const { service, id } = await requireRun(req);
244666
+ return { status: 200, body: { items: await service.listToolCalls(id) } };
244555
244667
  });
244556
244668
  router.get("/api/traces/runs/:id/bundle", async (req) => {
244557
244669
  if (!opts.readBundleFile) return { status: 404, body: { error: "bundle not available" } };
244558
244670
  const rel = req.query.get("path");
244559
244671
  if (!rel) return { status: 400, body: { error: "path query required" } };
244672
+ await requireRun(req);
244560
244673
  const content3 = opts.readBundleFile(req.params.id, rel);
244561
244674
  if (content3 == null) return { status: 404, body: { error: "not found" } };
244562
244675
  return { status: 200, body: { path: rel, content: content3 } };
@@ -244568,7 +244681,9 @@ function traceDomain(opts) {
244568
244681
  const runtimeKinds = q2.get("runtimeKind")?.split(",").filter(Boolean);
244569
244682
  const effectiveModels = q2.get("model")?.split(",").filter(Boolean);
244570
244683
  const granularity = q2.get("granularity") ?? "hour";
244684
+ const scope2 = await scopeOf(req);
244571
244685
  const items = await (await svc(req)).queryUsageStats({
244686
+ ...scope2.companyScoped ? {} : { legacyScope: scope2.legacyScope },
244572
244687
  ...actorIds?.length ? { actorIds } : {},
244573
244688
  ...runtimeInstanceIds?.length ? { runtimeInstanceIds } : {},
244574
244689
  ...runtimeKinds?.length ? { runtimeKinds } : {},
@@ -244693,6 +244808,7 @@ var init_routes9 = __esm({
244693
244808
  init_src();
244694
244809
  init_router();
244695
244810
  init_map2();
244811
+ init_read_scope();
244696
244812
  }
244697
244813
  });
244698
244814
 
@@ -244768,6 +244884,7 @@ function createTraceDomain(opts) {
244768
244884
  register: traceDomain({
244769
244885
  service,
244770
244886
  ...resolveService ? { resolveService } : {},
244887
+ ...opts.resolveReadScope ? { resolveReadScope: opts.resolveReadScope } : {},
244771
244888
  readBundleFile: opts.readBundleFile
244772
244889
  })
244773
244890
  };
@@ -244779,6 +244896,7 @@ var init_trace2 = __esm({
244779
244896
  init_routes9();
244780
244897
  init_service7();
244781
244898
  init_routes9();
244899
+ init_read_scope();
244782
244900
  init_sink();
244783
244901
  init_chat_parts();
244784
244902
  init_trace_health();
@@ -257454,6 +257572,18 @@ function companyIdFromMetadata(metadata) {
257454
257572
  const cid = metadata.companyId;
257455
257573
  return typeof cid === "string" && cid.trim() ? cid : void 0;
257456
257574
  }
257575
+ function legacyScopeSql(scope2, args, prefix = "") {
257576
+ const parts = [];
257577
+ args.push(scope2.artifactIds);
257578
+ parts.push(`${prefix}artifact_id = ANY($${args.length}::text[])`);
257579
+ args.push(scope2.chatSessionIds);
257580
+ parts.push(`${prefix}chat_session_id = ANY($${args.length}::text[])`);
257581
+ if (scope2.runtimeInstanceIds?.length) {
257582
+ args.push(scope2.runtimeInstanceIds);
257583
+ parts.push(`${prefix}runtime_instance_id = ANY($${args.length}::text[])`);
257584
+ }
257585
+ return `(${parts.join(" OR ")})`;
257586
+ }
257457
257587
  function normalizeUsagePoint2(input, now) {
257458
257588
  let seq;
257459
257589
  if (input.kind === "checkpoint") {
@@ -258248,13 +258378,19 @@ var init_postgres_trace = __esm({
258248
258378
  if (filter.runtimeKind) push2((n) => `r.runtime_kind = $${n}`, filter.runtimeKind);
258249
258379
  if (filter.status) push2((n) => `r.status = $${n}`, filter.status);
258250
258380
  if (filter.rootRunId) push2((n) => `r.root_run_id = $${n}`, filter.rootRunId);
258381
+ if (filter.legacyScope) {
258382
+ if (legacyScopeIsEmpty(filter.legacyScope)) return { items: [], nextCursor: null };
258383
+ conds.push(legacyScopeSql(filter.legacyScope, args, "r."));
258384
+ }
258251
258385
  if (filter.from) push2((n) => `r.started_at >= $${n}`, filter.from);
258252
258386
  if (filter.to) push2((n) => `r.started_at <= $${n}`, filter.to);
258253
258387
  if (filter.excludeAnalysis) conds.push(`(r.metadata->>'analyzedRunId') IS NULL`);
258254
258388
  if (filter.cursor) {
258389
+ const cursorArgs = [filter.cursor];
258390
+ const cursorScope = filter.legacyScope ? ` AND ${legacyScopeSql(filter.legacyScope, cursorArgs)}` : "";
258255
258391
  const c = await this.pool.query(
258256
- `SELECT started_at, id FROM ${this.s}.agent_runs WHERE id = $1`,
258257
- [filter.cursor]
258392
+ `SELECT started_at, id FROM ${this.s}.agent_runs WHERE id = $1${cursorScope}`,
258393
+ cursorArgs
258258
258394
  );
258259
258395
  if (c.rows[0]) {
258260
258396
  args.push(c.rows[0].started_at);
@@ -259387,6 +259523,7 @@ var init_postgres_trace = __esm({
259387
259523
  }
259388
259524
  /** 按维度查聚合用量。granularity=day 查 daily 表,否则 hourly。 */
259389
259525
  async queryUsageStats(filter) {
259526
+ if (filter.legacyScope) return this.queryUsageStatsScoped(filter, filter.legacyScope);
259390
259527
  const gran = filter.granularity ?? "hour";
259391
259528
  const table = gran === "day" ? "agent_usage_daily" : "agent_usage_hourly";
259392
259529
  const timeCol = gran === "day" ? "day" : "hour";
@@ -259427,6 +259564,67 @@ var init_postgres_trace = __esm({
259427
259564
  costUsdMicros: Number(row.cost_usd_micros)
259428
259565
  }));
259429
259566
  }
259567
+ /**
259568
+ * legacy 共享账本上的按维度用量:**绕开聚合表,按租户谓词从 `agent_runs` 现算**。
259569
+ *
259570
+ * 为什么不能用 `agent_usage_hourly/daily`:那两张表的仲裁键里没有 artifact / chat_session,
259571
+ * 表达不了 {@link LegacyTenantScope};而且 legacy 落点写入时 `companyIdForWrite` 拿不到
259572
+ * `billingCompanyId`、run.metadata 又不带 companyId,所有未切公司的行都落在同一个
259573
+ * `company_id='default'` 桶里——读它就是所有未切公司互相看见(2026-09-22 泄漏的 usage 面)。
259574
+ *
259575
+ * 口径与 {@link backfillUsageAggregates} 完全一致(只算 `usage` 是对象的 run、按 `started_at`
259576
+ * 落桶、同一组 GROUP BY 键),所以 company-primary 公司读聚合表、legacy 公司现算,两条路
259577
+ * 对同一批 run 给出同一组数字。
259578
+ */
259579
+ async queryUsageStatsScoped(filter, scope2) {
259580
+ if (legacyScopeIsEmpty(scope2)) return [];
259581
+ const gran = filter.granularity ?? "hour";
259582
+ const args = [];
259583
+ const conds = [`jsonb_typeof(usage) = 'object'`, legacyScopeSql(scope2, args)];
259584
+ const push2 = (sql, val) => {
259585
+ args.push(val);
259586
+ conds.push(sql.replace("$$", `$${args.length}`));
259587
+ };
259588
+ if (filter.actorIds?.length) push2(`actor_id = ANY($$)`, filter.actorIds);
259589
+ if (filter.runtimeInstanceIds?.length) push2(`runtime_instance_id = ANY($$)`, filter.runtimeInstanceIds);
259590
+ if (filter.runtimeKinds?.length) push2(`runtime_kind = ANY($$)`, filter.runtimeKinds);
259591
+ if (filter.effectiveModels?.length) push2(`effective_model = ANY($$)`, filter.effectiveModels);
259592
+ const bucket2 = gran === "day" ? `date_trunc('day', started_at::timestamptz)` : `date_trunc('hour', started_at::timestamptz)`;
259593
+ if (filter.from) {
259594
+ push2(`${bucket2} >= $$`, gran === "day" ? this.truncDayISO(new Date(filter.from)) : this.truncHourISO(new Date(filter.from)));
259595
+ }
259596
+ if (filter.to) push2(`${bucket2} <= $$`, filter.to);
259597
+ const r = await this.pool.query(
259598
+ `SELECT actor_id, runtime_instance_id, runtime_kind, effective_model,
259599
+ ${gran === "day" ? `${bucket2}::date::text` : bucket2} AS bucket,
259600
+ COUNT(*)::bigint AS run_count,
259601
+ COALESCE(SUM(COALESCE((usage->>'inputTokens')::bigint, 0)), 0) AS input_tokens,
259602
+ COALESCE(SUM(COALESCE((usage->>'outputTokens')::bigint, 0)), 0) AS output_tokens,
259603
+ COALESCE(SUM(COALESCE((usage->>'totalTokens')::bigint, 0)), 0) AS total_tokens,
259604
+ COALESCE(SUM(COALESCE((usage->>'cacheReadTokens')::bigint, 0)), 0) AS cache_read_tokens,
259605
+ COALESCE(SUM(COALESCE((usage->>'cacheCreationTokens')::bigint, 0)), 0) AS cache_creation_tokens,
259606
+ COALESCE(SUM(COALESCE((usage->>'costUsdMicros')::bigint, 0)), 0) AS cost_usd_micros
259607
+ FROM ${this.s}.agent_runs
259608
+ WHERE ${conds.join(" AND ")}
259609
+ GROUP BY actor_id, runtime_instance_id, runtime_kind, effective_model, ${bucket2}
259610
+ ORDER BY ${bucket2} DESC, runtime_instance_id, actor_id, effective_model`,
259611
+ args
259612
+ );
259613
+ return r.rows.map((row) => ({
259614
+ actorId: row.actor_id,
259615
+ runtimeInstanceId: row.runtime_instance_id ?? null,
259616
+ runtimeKind: row.runtime_kind,
259617
+ effectiveModel: row.effective_model ?? null,
259618
+ bucket: this.formatUsageBucket(row.bucket, gran),
259619
+ runCount: Number(row.run_count),
259620
+ inputTokens: Number(row.input_tokens),
259621
+ outputTokens: Number(row.output_tokens),
259622
+ totalTokens: Number(row.total_tokens),
259623
+ cacheReadTokens: Number(row.cache_read_tokens),
259624
+ cacheCreationTokens: Number(row.cache_creation_tokens),
259625
+ costUsdMicros: Number(row.cost_usd_micros)
259626
+ }));
259627
+ }
259430
259628
  /** hour → 整点 ISO;day → YYYY-MM-DD(优先吃 SQL ::text,Date 兜底用本地日历日)。 */
259431
259629
  formatUsageBucket(raw, gran) {
259432
259630
  if (gran === "day") {
@@ -272317,6 +272515,7 @@ __export(src_exports2, {
272317
272515
  CHAT_TURN_ORPHAN_GRACE_MS: () => CHAT_TURN_ORPHAN_GRACE_MS,
272318
272516
  CLEAR_SESSION_RUNTIME_HINT: () => CLEAR_SESSION_RUNTIME_HINT,
272319
272517
  COMPANY_CROSS_TENANT_PREFIXES: () => COMPANY_CROSS_TENANT_PREFIXES,
272518
+ COMPANY_SCOPED_TRACE_READ: () => COMPANY_SCOPED_TRACE_READ,
272320
272519
  CONSOLE_ROUTE_TABLES: () => CONSOLE_ROUTE_TABLES,
272321
272520
  CONVERSATIONAL_ESCALATION_TOOLS: () => CONVERSATIONAL_ESCALATION_TOOLS,
272322
272521
  CONVERSATIONAL_ETHOS: () => CONVERSATIONAL_ETHOS,
@@ -272345,6 +272544,7 @@ __export(src_exports2, {
272345
272544
  DEFAULT_SIMPLE_QUERY_MAX_CHARS: () => DEFAULT_SIMPLE_QUERY_MAX_CHARS,
272346
272545
  DEFAULT_TERMINAL_MAX_AGE_MS: () => DEFAULT_TERMINAL_MAX_AGE_MS,
272347
272546
  DELIVERY_REPAIR_BATCH: () => DELIVERY_REPAIR_BATCH,
272547
+ DENY_ALL_TRACE_READ: () => DENY_ALL_TRACE_READ,
272348
272548
  DISPATCH_DROP_BACKOFF_MS: () => DISPATCH_DROP_BACKOFF_MS,
272349
272549
  DISPATCH_DROP_GRACE_MS: () => DISPATCH_DROP_GRACE_MS,
272350
272550
  DISPATCH_DROP_MAX_PER_TICK: () => DISPATCH_DROP_MAX_PER_TICK,
@@ -272830,6 +273030,7 @@ __export(src_exports2, {
272830
273030
  scanFrontmatterEntries: () => scanFrontmatterEntries,
272831
273031
  scanSessionOutputs: () => scanSessionOutputs,
272832
273032
  scanZeroOutputBreaker: () => scanZeroOutputBreaker,
273033
+ scopedTraceFilters: () => scopedTraceFilters,
272833
273034
  scoreKnowledgeChunk: () => scoreKnowledgeChunk,
272834
273035
  sealKnowledgeSnapshot: () => sealKnowledgeSnapshot,
272835
273036
  seedRoleCatalog: () => seedRoleCatalog,
@@ -272872,6 +273073,7 @@ __export(src_exports2, {
272872
273073
  toYamlDoubleQuoted: () => toYamlDoubleQuoted,
272873
273074
  touchKey: () => touchKey,
272874
273075
  traceDomain: () => traceDomain,
273076
+ traceReadAllows: () => traceReadAllows,
272875
273077
  trajectoryEventToRunEvent: () => trajectoryEventToRunEvent,
272876
273078
  trustedDelegationInvocationId: () => trustedDelegationInvocationId,
272877
273079
  trustedKnowledgeInvocationId: () => trustedKnowledgeInvocationId,
@@ -277050,6 +277252,8 @@ async function startServe(opts) {
277050
277252
  const trace = createTraceDomain({
277051
277253
  store: traceStore,
277052
277254
  ...pgDsn ? { resolveStore: (cid) => traceStoreFor(cid) } : {},
277255
+ // 轨迹读面的租户闸门。PG 部署必给——不给就是未切 `company-primary` 的公司在共享账本上互相可见。
277256
+ resolveReadScope: (cid) => traceReadScopeFor(cid),
277053
277257
  readBundleFile: (id, rel) => trajReader.readBundleFile(id, rel)
277054
277258
  });
277055
277259
  const traceHealth = createTraceHealth();
@@ -278068,6 +278272,33 @@ async function startServe(opts) {
278068
278272
  const chatTurnsFor = async (companyId) => chatStoreRouter ? (await chatStoreRouter.open(companyId, "chatTurns")).chatTurns ?? chatTurnStore : chatTurnStore;
278069
278273
  const chatItemsFor = async (companyId) => chatStoreRouter ? (await chatStoreRouter.open(companyId, "chatItems")).chatItems : void 0;
278070
278274
  const chatStoreFor = async (companyId) => chatStoreRouter ? (await chatStoreRouter.open(companyId)).chatSessions : chatSessionStore;
278275
+ const traceReadScopeFor = async (companyId) => {
278276
+ if (!pgPool) return COMPANY_SCOPED_TRACE_READ;
278277
+ if (!companyId) return DENY_ALL_TRACE_READ;
278278
+ try {
278279
+ const store = await traceStoreFor(companyId);
278280
+ if (store instanceof CutoverAwareTraceStore && (await store.resolveUsageReadTarget()).companyScoped) {
278281
+ return COMPANY_SCOPED_TRACE_READ;
278282
+ }
278283
+ const [model, sessions, runtimes] = await Promise.all([
278284
+ getEngine(companyId).then((e) => e.kernel.model),
278285
+ chatStoreFor(companyId).then((s2) => s2.listUsageSessionMeta ? s2.listUsageSessionMeta() : []),
278286
+ // 与 usageRead.sources.listRuntimes 同一条读:按公司过滤,归属未定(company_id IS NULL)的存量行不算本公司。
278287
+ nodeStore.listRuntimes(void 0, { companyId })
278288
+ ]);
278289
+ return {
278290
+ companyScoped: false,
278291
+ legacyScope: {
278292
+ artifactIds: [...model.artifacts.keys()],
278293
+ chatSessionIds: sessions.map((s2) => s2.id),
278294
+ runtimeInstanceIds: runtimes.map((r) => r.id)
278295
+ }
278296
+ };
278297
+ } catch (err) {
278298
+ console.warn(`[trace] \u89E3\u6790 ${companyId} \u7684\u8F68\u8FF9\u8BFB\u95F8\u95E8\u5931\u8D25\uFF0C\u672C\u6B21\u6309\u300C\u65E0\u53EF\u89C1\u8BB0\u5F55\u300D\u5904\u7406\uFF1A${String(err)}`);
278299
+ return DENY_ALL_TRACE_READ;
278300
+ }
278301
+ };
278071
278302
  const artifactStateFor = async (companyId) => {
278072
278303
  if (!chatStoreRouter) return artifactStateStore;
278073
278304
  const stores = await chatStoreRouter.open(companyId, "work-order-files");
@@ -287843,7 +288074,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
287843
288074
  }
287844
288075
  }
287845
288076
  }
287846
- var CLI_VERSION = "2.2.67" ? "2.2.67" : "dev";
288077
+ var CLI_VERSION = "2.2.68" ? "2.2.68" : "dev";
287847
288078
  function apiHeaders(token, company) {
287848
288079
  const headers = {
287849
288080
  authorization: `Bearer ${token}`,
@@ -291649,7 +291880,7 @@ function shimScript() {
291649
291880
  }
291650
291881
 
291651
291882
  // src/index.ts
291652
- var PKG_VERSION = true ? "2.2.67" : "dev";
291883
+ var PKG_VERSION = true ? "2.2.68" : "dev";
291653
291884
  var LOCAL_BIN = localBin();
291654
291885
  var NPM_PREFIX = npmPrefix();
291655
291886
  var INSTANCE = DEFAULT_INSTANCE;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test_v2",
3
- "version": "2.2.67",
3
+ "version": "2.2.68",
4
4
  "description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
5
5
  "bin": {
6
6
  "oasis": "./dist/index.js"
@@ -26,6 +26,6 @@
26
26
  "node": ">=20"
27
27
  },
28
28
  "oasisRelease": {
29
- "sourceHead": "4e649f6aa7bc6633070aefaf241972ac1c42f269"
29
+ "sourceHead": "c84c49eb61b038824f5eb651f7653d8fcf31e318"
30
30
  }
31
31
  }