sneakoscope 4.0.3 → 4.0.5

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.
Files changed (30) hide show
  1. package/README.md +9 -8
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/crates/sks-core/src/main.rs +1 -1
  5. package/dist/bin/sks.js +1 -1
  6. package/dist/core/codex-app/glm-profile-schema.js +5 -1
  7. package/dist/core/commands/glm-command.js +20 -1
  8. package/dist/core/commands/mad-sks-command.js +174 -20
  9. package/dist/core/fsx.js +1 -1
  10. package/dist/core/perf/lru-cache.js +33 -0
  11. package/dist/core/providers/glm/glm-52-profile.js +14 -7
  12. package/dist/core/providers/glm/glm-52-request.js +40 -12
  13. package/dist/core/providers/glm/glm-52-response-guard.js +1 -2
  14. package/dist/core/providers/glm/glm-52-settings.js +50 -8
  15. package/dist/core/providers/glm/glm-bench.js +90 -0
  16. package/dist/core/providers/glm/glm-context-budget.js +15 -0
  17. package/dist/core/providers/glm/glm-context-cache.js +9 -0
  18. package/dist/core/providers/glm/glm-latency-trace.js +40 -0
  19. package/dist/core/providers/glm/glm-mad-launch.js +128 -0
  20. package/dist/core/providers/glm/glm-mad-mode.js +48 -20
  21. package/dist/core/providers/glm/glm-model-meta-cache.js +19 -0
  22. package/dist/core/providers/glm/glm-profile-resolver.js +104 -0
  23. package/dist/core/providers/glm/glm-reasoning-policy.js +15 -0
  24. package/dist/core/providers/glm/glm-request-cache.js +47 -0
  25. package/dist/core/providers/glm/glm-speed-context.js +82 -0
  26. package/dist/core/providers/glm/glm-speed-gate.js +40 -0
  27. package/dist/core/providers/glm/glm-speed-output-parser.js +40 -0
  28. package/dist/core/providers/glm/glm-tool-schema-cache.js +19 -0
  29. package/dist/core/version.js +1 -1
  30. package/package.json +1 -1
@@ -1,24 +1,66 @@
1
1
  export { OPENROUTER_CHAT_COMPLETIONS_URL } from '../openrouter/openrouter-types.js';
2
2
  export const GLM_52_OPENROUTER_MODEL = 'z-ai/glm-5.2';
3
- export const GLM_MAD_MODE = 'mad-glm';
4
- export const GLM_52_MAX_TOKENS_DEFAULT = 32768;
3
+ export const GLM_52_MODEL = GLM_52_OPENROUTER_MODEL;
4
+ export const GLM_SPEED_MODE = 'mad-glm-speed';
5
+ export const GLM_DEEP_MODE = 'mad-glm-deep';
6
+ export const GLM_XHIGH_MODE = 'mad-glm-xhigh';
7
+ export const GLM_STRICT_MODE = 'mad-glm-strict';
8
+ export const GLM_MAD_MODE = GLM_SPEED_MODE;
9
+ export const GLM_52_MAX_TOKENS_SPEED = 4096;
10
+ export const GLM_52_MAX_TOKENS_DEFAULT = GLM_52_MAX_TOKENS_SPEED;
11
+ export const GLM_52_MAX_TOKENS_DEEP = 16384;
12
+ export const GLM_52_MAX_TOKENS_XHIGH = 32768;
5
13
  export const GLM_52_MAX_TOKENS_LONG = 65536;
6
14
  export const GLM_52_MAX_TOKENS_XLONG = 131072;
7
15
  export const GLM_52_TOP_PROVIDER_MAX_COMPLETION_TOKENS = 262144;
