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.
- package/dist/index.js +247 -16
- 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
|
-
/**
|
|
244213
|
-
|
|
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
|
-
/**
|
|
244233
|
-
|
|
244234
|
-
|
|
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
|
-
|
|
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
|
|
244539
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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": "
|
|
29
|
+
"sourceHead": "c84c49eb61b038824f5eb651f7653d8fcf31e318"
|
|
30
30
|
}
|
|
31
31
|
}
|