ghagga-core 2.5.0 → 2.6.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.
Files changed (153) hide show
  1. package/README.md +1 -1
  2. package/dist/agents/consensus.d.ts +16 -0
  3. package/dist/agents/consensus.d.ts.map +1 -1
  4. package/dist/agents/consensus.js +57 -33
  5. package/dist/agents/consensus.js.map +1 -1
  6. package/dist/agents/diagnostic.d.ts +55 -0
  7. package/dist/agents/diagnostic.d.ts.map +1 -0
  8. package/dist/agents/diagnostic.js +143 -0
  9. package/dist/agents/diagnostic.js.map +1 -0
  10. package/dist/agents/prompts.d.ts +6 -4
  11. package/dist/agents/prompts.d.ts.map +1 -1
  12. package/dist/agents/prompts.js +110 -24
  13. package/dist/agents/prompts.js.map +1 -1
  14. package/dist/agents/simple.d.ts +7 -0
  15. package/dist/agents/simple.d.ts.map +1 -1
  16. package/dist/agents/simple.js +32 -18
  17. package/dist/agents/simple.js.map +1 -1
  18. package/dist/agents/workflow.d.ts +28 -1
  19. package/dist/agents/workflow.d.ts.map +1 -1
  20. package/dist/agents/workflow.js +112 -45
  21. package/dist/agents/workflow.js.map +1 -1
  22. package/dist/enhance/enhance.d.ts.map +1 -1
  23. package/dist/enhance/enhance.js +16 -4
  24. package/dist/enhance/enhance.js.map +1 -1
  25. package/dist/format.d.ts +47 -1
  26. package/dist/format.d.ts.map +1 -1
  27. package/dist/format.js +175 -3
  28. package/dist/format.js.map +1 -1
  29. package/dist/graph/blast-radius.d.ts +57 -0
  30. package/dist/graph/blast-radius.d.ts.map +1 -0
  31. package/dist/graph/blast-radius.js +145 -0
  32. package/dist/graph/blast-radius.js.map +1 -0
  33. package/dist/graph/builder.d.ts +50 -0
  34. package/dist/graph/builder.d.ts.map +1 -0
  35. package/dist/graph/builder.js +210 -0
  36. package/dist/graph/builder.js.map +1 -0
  37. package/dist/graph/extractors/go.d.ts +9 -0
  38. package/dist/graph/extractors/go.d.ts.map +1 -0
  39. package/dist/graph/extractors/go.js +78 -0
  40. package/dist/graph/extractors/go.js.map +1 -0
  41. package/dist/graph/extractors/index.d.ts +22 -0
  42. package/dist/graph/extractors/index.d.ts.map +1 -0
  43. package/dist/graph/extractors/index.js +37 -0
  44. package/dist/graph/extractors/index.js.map +1 -0
  45. package/dist/graph/extractors/java.d.ts +9 -0
  46. package/dist/graph/extractors/java.d.ts.map +1 -0
  47. package/dist/graph/extractors/java.js +80 -0
  48. package/dist/graph/extractors/java.js.map +1 -0
  49. package/dist/graph/extractors/javascript.d.ts +9 -0
  50. package/dist/graph/extractors/javascript.d.ts.map +1 -0
  51. package/dist/graph/extractors/javascript.js +204 -0
  52. package/dist/graph/extractors/javascript.js.map +1 -0
  53. package/dist/graph/extractors/python.d.ts +9 -0
  54. package/dist/graph/extractors/python.d.ts.map +1 -0
  55. package/dist/graph/extractors/python.js +103 -0
  56. package/dist/graph/extractors/python.js.map +1 -0
  57. package/dist/graph/extractors/rust.d.ts +9 -0
  58. package/dist/graph/extractors/rust.d.ts.map +1 -0
  59. package/dist/graph/extractors/rust.js +115 -0
  60. package/dist/graph/extractors/rust.js.map +1 -0
  61. package/dist/graph/extractors/types.d.ts +31 -0
  62. package/dist/graph/extractors/types.d.ts.map +1 -0
  63. package/dist/graph/extractors/types.js +9 -0
  64. package/dist/graph/extractors/types.js.map +1 -0
  65. package/dist/graph/extractors/typescript.d.ts +9 -0
  66. package/dist/graph/extractors/typescript.d.ts.map +1 -0
  67. package/dist/graph/extractors/typescript.js +151 -0
  68. package/dist/graph/extractors/typescript.js.map +1 -0
  69. package/dist/graph/index.d.ts +15 -0
  70. package/dist/graph/index.d.ts.map +1 -0
  71. package/dist/graph/index.js +14 -0
  72. package/dist/graph/index.js.map +1 -0
  73. package/dist/graph/loader.d.ts +43 -0
  74. package/dist/graph/loader.d.ts.map +1 -0
  75. package/dist/graph/loader.js +104 -0
  76. package/dist/graph/loader.js.map +1 -0
  77. package/dist/graph/schema.d.ts +113 -0
  78. package/dist/graph/schema.d.ts.map +1 -0
  79. package/dist/graph/schema.js +144 -0
  80. package/dist/graph/schema.js.map +1 -0
  81. package/dist/health/trends.js +1 -1
  82. package/dist/health/trends.js.map +1 -1
  83. package/dist/index.d.ts +20 -5
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +10 -4
  86. package/dist/index.js.map +1 -1
  87. package/dist/memory/sqlite.js +4 -4
  88. package/dist/memory/sqlite.js.map +1 -1
  89. package/dist/pipeline.d.ts.map +1 -1
  90. package/dist/pipeline.js +291 -42
  91. package/dist/pipeline.js.map +1 -1
  92. package/dist/providers/cli-bridge.d.ts +136 -0
  93. package/dist/providers/cli-bridge.d.ts.map +1 -0
  94. package/dist/providers/cli-bridge.js +457 -0
  95. package/dist/providers/cli-bridge.js.map +1 -0
  96. package/dist/providers/fallback.d.ts +8 -0
  97. package/dist/providers/fallback.d.ts.map +1 -1
  98. package/dist/providers/fallback.js +24 -8
  99. package/dist/providers/fallback.js.map +1 -1
  100. package/dist/providers/gateway.d.ts +40 -0
  101. package/dist/providers/gateway.d.ts.map +1 -0
  102. package/dist/providers/gateway.js +52 -0
  103. package/dist/providers/gateway.js.map +1 -0
  104. package/dist/providers/generate-fn.d.ts +62 -0
  105. package/dist/providers/generate-fn.d.ts.map +1 -0
  106. package/dist/providers/generate-fn.js +84 -0
  107. package/dist/providers/generate-fn.js.map +1 -0
  108. package/dist/providers/index.d.ts +5 -0
  109. package/dist/providers/index.d.ts.map +1 -1
  110. package/dist/providers/index.js +53 -0
  111. package/dist/providers/index.js.map +1 -1
  112. package/dist/tools/plugins/index.d.ts +2 -0
  113. package/dist/tools/plugins/index.d.ts.map +1 -1
  114. package/dist/tools/plugins/index.js +7 -0
  115. package/dist/tools/plugins/index.js.map +1 -1
  116. package/dist/tools/plugins/zizmor.d.ts +22 -0
  117. package/dist/tools/plugins/zizmor.d.ts.map +1 -0
  118. package/dist/tools/plugins/zizmor.js +112 -0
  119. package/dist/tools/plugins/zizmor.js.map +1 -0
  120. package/dist/tools/resolve.js +1 -1
  121. package/dist/tools/resolve.js.map +1 -1
  122. package/dist/tools/types.d.ts +1 -1
  123. package/dist/tools/types.d.ts.map +1 -1
  124. package/dist/types.d.ts +54 -3
  125. package/dist/types.d.ts.map +1 -1
  126. package/dist/types.js +21 -1
  127. package/dist/types.js.map +1 -1
  128. package/dist/utils/concurrency.d.ts +29 -0
  129. package/dist/utils/concurrency.d.ts.map +1 -0
  130. package/dist/utils/concurrency.js +40 -0
  131. package/dist/utils/concurrency.js.map +1 -0
  132. package/dist/utils/context-levels.d.ts +113 -0
  133. package/dist/utils/context-levels.d.ts.map +1 -0
  134. package/dist/utils/context-levels.js +255 -0
  135. package/dist/utils/context-levels.js.map +1 -0
  136. package/dist/utils/diff.d.ts +25 -0
  137. package/dist/utils/diff.d.ts.map +1 -1
  138. package/dist/utils/diff.js +28 -0
  139. package/dist/utils/diff.js.map +1 -1
  140. package/dist/utils/llm-timeout.d.ts +38 -0
  141. package/dist/utils/llm-timeout.d.ts.map +1 -0
  142. package/dist/utils/llm-timeout.js +76 -0
  143. package/dist/utils/llm-timeout.js.map +1 -0
  144. package/dist/utils/path-protection.d.ts +59 -0
  145. package/dist/utils/path-protection.d.ts.map +1 -0
  146. package/dist/utils/path-protection.js +136 -0
  147. package/dist/utils/path-protection.js.map +1 -0
  148. package/dist/utils/token-budget.d.ts +34 -1
  149. package/dist/utils/token-budget.d.ts.map +1 -1
  150. package/dist/utils/token-budget.js +108 -3
  151. package/dist/utils/token-budget.js.map +1 -1
  152. package/package.json +21 -19
  153. package/LICENSE +0 -21
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Three-tier path protection for sensitive files.
3
+ *
4
+ * Provides a non-overridable security layer that filters sensitive files
5
+ * BEFORE user-configurable ignorePatterns are applied. This ensures that
6
+ * secrets, credentials, and private keys are never sent to the LLM for review.
7
+ *
8
+ * Tiers:
9
+ * 1. ZERO_ACCESS — hardcoded, content never sent to LLM, non-overridable
10
+ * 2. REDACT — content replaced with redaction notice, path still visible
11
+ * 3. User ignore — existing configurable ignorePatterns (handled in diff.ts)
12
+ */
13
+ import { minimatch } from 'minimatch';
14
+ // ─── Constants ──────────────────────────────────────────────────
15
+ /** Redaction notice used to replace content of REDACT-tier files. */
16
+ export const REDACTED_CONTENT = '[REDACTED — sensitive file detected by GHAGGA path protection]';
17
+ /**
18
+ * Tier 1 — ZERO_ACCESS patterns.
19
+ *
20
+ * Files matching these patterns are completely blocked from the review
21
+ * pipeline. Their content is never sent to the LLM. These patterns are
22
+ * hardcoded and cannot be overridden by user configuration.
23
+ */
24
+ export const ZERO_ACCESS_PATTERNS = [
25
+ // Environment files
26
+ '.env',
27
+ '.env.*',
28
+ // Private keys and certificates
29
+ '*.pem',
30
+ '*.key',
31
+ '*.p12',
32
+ '*.pfx',
33
+ '*.jks',
34
+ '*.keystore',
35
+ // SSH keys
36
+ 'id_rsa',
37
+ 'id_ed25519',
38
+ 'id_ecdsa',
39
+ '*.pub',
40
+ // Cloud credentials
41
+ 'credentials.json',
42
+ 'service-account*.json',
43
+ 'gcloud*.json',
44
+ // Package manager credentials
45
+ '.npmrc',
46
+ '.pypirc',
47
+ '.gem/credentials',
48
+ // Container and cluster configs
49
+ '.docker/config.json',
50
+ 'kubeconfig',
51
+ 'kube/config',
52
+ // Directory-level patterns
53
+ '**/.aws/*',
54
+ '**/.ssh/*',
55
+ '**/.gnupg/*',
56
+ // Generic secrets
57
+ '*.secret',
58
+ '*.secrets',
59
+ 'secrets.yml',
60
+ 'secrets.yaml',
61
+ 'vault.yml',
62
+ ];
63
+ /**
64
+ * Tier 2 — REDACT patterns.
65
+ *
66
+ * Files matching these patterns have their content replaced with a
67
+ * redaction notice. The file path is still visible in the review so
68
+ * reviewers know the file was changed, but the actual content is not
69
+ * sent to the LLM.
70
+ */
71
+ export const REDACT_PATTERNS = [
72
+ // Environment templates (may leak structure)
73
+ '.env.example',
74
+ '.env.sample',
75
+ '.env.template',
76
+ // Docker Compose (may contain credentials in environment blocks)
77
+ 'docker-compose*.yml',
78
+ // Terraform state and variables (may contain secrets)
79
+ '**/terraform.tfvars',
80
+ '**/terraform.tfstate*',
81
+ ];
82
+ // ─── Matching Options ───────────────────────────────────────────
83
+ /** Minimatch options used for all path protection matching. */
84
+ const MATCH_OPTIONS = { dot: true, matchBase: true };
85
+ /**
86
+ * Apply three-tier path protection to a set of diff files.
87
+ *
88
+ * This function is pure and deterministic. It processes files in the
89
+ * following order:
90
+ * 1. Check against REDACT patterns first — these are specific exceptions
91
+ * (e.g., `.env.example`) that would otherwise be caught by broader
92
+ * ZERO_ACCESS globs (e.g., `.env.*`). Content is replaced.
93
+ * 2. Check against ZERO_ACCESS patterns — block entirely
94
+ * 3. Everything else passes through untouched
95
+ *
96
+ * @param files - Array of DiffFile objects from the parsed diff
97
+ * @returns Object with allowed, redacted, and blocked files
98
+ */
99
+ export function applyPathProtection(files) {
100
+ const allowed = [];
101
+ const redacted = [];
102
+ const blocked = [];
103
+ for (const file of files) {
104
+ if (matchesAnyPattern(file.path, REDACT_PATTERNS)) {
105
+ // Tier 2: REDACT — checked first because REDACT patterns are more
106
+ // specific exceptions (e.g. .env.example) that would otherwise be
107
+ // caught by broader ZERO_ACCESS globs (e.g. .env.*)
108
+ redacted.push({
109
+ path: file.path,
110
+ additions: file.additions,
111
+ deletions: file.deletions,
112
+ content: REDACTED_CONTENT,
113
+ });
114
+ }
115
+ else if (matchesAnyPattern(file.path, ZERO_ACCESS_PATTERNS)) {
116
+ // Tier 1: ZERO_ACCESS — broad security patterns
117
+ blocked.push(file.path);
118
+ }
119
+ else {
120
+ allowed.push(file);
121
+ }
122
+ }
123
+ return { allowed, redacted, blocked };
124
+ }
125
+ // ─── Internal Helpers ───────────────────────────────────────────
126
+ /**
127
+ * Check if a file path matches any of the given glob patterns.
128
+ *
129
+ * Uses minimatch with `{ dot: true, matchBase: true }` to ensure:
130
+ * - Dotfiles are matched (e.g., `.env`)
131
+ * - Basename matching works (e.g., `.env` matches `src/.env`)
132
+ */
133
+ function matchesAnyPattern(filePath, patterns) {
134
+ return patterns.some((pattern) => minimatch(filePath, pattern, MATCH_OPTIONS));
135
+ }
136
+ //# sourceMappingURL=path-protection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-protection.js","sourceRoot":"","sources":["../../src/utils/path-protection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,mEAAmE;AAEnE,qEAAqE;AACrE,MAAM,CAAC,MAAM,gBAAgB,GAAG,gEAAgE,CAAC;AAEjG;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAsB;IACrD,oBAAoB;IACpB,MAAM;IACN,QAAQ;IAER,gCAAgC;IAChC,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,YAAY;IAEZ,WAAW;IACX,QAAQ;IACR,YAAY;IACZ,UAAU;IACV,OAAO;IAEP,oBAAoB;IACpB,kBAAkB;IAClB,uBAAuB;IACvB,cAAc;IAEd,8BAA8B;IAC9B,QAAQ;IACR,SAAS;IACT,kBAAkB;IAElB,gCAAgC;IAChC,qBAAqB;IACrB,YAAY;IACZ,aAAa;IAEb,2BAA2B;IAC3B,WAAW;IACX,WAAW;IACX,aAAa;IAEb,kBAAkB;IAClB,UAAU;IACV,WAAW;IACX,aAAa;IACb,cAAc;IACd,WAAW;CACH,CAAC;AAEX;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,eAAe,GAAsB;IAChD,6CAA6C;IAC7C,cAAc;IACd,aAAa;IACb,eAAe;IAEf,iEAAiE;IACjE,qBAAqB;IAErB,sDAAsD;IACtD,qBAAqB;IACrB,uBAAuB;CACf,CAAC;AAEX,mEAAmE;AAEnE,+DAA+D;AAC/D,MAAM,aAAa,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAW,CAAC;AAkB9D;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAiB;IACnD,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAe,EAAE,CAAC;IAChC,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC,EAAE,CAAC;YAClD,kEAAkE;YAClE,kEAAkE;YAClE,oDAAoD;YACpD,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,OAAO,EAAE,gBAAgB;aAC1B,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,oBAAoB,CAAC,EAAE,CAAC;YAC9D,gDAAgD;YAChD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AACxC,CAAC;AAED,mEAAmE;AAEnE;;;;;;GAMG;AACH,SAAS,iBAAiB,CAAC,QAAgB,EAAE,QAA2B;IACtE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC;AACjF,CAAC"}
@@ -5,11 +5,20 @@
5
5
  * provides utilities to calculate how much of the token budget should
