@cueai/omni-reader-mcp 1.6.0 → 1.7.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/README.md +61 -34
- package/dist/capabilities.d.ts +129 -2
- package/dist/capabilities.js +122 -19
- package/dist/cli/agent-config.js +2 -2
- package/dist/constants.d.ts +5 -1
- package/dist/constants.js +7 -3
- package/dist/cube-client.d.ts +4 -1
- package/dist/cube-client.js +286 -32
- package/dist/errors.d.ts +1 -0
- package/dist/errors.js +15 -0
- package/dist/iiis-client.d.ts +33 -2
- package/dist/iiis-client.js +368 -40
- package/dist/operation-journal.d.ts +13 -0
- package/dist/operation-journal.js +188 -13
- package/dist/operation-manager.d.ts +1 -1
- package/dist/operation-manager.js +203 -27
- package/dist/protocol.d.ts +2 -2
- package/dist/protocol.js +6 -2
- package/dist/remote-client.js +3 -13
- package/dist/result-contract.d.ts +30 -26
- package/dist/result-contract.js +3 -2
- package/dist/tools.js +4 -15
- package/package.json +1 -1
|
@@ -36,6 +36,78 @@ function managerError(code, message, facts = {}) {
|
|
|
36
36
|
retryable: facts.retryable ?? false,
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
|
+
function journalIntegrityError(message, record) {
|
|
40
|
+
return managerError("JOURNAL_INTEGRITY_FAILED", message, record === undefined
|
|
41
|
+
? {}
|
|
42
|
+
: {
|
|
43
|
+
operationCreated: record.operationId !== null,
|
|
44
|
+
fileUploaded: record.fileUploaded,
|
|
45
|
+
parserStarted: record.parserStarted,
|
|
46
|
+
billed: record.billed,
|
|
47
|
+
contentReleased: record.contentReleased,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function isBillingProfile(profile) {
|
|
51
|
+
return profile === "omni.direct_text_billing.v1"
|
|
52
|
+
|| profile === "omni.direct_grounding_billing.v1";
|
|
53
|
+
}
|
|
54
|
+
function toJournalBilling(billing) {
|
|
55
|
+
return {
|
|
56
|
+
creditsCharged: billing.credits_charged,
|
|
57
|
+
creditsRemaining: billing.credits_remaining,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function toWireBilling(billing) {
|
|
61
|
+
return {
|
|
62
|
+
credits_charged: billing.creditsCharged,
|
|
63
|
+
credits_remaining: billing.creditsRemaining,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function resultBilling(result) {
|
|
67
|
+
if (result.status === "completed"
|
|
68
|
+
|| result.status === "cleanup_pending"
|
|
69
|
+
|| result.status === "canceled"
|
|
70
|
+
|| result.status === "expired") {
|
|
71
|
+
return result.billing ?? null;
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
function projectBilling(result, billing) {
|
|
76
|
+
if (billing === null
|
|
77
|
+
|| (result.status !== "completed"
|
|
78
|
+
&& result.status !== "cleanup_pending"
|
|
79
|
+
&& result.status !== "canceled"
|
|
80
|
+
&& result.status !== "expired")) {
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
return { ...result, billing };
|
|
84
|
+
}
|
|
85
|
+
function requireWireBillingForSettledProfile(profile, billed, billing) {
|
|
86
|
+
if (!isBillingProfile(profile))
|
|
87
|
+
return billing ?? undefined;
|
|
88
|
+
if (!billed && billing !== null) {
|
|
89
|
+
throw journalIntegrityError("An unbilled direct terminal carries billing facts.");
|
|
90
|
+
}
|
|
91
|
+
if (billed && billing === null) {
|
|
92
|
+
throw journalIntegrityError("New-profile settlement billing is missing.");
|
|
93
|
+
}
|
|
94
|
+
return billing ?? undefined;
|
|
95
|
+
}
|
|
96
|
+
function assertDirectTerminalSnapshot(profile, snapshot) {
|
|
97
|
+
if (!isBillingProfile(profile))
|
|
98
|
+
return;
|
|
99
|
+
if ((snapshot.directProfile ?? null) !== profile) {
|
|
100
|
+
throw journalIntegrityError("IIIS changed the selected direct profile.");
|
|
101
|
+
}
|
|
102
|
+
if (snapshot.status === "CANCELED"
|
|
103
|
+
|| snapshot.status === "FAILED"
|
|
104
|
+
|| snapshot.status === "UNSUPPORTED"
|
|
105
|
+
|| snapshot.status === "SETTLEMENT_DENIED") {
|
|
106
|
+
if (snapshot.billed || snapshot.contentReleased || snapshot.billing !== null) {
|
|
107
|
+
throw journalIntegrityError("A canceled or failed direct-v5 operation is not strictly uncharged.");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
39
111
|
function canonicalValue(value) {
|
|
40
112
|
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
41
113
|
return value;
|
|
@@ -162,6 +234,7 @@ function resultFromRecord(record) {
|
|
|
162
234
|
status: "expired",
|
|
163
235
|
operation_id: record.operationId,
|
|
164
236
|
requires_user_confirmation: true,
|
|
237
|
+
...(record.billing === null ? {} : { billing: toWireBilling(record.billing) }),
|
|
165
238
|
};
|
|
166
239
|
}
|
|
167
240
|
if (record.state === "CANCELED") {
|
|
@@ -170,6 +243,7 @@ function resultFromRecord(record) {
|
|
|
170
243
|
status: "canceled",
|
|
171
244
|
operation_id: record.operationId,
|
|
172
245
|
...(cleanupDeadline === null ? {} : { cleanup_deadline: cleanupDeadline }),
|
|
246
|
+
...(record.billing === null ? {} : { billing: toWireBilling(record.billing) }),
|
|
173
247
|
data_handling: recordDataHandling(record),
|
|
174
248
|
};
|
|
175
249
|
}
|
|
@@ -188,6 +262,7 @@ function resultFromRecord(record) {
|
|
|
188
262
|
return {
|
|
189
263
|
status: "cleanup_pending",
|
|
190
264
|
operation_id: record.operationId,
|
|
265
|
+
...(record.billing === null ? {} : { billing: toWireBilling(record.billing) }),
|
|
191
266
|
cleanup_deadline: record.resultExpiresAt ?? record.expiresAt ?? new Date(0).toISOString(),
|
|
192
267
|
data_handling: recordDataHandling(record),
|
|
193
268
|
};
|
|
@@ -364,6 +439,37 @@ export class OperationManager {
|
|
|
364
439
|
throw structured;
|
|
365
440
|
}
|
|
366
441
|
}
|
|
442
|
+
async #bindResultBilling(record, result) {
|
|
443
|
+
const billing = resultBilling(result);
|
|
444
|
+
if (billing === null)
|
|
445
|
+
return record;
|
|
446
|
+
const latest = await this.#journal.loadByRequestId(record.clientRequestId) ?? record;
|
|
447
|
+
const directProfile = latest.sourceKind === "url" ? null : latest.directProfile;
|
|
448
|
+
if (latest.sourceKind === "local" && directProfile === null) {
|
|
449
|
+
throw journalIntegrityError("A local terminal carries billing without a saved direct profile.", latest);
|
|
450
|
+
}
|
|
451
|
+
return this.#journal.bindSettlementFacts(latest.clientRequestId, {
|
|
452
|
+
directProfile,
|
|
453
|
+
billing: toJournalBilling(billing),
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
async #normalizeResultBilling(record, result) {
|
|
457
|
+
const bound = await this.#bindResultBilling(record, result);
|
|
458
|
+
const billing = resultBilling(result)
|
|
459
|
+
?? (bound.billing === null ? null : toWireBilling(bound.billing));
|
|
460
|
+
if (isBillingProfile(bound.directProfile)) {
|
|
461
|
+
if (result.status === "failed" || result.status === "canceled") {
|
|
462
|
+
if (bound.billed || bound.billing !== null || bound.contentReleased) {
|
|
463
|
+
throw journalIntegrityError("A failed or canceled direct-v5 terminal is not strictly uncharged.", bound);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
else if (result.status === "completed"
|
|
467
|
+
|| (result.status === "cleanup_pending" && result.result !== undefined)) {
|
|
468
|
+
requireWireBillingForSettledProfile(bound.directProfile, bound.billed, billing);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
return projectBilling(result, billing);
|
|
472
|
+
}
|
|
367
473
|
async #present(record, canonicalResult) {
|
|
368
474
|
if (canonicalResult.status === "processing")
|
|
369
475
|
return canonicalResult;
|
|
@@ -419,8 +525,9 @@ export class OperationManager {
|
|
|
419
525
|
if (TERMINAL_STATES.has(record.state)) {
|
|
420
526
|
const recovered = await this.#driver.result?.(record, signal);
|
|
421
527
|
if (recovered !== undefined) {
|
|
422
|
-
this.#
|
|
423
|
-
|
|
528
|
+
const normalized = await this.#normalizeResultBilling(record, recovered);
|
|
529
|
+
this.#results.set(operationId, normalized);
|
|
530
|
+
return this.#present(record, normalized);
|
|
424
531
|
}
|
|
425
532
|
return this.#present(record, resultFromRecord(record));
|
|
426
533
|
}
|
|
@@ -491,7 +598,7 @@ export class OperationManager {
|
|
|
491
598
|
return record;
|
|
492
599
|
const updated = await this.#applyUpdate(record, update);
|
|
493
600
|
if (update.result !== undefined && updated.operationId !== null) {
|
|
494
|
-
this.#results.set(updated.operationId, update.result);
|
|
601
|
+
this.#results.set(updated.operationId, await this.#normalizeResultBilling(updated, update.result));
|
|
495
602
|
}
|
|
496
603
|
return updated;
|
|
497
604
|
}
|
|
@@ -505,7 +612,7 @@ export class OperationManager {
|
|
|
505
612
|
if (!isExecution(start)) {
|
|
506
613
|
const updated = await this.#applyUpdate(record, start);
|
|
507
614
|
if (start.result !== undefined && updated.operationId !== null) {
|
|
508
|
-
this.#results.set(updated.operationId, start.result);
|
|
615
|
+
this.#results.set(updated.operationId, await this.#normalizeResultBilling(updated, start.result));
|
|
509
616
|
}
|
|
510
617
|
return updated;
|
|
511
618
|
}
|
|
@@ -517,16 +624,17 @@ export class OperationManager {
|
|
|
517
624
|
let managed;
|
|
518
625
|
const settled = start.completed.then(async (completion) => {
|
|
519
626
|
const current = await this.#journal.loadByOperationId(operationId);
|
|
520
|
-
|
|
521
|
-
await this.#applyUpdate(current, completion.update)
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
627
|
+
const updated = current !== null && !TERMINAL_STATES.has(current.state)
|
|
628
|
+
? await this.#applyUpdate(current, completion.update)
|
|
629
|
+
: current ?? initial;
|
|
630
|
+
const normalized = await this.#normalizeResultBilling(updated, completion.result);
|
|
631
|
+
if (normalized.status !== "processing") {
|
|
632
|
+
this.#results.set(operationId, normalized);
|
|
525
633
|
}
|
|
526
634
|
else {
|
|
527
635
|
this.#results.delete(operationId);
|
|
528
636
|
}
|
|
529
|
-
return
|
|
637
|
+
return normalized;
|
|
530
638
|
}).catch(async (error) => {
|
|
531
639
|
const structured = error instanceof OmniBridgeError
|
|
532
640
|
? error
|
|
@@ -620,7 +728,9 @@ export class OperationManager {
|
|
|
620
728
|
return record;
|
|
621
729
|
}
|
|
622
730
|
async #applyUpdate(record, update) {
|
|
623
|
-
let current =
|
|
731
|
+
let current = update.result === undefined
|
|
732
|
+
? record
|
|
733
|
+
: await this.#bindResultBilling(record, update.result);
|
|
624
734
|
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
625
735
|
try {
|
|
626
736
|
return await this.#journal.transition(current.clientRequestId, current.state, update.state, update.patch ?? {});
|
|
@@ -967,11 +1077,12 @@ function localResultCache(local) {
|
|
|
967
1077
|
expiresAt: local.expiresAt,
|
|
968
1078
|
});
|
|
969
1079
|
}
|
|
970
|
-
function completedLocalParse(local) {
|
|
1080
|
+
function completedLocalParse(local, billing) {
|
|
971
1081
|
return {
|
|
972
1082
|
status: "completed",
|
|
973
1083
|
operation_id: local.operationId,
|
|
974
1084
|
result: localResultValue(local),
|
|
1085
|
+
...(billing === undefined ? {} : { billing }),
|
|
975
1086
|
data_handling: {
|
|
976
1087
|
processing_copy: "deleted",
|
|
977
1088
|
temporary_data: "deleted",
|
|
@@ -982,11 +1093,12 @@ function completedLocalParse(local) {
|
|
|
982
1093
|
local_result_cache: localResultCache(local),
|
|
983
1094
|
};
|
|
984
1095
|
}
|
|
985
|
-
function cleanupPendingParse(local, cleanupDeadline) {
|
|
1096
|
+
function cleanupPendingParse(local, cleanupDeadline, billing) {
|
|
986
1097
|
return {
|
|
987
1098
|
status: "cleanup_pending",
|
|
988
1099
|
operation_id: local.operationId,
|
|
989
1100
|
result: localResultValue(local),
|
|
1101
|
+
...(billing === undefined ? {} : { billing }),
|
|
990
1102
|
cleanup_deadline: cleanupDeadline,
|
|
991
1103
|
data_handling: {
|
|
992
1104
|
processing_copy: "pending",
|
|
@@ -1016,6 +1128,7 @@ function recoveredRemoteParse(record, local) {
|
|
|
1016
1128
|
status: "cleanup_pending",
|
|
1017
1129
|
operation_id: record.operationId,
|
|
1018
1130
|
result: localResultValue(local),
|
|
1131
|
+
...(record.billing === null ? {} : { billing: toWireBilling(record.billing) }),
|
|
1019
1132
|
cleanup_deadline: record.resultExpiresAt ?? record.expiresAt ?? new Date(0).toISOString(),
|
|
1020
1133
|
data_handling: recordDataHandling(record),
|
|
1021
1134
|
local_result_cache: localResultCache(local),
|
|
@@ -1025,6 +1138,7 @@ function recoveredRemoteParse(record, local) {
|
|
|
1025
1138
|
status: "completed",
|
|
1026
1139
|
operation_id: record.operationId,
|
|
1027
1140
|
result: localResultValue(local),
|
|
1141
|
+
...(record.billing === null ? {} : { billing: toWireBilling(record.billing) }),
|
|
1028
1142
|
data_handling: recordDataHandling(record),
|
|
1029
1143
|
local_result_cache: localResultCache(local),
|
|
1030
1144
|
};
|
|
@@ -1077,7 +1191,9 @@ function safeOperationStage(status, fallback) {
|
|
|
1077
1191
|
return "canceled";
|
|
1078
1192
|
if (status === "EXPIRED" || status === "DELIVERY_EXPIRED")
|
|
1079
1193
|
return "expired";
|
|
1080
|
-
if (status === "FAILED"
|
|
1194
|
+
if (status === "FAILED"
|
|
1195
|
+
|| status === "UNSUPPORTED"
|
|
1196
|
+
|| status === "SETTLEMENT_DENIED")
|
|
1081
1197
|
return "failed";
|
|
1082
1198
|
return safeJournalStage(fallback);
|
|
1083
1199
|
}
|
|
@@ -1116,6 +1232,23 @@ function requireBundleResult(retention) {
|
|
|
1116
1232
|
}
|
|
1117
1233
|
return retention.bundleResult();
|
|
1118
1234
|
}
|
|
1235
|
+
async function requireExpectedBundleDetail(local, expectedDetail, retention) {
|
|
1236
|
+
if (local.kind === "bundle" && local.detail === expectedDetail)
|
|
1237
|
+
return local;
|
|
1238
|
+
try {
|
|
1239
|
+
await retention.abort();
|
|
1240
|
+
}
|
|
1241
|
+
catch {
|
|
1242
|
+
// Preserve the exact-detail protocol failure over best-effort local cleanup.
|
|
1243
|
+
}
|
|
1244
|
+
throw managerError("IIIS_INVALID_RESPONSE", "IIIS returned a result for a different representation detail.", {
|
|
1245
|
+
operationCreated: true,
|
|
1246
|
+
fileUploaded: true,
|
|
1247
|
+
parserStarted: true,
|
|
1248
|
+
billed: false,
|
|
1249
|
+
contentReleased: false,
|
|
1250
|
+
});
|
|
1251
|
+
}
|
|
1119
1252
|
export function createLocalParseOperationManager(options) {
|
|
1120
1253
|
const now = options.now ?? (() => new Date());
|
|
1121
1254
|
const openFile = options.openFile ?? openAllowedFile;
|
|
@@ -1287,6 +1420,9 @@ export function createLocalParseOperationManager(options) {
|
|
|
1287
1420
|
output: "markdown",
|
|
1288
1421
|
...(representation.detail === "text" ? {} : { detail: representation.detail }),
|
|
1289
1422
|
}, input.clientRequestId, input.signal, { journal: false });
|
|
1423
|
+
if (isBillingProfile(granted.directProfile)) {
|
|
1424
|
+
await options.journal.bindDirectProfile(input.clientRequestId, granted.directProfile);
|
|
1425
|
+
}
|
|
1290
1426
|
}
|
|
1291
1427
|
catch (error) {
|
|
1292
1428
|
await opened.close().catch(() => undefined);
|
|
@@ -1348,9 +1484,17 @@ export function createLocalParseOperationManager(options) {
|
|
|
1348
1484
|
await (context?.progress ?? NOOP_PROGRESS).report(value, total, message, latestProgress ?? undefined);
|
|
1349
1485
|
},
|
|
1350
1486
|
};
|
|
1487
|
+
const expectedDetail = granted?.requestedDetail ?? representation.detail;
|
|
1488
|
+
if (expectedDetail !== representation.detail) {
|
|
1489
|
+
await opened?.close().catch(() => undefined);
|
|
1490
|
+
opened = undefined;
|
|
1491
|
+
throw managerError("CUBE_PROTOCOL_ERROR", "Cube returned a grant for a different representation detail.", { operationCreated: true });
|
|
1492
|
+
}
|
|
1351
1493
|
const operation = {
|
|
1352
1494
|
operationId,
|
|
1353
1495
|
operationToken,
|
|
1496
|
+
directProfile: granted?.directProfile ?? recovery?.directProfile ?? null,
|
|
1497
|
+
expectedDetail,
|
|
1354
1498
|
...(granted === undefined || opened === undefined
|
|
1355
1499
|
? {}
|
|
1356
1500
|
: {
|
|
@@ -1395,18 +1539,19 @@ export function createLocalParseOperationManager(options) {
|
|
|
1395
1539
|
recovery?.state === "ACK_PENDING" ||
|
|
1396
1540
|
recovery?.state === "CLEANUP_PENDING";
|
|
1397
1541
|
let local;
|
|
1542
|
+
let released;
|
|
1398
1543
|
if (deliveryRecovery && recovery.resultId !== null) {
|
|
1399
1544
|
local = await recoverLocalArtifact(recovery);
|
|
1400
1545
|
}
|
|
1401
1546
|
else {
|
|
1402
1547
|
if (deliveryRecovery) {
|
|
1403
|
-
await options.iiisClient.downloadResult(operation, progress);
|
|
1548
|
+
released = await options.iiisClient.downloadResult(operation, progress);
|
|
1404
1549
|
}
|
|
1405
1550
|
else if (recovery?.state === "UPLOADING" || recovery?.state === "PROCESSING") {
|
|
1406
|
-
await options.iiisClient.recoverAndWait(operation);
|
|
1551
|
+
released = await options.iiisClient.recoverAndWait(operation);
|
|
1407
1552
|
}
|
|
1408
1553
|
else {
|
|
1409
|
-
await options.iiisClient.uploadAndWait(operation);
|
|
1554
|
+
released = await options.iiisClient.uploadAndWait(operation);
|
|
1410
1555
|
}
|
|
1411
1556
|
// Non-text results require the durable BundleLocalResult (both named
|
|
1412
1557
|
// parts verified and fsynced); ACK_PENDING is persisted only after
|
|
@@ -1415,6 +1560,27 @@ export function createLocalParseOperationManager(options) {
|
|
|
1415
1560
|
? requireBundleResult(retention)
|
|
1416
1561
|
: retention.result();
|
|
1417
1562
|
}
|
|
1563
|
+
if (representation.detail !== "text") {
|
|
1564
|
+
local = await requireExpectedBundleDetail(local, representation.detail, retention);
|
|
1565
|
+
}
|
|
1566
|
+
const directProfile = released?.directProfile
|
|
1567
|
+
?? recovery?.directProfile
|
|
1568
|
+
?? operation.directProfile
|
|
1569
|
+
?? null;
|
|
1570
|
+
if (released?.directProfile !== undefined
|
|
1571
|
+
&& released.directProfile !== (operation.directProfile ?? null)) {
|
|
1572
|
+
throw journalIntegrityError("IIIS changed the selected direct profile.", recovery);
|
|
1573
|
+
}
|
|
1574
|
+
const recoveredBilling = recovery?.billing === null || recovery?.billing === undefined
|
|
1575
|
+
? null
|
|
1576
|
+
: toWireBilling(recovery.billing);
|
|
1577
|
+
const wireBilling = requireWireBillingForSettledProfile(directProfile, true, released?.billing ?? recoveredBilling);
|
|
1578
|
+
if (wireBilling !== undefined) {
|
|
1579
|
+
await options.journal.bindSettlementFacts(input.clientRequestId, {
|
|
1580
|
+
directProfile,
|
|
1581
|
+
billing: toJournalBilling(wireBilling),
|
|
1582
|
+
});
|
|
1583
|
+
}
|
|
1418
1584
|
const cleanupDeadline = recovery?.resultExpiresAt ?? new Date(now().getTime() + DELIVERY_TTL_SECONDS * 1000).toISOString();
|
|
1419
1585
|
const resultPatch = {
|
|
1420
1586
|
fileUploaded: true,
|
|
@@ -1465,7 +1631,7 @@ export function createLocalParseOperationManager(options) {
|
|
|
1465
1631
|
deliveryResult: "deleted_after_ack",
|
|
1466
1632
|
},
|
|
1467
1633
|
},
|
|
1468
|
-
result: completedLocalParse(local),
|
|
1634
|
+
result: completedLocalParse(local, wireBilling),
|
|
1469
1635
|
};
|
|
1470
1636
|
}
|
|
1471
1637
|
catch (error) {
|
|
@@ -1489,6 +1655,7 @@ export function createLocalParseOperationManager(options) {
|
|
|
1489
1655
|
result: processingParse(operationId, stage, latestPercent, confirmed.contentReleased === true),
|
|
1490
1656
|
};
|
|
1491
1657
|
}
|
|
1658
|
+
assertDirectTerminalSnapshot(operation.directProfile ?? null, inspected);
|
|
1492
1659
|
const patch = {
|
|
1493
1660
|
...confirmed,
|
|
1494
1661
|
fileUploaded: confirmed.fileUploaded === true || inspected.fileUploaded,
|
|
@@ -1528,7 +1695,9 @@ export function createLocalParseOperationManager(options) {
|
|
|
1528
1695
|
},
|
|
1529
1696
|
};
|
|
1530
1697
|
}
|
|
1531
|
-
if (inspected.status === "FAILED"
|
|
1698
|
+
if (inspected.status === "FAILED"
|
|
1699
|
+
|| inspected.status === "UNSUPPORTED"
|
|
1700
|
+
|| inspected.status === "SETTLEMENT_DENIED") {
|
|
1532
1701
|
const failed = managerError(inspected.status, `The Omni operation ended with status ${inspected.status}.`, {
|
|
1533
1702
|
operationCreated: true,
|
|
1534
1703
|
fileUploaded: patch.fileUploaded,
|
|
@@ -1584,12 +1753,14 @@ export function createLocalParseOperationManager(options) {
|
|
|
1584
1753
|
state: "FAILED",
|
|
1585
1754
|
patch: {
|
|
1586
1755
|
...failurePatch(stable),
|
|
1587
|
-
//
|
|
1588
|
-
//
|
|
1589
|
-
//
|
|
1590
|
-
//
|
|
1591
|
-
|
|
1592
|
-
|
|
1756
|
+
// Recovery starts from persisted monotonic facts. A protocol
|
|
1757
|
+
// rejection cannot make a confirmed upload, parser start,
|
|
1758
|
+
// settlement, or release become false merely because the invalid
|
|
1759
|
+
// response itself was not trusted.
|
|
1760
|
+
fileUploaded: recovery?.fileUploaded === true || stable.fileUploaded,
|
|
1761
|
+
parserStarted: recovery?.parserStarted === true || stable.parserStarted,
|
|
1762
|
+
billed: checkpointBilled || recovery?.billed === true || stable.billed,
|
|
1763
|
+
contentReleased: recovery?.contentReleased === true || stable.contentReleased,
|
|
1593
1764
|
},
|
|
1594
1765
|
},
|
|
1595
1766
|
result: {
|
|
@@ -1702,6 +1873,8 @@ export function createLocalParseOperationManager(options) {
|
|
|
1702
1873
|
const operation = {
|
|
1703
1874
|
operationId: record.operationId,
|
|
1704
1875
|
operationToken: record.operationToken,
|
|
1876
|
+
directProfile: record.directProfile,
|
|
1877
|
+
expectedDetail: record.detail,
|
|
1705
1878
|
retention: {
|
|
1706
1879
|
async reset() { },
|
|
1707
1880
|
async begin() { },
|
|
@@ -1714,6 +1887,7 @@ export function createLocalParseOperationManager(options) {
|
|
|
1714
1887
|
const inspected = options.iiisClient.cancelOperation === undefined
|
|
1715
1888
|
? await options.iiisClient.inspectOperation(operation)
|
|
1716
1889
|
: await options.iiisClient.cancelOperation(operation);
|
|
1890
|
+
assertDirectTerminalSnapshot(operation.directProfile ?? null, inspected);
|
|
1717
1891
|
const patch = {
|
|
1718
1892
|
fileUploaded: inspected.fileUploaded,
|
|
1719
1893
|
parserStarted: inspected.parserStarted,
|
|
@@ -1747,7 +1921,9 @@ export function createLocalParseOperationManager(options) {
|
|
|
1747
1921
|
},
|
|
1748
1922
|
};
|
|
1749
1923
|
}
|
|
1750
|
-
if (inspected.status === "FAILED"
|
|
1924
|
+
if (inspected.status === "FAILED"
|
|
1925
|
+
|| inspected.status === "UNSUPPORTED"
|
|
1926
|
+
|| inspected.status === "SETTLEMENT_DENIED") {
|
|
1751
1927
|
return {
|
|
1752
1928
|
state: "FAILED",
|
|
1753
1929
|
patch: { ...patch, errorCode: inspected.status },
|
|
@@ -1773,7 +1949,7 @@ export function createLocalParseOperationManager(options) {
|
|
|
1773
1949
|
if (record.operationId === null || record.state !== "COMPLETED")
|
|
1774
1950
|
return undefined;
|
|
1775
1951
|
if (record.sourceKind === "local" && record.resultId !== null) {
|
|
1776
|
-
return completedLocalParse(await recoverLocalArtifact(record));
|
|
1952
|
+
return completedLocalParse(await recoverLocalArtifact(record), record.billing === null ? undefined : toWireBilling(record.billing));
|
|
1777
1953
|
}
|
|
1778
1954
|
if (record.sourceKind === "url" && record.resultId !== null) {
|
|
1779
1955
|
try {
|
package/dist/protocol.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
export declare const LOCAL_BRIDGE_PROTOCOL_VERSION = "omni.local_bridge_tools.
|
|
3
|
-
export declare const OPERATION_JOURNAL_VERSION =
|
|
2
|
+
export declare const LOCAL_BRIDGE_PROTOCOL_VERSION = "omni.local_bridge_tools.v5";
|
|
3
|
+
export declare const OPERATION_JOURNAL_VERSION = 5;
|
|
4
4
|
export declare const BUNDLE_CURSOR_VERSION = 2;
|
|
5
5
|
export declare const RESULT_BUNDLE_PROTOCOL_VERSION = "omni.result_bundle.v1";
|
|
6
6
|
export declare const GROUNDING_SCHEMA_VERSION = "omni.grounding.v1";
|
package/dist/protocol.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { RESULT_CHUNK_MAX_BYTES, STATUS_LONG_POLL_MAX_MS } from "./constants.js";
|
|
3
|
-
export const LOCAL_BRIDGE_PROTOCOL_VERSION = "omni.local_bridge_tools.
|
|
4
|
-
export const OPERATION_JOURNAL_VERSION =
|
|
3
|
+
export const LOCAL_BRIDGE_PROTOCOL_VERSION = "omni.local_bridge_tools.v5";
|
|
4
|
+
export const OPERATION_JOURNAL_VERSION = 5;
|
|
5
5
|
export const BUNDLE_CURSOR_VERSION = 2;
|
|
6
6
|
// Canonical bundle/grounding literals carried by non-text representations.
|
|
7
7
|
export const RESULT_BUNDLE_PROTOCOL_VERSION = "omni.result_bundle.v1";
|
|
@@ -21,6 +21,7 @@ export function normalizeRepresentation(detail) {
|
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
export const MACHINE_INSTRUCTIONS = [
|
|
24
|
+
"Use parse as the only first call for both HTTP(S) URLs and local paths; do not ask the user to choose a local, remote, upload, or URL mode.",
|
|
24
25
|
"Pass the user-provided source string directly to parse.",
|
|
25
26
|
"Treat only HTTP(S) as URL; ordinary paths require the local Bridge.",
|
|
26
27
|
"Never read, attach, base64-encode, or insert local source content before calling Omni.",
|
|
@@ -32,6 +33,9 @@ export const MACHINE_INSTRUCTIONS = [
|
|
|
32
33
|
"Do not promise background notification when the client lacks task support.",
|
|
33
34
|
"Do not claim deletion before cleanup is confirmed.",
|
|
34
35
|
"Report authoritative unit progress when present; never treat partial output as final.",
|
|
36
|
+
"Choose continuation tools from the structured result; do not present the Bridge tool menu to the user.",
|
|
37
|
+
"Text output is Markdown and may retain headings, lists, GFM tables, or raw HTML tables; it lacks grounding/layout sidecars, not all structure.",
|
|
38
|
+
"An empty outline means no recognized headings, not that the text has no structure.",
|
|
35
39
|
"Answer directly → use inline text when present; otherwise read_result",
|
|
36
40
|
"Find one section → read_outline, then pass its cursor to read_result",
|
|
37
41
|
"Read all content → read_result until next_cursor is absent",
|
package/dist/remote-client.js
CHANGED
|
@@ -2,7 +2,7 @@ import { LATEST_PROTOCOL_VERSION } from "@modelcontextprotocol/sdk/types.js";
|
|
|
2
2
|
import { parseReaderCapabilities, selectUrlProfile, } from "./capabilities.js";
|
|
3
3
|
import { BRIDGE_RELEASE_VERSION, REMOTE_CAPABILITIES_CUSTOM_FIELD, REMOTE_OMNI_MCP_URL, } from "./constants.js";
|
|
4
4
|
import { API_KEY_URL } from "./onboarding-policy.js";
|
|
5
|
-
import { OmniBridgeError } from "./errors.js";
|
|
5
|
+
import { OmniBridgeError, unsupportedDetailError } from "./errors.js";
|
|
6
6
|
import { parseResultSchema } from "./result-contract.js";
|
|
7
7
|
import { classifySource } from "./source.js";
|
|
8
8
|
const INITIALIZE_REQUEST_ID = "initialize";
|
|
@@ -108,16 +108,6 @@ function protocolError() {
|
|
|
108
108
|
retryable: false,
|
|
109
109
|
});
|
|
110
110
|
}
|
|
111
|
-
function unsupportedDetail() {
|
|
112
|
-
return remoteError({
|
|
113
|
-
code: "UNSUPPORTED_DETAIL",
|
|
114
|
-
message: "This remote Omni service does not support the requested output detail.",
|
|
115
|
-
failureScope: "service",
|
|
116
|
-
userAction: "Use plain Markdown output for this source.",
|
|
117
|
-
operationCreated: false,
|
|
118
|
-
retryable: false,
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
111
|
// Extracts exactly `result.capabilities.experimental["cue.omni-reader"]` from
|
|
122
112
|
// an MCP initialize envelope; returns undefined when the exact custom field is
|
|
123
113
|
// absent (server did not declare the capability), throws on contract
|
|
@@ -351,7 +341,7 @@ export class HttpRemoteOmniClient {
|
|
|
351
341
|
}
|
|
352
342
|
const custom = initializeCustomCapability(envelope, INITIALIZE_REQUEST_ID);
|
|
353
343
|
if (custom === undefined) {
|
|
354
|
-
throw
|
|
344
|
+
throw unsupportedDetailError("url");
|
|
355
345
|
}
|
|
356
346
|
let capabilities;
|
|
357
347
|
try {
|
|
@@ -388,7 +378,7 @@ export class HttpRemoteOmniClient {
|
|
|
388
378
|
// non-text v3 call; a missing/mismatched profile fails closed with
|
|
389
379
|
// UNSUPPORTED_DETAIL and zero tools/call requests.
|
|
390
380
|
const capabilities = await this.initializeCapabilities(signal);
|
|
391
|
-
selectUrlProfile(capabilities, detail);
|
|
381
|
+
selectUrlProfile(capabilities, detail, "url");
|
|
392
382
|
args = { source: classified.source, detail, wait: false };
|
|
393
383
|
}
|
|
394
384
|
return this.#call("parse", args, clientRequestId, signal);
|