dsh-lcx-codex 0.4.3-pre.4 → 0.4.3

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.
Files changed (42) hide show
  1. package/README.md +68 -126
  2. package/THIRD_PARTY_NOTICES.md +64 -0
  3. package/lib/auxiliary-usage.js +63 -0
  4. package/lib/client.js +1363 -295
  5. package/lib/dsh-compat.js +80 -18
  6. package/lib/dsh-responses.js +75 -8
  7. package/lib/grok-native-search.js +151 -79
  8. package/lib/index.js +159 -101
  9. package/lib/invocation-policy-scope.js +261 -0
  10. package/lib/json-store.js +11 -4
  11. package/lib/pi-responses-runtime.js +1571 -0
  12. package/lib/responses-request.js +1 -1
  13. package/lib/responses-stream.js +152 -84
  14. package/lib/route.js +17 -3
  15. package/lib/search-accounting.js +86 -0
  16. package/lib/search-usage.js +86 -0
  17. package/lib/transport.js +38 -10
  18. package/lib/types/client/index.d.ts +12 -0
  19. package/lib/types/client/search-media.d.ts +16 -0
  20. package/lib/web-run-output.js +22 -0
  21. package/lib/web-search-alpha.js +230 -28
  22. package/lib/web-search-capability.js +26 -1
  23. package/lib/web-search-hosted.js +119 -9
  24. package/lib/web-search-ref-store.js +88 -7
  25. package/package.json +45 -24
  26. package/lib/types/compact-v2.d.ts +0 -104
  27. package/lib/types/dsh-compat.d.ts +0 -78
  28. package/lib/types/dsh-responses.d.ts +0 -82
  29. package/lib/types/grok-native-search.d.ts +0 -39
  30. package/lib/types/json-store.d.ts +0 -10
  31. package/lib/types/native-checkpoint.d.ts +0 -213
  32. package/lib/types/responses-request.d.ts +0 -59
  33. package/lib/types/responses-stream.d.ts +0 -64
  34. package/lib/types/route.d.ts +0 -153
  35. package/lib/types/service-mutex.d.ts +0 -14
  36. package/lib/types/token-budget.d.ts +0 -50
  37. package/lib/types/transport.d.ts +0 -21
  38. package/lib/types/web-run-output.d.ts +0 -29
  39. package/lib/types/web-search-alpha.d.ts +0 -286
  40. package/lib/types/web-search-capability.d.ts +0 -26
  41. package/lib/types/web-search-hosted.d.ts +0 -246
  42. package/lib/types/web-search-ref-store.d.ts +0 -22
@@ -1,6 +1,6 @@
1
1
  import { outputDomains, outputLineRange, parseWebRunOutput } from "./web-run-output.js";
2
2
  export const HOSTED_SEARCH_PARAMETERS = { type: "object", properties: { query: { type: "string", description: "Advanced Responses Hosted Web Search query. Use DSH web_search for ordinary searches." }, searchContextSize: { type: "string", enum: ["low", "medium", "high"] }, allowedDomains: { type: "array", items: { type: "string" } }, blockedDomains: { type: "array", items: { type: "string" } }, userLocation: { type: "object", properties: { country: { type: "string" }, city: { type: "string" }, region: { type: "string" }, timezone: { type: "string" } }, additionalProperties: false }, externalWebAccess: { type: "boolean" }, returnTokenBudget: { type: "string", enum: ["default", "unlimited"] }, searchContentTypes: { type: "array", items: { type: "string", enum: ["text", "image"] } }, imageSettings: { type: "object", properties: { maxResults: { type: "integer" }, caption: { type: "boolean" } }, additionalProperties: false } }, required: ["query"], additionalProperties: false };
3
- export const HOSTED_SEARCH_OUTPUT = { type: "object", properties: { mode: { type: "string", enum: ["hosted"] }, action: { type: "string" }, emulation: { type: "string", enum: ["native"] }, content: { type: "string" }, sources: { type: "array", items: { type: "object" } }, citations: { type: "array", items: { type: "object" } }, images: { type: "array", items: { type: "object" } }, warnings: { type: "array", items: { type: "string" } }, outputBlocks: { type: "array", items: { type: "object" } }, domains: { type: "array", items: { type: "string" } }, lineRange: { type: "object" }, requestId: { type: "string" }, responseId: { type: "string" }, retrievedAt: { type: "string" }, truncated: { type: "boolean" } }, required: ["mode", "action", "emulation", "content", "sources", "citations", "images", "warnings", "requestId", "retrievedAt", "truncated"], additionalProperties: false };
3
+ export const HOSTED_SEARCH_OUTPUT = { type: "object", properties: { mode: { type: "string", enum: ["hosted"] }, action: { type: "string" }, emulation: { type: "string", enum: ["native"] }, content: { type: "string" }, sources: { type: "array", items: { type: "object" } }, citations: { type: "array", items: { type: "object" } }, images: { type: "array", items: { type: "object" } }, warnings: { type: "array", items: { type: "string" } }, outputBlocks: { type: "array", items: { type: "object" } }, domains: { type: "array", items: { type: "string" } }, lineRange: { type: "object" }, requestId: { type: "string" }, responseId: { type: "string" }, retrievedAt: { type: "string" }, truncated: { type: "boolean" }, usage: { type: "object", properties: { inputTokens: { type: "number" }, outputTokens: { type: "number" }, totalTokens: { type: "number" }, cachedInputTokens: { type: "number" }, actionCount: { type: "number" }, serverWebSearchCalls: { type: "number" } }, additionalProperties: false } }, required: ["mode", "action", "emulation", "content", "sources", "citations", "images", "warnings", "requestId", "retrievedAt", "truncated"], additionalProperties: false };
4
4
  function failure(message, code = "WEB_INVALID_REQUEST") { return Object.assign(new Error(message), { code }); }
