@opengeni/api-router 2.4.2-canary.0 → 2.5.0
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/app.js +1 -1
- package/dist/{chunk-L7GVVSSQ.js → chunk-QESX7HDK.js} +650 -98
- package/dist/chunk-QESX7HDK.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/integrations/slack-interactions.d.ts +1 -1
- package/dist/mcp/server.d.ts +33 -0
- package/dist/routes/sessions.d.ts +17 -5
- package/dist/work-discovery-observability.d.ts +33 -0
- package/package.json +18 -18
- package/src/mcp/server.ts +304 -29
- package/src/routes/sessions.ts +377 -81
- package/src/work-discovery-observability.ts +121 -0
- package/dist/chunk-L7GVVSSQ.js.map +0 -1
|
@@ -2164,6 +2164,14 @@ import {
|
|
|
2164
2164
|
TASK_NOTE_MAX_LIFETIME_DAYS,
|
|
2165
2165
|
TASK_NOTE_REASON_MAX_BYTES,
|
|
2166
2166
|
TASK_NOTE_TEXT_MAX_BYTES,
|
|
2167
|
+
WORK_CLAIM_CANONICAL_KEY_MAX_BYTES,
|
|
2168
|
+
WORK_CLAIM_DISPLAY_LABEL_MAX_BYTES,
|
|
2169
|
+
WORK_CLAIM_DISCOVERY_LIMIT,
|
|
2170
|
+
WORK_CLAIM_NAMESPACE_MAX_BYTES,
|
|
2171
|
+
WORK_CLAIM_VERSION_VALUE_MAX_BYTES,
|
|
2172
|
+
WORK_DISCOVERY_QUERY_MAX_CHARS,
|
|
2173
|
+
WORK_DISCOVERY_RECENT_HOURS_MAX,
|
|
2174
|
+
WorkClaimSubjectType,
|
|
2167
2175
|
SubmitHumanInputResponseRequest
|
|
2168
2176
|
} from "@opengeni/contracts";
|
|
2169
2177
|
import {
|
|
@@ -2221,6 +2229,8 @@ import {
|
|
|
2221
2229
|
createTaskNote,
|
|
2222
2230
|
listTaskNotes,
|
|
2223
2231
|
replaceTaskNote,
|
|
2232
|
+
releaseWorkClaim,
|
|
2233
|
+
upsertWorkClaim,
|
|
2224
2234
|
acceptSessionHumanInputResponse,
|
|
2225
2235
|
HumanInputResponseValidationError
|
|
2226
2236
|
} from "@opengeni/db";
|
|
@@ -18354,6 +18364,89 @@ async function deleteScheduledTaskWithDurableCleanup(deps, input) {
|
|
|
18354
18364
|
return { task: result.task, changed: result.changed };
|
|
18355
18365
|
}
|
|
18356
18366
|
|
|
18367
|
+
// src/work-discovery-observability.ts
|
|
18368
|
+
var RESULT_BUCKETS = [0, 1, 2, 4, 8, 16, 32, 64, 100];
|
|
18369
|
+
var RESPONSE_BYTE_BUCKETS = [512, 1024, 4096, 16384, 65536, 128e3, 262144];
|
|
18370
|
+
var DURATION_BUCKETS = [5e-3, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5];
|
|
18371
|
+
function summarizeWorkDiscoveryRows(rows) {
|
|
18372
|
+
const matchCounts = {};
|
|
18373
|
+
let overlapCount = 0;
|
|
18374
|
+
for (const row of rows) {
|
|
18375
|
+
if (row.relatedWork.possibleOverlap) overlapCount += 1;
|
|
18376
|
+
const matchClass = row.relatedWork.match?.class;
|
|
18377
|
+
if (matchClass) matchCounts[matchClass] = (matchCounts[matchClass] ?? 0) + 1;
|
|
18378
|
+
}
|
|
18379
|
+
return { resultCount: rows.length, overlapCount, matchCounts };
|
|
18380
|
+
}
|
|
18381
|
+
function observeWorkDiscovery(observability, observation) {
|
|
18382
|
+
if (!observability) return;
|
|
18383
|
+
const labels = {
|
|
18384
|
+
surface: observation.surface,
|
|
18385
|
+
mode: observation.mode,
|
|
18386
|
+
outcome: observation.outcome,
|
|
18387
|
+
authorization_scope: observation.authorizationScope
|
|
18388
|
+
};
|
|
18389
|
+
try {
|
|
18390
|
+
observability.incrementCounter({
|
|
18391
|
+
name: "opengeni_work_discovery_requests_total",
|
|
18392
|
+
help: "Advisory work-discovery requests by bounded surface, mode, outcome, and authorization scope.",
|
|
18393
|
+
labels
|
|
18394
|
+
});
|
|
18395
|
+
observability.observeHistogram({
|
|
18396
|
+
name: "opengeni_work_discovery_duration_seconds",
|
|
18397
|
+
help: "Advisory work-discovery request duration in seconds.",
|
|
18398
|
+
labels,
|
|
18399
|
+
buckets: DURATION_BUCKETS,
|
|
18400
|
+
value: Math.max(0, observation.durationMs) / 1e3
|
|
18401
|
+
});
|
|
18402
|
+
observability.observeHistogram({
|
|
18403
|
+
name: "opengeni_work_discovery_results",
|
|
18404
|
+
help: "Bounded advisory work-discovery result rows per request.",
|
|
18405
|
+
labels: { surface: observation.surface, mode: observation.mode },
|
|
18406
|
+
buckets: RESULT_BUCKETS,
|
|
18407
|
+
value: Math.max(0, Math.floor(observation.resultCount))
|
|
18408
|
+
});
|
|
18409
|
+
observability.observeHistogram({
|
|
18410
|
+
name: "opengeni_work_discovery_response_bytes",
|
|
18411
|
+
help: "Serialized advisory work-discovery response bytes.",
|
|
18412
|
+
labels: { surface: observation.surface, mode: observation.mode },
|
|
18413
|
+
buckets: RESPONSE_BYTE_BUCKETS,
|
|
18414
|
+
value: Math.max(0, Math.floor(observation.responseBytes))
|
|
18415
|
+
});
|
|
18416
|
+
if (observation.overlapCount > 0) {
|
|
18417
|
+
observability.incrementCounter({
|
|
18418
|
+
name: "opengeni_work_discovery_overlap_results_total",
|
|
18419
|
+
help: "Advisory discovery rows carrying a possible-overlap explanation.",
|
|
18420
|
+
labels: { surface: observation.surface, mode: observation.mode },
|
|
18421
|
+
amount: Math.floor(observation.overlapCount)
|
|
18422
|
+
});
|
|
18423
|
+
}
|
|
18424
|
+
for (const matchClass of ["exact_subject", "title", "goal", "fuzzy"]) {
|
|
18425
|
+
const amount = Math.floor(observation.matchCounts[matchClass] ?? 0);
|
|
18426
|
+
if (amount < 1) continue;
|
|
18427
|
+
observability.incrementCounter({
|
|
18428
|
+
name: "opengeni_work_discovery_matches_total",
|
|
18429
|
+
help: "Advisory discovery matches by stable explanation class.",
|
|
18430
|
+
labels: {
|
|
18431
|
+
surface: observation.surface,
|
|
18432
|
+
mode: observation.mode,
|
|
18433
|
+
match_class: matchClass
|
|
18434
|
+
},
|
|
18435
|
+
amount
|
|
18436
|
+
});
|
|
18437
|
+
}
|
|
18438
|
+
} catch {
|
|
18439
|
+
try {
|
|
18440
|
+
observability.incrementCounter({
|
|
18441
|
+
name: "opengeni_observability_observer_errors_total",
|
|
18442
|
+
help: "Observability observer failures isolated from product execution.",
|
|
18443
|
+
labels: { observer: "work_discovery" }
|
|
18444
|
+
});
|
|
18445
|
+
} catch {
|
|
18446
|
+
}
|
|
18447
|
+
}
|
|
18448
|
+
}
|
|
18449
|
+
|
|
18357
18450
|
// src/mcp/server.ts
|
|
18358
18451
|
var ORCHESTRATION_FAILURE_CODE_MAX_LENGTH = 128;
|
|
18359
18452
|
var ORCHESTRATION_FAILURE_MESSAGE_MAX_UTF8_BYTES = 1024;
|
|
@@ -18455,6 +18548,8 @@ var FIRST_PARTY_TOOL_AUTHORIZATION = {
|
|
|
18455
18548
|
task_note_save: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
18456
18549
|
task_note_archive: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
18457
18550
|
task_note_replace: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
18551
|
+
work_claim_upsert: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
18552
|
+
work_claim_release: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
18458
18553
|
knowledge_propose: { sessionRequired: true, allOf: ["documents:search"] },
|
|
18459
18554
|
knowledge_correct: { sessionRequired: true, allOf: ["documents:search"] },
|
|
18460
18555
|
task_note_promote_knowledge: {
|
|
@@ -18784,6 +18879,9 @@ function buildOpenGeniMcpServer(deps, grant, options = {}) {
|
|
|
18784
18879
|
if (sessionId !== null && exactAgentAttemptClaims(grant) !== null) {
|
|
18785
18880
|
registerPreferenceRegistryTools(server, deps, grant, json);
|
|
18786
18881
|
registerTaskNoteTools(server, deps, grant, sessionId, json);
|
|
18882
|
+
if (deps.settings.workClaimMutationsEnabled) {
|
|
18883
|
+
registerWorkClaimTools(server, deps, grant, sessionId, json);
|
|
18884
|
+
}
|
|
18787
18885
|
const attempt = exactAgentAttemptClaims(grant);
|
|
18788
18886
|
registerCompanyBrainGovernedWriteTools({
|
|
18789
18887
|
server,
|
|
@@ -20865,6 +20963,118 @@ function registerTaskNoteTools(server, deps, grant, sessionId, json) {
|
|
|
20865
20963
|
}
|
|
20866
20964
|
);
|
|
20867
20965
|
}
|
|
20966
|
+
function registerWorkClaimTools(server, deps, grant, sessionId, json) {
|
|
20967
|
+
const attemptClaims = () => {
|
|
20968
|
+
const resolved = exactAgentAttemptClaims(grant);
|
|
20969
|
+
if (!resolved || resolved.sessionId !== sessionId) {
|
|
20970
|
+
throw new Error("Exact signed work-claim attempt authority is required.");
|
|
20971
|
+
}
|
|
20972
|
+
return {
|
|
20973
|
+
accountId: grant.accountId,
|
|
20974
|
+
workspaceId: grant.workspaceId,
|
|
20975
|
+
...resolved
|
|
20976
|
+
};
|
|
20977
|
+
};
|
|
20978
|
+
const authorize = async () => {
|
|
20979
|
+
await authorizeFirstPartySession(deps, grant, sessionId, "session.first_party_mcp.call");
|
|
20980
|
+
};
|
|
20981
|
+
server.registerTool(
|
|
20982
|
+
"work_claim_upsert",
|
|
20983
|
+
{
|
|
20984
|
+
description: "Create or refresh one typed, non-exclusive claim describing this session's current external work. Claims are advisory evidence, never locks or authority. Use stable public identifiers only; never put credentials, tokens, or other secrets in claim fields. expectedRevision=0 creates a new active claim; refreshing an existing active claim requires its exact revision. Use a fresh operationId; an exact retry from a replacement attempt on the same logical turn replays safely.",
|
|
20985
|
+
inputSchema: {
|
|
20986
|
+
operationId: z43.string().uuid(),
|
|
20987
|
+
expectedRevision: z43.number().int().min(0),
|
|
20988
|
+
subjectNamespace: z43.string().min(1).max(WORK_CLAIM_NAMESPACE_MAX_BYTES),
|
|
20989
|
+
subjectType: z43.enum([
|
|
20990
|
+
"repository",
|
|
20991
|
+
"branch",
|
|
20992
|
+
"pull_request",
|
|
20993
|
+
"issue",
|
|
20994
|
+
"artifact",
|
|
20995
|
+
"release",
|
|
20996
|
+
"ci_run",
|
|
20997
|
+
"other"
|
|
20998
|
+
]),
|
|
20999
|
+
canonicalKey: z43.string().min(1).max(WORK_CLAIM_CANONICAL_KEY_MAX_BYTES),
|
|
21000
|
+
displayLabel: z43.string().min(1).max(WORK_CLAIM_DISPLAY_LABEL_MAX_BYTES).optional(),
|
|
21001
|
+
role: z43.enum(["working", "reviewing", "monitoring", "delivering"]),
|
|
21002
|
+
versionKind: z43.enum([
|
|
21003
|
+
"git_commit",
|
|
21004
|
+
"branch_head",
|
|
21005
|
+
"pull_request_head",
|
|
21006
|
+
"artifact_version",
|
|
21007
|
+
"release_version",
|
|
21008
|
+
"ci_run",
|
|
21009
|
+
"other"
|
|
21010
|
+
]).optional(),
|
|
21011
|
+
versionValue: z43.string().min(1).max(WORK_CLAIM_VERSION_VALUE_MAX_BYTES).optional()
|
|
21012
|
+
}
|
|
21013
|
+
},
|
|
21014
|
+
async ({
|
|
21015
|
+
operationId,
|
|
21016
|
+
expectedRevision,
|
|
21017
|
+
subjectNamespace,
|
|
21018
|
+
subjectType,
|
|
21019
|
+
canonicalKey,
|
|
21020
|
+
displayLabel,
|
|
21021
|
+
role,
|
|
21022
|
+
versionKind,
|
|
21023
|
+
versionValue
|
|
21024
|
+
}) => {
|
|
21025
|
+
await authorize();
|
|
21026
|
+
if (versionKind === void 0 !== (versionValue === void 0)) {
|
|
21027
|
+
throw new Error("work_claim_upsert versionKind and versionValue must be supplied together");
|
|
21028
|
+
}
|
|
21029
|
+
return json(
|
|
21030
|
+
await upsertWorkClaim(deps.db, {
|
|
21031
|
+
...attemptClaims(),
|
|
21032
|
+
operationId,
|
|
21033
|
+
expectedRevision,
|
|
21034
|
+
subjectNamespace,
|
|
21035
|
+
subjectType,
|
|
21036
|
+
canonicalKey,
|
|
21037
|
+
...displayLabel === void 0 ? {} : { displayLabel },
|
|
21038
|
+
role,
|
|
21039
|
+
...versionKind && versionValue ? { version: { kind: versionKind, value: versionValue } } : {}
|
|
21040
|
+
})
|
|
21041
|
+
);
|
|
21042
|
+
}
|
|
21043
|
+
);
|
|
21044
|
+
server.registerTool(
|
|
21045
|
+
"work_claim_release",
|
|
21046
|
+
{
|
|
21047
|
+
description: "Release one exact active claim owned by this session. This records an immutable receipt and does not affect other sessions claiming the same subject. Use a fresh operationId and the claim's exact revision.",
|
|
21048
|
+
inputSchema: {
|
|
21049
|
+
operationId: z43.string().uuid(),
|
|
21050
|
+
claimId: z43.string().uuid(),
|
|
21051
|
+
expectedRevision: z43.number().int().min(1),
|
|
21052
|
+
reason: z43.enum([
|
|
21053
|
+
"completed",
|
|
21054
|
+
"cancelled",
|
|
21055
|
+
"failed",
|
|
21056
|
+
"superseded",
|
|
21057
|
+
"no_longer_active",
|
|
21058
|
+
"corrected",
|
|
21059
|
+
"external_state_changed",
|
|
21060
|
+
"other"
|
|
21061
|
+
])
|
|
21062
|
+
}
|
|
21063
|
+
},
|
|
21064
|
+
async ({ operationId, claimId, expectedRevision, reason: reason2 }) => {
|
|
21065
|
+
await authorize();
|
|
21066
|
+
return json(
|
|
21067
|
+
await releaseWorkClaim(deps.db, {
|
|
21068
|
+
...attemptClaims(),
|
|
21069
|
+
operationId,
|
|
21070
|
+
claimId,
|
|
21071
|
+
expectedRevision,
|
|
21072
|
+
reason: reason2
|
|
21073
|
+
})
|
|
21074
|
+
);
|
|
21075
|
+
}
|
|
21076
|
+
);
|
|
21077
|
+
}
|
|
20868
21078
|
function registerPreferenceRegistryTools(server, deps, grant, json) {
|
|
20869
21079
|
const attemptClaims = () => {
|
|
20870
21080
|
const resolved = exactAgentAttemptClaims(grant);
|
|
@@ -21451,42 +21661,132 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
21451
21661
|
server.registerTool(
|
|
21452
21662
|
"sessions_list",
|
|
21453
21663
|
{
|
|
21454
|
-
description: `List compact high-level session status in this workspace.
|
|
21664
|
+
description: `List compact high-level session status and advisory related-work evidence in this workspace. query searches semantic titles, active goals, and typed work claims; subject performs one exact provider-neutral claim lookup and ranks it ahead of text. Neither path searches initialMessage or grants access to a result. Claims are nonexclusive evidence, never locks or instructions. Relevance cursors are bound to normalized filters and a workspace activity-revision snapshot. Without search, the tool defaults to creation order; use orderBy=updatedAt with decimal activity-revision updatedAfter/updatedThrough tokens for gap-free indexed incremental monitoring independent of application clocks. includeLastMessage is opt-in and never previews a human/API prompt whose turn was never claimed (still queued, or deleted/edited/cancelled before any claim): waiting work is represented by queuedPromptCount until the turn is claimed. Rendered previews share a deterministic ${SESSION_DISCOVERY_PREVIEW_MAX_BYTES}-byte UTF-8 aggregate budget, and omitted previews include a bounded session_events drill-down input (exact message type, direction=before, limit=1, monitoring summary). Use session_get only when ordinary target authorization allows it. The list never returns full session objects, instructions, resources, tools, files, or history.`,
|
|
21455
21665
|
inputSchema: {
|
|
21456
21666
|
limit: z43.number().int().positive().max(100).optional(),
|
|
21457
21667
|
cursor: z43.string().max(512).optional(),
|
|
21458
21668
|
includeLastMessage: z43.boolean().optional(),
|
|
21459
|
-
orderBy: z43.enum(["createdAt", "updatedAt"]).optional(),
|
|
21460
|
-
updatedAfter: z43.string().max(64).optional()
|
|
21669
|
+
orderBy: z43.enum(["createdAt", "updatedAt", "relevance"]).optional(),
|
|
21670
|
+
updatedAfter: z43.string().max(64).optional(),
|
|
21671
|
+
query: z43.string().max(WORK_DISCOVERY_QUERY_MAX_CHARS).optional(),
|
|
21672
|
+
statuses: z43.array(
|
|
21673
|
+
z43.enum([
|
|
21674
|
+
"queued",
|
|
21675
|
+
"running",
|
|
21676
|
+
"idle",
|
|
21677
|
+
"requires_action",
|
|
21678
|
+
"recovering",
|
|
21679
|
+
"waiting_capacity",
|
|
21680
|
+
"failed",
|
|
21681
|
+
"cancelled"
|
|
21682
|
+
])
|
|
21683
|
+
).max(8).optional(),
|
|
21684
|
+
activeOnly: z43.boolean().optional(),
|
|
21685
|
+
recentHours: z43.number().int().positive().max(WORK_DISCOVERY_RECENT_HOURS_MAX).optional(),
|
|
21686
|
+
rootSessionId: z43.string().uuid().optional(),
|
|
21687
|
+
parentSessionId: z43.string().uuid().nullable().optional(),
|
|
21688
|
+
subject: z43.object({
|
|
21689
|
+
namespace: z43.string().min(1).max(WORK_CLAIM_NAMESPACE_MAX_BYTES),
|
|
21690
|
+
type: WorkClaimSubjectType,
|
|
21691
|
+
canonicalKey: z43.string().min(1).max(WORK_CLAIM_CANONICAL_KEY_MAX_BYTES)
|
|
21692
|
+
}).strict().optional(),
|
|
21693
|
+
claimLimit: z43.number().int().positive().max(WORK_CLAIM_DISCOVERY_LIMIT).optional()
|
|
21461
21694
|
}
|
|
21462
21695
|
},
|
|
21463
|
-
async ({
|
|
21696
|
+
async ({
|
|
21697
|
+
limit,
|
|
21698
|
+
cursor,
|
|
21699
|
+
includeLastMessage,
|
|
21700
|
+
orderBy: requestedOrderBy,
|
|
21701
|
+
updatedAfter,
|
|
21702
|
+
query,
|
|
21703
|
+
statuses,
|
|
21704
|
+
activeOnly,
|
|
21705
|
+
recentHours,
|
|
21706
|
+
rootSessionId,
|
|
21707
|
+
parentSessionId,
|
|
21708
|
+
subject,
|
|
21709
|
+
claimLimit
|
|
21710
|
+
}) => {
|
|
21464
21711
|
const authorizationScope = await requireSessionAuthorizationListScope(
|
|
21465
21712
|
deps,
|
|
21466
21713
|
grant,
|
|
21467
21714
|
"first_party_mcp"
|
|
21468
21715
|
);
|
|
21716
|
+
const startedAtMs = performance.now();
|
|
21717
|
+
const mode = subject ? "subject" : query?.trim() ? "query" : "browse";
|
|
21718
|
+
const metricAuthorizationScope = authorizationScope?.kind === "scoped" ? "scoped" : "workspace";
|
|
21469
21719
|
const decodedCursor = cursor ? decodeSessionDiscoveryCursor(cursor) : void 0;
|
|
21470
|
-
const
|
|
21471
|
-
if (
|
|
21472
|
-
|
|
21473
|
-
|
|
21474
|
-
|
|
21475
|
-
|
|
21476
|
-
|
|
21720
|
+
const relevanceRequested = Boolean(query?.trim() || subject);
|
|
21721
|
+
if (relevanceRequested && !deps.settings.workDiscoveryEnabled) {
|
|
21722
|
+
observeWorkDiscovery(deps.observability, {
|
|
21723
|
+
surface: "first_party_mcp",
|
|
21724
|
+
mode,
|
|
21725
|
+
outcome: "disabled",
|
|
21726
|
+
authorizationScope: metricAuthorizationScope,
|
|
21727
|
+
durationMs: performance.now() - startedAtMs,
|
|
21728
|
+
responseBytes: 0,
|
|
21729
|
+
resultCount: 0,
|
|
21730
|
+
overlapCount: 0,
|
|
21731
|
+
matchCounts: {}
|
|
21732
|
+
});
|
|
21733
|
+
throw new Error("sessions_list work discovery is disabled by the operator");
|
|
21477
21734
|
}
|
|
21478
|
-
|
|
21479
|
-
|
|
21735
|
+
try {
|
|
21736
|
+
const orderBy = requestedOrderBy ?? decodedCursor?.orderBy ?? (relevanceRequested ? "relevance" : "createdAt");
|
|
21737
|
+
if (decodedCursor && decodedCursor.orderBy !== orderBy) {
|
|
21738
|
+
throw new Error("sessions_list cursor order does not match orderBy");
|
|
21739
|
+
}
|
|
21740
|
+
const normalizedUpdatedAfter = updatedAfter !== void 0 ? normalizeSessionDiscoveryRevision(updatedAfter, "updatedAfter") : decodedCursor?.updatedAfter ?? void 0;
|
|
21741
|
+
if (normalizedUpdatedAfter !== void 0 && orderBy !== "updatedAt") {
|
|
21742
|
+
throw new Error("sessions_list updatedAfter requires orderBy=updatedAt");
|
|
21743
|
+
}
|
|
21744
|
+
if (decodedCursor && decodedCursor.updatedAfter !== (normalizedUpdatedAfter ?? null)) {
|
|
21745
|
+
throw new Error("sessions_list cursor does not match updatedAfter");
|
|
21746
|
+
}
|
|
21747
|
+
const page = await listSessionDiscoverySummaries(deps.db, grant.workspaceId, {
|
|
21748
|
+
limit: boundedSessionDiscoveryLimit(limit),
|
|
21749
|
+
...decodedCursor ? { cursor: decodedCursor } : {},
|
|
21750
|
+
includeLastMessage: includeLastMessage === true,
|
|
21751
|
+
orderBy,
|
|
21752
|
+
...normalizedUpdatedAfter ? { updatedAfter: normalizedUpdatedAfter } : {},
|
|
21753
|
+
...query?.trim() ? { query } : {},
|
|
21754
|
+
...statuses ? { statuses } : {},
|
|
21755
|
+
activeOnly: activeOnly === true,
|
|
21756
|
+
...recentHours !== void 0 ? { recentHours } : {},
|
|
21757
|
+
...rootSessionId ? { rootSessionId } : {},
|
|
21758
|
+
...parentSessionId !== void 0 ? { parentSessionId } : {},
|
|
21759
|
+
...subject ? { subject } : {},
|
|
21760
|
+
...claimLimit !== void 0 ? { claimLimit } : {},
|
|
21761
|
+
includeWorkDiscovery: deps.settings.workDiscoveryEnabled,
|
|
21762
|
+
subjectId: grant.subjectId,
|
|
21763
|
+
...authorizationScope ? { authorizationScope } : {}
|
|
21764
|
+
});
|
|
21765
|
+
const result = capSessionDiscoveryPage(page, includeLastMessage === true);
|
|
21766
|
+
observeWorkDiscovery(deps.observability, {
|
|
21767
|
+
surface: "first_party_mcp",
|
|
21768
|
+
mode,
|
|
21769
|
+
outcome: result.sessions.length === 0 ? "empty" : "ok",
|
|
21770
|
+
authorizationScope: metricAuthorizationScope,
|
|
21771
|
+
durationMs: performance.now() - startedAtMs,
|
|
21772
|
+
responseBytes: result.bytes,
|
|
21773
|
+
...summarizeWorkDiscoveryRows(result.sessions)
|
|
21774
|
+
});
|
|
21775
|
+
return json(result);
|
|
21776
|
+
} catch (error) {
|
|
21777
|
+
observeWorkDiscovery(deps.observability, {
|
|
21778
|
+
surface: "first_party_mcp",
|
|
21779
|
+
mode,
|
|
21780
|
+
outcome: "error",
|
|
21781
|
+
authorizationScope: metricAuthorizationScope,
|
|
21782
|
+
durationMs: performance.now() - startedAtMs,
|
|
21783
|
+
responseBytes: 0,
|
|
21784
|
+
resultCount: 0,
|
|
21785
|
+
overlapCount: 0,
|
|
21786
|
+
matchCounts: {}
|
|
21787
|
+
});
|
|
21788
|
+
throw error;
|
|
21480
21789
|
}
|
|
21481
|
-
const page = await listSessionDiscoverySummaries(deps.db, grant.workspaceId, {
|
|
21482
|
-
limit: boundedSessionDiscoveryLimit(limit),
|
|
21483
|
-
...decodedCursor ? { cursor: decodedCursor } : {},
|
|
21484
|
-
includeLastMessage: includeLastMessage === true,
|
|
21485
|
-
orderBy,
|
|
21486
|
-
...normalizedUpdatedAfter ? { updatedAfter: normalizedUpdatedAfter } : {},
|
|
21487
|
-
...authorizationScope ? { authorizationScope } : {}
|
|
21488
|
-
});
|
|
21489
|
-
return json(capSessionDiscoveryPage(page, includeLastMessage === true));
|
|
21490
21790
|
}
|
|
21491
21791
|
);
|
|
21492
21792
|
server.registerTool(
|
|
@@ -22699,10 +22999,12 @@ function boundedSessionDiscoveryLimit(limit) {
|
|
|
22699
22999
|
return Math.min(SESSION_DISCOVERY_MAX_LIMIT, Math.max(1, Math.floor(limit)));
|
|
22700
23000
|
}
|
|
22701
23001
|
function encodeSessionDiscoveryCursor(cursor) {
|
|
23002
|
+
const relevance = cursor.orderBy === "relevance";
|
|
22702
23003
|
return Buffer.from(
|
|
22703
23004
|
JSON.stringify({
|
|
22704
|
-
v: 2,
|
|
23005
|
+
v: relevance ? 3 : 2,
|
|
22705
23006
|
orderBy: cursor.orderBy,
|
|
23007
|
+
...relevance ? { sortRank: cursor.sortRank, filterHash: cursor.filterHash } : {},
|
|
22706
23008
|
sortRevision: cursor.sortRevision,
|
|
22707
23009
|
sortAt: cursor.sortAt,
|
|
22708
23010
|
id: cursor.id,
|
|
@@ -22743,28 +23045,40 @@ function decodeSessionDiscoveryCursor(value) {
|
|
|
22743
23045
|
);
|
|
22744
23046
|
return {
|
|
22745
23047
|
orderBy: "createdAt",
|
|
23048
|
+
sortRank: null,
|
|
22746
23049
|
sortRevision: "0",
|
|
22747
23050
|
sortAt: createdAt,
|
|
22748
23051
|
id: parsed.id,
|
|
22749
23052
|
snapshotAt: createdAt,
|
|
22750
23053
|
snapshotRevision: "0",
|
|
22751
|
-
updatedAfter: null
|
|
23054
|
+
updatedAfter: null,
|
|
23055
|
+
filterHash: null
|
|
22752
23056
|
};
|
|
22753
23057
|
}
|
|
22754
23058
|
if (parsed.v === 1 && parsed.orderBy === "createdAt" && typeof parsed.sortAt === "string" && typeof parsed.snapshotAt === "string" && parsed.updatedAfter === null && typeof parsed.id === "string" && SESSION_DISCOVERY_UUID.test(parsed.id)) {
|
|
22755
23059
|
return {
|
|
22756
23060
|
orderBy: "createdAt",
|
|
23061
|
+
sortRank: null,
|
|
22757
23062
|
sortRevision: "0",
|
|
22758
23063
|
sortAt: normalizeSessionDiscoveryTimestamp(parsed.sortAt, "cursor sortAt"),
|
|
22759
23064
|
id: parsed.id,
|
|
22760
23065
|
snapshotAt: normalizeSessionDiscoveryTimestamp(parsed.snapshotAt, "cursor snapshotAt"),
|
|
22761
23066
|
snapshotRevision: "0",
|
|
22762
|
-
updatedAfter: null
|
|
23067
|
+
updatedAfter: null,
|
|
23068
|
+
filterHash: null
|
|
22763
23069
|
};
|
|
22764
23070
|
}
|
|
22765
|
-
|
|
23071
|
+
const isV2 = parsed.v === 2;
|
|
23072
|
+
const isV3 = parsed.v === 3;
|
|
23073
|
+
if (!isV2 && !isV3 || isV2 && parsed.orderBy !== "createdAt" && parsed.orderBy !== "updatedAt" || isV3 && parsed.orderBy !== "relevance" || typeof parsed.sortRevision !== "string" || typeof parsed.sortAt !== "string" || typeof parsed.snapshotAt !== "string" || typeof parsed.snapshotRevision !== "string" || parsed.updatedAfter !== null && typeof parsed.updatedAfter !== "string" || typeof parsed.id !== "string" || !SESSION_DISCOVERY_UUID.test(parsed.id)) {
|
|
22766
23074
|
throw new Error("invalid cursor fields");
|
|
22767
23075
|
}
|
|
23076
|
+
if (isV3 && (!Number.isSafeInteger(parsed.sortRank) || parsed.sortRank < 0 || typeof parsed.filterHash !== "string" || !/^[0-9a-f]{64}$/.test(parsed.filterHash))) {
|
|
23077
|
+
throw new Error("invalid relevance cursor fields");
|
|
23078
|
+
}
|
|
23079
|
+
if (isV2 && (parsed.sortRank !== void 0 || parsed.filterHash !== void 0)) {
|
|
23080
|
+
throw new Error("chronological cursor cannot carry relevance fields");
|
|
23081
|
+
}
|
|
22768
23082
|
const sortAt = normalizeSessionDiscoveryTimestamp(parsed.sortAt, "cursor sortAt");
|
|
22769
23083
|
const snapshotAt = normalizeSessionDiscoveryTimestamp(parsed.snapshotAt, "cursor snapshotAt");
|
|
22770
23084
|
const sortRevision = normalizeSessionDiscoveryRevision(
|
|
@@ -22782,14 +23096,17 @@ function decodeSessionDiscoveryCursor(value) {
|
|
|
22782
23096
|
if (parsed.orderBy === "createdAt" && (sortRevision !== "0" || snapshotRevision !== "0")) {
|
|
22783
23097
|
throw new Error("creation cursor cannot carry activity revisions");
|
|
22784
23098
|
}
|
|
23099
|
+
const orderBy = isV3 ? "relevance" : parsed.orderBy;
|
|
22785
23100
|
return {
|
|
22786
|
-
orderBy
|
|
23101
|
+
orderBy,
|
|
23102
|
+
sortRank: isV3 ? parsed.sortRank : null,
|
|
22787
23103
|
sortRevision,
|
|
22788
23104
|
sortAt,
|
|
22789
23105
|
id: parsed.id,
|
|
22790
23106
|
snapshotAt,
|
|
22791
23107
|
snapshotRevision,
|
|
22792
|
-
updatedAfter: normalizedUpdatedAfter
|
|
23108
|
+
updatedAfter: normalizedUpdatedAfter,
|
|
23109
|
+
filterHash: isV3 ? parsed.filterHash : null
|
|
22793
23110
|
};
|
|
22794
23111
|
} catch {
|
|
22795
23112
|
throw new Error("sessions_list cursor is invalid");
|
|
@@ -22857,6 +23174,7 @@ function capSessionDiscoveryPage(page, includeLastMessage) {
|
|
|
22857
23174
|
} : null,
|
|
22858
23175
|
queuedPromptCount: session.queuedPromptCount,
|
|
22859
23176
|
children: session.treeStats,
|
|
23177
|
+
relatedWork: session.workDiscovery,
|
|
22860
23178
|
...includeLastMessage ? {
|
|
22861
23179
|
latestMessage: session.latestMessage ? {
|
|
22862
23180
|
type: session.latestMessage.type,
|
|
@@ -22907,12 +23225,14 @@ function capSessionDiscoveryPage(page, includeLastMessage) {
|
|
|
22907
23225
|
const sourceLast = lastKept ? page.sessions.find((session) => session.id === lastKept.id) : void 0;
|
|
22908
23226
|
const nextCursor = droppedForByteCap ? sourceLast ? encodeSessionDiscoveryCursor({
|
|
22909
23227
|
orderBy: page.orderBy,
|
|
23228
|
+
sortRank: sourceLast.sortRank,
|
|
22910
23229
|
sortRevision: sourceLast.sortRevision,
|
|
22911
23230
|
sortAt: sourceLast.sortAt,
|
|
22912
23231
|
id: sourceLast.id,
|
|
22913
23232
|
snapshotAt: page.snapshotAt,
|
|
22914
23233
|
snapshotRevision: page.snapshotRevision,
|
|
22915
|
-
updatedAfter: page.updatedAfter
|
|
23234
|
+
updatedAfter: page.updatedAfter,
|
|
23235
|
+
filterHash: page.filterHash
|
|
22916
23236
|
}) : null : page.nextCursor ? encodeSessionDiscoveryCursor(page.nextCursor) : null;
|
|
22917
23237
|
const result2 = {
|
|
22918
23238
|
sessions: kept,
|
|
@@ -46725,6 +47045,15 @@ import {
|
|
|
46725
47045
|
UpdateSessionToolPolicyRequest,
|
|
46726
47046
|
ViewerHeartbeatRequest,
|
|
46727
47047
|
WORKSPACE_CONTROL_ACTOR_MAX_BYTES,
|
|
47048
|
+
WORK_CLAIM_CANONICAL_KEY_MAX_BYTES as WORK_CLAIM_CANONICAL_KEY_MAX_BYTES2,
|
|
47049
|
+
WORK_CLAIM_DISCOVERY_LIMIT as WORK_CLAIM_DISCOVERY_LIMIT2,
|
|
47050
|
+
WORK_CLAIM_NAMESPACE_MAX_BYTES as WORK_CLAIM_NAMESPACE_MAX_BYTES2,
|
|
47051
|
+
WORK_DISCOVERY_QUERY_MAX_CHARS as WORK_DISCOVERY_QUERY_MAX_CHARS2,
|
|
47052
|
+
WORK_DISCOVERY_RECENT_HOURS_MAX as WORK_DISCOVERY_RECENT_HOURS_MAX2,
|
|
47053
|
+
WorkClaimSubjectFilter as WorkClaimSubjectFilterSchema,
|
|
47054
|
+
WorkClaimSubjectType as WorkClaimSubjectType2,
|
|
47055
|
+
normalizeWorkClaimCanonicalKey,
|
|
47056
|
+
normalizeWorkClaimNamespace,
|
|
46728
47057
|
workspaceControlUtf8Bytes
|
|
46729
47058
|
} from "@opengeni/contracts";
|
|
46730
47059
|
import { streamTokenDegraded } from "@opengeni/config";
|
|
@@ -48178,60 +48507,127 @@ function registerSessionRoutes(app, deps) {
|
|
|
48178
48507
|
throw sessionAuthorizationHttpError(error);
|
|
48179
48508
|
}
|
|
48180
48509
|
const query = agentTopologyQuery(c.req.query());
|
|
48181
|
-
const
|
|
48182
|
-
|
|
48183
|
-
|
|
48184
|
-
|
|
48185
|
-
|
|
48186
|
-
|
|
48187
|
-
|
|
48188
|
-
|
|
48189
|
-
|
|
48190
|
-
|
|
48191
|
-
|
|
48192
|
-
|
|
48193
|
-
|
|
48194
|
-
|
|
48195
|
-
|
|
48196
|
-
|
|
48197
|
-
|
|
48198
|
-
|
|
48199
|
-
|
|
48200
|
-
|
|
48201
|
-
|
|
48202
|
-
|
|
48203
|
-
|
|
48204
|
-
|
|
48205
|
-
|
|
48206
|
-
|
|
48207
|
-
|
|
48208
|
-
}
|
|
48209
|
-
|
|
48210
|
-
|
|
48211
|
-
|
|
48212
|
-
|
|
48213
|
-
|
|
48214
|
-
|
|
48215
|
-
|
|
48216
|
-
|
|
48217
|
-
|
|
48218
|
-
|
|
48219
|
-
|
|
48220
|
-
|
|
48221
|
-
|
|
48222
|
-
|
|
48510
|
+
const startedAtMs = performance.now();
|
|
48511
|
+
const mode = query.subject ? "subject" : query.query ? "query" : "browse";
|
|
48512
|
+
const metricAuthorizationScope = authorizationScope?.kind === "scoped" ? "scoped" : "workspace";
|
|
48513
|
+
if ((query.query || query.subject) && !settings.workDiscoveryEnabled) {
|
|
48514
|
+
observeWorkDiscovery(deps.observability, {
|
|
48515
|
+
surface: "agent_topology",
|
|
48516
|
+
mode,
|
|
48517
|
+
outcome: "disabled",
|
|
48518
|
+
authorizationScope: metricAuthorizationScope,
|
|
48519
|
+
durationMs: performance.now() - startedAtMs,
|
|
48520
|
+
responseBytes: 0,
|
|
48521
|
+
resultCount: 0,
|
|
48522
|
+
overlapCount: 0,
|
|
48523
|
+
matchCounts: {}
|
|
48524
|
+
});
|
|
48525
|
+
throw new HTTPException53(503, {
|
|
48526
|
+
message: "Agent work discovery is disabled by the operator."
|
|
48527
|
+
});
|
|
48528
|
+
}
|
|
48529
|
+
try {
|
|
48530
|
+
const orderBy = query.query || query.subject ? "relevance" : "updatedAt";
|
|
48531
|
+
const page = await listSessionDiscoverySummaries2(db, workspaceId, {
|
|
48532
|
+
limit: query.limit,
|
|
48533
|
+
orderBy,
|
|
48534
|
+
subjectId: grant.subjectId,
|
|
48535
|
+
...query.cursor ? { cursor: query.cursor } : {},
|
|
48536
|
+
...query.parentSessionId !== void 0 ? { parentSessionId: query.parentSessionId } : {},
|
|
48537
|
+
...query.rootSessionId ? { rootSessionId: query.rootSessionId } : {},
|
|
48538
|
+
...query.query ? { query: query.query } : {},
|
|
48539
|
+
...query.statuses ? { statuses: query.statuses } : {},
|
|
48540
|
+
activeOnly: query.activeOnly,
|
|
48541
|
+
...query.recentHours !== void 0 ? { recentHours: query.recentHours } : {},
|
|
48542
|
+
...query.subject ? { subject: query.subject } : {},
|
|
48543
|
+
...query.claimLimit !== void 0 ? { claimLimit: query.claimLimit } : {},
|
|
48544
|
+
includeWorkDiscovery: settings.workDiscoveryEnabled,
|
|
48545
|
+
...authorizationScope ? { authorizationScope } : {}
|
|
48546
|
+
});
|
|
48547
|
+
const ancestorPaths = query.query || query.subject ? await listSessionDiscoveryAncestorPaths(
|
|
48548
|
+
db,
|
|
48549
|
+
workspaceId,
|
|
48550
|
+
page.sessions.map((session) => session.id),
|
|
48551
|
+
authorizationScope ?? void 0,
|
|
48552
|
+
grant.subjectId
|
|
48553
|
+
) : /* @__PURE__ */ new Map();
|
|
48554
|
+
const sessions = page.sessions.map((session) => {
|
|
48555
|
+
const blocker = session.effectiveControl.primaryBlocker;
|
|
48556
|
+
return {
|
|
48557
|
+
id: session.id,
|
|
48558
|
+
title: session.title,
|
|
48559
|
+
titleTruncated: session.titleOriginalChars !== null && session.titleOriginalChars > Array.from(session.title ?? "").length,
|
|
48560
|
+
parentSessionId: session.parentSessionId,
|
|
48561
|
+
rootSessionId: session.rootSessionId,
|
|
48562
|
+
nestedAgentDepth: session.nestedAgentDepth,
|
|
48563
|
+
ancestorPath: (ancestorPaths.get(session.id) ?? []).map((ancestor) => ({
|
|
48564
|
+
id: ancestor.id,
|
|
48565
|
+
title: ancestor.title,
|
|
48566
|
+
titleTruncated: ancestor.titleOriginalChars !== null && ancestor.titleOriginalChars > Array.from(ancestor.title ?? "").length
|
|
48567
|
+
})),
|
|
48568
|
+
status: session.status,
|
|
48569
|
+
goal: session.goal ? {
|
|
48570
|
+
status: session.goal.status,
|
|
48571
|
+
summary: session.goal.text,
|
|
48572
|
+
summaryTruncated: session.goal.textOriginalChars > Array.from(session.goal.text).length
|
|
48573
|
+
} : null,
|
|
48574
|
+
pause: {
|
|
48575
|
+
state: session.effectiveControl.state,
|
|
48576
|
+
additionalBlockerCount: session.effectiveControl.additionalBlockerCount,
|
|
48577
|
+
source: blocker ? {
|
|
48578
|
+
kind: blocker.kind,
|
|
48579
|
+
...blocker.sessionId ? { sessionId: blocker.sessionId } : {},
|
|
48580
|
+
displayName: blocker.displayName,
|
|
48581
|
+
displayNameTruncated: blocker.displayNameOriginalChars > Array.from(blocker.displayName).length
|
|
48582
|
+
} : null
|
|
48583
|
+
},
|
|
48584
|
+
children: session.treeStats,
|
|
48585
|
+
relatedWork: session.workDiscovery,
|
|
48586
|
+
createdAt: session.createdAt,
|
|
48587
|
+
updatedAt: session.updatedAt
|
|
48588
|
+
};
|
|
48589
|
+
});
|
|
48590
|
+
const response = {
|
|
48591
|
+
sessions,
|
|
48592
|
+
total: page.total,
|
|
48593
|
+
hasMore: page.hasMore,
|
|
48594
|
+
humanAdvisoriesEnabled: settings.workDiscoveryEnabled && settings.workDiscoveryHumanAdvisoriesEnabled,
|
|
48595
|
+
nextCursor: page.nextCursor ? encodeAgentTopologyCursor({
|
|
48596
|
+
cursor: page.nextCursor,
|
|
48597
|
+
parentSessionId: query.parentSessionId === void 0 ? "all" : query.parentSessionId,
|
|
48598
|
+
rootSessionId: query.rootSessionId ?? null,
|
|
48599
|
+
query: query.query ?? null,
|
|
48600
|
+
statuses: query.statuses ?? [],
|
|
48601
|
+
activeOnly: query.activeOnly,
|
|
48602
|
+
recentHours: query.recentHours ?? null,
|
|
48603
|
+
subject: query.subject ?? null,
|
|
48604
|
+
claimLimit: query.claimLimit ?? null
|
|
48605
|
+
}) : null
|
|
48223
48606
|
};
|
|
48224
|
-
|
|
48225
|
-
|
|
48226
|
-
|
|
48227
|
-
|
|
48228
|
-
|
|
48229
|
-
|
|
48230
|
-
|
|
48231
|
-
|
|
48232
|
-
|
|
48233
|
-
|
|
48234
|
-
})
|
|
48607
|
+
observeWorkDiscovery(deps.observability, {
|
|
48608
|
+
surface: "agent_topology",
|
|
48609
|
+
mode,
|
|
48610
|
+
outcome: sessions.length === 0 ? "empty" : "ok",
|
|
48611
|
+
authorizationScope: metricAuthorizationScope,
|
|
48612
|
+
durationMs: performance.now() - startedAtMs,
|
|
48613
|
+
responseBytes: Buffer.byteLength(JSON.stringify(response), "utf8"),
|
|
48614
|
+
...summarizeWorkDiscoveryRows(sessions)
|
|
48615
|
+
});
|
|
48616
|
+
return c.json(response);
|
|
48617
|
+
} catch (error) {
|
|
48618
|
+
observeWorkDiscovery(deps.observability, {
|
|
48619
|
+
surface: "agent_topology",
|
|
48620
|
+
mode,
|
|
48621
|
+
outcome: "error",
|
|
48622
|
+
authorizationScope: metricAuthorizationScope,
|
|
48623
|
+
durationMs: performance.now() - startedAtMs,
|
|
48624
|
+
responseBytes: 0,
|
|
48625
|
+
resultCount: 0,
|
|
48626
|
+
overlapCount: 0,
|
|
48627
|
+
matchCounts: {}
|
|
48628
|
+
});
|
|
48629
|
+
throw error;
|
|
48630
|
+
}
|
|
48235
48631
|
});
|
|
48236
48632
|
app.get("/v1/workspaces/:workspaceId/sessions/:sessionId", async (c) => {
|
|
48237
48633
|
const workspaceId = c.req.param("workspaceId");
|
|
@@ -51498,7 +51894,7 @@ function sessionListQuery(query, allowCursor = true) {
|
|
|
51498
51894
|
};
|
|
51499
51895
|
}
|
|
51500
51896
|
function encodeAgentTopologyCursor(value) {
|
|
51501
|
-
return Buffer.from(JSON.stringify({ v:
|
|
51897
|
+
return Buffer.from(JSON.stringify({ v: 2, ...value }), "utf8").toString("base64url");
|
|
51502
51898
|
}
|
|
51503
51899
|
function decodeAgentTopologyCursor(value) {
|
|
51504
51900
|
if (value.length > 2048) {
|
|
@@ -51507,23 +51903,85 @@ function decodeAgentTopologyCursor(value) {
|
|
|
51507
51903
|
});
|
|
51508
51904
|
}
|
|
51509
51905
|
try {
|
|
51510
|
-
const
|
|
51906
|
+
const decoded2 = JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
|
|
51907
|
+
const legacy = z13.object({
|
|
51511
51908
|
v: z13.literal(1),
|
|
51512
51909
|
parentSessionId: z13.string().uuid().nullable(),
|
|
51513
|
-
search: z13.string().max(
|
|
51910
|
+
search: z13.string().max(WORK_DISCOVERY_QUERY_MAX_CHARS2).nullable(),
|
|
51514
51911
|
cursor: z13.object({
|
|
51515
|
-
orderBy: z13.
|
|
51912
|
+
orderBy: z13.literal("updatedAt"),
|
|
51516
51913
|
sortRevision: z13.string().max(64),
|
|
51517
51914
|
sortAt: z13.string().max(64),
|
|
51518
51915
|
id: z13.string().uuid(),
|
|
51519
51916
|
snapshotAt: z13.string().max(64),
|
|
51520
51917
|
snapshotRevision: z13.string().max(64),
|
|
51521
|
-
updatedAfter: z13.
|
|
51918
|
+
updatedAfter: z13.null()
|
|
51522
51919
|
})
|
|
51523
|
-
}).
|
|
51524
|
-
if (
|
|
51920
|
+
}).safeParse(decoded2);
|
|
51921
|
+
if (legacy.success) {
|
|
51922
|
+
if (legacy.data.search !== null) {
|
|
51923
|
+
throw new Error("legacy search cursor is not relevance-fenced");
|
|
51924
|
+
}
|
|
51925
|
+
const cursor = {
|
|
51926
|
+
...legacy.data.cursor,
|
|
51927
|
+
sortRank: null,
|
|
51928
|
+
filterHash: null
|
|
51929
|
+
};
|
|
51930
|
+
return {
|
|
51931
|
+
cursor,
|
|
51932
|
+
parentSessionId: legacy.data.parentSessionId,
|
|
51933
|
+
rootSessionId: null,
|
|
51934
|
+
query: null,
|
|
51935
|
+
statuses: [],
|
|
51936
|
+
activeOnly: false,
|
|
51937
|
+
recentHours: null,
|
|
51938
|
+
subject: null,
|
|
51939
|
+
claimLimit: null
|
|
51940
|
+
};
|
|
51941
|
+
}
|
|
51942
|
+
const parsed = z13.object({
|
|
51943
|
+
v: z13.literal(2),
|
|
51944
|
+
parentSessionId: z13.union([z13.string().uuid(), z13.literal("all"), z13.null()]),
|
|
51945
|
+
rootSessionId: z13.string().uuid().nullable(),
|
|
51946
|
+
query: z13.string().max(WORK_DISCOVERY_QUERY_MAX_CHARS2).nullable(),
|
|
51947
|
+
statuses: z13.array(
|
|
51948
|
+
z13.enum([
|
|
51949
|
+
"queued",
|
|
51950
|
+
"running",
|
|
51951
|
+
"idle",
|
|
51952
|
+
"requires_action",
|
|
51953
|
+
"recovering",
|
|
51954
|
+
"waiting_capacity",
|
|
51955
|
+
"failed",
|
|
51956
|
+
"cancelled"
|
|
51957
|
+
])
|
|
51958
|
+
).max(8),
|
|
51959
|
+
activeOnly: z13.boolean(),
|
|
51960
|
+
recentHours: z13.number().int().positive().max(WORK_DISCOVERY_RECENT_HOURS_MAX2).nullable(),
|
|
51961
|
+
subject: z13.object({
|
|
51962
|
+
namespace: z13.string().min(1).max(WORK_CLAIM_NAMESPACE_MAX_BYTES2),
|
|
51963
|
+
type: WorkClaimSubjectType2,
|
|
51964
|
+
canonicalKey: z13.string().min(1).max(WORK_CLAIM_CANONICAL_KEY_MAX_BYTES2)
|
|
51965
|
+
}).strict().nullable(),
|
|
51966
|
+
claimLimit: z13.number().int().positive().max(WORK_CLAIM_DISCOVERY_LIMIT2).nullable(),
|
|
51967
|
+
cursor: z13.object({
|
|
51968
|
+
orderBy: z13.enum(["updatedAt", "relevance"]),
|
|
51969
|
+
sortRank: z13.number().int().nonnegative().nullable(),
|
|
51970
|
+
sortRevision: z13.string().max(64),
|
|
51971
|
+
sortAt: z13.string().max(64),
|
|
51972
|
+
id: z13.string().uuid(),
|
|
51973
|
+
snapshotAt: z13.string().max(64),
|
|
51974
|
+
snapshotRevision: z13.string().max(64),
|
|
51975
|
+
updatedAfter: z13.null(),
|
|
51976
|
+
filterHash: z13.string().regex(/^[0-9a-f]{64}$/).nullable()
|
|
51977
|
+
})
|
|
51978
|
+
}).parse(decoded2);
|
|
51979
|
+
if (!/^(?:0|[1-9]\d*)$/.test(parsed.cursor.sortRevision) || !/^(?:0|[1-9]\d*)$/.test(parsed.cursor.snapshotRevision) || BigInt(parsed.cursor.sortRevision) > 9223372036854775807n || BigInt(parsed.cursor.snapshotRevision) > 9223372036854775807n || Number.isNaN(Date.parse(parsed.cursor.sortAt)) || Number.isNaN(Date.parse(parsed.cursor.snapshotAt))) {
|
|
51525
51980
|
throw new Error("invalid topology cursor fields");
|
|
51526
51981
|
}
|
|
51982
|
+
if (parsed.cursor.orderBy === "relevance" && (parsed.cursor.sortRank === null || parsed.cursor.filterHash === null) || parsed.cursor.orderBy === "updatedAt" && (parsed.cursor.sortRank !== null || parsed.cursor.filterHash !== null)) {
|
|
51983
|
+
throw new Error("invalid topology cursor relevance fields");
|
|
51984
|
+
}
|
|
51527
51985
|
return parsed;
|
|
51528
51986
|
} catch {
|
|
51529
51987
|
throw new HTTPException53(400, {
|
|
@@ -51545,20 +52003,108 @@ function agentTopologyQuery(query) {
|
|
|
51545
52003
|
message: 'parentSessionId must be a session id or the literal "null"'
|
|
51546
52004
|
});
|
|
51547
52005
|
}
|
|
51548
|
-
const
|
|
51549
|
-
|
|
51550
|
-
|
|
52006
|
+
const rootSessionId = query.rootSessionId?.trim();
|
|
52007
|
+
if (rootSessionId && !z13.string().uuid().safeParse(rootSessionId).success) {
|
|
52008
|
+
throw new HTTPException53(400, { message: "rootSessionId must be a session id" });
|
|
52009
|
+
}
|
|
52010
|
+
const normalizeSearchQuery = (value) => {
|
|
52011
|
+
if (value === void 0) return void 0;
|
|
52012
|
+
const canonical = value.normalize("NFKC");
|
|
52013
|
+
if (/[\u0000-\u001f\u007f-\u009f]/u.test(canonical)) {
|
|
52014
|
+
throw new HTTPException53(400, { message: "query must not contain control characters" });
|
|
52015
|
+
}
|
|
52016
|
+
const normalized = canonical.trim().replace(/\s+/gu, " ").toLowerCase();
|
|
52017
|
+
if (!normalized) return void 0;
|
|
52018
|
+
if (Array.from(normalized).length > WORK_DISCOVERY_QUERY_MAX_CHARS2) {
|
|
52019
|
+
throw new HTTPException53(400, {
|
|
52020
|
+
message: `query must be at most ${WORK_DISCOVERY_QUERY_MAX_CHARS2} characters`
|
|
52021
|
+
});
|
|
52022
|
+
}
|
|
52023
|
+
return normalized;
|
|
52024
|
+
};
|
|
52025
|
+
const requestedQuery = normalizeSearchQuery(query.query);
|
|
52026
|
+
const legacySearch = normalizeSearchQuery(query.search);
|
|
52027
|
+
const searchQuery = requestedQuery ?? legacySearch;
|
|
52028
|
+
if (requestedQuery && legacySearch && requestedQuery !== legacySearch) {
|
|
52029
|
+
throw new HTTPException53(400, { message: "query and legacy search must match" });
|
|
52030
|
+
}
|
|
52031
|
+
const statuses = query.statuses ? [
|
|
52032
|
+
...new Set(
|
|
52033
|
+
query.statuses.split(",").map((status) => status.trim()).filter(Boolean)
|
|
52034
|
+
)
|
|
52035
|
+
].sort() : [];
|
|
52036
|
+
const parsedStatuses = z13.array(
|
|
52037
|
+
z13.enum([
|
|
52038
|
+
"queued",
|
|
52039
|
+
"running",
|
|
52040
|
+
"idle",
|
|
52041
|
+
"requires_action",
|
|
52042
|
+
"recovering",
|
|
52043
|
+
"waiting_capacity",
|
|
52044
|
+
"failed",
|
|
52045
|
+
"cancelled"
|
|
52046
|
+
])
|
|
52047
|
+
).max(8).safeParse(statuses);
|
|
52048
|
+
if (!parsedStatuses.success) {
|
|
52049
|
+
throw new HTTPException53(400, { message: "statuses contains an unsupported lifecycle state" });
|
|
52050
|
+
}
|
|
52051
|
+
const activeOnly = query.activeOnly === "true";
|
|
52052
|
+
if (query.activeOnly !== void 0 && query.activeOnly !== "true" && query.activeOnly !== "false") {
|
|
52053
|
+
throw new HTTPException53(400, { message: "activeOnly must be true or false" });
|
|
52054
|
+
}
|
|
52055
|
+
const recentHours = query.recentHours === void 0 ? void 0 : Number(query.recentHours);
|
|
52056
|
+
if (recentHours !== void 0 && (!Number.isSafeInteger(recentHours) || recentHours < 1 || recentHours > WORK_DISCOVERY_RECENT_HOURS_MAX2)) {
|
|
51551
52057
|
throw new HTTPException53(400, {
|
|
51552
|
-
message:
|
|
52058
|
+
message: `recentHours must be an integer between 1 and ${WORK_DISCOVERY_RECENT_HOURS_MAX2}`
|
|
52059
|
+
});
|
|
52060
|
+
}
|
|
52061
|
+
const subjectFields = [query.subjectNamespace, query.subjectType, query.subjectKey];
|
|
52062
|
+
if (subjectFields.some((value) => value !== void 0) && subjectFields.some((value) => !value)) {
|
|
52063
|
+
throw new HTTPException53(400, {
|
|
52064
|
+
message: "subjectNamespace, subjectType, and subjectKey must be supplied together"
|
|
51553
52065
|
});
|
|
51554
52066
|
}
|
|
51555
|
-
|
|
52067
|
+
const parsedSubject = subjectFields.every((value) => value !== void 0) ? WorkClaimSubjectFilterSchema.safeParse({
|
|
52068
|
+
namespace: normalizeWorkClaimNamespace(query.subjectNamespace),
|
|
52069
|
+
type: query.subjectType,
|
|
52070
|
+
canonicalKey: normalizeWorkClaimCanonicalKey(query.subjectKey)
|
|
52071
|
+
}) : null;
|
|
52072
|
+
if (parsedSubject && !parsedSubject.success) {
|
|
52073
|
+
throw new HTTPException53(400, { message: "exact subject filter is invalid" });
|
|
52074
|
+
}
|
|
52075
|
+
const subject = parsedSubject?.success ? parsedSubject.data : void 0;
|
|
52076
|
+
if (searchQuery && subject) {
|
|
52077
|
+
throw new HTTPException53(400, { message: "query cannot be combined with an exact subject" });
|
|
52078
|
+
}
|
|
52079
|
+
const relevanceRequested = Boolean(searchQuery || subject);
|
|
52080
|
+
const parentSessionId = rawParent === void 0 ? relevanceRequested ? void 0 : null : rawParent === "null" ? null : rawParent;
|
|
52081
|
+
const claimLimit = query.claimLimit === void 0 ? void 0 : Number(query.claimLimit);
|
|
52082
|
+
if (claimLimit !== void 0 && (!Number.isSafeInteger(claimLimit) || claimLimit < 1 || claimLimit > WORK_CLAIM_DISCOVERY_LIMIT2)) {
|
|
51556
52083
|
throw new HTTPException53(400, {
|
|
51557
|
-
message:
|
|
52084
|
+
message: `claimLimit must be an integer between 1 and ${WORK_CLAIM_DISCOVERY_LIMIT2}`
|
|
51558
52085
|
});
|
|
51559
52086
|
}
|
|
51560
52087
|
const envelope = query.cursor ? decodeAgentTopologyCursor(query.cursor) : void 0;
|
|
51561
|
-
|
|
52088
|
+
const expectedEnvelope = {
|
|
52089
|
+
parentSessionId: parentSessionId === void 0 ? "all" : parentSessionId,
|
|
52090
|
+
rootSessionId: rootSessionId ?? null,
|
|
52091
|
+
query: searchQuery || null,
|
|
52092
|
+
statuses: parsedStatuses.data,
|
|
52093
|
+
activeOnly,
|
|
52094
|
+
recentHours: recentHours ?? null,
|
|
52095
|
+
subject: subject ?? null,
|
|
52096
|
+
claimLimit: claimLimit ?? null
|
|
52097
|
+
};
|
|
52098
|
+
if (envelope && JSON.stringify({
|
|
52099
|
+
parentSessionId: envelope.parentSessionId,
|
|
52100
|
+
rootSessionId: envelope.rootSessionId,
|
|
52101
|
+
query: envelope.query,
|
|
52102
|
+
statuses: envelope.statuses,
|
|
52103
|
+
activeOnly: envelope.activeOnly,
|
|
52104
|
+
recentHours: envelope.recentHours,
|
|
52105
|
+
subject: envelope.subject,
|
|
52106
|
+
claimLimit: envelope.claimLimit
|
|
52107
|
+
}) !== JSON.stringify(expectedEnvelope)) {
|
|
51562
52108
|
throw new HTTPException53(400, {
|
|
51563
52109
|
message: "agent topology cursor does not match its filters"
|
|
51564
52110
|
});
|
|
@@ -51566,7 +52112,13 @@ function agentTopologyQuery(query) {
|
|
|
51566
52112
|
return {
|
|
51567
52113
|
limit,
|
|
51568
52114
|
parentSessionId,
|
|
51569
|
-
|
|
52115
|
+
rootSessionId: rootSessionId || void 0,
|
|
52116
|
+
query: searchQuery || void 0,
|
|
52117
|
+
statuses: parsedStatuses.data.length > 0 ? parsedStatuses.data : void 0,
|
|
52118
|
+
activeOnly,
|
|
52119
|
+
recentHours,
|
|
52120
|
+
subject,
|
|
52121
|
+
claimLimit,
|
|
51570
52122
|
cursor: envelope?.cursor
|
|
51571
52123
|
};
|
|
51572
52124
|
}
|
|
@@ -65379,4 +65931,4 @@ export {
|
|
|
65379
65931
|
withDefaultEnabledCapabilityMcpTools,
|
|
65380
65932
|
workflowIdForSession3 as workflowIdForSession
|
|
65381
65933
|
};
|
|
65382
|
-
//# sourceMappingURL=chunk-
|
|
65934
|
+
//# sourceMappingURL=chunk-QESX7HDK.js.map
|