oasis_test_v2 2.2.68 → 2.2.69
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 +328 -30
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -444,13 +444,14 @@ function isUnread(eventAt, marker) {
|
|
|
444
444
|
function isChatSessionUnread(session, marker) {
|
|
445
445
|
return session.lastTurnQuality !== void 0 && isUnread(session.touchedAt, marker);
|
|
446
446
|
}
|
|
447
|
-
var chatScope, letterScope, INBOX_BASELINE_SCOPE;
|
|
447
|
+
var chatScope, letterScope, INBOX_BASELINE_SCOPE, INBOX_READ_ALL_SCOPE;
|
|
448
448
|
var init_inbox_read = __esm({
|
|
449
449
|
"../contract/src/inbox-read.ts"() {
|
|
450
450
|
"use strict";
|
|
451
451
|
chatScope = (sessionId) => `chat:${sessionId}`;
|
|
452
452
|
letterScope = (annotationId) => `letter:${annotationId}`;
|
|
453
453
|
INBOX_BASELINE_SCOPE = "inbox-baseline";
|
|
454
|
+
INBOX_READ_ALL_SCOPE = "inbox-read-all";
|
|
454
455
|
}
|
|
455
456
|
});
|
|
456
457
|
|
|
@@ -125858,7 +125859,7 @@ function isReplyWork(w2) {
|
|
|
125858
125859
|
function replyIssueIdOf(w2) {
|
|
125859
125860
|
return w2.lane === "reply" ? w2.replyToIssueId ?? null : null;
|
|
125860
125861
|
}
|
|
125861
|
-
var BUSINESS_HANDOFF_POLICY_FIELD, BUSINESS_HANDOFF_POLICY_EXEMPT, DEFAULT_CONFIG, deriveWorkId, deriveReviewId, deriveReplyId;
|
|
125862
|
+
var BUSINESS_HANDOFF_POLICY_FIELD, BUSINESS_HANDOFF_POLICY_EXEMPT, DEFAULT_CONFIG, deriveWorkId, deriveReviewId, ENGINE_SYSTEM_ACTOR, REVIEW_EXHAUSTED_ESC_PREFIX, deriveReplyId;
|
|
125862
125863
|
var init_model = __esm({
|
|
125863
125864
|
"../engine/src/model.ts"() {
|
|
125864
125865
|
"use strict";
|
|
@@ -125871,6 +125872,8 @@ var init_model = __esm({
|
|
|
125871
125872
|
};
|
|
125872
125873
|
deriveWorkId = (nodeId, version2) => `wk:${nodeId}:${version2}`;
|
|
125873
125874
|
deriveReviewId = (workId, reviewer, group) => `rv:${workId}:${reviewer}:${group}`;
|
|
125875
|
+
ENGINE_SYSTEM_ACTOR = "actor:system:engine";
|
|
125876
|
+
REVIEW_EXHAUSTED_ESC_PREFIX = "esc:review-exhausted:";
|
|
125874
125877
|
deriveReplyId = (issueId, salt) => `ir:${issueId}:${salt}`;
|
|
125875
125878
|
}
|
|
125876
125879
|
});
|
|
@@ -126414,6 +126417,7 @@ var init_kill = __esm({
|
|
|
126414
126417
|
function scan(state, ctx) {
|
|
126415
126418
|
if (state.workorder.dispatchPaused) return { events: [], terminated: false };
|
|
126416
126419
|
const events = [];
|
|
126420
|
+
closeSettledReviewEscalations(state, events);
|
|
126417
126421
|
for (const node2 of state.liveNodes()) {
|
|
126418
126422
|
const lw = node2.latestWorkId ? state.work(node2.latestWorkId) : null;
|
|
126419
126423
|
const continuationPolicy = node2.assigneeActorId ? ctx.continuationPolicies?.get(node2.assigneeActorId) : null;
|
|
@@ -126942,6 +126946,55 @@ function reviewMaxRetriesOf(policy) {
|
|
|
126942
126946
|
const act = policy.resolve({ executor: "agent", scenario: "review" }).timeoutAction;
|
|
126943
126947
|
return act.kind === "kill-rebuild" ? act.maxRetries : AGENT_REVIEW_MAX_RETRIES;
|
|
126944
126948
|
}
|
|
126949
|
+
function pushReviewExhaustedEscalation(state, nodeId, workId, reviewId, reviewerActorId, rounds, events) {
|
|
126950
|
+
const node2 = state.node(nodeId);
|
|
126951
|
+
if (!node2) return;
|
|
126952
|
+
if (node2.latestAcceptId === workId) return;
|
|
126953
|
+
const escId = `${REVIEW_EXHAUSTED_ESC_PREFIX}${reviewId}`;
|
|
126954
|
+
if (state.allIssues().some((i) => i.id === escId)) return;
|
|
126955
|
+
events.push({
|
|
126956
|
+
kind: "issue.create",
|
|
126957
|
+
workorderId: state.workorder.id,
|
|
126958
|
+
issueId: escId,
|
|
126959
|
+
issueKind: "escalation",
|
|
126960
|
+
body: `\u300A${node2.title}\u300B\u7684\u8BC4\u5BA1\u8FDE\u7EED ${rounds} \u6B21\u5931\u8D25\uFF0C\u8FD9\u4E00\u8F6E\u8BC4\u5BA1\u6536\u4E0D\u9F50\u2014\u2014\u9700\u8981\u6709\u4EBA\u91CD\u5F00\u3002
|
|
126961
|
+
|
|
126962
|
+
\u672B\u6B21\u8BC4\u5BA1\u4F1A\u8BDD\u7ED3\u675F\u65F6\u6CA1\u6709\u6295\u7968\uFF1B\u62A5\u9519\u539F\u8BDD\u89C1\u8FD9\u4E2A\u8282\u70B9\u7684\u6267\u884C\u8F68\u8FF9\u3002`,
|
|
126963
|
+
aboutNodeId: nodeId,
|
|
126964
|
+
aboutWorkId: workId,
|
|
126965
|
+
raisedByNodeId: null,
|
|
126966
|
+
authorActorId: reviewerActorId,
|
|
126967
|
+
handActorId: null,
|
|
126968
|
+
recipients: [state.workorder.ownerActorId],
|
|
126969
|
+
attachments: [],
|
|
126970
|
+
intent: "advisory"
|
|
126971
|
+
});
|
|
126972
|
+
}
|
|
126973
|
+
function closeSettledReviewEscalations(state, events) {
|
|
126974
|
+
for (const issue2 of state.allIssues()) {
|
|
126975
|
+
if (issue2.resolvedAt !== null || issue2.kind !== "escalation") continue;
|
|
126976
|
+
const id = issue2.id;
|
|
126977
|
+
if (!id.startsWith(REVIEW_EXHAUSTED_ESC_PREFIX)) continue;
|
|
126978
|
+
const node2 = issue2.aboutNodeId ? state.node(issue2.aboutNodeId) : void 0;
|
|
126979
|
+
if (!node2 || node2.cancelledAt) continue;
|
|
126980
|
+
const lw = node2.latestWorkId ? state.work(node2.latestWorkId) : null;
|
|
126981
|
+
if (lw && workState(lw, hasOutput(lw, state.artifactsOf(lw.id).length)) === "dead") continue;
|
|
126982
|
+
const review = state.review(id.slice(REVIEW_EXHAUSTED_ESC_PREFIX.length));
|
|
126983
|
+
if (!review) continue;
|
|
126984
|
+
const head = state.requirementsOf(node2.id).find((r) => r.reviewGroup === review.reviewGroup)?.latestReviewId ?? null;
|
|
126985
|
+
const note = head !== review.id ? "\u8BC4\u5BA1\u5DF2\u91CD\u65B0\u5B89\u6392" : node2.latestAcceptId === review.targetWorkId ? "\u8FD9\u4E00\u7248\u5DF2\u9A8C\u6536" : null;
|
|
126986
|
+
if (note === null) continue;
|
|
126987
|
+
events.push({
|
|
126988
|
+
kind: "issue.resolve",
|
|
126989
|
+
workorderId: state.workorder.id,
|
|
126990
|
+
issueId: issue2.id,
|
|
126991
|
+
state: "resolved",
|
|
126992
|
+
by: SYSTEM_ENGINE_ACTOR,
|
|
126993
|
+
note,
|
|
126994
|
+
viaWorkId: null
|
|
126995
|
+
});
|
|
126996
|
+
}
|
|
126997
|
+
}
|
|
126945
126998
|
function processReviews(state, nodeId, workId, ctx, events) {
|
|
126946
126999
|
const policy = ctx.policy ?? CODE_DEFAULT_POLICY;
|
|
126947
127000
|
const reqs = state.requirementsOf(nodeId);
|
|
@@ -127003,15 +127056,19 @@ function processReviews(state, nodeId, workId, ctx, events) {
|
|
|
127003
127056
|
}
|
|
127004
127057
|
} else if (info.status === "failed") {
|
|
127005
127058
|
const req = reqs.find((r) => r.reviewGroup === g2);
|
|
127006
|
-
const
|
|
127059
|
+
const exhausted = reviewRetriesExhausted(g2, reviews, { policy });
|
|
127060
|
+
const overLimit = exhausted !== null;
|
|
127007
127061
|
if (overLimit && classify(req.reviewerActorId) === "agent") {
|
|
127008
127062
|
const lrId = req.latestReviewId;
|
|
127009
|
-
if (lrId)
|
|
127010
|
-
|
|
127011
|
-
|
|
127012
|
-
|
|
127013
|
-
|
|
127014
|
-
|
|
127063
|
+
if (lrId) {
|
|
127064
|
+
events.push({
|
|
127065
|
+
kind: "review.kill",
|
|
127066
|
+
workorderId: state.workorder.id,
|
|
127067
|
+
reviewId: lrId,
|
|
127068
|
+
reason: "exhausted"
|
|
127069
|
+
});
|
|
127070
|
+
pushReviewExhaustedEscalation(state, nodeId, workId, lrId, req.reviewerActorId, exhausted.rounds, events);
|
|
127071
|
+
}
|
|
127015
127072
|
} else if (!overLimit) {
|
|
127016
127073
|
events.push({
|
|
127017
127074
|
kind: "review.create",
|
|
@@ -127202,6 +127259,7 @@ function assessConvergence(state, ctx) {
|
|
|
127202
127259
|
const anyUnfinished = state.liveNodes().some((n) => !n.latestAcceptId);
|
|
127203
127260
|
return { stuck: !anyRunning && !anyBlockingIssue && allIdle && anyUnfinished, codes };
|
|
127204
127261
|
}
|
|
127262
|
+
var SYSTEM_ENGINE_ACTOR;
|
|
127205
127263
|
var init_activate = __esm({
|
|
127206
127264
|
"../engine/src/activate.ts"() {
|
|
127207
127265
|
"use strict";
|
|
@@ -127216,6 +127274,7 @@ var init_activate = __esm({
|
|
|
127216
127274
|
init_model();
|
|
127217
127275
|
init_views2();
|
|
127218
127276
|
init_kill();
|
|
127277
|
+
SYSTEM_ENGINE_ACTOR = ENGINE_SYSTEM_ACTOR;
|
|
127219
127278
|
}
|
|
127220
127279
|
});
|
|
127221
127280
|
|
|
@@ -135090,6 +135149,7 @@ var init_issue = __esm({
|
|
|
135090
135149
|
"../engine/src/handlers/issue.ts"() {
|
|
135091
135150
|
"use strict";
|
|
135092
135151
|
init_plan();
|
|
135152
|
+
init_model();
|
|
135093
135153
|
init_letters();
|
|
135094
135154
|
issueCreate = {
|
|
135095
135155
|
name: "issue/create",
|
|
@@ -135181,7 +135241,8 @@ var init_issue = __esm({
|
|
|
135181
135241
|
}
|
|
135182
135242
|
if (issue2.resolvedAt !== null) return;
|
|
135183
135243
|
const humanResolution = e.by.startsWith("actor:human:") && e.by === ctx.actorId;
|
|
135184
|
-
|
|
135244
|
+
const engineSelfClosure = e.by === ENGINE_SYSTEM_ACTOR && ctx.actorId === ENGINE_SYSTEM_ACTOR && issue2.id.startsWith(REVIEW_EXHAUSTED_ESC_PREFIX);
|
|
135245
|
+
if (e.semanticsVersion === 2 && issue2.kind === "escalation" && !humanResolution && !engineSelfClosure) {
|
|
135185
135246
|
throw new Error("\u5173\u95ED\u5347\u7EA7\u9700\u8981\u4EBA\u660E\u786E\u786E\u8BA4\uFF1Bagent \u8BF7\u63D0\u4EA4\u5173\u95ED\u6388\u6743\u7533\u8BF7");
|
|
135186
135247
|
}
|
|
135187
135248
|
state.updateIssue(e.issueId, {
|
|
@@ -213900,7 +213961,10 @@ ${composed}`;
|
|
|
213900
213961
|
auth: {
|
|
213901
213962
|
actor,
|
|
213902
213963
|
...companyId !== void 0 ? { companyId } : {},
|
|
213903
|
-
...dispatch && Object.keys(dispatch).length > 0 ? { dispatch } : {}
|
|
213964
|
+
...dispatch && Object.keys(dispatch).length > 0 ? { dispatch } : {},
|
|
213965
|
+
// 签名 scopes 原样透出(ADR 0609 D1):部署级 operator-token 靠它被认出来。
|
|
213966
|
+
// 只来自签名 token;cookie / 简单 token 没有这一项。
|
|
213967
|
+
...domainClaims?.scopes ? { scopes: domainClaims.scopes } : {}
|
|
213904
213968
|
},
|
|
213905
213969
|
raw: req
|
|
213906
213970
|
});
|
|
@@ -214351,6 +214415,18 @@ var init_tokens = __esm({
|
|
|
214351
214415
|
}
|
|
214352
214416
|
});
|
|
214353
214417
|
|
|
214418
|
+
// ../server/src/auth/operator.ts
|
|
214419
|
+
function isOperatorRequest(auth) {
|
|
214420
|
+
return auth.scopes?.includes(OPERATOR_SCOPE) === true;
|
|
214421
|
+
}
|
|
214422
|
+
var OPERATOR_SCOPE;
|
|
214423
|
+
var init_operator = __esm({
|
|
214424
|
+
"../server/src/auth/operator.ts"() {
|
|
214425
|
+
"use strict";
|
|
214426
|
+
OPERATOR_SCOPE = "oasis:operator";
|
|
214427
|
+
}
|
|
214428
|
+
});
|
|
214429
|
+
|
|
214354
214430
|
// ../server/src/session-dataplane-token.ts
|
|
214355
214431
|
function createDataplaneTokenIssuer(opts = {}) {
|
|
214356
214432
|
const secret = readOrCreateSecret2(opts.secretFile);
|
|
@@ -233203,6 +233279,7 @@ var init_review_requirement_activity = __esm({
|
|
|
233203
233279
|
// ../server/src/domains/collab/activity.ts
|
|
233204
233280
|
function escalationKindOf(issueId, authorActorId) {
|
|
233205
233281
|
if (issueId.startsWith(RETRY_EXHAUSTED_ESC_PREFIX)) return "retry_exhausted";
|
|
233282
|
+
if (issueId.startsWith(REVIEW_EXHAUSTED_ESC_PREFIX2)) return "review_exhausted";
|
|
233206
233283
|
return isSystemActorId(authorActorId) ? "output_stall" : "manual";
|
|
233207
233284
|
}
|
|
233208
233285
|
function parseStopLossFacts(kind, body2) {
|
|
@@ -234111,8 +234188,12 @@ function buildWorkorderActivity(input) {
|
|
|
234111
234188
|
const gapId = issueById.get(id)?.gapId;
|
|
234112
234189
|
return typeof gapId === "string" && !!issueById.get(gapId);
|
|
234113
234190
|
};
|
|
234114
|
-
const
|
|
234115
|
-
const
|
|
234191
|
+
const lastReviewFailure = kind === "review_exhausted" ? (input.runFailures ?? []).filter((f2) => f2.nodeId === latest.nodeId && f2.actorId === latest.authorId && f2.startedAt <= latest.at && f2.message.trim()).sort((a, b2) => a.startedAt.localeCompare(b2.startedAt)).at(-1)?.message : void 0;
|
|
234192
|
+
const head = kind === "retry_exhausted" ? ACTIVITY_COPY.escalationHeadRetryExhausted(nodeName(latest.nodeId)) : kind === "review_exhausted" ? ACTIVITY_COPY.escalationHeadReviewExhausted(
|
|
234193
|
+
nodeName(latest.nodeId),
|
|
234194
|
+
lastReviewFailure ? firstSentence(lastReviewFailure) : void 0
|
|
234195
|
+
) : kind === "output_stall" ? ACTIVITY_COPY.escalationHeadOutputStall(nodeName(latest.nodeId)) : gapBehind(latest.id) ? ACTIVITY_COPY.escalationHeadGapEscalated(nameOf(latest.authorId), nodeName(latest.nodeId)) : ACTIVITY_COPY.escalationHeadManual(nameOf(stuckActor));
|
|
234196
|
+
const howTo = kind === "retry_exhausted" ? ACTIVITY_COPY.escalationHowToRetryExhausted : kind === "review_exhausted" ? ACTIVITY_COPY.escalationHowToReviewExhausted : kind === "output_stall" ? ACTIVITY_COPY.escalationHowToOutputStall : void 0;
|
|
234116
234197
|
const closing = issueById.get(latest.id);
|
|
234117
234198
|
const closeEvent = plainResolveEvents.get(latest.id);
|
|
234118
234199
|
const closedBy = text5(closing?.resolvedBy) ?? closeEvent?.by ?? target;
|
|
@@ -234434,7 +234515,7 @@ function buildWorkorderActivity(input) {
|
|
|
234434
234515
|
cards.sort((a, b2) => a.at.localeCompare(b2.at) || a.seq - b2.seq || a.id.localeCompare(b2.id));
|
|
234435
234516
|
return { workorderId, cards, truncated };
|
|
234436
234517
|
}
|
|
234437
|
-
var ACTIVITY_EVENT_KINDS, LEGACY_PAUSE_REASON, ACTIVITY_EVENT_LIMIT, UPSTREAM_ACK_NOTE_CAP, ACTIVITY_COPY, REWORK_ANNOTATION_PREFIX, RECOVERY_ANNOTATION_PREFIX, ENGINE_RETRY_EXHAUSTED, BUTTON, PHASE_LABEL, COORDINATOR_CARD_PREFIX, RETRY_EXHAUSTED_ESC_PREFIX, isStopLoss;
|
|
234518
|
+
var ACTIVITY_EVENT_KINDS, LEGACY_PAUSE_REASON, ACTIVITY_EVENT_LIMIT, UPSTREAM_ACK_NOTE_CAP, ACTIVITY_COPY, REWORK_ANNOTATION_PREFIX, RECOVERY_ANNOTATION_PREFIX, ENGINE_RETRY_EXHAUSTED, BUTTON, PHASE_LABEL, COORDINATOR_CARD_PREFIX, RETRY_EXHAUSTED_ESC_PREFIX, REVIEW_EXHAUSTED_ESC_PREFIX2, isStopLoss;
|
|
234438
234519
|
var init_activity2 = __esm({
|
|
234439
234520
|
"../server/src/domains/collab/activity.ts"() {
|
|
234440
234521
|
"use strict";
|
|
@@ -234578,6 +234659,8 @@ var init_activity2 = __esm({
|
|
|
234578
234659
|
同一件事,只换后半句(「等 @X 处理」→「X 已处理:…」)。 */
|
|
234579
234660
|
escalationHeadRetryExhausted: (node2) => `\u300A${node2}\u300B\u91CD\u8BD5\u5DF2\u7528\u5C3D\uFF0C`,
|
|
234580
234661
|
escalationHeadOutputStall: (node2) => `\u7CFB\u7EDF\u6B62\u635F\uFF1A\u300A${node2}\u300B\u505C\u4F4F\u4E86\uFF0C`,
|
|
234662
|
+
/** 评审连败熔断(Bug 0212):卡住的是**这一轮评审**,不是那一版活——话不能写成「执行异常」。 */
|
|
234663
|
+
escalationHeadReviewExhausted: (node2, lastReason) => `\u300A${node2}\u300B\u7684\u8BC4\u5BA1\u8FDE\u7740\u6CA1\u8DD1\u6210\uFF0C\u8FD9\u4E00\u8F6E\u6536\u4E0D\u9F50${lastReason ? `\uFF08\u672B\u6B21\uFF1A${lastReason}\uFF09` : ""}\uFF0C`,
|
|
234581
234664
|
/** 人工上报里**关联着缺口**的那一档:协调者接了缺口、补不了,于是升级给人(四种停法的第二种)。 */
|
|
234582
234665
|
escalationHeadGapEscalated: (coordinator, node2) => `${coordinator} \u8865\u4E0D\u4E86\u300A${node2}\u300B\u7684\u7F3A\u53E3\uFF0C`,
|
|
234583
234666
|
/** 其余人工上报:主语是卡住的那个执行人(异常是它的,不是上报作者的)。 */
|
|
@@ -234593,6 +234676,8 @@ var init_activity2 = __esm({
|
|
|
234593
234676
|
/** 「你要做什么」那半句——两种系统止损各一份(F6 的立论就在这里:执行者一样,只有话不一样)。 */
|
|
234594
234677
|
escalationHowToRetryExhausted: "\u5904\u7406\u5E76\u5173\u6389\u8FD9\u6761\u4E0A\u62A5\u540E\uFF0C\u8FD9\u4E00\u6B65\u4F1A\u81EA\u52A8\u91CD\u8BD5\uFF1B\u591A\u534A\u662F\u989D\u5EA6 / \u767B\u5F55\u8FC7\u671F / \u9650\u6D41\u8FD9\u7C7B\u73AF\u5883\u95EE\u9898\uFF0C\u5148\u770B\u8F68\u8FF9\u518D\u51B3\u5B9A\u91CD\u8BD5\u3002",
|
|
234595
234678
|
escalationHowToOutputStall: "\u5904\u7406\u5E76\u5173\u6389\u8FD9\u6761\u4E0A\u62A5\u540E\uFF0C\u8FD9\u4E00\u6B65\u4F1A\u81EA\u52A8\u91CD\u8BD5\uFF1B\u4E0D\u67E5\u6E05\u539F\u56E0\u5C31\u91CD\u8BD5\u4F1A\u7EE7\u7EED\u7A7A\u70E7\uFF0C\u5148\u8FDB\u8BA8\u8BBA\u623F\u3002",
|
|
234679
|
+
/** 评审熔断那一份:关掉之后重开的是**评审**,不是这一步的活(活已经交了,等的是审)。 */
|
|
234680
|
+
escalationHowToReviewExhausted: "\u5904\u7406\u5E76\u5173\u6389\u8FD9\u6761\u4E0A\u62A5\u540E\uFF0C\u8FD9\u4E00\u8F6E\u8BC4\u5BA1\u4F1A\u81EA\u52A8\u91CD\u5F00\uFF1B\u591A\u534A\u662F\u8BC4\u5BA1\u5458\u7684\u8FD0\u884C\u73AF\u5883\u51FA\u4E86\u95EE\u9898\uFF08\u989D\u5EA6 / \u767B\u5F55\u8FC7\u671F / \u9650\u6D41\uFF09\uFF0C\u5148\u770B\u8F68\u8FF9\u518D\u51B3\u5B9A\u3002",
|
|
234596
234681
|
/** 关掉了:接着开头那半句说「谁处理的、怎么处理的」。没写处置说明就只说「已处理」。
|
|
234597
234682
|
* 处置说明常常是人自己写的一整段、末尾自带句号——**别再补一个**,否则卡面收在「。。」上。 */
|
|
234598
234683
|
escalationHandled: (head, by, note) => `${head}${by} \u5DF2\u5904\u7406${note ? `\uFF1A${note}` : ""}${note && /[。!?.!?]$/.test(note) ? "" : "\u3002"}`,
|
|
@@ -234782,7 +234867,8 @@ var init_activity2 = __esm({
|
|
|
234782
234867
|
};
|
|
234783
234868
|
COORDINATOR_CARD_PREFIX = "coordinator:";
|
|
234784
234869
|
RETRY_EXHAUSTED_ESC_PREFIX = "esc:retry-exhausted:";
|
|
234785
|
-
|
|
234870
|
+
REVIEW_EXHAUSTED_ESC_PREFIX2 = "esc:review-exhausted:";
|
|
234871
|
+
isStopLoss = (kind) => kind === "retry_exhausted" || kind === "output_stall";
|
|
234786
234872
|
}
|
|
234787
234873
|
});
|
|
234788
234874
|
|
|
@@ -235482,6 +235568,15 @@ function backfillInboxUnread(items, markers) {
|
|
|
235482
235568
|
item.unread = !Number.isFinite(effective) ? true : sinceMs > effective;
|
|
235483
235569
|
}
|
|
235484
235570
|
}
|
|
235571
|
+
function applyReadAllWatermark(items, markers) {
|
|
235572
|
+
const at = markers.find((m2) => m2.scope === INBOX_READ_ALL_SCOPE)?.readAt;
|
|
235573
|
+
const atMs = at ? Date.parse(at) : Number.NaN;
|
|
235574
|
+
if (!Number.isFinite(atMs)) return;
|
|
235575
|
+
for (const item of items) {
|
|
235576
|
+
const sinceMs = Date.parse(item.since);
|
|
235577
|
+
if (Number.isFinite(sinceMs) && sinceMs <= atMs) item.unread = false;
|
|
235578
|
+
}
|
|
235579
|
+
}
|
|
235485
235580
|
var C_ACTION_LABEL;
|
|
235486
235581
|
var init_inbox = __esm({
|
|
235487
235582
|
"../server/src/domains/collab/inbox.ts"() {
|
|
@@ -236060,6 +236155,16 @@ var init_notification_store = __esm({
|
|
|
236060
236155
|
}
|
|
236061
236156
|
if (changed) this.save();
|
|
236062
236157
|
}
|
|
236158
|
+
async markAllRead(recipient, at) {
|
|
236159
|
+
let n = 0;
|
|
236160
|
+
for (const [id, r] of this.rows) {
|
|
236161
|
+
if (r.recipient !== recipient || r.readAt) continue;
|
|
236162
|
+
this.rows.set(id, { ...r, readAt: at });
|
|
236163
|
+
n++;
|
|
236164
|
+
}
|
|
236165
|
+
if (n > 0) this.save();
|
|
236166
|
+
return n;
|
|
236167
|
+
}
|
|
236063
236168
|
async countUnread(recipient) {
|
|
236064
236169
|
let pending = 0;
|
|
236065
236170
|
let all2 = 0;
|
|
@@ -236250,6 +236355,13 @@ var init_notification_store = __esm({
|
|
|
236250
236355
|
[recipient, [...ids2], at]
|
|
236251
236356
|
);
|
|
236252
236357
|
}
|
|
236358
|
+
async markAllRead(recipient, at) {
|
|
236359
|
+
const r = await this.sql.query(
|
|
236360
|
+
`UPDATE ${this.t} SET read_at = $2::timestamptz WHERE recipient = $1 AND read_at IS NULL`,
|
|
236361
|
+
[recipient, at]
|
|
236362
|
+
);
|
|
236363
|
+
return r.rowCount ?? 0;
|
|
236364
|
+
}
|
|
236253
236365
|
async countUnread(recipient) {
|
|
236254
236366
|
const r = await this.sql.query(
|
|
236255
236367
|
`SELECT count(*) FILTER (WHERE status = 'pending')::int AS pending, count(*)::int AS "all"
|
|
@@ -236780,7 +236892,7 @@ var init_workorder_metrics = __esm({
|
|
|
236780
236892
|
});
|
|
236781
236893
|
|
|
236782
236894
|
// ../server/src/domains/usage/statistics-model.ts
|
|
236783
|
-
var UsageQueryError;
|
|
236895
|
+
var UsageQueryError, ZERO_USAGE_AMOUNT;
|
|
236784
236896
|
var init_statistics_model = __esm({
|
|
236785
236897
|
"../server/src/domains/usage/statistics-model.ts"() {
|
|
236786
236898
|
"use strict";
|
|
@@ -236791,6 +236903,13 @@ var init_statistics_model = __esm({
|
|
|
236791
236903
|
this.name = "UsageQueryError";
|
|
236792
236904
|
}
|
|
236793
236905
|
};
|
|
236906
|
+
ZERO_USAGE_AMOUNT = {
|
|
236907
|
+
tokens: { input: 0, cache: 0, cacheRead: 0, cacheCreation: 0, output: 0, total: 0 },
|
|
236908
|
+
costUsdMicros: 0,
|
|
236909
|
+
costParts: { input: 0, cacheRead: 0, cacheCreation: 0, output: 0, unsplit: 0 },
|
|
236910
|
+
costKnown: "full",
|
|
236911
|
+
costUnknownTokens: 0
|
|
236912
|
+
};
|
|
236794
236913
|
}
|
|
236795
236914
|
});
|
|
236796
236915
|
|
|
@@ -237166,6 +237285,11 @@ function bucketIndex(starts, ms) {
|
|
|
237166
237285
|
}
|
|
237167
237286
|
return ans;
|
|
237168
237287
|
}
|
|
237288
|
+
function pushView(map, key2, v2) {
|
|
237289
|
+
const list2 = map.get(key2);
|
|
237290
|
+
if (list2) list2.push(v2);
|
|
237291
|
+
else map.set(key2, [v2]);
|
|
237292
|
+
}
|
|
237169
237293
|
function getCell(map, key2) {
|
|
237170
237294
|
let c = map.get(key2);
|
|
237171
237295
|
if (!c) {
|
|
@@ -237403,12 +237527,15 @@ function attributed(facts, relations) {
|
|
|
237403
237527
|
const taskCells = /* @__PURE__ */ new Map();
|
|
237404
237528
|
const taskActorCells = /* @__PURE__ */ new Map();
|
|
237405
237529
|
const convSessionCells = /* @__PURE__ */ new Map();
|
|
237530
|
+
const convViews = /* @__PURE__ */ new Map();
|
|
237531
|
+
const taskViews = /* @__PURE__ */ new Map();
|
|
237406
237532
|
const unlinked = new Cell();
|
|
237407
237533
|
for (const v2 of facts.views) {
|
|
237408
237534
|
if (!v2.relevant) continue;
|
|
237409
237535
|
const attr = runAttribution(relations, v2.run, memo);
|
|
237410
237536
|
if (attr.kind === "task") {
|
|
237411
237537
|
getCell(taskCells, attr.workorderId).addView(v2);
|
|
237538
|
+
pushView(taskViews, attr.workorderId, v2);
|
|
237412
237539
|
let byActor2 = taskActorCells.get(attr.workorderId);
|
|
237413
237540
|
if (!byActor2) {
|
|
237414
237541
|
byActor2 = /* @__PURE__ */ new Map();
|
|
@@ -237422,6 +237549,7 @@ function attributed(facts, relations) {
|
|
|
237422
237549
|
convSessionCells.set(attr.rootSessionId, bySession);
|
|
237423
237550
|
}
|
|
237424
237551
|
getCell(bySession, attr.sessionId).addView(v2);
|
|
237552
|
+
pushView(convViews, attr.rootSessionId, v2);
|
|
237425
237553
|
} else unlinked.addView(v2);
|
|
237426
237554
|
}
|
|
237427
237555
|
const taskAmount = /* @__PURE__ */ new Map();
|
|
@@ -237453,8 +237581,13 @@ function attributed(facts, relations) {
|
|
|
237453
237581
|
}
|
|
237454
237582
|
const conversations = [];
|
|
237455
237583
|
const convGroupAcc = /* @__PURE__ */ new Map();
|
|
237584
|
+
const treeViews = /* @__PURE__ */ new Map();
|
|
237456
237585
|
for (const rootId of /* @__PURE__ */ new Set([...convSessionCells.keys(), ...tasksByRoot.keys()])) {
|
|
237457
237586
|
const root = relations.sessions.get(rootId);
|
|
237587
|
+
treeViews.set(rootId, [
|
|
237588
|
+
...convViews.get(rootId) ?? [],
|
|
237589
|
+
...(tasksByRoot.get(rootId) ?? []).flatMap((workorderId) => taskViews.get(workorderId) ?? [])
|
|
237590
|
+
]);
|
|
237458
237591
|
const group = new Cell();
|
|
237459
237592
|
const rows = [];
|
|
237460
237593
|
const sessionRows = [];
|
|
@@ -237576,9 +237709,83 @@ function attributed(facts, relations) {
|
|
|
237576
237709
|
{ amount: a.amount, name: a.name, id: a.projectId ?? "" },
|
|
237577
237710
|
{ amount: b2.amount, name: b2.name, id: b2.projectId ?? "" }
|
|
237578
237711
|
));
|
|
237579
|
-
return { conversations, tasks, projects };
|
|
237712
|
+
return { conversations, tasks, projects, treeViews };
|
|
237713
|
+
}
|
|
237714
|
+
function deriveTreeDuration(views, now) {
|
|
237715
|
+
const nowMs = now.getTime();
|
|
237716
|
+
const spans = [];
|
|
237717
|
+
let countedRuns = 0;
|
|
237718
|
+
let unstartedRuns = 0;
|
|
237719
|
+
let inProgress = false;
|
|
237720
|
+
let firstMs = Infinity;
|
|
237721
|
+
let lastMs = -Infinity;
|
|
237722
|
+
let runtimeMs = 0;
|
|
237723
|
+
for (const v2 of views) {
|
|
237724
|
+
const startMs = v2.run.runtimeStartedAt ? Date.parse(v2.run.runtimeStartedAt) : NaN;
|
|
237725
|
+
if (!Number.isFinite(startMs)) {
|
|
237726
|
+
unstartedRuns += 1;
|
|
237727
|
+
continue;
|
|
237728
|
+
}
|
|
237729
|
+
const endedMs = v2.run.endedAt ? Date.parse(v2.run.endedAt) : NaN;
|
|
237730
|
+
const running = !Number.isFinite(endedMs) && !isRunEnded(v2.run);
|
|
237731
|
+
if (running) inProgress = true;
|
|
237732
|
+
const rawEnd = Number.isFinite(endedMs) ? endedMs : running ? nowMs : startMs;
|
|
237733
|
+
const end = Math.max(rawEnd, startMs);
|
|
237734
|
+
countedRuns += 1;
|
|
237735
|
+
runtimeMs += end - startMs;
|
|
237736
|
+
spans.push({ start: startMs, end });
|
|
237737
|
+
if (startMs < firstMs) firstMs = startMs;
|
|
237738
|
+
if (end > lastMs) lastMs = end;
|
|
237739
|
+
}
|
|
237740
|
+
if (countedRuns === 0) return { ...ZERO_DURATION, unstartedRuns };
|
|
237741
|
+
spans.sort((a, b2) => a.start - b2.start || a.end - b2.end);
|
|
237742
|
+
let activeMs = 0;
|
|
237743
|
+
let curStart = spans[0].start;
|
|
237744
|
+
let curEnd = spans[0].end;
|
|
237745
|
+
for (const span of spans.slice(1)) {
|
|
237746
|
+
if (span.start > curEnd) {
|
|
237747
|
+
activeMs += curEnd - curStart;
|
|
237748
|
+
curStart = span.start;
|
|
237749
|
+
curEnd = span.end;
|
|
237750
|
+
} else if (span.end > curEnd) curEnd = span.end;
|
|
237751
|
+
}
|
|
237752
|
+
activeMs += curEnd - curStart;
|
|
237753
|
+
return {
|
|
237754
|
+
firstStartedAt: new Date(firstMs).toISOString(),
|
|
237755
|
+
lastEndedAt: new Date(lastMs).toISOString(),
|
|
237756
|
+
inProgress,
|
|
237757
|
+
wallClockMs: lastMs - firstMs,
|
|
237758
|
+
runtimeMs,
|
|
237759
|
+
activeMs,
|
|
237760
|
+
countedRuns,
|
|
237761
|
+
unstartedRuns
|
|
237762
|
+
};
|
|
237580
237763
|
}
|
|
237581
|
-
|
|
237764
|
+
function buildChatSessionUsage(sessionId, input) {
|
|
237765
|
+
const facts = computeFacts(input);
|
|
237766
|
+
const lists = attributed(facts, input.relations);
|
|
237767
|
+
const attr = sessionAttribution(input.relations, sessionId, /* @__PURE__ */ new Map());
|
|
237768
|
+
const rootId = attr.kind === "conversation" ? attr.rootSessionId : sessionId;
|
|
237769
|
+
const session = input.relations.sessions.get(rootId);
|
|
237770
|
+
const group = lists.conversations.find((g2) => g2.sessionId === rootId) ?? {
|
|
237771
|
+
sessionId: rootId,
|
|
237772
|
+
title: session?.title || UNTITLED_CONVERSATION,
|
|
237773
|
+
projectId: session?.projectId ?? null,
|
|
237774
|
+
createdAt: session?.createdAt ?? null,
|
|
237775
|
+
amount: ZERO_USAGE_AMOUNT,
|
|
237776
|
+
flags: { inProgress: false, usagePending: false, costUnknownRuns: 0 },
|
|
237777
|
+
rows: []
|
|
237778
|
+
};
|
|
237779
|
+
return {
|
|
237780
|
+
companyId: input.companyId,
|
|
237781
|
+
sessionId,
|
|
237782
|
+
window: input.resolved.window,
|
|
237783
|
+
generatedAt: input.now.toISOString(),
|
|
237784
|
+
group,
|
|
237785
|
+
duration: deriveTreeDuration(lists.treeViews.get(rootId) ?? [], input.now)
|
|
237786
|
+
};
|
|
237787
|
+
}
|
|
237788
|
+
var UNKNOWN_AGENT_NAME, UNREGISTERED_RUNTIME_NAME, UNSPECIFIED_PROJECT_NAME, UNLINKED_ROW_TITLE, UNTITLED_CONVERSATION, BUCKET_KEYS, AmountAcc, FlagAcc, Cell, collator, ModelCells, ZERO_DURATION;
|
|
237582
237789
|
var init_statistics = __esm({
|
|
237583
237790
|
"../server/src/domains/usage/statistics.ts"() {
|
|
237584
237791
|
"use strict";
|
|
@@ -237586,6 +237793,7 @@ var init_statistics = __esm({
|
|
|
237586
237793
|
init_uncategorized_project();
|
|
237587
237794
|
init_model_pricing();
|
|
237588
237795
|
init_accounting();
|
|
237796
|
+
init_statistics_model();
|
|
237589
237797
|
UNKNOWN_AGENT_NAME = "\u672A\u77E5 Agent";
|
|
237590
237798
|
UNREGISTERED_RUNTIME_NAME = "\u672A\u767B\u8BB0\u8FD0\u884C\u65F6";
|
|
237591
237799
|
UNSPECIFIED_PROJECT_NAME = UNCATEGORIZED_PROJECT_NAME;
|
|
@@ -237704,6 +237912,16 @@ var init_statistics = __esm({
|
|
|
237704
237912
|
return [...this.cells].map(([model, c]) => ({ model, runCount: c.runCount, amount: c.amount.toAmount(), flags: c.flags.toFlags() })).filter((r) => r.runCount > 0 || r.amount.tokens.total > 0 || r.amount.costUsdMicros > 0 || r.amount.costKnown !== "full").sort((a, b2) => b2.amount.tokens.total - a.amount.tokens.total || b2.runCount - a.runCount || (a.model === null ? 1 : b2.model === null ? -1 : collator.compare(a.model, b2.model)));
|
|
237705
237913
|
}
|
|
237706
237914
|
};
|
|
237915
|
+
ZERO_DURATION = {
|
|
237916
|
+
firstStartedAt: null,
|
|
237917
|
+
lastEndedAt: null,
|
|
237918
|
+
inProgress: false,
|
|
237919
|
+
wallClockMs: null,
|
|
237920
|
+
runtimeMs: 0,
|
|
237921
|
+
activeMs: 0,
|
|
237922
|
+
countedRuns: 0,
|
|
237923
|
+
unstartedRuns: 0
|
|
237924
|
+
};
|
|
237707
237925
|
}
|
|
237708
237926
|
});
|
|
237709
237927
|
|
|
@@ -237959,6 +238177,22 @@ function createUsageReadService(deps) {
|
|
|
237959
238177
|
logRequest({ companyId, op: "breakdown", range: r.query.range, dimension, runs: r.runs.length, companyScoped: r.target.companyScoped, startedMs });
|
|
237960
238178
|
return body2;
|
|
237961
238179
|
},
|
|
238180
|
+
async conversationUsage(companyId, sessionId, raw) {
|
|
238181
|
+
const startedMs = Date.now();
|
|
238182
|
+
const loads = requestLoads(companyId);
|
|
238183
|
+
const r = await readLedger(companyId, { ...raw, range: raw.range ?? "all" }, loads);
|
|
238184
|
+
const relations = await loadRelations(companyId, loads);
|
|
238185
|
+
const body2 = buildChatSessionUsage(sessionId, {
|
|
238186
|
+
companyId,
|
|
238187
|
+
resolved: r.resolved,
|
|
238188
|
+
runs: r.runs,
|
|
238189
|
+
coverage: r.coverage,
|
|
238190
|
+
now: r.now,
|
|
238191
|
+
relations
|
|
238192
|
+
});
|
|
238193
|
+
logRequest({ companyId, op: "conversation", range: r.query.range, runs: r.runs.length, companyScoped: r.target.companyScoped, startedMs });
|
|
238194
|
+
return body2;
|
|
238195
|
+
},
|
|
237962
238196
|
async runtimeLedger(companyId, runtimeInstanceId, raw) {
|
|
237963
238197
|
const startedMs = Date.now();
|
|
237964
238198
|
const loads = requestLoads(companyId);
|
|
@@ -238936,6 +239170,7 @@ function collabDomain(opts) {
|
|
|
238936
239170
|
backfillInboxUnread(waitingItems, markers);
|
|
238937
239171
|
}
|
|
238938
239172
|
const items = mergeInbox(kernelItems, [...chatItems, ...waitingItems]);
|
|
239173
|
+
if (myReadMarkers) applyReadAllWatermark(items, markers);
|
|
238939
239174
|
return { status: 200, body: { items: myReadMarkers ? withEscalationAttention(items, req.auth.companyId ?? opts.defaultCompanyId ?? "", markers, Date.now(), opts.escalationReminders) : items } };
|
|
238940
239175
|
});
|
|
238941
239176
|
router.post("/api/inbox/escalations/:id/acknowledge", async (req) => {
|
|
@@ -239205,6 +239440,28 @@ function collabDomain(opts) {
|
|
|
239205
239440
|
await marks.markRead(me, scope2, (/* @__PURE__ */ new Date()).toISOString());
|
|
239206
239441
|
return { status: 200, body: { ok: true } };
|
|
239207
239442
|
});
|
|
239443
|
+
router.post("/api/inbox/read-all", async (req) => {
|
|
239444
|
+
const me = req.auth.actor;
|
|
239445
|
+
if (!isHumanActor(me)) {
|
|
239446
|
+
return { status: 403, body: { error: { code: "human_only", message: "\u53EA\u6709\u4EBA\u7C7B\u8EAB\u4EFD\u53EF\u4EE5\u6807\u8BB0\u5DF2\u8BFB" } } };
|
|
239447
|
+
}
|
|
239448
|
+
const marks = opts.resolveReadMarkers ? await opts.resolveReadMarkers(req.auth.companyId).catch(() => void 0) : opts.readMarkers;
|
|
239449
|
+
let ledger;
|
|
239450
|
+
if (opts.resolveNotificationLedger) {
|
|
239451
|
+
try {
|
|
239452
|
+
ledger = await opts.resolveNotificationLedger(req.auth.companyId);
|
|
239453
|
+
} catch (err) {
|
|
239454
|
+
console.warn(`[notifications] \u65E0\u53EF\u4FE1\u516C\u53F8\u4E0A\u4E0B\u6587\uFF0C\u4E0D\u6807\u5DF2\u8BFB\uFF08\u4E0D\u56DE\u843D\u9ED8\u8BA4\u516C\u53F8\uFF09: ${String(err)}`);
|
|
239455
|
+
}
|
|
239456
|
+
}
|
|
239457
|
+
if (!marks && !ledger) {
|
|
239458
|
+
return { status: 503, body: { error: { code: "unavailable", message: "\u5DF2\u8BFB\u6C34\u4F4D\u4E0E\u901A\u77E5\u53F0\u8D26\u90FD\u4E0D\u53EF\u7528" } } };
|
|
239459
|
+
}
|
|
239460
|
+
const readAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
239461
|
+
const notifications = ledger ? await ledger.markAllRead(me, readAt) : 0;
|
|
239462
|
+
if (marks) await marks.markRead(me, INBOX_READ_ALL_SCOPE, readAt);
|
|
239463
|
+
return { status: 200, body: { ok: true, readAt, notifications } };
|
|
239464
|
+
});
|
|
239208
239465
|
router.get("/api/audit", async (req) => {
|
|
239209
239466
|
const { engineStore, oplog, kernel } = await resolveCtx(req.auth.companyId);
|
|
239210
239467
|
const q2 = req.query;
|
|
@@ -244601,6 +244858,7 @@ function parseFilters(q2) {
|
|
|
244601
244858
|
const actorId = q2.get("actorId");
|
|
244602
244859
|
const artifactId = q2.get("artifactId");
|
|
244603
244860
|
const projectId2 = q2.get("projectId");
|
|
244861
|
+
const chatSessionId = q2.get("chatSessionId");
|
|
244604
244862
|
const runtimeKind = q2.get("runtimeKind");
|
|
244605
244863
|
const status = q2.get("status");
|
|
244606
244864
|
const rootRunId = q2.get("rootRunId");
|
|
@@ -244611,6 +244869,7 @@ function parseFilters(q2) {
|
|
|
244611
244869
|
if (actorId) f2.actorId = actorId;
|
|
244612
244870
|
if (artifactId) f2.artifactId = artifactId;
|
|
244613
244871
|
if (projectId2) f2.projectId = projectId2;
|
|
244872
|
+
if (chatSessionId) f2.chatSessionId = chatSessionId;
|
|
244614
244873
|
if (runtimeKind) f2.runtimeKind = runtimeKind;
|
|
244615
244874
|
if (status) f2.status = status;
|
|
244616
244875
|
if (rootRunId) f2.rootRunId = rootRunId;
|
|
@@ -246581,9 +246840,12 @@ function createChatSessionsDomain(opts) {
|
|
|
246581
246840
|
}
|
|
246582
246841
|
return manager ? manager : null;
|
|
246583
246842
|
}
|
|
246584
|
-
function
|
|
246843
|
+
function ownsSessionOrOperator(session, auth) {
|
|
246844
|
+
return session.humanActorId === auth.actor || isOperatorRequest(auth);
|
|
246845
|
+
}
|
|
246846
|
+
function ensureSessionReadable(session, auth, kernel) {
|
|
246585
246847
|
if (!session) throw new ApiError(404, "NOT_FOUND", "session not found");
|
|
246586
|
-
if (session
|
|
246848
|
+
if (ownsSessionOrOperator(session, auth)) return session;
|
|
246587
246849
|
if (session.workspace) {
|
|
246588
246850
|
const coordinator = coordinatorOfWorkspace(kernel, session.workspace);
|
|
246589
246851
|
if (coordinator && session.aiActorId === coordinator) return session;
|
|
@@ -246748,7 +247010,7 @@ function createChatSessionsDomain(opts) {
|
|
|
246748
247010
|
router.get("/api/chat-sessions/:id", async (req) => {
|
|
246749
247011
|
const store2 = await storeFor(req);
|
|
246750
247012
|
const [raw, kernel] = await Promise.all([store2.getSession(req.params.id), kernelFor(req)]);
|
|
246751
|
-
const session = ensureSessionReadable(raw, req.auth
|
|
247013
|
+
const session = ensureSessionReadable(raw, req.auth, kernel);
|
|
246752
247014
|
const [window3, curRuntimeId] = await Promise.all([
|
|
246753
247015
|
listRecentTurns(store2, session.id, parseTurns(req.query?.get("turns"))),
|
|
246754
247016
|
currentRuntimeId(req.auth.companyId, session.aiActorId)
|
|
@@ -246889,7 +247151,7 @@ function createChatSessionsDomain(opts) {
|
|
|
246889
247151
|
if (!items) throw new ApiError(404, "NOT_FOUND", "\u672C\u5B9E\u4F8B\u672A\u63A5 chat_items \u5FEB\u7167\u8BFB\u53E3");
|
|
246890
247152
|
const store2 = await storeFor(req);
|
|
246891
247153
|
const [session, kernel] = await Promise.all([store2.getSession(req.params.id), kernelFor(req)]);
|
|
246892
|
-
ensureSessionReadable(session, req.auth
|
|
247154
|
+
ensureSessionReadable(session, req.auth, kernel);
|
|
246893
247155
|
const chatSessionId = req.params.id;
|
|
246894
247156
|
const sinceVersion = Math.max(0, Number(req.query?.get("sinceVersion") ?? "0") || 0);
|
|
246895
247157
|
const beforeOrdRaw = Number(req.query?.get("beforeOrd") ?? "0") || 0;
|
|
@@ -247060,7 +247322,7 @@ function createChatSessionsDomain(opts) {
|
|
|
247060
247322
|
router.get("/api/chat-sessions/:id/delegations", async (req) => {
|
|
247061
247323
|
const store2 = await storeFor(req);
|
|
247062
247324
|
const session = await store2.getSession(req.params.id);
|
|
247063
|
-
if (!session || session
|
|
247325
|
+
if (!session || !ownsSessionOrOperator(session, req.auth)) throw new ApiError(404, "NOT_FOUND", "session not found");
|
|
247064
247326
|
const wiring = opts.delegations;
|
|
247065
247327
|
if (!wiring || !wiring.enabled()) return { status: 200, body: { items: [] } };
|
|
247066
247328
|
const companyId = session.companyId ?? req.auth.companyId ?? void 0;
|
|
@@ -247126,7 +247388,7 @@ function createChatSessionsDomain(opts) {
|
|
|
247126
247388
|
router.get("/api/chat-sessions/:id/work-orders", async (req) => {
|
|
247127
247389
|
const store2 = await storeFor(req);
|
|
247128
247390
|
const session = await store2.getSession(req.params.id);
|
|
247129
|
-
if (!session || session
|
|
247391
|
+
if (!session || !ownsSessionOrOperator(session, req.auth)) throw new ApiError(404, "NOT_FOUND", "session not found");
|
|
247130
247392
|
const workOrderIds = await store2.listWorkOrdersForSession(req.params.id);
|
|
247131
247393
|
const wkKernel = await kernelFor(req);
|
|
247132
247394
|
if (!wkKernel || workOrderIds.length === 0) return { status: 200, body: { items: [] } };
|
|
@@ -247149,6 +247411,29 @@ function createChatSessionsDomain(opts) {
|
|
|
247149
247411
|
});
|
|
247150
247412
|
return { status: 200, body: { items } };
|
|
247151
247413
|
});
|
|
247414
|
+
router.get("/api/chat-sessions/:id/usage", async (req) => {
|
|
247415
|
+
const store2 = await storeFor(req);
|
|
247416
|
+
const session = await store2.getSession(req.params.id);
|
|
247417
|
+
if (!session || !ownsSessionOrOperator(session, req.auth)) throw new ApiError(404, "NOT_FOUND", "session not found");
|
|
247418
|
+
const companyId = req.auth.companyId ?? session.companyId ?? opts.defaultCompanyId;
|
|
247419
|
+
if (!opts.usageRead || !companyId) {
|
|
247420
|
+
return { status: 503, body: { error: { code: "usage_ledger_unavailable", message: "\u4F7F\u7528\u4E0E\u7EDF\u8BA1\u6570\u636E\u6E90\u672A\u63A5\u5165" } } };
|
|
247421
|
+
}
|
|
247422
|
+
try {
|
|
247423
|
+
return {
|
|
247424
|
+
status: 200,
|
|
247425
|
+
body: await opts.usageRead.conversationUsage(companyId, session.id, {
|
|
247426
|
+
range: req.query.get("range") ?? void 0,
|
|
247427
|
+
asOf: req.query.get("asOf") ?? void 0,
|
|
247428
|
+
timeZone: req.query.get("timeZone") ?? void 0
|
|
247429
|
+
})
|
|
247430
|
+
};
|
|
247431
|
+
} catch (err) {
|
|
247432
|
+
const mapped = usageErrorResponse(err);
|
|
247433
|
+
if (mapped) return mapped;
|
|
247434
|
+
throw err;
|
|
247435
|
+
}
|
|
247436
|
+
});
|
|
247152
247437
|
router.get("/api/chat-broadcasts/pending", async (req) => {
|
|
247153
247438
|
if (!opts.broadcastOps) throw new ApiError(404, "NOT_FOUND", "\u672C\u5B9E\u4F8B\u672A\u542F\u7528\u5DE5\u5355\u7EC8\u6001\u64AD\u62A5");
|
|
247154
247439
|
const store2 = await storeFor(req);
|
|
@@ -247605,6 +247890,8 @@ var init_chat_sessions2 = __esm({
|
|
|
247605
247890
|
init_persistent_files();
|
|
247606
247891
|
init_files_view();
|
|
247607
247892
|
init_router();
|
|
247893
|
+
init_operator();
|
|
247894
|
+
init_usage_read();
|
|
247608
247895
|
init_collab();
|
|
247609
247896
|
init_gap_thread();
|
|
247610
247897
|
init_escalation_opening();
|
|
@@ -258375,6 +258662,7 @@ var init_postgres_trace = __esm({
|
|
|
258375
258662
|
if (filter.actorId) push2((n) => `r.actor_id = $${n}`, filter.actorId);
|
|
258376
258663
|
if (filter.artifactId) push2((n) => `r.artifact_id = $${n}`, filter.artifactId);
|
|
258377
258664
|
if (filter.projectId) push2((n) => `r.project_id = $${n}`, filter.projectId);
|
|
258665
|
+
if (filter.chatSessionId) push2((n) => `r.chat_session_id = $${n}`, filter.chatSessionId);
|
|
258378
258666
|
if (filter.runtimeKind) push2((n) => `r.runtime_kind = $${n}`, filter.runtimeKind);
|
|
258379
258667
|
if (filter.status) push2((n) => `r.status = $${n}`, filter.status);
|
|
258380
258668
|
if (filter.rootRunId) push2((n) => `r.root_run_id = $${n}`, filter.rootRunId);
|
|
@@ -258493,7 +258781,7 @@ var init_postgres_trace = __esm({
|
|
|
258493
258781
|
*/
|
|
258494
258782
|
async listRunFailures(workOrderId) {
|
|
258495
258783
|
const r = await this.pool.query(
|
|
258496
|
-
`SELECT node_id, error_message, COALESCE(started_at, created_at) AS at
|
|
258784
|
+
`SELECT node_id, actor_id, error_message, COALESCE(started_at, created_at) AS at
|
|
258497
258785
|
FROM ${this.s}.agent_runs
|
|
258498
258786
|
WHERE work_order_id = $1 AND node_id IS NOT NULL
|
|
258499
258787
|
AND error_message IS NOT NULL AND error_message <> ''
|
|
@@ -258502,6 +258790,7 @@ var init_postgres_trace = __esm({
|
|
|
258502
258790
|
);
|
|
258503
258791
|
return r.rows.map((row) => ({
|
|
258504
258792
|
nodeId: row.node_id,
|
|
258793
|
+
actorId: row.actor_id ?? null,
|
|
258505
258794
|
startedAt: new Date(row.at).toISOString(),
|
|
258506
258795
|
message: row.error_message
|
|
258507
258796
|
}));
|
|
@@ -272632,6 +272921,7 @@ __export(src_exports2, {
|
|
|
272632
272921
|
NdjsonOplogStore: () => NdjsonOplogStore,
|
|
272633
272922
|
NodeHealthTracker: () => NodeHealthTracker,
|
|
272634
272923
|
NotificationLedgerWorker: () => NotificationLedgerWorker,
|
|
272924
|
+
OPERATOR_SCOPE: () => OPERATOR_SCOPE,
|
|
272635
272925
|
ORPHANED_TURN_ASSISTANT_NOTICE: () => ORPHANED_TURN_ASSISTANT_NOTICE,
|
|
272636
272926
|
OUTPUT_COPY_LIMITS: () => OUTPUT_COPY_LIMITS,
|
|
272637
272927
|
PARENT_CONVERSATION_PATH: () => PARENT_CONVERSATION_PATH,
|
|
@@ -272868,6 +273158,7 @@ __export(src_exports2, {
|
|
|
272868
273158
|
isKnowledgeQueryPlanV2: () => isKnowledgeQueryPlanV2,
|
|
272869
273159
|
isLocationFailureCode: () => isLocationFailureCode,
|
|
272870
273160
|
isNodeHealthy: () => isNodeHealthy,
|
|
273161
|
+
isOperatorRequest: () => isOperatorRequest,
|
|
272871
273162
|
isRunTerminalStatus: () => isRunTerminalStatus,
|
|
272872
273163
|
isRuntimeDrifted: () => isRuntimeDrifted,
|
|
272873
273164
|
isRuntimeRunReader: () => isRuntimeRunReader,
|
|
@@ -273097,6 +273388,7 @@ var init_src11 = __esm({
|
|
|
273097
273388
|
"use strict";
|
|
273098
273389
|
init_server3();
|
|
273099
273390
|
init_tokens();
|
|
273391
|
+
init_operator();
|
|
273100
273392
|
init_session_dataplane_token();
|
|
273101
273393
|
init_dev_store();
|
|
273102
273394
|
init_control_plane_file_store();
|
|
@@ -276768,7 +277060,7 @@ async function startServe(opts) {
|
|
|
276768
277060
|
const issuer = createTokenIssuer({ secretFile: path28.join(opts.dir, "session-token-secret") });
|
|
276769
277061
|
const apiActivity = createApiActivityLedger();
|
|
276770
277062
|
const operatorActor = `actor:human:${os8.userInfo().username}`;
|
|
276771
|
-
const operatorToken = issuer.issue(operatorActor);
|
|
277063
|
+
const operatorToken = issuer.issue(operatorActor, { scopes: [OPERATOR_SCOPE] });
|
|
276772
277064
|
fs34.writeFileSync(path28.join(opts.dir, "operator-token"), operatorToken, { mode: 384 });
|
|
276773
277065
|
let nodeTokens = createNodeTokenStore(path28.join(opts.dir, "node-tokens.json"));
|
|
276774
277066
|
const enrollTokens = createEnrollTokenStore(30 * 60 * 1e3, path28.join(opts.dir, "enroll-tokens.json"));
|
|
@@ -279200,7 +279492,11 @@ async function startServe(opts) {
|
|
|
279200
279492
|
resolveChatItems: (companyId) => chatItemsFor(companyId),
|
|
279201
279493
|
liveChat,
|
|
279202
279494
|
// ADR-0587:列表行派生 `unread`,与 collab 域收件箱读同一份按公司的水位(无 PG 时闭包自己回落单实例)。
|
|
279203
|
-
resolveReadMarkers: readMarkerStoreFor
|
|
279495
|
+
resolveReadMarkers: readMarkerStoreFor,
|
|
279496
|
+
// ADR 0609 D4:`GET /api/chat-sessions/:id/usage` 的取数口——**与 collab 域是同一个实例**,
|
|
279497
|
+
// 按会话取数与组织统计因此永远同一份账本、同一套归属,不会出现两条路各算各的。
|
|
279498
|
+
usageRead,
|
|
279499
|
+
defaultCompanyId
|
|
279204
279500
|
})] : []
|
|
279205
279501
|
],
|
|
279206
279502
|
workorderDrafts,
|
|
@@ -279747,7 +280043,9 @@ async function startServe(opts) {
|
|
|
279747
280043
|
...c.dispatchId !== void 0 ? { dispatchId: c.dispatchId } : {},
|
|
279748
280044
|
// ADR-0078 D3:写入围栏的钥匙
|
|
279749
280045
|
...c.artifactId !== void 0 ? { artifactId: c.artifactId } : {},
|
|
279750
|
-
...c.sessionId !== void 0 ? { sessionId: c.sessionId } : {}
|
|
280046
|
+
...c.sessionId !== void 0 ? { sessionId: c.sessionId } : {},
|
|
280047
|
+
// ADR 0609 D1:签名 scopes 透给域路由,`isOperatorRequest` 据此认出部署级 operator-token。
|
|
280048
|
+
...c.scopes !== void 0 ? { scopes: c.scopes } : {}
|
|
279751
280049
|
} : null;
|
|
279752
280050
|
},
|
|
279753
280051
|
/**
|
|
@@ -288074,7 +288372,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
|
|
|
288074
288372
|
}
|
|
288075
288373
|
}
|
|
288076
288374
|
}
|
|
288077
|
-
var CLI_VERSION = "2.2.
|
|
288375
|
+
var CLI_VERSION = "2.2.69" ? "2.2.69" : "dev";
|
|
288078
288376
|
function apiHeaders(token, company) {
|
|
288079
288377
|
const headers = {
|
|
288080
288378
|
authorization: `Bearer ${token}`,
|
|
@@ -291880,7 +292178,7 @@ function shimScript() {
|
|
|
291880
292178
|
}
|
|
291881
292179
|
|
|
291882
292180
|
// src/index.ts
|
|
291883
|
-
var PKG_VERSION = true ? "2.2.
|
|
292181
|
+
var PKG_VERSION = true ? "2.2.69" : "dev";
|
|
291884
292182
|
var LOCAL_BIN = localBin();
|
|
291885
292183
|
var NPM_PREFIX = npmPrefix();
|
|
291886
292184
|
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.69",
|
|
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": "ac031d8ccbeea2dca6ecc80ad012b61de5ca2888"
|
|
30
30
|
}
|
|
31
31
|
}
|