5
5
  function isRecord(value) { return value !== null && typeof value === "object" && !Array.isArray(value); }
6
6
  function isStringArray(value) { return Array.isArray(value) && value.every((item) => typeof item === "string"); }
@@ -182,6 +182,59 @@ function uniqueByUrl(values) { const result = []; const seen = new Set(); for (c
182
182
  seen.add(key);
183
183
  result.push(value);
184
184
  } return result; }
185
+ function nonNegativeInt(value) {
186
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
187
+ }
188
+ function hostedUsageFrom(response, actionCount) {
189
+ const usage = isRecord(response) && isRecord(response.usage) ? response.usage : undefined;
190
+ const inputDetails = usage && isRecord(usage.input_tokens_details)
191
+ ? usage.input_tokens_details
192
+ : usage && isRecord(usage.prompt_tokens_details)
193
+ ? usage.prompt_tokens_details
194
+ : undefined;
195
+ const serverDetails = usage && isRecord(usage.server_side_tool_usage_details)
196
+ ? usage.server_side_tool_usage_details
197
+ : undefined;
198
+ const result = {};
199
+ const inputTokens = usage ? nonNegativeInt(usage.input_tokens ?? usage.prompt_tokens) : undefined;
200
+ const outputTokens = usage ? nonNegativeInt(usage.output_tokens ?? usage.completion_tokens) : undefined;
201
+ const totalTokens = usage ? nonNegativeInt(usage.total_tokens) : undefined;
202
+ const cachedInputTokens = inputDetails ? nonNegativeInt(inputDetails.cached_tokens) : undefined;
203
+ const serverWebSearchCalls = serverDetails ? nonNegativeInt(serverDetails.web_search_calls) : undefined;
204
+ if (inputTokens !== undefined)
205
+ result.inputTokens = inputTokens;
206
+ if (outputTokens !== undefined)
207
+ result.outputTokens = outputTokens;
208
+ if (totalTokens !== undefined)
209
+ result.totalTokens = totalTokens;
210
+ // cachedInputTokens is a subset of inputTokens (cache hits), not an extra addend.
211
+ if (cachedInputTokens !== undefined)
212
+ result.cachedInputTokens = cachedInputTokens;
213
+ if (actionCount > 0)
214
+ result.actionCount = actionCount;
215
+ if (serverWebSearchCalls !== undefined)
216
+ result.serverWebSearchCalls = serverWebSearchCalls;
217
+ return Object.keys(result).length ? result : undefined;
218
+ }
219
+ function sourceLine(source) {
220
+ return `- [${String(source.title ?? source.url ?? "")}](${String(source.url ?? "")})${source.snippet ? ` — ${String(source.snippet)}` : ""}`;
221
+ }
222
+ function usageLine(usage) {
223
+ const parts = [];
224
+ if (usage.inputTokens !== undefined)
225
+ parts.push(`input=${String(usage.inputTokens)}`);
226
+ if (usage.outputTokens !== undefined)
227
+ parts.push(`output=${String(usage.outputTokens)}`);
228
+ if (usage.totalTokens !== undefined)
229
+ parts.push(`total=${String(usage.totalTokens)}`);
230
+ if (usage.cachedInputTokens !== undefined)
231
+ parts.push(`cachedInput=${String(usage.cachedInputTokens)}`);
232
+ if (usage.actionCount !== undefined)
233
+ parts.push(`actionCount=${String(usage.actionCount)}`);
234
+ if (usage.serverWebSearchCalls !== undefined)
235
+ parts.push(`serverWebSearchCalls=${String(usage.serverWebSearchCalls)}`);
236
+ return parts.length ? `用量:${parts.join(" ")}` : "";
237
+ }
185
238
  export function parseHostedSearchResponse(response, requestId, maxResults = 8, retrievedAt = new Date().toISOString()) {
186
239
  if (!isRecord(response))
187
240
  throw failure("Hosted Web Search returned an invalid response", "WEB_RESPONSE_INCOMPLETE");
@@ -196,16 +249,73 @@ export function parseHostedSearchResponse(response, requestId, maxResults = 8, r
196
249
  const artifacts = responseArtifacts(response);
197
250
  if (!artifacts.actions.length)
198
251
  throw failure("Hosted Web Search completed without web_search", "WEB_SEARCH_NOT_EXECUTED");
199
- const sources = uniqueByUrl([...artifacts.sources, ...outputBlocks.flatMap((block) => block.url ? [{ url: block.url, ...(block.title ? { title: block.title } : {}) }] : [])]);
200
252
  const citations = uniqueByUrl(artifacts.citations);
201
- const limited = sources.slice(0, Math.max(1, maxResults));
253
+ const discovered = uniqueByUrl([...artifacts.sources, ...outputBlocks.flatMap((block) => block.url ? [{ url: block.url, ...(block.title ? { title: block.title } : {}) }] : [])]);
254
+ const ranked = uniqueByUrl([...citations, ...discovered]);
255
+ const limited = ranked.slice(0, Math.max(1, maxResults));
202
256
  const images = artifacts.images.slice(0, Math.max(1, maxResults));
257
+ const usage = hostedUsageFrom(response, artifacts.actions.length);
203
258
  if (!output && !limited.length && !images.length)
204
259
  throw failure("Hosted Web Search returned no output", "WEB_NO_SOURCES");
205
- return { mode: "hosted", action: artifacts.actions[0], emulation: "native", content: output, sources: limited, citations, images, warnings: artifacts.actions.length > 1 ? [`Multiple hosted search actions were returned: ${artifacts.actions.join(", ")}`] : [], outputBlocks, domains: outputDomains(outputBlocks), ...(outputLineRange(outputBlocks) ? { lineRange: outputLineRange(outputBlocks) } : {}), requestId, ...(typeof response.id === "string" ? { responseId: response.id } : {}), retrievedAt, truncated: sources.length > limited.length || artifacts.images.length > images.length };
260
+ return { mode: "hosted", action: artifacts.actions[0], emulation: "native", content: output, sources: limited, citations, images, warnings: artifacts.actions.length > 1 ? [`Multiple hosted search actions were returned: ${artifacts.actions.join(", ")}`] : [], outputBlocks, domains: outputDomains(outputBlocks), ...(outputLineRange(outputBlocks) ? { lineRange: outputLineRange(outputBlocks) } : {}), requestId, ...(typeof response.id === "string" ? { responseId: response.id } : {}), retrievedAt, truncated: ranked.length > limited.length || artifacts.images.length > images.length, ...(usage ? { usage } : {}) };
261
+ }
262
+ /** Project Hosted image results into LCX-owned, tool-private, replayable UI metadata. */
263
+ export function hostedMediaPresentationMeta(value, tool, base = {}) {
264
+ const inherited = base !== null && typeof base === "object" && !Array.isArray(base) ? base : {};
265
+ if (!isRecord(value) || !Array.isArray(value.images))
266
+ return inherited;
267
+ const candidates = value.images.flatMap((entry) => {
268
+ if (!isRecord(entry))
269
+ return [];
270
+ const imageUrl = httpUrl(entry.imageUrl);
271
+ if (!imageUrl)
272
+ return [];
273
+ const previewUrl = httpUrl(entry.thumbnailUrl);
274
+ const sourceUrl = httpUrl(entry.sourceWebsiteUrl);
275
+ return [{
276
+ kind: "image",
277
+ url: imageUrl.toString(),
278
+ ...(previewUrl ? { previewUrl: previewUrl.toString() } : {}),
279
+ ...(sourceUrl ? { sourceUrl: sourceUrl.toString() } : {}),
280
+ ...(typeof entry.caption === "string" && entry.caption ? { caption: entry.caption } : {}),
281
+ structured: true,
282
+ }];
283
+ });
284
+ return candidates.length
285
+ ? { ...inherited, lcxHostedMedia: { version: 1, tool, candidates } }
286
+ : inherited;
287
+ }
288
+ export function renderHostedSearchResult(value) {
289
+ const data = isRecord(value) ? value : {};
290
+ const parts = [];
291
+ if (typeof data.content === "string" && data.content)
292
+ parts.push(data.content);
293
+ const citations = Array.isArray(data.citations) ? data.citations.filter(isRecord) : [];
294
+ const citationUrls = new Set(citations.map((source) => String(source.url ?? "")).filter(Boolean));
295
+ if (citations.length)
296
+ parts.push(`引用:\n${citations.map(sourceLine).join("\n")}`);
297
+ const extraSources = Array.isArray(data.sources)
298
+ ? data.sources.filter(isRecord).filter((source) => !citationUrls.has(String(source.url ?? "")))
299
+ : [];
300
+ if (extraSources.length)
301
+ parts.push(`来源:\n${extraSources.map(sourceLine).join("\n")}`);
302
+ if (Array.isArray(data.images) && data.images.length) {
303
+ parts.push(`图片:\n${data.images.filter(isRecord).map((image) => {
304
+ const caption = String(image.caption ?? image.imageUrl ?? "");
305
+ const imageUrl = String(image.imageUrl ?? "");
306
+ const sourcePage = typeof image.sourceWebsiteUrl === "string" && image.sourceWebsiteUrl
307
+ ? ` 来源页: ${image.sourceWebsiteUrl}`
308
+ : "";
309
+ return `- [${caption}](${imageUrl})${sourcePage}`;
310
+ }).join("\n")}`);
311
+ }
312
+ if (Array.isArray(data.warnings) && data.warnings.length)
313
+ parts.push(data.warnings.map((warning) => `警告:${String(warning)}`).join("\n"));
314
+ if (isRecord(data.usage)) {
315
+ const renderedUsage = usageLine(data.usage);
316
+ if (renderedUsage)
317
+ parts.push(renderedUsage);
318
+ }
319
+ parts.push(`检索时间:${String(data.retrievedAt ?? "")}`);
320
+ return [{ type: "text", text: parts.filter(Boolean).join("\n\n") }];
206
321
  }
207
- export function renderHostedSearchResult(value) { const data = isRecord(value) ? value : {}; const parts = []; if (typeof data.content === "string" && data.content)
208
- parts.push(data.content); if (Array.isArray(data.sources) && data.sources.length)
209
- parts.push(`来源:\n${data.sources.filter(isRecord).map((source) => `- [${String(source.title ?? source.url ?? "")}](${String(source.url ?? "")})${source.snippet ? ` — ${String(source.snippet)}` : ""}`).join("\n")}`); if (Array.isArray(data.images) && data.images.length)
210
- parts.push(`图片:\n${data.images.filter(isRecord).map((image) => `- [${String(image.caption ?? image.imageUrl ?? "")}](${String(image.imageUrl ?? "")})`).join("\n")}`); if (Array.isArray(data.warnings) && data.warnings.length)
211
- parts.push(data.warnings.map((warning) => `警告:${String(warning)}`).join("\n")); parts.push(`检索时间:${String(data.retrievedAt ?? "")}`); return [{ type: "text", text: parts.filter(Boolean).join("\n\n") }]; }
@@ -1,5 +1,6 @@
1
+ import { createHash } from "node:crypto";
1
2
  import { JsonStore } from "./json-store.js";
2
- const VERSION = 1;
3
+ const VERSION = 2;
3
4
  function isRecord(value) {
4
5
  return value !== null && typeof value === "object" && !Array.isArray(value);
5
6
  }
@@ -15,8 +16,18 @@ function validHttpUrl(value) {
15
16
  return false;
16
17
  }
17
18
  }
