@opengeni/jev 4.2.1-canary.39593846423001 → 4.3.1
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/README.md +18 -4
- package/dist/client.d.ts +4 -17
- package/dist/code-search/judge.d.ts +23 -18
- package/dist/code-search/search.d.ts +19 -12
- package/dist/decision-model.d.ts +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +152 -60
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
- package/src/client.ts +18 -21
- package/src/code-search/judge.ts +90 -56
- package/src/code-search/search.ts +55 -22
- package/src/decision-model.ts +68 -0
- package/src/index.ts +1 -0
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# `@opengeni/jev`
|
|
2
2
|
|
|
3
|
-
`@opengeni/jev` holds Opengeni's client for TypeSafe Jev,
|
|
4
|
-
`
|
|
5
|
-
|
|
3
|
+
`@opengeni/jev` holds Opengeni's client for TypeSafe Jev, its adapter to the shared
|
|
4
|
+
`@opengeni/decisions` interface, and the provider-neutral `code_search` engine.
|
|
5
|
+
Its only runtime dependency is that shared typed contract. It uses global `fetch`, runs under Node 18+ and Bun, and makes no filesystem or process
|
|
6
6
|
calls of its own.
|
|
7
7
|
|
|
8
8
|
## Jev client
|
|
@@ -58,9 +58,23 @@ Retries and errors work like this:
|
|
|
58
58
|
|
|
59
59
|
## code_search
|
|
60
60
|
|
|
61
|
-
`
|
|
61
|
+
`createJevDecisionModel(client)` adapts the existing client without replacing its
|
|
62
|
+
transport policy. `JevError`, `JevUnavailableError` and `JevRequestError` remain
|
|
63
|
+
exported aliases of the shared decision errors. The existing breaker accepts those
|
|
64
|
+
same canonical errors for every provider, with unchanged thresholds and cooldowns.
|
|
65
|
+
The direct client's numeric usage fields remain compatible; `inputTokensReported`
|
|
66
|
+
distinguishes missing counts. The shared adapter reports null token/cost values
|
|
67
|
+
when any successful chunk omitted a valid count, not a zero-cost estimate.
|
|
68
|
+
|
|
69
|
+
`runCodeSearch({question, keywords, subQuestions?, paths?, workspace, decisionModel, signal?, budgetTokens?})`
|
|
62
70
|
is scout-0.4. It keeps the recall, triage and verification defaults of the validated research tool
|
|
63
71
|
scout-0.3.1, and adds the stages that let an agent read less irrelevant code without reading less relevant code.
|
|
72
|
+
The legacy `jev: JevClient` input remains supported when `decisionModel` is absent.
|
|
73
|
+
Stages now use the shared typed interface; the following Jev-based pipeline was
|
|
74
|
+
the original validated configuration, not a performance claim for every backend.
|
|
75
|
+
Usage is under `stats.decision` (nullable token/cost counts, model/provider and
|
|
76
|
+
cost source); stage events are named `decision`. Refusals fail rather than turning
|
|
77
|
+
into lexical scores. See [decision models](../../docs/decision-models.md).
|
|
64
78
|
The pipeline:
|
|
65
79
|
|
|
66
80
|
1. **Recall:** one ripgrep pass over the keyword variants, then IDF scoring per file.
|
package/dist/client.d.ts
CHANGED
|
@@ -63,6 +63,8 @@ export interface JevAskResult<Q extends Record<string, JevQuestion>> {
|
|
|
63
63
|
model: string;
|
|
64
64
|
usage: {
|
|
65
65
|
inputTokens: number;
|
|
66
|
+
/** Whether every successful chunk reported a valid count; numeric field retains compatibility. */
|
|
67
|
+
inputTokensReported?: boolean;
|
|
66
68
|
};
|
|
67
69
|
/** HTTP requests (chunks) that made up this ask. */
|
|
68
70
|
requests: number;
|
|
@@ -78,23 +80,8 @@ export declare function noul(instructions: JevInstructions, criteria?: {
|
|
|
78
80
|
false?: JevInstructions;
|
|
79
81
|
}): JevNoulQuestion;
|
|
80
82
|
export declare function jevCostUsd(inputTokens: number): number;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
readonly status: number | undefined;
|
|
84
|
-
/** Machine-readable reason when known (for example "max_tokens_exceeded" or "state_too_large"). */
|
|
85
|
-
readonly code: string | undefined;
|
|
86
|
-
constructor(message: string, options?: {
|
|
87
|
-
status?: number;
|
|
88
|
-
code?: string;
|
|
89
|
-
cause?: unknown;
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
/** Jev cannot be used right now: network, timeout, 5xx, 429 after retries, or 401/402/403 auth and billing. */
|
|
93
|
-
export declare class JevUnavailableError extends JevError {
|
|
94
|
-
}
|
|
95
|
-
/** Jev rejected the request itself (other 4xx), or the request cannot fit the limits. Never retried. */
|
|
96
|
-
export declare class JevRequestError extends JevError {
|
|
97
|
-
}
|
|
83
|
+
import { DecisionError as JevError, DecisionUnavailableError as JevUnavailableError, DecisionRequestError as JevRequestError } from "@opengeni/decisions";
|
|
84
|
+
export { JevError, JevUnavailableError, JevRequestError };
|
|
98
85
|
export interface JevLimits {
|
|
99
86
|
/** Documented: state + longest question. */
|
|
100
87
|
stateLongestMax: number;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* judge.ts - the only place where scores come from:
|
|
2
|
+
* judge.ts - the only place where scores come from: a typed model returns a probability per item.
|
|
3
3
|
*
|
|
4
|
-
* All
|
|
5
|
-
* - one state + many narrow
|
|
4
|
+
* All judge wording lives in PROMPTS below (one place to review). Design rules followed:
|
|
5
|
+
* - one state + many narrow predicates per request; one predicate per candidate
|
|
6
6
|
* - criteria text is explicit (in the state for 60-file triage batches, per question for passages)
|
|
7
7
|
* - the literal question text is inlined in every question (no `collections[i]`-style indirection)
|
|
8
8
|
* - state holds only the candidates being judged (filtered by code first)
|
|
9
|
-
* - no counting, math or dates asked of
|
|
10
|
-
* A
|
|
9
|
+
* - no counting, math or dates asked of the model; code combines answers
|
|
10
|
+
* A model failure or refusal is not replaced by lexical scores.
|
|
11
11
|
*/
|
|
12
|
-
import { type
|
|
12
|
+
import { type DecisionModel, type DecisionPredicateQuestion, type DecisionUsage } from "@opengeni/decisions";
|
|
13
13
|
import type { CodeSearchConfig } from "./config.js";
|
|
14
14
|
export interface JudgeContext {
|
|
15
15
|
question: string;
|
|
@@ -20,7 +20,7 @@ export interface FileItem {
|
|
|
20
20
|
path: string;
|
|
21
21
|
/** path + best hit lines, as shown to the judge */
|
|
22
22
|
descriptor: string;
|
|
23
|
-
/** Normalized lexical score
|
|
23
|
+
/** Normalized lexical score retained for candidate ordering. */
|
|
24
24
|
lex: number;
|
|
25
25
|
}
|
|
26
26
|
export interface PassageItem {
|
|
@@ -51,8 +51,8 @@ export interface StatusScore {
|
|
|
51
51
|
}
|
|
52
52
|
export interface StageStats {
|
|
53
53
|
requests: number;
|
|
54
|
-
inputTokens: number;
|
|
55
|
-
costUsd: number;
|
|
54
|
+
inputTokens: number | null;
|
|
55
|
+
costUsd: number | null;
|
|
56
56
|
ms: number;
|
|
57
57
|
}
|
|
58
58
|
export type JudgeEvent = (stage: string, data: Record<string, unknown>) => void;
|
|
@@ -113,7 +113,7 @@ export declare function buildFileRequest(items: FileItem[], ctx: JudgeContext, c
|
|
|
113
113
|
[k: string]: string;
|
|
114
114
|
};
|
|
115
115
|
};
|
|
116
|
-
questions: Record<string,
|
|
116
|
+
questions: Record<string, DecisionPredicateQuestion>;
|
|
117
117
|
};
|
|
118
118
|
export declare function buildPassageRequest(items: PassageItem[], ctx: JudgeContext, cfg: CodeSearchConfig): {
|
|
119
119
|
state: {
|
|
@@ -128,7 +128,7 @@ export declare function buildPassageRequest(items: PassageItem[], ctx: JudgeCont
|
|
|
128
128
|
};
|
|
129
129
|
};
|
|
130
130
|
};
|
|
131
|
-
questions: Record<string,
|
|
131
|
+
questions: Record<string, DecisionPredicateQuestion>;
|
|
132
132
|
};
|
|
133
133
|
export declare function buildLeadRequest(items: LeadItem[], ctx: JudgeContext, cfg: CodeSearchConfig): {
|
|
134
134
|
state: {
|
|
@@ -142,7 +142,7 @@ export declare function buildLeadRequest(items: LeadItem[], ctx: JudgeContext, c
|
|
|
142
142
|
[k: string]: string;
|
|
143
143
|
};
|
|
144
144
|
};
|
|
145
|
-
questions: Record<string,
|
|
145
|
+
questions: Record<string, DecisionPredicateQuestion>;
|
|
146
146
|
};
|
|
147
147
|
export declare function buildSymbolRequest(items: LeadItem[], ctx: JudgeContext, cfg: CodeSearchConfig): {
|
|
148
148
|
state: {
|
|
@@ -156,7 +156,7 @@ export declare function buildSymbolRequest(items: LeadItem[], ctx: JudgeContext,
|
|
|
156
156
|
[k: string]: string;
|
|
157
157
|
};
|
|
158
158
|
};
|
|
159
|
-
questions: Record<string,
|
|
159
|
+
questions: Record<string, DecisionPredicateQuestion>;
|
|
160
160
|
};
|
|
161
161
|
export declare function buildChangeRequest(items: LeadItem[], ctx: JudgeContext, cfg: CodeSearchConfig): {
|
|
162
162
|
state: {
|
|
@@ -170,7 +170,7 @@ export declare function buildChangeRequest(items: LeadItem[], ctx: JudgeContext,
|
|
|
170
170
|
[k: string]: string;
|
|
171
171
|
};
|
|
172
172
|
};
|
|
173
|
-
questions: Record<string,
|
|
173
|
+
questions: Record<string, DecisionPredicateQuestion>;
|
|
174
174
|
};
|
|
175
175
|
export declare function buildStatusRequest(evidence: string, ctx: JudgeContext, cfg: CodeSearchConfig): {
|
|
176
176
|
state: {
|
|
@@ -178,24 +178,29 @@ export declare function buildStatusRequest(evidence: string, ctx: JudgeContext,
|
|
|
178
178
|
question: string;
|
|
179
179
|
evidence: string;
|
|
180
180
|
};
|
|
181
|
-
questions: Record<string,
|
|
181
|
+
questions: Record<string, DecisionPredicateQuestion>;
|
|
182
182
|
};
|
|
183
183
|
/** Group passages into requests: consecutive (same-file first) up to perRequest items and maxChars of text. */
|
|
184
184
|
export declare function chunkPassages(items: PassageItem[], perRequest: number, maxChars: number): PassageItem[][];
|
|
185
185
|
/** Split into the fewest groups of at most n items, as equal in size as possible (69 -> 35 + 34, not 60 + 9). */
|
|
186
186
|
export declare function chunkEven<T>(xs: T[], n: number): T[][];
|
|
187
|
-
export declare class
|
|
187
|
+
export declare class CodeSearchJudge {
|
|
188
188
|
private readonly o;
|
|
189
189
|
private readonly stageStats;
|
|
190
|
-
private
|
|
190
|
+
private decisionModelName;
|
|
191
|
+
private decisionProvider;
|
|
192
|
+
private readonly usageCostSources;
|
|
191
193
|
constructor(o: {
|
|
192
|
-
client:
|
|
194
|
+
client: DecisionModel;
|
|
193
195
|
config: CodeSearchConfig;
|
|
194
196
|
signal: AbortSignal;
|
|
195
197
|
onEvent?: JudgeEvent | undefined;
|
|
198
|
+
onUsage?: ((usage: DecisionUsage) => void | Promise<void>) | undefined;
|
|
196
199
|
});
|
|
197
200
|
stats(): Record<string, StageStats>;
|
|
198
201
|
model(): string | null;
|
|
202
|
+
provider(): string | null;
|
|
203
|
+
costSources(): ("estimate" | "provider-reported" | "unknown")[];
|
|
199
204
|
private stat;
|
|
200
205
|
/** One logical request (the client may split its questions into several HTTP requests). */
|
|
201
206
|
private ask;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* search.ts - the code_search pipeline
|
|
2
|
+
* search.ts - the code_search pipeline with a shared typed judge:
|
|
3
3
|
*
|
|
4
4
|
* 1. recall (ripgrep) -> top maxCandidates files by distinct-keyword IDF
|
|
5
5
|
* 2. wave 1 (file triage, 1 Noul per file) -> up to maxFiles files (+ lexical guard)
|
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
* 4. wave 3 (leads, exactly one round) -> <= maxLeadsFollowed definitions, verified like wave 2
|
|
8
8
|
* 5. pack (bounded, verbatim, line-numbered) + status (1 request over the packed evidence)
|
|
9
9
|
*
|
|
10
|
-
* Every file and process access goes through the injected CodeSearchWorkspace. A
|
|
11
|
-
* search (
|
|
12
|
-
* fully
|
|
10
|
+
* Every file and process access goes through the injected CodeSearchWorkspace. A judge failure fails the
|
|
11
|
+
* search (DecisionUnavailableError / DecisionRequestError propagate); only a failed final status check keeps the
|
|
12
|
+
* fully scored pack and reports the status as unknown.
|
|
13
13
|
*/
|
|
14
|
-
import {
|
|
14
|
+
import { DecisionRequestError, DecisionUnavailableError, type DecisionModel, type DecisionUsage } from "@opengeni/decisions";
|
|
15
|
+
import type { JevClient } from "../client.js";
|
|
15
16
|
import { type CodeSearchConfig } from "./config.js";
|
|
16
17
|
import { type FileCandidate, type KeywordInfo, type RecallResult } from "./recall.js";
|
|
17
18
|
import type { CodeSearchWorkspace } from "./workspace.js";
|
|
@@ -25,20 +26,24 @@ export interface CodeSearchInput {
|
|
|
25
26
|
/** Workspace-relative path prefixes to search; default the whole workspace. */
|
|
26
27
|
paths?: string[] | undefined;
|
|
27
28
|
workspace: CodeSearchWorkspace;
|
|
28
|
-
|
|
29
|
+
decisionModel?: DecisionModel;
|
|
30
|
+
/** Compatibility for public callers of the existing client API; adapted once at entry. */
|
|
31
|
+
jev?: JevClient;
|
|
29
32
|
signal?: AbortSignal | undefined;
|
|
30
33
|
/** Max pack size in tokens (default 12000). */
|
|
31
34
|
budgetTokens?: number | undefined;
|
|
32
35
|
/** Tuning and tests only; defaults to DEFAULT_CODE_SEARCH_CONFIG. */
|
|
33
36
|
config?: CodeSearchConfig | undefined;
|
|
34
|
-
/** In-memory stage trace
|
|
37
|
+
/** In-memory stage trace, including one "decision" event per typed judgment request. */
|
|
35
38
|
onStage?: ((stage: string, data: Record<string, unknown>) => void) | undefined;
|
|
39
|
+
/** Received provider usage is observable even if a later stage or answer fails. */
|
|
40
|
+
onDecisionUsage?: ((usage: DecisionUsage) => void | Promise<void>) | undefined;
|
|
36
41
|
}
|
|
37
42
|
export interface CodeSearchStatus {
|
|
38
43
|
label: "sufficient" | "partial" | "insufficient" | "unknown";
|
|
39
44
|
overall: number | null;
|
|
40
45
|
subs: Array<number | null>;
|
|
41
|
-
/** Set when the final
|
|
46
|
+
/** Set when the final evidence check failed (the pack itself is fully scored). */
|
|
42
47
|
error?: string;
|
|
43
48
|
}
|
|
44
49
|
export interface CodeSearchStats {
|
|
@@ -53,11 +58,13 @@ export interface CodeSearchStats {
|
|
|
53
58
|
workspaceCalls: number;
|
|
54
59
|
/** A ripgrep call returned partial output (byte cap or time limit); the pack header says so. */
|
|
55
60
|
ripgrepTruncated: boolean;
|
|
56
|
-
|
|
61
|
+
decision: {
|
|
57
62
|
requests: number;
|
|
58
|
-
inputTokens: number;
|
|
59
|
-
costUsd: number;
|
|
63
|
+
inputTokens: number | null;
|
|
64
|
+
costUsd: number | null;
|
|
60
65
|
model: string | null;
|
|
66
|
+
provider: string | null;
|
|
67
|
+
costSources: Array<"provider-reported" | "estimate" | "unknown">;
|
|
61
68
|
};
|
|
62
69
|
}
|
|
63
70
|
export interface CodeSearchResult {
|
|
@@ -67,7 +74,7 @@ export interface CodeSearchResult {
|
|
|
67
74
|
status: CodeSearchStatus;
|
|
68
75
|
stats: CodeSearchStats;
|
|
69
76
|
/** The error of a failed final status check, for a circuit breaker (the search itself succeeded). */
|
|
70
|
-
statusCheckError?:
|
|
77
|
+
statusCheckError?: DecisionUnavailableError | DecisionRequestError;
|
|
71
78
|
}
|
|
72
79
|
/** Lexical passage relevance in [0,1]: keyword IDF mass present, question-term overlap, file prior. */
|
|
73
80
|
export declare function lexicalPassageScore(text: string, kwPresent: number[], keywords: KeywordInfo[], qTerms: string[], fileNorm: number): number;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type DecisionModel } from "@opengeni/decisions";
|
|
2
|
+
import { JevClient } from "./client.js";
|
|
3
|
+
/** Adapt the existing typed client without duplicating its transport/chunking policy. */
|
|
4
|
+
export declare function createJevDecisionModel(client: JevClient): DecisionModel;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { JEV_CHARS_PER_TOKEN, JEV_DEFAULT_BASE_URL, JEV_DEFAULT_LIMITS, JEV_DEFAULT_MODEL, JEV_PRICE_PER_MILLION_INPUT_TOKENS_USD, JevClient, JevError, JevLimiter, JevRequestError, JevUnavailableError, estimateJevTokens, jevCostUsd, noul, planChunks, type JevAnswer, type JevAnswerFor, type JevAskOptions, type JevAskResult, type JevChoiceAnswer, type JevChoiceQuestion, type JevClientOptions, type JevFetch, type JevInstructions, type JevLimits, type JevNoulAnswer, type JevNoulQuestion, type JevQuestion, type JevScoreAnswer, type JevScoreQuestion, } from "./client.js";
|
|
2
|
+
export { createJevDecisionModel } from "./decision-model.js";
|
|
2
3
|
export { JevCircuitBreaker, type JevCircuitBreakerOptions, type JevCircuitLease, type JevCircuitState, type JevCircuitStatus, } from "./circuit-breaker.js";
|
|
3
4
|
export { CODE_SEARCH_DEFAULT_BUDGET_TOKENS, CODE_SEARCH_ENGINE_VERSION, runCodeSearch, type CodeSearchInput, type CodeSearchResult, type CodeSearchStats, type CodeSearchStatus, } from "./code-search/search.js";
|
|
4
5
|
export { CODE_SEARCH_CREDENTIAL_DIRS, isCodeSearchCredentialPath } from "./code-search/recall.js";
|