yuangs 2.18.0 → 2.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/AgentPipelineEnhanced.d.ts +33 -0
- package/dist/agent/AgentPipelineEnhanced.js +229 -0
- package/dist/agent/AgentPipelineEnhanced.js.map +1 -0
- package/dist/policy/model/ModelRegistry.d.ts +38 -0
- package/dist/policy/model/ModelRegistry.js +69 -0
- package/dist/policy/model/ModelRegistry.js.map +1 -0
- package/dist/policy/sampler.d.ts +22 -0
- package/dist/policy/sampler.js +70 -0
- package/dist/policy/sampler.js.map +1 -0
- package/dist/policy/syntaxHandler.d.ts +32 -0
- package/dist/policy/syntaxHandler.js +155 -0
- package/dist/policy/syntaxHandler.js.map +1 -0
- package/dist/policy/token/DefaultTokenPolicy.d.ts +28 -0
- package/dist/policy/token/DefaultTokenPolicy.js +136 -0
- package/dist/policy/token/DefaultTokenPolicy.js.map +1 -0
- package/dist/policy/token/TokenEstimator.d.ts +36 -0
- package/dist/policy/token/TokenEstimator.js +110 -0
- package/dist/policy/token/TokenEstimator.js.map +1 -0
- package/dist/policy/token/types.d.ts +74 -0
- package/dist/policy/token/types.js +3 -0
- package/dist/policy/token/types.js.map +1 -0
- package/dist/ui/PolicyPresenter.d.ts +52 -0
- package/dist/ui/PolicyPresenter.js +193 -0
- package/dist/ui/PolicyPresenter.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { AgentInput, AgentMode } from './types';
|
|
2
|
+
import { ModelRegistry } from '../policy/model/ModelRegistry';
|
|
3
|
+
export declare class AgentPipeline {
|
|
4
|
+
private contextBuffer;
|
|
5
|
+
private modelRegistry;
|
|
6
|
+
private policy;
|
|
7
|
+
constructor(modelRegistry?: ModelRegistry);
|
|
8
|
+
run(input: AgentInput, mode: AgentMode): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* 执行带 TokenPolicy 的 pipeline
|
|
11
|
+
*/
|
|
12
|
+
private runWithTokenPolicy;
|
|
13
|
+
/**
|
|
14
|
+
* 处理 Policy 结果
|
|
15
|
+
*/
|
|
16
|
+
private handlePolicyResult;
|
|
17
|
+
/**
|
|
18
|
+
* 应用用户决策
|
|
19
|
+
*/
|
|
20
|
+
private applyDecision;
|
|
21
|
+
/**
|
|
22
|
+
* 执行 LLM Pipeline(原有的流程)
|
|
23
|
+
*/
|
|
24
|
+
private executeLLMPipeline;
|
|
25
|
+
/**
|
|
26
|
+
* 从输入中提取上下文 tokens (@file, #dir)
|
|
27
|
+
*/
|
|
28
|
+
private extractContextTokens;
|
|
29
|
+
/**
|
|
30
|
+
* 确定 mode
|
|
31
|
+
*/
|
|
32
|
+
private determineMode;
|
|
33
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AgentPipeline = void 0;
|
|
7
|
+
const contextBuffer_1 = require("../commands/contextBuffer");
|
|
8
|
+
const intent_1 = require("./intent");
|
|
9
|
+
const context_1 = require("./context");
|
|
10
|
+
const prompt_1 = require("./prompt");
|
|
11
|
+
const llm_1 = require("./llm");
|
|
12
|
+
const interpret_1 = require("./interpret");
|
|
13
|
+
const planExecutor_1 = require("./planExecutor");
|
|
14
|
+
const record_1 = require("./record");
|
|
15
|
+
const skills_1 = require("./skills");
|
|
16
|
+
const crypto_1 = require("crypto");
|
|
17
|
+
const renderer_1 = require("../utils/renderer");
|
|
18
|
+
const ora_1 = __importDefault(require("ora"));
|
|
19
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
20
|
+
const DefaultTokenPolicy_1 = require("../policy/token/DefaultTokenPolicy");
|
|
21
|
+
const ModelRegistry_1 = require("../policy/model/ModelRegistry");
|
|
22
|
+
const syntaxHandler_1 = require("../policy/syntaxHandler");
|
|
23
|
+
const PolicyPresenter_1 = require("../ui/PolicyPresenter");
|
|
24
|
+
const sampler_1 = require("../policy/sampler");
|
|
25
|
+
const MAX_PIPELINE_ITERATIONS = 3;
|
|
26
|
+
class AgentPipeline {
|
|
27
|
+
contextBuffer = new contextBuffer_1.ContextBuffer();
|
|
28
|
+
modelRegistry;
|
|
29
|
+
policy;
|
|
30
|
+
constructor(modelRegistry) {
|
|
31
|
+
this.modelRegistry = modelRegistry || new ModelRegistry_1.ModelRegistry([]);
|
|
32
|
+
this.policy = new DefaultTokenPolicy_1.DefaultTokenPolicy();
|
|
33
|
+
}
|
|
34
|
+
async run(input, mode) {
|
|
35
|
+
const id = (0, crypto_1.randomUUID)();
|
|
36
|
+
try {
|
|
37
|
+
await this.runWithTokenPolicy(input, mode, id);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error.name === 'MaxIterationsExceeded') {
|
|
41
|
+
console.log(chalk_1.default.yellow('\n⚠️ 已达到最大迭代次数,操作终止'));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
console.log(chalk_1.default.red(`\n❌ Pipeline 错误: ${error.message}`));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
PolicyPresenter_1.PolicyPresenter.clearSuppressCache();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 执行带 TokenPolicy 的 pipeline
|
|
51
|
+
*/
|
|
52
|
+
async runWithTokenPolicy(input, mode, executionId) {
|
|
53
|
+
// 1. 意图解析 (Syntax Phase)
|
|
54
|
+
const tokens = this.extractContextTokens(input.rawInput);
|
|
55
|
+
let pendingItems = syntaxHandler_1.SyntaxHandler.parse(tokens);
|
|
56
|
+
// 2. 治理审计循环 (Governance Loop)
|
|
57
|
+
// 最多重试 3 次(包括初始评估)以防止无限循环
|
|
58
|
+
const MAX_ITERATIONS = 3;
|
|
59
|
+
let passed = false;
|
|
60
|
+
let iterations = 0;
|
|
61
|
+
let currentModel = this.modelRegistry.get(input.options?.model || 'gemini-2.5-flash-lite') || this.modelRegistry.getDefault();
|
|
62
|
+
while (!passed && iterations < MAX_ITERATIONS) {
|
|
63
|
+
iterations++;
|
|
64
|
+
const result = await this.policy.evaluate({
|
|
65
|
+
model: currentModel,
|
|
66
|
+
contextItems: pendingItems,
|
|
67
|
+
mode: this.determineMode(mode),
|
|
68
|
+
userIntent: input.rawInput
|
|
69
|
+
});
|
|
70
|
+
passed = await this.handlePolicyResult(result, pendingItems, currentModel, iterations);
|
|
71
|
+
if (passed)
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
if (!passed) {
|
|
75
|
+
throw new Error('MaxIterationsExceeded');
|
|
76
|
+
}
|
|
77
|
+
// 3. 授权执行 (Execution Phase)
|
|
78
|
+
const resolved = await Promise.all(pendingItems.map(item => item.resolve()));
|
|
79
|
+
resolved.forEach(r => {
|
|
80
|
+
this.contextBuffer.add({
|
|
81
|
+
type: 'file',
|
|
82
|
+
path: pendingItems.find((p) => p.id.includes(r.content.substring(0, 20)))?.id || 'unknown',
|
|
83
|
+
content: r.content
|
|
84
|
+
}, true // bypassTokenLimit = true (已通过 policy 审计)
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
// 4. 正常 LLM Pipeline
|
|
88
|
+
await this.executeLLMPipeline(input, mode, currentModel, executionId);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* 处理 Policy 结果
|
|
92
|
+
*/
|
|
93
|
+
async handlePolicyResult(result, pendingItems, currentModel, iteration) {
|
|
94
|
+
if (result.status === 'ok') {
|
|
95
|
+
return true; // passed
|
|
96
|
+
}
|
|
97
|
+
if (result.status === 'block') {
|
|
98
|
+
await PolicyPresenter_1.PolicyPresenter.presentBlock(result);
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
if (result.status === 'warn') {
|
|
102
|
+
const decision = await PolicyPresenter_1.PolicyPresenter.presentWarning(result, `${currentModel.name}:${pendingItems.map(p => p.id).join(',')}`);
|
|
103
|
+
return this.applyDecision(decision, pendingItems, currentModel);
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 应用用户决策
|
|
109
|
+
*/
|
|
110
|
+
async applyDecision(decision, pendingItems, currentModel) {
|
|
111
|
+
switch (decision.type) {
|
|
112
|
+
case 'continue':
|
|
113
|
+
return true;
|
|
114
|
+
case 'abort':
|
|
115
|
+
return false;
|
|
116
|
+
case 'switch_model':
|
|
117
|
+
if (decision.targetModel) {
|
|
118
|
+
const newModel = this.modelRegistry.get(decision.targetModel);
|
|
119
|
+
if (newModel) {
|
|
120
|
+
console.log(chalk_1.default.green(`\n🔄 切换至模型: ${decision.targetModel}`));
|
|
121
|
+
currentModel = newModel;
|
|
122
|
+
return false; // 需要重新评估
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
console.log(chalk_1.default.yellow(`⚠️ 模型 ${decision.targetModel} 未找到`));
|
|
126
|
+
return false;
|
|
127
|
+
case 'sample':
|
|
128
|
+
if (decision.strategy === 'head_tail') {
|
|
129
|
+
console.log(chalk_1.default.cyan('\n✂ 应用 head_tail 采样...'));
|
|
130
|
+
pendingItems = await Promise.all(pendingItems.map(item => sampler_1.ContextSampler.applySampling(item, 'head_tail')));
|
|
131
|
+
return false; // 需要重新评估
|
|
132
|
+
}
|
|
133
|
+
return true;
|
|
134
|
+
default:
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* 执行 LLM Pipeline(原有的流程)
|
|
140
|
+
*/
|
|
141
|
+
async executeLLMPipeline(input, mode, model, executionId) {
|
|
142
|
+
const intent = (0, intent_1.inferIntent)(input, mode);
|
|
143
|
+
const context = (0, context_1.buildContext)(input, this.contextBuffer);
|
|
144
|
+
const prompt = (0, prompt_1.buildPrompt)(intent, context, mode, input.rawInput);
|
|
145
|
+
let renderer;
|
|
146
|
+
let spinner;
|
|
147
|
+
if (mode === 'chat') {
|
|
148
|
+
spinner = (0, ora_1.default)(chalk_1.default.cyan('Thinking...')).start();
|
|
149
|
+
renderer = new renderer_1.StreamMarkdownRenderer(chalk_1.default.bold.blue('🤖 AI: '), spinner);
|
|
150
|
+
}
|
|
151
|
+
const result = await (0, llm_1.runLLM)({
|
|
152
|
+
prompt,
|
|
153
|
+
model: model.name,
|
|
154
|
+
stream: mode === 'chat',
|
|
155
|
+
onChunk: mode === 'chat' && renderer
|
|
156
|
+
? (s) => renderer.onChunk(s)
|
|
157
|
+
: undefined,
|
|
158
|
+
});
|
|
159
|
+
if (mode === 'chat' && renderer) {
|
|
160
|
+
renderer.finish();
|
|
161
|
+
}
|
|
162
|
+
const isStreaming = mode === 'chat';
|
|
163
|
+
const plan = (0, interpret_1.interpretResultToPlan)(result, intent, mode, isStreaming);
|
|
164
|
+
result.plan = plan;
|
|
165
|
+
(0, record_1.saveRecord)({
|
|
166
|
+
id: executionId,
|
|
167
|
+
timestamp: Date.now(),
|
|
168
|
+
mode,
|
|
169
|
+
input,
|
|
170
|
+
prompt,
|
|
171
|
+
model: model.name,
|
|
172
|
+
llmResult: result,
|
|
173
|
+
action: plan.tasks[0]?.type === 'shell' ? {
|
|
174
|
+
type: 'execute',
|
|
175
|
+
command: plan.tasks[0].payload.command,
|
|
176
|
+
risk: plan.tasks[0].payload.risk
|
|
177
|
+
} : { type: 'print', content: result.rawText },
|
|
178
|
+
});
|
|
179
|
+
const summary = await (0, planExecutor_1.executePlan)(plan, input.options);
|
|
180
|
+
(0, skills_1.learnSkillFromRecord)({
|
|
181
|
+
id: executionId,
|
|
182
|
+
timestamp: Date.now(),
|
|
183
|
+
mode,
|
|
184
|
+
input,
|
|
185
|
+
prompt,
|
|
186
|
+
model: model.name,
|
|
187
|
+
llmResult: result,
|
|
188
|
+
action: plan.tasks[0]?.type === 'shell' ? {
|
|
189
|
+
type: 'execute',
|
|
190
|
+
command: plan.tasks[0].payload.command,
|
|
191
|
+
risk: plan.tasks[0].payload.risk
|
|
192
|
+
} : { type: 'print', content: result.rawText },
|
|
193
|
+
}, summary.success);
|
|
194
|
+
if (input.options?.verbose) {
|
|
195
|
+
console.log(`\n${'-'.repeat(50)}`);
|
|
196
|
+
console.log(`Execution ID: ${executionId}`);
|
|
197
|
+
console.log(`Model: ${model.name}`);
|
|
198
|
+
console.log(`Latency: ${result.latencyMs}ms`);
|
|
199
|
+
if (result.tokens) {
|
|
200
|
+
console.log(`Tokens: ${result.tokens.total}`);
|
|
201
|
+
}
|
|
202
|
+
console.log(`${'-'.repeat(50)}\n`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* 从输入中提取上下文 tokens (@file, #dir)
|
|
207
|
+
*/
|
|
208
|
+
extractContextTokens(rawInput) {
|
|
209
|
+
return rawInput
|
|
210
|
+
.split(' ')
|
|
211
|
+
.filter(token => token.startsWith('@') || token.startsWith('#'));
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* 确定 mode
|
|
215
|
+
*/
|
|
216
|
+
determineMode(mode) {
|
|
217
|
+
// 将 Agent mode 映射到 Policy mode
|
|
218
|
+
// chat → agent, command → command, command+exec → command
|
|
219
|
+
if (mode === 'chat') {
|
|
220
|
+
return 'agent';
|
|
221
|
+
}
|
|
222
|
+
if (mode === 'command+exec') {
|
|
223
|
+
return 'command';
|
|
224
|
+
}
|
|
225
|
+
return mode; // command 默认为 command
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
exports.AgentPipeline = AgentPipeline;
|
|
229
|
+
//# sourceMappingURL=AgentPipelineEnhanced.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentPipelineEnhanced.js","sourceRoot":"","sources":["../../src/agent/AgentPipelineEnhanced.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ModelCapabilities } from '../../core/modelMatcher';
|
|
2
|
+
import { ModelSpec } from '../token/types';
|
|
3
|
+
/**
|
|
4
|
+
* ModelRegistry - 模型规格注册表
|
|
5
|
+
*
|
|
6
|
+
* 将现有的 ModelCapabilities 扩展为 ModelSpec,
|
|
7
|
+
* 提供统一的模型信息查询接口。
|
|
8
|
+
*/
|
|
9
|
+
export declare class ModelRegistry {
|
|
10
|
+
private models;
|
|
11
|
+
constructor(baseCapabilities: ModelCapabilities[]);
|
|
12
|
+
/**
|
|
13
|
+
* 注册模型规格
|
|
14
|
+
*/
|
|
15
|
+
private register;
|
|
16
|
+
/**
|
|
17
|
+
* 根据名称获取模型规格
|
|
18
|
+
*/
|
|
19
|
+
get(name: string): ModelSpec | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* 获取默认模型
|
|
22
|
+
*/
|
|
23
|
+
getDefault(): ModelSpec;
|
|
24
|
+
/**
|
|
25
|
+
* 查找所有支持长文本的模型
|
|
26
|
+
* 按上下文窗口大小降序排列
|
|
27
|
+
*/
|
|
28
|
+
findLongContextCapable(): ModelSpec[];
|
|
29
|
+
/**
|
|
30
|
+
* 查找最佳长文本模型
|
|
31
|
+
* 返回上下文窗口最大的模型
|
|
32
|
+
*/
|
|
33
|
+
findBestLongContextModel(): ModelSpec | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* 列出所有已注册的模型
|
|
36
|
+
*/
|
|
37
|
+
listModels(): ModelSpec[];
|
|
38
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ModelRegistry = void 0;
|
|
4
|
+
const capabilities_1 = require("../../core/capabilities");
|
|
5
|
+
/**
|
|
6
|
+
* ModelRegistry - 模型规格注册表
|
|
7
|
+
*
|
|
8
|
+
* 将现有的 ModelCapabilities 扩展为 ModelSpec,
|
|
9
|
+
* 提供统一的模型信息查询接口。
|
|
10
|
+
*/
|
|
11
|
+
class ModelRegistry {
|
|
12
|
+
models = new Map();
|
|
13
|
+
constructor(baseCapabilities) {
|
|
14
|
+
baseCapabilities.forEach(cap => this.register(cap));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 注册模型规格
|
|
18
|
+
*/
|
|
19
|
+
register(cap) {
|
|
20
|
+
const spec = {
|
|
21
|
+
name: cap.name,
|
|
22
|
+
contextWindow: cap.contextWindow ?? 32768,
|
|
23
|
+
costTier: cap.costProfile ?? 'medium',
|
|
24
|
+
longContextCapable: cap.atomicCapabilities.includes(capabilities_1.AtomicCapability.LONG_CONTEXT)
|
|
25
|
+
};
|
|
26
|
+
this.models.set(cap.name, spec);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 根据名称获取模型规格
|
|
30
|
+
*/
|
|
31
|
+
get(name) {
|
|
32
|
+
return this.models.get(name);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 获取默认模型
|
|
36
|
+
*/
|
|
37
|
+
getDefault() {
|
|
38
|
+
const defaultModel = this.get('gemini-2.5-flash-lite');
|
|
39
|
+
if (!defaultModel) {
|
|
40
|
+
throw new Error('Default model not found in registry');
|
|
41
|
+
}
|
|
42
|
+
return defaultModel;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 查找所有支持长文本的模型
|
|
46
|
+
* 按上下文窗口大小降序排列
|
|
47
|
+
*/
|
|
48
|
+
findLongContextCapable() {
|
|
49
|
+
return Array.from(this.models.values())
|
|
50
|
+
.filter(m => m.longContextCapable)
|
|
51
|
+
.sort((a, b) => b.contextWindow - a.contextWindow);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 查找最佳长文本模型
|
|
55
|
+
* 返回上下文窗口最大的模型
|
|
56
|
+
*/
|
|
57
|
+
findBestLongContextModel() {
|
|
58
|
+
const longContextModels = this.findLongContextCapable();
|
|
59
|
+
return longContextModels.length > 0 ? longContextModels[0] : undefined;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 列出所有已注册的模型
|
|
63
|
+
*/
|
|
64
|
+
listModels() {
|
|
65
|
+
return Array.from(this.models.values());
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.ModelRegistry = ModelRegistry;
|
|
69
|
+
//# sourceMappingURL=ModelRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModelRegistry.js","sourceRoot":"","sources":["../../../src/policy/model/ModelRegistry.ts"],"names":[],"mappings":";;;AACA,0DAA2D;AAG3D;;;;;GAKG;AACH,MAAa,aAAa;IACd,MAAM,GAA2B,IAAI,GAAG,EAAE,CAAC;IAEnD,YAAY,gBAAqC;QAC7C,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IACxD,CAAC;IAED;;OAEG;IACK,QAAQ,CAAC,GAAsB;QACnC,MAAM,IAAI,GAAc;YACpB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,KAAK;YACzC,QAAQ,EAAE,GAAG,CAAC,WAAW,IAAI,QAAQ;YACrC,kBAAkB,EAAE,GAAG,CAAC,kBAAkB,CAAC,QAAQ,CAC/C,+BAAgB,CAAC,YAAY,CAChC;SACJ,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IAED;;OAEG;IACH,GAAG,CAAC,IAAY;QACZ,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,UAAU;QACN,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACvD,IAAI,CAAC,YAAY,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QAC3D,CAAC;QACD,OAAO,YAAY,CAAC;IACxB,CAAC;IAED;;;OAGG;IACH,sBAAsB;QAClB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;aAClC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC;aACjC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC;IAC3D,CAAC;IAED;;;OAGG;IACH,wBAAwB;QACpB,MAAM,iBAAiB,GAAG,IAAI,CAAC,sBAAsB,EAAE,CAAC;QACxD,OAAO,iBAAiB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3E,CAAC;IAED;;OAEG;IACH,UAAU;QACN,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5C,CAAC;CACJ;AAjED,sCAiEC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { PendingContextItem, SamplingStrategy } from '../policy/token/types';
|
|
2
|
+
/**
|
|
3
|
+
* ContextSampler - 上下文采样器
|
|
4
|
+
*
|
|
5
|
+
* 职责:
|
|
6
|
+
* - 实现 head_tail 采样策略
|
|
7
|
+
* - 保留文件头部和尾部,丢弃中间部分
|
|
8
|
+
*/
|
|
9
|
+
export declare class ContextSampler {
|
|
10
|
+
/**
|
|
11
|
+
* 对 PendingContextItem 应用采样策略
|
|
12
|
+
*/
|
|
13
|
+
static applySampling(item: PendingContextItem, strategy: SamplingStrategy): Promise<PendingContextItem>;
|
|
14
|
+
/**
|
|
15
|
+
* Head-Tail 采样:保留头部和尾部各 30 行
|
|
16
|
+
*/
|
|
17
|
+
private static applyHeadTail;
|
|
18
|
+
/**
|
|
19
|
+
* Random 采样:随机保留 50% 的行
|
|
20
|
+
*/
|
|
21
|
+
private static applyRandom;
|
|
22
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ContextSampler = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* ContextSampler - 上下文采样器
|
|
6
|
+
*
|
|
7
|
+
* 职责:
|
|
8
|
+
* - 实现 head_tail 采样策略
|
|
9
|
+
* - 保留文件头部和尾部,丢弃中间部分
|
|
10
|
+
*/
|
|
11
|
+
class ContextSampler {
|
|
12
|
+
/**
|
|
13
|
+
* 对 PendingContextItem 应用采样策略
|
|
14
|
+
*/
|
|
15
|
+
static async applySampling(item, strategy) {
|
|
16
|
+
if (strategy === 'none' || item.samplingStrategy === 'none') {
|
|
17
|
+
return item;
|
|
18
|
+
}
|
|
19
|
+
if (strategy === 'head_tail' || item.samplingStrategy === 'head_tail') {
|
|
20
|
+
return this.applyHeadTail(item);
|
|
21
|
+
}
|
|
22
|
+
if (strategy === 'random') {
|
|
23
|
+
return this.applyRandom(item);
|
|
24
|
+
}
|
|
25
|
+
return item;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Head-Tail 采样:保留头部和尾部各 30 行
|
|
29
|
+
*/
|
|
30
|
+
static async applyHeadTail(item) {
|
|
31
|
+
const resolved = await item.resolve();
|
|
32
|
+
const lines = resolved.content.split('\n');
|
|
33
|
+
const keepLines = 60;
|
|
34
|
+
const headLines = Math.min(30, Math.floor(lines.length / 2));
|
|
35
|
+
const tailLines = Math.min(30, Math.floor(lines.length / 2));
|
|
36
|
+
const sampledLines = [
|
|
37
|
+
...lines.slice(0, headLines),
|
|
38
|
+
// ...lines.slice(headLines, lines.length - tailLines), // 跳过中间部分
|
|
39
|
+
...lines.slice(-tailLines)
|
|
40
|
+
];
|
|
41
|
+
return {
|
|
42
|
+
...item,
|
|
43
|
+
id: `${item.id} (sampled)`,
|
|
44
|
+
resolve: async () => ({
|
|
45
|
+
content: sampledLines.join('\n'),
|
|
46
|
+
byteSize: Buffer.byteLength(sampledLines.join('\n'), 'utf-8'),
|
|
47
|
+
lineCount: sampledLines.length
|
|
48
|
+
})
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Random 采样:随机保留 50% 的行
|
|
53
|
+
*/
|
|
54
|
+
static async applyRandom(item) {
|
|
55
|
+
const resolved = await item.resolve();
|
|
56
|
+
const lines = resolved.content.split('\n');
|
|
57
|
+
const sampledLines = lines.filter((_, index) => Math.random() > 0.5);
|
|
58
|
+
return {
|
|
59
|
+
...item,
|
|
60
|
+
id: `${item.id} (random)`,
|
|
61
|
+
resolve: async () => ({
|
|
62
|
+
content: sampledLines.join('\n'),
|
|
63
|
+
byteSize: Buffer.byteLength(sampledLines.join('\n'), 'utf-8'),
|
|
64
|
+
lineCount: sampledLines.length
|
|
65
|
+
})
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.ContextSampler = ContextSampler;
|
|
70
|
+
//# sourceMappingURL=sampler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sampler.js","sourceRoot":"","sources":["../../src/policy/sampler.ts"],"names":[],"mappings":";;;AAEA;;;;;;GAMG;AACH,MAAa,cAAc;IACvB;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,aAAa,CACtB,IAAwB,EACxB,QAA0B;QAE1B,IAAI,QAAQ,KAAK,MAAM,IAAI,IAAI,CAAC,gBAAgB,KAAK,MAAM,EAAE,CAAC;YAC1D,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,IAAI,QAAQ,KAAK,WAAW,IAAI,IAAI,CAAC,gBAAgB,KAAK,WAAW,EAAE,CAAC;YACpE,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QACpC,CAAC;QAED,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,KAAK,CAAC,aAAa,CAC9B,IAAwB;QAExB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAE3C,MAAM,SAAS,GAAG,EAAE,CAAC;QACrB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAC7D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAE7D,MAAM,YAAY,GAAG;YACjB,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC;YAC5B,iEAAiE;YACjE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC;SAC7B,CAAC;QAEF,OAAO;YACH,GAAG,IAAI;YACP,EAAE,EAAE,GAAG,IAAI,CAAC,EAAE,YAAY;YAC1B,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;gBAClB,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;gBAChC,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;gBAC7D,SAAS,EAAE,YAAY,CAAC,MAAM;aACjC,CAAC;SACL,CAAC;IACN,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,KAAK,CAAC,WAAW,CAC5B,IAAwB;QAExB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAE3C,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;QAErE,OAAO;YACH,GAAG,IAAI;YACP,EAAE,EAAE,GAAG,IAAI,CAAC,EAAE,WAAW;YACzB,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;gBAClB,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;gBAChC,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;gBAC7D,SAAS,EAAE,YAAY,CAAC,MAAM;aACjC,CAAC;SACL,CAAC;IACN,CAAC;CACJ;AA1ED,wCA0EC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { PendingContextItem } from '../policy/token/types';
|
|
2
|
+
/**
|
|
3
|
+
* SyntaxHandler - 语法解析器和延迟加载生成器
|
|
4
|
+
*
|
|
5
|
+
* 职责:
|
|
6
|
+
* - 解析 @file 和 #dir 语法
|
|
7
|
+
* - 返回 PendingContextItem[](不读取内容)
|
|
8
|
+
* - 提供 estimate() 和 resolve() 方法
|
|
9
|
+
*/
|
|
10
|
+
export declare class SyntaxHandler {
|
|
11
|
+
static parse(tokens: string[]): PendingContextItem[];
|
|
12
|
+
/**
|
|
13
|
+
* 解析文件引用 @file:path:start-end
|
|
14
|
+
*/
|
|
15
|
+
private static parseFileToken;
|
|
16
|
+
/**
|
|
17
|
+
* 解析目录引用 #dir
|
|
18
|
+
*/
|
|
19
|
+
private static parseDirToken;
|
|
20
|
+
/**
|
|
21
|
+
* 解析路径和行号范围
|
|
22
|
+
*/
|
|
23
|
+
private static parsePathAndRange;
|
|
24
|
+
/**
|
|
25
|
+
* 应用行号范围
|
|
26
|
+
*/
|
|
27
|
+
private static applyRange;
|
|
28
|
+
/**
|
|
29
|
+
* 扫描目录(递归)
|
|
30
|
+
*/
|
|
31
|
+
private static scanDir;
|
|
32
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SyntaxHandler = void 0;
|
|
7
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
/**
|
|
10
|
+
* SyntaxHandler - 语法解析器和延迟加载生成器
|
|
11
|
+
*
|
|
12
|
+
* 职责:
|
|
13
|
+
* - 解析 @file 和 #dir 语法
|
|
14
|
+
* - 返回 PendingContextItem[](不读取内容)
|
|
15
|
+
* - 提供 estimate() 和 resolve() 方法
|
|
16
|
+
*/
|
|
17
|
+
class SyntaxHandler {
|
|
18
|
+
static parse(tokens) {
|
|
19
|
+
const items = [];
|
|
20
|
+
for (const token of tokens) {
|
|
21
|
+
if (token.startsWith('@')) {
|
|
22
|
+
const item = this.parseFileToken(token);
|
|
23
|
+
if (item)
|
|
24
|
+
items.push(item);
|
|
25
|
+
}
|
|
26
|
+
else if (token.startsWith('#')) {
|
|
27
|
+
const item = this.parseDirToken(token);
|
|
28
|
+
if (item)
|
|
29
|
+
items.push(item);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return items;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 解析文件引用 @file:path:start-end
|
|
36
|
+
*/
|
|
37
|
+
static parseFileToken(token) {
|
|
38
|
+
const raw = token.slice(1);
|
|
39
|
+
const { filePath, range } = this.parsePathAndRange(raw);
|
|
40
|
+
if (!filePath)
|
|
41
|
+
return null;
|
|
42
|
+
const absPath = path_1.default.resolve(filePath);
|
|
43
|
+
return {
|
|
44
|
+
id: absPath,
|
|
45
|
+
type: 'file',
|
|
46
|
+
originalToken: token,
|
|
47
|
+
samplingStrategy: 'head_tail',
|
|
48
|
+
estimate: async () => {
|
|
49
|
+
try {
|
|
50
|
+
const stat = await promises_1.default.stat(absPath);
|
|
51
|
+
return { byteSize: stat.size };
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
resolve: async () => {
|
|
58
|
+
let content = await promises_1.default.readFile(absPath, 'utf-8');
|
|
59
|
+
if (range) {
|
|
60
|
+
content = this.applyRange(content, range);
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
content,
|
|
64
|
+
byteSize: Buffer.byteLength(content, 'utf-8'),
|
|
65
|
+
lineCount: content.split('\n').length
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 解析目录引用 #dir
|
|
72
|
+
*/
|
|
73
|
+
static parseDirToken(token) {
|
|
74
|
+
const dir = token.slice(1);
|
|
75
|
+
const absPath = path_1.default.resolve(dir);
|
|
76
|
+
return {
|
|
77
|
+
id: absPath,
|
|
78
|
+
type: 'dir',
|
|
79
|
+
originalToken: token,
|
|
80
|
+
samplingStrategy: 'head_tail',
|
|
81
|
+
estimate: async () => {
|
|
82
|
+
try {
|
|
83
|
+
const files = await this.scanDir(absPath);
|
|
84
|
+
let total = 0;
|
|
85
|
+
for (const f of files) {
|
|
86
|
+
const stat = await promises_1.default.stat(f);
|
|
87
|
+
total += stat.size;
|
|
88
|
+
}
|
|
89
|
+
return { byteSize: total };
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
resolve: async () => {
|
|
96
|
+
const files = await this.scanDir(absPath);
|
|
97
|
+
let content = '';
|
|
98
|
+
for (const f of files) {
|
|
99
|
+
content += `\n// ===== ${f} =====\n`;
|
|
100
|
+
content += await promises_1.default.readFile(f, 'utf-8');
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
content,
|
|
104
|
+
byteSize: Buffer.byteLength(content, 'utf-8')
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* 解析路径和行号范围
|
|
111
|
+
*/
|
|
112
|
+
static parsePathAndRange(raw) {
|
|
113
|
+
const match = raw.match(/^(.*?)(?::(\d+)-(\d+))?$/);
|
|
114
|
+
if (!match)
|
|
115
|
+
return { filePath: raw };
|
|
116
|
+
const [, filePath, start, end] = match;
|
|
117
|
+
if (!start || !end)
|
|
118
|
+
return { filePath };
|
|
119
|
+
return {
|
|
120
|
+
filePath,
|
|
121
|
+
range: { start: Number(start), end: Number(end) }
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 应用行号范围
|
|
126
|
+
*/
|
|
127
|
+
static applyRange(content, range) {
|
|
128
|
+
if (!range)
|
|
129
|
+
return content;
|
|
130
|
+
const lines = content.split('\n');
|
|
131
|
+
return lines.slice(range.start - 1, range.end).join('\n');
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 扫描目录(递归)
|
|
135
|
+
*/
|
|
136
|
+
static async scanDir(dirPath) {
|
|
137
|
+
const files = [];
|
|
138
|
+
async function scan(dirPath) {
|
|
139
|
+
const entries = await promises_1.default.readdir(dirPath, { withFileTypes: true });
|
|
140
|
+
for (const entry of entries) {
|
|
141
|
+
const fullPath = path_1.default.join(dirPath, entry.name);
|
|
142
|
+
if (entry.isDirectory()) {
|
|
143
|
+
await scan(fullPath);
|
|
144
|
+
}
|
|
145
|
+
else if (entry.isFile()) {
|
|
146
|
+
files.push(fullPath);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
await scan(dirPath);
|
|
151
|
+
return files;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
exports.SyntaxHandler = SyntaxHandler;
|
|
155
|
+
//# sourceMappingURL=syntaxHandler.js.map
|