19
+ function validFingerprint(value) {
20
+ return typeof value === "string" && /^[a-f0-9]{64}$/u.test(value);
21
+ }
22
+ function validProvenance(value) {
23
+ return isRecord(value) &&
24
+ typeof value.action === "string" && value.action.length > 0 &&
25
+ (value.originKind === "response" || value.originKind === "request" || value.originKind === "legacy-unattributed") &&
26
+ validFingerprint(value.originFingerprint) &&
27
+ (value.artifactFingerprint === undefined || validFingerprint(value.artifactFingerprint));
28
+ }
18
29
  function validRef(refId, value) {
19
- return isRecord(value) && value.refId === refId && validHttpUrl(value.url);
30
+ return isRecord(value) && value.refId === refId && validHttpUrl(value.url) && validProvenance(value.provenance);
20
31
  }
21
32
  function validSession(value) {
22
33
  return isRecord(value) &&
@@ -28,15 +39,65 @@ function validData(data) {
28
39
  return isRecord(data) && data.version === VERSION && isRecord(data.sessions) &&
29
40
  Object.entries(data.sessions).every(([sessionId, session]) => sessionId.length > 0 && validSession(session));
30
41
  }
42
+ function validLegacyRef(refId, value) {
43
+ return isRecord(value) && value.refId === refId && validHttpUrl(value.url);
44
+ }
45
+ function validLegacySession(value) {
46
+ return isRecord(value) &&
47
+ typeof value.routeFingerprint === "string" && value.routeFingerprint.length > 0 &&
48
+ typeof value.updatedAt === "string" && !Number.isNaN(Date.parse(value.updatedAt)) &&
49
+ isRecord(value.refs) && Object.entries(value.refs).every(([refId, ref]) => refId.length > 0 && validLegacyRef(refId, ref));
50
+ }
51
+ function validLegacyData(data) {
52
+ return isRecord(data) && data.version === 1 && isRecord(data.sessions) &&
53
+ Object.entries(data.sessions).every(([sessionId, session]) => sessionId.length > 0 && validLegacySession(session));
54
+ }
55
+ function legacyFingerprint(sessionId, routeFingerprint, ref) {
56
+ return createHash("sha256")
57
+ .update(JSON.stringify([sessionId, routeFingerprint, ref.refId, ref.url ?? null]))
58
+ .digest("hex");
59
+ }
60
+ function migrateLegacyData(data) {
61
+ if (!validLegacyData(data))
62
+ return undefined;
63
+ return {
64
+ version: VERSION,
65
+ sessions: Object.fromEntries(Object.entries(data.sessions).map(([sessionId, session]) => [sessionId, {
66
+ routeFingerprint: session.routeFingerprint,
67
+ updatedAt: session.updatedAt,
68
+ refs: Object.fromEntries(Object.entries(session.refs).map(([refId, ref]) => [refId, {
69
+ refId,
70
+ ...(ref.url ? { url: ref.url } : {}),
71
+ provenance: {
72
+ action: "legacy-unattributed",
73
+ originKind: "legacy-unattributed",
74
+ originFingerprint: legacyFingerprint(sessionId, session.routeFingerprint, ref),
75
+ },
76
+ }])),
77
+ }])),
78
+ };
79
+ }
31
80
  function unavailable(refId) {
32
81
  return Object.assign(new Error(`Alpha reference is unavailable in this session and route: ${refId}`), {
33
82
  code: "LCX_ALPHA_REF_UNAVAILABLE",
34
83
  });
35
84
  }
85
+ function collision(refId) {
86
+ return Object.assign(new Error(`Alpha reference collision in this session and route: ${refId}`), {
87
+ code: "LCX_ALPHA_REF_COLLISION",
88
+ });
89
+ }
90
+ function sameObservation(left, right) {
91
+ return left.refId === right.refId && left.url === right.url &&
92
+ left.provenance.action === right.provenance.action &&
93
+ left.provenance.originKind === right.provenance.originKind &&
94
+ left.provenance.originFingerprint === right.provenance.originFingerprint &&
95
+ left.provenance.artifactFingerprint === right.provenance.artifactFingerprint;
96
+ }
36
97
  export class AlphaRefStore {
37
98
  store;
38
99
  constructor(file) {
39
- this.store = new JsonStore(file, () => ({ version: VERSION, sessions: {} }), validData, "LCX_ALPHA_REF_STORE_CORRUPT");
100
+ this.store = new JsonStore(file, () => ({ version: VERSION, sessions: {} }), validData, "LCX_ALPHA_REF_STORE_CORRUPT", migrateLegacyData);
40
101
  }
41
102
  record(sessionId, routeFingerprint, refs) {
42
103
  if (typeof sessionId !== "string" || !sessionId || typeof routeFingerprint !== "string" || !routeFingerprint || !Array.isArray(refs)) {
@@ -44,13 +105,33 @@ export class AlphaRefStore {
44
105
  }
45
106
  this.store.update((current) => {
46
107
  const previous = current.sessions[sessionId];
47
- const previousRefs = previous?.routeFingerprint === routeFingerprint ? previous.refs : {};
48
- const nextRefs = { ...previousRefs };
108
+ const sameRoute = previous?.routeFingerprint === routeFingerprint;
109
+ const nextRefs = { ...(sameRoute ? previous.refs : {}) };
110
+ let changed = !sameRoute;
49
111
  for (const value of refs) {
50
- if (!isRecord(value) || typeof value.refId !== "string" || !value.refId || !validHttpUrl(value.url))
112
+ if (!isRecord(value) || typeof value.refId !== "string" || !value.refId)
113
+ throw unavailable("invalid-record");
114
+ const accepted = nextRefs[value.refId];
115
+ if (!validHttpUrl(value.url) || !validProvenance(value.provenance)) {
116
+ if (accepted)
117
+ throw collision(value.refId);
118
+ throw unavailable("invalid-record");
119
+ }
120
+ const observation = {
121
+ refId: value.refId,
122
+ ...(value.url ? { url: value.url } : {}),
123
+ provenance: { ...value.provenance },
124
+ };
125
+ if (accepted) {
126
+ if (!sameObservation(accepted, observation))
127
+ throw collision(observation.refId);
51
128
  continue;
52
- nextRefs[value.refId] = { refId: value.refId, ...(value.url ? { url: value.url } : {}) };
129
+ }
130
+ nextRefs[observation.refId] = observation;
131
+ changed = true;
53
132
  }
133
+ if (!changed && previous)
134
+ return current;
54
135
  const sessions = {
55
136
  ...current.sessions,
56
137
  [sessionId]: { routeFingerprint, refs: nextRefs, updatedAt: new Date().toISOString() },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-lcx-codex",
3
- "version": "0.4.3-pre.4",
3
+ "version": "0.4.3",
4
4
  "description": "Model-scoped DSH plugin: GPT Responses lifecycle, Native V2 compaction and Hosted/Alpha Search; Grok native Web/X Search",
5
5
  "keywords": [
6
6
  "deepseek-harness",
@@ -41,8 +41,11 @@
41
41
  },
42
42
  "files": [
43
43
  "lib/*.js",
44
- "lib/types/**/*.d.ts",
45
- "cordis.patch.yml"
44
+ "lib/types/index.d.ts",
45
+ "lib/types/client/index.d.ts",
46
+ "lib/types/client/search-media.d.ts",
47
+ "cordis.patch.yml",
48
+ "THIRD_PARTY_NOTICES.md"
46
49
  ],
47
50
  "dsh": {
48
51
  "bundle": {
@@ -51,39 +54,46 @@
51
54
  "client": {
52
55
  "platform": "web",
53
56
  "inject": [
57
+ "@deepseek-ai/dsh-client-ui-chat",
58
+ "@deepseek-ai/dsh-client-ui-conversation",
54
59
  "@deepseek-ai/dsh-client-ui-settings-plugins"
55
60
  ]
56
61
  }
57
62
  },
58
- "dependencies": {
59
- "@earendil-works/pi-ai": "0.85.1"
60
- },
61
63
  "devDependencies": {
64
+ "@deepseek-ai/dsh": "0.1.5-rc.1",
65
+ "@earendil-works/pi-ai": "0.85.1",
62
66
  "@deepseek-ai/schemastery": "^3.18.2",
63
67
  "@types/node": "^22.20.0",
64
68
  "@types/react": "~18.3.1",
65
69
  "esbuild": "^0.28.2",
70
+ "linkedom": "^0.18.13",
66
71
  "typescript": "7.0.2"
67
72
  },
68
73
  "peerDependencies": {
69
74
  "@deepseek-ai/cordis": "^4.0.2",
70
- "@deepseek-ai/dsh-agent": "0.1.3-alpha.2",
71
- "@deepseek-ai/dsh-attachment": "0.1.3-alpha.2",
72
- "@deepseek-ai/dsh-client-locale": "0.1.3-alpha.2",
73
- "@deepseek-ai/dsh-client-modules": "0.1.3-alpha.2",
74
- "@deepseek-ai/dsh-client-store": "0.1.3-alpha.2",
75
- "@deepseek-ai/dsh-client-ui-settings-plugins": "0.1.3-alpha.2",
76
- "@deepseek-ai/dsh-compaction": "0.1.3-alpha.2",
77
- "@deepseek-ai/dsh-credentials": "0.1.3-alpha.2",
78
- "@deepseek-ai/dsh-fs": "0.1.3-alpha.2",
79
- "@deepseek-ai/dsh-llm": "0.1.3-alpha.2",
80
- "@deepseek-ai/dsh-session": "0.1.3-alpha.2",
81
- "@deepseek-ai/dsh-settings": "0.1.3-alpha.2",
82
- "@deepseek-ai/dsh-tool-web": "0.1.3-alpha.2",
83
- "@deepseek-ai/dsh-tools": "0.1.3-alpha.2",
84
- "@deepseek-ai/dsh-web": "0.1.3-alpha.2",
75
+ "@deepseek-ai/dsh-agent": ">=0.1.5-rc.1 <0.1.6",
76
+ "@deepseek-ai/dsh-attachment": ">=0.1.5-rc.1 <0.1.6",
77
+ "@deepseek-ai/dsh-client-locale": ">=0.1.5-rc.1 <0.1.6",
78
+ "@deepseek-ai/dsh-client-modules": ">=0.1.5-rc.1 <0.1.6",
79
+ "@deepseek-ai/dsh-client-store": ">=0.1.5-rc.1 <0.1.6",
80
+ "@deepseek-ai/dsh-client-ui-chat": ">=0.1.5-rc.1 <0.1.6",
81
+ "@deepseek-ai/dsh-client-ui-conversation": ">=0.1.5-rc.1 <0.1.6",
82
+ "@deepseek-ai/dsh-client-ui-settings-plugins": ">=0.1.5-rc.1 <0.1.6",
83
+ "@deepseek-ai/dsh-compaction": ">=0.1.5-rc.1 <0.1.6",
84
+ "@deepseek-ai/dsh-credentials": ">=0.1.5-rc.1 <0.1.6",
85
+ "@deepseek-ai/dsh-fs": ">=0.1.5-rc.1 <0.1.6",
86
+ "@deepseek-ai/dsh-llm": ">=0.1.5-rc.1 <0.1.6",
87
+ "@deepseek-ai/dsh-session": ">=0.1.5-rc.1 <0.1.6",
88
+ "@deepseek-ai/dsh-settings": ">=0.1.5-rc.1 <0.1.6",
89
+ "@deepseek-ai/dsh-tool-web": ">=0.1.5-rc.1 <0.1.6",
90
+ "@deepseek-ai/dsh-tools": ">=0.1.5-rc.1 <0.1.6",
91
+ "@deepseek-ai/dsh-web": ">=0.1.5-rc.1 <0.1.6",
85
92
  "@deepseek-ai/schemastery": "^3.18.2",
86
- "react": "^18.2.0"
93
+ "react": "^18.2.0",
94
+ "@deepseek-ai/dsh-token-meter": ">=0.1.5-rc.1 <0.1.6",
95
+ "@deepseek-ai/dsh-session-projection": ">=0.1.5-rc.1 <0.1.6",
96
+ "zod": "^4.5.4"
87
97
  },
88
98
  "peerDependenciesMeta": {
89
99
  "@deepseek-ai/dsh-client-locale": {
@@ -101,6 +111,12 @@
101
111
  "@deepseek-ai/dsh-client-store": {
102
112
  "optional": true
103
113
  },
114
+ "@deepseek-ai/dsh-client-ui-chat": {
115
+ "optional": true
116
+ },
117
+ "@deepseek-ai/dsh-client-ui-conversation": {
118
+ "optional": true
119
+ },
104
120
  "@deepseek-ai/dsh-client-ui-settings-plugins": {
105
121
  "optional": true
106
122
  },
@@ -134,7 +150,7 @@
134
150
  },
135
151
  "scripts": {
136
152
  "build": "npm run build:host && npm run build:client",
137
- "build:host": "tsc -p tsconfig.json",
153
+ "build:host": "tsc -p tsconfig.json && node scripts/build-pi-runtime.mjs",
138
154
  "build:client": "tsc -p tsconfig.client.json && node scripts/build-client.mjs",
139
155
  "test": "node --test tests/*.test.mjs",
140
156
  "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit",
@@ -148,5 +164,10 @@
148
164
  "publishConfig": {
149
165
  "access": "public"
150
166
  },
151
- "license": "MIT"
167
+ "license": "MIT",
168
+ "lcxCompatibility": {
169
+ "dshInstallRange": ">=0.1.5-rc.1 <0.1.6",
170
+ "verifiedDsh": "0.1.5-rc.1",
171
+ "verifiedHostPi": "0.85.1"
172
+ }
152
173
  }
@@ -1,104 +0,0 @@
1
- import { buildCompactionResponsesBody } from "./responses-request.js";
2
- type HeaderMap = Record<string, string>;
3
- type CompactionItem = {
4
- type: "compaction";
5
- encrypted_content: string;
6
- };
7
- type FunctionCallItem = {
8
- type: "function_call";
9
- call_id: string;
10
- };
11
- type FunctionCallOutputItem = {
12
- type: "function_call_output";
13
- call_id: string;
14
- };
15
- type ValidatedOutputItem = CompactionItem | FunctionCallItem | FunctionCallOutputItem | {
16
- type: string;
17
- };
18
- type CanonicalUsage = {
19
- inputTokens: number;
20
- outputTokens: number;
21
- cacheReadTokens?: number;
22
- cacheWriteTokens?: number;
23
- reasoningTokens?: number;
24
- };
25
- type GenerationControls = {
26
- reasoningEffort?: unknown;
27
- temperature?: unknown;
28
- maxTokens?: unknown;
29
- };
30
- type GenerationEnvelope = {
31
- reasoning?: {
32
- effort: string;
33
- summary: "auto";
34
- };
35
- include?: string[];
36
- temperature?: number;
37
- max_output_tokens?: number;
38
- };
39
- type NativeCompactionBodyOptions = GenerationControls & {
40
- model: string;
41
- modelDescriptor?: Exclude<Parameters<typeof buildCompactionResponsesBody>[0]["model"], string>;
42
- input: unknown[];
43
- tools?: unknown;
44
- promptCacheKey?: string;
45
- promptCacheRetention?: string;
46
- cacheRetention?: "none" | "short" | "long";
47
- };
48
- type NativeCompactionRequestOptions = NativeCompactionBodyOptions & {
49
- baseURL: string;
50
- idempotencyKey?: string;
51
- headers?: HeaderMap;
52
- signal?: AbortSignal;
53
- timeoutMs?: number;
54
- maxAttempts?: number;
55
- maxResponseBytes?: number;
56
- };
57
- type SseParseOptions = {
58
- signal?: AbortSignal;
59
- maxResponseBytes?: number;
60
- };
61
- type NativeCompactionResult = {
62
- object: unknown;
63
- id?: string;
64
- output: ValidatedOutputItem[];
65
- compaction: CompactionItem;
66
- usage?: CanonicalUsage;
67
- };
68
- export declare const REMOTE_COMPACTION_V2_FEATURE = "remote_compaction_v2";
69
- /**
70
- * @param {HeaderMap} [headers]
71
- * @returns {HeaderMap}
72
- */
73
- export declare function mergeFeatureHeader(headers?: HeaderMap): HeaderMap;
74
- /**
75
- * @param {GenerationControls} [controls]
76
- * @returns {GenerationEnvelope}
77
- */
78
- export declare function responsesGenerationEnvelope(controls?: GenerationControls): GenerationEnvelope;
79
- /**
80
- * @param {NativeCompactionBodyOptions} options
81
- * @returns {NativeCompactionBody}
82
- */
83
- export declare function buildNativeCompactionBody({ model, modelDescriptor, input, tools, promptCacheKey, promptCacheRetention, cacheRetention, reasoningEffort, temperature, maxTokens, }: NativeCompactionBodyOptions): {
84
- [x: string]: unknown;
85
- } & {
86
- model: string;
87
- input: unknown[];
88
- stream: boolean;
89
- store: boolean;
90
- tool_choice?: string;
91
- parallel_tool_calls?: boolean;
92
- };
93
- /**
94
- * Provider SSE events enter as unknown; response.completed remains authoritative.
95
- * @param {Response} response
96
- * @param {SseParseOptions} [options]
97
- * @returns {Promise<NativeCompactionResult>}
98
- */
99
- export declare function parseNativeCompactionSse(response: Response, options?: SseParseOptions): Promise<NativeCompactionResult>;
100
- /**
101
- * @param {NativeCompactionRequestOptions} options
102
- */
103
- export declare function requestNativeCompaction({ baseURL, model, modelDescriptor, input, tools, promptCacheKey, promptCacheRetention, cacheRetention, reasoningEffort, temperature, maxTokens, idempotencyKey, headers, signal, timeoutMs, maxAttempts, maxResponseBytes, }: NativeCompactionRequestOptions): Promise<NativeCompactionResult>;
104
- export {};
@@ -1,78 +0,0 @@
1
- import { Session, type SessionStore } from "@deepseek-ai/dsh-session";
2
- import type { ToolRuntime } from "@deepseek-ai/dsh-tools";
3
- import { ServiceMutex } from "./service-mutex.js";
4
- type CompatMethod = (this: object, agent: unknown, trigger: string, signal: AbortSignal) => Promise<unknown>;
5
- type PrunerMethod = (...args: unknown[]) => unknown;
6
- type MutableService = Record<PropertyKey, unknown>;
7
- interface CompactionService extends MutableService {
8
- compactIfNeeded: CompatMethod;
9
- }
10
- export interface CompactionPatchRecord {
11
- compaction: CompactionService;
12
- original: CompatMethod;
13
- wrapper: CompatMethod;
14
- mutex: ServiceMutex;
15
- lifecycle: AbortController;
16
- }
17
- export type CompactionPatchRecords = Map<object, CompactionPatchRecord>;
18
- export type CompactionPatchBehavior = (agent: unknown, trigger: string, signal: AbortSignal, callOriginal: (signal: AbortSignal) => Promise<unknown>) => Promise<unknown>;
19
- interface PrunerService extends MutableService {
20
- pruneSession: unknown;
21
- }
22
- export interface PrunerPatchRecord {
23
- pruner: PrunerService;
24
- original: unknown;
25
- replacement: PrunerMethod;
26
- }
27
- interface ConfigService extends MutableService {
28
- config: unknown;
29
- }
30
- export interface ConfigPatchRecord {
31
- service: ConfigService;
32
- original: unknown;
33
- installed: unknown;
34
- }
35
- export declare function agentSessionId(agent: unknown): string;
36
- export declare function agentUsesSession(agent: unknown, session: Session): boolean;
37
- export declare function sessionFromAgent(agent: unknown): Session | undefined;
38
- export declare function readAgentRouteState(agent: unknown): {
39
- requestConfig: unknown;
40
- options: unknown;
41
- sessionId: string;
42
- };
43
- export declare function scopedToolRuntime(agent: unknown): (Pick<ToolRuntime, "register"> & Partial<Pick<ToolRuntime, "get">>) | undefined;
44
- export declare function tokenMeterTotal(value: unknown, session: Session): number | undefined;
45
- export declare function sessionsService(ctx: unknown): Pick<SessionStore, "get"> | undefined;
46
- export declare function sessionFor(ctx: unknown, sessionId: string): Session | undefined;
47
- export declare function readWebSearchProvider(ctx: unknown): unknown;
48
- export declare function writeWebSearchProvider(ctx: unknown, providerId: unknown): boolean;
49
- export declare function contextService(ctx: unknown, name: string): unknown;
50
- export declare function resolveContextService(ctx: unknown, name: string): unknown;
51
- export declare function resolveScopedService(agent: unknown, name: string): unknown;
52
- export declare function resolveAgentService(ctx: unknown, agent: unknown, name: string): unknown;
53
- export declare function concreteService(value: unknown): unknown;
54
- export declare function compactionPatchCandidate(value: unknown, records: ReadonlyMap<object, CompactionPatchRecord>): Pick<CompactionPatchRecord, "compaction" | "original"> | undefined;
55
- export declare function installCompactionPatch(records: CompactionPatchRecords, candidate: Pick<CompactionPatchRecord, "compaction" | "original">, mutex: ServiceMutex, lifecycle: AbortController, behavior: CompactionPatchBehavior): boolean;
56
- export declare function restoreCompactionPatches(records: Map<object, CompactionPatchRecord>, entries?: Iterable<CompactionPatchRecord>): void;
57
- export declare function toolResultPrunerState(value: unknown): {
58
- pruner: PrunerService | undefined;
59
- original: unknown;
60
- };
61
- export declare function patchToolResultPruner(state: {
62
- pruner: PrunerService | undefined;
63
- original: unknown;
64
- }, replacement: PrunerMethod): PrunerPatchRecord | undefined;
65
- export declare function restoreToolResultPruner(record: PrunerPatchRecord | undefined): void;
66
- export declare function compactionConfigState(service: unknown): {
67
- service: ConfigService | undefined;
68
- original: unknown;
69
- };
70
- export declare function patchCompactionConfig(state: {
71
- service: ConfigService | undefined;
72
- original: unknown;
73
- }, createConfig: (originalConfig: unknown) => unknown): ConfigPatchRecord | undefined;
74
- export declare function restoreCompactionConfig(record: ConfigPatchRecord | undefined): void;
75
- export declare function patchVisibleWebSearchTimeout(agent: unknown, getTimeoutMs: () => number | undefined, patchedDefinitions: Map<MutableService, unknown>): void;
76
- export declare function refreshVisibleWebSearchTimeouts(patchedDefinitions: ReadonlyMap<MutableService, unknown>, timeoutMs: number | undefined): void;
77
- export declare function restoreVisibleWebSearchTimeouts(patchedDefinitions: Map<MutableService, unknown>): void;
78
- export {};