dsh-lcx-codex 0.4.2 → 0.4.3-pre.13
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 +75 -224
- package/THIRD_PARTY_NOTICES.md +64 -0
- package/cordis.patch.yml +3 -20
- package/lib/auxiliary-usage.js +63 -0
- package/lib/client.js +1398 -167
- package/lib/compact-v2.js +218 -199
- package/lib/dsh-compat.js +294 -100
- package/lib/dsh-responses.js +512 -277
- package/lib/grok-native-search.js +391 -0
- package/lib/index.js +1066 -758
- package/lib/invocation-policy-scope.js +261 -0
- package/lib/json-store.js +57 -31
- package/lib/native-checkpoint.js +520 -194
- package/lib/pi-responses-runtime.js +1571 -0
- package/lib/responses-request.js +109 -121
- package/lib/responses-stream.js +1280 -447
- package/lib/route.js +425 -369
- package/lib/search-accounting.js +86 -0
- package/lib/search-usage.js +86 -0
- package/lib/service-mutex.js +73 -64
- package/lib/token-budget.js +176 -108
- package/lib/transport.js +308 -68
- package/lib/types/client/index.d.ts +18 -0
- package/lib/types/client/search-media.d.ts +16 -0
- package/lib/types/index.d.ts +83 -0
- package/lib/web-run-output.js +189 -18
- package/lib/web-search-alpha.js +1067 -163
- package/lib/web-search-capability.js +80 -65
- package/lib/web-search-hosted.js +321 -33
- package/lib/web-search-ref-store.js +145 -60
- package/package.json +112 -32
- package/ARCHITECTURE.md +0 -117
- package/CHANGELOG.md +0 -224
- package/README_EN.md +0 -277
- package/assets/dsh-lcx-codex-banner.jpg +0 -0
- package/lib/legacy-v3.js +0 -20
- package/lib/responses-replay.js +0 -68
- package/scripts/probe-alpha.mjs +0 -43
- package/scripts/validate-dsh-schema.mjs +0 -31
package/lib/web-run-output.js
CHANGED
|
@@ -1,18 +1,189 @@
|
|
|
1
|
-
const RESULT_SEPARATOR_PATTERN = /(?:\r?\n)?-{80}(?:\r?\n)?/gu
|
|
2
|
-
const CITATION_PATTERN = /cite([^]+)/gu
|
|
3
|
-
const PAGE_LINE_PATTERN = /^L(\d+)(?:@P(\d+)(?:-(\d+))?)?:\s?(.*)$/u
|
|
4
|
-
const EMBEDDED_PAGE_LINE_PATTERN = / (?=L\d+(?:@P\d+(?:-\d+)?)?:)/gu
|
|
5
|
-
const TITLE_URL_PATTERN = /^(.*?)\s*\((https?:\/\/[^)]+)\)\s*$/u
|
|
6
|
-
function pushUnique(target, value) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
const RESULT_SEPARATOR_PATTERN = /(?:\r?\n)?-{80}(?:\r?\n)?/gu;
|
|
2
|
+
const CITATION_PATTERN = /cite([^]+)/gu;
|
|
3
|
+
const PAGE_LINE_PATTERN = /^L(\d+)(?:@P(\d+)(?:-(\d+))?)?:\s?(.*)$/u;
|
|
4
|
+
const EMBEDDED_PAGE_LINE_PATTERN = / (?=L\d+(?:@P\d+(?:-\d+)?)?:)/gu;
|
|
5
|
+
const TITLE_URL_PATTERN = /^(.*?)\s*\((https?:\/\/[^)]+)\)\s*$/u;
|
|
6
|
+
function pushUnique(target, value) {
|
|
7
|
+
if (!target.includes(value))
|
|
8
|
+
target.push(value);
|
|
9
|
+
}
|
|
10
|
+
function pushLink(target, payload) {
|
|
11
|
+
const [idValue, labelValue, domainValue] = payload.split("†");
|
|
12
|
+
if (!/^\d+$/u.test(idValue ?? "") || !labelValue)
|
|
13
|
+
return false;
|
|
14
|
+
const id = Number(idValue);
|
|
15
|
+
if (!Number.isSafeInteger(id))
|
|
16
|
+
return false;
|
|
17
|
+
const label = labelValue.trim().slice(0, 500);
|
|
18
|
+
const domain = domainValue?.trim().slice(0, 253);
|
|
19
|
+
if (!label)
|
|
20
|
+
return false;
|
|
21
|
+
const existing = target.find((link) => link.id === id);
|
|
22
|
+
if (!existing)
|
|
23
|
+
target.push({ id, label, ...(domain ? { domain } : {}) });
|
|
24
|
+
else if (!existing.domain && domain)
|
|
25
|
+
existing.domain = domain;
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
function cleanCitations(value, references, links) {
|
|
29
|
+
return String(value ?? "")
|
|
30
|
+
.replace(CITATION_PATTERN, (_match, payload) => {
|
|
31
|
+
if (/^turn[\w-]+$/u.test(payload)) {
|
|
32
|
+
pushUnique(references, payload);
|
|
33
|
+
return "";
|
|
34
|
+
}
|
|
35
|
+
if (pushLink(links, payload))
|
|
36
|
+
return payload.split("†")[1] ?? "";
|
|
37
|
+
const separator = payload.indexOf("†");
|
|
38
|
+
return separator < 0 ? payload : payload.slice(separator + 1);
|
|
39
|
+
})
|
|
40
|
+
.trim();
|
|
41
|
+
}
|
|
42
|
+
function metadataParts(value) {
|
|
43
|
+
return value
|
|
44
|
+
.replace(/^\[wordlim:\s*(\d+)\]\s*/u, "$1-word excerpt; ")
|
|
45
|
+
.split(/;\s*/u)
|
|
46
|
+
.map((part) => part.trim())
|
|
47
|
+
.filter(Boolean)
|
|
48
|
+
.map((part) => {
|
|
49
|
+
const contentType = part.match(/^Content type:\s*(.+)$/u);
|
|
50
|
+
if (contentType)
|
|
51
|
+
return contentType[1] === "text/html"
|
|
52
|
+
? "HTML"
|
|
53
|
+
: contentType[1] === "application/pdf"
|
|
54
|
+
? "PDF"
|
|
55
|
+
: contentType[1];
|
|
56
|
+
const totalLines = part.match(/^Total lines:\s*(\d+)$/u);
|
|
57
|
+
if (totalLines)
|
|
58
|
+
return `${totalLines[1]} lines`;
|
|
59
|
+
const pages = part.match(/^Number of pages:\s*(\d+)$/u);
|
|
60
|
+
if (pages)
|
|
61
|
+
return `${pages[1]} pages`;
|
|
62
|
+
return part;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function isMetadata(value) {
|
|
66
|
+
return (value.startsWith("[wordlim:") ||
|
|
67
|
+
/^(?:Published|Crawled|Content type|Source|Total lines|Number of pages):/u.test(value));
|
|
68
|
+
}
|
|
69
|
+
function parseLine(value, references, links) {
|
|
70
|
+
const clean = cleanCitations(value, references, links);
|
|
71
|
+
const pageLine = clean.match(PAGE_LINE_PATTERN);
|
|
72
|
+
if (pageLine) {
|
|
73
|
+
const text = pageLine[4] ?? "";
|
|
74
|
+
const heading = text.match(/^(#{1,6})\s+(.+)$/u);
|
|
75
|
+
return {
|
|
76
|
+
line: Number(pageLine[1]),
|
|
77
|
+
...(pageLine[2] === undefined ? {} : { page: Number(pageLine[2]) }),
|
|
78
|
+
...(pageLine[3] === undefined ? {} : { pageEnd: Number(pageLine[3]) }),
|
|
79
|
+
text: heading?.[2] ?? text,
|
|
80
|
+
...(heading ? { heading: heading[1].length } : {}),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const heading = clean.match(/^(#{1,6})\s+(.+)$/u);
|
|
84
|
+
return heading ? { text: heading[2], heading: heading[1].length } : { text: clean };
|
|
85
|
+
}
|
|
86
|
+
function parseBlock(value) {
|
|
87
|
+
const references = [];
|
|
88
|
+
const links = [];
|
|
89
|
+
const rawLines = value
|
|
90
|
+
.replace(EMBEDDED_PAGE_LINE_PATTERN, "\n")
|
|
91
|
+
.split(/\r?\n/u)
|
|
92
|
+
.map((line) => line.trimEnd());
|
|
93
|
+
while (rawLines[0]?.trim() === "")
|
|
94
|
+
rawLines.shift();
|
|
95
|
+
while (rawLines.at(-1)?.trim() === "")
|
|
96
|
+
rawLines.pop();
|
|
97
|
+
if (!rawLines.length)
|
|
98
|
+
return undefined;
|
|
99
|
+
const firstLine = cleanCitations(rawLines[0], references, links);
|
|
100
|
+
const header = firstLine.match(TITLE_URL_PATTERN);
|
|
101
|
+
const titleOnly = firstLine.match(/^(.+?)\s*\(\)\s*$/u);
|
|
102
|
+
let title = header?.[1]?.trim() || titleOnly?.[1]?.trim() || undefined;
|
|
103
|
+
const url = header?.[2];
|
|
104
|
+
let bodyStart = header || titleOnly ? 1 : 0;
|
|
105
|
+
if (!header && /^\s*\([^)]*\)\s*$/u.test(firstLine))
|
|
106
|
+
bodyStart = 1;
|
|
107
|
+
const metadata = [];
|
|
108
|
+
while (bodyStart < rawLines.length) {
|
|
109
|
+
const clean = cleanCitations(rawLines[bodyStart], references, links);
|
|
110
|
+
if (!isMetadata(clean))
|
|
111
|
+
break;
|
|
112
|
+
metadata.push(...metadataParts(clean));
|
|
113
|
+
bodyStart += 1;
|
|
114
|
+
}
|
|
115
|
+
const lines = rawLines.slice(bodyStart).map((line) => parseLine(line, references, links));
|
|
116
|
+
if (!title && url) {
|
|
117
|
+
try {
|
|
118
|
+
title = new URL(url).hostname;
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
title = url;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return { ...(title ? { title } : {}), ...(url ? { url } : {}), references, links, metadata, lines };
|
|
125
|
+
}
|
|
126
|
+
export function parseWebRunOutput(output) {
|
|
127
|
+
return typeof output === "string" && output
|
|
128
|
+
? output.split(RESULT_SEPARATOR_PATTERN).map(parseBlock).filter((block) => block !== undefined)
|
|
129
|
+
: [];
|
|
130
|
+
}
|
|
131
|
+
export function outputLineRange(blocks) {
|
|
132
|
+
const numbers = blocks.flatMap((block) => block.lines.flatMap((line) => line.line === undefined ? [] : [line.line]));
|
|
133
|
+
return numbers.length ? { first: Math.min(...numbers), last: Math.max(...numbers) } : undefined;
|
|
134
|
+
}
|
|
135
|
+
export function outputDomains(blocks) {
|
|
136
|
+
const domains = [];
|
|
137
|
+
for (const block of blocks)
|
|
138
|
+
if (block.url) {
|
|
139
|
+
try {
|
|
140
|
+
pushUnique(domains, new URL(block.url).hostname);
|
|
141
|
+
}
|
|
142
|
+
catch { }
|
|
143
|
+
}
|
|
144
|
+
return domains;
|
|
145
|
+
}
|
|
146
|
+
export function outputLinks(blocks) {
|
|
147
|
+
const links = [];
|
|
148
|
+
for (const block of blocks)
|
|
149
|
+
for (const link of block.links) {
|
|
150
|
+
if (!links.some((value) => value.id === link.id))
|
|
151
|
+
links.push({ ...link });
|
|
152
|
+
}
|
|
153
|
+
return links;
|
|
154
|
+
}
|
|
155
|
+
export function mergeWebRunLinks(base, extra) {
|
|
156
|
+
const links = [];
|
|
157
|
+
for (const link of [...base, ...extra]) {
|
|
158
|
+
if (!Number.isSafeInteger(link.id) || !link.label)
|
|
159
|
+
continue;
|
|
160
|
+
const existing = links.find((value) => value.id === link.id);
|
|
161
|
+
if (!existing) {
|
|
162
|
+
links.push({
|
|
163
|
+
id: link.id,
|
|
164
|
+
label: link.label,
|
|
165
|
+
...(link.domain ? { domain: link.domain } : {}),
|
|
166
|
+
...(link.url ? { url: link.url } : {}),
|
|
167
|
+
});
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (!existing.domain && link.domain)
|
|
171
|
+
existing.domain = link.domain;
|
|
172
|
+
if (!existing.url && link.url)
|
|
173
|
+
existing.url = link.url;
|
|
174
|
+
}
|
|
175
|
+
return links;
|
|
176
|
+
}
|
|
177
|
+
export function outputPdfRefs(blocks) {
|
|
178
|
+
const refs = [];
|
|
179
|
+
for (const block of blocks) {
|
|
180
|
+
if (!block.metadata.includes("PDF"))
|
|
181
|
+
continue;
|
|
182
|
+
for (const ref of block.references)
|
|
183
|
+
pushUnique(refs, ref);
|
|
184
|
+
}
|
|
185
|
+
return refs;
|
|
186
|
+
}
|
|
187
|
+
export function blockPlainText(block) {
|
|
188
|
+
return block.lines.map((line) => line.text).filter(Boolean).join(" ");
|
|
189
|
+
}
|