6
6
  * be allocated to the diff vs. surrounding context (system prompt,
7
7
  * static analysis, memory, stack hints).
8
+ *
9
+ * For providers with low TPM (Tokens Per Minute) limits on free tiers
10
+ * (e.g., Groq, Cerebras), the effective context window is capped to
11
+ * ensure individual requests don't exceed the TPM limit.
8
12
  */
9
13
  /**
10
14
  * Get the context window size for a given model.
11
15
  *
12
- * @param model - Model identifier (e.g., "claude-sonnet-4-20250514", "gpt-4o")
16
+ * Handles model name normalization:
17
+ * - Strips common prefixes (e.g., "openai/gpt-oss-120b" → lookup "openai/gpt-oss-120b" first,
18
+ * then try "gpt-oss-120b")
19
+ * - Falls back to DEFAULT_CONTEXT_WINDOW for truly unknown models
20
+ *
21
+ * @param model - Model identifier (e.g., "claude-sonnet-4-20250514", "openai/gpt-oss-120b")
13
22
  * @returns Context window size in tokens
14
23
  */
15
24
  export declare function getContextWindow(model: string): number;
@@ -21,6 +30,10 @@ export declare function getContextWindow(model: string): number;
21
30
  * This ensures the diff always has enough room while leaving space
22
31
  * for enrichment.
