@alint-js/core 0.0.25 → 0.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.d.mts +13 -4
- package/dist/agent.mjs +7 -2
- package/dist/index.d.mts +30 -3
- package/dist/index.mjs +49 -6
- package/dist/retry-C4sGjSE5.mjs +50 -0
- package/dist/structured-output.d.mts +3 -2
- package/dist/structured-output.mjs +6 -3
- package/dist/{types-CIqhJ96f.d.mts → types-BM_nUu_Z.d.mts} +9 -0
- package/package.json +4 -4
package/dist/agent.d.mts
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import { J as AgentResult, K as AgentAdapter, X as AgentUsage, Y as AgentTool, q as AgentRequest, v as RuleContext } from "./types-
|
|
2
|
-
|
|
1
|
+
import { J as AgentResult, K as AgentAdapter, X as AgentUsage, Y as AgentTool, q as AgentRequest, v as RuleContext } from "./types-BM_nUu_Z.mjs";
|
|
2
|
+
//#region src/agent/retry.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Declares that the complete adapter invocation can be safely replayed.
|
|
5
|
+
* Adapters must not throw this after a tool or another externally visible side effect starts.
|
|
6
|
+
*/
|
|
7
|
+
declare class RetryableAgentError extends Error {
|
|
8
|
+
constructor(message: string, options?: ErrorOptions);
|
|
9
|
+
}
|
|
10
|
+
declare function isRetryableAgentError(error: unknown): error is RetryableAgentError;
|
|
11
|
+
//#endregion
|
|
3
12
|
//#region src/agent/index.d.ts
|
|
4
13
|
declare function defineTool(tool: AgentTool): AgentTool;
|
|
5
|
-
declare function requireAgent(context: Pick<RuleContext, 'agent' | 'id'>): AgentAdapter;
|
|
14
|
+
declare function requireAgent(context: Pick<RuleContext, 'agent' | 'id' | 'signal'>): AgentAdapter;
|
|
6
15
|
//#endregion
|
|
7
|
-
export { type AgentAdapter, type AgentRequest, type AgentResult, type AgentTool, type AgentUsage, defineTool, requireAgent };
|
|
16
|
+
export { type AgentAdapter, type AgentRequest, type AgentResult, type AgentTool, type AgentUsage, RetryableAgentError, defineTool, isRetryableAgentError, requireAgent };
|
package/dist/agent.mjs
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import { n as isRetryableAgentError, t as RetryableAgentError } from "./retry-C4sGjSE5.mjs";
|
|
1
2
|
//#region src/agent/index.ts
|
|
2
3
|
function defineTool(tool) {
|
|
3
4
|
return tool;
|
|
4
5
|
}
|
|
5
6
|
function requireAgent(context) {
|
|
6
7
|
if (!context.agent) throw new TypeError(`Rule "${context.id}" requires an agent, but none is configured. Set "agent" in alint config (e.g. agent: createApeiraAdapter()).`);
|
|
7
|
-
|
|
8
|
+
const agent = context.agent;
|
|
9
|
+
return async (request) => agent({
|
|
10
|
+
...request,
|
|
11
|
+
signal: request.signal ?? context.signal
|
|
12
|
+
});
|
|
8
13
|
}
|
|
9
14
|
//#endregion
|
|
10
|
-
export { defineTool, requireAgent };
|
|
15
|
+
export { RetryableAgentError, defineTool, isRetryableAgentError, requireAgent };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { $ as ResolvedModel, A as LanguageContext, B as SourceRuntime, C as RuleSeverity, D as ClassTarget, E as Target, F as ProcessorPostprocessContext, G as SourceText, H as SourceTargetKind, I as SourceFile, L as SourceLocation, M as ProcessedSource, N as ProcessedSourceOrigin, O as FileTarget, P as ProcessorContext, Q as ResolveModelOptions, R as SourcePosition, S as RuleRegistry, T as RuleWithHandler, U as SourceTargetOfKind, V as SourceTarget, W as SourceTargetOrigin, Z as ModelRequirement, _ as RuleConfigEntry, a as AlintLinterOptions, at as RunnerStatsConfig, b as RuleHandlers, c as DiagnosticLocation, d as IgnoreConfig, et as ResolvedProvider, f as LanguageDefinition, g as RuleCacheConfig, h as ProjectTarget, i as AlintConfigItem, it as RunnerConfig, j as LineRange, k as FunctionTarget, l as DirectoryTarget, m as ProcessorDefinition, n as AlintConfigExtends, nt as ProviderDefinition, o as Awaitable, ot as SetupConfig, p as PluginDefinition, r as AlintConfigInput, rt as ProviderType, s as DiagnosticDescriptor, st as SetupModelDefinition, t as AlintConfig, tt as ModelSize, u as EnabledRule, v as RuleContext, w as RuleSpecializedHandlers, x as RuleInferenceUsageRecord, y as RuleDefinition, z as SourceRange } from "./types-
|
|
2
|
-
|
|
1
|
+
import { $ as ResolvedModel, A as LanguageContext, B as SourceRuntime, C as RuleSeverity, D as ClassTarget, E as Target, F as ProcessorPostprocessContext, G as SourceText, H as SourceTargetKind, I as SourceFile, L as SourceLocation, M as ProcessedSource, N as ProcessedSourceOrigin, O as FileTarget, P as ProcessorContext, Q as ResolveModelOptions, R as SourcePosition, S as RuleRegistry, T as RuleWithHandler, U as SourceTargetOfKind, V as SourceTarget, W as SourceTargetOrigin, Z as ModelRequirement, _ as RuleConfigEntry, a as AlintLinterOptions, at as RunnerStatsConfig, b as RuleHandlers, c as DiagnosticLocation, d as IgnoreConfig, et as ResolvedProvider, f as LanguageDefinition, g as RuleCacheConfig, h as ProjectTarget, i as AlintConfigItem, it as RunnerConfig, j as LineRange, k as FunctionTarget, l as DirectoryTarget, m as ProcessorDefinition, n as AlintConfigExtends, nt as ProviderDefinition, o as Awaitable, ot as SetupConfig, p as PluginDefinition, r as AlintConfigInput, rt as ProviderType, s as DiagnosticDescriptor, st as SetupModelDefinition, t as AlintConfig, tt as ModelSize, u as EnabledRule, v as RuleContext, w as RuleSpecializedHandlers, x as RuleInferenceUsageRecord, y as RuleDefinition, z as SourceRange } from "./types-BM_nUu_Z.mjs";
|
|
3
2
|
//#region src/config/config-array.d.ts
|
|
4
3
|
interface EffectiveAlintConfig {
|
|
5
4
|
agent?: AlintConfigItem['agent'];
|
|
@@ -126,7 +125,11 @@ interface RuleEndPayload {
|
|
|
126
125
|
endedAt?: number;
|
|
127
126
|
path: ProgressPath;
|
|
128
127
|
startedAt?: number;
|
|
129
|
-
|
|
128
|
+
/**
|
|
129
|
+
* `skipped` only occurs under {@link RunOptions.cacheOnly}: the rule missed the cache and was
|
|
130
|
+
* never executed, so it produced no diagnostics. `cache` is still `'miss'` in that case.
|
|
131
|
+
*/
|
|
132
|
+
state: 'completed' | 'errored' | 'skipped';
|
|
130
133
|
}
|
|
131
134
|
interface RuleStartPayload {
|
|
132
135
|
path: ProgressPath;
|
|
@@ -139,6 +142,8 @@ interface RunEndPayload {
|
|
|
139
142
|
endedAt?: number;
|
|
140
143
|
errored: number;
|
|
141
144
|
planned: number;
|
|
145
|
+
/** Rules left unexecuted because they missed the cache under {@link RunOptions.cacheOnly}. Always 0 otherwise. */
|
|
146
|
+
skipped: number;
|
|
142
147
|
startedAt?: number;
|
|
143
148
|
usage: RunUsage;
|
|
144
149
|
}
|
|
@@ -147,9 +152,22 @@ interface RunExecution {
|
|
|
147
152
|
completed: number;
|
|
148
153
|
errored: number;
|
|
149
154
|
planned: number;
|
|
155
|
+
/** Rules left unexecuted because they missed the cache under {@link RunOptions.cacheOnly}. Always 0 otherwise. */
|
|
156
|
+
skipped: number;
|
|
150
157
|
}
|
|
151
158
|
type RunnerOptions = RunnerConfig;
|
|
152
159
|
interface RunOptions {
|
|
160
|
+
/**
|
|
161
|
+
* Return only diagnostics that are already cached, without calling any model.
|
|
162
|
+
*
|
|
163
|
+
* Rules that miss the cache are skipped instead of executed, and the run leaves the cache
|
|
164
|
+
* file untouched. Read {@link RunExecution.skipped} to see how many rules a full run would
|
|
165
|
+
* still have to execute.
|
|
166
|
+
*
|
|
167
|
+
* Intended for callers that want to show known results for free, such as an editor
|
|
168
|
+
* displaying diagnostics on file open.
|
|
169
|
+
*/
|
|
170
|
+
cacheOnly?: boolean;
|
|
153
171
|
config?: AlintConfig;
|
|
154
172
|
cwd?: string;
|
|
155
173
|
directories?: string[];
|
|
@@ -159,6 +177,15 @@ interface RunOptions {
|
|
|
159
177
|
progress?: ProgressReporter;
|
|
160
178
|
runner?: RunnerOptions;
|
|
161
179
|
setupConfig?: SetupConfig;
|
|
180
|
+
/**
|
|
181
|
+
* Cancels the run. Aborting stops the engine from starting further rules and cancels the
|
|
182
|
+
* in-flight model call, so a cancelled run stops spending tokens.
|
|
183
|
+
*
|
|
184
|
+
* `runAlint` rejects with {@link AlintAbortError}, which carries the diagnostics gathered
|
|
185
|
+
* before the abort. Rules that already finished keep their cache entries: cancelling never
|
|
186
|
+
* throws away work you already paid for.
|
|
187
|
+
*/
|
|
188
|
+
signal?: AbortSignal;
|
|
162
189
|
}
|
|
163
190
|
interface RunResult {
|
|
164
191
|
diagnostics: Diagnostic[];
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { r as withAgentRetry } from "./retry-C4sGjSE5.mjs";
|
|
1
2
|
import { minimatch } from "minimatch";
|
|
2
3
|
import { isAbsolute, relative, resolve } from "pathe";
|
|
3
4
|
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
@@ -967,7 +968,7 @@ function createDirectoryExecutionPlans(directories, fileOffset) {
|
|
|
967
968
|
}
|
|
968
969
|
//#endregion
|
|
969
970
|
//#region package.json
|
|
970
|
-
var version = "0.0.
|
|
971
|
+
var version = "0.0.28";
|
|
971
972
|
//#endregion
|
|
972
973
|
//#region src/core/targets/execution.ts
|
|
973
974
|
var AlintRuleExecutionError = class extends Error {
|
|
@@ -1048,7 +1049,8 @@ function emitErroredRuleEnd(progress, clock, path, startedAt, cache) {
|
|
|
1048
1049
|
} catch {}
|
|
1049
1050
|
}
|
|
1050
1051
|
async function executeRule(execution, path, target, options) {
|
|
1051
|
-
const { cache, clock, counters, diagnostics, progress, usage } = options;
|
|
1052
|
+
const { cache, clock, counters, diagnostics, progress, signal, usage } = options;
|
|
1053
|
+
signal?.throwIfAborted();
|
|
1052
1054
|
const startedAt = clock();
|
|
1053
1055
|
const cacheKey = createExecutionCacheKey(execution.runtime, target, path, cache);
|
|
1054
1056
|
const cachedEntry = cacheKey ? cache.store.get(cacheKey) : void 0;
|
|
@@ -1075,6 +1077,17 @@ async function executeRule(execution, path, target, options) {
|
|
|
1075
1077
|
});
|
|
1076
1078
|
return;
|
|
1077
1079
|
}
|
|
1080
|
+
if (options.cacheOnly) {
|
|
1081
|
+
counters.skip();
|
|
1082
|
+
progress?.onRuleEnd?.({
|
|
1083
|
+
cache: "miss",
|
|
1084
|
+
endedAt: clock(),
|
|
1085
|
+
path,
|
|
1086
|
+
startedAt,
|
|
1087
|
+
state: "skipped"
|
|
1088
|
+
});
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1078
1091
|
let handlerError;
|
|
1079
1092
|
let handlerFailed = false;
|
|
1080
1093
|
const cacheDiagnostics = cacheKey ? [] : void 0;
|
|
@@ -1091,6 +1104,7 @@ async function executeRule(execution, path, target, options) {
|
|
|
1091
1104
|
handlerFailed = true;
|
|
1092
1105
|
}
|
|
1093
1106
|
if (handlerFailed) {
|
|
1107
|
+
signal?.throwIfAborted();
|
|
1094
1108
|
counters.error();
|
|
1095
1109
|
emitErroredRuleEnd(progress, clock, path, startedAt, "miss");
|
|
1096
1110
|
throw new AlintRuleExecutionError(handlerError, path);
|
|
@@ -1397,6 +1411,18 @@ var AlintRunError = class extends Error {
|
|
|
1397
1411
|
this.result = result;
|
|
1398
1412
|
}
|
|
1399
1413
|
};
|
|
1414
|
+
/**
|
|
1415
|
+
* Thrown when {@link RunOptions.signal} aborts a run.
|
|
1416
|
+
*
|
|
1417
|
+
* Extends {@link AlintRunError} so existing handlers still receive the partial `result`, while
|
|
1418
|
+
* callers that treat cancellation differently from failure can test for this type.
|
|
1419
|
+
*/
|
|
1420
|
+
var AlintAbortError = class extends AlintRunError {
|
|
1421
|
+
constructor(result, options = {}) {
|
|
1422
|
+
super("alint run was aborted", result, { cause: options.cause });
|
|
1423
|
+
this.name = "AlintAbortError";
|
|
1424
|
+
}
|
|
1425
|
+
};
|
|
1400
1426
|
async function runAlint(options = {}) {
|
|
1401
1427
|
const cwd$1 = options.cwd ?? cwd();
|
|
1402
1428
|
const config = options.config ?? [];
|
|
@@ -1511,6 +1537,7 @@ async function runAlint(options = {}) {
|
|
|
1511
1537
|
let runStartedAt;
|
|
1512
1538
|
let runError;
|
|
1513
1539
|
try {
|
|
1540
|
+
options.signal?.throwIfAborted();
|
|
1514
1541
|
filePlans = createSourceExecutionPlans(files, cwd$1);
|
|
1515
1542
|
directoryPlans = createDirectoryExecutionPlans(directories, filePlans.length);
|
|
1516
1543
|
projectPlan = resolvedProjectConfig.ignored ? void 0 : createProjectExecutionPlan({
|
|
@@ -1535,38 +1562,44 @@ async function runAlint(options = {}) {
|
|
|
1535
1562
|
});
|
|
1536
1563
|
await runConcurrently(filePlans.filter((filePlan) => filePlan.targets.length > 0), resolveFileConcurrency(options.runner?.fileConcurrency), (filePlan) => executeTargetPlans({
|
|
1537
1564
|
cache: cacheContext,
|
|
1565
|
+
cacheOnly: options.cacheOnly,
|
|
1538
1566
|
clock,
|
|
1539
1567
|
counters,
|
|
1540
1568
|
diagnostics,
|
|
1541
1569
|
filesTotal: inputsTotal,
|
|
1542
1570
|
plans: [filePlan],
|
|
1543
1571
|
progress: options.progress,
|
|
1572
|
+
signal: options.signal,
|
|
1544
1573
|
usage
|
|
1545
1574
|
}));
|
|
1546
1575
|
await runConcurrently(activeDirectoryPlans, resolveFileConcurrency(options.runner?.fileConcurrency), (directoryPlan) => executeTargetPlans({
|
|
1547
1576
|
cache: cacheContext,
|
|
1577
|
+
cacheOnly: options.cacheOnly,
|
|
1548
1578
|
clock,
|
|
1549
1579
|
counters,
|
|
1550
1580
|
diagnostics,
|
|
1551
1581
|
filesTotal: inputsTotal,
|
|
1552
1582
|
plans: [directoryPlan],
|
|
1553
1583
|
progress: options.progress,
|
|
1584
|
+
signal: options.signal,
|
|
1554
1585
|
usage
|
|
1555
1586
|
}));
|
|
1556
1587
|
if (projectPlan) await executeTargetPlans({
|
|
1557
1588
|
cache: cacheContext,
|
|
1589
|
+
cacheOnly: options.cacheOnly,
|
|
1558
1590
|
clock,
|
|
1559
1591
|
counters,
|
|
1560
1592
|
diagnostics,
|
|
1561
1593
|
filesTotal: inputsTotal,
|
|
1562
1594
|
plans: [projectPlan],
|
|
1563
1595
|
progress: options.progress,
|
|
1596
|
+
signal: options.signal,
|
|
1564
1597
|
usage
|
|
1565
1598
|
});
|
|
1566
1599
|
} catch (error) {
|
|
1567
1600
|
runError = error;
|
|
1568
1601
|
} finally {
|
|
1569
|
-
await reconcileCache(filePlans, cacheContext);
|
|
1602
|
+
if (!options.cacheOnly) await reconcileCache(filePlans, cacheContext);
|
|
1570
1603
|
try {
|
|
1571
1604
|
options.progress?.onRunEnd?.({
|
|
1572
1605
|
...counters.snapshot(planned),
|
|
@@ -1584,7 +1617,10 @@ async function runAlint(options = {}) {
|
|
|
1584
1617
|
execution: counters.snapshot(planned),
|
|
1585
1618
|
usage: usage.toJSON()
|
|
1586
1619
|
};
|
|
1587
|
-
if (runError)
|
|
1620
|
+
if (runError) {
|
|
1621
|
+
if (options.signal?.aborted) throw new AlintAbortError(result, { cause: runError });
|
|
1622
|
+
throw createAlintRunError(runError, result);
|
|
1623
|
+
}
|
|
1588
1624
|
return result;
|
|
1589
1625
|
}
|
|
1590
1626
|
function addTokenCount(base, value) {
|
|
@@ -1612,6 +1648,7 @@ function createRuleEndCounters() {
|
|
|
1612
1648
|
let cached = 0;
|
|
1613
1649
|
let completed = 0;
|
|
1614
1650
|
let errored = 0;
|
|
1651
|
+
let skipped = 0;
|
|
1615
1652
|
return {
|
|
1616
1653
|
cache() {
|
|
1617
1654
|
cached += 1;
|
|
@@ -1622,21 +1659,26 @@ function createRuleEndCounters() {
|
|
|
1622
1659
|
error() {
|
|
1623
1660
|
errored += 1;
|
|
1624
1661
|
},
|
|
1662
|
+
skip() {
|
|
1663
|
+
skipped += 1;
|
|
1664
|
+
},
|
|
1625
1665
|
snapshot(planned) {
|
|
1626
1666
|
return {
|
|
1627
1667
|
cached,
|
|
1628
1668
|
completed,
|
|
1629
1669
|
errored,
|
|
1630
|
-
planned
|
|
1670
|
+
planned,
|
|
1671
|
+
skipped
|
|
1631
1672
|
};
|
|
1632
1673
|
}
|
|
1633
1674
|
};
|
|
1634
1675
|
}
|
|
1635
1676
|
function createRuleRuntimes(options) {
|
|
1677
|
+
const agent = options.effectiveAgent ? withAgentRetry(options.effectiveAgent, options.options.runner?.agentRetries) : void 0;
|
|
1636
1678
|
return options.registry.enabledRules.map((enabledRule) => {
|
|
1637
1679
|
const executionState = new AsyncLocalStorage();
|
|
1638
1680
|
const context = {
|
|
1639
|
-
agent
|
|
1681
|
+
agent,
|
|
1640
1682
|
cwd: options.cwd,
|
|
1641
1683
|
id: enabledRule.id,
|
|
1642
1684
|
localId: enabledRule.localId,
|
|
@@ -1691,6 +1733,7 @@ function createRuleRuntimes(options) {
|
|
|
1691
1733
|
});
|
|
1692
1734
|
},
|
|
1693
1735
|
settings: options.effectiveSettings,
|
|
1736
|
+
signal: options.options.signal,
|
|
1694
1737
|
src: options.src
|
|
1695
1738
|
};
|
|
1696
1739
|
return {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { withRetry } from "@moeru/std/with-retry";
|
|
2
|
+
//#region src/agent/retry.ts
|
|
3
|
+
/**
|
|
4
|
+
* Declares that the complete adapter invocation can be safely replayed.
|
|
5
|
+
* Adapters must not throw this after a tool or another externally visible side effect starts.
|
|
6
|
+
*/
|
|
7
|
+
var RetryableAgentError = class extends Error {
|
|
8
|
+
constructor(message, options) {
|
|
9
|
+
super(message, options);
|
|
10
|
+
this.name = "RetryableAgentError";
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
function isRetryableAgentError(error) {
|
|
14
|
+
return error instanceof RetryableAgentError;
|
|
15
|
+
}
|
|
16
|
+
function withAgentRetry(adapter, retries = 2) {
|
|
17
|
+
const invoke = withRetry(async (request) => {
|
|
18
|
+
try {
|
|
19
|
+
request.signal?.throwIfAborted();
|
|
20
|
+
const result = await adapter(request);
|
|
21
|
+
request.signal?.throwIfAborted();
|
|
22
|
+
return {
|
|
23
|
+
ok: true,
|
|
24
|
+
result
|
|
25
|
+
};
|
|
26
|
+
} catch (error) {
|
|
27
|
+
if (request.signal?.aborted) return {
|
|
28
|
+
error: request.signal.reason,
|
|
29
|
+
ok: false
|
|
30
|
+
};
|
|
31
|
+
if (isRetryableAgentError(error)) throw error;
|
|
32
|
+
return {
|
|
33
|
+
error,
|
|
34
|
+
ok: false
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}, {
|
|
38
|
+
retry: retries,
|
|
39
|
+
retryDelay: 500,
|
|
40
|
+
retryDelayFactor: 2,
|
|
41
|
+
retryDelayMax: 3e4
|
|
42
|
+
});
|
|
43
|
+
return async (request) => {
|
|
44
|
+
const attempt = await invoke(request);
|
|
45
|
+
if (!attempt.ok) throw attempt.error;
|
|
46
|
+
return attempt.result;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { isRetryableAgentError as n, withAgentRetry as r, RetryableAgentError as t };
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { $ as ResolvedModel, v as RuleContext } from "./types-
|
|
1
|
+
import { $ as ResolvedModel, v as RuleContext } from "./types-BM_nUu_Z.mjs";
|
|
2
2
|
import { GenericSchema, InferOutput } from "valibot";
|
|
3
3
|
import { JsonSchema } from "@valibot/to-json-schema";
|
|
4
4
|
import { Message } from "@xsai/shared-chat";
|
|
5
|
-
|
|
6
5
|
//#region src/structuredOutput/index.d.ts
|
|
7
6
|
interface GenerateStructuredOptions<Schema extends GenericSchema> {
|
|
8
7
|
/**
|
|
@@ -21,6 +20,8 @@ interface GenerateStructuredOptions<Schema extends GenericSchema> {
|
|
|
21
20
|
/** Milliseconds to wait before the given (1-based) attempt is retried. */
|
|
22
21
|
retryDelay?: (attempt: number) => number;
|
|
23
22
|
schema: Schema;
|
|
23
|
+
/** Cancels the model call and any pending retry backoff. Pass `ctx.signal` from a rule. */
|
|
24
|
+
signal?: AbortSignal;
|
|
24
25
|
temperature?: number;
|
|
25
26
|
/** Shown to the model as the tool description. Defaults to the schema's valibot description. */
|
|
26
27
|
toolDescription?: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { errorMessageFrom } from "@moeru/std/error";
|
|
2
2
|
import { getDescription, parse } from "valibot";
|
|
3
|
-
import {
|
|
3
|
+
import { setTimeout } from "node:timers/promises";
|
|
4
4
|
import { toJsonSchema } from "@valibot/to-json-schema";
|
|
5
5
|
import { generateText } from "@xsai/generate-text";
|
|
6
6
|
import { rawTool } from "@xsai/tool";
|
|
@@ -41,9 +41,11 @@ async function generateStructured(options) {
|
|
|
41
41
|
});
|
|
42
42
|
let previousError;
|
|
43
43
|
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
44
|
+
options.signal?.throwIfAborted();
|
|
44
45
|
let response;
|
|
45
46
|
try {
|
|
46
47
|
response = await generateText({
|
|
48
|
+
abortSignal: options.signal,
|
|
47
49
|
baseURL: options.model.provider.endpoint,
|
|
48
50
|
headers: options.model.provider.headers,
|
|
49
51
|
messages: options.createMessages(previousError ? retryFeedbackFrom(toolName, previousError) : void 0),
|
|
@@ -57,11 +59,12 @@ async function generateStructured(options) {
|
|
|
57
59
|
tools: [tool]
|
|
58
60
|
});
|
|
59
61
|
} catch (error) {
|
|
62
|
+
options.signal?.throwIfAborted();
|
|
60
63
|
const callError = `Tool call failed before validation: ${errorMessageFrom(error) ?? String(error)}`;
|
|
61
64
|
previousError = isRetriableHttpError(error) ? void 0 : callError;
|
|
62
65
|
options.logger?.debug(`${options.operation} attempt ${attempt} failed while calling the model: ${callError}`);
|
|
63
66
|
if (!isRetriableCallError(error) || attempt === maxAttempts) throw error;
|
|
64
|
-
await
|
|
67
|
+
await setTimeout(retryDelay(attempt), void 0, { signal: options.signal });
|
|
65
68
|
continue;
|
|
66
69
|
}
|
|
67
70
|
recordAttemptUsage(options, response);
|
|
@@ -70,7 +73,7 @@ async function generateStructured(options) {
|
|
|
70
73
|
previousError = result.error;
|
|
71
74
|
options.logger?.debug(`${options.operation} attempt ${attempt} returned an invalid structured result: ${previousError}`);
|
|
72
75
|
if (!result.retriable || attempt === maxAttempts) throw new InvalidStructuredOutputError(`Invalid structured model response: ${previousError}`);
|
|
73
|
-
await
|
|
76
|
+
await setTimeout(retryDelay(attempt), void 0, { signal: options.signal });
|
|
74
77
|
}
|
|
75
78
|
throw new InvalidStructuredOutputError("Model did not return a valid structured result");
|
|
76
79
|
}
|
|
@@ -13,6 +13,8 @@ interface RunnerCacheConfig {
|
|
|
13
13
|
location?: string;
|
|
14
14
|
}
|
|
15
15
|
interface RunnerConfig {
|
|
16
|
+
/** Retries after the initial attempt for replay-safe agent failures. @default 2 */
|
|
17
|
+
agentRetries?: number;
|
|
16
18
|
cache?: boolean | RunnerCacheConfig;
|
|
17
19
|
fileConcurrency?: number;
|
|
18
20
|
ruleConcurrency?: number;
|
|
@@ -275,6 +277,13 @@ interface RuleContext {
|
|
|
275
277
|
outputLanguage?: string;
|
|
276
278
|
report: (diagnostic: DiagnosticDescriptor) => void;
|
|
277
279
|
settings: Record<string, unknown>;
|
|
280
|
+
/**
|
|
281
|
+
* Cancels the run. Forward it to anything long-running a rule starts, so cancelling stops
|
|
282
|
+
* the work instead of letting it finish and bill.
|
|
283
|
+
*
|
|
284
|
+
* `ctx.agent` already injects it, and `generateStructured` accepts it as `signal`.
|
|
285
|
+
*/
|
|
286
|
+
signal?: AbortSignal;
|
|
278
287
|
src: SourceRuntime;
|
|
279
288
|
}
|
|
280
289
|
interface RuleDefinition {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alint-js/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.28",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
7
|
"types": "./dist/index.d.mts",
|
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
"@xsai/tool": "^0.5.0-beta.7",
|
|
29
29
|
"es-toolkit": "^1.49.0",
|
|
30
30
|
"minimatch": "^10.2.5",
|
|
31
|
-
"oxc-parser": "^0.
|
|
31
|
+
"oxc-parser": "^0.140.0",
|
|
32
32
|
"pathe": "^2.0.3",
|
|
33
|
-
"valibot": "^1.4.
|
|
33
|
+
"valibot": "^1.4.2"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"effect": "^3.22.0",
|
|
37
|
-
"sury": "^
|
|
37
|
+
"sury": "^11.0.0-alpha.10"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "tsdown",
|