nexus-agents 2.166.3 → 2.167.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{child-mcp-config-AUA4TFBG.js → child-mcp-config-X4YLQKGK.js} +2 -2
- package/dist/{chunk-P54BDACX.js → chunk-2NU774CB.js} +2 -2
- package/dist/{chunk-ORRKK563.js → chunk-7K5LSUEU.js} +3 -3
- package/dist/{chunk-GS3UPAUE.js → chunk-7USEQLMS.js} +2 -2
- package/dist/{chunk-K2IX6BEK.js → chunk-7YD3TRDX.js} +4 -4
- package/dist/{chunk-IF46G2LM.js → chunk-BB7KSLNA.js} +2 -2
- package/dist/{chunk-NEQJSYJH.js → chunk-COIZLMGV.js} +3 -3
- package/dist/{chunk-Z66EEQ4A.js → chunk-CURHM4TH.js} +3 -3
- package/dist/{chunk-FZV4YAYT.js → chunk-DFCC7FN4.js} +3 -3
- package/dist/{chunk-BZFF3YWU.js → chunk-GGYQTV2Y.js} +4 -4
- package/dist/{chunk-HNAFWKJG.js → chunk-GRWHPG72.js} +7 -7
- package/dist/{chunk-AWPSFL5C.js → chunk-GVNY4ZB6.js} +2 -2
- package/dist/{chunk-YKTVN2TF.js → chunk-IFSIKGHI.js} +2 -2
- package/dist/{chunk-LRBEUBZ3.js → chunk-JKUX73VD.js} +3 -3
- package/dist/{chunk-I7OZP6FS.js → chunk-KM3YEIEN.js} +4 -4
- package/dist/{chunk-THI3VWHO.js → chunk-O6VL6LA4.js} +2 -2
- package/dist/{chunk-6LXTT6AK.js → chunk-PC4Y4VPX.js} +2 -2
- package/dist/{chunk-PXTZ6RPP.js → chunk-QLZDOEO4.js} +7 -7
- package/dist/{chunk-DMFMJFRY.js → chunk-QPSYBHK6.js} +2 -2
- package/dist/{chunk-BFDVV3Q3.js → chunk-QV52AXTF.js} +2 -2
- package/dist/chunk-QZUG667L.js +56 -0
- package/dist/chunk-QZUG667L.js.map +1 -0
- package/dist/{chunk-JYVPM37A.js → chunk-RKIPSMCN.js} +5 -5
- package/dist/{chunk-ZI4PO2A3.js → chunk-S6HCREYY.js} +12 -62
- package/dist/chunk-S6HCREYY.js.map +1 -0
- package/dist/{chunk-F2YZ3U6O.js → chunk-SRNAXDOT.js} +2 -2
- package/dist/{chunk-V5RPW2ZX.js → chunk-STMW5BSR.js} +3 -3
- package/dist/{chunk-FQNG6ZIW.js → chunk-TGAVZ2ZL.js} +8 -8
- package/dist/{chunk-UWRDWX6L.js → chunk-UNIDAVVR.js} +2 -2
- package/dist/{chunk-UO6C5J5D.js → chunk-USBKBGT3.js} +5 -5
- package/dist/{chunk-OI6H3DL6.js → chunk-VGEVDF44.js} +4 -4
- package/dist/{chunk-76Q6GTPU.js → chunk-VNVGGM73.js} +2 -2
- package/dist/{chunk-FKHQWC2L.js → chunk-XUMLVCFL.js} +2 -2
- package/dist/{chunk-WL4SGKAW.js → chunk-ZAPCPHGZ.js} +2 -2
- package/dist/{chunk-PRSGZQNB.js → chunk-ZIC6ZZFU.js} +3 -3
- package/dist/{chunk-WOY6TQCH.js → chunk-ZSUN7BHE.js} +439 -12
- package/dist/chunk-ZSUN7BHE.js.map +1 -0
- package/dist/{chunk-3LVB5OE2.js → chunk-ZTTUXPBQ.js} +2 -2
- package/dist/{chunk-JBH4CU46.js → chunk-ZTWKSN5K.js} +34 -34
- package/dist/{cli-circuit-breaker-FSUDU7BV.js → cli-circuit-breaker-2AAHSCHR.js} +4 -4
- package/dist/cli.js +42 -41
- package/dist/cli.js.map +1 -1
- package/dist/{composite-router-HC4YLG5W.js → composite-router-WOVGICBS.js} +2 -2
- package/dist/{consensus-vote-KWPS6WNH.js → consensus-vote-322S65GQ.js} +16 -15
- package/dist/{context-retriever-YCKTCDGM.js → context-retriever-YMJY6YBJ.js} +9 -8
- package/dist/{doctor-deep-4UARVVSD.js → doctor-deep-DALT3OXC.js} +3 -3
- package/dist/{expert-bridge-EAR6XZJA.js → expert-bridge-WNV3ST2T.js} +4 -4
- package/dist/factory-33HQYVCK.js +23 -0
- package/dist/{factory-7SVW7XMV.js → factory-TLSTFONW.js} +5 -5
- package/dist/{improvement-review-AHSY5ZXD.js → improvement-review-2W6LKP74.js} +5 -5
- package/dist/index.js +38 -312
- package/dist/index.js.map +1 -1
- package/dist/{init-opencode-5BKE7UEB.js → init-opencode-I4FY4OGP.js} +6 -6
- package/dist/{issue-triage-TNV4R33I.js → issue-triage-CVMVZ3IV.js} +6 -6
- package/dist/{pr-reviewer-helpers-ZC2I5ZYD.js → pr-reviewer-helpers-SAMOVLNJ.js} +4 -4
- package/dist/{registry-command-O2GLHG3G.js → registry-command-5D2DJT53.js} +2 -2
- package/dist/{repo-security-plan-CFRLHIMY.js → repo-security-plan-F7V5SHAQ.js} +3 -3
- package/dist/{research-helpers-synthesize-ONWBGXHO.js → research-helpers-synthesize-F4PV4B4B.js} +4 -4
- package/dist/{routing-memory-XHZKEPUH.js → routing-memory-G6YBK4WI.js} +2 -2
- package/dist/{session-memory-5QVKDE4U.js → session-memory-DAJHLPOY.js} +3 -3
- package/dist/{setup-command-G7OB4QQG.js → setup-command-S4AOTSY5.js} +12 -11
- package/dist/{setup-config-MMBOL5CW.js → setup-config-HKUWFV5N.js} +3 -3
- package/dist/{setup-custom-api-RQ3BUMJC.js → setup-custom-api-XRUPWEPF.js} +3 -3
- package/dist/{tool-memory-VK4IZLPN.js → tool-memory-XJ5VRMNQ.js} +5 -5
- package/dist/{unified-registry-ZOTGM4EY.js → unified-registry-ETKPTZBU.js} +10 -9
- package/dist/{weather-report-MPD66LKP.js → weather-report-TWBLIHPZ.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-WOY6TQCH.js.map +0 -1
- package/dist/chunk-ZI4PO2A3.js.map +0 -1
- package/dist/factory-JYAUOFEN.js +0 -22
- /package/dist/{child-mcp-config-AUA4TFBG.js.map → child-mcp-config-X4YLQKGK.js.map} +0 -0
- /package/dist/{chunk-P54BDACX.js.map → chunk-2NU774CB.js.map} +0 -0
- /package/dist/{chunk-ORRKK563.js.map → chunk-7K5LSUEU.js.map} +0 -0
- /package/dist/{chunk-GS3UPAUE.js.map → chunk-7USEQLMS.js.map} +0 -0
- /package/dist/{chunk-K2IX6BEK.js.map → chunk-7YD3TRDX.js.map} +0 -0
- /package/dist/{chunk-IF46G2LM.js.map → chunk-BB7KSLNA.js.map} +0 -0
- /package/dist/{chunk-NEQJSYJH.js.map → chunk-COIZLMGV.js.map} +0 -0
- /package/dist/{chunk-Z66EEQ4A.js.map → chunk-CURHM4TH.js.map} +0 -0
- /package/dist/{chunk-FZV4YAYT.js.map → chunk-DFCC7FN4.js.map} +0 -0
- /package/dist/{chunk-BZFF3YWU.js.map → chunk-GGYQTV2Y.js.map} +0 -0
- /package/dist/{chunk-HNAFWKJG.js.map → chunk-GRWHPG72.js.map} +0 -0
- /package/dist/{chunk-AWPSFL5C.js.map → chunk-GVNY4ZB6.js.map} +0 -0
- /package/dist/{chunk-YKTVN2TF.js.map → chunk-IFSIKGHI.js.map} +0 -0
- /package/dist/{chunk-LRBEUBZ3.js.map → chunk-JKUX73VD.js.map} +0 -0
- /package/dist/{chunk-I7OZP6FS.js.map → chunk-KM3YEIEN.js.map} +0 -0
- /package/dist/{chunk-THI3VWHO.js.map → chunk-O6VL6LA4.js.map} +0 -0
- /package/dist/{chunk-6LXTT6AK.js.map → chunk-PC4Y4VPX.js.map} +0 -0
- /package/dist/{chunk-PXTZ6RPP.js.map → chunk-QLZDOEO4.js.map} +0 -0
- /package/dist/{chunk-DMFMJFRY.js.map → chunk-QPSYBHK6.js.map} +0 -0
- /package/dist/{chunk-BFDVV3Q3.js.map → chunk-QV52AXTF.js.map} +0 -0
- /package/dist/{chunk-JYVPM37A.js.map → chunk-RKIPSMCN.js.map} +0 -0
- /package/dist/{chunk-F2YZ3U6O.js.map → chunk-SRNAXDOT.js.map} +0 -0
- /package/dist/{chunk-V5RPW2ZX.js.map → chunk-STMW5BSR.js.map} +0 -0
- /package/dist/{chunk-FQNG6ZIW.js.map → chunk-TGAVZ2ZL.js.map} +0 -0
- /package/dist/{chunk-UWRDWX6L.js.map → chunk-UNIDAVVR.js.map} +0 -0
- /package/dist/{chunk-UO6C5J5D.js.map → chunk-USBKBGT3.js.map} +0 -0
- /package/dist/{chunk-OI6H3DL6.js.map → chunk-VGEVDF44.js.map} +0 -0
- /package/dist/{chunk-76Q6GTPU.js.map → chunk-VNVGGM73.js.map} +0 -0
- /package/dist/{chunk-FKHQWC2L.js.map → chunk-XUMLVCFL.js.map} +0 -0
- /package/dist/{chunk-WL4SGKAW.js.map → chunk-ZAPCPHGZ.js.map} +0 -0
- /package/dist/{chunk-PRSGZQNB.js.map → chunk-ZIC6ZZFU.js.map} +0 -0
- /package/dist/{chunk-3LVB5OE2.js.map → chunk-ZTTUXPBQ.js.map} +0 -0
- /package/dist/{chunk-JBH4CU46.js.map → chunk-ZTWKSN5K.js.map} +0 -0
- /package/dist/{cli-circuit-breaker-FSUDU7BV.js.map → cli-circuit-breaker-2AAHSCHR.js.map} +0 -0
- /package/dist/{composite-router-HC4YLG5W.js.map → composite-router-WOVGICBS.js.map} +0 -0
- /package/dist/{consensus-vote-KWPS6WNH.js.map → consensus-vote-322S65GQ.js.map} +0 -0
- /package/dist/{context-retriever-YCKTCDGM.js.map → context-retriever-YMJY6YBJ.js.map} +0 -0
- /package/dist/{doctor-deep-4UARVVSD.js.map → doctor-deep-DALT3OXC.js.map} +0 -0
- /package/dist/{expert-bridge-EAR6XZJA.js.map → expert-bridge-WNV3ST2T.js.map} +0 -0
- /package/dist/{factory-7SVW7XMV.js.map → factory-33HQYVCK.js.map} +0 -0
- /package/dist/{factory-JYAUOFEN.js.map → factory-TLSTFONW.js.map} +0 -0
- /package/dist/{improvement-review-AHSY5ZXD.js.map → improvement-review-2W6LKP74.js.map} +0 -0
- /package/dist/{init-opencode-5BKE7UEB.js.map → init-opencode-I4FY4OGP.js.map} +0 -0
- /package/dist/{issue-triage-TNV4R33I.js.map → issue-triage-CVMVZ3IV.js.map} +0 -0
- /package/dist/{pr-reviewer-helpers-ZC2I5ZYD.js.map → pr-reviewer-helpers-SAMOVLNJ.js.map} +0 -0
- /package/dist/{registry-command-O2GLHG3G.js.map → registry-command-5D2DJT53.js.map} +0 -0
- /package/dist/{repo-security-plan-CFRLHIMY.js.map → repo-security-plan-F7V5SHAQ.js.map} +0 -0
- /package/dist/{research-helpers-synthesize-ONWBGXHO.js.map → research-helpers-synthesize-F4PV4B4B.js.map} +0 -0
- /package/dist/{routing-memory-XHZKEPUH.js.map → routing-memory-G6YBK4WI.js.map} +0 -0
- /package/dist/{session-memory-5QVKDE4U.js.map → session-memory-DAJHLPOY.js.map} +0 -0
- /package/dist/{setup-command-G7OB4QQG.js.map → setup-command-S4AOTSY5.js.map} +0 -0
- /package/dist/{setup-config-MMBOL5CW.js.map → setup-config-HKUWFV5N.js.map} +0 -0
- /package/dist/{setup-custom-api-RQ3BUMJC.js.map → setup-custom-api-XRUPWEPF.js.map} +0 -0
- /package/dist/{tool-memory-VK4IZLPN.js.map → tool-memory-XJ5VRMNQ.js.map} +0 -0
- /package/dist/{unified-registry-ZOTGM4EY.js.map → unified-registry-ETKPTZBU.js.map} +0 -0
- /package/dist/{weather-report-MPD66LKP.js.map → weather-report-TWBLIHPZ.js.map} +0 -0
|
@@ -1,37 +1,50 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveToken
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-UNIDAVVR.js";
|
|
4
4
|
import {
|
|
5
5
|
REGISTRY_PATH,
|
|
6
6
|
getProjectRoot,
|
|
7
7
|
loadPapersRegistry,
|
|
8
8
|
loadTechniquesRegistry,
|
|
9
9
|
savePapersRegistry
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PC4Y4VPX.js";
|
|
11
11
|
import {
|
|
12
12
|
resolveInsideRoot
|
|
13
13
|
} from "./chunk-NUBSJGQZ.js";
|
|
14
14
|
import {
|
|
15
15
|
getToolMemory
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-KM3YEIEN.js";
|
|
17
17
|
import {
|
|
18
18
|
capitalizeWords
|
|
19
19
|
} from "./chunk-6T3EPABN.js";
|
|
20
|
+
import {
|
|
21
|
+
extractSystemPrompt,
|
|
22
|
+
generateCacheKey,
|
|
23
|
+
messagesToAnthropicFormat
|
|
24
|
+
} from "./chunk-QZUG667L.js";
|
|
20
25
|
import {
|
|
21
26
|
API_TIMEOUTS,
|
|
22
27
|
CLI_NAMES,
|
|
23
28
|
CLI_SUBPROCESS_TIMEOUTS,
|
|
29
|
+
ErrorCode,
|
|
30
|
+
JsonlStore,
|
|
31
|
+
NexusError,
|
|
24
32
|
StrategyDistiller,
|
|
25
33
|
createLogger,
|
|
34
|
+
err,
|
|
26
35
|
getErrorMessage,
|
|
27
36
|
getOutcomeStore,
|
|
28
37
|
getTimeProvider,
|
|
38
|
+
ok,
|
|
29
39
|
registerPersistentDistillerFactory
|
|
30
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-CURHM4TH.js";
|
|
31
41
|
import {
|
|
32
42
|
ensureLearningDir,
|
|
33
43
|
getRulesFile
|
|
34
44
|
} from "./chunk-AXTD4TFK.js";
|
|
45
|
+
import {
|
|
46
|
+
nexusDataPath
|
|
47
|
+
} from "./chunk-DHVMSIT5.js";
|
|
35
48
|
|
|
36
49
|
// src/learning/strategy-distiller-persistence.ts
|
|
37
50
|
import { writeFileSync, readFileSync, renameSync, unlinkSync, existsSync } from "fs";
|
|
@@ -704,8 +717,8 @@ function parseArxivXml(arxivId, xml) {
|
|
|
704
717
|
function createArxivError(code, arxivId, message, cause) {
|
|
705
718
|
return { code, message, arxivId, cause };
|
|
706
719
|
}
|
|
707
|
-
function getErrorCodeFromException(
|
|
708
|
-
if (
|
|
720
|
+
function getErrorCodeFromException(err2) {
|
|
721
|
+
if (err2 instanceof Error && err2.name === "TimeoutError") {
|
|
709
722
|
return "TIMEOUT";
|
|
710
723
|
}
|
|
711
724
|
return "NETWORK";
|
|
@@ -735,10 +748,10 @@ async function fetchArxivMetadataResult(arxivId) {
|
|
|
735
748
|
};
|
|
736
749
|
}
|
|
737
750
|
return { ok: true, value: metadata };
|
|
738
|
-
} catch (
|
|
739
|
-
const code = getErrorCodeFromException(
|
|
751
|
+
} catch (err2) {
|
|
752
|
+
const code = getErrorCodeFromException(err2);
|
|
740
753
|
const message = code === "TIMEOUT" ? `arXiv API request timed out after ${String(ARXIV_API_TIMEOUT_MS / 1e3)} seconds` : "Network error while fetching from arXiv API";
|
|
741
|
-
return { ok: false, error: createArxivError(code, arxivId, message,
|
|
754
|
+
return { ok: false, error: createArxivError(code, arxivId, message, err2) };
|
|
742
755
|
}
|
|
743
756
|
}
|
|
744
757
|
async function paperExists(arxivId) {
|
|
@@ -2421,6 +2434,403 @@ function clamp01(n) {
|
|
|
2421
2434
|
return Math.min(1, Math.max(0, n));
|
|
2422
2435
|
}
|
|
2423
2436
|
|
|
2437
|
+
// src/context/token-counter.ts
|
|
2438
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
2439
|
+
import { GoogleGenAI } from "@google/genai";
|
|
2440
|
+
import { encoding_for_model } from "tiktoken";
|
|
2441
|
+
|
|
2442
|
+
// src/context/token-counter-types.ts
|
|
2443
|
+
var TokenCounterProvider = {
|
|
2444
|
+
ANTHROPIC: "anthropic",
|
|
2445
|
+
GEMINI: "gemini",
|
|
2446
|
+
OPENAI: "openai"
|
|
2447
|
+
};
|
|
2448
|
+
var TokenCountError = class extends NexusError {
|
|
2449
|
+
constructor(message, options) {
|
|
2450
|
+
super(message, { code: ErrorCode.MODEL_ERROR, ...options });
|
|
2451
|
+
this.name = "TokenCountError";
|
|
2452
|
+
}
|
|
2453
|
+
};
|
|
2454
|
+
var CHARS_PER_TOKEN2 = {
|
|
2455
|
+
anthropic: 3.5,
|
|
2456
|
+
// Claude models
|
|
2457
|
+
gemini: 4,
|
|
2458
|
+
// Gemini models
|
|
2459
|
+
openai: 4,
|
|
2460
|
+
// GPT models
|
|
2461
|
+
default: 4
|
|
2462
|
+
// Generic fallback
|
|
2463
|
+
};
|
|
2464
|
+
var DEFAULT_MAX_CACHE_SIZE = 1e3;
|
|
2465
|
+
var DEFAULT_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
2466
|
+
var DEFAULT_TIKTOKEN_MODEL = "gpt-4o";
|
|
2467
|
+
var TIKTOKEN_MODEL_MAP = {
|
|
2468
|
+
"gpt-4o": "gpt-4o",
|
|
2469
|
+
"gpt-4o-mini": "gpt-4o",
|
|
2470
|
+
"gpt-4-turbo": "gpt-4-turbo",
|
|
2471
|
+
"gpt-4": "gpt-4",
|
|
2472
|
+
"gpt-3.5-turbo": "gpt-3.5-turbo",
|
|
2473
|
+
o1: "o1",
|
|
2474
|
+
"o1-mini": "o1",
|
|
2475
|
+
"o1-preview": "o1"
|
|
2476
|
+
};
|
|
2477
|
+
|
|
2478
|
+
// src/context/token-counter.ts
|
|
2479
|
+
var TokenCounter = class {
|
|
2480
|
+
anthropicClient;
|
|
2481
|
+
geminiClient;
|
|
2482
|
+
cache;
|
|
2483
|
+
maxCacheSize;
|
|
2484
|
+
cacheTtlMs;
|
|
2485
|
+
tiktokenEncoder;
|
|
2486
|
+
currentTiktokenModel;
|
|
2487
|
+
/**
|
|
2488
|
+
* Creates a new TokenCounter instance.
|
|
2489
|
+
*
|
|
2490
|
+
* @param config - Token counter configuration
|
|
2491
|
+
*/
|
|
2492
|
+
constructor(config = {}) {
|
|
2493
|
+
this.maxCacheSize = config.maxCacheSize ?? DEFAULT_MAX_CACHE_SIZE;
|
|
2494
|
+
this.cacheTtlMs = config.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS;
|
|
2495
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
2496
|
+
if (config.anthropicApiKey !== void 0 && config.anthropicApiKey !== "") {
|
|
2497
|
+
this.anthropicClient = new Anthropic({ apiKey: config.anthropicApiKey });
|
|
2498
|
+
}
|
|
2499
|
+
if (config.googleApiKey !== void 0 && config.googleApiKey !== "") {
|
|
2500
|
+
this.geminiClient = new GoogleGenAI({ apiKey: config.googleApiKey });
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
/**
|
|
2504
|
+
* Count tokens for Anthropic/Claude models via API.
|
|
2505
|
+
*/
|
|
2506
|
+
async countAnthropic(messages, model) {
|
|
2507
|
+
const cacheKey = generateCacheKey(messages, TokenCounterProvider.ANTHROPIC, model);
|
|
2508
|
+
const cached = this.getCached(cacheKey);
|
|
2509
|
+
if (cached !== void 0) {
|
|
2510
|
+
return ok({ count: cached.count, cached: true, provider: cached.provider, model });
|
|
2511
|
+
}
|
|
2512
|
+
if (this.anthropicClient === void 0) {
|
|
2513
|
+
return err(
|
|
2514
|
+
new TokenCountError("Anthropic API key not configured", {
|
|
2515
|
+
context: { provider: "anthropic", model }
|
|
2516
|
+
})
|
|
2517
|
+
);
|
|
2518
|
+
}
|
|
2519
|
+
try {
|
|
2520
|
+
const anthropicMessages = messagesToAnthropicFormat(messages);
|
|
2521
|
+
const systemPrompt = extractSystemPrompt(messages);
|
|
2522
|
+
const params = {
|
|
2523
|
+
model,
|
|
2524
|
+
messages: anthropicMessages
|
|
2525
|
+
};
|
|
2526
|
+
if (systemPrompt !== void 0) {
|
|
2527
|
+
params.system = systemPrompt;
|
|
2528
|
+
}
|
|
2529
|
+
const response = await this.anthropicClient.messages.countTokens(params);
|
|
2530
|
+
const count = response.input_tokens;
|
|
2531
|
+
this.setCache(cacheKey, {
|
|
2532
|
+
count,
|
|
2533
|
+
provider: TokenCounterProvider.ANTHROPIC,
|
|
2534
|
+
model,
|
|
2535
|
+
timestamp: getTimeProvider().now()
|
|
2536
|
+
});
|
|
2537
|
+
return ok({ count, cached: false, provider: TokenCounterProvider.ANTHROPIC, model });
|
|
2538
|
+
} catch (error) {
|
|
2539
|
+
const cause = error instanceof Error ? error : new Error(String(error));
|
|
2540
|
+
return err(
|
|
2541
|
+
new TokenCountError(`Anthropic token counting failed: ${cause.message}`, {
|
|
2542
|
+
cause,
|
|
2543
|
+
context: { provider: "anthropic", model }
|
|
2544
|
+
})
|
|
2545
|
+
);
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
/**
|
|
2549
|
+
* Count tokens for Gemini models via API.
|
|
2550
|
+
*/
|
|
2551
|
+
async countGemini(content, model) {
|
|
2552
|
+
const cacheKey = generateCacheKey(content, TokenCounterProvider.GEMINI, model);
|
|
2553
|
+
const cached = this.getCached(cacheKey);
|
|
2554
|
+
if (cached !== void 0) {
|
|
2555
|
+
return ok({ count: cached.count, cached: true, provider: cached.provider, model });
|
|
2556
|
+
}
|
|
2557
|
+
if (this.geminiClient === void 0) {
|
|
2558
|
+
return err(
|
|
2559
|
+
new TokenCountError("Google API key not configured", {
|
|
2560
|
+
context: { provider: "gemini", model }
|
|
2561
|
+
})
|
|
2562
|
+
);
|
|
2563
|
+
}
|
|
2564
|
+
try {
|
|
2565
|
+
const response = await this.geminiClient.models.countTokens({
|
|
2566
|
+
model,
|
|
2567
|
+
contents: content
|
|
2568
|
+
});
|
|
2569
|
+
const count = response.totalTokens ?? 0;
|
|
2570
|
+
this.setCache(cacheKey, {
|
|
2571
|
+
count,
|
|
2572
|
+
provider: TokenCounterProvider.GEMINI,
|
|
2573
|
+
model,
|
|
2574
|
+
timestamp: getTimeProvider().now()
|
|
2575
|
+
});
|
|
2576
|
+
return ok({ count, cached: false, provider: TokenCounterProvider.GEMINI, model });
|
|
2577
|
+
} catch (error) {
|
|
2578
|
+
const cause = error instanceof Error ? error : new Error(String(error));
|
|
2579
|
+
return err(
|
|
2580
|
+
new TokenCountError(`Gemini token counting failed: ${cause.message}`, {
|
|
2581
|
+
cause,
|
|
2582
|
+
context: { provider: "gemini", model }
|
|
2583
|
+
})
|
|
2584
|
+
);
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
/**
|
|
2588
|
+
* Count tokens for OpenAI models using local tiktoken.
|
|
2589
|
+
*/
|
|
2590
|
+
countOpenAI(text, model = DEFAULT_TIKTOKEN_MODEL) {
|
|
2591
|
+
const cacheKey = generateCacheKey(text, TokenCounterProvider.OPENAI, model);
|
|
2592
|
+
const cached = this.getCached(cacheKey);
|
|
2593
|
+
if (cached !== void 0) {
|
|
2594
|
+
return ok({ count: cached.count, cached: true, provider: cached.provider, model });
|
|
2595
|
+
}
|
|
2596
|
+
try {
|
|
2597
|
+
const encoder = this.getOrCreateTiktokenEncoder(model);
|
|
2598
|
+
const tokens = encoder.encode(text);
|
|
2599
|
+
const count = tokens.length;
|
|
2600
|
+
this.setCache(cacheKey, {
|
|
2601
|
+
count,
|
|
2602
|
+
provider: TokenCounterProvider.OPENAI,
|
|
2603
|
+
model,
|
|
2604
|
+
timestamp: getTimeProvider().now()
|
|
2605
|
+
});
|
|
2606
|
+
return ok({ count, cached: false, provider: TokenCounterProvider.OPENAI, model });
|
|
2607
|
+
} catch (error) {
|
|
2608
|
+
const cause = error instanceof Error ? error : new Error(String(error));
|
|
2609
|
+
return err(
|
|
2610
|
+
new TokenCountError(`OpenAI token counting failed: ${cause.message}`, {
|
|
2611
|
+
cause,
|
|
2612
|
+
context: { provider: "openai", model }
|
|
2613
|
+
})
|
|
2614
|
+
);
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
/**
|
|
2618
|
+
* Estimate tokens offline using character-based heuristic.
|
|
2619
|
+
* Uses ~4 characters per token as a general approximation.
|
|
2620
|
+
*/
|
|
2621
|
+
estimate(text) {
|
|
2622
|
+
if (text.length === 0) {
|
|
2623
|
+
return 0;
|
|
2624
|
+
}
|
|
2625
|
+
return Math.ceil(text.length / CHARS_PER_TOKEN2.default);
|
|
2626
|
+
}
|
|
2627
|
+
/**
|
|
2628
|
+
* Estimate tokens for a specific provider.
|
|
2629
|
+
*/
|
|
2630
|
+
estimateForProvider(text, provider) {
|
|
2631
|
+
if (text.length === 0) {
|
|
2632
|
+
return 0;
|
|
2633
|
+
}
|
|
2634
|
+
const charsPerToken = CHARS_PER_TOKEN2[provider];
|
|
2635
|
+
return Math.ceil(text.length / charsPerToken);
|
|
2636
|
+
}
|
|
2637
|
+
/**
|
|
2638
|
+
* Clear the token count cache.
|
|
2639
|
+
*/
|
|
2640
|
+
clearCache() {
|
|
2641
|
+
this.cache.clear();
|
|
2642
|
+
}
|
|
2643
|
+
/**
|
|
2644
|
+
* Get current cache statistics.
|
|
2645
|
+
*/
|
|
2646
|
+
getCacheStats() {
|
|
2647
|
+
return {
|
|
2648
|
+
size: this.cache.size,
|
|
2649
|
+
maxSize: this.maxCacheSize,
|
|
2650
|
+
ttlMs: this.cacheTtlMs
|
|
2651
|
+
};
|
|
2652
|
+
}
|
|
2653
|
+
/**
|
|
2654
|
+
* Gets or creates a tiktoken encoder for the specified model.
|
|
2655
|
+
*/
|
|
2656
|
+
getOrCreateTiktokenEncoder(model) {
|
|
2657
|
+
const tiktokenModel = TIKTOKEN_MODEL_MAP[model] ?? DEFAULT_TIKTOKEN_MODEL;
|
|
2658
|
+
if (this.tiktokenEncoder !== void 0 && this.currentTiktokenModel === tiktokenModel) {
|
|
2659
|
+
return this.tiktokenEncoder;
|
|
2660
|
+
}
|
|
2661
|
+
if (this.tiktokenEncoder !== void 0) {
|
|
2662
|
+
this.tiktokenEncoder.free();
|
|
2663
|
+
}
|
|
2664
|
+
this.tiktokenEncoder = encoding_for_model(
|
|
2665
|
+
tiktokenModel
|
|
2666
|
+
);
|
|
2667
|
+
this.currentTiktokenModel = tiktokenModel;
|
|
2668
|
+
return this.tiktokenEncoder;
|
|
2669
|
+
}
|
|
2670
|
+
/**
|
|
2671
|
+
* Gets a cached entry if valid.
|
|
2672
|
+
*/
|
|
2673
|
+
getCached(key) {
|
|
2674
|
+
const entry = this.cache.get(key);
|
|
2675
|
+
if (entry === void 0) {
|
|
2676
|
+
return void 0;
|
|
2677
|
+
}
|
|
2678
|
+
if (getTimeProvider().now() - entry.timestamp > this.cacheTtlMs) {
|
|
2679
|
+
this.cache.delete(key);
|
|
2680
|
+
return void 0;
|
|
2681
|
+
}
|
|
2682
|
+
return entry;
|
|
2683
|
+
}
|
|
2684
|
+
/**
|
|
2685
|
+
* Sets a cache entry, evicting oldest if at capacity.
|
|
2686
|
+
*/
|
|
2687
|
+
setCache(key, entry) {
|
|
2688
|
+
if (this.cache.size >= this.maxCacheSize) {
|
|
2689
|
+
const firstKey = this.cache.keys().next();
|
|
2690
|
+
if (firstKey.done !== true) {
|
|
2691
|
+
this.cache.delete(firstKey.value);
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
this.cache.set(key, entry);
|
|
2695
|
+
}
|
|
2696
|
+
/**
|
|
2697
|
+
* Frees resources (tiktoken encoder).
|
|
2698
|
+
* Call this when done with the counter.
|
|
2699
|
+
*/
|
|
2700
|
+
dispose() {
|
|
2701
|
+
if (this.tiktokenEncoder !== void 0) {
|
|
2702
|
+
this.tiktokenEncoder.free();
|
|
2703
|
+
this.tiktokenEncoder = void 0;
|
|
2704
|
+
this.currentTiktokenModel = void 0;
|
|
2705
|
+
}
|
|
2706
|
+
this.cache.clear();
|
|
2707
|
+
}
|
|
2708
|
+
};
|
|
2709
|
+
function createTokenCounter(config = {}) {
|
|
2710
|
+
return new TokenCounter(config);
|
|
2711
|
+
}
|
|
2712
|
+
|
|
2713
|
+
// src/context/token-ledger.ts
|
|
2714
|
+
import { z as z5 } from "zod";
|
|
2715
|
+
var TokenLedgerEventSchema = z5.object({
|
|
2716
|
+
/** Schema version. Forward-compat for on-disk evolution. */
|
|
2717
|
+
v: z5.literal(1),
|
|
2718
|
+
/** ISO-8601 timestamp of the call. */
|
|
2719
|
+
ts: z5.iso.datetime(),
|
|
2720
|
+
/** Tool/call-site identifier (e.g. an MCP tool name or module.function). */
|
|
2721
|
+
tool: z5.string().min(1).max(200),
|
|
2722
|
+
/** Context-source classification. See {@link CONTEXT_SOURCE_TAGS}. */
|
|
2723
|
+
contextSource: z5.string().min(1).max(64),
|
|
2724
|
+
/** Input tokens attributed to this call/source. */
|
|
2725
|
+
inputTokens: z5.number().nonnegative(),
|
|
2726
|
+
/** Output tokens attributed to this call. `0` when the call is context-only. */
|
|
2727
|
+
outputTokens: z5.number().nonnegative(),
|
|
2728
|
+
/** Model identifier, when the calling surface exposes one. */
|
|
2729
|
+
model: z5.string().min(1).max(200).optional(),
|
|
2730
|
+
/** Task/operation identifier, mirroring {@link TokenUsageRecord.taskId}. */
|
|
2731
|
+
taskId: z5.string().min(1).max(200).optional(),
|
|
2732
|
+
/**
|
|
2733
|
+
* Free-form call-site variant (e.g. `'ranked' | 'legacy'` for the
|
|
2734
|
+
* `context-retriever.ts` rendering path, #4252 wiring). Optional dimension
|
|
2735
|
+
* so producers that have no variant to report don't need a placeholder.
|
|
2736
|
+
*/
|
|
2737
|
+
variant: z5.string().min(1).max(100).optional()
|
|
2738
|
+
});
|
|
2739
|
+
var DEFAULT_MAX_EVENTS = 5e4;
|
|
2740
|
+
var LEDGER_SUBDIR = "token-ledger";
|
|
2741
|
+
var LEDGER_FILE = "ledger.jsonl";
|
|
2742
|
+
var TokenLedger = class {
|
|
2743
|
+
store;
|
|
2744
|
+
constructor(config) {
|
|
2745
|
+
this.store = new JsonlStore({
|
|
2746
|
+
filePath: config?.filePath ?? nexusDataPath(LEDGER_SUBDIR, LEDGER_FILE),
|
|
2747
|
+
schema: TokenLedgerEventSchema,
|
|
2748
|
+
maxRecords: config?.maxEvents ?? DEFAULT_MAX_EVENTS,
|
|
2749
|
+
component: "TokenLedger"
|
|
2750
|
+
});
|
|
2751
|
+
}
|
|
2752
|
+
/**
|
|
2753
|
+
* Record one call's token usage. `v`/`ts` are stamped here so callers pass
|
|
2754
|
+
* only the observed signal. Best-effort durability (inherited from
|
|
2755
|
+
* JsonlStore): never throws into the observed operation.
|
|
2756
|
+
*/
|
|
2757
|
+
record(event) {
|
|
2758
|
+
const record = {
|
|
2759
|
+
v: 1,
|
|
2760
|
+
ts: event.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
2761
|
+
tool: event.tool,
|
|
2762
|
+
contextSource: event.contextSource,
|
|
2763
|
+
inputTokens: event.inputTokens,
|
|
2764
|
+
outputTokens: event.outputTokens ?? 0,
|
|
2765
|
+
...event.model !== void 0 ? { model: event.model } : {},
|
|
2766
|
+
...event.taskId !== void 0 ? { taskId: event.taskId } : {},
|
|
2767
|
+
...event.variant !== void 0 ? { variant: event.variant } : {}
|
|
2768
|
+
};
|
|
2769
|
+
this.store.append(record);
|
|
2770
|
+
}
|
|
2771
|
+
/** Total retained events. */
|
|
2772
|
+
size() {
|
|
2773
|
+
return this.store.count();
|
|
2774
|
+
}
|
|
2775
|
+
/** All retained events, oldest first. Mainly for tests/inspection. */
|
|
2776
|
+
all() {
|
|
2777
|
+
return this.store.all();
|
|
2778
|
+
}
|
|
2779
|
+
/**
|
|
2780
|
+
* Aggregate totals by `contextSource` tag and by `tool`, optionally
|
|
2781
|
+
* restricted to a time window (#4252 query surface). Pure over the current
|
|
2782
|
+
* retained event set — no I/O.
|
|
2783
|
+
*
|
|
2784
|
+
* Manual before/after comparison (the #4251 A/B measurement need) is
|
|
2785
|
+
* possible today by calling this twice with windows that bracket a change,
|
|
2786
|
+
* e.g. `summarize({ untilMs: deployedAt })` vs.
|
|
2787
|
+
* `summarize({ sinceMs: deployedAt })`. A dedicated harness that fixes a
|
|
2788
|
+
* task sample and runs it under two configurations is deliberately out of
|
|
2789
|
+
* scope here — tracked as a follow-up under epic #4251.
|
|
2790
|
+
*/
|
|
2791
|
+
summarize(window = {}) {
|
|
2792
|
+
const events = this.store.all().filter((e) => withinWindow(e.ts, window));
|
|
2793
|
+
return aggregateEvents(events);
|
|
2794
|
+
}
|
|
2795
|
+
};
|
|
2796
|
+
function withinWindow(ts, window) {
|
|
2797
|
+
const t = Date.parse(ts);
|
|
2798
|
+
if (window.sinceMs !== void 0 && t < window.sinceMs) return false;
|
|
2799
|
+
if (window.untilMs !== void 0 && t >= window.untilMs) return false;
|
|
2800
|
+
return true;
|
|
2801
|
+
}
|
|
2802
|
+
function emptyAggregate() {
|
|
2803
|
+
return { entries: 0, inputTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
2804
|
+
}
|
|
2805
|
+
function addEvent(agg, e) {
|
|
2806
|
+
return {
|
|
2807
|
+
entries: agg.entries + 1,
|
|
2808
|
+
inputTokens: agg.inputTokens + e.inputTokens,
|
|
2809
|
+
outputTokens: agg.outputTokens + e.outputTokens,
|
|
2810
|
+
totalTokens: agg.totalTokens + e.inputTokens + e.outputTokens
|
|
2811
|
+
};
|
|
2812
|
+
}
|
|
2813
|
+
function aggregateEvents(events) {
|
|
2814
|
+
let overall = emptyAggregate();
|
|
2815
|
+
const bySource = /* @__PURE__ */ new Map();
|
|
2816
|
+
const byTool = /* @__PURE__ */ new Map();
|
|
2817
|
+
for (const e of events) {
|
|
2818
|
+
overall = addEvent(overall, e);
|
|
2819
|
+
bySource.set(e.contextSource, addEvent(bySource.get(e.contextSource) ?? emptyAggregate(), e));
|
|
2820
|
+
byTool.set(e.tool, addEvent(byTool.get(e.tool) ?? emptyAggregate(), e));
|
|
2821
|
+
}
|
|
2822
|
+
return {
|
|
2823
|
+
overall,
|
|
2824
|
+
bySource: Object.fromEntries(bySource),
|
|
2825
|
+
byTool: Object.fromEntries(byTool)
|
|
2826
|
+
};
|
|
2827
|
+
}
|
|
2828
|
+
var singleton;
|
|
2829
|
+
function getTokenLedger() {
|
|
2830
|
+
singleton ??= new TokenLedger();
|
|
2831
|
+
return singleton;
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2424
2834
|
// src/context/context-retriever.ts
|
|
2425
2835
|
var DEFAULT_LIMIT = 5;
|
|
2426
2836
|
async function getContextForTask(options) {
|
|
@@ -2580,8 +2990,21 @@ function oneLine2(value) {
|
|
|
2580
2990
|
return value.replace(/\s+/g, " ").trim().slice(0, MAX_SUMMARY_FIELD);
|
|
2581
2991
|
}
|
|
2582
2992
|
function summarizeContextForPrompt(ctx, budgetTokens = DEFAULT_CONTEXT_BUDGET_TOKENS) {
|
|
2583
|
-
const
|
|
2584
|
-
|
|
2993
|
+
const ranked = process.env[CONTEXT_RANKED_FLAG] === "1";
|
|
2994
|
+
const rendered = ranked ? summarizeRankedContext(ctx) : summarizeLegacyContext(ctx);
|
|
2995
|
+
const clamped = clampRenderedContext(rendered, budgetTokens);
|
|
2996
|
+
recordAssembledContextTokens(clamped, ranked);
|
|
2997
|
+
return clamped;
|
|
2998
|
+
}
|
|
2999
|
+
var contextTokenCounter = createTokenCounter();
|
|
3000
|
+
function recordAssembledContextTokens(rendered, ranked) {
|
|
3001
|
+
if (rendered === "") return;
|
|
3002
|
+
getTokenLedger().record({
|
|
3003
|
+
tool: "context-retriever.summarizeContextForPrompt",
|
|
3004
|
+
contextSource: "memory-backend",
|
|
3005
|
+
inputTokens: contextTokenCounter.estimate(rendered),
|
|
3006
|
+
variant: ranked ? "ranked" : "legacy"
|
|
3007
|
+
});
|
|
2585
3008
|
}
|
|
2586
3009
|
var DEFAULT_CONTEXT_BUDGET_TOKENS = 2500;
|
|
2587
3010
|
var CLIP_NOTICE_RESERVE_TOKENS = 30;
|
|
@@ -2702,6 +3125,10 @@ export {
|
|
|
2702
3125
|
handleCheckCommand,
|
|
2703
3126
|
formatResearchIssueBody,
|
|
2704
3127
|
createResearchIssue,
|
|
3128
|
+
TokenCounterProvider,
|
|
3129
|
+
TokenCountError,
|
|
3130
|
+
TokenCounter,
|
|
3131
|
+
createTokenCounter,
|
|
2705
3132
|
getContextForTask,
|
|
2706
3133
|
selectRelevantResearch,
|
|
2707
3134
|
getResearchInsightsForTask,
|
|
@@ -2710,4 +3137,4 @@ export {
|
|
|
2710
3137
|
DEFAULT_CONTEXT_BUDGET_TOKENS,
|
|
2711
3138
|
getContextPromptPrefix
|
|
2712
3139
|
};
|
|
2713
|
-
//# sourceMappingURL=chunk-
|
|
3140
|
+
//# sourceMappingURL=chunk-ZSUN7BHE.js.map
|