@jsonstudio/llms 0.6.1892 → 0.6.2172
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/conversion/compat/actions/deepseek-web-request.js +16 -2
- package/dist/conversion/compat/actions/deepseek-web-response.d.ts +7 -1
- package/dist/conversion/compat/actions/deepseek-web-response.js +302 -40
- package/dist/conversion/compat/actions/harvest-tool-calls-from-text.d.ts +5 -0
- package/dist/conversion/compat/actions/harvest-tool-calls-from-text.js +7 -4
- package/dist/conversion/compat/actions/iflow-tool-text-fallback.d.ts +1 -0
- package/dist/conversion/compat/actions/iflow-tool-text-fallback.js +12 -0
- package/dist/conversion/compat/actions/strip-orphan-function-calls-tag.js +1 -1
- package/dist/conversion/compat/actions/tool-text-request-guidance.d.ts +9 -0
- package/dist/conversion/compat/actions/tool-text-request-guidance.js +177 -0
- package/dist/conversion/compat/antigravity-session-signature.d.ts +6 -0
- package/dist/conversion/compat/antigravity-session-signature.js +15 -0
- package/dist/conversion/compat/profiles/chat-deepseek-web.json +52 -1
- package/dist/conversion/compat/profiles/chat-glm.json +22 -0
- package/dist/conversion/compat/profiles/chat-iflow.json +4 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +13 -27
- package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +10 -1
- package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +13 -4
- package/dist/conversion/hub/pipeline/compat/compat-profile-resolver.js +1 -53
- package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +8 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +8 -4
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +191 -9
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +118 -15
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +65 -2
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage3_servertool_orchestration/index.d.ts +34 -0
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage3_servertool_orchestration/index.js +75 -0
- package/dist/conversion/hub/process/chat-process.js +85 -18
- package/dist/conversion/hub/response/provider-response.js +21 -50
- package/dist/conversion/hub/response/response-runtime.js +71 -10
- package/dist/conversion/responses/responses-openai-bridge/response-payload.d.ts +3 -0
- package/dist/conversion/responses/responses-openai-bridge/response-payload.js +576 -0
- package/dist/conversion/responses/responses-openai-bridge/types.d.ts +42 -0
- package/dist/conversion/responses/responses-openai-bridge/types.js +1 -0
- package/dist/conversion/responses/responses-openai-bridge.d.ts +3 -44
- package/dist/conversion/responses/responses-openai-bridge.js +193 -504
- package/dist/conversion/shared/anthropic-message-utils.js +82 -2
- package/dist/conversion/shared/bridge-message-utils.js +92 -39
- package/dist/conversion/shared/snapshot-hooks.js +8 -13
- package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.d.ts +2 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.js +129 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-json.d.ts +4 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-json.js +637 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-shared.d.ts +21 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-shared.js +177 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.d.ts +5 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.js +385 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-xml.d.ts +10 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-xml.js +602 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors.d.ts +5 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors.js +4 -0
- package/dist/conversion/shared/text-markup-normalizer/normalize.d.ts +2 -0
- package/dist/conversion/shared/text-markup-normalizer/normalize.js +76 -0
- package/dist/conversion/shared/text-markup-normalizer.d.ts +3 -25
- package/dist/conversion/shared/text-markup-normalizer.js +2 -1386
- package/dist/conversion/shared/tool-governor.js +136 -10
- package/dist/filters/utils/snapshot-writer.js +3 -3
- package/dist/router/virtual-router/bootstrap/auth-utils.d.ts +6 -0
- package/dist/router/virtual-router/bootstrap/auth-utils.js +288 -0
- package/dist/router/virtual-router/bootstrap/claude-code-helpers.d.ts +11 -0
- package/dist/router/virtual-router/bootstrap/claude-code-helpers.js +18 -0
- package/dist/router/virtual-router/bootstrap/config-defaults.d.ts +5 -0
- package/dist/router/virtual-router/bootstrap/config-defaults.js +13 -0
- package/dist/router/virtual-router/bootstrap/config-normalizers.d.ts +4 -0
- package/dist/router/virtual-router/bootstrap/config-normalizers.js +106 -0
- package/dist/router/virtual-router/bootstrap/profile-builder.d.ts +7 -0
- package/dist/router/virtual-router/bootstrap/profile-builder.js +68 -0
- package/dist/router/virtual-router/bootstrap/provider-normalization.d.ts +40 -0
- package/dist/router/virtual-router/bootstrap/provider-normalization.js +212 -0
- package/dist/router/virtual-router/bootstrap/responses-helpers.d.ts +15 -0
- package/dist/router/virtual-router/bootstrap/responses-helpers.js +65 -0
- package/dist/router/virtual-router/bootstrap/routing-config.d.ts +23 -0
- package/dist/router/virtual-router/bootstrap/routing-config.js +293 -0
- package/dist/router/virtual-router/bootstrap/streaming-helpers.d.ts +12 -0
- package/dist/router/virtual-router/bootstrap/streaming-helpers.js +128 -0
- package/dist/router/virtual-router/bootstrap/utils.d.ts +5 -0
- package/dist/router/virtual-router/bootstrap/utils.js +41 -0
- package/dist/router/virtual-router/bootstrap/web-search-config.d.ts +4 -0
- package/dist/router/virtual-router/bootstrap/web-search-config.js +131 -0
- package/dist/router/virtual-router/bootstrap.d.ts +0 -4
- package/dist/router/virtual-router/bootstrap.js +31 -1275
- package/dist/router/virtual-router/classifier.js +32 -14
- package/dist/router/virtual-router/engine/antigravity/alias-lease.js +2 -2
- package/dist/router/virtual-router/engine/cooldown-manager.d.ts +34 -0
- package/dist/router/virtual-router/engine/cooldown-manager.js +118 -0
- package/dist/router/virtual-router/engine/route-analytics.d.ts +28 -0
- package/dist/router/virtual-router/engine/route-analytics.js +44 -0
- package/dist/router/virtual-router/engine/routing-pools/index.js +165 -4
- package/dist/router/virtual-router/engine/sticky-session-manager.d.ts +29 -0
- package/dist/router/virtual-router/engine/sticky-session-manager.js +55 -0
- package/dist/router/virtual-router/engine-logging.d.ts +42 -1
- package/dist/router/virtual-router/engine-logging.js +82 -15
- package/dist/router/virtual-router/engine-selection/multimodal-capability.d.ts +3 -0
- package/dist/router/virtual-router/engine-selection/multimodal-capability.js +26 -0
- package/dist/router/virtual-router/engine-selection/route-utils.js +6 -2
- package/dist/router/virtual-router/engine-selection/selection-deps.d.ts +1 -0
- package/dist/router/virtual-router/engine-selection/tier-selection.js +31 -1
- package/dist/router/virtual-router/engine.d.ts +21 -7
- package/dist/router/virtual-router/engine.js +198 -194
- package/dist/router/virtual-router/features.js +12 -4
- package/dist/router/virtual-router/message-utils.d.ts +8 -0
- package/dist/router/virtual-router/message-utils.js +170 -45
- package/dist/router/virtual-router/pre-command-file-resolver.js +40 -2
- package/dist/router/virtual-router/routing-instructions.d.ts +8 -0
- package/dist/router/virtual-router/routing-instructions.js +18 -2
- package/dist/router/virtual-router/routing-stop-message-actions.js +34 -10
- package/dist/router/virtual-router/routing-stop-message-state-codec.d.ts +2 -0
- package/dist/router/virtual-router/routing-stop-message-state-codec.js +50 -1
- package/dist/router/virtual-router/stop-message-state-sync.d.ts +1 -1
- package/dist/router/virtual-router/stop-message-state-sync.js +3 -0
- package/dist/router/virtual-router/token-counter.js +51 -10
- package/dist/router/virtual-router/tool-signals.js +4 -0
- package/dist/router/virtual-router/types.d.ts +15 -0
- package/dist/servertool/clock/session-scope.d.ts +3 -0
- package/dist/servertool/clock/session-scope.js +52 -0
- package/dist/servertool/clock/state.js +9 -0
- package/dist/servertool/clock/tasks.js +12 -1
- package/dist/servertool/clock/types.d.ts +3 -0
- package/dist/servertool/engine.js +177 -31
- package/dist/servertool/handlers/clock-auto.js +2 -8
- package/dist/servertool/handlers/clock.js +6 -9
- package/dist/servertool/handlers/recursive-detection-guard.js +53 -14
- package/dist/servertool/handlers/stop-message-auto/blocked-report.d.ts +16 -0
- package/dist/servertool/handlers/stop-message-auto/blocked-report.js +349 -0
- package/dist/servertool/handlers/stop-message-auto/iflow-followup.d.ts +23 -0
- package/dist/servertool/handlers/stop-message-auto/iflow-followup.js +503 -0
- package/dist/servertool/handlers/stop-message-auto/routing-state.d.ts +38 -0
- package/dist/servertool/handlers/stop-message-auto/routing-state.js +149 -0
- package/dist/servertool/handlers/stop-message-auto/runtime-utils.d.ts +67 -0
- package/dist/servertool/handlers/stop-message-auto/runtime-utils.js +387 -0
- package/dist/servertool/handlers/stop-message-auto.d.ts +1 -1
- package/dist/servertool/handlers/stop-message-auto.js +80 -556
- package/dist/servertool/handlers/stop-message-stage-policy/bd-runtime.d.ts +18 -0
- package/dist/servertool/handlers/stop-message-stage-policy/bd-runtime.js +398 -0
- package/dist/servertool/handlers/stop-message-stage-policy/decision.d.ts +9 -0
- package/dist/servertool/handlers/stop-message-stage-policy/decision.js +127 -0
- package/dist/servertool/handlers/stop-message-stage-policy/observation.d.ts +2 -0
- package/dist/servertool/handlers/stop-message-stage-policy/observation.js +179 -0
- package/dist/servertool/handlers/stop-message-stage-policy/templates.d.ts +4 -0
- package/dist/servertool/handlers/stop-message-stage-policy/templates.js +96 -0
- package/dist/servertool/handlers/stop-message-stage-policy/text-utils.d.ts +9 -0
- package/dist/servertool/handlers/stop-message-stage-policy/text-utils.js +89 -0
- package/dist/servertool/handlers/stop-message-stage-policy/types.d.ts +59 -0
- package/dist/servertool/handlers/stop-message-stage-policy/types.js +1 -0
- package/dist/servertool/handlers/stop-message-stage-policy.d.ts +3 -43
- package/dist/servertool/handlers/stop-message-stage-policy.js +2 -684
- package/dist/servertool/handlers/web-search.js +117 -0
- package/dist/servertool/server-side-tools.d.ts +0 -1
- package/dist/servertool/server-side-tools.js +4 -3
- package/dist/sse/sse-to-json/builders/response-builder.js +16 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +1 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +110 -37
- package/dist/telemetry/stats-center.d.ts +9 -0
- package/dist/telemetry/stats-center.js +29 -1
- package/dist/tools/apply-patch/structured/coercion.js +3 -11
- package/dist/tools/exec-command/validator.d.ts +1 -0
- package/dist/tools/exec-command/validator.js +132 -0
- package/dist/tools/tool-registry.d.ts +1 -0
- package/dist/tools/tool-registry.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { StopMessageBdCommandRunner, StopMessageBdTaskProbeResult, StopMessageBdWorkState } from './types.js';
|
|
2
|
+
export declare function resolveBdTaskSelectionFromRuntime(options?: {
|
|
3
|
+
bdCommandRunner?: StopMessageBdCommandRunner;
|
|
4
|
+
nowMs?: number;
|
|
5
|
+
cwd?: string;
|
|
6
|
+
limit?: number;
|
|
7
|
+
}): StopMessageBdTaskProbeResult;
|
|
8
|
+
export declare function resolveBdWorkStateFromRuntime(options?: {
|
|
9
|
+
bdCommandRunner?: StopMessageBdCommandRunner;
|
|
10
|
+
nowMs?: number;
|
|
11
|
+
cwd?: string;
|
|
12
|
+
}): StopMessageBdWorkState;
|
|
13
|
+
export declare function detectBdWorkState(messages: unknown[], options?: {
|
|
14
|
+
bdCommandRunner?: StopMessageBdCommandRunner;
|
|
15
|
+
nowMs?: number;
|
|
16
|
+
cwd?: string;
|
|
17
|
+
}): StopMessageBdWorkState;
|
|
18
|
+
export declare function resetStopMessageBdRuntimeCacheForTests(): void;
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import * as childProcess from 'node:child_process';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { normalizeMessageForHeuristics, normalizeText } from './text-utils.js';
|
|
5
|
+
let bdRuntimeCache = null;
|
|
6
|
+
const DEFAULT_BD_TIMEOUT_MS = 1200;
|
|
7
|
+
const DEFAULT_BD_CACHE_TTL_MS = 1500;
|
|
8
|
+
export function resolveBdTaskSelectionFromRuntime(options) {
|
|
9
|
+
const commandRunner = options?.bdCommandRunner ?? runBdCommand;
|
|
10
|
+
const timeoutMs = resolveBdTimeoutMs();
|
|
11
|
+
const cwd = resolveBdWorkingDirectory(options?.cwd);
|
|
12
|
+
const limit = typeof options?.limit === 'number' && Number.isFinite(options.limit) && options.limit > 0
|
|
13
|
+
? Math.max(1, Math.floor(options.limit))
|
|
14
|
+
: 20;
|
|
15
|
+
const inProgress = runBdIssueQuery(commandRunner, ['--no-db', 'list', '--status', 'in_progress', '--json', '--limit', String(limit)], { cwd, timeoutMs, source: 'in_progress' });
|
|
16
|
+
if (inProgress.status === 'unknown')
|
|
17
|
+
return { status: 'unknown' };
|
|
18
|
+
if (inProgress.issues.length > 0)
|
|
19
|
+
return { status: 'ok', task: inProgress.issues[0] };
|
|
20
|
+
const ready = runBdIssueQuery(commandRunner, ['--no-db', 'ready', '--json', '--limit', String(limit)], {
|
|
21
|
+
cwd,
|
|
22
|
+
timeoutMs,
|
|
23
|
+
source: 'ready'
|
|
24
|
+
});
|
|
25
|
+
if (ready.status === 'unknown')
|
|
26
|
+
return { status: 'unknown' };
|
|
27
|
+
if (ready.issues.length > 0)
|
|
28
|
+
return { status: 'ok', task: ready.issues[0] };
|
|
29
|
+
const open = runBdIssueQuery(commandRunner, ['--no-db', 'list', '--status', 'open', '--json', '--limit', String(limit)], {
|
|
30
|
+
cwd,
|
|
31
|
+
timeoutMs,
|
|
32
|
+
source: 'open'
|
|
33
|
+
});
|
|
34
|
+
if (open.status === 'unknown')
|
|
35
|
+
return { status: 'unknown' };
|
|
36
|
+
if (open.issues.length > 0)
|
|
37
|
+
return { status: 'ok', task: open.issues[0] };
|
|
38
|
+
return { status: 'ok' };
|
|
39
|
+
}
|
|
40
|
+
export function resolveBdWorkStateFromRuntime(options) {
|
|
41
|
+
const mode = resolveBdMode();
|
|
42
|
+
const nowMs = typeof options?.nowMs === 'number' && Number.isFinite(options.nowMs) ? options.nowMs : Date.now();
|
|
43
|
+
const cwd = resolveBdWorkingDirectory(options?.cwd);
|
|
44
|
+
const ttlMs = resolveBdCacheTtlMs();
|
|
45
|
+
if (ttlMs > 0 &&
|
|
46
|
+
bdRuntimeCache &&
|
|
47
|
+
bdRuntimeCache.mode === mode &&
|
|
48
|
+
bdRuntimeCache.cwd === cwd &&
|
|
49
|
+
bdRuntimeCache.expiresAt > nowMs) {
|
|
50
|
+
return bdRuntimeCache.state;
|
|
51
|
+
}
|
|
52
|
+
const commandRunner = options?.bdCommandRunner ?? runBdCommand;
|
|
53
|
+
const timeoutMs = resolveBdTimeoutMs();
|
|
54
|
+
const inProgress = runBdQuery(commandRunner, ['--no-db', 'list', '--status', 'in_progress', '--json', '--limit', '1'], {
|
|
55
|
+
cwd,
|
|
56
|
+
timeoutMs
|
|
57
|
+
});
|
|
58
|
+
if (inProgress === 'active') {
|
|
59
|
+
return writeBdRuntimeCacheAndReturn(mode, cwd, nowMs, ttlMs, 'active');
|
|
60
|
+
}
|
|
61
|
+
if (inProgress === 'unknown') {
|
|
62
|
+
return writeBdRuntimeCacheAndReturn(mode, cwd, nowMs, ttlMs, 'unknown');
|
|
63
|
+
}
|
|
64
|
+
const ready = runBdQuery(commandRunner, ['--no-db', 'ready', '--json', '--limit', '1'], {
|
|
65
|
+
cwd,
|
|
66
|
+
timeoutMs
|
|
67
|
+
});
|
|
68
|
+
if (ready === 'active') {
|
|
69
|
+
return writeBdRuntimeCacheAndReturn(mode, cwd, nowMs, ttlMs, 'active');
|
|
70
|
+
}
|
|
71
|
+
if (ready === 'unknown') {
|
|
72
|
+
return writeBdRuntimeCacheAndReturn(mode, cwd, nowMs, ttlMs, 'unknown');
|
|
73
|
+
}
|
|
74
|
+
const open = runBdQuery(commandRunner, ['--no-db', 'list', '--status', 'open', '--json', '--limit', '1'], {
|
|
75
|
+
cwd,
|
|
76
|
+
timeoutMs
|
|
77
|
+
});
|
|
78
|
+
if (open === 'active') {
|
|
79
|
+
return writeBdRuntimeCacheAndReturn(mode, cwd, nowMs, ttlMs, 'active');
|
|
80
|
+
}
|
|
81
|
+
if (open === 'unknown') {
|
|
82
|
+
return writeBdRuntimeCacheAndReturn(mode, cwd, nowMs, ttlMs, 'unknown');
|
|
83
|
+
}
|
|
84
|
+
const blocked = runBdQuery(commandRunner, ['--no-db', 'list', '--status', 'blocked', '--json', '--limit', '1'], {
|
|
85
|
+
cwd,
|
|
86
|
+
timeoutMs
|
|
87
|
+
});
|
|
88
|
+
if (blocked === 'active') {
|
|
89
|
+
return writeBdRuntimeCacheAndReturn(mode, cwd, nowMs, ttlMs, 'active');
|
|
90
|
+
}
|
|
91
|
+
if (blocked === 'unknown') {
|
|
92
|
+
return writeBdRuntimeCacheAndReturn(mode, cwd, nowMs, ttlMs, 'unknown');
|
|
93
|
+
}
|
|
94
|
+
return writeBdRuntimeCacheAndReturn(mode, cwd, nowMs, ttlMs, 'idle');
|
|
95
|
+
}
|
|
96
|
+
export function detectBdWorkState(messages, options) {
|
|
97
|
+
const mode = resolveBdMode();
|
|
98
|
+
if (mode !== 'heuristic') {
|
|
99
|
+
const runtimeState = resolveBdWorkStateFromRuntime({
|
|
100
|
+
bdCommandRunner: options?.bdCommandRunner,
|
|
101
|
+
nowMs: options?.nowMs,
|
|
102
|
+
cwd: options?.cwd
|
|
103
|
+
});
|
|
104
|
+
if (runtimeState === 'active' || runtimeState === 'idle') {
|
|
105
|
+
return runtimeState;
|
|
106
|
+
}
|
|
107
|
+
if (mode === 'runtime') {
|
|
108
|
+
return 'unknown';
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return detectBdWorkStateFromHeuristics(messages);
|
|
112
|
+
}
|
|
113
|
+
export function resetStopMessageBdRuntimeCacheForTests() {
|
|
114
|
+
bdRuntimeCache = null;
|
|
115
|
+
}
|
|
116
|
+
function detectBdWorkStateFromHeuristics(messages) {
|
|
117
|
+
const normalizedTail = messages
|
|
118
|
+
.slice(-30)
|
|
119
|
+
.map((message) => normalizeMessageForHeuristics(message))
|
|
120
|
+
.filter(Boolean)
|
|
121
|
+
.join('\n')
|
|
122
|
+
.toLowerCase();
|
|
123
|
+
if (!normalizedTail.includes('bd')) {
|
|
124
|
+
return 'unknown';
|
|
125
|
+
}
|
|
126
|
+
const idlePatterns = [
|
|
127
|
+
/\bno\s+(ready|open|in_progress)\b/i,
|
|
128
|
+
/\b0\s+(ready|open|in_progress)\b/i,
|
|
129
|
+
/\bnothing\s+(to\s+do|ready|in\s+progress)\b/i,
|
|
130
|
+
/\ball\s+(tasks?|issues?)\s+(done|closed)\b/i,
|
|
131
|
+
/没有可(做|推进)任务/i,
|
|
132
|
+
/无\s*(ready|open|in_progress)\s*任务/i
|
|
133
|
+
];
|
|
134
|
+
if (idlePatterns.some((pattern) => pattern.test(normalizedTail))) {
|
|
135
|
+
return 'idle';
|
|
136
|
+
}
|
|
137
|
+
const activePatterns = [/\bin_progress\b/i, /\bready\b/i, /\bblocked\b/i, /\bopen\b/i, /\bepic status\b/i, /\bshow\s+[a-z0-9._-]+\b/i];
|
|
138
|
+
if (activePatterns.some((pattern) => pattern.test(normalizedTail))) {
|
|
139
|
+
return 'active';
|
|
140
|
+
}
|
|
141
|
+
return 'unknown';
|
|
142
|
+
}
|
|
143
|
+
function writeBdRuntimeCacheAndReturn(mode, cwd, nowMs, ttlMs, state) {
|
|
144
|
+
if (ttlMs > 0) {
|
|
145
|
+
bdRuntimeCache = {
|
|
146
|
+
mode,
|
|
147
|
+
cwd,
|
|
148
|
+
expiresAt: nowMs + ttlMs,
|
|
149
|
+
state
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
return state;
|
|
153
|
+
}
|
|
154
|
+
function resolveBdMode() {
|
|
155
|
+
const modeRaw = normalizeText(process.env.ROUTECODEX_STOPMESSAGE_BD_MODE).toLowerCase();
|
|
156
|
+
if (modeRaw === 'runtime' || modeRaw === 'real') {
|
|
157
|
+
return 'runtime';
|
|
158
|
+
}
|
|
159
|
+
if (modeRaw === 'heuristic' || modeRaw === 'text') {
|
|
160
|
+
return 'heuristic';
|
|
161
|
+
}
|
|
162
|
+
const legacyRuntimeRaw = normalizeText(process.env.ROUTECODEX_STOPMESSAGE_BD_RUNTIME).toLowerCase();
|
|
163
|
+
if (legacyRuntimeRaw === '1' || legacyRuntimeRaw === 'true' || legacyRuntimeRaw === 'on') {
|
|
164
|
+
return 'runtime';
|
|
165
|
+
}
|
|
166
|
+
if (legacyRuntimeRaw === '0' || legacyRuntimeRaw === 'false' || legacyRuntimeRaw === 'off') {
|
|
167
|
+
return 'heuristic';
|
|
168
|
+
}
|
|
169
|
+
return 'auto';
|
|
170
|
+
}
|
|
171
|
+
function resolveBdCacheTtlMs() {
|
|
172
|
+
const parsed = parseNonNegativeInteger(process.env.ROUTECODEX_STOPMESSAGE_BD_CACHE_TTL_MS);
|
|
173
|
+
if (typeof parsed === 'number') {
|
|
174
|
+
return parsed;
|
|
175
|
+
}
|
|
176
|
+
return DEFAULT_BD_CACHE_TTL_MS;
|
|
177
|
+
}
|
|
178
|
+
function resolveBdTimeoutMs() {
|
|
179
|
+
const parsed = parsePositiveInteger(process.env.ROUTECODEX_STOPMESSAGE_BD_TIMEOUT_MS);
|
|
180
|
+
if (typeof parsed === 'number') {
|
|
181
|
+
return parsed;
|
|
182
|
+
}
|
|
183
|
+
return DEFAULT_BD_TIMEOUT_MS;
|
|
184
|
+
}
|
|
185
|
+
function parseNonNegativeInteger(value) {
|
|
186
|
+
if (typeof value !== 'string') {
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
const parsed = Number.parseInt(value.trim(), 10);
|
|
190
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
return parsed;
|
|
194
|
+
}
|
|
195
|
+
function parsePositiveInteger(value) {
|
|
196
|
+
const parsed = parseNonNegativeInteger(value);
|
|
197
|
+
if (typeof parsed !== 'number' || parsed <= 0) {
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
return parsed;
|
|
201
|
+
}
|
|
202
|
+
function resolveBdWorkingDirectory(cwdOverride) {
|
|
203
|
+
const fromOverride = normalizeText(cwdOverride);
|
|
204
|
+
if (fromOverride) {
|
|
205
|
+
return path.resolve(fromOverride);
|
|
206
|
+
}
|
|
207
|
+
const fromEnv = normalizeText(process.env.ROUTECODEX_STOPMESSAGE_BD_WORKDIR);
|
|
208
|
+
if (fromEnv) {
|
|
209
|
+
return path.resolve(fromEnv);
|
|
210
|
+
}
|
|
211
|
+
const current = process.cwd();
|
|
212
|
+
return findBdProjectRoot(current) || current;
|
|
213
|
+
}
|
|
214
|
+
function findBdProjectRoot(startDirectory) {
|
|
215
|
+
let current = path.resolve(startDirectory);
|
|
216
|
+
while (true) {
|
|
217
|
+
const beadsDir = path.join(current, '.beads');
|
|
218
|
+
const issuesJsonlPath = path.join(beadsDir, 'issues.jsonl');
|
|
219
|
+
if (fs.existsSync(issuesJsonlPath)) {
|
|
220
|
+
return current;
|
|
221
|
+
}
|
|
222
|
+
if (fs.existsSync(beadsDir)) {
|
|
223
|
+
return current;
|
|
224
|
+
}
|
|
225
|
+
const parent = path.dirname(current);
|
|
226
|
+
if (parent === current) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
current = parent;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
function runBdCommand(args, options) {
|
|
233
|
+
try {
|
|
234
|
+
const result = childProcess.spawnSync('bd', args, {
|
|
235
|
+
cwd: options.cwd,
|
|
236
|
+
encoding: 'utf8',
|
|
237
|
+
timeout: options.timeoutMs,
|
|
238
|
+
maxBuffer: 1024 * 1024
|
|
239
|
+
});
|
|
240
|
+
return {
|
|
241
|
+
status: result.status,
|
|
242
|
+
stdout: typeof result.stdout === 'string' ? result.stdout : String(result.stdout ?? ''),
|
|
243
|
+
stderr: typeof result.stderr === 'string' ? result.stderr : String(result.stderr ?? ''),
|
|
244
|
+
error: result.error
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
return {
|
|
249
|
+
status: null,
|
|
250
|
+
stdout: '',
|
|
251
|
+
stderr: '',
|
|
252
|
+
error
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function runBdQuery(commandRunner, args, options) {
|
|
257
|
+
const result = commandRunner(args, options);
|
|
258
|
+
if (result.error || result.status !== 0) {
|
|
259
|
+
return 'unknown';
|
|
260
|
+
}
|
|
261
|
+
const list = parseJsonArrayOutput(result.stdout);
|
|
262
|
+
if (!list) {
|
|
263
|
+
return 'unknown';
|
|
264
|
+
}
|
|
265
|
+
return list.length > 0 ? 'active' : 'idle';
|
|
266
|
+
}
|
|
267
|
+
function runBdIssueQuery(commandRunner, args, options) {
|
|
268
|
+
const result = commandRunner(args, { cwd: options.cwd, timeoutMs: options.timeoutMs });
|
|
269
|
+
if (result.error || result.status !== 0) {
|
|
270
|
+
return { status: 'unknown', issues: [] };
|
|
271
|
+
}
|
|
272
|
+
const list = parseJsonArrayOutput(result.stdout);
|
|
273
|
+
if (!list) {
|
|
274
|
+
return { status: 'unknown', issues: [] };
|
|
275
|
+
}
|
|
276
|
+
if (list.length === 0) {
|
|
277
|
+
return { status: 'ok', issues: [] };
|
|
278
|
+
}
|
|
279
|
+
const issues = list
|
|
280
|
+
.map((item) => normalizeIssueSelection(item, options.source))
|
|
281
|
+
.filter((item) => Boolean(item))
|
|
282
|
+
.sort(compareIssueSelection);
|
|
283
|
+
if (issues.length === 0) {
|
|
284
|
+
return { status: 'unknown', issues: [] };
|
|
285
|
+
}
|
|
286
|
+
return { status: 'ok', issues };
|
|
287
|
+
}
|
|
288
|
+
function parseJsonArrayOutput(stdout) {
|
|
289
|
+
const trimmed = typeof stdout === 'string' ? stdout.trim() : '';
|
|
290
|
+
if (!trimmed) {
|
|
291
|
+
return [];
|
|
292
|
+
}
|
|
293
|
+
const parsedDirect = parseJsonArray(trimmed);
|
|
294
|
+
if (parsedDirect) {
|
|
295
|
+
return parsedDirect;
|
|
296
|
+
}
|
|
297
|
+
const firstBracket = trimmed.indexOf('[');
|
|
298
|
+
const lastBracket = trimmed.lastIndexOf(']');
|
|
299
|
+
if (firstBracket >= 0 && lastBracket > firstBracket) {
|
|
300
|
+
const arraySlice = trimmed.slice(firstBracket, lastBracket + 1).trim();
|
|
301
|
+
const parsedSlice = parseJsonArray(arraySlice);
|
|
302
|
+
if (parsedSlice) {
|
|
303
|
+
return parsedSlice;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
function parseJsonArray(raw) {
|
|
309
|
+
try {
|
|
310
|
+
const value = JSON.parse(raw);
|
|
311
|
+
if (Array.isArray(value)) {
|
|
312
|
+
return value;
|
|
313
|
+
}
|
|
314
|
+
if (value && typeof value === 'object') {
|
|
315
|
+
const record = value;
|
|
316
|
+
if (Array.isArray(record.items)) {
|
|
317
|
+
return record.items;
|
|
318
|
+
}
|
|
319
|
+
if (Array.isArray(record.issues)) {
|
|
320
|
+
return record.issues;
|
|
321
|
+
}
|
|
322
|
+
if (Array.isArray(record.data)) {
|
|
323
|
+
return record.data;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
function normalizeIssueSelection(item, source) {
|
|
333
|
+
if (!item || typeof item !== 'object' || Array.isArray(item)) {
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
const record = item;
|
|
337
|
+
const issueId = normalizeText(record.id);
|
|
338
|
+
if (!issueId) {
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
const issueTitle = normalizeText(record.title) ||
|
|
342
|
+
normalizeText(record.summary) ||
|
|
343
|
+
normalizeText(record.name) ||
|
|
344
|
+
`Issue ${issueId}`;
|
|
345
|
+
const priority = parseIssuePriority(record.priority);
|
|
346
|
+
return {
|
|
347
|
+
issueId,
|
|
348
|
+
issueTitle: issueTitle.slice(0, 240),
|
|
349
|
+
priority,
|
|
350
|
+
source
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
function parseIssuePriority(value) {
|
|
354
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
355
|
+
return Math.max(0, Math.floor(value));
|
|
356
|
+
}
|
|
357
|
+
if (typeof value === 'string') {
|
|
358
|
+
const normalized = value.trim().toLowerCase();
|
|
359
|
+
const pMatch = normalized.match(/^p?(\d+)$/);
|
|
360
|
+
if (pMatch) {
|
|
361
|
+
const parsed = Number.parseInt(pMatch[1], 10);
|
|
362
|
+
if (Number.isFinite(parsed)) {
|
|
363
|
+
return Math.max(0, parsed);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return 99;
|
|
368
|
+
}
|
|
369
|
+
function compareIssueSelection(a, b) {
|
|
370
|
+
if (a.priority !== b.priority) {
|
|
371
|
+
return a.priority - b.priority;
|
|
372
|
+
}
|
|
373
|
+
const idCompare = compareIssueId(a.issueId, b.issueId);
|
|
374
|
+
if (idCompare !== 0) {
|
|
375
|
+
return idCompare;
|
|
376
|
+
}
|
|
377
|
+
return a.issueTitle.localeCompare(b.issueTitle);
|
|
378
|
+
}
|
|
379
|
+
function compareIssueId(left, right) {
|
|
380
|
+
const leftParts = left.match(/\d+|\D+/g) || [left];
|
|
381
|
+
const rightParts = right.match(/\d+|\D+/g) || [right];
|
|
382
|
+
const maxLen = Math.max(leftParts.length, rightParts.length);
|
|
383
|
+
for (let idx = 0; idx < maxLen; idx += 1) {
|
|
384
|
+
const l = leftParts[idx] || '';
|
|
385
|
+
const r = rightParts[idx] || '';
|
|
386
|
+
const lNum = /^\d+$/.test(l) ? Number.parseInt(l, 10) : NaN;
|
|
387
|
+
const rNum = /^\d+$/.test(r) ? Number.parseInt(r, 10) : NaN;
|
|
388
|
+
if (Number.isFinite(lNum) && Number.isFinite(rNum)) {
|
|
389
|
+
if (lNum !== rNum)
|
|
390
|
+
return lNum - rNum;
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
const compare = l.localeCompare(r);
|
|
394
|
+
if (compare !== 0)
|
|
395
|
+
return compare;
|
|
396
|
+
}
|
|
397
|
+
return 0;
|
|
398
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { StopMessageBdCommandRunner, StopMessageStageDecision, StopMessageStageStateSnapshot } from './types.js';
|
|
2
|
+
export declare function resolveStopMessageStageDecision(args: {
|
|
3
|
+
baseText: string;
|
|
4
|
+
state: StopMessageStageStateSnapshot;
|
|
5
|
+
capturedMessages: unknown[];
|
|
6
|
+
bdCommandRunner?: StopMessageBdCommandRunner;
|
|
7
|
+
bdWorkingDirectory?: string;
|
|
8
|
+
nowMs?: number;
|
|
9
|
+
}): StopMessageStageDecision;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { detectBdWorkState, resolveBdTaskSelectionFromRuntime } from './bd-runtime.js';
|
|
2
|
+
import { buildObservationHash, buildToolSignatureHash } from './observation.js';
|
|
3
|
+
import { buildStageMessage, resolveStageMode, resolveStageTemplates } from './templates.js';
|
|
4
|
+
import { normalizeBdWorkState, normalizeStageName, normalizeText, toSafeInt } from './text-utils.js';
|
|
5
|
+
function buildAssignedTaskBaseText(baseText, assignedTask) {
|
|
6
|
+
const assignmentLine = `系统已分配任务:${assignedTask.issueId} - ${assignedTask.issueTitle}(来源:${assignedTask.source})`;
|
|
7
|
+
const behaviorLine = '请直接执行该任务,优先推进实现、修复与验证。';
|
|
8
|
+
const suffix = normalizeText(baseText);
|
|
9
|
+
if (!suffix) {
|
|
10
|
+
return `${assignmentLine}\n${behaviorLine}`.trim();
|
|
11
|
+
}
|
|
12
|
+
return `${assignmentLine}\n${behaviorLine}\n\n${suffix}`.trim();
|
|
13
|
+
}
|
|
14
|
+
export function resolveStopMessageStageDecision(args) {
|
|
15
|
+
const mode = resolveStageMode(args.state.stopMessageStageMode);
|
|
16
|
+
const observationHash = buildObservationHash(args.capturedMessages);
|
|
17
|
+
const toolSignatureHash = buildToolSignatureHash(args.capturedMessages);
|
|
18
|
+
if (mode === 'off') {
|
|
19
|
+
return {
|
|
20
|
+
action: 'stop',
|
|
21
|
+
observationHash,
|
|
22
|
+
observationStableCount: 0,
|
|
23
|
+
bdWorkState: 'unknown',
|
|
24
|
+
stopReason: 'mode_off',
|
|
25
|
+
...(toolSignatureHash ? { toolSignatureHash } : {})
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const templates = resolveStageTemplates(mode);
|
|
29
|
+
if (!templates.enabled) {
|
|
30
|
+
return {
|
|
31
|
+
action: 'followup',
|
|
32
|
+
followupText: args.baseText,
|
|
33
|
+
observationHash,
|
|
34
|
+
observationStableCount: 0,
|
|
35
|
+
bdWorkState: 'unknown',
|
|
36
|
+
...(toolSignatureHash ? { toolSignatureHash } : {})
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const previousHash = normalizeText(args.state.stopMessageObservationHash);
|
|
40
|
+
const previousStableCount = toSafeInt(args.state.stopMessageObservationStableCount, 0);
|
|
41
|
+
const stableCount = previousHash && previousHash === observationHash ? previousStableCount + 1 : 0;
|
|
42
|
+
const taskProbe = resolveBdTaskSelectionFromRuntime({
|
|
43
|
+
bdCommandRunner: args.bdCommandRunner,
|
|
44
|
+
cwd: args.bdWorkingDirectory,
|
|
45
|
+
nowMs: args.nowMs
|
|
46
|
+
});
|
|
47
|
+
const assignedTask = taskProbe.status === 'ok' ? taskProbe.task : undefined;
|
|
48
|
+
const bdWorkState = detectBdWorkState(args.capturedMessages, {
|
|
49
|
+
bdCommandRunner: args.bdCommandRunner,
|
|
50
|
+
cwd: args.bdWorkingDirectory,
|
|
51
|
+
nowMs: args.nowMs
|
|
52
|
+
});
|
|
53
|
+
if (taskProbe.status === 'ok' && !assignedTask) {
|
|
54
|
+
if (Boolean(args.state.stopMessageNoTaskSummaryUsed)) {
|
|
55
|
+
return {
|
|
56
|
+
action: 'stop',
|
|
57
|
+
observationHash,
|
|
58
|
+
observationStableCount: stableCount,
|
|
59
|
+
bdWorkState,
|
|
60
|
+
noTaskSummaryUsed: true,
|
|
61
|
+
stopReason: 'no_task_after_summary',
|
|
62
|
+
...(toolSignatureHash ? { toolSignatureHash } : {})
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
action: 'followup',
|
|
67
|
+
stage: 'status_probe',
|
|
68
|
+
followupText: buildStageMessage(templates.noTaskSummaryTemplate, args.baseText),
|
|
69
|
+
observationHash,
|
|
70
|
+
observationStableCount: stableCount,
|
|
71
|
+
bdWorkState,
|
|
72
|
+
noTaskSummaryUsed: true,
|
|
73
|
+
...(toolSignatureHash ? { toolSignatureHash } : {})
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (mode !== 'on') {
|
|
77
|
+
const previousStage = normalizeStageName(args.state.stopMessageStage);
|
|
78
|
+
const previousBdWorkState = normalizeBdWorkState(args.state.stopMessageBdWorkState);
|
|
79
|
+
const idleConfirmed = bdWorkState === 'idle' && previousBdWorkState === 'idle' && previousStage === 'status_probe';
|
|
80
|
+
if (bdWorkState === 'idle') {
|
|
81
|
+
if (idleConfirmed) {
|
|
82
|
+
return {
|
|
83
|
+
action: 'stop',
|
|
84
|
+
observationHash,
|
|
85
|
+
observationStableCount: stableCount,
|
|
86
|
+
bdWorkState,
|
|
87
|
+
stopReason: 'bd_idle',
|
|
88
|
+
...(toolSignatureHash ? { toolSignatureHash } : {})
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (stableCount >= 2) {
|
|
93
|
+
return {
|
|
94
|
+
action: 'stop',
|
|
95
|
+
observationHash,
|
|
96
|
+
observationStableCount: stableCount,
|
|
97
|
+
bdWorkState,
|
|
98
|
+
stopReason: 'loop_stable',
|
|
99
|
+
...(toolSignatureHash ? { toolSignatureHash } : {})
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const stage = stableCount > 0 ? 'loop_self_check' : bdWorkState === 'active' ? 'active_continue' : 'status_probe';
|
|
104
|
+
const stageTemplate = stage === 'status_probe'
|
|
105
|
+
? templates.statusProbeTemplate
|
|
106
|
+
: stage === 'active_continue'
|
|
107
|
+
? templates.activeContinueTemplate
|
|
108
|
+
: templates.loopSelfCheckTemplate;
|
|
109
|
+
const followupText = buildStageMessage(stageTemplate, assignedTask ? buildAssignedTaskBaseText(args.baseText, assignedTask) : args.baseText);
|
|
110
|
+
return {
|
|
111
|
+
action: 'followup',
|
|
112
|
+
stage,
|
|
113
|
+
followupText,
|
|
114
|
+
observationHash,
|
|
115
|
+
observationStableCount: stableCount,
|
|
116
|
+
bdWorkState,
|
|
117
|
+
...(assignedTask
|
|
118
|
+
? {
|
|
119
|
+
assignedIssueId: assignedTask.issueId,
|
|
120
|
+
assignedIssueTitle: assignedTask.issueTitle,
|
|
121
|
+
assignedIssueSource: assignedTask.source
|
|
122
|
+
}
|
|
123
|
+
: {}),
|
|
124
|
+
noTaskSummaryUsed: false,
|
|
125
|
+
...(toolSignatureHash ? { toolSignatureHash } : {})
|
|
126
|
+
};
|
|
127
|
+
}
|