23
32
  *
33
+ * For very constrained models (e.g., Groq free tier with 6K effective window),
34
+ * the budgets are still split 70/30 but the absolute numbers are much smaller,
35
+ * ensuring the diff is aggressively truncated to fit.
36
+ *
24
37
  * @param model - Model identifier
25
38
  * @returns Object with diffBudget and contextBudget in tokens
26
39
  */
@@ -28,4 +41,24 @@ export declare function calculateTokenBudget(model: string): {
28
41
  diffBudget: number;
29
42
  contextBudget: number;
30
43
  };
44
+ /**
45
+ * Calculate concurrency and delay for workflow/consensus specialists
46
+ * based on the model's effective token budget (TPM for free tiers).
47
+ *
48
+ * For free-tier models with low TPM:
49
+ * - concurrency=1, delay=60s → one specialist per minute
50
+ *
51
+ * For mid-range models:
52
+ * - concurrency=2, delay=30s → two at a time with gaps
53
+ *
54
+ * For high-capacity models:
55
+ * - concurrency=5, delay=0 → full parallel, no delays
56
+ *
57
+ * @param model - Model identifier
58
+ * @returns { concurrency, delayMs } for runWithConcurrency
59
+ */
60
+ export declare function calculateRateSchedule(model: string): {
61
+ concurrency: number;
62
+ delayMs: number;
63
+ };
31
64
  //# sourceMappingURL=token-budget.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"token-budget.d.ts","sourceRoot":"","sources":["../../src/utils/token-budget.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAyCH;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB,CAOA"}
