sneakoscope 4.0.11 → 4.0.13
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 +7 -7
- 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/commands/glm-command.js +11 -5
- package/dist/core/fsx.js +1 -1
- package/dist/core/providers/glm/bench/glm-bench-comparison.js +48 -0
- package/dist/core/providers/glm/bench/glm-bench-fixture.js +65 -0
- package/dist/core/providers/glm/bench/glm-bench-model-lock-proof.js +24 -0
- package/dist/core/providers/glm/bench/glm-bench-report.js +75 -0
- package/dist/core/providers/glm/bench/glm-benchmark-runner.js +219 -0
- package/dist/core/providers/glm/bench/glm-benchmark-types.js +2 -0
- package/dist/core/providers/glm/bench/glm-direct-bench-runner.js +73 -0
- package/dist/core/providers/glm/naruto/glm-naruto-apply-transaction.js +54 -8
- package/dist/core/providers/glm/naruto/glm-naruto-bench.js +4 -118
- package/dist/core/providers/glm/naruto/glm-naruto-command.js +20 -3
- package/dist/core/providers/glm/naruto/glm-naruto-final-seal.js +75 -0
- package/dist/core/providers/glm/naruto/glm-naruto-orchestrator.js +41 -5
- package/dist/core/providers/glm/naruto/glm-naruto-targeted-checks.js +76 -0
- package/dist/core/providers/glm/naruto/glm-naruto-trace.js +50 -0
- package/dist/core/providers/glm/naruto/glm-naruto-worker-pool.js +61 -19
- package/dist/core/providers/glm/naruto/glm-naruto-worker-runtime.js +26 -4
- package/dist/core/providers/glm/naruto/glm-naruto-worker-scheduler.js +178 -0
- package/dist/core/providers/glm/naruto/glm-naruto-worktree-worker.js +34 -4
- package/dist/core/version.js +1 -1
- package/package.json +1 -1
- package/dist/core/providers/glm/glm-bench.js +0 -127
|
@@ -1,20 +1,18 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { writeJsonAtomic, writeTextAtomic } from '../../../fsx.js';
|
|
1
3
|
import { runPatchWorker } from './glm-naruto-worker-runtime.js';
|
|
2
4
|
import { decideConcurrency } from './glm-naruto-concurrency-governor.js';
|
|
3
|
-
import { planFileLeases } from './glm-naruto-file-lease.js';
|
|
4
5
|
import { evaluateGlmNarutoPatchCandidateGate } from './glm-naruto-patch-candidate-gate.js';
|
|
5
6
|
import { createPatchEnvelope } from './glm-naruto-patch-envelope.js';
|
|
6
7
|
import { writeGlmNarutoWorkerArtifacts } from './glm-naruto-worker-artifacts.js';
|
|
7
8
|
import { materializePatchViaWorktree } from './glm-naruto-worktree-worker.js';
|
|
9
|
+
import { createProviderHealthTracker } from '../../openrouter/openrouter-provider-health.js';
|
|
10
|
+
import { runGlmNarutoWorkerScheduler } from './glm-naruto-worker-scheduler.js';
|
|
8
11
|
export async function runPatchWorkerPool(input) {
|
|
9
12
|
const envelopes = [];
|
|
10
13
|
const traces = [];
|
|
11
14
|
const failedShardIds = [];
|
|
12
15
|
const concurrencyDecisions = [];
|
|
13
|
-
const shardPathMap = new Map();
|
|
14
|
-
for (const shard of input.shards) {
|
|
15
|
-
shardPathMap.set(shard.id, shard.target_paths);
|
|
16
|
-
}
|
|
17
|
-
const leases = planFileLeases(shardPathMap);
|
|
18
16
|
const mutableShards = input.shards.filter((s) => s.mutable);
|
|
19
17
|
const decision = decideConcurrency({
|
|
20
18
|
requestedClones: input.maxWorkers,
|
|
@@ -24,26 +22,38 @@ export async function runPatchWorkerPool(input) {
|
|
|
24
22
|
failureRate: 0,
|
|
25
23
|
operatorMax: input.maxWorkers
|
|
26
24
|
});
|
|
27
|
-
|
|
28
|
-
const workerTasks = [];
|
|
25
|
+
const jobs = [];
|
|
29
26
|
let workerIdx = 0;
|
|
30
27
|
for (const shard of mutableShards) {
|
|
31
28
|
const strategies = input.strategies.get(shard.id) || [shard.strategy];
|
|
32
29
|
for (const strategy of strategies) {
|
|
33
30
|
const workerId = `worker-${shard.id}-${strategy}-${workerIdx++}`;
|
|
34
31
|
const shardWithStrategy = { ...shard, strategy };
|
|
35
|
-
|
|
36
|
-
apiKey: input.apiKey,
|
|
37
|
-
missionId: input.missionId,
|
|
38
|
-
workerId,
|
|
39
|
-
root: input.cwd,
|
|
40
|
-
shard: shardWithStrategy,
|
|
41
|
-
contextSummary: input.contextSummary,
|
|
42
|
-
timeoutMs: input.workerTimeoutMs
|
|
43
|
-
}));
|
|
32
|
+
jobs.push({ worker_id: workerId, shard: shardWithStrategy, strategy });
|
|
44
33
|
}
|
|
45
34
|
}
|
|
46
|
-
const
|
|
35
|
+
const health = input.health ?? createProviderHealthTracker();
|
|
36
|
+
const schedulerResult = await runGlmNarutoWorkerScheduler({
|
|
37
|
+
jobs,
|
|
38
|
+
initial_active_workers: decision.target_active_workers,
|
|
39
|
+
max_active_workers: input.maxWorkers,
|
|
40
|
+
worker_timeout_ms: input.workerTimeoutMs,
|
|
41
|
+
health,
|
|
42
|
+
onDecision: (nextDecision) => {
|
|
43
|
+
concurrencyDecisions.push(nextDecision);
|
|
44
|
+
},
|
|
45
|
+
runJob: (job) => runPatchWorker({
|
|
46
|
+
apiKey: input.apiKey,
|
|
47
|
+
missionId: input.missionId,
|
|
48
|
+
workerId: job.worker_id,
|
|
49
|
+
root: input.cwd,
|
|
50
|
+
shard: job.shard,
|
|
51
|
+
contextSummary: input.contextSummary,
|
|
52
|
+
timeoutMs: input.workerTimeoutMs
|
|
53
|
+
})
|
|
54
|
+
});
|
|
55
|
+
await writeSchedulerArtifacts(input.cwd, input.missionId, schedulerResult).catch(() => undefined);
|
|
56
|
+
const results = schedulerResult.results;
|
|
47
57
|
for (const result of results) {
|
|
48
58
|
if (result.status === 'fulfilled' && result.value.ok && result.value.envelope) {
|
|
49
59
|
const isolationMode = input.isolationMode ?? 'patch-envelope-only';
|
|
@@ -65,6 +75,9 @@ export async function runPatchWorkerPool(input) {
|
|
|
65
75
|
worktree_path: worktree.lease?.path ?? null,
|
|
66
76
|
branch: worktree.lease?.branch ?? null,
|
|
67
77
|
base_commit: worktree.lease?.base_commit ?? input.baseCommit ?? null,
|
|
78
|
+
candidate_body_sha256: worktree.worktree?.candidate_body_sha256 ?? null,
|
|
79
|
+
extracted_patch_sha256: worktree.worktree?.extracted_patch_sha256 ?? null,
|
|
80
|
+
applied_patch_was_extracted: worktree.worktree?.applied_patch_was_extracted ?? false,
|
|
68
81
|
blockers: worktree.blockers
|
|
69
82
|
};
|
|
70
83
|
if (!worktree.ok) {
|
|
@@ -143,6 +156,35 @@ export async function runPatchWorkerPool(input) {
|
|
|
143
156
|
failedShardIds.push('unknown');
|
|
144
157
|
}
|
|
145
158
|
}
|
|
146
|
-
return {
|
|
159
|
+
return {
|
|
160
|
+
envelopes,
|
|
161
|
+
traces,
|
|
162
|
+
failedShardIds,
|
|
163
|
+
concurrencyDecisions,
|
|
164
|
+
schedulerSummary: {
|
|
165
|
+
max_observed_active_workers: schedulerResult.max_observed_active_workers,
|
|
166
|
+
backpressure_events: schedulerResult.backpressure_events,
|
|
167
|
+
queue_drained: true
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
async function writeSchedulerArtifacts(root, missionId, schedulerResult) {
|
|
172
|
+
const dir = path.join(root, '.sneakoscope', 'glm-naruto', missionId);
|
|
173
|
+
await writeTextAtomic(path.join(dir, 'scheduler-decisions.jsonl'), schedulerResult.decisions.map((decision) => JSON.stringify(decision)).join('\n') + (schedulerResult.decisions.length ? '\n' : ''));
|
|
174
|
+
await writeJsonAtomic(path.join(dir, 'scheduler-summary.json'), {
|
|
175
|
+
schema: 'sks.glm-naruto-scheduler-summary.v1',
|
|
176
|
+
max_observed_active_workers: schedulerResult.max_observed_active_workers,
|
|
177
|
+
backpressure_events: schedulerResult.backpressure_events,
|
|
178
|
+
queue_drained: true,
|
|
179
|
+
result_count: schedulerResult.results.length,
|
|
180
|
+
decision_count: schedulerResult.decisions.length,
|
|
181
|
+
retry_count: schedulerResult.retry_events.length
|
|
182
|
+
});
|
|
183
|
+
if (schedulerResult.backpressure_records.length > 0) {
|
|
184
|
+
await writeTextAtomic(path.join(dir, 'provider-backpressure.jsonl'), schedulerResult.backpressure_records.map((row) => JSON.stringify(row)).join('\n') + '\n');
|
|
185
|
+
}
|
|
186
|
+
if (schedulerResult.retry_events.length > 0) {
|
|
187
|
+
await writeTextAtomic(path.join(dir, 'worker-retries.jsonl'), schedulerResult.retry_events.map((row) => JSON.stringify(row)).join('\n') + '\n');
|
|
188
|
+
}
|
|
147
189
|
}
|
|
148
190
|
//# sourceMappingURL=glm-naruto-worker-pool.js.map
|
|
@@ -94,6 +94,7 @@ export async function runPatchWorker(input) {
|
|
|
94
94
|
...(input.fetchImpl ? { fetchImpl: input.fetchImpl } : {})
|
|
95
95
|
});
|
|
96
96
|
if (!response.ok) {
|
|
97
|
+
const issue = classifyWorkerIssue(response.error);
|
|
97
98
|
const trace = { ...traceBase, total_ms: Date.now() - started, status: 'failed', chunk_count: 0, real_stream: false };
|
|
98
99
|
await writeGlmNarutoWorkerArtifacts({
|
|
99
100
|
root: artifactRoot,
|
|
@@ -107,7 +108,8 @@ export async function runPatchWorker(input) {
|
|
|
107
108
|
envelope: null,
|
|
108
109
|
trace,
|
|
109
110
|
ok: false,
|
|
110
|
-
error: response.error.code
|
|
111
|
+
error: response.error.code,
|
|
112
|
+
issue
|
|
111
113
|
};
|
|
112
114
|
}
|
|
113
115
|
const modelGuard = assertGlm52ActualModel(response.value.model);
|
|
@@ -126,7 +128,8 @@ export async function runPatchWorker(input) {
|
|
|
126
128
|
envelope: null,
|
|
127
129
|
trace,
|
|
128
130
|
ok: false,
|
|
129
|
-
error: `model_guard:${modelGuard.code}
|
|
131
|
+
error: `model_guard:${modelGuard.code}`,
|
|
132
|
+
issue: { code: `model_guard:${modelGuard.code}`, retryable: false }
|
|
130
133
|
};
|
|
131
134
|
}
|
|
132
135
|
const parsed = parsePatchCandidateOutput(response.value.content);
|
|
@@ -153,7 +156,8 @@ export async function runPatchWorker(input) {
|
|
|
153
156
|
envelope: null,
|
|
154
157
|
trace,
|
|
155
158
|
ok: false,
|
|
156
|
-
error: parsed.kind
|
|
159
|
+
error: parsed.kind,
|
|
160
|
+
issue: { code: parsed.kind, retryable: false }
|
|
157
161
|
};
|
|
158
162
|
}
|
|
159
163
|
const envelope = createPatchEnvelope({
|
|
@@ -196,6 +200,7 @@ export async function runPatchWorker(input) {
|
|
|
196
200
|
return { envelope, trace, ok: true };
|
|
197
201
|
}
|
|
198
202
|
catch (err) {
|
|
203
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
199
204
|
const trace = { ...traceBase, total_ms: Date.now() - started, status: 'failed', chunk_count: 0, real_stream: false };
|
|
200
205
|
await writeGlmNarutoWorkerArtifacts({
|
|
201
206
|
root: artifactRoot,
|
|
@@ -209,10 +214,27 @@ export async function runPatchWorker(input) {
|
|
|
209
214
|
envelope: null,
|
|
210
215
|
trace,
|
|
211
216
|
ok: false,
|
|
212
|
-
error:
|
|
217
|
+
error: message,
|
|
218
|
+
issue: classifyWorkerIssue({ code: message, message, severity: 'failed' })
|
|
213
219
|
};
|
|
214
220
|
}
|
|
215
221
|
}
|
|
222
|
+
function classifyWorkerIssue(issue) {
|
|
223
|
+
const code = String(issue.code || 'glm_worker_failed');
|
|
224
|
+
const status = typeof issue.status === 'number' ? issue.status : undefined;
|
|
225
|
+
const retryable = code === 'glm_openrouter_rate_limited'
|
|
226
|
+
|| status === 429
|
|
227
|
+
|| (typeof status === 'number' && status >= 500)
|
|
228
|
+
|| code === 'glm_openrouter_provider_unavailable'
|
|
229
|
+
|| code === 'glm_stream_idle_timeout'
|
|
230
|
+
|| code === 'glm_request_timeout';
|
|
231
|
+
return {
|
|
232
|
+
code,
|
|
233
|
+
retryable,
|
|
234
|
+
...(status !== undefined ? { provider_status: status } : {}),
|
|
235
|
+
retry_after_ms: null
|
|
236
|
+
};
|
|
237
|
+
}
|
|
216
238
|
export async function runVerifierWorker(input) {
|
|
217
239
|
const started = Date.now();
|
|
218
240
|
const sessionId = normalizeGlmNarutoSessionId(`sks-glm-naruto-verify-${input.missionId}-${input.workerId}`);
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { nowIso } from '../../../fsx.js';
|
|
2
|
+
import { decideConcurrency } from './glm-naruto-concurrency-governor.js';
|
|
3
|
+
export async function runGlmNarutoWorkerScheduler(input) {
|
|
4
|
+
const queue = input.jobs.map((job) => ({ job, attempt: 0 }));
|
|
5
|
+
const running = new Map();
|
|
6
|
+
const results = [];
|
|
7
|
+
const decisions = [];
|
|
8
|
+
const retryEvents = [];
|
|
9
|
+
const backpressureRecords = [];
|
|
10
|
+
const maxActive = Math.max(1, input.max_active_workers);
|
|
11
|
+
let targetActive = Math.max(1, Math.min(maxActive, input.initial_active_workers || 1));
|
|
12
|
+
let nextRunKey = 0;
|
|
13
|
+
let maxObservedActive = 0;
|
|
14
|
+
let backpressureEvents = 0;
|
|
15
|
+
let failureCount = 0;
|
|
16
|
+
let finishedCount = 0;
|
|
17
|
+
let pauseUntilMs = 0;
|
|
18
|
+
await recordDecision('initial');
|
|
19
|
+
while (queue.length > 0 || running.size > 0) {
|
|
20
|
+
const now = Date.now();
|
|
21
|
+
if (pauseUntilMs > now && running.size === 0) {
|
|
22
|
+
await sleep(Math.min(1_000, pauseUntilMs - now));
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
while (queue.length > 0 && running.size < targetActive && Date.now() >= pauseUntilMs) {
|
|
26
|
+
const entry = queue.shift();
|
|
27
|
+
const key = nextRunKey++;
|
|
28
|
+
running.set(key, runTimedJob(key, entry, input));
|
|
29
|
+
maxObservedActive = Math.max(maxObservedActive, running.size);
|
|
30
|
+
}
|
|
31
|
+
if (running.size === 0) {
|
|
32
|
+
if (queue.length > 0) {
|
|
33
|
+
targetActive = Math.max(1, targetActive);
|
|
34
|
+
pauseUntilMs = Math.min(pauseUntilMs || Date.now(), Date.now());
|
|
35
|
+
}
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const completed = await Promise.race([...running.values()]);
|
|
39
|
+
running.delete(completed.key);
|
|
40
|
+
finishedCount++;
|
|
41
|
+
const issue = issueFromSettled(completed.settled);
|
|
42
|
+
if (completed.settled.status === 'rejected' || (completed.settled.status === 'fulfilled' && !completed.settled.value.ok)) {
|
|
43
|
+
failureCount++;
|
|
44
|
+
}
|
|
45
|
+
updateProviderHealth(input.health, completed.settled);
|
|
46
|
+
if (issue && shouldBackoff(issue)) {
|
|
47
|
+
backpressureEvents++;
|
|
48
|
+
const pauseMs = backoffMs(issue);
|
|
49
|
+
pauseUntilMs = Math.max(pauseUntilMs, Date.now() + pauseMs);
|
|
50
|
+
backpressureRecords.push({
|
|
51
|
+
schema: 'sks.glm-naruto-provider-backpressure.v1',
|
|
52
|
+
created_at: nowIso(),
|
|
53
|
+
worker_id: completed.entry.job.worker_id,
|
|
54
|
+
attempt: completed.entry.attempt,
|
|
55
|
+
code: issue.code,
|
|
56
|
+
provider_status: issue.provider_status ?? null,
|
|
57
|
+
retry_after_ms: issue.retry_after_ms ?? null,
|
|
58
|
+
pause_ms: pauseMs
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
if (shouldRetry(completed.entry, completed.settled, issue)) {
|
|
62
|
+
const retryEntry = { job: completed.entry.job, attempt: completed.entry.attempt + 1 };
|
|
63
|
+
retryEvents.push({
|
|
64
|
+
schema: 'sks.glm-naruto-worker-retry.v1',
|
|
65
|
+
created_at: nowIso(),
|
|
66
|
+
worker_id: completed.entry.job.worker_id,
|
|
67
|
+
shard_id: completed.entry.job.shard.id,
|
|
68
|
+
next_attempt: retryEntry.attempt,
|
|
69
|
+
code: issue?.code ?? 'worker_scheduler_rejected'
|
|
70
|
+
});
|
|
71
|
+
queue.push(retryEntry);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
results.push(completed.settled);
|
|
75
|
+
}
|
|
76
|
+
await recordDecision(issue?.code ?? 'worker_finished');
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
results,
|
|
80
|
+
decisions,
|
|
81
|
+
max_observed_active_workers: maxObservedActive,
|
|
82
|
+
backpressure_events: backpressureEvents,
|
|
83
|
+
retry_events: retryEvents,
|
|
84
|
+
backpressure_records: backpressureRecords
|
|
85
|
+
};
|
|
86
|
+
async function recordDecision(reasonSuffix) {
|
|
87
|
+
const health = input.health.getHealth();
|
|
88
|
+
const decision = decideConcurrency({
|
|
89
|
+
requestedClones: maxActive,
|
|
90
|
+
activeWorkers: targetActive,
|
|
91
|
+
rateLimited429: health?.count_429 ?? 0,
|
|
92
|
+
ttftP90Ms: health?.p90_ttft_ms ?? 0,
|
|
93
|
+
failureRate: finishedCount ? failureCount / finishedCount : 0,
|
|
94
|
+
operatorMax: maxActive
|
|
95
|
+
});
|
|
96
|
+
targetActive = Math.max(running.size > 0 ? 1 : 0, Math.min(maxActive, decision.target_active_workers));
|
|
97
|
+
if (targetActive === 0 && queue.length > 0 && running.size === 0)
|
|
98
|
+
targetActive = 1;
|
|
99
|
+
const recorded = { ...decision, reason: `${decision.reason}:${reasonSuffix}` };
|
|
100
|
+
decisions.push(recorded);
|
|
101
|
+
if (recorded.backpressure)
|
|
102
|
+
backpressureEvents++;
|
|
103
|
+
await input.onDecision(recorded);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async function runTimedJob(key, entry, input) {
|
|
107
|
+
try {
|
|
108
|
+
const value = await withTimeout(input.runJob(entry.job), input.worker_timeout_ms);
|
|
109
|
+
return { key, entry, settled: { status: 'fulfilled', value } };
|
|
110
|
+
}
|
|
111
|
+
catch (reason) {
|
|
112
|
+
return { key, entry, settled: { status: 'rejected', reason } };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function updateProviderHealth(health, settled) {
|
|
116
|
+
if (settled.status !== 'fulfilled') {
|
|
117
|
+
health.record({ provider_slug: 'openrouter', model: 'z-ai/glm-5.2', count_5xx: 1, last_failure: nowIso() });
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const issue = settled.value.issue;
|
|
121
|
+
const trace = settled.value.trace;
|
|
122
|
+
health.record({
|
|
123
|
+
provider_slug: trace.provider_slug || 'openrouter',
|
|
124
|
+
model: trace.model,
|
|
125
|
+
...(trace.ttft_ms !== null ? { p50_ttft_ms: trace.ttft_ms } : {}),
|
|
126
|
+
...(issue?.provider_status === 429 || issue?.code === 'glm_openrouter_rate_limited' ? { count_429: 1 } : {}),
|
|
127
|
+
...(typeof issue?.provider_status === 'number' && issue.provider_status >= 500 ? { count_5xx: 1 } : {}),
|
|
128
|
+
last_success: settled.value.ok ? nowIso() : null,
|
|
129
|
+
last_failure: settled.value.ok ? null : nowIso()
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
function issueFromSettled(settled) {
|
|
133
|
+
if (settled.status === 'rejected') {
|
|
134
|
+
return { code: 'worker_scheduler_rejected', retryable: true, retry_after_ms: null };
|
|
135
|
+
}
|
|
136
|
+
return settled.value.issue ?? null;
|
|
137
|
+
}
|
|
138
|
+
function shouldRetry(entry, settled, issue) {
|
|
139
|
+
if (entry.attempt >= 1)
|
|
140
|
+
return false;
|
|
141
|
+
if (settled.status === 'rejected')
|
|
142
|
+
return true;
|
|
143
|
+
return settled.value.ok === false && issue?.retryable === true;
|
|
144
|
+
}
|
|
145
|
+
function shouldBackoff(issue) {
|
|
146
|
+
return issue.provider_status === 429
|
|
147
|
+
|| issue.code === 'glm_openrouter_rate_limited'
|
|
148
|
+
|| (typeof issue.provider_status === 'number' && issue.provider_status >= 500)
|
|
149
|
+
|| issue.code === 'glm_openrouter_provider_unavailable'
|
|
150
|
+
|| issue.code === 'glm_stream_idle_timeout'
|
|
151
|
+
|| issue.code === 'glm_request_timeout';
|
|
152
|
+
}
|
|
153
|
+
function backoffMs(issue) {
|
|
154
|
+
if (typeof issue.retry_after_ms === 'number' && Number.isFinite(issue.retry_after_ms) && issue.retry_after_ms > 0) {
|
|
155
|
+
return Math.min(30_000, issue.retry_after_ms);
|
|
156
|
+
}
|
|
157
|
+
if (issue.provider_status === 429 || issue.code === 'glm_openrouter_rate_limited')
|
|
158
|
+
return 1_000;
|
|
159
|
+
return 250;
|
|
160
|
+
}
|
|
161
|
+
function withTimeout(promise, timeoutMs) {
|
|
162
|
+
if (!timeoutMs || timeoutMs <= 0)
|
|
163
|
+
return promise;
|
|
164
|
+
let timer;
|
|
165
|
+
return Promise.race([
|
|
166
|
+
promise,
|
|
167
|
+
new Promise((_, reject) => {
|
|
168
|
+
timer = setTimeout(() => reject(new Error('worker_scheduler_timeout')), timeoutMs);
|
|
169
|
+
})
|
|
170
|
+
]).finally(() => {
|
|
171
|
+
if (timer)
|
|
172
|
+
clearTimeout(timer);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
function sleep(ms) {
|
|
176
|
+
return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=glm-naruto-worker-scheduler.js.map
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { createPatchEnvelope } from './glm-naruto-patch-envelope.js';
|
|
2
|
+
import { sha256 } from '../../../fsx.js';
|
|
3
|
+
import { parseGlmNarutoPatchCandidate } from './glm-naruto-patch-candidate-parser.js';
|
|
2
4
|
import { applyPatchInWorktree, createGlmNarutoWorkerWorktree, diffWorktree } from './glm-naruto-worktree-manager.js';
|
|
3
5
|
import { cleanupGlmNarutoWorktree } from './glm-naruto-worktree-cleanup.js';
|
|
4
6
|
export async function materializePatchViaWorktree(input) {
|
|
@@ -10,10 +12,32 @@ export async function materializePatchViaWorktree(input) {
|
|
|
10
12
|
workerId: input.envelope.worker_id,
|
|
11
13
|
...(input.baseCommit !== undefined ? { baseCommit: input.baseCommit } : {})
|
|
12
14
|
});
|
|
13
|
-
const
|
|
15
|
+
const parsed = parseGlmNarutoPatchCandidate(input.envelope.patch);
|
|
16
|
+
const parseProof = {
|
|
17
|
+
candidate_body_sha256: sha256(input.envelope.patch),
|
|
18
|
+
extracted_patch_sha256: parsed.ok ? sha256(parsed.patch) : null,
|
|
19
|
+
applied_patch_was_extracted: false
|
|
20
|
+
};
|
|
21
|
+
if (!parsed.ok) {
|
|
22
|
+
await cleanupGlmNarutoWorktree({ repoRoot: input.repoRoot, missionId: input.missionId, lease, cleanup: input.cleanup });
|
|
23
|
+
return {
|
|
24
|
+
ok: false,
|
|
25
|
+
envelope: { ...input.envelope, status: 'gate_failed', blockers: parsed.blockers },
|
|
26
|
+
lease,
|
|
27
|
+
blockers: parsed.blockers,
|
|
28
|
+
worktree: parseProof
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const applied = await applyPatchInWorktree(lease.path, parsed.patch);
|
|
14
32
|
if (!applied.ok) {
|
|
15
33
|
await cleanupGlmNarutoWorktree({ repoRoot: input.repoRoot, missionId: input.missionId, lease, cleanup: input.cleanup });
|
|
16
|
-
return {
|
|
34
|
+
return {
|
|
35
|
+
ok: false,
|
|
36
|
+
envelope: { ...input.envelope, status: 'gate_failed', blockers: ['worktree_patch_apply_failed'] },
|
|
37
|
+
lease,
|
|
38
|
+
blockers: ['worktree_patch_apply_failed'],
|
|
39
|
+
worktree: { ...parseProof, applied_patch_was_extracted: true }
|
|
40
|
+
};
|
|
17
41
|
}
|
|
18
42
|
const diff = await diffWorktree(lease.path);
|
|
19
43
|
const envelope = createPatchEnvelope({
|
|
@@ -21,14 +45,20 @@ export async function materializePatchViaWorktree(input) {
|
|
|
21
45
|
workerId: input.envelope.worker_id,
|
|
22
46
|
shardId: input.envelope.shard_id,
|
|
23
47
|
baseDigest: input.envelope.base_digest,
|
|
24
|
-
patch: diff,
|
|
48
|
+
patch: diff || parsed.patch,
|
|
25
49
|
strategy: input.envelope.strategy,
|
|
26
50
|
reasoningEffort: input.envelope.reasoning_effort,
|
|
27
51
|
status: input.envelope.status,
|
|
28
52
|
warnings: [...input.envelope.warnings, `worktree:${lease.path}`]
|
|
29
53
|
});
|
|
30
54
|
await cleanupGlmNarutoWorktree({ repoRoot: input.repoRoot, missionId: input.missionId, lease, cleanup: input.cleanup });
|
|
31
|
-
return {
|
|
55
|
+
return {
|
|
56
|
+
ok: true,
|
|
57
|
+
envelope,
|
|
58
|
+
lease,
|
|
59
|
+
blockers: [],
|
|
60
|
+
worktree: { ...parseProof, applied_patch_was_extracted: true }
|
|
61
|
+
};
|
|
32
62
|
}
|
|
33
63
|
catch (err) {
|
|
34
64
|
if (lease)
|
package/dist/core/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '4.0.
|
|
1
|
+
export const PACKAGE_VERSION = '4.0.13';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "ㅅㅋㅅ",
|
|
4
|
-
"version": "4.0.
|
|
4
|
+
"version": "4.0.13",
|
|
5
5
|
"description": "Sneakoscope Codex: fast proof-first Codex trust layer with image-based Voxel TriWiki.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
|
|
@@ -1,127 +0,0 @@
|
|
|
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.9',
|
|
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.9',
|
|
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.9',
|
|
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.9',
|
|
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
|