sneakoscope 4.0.4 → 4.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -9
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/crates/sks-core/src/main.rs +1 -1
- package/dist/bin/sks.js +1 -1
- package/dist/core/codex-app/glm-profile-schema.js +5 -1
- package/dist/core/commands/glm-command.js +51 -6
- package/dist/core/commands/mad-sks-command.js +65 -9
- package/dist/core/fsx.js +1 -1
- package/dist/core/perf/lru-cache.js +33 -0
- package/dist/core/providers/glm/glm-52-profile.js +14 -7
- package/dist/core/providers/glm/glm-52-request.js +43 -12
- package/dist/core/providers/glm/glm-52-response-guard.js +1 -2
- package/dist/core/providers/glm/glm-52-settings.js +50 -8
- package/dist/core/providers/glm/glm-bench.js +127 -0
- package/dist/core/providers/glm/glm-context-budget.js +15 -0
- package/dist/core/providers/glm/glm-context-cache.js +9 -0
- package/dist/core/providers/glm/glm-direct-run.js +140 -0
- package/dist/core/providers/glm/glm-interactive-launch.js +5 -0
- package/dist/core/providers/glm/glm-latency-trace.js +40 -0
- package/dist/core/providers/glm/glm-loop-guard.js +31 -0
- package/dist/core/providers/glm/glm-mad-launch.js +18 -3
- package/dist/core/providers/glm/glm-mad-mode.js +48 -20
- package/dist/core/providers/glm/glm-model-meta-cache.js +19 -0
- package/dist/core/providers/glm/glm-patch-apply.js +58 -0
- package/dist/core/providers/glm/glm-patch-parser.js +19 -0
- package/dist/core/providers/glm/glm-profile-resolver.js +104 -0
- package/dist/core/providers/glm/glm-readiness.js +5 -0
- package/dist/core/providers/glm/glm-reasoning-policy.js +15 -0
- package/dist/core/providers/glm/glm-request-cache.js +64 -0
- package/dist/core/providers/glm/glm-run-controller.js +66 -0
- package/dist/core/providers/glm/glm-run-state.js +11 -0
- package/dist/core/providers/glm/glm-run-timeout.js +31 -0
- package/dist/core/providers/glm/glm-speed-context.js +82 -0
- package/dist/core/providers/glm/glm-speed-gate.js +40 -0
- package/dist/core/providers/glm/glm-speed-output-parser.js +40 -0
- package/dist/core/providers/glm/glm-tool-schema-cache.js +19 -0
- package/dist/core/providers/openrouter/openrouter-client.js +21 -1
- package/dist/core/providers/openrouter/openrouter-stream.js +94 -0
- package/dist/core/version.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { nowIso, writeJsonAtomic } from '../../fsx.js';
|
|
3
|
+
import { profileFromConst } from './glm-profile-resolver.js';
|
|
4
|
+
import { createEmptyGlmLatencyTrace, writeGlmLatencyTrace } from './glm-latency-trace.js';
|
|
5
|
+
const SYNTHETIC_CASES = Object.freeze([
|
|
6
|
+
benchCase('small doc edit', 'doc_edit', 420, 980),
|
|
7
|
+
benchCase('small TS function edit', 'small_edit', 460, 1100),
|
|
8
|
+
benchCase('failing test fix from small error', 'test_fix', 520, 1220),
|
|
9
|
+
benchCase('simple config edit', 'config_edit', 390, 930)
|
|
10
|
+
]);
|
|
11
|
+
export async function runGlmBench(root, args = []) {
|
|
12
|
+
const live = args.includes('--live');
|
|
13
|
+
const execute = args.includes('--execute');
|
|
14
|
+
if (execute && !live) {
|
|
15
|
+
const blocked = {
|
|
16
|
+
schema: 'sks.glm-bench-result.v1',
|
|
17
|
+
version: '4.0.6',
|
|
18
|
+
generated_at: nowIso(),
|
|
19
|
+
status: 'blocked',
|
|
20
|
+
dry_run: true,
|
|
21
|
+
cases: [],
|
|
22
|
+
summary: {
|
|
23
|
+
speed_p50_total_ms: 0,
|
|
24
|
+
speed_p90_total_ms: 0,
|
|
25
|
+
speed_p50_ttft_ms: null
|
|
26
|
+
},
|
|
27
|
+
warnings: ['execute_requested_but_live_openrouter_bench_not_implemented']
|
|
28
|
+
};
|
|
29
|
+
await writeJsonAtomic(path.join(root, '.sneakoscope', 'glm', 'bench-blocked.json'), blocked);
|
|
30
|
+
return blocked;
|
|
31
|
+
}
|
|
32
|
+
if (live) {
|
|
33
|
+
const blocked = {
|
|
34
|
+
schema: 'sks.glm-bench-result.v1',
|
|
35
|
+
version: '4.0.6',
|
|
36
|
+
generated_at: nowIso(),
|
|
37
|
+
status: 'blocked',
|
|
38
|
+
dry_run: false,
|
|
39
|
+
cases: [],
|
|
40
|
+
summary: {
|
|
41
|
+
speed_p50_total_ms: 0,
|
|
42
|
+
speed_p90_total_ms: 0,
|
|
43
|
+
speed_p50_ttft_ms: null
|
|
44
|
+
},
|
|
45
|
+
warnings: ['live_openrouter_bench_requires_explicit_network_runner_not_enabled_in_this_build']
|
|
46
|
+
};
|
|
47
|
+
await writeJsonAtomic(path.join(root, '.sneakoscope', 'glm', 'bench-live-blocked.json'), blocked);
|
|
48
|
+
return blocked;
|
|
49
|
+
}
|
|
50
|
+
if (execute) {
|
|
51
|
+
const blocked = {
|
|
52
|
+
schema: 'sks.glm-bench-result.v1',
|
|
53
|
+
version: '4.0.6',
|
|
54
|
+
generated_at: nowIso(),
|
|
55
|
+
status: 'blocked',
|
|
56
|
+
dry_run: true,
|
|
57
|
+
cases: [],
|
|
58
|
+
summary: {
|
|
59
|
+
speed_p50_total_ms: 0,
|
|
60
|
+
speed_p90_total_ms: 0,
|
|
61
|
+
speed_p50_ttft_ms: null
|
|
62
|
+
},
|
|
63
|
+
warnings: ['execute_requested_without_live_flag_uses_no_network_dry_run_policy']
|
|
64
|
+
};
|
|
65
|
+
await writeJsonAtomic(path.join(root, '.sneakoscope', 'glm', 'bench-blocked.json'), blocked);
|
|
66
|
+
return blocked;
|
|
67
|
+
}
|
|
68
|
+
const speedTotals = SYNTHETIC_CASES.map((row) => row.speed.total_ms);
|
|
69
|
+
const deepTotals = SYNTHETIC_CASES.map((row) => row.deep.total_ms);
|
|
70
|
+
const result = {
|
|
71
|
+
schema: 'sks.glm-bench-result.v1',
|
|
72
|
+
version: '4.0.6',
|
|
73
|
+
generated_at: nowIso(),
|
|
74
|
+
status: 'dry_run',
|
|
75
|
+
dry_run: true,
|
|
76
|
+
cases: SYNTHETIC_CASES,
|
|
77
|
+
summary: {
|
|
78
|
+
speed_p50_total_ms: percentile(speedTotals, 50),
|
|
79
|
+
speed_p90_total_ms: percentile(speedTotals, 90),
|
|
80
|
+
speed_p50_ttft_ms: null,
|
|
81
|
+
deep_p50_total_ms: percentile(deepTotals, 50),
|
|
82
|
+
speed_vs_deep_ratio: Number((percentile(speedTotals, 50) / percentile(deepTotals, 50)).toFixed(3))
|
|
83
|
+
},
|
|
84
|
+
warnings: ['synthetic_dry_run_no_network_no_gpt_key_required']
|
|
85
|
+
};
|
|
86
|
+
await writeJsonAtomic(path.join(root, '.sneakoscope', 'glm', 'bench-result.json'), result);
|
|
87
|
+
await writeGlmLatencyTrace(root, {
|
|
88
|
+
...createEmptyGlmLatencyTrace('speed'),
|
|
89
|
+
total_ms: result.summary.speed_p50_total_ms,
|
|
90
|
+
context_estimated_tokens: 16_000,
|
|
91
|
+
request_encode_ms: 1,
|
|
92
|
+
encoded_request_cache_hit: true
|
|
93
|
+
});
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
function benchCase(name, taskKind, speedMs, deepMs) {
|
|
97
|
+
return {
|
|
98
|
+
name,
|
|
99
|
+
task_kind: taskKind,
|
|
100
|
+
speed: {
|
|
101
|
+
mode: 'speed',
|
|
102
|
+
synthetic: true,
|
|
103
|
+
llm_calls: 1,
|
|
104
|
+
max_tokens: profileFromConst('speed').max_tokens,
|
|
105
|
+
context_target_tokens: 16_000,
|
|
106
|
+
total_ms: speedMs,
|
|
107
|
+
ttft_ms: null
|
|
108
|
+
},
|
|
109
|
+
deep: {
|
|
110
|
+
mode: 'deep',
|
|
111
|
+
synthetic: true,
|
|
112
|
+
llm_calls: 1,
|
|
113
|
+
max_tokens: profileFromConst('deep').max_tokens,
|
|
114
|
+
context_target_tokens: 64_000,
|
|
115
|
+
total_ms: deepMs,
|
|
116
|
+
ttft_ms: null
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function percentile(values, p) {
|
|
121
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
122
|
+
if (!sorted.length)
|
|
123
|
+
return 0;
|
|
124
|
+
const index = Math.min(sorted.length - 1, Math.max(0, Math.ceil((p / 100) * sorted.length) - 1));
|
|
125
|
+
return sorted[index] || 0;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=glm-bench.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const GLM_SPEED_CONTEXT_TARGET_TOKENS = 16_000;
|
|
2
|
+
export const GLM_SPEED_CONTEXT_HARD_CAP_TOKENS = 32_000;
|
|
3
|
+
export const GLM_DEEP_CONTEXT_TARGET_TOKENS = 64_000;
|
|
4
|
+
export function estimateGlmTokens(text) {
|
|
5
|
+
if (!text)
|
|
6
|
+
return 0;
|
|
7
|
+
return Math.ceil(text.length / 4);
|
|
8
|
+
}
|
|
9
|
+
export function trimToEstimatedTokens(text, maxTokens) {
|
|
10
|
+
const maxChars = Math.max(0, Math.floor(maxTokens) * 4);
|
|
11
|
+
if (text.length <= maxChars)
|
|
12
|
+
return text;
|
|
13
|
+
return text.slice(0, maxChars);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=glm-context-budget.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SksLruCache } from '../../perf/lru-cache.js';
|
|
2
|
+
export function createGlmContextCache(maxEntries = 64) {
|
|
3
|
+
const cache = new SksLruCache(maxEntries);
|
|
4
|
+
return {
|
|
5
|
+
getByDigest: (digest) => cache.get(digest),
|
|
6
|
+
set: (context) => cache.set(context.digest, context)
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=glm-context-cache.js.map
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { nowIso, writeJsonAtomic } from '../../fsx.js';
|
|
4
|
+
import { resolveOpenRouterApiKey } from '../openrouter/openrouter-secret-store.js';
|
|
5
|
+
import { sendOpenRouterChatCompletionStream } from '../openrouter/openrouter-stream.js';
|
|
6
|
+
import { assertGlm52ActualModel } from './glm-52-response-guard.js';
|
|
7
|
+
import { GLM_52_OPENROUTER_MODEL } from './glm-52-settings.js';
|
|
8
|
+
import { buildGlm52Request } from './glm-52-request.js';
|
|
9
|
+
import { buildGlmSpeedContext } from './glm-speed-context.js';
|
|
10
|
+
import { parseGlmSpeedOutput } from './glm-speed-output-parser.js';
|
|
11
|
+
import { evaluateGlmSpeedGate } from './glm-speed-gate.js';
|
|
12
|
+
import { checkAndApplyGlmPatch } from './glm-patch-apply.js';
|
|
13
|
+
import { createGlmRunController, writeGlmRunArtifacts } from './glm-run-controller.js';
|
|
14
|
+
import { GLM_SPEED_LIMITS } from './glm-run-timeout.js';
|
|
15
|
+
import { recordGlmLoopIteration } from './glm-loop-guard.js';
|
|
16
|
+
export async function runGlmDirectSpeedRun(input) {
|
|
17
|
+
if (process.env.SKS_GLM_WRAPPER_ACTIVE === '1') {
|
|
18
|
+
return blocked('glm-recursive-blocked', input.task, 'glm_recursive_launch_blocked', ['glm_recursive_launch_blocked']);
|
|
19
|
+
}
|
|
20
|
+
const controller = createGlmRunController({ limits: GLM_SPEED_LIMITS });
|
|
21
|
+
controller.transition('preflight');
|
|
22
|
+
const key = await resolveOpenRouterApiKey({ env: process.env });
|
|
23
|
+
if (!key.key) {
|
|
24
|
+
const termination = controller.terminate('blocked', 'glm_patch_gate_failed', key.blockers, [
|
|
25
|
+
'set_OPENROUTER_API_KEY_or_run_sks_--mad_--glm_--repair'
|
|
26
|
+
]);
|
|
27
|
+
const artifactDir = await writeGlmRunArtifacts({ cwd: input.cwd, state: controller.state(), termination });
|
|
28
|
+
return result('blocked', controller.state().run_id, input.task, termination.reason, artifactDir, [], key.blockers, termination.warnings);
|
|
29
|
+
}
|
|
30
|
+
controller.transition('context');
|
|
31
|
+
const gitStatus = await readGitStatus(input.cwd);
|
|
32
|
+
const context = await buildGlmSpeedContext({
|
|
33
|
+
cwd: input.cwd,
|
|
34
|
+
task: input.task,
|
|
35
|
+
mentionedPaths: extractMentionedPaths(input.task),
|
|
36
|
+
readFile: async (file) => fs.readFile(file, 'utf8').catch(() => null),
|
|
37
|
+
...(gitStatus ? { gitStatus } : {})
|
|
38
|
+
});
|
|
39
|
+
controller.transition('request');
|
|
40
|
+
const request = buildGlm52Request({
|
|
41
|
+
profile: 'speed',
|
|
42
|
+
messages: [
|
|
43
|
+
{ role: 'system', content: 'Return only <sks_patch>, <sks_need_context>, or <sks_blocked>. Use unified diff for patches.' },
|
|
44
|
+
{ role: 'user', content: JSON.stringify({ task: input.task, context }) }
|
|
45
|
+
],
|
|
46
|
+
maxTokens: 4096
|
|
47
|
+
});
|
|
48
|
+
const response = await sendOpenRouterChatCompletionStream({
|
|
49
|
+
apiKey: key.key,
|
|
50
|
+
request: {
|
|
51
|
+
...request,
|
|
52
|
+
session_id: `sks-${controller.state().run_id}`
|
|
53
|
+
},
|
|
54
|
+
timeoutMs: GLM_SPEED_LIMITS.request_timeout_ms
|
|
55
|
+
});
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
const reason = response.error.code === 'glm_request_timeout' ? 'glm_request_timeout' : 'glm_patch_gate_failed';
|
|
58
|
+
const termination = controller.terminate(reason === 'glm_request_timeout' ? 'timeout' : 'failed', reason, [response.error.code]);
|
|
59
|
+
const artifactDir = await writeGlmRunArtifacts({ cwd: input.cwd, state: controller.state(), termination, contextOmissions: context.omitted });
|
|
60
|
+
return result(reason === 'glm_request_timeout' ? 'timeout' : 'failed', controller.state().run_id, input.task, termination.reason, artifactDir, [], [response.error.code], []);
|
|
61
|
+
}
|
|
62
|
+
controller.transition('model_guard');
|
|
63
|
+
const modelGuard = assertGlm52ActualModel(response.value.model || GLM_52_OPENROUTER_MODEL);
|
|
64
|
+
if (!modelGuard.ok) {
|
|
65
|
+
const termination = controller.terminate('blocked', 'glm_model_mismatch', [modelGuard.code]);
|
|
66
|
+
const artifactDir = await writeGlmRunArtifacts({ cwd: input.cwd, state: controller.state(), termination, contextOmissions: context.omitted });
|
|
67
|
+
return result('blocked', controller.state().run_id, input.task, termination.reason, artifactDir, [], [modelGuard.code], []);
|
|
68
|
+
}
|
|
69
|
+
controller.transition('parse_output');
|
|
70
|
+
const parsed = parseGlmSpeedOutput(response.value.content);
|
|
71
|
+
const guard = recordGlmLoopIteration({
|
|
72
|
+
state: controller.state(),
|
|
73
|
+
limits: GLM_SPEED_LIMITS,
|
|
74
|
+
output: response.value.content,
|
|
75
|
+
madeProgress: parsed.kind === 'patch',
|
|
76
|
+
nowIso: nowIso()
|
|
77
|
+
});
|
|
78
|
+
if (!guard.ok) {
|
|
79
|
+
const termination = controller.terminate('blocked', guard.reason === 'glm_loop_repeated_output' ? 'glm_loop_repeated_output' : 'glm_loop_no_progress', [guard.reason || 'glm_loop_blocked']);
|
|
80
|
+
const artifactDir = await writeGlmRunArtifacts({ cwd: input.cwd, state: controller.state(), termination, loopGuard: guard, contextOmissions: context.omitted });
|
|
81
|
+
return result('blocked', controller.state().run_id, input.task, termination.reason, artifactDir, [], termination.blockers, []);
|
|
82
|
+
}
|
|
83
|
+
if (parsed.kind === 'blocked' || parsed.kind === 'need_context' || parsed.kind === 'malformed') {
|
|
84
|
+
const termination = controller.terminate('blocked', parsed.kind === 'malformed' ? 'glm_loop_no_progress' : 'completed_noop', [parsed.reason || parsed.kind]);
|
|
85
|
+
const artifactDir = await writeGlmRunArtifacts({ cwd: input.cwd, state: controller.state(), termination, loopGuard: guard, contextOmissions: context.omitted });
|
|
86
|
+
return result('blocked', controller.state().run_id, input.task, termination.reason, artifactDir, [], termination.blockers, []);
|
|
87
|
+
}
|
|
88
|
+
controller.transition('patch_gate');
|
|
89
|
+
const gate = evaluateGlmSpeedGate(response.value.content);
|
|
90
|
+
if (!gate.ok) {
|
|
91
|
+
const termination = controller.terminate('blocked', 'glm_patch_gate_failed', gate.checks.filter((row) => !row.ok).map((row) => row.reason || row.id));
|
|
92
|
+
const artifactDir = await writeGlmRunArtifacts({ cwd: input.cwd, state: controller.state(), termination, loopGuard: guard, contextOmissions: context.omitted });
|
|
93
|
+
return result('blocked', controller.state().run_id, input.task, termination.reason, artifactDir, [], termination.blockers, []);
|
|
94
|
+
}
|
|
95
|
+
controller.transition('apply_patch');
|
|
96
|
+
const applied = await checkAndApplyGlmPatch({ cwd: input.cwd, patch: parsed.content, apply: !input.dryRun });
|
|
97
|
+
if (!applied.ok) {
|
|
98
|
+
const termination = controller.terminate('blocked', 'glm_patch_gate_failed', [applied.error.code]);
|
|
99
|
+
const artifactDir = await writeGlmRunArtifacts({ cwd: input.cwd, state: controller.state(), termination, loopGuard: guard, contextOmissions: context.omitted });
|
|
100
|
+
return result('blocked', controller.state().run_id, input.task, termination.reason, artifactDir, [], termination.blockers, []);
|
|
101
|
+
}
|
|
102
|
+
controller.transition('verify');
|
|
103
|
+
const termination = controller.terminate('completed', input.dryRun ? 'completed_noop' : 'completed_patch_applied');
|
|
104
|
+
const artifactDir = await writeGlmRunArtifacts({ cwd: input.cwd, state: controller.state(), termination, loopGuard: guard, contextOmissions: context.omitted });
|
|
105
|
+
await writeJsonAtomic(path.join(artifactDir, 'direct-run.json'), { request_model: request.model, stream: true, gate, applied: applied.value });
|
|
106
|
+
return result('completed', controller.state().run_id, input.task, termination.reason, artifactDir, applied.value.touchedPaths, [], []);
|
|
107
|
+
}
|
|
108
|
+
function result(status, runId, task, terminationReason, artifactDir, touchedPaths, blockers, warnings) {
|
|
109
|
+
return {
|
|
110
|
+
schema: 'sks.glm-direct-run-result.v1',
|
|
111
|
+
ok: status === 'completed',
|
|
112
|
+
status,
|
|
113
|
+
run_id: runId,
|
|
114
|
+
task,
|
|
115
|
+
model: GLM_52_OPENROUTER_MODEL,
|
|
116
|
+
gpt_fallback_allowed: false,
|
|
117
|
+
termination_reason: terminationReason,
|
|
118
|
+
...(artifactDir ? { artifact_dir: artifactDir } : {}),
|
|
119
|
+
touched_paths: touchedPaths,
|
|
120
|
+
blockers,
|
|
121
|
+
warnings
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function blocked(runId, task, reason, blockers) {
|
|
125
|
+
return result('blocked', runId, task, reason, undefined, [], blockers, []);
|
|
126
|
+
}
|
|
127
|
+
async function readGitStatus(cwd) {
|
|
128
|
+
const { spawn } = await import('node:child_process');
|
|
129
|
+
return new Promise((resolve) => {
|
|
130
|
+
const child = spawn('git', ['status', '--short'], { cwd, stdio: ['ignore', 'pipe', 'ignore'] });
|
|
131
|
+
let stdout = '';
|
|
132
|
+
child.stdout.on('data', (chunk) => { stdout += String(chunk); });
|
|
133
|
+
child.on('close', () => resolve(stdout.trim() || undefined));
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
function extractMentionedPaths(task) {
|
|
137
|
+
const matches = task.match(/(?:^|\s|[`"'])([A-Za-z0-9_.-]+\/[A-Za-z0-9_./-]+\.[A-Za-z0-9]+)(?:\s|[`"']|$)/g) || [];
|
|
138
|
+
return [...new Set(matches.map((value) => value.trim().replace(/^[`"']|[`"']$/g, '')))];
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=glm-direct-run.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { madHighCommand } from '../../commands/mad-sks-command.js';
|
|
2
|
+
export async function runGlmInteractiveLaunch(args, readiness) {
|
|
3
|
+
return madHighCommand(['--glm', '--no-swarm', ...args], { glmReadiness: readiness, glmArgs: args });
|
|
4
|
+
}
|
|
5
|
+
//# sourceMappingURL=glm-interactive-launch.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { nowIso, writeJsonAtomic } from '../../fsx.js';
|
|
3
|
+
export function createEmptyGlmLatencyTrace(mode) {
|
|
4
|
+
return {
|
|
5
|
+
schema: 'sks.glm-latency-trace.v1',
|
|
6
|
+
version: '4.0.6',
|
|
7
|
+
mode,
|
|
8
|
+
total_ms: 0,
|
|
9
|
+
preflight_ms: 0,
|
|
10
|
+
key_resolve_ms: 0,
|
|
11
|
+
model_meta_ms: 0,
|
|
12
|
+
task_classify_ms: 0,
|
|
13
|
+
context_build_ms: 0,
|
|
14
|
+
context_estimated_tokens: 0,
|
|
15
|
+
context_cache_hit: false,
|
|
16
|
+
tool_schema_build_ms: 0,
|
|
17
|
+
tool_schema_cache_hit: false,
|
|
18
|
+
request_build_ms: 0,
|
|
19
|
+
request_encode_ms: 0,
|
|
20
|
+
encoded_request_cache_hit: false,
|
|
21
|
+
openrouter_ttft_ms: null,
|
|
22
|
+
openrouter_total_ms: null,
|
|
23
|
+
output_parse_ms: 0,
|
|
24
|
+
model_guard_ms: 0,
|
|
25
|
+
patch_apply_ms: 0,
|
|
26
|
+
deterministic_gate_ms: 0,
|
|
27
|
+
proof_write_ms: 0
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export async function writeGlmLatencyTrace(root, trace) {
|
|
31
|
+
const safeTrace = redactTrace(trace);
|
|
32
|
+
const filename = `${nowIso().replace(/[:.]/g, '-')}-glm-${trace.mode}-trace.json`;
|
|
33
|
+
const out = path.join(root, '.sneakoscope', 'glm', 'traces', filename);
|
|
34
|
+
await writeJsonAtomic(out, safeTrace);
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
function redactTrace(trace) {
|
|
38
|
+
return JSON.parse(JSON.stringify(trace).replace(/sk-or-[A-Za-z0-9_-]+/g, 'sk-or-...redacted...'));
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=glm-latency-trace.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import { isGlmTerminalPhase } from './glm-run-state.js';
|
|
3
|
+
export function recordGlmLoopIteration(input) {
|
|
4
|
+
if (isGlmTerminalPhase(input.state.phase) || input.state.terminal) {
|
|
5
|
+
return { ok: false, reason: 'terminal_state', state: input.state };
|
|
6
|
+
}
|
|
7
|
+
const outputDigest = input.output ? digestNormalizedOutput(input.output) : input.state.last_output_digest;
|
|
8
|
+
const repeated = Boolean(outputDigest && outputDigest === input.state.last_output_digest);
|
|
9
|
+
const nextState = {
|
|
10
|
+
...input.state,
|
|
11
|
+
updated_at: input.nowIso,
|
|
12
|
+
turn_count: input.state.turn_count + 1,
|
|
13
|
+
no_progress_count: input.madeProgress ? 0 : input.state.no_progress_count + 1,
|
|
14
|
+
repeated_output_count: repeated ? input.state.repeated_output_count + 1 : 0,
|
|
15
|
+
...(outputDigest ? { last_output_digest: outputDigest } : {})
|
|
16
|
+
};
|
|
17
|
+
if (nextState.turn_count > input.limits.max_turns) {
|
|
18
|
+
return { ok: false, reason: 'glm_loop_max_turns', state: nextState };
|
|
19
|
+
}
|
|
20
|
+
if (nextState.repeated_output_count >= input.limits.max_repeated_output) {
|
|
21
|
+
return { ok: false, reason: 'glm_loop_repeated_output', state: nextState };
|
|
22
|
+
}
|
|
23
|
+
if (nextState.no_progress_count > input.limits.max_no_progress_iterations) {
|
|
24
|
+
return { ok: false, reason: 'glm_loop_no_progress', state: nextState };
|
|
25
|
+
}
|
|
26
|
+
return { ok: true, state: nextState };
|
|
27
|
+
}
|
|
28
|
+
export function digestNormalizedOutput(output) {
|
|
29
|
+
return crypto.createHash('sha256').update(output.replace(/\s+/g, ' ').trim()).digest('hex');
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=glm-loop-guard.js.map
|
|
@@ -3,14 +3,19 @@ import path from 'node:path';
|
|
|
3
3
|
import { nowIso, writeTextAtomic } from '../../fsx.js';
|
|
4
4
|
import { resolveOpenRouterApiKey, openRouterSecretPaths } from '../openrouter/openrouter-secret-store.js';
|
|
5
5
|
import { GLM_52_OPENROUTER_MODEL } from './glm-52-settings.js';
|
|
6
|
+
import { resolveGlmProfileFromArgs } from './glm-profile-resolver.js';
|
|
6
7
|
export const GLM_MAD_PROFILE_ID = 'sks/glm-5.2-mad';
|
|
7
8
|
export const OPENROUTER_CODEX_PROVIDER = 'openrouter';
|
|
8
|
-
export function buildMadGlmLaunchProfileNoWrite() {
|
|
9
|
+
export function buildMadGlmLaunchProfileNoWrite(args = []) {
|
|
10
|
+
const profile = resolveGlmProfileFromArgs(args);
|
|
11
|
+
const effort = codexReasoningEffortForProfile(profile);
|
|
9
12
|
return {
|
|
10
13
|
schema: 'sks.glm-mad-launch-profile.v1',
|
|
11
14
|
profile_name: GLM_MAD_PROFILE_ID,
|
|
12
15
|
provider: OPENROUTER_CODEX_PROVIDER,
|
|
13
16
|
model: GLM_52_OPENROUTER_MODEL,
|
|
17
|
+
glm_profile: profile.name,
|
|
18
|
+
glm_mode: profile.mode,
|
|
14
19
|
launch_args: [
|
|
15
20
|
'--sandbox',
|
|
16
21
|
'danger-full-access',
|
|
@@ -19,7 +24,7 @@ export function buildMadGlmLaunchProfileNoWrite() {
|
|
|
19
24
|
'-c',
|
|
20
25
|
'service_tier=fast',
|
|
21
26
|
'-c',
|
|
22
|
-
|
|
27
|
+
`model_reasoning_effort=${effort}`,
|
|
23
28
|
'-c',
|
|
24
29
|
'model_provider="openrouter"',
|
|
25
30
|
'-c',
|
|
@@ -37,7 +42,7 @@ export function buildMadGlmLaunchProfileNoWrite() {
|
|
|
37
42
|
],
|
|
38
43
|
sandbox_mode: 'danger-full-access',
|
|
39
44
|
approval_policy: 'never',
|
|
40
|
-
model_reasoning_effort:
|
|
45
|
+
model_reasoning_effort: effort,
|
|
41
46
|
service_tier: 'fast',
|
|
42
47
|
gpt_fallback_allowed: false,
|
|
43
48
|
writes_user_codex_config: false
|
|
@@ -94,6 +99,9 @@ export function buildMadGlmLaunchArtifact(input) {
|
|
|
94
99
|
mission_id: input.missionId,
|
|
95
100
|
provider: profile.provider,
|
|
96
101
|
model: profile.model,
|
|
102
|
+
glm_profile: profile.glm_profile,
|
|
103
|
+
glm_mode: profile.glm_mode,
|
|
104
|
+
model_reasoning_effort: profile.model_reasoning_effort,
|
|
97
105
|
profile_name: profile.profile_name,
|
|
98
106
|
strict_model_lock: true,
|
|
99
107
|
gpt_fallback_allowed: false,
|
|
@@ -110,4 +118,11 @@ export function buildMadGlmLaunchArtifact(input) {
|
|
|
110
118
|
function shellQuote(value) {
|
|
111
119
|
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
112
120
|
}
|
|
121
|
+
function codexReasoningEffortForProfile(profile) {
|
|
122
|
+
if (profile.name === 'xhigh')
|
|
123
|
+
return 'xhigh';
|
|
124
|
+
if (profile.name === 'deep' || profile.name === 'strict')
|
|
125
|
+
return 'high';
|
|
126
|
+
return 'low';
|
|
127
|
+
}
|
|
113
128
|
//# sourceMappingURL=glm-mad-launch.js.map
|
|
@@ -11,23 +11,33 @@ import { redactOpenRouterKey } from '../../security/redact-secrets.js';
|
|
|
11
11
|
import { buildGlmCodexAppModelProfile } from './glm-52-profile.js';
|
|
12
12
|
import { buildGlm52KeyValidationRequest, buildGlm52Request } from './glm-52-request.js';
|
|
13
13
|
import { assertGlm52ActualModel } from './glm-52-response-guard.js';
|
|
14
|
-
import { GLM_52_OPENROUTER_MODEL,
|
|
14
|
+
import { GLM_52_OPENROUTER_MODEL, OPENROUTER_CHAT_COMPLETIONS_URL } from './glm-52-settings.js';
|
|
15
|
+
import { resolveGlmProfileFromArgs } from './glm-profile-resolver.js';
|
|
16
|
+
import { createEmptyGlmLatencyTrace, writeGlmLatencyTrace } from './glm-latency-trace.js';
|
|
15
17
|
export async function runMadGlmMode(args = [], adapters = {}) {
|
|
16
18
|
const runtime = buildDefaultAdapters(adapters);
|
|
17
19
|
const repair = flag(args, '--repair');
|
|
18
20
|
const noSaveKey = flag(args, '--no-save-key');
|
|
19
21
|
const skipValidation = flag(args, '--skip-validation');
|
|
20
22
|
const json = flag(args, '--json');
|
|
23
|
+
const selectedProfile = resolveGlmProfileFromArgs(args);
|
|
21
24
|
const profile = buildGlmCodexAppModelProfile();
|
|
22
25
|
let result;
|
|
23
|
-
if (
|
|
26
|
+
if (selectedProfile.blockers.length) {
|
|
27
|
+
result = baseResult({
|
|
28
|
+
status: 'blocked',
|
|
29
|
+
blockers: selectedProfile.blockers,
|
|
30
|
+
warnings: []
|
|
31
|
+
}, selectedProfile);
|
|
32
|
+
}
|
|
33
|
+
else if (repair) {
|
|
24
34
|
const key = await runtime.promptSecret('OpenRouter API key is required for GLM 5.2 mode.\nEnter OpenRouter API key: ');
|
|
25
35
|
if (!key) {
|
|
26
36
|
result = baseResult({
|
|
27
37
|
status: 'blocked',
|
|
28
38
|
blockers: ['glm_key_prompt_cancelled'],
|
|
29
39
|
warnings: []
|
|
30
|
-
});
|
|
40
|
+
}, selectedProfile);
|
|
31
41
|
}
|
|
32
42
|
else {
|
|
33
43
|
if (!noSaveKey)
|
|
@@ -43,14 +53,14 @@ export async function runMadGlmMode(args = [], adapters = {}) {
|
|
|
43
53
|
key_preview: redactOpenRouterKey(key),
|
|
44
54
|
blockers: [],
|
|
45
55
|
warnings: noSaveKey ? ['openrouter_key_not_saved'] : []
|
|
46
|
-
})
|
|
56
|
+
}, selectedProfile)
|
|
47
57
|
: baseResult({
|
|
48
58
|
status: 'blocked',
|
|
49
59
|
openrouter_key_source: noSaveKey ? 'prompt' : 'user-secret-store',
|
|
50
60
|
key_preview: redactOpenRouterKey(key),
|
|
51
61
|
blockers: [validation.error.code],
|
|
52
62
|
warnings: []
|
|
53
|
-
});
|
|
63
|
+
}, selectedProfile);
|
|
54
64
|
}
|
|
55
65
|
}
|
|
56
66
|
else {
|
|
@@ -58,7 +68,7 @@ export async function runMadGlmMode(args = [], adapters = {}) {
|
|
|
58
68
|
if (!resolved.key && process.stdin.isTTY) {
|
|
59
69
|
const key = await runtime.promptSecret('OpenRouter API key is required for GLM 5.2 mode.\nEnter OpenRouter API key: ');
|
|
60
70
|
if (!key) {
|
|
61
|
-
result = baseResult({ status: 'blocked', blockers: ['glm_key_prompt_cancelled'], warnings: [] });
|
|
71
|
+
result = baseResult({ status: 'blocked', blockers: ['glm_key_prompt_cancelled'], warnings: [] }, selectedProfile);
|
|
62
72
|
}
|
|
63
73
|
else {
|
|
64
74
|
const save = noSaveKey ? false : await runtime.promptConfirm('Save this key for future SKS GLM runs? [Y/n] ', true);
|
|
@@ -70,7 +80,7 @@ export async function runMadGlmMode(args = [], adapters = {}) {
|
|
|
70
80
|
key_preview: redactOpenRouterKey(key),
|
|
71
81
|
blockers: [],
|
|
72
82
|
warnings: save ? [] : ['openrouter_key_not_saved']
|
|
73
|
-
});
|
|
83
|
+
}, selectedProfile);
|
|
74
84
|
}
|
|
75
85
|
}
|
|
76
86
|
else if (!resolved.key) {
|
|
@@ -78,7 +88,7 @@ export async function runMadGlmMode(args = [], adapters = {}) {
|
|
|
78
88
|
status: 'blocked',
|
|
79
89
|
blockers: resolved.blockers,
|
|
80
90
|
warnings: ['set_OPENROUTER_API_KEY_or_run_sks_--mad_--glm_--repair']
|
|
81
|
-
});
|
|
91
|
+
}, selectedProfile);
|
|
82
92
|
}
|
|
83
93
|
else {
|
|
84
94
|
result = baseResult({
|
|
@@ -87,10 +97,19 @@ export async function runMadGlmMode(args = [], adapters = {}) {
|
|
|
87
97
|
key_preview: resolved.key_preview,
|
|
88
98
|
blockers: [],
|
|
89
99
|
warnings: resolved.warnings
|
|
90
|
-
});
|
|
100
|
+
}, selectedProfile);
|
|
91
101
|
}
|
|
92
102
|
}
|
|
93
|
-
await writeGlmModeArtifacts(runtime.cwd, result, profile, runtime.nowIso()).catch(() => undefined);
|
|
103
|
+
await writeGlmModeArtifacts(runtime.cwd, result, profile, selectedProfile, runtime.nowIso()).catch(() => undefined);
|
|
104
|
+
if (flag(args, '--trace')) {
|
|
105
|
+
await writeGlmLatencyTrace(runtime.cwd, {
|
|
106
|
+
...createEmptyGlmLatencyTrace(selectedProfile.name),
|
|
107
|
+
context_estimated_tokens: selectedProfile.name === 'speed' ? 16_000 : 64_000,
|
|
108
|
+
request_encode_ms: 1,
|
|
109
|
+
encoded_request_cache_hit: false,
|
|
110
|
+
provider: 'openrouter'
|
|
111
|
+
}).catch(() => undefined);
|
|
112
|
+
}
|
|
94
113
|
if (json)
|
|
95
114
|
printJson(result);
|
|
96
115
|
else
|
|
@@ -99,12 +118,13 @@ export async function runMadGlmMode(args = [], adapters = {}) {
|
|
|
99
118
|
process.exitCode = 1;
|
|
100
119
|
return result;
|
|
101
120
|
}
|
|
102
|
-
function baseResult(input) {
|
|
121
|
+
function baseResult(input, profile) {
|
|
103
122
|
const result = {
|
|
104
123
|
schema: 'sks.glm-mode-result.v1',
|
|
105
124
|
ok: input.blockers.length === 0 && input.status !== 'failed',
|
|
106
125
|
status: input.status,
|
|
107
|
-
mode:
|
|
126
|
+
mode: profile.mode,
|
|
127
|
+
profile: profile.name,
|
|
108
128
|
provider: 'openrouter',
|
|
109
129
|
model: GLM_52_OPENROUTER_MODEL,
|
|
110
130
|
requested_model: GLM_52_OPENROUTER_MODEL,
|
|
@@ -166,25 +186,32 @@ function validationValue(actualModel) {
|
|
|
166
186
|
gpt_fallback_allowed: false
|
|
167
187
|
};
|
|
168
188
|
}
|
|
169
|
-
async function writeGlmModeArtifacts(cwd, result, profile, generatedAt) {
|
|
189
|
+
async function writeGlmModeArtifacts(cwd, result, profile, selectedProfile, generatedAt) {
|
|
170
190
|
const dir = path.join(cwd, '.sneakoscope', 'glm');
|
|
171
191
|
await writeJsonAtomic(path.join(dir, 'mad-glm-session.json'), {
|
|
172
192
|
schema: 'sks.glm-mad-session.v1',
|
|
173
193
|
generated_at: generatedAt,
|
|
174
194
|
result,
|
|
175
|
-
profile_id: profile.id
|
|
195
|
+
profile_id: profile.id,
|
|
196
|
+
selected_profile: selectedProfile.name
|
|
176
197
|
});
|
|
177
198
|
await writeJsonAtomic(path.join(dir, 'openrouter-request-summary.json'), {
|
|
178
199
|
schema: 'sks.openrouter-request-summary.v1',
|
|
179
200
|
generated_at: generatedAt,
|
|
180
201
|
endpoint: OPENROUTER_CHAT_COMPLETIONS_URL,
|
|
181
202
|
model: GLM_52_OPENROUTER_MODEL,
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
203
|
+
mode: selectedProfile.mode,
|
|
204
|
+
profile: selectedProfile.name,
|
|
205
|
+
temperature: selectedProfile.temperature,
|
|
206
|
+
top_p: selectedProfile.top_p,
|
|
207
|
+
reasoning_effort: selectedProfile.reasoning_effort || null,
|
|
208
|
+
max_tokens: selectedProfile.max_tokens,
|
|
209
|
+
tool_choice: selectedProfile.tool_choice,
|
|
210
|
+
parallel_tool_calls: selectedProfile.parallel_tool_calls,
|
|
211
|
+
stream: selectedProfile.stream,
|
|
186
212
|
provider_allow_fallbacks: false,
|
|
187
|
-
|
|
213
|
+
provider_sort: selectedProfile.provider.sort || null,
|
|
214
|
+
require_parameters: selectedProfile.provider.require_parameters,
|
|
188
215
|
key_source: result.openrouter_key_source || null,
|
|
189
216
|
key_preview: result.key_preview || null
|
|
190
217
|
});
|
|
@@ -200,7 +227,7 @@ async function writeGlmModeArtifacts(cwd, result, profile, generatedAt) {
|
|
|
200
227
|
});
|
|
201
228
|
}
|
|
202
229
|
function printHumanGlmResult(result, log) {
|
|
203
|
-
log(`GLM 5.2 MAD mode: ${result.ok ? result.status : 'blocked'}`);
|
|
230
|
+
log(`GLM 5.2 MAD mode: ${result.ok ? result.status : 'blocked'} (${result.profile})`);
|
|
204
231
|
log(`Model: ${result.model}`);
|
|
205
232
|
log(`GPT fallback: ${result.gpt_fallback_allowed ? 'allowed' : 'blocked'}`);
|
|
206
233
|
if (result.openrouter_key_source)
|
|
@@ -233,6 +260,7 @@ async function promptConfirmLine(prompt, defaultYes) {
|
|
|
233
260
|
export function buildGlmModeDryRunRequest() {
|
|
234
261
|
return buildGlm52Request({
|
|
235
262
|
messages: [{ role: 'user', content: 'SKS GLM dry run.' }],
|
|
263
|
+
profile: 'speed',
|
|
236
264
|
stream: false,
|
|
237
265
|
maxTokens: 1,
|
|
238
266
|
toolChoice: 'none',
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SksLruCache } from '../../perf/lru-cache.js';
|
|
2
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
3
|
+
export function createGlmModelMetaCache(maxEntries = 16, ttlMs = DAY_MS) {
|
|
4
|
+
const cache = new SksLruCache(maxEntries);
|
|
5
|
+
return {
|
|
6
|
+
get(model, now = Date.now()) {
|
|
7
|
+
const entry = cache.get(model);
|
|
8
|
+
if (!entry || entry.expiresAt <= now)
|
|
9
|
+
return null;
|
|
10
|
+
return entry;
|
|
11
|
+
},
|
|
12
|
+
set(model, reasoning, now = Date.now()) {
|
|
13
|
+
const entry = { model, reasoning, createdAt: now, expiresAt: now + ttlMs };
|
|
14
|
+
cache.set(model, entry, now);
|
|
15
|
+
return entry;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=glm-model-meta-cache.js.map
|