8
- export const GLM_52_DEFAULT_REQUEST_SETTINGS = {
16
+ export const GLM_SPEED_PROFILE = {
9
17
  model: GLM_52_OPENROUTER_MODEL,
10
- temperature: 1,
11
- top_p: 0.95,
12
- reasoning_effort: 'high',
18
+ mode: GLM_SPEED_MODE,
19
+ temperature: 0.2,
20
+ top_p: 0.85,
13
21
  stream: true,
14
22
  provider: {
15
23
  allow_fallbacks: false,
16
- require_parameters: true
24
+ require_parameters: true,
25
+ sort: 'throughput',
26
+ preferred_min_throughput: { p50: 80, p90: 40 },
27
+ preferred_max_latency: { p50: 2, p90: 5 }
28
+ },
29
+ tool_choice: 'none',
30
+ parallel_tool_calls: false,
31
+ max_tokens: GLM_52_MAX_TOKENS_SPEED,
32
+ reasoning_effort: 'xhigh',
33
+ reasoning_default: 'xhigh-speed-optimized'
34
+ };
35
+ export const GLM_DEEP_PROFILE = {
36
+ model: GLM_52_OPENROUTER_MODEL,
37
+ mode: GLM_DEEP_MODE,
38
+ temperature: 0.3,
39
+ top_p: 0.9,
40
+ stream: true,
41
+ provider: {
42
+ allow_fallbacks: false,
43
+ require_parameters: true,
44
+ sort: 'throughput'
17
45
  },
18
46
  tool_choice: 'auto',
19
47
  parallel_tool_calls: false,
20
- max_tokens: GLM_52_MAX_TOKENS_DEFAULT
48
+ max_tokens: GLM_52_MAX_TOKENS_DEEP,
49
+ reasoning_effort: 'high'
50
+ };
51
+ export const GLM_XHIGH_PROFILE = {
52
+ ...GLM_DEEP_PROFILE,
53
+ mode: GLM_XHIGH_MODE,
54
+ max_tokens: GLM_52_MAX_TOKENS_XHIGH,
55
+ reasoning_effort: 'xhigh'
56
+ };
57
+ export const GLM_STRICT_PROFILE = {
58
+ ...GLM_DEEP_PROFILE,
59
+ mode: GLM_STRICT_MODE,
60
+ structured_outputs: true,
61
+ response_format: 'json_schema'
21
62
  };
63
+ export const GLM_52_DEFAULT_REQUEST_SETTINGS = GLM_SPEED_PROFILE;
22
64
  export function clampGlm52MaxTokens(value) {
23
65
  const numeric = Number.isFinite(value) ? Math.floor(Number(value)) : GLM_52_MAX_TOKENS_DEFAULT;
24
66
  return Math.max(1, Math.min(numeric, GLM_52_TOP_PROVIDER_MAX_COMPLETION_TOKENS));
@@ -0,0 +1,90 @@
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 execute = args.includes('--execute');
13
+ if (execute) {
14
+ const blocked = {
15
+ schema: 'sks.glm-bench-result.v1',
16
+ version: '4.0.5',
17
+ generated_at: nowIso(),
18
+ status: 'blocked',
19
+ dry_run: true,
20
+ cases: [],
21
+ summary: {
22
+ speed_p50_total_ms: 0,
23
+ speed_p90_total_ms: 0,
24
+ speed_p50_ttft_ms: null
25
+ },
26
+ warnings: ['execute_requested_but_live_openrouter_bench_not_implemented']
27
+ };
28
+ await writeJsonAtomic(path.join(root, '.sneakoscope', 'glm', 'bench-blocked.json'), blocked);
29
+ return blocked;
30
+ }
31
+ const speedTotals = SYNTHETIC_CASES.map((row) => row.speed.total_ms);
32
+ const deepTotals = SYNTHETIC_CASES.map((row) => row.deep.total_ms);
33
+ const result = {
34
+ schema: 'sks.glm-bench-result.v1',
35
+ version: '4.0.5',
36
+ generated_at: nowIso(),
37
+ status: 'dry_run',
38
+ dry_run: true,
39
+ cases: SYNTHETIC_CASES,
40
+ summary: {
41
+ speed_p50_total_ms: percentile(speedTotals, 50),
42
+ speed_p90_total_ms: percentile(speedTotals, 90),
43
+ speed_p50_ttft_ms: null,
44
+ deep_p50_total_ms: percentile(deepTotals, 50),
45
+ speed_vs_deep_ratio: Number((percentile(speedTotals, 50) / percentile(deepTotals, 50)).toFixed(3))
46
+ },
47
+ warnings: ['synthetic_dry_run_no_network_no_gpt_key_required']
48
+ };
49
+ await writeJsonAtomic(path.join(root, '.sneakoscope', 'glm', 'bench-result.json'), result);
50
+ await writeGlmLatencyTrace(root, {
51
+ ...createEmptyGlmLatencyTrace('speed'),
52
+ total_ms: result.summary.speed_p50_total_ms,
53
+ context_estimated_tokens: 16_000,
54
+ request_encode_ms: 1,
55
+ encoded_request_cache_hit: true
56
+ });
57
+ return result;
58
+ }
59
+ function benchCase(name, taskKind, speedMs, deepMs) {
60
+ return {
61
+ name,
62
+ task_kind: taskKind,
63
+ speed: {
64
+ mode: 'speed',
65
+ synthetic: true,
66
+ llm_calls: 1,
67
+ max_tokens: profileFromConst('speed').max_tokens,
68
+ context_target_tokens: 16_000,
69
+ total_ms: speedMs,
70
+ ttft_ms: null
71
+ },
72
+ deep: {
73
+ mode: 'deep',
74
+ synthetic: true,
75
+ llm_calls: 1,
76
+ max_tokens: profileFromConst('deep').max_tokens,
77
+ context_target_tokens: 64_000,
78
+ total_ms: deepMs,
79
+ ttft_ms: null
80
+ }
81
+ };
82
+ }
83
+ function percentile(values, p) {
84
+ const sorted = [...values].sort((a, b) => a - b);
85
+ if (!sorted.length)
86
+ return 0;
87
+ const index = Math.min(sorted.length - 1, Math.max(0, Math.ceil((p / 100) * sorted.length) - 1));
88
+ return sorted[index] || 0;
89
+ }
90
+ //# 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,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.5',
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,128 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { nowIso, writeTextAtomic } from '../../fsx.js';
4
+ import { resolveOpenRouterApiKey, openRouterSecretPaths } from '../openrouter/openrouter-secret-store.js';
5
+ import { GLM_52_OPENROUTER_MODEL } from './glm-52-settings.js';
6
+ import { resolveGlmProfileFromArgs } from './glm-profile-resolver.js';
7
+ export const GLM_MAD_PROFILE_ID = 'sks/glm-5.2-mad';
8
+ export const OPENROUTER_CODEX_PROVIDER = 'openrouter';
9
+ export function buildMadGlmLaunchProfileNoWrite(args = []) {
10
+ const profile = resolveGlmProfileFromArgs(args);
11
+ const effort = codexReasoningEffortForProfile(profile);
12
+ return {
13
+ schema: 'sks.glm-mad-launch-profile.v1',
14
+ profile_name: GLM_MAD_PROFILE_ID,
15
+ provider: OPENROUTER_CODEX_PROVIDER,
16
+ model: GLM_52_OPENROUTER_MODEL,
17
+ glm_profile: profile.name,
18
+ glm_mode: profile.mode,
19
+ launch_args: [
20
+ '--sandbox',
21
+ 'danger-full-access',
22
+ '--ask-for-approval',
23
+ 'never',
24
+ '-c',
25
+ 'service_tier=fast',
26
+ '-c',
27
+ `model_reasoning_effort=${effort}`,
28
+ '-c',
29
+ 'model_provider="openrouter"',
30
+ '-c',
31
+ `model="${GLM_52_OPENROUTER_MODEL}"`,
32
+ '-c',
33
+ 'model_providers.openrouter.name="OpenRouter"',
34
+ '-c',
35
+ 'model_providers.openrouter.base_url="https://openrouter.ai/api/v1"',
36
+ '-c',
37
+ 'model_providers.openrouter.env_key="OPENROUTER_API_KEY"',
38
+ '-c',
39
+ 'model_providers.openrouter.wire_api="responses"',
40
+ '-c',
41
+ 'model_providers.openrouter.requires_openai_auth=false'
42
+ ],
43
+ sandbox_mode: 'danger-full-access',
44
+ approval_policy: 'never',
45
+ model_reasoning_effort: effort,
46
+ service_tier: 'fast',
47
+ gpt_fallback_allowed: false,
48
+ writes_user_codex_config: false
49
+ };
50
+ }
51
+ export async function resolveMadGlmLaunchKey(env = process.env) {
52
+ return resolveOpenRouterApiKey({ env });
53
+ }
54
+ export async function writeMadGlmCodexWrapper(input) {
55
+ const env = input.env || process.env;
56
+ const paths = openRouterSecretPaths(env);
57
+ const realCodexBin = String(input.realCodexBin || env.SKS_CODEX_BIN || 'codex');
58
+ const wrapperPath = path.join(input.missionDir, 'sks-glm-codex-wrapper.sh');
59
+ await writeTextAtomic(wrapperPath, buildMadGlmCodexWrapperScript({
60
+ realCodexBin,
61
+ secretKeyPath: paths.keyPath
62
+ }));
63
+ await fs.chmod(wrapperPath, 0o700).catch(() => undefined);
64
+ return {
65
+ wrapper_path: wrapperPath,
66
+ real_codex_bin: realCodexBin,
67
+ secret_key_path: paths.keyPath,
68
+ raw_key_written_to_wrapper: false
69
+ };
70
+ }
71
+ export function buildMadGlmCodexWrapperScript(input) {
72
+ return [
73
+ '#!/bin/sh',
74
+ 'set -eu',
75
+ '# Generated by SKS GLM MAD launch. This wrapper reads the key at runtime',
76
+ '# so Zellij layout artifacts never contain the raw OpenRouter secret.',
77
+ 'if [ -z "${OPENROUTER_API_KEY:-}" ] && [ -n "${SKS_OPENROUTER_API_KEY:-}" ]; then',
78
+ ' OPENROUTER_API_KEY="$SKS_OPENROUTER_API_KEY"',
79
+ ' export OPENROUTER_API_KEY',
80
+ 'fi',
81
+ `if [ -z "\${OPENROUTER_API_KEY:-}" ] && [ -r ${shellQuote(input.secretKeyPath)} ]; then`,
82
+ ` OPENROUTER_API_KEY="$(cat ${shellQuote(input.secretKeyPath)})"`,
83
+ ' export OPENROUTER_API_KEY',
84
+ 'fi',
85
+ 'if [ -z "${OPENROUTER_API_KEY:-}" ]; then',
86
+ ' echo "SKS GLM MAD blocked: OPENROUTER_API_KEY is missing. Run sks --mad --glm --repair or export OPENROUTER_API_KEY." >&2',
87
+ ' exit 66',
88
+ 'fi',
89
+ `exec ${shellQuote(input.realCodexBin)} "$@"`,
90
+ ''
91
+ ].join('\n');
92
+ }
93
+ export function buildMadGlmLaunchArtifact(input) {
94
+ const profile = input.profile || buildMadGlmLaunchProfileNoWrite();
95
+ return {
96
+ schema: 'sks.glm-mad-launch.v1',
97
+ generated_at: nowIso(),
98
+ ok: Boolean(input.keyResolution.key),
99
+ mission_id: input.missionId,
100
+ provider: profile.provider,
101
+ model: profile.model,
102
+ glm_profile: profile.glm_profile,
103
+ glm_mode: profile.glm_mode,
104
+ model_reasoning_effort: profile.model_reasoning_effort,
105
+ profile_name: profile.profile_name,
106
+ strict_model_lock: true,
107
+ gpt_fallback_allowed: false,
108
+ openrouter_key_source: input.keyResolution.source || null,
109
+ key_preview: input.keyResolution.key_preview || null,
110
+ wrapper_path: input.wrapper.wrapper_path,
111
+ real_codex_bin: input.wrapper.real_codex_bin,
112
+ raw_key_written_to_wrapper: false,
113
+ codex_args: profile.launch_args,
114
+ blockers: input.keyResolution.key ? [] : input.keyResolution.blockers,
115
+ warnings: input.keyResolution.warnings || []
116
+ };
117
+ }
118
+ function shellQuote(value) {
119
+ return `'${String(value).replace(/'/g, `'\\''`)}'`;
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 'xhigh';
127
+ }
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, GLM_MAD_MODE, OPENROUTER_CHAT_COMPLETIONS_URL } from './glm-52-settings.js';
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 (repair) {
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: GLM_MAD_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
- temperature: 1,
183
- top_p: 0.95,
184
- reasoning_effort: 'high',
185
- stream: true,
203
+ mode: selectedProfile.mode,
204
+ profile: selectedProfile.name,
205
+ temperature: selectedProfile.temperature,
206
+ top_p: selectedProfile.top_p,
207
+ reasoning_effort: selectedProfile.reasoning_effort || 'xhigh',
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
- require_parameters: true,
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
@@ -0,0 +1,104 @@
1
+ import { readOption } from '../../../cli/args.js';
2
+ import { GLM_DEEP_MODE, GLM_DEEP_PROFILE, GLM_SPEED_MODE, GLM_SPEED_PROFILE, GLM_STRICT_MODE, GLM_STRICT_PROFILE, GLM_XHIGH_MODE, GLM_XHIGH_PROFILE } from './glm-52-settings.js';
3
+ export function resolveGlmProfileFromArgs(args = []) {
4
+ const list = args.map(String);
5
+ const exactProvider = readOption(list, '--exact-provider', null);
6
+ const providerBlockers = exactProvider && !isValidOpenRouterProviderSlug(exactProvider)
7
+ ? [`invalid_openrouter_provider_slug:${exactProvider}`]
8
+ : [];
9
+ const base = list.includes('--xhigh')
10
+ ? profileFromConst('xhigh')
11
+ : list.includes('--strict')
12
+ ? profileFromConst('strict')
13
+ : list.includes('--deep')
14
+ ? profileFromConst('deep')
15
+ : profileFromConst('speed');
16
+ const provider = exactProvider && !providerBlockers.length
17
+ ? {
18
+ allow_fallbacks: false,
19
+ require_parameters: base.provider.require_parameters,
20
+ order: [exactProvider]
21
+ }
22
+ : list.includes('--ttft')
23
+ ? {
24
+ ...base.provider,
25
+ sort: 'latency',
26
+ preferred_max_latency: { p50: 1.5, p90: 4 }
27
+ }
28
+ : base.provider;
29
+ return {
30
+ ...base,
31
+ provider,
32
+ blockers: providerBlockers
33
+ };
34
+ }
35
+ export function profileFromConst(name) {
36
+ if (name === 'deep') {
37
+ return {
38
+ name,
39
+ mode: GLM_DEEP_MODE,
40
+ stream: GLM_DEEP_PROFILE.stream,
41
+ max_tokens: GLM_DEEP_PROFILE.max_tokens,
42
+ temperature: GLM_DEEP_PROFILE.temperature,
43
+ top_p: GLM_DEEP_PROFILE.top_p,
44
+ tool_choice: GLM_DEEP_PROFILE.tool_choice,
45
+ parallel_tool_calls: GLM_DEEP_PROFILE.parallel_tool_calls,
46
+ provider: GLM_DEEP_PROFILE.provider,
47
+ reasoning_effort: GLM_DEEP_PROFILE.reasoning_effort,
48
+ blockers: []
49
+ };
50
+ }
51
+ if (name === 'xhigh') {
52
+ return {
53
+ ...profileFromConst('deep'),
54
+ name,
55
+ mode: GLM_XHIGH_MODE,
56
+ max_tokens: GLM_XHIGH_PROFILE.max_tokens,
57
+ reasoning_effort: GLM_XHIGH_PROFILE.reasoning_effort,
58
+ blockers: []
59
+ };
60
+ }
61
+ if (name === 'strict') {
62
+ return {
63
+ ...profileFromConst('deep'),
64
+ name,
65
+ mode: GLM_STRICT_MODE,
66
+ response_format: {
67
+ type: 'json_schema',
68
+ json_schema: {
69
+ name: 'sks_glm_strict_proof',
70
+ strict: true,
71
+ schema: {
72
+ type: 'object',
73
+ additionalProperties: false,
74
+ properties: {
75
+ summary: { type: 'string' },
76
+ patch: { type: 'string' },
77
+ proof: { type: 'object' }
78
+ },
79
+ required: ['summary', 'patch', 'proof']
80
+ }
81
+ }
82
+ },
83
+ blockers: []
84
+ };
85
+ }
86
+ return {
87
+ name,
88
+ mode: GLM_SPEED_MODE,
89
+ stream: GLM_SPEED_PROFILE.stream,
90
+ max_tokens: GLM_SPEED_PROFILE.max_tokens,
91
+ temperature: GLM_SPEED_PROFILE.temperature,
92
+ top_p: GLM_SPEED_PROFILE.top_p,
93
+ tool_choice: GLM_SPEED_PROFILE.tool_choice,
94
+ parallel_tool_calls: GLM_SPEED_PROFILE.parallel_tool_calls,
95
+ provider: GLM_SPEED_PROFILE.provider,
96
+ reasoning_effort: GLM_SPEED_PROFILE.reasoning_effort,
97
+ stop: ['</sks_patch>'],
98
+ blockers: []
99
+ };
100
+ }
101
+ export function isValidOpenRouterProviderSlug(value) {
102
+ return /^(?!.*(?:^|\/)\.\.?(?:\/|$))[a-z0-9][a-z0-9._-]{0,63}(?:\/[a-z0-9][a-z0-9._-]{0,63}){0,3}$/i.test(value);
103
+ }
104
+ //# sourceMappingURL=glm-profile-resolver.js.map
@@ -0,0 +1,15 @@
1
+ const FAST_REASONING_ORDER = ['none', 'minimal', 'low'];
2
+ export function buildFastReasoningConfig(meta = null) {
3
+ if (meta?.mandatory === true)
4
+ return { exclude: true };
5
+ const supported = new Set(meta?.supported_efforts || []);
6
+ for (const effort of FAST_REASONING_ORDER) {
7
+ if (supported.has(effort))
8
+ return { effort, exclude: true };
9
+ }
10
+ return { exclude: true };
11
+ }
12
+ export function buildDeepReasoningConfig(effort) {
13
+ return { effort, exclude: true };
14
+ }
15
+ //# sourceMappingURL=glm-reasoning-policy.js.map