1
+ {"version":3,"file":"token-budget.d.ts","sourceRoot":"","sources":["../../src/utils/token-budget.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAoFH;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAgBtD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB,CAOA;AAiBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB,CAiBA"}
@@ -5,6 +5,10 @@
5
5
  * provides utilities to calculate how much of the token budget should
6
6
  * be allocated to the diff vs. surrounding context (system prompt,
7
7
  * static analysis, memory, stack hints).
8
+ *
9
+ * For providers with low TPM (Tokens Per Minute) limits on free tiers
10
+ * (e.g., Groq, Cerebras), the effective context window is capped to
11
+ * ensure individual requests don't exceed the TPM limit.
8
12
  */
9
13
  // ─── Context Window Sizes ───────────────────────────────────────
10
14
  /**
@@ -14,12 +18,15 @@
14
18
  const MODEL_CONTEXT_WINDOWS = {
15
19
  // Anthropic
16
20
  'claude-sonnet-4-20250514': 200_000,
21
+ 'claude-opus-4-20250514': 200_000,
22
+ 'claude-haiku-4-20250414': 200_000,
17
23
  'claude-3-5-sonnet-20241022': 200_000,
18
24
  'claude-3-5-haiku-20241022': 200_000,
19
25
  // OpenAI
20
26
  'gpt-4o': 128_000,
21
27
  'gpt-4o-mini': 128_000,
22
28
  'gpt-4-turbo': 128_000,
29
+ 'o3-mini': 128_000,
23
30
  // Google
24
31
  'gemini-2.5-flash': 1_048_576,
25
32
  'gemini-2.5-flash-lite': 1_048_576,
@@ -29,9 +36,43 @@ const MODEL_CONTEXT_WINDOWS = {
29
36
  'gemini-2.0-flash-lite': 1_048_576,
30
37
  'gemini-1.5-pro': 2_097_152,
31
38
  'gemini-1.5-flash': 1_048_576,
39
+ // Groq — context windows are large but FREE-TIER TPM limits are very low.
40
+ // We cap to TPM limit since Groq rejects any single request exceeding TPM.
41
+ // Free tier TPM: gpt-oss-120b=8K, llama-3.3-70b=12K, llama-3.1-8b=6K
42
+ 'openai/gpt-oss-120b': 6_000,
43
+ 'llama-3.3-70b-versatile': 8_000,
44
+ 'llama-3.1-70b-versatile': 8_000,
45
+ 'llama-3.1-8b-instant': 4_000,
46
+ 'gemma2-9b-it': 6_000,
47
+ 'mixtral-8x7b-32768': 12_000,
48
+ 'qwen-qwq-32b': 8_000,
49
+ // Cerebras — very fast inference, generous limits
50
+ 'llama3.1-8b': 128_000,
51
+ 'qwen-3-235b-a22b-instruct-2507': 128_000,
52
+ 'zai-glm-4.7': 128_000,
53
+ // DeepSeek
54
+ 'deepseek-chat': 64_000,
55
+ 'deepseek-reasoner': 64_000,
56
+ // GitHub Models
57
+ 'Phi-4': 16_000,
58
+ 'Mistral-Large-2411': 128_000,
59
+ 'DeepSeek-R1': 64_000,
60
+ // Qwen
61
+ 'qwen-coder-plus': 128_000,
62
+ 'qwen-plus': 128_000,
63
+ 'qwen-max': 32_000,
64
+ 'qwen-turbo': 128_000,
65
+ 'qwen-coder-turbo': 128_000,
66
+ 'qwen-long': 1_000_000,
32
67
  };
33
68
  /** Default context window when the model is not in our lookup table. */
34
69
  const DEFAULT_CONTEXT_WINDOW = 128_000;
70
+ /**
71
+ * Minimum effective context window.
72
+ * Even for the most constrained models, we need at least this much
73
+ * to produce a meaningful review (system prompt + small diff).
74
+ */
75
+ const MINIMUM_CONTEXT_WINDOW = 2_000;
35
76
  /** Fraction of total budget allocated to the diff content. */
36
77
  const DIFF_BUDGET_RATIO = 0.7;
37
78
  /** Fraction of total budget allocated to context (system, memory, static analysis). */
@@ -40,11 +81,28 @@ const CONTEXT_BUDGET_RATIO = 0.3;
40
81
  /**
41
82
  * Get the context window size for a given model.
42
83
  *
43
- * @param model - Model identifier (e.g., "claude-sonnet-4-20250514", "gpt-4o")
84
+ * Handles model name normalization:
85
+ * - Strips common prefixes (e.g., "openai/gpt-oss-120b" → lookup "openai/gpt-oss-120b" first,
86
+ * then try "gpt-oss-120b")
87
+ * - Falls back to DEFAULT_CONTEXT_WINDOW for truly unknown models
88
+ *
89
+ * @param model - Model identifier (e.g., "claude-sonnet-4-20250514", "openai/gpt-oss-120b")
44
90
  * @returns Context window size in tokens
45
91
  */
46
92
  export function getContextWindow(model) {
47
- return MODEL_CONTEXT_WINDOWS[model] ?? DEFAULT_CONTEXT_WINDOW;
93
+ // Direct lookup first
94
+ if (model in MODEL_CONTEXT_WINDOWS) {
95
+ return MODEL_CONTEXT_WINDOWS[model] ?? DEFAULT_CONTEXT_WINDOW;
96
+ }
97
+ // Try without provider prefix (e.g., "deepseek/deepseek-chat" → "deepseek-chat")
98
+ const slashIndex = model.indexOf('/');
99
+ if (slashIndex !== -1) {
100
+ const modelWithoutPrefix = model.slice(slashIndex + 1);
101
+ if (modelWithoutPrefix in MODEL_CONTEXT_WINDOWS) {
102
+ return MODEL_CONTEXT_WINDOWS[modelWithoutPrefix] ?? DEFAULT_CONTEXT_WINDOW;
103
+ }
104
+ }
105
+ return DEFAULT_CONTEXT_WINDOW;
48
106
  }
49
107
  /**
50
108
  * Calculate token budgets for diff and context.
@@ -54,14 +112,61 @@ export function getContextWindow(model) {
54
112
  * This ensures the diff always has enough room while leaving space
55
113
  * for enrichment.
56
114
  *
115
+ * For very constrained models (e.g., Groq free tier with 6K effective window),
116
+ * the budgets are still split 70/30 but the absolute numbers are much smaller,
117
+ * ensuring the diff is aggressively truncated to fit.
118
+ *
57
119
  * @param model - Model identifier
58
120
  * @returns Object with diffBudget and contextBudget in tokens
59
121
  */
60
122
  export function calculateTokenBudget(model) {
61
- const total = getContextWindow(model);
123
+ const total = Math.max(getContextWindow(model), MINIMUM_CONTEXT_WINDOW);
62
124
  return {
63
125
  diffBudget: Math.floor(total * DIFF_BUDGET_RATIO),
64
126
  contextBudget: Math.floor(total * CONTEXT_BUDGET_RATIO),
65
127
  };
66
128
  }
129
+ // ─── Rate-Aware Scheduling ─────────────────────────────────────
130
+ /**
131
+ * Threshold below which a model is considered "TPM-constrained".
132
+ * Models with context windows below this are free-tier providers
133
+ * where we need to serialize requests to avoid rate limiting.
134
+ */
135
+ const TPM_CONSTRAINED_THRESHOLD = 16_000;
136
+ /**
137
+ * Estimate tokens per specialist call (system prompt + diff + response).
138
+ * Used to calculate how many specialists can run per TPM window.
139
+ */
140
+ const ESTIMATED_TOKENS_PER_SPECIALIST = 7_000;
141
+ /**
142
+ * Calculate concurrency and delay for workflow/consensus specialists
143
+ * based on the model's effective token budget (TPM for free tiers).
144
+ *
145
+ * For free-tier models with low TPM:
146
+ * - concurrency=1, delay=60s → one specialist per minute
147
+ *
148
+ * For mid-range models:
149
+ * - concurrency=2, delay=30s → two at a time with gaps
150
+ *
151
+ * For high-capacity models:
152
+ * - concurrency=5, delay=0 → full parallel, no delays
153
+ *
154
+ * @param model - Model identifier
155
+ * @returns { concurrency, delayMs } for runWithConcurrency
156
+ */
157
+ export function calculateRateSchedule(model) {
158
+ const contextWindow = getContextWindow(model);
159
+ // High-capacity models (paid tiers, large context) → full parallel
160
+ if (contextWindow >= TPM_CONSTRAINED_THRESHOLD * 4) {
161
+ return { concurrency: 5, delayMs: 0 };
162
+ }
163
+ // Mid-range models (e.g., Cerebras 60K TPM) → some parallelism
164
+ if (contextWindow >= TPM_CONSTRAINED_THRESHOLD) {
165
+ const parallelCalls = Math.max(1, Math.floor(contextWindow / ESTIMATED_TOKENS_PER_SPECIALIST));
166
+ return { concurrency: Math.min(parallelCalls, 5), delayMs: 5_000 };
167
+ }
168
+ // TPM-constrained models (Groq free tier, 4K-12K) → serialize with 60s delay
169
+ // Groq resets TPM every 60 seconds, so we wait between each call
170
+ return { concurrency: 1, delayMs: 60_000 };
171
+ }
67
172
  //# sourceMappingURL=token-budget.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"token-budget.js","sourceRoot":"","sources":["../../src/utils/token-budget.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,mEAAmE;AAEnE;;;GAGG;AACH,MAAM,qBAAqB,GAA2B;IACpD,YAAY;IACZ,0BAA0B,EAAE,OAAO;IACnC,4BAA4B,EAAE,OAAO;IACrC,2BAA2B,EAAE,OAAO;IAEpC,SAAS;IACT,QAAQ,EAAE,OAAO;IACjB,aAAa,EAAE,OAAO;IACtB,aAAa,EAAE,OAAO;IAEtB,SAAS;IACT,kBAAkB,EAAE,SAAS;IAC7B,uBAAuB,EAAE,SAAS;IAClC,gBAAgB,EAAE,SAAS;IAC3B,gBAAgB,EAAE,SAAS;IAC3B,kBAAkB,EAAE,SAAS;IAC7B,uBAAuB,EAAE,SAAS;IAClC,gBAAgB,EAAE,SAAS;IAC3B,kBAAkB,EAAE,SAAS;CAC9B,CAAC;AAEF,wEAAwE;AACxE,MAAM,sBAAsB,GAAG,OAAO,CAAC;AAEvC,8DAA8D;AAC9D,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B,uFAAuF;AACvF,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAEjC,mEAAmE;AAEnE;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,qBAAqB,CAAC,KAAK,CAAC,IAAI,sBAAsB,CAAC;AAChE,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAa;IAIhD,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAEtC,OAAO;QACL,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,iBAAiB,CAAC;QACjD,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,oBAAoB,CAAC;KACxD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"token-budget.js","sourceRoot":"","sources":["../../src/utils/token-budget.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ghagga-core",
3
- "version": "2.5.0",
3
+ "version": "2.6.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Core review engine for GHAGGA — AI-powered multi-agent code reviewer",
@@ -39,22 +39,6 @@
39
39
  "dist",
40
40
  "README.md"
41
41
  ],
