@jsonstudio/llms 0.6.802 → 0.6.954
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/bridge/routecodex-adapter.d.ts +74 -0
- package/dist/config-unified/enhanced-path-resolver.d.ts +5 -0
- package/dist/config-unified/unified-config.d.ts +26 -0
- package/dist/conversion/codec-registry.d.ts +10 -0
- package/dist/conversion/codecs/gemini-openai-codec.d.ts +16 -0
- package/dist/conversion/codecs/openai-openai-codec.d.ts +12 -0
- package/dist/conversion/codecs/responses-openai-codec.d.ts +12 -0
- package/dist/conversion/compat/profiles/chat-gemini.json +12 -0
- package/dist/conversion/config/config-manager.d.ts +212 -0
- package/dist/conversion/hub/config/types.d.ts +26 -0
- package/dist/conversion/hub/core/detour-registry.d.ts +9 -0
- package/dist/conversion/hub/core/hub-context.d.ts +21 -0
- package/dist/conversion/hub/core/index.d.ts +3 -0
- package/dist/conversion/hub/core/stage-driver.d.ts +30 -0
- package/dist/conversion/hub/format-adapters/anthropic-format-adapter.d.ts +16 -0
- package/dist/conversion/hub/format-adapters/chat-format-adapter.d.ts +17 -0
- package/dist/conversion/hub/format-adapters/gemini-format-adapter.d.ts +16 -0
- package/dist/conversion/hub/format-adapters/index.d.ts +21 -0
- package/dist/conversion/hub/hub-feature.d.ts +1 -0
- package/dist/conversion/hub/node-support.d.ts +19 -0
- package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +11 -0
- package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +3 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +7 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +113 -17
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +6 -3
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage1_tool_governance/index.js +4 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +23 -1
- package/dist/conversion/hub/pipelines/inbound.d.ts +22 -0
- package/dist/conversion/hub/pipelines/outbound.d.ts +22 -0
- package/dist/conversion/hub/policy/policy-engine.d.ts +46 -0
- package/dist/conversion/hub/policy/policy-engine.js +176 -0
- package/dist/conversion/hub/policy/protocol-spec.d.ts +50 -0
- package/dist/conversion/hub/policy/protocol-spec.js +105 -0
- package/dist/conversion/hub/process/chat-process.d.ts +32 -0
- package/dist/conversion/hub/registry.d.ts +28 -0
- package/dist/conversion/hub/response/chat-response-utils.d.ts +6 -0
- package/dist/conversion/hub/response/provider-response.js +31 -0
- package/dist/conversion/hub/semantic-mappers/chat-mapper.js +32 -1
- package/dist/conversion/hub/semantic-mappers/gemini-mapper.d.ts +7 -0
- package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +96 -1
- package/dist/conversion/hub/semantic-mappers/index.d.ts +4 -0
- package/dist/conversion/hub/semantic-mappers/responses-mapper.d.ts +21 -0
- package/dist/conversion/hub/standardized-bridge.d.ts +12 -0
- package/dist/conversion/hub/types/chat-schema.d.ts +112 -0
- package/dist/conversion/hub/types/errors.d.ts +5 -0
- package/dist/conversion/hub/types/format-envelope.d.ts +7 -0
- package/dist/conversion/hub/types/index.d.ts +6 -0
- package/dist/conversion/hub/types/json.d.ts +9 -0
- package/dist/conversion/hub/types/node.d.ts +31 -0
- package/dist/conversion/responses/responses-openai-bridge.js +263 -10
- package/dist/conversion/schema-validator.d.ts +7 -0
- package/dist/conversion/shared/args-mapping.d.ts +18 -0
- package/dist/conversion/shared/chat-request-filters.d.ts +9 -0
- package/dist/conversion/shared/errors.d.ts +1 -1
- package/dist/conversion/shared/gemini-tool-utils.js +105 -1
- package/dist/conversion/shared/jsonish.d.ts +3 -0
- package/dist/conversion/shared/mcp-injection.d.ts +2 -0
- package/dist/conversion/shared/media.d.ts +1 -0
- package/dist/conversion/shared/openai-message-normalize.d.ts +1 -0
- package/dist/conversion/shared/payload-budget.d.ts +13 -0
- package/dist/conversion/shared/reasoning-mapping.d.ts +5 -0
- package/dist/conversion/shared/responses-request-adapter.d.ts +1 -28
- package/dist/conversion/shared/responses-request-adapter.js +1 -430
- package/dist/conversion/shared/snapshot-hooks.js +58 -3
- package/dist/conversion/shared/tool-governor.js +8 -2
- package/dist/conversion/shared/tool-harvester.d.ts +31 -0
- package/dist/conversion/shared/tool-mapping.js +10 -29
- package/dist/conversion/types.d.ts +33 -0
- package/dist/filters/builtin/add-fields-filter.d.ts +8 -0
- package/dist/filters/builtin/blacklist-filter.d.ts +8 -0
- package/dist/filters/builtin/whitelist-filter.d.ts +8 -0
- package/dist/filters/engine.d.ts +16 -0
- package/dist/filters/special/request-tool-choice-policy.d.ts +11 -0
- package/dist/filters/special/response-finish-invariants.d.ts +11 -0
- package/dist/filters/special/response-openai-to-responses-bridge.d.ts +13 -0
- package/dist/filters/special/response-tool-arguments-blacklist.d.ts +12 -0
- package/dist/filters/special/response-tool-arguments-schema-converge.d.ts +13 -0
- package/dist/filters/special/response-tool-arguments-stringify.d.ts +9 -0
- package/dist/filters/special/response-tool-arguments-whitelist.d.ts +11 -0
- package/dist/filters/special/tool-filter-hooks.d.ts +19 -0
- package/dist/filters/special/tool-post-constraints.d.ts +31 -0
- package/dist/filters/types.d.ts +68 -0
- package/dist/filters/utils/fieldmap-loader.d.ts +2 -0
- package/dist/filters/utils/snapshot-writer.d.ts +10 -0
- package/dist/guidance/index.d.ts +3 -0
- package/dist/guidance/index.js +78 -83
- package/dist/http/sse-response.d.ts +22 -0
- package/dist/router/virtual-router/bootstrap.d.ts +6 -0
- package/dist/router/virtual-router/bootstrap.js +49 -5
- package/dist/router/virtual-router/classifier.d.ts +10 -0
- package/dist/router/virtual-router/engine-selection.js +98 -11
- package/dist/router/virtual-router/engine.js +177 -31
- package/dist/router/virtual-router/error-center.d.ts +10 -0
- package/dist/router/virtual-router/features.d.ts +3 -0
- package/dist/router/virtual-router/routing-instructions.d.ts +23 -1
- package/dist/router/virtual-router/routing-instructions.js +120 -30
- package/dist/router/virtual-router/types.d.ts +11 -0
- package/dist/servertool/engine.js +192 -17
- package/dist/servertool/handlers/apply-patch-guard.js +269 -0
- package/dist/servertool/handlers/exec-command-guard.js +558 -0
- package/dist/servertool/handlers/followup-message-trimmer.d.ts +16 -0
- package/dist/servertool/handlers/followup-message-trimmer.js +198 -0
- package/dist/servertool/handlers/followup-request-builder.d.ts +17 -0
- package/dist/servertool/handlers/followup-request-builder.js +122 -0
- package/dist/servertool/handlers/gemini-empty-reply-continue.js +252 -51
- package/dist/servertool/handlers/iflow-model-error-retry.js +12 -22
- package/dist/servertool/handlers/stop-message-auto.js +237 -75
- package/dist/servertool/handlers/vision.js +15 -27
- package/dist/servertool/handlers/web-search.js +17 -43
- package/dist/servertool/server-side-tools.d.ts +3 -0
- package/dist/servertool/server-side-tools.js +3 -0
- package/dist/sse/json-to-sse/anthropic-json-to-sse-converter.d.ts +2 -1
- package/dist/sse/json-to-sse/chat-json-to-sse-converter.d.ts +80 -0
- package/dist/sse/json-to-sse/event-generators/chat.d.ts +55 -0
- package/dist/sse/json-to-sse/event-generators/responses.d.ts +99 -0
- package/dist/sse/json-to-sse/gemini-json-to-sse-converter.d.ts +2 -1
- package/dist/sse/json-to-sse/responses-json-to-sse-converter.d.ts +80 -0
- package/dist/sse/json-to-sse/sequencers/anthropic-sequencer.d.ts +1 -1
- package/dist/sse/json-to-sse/sequencers/chat-sequencer.d.ts +2 -2
- package/dist/sse/json-to-sse/sequencers/gemini-sequencer.d.ts +1 -1
- package/dist/sse/json-to-sse/sequencers/responses-sequencer.d.ts +40 -0
- package/dist/sse/shared/chat-serializer.d.ts +4 -0
- package/dist/sse/shared/constants.d.ts +272 -0
- package/dist/sse/shared/serializers/anthropic-event-serializer.d.ts +1 -1
- package/dist/sse/shared/serializers/base-serializer.d.ts +158 -0
- package/dist/sse/shared/serializers/chat-event-serializer.d.ts +82 -0
- package/dist/sse/shared/serializers/gemini-event-serializer.d.ts +1 -1
- package/dist/sse/shared/serializers/index.d.ts +2 -1
- package/dist/sse/shared/serializers/responses-event-serializer.d.ts +123 -0
- package/dist/sse/shared/serializers/types.d.ts +51 -0
- package/dist/sse/shared/utils.d.ts +254 -0
- package/dist/sse/shared/writer.d.ts +2 -2
- package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +1 -1
- package/dist/sse/sse-to-json/builders/anthropic-response-builder.d.ts +1 -1
- package/dist/sse/sse-to-json/builders/response-builder.d.ts +1 -1
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +2 -1
- package/dist/sse/sse-to-json/gemini-sse-to-json-converter.d.ts +2 -1
- package/dist/sse/sse-to-json/parsers/sse-parser.d.ts +73 -0
- package/dist/sse/sse-to-json/responses-sse-to-json-converter.d.ts +1 -1
- package/dist/sse/types/chat-types.d.ts +1 -1
- package/dist/sse/types/responses-types.d.ts +1 -1
- package/dist/tools/apply-patch/execution-capturer.d.ts +13 -0
- package/dist/tools/apply-patch/execution-capturer.js +158 -0
- package/dist/tools/apply-patch/regression-capturer.d.ts +1 -0
- package/dist/tools/apply-patch/regression-capturer.js +5 -4
- package/dist/tools/apply-patch/structured.js +109 -13
- package/dist/tools/apply-patch/validator.js +112 -18
- package/dist/tools/tool-registry.d.ts +8 -0
- package/dist/tools/tool-registry.js +2 -1
- package/package.json +4 -4
- package/dist/conversion/compat/actions/apply-patch-format-fixer.js +0 -233
- package/dist/conversion/config/compat-profiles.json +0 -38
- package/dist/conversion/hub/pipeline/context-limit.d.ts +0 -13
- package/dist/conversion/hub/pipeline/context-limit.js +0 -55
- package/dist/conversion/hub/response/server-side-tools.d.ts +0 -26
- package/dist/conversion/hub/response/server-side-tools.js +0 -383
- package/dist/conversion/shared/bridge-conversation-store.d.ts +0 -41
- package/dist/conversion/shared/bridge-conversation-store.js +0 -279
- package/dist/conversion/shared/bridge-request-adapter.d.ts +0 -28
- package/dist/conversion/shared/bridge-request-adapter.js +0 -430
- package/dist/conversion/shared/responses-id-utils.js +0 -42
- package/dist/conversion/shared/responses-instructions.js +0 -113
- package/dist/conversion/shared/responses-message-utils.d.ts +0 -15
- package/dist/conversion/shared/responses-message-utils.js +0 -206
- package/dist/conversion/shared/responses-metadata.js +0 -1
- package/dist/conversion/shared/responses-output-utils.d.ts +0 -7
- package/dist/conversion/shared/responses-output-utils.js +0 -108
- package/dist/conversion/shared/responses-types.d.ts +0 -33
- package/dist/conversion/shared/tool-normalizers.d.ts +0 -4
- package/dist/conversion/shared/tool-normalizers.js +0 -84
- package/dist/filters/special/request-streaming-to-nonstreaming.d.ts +0 -13
- package/dist/filters/special/request-streaming-to-nonstreaming.js +0 -39
- package/dist/filters/special/response-apply-patch-toon-decode.d.ts +0 -23
- package/dist/filters/special/response-apply-patch-toon-decode.js +0 -460
- package/dist/filters/special/response-tool-arguments-toon-decode.d.ts +0 -10
- package/dist/filters/special/response-tool-arguments-toon-decode.js +0 -154
- package/dist/servertool/flow-types.d.ts +0 -40
- package/dist/servertool/flow-types.js +0 -1
- package/dist/servertool/orchestration-types.d.ts +0 -33
- package/dist/servertool/orchestration-types.js +0 -1
- package/dist/servertool/vision-tool.d.ts +0 -2
- package/dist/servertool/vision-tool.js +0 -185
- package/dist/tools/patch-args-normalizer.d.ts +0 -15
- package/dist/tools/patch-args-normalizer.js +0 -472
- package/dist/utils/toon.d.ts +0 -4
- package/dist/utils/toon.js +0 -75
- /package/dist/{conversion/compat/actions/apply-patch-format-fixer.d.ts → servertool/handlers/apply-patch-guard.d.ts} +0 -0
- /package/dist/{conversion/shared/responses-types.js → servertool/handlers/exec-command-guard.d.ts} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnthropicMessageResponse, AnthropicSseEvent } from '../../types/index.js';
|
|
1
|
+
import type { AnthropicMessageResponse, AnthropicSseEvent } from '../../types/index.js';
|
|
2
2
|
import type { ChatReasoningMode } from '../../types/chat-types.js';
|
|
3
3
|
interface BuilderOptions {
|
|
4
4
|
reasoningMode?: ChatReasoningMode;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Responses响应构建器
|
|
3
3
|
* 负责状态机和事件聚合,从SSE事件构建完整的Responses响应对象
|
|
4
4
|
*/
|
|
5
|
-
import { ResponsesSseEvent, ResponsesResponse } from '../../types/index.js';
|
|
5
|
+
import type { ResponsesSseEvent, ResponsesResponse } from '../../types/index.js';
|
|
6
6
|
export type ResponseBuilderState = 'initial' | 'building' | 'completed' | 'error';
|
|
7
7
|
export interface ResponseBuilderConfig {
|
|
8
8
|
enableStrictValidation: boolean;
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Chat SSE → JSON转换器
|
|
3
3
|
* 将SSE事件流聚合为ChatCompletion响应
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { DEFAULT_CHAT_CONVERSION_CONFIG } from '../types/index.js';
|
|
6
|
+
import type { ChatCompletionResponse, ChatSseEvent, SseToChatJsonOptions, ChatEventStats } from '../types/index.js';
|
|
6
7
|
/**
|
|
7
8
|
* Chat SSE到JSON转换器
|
|
8
9
|
*/
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DEFAULT_GEMINI_CONVERSION_CONFIG } from '../types/index.js';
|
|
2
|
+
import type { GeminiResponse, SseToGeminiJsonOptions } from '../types/index.js';
|
|
2
3
|
export declare class GeminiSseToJsonConverter {
|
|
3
4
|
private config;
|
|
4
5
|
private contexts;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE事件解析器
|
|
3
|
+
* 负责将SSE文本帧解析为标准化的SSE事件对象
|
|
4
|
+
*/
|
|
5
|
+
import type { BaseSseEvent } from '../../types/index.js';
|
|
6
|
+
export interface SseParserConfig {
|
|
7
|
+
enableStrictValidation: boolean;
|
|
8
|
+
enableEventRecovery: boolean;
|
|
9
|
+
maxEventSize: number;
|
|
10
|
+
allowedEventTypes: Set<string>;
|
|
11
|
+
}
|
|
12
|
+
export interface SseParseResult {
|
|
13
|
+
success: boolean;
|
|
14
|
+
event?: BaseSseEvent;
|
|
15
|
+
error?: string;
|
|
16
|
+
rawData: string;
|
|
17
|
+
}
|
|
18
|
+
export declare const DEFAULT_SSE_PARSER_CONFIG: SseParserConfig;
|
|
19
|
+
/**
|
|
20
|
+
* SSE原始事件数据
|
|
21
|
+
*/
|
|
22
|
+
export interface RawSseEvent {
|
|
23
|
+
id?: string;
|
|
24
|
+
event: string;
|
|
25
|
+
data: string;
|
|
26
|
+
retry?: string;
|
|
27
|
+
timestamp?: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 将原始SSE行组装为事件
|
|
31
|
+
*/
|
|
32
|
+
export declare function assembleSseEvent(lines: string[]): RawSseEvent | null;
|
|
33
|
+
/**
|
|
34
|
+
* 解析SSE事件文本为标准化事件对象
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseSseEvent(sseText: string, config?: SseParserConfig): SseParseResult;
|
|
37
|
+
/**
|
|
38
|
+
* 解析SSE流(处理多事件数据)
|
|
39
|
+
*/
|
|
40
|
+
export declare function parseSseStream(sseData: string, config?: SseParserConfig): Generator<SseParseResult>;
|
|
41
|
+
/**
|
|
42
|
+
* 流式解析SSE数据
|
|
43
|
+
*/
|
|
44
|
+
export declare function parseSseStreamAsync(asyncSseData: AsyncIterable<string>, config?: SseParserConfig): AsyncGenerator<SseParseResult>;
|
|
45
|
+
/**
|
|
46
|
+
* 创建SSE解析器工厂
|
|
47
|
+
*/
|
|
48
|
+
export declare function createSseParser(config?: Partial<SseParserConfig>): {
|
|
49
|
+
/**
|
|
50
|
+
* 解析单个事件
|
|
51
|
+
*/
|
|
52
|
+
parseEvent(sseText: string): SseParseResult;
|
|
53
|
+
/**
|
|
54
|
+
* 解析多事件流
|
|
55
|
+
*/
|
|
56
|
+
parseStream(sseData: string): Generator<SseParseResult>;
|
|
57
|
+
/**
|
|
58
|
+
* 异步解析流
|
|
59
|
+
*/
|
|
60
|
+
parseStreamAsync(asyncSseData: AsyncIterable<string>): AsyncGenerator<SseParseResult>;
|
|
61
|
+
/**
|
|
62
|
+
* 获取当前配置
|
|
63
|
+
*/
|
|
64
|
+
getConfig(): SseParserConfig;
|
|
65
|
+
/**
|
|
66
|
+
* 添加允许的事件类型
|
|
67
|
+
*/
|
|
68
|
+
addEventType(eventType: string): void;
|
|
69
|
+
/**
|
|
70
|
+
* 移除允许的事件类型
|
|
71
|
+
*/
|
|
72
|
+
removeEventType(eventType: string): void;
|
|
73
|
+
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Responses SSE → JSON转换器(重构版本)
|
|
3
3
|
* 使用函数化架构:解析 + 构建 + 验证分离
|
|
4
4
|
*/
|
|
5
|
-
import { ResponsesResponse, SseToResponsesJsonContext, SseToResponsesJsonOptions, ResponsesSseEventStream } from '../types/index.js';
|
|
5
|
+
import type { ResponsesResponse, SseToResponsesJsonContext, SseToResponsesJsonOptions, ResponsesSseEventStream } from '../types/index.js';
|
|
6
6
|
/**
|
|
7
7
|
* 重构后的Responses SSE到JSON转换器
|
|
8
8
|
* 采用函数化架构,专注于编排而非具体业务逻辑
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Chat协议相关类型定义
|
|
3
3
|
* 支持OpenAI Chat Completions的JSON↔SSE双向转换
|
|
4
4
|
*/
|
|
5
|
-
import { BaseSseEvent, StreamDirection } from './core-interfaces.js';
|
|
5
|
+
import type { BaseSseEvent, StreamDirection } from './core-interfaces.js';
|
|
6
6
|
type JsonObject = Record<string, unknown>;
|
|
7
7
|
export type ChatSseEventType = 'chat_chunk' | 'chat.done' | 'error' | 'ping';
|
|
8
8
|
export interface ChatSseEvent extends BaseSseEvent {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Responses协议相关类型定义
|
|
3
3
|
* 支持OpenAI Responses API的JSON↔SSE双向转换
|
|
4
4
|
*/
|
|
5
|
-
import { BaseSseEvent, StreamDirection,
|
|
5
|
+
import type { BaseSseEvent, StreamDirection, JsonObject, JsonValue } from './core-interfaces.js';
|
|
6
6
|
import type { RequiredAction } from './sse-events.js';
|
|
7
7
|
export * from './sse-events.js';
|
|
8
8
|
export type ResponsesSseEventType = 'response.created' | 'response.in_progress' | 'response.completed' | 'response.required_action' | 'response.done' | 'response.output_item.added' | 'response.output_item.done' | 'response.content_part.added' | 'response.content_part.done' | 'response.output_text.delta' | 'response.output_text.done' | 'response.reasoning_text.delta' | 'response.reasoning_text.done' | 'response.reasoning_signature.delta' | 'response.reasoning_image.delta' | 'response.reasoning_summary_part.added' | 'response.reasoning_summary_part.done' | 'response.reasoning_summary_text.delta' | 'response.reasoning_summary_text.done' | 'response.function_call_arguments.delta' | 'response.function_call_arguments.done' | 'response.error' | 'response.cancelled' | 'response.start' | 'content_part.delta' | 'reasoning.delta' | 'function_call.start' | 'function_call.delta' | 'function_call.done' | 'output_item.start' | 'content_part.start' | 'content_part.done' | 'output_item.done' | 'reasoning.start' | 'reasoning.done' | 'required_action' | 'error';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface ApplyPatchExecutionFailureCaptureContext {
|
|
2
|
+
requestId?: string;
|
|
3
|
+
entryEndpoint?: string;
|
|
4
|
+
providerKey?: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
source?: string;
|
|
7
|
+
meta?: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
export declare function captureApplyPatchExecutionFailure(content: string, context: ApplyPatchExecutionFailureCaptureContext & {
|
|
10
|
+
toolCallId?: string;
|
|
11
|
+
toolCallArgs?: string;
|
|
12
|
+
}): void;
|
|
13
|
+
export declare function captureApplyPatchExecutionFailuresFromProcessedRequest(processedRequest: unknown): void;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import { createHash } from 'crypto';
|
|
5
|
+
/**
|
|
6
|
+
* Captures apply_patch execution failures (tool role message contents) into errorsamples.
|
|
7
|
+
*
|
|
8
|
+
* These failures are not schema/shape failures; they happen when the tool is executed
|
|
9
|
+
* (e.g. file missing, context mismatch). We capture for debugging and compatibility
|
|
10
|
+
* tracking, but do NOT attempt semantic repair.
|
|
11
|
+
*
|
|
12
|
+
* Default destination:
|
|
13
|
+
* ~/.routecodex/errorsamples/apply_patch_exec/<error-type>/
|
|
14
|
+
*
|
|
15
|
+
* Explicit override:
|
|
16
|
+
* ROUTECODEX_APPLY_PATCH_EXEC_DIR=/abs/path
|
|
17
|
+
*
|
|
18
|
+
* Note: if ROUTECODEX_ERRORSAMPLES_DIR is set, it is used as the base root.
|
|
19
|
+
*/
|
|
20
|
+
const MAX_SAMPLES_PER_TYPE = 250;
|
|
21
|
+
function resolveSamplesRoot() {
|
|
22
|
+
const explicit = String(process?.env?.ROUTECODEX_APPLY_PATCH_EXEC_DIR || '').trim();
|
|
23
|
+
if (explicit)
|
|
24
|
+
return path.resolve(explicit);
|
|
25
|
+
const base = String(process?.env?.ROUTECODEX_ERRORSAMPLES_DIR || '').trim();
|
|
26
|
+
if (base)
|
|
27
|
+
return path.join(path.resolve(base), 'apply_patch_exec');
|
|
28
|
+
return path.join(os.homedir(), '.routecodex', 'errorsamples', 'apply_patch_exec');
|
|
29
|
+
}
|
|
30
|
+
function classifyExecutionFailure(content) {
|
|
31
|
+
const raw = String(content || '');
|
|
32
|
+
const trimmed = raw.trim();
|
|
33
|
+
const prefix = 'apply_patch verification failed:';
|
|
34
|
+
const msg = trimmed.toLowerCase().startsWith(prefix) ? trimmed.slice(prefix.length).trim() : trimmed;
|
|
35
|
+
const lower = msg.toLowerCase();
|
|
36
|
+
if (lower.includes('failed to read file'))
|
|
37
|
+
return { errorType: 'read_file_failed', message: msg };
|
|
38
|
+
if (lower.includes('no such file') || lower.includes('file not found'))
|
|
39
|
+
return { errorType: 'file_not_found', message: msg };
|
|
40
|
+
if (lower.includes('failed to find context'))
|
|
41
|
+
return { errorType: 'context_not_found', message: msg };
|
|
42
|
+
if (lower.includes('failed to find expected lines'))
|
|
43
|
+
return { errorType: 'expected_lines_not_found', message: msg };
|
|
44
|
+
if (lower.includes('invalid patch'))
|
|
45
|
+
return { errorType: 'invalid_patch', message: msg };
|
|
46
|
+
if (lower.includes('failed to parse'))
|
|
47
|
+
return { errorType: 'parse_failed', message: msg };
|
|
48
|
+
return { errorType: 'unknown', message: msg };
|
|
49
|
+
}
|
|
50
|
+
function stableSampleId(fields) {
|
|
51
|
+
const key = `${String(fields.errorType || 'unknown')}:${String(fields.errorMessage || '')}:` +
|
|
52
|
+
`${String(fields.toolCallId || '')}:${String(fields.toolCallArgs || '')}:${String(fields.requestId || '')}:${String(fields.mode || '')}`;
|
|
53
|
+
return createHash('sha1').update(key).digest('hex').slice(0, 16);
|
|
54
|
+
}
|
|
55
|
+
export function captureApplyPatchExecutionFailure(content, context) {
|
|
56
|
+
try {
|
|
57
|
+
const { errorType, message } = classifyExecutionFailure(content);
|
|
58
|
+
const root = resolveSamplesRoot();
|
|
59
|
+
const safeType = String(errorType || 'unknown').replace(/[^a-z0-9-]/gi, '_');
|
|
60
|
+
const typeDir = path.join(root, safeType);
|
|
61
|
+
if (!fs.existsSync(typeDir))
|
|
62
|
+
fs.mkdirSync(typeDir, { recursive: true });
|
|
63
|
+
// Check limit (best-effort; keep runtime safe)
|
|
64
|
+
try {
|
|
65
|
+
const existing = fs.readdirSync(typeDir).filter((f) => f.endsWith('.json'));
|
|
66
|
+
if (existing.length >= MAX_SAMPLES_PER_TYPE)
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// ignore
|
|
71
|
+
}
|
|
72
|
+
const mode = String(context.meta?.applyPatchToolMode || '').trim();
|
|
73
|
+
const id = `sample_${stableSampleId({
|
|
74
|
+
errorType,
|
|
75
|
+
errorMessage: message,
|
|
76
|
+
toolCallId: context.toolCallId,
|
|
77
|
+
toolCallArgs: context.toolCallArgs,
|
|
78
|
+
requestId: context.requestId,
|
|
79
|
+
mode
|
|
80
|
+
})}`;
|
|
81
|
+
const file = path.join(typeDir, `${id}.json`);
|
|
82
|
+
if (fs.existsSync(file))
|
|
83
|
+
return;
|
|
84
|
+
const sample = {
|
|
85
|
+
id,
|
|
86
|
+
timestamp: new Date().toISOString(),
|
|
87
|
+
errorType,
|
|
88
|
+
errorMessage: message,
|
|
89
|
+
toolCallId: context.toolCallId,
|
|
90
|
+
toolCallArgs: context.toolCallArgs,
|
|
91
|
+
requestId: context.requestId,
|
|
92
|
+
entryEndpoint: context.entryEndpoint,
|
|
93
|
+
providerKey: context.providerKey,
|
|
94
|
+
model: context.model,
|
|
95
|
+
source: context.source,
|
|
96
|
+
meta: context.meta
|
|
97
|
+
};
|
|
98
|
+
fs.writeFileSync(file, JSON.stringify(sample, null, 2), 'utf-8');
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// Silently fail to avoid disrupting runtime
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export function captureApplyPatchExecutionFailuresFromProcessedRequest(processedRequest) {
|
|
105
|
+
try {
|
|
106
|
+
const anyReq = processedRequest;
|
|
107
|
+
const messages = Array.isArray(anyReq?.messages) ? anyReq.messages : [];
|
|
108
|
+
if (!messages.length)
|
|
109
|
+
return;
|
|
110
|
+
const metadata = anyReq?.metadata || {};
|
|
111
|
+
const requestId = typeof metadata?.requestId === 'string' ? metadata.requestId : undefined;
|
|
112
|
+
const entryEndpoint = typeof metadata?.originalEndpoint === 'string' ? metadata.originalEndpoint : undefined;
|
|
113
|
+
const providerKey = typeof metadata?.providerKey === 'string' ? metadata.providerKey : undefined;
|
|
114
|
+
const model = typeof anyReq?.model === 'string' ? anyReq.model : undefined;
|
|
115
|
+
const toolCallArgsById = new Map();
|
|
116
|
+
for (const msg of messages) {
|
|
117
|
+
if (!msg || typeof msg !== 'object')
|
|
118
|
+
continue;
|
|
119
|
+
const toolCalls = Array.isArray(msg.tool_calls) ? msg.tool_calls : [];
|
|
120
|
+
for (const tc of toolCalls) {
|
|
121
|
+
const id = typeof tc?.id === 'string' ? String(tc.id) : '';
|
|
122
|
+
const fn = tc?.function;
|
|
123
|
+
const name = typeof fn?.name === 'string' ? String(fn.name).trim().toLowerCase() : '';
|
|
124
|
+
if (!id || name !== 'apply_patch')
|
|
125
|
+
continue;
|
|
126
|
+
const args = typeof fn?.arguments === 'string' ? String(fn.arguments) : '';
|
|
127
|
+
if (args)
|
|
128
|
+
toolCallArgsById.set(id, args);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
for (const msg of messages) {
|
|
132
|
+
if (!msg || typeof msg !== 'object')
|
|
133
|
+
continue;
|
|
134
|
+
const role = msg.role;
|
|
135
|
+
const name = typeof msg.name === 'string' ? String(msg.name).trim().toLowerCase() : '';
|
|
136
|
+
const content = typeof msg.content === 'string' ? String(msg.content) : '';
|
|
137
|
+
if (role !== 'tool' || name !== 'apply_patch')
|
|
138
|
+
continue;
|
|
139
|
+
if (!content.toLowerCase().includes('apply_patch verification failed'))
|
|
140
|
+
continue;
|
|
141
|
+
const toolCallId = typeof msg.tool_call_id === 'string' ? String(msg.tool_call_id) : undefined;
|
|
142
|
+
const toolCallArgs = toolCallId ? toolCallArgsById.get(toolCallId) : undefined;
|
|
143
|
+
captureApplyPatchExecutionFailure(content, {
|
|
144
|
+
requestId,
|
|
145
|
+
entryEndpoint,
|
|
146
|
+
providerKey,
|
|
147
|
+
model,
|
|
148
|
+
source: 'req_process_stage1_tool_governance',
|
|
149
|
+
meta: { applyPatchToolMode: 'freeform' },
|
|
150
|
+
toolCallId,
|
|
151
|
+
toolCallArgs
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// ignore
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -7,6 +7,7 @@ interface RegressionSample {
|
|
|
7
7
|
fixerResult?: string;
|
|
8
8
|
validationError?: string;
|
|
9
9
|
source?: string;
|
|
10
|
+
meta?: Record<string, unknown>;
|
|
10
11
|
}
|
|
11
12
|
export declare function captureApplyPatchRegression(sample: Omit<RegressionSample, 'id' | 'timestamp'>): void;
|
|
12
13
|
export {};
|
|
@@ -9,7 +9,7 @@ import { createHash } from 'crypto';
|
|
|
9
9
|
* Condition: non-context errors only (format/json/prefix/etc.)
|
|
10
10
|
*
|
|
11
11
|
* Default destination:
|
|
12
|
-
* ~/.routecodex/
|
|
12
|
+
* ~/.routecodex/errorsamples/apply_patch/<error-type>/
|
|
13
13
|
*
|
|
14
14
|
* Optional repo destination (explicit opt-in):
|
|
15
15
|
* ROUTECODEX_APPLY_PATCH_REGRESSION_TO_REPO=1
|
|
@@ -18,7 +18,7 @@ import { createHash } from 'crypto';
|
|
|
18
18
|
* Explicit override:
|
|
19
19
|
* ROUTECODEX_APPLY_PATCH_REGRESSION_DIR=/abs/path
|
|
20
20
|
*/
|
|
21
|
-
const MAX_SAMPLES_PER_TYPE =
|
|
21
|
+
const MAX_SAMPLES_PER_TYPE = 250;
|
|
22
22
|
function detectRepoRootFromCwd() {
|
|
23
23
|
try {
|
|
24
24
|
let dir = process.cwd();
|
|
@@ -60,7 +60,7 @@ function resolveSamplesRoot() {
|
|
|
60
60
|
return path.join(repoRoot, 'samples', 'ci-goldens', '_regressions', 'apply_patch');
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
-
return path.join(os.homedir(), '.routecodex', '
|
|
63
|
+
return path.join(os.homedir(), '.routecodex', 'errorsamples', 'apply_patch');
|
|
64
64
|
}
|
|
65
65
|
function isContextError(error) {
|
|
66
66
|
if (!error)
|
|
@@ -72,8 +72,9 @@ function isContextError(error) {
|
|
|
72
72
|
lower.includes('no such file'));
|
|
73
73
|
}
|
|
74
74
|
function stableSampleId(sample) {
|
|
75
|
+
const mode = String(sample.meta?.applyPatchToolMode || '').trim();
|
|
75
76
|
const key = `${String(sample.errorType || 'unknown')}:${String(sample.originalArgs ?? '')}:` +
|
|
76
|
-
`${String(sample.normalizedArgs ?? '')}:${String(sample.fixerResult ?? '')}:${String(sample.validationError ?? '')}`;
|
|
77
|
+
`${String(sample.normalizedArgs ?? '')}:${String(sample.fixerResult ?? '')}:${String(sample.validationError ?? '')}:${mode}`;
|
|
77
78
|
return createHash('sha1').update(key).digest('hex').slice(0, 16);
|
|
78
79
|
}
|
|
79
80
|
export function captureApplyPatchRegression(sample) {
|
|
@@ -134,13 +134,25 @@ const tryApplyToFileLines = (section, kindRaw, change, changeRec, index) => {
|
|
|
134
134
|
change.target ??
|
|
135
135
|
change.context ??
|
|
136
136
|
change.from ??
|
|
137
|
-
change.old
|
|
137
|
+
change.old ??
|
|
138
|
+
change.oldText ??
|
|
139
|
+
change.old_text ??
|
|
140
|
+
change.beforeText ??
|
|
141
|
+
change.before_text;
|
|
138
142
|
const anchor = toSafeString(anchorSource, `changes[${index}].anchor`);
|
|
139
143
|
const anchorLines = splitTextIntoLines(anchor);
|
|
140
144
|
const anchorIndex = findSubsequence(lines, anchorLines);
|
|
141
145
|
if (anchorIndex < 0)
|
|
142
146
|
return false;
|
|
143
|
-
const linesSource = changeRec.lines ??
|
|
147
|
+
const linesSource = changeRec.lines ??
|
|
148
|
+
changeRec.text ??
|
|
149
|
+
changeRec.content ??
|
|
150
|
+
changeRec.body ??
|
|
151
|
+
changeRec.replacement ??
|
|
152
|
+
changeRec.newText ??
|
|
153
|
+
changeRec.new_text ??
|
|
154
|
+
changeRec.afterText ??
|
|
155
|
+
changeRec.after_text;
|
|
144
156
|
const additions = normalizeLines(linesSource, `changes[${index}].lines`);
|
|
145
157
|
if (!additions.length) {
|
|
146
158
|
throw new StructuredApplyPatchError('invalid_lines', `changes[${index}].lines must include at least one line`);
|
|
@@ -157,7 +169,11 @@ const tryApplyToFileLines = (section, kindRaw, change, changeRec, index) => {
|
|
|
157
169
|
change.anchor ??
|
|
158
170
|
change.context ??
|
|
159
171
|
change.from ??
|
|
160
|
-
change.old
|
|
172
|
+
change.old ??
|
|
173
|
+
change.oldText ??
|
|
174
|
+
change.old_text ??
|
|
175
|
+
change.beforeText ??
|
|
176
|
+
change.before_text;
|
|
161
177
|
const target = toSafeString(targetSource, `changes[${index}].target`);
|
|
162
178
|
const targetLines = splitTextIntoLines(target);
|
|
163
179
|
const targetIndex = findSubsequence(lines, targetLines);
|
|
@@ -167,7 +183,15 @@ const tryApplyToFileLines = (section, kindRaw, change, changeRec, index) => {
|
|
|
167
183
|
lines.splice(targetIndex, targetLines.length);
|
|
168
184
|
return true;
|
|
169
185
|
}
|
|
170
|
-
const linesSource = changeRec.lines ??
|
|
186
|
+
const linesSource = changeRec.lines ??
|
|
187
|
+
changeRec.text ??
|
|
188
|
+
changeRec.content ??
|
|
189
|
+
changeRec.body ??
|
|
190
|
+
changeRec.replacement ??
|
|
191
|
+
changeRec.newText ??
|
|
192
|
+
changeRec.new_text ??
|
|
193
|
+
changeRec.afterText ??
|
|
194
|
+
changeRec.after_text;
|
|
171
195
|
let replacements;
|
|
172
196
|
if ((linesSource === null || linesSource === undefined) && typeof change.anchor === 'string' && typeof change.target === 'string') {
|
|
173
197
|
replacements = splitTextIntoLines(String(change.anchor));
|
|
@@ -301,9 +325,25 @@ export function buildStructuredPatch(payload) {
|
|
|
301
325
|
}
|
|
302
326
|
// Common shape: replace with lines but no target → treat as full-file replacement.
|
|
303
327
|
if (kindRaw === 'replace') {
|
|
304
|
-
const targetSource = change.target ??
|
|
328
|
+
const targetSource = change.target ??
|
|
329
|
+
change.anchor ??
|
|
330
|
+
change.context ??
|
|
331
|
+
change.from ??
|
|
332
|
+
change.old ??
|
|
333
|
+
change.oldText ??
|
|
334
|
+
change.old_text ??
|
|
335
|
+
change.beforeText ??
|
|
336
|
+
change.before_text;
|
|
305
337
|
const hasTarget = typeof targetSource === 'string' && targetSource.trim().length > 0;
|
|
306
|
-
const linesSource = changeRec.lines ??
|
|
338
|
+
const linesSource = changeRec.lines ??
|
|
339
|
+
changeRec.text ??
|
|
340
|
+
changeRec.content ??
|
|
341
|
+
changeRec.body ??
|
|
342
|
+
changeRec.replacement ??
|
|
343
|
+
changeRec.newText ??
|
|
344
|
+
changeRec.new_text ??
|
|
345
|
+
changeRec.afterText ??
|
|
346
|
+
changeRec.after_text;
|
|
307
347
|
const hasReplacementBody = !(linesSource === null || linesSource === undefined);
|
|
308
348
|
if (!hasTarget && hasReplacementBody) {
|
|
309
349
|
const lines = normalizeLines(linesSource, `changes[${index}].lines`);
|
|
@@ -328,10 +368,26 @@ export function buildStructuredPatch(payload) {
|
|
|
328
368
|
const section = ensureUpdateSection(file);
|
|
329
369
|
switch (kindRaw) {
|
|
330
370
|
case 'insert_after': {
|
|
331
|
-
const anchorSource = change.anchor ??
|
|
371
|
+
const anchorSource = change.anchor ??
|
|
372
|
+
change.target ??
|
|
373
|
+
change.context ??
|
|
374
|
+
change.from ??
|
|
375
|
+
change.old ??
|
|
376
|
+
change.oldText ??
|
|
377
|
+
change.old_text ??
|
|
378
|
+
change.beforeText ??
|
|
379
|
+
change.before_text;
|
|
332
380
|
const anchor = toSafeString(anchorSource, `changes[${index}].anchor`);
|
|
333
381
|
const anchorLines = splitTextIntoLines(anchor);
|
|
334
|
-
const linesSource = changeRec.lines ??
|
|
382
|
+
const linesSource = changeRec.lines ??
|
|
383
|
+
changeRec.text ??
|
|
384
|
+
changeRec.content ??
|
|
385
|
+
changeRec.body ??
|
|
386
|
+
changeRec.replacement ??
|
|
387
|
+
changeRec.newText ??
|
|
388
|
+
changeRec.new_text ??
|
|
389
|
+
changeRec.afterText ??
|
|
390
|
+
changeRec.after_text;
|
|
335
391
|
const additions = normalizeLines(linesSource, `changes[${index}].lines`);
|
|
336
392
|
if (!additions.length) {
|
|
337
393
|
throw new StructuredApplyPatchError('invalid_lines', `changes[${index}].lines must include at least one line`);
|
|
@@ -342,10 +398,26 @@ export function buildStructuredPatch(payload) {
|
|
|
342
398
|
break;
|
|
343
399
|
}
|
|
344
400
|
case 'insert_before': {
|
|
345
|
-
const anchorSource = change.anchor ??
|
|
401
|
+
const anchorSource = change.anchor ??
|
|
402
|
+
change.target ??
|
|
403
|
+
change.context ??
|
|
404
|
+
change.from ??
|
|
405
|
+
change.old ??
|
|
406
|
+
change.oldText ??
|
|
407
|
+
change.old_text ??
|
|
408
|
+
change.beforeText ??
|
|
409
|
+
change.before_text;
|
|
346
410
|
const anchor = toSafeString(anchorSource, `changes[${index}].anchor`);
|
|
347
411
|
const anchorLines = splitTextIntoLines(anchor);
|
|
348
|
-
const linesSource = changeRec.lines ??
|
|
412
|
+
const linesSource = changeRec.lines ??
|
|
413
|
+
changeRec.text ??
|
|
414
|
+
changeRec.content ??
|
|
415
|
+
changeRec.body ??
|
|
416
|
+
changeRec.replacement ??
|
|
417
|
+
changeRec.newText ??
|
|
418
|
+
changeRec.new_text ??
|
|
419
|
+
changeRec.afterText ??
|
|
420
|
+
changeRec.after_text;
|
|
349
421
|
const additions = normalizeLines(linesSource, `changes[${index}].lines`);
|
|
350
422
|
if (!additions.length) {
|
|
351
423
|
throw new StructuredApplyPatchError('invalid_lines', `changes[${index}].lines must include at least one line`);
|
|
@@ -357,9 +429,25 @@ export function buildStructuredPatch(payload) {
|
|
|
357
429
|
}
|
|
358
430
|
case 'replace': {
|
|
359
431
|
// 兼容仅提供 anchor 的 replace 形态:将 anchor 视为 target 以尽可能保留用户意图。
|
|
360
|
-
const targetSource = change.target ??
|
|
432
|
+
const targetSource = change.target ??
|
|
433
|
+
change.anchor ??
|
|
434
|
+
change.context ??
|
|
435
|
+
change.from ??
|
|
436
|
+
change.old ??
|
|
437
|
+
change.oldText ??
|
|
438
|
+
change.old_text ??
|
|
439
|
+
change.beforeText ??
|
|
440
|
+
change.before_text;
|
|
361
441
|
const target = toSafeString(targetSource, `changes[${index}].target`);
|
|
362
|
-
const linesSource = changeRec.lines ??
|
|
442
|
+
const linesSource = changeRec.lines ??
|
|
443
|
+
changeRec.text ??
|
|
444
|
+
changeRec.content ??
|
|
445
|
+
changeRec.body ??
|
|
446
|
+
changeRec.replacement ??
|
|
447
|
+
changeRec.newText ??
|
|
448
|
+
changeRec.new_text ??
|
|
449
|
+
changeRec.afterText ??
|
|
450
|
+
changeRec.after_text;
|
|
363
451
|
let replacements;
|
|
364
452
|
if ((linesSource === null || linesSource === undefined) && typeof change.anchor === 'string' && typeof change.target === 'string') {
|
|
365
453
|
// Common model mistake: provide { anchor: <new>, target: <old> } but omit lines.
|
|
@@ -377,7 +465,15 @@ export function buildStructuredPatch(payload) {
|
|
|
377
465
|
break;
|
|
378
466
|
}
|
|
379
467
|
case 'delete': {
|
|
380
|
-
const targetSource = change.target ??
|
|
468
|
+
const targetSource = change.target ??
|
|
469
|
+
change.anchor ??
|
|
470
|
+
change.context ??
|
|
471
|
+
change.from ??
|
|
472
|
+
change.old ??
|
|
473
|
+
change.oldText ??
|
|
474
|
+
change.old_text ??
|
|
475
|
+
change.beforeText ??
|
|
476
|
+
change.before_text;
|
|
381
477
|
const target = toSafeString(targetSource, `changes[${index}].target`);
|
|
382
478
|
const hunkBody = buildPrefixedLines(splitTextIntoLines(target), '-');
|
|
383
479
|
section.hunks.push(hunkBody);
|