@cueai/omni-reader-mcp 1.5.5 → 1.6.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 +70 -37
- package/dist/artifact-store.d.ts +2 -0
- package/dist/artifact-store.js +45 -10
- package/dist/cli/agent-config.js +2 -2
- package/dist/cli/arguments.d.ts +8 -4
- package/dist/cli/arguments.js +62 -7
- package/dist/cli/config-inspection.d.ts +59 -0
- package/dist/cli/config-inspection.js +307 -0
- package/dist/cli/doctor.d.ts +7 -0
- package/dist/cli/doctor.js +37 -2
- package/dist/cli/setup.js +13 -2
- package/dist/constants.d.ts +2 -1
- package/dist/constants.js +4 -3
- package/dist/cursor.d.ts +4 -0
- package/dist/cursor.js +11 -13
- package/dist/index.js +10 -1
- package/dist/operation-journal.d.ts +4 -1
- package/dist/operation-journal.js +85 -15
- package/dist/operation-manager.d.ts +6 -2
- package/dist/operation-manager.js +246 -63
- package/dist/path-normalization.d.ts +5 -0
- package/dist/path-normalization.js +25 -0
- package/dist/path-security.d.ts +2 -1
- package/dist/path-security.js +49 -28
- package/dist/protocol.d.ts +10 -2
- package/dist/protocol.js +19 -7
- package/dist/result-contract.d.ts +46 -6
- package/dist/result-contract.js +118 -3
- package/dist/task-runtime.d.ts +3 -2
- package/dist/task-runtime.js +2 -2
- package/dist/tools.d.ts +4 -0
- package/dist/tools.js +37 -16
- package/package.json +1 -1
package/dist/path-security.js
CHANGED
|
@@ -5,6 +5,7 @@ import { homedir } from "node:os";
|
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { MAX_FILE_BYTES } from "./constants.js";
|
|
7
7
|
import { OmniBridgeError } from "./errors.js";
|
|
8
|
+
import { PathNormalizationError, normalizePlatformPath, } from "./path-normalization.js";
|
|
8
9
|
const CONTENT_TYPES = {
|
|
9
10
|
".pdf": "application/pdf",
|
|
10
11
|
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
@@ -92,29 +93,44 @@ function bridgeError(code, message, retryable, constraints) {
|
|
|
92
93
|
...(constraints === undefined ? {} : { constraints }),
|
|
93
94
|
});
|
|
94
95
|
}
|
|
96
|
+
function pathsFor(platform) {
|
|
97
|
+
return platform === "win32" ? path.win32 : path.posix;
|
|
98
|
+
}
|
|
95
99
|
function validatePathText(value) {
|
|
96
100
|
if (value.length === 0 || value.includes("\0")) {
|
|
97
101
|
throw bridgeError("INVALID_LOCAL_PATH", "Provide one valid local file path.", false);
|
|
98
102
|
}
|
|
99
103
|
}
|
|
100
|
-
function
|
|
104
|
+
function normalizedPath(value, platform) {
|
|
105
|
+
validatePathText(value);
|
|
106
|
+
try {
|
|
107
|
+
return normalizePlatformPath(value, platform);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
if (error instanceof PathNormalizationError) {
|
|
111
|
+
throw bridgeError(error.code, error.message, false);
|
|
112
|
+
}
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function expandHomeOnly(value, homeDirectory, paths) {
|
|
101
117
|
if (value === "~") {
|
|
102
118
|
return homeDirectory;
|
|
103
119
|
}
|
|
104
120
|
if (/^~[\\/]/u.test(value)) {
|
|
105
|
-
return
|
|
121
|
+
return paths.join(homeDirectory, value.slice(2));
|
|
106
122
|
}
|
|
107
123
|
return value;
|
|
108
124
|
}
|
|
109
|
-
function isInsideRoot(candidate, root) {
|
|
110
|
-
const relative =
|
|
125
|
+
function isInsideRoot(candidate, root, paths) {
|
|
126
|
+
const relative = paths.relative(root, candidate);
|
|
111
127
|
return (relative === "" ||
|
|
112
128
|
(relative !== ".." &&
|
|
113
|
-
!relative.startsWith(`..${
|
|
114
|
-
!
|
|
129
|
+
!relative.startsWith(`..${paths.sep}`) &&
|
|
130
|
+
!paths.isAbsolute(relative)));
|
|
115
131
|
}
|
|
116
|
-
function requireInsideAnyRoot(candidate, roots) {
|
|
117
|
-
if (!roots.some((root) => isInsideRoot(candidate, root))) {
|
|
132
|
+
function requireInsideAnyRoot(candidate, roots, paths) {
|
|
133
|
+
if (!roots.some((root) => isInsideRoot(candidate, root, paths))) {
|
|
118
134
|
throw bridgeError("PATH_NOT_ALLOWED", "Move the file into the current workspace or add its parent directory to OMNI_ALLOWED_ROOTS.", false);
|
|
119
135
|
}
|
|
120
136
|
}
|
|
@@ -148,8 +164,8 @@ function redactedSourceFingerprint(fileStat) {
|
|
|
148
164
|
].map((value) => value.toString()).join(":");
|
|
149
165
|
return `sha256:${createHash("sha256").update(identity, "utf8").digest("hex")}`;
|
|
150
166
|
}
|
|
151
|
-
function safeFileType(resolvedPath) {
|
|
152
|
-
const safeExtension =
|
|
167
|
+
function safeFileType(resolvedPath, paths) {
|
|
168
|
+
const safeExtension = paths.extname(resolvedPath).toLowerCase();
|
|
153
169
|
if (!/^\.[a-z0-9]{1,10}$/u.test(safeExtension)) {
|
|
154
170
|
throw bridgeError("UNSUPPORTED_MEDIA_TYPE", "The source media type is not supported.", false, { supported_extensions: SUPPORTED_EXTENSIONS });
|
|
155
171
|
}
|
|
@@ -175,19 +191,20 @@ function fileAccessError(error) {
|
|
|
175
191
|
}
|
|
176
192
|
return bridgeError("FILE_NOT_READABLE", "Omni cannot read the local file. Check its permissions and try again.", false);
|
|
177
193
|
}
|
|
178
|
-
async function resolveAllowedRoots(options, fileSystem, homeDirectory) {
|
|
179
|
-
|
|
180
|
-
const
|
|
194
|
+
async function resolveAllowedRoots(options, fileSystem, homeDirectory, platform, paths) {
|
|
195
|
+
const workspace = normalizedPath(options.workspace, platform);
|
|
196
|
+
const expandedWorkspace = expandHomeOnly(workspace, homeDirectory, paths);
|
|
197
|
+
const workspaceInput = paths.resolve(normalizedPath(expandedWorkspace, platform));
|
|
181
198
|
const requestedRoots = [
|
|
182
199
|
workspaceInput,
|
|
183
200
|
...(options.extraRoots ?? [])
|
|
184
201
|
.filter((root) => root.length > 0)
|
|
185
202
|
.map((root) => {
|
|
186
|
-
|
|
187
|
-
const expanded = expandHomeOnly(
|
|
188
|
-
return
|
|
203
|
+
const normalizedRoot = normalizedPath(root, platform);
|
|
204
|
+
const expanded = normalizedPath(expandHomeOnly(normalizedRoot, homeDirectory, paths), platform);
|
|
205
|
+
return paths.isAbsolute(expanded)
|
|
189
206
|
? expanded
|
|
190
|
-
:
|
|
207
|
+
: paths.resolve(workspaceInput, expanded);
|
|
191
208
|
}),
|
|
192
209
|
];
|
|
193
210
|
try {
|
|
@@ -199,7 +216,7 @@ async function resolveAllowedRoots(options, fileSystem, homeDirectory) {
|
|
|
199
216
|
}
|
|
200
217
|
return resolved;
|
|
201
218
|
}));
|
|
202
|
-
return [...new Set(roots)];
|
|
219
|
+
return { roots: [...new Set(roots)], workspaceInput };
|
|
203
220
|
}
|
|
204
221
|
catch (error) {
|
|
205
222
|
if (error instanceof OmniBridgeError) {
|
|
@@ -208,21 +225,25 @@ async function resolveAllowedRoots(options, fileSystem, homeDirectory) {
|
|
|
208
225
|
throw bridgeError("INVALID_ALLOWED_ROOT", "The workspace or an OMNI_ALLOWED_ROOTS entry is unavailable.", false);
|
|
209
226
|
}
|
|
210
227
|
}
|
|
211
|
-
export function splitAllowedRoots(value) {
|
|
228
|
+
export function splitAllowedRoots(value, platform = process.platform) {
|
|
212
229
|
if (value === undefined || value.length === 0) {
|
|
213
230
|
return [];
|
|
214
231
|
}
|
|
215
|
-
return value
|
|
232
|
+
return value
|
|
233
|
+
.split(pathsFor(platform).delimiter)
|
|
234
|
+
.filter((root) => root.length > 0);
|
|
216
235
|
}
|
|
217
236
|
export async function openAllowedFile(input, options) {
|
|
218
|
-
|
|
237
|
+
const platform = options.platform ?? process.platform;
|
|
238
|
+
const paths = pathsFor(platform);
|
|
219
239
|
const fileSystem = options.fileSystem ?? NODE_FILE_SYSTEM;
|
|
220
240
|
const homeDirectory = options.homeDirectory ?? homedir();
|
|
221
|
-
const
|
|
222
|
-
const expanded = expandHomeOnly(
|
|
223
|
-
const
|
|
241
|
+
const normalizedInput = normalizedPath(input, platform);
|
|
242
|
+
const expanded = normalizedPath(expandHomeOnly(normalizedInput, homeDirectory, paths), platform);
|
|
243
|
+
const { roots, workspaceInput } = await resolveAllowedRoots(options, fileSystem, homeDirectory, platform, paths);
|
|
244
|
+
const candidate = paths.isAbsolute(expanded)
|
|
224
245
|
? expanded
|
|
225
|
-
:
|
|
246
|
+
: paths.resolve(workspaceInput, expanded);
|
|
226
247
|
let resolved;
|
|
227
248
|
try {
|
|
228
249
|
resolved = await fileSystem.realpath(candidate);
|
|
@@ -230,7 +251,7 @@ export async function openAllowedFile(input, options) {
|
|
|
230
251
|
catch (error) {
|
|
231
252
|
throw fileAccessError(error);
|
|
232
253
|
}
|
|
233
|
-
requireInsideAnyRoot(resolved, roots);
|
|
254
|
+
requireInsideAnyRoot(resolved, roots, paths);
|
|
234
255
|
let handle;
|
|
235
256
|
try {
|
|
236
257
|
const pathStat = await fileSystem.stat(resolved);
|
|
@@ -244,11 +265,11 @@ export async function openAllowedFile(input, options) {
|
|
|
244
265
|
requireSameFile(pathStat, before);
|
|
245
266
|
const size = requireAllowedSize(before);
|
|
246
267
|
const afterPath = await fileSystem.realpath(resolved);
|
|
247
|
-
requireInsideAnyRoot(afterPath, roots);
|
|
268
|
+
requireInsideAnyRoot(afterPath, roots, paths);
|
|
248
269
|
const after = await fileSystem.stat(afterPath);
|
|
249
270
|
requireRegularFile(after);
|
|
250
271
|
requireSameFile(before, after);
|
|
251
|
-
const { safeExtension, contentType } = safeFileType(afterPath);
|
|
272
|
+
const { safeExtension, contentType } = safeFileType(afterPath, paths);
|
|
252
273
|
const opened = new DescriptorBackedFile(handle, size, safeExtension, contentType, redactedSourceFingerprint(before));
|
|
253
274
|
handle = undefined;
|
|
254
275
|
return opened;
|
package/dist/protocol.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
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.v4";
|
|
3
|
+
export declare const OPERATION_JOURNAL_VERSION = 4;
|
|
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";
|
|
7
|
+
export type ResultDelivery = "auto" | "artifact";
|
|
7
8
|
export interface RepresentationIntent {
|
|
8
9
|
readonly detail: "text" | "grounded" | "layout";
|
|
9
10
|
readonly groundingSchemaVersion: "none" | "omni.grounding.v1";
|
|
@@ -15,31 +16,38 @@ export declare const parseSchemaShape: {
|
|
|
15
16
|
source: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
16
17
|
url: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
17
18
|
detail: z.ZodOptional<z.ZodEnum<["text", "grounded", "layout"]>>;
|
|
19
|
+
result_delivery: z.ZodOptional<z.ZodEnum<["auto", "artifact"]>>;
|
|
18
20
|
};
|
|
19
21
|
export declare const parseSchema: z.ZodEffects<z.ZodObject<{
|
|
20
22
|
source: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
21
23
|
url: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
22
24
|
detail: z.ZodOptional<z.ZodEnum<["text", "grounded", "layout"]>>;
|
|
25
|
+
result_delivery: z.ZodOptional<z.ZodEnum<["auto", "artifact"]>>;
|
|
23
26
|
}, "strict", z.ZodTypeAny, {
|
|
24
27
|
source?: string | undefined;
|
|
25
28
|
url?: string | undefined;
|
|
26
29
|
detail?: "grounded" | "layout" | "text" | undefined;
|
|
30
|
+
result_delivery?: "auto" | "artifact" | undefined;
|
|
27
31
|
}, {
|
|
28
32
|
source?: string | undefined;
|
|
29
33
|
url?: string | undefined;
|
|
30
34
|
detail?: "grounded" | "layout" | "text" | undefined;
|
|
35
|
+
result_delivery?: "auto" | "artifact" | undefined;
|
|
31
36
|
}>, {
|
|
32
37
|
source?: string | undefined;
|
|
33
38
|
url?: string | undefined;
|
|
34
39
|
detail?: "grounded" | "layout" | "text" | undefined;
|
|
40
|
+
result_delivery?: "auto" | "artifact" | undefined;
|
|
35
41
|
}, {
|
|
36
42
|
source?: string | undefined;
|
|
37
43
|
url?: string | undefined;
|
|
38
44
|
detail?: "grounded" | "layout" | "text" | undefined;
|
|
45
|
+
result_delivery?: "auto" | "artifact" | undefined;
|
|
39
46
|
}>;
|
|
40
47
|
export interface NormalizedParseArguments {
|
|
41
48
|
readonly source: string;
|
|
42
49
|
readonly detail?: "text" | "grounded" | "layout";
|
|
50
|
+
readonly resultDelivery: ResultDelivery;
|
|
43
51
|
}
|
|
44
52
|
export declare function normalizeParseArguments(args: ParseArguments): NormalizedParseArguments;
|
|
45
53
|
export declare const getParseStatusSchema: z.ZodObject<{
|
package/dist/protocol.js
CHANGED
|
@@ -1,11 +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
|
-
|
|
5
|
-
// The journal record version and the bundle cursor version are bumped
|
|
6
|
-
// together with the tool contract; legacy v2 journal records still recover
|
|
7
|
-
// text operations unchanged and are never auto-upgraded.
|
|
8
|
-
export const OPERATION_JOURNAL_VERSION = 3;
|
|
3
|
+
export const LOCAL_BRIDGE_PROTOCOL_VERSION = "omni.local_bridge_tools.v4";
|
|
4
|
+
export const OPERATION_JOURNAL_VERSION = 4;
|
|
9
5
|
export const BUNDLE_CURSOR_VERSION = 2;
|
|
10
6
|
// Canonical bundle/grounding literals carried by non-text representations.
|
|
11
7
|
export const RESULT_BUNDLE_PROTOCOL_VERSION = "omni.result_bundle.v1";
|
|
@@ -36,6 +32,17 @@ export const MACHINE_INSTRUCTIONS = [
|
|
|
36
32
|
"Do not promise background notification when the client lacks task support.",
|
|
37
33
|
"Do not claim deletion before cleanup is confirmed.",
|
|
38
34
|
"Report authoritative unit progress when present; never treat partial output as final.",
|
|
35
|
+
"Answer directly → use inline text when present; otherwise read_result",
|
|
36
|
+
"Find one section → read_outline, then pass its cursor to read_result",
|
|
37
|
+
"Read all content → read_result until next_cursor is absent",
|
|
38
|
+
"Deliver a file → save_result",
|
|
39
|
+
"Outline navigation does not require save_result.",
|
|
40
|
+
"Use result_delivery=artifact for saving, section navigation, multiple documents, or strict context control.",
|
|
41
|
+
"Use bounded concurrent independent parse calls for multiple sources; there is no batch_parse tool.",
|
|
42
|
+
"Discover MCP Tasks, MCP Roots, host tool timeout, and process cwd versus active workspace; do not guess client capabilities.",
|
|
43
|
+
"Tasks unknown → use ordinary parse and get_parse_status polling.",
|
|
44
|
+
"Roots unknown → use process cwd and explicitly configured roots only.",
|
|
45
|
+
"Host timeout unknown → retain the bounded 20-second status wait.",
|
|
39
46
|
"After parsing, continue the user's original task.",
|
|
40
47
|
].join("\n");
|
|
41
48
|
const operationIdSchema = z.string().regex(/^op_[A-Za-z0-9_-]{16,64}$/u);
|
|
@@ -60,6 +67,7 @@ const parseSchemaObject = z
|
|
|
60
67
|
.refine((value) => !value.includes("\0"))
|
|
61
68
|
.optional(),
|
|
62
69
|
detail: z.enum(["text", "grounded", "layout"]).optional(),
|
|
70
|
+
result_delivery: z.enum(["auto", "artifact"]).optional(),
|
|
63
71
|
})
|
|
64
72
|
.strict();
|
|
65
73
|
export const parseSchemaShape = parseSchemaObject.shape;
|
|
@@ -71,7 +79,11 @@ export function normalizeParseArguments(args) {
|
|
|
71
79
|
// schema-validated input and guards misuse of the exported helper.
|
|
72
80
|
throw new Error("parse arguments require exactly one of source or url");
|
|
73
81
|
}
|
|
74
|
-
return {
|
|
82
|
+
return {
|
|
83
|
+
source,
|
|
84
|
+
detail: args.detail,
|
|
85
|
+
resultDelivery: args.result_delivery ?? "auto",
|
|
86
|
+
};
|
|
75
87
|
}
|
|
76
88
|
export const getParseStatusSchema = z
|
|
77
89
|
.object({
|
|
@@ -2,6 +2,7 @@ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import type { LocalResult } from "./artifact-store.js";
|
|
4
4
|
import { type OmniBridgeErrorPayload } from "./errors.js";
|
|
5
|
+
import { type ResultDelivery } from "./protocol.js";
|
|
5
6
|
export interface DataHandling {
|
|
6
7
|
processing_copy: "in_use" | "pending" | "deleted";
|
|
7
8
|
temporary_data: "in_use" | "pending" | "deleted";
|
|
@@ -11,6 +12,25 @@ export interface DataHandling {
|
|
|
11
12
|
original_source: "unchanged";
|
|
12
13
|
remote_content_retained?: false;
|
|
13
14
|
}
|
|
15
|
+
export declare const FLAT_RESULT_ACTIONS: readonly ["read_result", "read_outline", "save_result", "discard_result"];
|
|
16
|
+
export declare const LOCAL_ARTIFACT_RETENTION_WARNING: "LOCAL_ARTIFACT_RETENTION_FAILED";
|
|
17
|
+
export interface FlatLocalResultCache {
|
|
18
|
+
readonly result_id: string;
|
|
19
|
+
readonly result_bytes: number;
|
|
20
|
+
readonly expires_at: string;
|
|
21
|
+
readonly available_actions: typeof FLAT_RESULT_ACTIONS;
|
|
22
|
+
readonly discard_action: "discard_result";
|
|
23
|
+
}
|
|
24
|
+
export interface LegacyBundleLocalResultCache {
|
|
25
|
+
readonly expires_at: string;
|
|
26
|
+
readonly discard_action: "discard_result";
|
|
27
|
+
}
|
|
28
|
+
export type LocalResultCache = FlatLocalResultCache | LegacyBundleLocalResultCache;
|
|
29
|
+
export declare function createFlatLocalResultCache(input: {
|
|
30
|
+
readonly resultId: string;
|
|
31
|
+
readonly resultBytes: number;
|
|
32
|
+
readonly expiresAt: string;
|
|
33
|
+
}): FlatLocalResultCache;
|
|
14
34
|
export type ParseResult = {
|
|
15
35
|
status: "processing";
|
|
16
36
|
operation_id: string;
|
|
@@ -44,10 +64,8 @@ export type ParseResult = {
|
|
|
44
64
|
credits_remaining: number;
|
|
45
65
|
};
|
|
46
66
|
data_handling: DataHandling;
|
|
47
|
-
local_result_cache?:
|
|
48
|
-
|
|
49
|
-
discard_action: "discard_result";
|
|
50
|
-
};
|
|
67
|
+
local_result_cache?: LocalResultCache;
|
|
68
|
+
delivery_warning?: typeof LOCAL_ARTIFACT_RETENTION_WARNING;
|
|
51
69
|
} | {
|
|
52
70
|
status: "cleanup_pending";
|
|
53
71
|
operation_id: string;
|
|
@@ -64,6 +82,8 @@ export type ParseResult = {
|
|
|
64
82
|
};
|
|
65
83
|
cleanup_deadline: string;
|
|
66
84
|
data_handling: DataHandling;
|
|
85
|
+
local_result_cache?: LocalResultCache;
|
|
86
|
+
delivery_warning?: typeof LOCAL_ARTIFACT_RETENTION_WARNING;
|
|
67
87
|
} | {
|
|
68
88
|
status: "failed";
|
|
69
89
|
error: OmniBridgeErrorPayload;
|
|
@@ -132,7 +152,7 @@ export declare const stableErrorSchema: z.ZodObject<{
|
|
|
132
152
|
ok: false;
|
|
133
153
|
operation_created: boolean;
|
|
134
154
|
failure_scope?: "source" | "local_capability" | "authentication" | "billing" | "service" | "parser" | "operation" | "cleanup" | "bridge" | undefined;
|
|
135
|
-
source_kind?: "
|
|
155
|
+
source_kind?: "url" | "local" | undefined;
|
|
136
156
|
user_action?: string | undefined;
|
|
137
157
|
request_id?: string | undefined;
|
|
138
158
|
retry_after?: number | undefined;
|
|
@@ -151,7 +171,7 @@ export declare const stableErrorSchema: z.ZodObject<{
|
|
|
151
171
|
ok: false;
|
|
152
172
|
operation_created: boolean;
|
|
153
173
|
failure_scope?: "source" | "local_capability" | "authentication" | "billing" | "service" | "parser" | "operation" | "cleanup" | "bridge" | undefined;
|
|
154
|
-
source_kind?: "
|
|
174
|
+
source_kind?: "url" | "local" | undefined;
|
|
155
175
|
user_action?: string | undefined;
|
|
156
176
|
request_id?: string | undefined;
|
|
157
177
|
retry_after?: number | undefined;
|
|
@@ -454,6 +474,25 @@ export declare const bundleDescriptorSchema: z.ZodObject<{
|
|
|
454
474
|
};
|
|
455
475
|
};
|
|
456
476
|
}>;
|
|
477
|
+
export declare const flatLocalResultCacheSchema: z.ZodObject<{
|
|
478
|
+
result_id: z.ZodString;
|
|
479
|
+
result_bytes: z.ZodNumber;
|
|
480
|
+
expires_at: z.ZodString;
|
|
481
|
+
available_actions: z.ZodTuple<[z.ZodLiteral<"read_result">, z.ZodLiteral<"read_outline">, z.ZodLiteral<"save_result">, z.ZodLiteral<"discard_result">], null>;
|
|
482
|
+
discard_action: z.ZodLiteral<"discard_result">;
|
|
483
|
+
}, "strict", z.ZodTypeAny, {
|
|
484
|
+
result_id: string;
|
|
485
|
+
expires_at: string;
|
|
486
|
+
result_bytes: number;
|
|
487
|
+
available_actions: ["read_result", "read_outline", "save_result", "discard_result"];
|
|
488
|
+
discard_action: "discard_result";
|
|
489
|
+
}, {
|
|
490
|
+
result_id: string;
|
|
491
|
+
expires_at: string;
|
|
492
|
+
result_bytes: number;
|
|
493
|
+
available_actions: ["read_result", "read_outline", "save_result", "discard_result"];
|
|
494
|
+
discard_action: "discard_result";
|
|
495
|
+
}>;
|
|
457
496
|
export declare const parseResultSchema: z.ZodTypeAny;
|
|
458
497
|
export declare const bundlePartReadSchema: z.ZodObject<{
|
|
459
498
|
status: z.ZodLiteral<"completed">;
|
|
@@ -614,4 +653,5 @@ export declare const parseToolOutputSchema: z.ZodTypeAny;
|
|
|
614
653
|
export declare const readResultToolOutputSchema: z.ZodTypeAny;
|
|
615
654
|
export declare const discardResultToolOutputSchema: z.ZodTypeAny;
|
|
616
655
|
export declare const saveResultToolOutputSchema: z.ZodTypeAny;
|
|
656
|
+
export declare function presentRetainedResult(result: ParseResult, resultDelivery: ResultDelivery, mintReadCursor: (resultId: string, byteOffset: number) => Promise<string>): Promise<ParseResult>;
|
|
617
657
|
export declare function structuredResult(schema: z.ZodTypeAny, value: unknown): CallToolResult;
|
package/dist/result-contract.js
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { OmniBridgeError } from "./errors.js";
|
|
3
|
-
import { RESULT_BUNDLE_PROTOCOL_VERSION } from "./protocol.js";
|
|
3
|
+
import { RESULT_BUNDLE_PROTOCOL_VERSION, } from "./protocol.js";
|
|
4
|
+
export const FLAT_RESULT_ACTIONS = [
|
|
5
|
+
"read_result",
|
|
6
|
+
"read_outline",
|
|
7
|
+
"save_result",
|
|
8
|
+
"discard_result",
|
|
9
|
+
];
|
|
10
|
+
export const LOCAL_ARTIFACT_RETENTION_WARNING = "LOCAL_ARTIFACT_RETENTION_FAILED";
|
|
11
|
+
export function createFlatLocalResultCache(input) {
|
|
12
|
+
return {
|
|
13
|
+
result_id: input.resultId,
|
|
14
|
+
result_bytes: input.resultBytes,
|
|
15
|
+
expires_at: input.expiresAt,
|
|
16
|
+
available_actions: FLAT_RESULT_ACTIONS,
|
|
17
|
+
discard_action: "discard_result",
|
|
18
|
+
};
|
|
19
|
+
}
|
|
4
20
|
// Maps a retained LocalResult (ArtifactStore's own representation) into the
|
|
5
21
|
// wire ParseResult["result"] shape. Used both for local-file parses
|
|
6
22
|
// (tools.ts's completedLocalResult, which additionally sets its own
|
|
@@ -197,19 +213,38 @@ export const bundleDescriptorSchema = z
|
|
|
197
213
|
.strict(),
|
|
198
214
|
})
|
|
199
215
|
.strict();
|
|
200
|
-
const
|
|
216
|
+
export const flatLocalResultCacheSchema = z
|
|
201
217
|
.object({
|
|
218
|
+
result_id: resultIdSchema,
|
|
219
|
+
result_bytes: z.number().int().nonnegative(),
|
|
202
220
|
expires_at: z.string().datetime({ offset: true }),
|
|
221
|
+
available_actions: z.tuple([
|
|
222
|
+
z.literal("read_result"),
|
|
223
|
+
z.literal("read_outline"),
|
|
224
|
+
z.literal("save_result"),
|
|
225
|
+
z.literal("discard_result"),
|
|
226
|
+
]),
|
|
203
227
|
discard_action: z.literal("discard_result"),
|
|
204
228
|
})
|
|
205
229
|
.strict();
|
|
230
|
+
const legacyBundleLocalResultCacheSchema = z
|
|
231
|
+
.object({
|
|
232
|
+
expires_at: z.string().datetime({ offset: true }),
|
|
233
|
+
discard_action: z.literal("discard_result"),
|
|
234
|
+
})
|
|
235
|
+
.strict();
|
|
236
|
+
const localResultCacheSchema = z.union([
|
|
237
|
+
flatLocalResultCacheSchema,
|
|
238
|
+
legacyBundleLocalResultCacheSchema,
|
|
239
|
+
]);
|
|
240
|
+
const deliveryWarningSchema = z.literal(LOCAL_ARTIFACT_RETENTION_WARNING);
|
|
206
241
|
const failedResultSchema = z
|
|
207
242
|
.object({
|
|
208
243
|
status: z.literal("failed"),
|
|
209
244
|
error: stableErrorSchema,
|
|
210
245
|
})
|
|
211
246
|
.strict();
|
|
212
|
-
|
|
247
|
+
const parseResultDiscriminatedSchema = z.discriminatedUnion("status", [
|
|
213
248
|
z
|
|
214
249
|
.object({
|
|
215
250
|
status: z.literal("processing"),
|
|
@@ -235,6 +270,7 @@ export const parseResultSchema = z.discriminatedUnion("status", [
|
|
|
235
270
|
billing: billingSchema.optional(),
|
|
236
271
|
data_handling: dataHandlingSchema,
|
|
237
272
|
local_result_cache: localResultCacheSchema.optional(),
|
|
273
|
+
delivery_warning: deliveryWarningSchema.optional(),
|
|
238
274
|
})
|
|
239
275
|
.strict(),
|
|
240
276
|
z
|
|
@@ -248,6 +284,8 @@ export const parseResultSchema = z.discriminatedUnion("status", [
|
|
|
248
284
|
]).optional(),
|
|
249
285
|
cleanup_deadline: z.string().datetime({ offset: true }),
|
|
250
286
|
data_handling: dataHandlingSchema,
|
|
287
|
+
local_result_cache: localResultCacheSchema.optional(),
|
|
288
|
+
delivery_warning: deliveryWarningSchema.optional(),
|
|
251
289
|
})
|
|
252
290
|
.strict(),
|
|
253
291
|
failedResultSchema,
|
|
@@ -269,6 +307,41 @@ export const parseResultSchema = z.discriminatedUnion("status", [
|
|
|
269
307
|
})
|
|
270
308
|
.strict(),
|
|
271
309
|
]);
|
|
310
|
+
export const parseResultSchema = parseResultDiscriminatedSchema
|
|
311
|
+
.superRefine((value, context) => {
|
|
312
|
+
if (value.status !== "completed" && value.status !== "cleanup_pending")
|
|
313
|
+
return;
|
|
314
|
+
const result = value.result;
|
|
315
|
+
const cache = value.local_result_cache;
|
|
316
|
+
if (cache !== undefined) {
|
|
317
|
+
const cacheMatches = result !== undefined && (result.kind === "bundle"
|
|
318
|
+
? legacyBundleLocalResultCacheSchema.safeParse(cache).success
|
|
319
|
+
: flatLocalResultCacheSchema.safeParse(cache).success);
|
|
320
|
+
if (!cacheMatches) {
|
|
321
|
+
context.addIssue({
|
|
322
|
+
code: z.ZodIssueCode.custom,
|
|
323
|
+
path: ["local_result_cache"],
|
|
324
|
+
message: "the local result cache does not match the result shape",
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (value.delivery_warning !== undefined) {
|
|
329
|
+
if (cache !== undefined) {
|
|
330
|
+
context.addIssue({
|
|
331
|
+
code: z.ZodIssueCode.custom,
|
|
332
|
+
path: ["local_result_cache"],
|
|
333
|
+
message: "a retention warning cannot advertise a local result cache",
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
if (result === undefined || result.kind !== "inline") {
|
|
337
|
+
context.addIssue({
|
|
338
|
+
code: z.ZodIssueCode.custom,
|
|
339
|
+
path: ["delivery_warning"],
|
|
340
|
+
message: "a retention warning requires delivered inline content",
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
});
|
|
272
345
|
const resultChunkSchema = z
|
|
273
346
|
.object({
|
|
274
347
|
result_id: resultIdSchema,
|
|
@@ -419,6 +492,7 @@ export const parseToolOutputSchema = z
|
|
|
419
492
|
billing: billingSchema.optional(),
|
|
420
493
|
data_handling: dataHandlingSchema.optional(),
|
|
421
494
|
local_result_cache: localResultCacheSchema.optional(),
|
|
495
|
+
delivery_warning: deliveryWarningSchema.optional(),
|
|
422
496
|
cleanup_deadline: z.string().datetime({ offset: true }).optional(),
|
|
423
497
|
error: stableErrorSchema.optional(),
|
|
424
498
|
requires_user_confirmation: z.literal(true).optional(),
|
|
@@ -449,6 +523,47 @@ export const saveResultToolOutputSchema = z
|
|
|
449
523
|
error: stableErrorSchema.optional(),
|
|
450
524
|
})
|
|
451
525
|
.strict();
|
|
526
|
+
export async function presentRetainedResult(result, resultDelivery, mintReadCursor) {
|
|
527
|
+
if (resultDelivery === "auto" ||
|
|
528
|
+
(result.status !== "completed" && result.status !== "cleanup_pending") ||
|
|
529
|
+
result.result === undefined) {
|
|
530
|
+
return result;
|
|
531
|
+
}
|
|
532
|
+
const current = result.result;
|
|
533
|
+
if (current.kind === "bundle" || current.kind === "artifact")
|
|
534
|
+
return result;
|
|
535
|
+
if (current.kind !== "inline")
|
|
536
|
+
return result;
|
|
537
|
+
const parsedCache = flatLocalResultCacheSchema.safeParse(result.local_result_cache);
|
|
538
|
+
if (!parsedCache.success) {
|
|
539
|
+
if (result.delivery_warning === LOCAL_ARTIFACT_RETENTION_WARNING)
|
|
540
|
+
return result;
|
|
541
|
+
throw new OmniBridgeError({
|
|
542
|
+
code: "LOCAL_RESULT_INTEGRITY_FAILED",
|
|
543
|
+
failureScope: "bridge",
|
|
544
|
+
message: "The retained inline result descriptor is unavailable.",
|
|
545
|
+
operationCreated: false,
|
|
546
|
+
fileUploaded: false,
|
|
547
|
+
parserStarted: false,
|
|
548
|
+
billed: false,
|
|
549
|
+
contentReleased: false,
|
|
550
|
+
retryable: false,
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
const cache = parsedCache.data;
|
|
554
|
+
const nextCursor = await mintReadCursor(cache.result_id, 0);
|
|
555
|
+
return {
|
|
556
|
+
...result,
|
|
557
|
+
result: {
|
|
558
|
+
kind: "artifact",
|
|
559
|
+
result_id: cache.result_id,
|
|
560
|
+
result_bytes: cache.result_bytes,
|
|
561
|
+
expires_at: cache.expires_at,
|
|
562
|
+
preview: "",
|
|
563
|
+
next_cursor: nextCursor,
|
|
564
|
+
},
|
|
565
|
+
};
|
|
566
|
+
}
|
|
452
567
|
function storageText(result) {
|
|
453
568
|
const parts = result.parts;
|
|
454
569
|
if (parts === null || typeof parts !== "object" || Array.isArray(parts)) {
|
package/dist/task-runtime.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { RequestTaskStore } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
2
|
+
import type { NormalizedParseArguments } from "./protocol.js";
|
|
2
3
|
import { type ParseResult } from "./result-contract.js";
|
|
3
4
|
export interface TaskRuntimeOperations {
|
|
4
|
-
parse(
|
|
5
|
+
parse(args: NormalizedParseArguments, signal: AbortSignal): Promise<ParseResult>;
|
|
5
6
|
status(operationId: string, waitMs: number, signal: AbortSignal): Promise<ParseResult>;
|
|
6
7
|
cancel(operationId: string, signal: AbortSignal): Promise<ParseResult>;
|
|
7
8
|
}
|
|
8
9
|
export declare class TaskRuntime {
|
|
9
10
|
#private;
|
|
10
11
|
constructor(operations: TaskRuntimeOperations);
|
|
11
|
-
start(taskId: string,
|
|
12
|
+
start(taskId: string, args: NormalizedParseArguments, store: RequestTaskStore): Promise<void>;
|
|
12
13
|
cancel(taskId: string): Promise<void>;
|
|
13
14
|
}
|
package/dist/task-runtime.js
CHANGED
|
@@ -39,7 +39,7 @@ export class TaskRuntime {
|
|
|
39
39
|
constructor(operations) {
|
|
40
40
|
this.#operations = operations;
|
|
41
41
|
}
|
|
42
|
-
async start(taskId,
|
|
42
|
+
async start(taskId, args, store) {
|
|
43
43
|
if (this.#running.has(taskId)) {
|
|
44
44
|
throw new Error(`Task ${taskId} is already running.`);
|
|
45
45
|
}
|
|
@@ -48,7 +48,7 @@ export class TaskRuntime {
|
|
|
48
48
|
};
|
|
49
49
|
this.#running.set(taskId, running);
|
|
50
50
|
try {
|
|
51
|
-
let result = await this.#operations.parse(
|
|
51
|
+
let result = await this.#operations.parse(args, running.controller.signal);
|
|
52
52
|
while (result.status === "processing") {
|
|
53
53
|
running.operationId = result.operation_id;
|
|
54
54
|
if (await isCancelled(store, taskId)) {
|
package/dist/tools.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { type CubeGrantClient } from "./cube-client.js";
|
|
|
6
6
|
import type { IiisClient, ResultRetentionSink } from "./iiis-client.js";
|
|
7
7
|
import { type OpenAllowedFileOptions, type OpenedAllowedFile } from "./path-security.js";
|
|
8
8
|
import type { OutlineResult } from "./outline.js";
|
|
9
|
+
import { type NormalizedParseArguments } from "./protocol.js";
|
|
9
10
|
import type { RemoteOmniClient } from "./remote-client.js";
|
|
10
11
|
import { type ParseResult } from "./result-contract.js";
|
|
11
12
|
interface ToolRetention extends ResultRetentionSink {
|
|
@@ -13,7 +14,9 @@ interface ToolRetention extends ResultRetentionSink {
|
|
|
13
14
|
}
|
|
14
15
|
interface ToolArtifactStore {
|
|
15
16
|
createRetention(): ToolRetention;
|
|
17
|
+
preflightWrite?(): Promise<void>;
|
|
16
18
|
read(resultId: string, cursor?: string, maxBytes?: number): Promise<ArtifactReadResult>;
|
|
19
|
+
mintReadCursor?(resultId: string, byteOffset: number): Promise<string>;
|
|
17
20
|
readBundlePart?(resultId: string, cursor: string, maxBytes?: number): Promise<BundlePartReadChunk>;
|
|
18
21
|
readOutline?(resultId: string): Promise<OutlineResult>;
|
|
19
22
|
mintOutlineCursor?(resultId: string, byteOffset: number): Promise<string>;
|
|
@@ -29,6 +32,7 @@ export interface ParseOperationController {
|
|
|
29
32
|
sourceFacts: Readonly<Record<string, unknown>>;
|
|
30
33
|
clientRequestId: string;
|
|
31
34
|
signal: AbortSignal;
|
|
35
|
+
resultDelivery: NormalizedParseArguments["resultDelivery"];
|
|
32
36
|
context: unknown;
|
|
33
37
|
}): Promise<ParseResult>;
|
|
34
38
|
statusResult(operationId: string, waitMs: number | undefined, signal: AbortSignal): Promise<ParseResult>;
|