42
- "dependencies": {
43
- "@ai-sdk/anthropic": "^2.0.0",
44
- "@ai-sdk/google": "^2.0.0",
45
- "@ai-sdk/openai": "^2.0.0",
46
- "ai": "^5.0.0",
47
- "minimatch": "^10.0.1",
48
- "fts5-sql-bundle": "^1.0.2",
49
- "zod": "^4.1.8"
50
- },
51
- "devDependencies": {
52
- "@stryker-mutator/core": "^9.6.0",
53
- "@stryker-mutator/vitest-runner": "^9.6.0",
54
- "@types/node": "^25.3.5",
55
- "typescript": "^5.7.0",
56
- "vitest": "^3.0.0"
57
- },
58
42
  "scripts": {
59
43
  "build": "tsc",
60
44
  "dev": "tsc --watch",
@@ -63,6 +47,24 @@
63
47
  "test:coverage": "vitest run --coverage",
64
48
  "test:watch": "vitest",
65
49
  "test:mutate": "stryker run",
66
- "clean": "rm -rf dist"
50
+ "clean": "rm -rf dist",
51
+ "prepublishOnly": "npm run build"
52
+ },
53
+ "dependencies": {
54
+ "@ai-sdk/anthropic": "^3.0.0",
55
+ "@ai-sdk/google": "^3.0.0",
56
+ "@ai-sdk/openai": "^3.0.0",
57
+ "@ai-sdk/openai-compatible": "^2.0.35",
58
+ "ai": "^6.0.0",
59
+ "fts5-sql-bundle": "^1.0.2",
60
+ "minimatch": "^10.2.0",
61
+ "zod": "^4.3.0"
62
+ },
63
+ "devDependencies": {
64
+ "@stryker-mutator/core": "^9.6.0",
65
+ "@stryker-mutator/vitest-runner": "^9.6.0",
66
+ "@types/node": "^25.3.5",
67
+ "typescript": "^5.9.0",
68
+ "vitest": "^4.0.0"
67
69
  }
68
- }
70
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 JNZader & Gentleman Programming Community
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.