@xopcai/xopc 0.0.202 → 0.0.204
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-DOhnAQOQ.js → activity-store-DJBadfSX.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CAjfa48Q.js → agent-avatar-dicebear-BaH7Poqk.js} +1 -1
- package/dist/gateway/static/root/assets/agents-HctDDhtH.js +68 -0
- package/dist/gateway/static/root/assets/{api-E9Bk-Idp.js → api-B5O7fKXa.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-GNT3iv0V.js → app-management-settings-panel-CCLK9wdi.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-BFond2ll.js → appearance-settings-DYSHvGJP.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-kCUkEIoM.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-C6qpchzp.js → archive-plugin-CZX6pfRb.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-B4CcSDdV.js → attachment-load-CGYpcBXN.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-D2Ao4Dwi.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-xYL_41XP.js → binary-plugins-BJ1AQfTa.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-nYiJQItv.js → block-editor-DR6LCljI.js} +46 -46
- package/dist/gateway/static/root/assets/browser-settings-page-B_IjOjtT.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-D_jnndyz.js → browser-workflow-inputs-Bd68yluo.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-pT7Hvwwh.js → browser-workflows-page-BG-hEoGn.js} +2 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-DDC5-wqk.js +7 -0
- package/dist/gateway/static/root/assets/{capability-presets-api--tz0mGLY.js → capability-presets-api-BerPMp6f.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-CxpKaTzc.js +3 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-CkOKF9nc.js → channel-recipient-api-D2d21_XA.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-D7pmMIbZ.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-CZ5P9jbB.js +1 -0
- package/dist/gateway/static/root/assets/{connectors-api-X5ukNasZ.js → connectors-api-Sw0BrUmJ.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-DTyM5bMS.js +2 -0
- package/dist/gateway/static/root/assets/cron-expression-DfZsNMAq.js +2 -0
- package/dist/gateway/static/root/assets/{date-picker-CGm8EH8G.js → date-picker-DjHSmgq9.js} +1 -1
- package/dist/gateway/static/root/assets/dependency-picker-CRajhh0O.js +1 -0
- package/dist/gateway/static/root/assets/desktop-pet-a3DXD4IR.js +1 -0
- package/dist/gateway/static/root/assets/{desktop-pet-settings-s4kmnf-W.js → desktop-pet-settings-BWx0Duz-.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-DmfFg4Gq.js → directory-picker-path-field-CEZrPGZx.js} +1 -1
- package/dist/gateway/static/root/assets/download-Dk-ZjtO6.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-DrLEK8GU.js → extension-debug-page-CwJ-R0DC.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DtyFPtMR.js → extension-page-BpXWrZFh.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-Xok6T2KD.js → extension-settings-page-D0c4RgxT.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-DwSpEYiw.js → gateway-config-api-Dn2FSNBa.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-Cv2ywpdb.js → gateway-config-swr-VVcfd3sG.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-B5Zh2rx9.js → gateway-settings-BNamAC3x.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-undf-k5g.js → gateway-startup-retry-qAX_T2t2.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-C2RxqeK0.js → heartbeat-settings-BagVvGe6.js} +1 -1
- package/dist/gateway/static/root/assets/home-page-Ci0h-uKG.js +3 -0
- package/dist/gateway/static/root/assets/index-DHGnTdgl.js +85 -0
- package/dist/gateway/static/root/assets/index-Dm-cvIpl.css +2 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BN3p-1wI.js → keyboard-shortcuts-settings-BOoz5DNd.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-B1mLlQT6.js +2 -0
- package/dist/gateway/static/root/assets/local-apps-page-B2mV4Olf.js +1 -0
- package/dist/gateway/static/root/assets/{locale-store-CnamlR07.js → locale-store-CbPVxonP.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-DLFwiLa6.js +2 -0
- package/dist/gateway/static/root/assets/{management-settings-CTIaHfgU.js → management-settings-BEduNvMc.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-C0iKadAm.js → markdown-split-BgE9kKG6.js} +1 -1
- package/dist/gateway/static/root/assets/markdown-view-B12xeflb.css +1 -0
- package/dist/gateway/static/root/assets/markdown-view-Dl-0_9JR.js +69 -0
- package/dist/gateway/static/root/assets/{media-plugins-DcM72GSJ.js → media-plugins-DNESLGDB.js} +1 -1
- package/dist/gateway/static/root/assets/messages-9zCa8KkW.js +3 -0
- package/dist/gateway/static/root/assets/{notes-page-By_EzRhP.js → notes-page-COgmlorx.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-Ce5ORQus.js +4 -0
- package/dist/gateway/static/root/assets/plus-Q2yW6OE7.js +1 -0
- package/dist/gateway/static/root/assets/preview-open-alternatives-BV_58lf7.js +1 -0
- package/dist/gateway/static/root/assets/{product-open-page-dQ2_5PLu.js → product-open-page-Bh8WERvg.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-C0vjVpKC.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-RGaztvxc.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-C7EfVrqr.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DiPj9FLN.js → runtime-tools-settings-panel-HZYyqA5T.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-BDLYItBP.js → schema-form-C6EnKgW2.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-BTpLFg2e.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-RV6nphHJ.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-Dr4Uf_CY.js → settings-form-section-sAjYWtCZ.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-Bqi7tsXj.js → settings-loading-skeleton-Bw56H64J.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-BbookgxJ.js → settings-page-aduxT-Nu.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-CVg8oOTw.js +1 -0
- package/dist/gateway/static/root/assets/share-preview-page-SmtgZyVf.js +2 -0
- package/dist/gateway/static/root/assets/shares-settings-DNXQwu2U.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-DhgLGYw8.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-BHBDl1pN.js +2 -0
- package/dist/gateway/static/root/assets/{skills-page.utils-b9byH-KL.js → skills-page.utils-D5SnlPVg.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-CL_AXjw1.js → system-settings-panel-wiXKgbG9.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-DBu-p3Iv.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-BDyUTObE.js → theme-store-Bc_eRUev.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-CUI3q_I-.js → use-autosave-CiuRY85U.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-B-uZKYIg.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-DLXOB1jw.js → voice-api-key-field-CX9xuc7h.js} +1 -1
- package/dist/gateway/static/root/assets/work-discovery-overlay-DrTD6gtS.js +1 -0
- package/dist/gateway/static/root/assets/work-discovery-page-C4Ivt1_C.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-DKpUxB-i.js → workflow-run-setup-panel-CG0fSFFv.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-CT5g5who.js +5 -0
- package/dist/gateway/static/root/assets/{working-directory-picker-modal-BcyiDXU3.js → working-directory-picker-modal-CYWdZUJ5.js} +1 -1
- package/dist/gateway/static/root/assets/x-B_N4OPjy.js +1 -0
- package/dist/gateway/static/root/index.html +19 -14
- package/dist/package.js +1 -1
- package/dist/packages/realtime-client/src/index.js +11 -7
- package/dist/src/agent/agent-manager.js +3 -2
- package/dist/src/agent/embedded/run-for-session.js +3 -2
- package/dist/src/agent/embedded/run-turn.js +29 -16
- package/dist/src/agent/embedded/types.d.ts +2 -2
- package/dist/src/agent/embedded/xopc-stream-bridge.d.ts +2 -1
- package/dist/src/agent/embedded/xopc-stream-bridge.js +2 -2
- package/dist/src/agent/memory/compaction-planner.js +20 -4
- package/dist/src/agent/memory/compaction.js +22 -4
- package/dist/src/agent/memory/context-budget.d.ts +6 -1
- package/dist/src/agent/memory/context-budget.js +94 -2
- package/dist/src/agent/memory/create-memory-manager.js +1 -1
- package/dist/src/agent/prompt/cache-boundary.d.ts +2 -0
- package/dist/src/agent/prompt/cache-boundary.js +10 -1
- package/dist/src/agent/prompt/sections/project-context.d.ts +1 -4
- package/dist/src/agent/prompt/sections/project-context.js +6 -13
- package/dist/src/agent/prompt/service-prompt-builder.js +2 -1
- package/dist/src/agent/prompt/system-prompt.d.ts +1 -3
- package/dist/src/agent/prompt/system-prompt.js +6 -15
- package/dist/src/agent/tools/cache-stability.d.ts +3 -0
- package/dist/src/agent/tools/cache-stability.js +19 -0
- package/dist/src/agent/tools/factory.js +2 -1
- package/dist/src/agent-manifest/schema.d.ts +40 -20
- package/dist/src/agent-manifest/schema.js +4 -5
- package/dist/src/agent-runtime/index.js +1 -1
- package/dist/src/agent-runtime/runtime-profile.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/config/schema.d.ts +40 -20
- package/dist/src/extensions/types/providers.d.ts +0 -2
- package/dist/src/gateway/chat-stream/mapper.js +44 -4
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +4 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/providers/extension-stream-bridge.js +0 -2
- package/dist/src/providers/google-managed-prompt-cache.d.ts +14 -0
- package/dist/src/providers/google-managed-prompt-cache.js +125 -0
- package/dist/src/providers/index.js +5 -4
- package/dist/src/providers/model-call.js +2 -2
- package/dist/src/providers/model-supplements.d.ts +2 -0
- package/dist/src/providers/model-supplements.js +23 -2
- package/dist/src/providers/prompt-cache-fingerprint.d.ts +4 -0
- package/dist/src/providers/prompt-cache-fingerprint.js +44 -0
- package/dist/src/providers/prompt-cache-lifecycle.d.ts +9 -0
- package/dist/src/providers/prompt-cache-lifecycle.js +31 -0
- package/dist/src/providers/prompt-cache-observability.d.ts +20 -0
- package/dist/src/providers/prompt-cache-observability.js +44 -0
- package/dist/src/providers/prompt-cache-payload.d.ts +10 -3
- package/dist/src/providers/prompt-cache-payload.js +204 -31
- package/dist/src/providers/prompt-cache-plan.d.ts +15 -0
- package/dist/src/providers/prompt-cache-plan.js +29 -0
- package/dist/src/realtime/runtime.js +9 -2
- package/dist/src/realtime/writer.js +5 -0
- package/package.json +3 -3
- package/dist/gateway/static/root/assets/agents-Cke8EF5Z.js +0 -68
- package/dist/gateway/static/root/assets/apps-page-B9D-6sJt.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-BFS3dH43.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-ELV-Y8rz.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-Dbx_nPAI.js +0 -7
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-DHg_JMUz.js +0 -3
- package/dist/gateway/static/root/assets/channels-settings-DjHOlPq-.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-DNDvMWpl.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-RY-W6CQt.js +0 -2
- package/dist/gateway/static/root/assets/cron-expression-DHY0LrLq.js +0 -2
- package/dist/gateway/static/root/assets/dependency-picker-DDECr6Hj.js +0 -1
- package/dist/gateway/static/root/assets/desktop-pet-BoEIRgm2.js +0 -1
- package/dist/gateway/static/root/assets/home-page-DPhkqxEb.js +0 -3
- package/dist/gateway/static/root/assets/index-Bp8I_eX4.css +0 -1
- package/dist/gateway/static/root/assets/index-CKSplmFw.js +0 -152
- package/dist/gateway/static/root/assets/local-app-workbench-page-D7FmunJF.js +0 -2
- package/dist/gateway/static/root/assets/local-apps-page-C7H807zd.js +0 -1
- package/dist/gateway/static/root/assets/logs-page-vrjf-JTk.js +0 -2
- package/dist/gateway/static/root/assets/messages-D7kOD_o_.js +0 -3
- package/dist/gateway/static/root/assets/notes-workbench-Cp1ierS_.js +0 -4
- package/dist/gateway/static/root/assets/preview-open-alternatives-CpblfmWk.js +0 -1
- package/dist/gateway/static/root/assets/project-detail-page-Cp_jfZJj.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-DYbmweGw.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-U2qXVyLH.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-CtNKNhCi.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-B6IMzhWo.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-mUu0iDlD.js +0 -1
- package/dist/gateway/static/root/assets/share-preview-page-1M79esSO.js +0 -2
- package/dist/gateway/static/root/assets/shares-settings-DadcMA8y.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-C3ZzYCz0.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-B3kqZ-ke.js +0 -2
- package/dist/gateway/static/root/assets/task-detail-page-Bnjpkl4v.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-CBgAAZiB.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-overlay-BvlvyVJX.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-page-BBpnnnrs.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-Dd_9p9ji.js +0 -5
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
//#region src/providers/prompt-cache-fingerprint.ts
|
|
3
|
+
function asRecord(value) {
|
|
4
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
5
|
+
}
|
|
6
|
+
const MAX_FINGERPRINT_DEPTH = 64;
|
|
7
|
+
const MAX_FINGERPRINT_NODES = 2e4;
|
|
8
|
+
const MAX_FINGERPRINT_STRING_CHARS = 1e5;
|
|
9
|
+
function canonicalize(value, state, depth) {
|
|
10
|
+
state.nodes += 1;
|
|
11
|
+
if (depth > MAX_FINGERPRINT_DEPTH || state.nodes > MAX_FINGERPRINT_NODES) return "\"[fingerprint-limit]\"";
|
|
12
|
+
if (typeof value === "string" && value.length > MAX_FINGERPRINT_STRING_CHARS) return JSON.stringify(`${value.slice(0, MAX_FINGERPRINT_STRING_CHARS)}[fingerprint-limit]`);
|
|
13
|
+
if (Array.isArray(value)) {
|
|
14
|
+
if (state.seen.has(value)) return "\"[circular]\"";
|
|
15
|
+
state.seen.add(value);
|
|
16
|
+
const result = `[${value.map((entry) => canonicalize(entry, state, depth + 1)).join(",")}]`;
|
|
17
|
+
state.seen.delete(value);
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
const record = asRecord(value);
|
|
21
|
+
if (record) {
|
|
22
|
+
if (state.seen.has(record)) return "\"[circular]\"";
|
|
23
|
+
state.seen.add(record);
|
|
24
|
+
const result = `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${canonicalize(record[key], state, depth + 1)}`).join(",")}}`;
|
|
25
|
+
state.seen.delete(record);
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
return JSON.stringify(value) ?? "null";
|
|
29
|
+
}
|
|
30
|
+
/** Canonical JSON used only for bounded prompt-cache fingerprints. */
|
|
31
|
+
function canonicalizeCacheValue(value) {
|
|
32
|
+
return canonicalize(value, {
|
|
33
|
+
nodes: 0,
|
|
34
|
+
seen: /* @__PURE__ */ new WeakSet()
|
|
35
|
+
}, 0);
|
|
36
|
+
}
|
|
37
|
+
function digestCacheValue(value) {
|
|
38
|
+
return createHash("sha256").update(canonicalizeCacheValue(value)).digest("base64url");
|
|
39
|
+
}
|
|
40
|
+
function digestCacheText(value) {
|
|
41
|
+
return createHash("sha256").update(value).digest("base64url");
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { canonicalizeCacheValue, digestCacheText, digestCacheValue };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Api, Model } from '@earendil-works/pi-ai';
|
|
2
|
+
import type { PromptCachePolicy } from './prompt-cache-plan.js';
|
|
3
|
+
export declare function resolvePromptCacheTtlMs(model: Model<Api>, policy: PromptCachePolicy): number;
|
|
4
|
+
export declare function recordPromptCacheTouch(sessionKey: string, model: Model<Api>, usage: {
|
|
5
|
+
cacheRead?: number;
|
|
6
|
+
cacheWrite?: number;
|
|
7
|
+
}, now?: number): void;
|
|
8
|
+
export declare function isPromptCacheExpired(sessionKey: string, model: Model<Api>, policy: PromptCachePolicy, now?: number): boolean;
|
|
9
|
+
export declare function clearPromptCacheTouches(): void;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/providers/prompt-cache-lifecycle.ts
|
|
2
|
+
const cacheTouchByScope = /* @__PURE__ */ new Map();
|
|
3
|
+
const MAX_CACHE_TOUCHES = 512;
|
|
4
|
+
function scopeKey(sessionKey, model) {
|
|
5
|
+
return `${sessionKey}\0${model.provider}/${model.id}`;
|
|
6
|
+
}
|
|
7
|
+
function resolvePromptCacheTtlMs(model, policy) {
|
|
8
|
+
if (model.api === "openai-responses" && /^gpt-5\.6(?:-|$)/.test(model.id)) return 30 * 6e4;
|
|
9
|
+
return policy.lifetime === "long" ? 60 * 6e4 : 5 * 6e4;
|
|
10
|
+
}
|
|
11
|
+
function recordPromptCacheTouch(sessionKey, model, usage, now = Date.now()) {
|
|
12
|
+
if ((usage.cacheRead ?? 0) <= 0 && (usage.cacheWrite ?? 0) <= 0) return;
|
|
13
|
+
const key = scopeKey(sessionKey, model);
|
|
14
|
+
cacheTouchByScope.delete(key);
|
|
15
|
+
cacheTouchByScope.set(key, now);
|
|
16
|
+
while (cacheTouchByScope.size > MAX_CACHE_TOUCHES) {
|
|
17
|
+
const oldest = cacheTouchByScope.keys().next().value;
|
|
18
|
+
if (typeof oldest !== "string") break;
|
|
19
|
+
cacheTouchByScope.delete(oldest);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function isPromptCacheExpired(sessionKey, model, policy, now = Date.now()) {
|
|
23
|
+
if (policy.mode === "off") return false;
|
|
24
|
+
const touchedAt = cacheTouchByScope.get(scopeKey(sessionKey, model));
|
|
25
|
+
return touchedAt !== void 0 && now - touchedAt >= resolvePromptCacheTtlMs(model, policy);
|
|
26
|
+
}
|
|
27
|
+
function clearPromptCacheTouches() {
|
|
28
|
+
cacheTouchByScope.clear();
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { clearPromptCacheTouches, isPromptCacheExpired, recordPromptCacheTouch, resolvePromptCacheTtlMs };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Api, Model } from '@earendil-works/pi-ai';
|
|
2
|
+
export type PromptCacheChangeReason = 'model_changed' | 'reasoning_changed' | 'system_changed' | 'dynamic_context_changed' | 'tools_changed';
|
|
3
|
+
export interface PromptCacheSnapshot {
|
|
4
|
+
modelRef: string;
|
|
5
|
+
api: string;
|
|
6
|
+
reasoning?: string;
|
|
7
|
+
stableSystemDigest: string;
|
|
8
|
+
dynamicSystemDigest: string;
|
|
9
|
+
toolDigest: string;
|
|
10
|
+
toolCount: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function buildPromptCacheSnapshot(params: {
|
|
13
|
+
model: Model<Api>;
|
|
14
|
+
systemPrompt?: string;
|
|
15
|
+
tools?: unknown[];
|
|
16
|
+
reasoning?: string;
|
|
17
|
+
}): PromptCacheSnapshot;
|
|
18
|
+
export declare function diffPromptCacheSnapshots(previous: PromptCacheSnapshot | undefined, next: PromptCacheSnapshot): PromptCacheChangeReason[];
|
|
19
|
+
export declare function observePromptCacheSnapshot(scope: string, snapshot: PromptCacheSnapshot): PromptCacheChangeReason[];
|
|
20
|
+
export declare function clearPromptCacheObservations(): void;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { splitPromptCacheBoundary, stripPromptCacheBoundary } from "../agent/prompt/cache-boundary.js";
|
|
2
|
+
import { digestCacheText, digestCacheValue } from "./prompt-cache-fingerprint.js";
|
|
3
|
+
//#region src/providers/prompt-cache-observability.ts
|
|
4
|
+
const MAX_TRACKED_SCOPES = 512;
|
|
5
|
+
const previousByScope = /* @__PURE__ */ new Map();
|
|
6
|
+
function buildPromptCacheSnapshot(params) {
|
|
7
|
+
const rawPrompt = params.systemPrompt ?? "";
|
|
8
|
+
const split = splitPromptCacheBoundary(rawPrompt);
|
|
9
|
+
return {
|
|
10
|
+
modelRef: `${params.model.provider}/${params.model.id}`,
|
|
11
|
+
api: params.model.api,
|
|
12
|
+
...params.reasoning ? { reasoning: params.reasoning } : {},
|
|
13
|
+
stableSystemDigest: digestCacheText(split?.stablePrefix ?? stripPromptCacheBoundary(rawPrompt)),
|
|
14
|
+
dynamicSystemDigest: digestCacheText(split?.dynamicSuffix ?? ""),
|
|
15
|
+
toolDigest: digestCacheValue(params.tools ?? []),
|
|
16
|
+
toolCount: params.tools?.length ?? 0
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function diffPromptCacheSnapshots(previous, next) {
|
|
20
|
+
if (!previous) return [];
|
|
21
|
+
const reasons = [];
|
|
22
|
+
if (previous.modelRef !== next.modelRef || previous.api !== next.api) reasons.push("model_changed");
|
|
23
|
+
if (previous.reasoning !== next.reasoning) reasons.push("reasoning_changed");
|
|
24
|
+
if (previous.stableSystemDigest !== next.stableSystemDigest) reasons.push("system_changed");
|
|
25
|
+
if (previous.dynamicSystemDigest !== next.dynamicSystemDigest) reasons.push("dynamic_context_changed");
|
|
26
|
+
if (previous.toolDigest !== next.toolDigest) reasons.push("tools_changed");
|
|
27
|
+
return reasons;
|
|
28
|
+
}
|
|
29
|
+
function observePromptCacheSnapshot(scope, snapshot) {
|
|
30
|
+
const reasons = diffPromptCacheSnapshots(previousByScope.get(scope), snapshot);
|
|
31
|
+
previousByScope.delete(scope);
|
|
32
|
+
previousByScope.set(scope, snapshot);
|
|
33
|
+
while (previousByScope.size > MAX_TRACKED_SCOPES) {
|
|
34
|
+
const oldest = previousByScope.keys().next().value;
|
|
35
|
+
if (typeof oldest !== "string") break;
|
|
36
|
+
previousByScope.delete(oldest);
|
|
37
|
+
}
|
|
38
|
+
return reasons;
|
|
39
|
+
}
|
|
40
|
+
function clearPromptCacheObservations() {
|
|
41
|
+
previousByScope.clear();
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { buildPromptCacheSnapshot, clearPromptCacheObservations, diffPromptCacheSnapshots, observePromptCacheSnapshot };
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import type { Api, Model, SimpleStreamOptions } from '@earendil-works/pi-ai';
|
|
2
|
-
|
|
2
|
+
import { type PromptCachePlan, type PromptCachePolicy } from './prompt-cache-plan.js';
|
|
3
3
|
export declare function buildPromptCacheKey(model: Model<Api>, context: {
|
|
4
4
|
systemPrompt?: string;
|
|
5
5
|
tools?: unknown[];
|
|
6
|
-
}): string;
|
|
6
|
+
}, reasoning?: string): string;
|
|
7
|
+
export declare function buildPromptCachePlan(model: Model<Api>, context: {
|
|
8
|
+
systemPrompt?: string;
|
|
9
|
+
tools?: unknown[];
|
|
10
|
+
}, policyInput?: PromptCachePolicy, reasoning?: string): PromptCachePlan;
|
|
11
|
+
export declare function transformPromptCachePayload(model: Model<Api>, payload: unknown, plan?: PromptCachePlan, context?: {
|
|
12
|
+
systemPrompt?: string;
|
|
13
|
+
}): unknown;
|
|
7
14
|
export declare function preparePromptCacheContext<T extends {
|
|
8
15
|
systemPrompt?: string;
|
|
9
16
|
}>(model: Model<Api>, context: T): T;
|
|
10
17
|
export declare function withPromptCachePayloadTransform(model: Model<Api>, context: {
|
|
11
18
|
systemPrompt?: string;
|
|
12
19
|
tools?: unknown[];
|
|
13
|
-
}, options: SimpleStreamOptions | undefined): SimpleStreamOptions
|
|
20
|
+
}, options: SimpleStreamOptions | undefined, policyInput?: PromptCachePolicy): SimpleStreamOptions;
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import { splitPromptCacheBoundary, stripPromptCacheBoundary } from "../agent/prompt/cache-boundary.js";
|
|
2
|
-
import {
|
|
2
|
+
import { canonicalizeCacheValue, digestCacheText } from "./prompt-cache-fingerprint.js";
|
|
3
|
+
import { resolvePromptCachePolicy, resolvePromptCacheProviderMode } from "./prompt-cache-plan.js";
|
|
4
|
+
import { applyGoogleManagedPromptCache } from "./google-managed-prompt-cache.js";
|
|
3
5
|
//#region src/providers/prompt-cache-payload.ts
|
|
4
6
|
function asRecord(value) {
|
|
5
7
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
6
8
|
}
|
|
7
|
-
function
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return model.provider === "openai" || model.baseUrl?.includes("api.openai.com") === true;
|
|
9
|
+
function buildPromptCacheKey(model, context, reasoning) {
|
|
10
|
+
const stablePrompt = context.systemPrompt ? splitPromptCacheBoundary(context.systemPrompt)?.stablePrefix ?? stripPromptCacheBoundary(context.systemPrompt) : "";
|
|
11
|
+
return `xopc-v2-${digestCacheText(`v2\0${model.provider}\0${model.id}\0${reasoning ?? ""}\0${stablePrompt}\0${canonicalizeCacheValue(context.tools ?? [])}`)}`;
|
|
11
12
|
}
|
|
12
|
-
function
|
|
13
|
+
function buildPromptCachePlan(model, context, policyInput, reasoning) {
|
|
14
|
+
const policy = resolvePromptCachePolicy(policyInput);
|
|
15
|
+
const providerMode = resolvePromptCacheProviderMode(model, policy);
|
|
16
|
+
return {
|
|
17
|
+
policy,
|
|
18
|
+
providerMode,
|
|
19
|
+
...providerMode === "implicit" || providerMode === "explicit" ? { cacheKey: buildPromptCacheKey(model, context, reasoning) } : {}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function splitAnthropicSystem(payload, lifetime) {
|
|
13
23
|
const record = asRecord(payload);
|
|
14
24
|
if (!record || !Array.isArray(record.system)) return payload;
|
|
15
25
|
let changed = false;
|
|
@@ -23,7 +33,11 @@ function splitAnthropicSystem(payload) {
|
|
|
23
33
|
return [{
|
|
24
34
|
...rest,
|
|
25
35
|
type: block.type ?? "text",
|
|
26
|
-
text: split.stablePrefix
|
|
36
|
+
text: split.stablePrefix,
|
|
37
|
+
cache_control: lifetime === "long" ? {
|
|
38
|
+
type: "ephemeral",
|
|
39
|
+
ttl: "1h"
|
|
40
|
+
} : { type: "ephemeral" }
|
|
27
41
|
}, ...split.dynamicSuffix ? [{
|
|
28
42
|
type: block.type ?? "text",
|
|
29
43
|
text: split.dynamicSuffix
|
|
@@ -34,6 +48,54 @@ function splitAnthropicSystem(payload) {
|
|
|
34
48
|
system
|
|
35
49
|
} : payload;
|
|
36
50
|
}
|
|
51
|
+
function addAnthropicHistoryBreakpoint(payload, lifetime) {
|
|
52
|
+
const record = asRecord(payload);
|
|
53
|
+
if (!record || !Array.isArray(record.messages)) return payload;
|
|
54
|
+
const messages = [...record.messages];
|
|
55
|
+
const cacheControl = lifetime === "long" ? {
|
|
56
|
+
type: "ephemeral",
|
|
57
|
+
ttl: "1h"
|
|
58
|
+
} : { type: "ephemeral" };
|
|
59
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
60
|
+
const message = asRecord(messages[index]);
|
|
61
|
+
if (!message || message.role !== "user") continue;
|
|
62
|
+
const blocks = Array.isArray(message.content) ? [...message.content] : void 0;
|
|
63
|
+
const containsToolResult = blocks?.some((block) => asRecord(block)?.type === "tool_result") ?? false;
|
|
64
|
+
if (index === messages.length - 1 && !containsToolResult) continue;
|
|
65
|
+
if (!blocks) {
|
|
66
|
+
if (typeof message.content !== "string") continue;
|
|
67
|
+
messages[index] = {
|
|
68
|
+
...message,
|
|
69
|
+
content: [{
|
|
70
|
+
type: "text",
|
|
71
|
+
text: message.content,
|
|
72
|
+
cache_control: cacheControl
|
|
73
|
+
}]
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
...record,
|
|
77
|
+
messages
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
for (let blockIndex = blocks.length - 1; blockIndex >= 0; blockIndex -= 1) {
|
|
81
|
+
const block = asRecord(blocks[blockIndex]);
|
|
82
|
+
if (!block) continue;
|
|
83
|
+
blocks[blockIndex] = {
|
|
84
|
+
...block,
|
|
85
|
+
cache_control: cacheControl
|
|
86
|
+
};
|
|
87
|
+
messages[index] = {
|
|
88
|
+
...message,
|
|
89
|
+
content: blocks
|
|
90
|
+
};
|
|
91
|
+
return {
|
|
92
|
+
...record,
|
|
93
|
+
messages
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return payload;
|
|
98
|
+
}
|
|
37
99
|
function splitBedrockSystem(payload) {
|
|
38
100
|
const record = asRecord(payload);
|
|
39
101
|
if (!record || !Array.isArray(record.system)) return payload;
|
|
@@ -56,7 +118,7 @@ function splitBedrockSystem(payload) {
|
|
|
56
118
|
if (next?.cachePoint) {
|
|
57
119
|
system.push(next);
|
|
58
120
|
index += 1;
|
|
59
|
-
}
|
|
121
|
+
} else system.push({ cachePoint: { type: "default" } });
|
|
60
122
|
if (split.dynamicSuffix) system.push({ text: split.dynamicSuffix });
|
|
61
123
|
}
|
|
62
124
|
return changed ? {
|
|
@@ -64,20 +126,128 @@ function splitBedrockSystem(payload) {
|
|
|
64
126
|
system
|
|
65
127
|
} : payload;
|
|
66
128
|
}
|
|
67
|
-
function
|
|
68
|
-
|
|
69
|
-
if (
|
|
129
|
+
function addBedrockHistoryBreakpoint(payload) {
|
|
130
|
+
const record = asRecord(payload);
|
|
131
|
+
if (!record || !Array.isArray(record.messages)) return payload;
|
|
132
|
+
const messages = [...record.messages];
|
|
133
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
134
|
+
const message = asRecord(messages[index]);
|
|
135
|
+
if (!message || message.role !== "user" || !Array.isArray(message.content)) continue;
|
|
136
|
+
const content = [...message.content];
|
|
137
|
+
const containsToolResult = content.some((block) => "toolResult" in (asRecord(block) ?? {}));
|
|
138
|
+
if (index === messages.length - 1 && !containsToolResult) continue;
|
|
139
|
+
content.push({ cachePoint: { type: "default" } });
|
|
140
|
+
messages[index] = {
|
|
141
|
+
...message,
|
|
142
|
+
content
|
|
143
|
+
};
|
|
144
|
+
return {
|
|
145
|
+
...record,
|
|
146
|
+
messages
|
|
147
|
+
};
|
|
148
|
+
}
|
|
70
149
|
return payload;
|
|
71
150
|
}
|
|
72
|
-
function
|
|
73
|
-
if (
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
151
|
+
function addBreakpointToContent(content) {
|
|
152
|
+
if (typeof content === "string") return [{
|
|
153
|
+
type: "input_text",
|
|
154
|
+
text: content,
|
|
155
|
+
prompt_cache_breakpoint: { mode: "explicit" }
|
|
156
|
+
}];
|
|
157
|
+
if (!Array.isArray(content)) return content;
|
|
158
|
+
const blocks = [...content];
|
|
159
|
+
for (let index = blocks.length - 1; index >= 0; index -= 1) {
|
|
160
|
+
const block = asRecord(blocks[index]);
|
|
161
|
+
if (!block) continue;
|
|
162
|
+
blocks[index] = {
|
|
163
|
+
...block,
|
|
164
|
+
prompt_cache_breakpoint: { mode: "explicit" }
|
|
165
|
+
};
|
|
166
|
+
return blocks;
|
|
167
|
+
}
|
|
168
|
+
return content;
|
|
77
169
|
}
|
|
78
|
-
function
|
|
79
|
-
|
|
80
|
-
|
|
170
|
+
function addOpenAIHistoryBreakpoint(items) {
|
|
171
|
+
if (!Array.isArray(items)) return items;
|
|
172
|
+
const next = [...items];
|
|
173
|
+
for (let index = next.length - 1; index >= 0; index -= 1) {
|
|
174
|
+
const item = asRecord(next[index]);
|
|
175
|
+
if (!item) continue;
|
|
176
|
+
if (item.type === "function_call_output") {
|
|
177
|
+
next[index] = {
|
|
178
|
+
...item,
|
|
179
|
+
output: addBreakpointToContent(item.output)
|
|
180
|
+
};
|
|
181
|
+
return next;
|
|
182
|
+
}
|
|
183
|
+
if (!("content" in item)) continue;
|
|
184
|
+
if (index === next.length - 1 && item.role === "user") continue;
|
|
185
|
+
const content = addBreakpointToContent(item.content);
|
|
186
|
+
if (content === item.content) continue;
|
|
187
|
+
next[index] = {
|
|
188
|
+
...item,
|
|
189
|
+
content
|
|
190
|
+
};
|
|
191
|
+
return next;
|
|
192
|
+
}
|
|
193
|
+
return items;
|
|
194
|
+
}
|
|
195
|
+
function applyOpenAIExplicitCache(payload, context, cacheKey) {
|
|
196
|
+
const record = asRecord(payload);
|
|
197
|
+
if (!record) return payload;
|
|
198
|
+
const split = splitPromptCacheBoundary(context.systemPrompt ?? "");
|
|
199
|
+
const stablePrompt = split?.stablePrefix ?? stripPromptCacheBoundary(context.systemPrompt ?? "");
|
|
200
|
+
const dynamicPrompt = split?.dynamicSuffix ?? "";
|
|
201
|
+
const stableContent = [{
|
|
202
|
+
type: "input_text",
|
|
203
|
+
text: stablePrompt,
|
|
204
|
+
prompt_cache_breakpoint: { mode: "explicit" }
|
|
205
|
+
}];
|
|
206
|
+
const dynamicContent = [{
|
|
207
|
+
type: "input_text",
|
|
208
|
+
text: dynamicPrompt
|
|
209
|
+
}];
|
|
210
|
+
if (Array.isArray(record.input)) {
|
|
211
|
+
const expectedInstructions = stripPromptCacheBoundary(context.systemPrompt ?? "");
|
|
212
|
+
const canReplaceInstructions = record.instructions === void 0 || record.instructions === expectedInstructions;
|
|
213
|
+
return {
|
|
214
|
+
...record,
|
|
215
|
+
...canReplaceInstructions ? { instructions: [{
|
|
216
|
+
type: "message",
|
|
217
|
+
role: "system",
|
|
218
|
+
content: stableContent
|
|
219
|
+
}, ...dynamicPrompt ? [{
|
|
220
|
+
type: "message",
|
|
221
|
+
role: "system",
|
|
222
|
+
content: dynamicContent
|
|
223
|
+
}] : []] } : {},
|
|
224
|
+
input: addOpenAIHistoryBreakpoint(record.input),
|
|
225
|
+
prompt_cache_key: cacheKey,
|
|
226
|
+
prompt_cache_options: {
|
|
227
|
+
mode: "explicit",
|
|
228
|
+
ttl: "30m"
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
...record,
|
|
234
|
+
prompt_cache_key: cacheKey,
|
|
235
|
+
prompt_cache_options: {
|
|
236
|
+
mode: "explicit",
|
|
237
|
+
ttl: "30m"
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
function transformPromptCachePayload(model, payload, plan = buildPromptCachePlan(model, {}), context = {}) {
|
|
242
|
+
if (plan.providerMode === "none" || plan.providerMode === "managed") return payload;
|
|
243
|
+
if (model.api === "anthropic-messages") return addAnthropicHistoryBreakpoint(splitAnthropicSystem(payload, plan.policy.lifetime), plan.policy.lifetime);
|
|
244
|
+
if (model.api === "bedrock-converse-stream") return addBedrockHistoryBreakpoint(splitBedrockSystem(payload));
|
|
245
|
+
if (plan.providerMode === "explicit" && plan.cacheKey) return applyOpenAIExplicitCache(payload, context, plan.cacheKey);
|
|
246
|
+
const record = asRecord(payload);
|
|
247
|
+
return record && plan.cacheKey ? {
|
|
248
|
+
...record,
|
|
249
|
+
prompt_cache_key: plan.cacheKey
|
|
250
|
+
} : payload;
|
|
81
251
|
}
|
|
82
252
|
function preparePromptCacheContext(model, context) {
|
|
83
253
|
if (model.api === "anthropic-messages" || model.api === "bedrock-converse-stream") return context;
|
|
@@ -87,24 +257,27 @@ function preparePromptCacheContext(model, context) {
|
|
|
87
257
|
systemPrompt: stripPromptCacheBoundary(context.systemPrompt)
|
|
88
258
|
};
|
|
89
259
|
}
|
|
90
|
-
function withPromptCachePayloadTransform(model, context, options) {
|
|
91
|
-
const
|
|
92
|
-
const openAiCacheKey = supportsPromptCacheKey(model) && options?.cacheRetention !== "none";
|
|
93
|
-
if (!explicitBoundary && !openAiCacheKey) return options;
|
|
260
|
+
function withPromptCachePayloadTransform(model, context, options, policyInput) {
|
|
261
|
+
const plan = buildPromptCachePlan(model, context, policyInput, options?.reasoning);
|
|
94
262
|
const upstream = options?.onPayload;
|
|
95
|
-
const
|
|
263
|
+
const cacheRetention = model.api === "anthropic-messages" || model.api === "bedrock-converse-stream" ? plan.providerMode === "none" ? "none" : plan.policy.lifetime : "none";
|
|
96
264
|
return {
|
|
97
265
|
...options,
|
|
266
|
+
cacheRetention,
|
|
98
267
|
onPayload: async (payload, payloadModel) => {
|
|
99
268
|
const upstreamPayload = await upstream?.(payload, payloadModel);
|
|
100
|
-
const transformed = transformPromptCachePayload(model, upstreamPayload === void 0 ? payload : upstreamPayload);
|
|
101
|
-
|
|
102
|
-
return
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
269
|
+
const transformed = transformPromptCachePayload(model, upstreamPayload === void 0 ? payload : upstreamPayload, plan, context);
|
|
270
|
+
if (plan.providerMode !== "managed") return transformed;
|
|
271
|
+
return applyGoogleManagedPromptCache({
|
|
272
|
+
model,
|
|
273
|
+
context,
|
|
274
|
+
payload: transformed,
|
|
275
|
+
policy: plan.policy,
|
|
276
|
+
apiKey: options?.apiKey,
|
|
277
|
+
fetchImpl: options?.fetch
|
|
278
|
+
});
|
|
106
279
|
}
|
|
107
280
|
};
|
|
108
281
|
}
|
|
109
282
|
//#endregion
|
|
110
|
-
export { buildPromptCacheKey, preparePromptCacheContext, transformPromptCachePayload, withPromptCachePayloadTransform };
|
|
283
|
+
export { buildPromptCacheKey, buildPromptCachePlan, preparePromptCacheContext, transformPromptCachePayload, withPromptCachePayloadTransform };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Api, Model } from '@earendil-works/pi-ai';
|
|
2
|
+
export interface PromptCachePolicy {
|
|
3
|
+
mode: 'off' | 'auto';
|
|
4
|
+
lifetime: 'short' | 'long';
|
|
5
|
+
}
|
|
6
|
+
export type PromptCacheProviderMode = 'none' | 'implicit' | 'explicit' | 'managed';
|
|
7
|
+
export interface PromptCachePlan {
|
|
8
|
+
policy: PromptCachePolicy;
|
|
9
|
+
providerMode: PromptCacheProviderMode;
|
|
10
|
+
cacheKey?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const DEFAULT_PROMPT_CACHE_POLICY: PromptCachePolicy;
|
|
13
|
+
export declare function resolvePromptCachePolicy(policy?: Partial<PromptCachePolicy>): PromptCachePolicy;
|
|
14
|
+
export declare function isOfficialOpenAIModel(model: Model<Api>): boolean;
|
|
15
|
+
export declare function resolvePromptCacheProviderMode(model: Model<Api>, policy: PromptCachePolicy): PromptCacheProviderMode;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/providers/prompt-cache-plan.ts
|
|
2
|
+
const DEFAULT_PROMPT_CACHE_POLICY = {
|
|
3
|
+
mode: "auto",
|
|
4
|
+
lifetime: "short"
|
|
5
|
+
};
|
|
6
|
+
function resolvePromptCachePolicy(policy) {
|
|
7
|
+
return {
|
|
8
|
+
mode: policy?.mode ?? DEFAULT_PROMPT_CACHE_POLICY.mode,
|
|
9
|
+
lifetime: policy?.lifetime ?? DEFAULT_PROMPT_CACHE_POLICY.lifetime
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function isOfficialOpenAIModel(model) {
|
|
13
|
+
if (model.api === "openai-codex-responses" || model.api === "azure-openai-responses") return true;
|
|
14
|
+
if (model.api !== "openai-completions" && model.api !== "openai-responses") return false;
|
|
15
|
+
return model.provider === "openai" || model.baseUrl?.includes("api.openai.com") === true;
|
|
16
|
+
}
|
|
17
|
+
function supportsExplicitOpenAICache(model) {
|
|
18
|
+
return model.api === "openai-responses" && isOfficialOpenAIModel(model) && /^gpt-5\.6(?:-|$)/.test(model.id);
|
|
19
|
+
}
|
|
20
|
+
function resolvePromptCacheProviderMode(model, policy) {
|
|
21
|
+
if (policy.mode === "off") return "none";
|
|
22
|
+
if (supportsExplicitOpenAICache(model)) return "explicit";
|
|
23
|
+
if (isOfficialOpenAIModel(model)) return "implicit";
|
|
24
|
+
if (model.api === "anthropic-messages" || model.api === "bedrock-converse-stream") return "explicit";
|
|
25
|
+
if (model.api === "google-generative-ai") return "managed";
|
|
26
|
+
return "none";
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { DEFAULT_PROMPT_CACHE_POLICY, isOfficialOpenAIModel, resolvePromptCachePolicy, resolvePromptCacheProviderMode };
|
|
@@ -241,7 +241,7 @@ var RealtimeRuntime = class {
|
|
|
241
241
|
socket.close(4400, "Invalid endpoint message");
|
|
242
242
|
}
|
|
243
243
|
});
|
|
244
|
-
socket.on("close", () => {
|
|
244
|
+
socket.on("close", (code, reasonBuffer) => {
|
|
245
245
|
clearTimeout(helloTimer);
|
|
246
246
|
clearInterval(heartbeatTimer);
|
|
247
247
|
releaseBudget();
|
|
@@ -249,7 +249,14 @@ var RealtimeRuntime = class {
|
|
|
249
249
|
for (const handle of subscriptions.values()) handle.unsubscribe();
|
|
250
250
|
subscriptions.clear();
|
|
251
251
|
if (endpointId && connectionId) this.endpointTools?.remove(endpointId, connectionId);
|
|
252
|
-
if (connectionId)
|
|
252
|
+
if (connectionId) {
|
|
253
|
+
const reason = reasonBuffer.toString();
|
|
254
|
+
log.info({
|
|
255
|
+
connectionId,
|
|
256
|
+
code,
|
|
257
|
+
...reason ? { reason } : {}
|
|
258
|
+
}, `Realtime client disconnected (${code}${reason ? `: ${reason}` : ""})`);
|
|
259
|
+
}
|
|
253
260
|
});
|
|
254
261
|
}
|
|
255
262
|
rawDataToText(data) {
|
|
@@ -26,6 +26,11 @@ var RealtimeSocketWriter = class {
|
|
|
26
26
|
data,
|
|
27
27
|
bytes: Buffer.byteLength(data)
|
|
28
28
|
};
|
|
29
|
+
if (item.bytes > MAX_QUEUED_BYTES) {
|
|
30
|
+
this.socket.close(1009, "Realtime event exceeds delivery limit");
|
|
31
|
+
this.close();
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
29
34
|
if (this.queuedBytes + item.bytes > MAX_QUEUED_BYTES) {
|
|
30
35
|
this.socket.close(4413, "Realtime client is too slow");
|
|
31
36
|
this.close();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xopcai/xopc",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.204",
|
|
4
4
|
"description": "Local-first AI system that remembers context, coordinates AI, and sustains long-term progress.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -163,9 +163,9 @@
|
|
|
163
163
|
"vitest": "4.1.5",
|
|
164
164
|
"vue": "^3.5.35",
|
|
165
165
|
"@xopcai/gateway-contract": "0.0.0",
|
|
166
|
-
"@xopcai/
|
|
166
|
+
"@xopcai/endpoint-tools-protocol": "0.0.0",
|
|
167
167
|
"@xopcai/realtime-protocol": "0.0.0",
|
|
168
|
-
"@xopcai/
|
|
168
|
+
"@xopcai/realtime-client": "0.0.0"
|
|
169
169
|
},
|
|
170
170
|
"scripts": {
|
|
171
171
|
"assets:brand": "node scripts/generate-brand-assets.mjs",
|