LibreChat/packages/api/package.json
Danny Avila fdc7e64bb7
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
GitNexus Index / index (push) Waiting to run
GitNexus Index / post-index (push) Blocked by required conditions
🪙 feat: SDK-Aligned Context-Usage Projection (gauge for window-switch & snapshot-less branches) (#13801)
* 🪙 feat: Context-usage projection — data-provider + client wiring

Consumer side of the SDK-aligned context projection (agents
`projectAgentContextUsage`). Adds the `/api/endpoints/context-projection`
data-provider plumbing (endpoint, service, query key, `TContextProjectionRequest`)
and a `useContextProjectionQuery` gated to fire only when no fresh snapshot
covers the viewed branch.

Wires `useTokenUsage` precedence to: live snapshot → fresh persisted snapshot
(window matches the resolved one) → server projection → per-message estimate.
A model/window switch marks the baked snapshot stale (its `maxContextTokens`
no longer matches) and falls to the projection — closing the gauge's
window-switch (G1) and snapshot-less-branch (G2) gaps. Snapshot and projection
share the render-relevant fields, so they render uniformly.

Backend endpoint + agents version bump land in follow-up commits. Includes the
design spec (CONTEXT_PROJECTION_SPEC.md).

* 🪙 feat: Context-projection backend endpoint

POST /api/endpoints/context-projection → resolveContextProjection (packages/api):
reconstructs the viewed branch (parent-chain walk from messageId), resolves the
agent config (instructions/provider/model/maxContextTokens), reuses LibreChat's
stored per-message tokenCounts as the index map (no re-tokenizing), and calls
the agents SDK projectAgentContextUsage — no model call. Thin controller injects
db.getMessages/db.getAgent; route mirrors /token-config.

First cut targets message-windowing accuracy; tool-schema tokens are deferred to
a follow-up that reuses the full initializeAgent path.

* 🩹 fix: Codex review on context projection (G1 guard, IDOR, recount, summary)

- Guard `currentActive` against a stale window: a model/window switch on the
  current branch left the live snapshot outranking the projection (G1 didn't
  fire). Now defers to the projection unless streaming or the window matches.
- Scope branch lookups to the authenticated user (`getMessages` filter +
  injected `userId`) — was loading any conversation by id (IDOR).
- Recount messages with no stored `tokenCount` via the tokenizer instead of
  charging 0, so snapshot-less/imported histories don't under-report.
- Fall back (null) for already-summarized branches rather than projecting from
  the full raw parent chain (the next call would send summary + tail); the
  client's summary-baseline-aware estimate handles them until a follow-up
  replays the summary boundary.

* 🩹 fix: Codex round 2 — drop agent load, summary marker, edit-invalidation

- Stop loading agent/model-spec config server-side (closes the agent-access
  IDOR and the spec-prompt special-casing). Provider/model/window now come from
  the client-resolved request (`limits.endpoint`/model — the agent's real
  provider, not the `agents` endpoint, so the tokenizer is right). Agent/spec/
  promptPrefix instructions are uniformly deferred to the full-fidelity follow-up.
- Detect summarized branches via the live path's `metadata.summaryUsedTokens`
  marker (was the wrong `summaryTokenCount` field) and fall back to the
  summary-aware estimate.
- Invalidate the projection query on in-place message edits via a branch
  content `revision` in the cache key (the tail id is unchanged on edit).

Deferred (valid, not a regression): same-window endpoint/model switch keeps a
window-matched snapshot — needs endpoint/model persisted on the snapshot, which
lands with the fidelity follow-up. Smoke-tested: fits / prunes / summarized→null
/ no-window→null.

* 🛡️ fix: make context projection strictly additive (no-regression)

Revert the G1 window-match guard on the live/branch snapshot. When no explicit
maxContextTokens is set (the common default), the SDK's snapshot window is
reserve-derived (~0.9·(modelContext − maxOutputTokens)) while useTokenLimits
resolves the raw model context — so `snapshot.maxContextTokens === resolvedMax`
is false for the SAME model, and the guard would wrongly drop a valid
current-branch snapshot to projection/estimate post-stream (a regression in the
default case, per initialize.ts:1240-1243).

The projection now activates ONLY for snapshot-less branches (G2): the
precedence is live snapshot → persisted branch snapshot → projection → estimate,
where the first two are byte-for-byte the prior behavior and the projection just
slots ahead of the estimate. Window/model-switch (G1) detection needs the
snapshot to carry its model/window and defers to the fidelity follow-up.

* 🩹 fix: surface projections as estimates, not authoritative snapshots

A first-cut projection carries the SDK's windowing but omits instruction/tool
overhead, so rendering it as `isEstimate: false` showed a confident under-count
for snapshot-less branches. Mark projection-sourced views `isEstimate: true` +
`snapshotActive: false` (and drop the snapshot field) so they present as a
better estimate than sumBranch — improved used/window number, estimate framing,
no misleading granular breakdown with ~0 tools. Real snapshots stay
authoritative. (Codex round 3, projection.ts:139.)

* 🧹 chore: drop CONTEXT_PROJECTION_SPEC.md from the PR

* 🎨 style: fix import-sort order in projection.ts (CI sort-imports check)

* 🔧 chore: update @librechat/agents dependency to version 3.2.36 in package-lock.json and related package.json files

* chore: npm audit fix

* 🎨 style: fix import-sort order in data-service.ts (CI sort-imports check)

* 🩹 fix: drop dead calibrationRatio in projectionParams (tsc never error)

Inside the ternary, branchSnapshot is narrowed to null (the gate is
), so  accessed a
property on  (frontend typecheck failure). It was also dead — there is
never a snapshot to seed from in this branch — so just remove it.

* Revert "chore: npm audit fix"

This reverts commit 4cdb862d0c.
2026-06-16 17:54:13 -04:00

167 lines
6.5 KiB
JSON

{
"name": "@librechat/api",
"version": "1.7.32",
"type": "commonjs",
"description": "MCP services for LibreChat",
"main": "dist/index.cjs",
"types": "./dist/index.d.cts",
"exports": {
".": {
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
},
"./telemetry": {
"require": {
"types": "./dist/telemetry.d.cts",
"default": "./dist/telemetry.cjs"
}
}
},
"scripts": {
"clean": "rimraf dist",
"build": "npm run clean && tsdown",
"build:dev": "npm run clean && tsdown",
"build:watch": "tsdown --watch",
"build:watch:prod": "tsdown --watch",
"test": "jest --coverage --watch --testPathIgnorePatterns=\"\\.*integration\\.|\\.*helper\\.|__tests__/helpers/|\\.*manual\\.spec\\.\"",
"test:ci": "jest --coverage --ci --testPathIgnorePatterns=\"\\.*integration\\.|\\.*helper\\.|__tests__/helpers/|\\.*manual\\.spec\\.\"",
"test:cache-integration:core": "jest --testPathPatterns=\"src/cache/.*\\.cache_integration\\.spec\\.ts$\" --coverage=false",
"test:cache-integration:cluster": "jest --testPathPatterns=\"src/cluster/.*\\.cache_integration\\.spec\\.ts$\" --coverage=false --runInBand",
"test:cache-integration:mcp": "jest --testPathPatterns=\"src/mcp/.*\\.cache_integration\\.spec\\.ts$\" --coverage=false",
"test:cache-integration:stream": "jest --testPathPatterns=\"src/stream/.*\\.stream_integration\\.spec\\.ts$\" --coverage=false --runInBand --forceExit",
"test:cache-integration": "npm run test:cache-integration:core && npm run test:cache-integration:cluster && npm run test:cache-integration:mcp && npm run test:cache-integration:stream",
"test:s3-integration": "jest --testPathPatterns=\"src/storage/s3/.*\\.integration\\.spec\\.ts$\" --coverage=false --runInBand",
"verify": "npm run test:ci",
"b:clean": "bun run rimraf dist",
"b:build": "bun run b:clean && bun run tsdown",
"b:build:dev": "bun run b:clean && bun run tsdown",
"start:everything-sse": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/examples/everything/sse.ts",
"start:everything": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/demo/everything.ts",
"start:filesystem": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/demo/filesystem.ts",
"start:servers": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/demo/servers.ts"
},
"repository": {
"type": "git",
"url": "git+https://github.com/danny-avila/LibreChat.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/danny-avila/LibreChat/issues"
},
"homepage": "https://librechat.ai",
"devDependencies": {
"@babel/preset-env": "^7.29.5",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.21.0",
"@rollup/plugin-alias": "^5.1.0",
"@rollup/plugin-commonjs": "^29.0.0",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.1.0",
"@rollup/plugin-replace": "^5.0.5",
"@rollup/plugin-typescript": "^12.1.2",
"@types/bun": "^1.2.15",
"@types/express": "^5.0.0",
"@types/express-session": "^1.18.2",
"@types/jest": "^29.5.2",
"@types/jsonwebtoken": "^9.0.0",
"@types/multer": "^1.4.13",
"@types/node": "^24.12.4",
"@types/node-fetch": "^2.6.13",
"@types/react": "^18.2.18",
"@types/sanitize-html": "^2.13.0",
"@types/supertest": "^7.2.0",
"@types/winston": "^2.4.4",
"@types/yauzl": "^2.10.3",
"aws-sdk-client-mock": "^4.1.0",
"dedent": "^1.5.3",
"get-stream": "^6.0.1",
"jest": "^30.2.0",
"jest-junit": "^17.0.0",
"jszip": "^3.10.1",
"librechat-data-provider": "*",
"lodash": "^4.17.23",
"mammoth": "^1.11.0",
"mongodb": "^6.14.2",
"nanoid": "^3.3.7",
"pdfjs-dist": "^5.4.624",
"rimraf": "^6.1.3",
"rollup": "^4.34.9",
"rollup-plugin-peer-deps-external": "^2.2.4",
"sanitize-html": "^2.13.0",
"ts-node": "^10.9.2",
"tsdown": "^0.22.2",
"typescript": "^5.9.3",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
"yauzl": "^3.2.1"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/"
},
"peerDependencies": {
"@anthropic-ai/vertex-sdk": "^0.16.0",
"@aws-sdk/client-bedrock-runtime": "^3.1013.0",
"@aws-sdk/client-cloudfront": "^3.1042.0",
"@aws-sdk/client-s3": "^3.980.0",
"@aws-sdk/cloudfront-signer": "^3.1036.0",
"@aws-sdk/credential-providers": "^3.1045.0",
"@aws-sdk/s3-request-presigner": "^3.758.0",
"@azure/identity": "^4.13.1",
"@azure/search-documents": "^12.0.0",
"@azure/storage-blob": "^12.30.0",
"@google/genai": "^2.8.0",
"@keyv/redis": "^4.3.3",
"@librechat/agents": "^3.2.36",
"@librechat/data-schemas": "*",
"@modelcontextprotocol/sdk": "^1.29.0",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/instrumentation-express": "^0.56.0",
"@opentelemetry/instrumentation-http": "^0.207.0",
"@opentelemetry/instrumentation-ioredis": "^0.55.0",
"@opentelemetry/instrumentation-mongodb": "^0.60.0",
"@opentelemetry/instrumentation-mongoose": "^0.54.0",
"@opentelemetry/instrumentation-undici": "^0.18.0",
"@opentelemetry/resources": "^2.6.1",
"@opentelemetry/sdk-node": "^0.218.0",
"@opentelemetry/semantic-conventions": "^1.39.0",
"@smithy/node-http-handler": "^4.4.5",
"ai-tokenizer": "^1.0.6",
"axios": "^1.16.0",
"connect-redis": "^8.1.0",
"dedent": "^1.5.3",
"eventsource": "^3.0.2",
"express": "^5.1.0",
"express-session": "^1.18.2",
"firebase": "^11.0.2",
"form-data": "^4.0.4",
"get-stream": "^6.0.1",
"google-auth-library": "^9.15.1",
"https-proxy-agent": "^7.0.6",
"ioredis": "^5.3.2",
"js-yaml": "^4.1.1",
"jsonwebtoken": "^9.0.0",
"jszip": "^3.10.1",
"jwks-rsa": "^3.2.0",
"keyv": "^5.3.2",
"keyv-file": "^5.1.2",
"librechat-data-provider": "*",
"lodash": "^4.17.23",
"mammoth": "^1.11.0",
"mathjs": "^15.2.0",
"memorystore": "^1.6.7",
"mongodb": "^6.14.2",
"mongoose": "^8.23.1",
"nanoid": "^3.3.7",
"node-fetch": "2.7.0",
"pdfjs-dist": "^5.4.624",
"prom-client": "^15.1.3",
"rate-limit-redis": "^4.2.0",
"sanitize-html": "^2.13.0",
"sharp": "^0.33.5",
"undici": "^7.24.1",
"yauzl": "^3.2.1",
"zod": "^3.22.4"
}
}