@adversarylabs/sdk 0.1.36 → 0.1.38
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 +30 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/model-diagnostics.d.ts +6 -0
- package/dist/model-diagnostics.d.ts.map +1 -0
- package/dist/model-diagnostics.js +78 -0
- package/dist/model-diagnostics.js.map +1 -0
- package/dist/model.d.ts +2 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +78 -23
- package/dist/model.js.map +1 -1
- package/dist/repository-diagnostics.d.ts +29 -0
- package/dist/repository-diagnostics.d.ts.map +1 -0
- package/dist/repository-diagnostics.js +73 -0
- package/dist/repository-diagnostics.js.map +1 -0
- package/dist/repository-model.d.ts +4 -0
- package/dist/repository-model.d.ts.map +1 -1
- package/dist/repository-model.js +334 -169
- package/dist/repository-model.js.map +1 -1
- package/dist/repository-path.d.ts +4 -0
- package/dist/repository-path.d.ts.map +1 -0
- package/dist/repository-path.js +16 -0
- package/dist/repository-path.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Bounded, content-free broker timing; never changes request or retry behavior. */
|
|
2
|
+
export declare function modelAttemptDiagnostics(deadlineMs: number, stage: "model_review" | "repository_planning"): {
|
|
3
|
+
startRetryDelay(attempt: number): (failureCode: string) => void;
|
|
4
|
+
start(attempt: number): (outcome: "succeeded" | "failed", actualProvider?: string, actualModel?: string, failureCode?: string) => void;
|
|
5
|
+
};
|
|
6
|
+
//# sourceMappingURL=model-diagnostics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-diagnostics.d.ts","sourceRoot":"","sources":["../src/model-diagnostics.ts"],"names":[],"mappings":"AAsBA,oFAAoF;AACpF,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,cAAc,GAAG,qBAAqB;6BAQlB,MAAM,IAGrB,aAAa,MAAM;mBAmBd,MAAM,IAajB,SAAS,WAAW,GAAG,QAAQ,EAC/B,iBAAiB,MAAM,EACvB,cAAc,MAAM,EACpB,cAAc,MAAM;EAgB3B"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { writeRepositoryDiagnostic } from "./repository-diagnostics.js";
|
|
3
|
+
function identity(value) {
|
|
4
|
+
return value && /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/.test(value) ? value : "unknown";
|
|
5
|
+
}
|
|
6
|
+
const failureCodes = new Set([
|
|
7
|
+
"broker_unavailable",
|
|
8
|
+
"model_timeout",
|
|
9
|
+
"model_response_too_large",
|
|
10
|
+
"model_response_limit",
|
|
11
|
+
"invalid_broker_response",
|
|
12
|
+
"unsupported_model_protocol",
|
|
13
|
+
"invalid_model_output",
|
|
14
|
+
"invalid_model_schema",
|
|
15
|
+
"model_review_failed",
|
|
16
|
+
"bad_gateway",
|
|
17
|
+
"rate_limited",
|
|
18
|
+
"provider_unavailable",
|
|
19
|
+
]);
|
|
20
|
+
/** Bounded, content-free broker timing; never changes request or retry behavior. */
|
|
21
|
+
export function modelAttemptDiagnostics(deadlineMs, stage) {
|
|
22
|
+
const requestId = randomUUID();
|
|
23
|
+
const reviewStarted = performance.now();
|
|
24
|
+
const jobId = identity(process.env.HOSTED_REVIEW_JOB_ID);
|
|
25
|
+
const provider = identity(process.env.ADVERSARY_MODEL_PROVIDER);
|
|
26
|
+
const model = identity(process.env.ADVERSARY_MODEL);
|
|
27
|
+
return {
|
|
28
|
+
startRetryDelay(attempt) {
|
|
29
|
+
const started = performance.now();
|
|
30
|
+
const remainingDeadlineMs = Math.max(0, Math.round(deadlineMs - (started - reviewStarted)));
|
|
31
|
+
return (failureCode) => {
|
|
32
|
+
writeRepositoryDiagnostic({
|
|
33
|
+
event: "model.retry-delay",
|
|
34
|
+
requestId,
|
|
35
|
+
jobId,
|
|
36
|
+
stage: "broker_retry_delay",
|
|
37
|
+
modelStage: stage,
|
|
38
|
+
attempt,
|
|
39
|
+
deadlineMs,
|
|
40
|
+
remainingDeadlineMs,
|
|
41
|
+
elapsedMs: Math.round(performance.now() - started),
|
|
42
|
+
outcome: "failed",
|
|
43
|
+
provider,
|
|
44
|
+
model,
|
|
45
|
+
identitySource: "runner_environment",
|
|
46
|
+
failureCode: failureCodes.has(failureCode) ? failureCode : "model_review_failed",
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
start(attempt) {
|
|
51
|
+
const started = performance.now();
|
|
52
|
+
const record = {
|
|
53
|
+
event: "model.attempt",
|
|
54
|
+
requestId,
|
|
55
|
+
jobId,
|
|
56
|
+
stage,
|
|
57
|
+
attempt,
|
|
58
|
+
deadlineMs,
|
|
59
|
+
remainingDeadlineMs: Math.max(0, Math.round(deadlineMs - (started - reviewStarted))),
|
|
60
|
+
};
|
|
61
|
+
writeRepositoryDiagnostic({ ...record, outcome: "started", elapsedMs: 0, provider, model });
|
|
62
|
+
return (outcome, actualProvider, actualModel, failureCode) => {
|
|
63
|
+
writeRepositoryDiagnostic({
|
|
64
|
+
...record,
|
|
65
|
+
outcome,
|
|
66
|
+
elapsedMs: Math.round(performance.now() - started),
|
|
67
|
+
provider: actualProvider === undefined ? provider : identity(actualProvider),
|
|
68
|
+
model: actualModel === undefined ? model : identity(actualModel),
|
|
69
|
+
identitySource: actualProvider === undefined ? "runner_environment" : "broker_response",
|
|
70
|
+
...(failureCode === undefined
|
|
71
|
+
? {}
|
|
72
|
+
: { failureCode: failureCodes.has(failureCode) ? failureCode : "model_review_failed" }),
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=model-diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-diagnostics.js","sourceRoot":"","sources":["../src/model-diagnostics.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { writeRepositoryDiagnostic } from \"./repository-diagnostics.js\";\n\nfunction identity(value: string | undefined): string {\n return value && /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/.test(value) ? value : \"unknown\";\n}\n\nconst failureCodes = new Set([\n \"broker_unavailable\",\n \"model_timeout\",\n \"model_response_too_large\",\n \"model_response_limit\",\n \"invalid_broker_response\",\n \"unsupported_model_protocol\",\n \"invalid_model_output\",\n \"invalid_model_schema\",\n \"model_review_failed\",\n \"bad_gateway\",\n \"rate_limited\",\n \"provider_unavailable\",\n]);\n\n/** Bounded, content-free broker timing; never changes request or retry behavior. */\nexport function modelAttemptDiagnostics(\n deadlineMs: number,\n stage: \"model_review\" | \"repository_planning\",\n) {\n const requestId = randomUUID();\n const reviewStarted = performance.now();\n const jobId = identity(process.env.HOSTED_REVIEW_JOB_ID);\n const provider = identity(process.env.ADVERSARY_MODEL_PROVIDER);\n const model = identity(process.env.ADVERSARY_MODEL);\n return {\n startRetryDelay(attempt: number) {\n const started = performance.now();\n const remainingDeadlineMs = Math.max(0, Math.round(deadlineMs - (started - reviewStarted)));\n return (failureCode: string) => {\n writeRepositoryDiagnostic({\n event: \"model.retry-delay\",\n requestId,\n jobId,\n stage: \"broker_retry_delay\",\n modelStage: stage,\n attempt,\n deadlineMs,\n remainingDeadlineMs,\n elapsedMs: Math.round(performance.now() - started),\n outcome: \"failed\",\n provider,\n model,\n identitySource: \"runner_environment\",\n failureCode: failureCodes.has(failureCode) ? failureCode : \"model_review_failed\",\n });\n };\n },\n start(attempt: number) {\n const started = performance.now();\n const record = {\n event: \"model.attempt\",\n requestId,\n jobId,\n stage,\n attempt,\n deadlineMs,\n remainingDeadlineMs: Math.max(0, Math.round(deadlineMs - (started - reviewStarted))),\n };\n writeRepositoryDiagnostic({ ...record, outcome: \"started\", elapsedMs: 0, provider, model });\n return (\n outcome: \"succeeded\" | \"failed\",\n actualProvider?: string,\n actualModel?: string,\n failureCode?: string,\n ) => {\n writeRepositoryDiagnostic({\n ...record,\n outcome,\n elapsedMs: Math.round(performance.now() - started),\n provider: actualProvider === undefined ? provider : identity(actualProvider),\n model: actualModel === undefined ? model : identity(actualModel),\n identitySource: actualProvider === undefined ? \"runner_environment\" : \"broker_response\",\n ...(failureCode === undefined\n ? {}\n : { failureCode: failureCodes.has(failureCode) ? failureCode : \"model_review_failed\" }),\n });\n };\n },\n };\n}\n"]}
|
package/dist/model.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export interface ModelReviewValidation<T = unknown> {
|
|
|
13
13
|
maximumAttempts?: number;
|
|
14
14
|
}
|
|
15
15
|
export interface ModelReviewRequest<T = unknown> {
|
|
16
|
+
/** Local timing classification only; never sent to the broker or model. */
|
|
17
|
+
diagnosticStage?: "model_review" | "repository_planning";
|
|
16
18
|
prompt: string;
|
|
17
19
|
input: unknown;
|
|
18
20
|
schema: Record<string, unknown>;
|
package/dist/model.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
|
package/dist/model.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Ajv2020 } from "ajv/dist/2020.js";
|
|
2
|
+
import { Agent } from "undici";
|
|
3
|
+
import { modelAttemptDiagnostics } from "./model-diagnostics.js";
|
|
2
4
|
export const ADVERSARY_MODEL_PROTOCOL_VERSION = 1;
|
|
3
5
|
export const ADVERSARY_MODEL_ENDPOINT_ENV = "ADVERSARY_MODEL_ENDPOINT";
|
|
4
6
|
export const ADVERSARY_MODEL_TOKEN_ENV = "ADVERSARY_MODEL_TOKEN";
|
|
5
|
-
const DEFAULT_MODEL_TIMEOUT_MS =
|
|
7
|
+
const DEFAULT_MODEL_TIMEOUT_MS = 600_000;
|
|
6
8
|
const MAX_MODEL_TIMEOUT_MS = 600_000;
|
|
7
9
|
const DEFAULT_MAXIMUM_OUTPUT_TOKENS = 8_192;
|
|
8
10
|
const MAX_MAXIMUM_OUTPUT_TOKENS = 65_536;
|
|
@@ -16,6 +18,23 @@ const MAX_BROKER_RETRY_DELAY_MS = 5_000;
|
|
|
16
18
|
const DEFAULT_VALIDATION_MAXIMUM_ATTEMPTS = 3;
|
|
17
19
|
const MAX_VALIDATION_MAXIMUM_ATTEMPTS = 5;
|
|
18
20
|
const MAX_VALIDATION_FEEDBACK_BYTES = 8 << 10;
|
|
21
|
+
// Fetch supplies its own five-minute header timeout, overriding Agent defaults.
|
|
22
|
+
// Override dispatch options for this review only; its shared AbortSignal remains
|
|
23
|
+
// the authoritative deadline across connection, headers, body, and retries.
|
|
24
|
+
class ModelBrokerDispatcher extends Agent {
|
|
25
|
+
deadlineMs;
|
|
26
|
+
constructor(deadlineMs) {
|
|
27
|
+
super({ connectTimeout: deadlineMs });
|
|
28
|
+
this.deadlineMs = deadlineMs;
|
|
29
|
+
}
|
|
30
|
+
dispatch(options, handler) {
|
|
31
|
+
return super.dispatch({
|
|
32
|
+
...options,
|
|
33
|
+
headersTimeout: this.deadlineMs,
|
|
34
|
+
bodyTimeout: this.deadlineMs,
|
|
35
|
+
}, handler);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
19
38
|
export class ModelUnavailableError extends Error {
|
|
20
39
|
constructor(message = "Model review is unavailable for this adversary execution.") {
|
|
21
40
|
super(message);
|
|
@@ -84,24 +103,23 @@ export class BrokerReviewModel {
|
|
|
84
103
|
throw new ModelReviewError("Repository model tools require ctx.model so the SDK can enforce the repository boundary.", { code: "invalid_model_request" });
|
|
85
104
|
}
|
|
86
105
|
const normalized = normalizeRequest(request);
|
|
106
|
+
const diagnostics = modelAttemptDiagnostics(normalized.budget.timeoutMs, request.diagnosticStage === "repository_planning" ? "repository_planning" : "model_review");
|
|
87
107
|
const controller = new AbortController();
|
|
88
108
|
const timeout = setTimeout(() => controller.abort(), normalized.budget.timeoutMs);
|
|
109
|
+
const dispatcher = new ModelBrokerDispatcher(normalized.budget.timeoutMs);
|
|
89
110
|
try {
|
|
90
111
|
for (let attempt = 1; attempt <= this.#maximumAttempts; attempt += 1) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
const exponential = Math.min(MAX_BROKER_RETRY_DELAY_MS, this.#initialRetryDelayMs * 2 ** (attempt - 1));
|
|
102
|
-
const jittered = Math.round(exponential * (0.75 + 0.5 * this.#random()));
|
|
103
|
-
await waitForRetry(jittered, controller.signal, normalized.budget.timeoutMs);
|
|
112
|
+
const outcome = await this.#reviewAttempt(normalized, controller.signal, dispatcher, diagnostics, attempt);
|
|
113
|
+
if (outcome.ok)
|
|
114
|
+
return outcome.result;
|
|
115
|
+
const error = outcome.error;
|
|
116
|
+
if (!(error instanceof ModelReviewError) ||
|
|
117
|
+
!error.retryable ||
|
|
118
|
+
controller.signal.aborted ||
|
|
119
|
+
attempt === this.#maximumAttempts) {
|
|
120
|
+
throw error;
|
|
104
121
|
}
|
|
122
|
+
await this.#waitForRetry(attempt, controller.signal, normalized.budget.timeoutMs, diagnostics);
|
|
105
123
|
}
|
|
106
124
|
throw new ModelReviewError("Model broker retry loop exhausted unexpectedly.", {
|
|
107
125
|
code: "broker_unavailable",
|
|
@@ -110,9 +128,44 @@ export class BrokerReviewModel {
|
|
|
110
128
|
}
|
|
111
129
|
finally {
|
|
112
130
|
clearTimeout(timeout);
|
|
131
|
+
// Cleanup must not replace the typed request error or a successful response.
|
|
132
|
+
try {
|
|
133
|
+
await dispatcher.destroy();
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// The dispatcher is no longer used after this request.
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// One attempt owns its timing and error outcome; retry decisions belong to review().
|
|
141
|
+
async #reviewAttempt(normalized, signal, dispatcher, diagnostics, attempt) {
|
|
142
|
+
const finish = diagnostics.start(attempt);
|
|
143
|
+
try {
|
|
144
|
+
const result = await this.#reviewOnce(normalized, signal, dispatcher);
|
|
145
|
+
finish("succeeded", result.provider, result.model);
|
|
146
|
+
return { ok: true, result };
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
finish("failed", undefined, undefined, error instanceof ModelReviewError ? error.code : "broker_unavailable");
|
|
150
|
+
return { ok: false, error };
|
|
113
151
|
}
|
|
114
152
|
}
|
|
115
|
-
|
|
153
|
+
// Keep backoff calculation and its terminal timeout diagnostic together.
|
|
154
|
+
async #waitForRetry(attempt, signal, timeoutMs, diagnostics) {
|
|
155
|
+
const exponential = Math.min(MAX_BROKER_RETRY_DELAY_MS, this.#initialRetryDelayMs * 2 ** (attempt - 1));
|
|
156
|
+
const jittered = Math.round(exponential * (0.75 + 0.5 * this.#random()));
|
|
157
|
+
const retryDelayFailed = diagnostics.startRetryDelay(attempt);
|
|
158
|
+
try {
|
|
159
|
+
await waitForRetry(jittered, signal, timeoutMs);
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
retryDelayFailed(error instanceof ModelReviewError
|
|
163
|
+
? (error.code ?? "model_review_failed")
|
|
164
|
+
: "model_review_failed");
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
async #reviewOnce(normalized, signal, dispatcher) {
|
|
116
169
|
let response;
|
|
117
170
|
try {
|
|
118
171
|
response = await fetch(this.endpoint, {
|
|
@@ -131,23 +184,18 @@ export class BrokerReviewModel {
|
|
|
131
184
|
budget: normalized.budget,
|
|
132
185
|
}),
|
|
133
186
|
signal,
|
|
187
|
+
dispatcher,
|
|
134
188
|
});
|
|
135
189
|
}
|
|
136
190
|
catch (error) {
|
|
137
|
-
|
|
138
|
-
throw modelTimeoutError(normalized.budget.timeoutMs);
|
|
139
|
-
}
|
|
140
|
-
throw new ModelReviewError(`Model broker request failed: ${error instanceof Error ? error.message : String(error)}`, { code: "broker_unavailable", retryable: true });
|
|
191
|
+
throw brokerTransportError(error, signal, normalized.budget.timeoutMs);
|
|
141
192
|
}
|
|
142
193
|
let body;
|
|
143
194
|
try {
|
|
144
195
|
body = await readBoundedResponse(response);
|
|
145
196
|
}
|
|
146
197
|
catch (error) {
|
|
147
|
-
|
|
148
|
-
throw modelTimeoutError(normalized.budget.timeoutMs);
|
|
149
|
-
}
|
|
150
|
-
throw error;
|
|
198
|
+
throw brokerTransportError(error, signal, normalized.budget.timeoutMs);
|
|
151
199
|
}
|
|
152
200
|
let decoded;
|
|
153
201
|
try {
|
|
@@ -333,6 +381,13 @@ function requireIntegerRange(value, name, minimum, maximum) {
|
|
|
333
381
|
});
|
|
334
382
|
}
|
|
335
383
|
}
|
|
384
|
+
function brokerTransportError(error, signal, timeoutMs) {
|
|
385
|
+
if (signal.aborted)
|
|
386
|
+
return modelTimeoutError(timeoutMs);
|
|
387
|
+
if (error instanceof ModelReviewError)
|
|
388
|
+
return error;
|
|
389
|
+
return new ModelReviewError(`Model broker request failed: ${error instanceof Error ? error.message : String(error)}`, { code: "broker_unavailable", retryable: true });
|
|
390
|
+
}
|
|
336
391
|
async function readBoundedResponse(response) {
|
|
337
392
|
const declared = response.headers.get("content-length");
|
|
338
393
|
if (declared !== null && Number(declared) > MAX_RESPONSE_BYTES) {
|
package/dist/model.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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","sourcesContent":["import { Ajv2020 } from \"ajv/dist/2020.js\";\nimport type {\n ModelRepositoryCitation,\n ModelRepositoryRetrieval,\n ModelRepositoryToolOptions,\n} from \"./repository-model.js\";\n\nexport const ADVERSARY_MODEL_PROTOCOL_VERSION = 1;\nexport const ADVERSARY_MODEL_ENDPOINT_ENV = \"ADVERSARY_MODEL_ENDPOINT\";\nexport const ADVERSARY_MODEL_TOKEN_ENV = \"ADVERSARY_MODEL_TOKEN\";\n\nconst DEFAULT_MODEL_TIMEOUT_MS = 120_000;\nconst MAX_MODEL_TIMEOUT_MS = 600_000;\nconst DEFAULT_MAXIMUM_OUTPUT_TOKENS = 8_192;\nconst MAX_MAXIMUM_OUTPUT_TOKENS = 65_536;\nconst MAX_PROMPT_BYTES = 256 << 10;\nconst MAX_INPUT_BYTES = 4 << 20;\nconst MAX_SCHEMA_BYTES = 512 << 10;\nconst MAX_RESPONSE_BYTES = 4 << 20;\nconst DEFAULT_BROKER_MAXIMUM_ATTEMPTS = 3;\nconst DEFAULT_BROKER_RETRY_DELAY_MS = 250;\nconst MAX_BROKER_RETRY_DELAY_MS = 5_000;\nconst DEFAULT_VALIDATION_MAXIMUM_ATTEMPTS = 3;\nconst MAX_VALIDATION_MAXIMUM_ATTEMPTS = 5;\nconst MAX_VALIDATION_FEEDBACK_BYTES = 8 << 10;\n\nexport interface ModelReviewBudget {\n maximumOutputTokens?: number;\n timeoutMs?: number;\n}\n\nexport interface ModelReviewValidation<T = unknown> {\n /** Validate a completed model result. Throw to retry generation with the error as feedback. */\n validate(result: ModelReviewResult<T>): void | Promise<void>;\n /** Total generation attempts, including the first. Defaults to 3 and is capped at 5. */\n maximumAttempts?: number;\n}\n\nexport interface ModelReviewRequest<T = unknown> {\n prompt: string;\n input: unknown;\n schema: Record<string, unknown>;\n budget?: ModelReviewBudget;\n validation?: ModelReviewValidation<T>;\n tools?: {\n repository: ModelRepositoryToolOptions;\n };\n}\n\nexport interface ModelReviewUsage {\n inputTokens?: number;\n outputTokens?: number;\n}\n\nexport interface ModelReviewResult<T = unknown> {\n output: T;\n provider: string;\n model: string;\n usage?: ModelReviewUsage;\n citations?: readonly ModelRepositoryCitation[];\n retrieval?: ModelRepositoryRetrieval;\n}\n\nexport interface ReviewModel {\n review<T = unknown>(request: ModelReviewRequest<T>): Promise<ModelReviewResult<T>>;\n}\n\nexport interface BrokerReviewModelOptions {\n maximumAttempts?: number;\n initialRetryDelayMs?: number;\n random?: () => number;\n}\n\n/**\n * Request a short noun-phrase concern suitable after \"I would address …\".\n * Implemented by the SDK via {@link ReviewModel.review} (CLI broker pass-through).\n */\nexport interface ModelConcernRequest {\n /** Free-form title, clause, or draft concern to rewrite. */\n text: string;\n budget?: ModelReviewBudget;\n /**\n * Extra attempts when the model returns a phrase that fails noun-phrase validation.\n * Defaults to 1 retry (2 total attempts).\n */\n maxAttempts?: number;\n}\n\nexport interface ModelConcernResult {\n /** Validated noun phrase (see requireOpinionConcern). */\n concern: string;\n /** False when `text` was already a valid noun phrase (no broker call). */\n rewritten: boolean;\n provider: string;\n model: string;\n usage?: ModelReviewUsage;\n}\n\n/** Rule-context model: broker review plus opinion-concern rewrite. */\nexport type ContextualReviewModel = ReviewModel & {\n concern(request: ModelConcernRequest): Promise<ModelConcernResult>;\n};\n\nexport type ModelEnvironment = Readonly<Record<string, string | undefined>>;\n\ninterface ModelBrokerRequest extends Omit<ModelReviewRequest, \"validation\" | \"tools\"> {\n protocolVersion: typeof ADVERSARY_MODEL_PROTOCOL_VERSION;\n}\n\ninterface ModelBrokerResponse {\n protocolVersion: typeof ADVERSARY_MODEL_PROTOCOL_VERSION;\n output: unknown;\n provider: string;\n model: string;\n usage?: ModelReviewUsage;\n}\n\ninterface ModelBrokerErrorResponse {\n error?: {\n code?: string;\n message?: string;\n retryable?: boolean;\n };\n}\n\ntype NormalizedModelReviewRequest = Omit<ModelReviewRequest, \"budget\" | \"validation\" | \"tools\"> & {\n budget: Required<ModelReviewBudget>;\n};\n\nexport class ModelUnavailableError extends Error {\n constructor(message = \"Model review is unavailable for this adversary execution.\") {\n super(message);\n this.name = \"ModelUnavailableError\";\n }\n}\n\nexport class ModelReviewError extends Error {\n readonly code?: string;\n readonly retryable: boolean;\n readonly diagnostics?: Readonly<Record<string, unknown>>;\n\n constructor(\n message: string,\n options: {\n code?: string;\n retryable?: boolean;\n diagnostics?: Readonly<Record<string, unknown>>;\n } = {},\n ) {\n super(message);\n this.name = \"ModelReviewError\";\n this.code = options.code;\n this.diagnostics = options.diagnostics;\n this.retryable = options.retryable ?? false;\n }\n}\n\nexport function createModelFromEnvironment(\n environment: ModelEnvironment = process.env,\n): ReviewModel {\n const endpoint = environment[ADVERSARY_MODEL_ENDPOINT_ENV]?.trim();\n const token = environment[ADVERSARY_MODEL_TOKEN_ENV]?.trim();\n if (endpoint === undefined || endpoint === \"\" || token === undefined || token === \"\") {\n return unavailableModel();\n }\n return new BrokerReviewModel(endpoint, token);\n}\n\nexport function unavailableModel(): ReviewModel {\n return Object.freeze({\n async review(): Promise<never> {\n throw new ModelUnavailableError();\n },\n });\n}\n\nexport class BrokerReviewModel implements ReviewModel {\n readonly endpoint: string;\n readonly #token: string;\n readonly #maximumAttempts: number;\n readonly #initialRetryDelayMs: number;\n readonly #random: () => number;\n\n constructor(endpoint: string, token: string, options: BrokerReviewModelOptions = {}) {\n const parsed = new URL(endpoint);\n if (\n parsed.protocol !== \"http:\" ||\n (parsed.hostname !== \"127.0.0.1\" &&\n parsed.hostname !== \"::1\" &&\n parsed.hostname !== \"[::1]\" &&\n parsed.hostname !== \"localhost\")\n ) {\n throw new ModelReviewError(\n \"The model broker endpoint must use HTTP on the local loopback interface.\",\n { code: \"invalid_broker_endpoint\" },\n );\n }\n if (token.trim() === \"\") {\n throw new ModelReviewError(\"The model broker token must not be empty.\", {\n code: \"invalid_broker_token\",\n });\n }\n this.endpoint = parsed.toString();\n this.#token = token;\n const maximumAttempts = options.maximumAttempts ?? DEFAULT_BROKER_MAXIMUM_ATTEMPTS;\n const initialRetryDelayMs = options.initialRetryDelayMs ?? DEFAULT_BROKER_RETRY_DELAY_MS;\n requireIntegerRange(maximumAttempts, \"maximumAttempts\", 1, 5);\n requireIntegerRange(initialRetryDelayMs, \"initialRetryDelayMs\", 0, MAX_BROKER_RETRY_DELAY_MS);\n this.#maximumAttempts = maximumAttempts;\n this.#initialRetryDelayMs = initialRetryDelayMs;\n this.#random = options.random ?? Math.random;\n }\n\n async review<T = unknown>(request: ModelReviewRequest<T>): Promise<ModelReviewResult<T>> {\n if (request.tools?.repository !== undefined) {\n throw new ModelReviewError(\n \"Repository model tools require ctx.model so the SDK can enforce the repository boundary.\",\n { code: \"invalid_model_request\" },\n );\n }\n const normalized = normalizeRequest(request);\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), normalized.budget.timeoutMs);\n try {\n for (let attempt = 1; attempt <= this.#maximumAttempts; attempt += 1) {\n try {\n return await this.#reviewOnce<T>(normalized, controller.signal);\n } catch (error) {\n if (\n !(error instanceof ModelReviewError) ||\n !error.retryable ||\n controller.signal.aborted ||\n attempt === this.#maximumAttempts\n ) {\n throw error;\n }\n const exponential = Math.min(\n MAX_BROKER_RETRY_DELAY_MS,\n this.#initialRetryDelayMs * 2 ** (attempt - 1),\n );\n const jittered = Math.round(exponential * (0.75 + 0.5 * this.#random()));\n await waitForRetry(jittered, controller.signal, normalized.budget.timeoutMs);\n }\n }\n throw new ModelReviewError(\"Model broker retry loop exhausted unexpectedly.\", {\n code: \"broker_unavailable\",\n retryable: true,\n });\n } finally {\n clearTimeout(timeout);\n }\n }\n\n async #reviewOnce<T>(\n normalized: NormalizedModelReviewRequest,\n signal: AbortSignal,\n ): Promise<ModelReviewResult<T>> {\n let response: Response;\n try {\n response = await fetch(this.endpoint, {\n method: \"POST\",\n headers: {\n accept: \"application/json\",\n authorization: `Bearer ${this.#token}`,\n \"content-type\": \"application/json\",\n \"x-adversary-model-protocol\": String(ADVERSARY_MODEL_PROTOCOL_VERSION),\n },\n body: JSON.stringify({\n protocolVersion: ADVERSARY_MODEL_PROTOCOL_VERSION,\n prompt: normalized.prompt,\n input: normalized.input,\n schema: normalized.schema,\n budget: normalized.budget,\n } satisfies ModelBrokerRequest),\n signal,\n });\n } catch (error) {\n if (signal.aborted) {\n throw modelTimeoutError(normalized.budget.timeoutMs);\n }\n throw new ModelReviewError(\n `Model broker request failed: ${error instanceof Error ? error.message : String(error)}`,\n { code: \"broker_unavailable\", retryable: true },\n );\n }\n\n let body: string;\n try {\n body = await readBoundedResponse(response);\n } catch (error) {\n if (signal.aborted) {\n throw modelTimeoutError(normalized.budget.timeoutMs);\n }\n throw error;\n }\n let decoded: unknown;\n try {\n decoded = JSON.parse(body);\n } catch {\n throw new ModelReviewError(\"Model broker returned malformed JSON.\", {\n code: \"invalid_broker_response\",\n });\n }\n if (!response.ok) {\n const failure = decoded as ModelBrokerErrorResponse;\n throw new ModelReviewError(\n failure.error?.message ?? `Model broker returned HTTP ${response.status}.`,\n {\n code: failure.error?.code ?? \"model_review_failed\",\n retryable: failure.error?.retryable ?? response.status >= 500,\n },\n );\n }\n\n const envelope = requireBrokerResponse(decoded);\n validateModelOutput(normalized.schema, envelope.output);\n return {\n output: envelope.output as T,\n provider: envelope.provider,\n model: envelope.model,\n ...(envelope.usage === undefined ? {} : { usage: envelope.usage }),\n };\n }\n}\n\n/**\n * Run adversary-owned semantic validation with SDK-owned bounded regeneration.\n *\n * Each retry receives the validator failure as trusted SDK feedback while retaining the\n * original input. The original timeout is shared by all validation attempts, and usage is\n * aggregated across them. Repository callers may decorate the raw result with citations before\n * validation without repeating repository retrieval.\n */\nexport async function reviewWithValidation<T>(\n model: ReviewModel,\n request: ModelReviewRequest<T>,\n decorate: (result: ModelReviewResult<T>) => ModelReviewResult<T> = (result) => result,\n): Promise<ModelReviewResult<T>> {\n const validation = request.validation;\n const { validation: _validation, tools: _tools, ...baseRequest } = request;\n if (validation === undefined) return decorate(await model.review<T>(baseRequest));\n\n const maximumAttempts = validation.maximumAttempts ?? DEFAULT_VALIDATION_MAXIMUM_ATTEMPTS;\n requireIntegerRange(\n maximumAttempts,\n \"validation.maximumAttempts\",\n 1,\n MAX_VALIDATION_MAXIMUM_ATTEMPTS,\n );\n const timeoutMs = request.budget?.timeoutMs ?? DEFAULT_MODEL_TIMEOUT_MS;\n const startedAt = Date.now();\n let usage: ModelReviewUsage = {};\n let feedback: string | undefined;\n\n for (let attempt = 1; attempt <= maximumAttempts; attempt += 1) {\n const elapsed = Date.now() - startedAt;\n const remainingTimeoutMs = timeoutMs - elapsed;\n if (remainingTimeoutMs <= 0) throw modelTimeoutError(timeoutMs);\n const result = decorate(\n await model.review<T>({\n ...baseRequest,\n prompt:\n feedback === undefined\n ? baseRequest.prompt\n : `${baseRequest.prompt}\\n\\nSDK VALIDATION FEEDBACK:\\nThe previous response failed adversary-defined validation. Correct the response using this trusted validation result and return the complete response again.\\n${JSON.stringify({ attempt, error: feedback })}`,\n budget: {\n ...baseRequest.budget,\n timeoutMs: remainingTimeoutMs,\n },\n }),\n );\n usage = addModelUsage(usage, result.usage);\n try {\n await validation.validate(result);\n return {\n ...result,\n ...(usage.inputTokens === undefined && usage.outputTokens === undefined ? {} : { usage }),\n };\n } catch (error) {\n feedback = boundedValidationFeedback(error);\n if (attempt === maximumAttempts) {\n throw new ModelReviewError(\n `Model output failed adversary validation after ${maximumAttempts} attempts: ${feedback}`,\n { code: \"model_validation_failed\", retryable: false },\n );\n }\n }\n }\n throw new ModelReviewError(\"Model validation retry loop exhausted unexpectedly.\", {\n code: \"model_validation_failed\",\n retryable: false,\n });\n}\n\nfunction boundedValidationFeedback(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n const encoded = Buffer.from(message, \"utf8\");\n return encoded.byteLength <= MAX_VALIDATION_FEEDBACK_BYTES\n ? message\n : `${encoded.subarray(0, MAX_VALIDATION_FEEDBACK_BYTES).toString(\"utf8\")}…`;\n}\n\nfunction addModelUsage(\n total: ModelReviewUsage,\n next: ModelReviewUsage | undefined,\n): ModelReviewUsage {\n if (next === undefined) return total;\n return {\n ...(total.inputTokens === undefined && next.inputTokens === undefined\n ? {}\n : { inputTokens: (total.inputTokens ?? 0) + (next.inputTokens ?? 0) }),\n ...(total.outputTokens === undefined && next.outputTokens === undefined\n ? {}\n : { outputTokens: (total.outputTokens ?? 0) + (next.outputTokens ?? 0) }),\n };\n}\n\nasync function waitForRetry(\n delayMs: number,\n signal: AbortSignal,\n timeoutMs: number,\n): Promise<void> {\n if (signal.aborted) {\n throw modelTimeoutError(timeoutMs);\n }\n await new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(modelTimeoutError(timeoutMs));\n };\n const timer = setTimeout(() => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve();\n }, delayMs);\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nfunction modelTimeoutError(timeoutMs: number): ModelReviewError {\n return new ModelReviewError(`Model review exceeded its ${timeoutMs}ms timeout.`, {\n code: \"model_timeout\",\n retryable: true,\n });\n}\n\nfunction normalizeRequest(request: ModelReviewRequest): NormalizedModelReviewRequest {\n if (typeof request !== \"object\" || request === null) {\n throw new ModelReviewError(\"Model review request must be an object.\", {\n code: \"invalid_model_request\",\n });\n }\n if (typeof request.prompt !== \"string\" || request.prompt.trim() === \"\") {\n throw new ModelReviewError(\"Model review prompt must be a non-empty string.\", {\n code: \"invalid_model_request\",\n });\n }\n const promptBytes = Buffer.byteLength(request.prompt, \"utf8\");\n if (promptBytes > MAX_PROMPT_BYTES) {\n throw new ModelReviewError(`Model review prompt exceeds ${MAX_PROMPT_BYTES} bytes.`, {\n code: \"model_request_too_large\",\n });\n }\n requireJsonSize(request.input, \"input\", MAX_INPUT_BYTES);\n if (\n typeof request.schema !== \"object\" ||\n request.schema === null ||\n Array.isArray(request.schema)\n ) {\n throw new ModelReviewError(\"Model review schema must be a JSON Schema object.\", {\n code: \"invalid_model_schema\",\n });\n }\n requireJsonSize(request.schema, \"schema\", MAX_SCHEMA_BYTES);\n\n const maximumOutputTokens = request.budget?.maximumOutputTokens ?? DEFAULT_MAXIMUM_OUTPUT_TOKENS;\n const timeoutMs = request.budget?.timeoutMs ?? DEFAULT_MODEL_TIMEOUT_MS;\n requireIntegerRange(\n maximumOutputTokens,\n \"budget.maximumOutputTokens\",\n 1,\n MAX_MAXIMUM_OUTPUT_TOKENS,\n );\n requireIntegerRange(timeoutMs, \"budget.timeoutMs\", 1, MAX_MODEL_TIMEOUT_MS);\n return {\n prompt: request.prompt,\n input: request.input,\n schema: request.schema,\n budget: { maximumOutputTokens, timeoutMs },\n };\n}\n\nfunction requireJsonSize(value: unknown, name: string, maximum: number): void {\n let encoded: string | undefined;\n try {\n encoded = JSON.stringify(value);\n } catch (error) {\n throw new ModelReviewError(\n `Model review ${name} must be JSON-serializable: ${error instanceof Error ? error.message : String(error)}`,\n { code: \"invalid_model_request\" },\n );\n }\n if (encoded === undefined) {\n throw new ModelReviewError(`Model review ${name} must be JSON-serializable.`, {\n code: \"invalid_model_request\",\n });\n }\n if (Buffer.byteLength(encoded, \"utf8\") > maximum) {\n throw new ModelReviewError(`Model review ${name} exceeds ${maximum} bytes.`, {\n code: \"model_request_too_large\",\n });\n }\n}\n\nfunction requireIntegerRange(value: number, name: string, minimum: number, maximum: number): void {\n if (!Number.isInteger(value) || value < minimum || value > maximum) {\n throw new ModelReviewError(`${name} must be an integer from ${minimum} through ${maximum}.`, {\n code: \"invalid_model_budget\",\n });\n }\n}\n\nasync function readBoundedResponse(response: Response): Promise<string> {\n const declared = response.headers.get(\"content-length\");\n if (declared !== null && Number(declared) > MAX_RESPONSE_BYTES) {\n throw new ModelReviewError(`Model broker response exceeds ${MAX_RESPONSE_BYTES} bytes.`, {\n code: \"model_response_too_large\",\n });\n }\n if (response.body === null) {\n return \"\";\n }\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let size = 0;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n size += value.byteLength;\n if (size > MAX_RESPONSE_BYTES) {\n await reader.cancel();\n throw new ModelReviewError(`Model broker response exceeds ${MAX_RESPONSE_BYTES} bytes.`, {\n code: \"model_response_too_large\",\n });\n }\n chunks.push(value);\n }\n const joined = new Uint8Array(size);\n let offset = 0;\n for (const chunk of chunks) {\n joined.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return new TextDecoder().decode(joined);\n}\n\nfunction requireBrokerResponse(value: unknown): ModelBrokerResponse {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new ModelReviewError(\"Model broker response must be an object.\", {\n code: \"invalid_broker_response\",\n });\n }\n const response = value as Partial<ModelBrokerResponse>;\n if (response.protocolVersion !== ADVERSARY_MODEL_PROTOCOL_VERSION) {\n throw new ModelReviewError(\n `Model broker protocol version must be ${ADVERSARY_MODEL_PROTOCOL_VERSION}.`,\n { code: \"unsupported_model_protocol\" },\n );\n }\n if (typeof response.provider !== \"string\" || response.provider.trim() === \"\") {\n throw new ModelReviewError(\"Model broker response provider must be a non-empty string.\", {\n code: \"invalid_broker_response\",\n });\n }\n if (typeof response.model !== \"string\" || response.model.trim() === \"\") {\n throw new ModelReviewError(\"Model broker response model must be a non-empty string.\", {\n code: \"invalid_broker_response\",\n });\n }\n if (!Object.hasOwn(response, \"output\")) {\n throw new ModelReviewError(\"Model broker response is missing output.\", {\n code: \"invalid_broker_response\",\n });\n }\n if (response.usage !== undefined) {\n validateUsage(response.usage);\n }\n return response as ModelBrokerResponse;\n}\n\nfunction validateUsage(value: unknown): asserts value is ModelReviewUsage {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new ModelReviewError(\"Model broker response usage must be an object.\", {\n code: \"invalid_broker_response\",\n });\n }\n for (const field of [\"inputTokens\", \"outputTokens\"] as const) {\n const count = (value as ModelReviewUsage)[field];\n if (count !== undefined && (!Number.isInteger(count) || count < 0)) {\n throw new ModelReviewError(\n `Model broker response usage.${field} must be a non-negative integer.`,\n {\n code: \"invalid_broker_response\",\n },\n );\n }\n }\n}\n\nfunction validateModelOutput(schema: Record<string, unknown>, output: unknown): void {\n const ajv = new Ajv2020({ allErrors: true, strict: true });\n let validate: ReturnType<Ajv2020[\"compile\"]>;\n try {\n validate = ajv.compile(schema);\n } catch (error) {\n throw new ModelReviewError(\n `Model review schema is invalid: ${error instanceof Error ? error.message : String(error)}`,\n { code: \"invalid_model_schema\" },\n );\n }\n if (!validate(output)) {\n const detail = ajv.errorsText(validate.errors, { separator: \"; \" });\n throw new ModelReviewError(`Model output does not match the requested schema: ${detail}`, {\n code: \"invalid_model_output\",\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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","sourcesContent":["import { Ajv2020 } from \"ajv/dist/2020.js\";\nimport { Agent, type Dispatcher } from \"undici\";\nimport { modelAttemptDiagnostics } from \"./model-diagnostics.js\";\nimport type {\n ModelRepositoryCitation,\n ModelRepositoryRetrieval,\n ModelRepositoryToolOptions,\n} from \"./repository-model.js\";\n\nexport const ADVERSARY_MODEL_PROTOCOL_VERSION = 1;\nexport const ADVERSARY_MODEL_ENDPOINT_ENV = \"ADVERSARY_MODEL_ENDPOINT\";\nexport const ADVERSARY_MODEL_TOKEN_ENV = \"ADVERSARY_MODEL_TOKEN\";\n\nconst DEFAULT_MODEL_TIMEOUT_MS = 600_000;\nconst MAX_MODEL_TIMEOUT_MS = 600_000;\nconst DEFAULT_MAXIMUM_OUTPUT_TOKENS = 8_192;\nconst MAX_MAXIMUM_OUTPUT_TOKENS = 65_536;\nconst MAX_PROMPT_BYTES = 256 << 10;\nconst MAX_INPUT_BYTES = 4 << 20;\nconst MAX_SCHEMA_BYTES = 512 << 10;\nconst MAX_RESPONSE_BYTES = 4 << 20;\nconst DEFAULT_BROKER_MAXIMUM_ATTEMPTS = 3;\nconst DEFAULT_BROKER_RETRY_DELAY_MS = 250;\nconst MAX_BROKER_RETRY_DELAY_MS = 5_000;\nconst DEFAULT_VALIDATION_MAXIMUM_ATTEMPTS = 3;\nconst MAX_VALIDATION_MAXIMUM_ATTEMPTS = 5;\nconst MAX_VALIDATION_FEEDBACK_BYTES = 8 << 10;\n\n// Fetch supplies its own five-minute header timeout, overriding Agent defaults.\n// Override dispatch options for this review only; its shared AbortSignal remains\n// the authoritative deadline across connection, headers, body, and retries.\nclass ModelBrokerDispatcher extends Agent {\n constructor(private readonly deadlineMs: number) {\n super({ connectTimeout: deadlineMs });\n }\n\n override dispatch(\n options: Dispatcher.DispatchOptions,\n handler: Dispatcher.DispatchHandlers,\n ): boolean {\n return super.dispatch(\n {\n ...options,\n headersTimeout: this.deadlineMs,\n bodyTimeout: this.deadlineMs,\n },\n handler,\n );\n }\n}\n\nexport interface ModelReviewBudget {\n maximumOutputTokens?: number;\n timeoutMs?: number;\n}\n\nexport interface ModelReviewValidation<T = unknown> {\n /** Validate a completed model result. Throw to retry generation with the error as feedback. */\n validate(result: ModelReviewResult<T>): void | Promise<void>;\n /** Total generation attempts, including the first. Defaults to 3 and is capped at 5. */\n maximumAttempts?: number;\n}\n\nexport interface ModelReviewRequest<T = unknown> {\n /** Local timing classification only; never sent to the broker or model. */\n diagnosticStage?: \"model_review\" | \"repository_planning\";\n prompt: string;\n input: unknown;\n schema: Record<string, unknown>;\n budget?: ModelReviewBudget;\n validation?: ModelReviewValidation<T>;\n tools?: {\n repository: ModelRepositoryToolOptions;\n };\n}\n\nexport interface ModelReviewUsage {\n inputTokens?: number;\n outputTokens?: number;\n}\n\nexport interface ModelReviewResult<T = unknown> {\n output: T;\n provider: string;\n model: string;\n usage?: ModelReviewUsage;\n citations?: readonly ModelRepositoryCitation[];\n retrieval?: ModelRepositoryRetrieval;\n}\n\nexport interface ReviewModel {\n review<T = unknown>(request: ModelReviewRequest<T>): Promise<ModelReviewResult<T>>;\n}\n\nexport interface BrokerReviewModelOptions {\n maximumAttempts?: number;\n initialRetryDelayMs?: number;\n random?: () => number;\n}\n\n/**\n * Request a short noun-phrase concern suitable after \"I would address …\".\n * Implemented by the SDK via {@link ReviewModel.review} (CLI broker pass-through).\n */\nexport interface ModelConcernRequest {\n /** Free-form title, clause, or draft concern to rewrite. */\n text: string;\n budget?: ModelReviewBudget;\n /**\n * Extra attempts when the model returns a phrase that fails noun-phrase validation.\n * Defaults to 1 retry (2 total attempts).\n */\n maxAttempts?: number;\n}\n\nexport interface ModelConcernResult {\n /** Validated noun phrase (see requireOpinionConcern). */\n concern: string;\n /** False when `text` was already a valid noun phrase (no broker call). */\n rewritten: boolean;\n provider: string;\n model: string;\n usage?: ModelReviewUsage;\n}\n\n/** Rule-context model: broker review plus opinion-concern rewrite. */\nexport type ContextualReviewModel = ReviewModel & {\n concern(request: ModelConcernRequest): Promise<ModelConcernResult>;\n};\n\nexport type ModelEnvironment = Readonly<Record<string, string | undefined>>;\n\ninterface ModelBrokerRequest\n extends Omit<ModelReviewRequest, \"validation\" | \"tools\" | \"diagnosticStage\"> {\n protocolVersion: typeof ADVERSARY_MODEL_PROTOCOL_VERSION;\n}\n\ninterface ModelBrokerResponse {\n protocolVersion: typeof ADVERSARY_MODEL_PROTOCOL_VERSION;\n output: unknown;\n provider: string;\n model: string;\n usage?: ModelReviewUsage;\n}\n\ninterface ModelBrokerErrorResponse {\n error?: {\n code?: string;\n message?: string;\n retryable?: boolean;\n };\n}\n\ntype NormalizedModelReviewRequest = Omit<\n ModelReviewRequest,\n \"budget\" | \"validation\" | \"tools\" | \"diagnosticStage\"\n> & {\n budget: Required<ModelReviewBudget>;\n};\n\nexport class ModelUnavailableError extends Error {\n constructor(message = \"Model review is unavailable for this adversary execution.\") {\n super(message);\n this.name = \"ModelUnavailableError\";\n }\n}\n\nexport class ModelReviewError extends Error {\n readonly code?: string;\n readonly retryable: boolean;\n readonly diagnostics?: Readonly<Record<string, unknown>>;\n\n constructor(\n message: string,\n options: {\n code?: string;\n retryable?: boolean;\n diagnostics?: Readonly<Record<string, unknown>>;\n } = {},\n ) {\n super(message);\n this.name = \"ModelReviewError\";\n this.code = options.code;\n this.diagnostics = options.diagnostics;\n this.retryable = options.retryable ?? false;\n }\n}\n\nexport function createModelFromEnvironment(\n environment: ModelEnvironment = process.env,\n): ReviewModel {\n const endpoint = environment[ADVERSARY_MODEL_ENDPOINT_ENV]?.trim();\n const token = environment[ADVERSARY_MODEL_TOKEN_ENV]?.trim();\n if (endpoint === undefined || endpoint === \"\" || token === undefined || token === \"\") {\n return unavailableModel();\n }\n return new BrokerReviewModel(endpoint, token);\n}\n\nexport function unavailableModel(): ReviewModel {\n return Object.freeze({\n async review(): Promise<never> {\n throw new ModelUnavailableError();\n },\n });\n}\n\nexport class BrokerReviewModel implements ReviewModel {\n readonly endpoint: string;\n readonly #token: string;\n readonly #maximumAttempts: number;\n readonly #initialRetryDelayMs: number;\n readonly #random: () => number;\n\n constructor(endpoint: string, token: string, options: BrokerReviewModelOptions = {}) {\n const parsed = new URL(endpoint);\n if (\n parsed.protocol !== \"http:\" ||\n (parsed.hostname !== \"127.0.0.1\" &&\n parsed.hostname !== \"::1\" &&\n parsed.hostname !== \"[::1]\" &&\n parsed.hostname !== \"localhost\")\n ) {\n throw new ModelReviewError(\n \"The model broker endpoint must use HTTP on the local loopback interface.\",\n { code: \"invalid_broker_endpoint\" },\n );\n }\n if (token.trim() === \"\") {\n throw new ModelReviewError(\"The model broker token must not be empty.\", {\n code: \"invalid_broker_token\",\n });\n }\n this.endpoint = parsed.toString();\n this.#token = token;\n const maximumAttempts = options.maximumAttempts ?? DEFAULT_BROKER_MAXIMUM_ATTEMPTS;\n const initialRetryDelayMs = options.initialRetryDelayMs ?? DEFAULT_BROKER_RETRY_DELAY_MS;\n requireIntegerRange(maximumAttempts, \"maximumAttempts\", 1, 5);\n requireIntegerRange(initialRetryDelayMs, \"initialRetryDelayMs\", 0, MAX_BROKER_RETRY_DELAY_MS);\n this.#maximumAttempts = maximumAttempts;\n this.#initialRetryDelayMs = initialRetryDelayMs;\n this.#random = options.random ?? Math.random;\n }\n\n async review<T = unknown>(request: ModelReviewRequest<T>): Promise<ModelReviewResult<T>> {\n if (request.tools?.repository !== undefined) {\n throw new ModelReviewError(\n \"Repository model tools require ctx.model so the SDK can enforce the repository boundary.\",\n { code: \"invalid_model_request\" },\n );\n }\n const normalized = normalizeRequest(request);\n const diagnostics = modelAttemptDiagnostics(\n normalized.budget.timeoutMs,\n request.diagnosticStage === \"repository_planning\" ? \"repository_planning\" : \"model_review\",\n );\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), normalized.budget.timeoutMs);\n const dispatcher = new ModelBrokerDispatcher(normalized.budget.timeoutMs);\n try {\n for (let attempt = 1; attempt <= this.#maximumAttempts; attempt += 1) {\n const outcome = await this.#reviewAttempt<T>(\n normalized,\n controller.signal,\n dispatcher,\n diagnostics,\n attempt,\n );\n if (outcome.ok) return outcome.result;\n const error = outcome.error;\n if (\n !(error instanceof ModelReviewError) ||\n !error.retryable ||\n controller.signal.aborted ||\n attempt === this.#maximumAttempts\n ) {\n throw error;\n }\n await this.#waitForRetry(\n attempt,\n controller.signal,\n normalized.budget.timeoutMs,\n diagnostics,\n );\n }\n throw new ModelReviewError(\"Model broker retry loop exhausted unexpectedly.\", {\n code: \"broker_unavailable\",\n retryable: true,\n });\n } finally {\n clearTimeout(timeout);\n // Cleanup must not replace the typed request error or a successful response.\n try {\n await dispatcher.destroy();\n } catch {\n // The dispatcher is no longer used after this request.\n }\n }\n }\n\n // One attempt owns its timing and error outcome; retry decisions belong to review().\n async #reviewAttempt<T>(\n normalized: NormalizedModelReviewRequest,\n signal: AbortSignal,\n dispatcher: ModelBrokerDispatcher,\n diagnostics: ReturnType<typeof modelAttemptDiagnostics>,\n attempt: number,\n ): Promise<{ ok: true; result: ModelReviewResult<T> } | { ok: false; error: unknown }> {\n const finish = diagnostics.start(attempt);\n try {\n const result = await this.#reviewOnce<T>(normalized, signal, dispatcher);\n finish(\"succeeded\", result.provider, result.model);\n return { ok: true, result };\n } catch (error) {\n finish(\n \"failed\",\n undefined,\n undefined,\n error instanceof ModelReviewError ? error.code : \"broker_unavailable\",\n );\n return { ok: false, error };\n }\n }\n\n // Keep backoff calculation and its terminal timeout diagnostic together.\n async #waitForRetry(\n attempt: number,\n signal: AbortSignal,\n timeoutMs: number,\n diagnostics: ReturnType<typeof modelAttemptDiagnostics>,\n ): Promise<void> {\n const exponential = Math.min(\n MAX_BROKER_RETRY_DELAY_MS,\n this.#initialRetryDelayMs * 2 ** (attempt - 1),\n );\n const jittered = Math.round(exponential * (0.75 + 0.5 * this.#random()));\n const retryDelayFailed = diagnostics.startRetryDelay(attempt);\n try {\n await waitForRetry(jittered, signal, timeoutMs);\n } catch (error) {\n retryDelayFailed(\n error instanceof ModelReviewError\n ? (error.code ?? \"model_review_failed\")\n : \"model_review_failed\",\n );\n throw error;\n }\n }\n\n async #reviewOnce<T>(\n normalized: NormalizedModelReviewRequest,\n signal: AbortSignal,\n dispatcher: ModelBrokerDispatcher,\n ): Promise<ModelReviewResult<T>> {\n let response: Response;\n try {\n response = await fetch(this.endpoint, {\n method: \"POST\",\n headers: {\n accept: \"application/json\",\n authorization: `Bearer ${this.#token}`,\n \"content-type\": \"application/json\",\n \"x-adversary-model-protocol\": String(ADVERSARY_MODEL_PROTOCOL_VERSION),\n },\n body: JSON.stringify({\n protocolVersion: ADVERSARY_MODEL_PROTOCOL_VERSION,\n prompt: normalized.prompt,\n input: normalized.input,\n schema: normalized.schema,\n budget: normalized.budget,\n } satisfies ModelBrokerRequest),\n signal,\n dispatcher,\n } as RequestInit & { dispatcher: Dispatcher });\n } catch (error) {\n throw brokerTransportError(error, signal, normalized.budget.timeoutMs);\n }\n\n let body: string;\n try {\n body = await readBoundedResponse(response);\n } catch (error) {\n throw brokerTransportError(error, signal, normalized.budget.timeoutMs);\n }\n let decoded: unknown;\n try {\n decoded = JSON.parse(body);\n } catch {\n throw new ModelReviewError(\"Model broker returned malformed JSON.\", {\n code: \"invalid_broker_response\",\n });\n }\n if (!response.ok) {\n const failure = decoded as ModelBrokerErrorResponse;\n throw new ModelReviewError(\n failure.error?.message ?? `Model broker returned HTTP ${response.status}.`,\n {\n code: failure.error?.code ?? \"model_review_failed\",\n retryable: failure.error?.retryable ?? response.status >= 500,\n },\n );\n }\n\n const envelope = requireBrokerResponse(decoded);\n validateModelOutput(normalized.schema, envelope.output);\n return {\n output: envelope.output as T,\n provider: envelope.provider,\n model: envelope.model,\n ...(envelope.usage === undefined ? {} : { usage: envelope.usage }),\n };\n }\n}\n\n/**\n * Run adversary-owned semantic validation with SDK-owned bounded regeneration.\n *\n * Each retry receives the validator failure as trusted SDK feedback while retaining the\n * original input. The original timeout is shared by all validation attempts, and usage is\n * aggregated across them. Repository callers may decorate the raw result with citations before\n * validation without repeating repository retrieval.\n */\nexport async function reviewWithValidation<T>(\n model: ReviewModel,\n request: ModelReviewRequest<T>,\n decorate: (result: ModelReviewResult<T>) => ModelReviewResult<T> = (result) => result,\n): Promise<ModelReviewResult<T>> {\n const validation = request.validation;\n const { validation: _validation, tools: _tools, ...baseRequest } = request;\n if (validation === undefined) return decorate(await model.review<T>(baseRequest));\n\n const maximumAttempts = validation.maximumAttempts ?? DEFAULT_VALIDATION_MAXIMUM_ATTEMPTS;\n requireIntegerRange(\n maximumAttempts,\n \"validation.maximumAttempts\",\n 1,\n MAX_VALIDATION_MAXIMUM_ATTEMPTS,\n );\n const timeoutMs = request.budget?.timeoutMs ?? DEFAULT_MODEL_TIMEOUT_MS;\n const startedAt = Date.now();\n let usage: ModelReviewUsage = {};\n let feedback: string | undefined;\n\n for (let attempt = 1; attempt <= maximumAttempts; attempt += 1) {\n const elapsed = Date.now() - startedAt;\n const remainingTimeoutMs = timeoutMs - elapsed;\n if (remainingTimeoutMs <= 0) throw modelTimeoutError(timeoutMs);\n const result = decorate(\n await model.review<T>({\n ...baseRequest,\n prompt:\n feedback === undefined\n ? baseRequest.prompt\n : `${baseRequest.prompt}\\n\\nSDK VALIDATION FEEDBACK:\\nThe previous response failed adversary-defined validation. Correct the response using this trusted validation result and return the complete response again.\\n${JSON.stringify({ attempt, error: feedback })}`,\n budget: {\n ...baseRequest.budget,\n timeoutMs: remainingTimeoutMs,\n },\n }),\n );\n usage = addModelUsage(usage, result.usage);\n try {\n await validation.validate(result);\n return {\n ...result,\n ...(usage.inputTokens === undefined && usage.outputTokens === undefined ? {} : { usage }),\n };\n } catch (error) {\n feedback = boundedValidationFeedback(error);\n if (attempt === maximumAttempts) {\n throw new ModelReviewError(\n `Model output failed adversary validation after ${maximumAttempts} attempts: ${feedback}`,\n { code: \"model_validation_failed\", retryable: false },\n );\n }\n }\n }\n throw new ModelReviewError(\"Model validation retry loop exhausted unexpectedly.\", {\n code: \"model_validation_failed\",\n retryable: false,\n });\n}\n\nfunction boundedValidationFeedback(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n const encoded = Buffer.from(message, \"utf8\");\n return encoded.byteLength <= MAX_VALIDATION_FEEDBACK_BYTES\n ? message\n : `${encoded.subarray(0, MAX_VALIDATION_FEEDBACK_BYTES).toString(\"utf8\")}…`;\n}\n\nfunction addModelUsage(\n total: ModelReviewUsage,\n next: ModelReviewUsage | undefined,\n): ModelReviewUsage {\n if (next === undefined) return total;\n return {\n ...(total.inputTokens === undefined && next.inputTokens === undefined\n ? {}\n : { inputTokens: (total.inputTokens ?? 0) + (next.inputTokens ?? 0) }),\n ...(total.outputTokens === undefined && next.outputTokens === undefined\n ? {}\n : { outputTokens: (total.outputTokens ?? 0) + (next.outputTokens ?? 0) }),\n };\n}\n\nasync function waitForRetry(\n delayMs: number,\n signal: AbortSignal,\n timeoutMs: number,\n): Promise<void> {\n if (signal.aborted) {\n throw modelTimeoutError(timeoutMs);\n }\n await new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(modelTimeoutError(timeoutMs));\n };\n const timer = setTimeout(() => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve();\n }, delayMs);\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nfunction modelTimeoutError(timeoutMs: number): ModelReviewError {\n return new ModelReviewError(`Model review exceeded its ${timeoutMs}ms timeout.`, {\n code: \"model_timeout\",\n retryable: true,\n });\n}\n\nfunction normalizeRequest(request: ModelReviewRequest): NormalizedModelReviewRequest {\n if (typeof request !== \"object\" || request === null) {\n throw new ModelReviewError(\"Model review request must be an object.\", {\n code: \"invalid_model_request\",\n });\n }\n if (typeof request.prompt !== \"string\" || request.prompt.trim() === \"\") {\n throw new ModelReviewError(\"Model review prompt must be a non-empty string.\", {\n code: \"invalid_model_request\",\n });\n }\n const promptBytes = Buffer.byteLength(request.prompt, \"utf8\");\n if (promptBytes > MAX_PROMPT_BYTES) {\n throw new ModelReviewError(`Model review prompt exceeds ${MAX_PROMPT_BYTES} bytes.`, {\n code: \"model_request_too_large\",\n });\n }\n requireJsonSize(request.input, \"input\", MAX_INPUT_BYTES);\n if (\n typeof request.schema !== \"object\" ||\n request.schema === null ||\n Array.isArray(request.schema)\n ) {\n throw new ModelReviewError(\"Model review schema must be a JSON Schema object.\", {\n code: \"invalid_model_schema\",\n });\n }\n requireJsonSize(request.schema, \"schema\", MAX_SCHEMA_BYTES);\n\n const maximumOutputTokens = request.budget?.maximumOutputTokens ?? DEFAULT_MAXIMUM_OUTPUT_TOKENS;\n const timeoutMs = request.budget?.timeoutMs ?? DEFAULT_MODEL_TIMEOUT_MS;\n requireIntegerRange(\n maximumOutputTokens,\n \"budget.maximumOutputTokens\",\n 1,\n MAX_MAXIMUM_OUTPUT_TOKENS,\n );\n requireIntegerRange(timeoutMs, \"budget.timeoutMs\", 1, MAX_MODEL_TIMEOUT_MS);\n return {\n prompt: request.prompt,\n input: request.input,\n schema: request.schema,\n budget: { maximumOutputTokens, timeoutMs },\n };\n}\n\nfunction requireJsonSize(value: unknown, name: string, maximum: number): void {\n let encoded: string | undefined;\n try {\n encoded = JSON.stringify(value);\n } catch (error) {\n throw new ModelReviewError(\n `Model review ${name} must be JSON-serializable: ${error instanceof Error ? error.message : String(error)}`,\n { code: \"invalid_model_request\" },\n );\n }\n if (encoded === undefined) {\n throw new ModelReviewError(`Model review ${name} must be JSON-serializable.`, {\n code: \"invalid_model_request\",\n });\n }\n if (Buffer.byteLength(encoded, \"utf8\") > maximum) {\n throw new ModelReviewError(`Model review ${name} exceeds ${maximum} bytes.`, {\n code: \"model_request_too_large\",\n });\n }\n}\n\nfunction requireIntegerRange(value: number, name: string, minimum: number, maximum: number): void {\n if (!Number.isInteger(value) || value < minimum || value > maximum) {\n throw new ModelReviewError(`${name} must be an integer from ${minimum} through ${maximum}.`, {\n code: \"invalid_model_budget\",\n });\n }\n}\n\nfunction brokerTransportError(\n error: unknown,\n signal: AbortSignal,\n timeoutMs: number,\n): ModelReviewError {\n if (signal.aborted) return modelTimeoutError(timeoutMs);\n if (error instanceof ModelReviewError) return error;\n return new ModelReviewError(\n `Model broker request failed: ${error instanceof Error ? error.message : String(error)}`,\n { code: \"broker_unavailable\", retryable: true },\n );\n}\n\nasync function readBoundedResponse(response: Response): Promise<string> {\n const declared = response.headers.get(\"content-length\");\n if (declared !== null && Number(declared) > MAX_RESPONSE_BYTES) {\n throw new ModelReviewError(`Model broker response exceeds ${MAX_RESPONSE_BYTES} bytes.`, {\n code: \"model_response_too_large\",\n });\n }\n if (response.body === null) {\n return \"\";\n }\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let size = 0;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n size += value.byteLength;\n if (size > MAX_RESPONSE_BYTES) {\n await reader.cancel();\n throw new ModelReviewError(`Model broker response exceeds ${MAX_RESPONSE_BYTES} bytes.`, {\n code: \"model_response_too_large\",\n });\n }\n chunks.push(value);\n }\n const joined = new Uint8Array(size);\n let offset = 0;\n for (const chunk of chunks) {\n joined.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return new TextDecoder().decode(joined);\n}\n\nfunction requireBrokerResponse(value: unknown): ModelBrokerResponse {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new ModelReviewError(\"Model broker response must be an object.\", {\n code: \"invalid_broker_response\",\n });\n }\n const response = value as Partial<ModelBrokerResponse>;\n if (response.protocolVersion !== ADVERSARY_MODEL_PROTOCOL_VERSION) {\n throw new ModelReviewError(\n `Model broker protocol version must be ${ADVERSARY_MODEL_PROTOCOL_VERSION}.`,\n { code: \"unsupported_model_protocol\" },\n );\n }\n if (typeof response.provider !== \"string\" || response.provider.trim() === \"\") {\n throw new ModelReviewError(\"Model broker response provider must be a non-empty string.\", {\n code: \"invalid_broker_response\",\n });\n }\n if (typeof response.model !== \"string\" || response.model.trim() === \"\") {\n throw new ModelReviewError(\"Model broker response model must be a non-empty string.\", {\n code: \"invalid_broker_response\",\n });\n }\n if (!Object.hasOwn(response, \"output\")) {\n throw new ModelReviewError(\"Model broker response is missing output.\", {\n code: \"invalid_broker_response\",\n });\n }\n if (response.usage !== undefined) {\n validateUsage(response.usage);\n }\n return response as ModelBrokerResponse;\n}\n\nfunction validateUsage(value: unknown): asserts value is ModelReviewUsage {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new ModelReviewError(\"Model broker response usage must be an object.\", {\n code: \"invalid_broker_response\",\n });\n }\n for (const field of [\"inputTokens\", \"outputTokens\"] as const) {\n const count = (value as ModelReviewUsage)[field];\n if (count !== undefined && (!Number.isInteger(count) || count < 0)) {\n throw new ModelReviewError(\n `Model broker response usage.${field} must be a non-negative integer.`,\n {\n code: \"invalid_broker_response\",\n },\n );\n }\n }\n}\n\nfunction validateModelOutput(schema: Record<string, unknown>, output: unknown): void {\n const ajv = new Ajv2020({ allErrors: true, strict: true });\n let validate: ReturnType<Ajv2020[\"compile\"]>;\n try {\n validate = ajv.compile(schema);\n } catch (error) {\n throw new ModelReviewError(\n `Model review schema is invalid: ${error instanceof Error ? error.message : String(error)}`,\n { code: \"invalid_model_schema\" },\n );\n }\n if (!validate(output)) {\n const detail = ajv.errorsText(validate.errors, { separator: \"; \" });\n throw new ModelReviewError(`Model output does not match the requested schema: ${detail}`, {\n code: \"invalid_model_output\",\n });\n }\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type RepositoryReadReason = "excluded_file" | "symlink_rejected" | "not_regular_file" | "unsafe_path" | "invalid_range" | "range_past_eof" | "binary_file" | "change_context_missing" | "file_not_changed" | "invalid_revision";
|
|
2
|
+
export declare class RepositoryReadError extends Error {
|
|
3
|
+
readonly reason: RepositoryReadReason;
|
|
4
|
+
constructor(reason: RepositoryReadReason, message: string);
|
|
5
|
+
}
|
|
6
|
+
export declare function readErrorReason(error: unknown): string;
|
|
7
|
+
export declare function safeDiagnosticPath(path: string, knownPaths: ReadonlySet<string>): string;
|
|
8
|
+
/** Optional diagnostics must never alter a review result or replace its error. */
|
|
9
|
+
export declare function writeRepositoryDiagnostic(record: Record<string, unknown>): void;
|
|
10
|
+
type Counts = {
|
|
11
|
+
rounds: number;
|
|
12
|
+
toolCalls: number;
|
|
13
|
+
bytes: number;
|
|
14
|
+
};
|
|
15
|
+
type Limits = {
|
|
16
|
+
maxRounds: number;
|
|
17
|
+
maxToolCalls: number;
|
|
18
|
+
maxTotalBytes: number;
|
|
19
|
+
maxBytesPerRead: number;
|
|
20
|
+
maxLinesPerRead: number;
|
|
21
|
+
};
|
|
22
|
+
export declare function repositoryDiagnostics(reviewer: string | undefined, limits: Limits, enabled?: boolean): {
|
|
23
|
+
readingId: `${string}-${string}-${string}-${string}-${string}`;
|
|
24
|
+
emit: (details: Record<string, string | number | boolean>, counts: Counts) => void;
|
|
25
|
+
start: () => void;
|
|
26
|
+
finish: (counts: Counts, complete: boolean) => void;
|
|
27
|
+
};
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=repository-diagnostics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-diagnostics.d.ts","sourceRoot":"","sources":["../src/repository-diagnostics.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,oBAAoB,GAC5B,eAAe,GACf,kBAAkB,GAClB,kBAAkB,GAClB,aAAa,GACb,eAAe,GACf,gBAAgB,GAChB,aAAa,GACb,wBAAwB,GACxB,kBAAkB,GAClB,kBAAkB,CAAC;AAEvB,qBAAa,mBAAoB,SAAQ,KAAK;IAE1C,QAAQ,CAAC,MAAM,EAAE,oBAAoB;gBAA5B,MAAM,EAAE,oBAAoB,EACrC,OAAO,EAAE,MAAM;CAKlB;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAYtD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,MAAM,CAIxF;AAED,kFAAkF;AAClF,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAM/E;AAED,KAAK,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AACnE,KAAK,MAAM,GAAG;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AACF,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,MAAM,EACd,OAAO,UAAO;;oBAMS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,UAAU,MAAM;;qBAyB7D,MAAM,YAAY,OAAO;EAM7C"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { normalizeRepositoryPath } from "./repository-path.js";
|
|
3
|
+
export class RepositoryReadError extends Error {
|
|
4
|
+
reason;
|
|
5
|
+
constructor(reason, message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.reason = reason;
|
|
8
|
+
this.name = "RepositoryReadError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function readErrorReason(error) {
|
|
12
|
+
if (error instanceof RepositoryReadError)
|
|
13
|
+
return error.reason;
|
|
14
|
+
const code = error?.code;
|
|
15
|
+
const codes = {
|
|
16
|
+
ENOENT: "file_missing",
|
|
17
|
+
EACCES: "permission_denied",
|
|
18
|
+
EPERM: "permission_denied",
|
|
19
|
+
ENOTDIR: "parent_not_directory",
|
|
20
|
+
EIO: "io_error",
|
|
21
|
+
ENOBUFS: "command_output_limit",
|
|
22
|
+
};
|
|
23
|
+
return typeof code === "string" && Object.hasOwn(codes, code) ? codes[code] : "read_failed";
|
|
24
|
+
}
|
|
25
|
+
export function safeDiagnosticPath(path, knownPaths) {
|
|
26
|
+
const normalized = normalizeRepositoryPath(path);
|
|
27
|
+
if (normalized === undefined)
|
|
28
|
+
return "[invalid repository path]";
|
|
29
|
+
return knownPaths.has(normalized) ? normalized : "[unverified repository path]";
|
|
30
|
+
}
|
|
31
|
+
/** Optional diagnostics must never alter a review result or replace its error. */
|
|
32
|
+
export function writeRepositoryDiagnostic(record) {
|
|
33
|
+
try {
|
|
34
|
+
process.stderr.write(`${JSON.stringify(record)}\n`);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// A failed diagnostic sink does not affect repository retrieval.
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function repositoryDiagnostics(reviewer, limits, enabled = true) {
|
|
41
|
+
const readingId = randomUUID();
|
|
42
|
+
// Each retrieval is already bounded to 128 operations. Cap gap diagnostics too.
|
|
43
|
+
let records = 0;
|
|
44
|
+
let omitted = 0;
|
|
45
|
+
const emit = (details, counts) => {
|
|
46
|
+
if (!enabled)
|
|
47
|
+
return;
|
|
48
|
+
if (records++ >= 1024) {
|
|
49
|
+
omitted++;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
writeRepositoryDiagnostic({
|
|
53
|
+
event: "repository.read-detail",
|
|
54
|
+
readingId,
|
|
55
|
+
reviewer: reviewer && /^[A-Za-z0-9][A-Za-z0-9._/-]{0,95}$/.test(reviewer) ? reviewer : "unknown",
|
|
56
|
+
...details,
|
|
57
|
+
...counts,
|
|
58
|
+
callsRemaining: Math.max(0, limits.maxToolCalls - counts.toolCalls),
|
|
59
|
+
bytesRemaining: Math.max(0, limits.maxTotalBytes - counts.bytes),
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
return {
|
|
63
|
+
readingId,
|
|
64
|
+
emit,
|
|
65
|
+
start: () => emit({ kind: "session", outcome: "started", ...limits }, { rounds: 0, toolCalls: 0, bytes: 0 }),
|
|
66
|
+
finish: (counts, complete) => {
|
|
67
|
+
// Reserve a completion record even when the diagnostic cap was reached.
|
|
68
|
+
records = Math.min(records, 1023);
|
|
69
|
+
emit({ kind: "session", outcome: "finished", complete, omittedRecords: omitted }, counts);
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=repository-diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-diagnostics.js","sourceRoot":"","sources":["../src/repository-diagnostics.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\n\nimport { normalizeRepositoryPath } from \"./repository-path.js\";\n\nexport type RepositoryReadReason =\n | \"excluded_file\"\n | \"symlink_rejected\"\n | \"not_regular_file\"\n | \"unsafe_path\"\n | \"invalid_range\"\n | \"range_past_eof\"\n | \"binary_file\"\n | \"change_context_missing\"\n | \"file_not_changed\"\n | \"invalid_revision\";\n\nexport class RepositoryReadError extends Error {\n constructor(\n readonly reason: RepositoryReadReason,\n message: string,\n ) {\n super(message);\n this.name = \"RepositoryReadError\";\n }\n}\n\nexport function readErrorReason(error: unknown): string {\n if (error instanceof RepositoryReadError) return error.reason;\n const code = (error as { code?: unknown } | null)?.code;\n const codes: Record<string, string> = {\n ENOENT: \"file_missing\",\n EACCES: \"permission_denied\",\n EPERM: \"permission_denied\",\n ENOTDIR: \"parent_not_directory\",\n EIO: \"io_error\",\n ENOBUFS: \"command_output_limit\",\n };\n return typeof code === \"string\" && Object.hasOwn(codes, code) ? codes[code] : \"read_failed\";\n}\n\nexport function safeDiagnosticPath(path: string, knownPaths: ReadonlySet<string>): string {\n const normalized = normalizeRepositoryPath(path);\n if (normalized === undefined) return \"[invalid repository path]\";\n return knownPaths.has(normalized) ? normalized : \"[unverified repository path]\";\n}\n\n/** Optional diagnostics must never alter a review result or replace its error. */\nexport function writeRepositoryDiagnostic(record: Record<string, unknown>): void {\n try {\n process.stderr.write(`${JSON.stringify(record)}\\n`);\n } catch {\n // A failed diagnostic sink does not affect repository retrieval.\n }\n}\n\ntype Counts = { rounds: number; toolCalls: number; bytes: number };\ntype Limits = {\n maxRounds: number;\n maxToolCalls: number;\n maxTotalBytes: number;\n maxBytesPerRead: number;\n maxLinesPerRead: number;\n};\nexport function repositoryDiagnostics(\n reviewer: string | undefined,\n limits: Limits,\n enabled = true,\n) {\n const readingId = randomUUID();\n // Each retrieval is already bounded to 128 operations. Cap gap diagnostics too.\n let records = 0;\n let omitted = 0;\n const emit = (details: Record<string, string | number | boolean>, counts: Counts) => {\n if (!enabled) return;\n if (records++ >= 1024) {\n omitted++;\n return;\n }\n writeRepositoryDiagnostic({\n event: \"repository.read-detail\",\n readingId,\n reviewer:\n reviewer && /^[A-Za-z0-9][A-Za-z0-9._/-]{0,95}$/.test(reviewer) ? reviewer : \"unknown\",\n ...details,\n ...counts,\n callsRemaining: Math.max(0, limits.maxToolCalls - counts.toolCalls),\n bytesRemaining: Math.max(0, limits.maxTotalBytes - counts.bytes),\n });\n };\n return {\n readingId,\n emit,\n start: () =>\n emit(\n { kind: \"session\", outcome: \"started\", ...limits },\n { rounds: 0, toolCalls: 0, bytes: 0 },\n ),\n finish: (counts: Counts, complete: boolean) => {\n // Reserve a completion record even when the diagnostic cap was reached.\n records = Math.min(records, 1023);\n emit({ kind: \"session\", outcome: \"finished\", complete, omittedRecords: omitted }, counts);\n },\n };\n}\n"]}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type ModelReviewRequest, type ModelReviewResult, type ReviewModel } from "./model.js";
|
|
2
2
|
export interface ModelRepositoryToolOptions {
|
|
3
|
+
/** Emit bounded file-reading diagnostics without source contents or raw errors. */
|
|
4
|
+
readDiagnostics?: boolean;
|
|
3
5
|
/** File globs the model may read. Empty means every regular non-excluded file. */
|
|
4
6
|
include?: readonly string[];
|
|
5
7
|
/** Additional file or directory globs hidden from repository tools. */
|
|
@@ -32,6 +34,8 @@ export interface ModelRepositoryCoverage {
|
|
|
32
34
|
reasons: readonly string[];
|
|
33
35
|
}
|
|
34
36
|
export interface ModelRepositoryRetrieval {
|
|
37
|
+
/** Correlates source reads and missing-line diagnostics for this retrieval. */
|
|
38
|
+
readingId?: string;
|
|
35
39
|
rounds: number;
|
|
36
40
|
toolCalls: number;
|
|
37
41
|
bytes: number;
|