sneakoscope 2.0.1 → 2.0.4
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 +26 -5
- 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/.sks-build-stamp.json +4 -4
- package/dist/bin/sks.js +1 -1
- package/dist/build-manifest.json +28 -8
- package/dist/cli/command-registry.js +2 -0
- package/dist/commands/doctor.js +29 -3
- package/dist/core/agents/agent-command-surface.js +13 -3
- package/dist/core/agents/agent-orchestrator.js +92 -4
- package/dist/core/agents/agent-output-validator.js +2 -1
- package/dist/core/agents/agent-patch-proof.js +5 -0
- package/dist/core/agents/agent-patch-schema.js +2 -1
- package/dist/core/agents/agent-proof-evidence.js +26 -0
- package/dist/core/agents/agent-roster.js +1 -1
- package/dist/core/agents/agent-runner-ollama.js +411 -0
- package/dist/core/agents/agent-schema.js +1 -1
- package/dist/core/agents/intelligent-work-graph.js +45 -3
- package/dist/core/agents/native-cli-session-swarm.js +8 -1
- package/dist/core/agents/native-cli-worker.js +1 -1
- package/dist/core/agents/native-worker-backend-router.js +44 -2
- package/dist/core/agents/ollama-worker-config.js +118 -0
- package/dist/core/auto-review.js +39 -6
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +42 -3
- package/dist/core/codex-control/codex-fake-sdk-adapter.js +20 -0
- package/dist/core/codex-control/codex-output-schemas.js +5 -1
- package/dist/core/codex-control/gpt-final-arbiter.js +160 -0
- package/dist/core/codex-control/gpt-final-context-compressor.js +17 -0
- package/dist/core/codex-control/gpt-final-proof-pack.js +120 -0
- package/dist/core/codex-control/gpt-final-review-schema.js +71 -0
- package/dist/core/commands/basic-cli.js +36 -1
- package/dist/core/commands/local-model-command.js +120 -0
- package/dist/core/commands/mad-sks-command.js +58 -9
- package/dist/core/commands/naruto-command.js +77 -5
- package/dist/core/commands/run-command.js +33 -1
- package/dist/core/commands/team-command.js +31 -2
- package/dist/core/doctor/doctor-readiness-matrix.js +19 -0
- package/dist/core/feature-fixtures.js +5 -0
- package/dist/core/fsx.js +1 -1
- package/dist/core/git-simple.js +143 -4
- package/dist/core/hooks-runtime.js +1 -1
- package/dist/core/init.js +2 -0
- package/dist/core/local-llm/local-collaboration-policy.js +93 -0
- package/dist/core/local-llm/local-llm-config.js +15 -0
- package/dist/core/pipeline/final-gpt-patch-stage.js +31 -0
- package/dist/core/pipeline/final-gpt-review-stage.js +5 -0
- package/dist/core/provider/provider-context.js +72 -9
- package/dist/core/retention.js +11 -0
- package/dist/core/routes.js +21 -1
- package/dist/core/safety/mutation-guard.js +2 -0
- package/dist/core/team-live.js +7 -1
- package/dist/core/update-check.js +215 -25
- package/dist/core/verification/verification-worker-pool.js +12 -0
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-worker-pane-manager.js +19 -2
- package/dist/scripts/agent-ast-aware-work-graph-check.js +1 -1
- package/dist/scripts/codex-sdk-team-naruto-agent-pipeline-check.js +2 -1
- package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +12 -2
- package/dist/scripts/gpt-final-arbiter-check.js +63 -0
- package/dist/scripts/gpt-final-arbiter-performance-check.js +36 -0
- package/dist/scripts/local-collab-gpt-final-availability-check.js +58 -0
- package/dist/scripts/local-collab-no-local-only-final-check.js +27 -0
- package/dist/scripts/local-collab-policy-check.js +17 -0
- package/dist/scripts/mad-sks-app-ui-no-mutation-check.js +92 -0
- package/dist/scripts/mad-sks-zellij-default-pane-worker-check.js +37 -0
- package/dist/scripts/mad-sks-zellij-launch-check.js +2 -1
- package/dist/scripts/provider-context-config-toml-check.js +63 -0
- package/dist/scripts/release-gate-existence-audit.js +4 -0
- package/dist/scripts/runtime-no-mjs-scripts-check.js +3 -2
- package/dist/scripts/zellij-worker-pane-manager-check.js +3 -0
- package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +39 -0
- package/package.json +13 -4
- package/schemas/local-llm/local-collaboration-policy.schema.json +57 -0
|
@@ -8,6 +8,7 @@ import { assertAgentSessionGenerationsClosed } from './agent-session-generation.
|
|
|
8
8
|
import { readZellijLaneSupervisor } from './zellij-lane-supervisor.js';
|
|
9
9
|
import { writeFakeRealProofPolicyReport } from '../proof/fake-real-proof-policy.js';
|
|
10
10
|
import { buildRuntimeTruthMatrix, writeRuntimeTruthMatrix } from '../proof/runtime-truth-matrix.js';
|
|
11
|
+
import { evaluateLocalCollaborationFinalGate, localCollaborationParticipated, resolveLocalCollaborationPolicy } from '../local-llm/local-collaboration-policy.js';
|
|
11
12
|
export async function writeAgentProofEvidence(root, input) {
|
|
12
13
|
const lifecycle = await assertAllAgentSessionsClosed(root);
|
|
13
14
|
const terminal = await assertAgentTerminalSessionsClosed(root);
|
|
@@ -28,6 +29,18 @@ export async function writeAgentProofEvidence(root, input) {
|
|
|
28
29
|
const patchRollbackProof = await readJson(path.join(root, 'agent-patch-rollback-proof.json'), null);
|
|
29
30
|
const patchProof = await readJson(path.join(root, 'agent-patch-proof.json'), null);
|
|
30
31
|
const patchSwarm = input.patchSwarm || await readJson(path.join(root, 'agent-patch-swarm-runtime.json'), null);
|
|
32
|
+
const localCollaborationPolicy = input.localCollaborationPolicy || await readJson(path.join(root, 'local-collaboration-policy.json'), null) || resolveLocalCollaborationPolicy();
|
|
33
|
+
const gptFinalArbiter = input.gptFinalArbiter || await readJson(path.join(root, 'gpt-final-arbiter', 'gpt-final-arbiter.json'), null);
|
|
34
|
+
const localParticipated = localCollaborationParticipated(input.results || []) || Number(gptFinalArbiter?.local_outputs_count || 0) > 0;
|
|
35
|
+
const finalGptPatchStage = input.finalGptPatchStage || null;
|
|
36
|
+
const localFinalGate = gptFinalArbiter?.final_gate || evaluateLocalCollaborationFinalGate({
|
|
37
|
+
policy: localCollaborationPolicy,
|
|
38
|
+
localParticipated,
|
|
39
|
+
gptFinalStatus: gptFinalArbiter?.result?.status || null,
|
|
40
|
+
gptFinalAvailable: Boolean(gptFinalArbiter),
|
|
41
|
+
gptFinalBackend: gptFinalArbiter?.backend || null,
|
|
42
|
+
applyPatches: parallelWritePolicy?.apply_patches === true
|
|
43
|
+
});
|
|
31
44
|
const nativeCliSessionProof = input.nativeCliSessionProof || await readJson(path.join(root, 'native-cli-session-proof.json'), null);
|
|
32
45
|
const noSubagentScalingPolicy = input.noSubagentScalingPolicy || await readJson(path.join(root, 'no-subagent-scaling-policy.json'), null);
|
|
33
46
|
const fastModePropagation = input.fastModePropagation || await readJson(path.join(root, 'fast-mode-propagation-proof.json'), null);
|
|
@@ -161,6 +174,9 @@ export async function writeAgentProofEvidence(root, input) {
|
|
|
161
174
|
...(patchSwarm && !patchApplyOk ? ['patch_apply_not_ok'] : []),
|
|
162
175
|
...(patchSwarm && !patchVerificationOk ? ['patch_verification_not_ok'] : []),
|
|
163
176
|
...(patchSwarm && !patchRollbackOk ? ['patch_rollback_not_ok'] : []),
|
|
177
|
+
...(localParticipated && localFinalGate.ok !== true ? localFinalGate.blockers || ['gpt_final_arbiter_gate_not_ok'] : []),
|
|
178
|
+
...(localParticipated && gptFinalArbiter?.ok !== true ? gptFinalArbiter?.blockers || ['gpt_final_arbiter_not_ok'] : []),
|
|
179
|
+
...(localParticipated && finalGptPatchStage?.ok === false ? finalGptPatchStage.blockers || ['final_gpt_patch_stage_not_ok'] : []),
|
|
164
180
|
...agentChangedFileLeaseViolations(input.results || [], input.partition?.leases || [])
|
|
165
181
|
];
|
|
166
182
|
const evidence = {
|
|
@@ -197,6 +213,15 @@ export async function writeAgentProofEvidence(root, input) {
|
|
|
197
213
|
parallel_write_apply_patches: parallelWritePolicy?.apply_patches === true,
|
|
198
214
|
parallel_write_dry_run_patches: parallelWritePolicy?.dry_run_patches === true,
|
|
199
215
|
parallel_write_max_write_agents: Number(parallelWritePolicy?.max_write_agents || 0),
|
|
216
|
+
local_collaboration_policy: 'local-collaboration-policy.json',
|
|
217
|
+
local_collaboration_mode: localCollaborationPolicy.mode || null,
|
|
218
|
+
local_collaboration_participated: localParticipated,
|
|
219
|
+
gpt_final_arbiter: gptFinalArbiter ? 'gpt-final-arbiter/gpt-final-arbiter.json' : null,
|
|
220
|
+
gpt_final_status: gptFinalArbiter?.result?.status || (localParticipated ? 'missing' : 'not_required_no_local_outputs'),
|
|
221
|
+
gpt_final_backend: gptFinalArbiter?.backend || null,
|
|
222
|
+
gpt_final_patch_source: finalGptPatchStage?.final_patch_source || (localParticipated ? 'blocked' : 'not_applicable'),
|
|
223
|
+
gpt_final_gate_ok: localFinalGate.ok === true,
|
|
224
|
+
gpt_final_gate: localFinalGate,
|
|
200
225
|
patch_swarm_runtime: patchSwarm ? 'agent-patch-swarm-runtime.json' : null,
|
|
201
226
|
patch_queue: patchSwarm ? 'agent-patch-queue.json' : null,
|
|
202
227
|
patch_queue_events: patchSwarm ? 'agent-patch-queue-events.jsonl' : null,
|
|
@@ -329,6 +354,7 @@ export async function writeAgentProofEvidence(root, input) {
|
|
|
329
354
|
'strategy-gate.json': strategyGate,
|
|
330
355
|
'agent-patch-proof.json': patchProof,
|
|
331
356
|
'agent-patch-swarm-runtime.json': patchSwarm,
|
|
357
|
+
'gpt-final-arbiter/gpt-final-arbiter.json': gptFinalArbiter,
|
|
332
358
|
'native-cli-session-proof.json': nativeCliSessionProof,
|
|
333
359
|
'no-subagent-scaling-policy.json': noSubagentScalingPolicy,
|
|
334
360
|
'fast-mode-propagation-proof.json': fastModePropagation
|
|
@@ -29,7 +29,7 @@ export function systemSafeNarutoConcurrency(opts = {}) {
|
|
|
29
29
|
const freeGb = freeBytes / (1024 * 1024 * 1024);
|
|
30
30
|
const totalGb = totalBytes / (1024 * 1024 * 1024);
|
|
31
31
|
const backend = String(opts.backend || 'codex-sdk');
|
|
32
|
-
const heavy = backend === 'codex-sdk' || backend === 'zellij' || backend === 'process';
|
|
32
|
+
const heavy = backend === 'codex-sdk' || backend === 'zellij' || backend === 'process' || backend === 'ollama';
|
|
33
33
|
const ceiling = MAX_NARUTO_AGENT_COUNT;
|
|
34
34
|
// macOS reports very low freemem while reclaimable memory is still available, so
|
|
35
35
|
// budget against a total-memory-derived floor rather than the instantaneous free.
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { nowIso, sha256, writeJsonAtomic } from '../fsx.js';
|
|
3
|
+
import { loadTriWikiRuntimeContext, triWikiContextBlock, triWikiProofRecord } from '../triwiki-runtime.js';
|
|
4
|
+
import { validateAgentWorkerResult } from './agent-worker-pipeline.js';
|
|
5
|
+
import { normalizeAgentPatchEnvelope } from './agent-patch-schema.js';
|
|
6
|
+
import { resolveOllamaWorkerConfig } from './ollama-worker-config.js';
|
|
7
|
+
export const OLLAMA_WORKER_POLICY_SCHEMA = 'sks.ollama-worker-policy.v1';
|
|
8
|
+
export const OLLAMA_WORKER_REQUEST_SCHEMA = 'sks.ollama-worker-request.v1';
|
|
9
|
+
export const OLLAMA_WORKER_RESPONSE_SCHEMA = 'sks.ollama-worker-response.v1';
|
|
10
|
+
export async function runOllamaAgent(agent, slice, opts = {}) {
|
|
11
|
+
const root = path.resolve(opts.agentRoot || opts.cwd || process.cwd());
|
|
12
|
+
const workerDirRel = String(opts.workerDirRel || agent.session_artifact_dir || path.join('sessions', String(agent.id || 'ollama-worker'), 'worker'));
|
|
13
|
+
const workerDir = path.join(root, workerDirRel);
|
|
14
|
+
const triwikiContext = await loadTriWikiRuntimeContext(root);
|
|
15
|
+
const config = await resolveOllamaWorkerConfig({
|
|
16
|
+
backend: 'ollama',
|
|
17
|
+
ollamaEnabled: opts.ollamaEnabled === true || opts.ollama_enabled === true,
|
|
18
|
+
model: opts.ollamaModel || opts.ollama_model || null,
|
|
19
|
+
baseUrl: opts.ollamaBaseUrl || opts.ollama_base_url || null,
|
|
20
|
+
keepAlive: opts.ollamaKeepAlive || opts.ollama_keep_alive || null,
|
|
21
|
+
timeoutMs: Number(opts.ollamaTimeoutMs || opts.ollama_timeout_ms || 0) || null,
|
|
22
|
+
temperature: Number(opts.ollamaTemperature || opts.ollama_temperature || 0),
|
|
23
|
+
think: typeof opts.ollamaThink === 'boolean' ? opts.ollamaThink
|
|
24
|
+
: typeof opts.ollama_think === 'boolean' ? opts.ollama_think
|
|
25
|
+
: null
|
|
26
|
+
});
|
|
27
|
+
const policy = classifyOllamaWorkerSlice(slice, { route: opts.route, agent });
|
|
28
|
+
await writeJsonAtomic(path.join(workerDir, 'ollama-worker-config.json'), config);
|
|
29
|
+
await writeJsonAtomic(path.join(workerDir, 'ollama-worker-policy.json'), policy);
|
|
30
|
+
await writeJsonAtomic(path.join(workerDir, 'ollama-triwiki-context.json'), buildOllamaTriWikiArtifact(triwikiContext));
|
|
31
|
+
if (!config.ok || !policy.ok) {
|
|
32
|
+
return validateAgentWorkerResult(blockedResult(agent, slice, opts, [...config.blockers, ...policy.blockers], [
|
|
33
|
+
path.join(workerDirRel, 'ollama-worker-config.json'),
|
|
34
|
+
path.join(workerDirRel, 'ollama-worker-policy.json'),
|
|
35
|
+
path.join(workerDirRel, 'ollama-triwiki-context.json')
|
|
36
|
+
]));
|
|
37
|
+
}
|
|
38
|
+
const requestId = `ollama:${sha256(`${nowIso()}:${agent.session_id || agent.id}:${slice?.id || ''}`).slice(0, 16)}`;
|
|
39
|
+
const request = buildOllamaGenerateRequest(agent, slice, opts, config, requestId, triwikiContext);
|
|
40
|
+
await writeJsonAtomic(path.join(workerDir, 'ollama-request.json'), {
|
|
41
|
+
schema: OLLAMA_WORKER_REQUEST_SCHEMA,
|
|
42
|
+
generated_at: nowIso(),
|
|
43
|
+
request_id: requestId,
|
|
44
|
+
endpoint: `${config.base_url}/api/generate`,
|
|
45
|
+
model: config.model,
|
|
46
|
+
keep_alive: config.keep_alive,
|
|
47
|
+
stream: false,
|
|
48
|
+
think: config.think,
|
|
49
|
+
policy: 'worker_only_no_strategy_planning_design',
|
|
50
|
+
triwiki_context: triWikiProofRecord(triwikiContext),
|
|
51
|
+
stack_current_docs_required: true,
|
|
52
|
+
prompt_sha256: sha256(request.prompt)
|
|
53
|
+
});
|
|
54
|
+
const response = await callOllamaGenerate(config, request)
|
|
55
|
+
.catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error) }));
|
|
56
|
+
const workerText = response.ok === true ? extractOllamaWorkerText(response.data) : { text: '', source: 'empty' };
|
|
57
|
+
await writeJsonAtomic(path.join(workerDir, 'ollama-response.json'), {
|
|
58
|
+
schema: OLLAMA_WORKER_RESPONSE_SCHEMA,
|
|
59
|
+
generated_at: nowIso(),
|
|
60
|
+
request_id: requestId,
|
|
61
|
+
ok: response.ok === true,
|
|
62
|
+
model: config.model,
|
|
63
|
+
response_sha256: response.ok === true ? sha256(workerText.text) : null,
|
|
64
|
+
response_source: response.ok === true ? workerText.source : null,
|
|
65
|
+
data: response.ok === true ? safeResponseData(response.data) : null,
|
|
66
|
+
error: response.ok === true ? null : response.error
|
|
67
|
+
});
|
|
68
|
+
if (response.ok !== true) {
|
|
69
|
+
return validateAgentWorkerResult(blockedResult(agent, slice, opts, ['ollama_generate_failed', String(response.error || 'unknown_error')], [
|
|
70
|
+
path.join(workerDirRel, 'ollama-triwiki-context.json'),
|
|
71
|
+
path.join(workerDirRel, 'ollama-request.json'),
|
|
72
|
+
path.join(workerDirRel, 'ollama-response.json')
|
|
73
|
+
]));
|
|
74
|
+
}
|
|
75
|
+
const parsed = parseWorkerJson(workerText.text);
|
|
76
|
+
if (!parsed.ok) {
|
|
77
|
+
return validateAgentWorkerResult(blockedResult(agent, slice, opts, ['ollama_worker_json_parse_failed'], [
|
|
78
|
+
path.join(workerDirRel, 'ollama-triwiki-context.json'),
|
|
79
|
+
path.join(workerDirRel, 'ollama-request.json'),
|
|
80
|
+
path.join(workerDirRel, 'ollama-response.json')
|
|
81
|
+
]));
|
|
82
|
+
}
|
|
83
|
+
const patchEnvelopes = normalizeOllamaPatchEnvelopes(parsed.value, agent, slice, opts, requestId);
|
|
84
|
+
const changedFiles = [...new Set(patchEnvelopes.flatMap((envelope) => envelope.operations.map((operation) => operation.path)))];
|
|
85
|
+
const writePaths = collectWritePaths(slice, opts);
|
|
86
|
+
return validateAgentWorkerResult({
|
|
87
|
+
mission_id: String(opts.missionId || opts.mission_id || ''),
|
|
88
|
+
agent_id: String(agent.id || 'ollama-worker'),
|
|
89
|
+
session_id: String(agent.session_id || ''),
|
|
90
|
+
persona_id: String(agent.persona_id || agent.id || 'ollama-worker'),
|
|
91
|
+
task_slice_id: String(slice?.id || ''),
|
|
92
|
+
status: writePaths.length > 0 && patchEnvelopes.length === 0 ? 'blocked' : 'done',
|
|
93
|
+
backend: 'ollama',
|
|
94
|
+
summary: String(parsed.value.summary || parsed.value.result || 'Ollama local worker completed.'),
|
|
95
|
+
findings: [
|
|
96
|
+
'ollama local worker executed through /api/generate',
|
|
97
|
+
'triwiki context consulted before local worker prompt',
|
|
98
|
+
...stringArray(parsed.value.findings)
|
|
99
|
+
],
|
|
100
|
+
proposed_changes: stringArray(parsed.value.proposed_changes || parsed.value.proposedChanges),
|
|
101
|
+
changed_files: changedFiles,
|
|
102
|
+
lease_compliance: { ok: true, violations: [] },
|
|
103
|
+
artifacts: [
|
|
104
|
+
path.join(workerDirRel, 'ollama-worker-config.json'),
|
|
105
|
+
path.join(workerDirRel, 'ollama-worker-policy.json'),
|
|
106
|
+
path.join(workerDirRel, 'ollama-triwiki-context.json'),
|
|
107
|
+
path.join(workerDirRel, 'ollama-request.json'),
|
|
108
|
+
path.join(workerDirRel, 'ollama-response.json')
|
|
109
|
+
],
|
|
110
|
+
blockers: writePaths.length > 0 && patchEnvelopes.length === 0 ? ['ollama_no_patch_envelopes_for_write_task'] : [],
|
|
111
|
+
confidence: 'model_authored_local',
|
|
112
|
+
handoff_notes: 'Local Ollama worker produced worker JSON; parent SKS remains responsible for merge, apply, verification, and rollback.',
|
|
113
|
+
unverified: [
|
|
114
|
+
'local_model_output_not_strategy_or_verification_authority',
|
|
115
|
+
...(triwikiContext.present ? [] : ['triwiki_context_missing_parent_should_refresh_with_context7_or_official_docs_before_relying_on_local_worker'])
|
|
116
|
+
],
|
|
117
|
+
writes: changedFiles,
|
|
118
|
+
...(patchEnvelopes.length ? { patch_envelopes: patchEnvelopes } : {}),
|
|
119
|
+
model_authored_patch_envelopes: patchEnvelopes.length > 0,
|
|
120
|
+
fixture_patch_envelopes: false,
|
|
121
|
+
source_intelligence_refs: agent.source_intelligence_refs || opts.source_intelligence_refs || null,
|
|
122
|
+
goal_mode_ref: agent.goal_mode_ref || opts.goal_mode_ref || null,
|
|
123
|
+
verification: { status: 'passed', checks: ['ollama-api-generate', 'ollama-worker-policy', 'triwiki-runtime-context', 'agent-patch-envelope-schema'] },
|
|
124
|
+
recursion_guard: { ok: true, violations: [] }
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
export function classifyOllamaWorkerSlice(slice, input = {}) {
|
|
128
|
+
const writePaths = collectWritePaths(slice, {});
|
|
129
|
+
const text = [
|
|
130
|
+
input.route,
|
|
131
|
+
input.agent?.role,
|
|
132
|
+
input.agent?.persona_id,
|
|
133
|
+
slice?.role,
|
|
134
|
+
slice?.domain,
|
|
135
|
+
slice?.title,
|
|
136
|
+
slice?.description,
|
|
137
|
+
...(Array.isArray(slice?.target_paths) ? slice.target_paths : [])
|
|
138
|
+
].map((value) => String(value || '')).join('\n');
|
|
139
|
+
const bannedRole = /(?:^|\b)(architect|verifier|safety|integrator|schema|release|ux|db)(?:\b|$)/i.test(String(input.agent?.role || slice?.role || ''));
|
|
140
|
+
const collection = /\b(collect|gather|extract|inventory|list|scan|grep|tail|summarize|catalog)\b|수집|추출|목록|스캔|인벤토리/i.test(text);
|
|
141
|
+
const coding = /\b(code|implement|patch|write|edit|fix|mechanical|simple)\b|코드|작성|수정|구현|패치|단순/i.test(text);
|
|
142
|
+
const banned = /\b(strategy|strategize|planning|plan|architecture|architect|design|review|verify|verification|safety|risk|consensus|debate|orchestrate|policy|decide|decision|migration|database|schema)\b|전략|기획|설계|디자인|검증|리뷰|안전|위험|합의|토론|결정|마이그레이션|데이터베이스/i.test(text);
|
|
143
|
+
const allowed = !bannedRole && !banned && (writePaths.length > 0 || collection || coding);
|
|
144
|
+
const blockers = [
|
|
145
|
+
...(allowed ? [] : ['ollama_worker_task_not_simple_code_or_collection']),
|
|
146
|
+
...(bannedRole ? ['ollama_worker_role_blocked'] : []),
|
|
147
|
+
...(banned ? ['ollama_worker_strategy_planning_design_blocked'] : [])
|
|
148
|
+
];
|
|
149
|
+
return {
|
|
150
|
+
schema: OLLAMA_WORKER_POLICY_SCHEMA,
|
|
151
|
+
generated_at: nowIso(),
|
|
152
|
+
ok: blockers.length === 0,
|
|
153
|
+
worker_only: true,
|
|
154
|
+
no_strategy_planning_design: true,
|
|
155
|
+
allowed_work: ['simple_code_patch_envelopes', 'read_only_collection'],
|
|
156
|
+
write_path_count: writePaths.length,
|
|
157
|
+
collection_detected: collection,
|
|
158
|
+
coding_detected: coding,
|
|
159
|
+
blockers
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function buildOllamaTriWikiArtifact(triwikiContext) {
|
|
163
|
+
return {
|
|
164
|
+
...triwikiContext,
|
|
165
|
+
proof: triWikiProofRecord(triwikiContext),
|
|
166
|
+
stack_current_docs_policy: {
|
|
167
|
+
required: true,
|
|
168
|
+
memory_path: '.sneakoscope/memory/q2_facts/stack-current-docs.md',
|
|
169
|
+
refresh_command: 'sks wiki refresh',
|
|
170
|
+
validate_command: 'sks wiki validate .sneakoscope/wiki/context-pack.json',
|
|
171
|
+
current_docs_source: 'Context7 or official vendor docs',
|
|
172
|
+
parent_action_when_stale_or_missing: 'Refresh stack-current-docs evidence with Context7 or official docs, then refresh/validate TriWiki before retrying the local worker.'
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function buildOllamaGenerateRequest(agent, slice, opts, config, requestId, triwikiContext) {
|
|
177
|
+
const writePaths = collectWritePaths(slice, opts);
|
|
178
|
+
const prompt = [
|
|
179
|
+
'You are an SKS local Ollama worker. You are not an architect, planner, reviewer, verifier, safety judge, or strategist.',
|
|
180
|
+
'Only perform the narrow worker task below. If the task asks for strategy, planning, design, review, verification, risk judgment, or orchestration, return JSON with status "blocked" and blockers.',
|
|
181
|
+
'Before writing or collecting, consult the TriWiki context below first. Treat use_first as high-trust project memory and hydrate_first as source/evidence that the parent must verify before risky or user-visible work.',
|
|
182
|
+
'If TriWiki is missing, stale, or lacks current stack syntax/version guidance, do not invent from model memory. Return blocked and tell the parent SKS route to update .sneakoscope/memory/q2_facts/stack-current-docs.md with Context7 or official vendor docs, then run `sks wiki refresh` and `sks wiki validate .sneakoscope/wiki/context-pack.json` before retrying.',
|
|
183
|
+
'Return JSON only. Do not wrap it in markdown.',
|
|
184
|
+
'Required shape: {"summary": string, "findings": string[], "proposed_changes": string[], "patch_envelopes": [patchEnvelope]}.',
|
|
185
|
+
'Each patchEnvelope must contain operations: [{"op":"write","path":"relative/path","content":"text"}] or replace/unified_diff operations.',
|
|
186
|
+
'Patch envelope operations may be write, replace, or unified_diff. Use only allowed write paths.',
|
|
187
|
+
'',
|
|
188
|
+
triWikiContextBlock(triwikiContext),
|
|
189
|
+
'',
|
|
190
|
+
JSON.stringify({
|
|
191
|
+
request_id: requestId,
|
|
192
|
+
mission_id: opts.missionId || opts.mission_id || '',
|
|
193
|
+
route: opts.route || '$Agent',
|
|
194
|
+
agent: {
|
|
195
|
+
id: agent.id || '',
|
|
196
|
+
session_id: agent.session_id || '',
|
|
197
|
+
slot_id: agent.slot_id || agent.id || '',
|
|
198
|
+
generation_index: Number(agent.generation_index || 1),
|
|
199
|
+
role: agent.role || agent.persona_id || ''
|
|
200
|
+
},
|
|
201
|
+
task_slice: slice || {},
|
|
202
|
+
allowed_write_paths: writePaths,
|
|
203
|
+
triwiki_context: triWikiProofRecord(triwikiContext),
|
|
204
|
+
stack_current_docs_policy: {
|
|
205
|
+
required: true,
|
|
206
|
+
memory_path: '.sneakoscope/memory/q2_facts/stack-current-docs.md',
|
|
207
|
+
refresh: 'sks wiki refresh',
|
|
208
|
+
validate: 'sks wiki validate .sneakoscope/wiki/context-pack.json',
|
|
209
|
+
current_docs_source: 'Context7 or official vendor docs'
|
|
210
|
+
}
|
|
211
|
+
}, null, 2)
|
|
212
|
+
].join('\n');
|
|
213
|
+
return {
|
|
214
|
+
model: config.model,
|
|
215
|
+
prompt,
|
|
216
|
+
stream: false,
|
|
217
|
+
format: 'json',
|
|
218
|
+
think: config.think,
|
|
219
|
+
keep_alive: config.keep_alive,
|
|
220
|
+
options: {
|
|
221
|
+
temperature: config.temperature
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
async function callOllamaGenerate(config, request) {
|
|
226
|
+
const controller = new AbortController();
|
|
227
|
+
const timer = setTimeout(() => controller.abort(), config.timeout_ms);
|
|
228
|
+
try {
|
|
229
|
+
const response = await fetch(`${config.base_url}/api/generate`, {
|
|
230
|
+
method: 'POST',
|
|
231
|
+
headers: { 'Content-Type': 'application/json' },
|
|
232
|
+
body: JSON.stringify(request),
|
|
233
|
+
signal: controller.signal
|
|
234
|
+
});
|
|
235
|
+
const text = await response.text();
|
|
236
|
+
if (!response.ok)
|
|
237
|
+
return { ok: false, error: `http_${response.status}:${text.slice(0, 500)}` };
|
|
238
|
+
return { ok: true, data: JSON.parse(text) };
|
|
239
|
+
}
|
|
240
|
+
finally {
|
|
241
|
+
clearTimeout(timer);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
function parseWorkerJson(text) {
|
|
245
|
+
const trimmed = text.trim().replace(/^```(?:json)?\s*/i, '').replace(/\s*```$/, '');
|
|
246
|
+
try {
|
|
247
|
+
return { ok: true, value: JSON.parse(trimmed) };
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
const match = trimmed.match(/\{[\s\S]*\}/);
|
|
251
|
+
if (!match)
|
|
252
|
+
return { ok: false };
|
|
253
|
+
try {
|
|
254
|
+
return { ok: true, value: JSON.parse(match[0] || '{}') };
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
return { ok: false };
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
function normalizeOllamaPatchEnvelopes(value, agent, slice, opts, requestId) {
|
|
262
|
+
const rawEnvelopes = Array.isArray(value?.patch_envelopes) ? value.patch_envelopes
|
|
263
|
+
: Array.isArray(value?.patchEnvelopes) ? value.patchEnvelopes
|
|
264
|
+
: value?.patch_envelope ? [value.patch_envelope]
|
|
265
|
+
: value?.patchEnvelope ? [value.patchEnvelope]
|
|
266
|
+
: Array.isArray(value?.operations) ? [{ operations: value.operations }]
|
|
267
|
+
: value?.operation ? [{ operation: value.operation }]
|
|
268
|
+
: looksLikePatchOperation(value) ? [value]
|
|
269
|
+
: [];
|
|
270
|
+
return rawEnvelopes.map((raw, index) => {
|
|
271
|
+
const operations = normalizeOllamaOperations(raw);
|
|
272
|
+
const allowedPaths = collectWritePaths(slice, opts);
|
|
273
|
+
const firstPath = String(operations[0]?.path || allowedPaths[index] || slice?.id || `ollama-${index + 1}`);
|
|
274
|
+
const leaseId = String(raw?.lease_id || raw?.lease_proof?.lease_id || `write:${String(agent.id || 'ollama')}:${firstPath}`);
|
|
275
|
+
const nodeId = String(slice?.micro_win_id || slice?.id || `ollama-patch-${index + 1}`);
|
|
276
|
+
const verificationNodeId = String(slice?.verification_node_id || `verify:${nodeId}`);
|
|
277
|
+
const rollbackNodeId = String(slice?.rollback_node_id || `rollback:${nodeId}`);
|
|
278
|
+
return normalizeAgentPatchEnvelope({
|
|
279
|
+
...raw,
|
|
280
|
+
source: 'model_authored',
|
|
281
|
+
mission_id: String(opts.missionId || opts.mission_id || raw?.mission_id || ''),
|
|
282
|
+
route: String(opts.route || raw?.route || '$Agent'),
|
|
283
|
+
agent_id: String(agent.id || raw?.agent_id || 'ollama-worker'),
|
|
284
|
+
session_id: String(agent.session_id || raw?.session_id || ''),
|
|
285
|
+
slot_id: String(agent.slot_id || raw?.slot_id || agent.id || 'ollama-worker'),
|
|
286
|
+
generation_index: Number(agent.generation_index || raw?.generation_index || 1),
|
|
287
|
+
task_slice_id: String(slice?.id || raw?.task_slice_id || ''),
|
|
288
|
+
native_cli_worker_session_id: String(agent.session_id || raw?.native_cli_worker_session_id || ''),
|
|
289
|
+
native_cli_process_id: process.pid,
|
|
290
|
+
worker_process_id: process.pid,
|
|
291
|
+
backend_ollama_request_id: requestId,
|
|
292
|
+
fast_mode: opts.fastMode !== false,
|
|
293
|
+
service_tier: opts.serviceTier === 'standard' ? 'standard' : 'fast',
|
|
294
|
+
lease_id: leaseId,
|
|
295
|
+
allowed_paths: allowedPaths.length ? allowedPaths : raw?.allowed_paths,
|
|
296
|
+
strategy_task_id: nodeId,
|
|
297
|
+
verification_node_id: verificationNodeId,
|
|
298
|
+
rollback_node_id: rollbackNodeId,
|
|
299
|
+
lease_proof: {
|
|
300
|
+
lease_id: leaseId,
|
|
301
|
+
owner_agent: String(agent.id || 'ollama-worker'),
|
|
302
|
+
owner_persona: String(agent.persona_id || agent.role || 'ollama-worker'),
|
|
303
|
+
allowed_paths: allowedPaths.length ? allowedPaths : raw?.allowed_paths,
|
|
304
|
+
strategy_task_id: nodeId,
|
|
305
|
+
micro_win_id: slice?.micro_win_id ? String(slice.micro_win_id) : undefined,
|
|
306
|
+
protected_path_check: 'passed',
|
|
307
|
+
conflict_prediction_id: `conflict:${nodeId}`,
|
|
308
|
+
verification_node_id: verificationNodeId,
|
|
309
|
+
rollback_node_id: rollbackNodeId
|
|
310
|
+
},
|
|
311
|
+
operations
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
function normalizeOllamaOperations(raw) {
|
|
316
|
+
if (Array.isArray(raw?.operations))
|
|
317
|
+
return raw.operations;
|
|
318
|
+
if (raw?.operation)
|
|
319
|
+
return normalizeOllamaOperations(raw.operation);
|
|
320
|
+
if (Array.isArray(raw?.changes))
|
|
321
|
+
return raw.changes.flatMap((change) => normalizeOllamaOperations(change));
|
|
322
|
+
if (Array.isArray(raw?.edits))
|
|
323
|
+
return raw.edits.flatMap((edit) => normalizeOllamaOperations(edit));
|
|
324
|
+
const pathValue = raw?.path || raw?.file || raw?.filepath || raw?.file_path || raw?.target_path || raw?.targetPath;
|
|
325
|
+
if (pathValue && (raw?.content !== undefined || raw?.text !== undefined)) {
|
|
326
|
+
return [{ op: 'write', path: String(pathValue), content: String(raw.content ?? raw.text ?? '') }];
|
|
327
|
+
}
|
|
328
|
+
if (pathValue && (raw?.diff !== undefined || raw?.unified_diff !== undefined || raw?.unifiedDiff !== undefined)) {
|
|
329
|
+
return [{ op: 'unified_diff', path: String(pathValue), diff: String(raw.diff ?? raw.unified_diff ?? raw.unifiedDiff ?? '') }];
|
|
330
|
+
}
|
|
331
|
+
if (pathValue && (raw?.search !== undefined || raw?.find !== undefined || raw?.replace !== undefined)) {
|
|
332
|
+
return [{
|
|
333
|
+
op: 'replace',
|
|
334
|
+
path: String(pathValue),
|
|
335
|
+
search: String(raw.search ?? raw.find ?? ''),
|
|
336
|
+
replace: String(raw.replace || '')
|
|
337
|
+
}];
|
|
338
|
+
}
|
|
339
|
+
return [];
|
|
340
|
+
}
|
|
341
|
+
function looksLikePatchOperation(value) {
|
|
342
|
+
return Boolean(value && typeof value === 'object' && (value.path !== undefined ||
|
|
343
|
+
value.file !== undefined ||
|
|
344
|
+
value.filepath !== undefined ||
|
|
345
|
+
value.file_path !== undefined ||
|
|
346
|
+
value.target_path !== undefined ||
|
|
347
|
+
value.targetPath !== undefined ||
|
|
348
|
+
value.content !== undefined ||
|
|
349
|
+
value.text !== undefined ||
|
|
350
|
+
value.diff !== undefined ||
|
|
351
|
+
value.unified_diff !== undefined ||
|
|
352
|
+
value.unifiedDiff !== undefined ||
|
|
353
|
+
value.search !== undefined ||
|
|
354
|
+
value.find !== undefined));
|
|
355
|
+
}
|
|
356
|
+
function blockedResult(agent, slice, opts, blockers, artifacts) {
|
|
357
|
+
return {
|
|
358
|
+
mission_id: String(opts.missionId || opts.mission_id || ''),
|
|
359
|
+
agent_id: String(agent.id || 'ollama-worker'),
|
|
360
|
+
session_id: String(agent.session_id || ''),
|
|
361
|
+
persona_id: String(agent.persona_id || agent.id || 'ollama-worker'),
|
|
362
|
+
task_slice_id: String(slice?.id || ''),
|
|
363
|
+
status: 'blocked',
|
|
364
|
+
backend: 'ollama',
|
|
365
|
+
summary: 'Ollama local worker blocked by configuration or worker-only policy.',
|
|
366
|
+
findings: [],
|
|
367
|
+
proposed_changes: [],
|
|
368
|
+
changed_files: [],
|
|
369
|
+
lease_compliance: { ok: true, violations: [] },
|
|
370
|
+
artifacts,
|
|
371
|
+
blockers,
|
|
372
|
+
confidence: 'blocked',
|
|
373
|
+
handoff_notes: 'Local model did not run.',
|
|
374
|
+
unverified: [],
|
|
375
|
+
writes: [],
|
|
376
|
+
verification: { status: 'failed', checks: ['ollama-worker-policy'] },
|
|
377
|
+
recursion_guard: { ok: true, violations: [] }
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
function collectWritePaths(slice, opts) {
|
|
381
|
+
return [
|
|
382
|
+
...(Array.isArray(slice?.write_paths) ? slice.write_paths : []),
|
|
383
|
+
...(Array.isArray(opts?.write_paths) ? opts.write_paths : [])
|
|
384
|
+
].map(String).filter(Boolean);
|
|
385
|
+
}
|
|
386
|
+
function stringArray(value) {
|
|
387
|
+
return Array.isArray(value) ? value.map(String) : [];
|
|
388
|
+
}
|
|
389
|
+
function safeResponseData(data) {
|
|
390
|
+
return {
|
|
391
|
+
model: data?.model || null,
|
|
392
|
+
created_at: data?.created_at || null,
|
|
393
|
+
done: data?.done === true,
|
|
394
|
+
response_present: typeof data?.response === 'string' && data.response.length > 0,
|
|
395
|
+
thinking_present: typeof data?.thinking === 'string' && data.thinking.length > 0,
|
|
396
|
+
total_duration: data?.total_duration || null,
|
|
397
|
+
load_duration: data?.load_duration || null,
|
|
398
|
+
prompt_eval_count: data?.prompt_eval_count || null,
|
|
399
|
+
eval_count: data?.eval_count || null
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
function extractOllamaWorkerText(data) {
|
|
403
|
+
const response = String(data?.response || '').trim();
|
|
404
|
+
if (response)
|
|
405
|
+
return { text: response, source: 'response' };
|
|
406
|
+
const thinking = String(data?.thinking || '').trim();
|
|
407
|
+
if (thinking)
|
|
408
|
+
return { text: thinking, source: 'thinking' };
|
|
409
|
+
return { text: '', source: 'empty' };
|
|
410
|
+
}
|
|
411
|
+
//# sourceMappingURL=agent-runner-ollama.js.map
|
|
@@ -14,7 +14,7 @@ export const DEFAULT_AGENT_CONCURRENCY = 5;
|
|
|
14
14
|
// cap; every other roster/scheduler caller keeps MAX_AGENT_COUNT as the default.
|
|
15
15
|
export const MAX_NARUTO_AGENT_COUNT = 100;
|
|
16
16
|
export const DEFAULT_NARUTO_CLONES = 12;
|
|
17
|
-
export const AGENT_BACKENDS = ['fake', 'process', 'codex-sdk', 'zellij'];
|
|
17
|
+
export const AGENT_BACKENDS = ['fake', 'process', 'codex-sdk', 'zellij', 'ollama'];
|
|
18
18
|
export function normalizeAgentBackend(input) {
|
|
19
19
|
const value = String(input || 'codex-sdk');
|
|
20
20
|
return AGENT_BACKENDS.includes(value) ? value : 'codex-sdk';
|
|
@@ -77,6 +77,8 @@ export function enhanceTaskGraphWithIntelligence(taskGraph, graph) {
|
|
|
77
77
|
return taskGraph;
|
|
78
78
|
const bottleneckTargets = new Set((graph.integration_bottlenecks?.bottlenecks || []).map((row) => String(row.file)));
|
|
79
79
|
const criticalTargets = new Set(graph.critical_path?.path || []);
|
|
80
|
+
const targetActiveSlots = Math.max(1, Math.floor(Number(taskGraph.target_active_slots || 1)));
|
|
81
|
+
const canSerializeCriticalPath = taskGraph.work_items.length > targetActiveSlots;
|
|
80
82
|
const workItems = taskGraph.work_items.map((item, index) => {
|
|
81
83
|
const targets = Array.isArray(item.target_paths) ? item.target_paths.map(String) : [];
|
|
82
84
|
const critical = targets.some((file) => criticalTargets.has(file));
|
|
@@ -90,7 +92,7 @@ export function enhanceTaskGraphWithIntelligence(taskGraph, graph) {
|
|
|
90
92
|
test_ownership_ref: 'agent-test-ownership-map.json',
|
|
91
93
|
critical_path_ref: 'agent-critical-path.json',
|
|
92
94
|
integration_bottleneck_ref: 'agent-integration-bottlenecks.json',
|
|
93
|
-
dependencies: mergeDependencies(item.dependencies, critical && index > 0 ? [taskGraph.work_items[index - 1]?.work_item_id].filter(Boolean) : []),
|
|
95
|
+
dependencies: mergeDependencies(item.dependencies, canSerializeCriticalPath && critical && index > 0 ? [taskGraph.work_items[index - 1]?.work_item_id].filter(Boolean) : []),
|
|
94
96
|
lease_requirements: [
|
|
95
97
|
...(Array.isArray(item.lease_requirements) ? item.lease_requirements : []),
|
|
96
98
|
...(bottleneck ? targets.map((file) => ({ kind: 'integration-bottleneck-read', path: file })) : [])
|
|
@@ -109,8 +111,9 @@ export function enhanceTaskGraphWithIntelligence(taskGraph, graph) {
|
|
|
109
111
|
};
|
|
110
112
|
}
|
|
111
113
|
export async function writeIntelligentWorkGraphArtifacts(root, graph) {
|
|
112
|
-
|
|
113
|
-
await writeJsonAtomic(path.join(root, 'agent-intelligent-work-graph
|
|
114
|
+
const compact = compactIntelligentWorkGraph(graph);
|
|
115
|
+
await writeJsonAtomic(path.join(root, 'agent-intelligent-work-graph.json'), compact);
|
|
116
|
+
await writeJsonAtomic(path.join(root, 'agent-intelligent-work-graph-v2.json'), compact);
|
|
114
117
|
await writeJsonAtomic(path.join(root, 'agent-symbol-ownership-map.json'), {
|
|
115
118
|
schema: 'sks.agent-symbol-ownership-map.v1',
|
|
116
119
|
generated_at: graph.generated_at,
|
|
@@ -180,6 +183,45 @@ export async function writeIntelligentWorkGraphArtifacts(root, graph) {
|
|
|
180
183
|
...graph.integration_bottlenecks
|
|
181
184
|
});
|
|
182
185
|
}
|
|
186
|
+
export function compactIntelligentWorkGraph(graph) {
|
|
187
|
+
return {
|
|
188
|
+
schema: graph.schema,
|
|
189
|
+
generated_at: graph.generated_at,
|
|
190
|
+
ok: graph.ok,
|
|
191
|
+
mode: graph.mode,
|
|
192
|
+
compact: true,
|
|
193
|
+
source_inventory_count: graph.source_inventory_count,
|
|
194
|
+
test_inventory_count: graph.test_inventory_count,
|
|
195
|
+
docs_inventory_count: graph.docs_inventory_count,
|
|
196
|
+
script_schema_inventory_count: graph.script_schema_inventory_count,
|
|
197
|
+
dependency_edge_count: graph.dependency_edge_count,
|
|
198
|
+
ast_coverage: graph.ast_coverage,
|
|
199
|
+
test_ownership_confidence: graph.test_ownership_confidence,
|
|
200
|
+
changed_file_candidates: limitArray(graph.changed_file_candidates, 200),
|
|
201
|
+
route_domain_priority: limitArray(graph.route_domain_priority, 100),
|
|
202
|
+
critical_path: graph.critical_path,
|
|
203
|
+
integration_bottlenecks: graph.integration_bottlenecks,
|
|
204
|
+
parallelizable_groups: limitArray(graph.parallelizable_groups, 80),
|
|
205
|
+
serial_dependency_groups: limitArray(graph.serial_dependency_groups, 40),
|
|
206
|
+
work_graph_quality_score: graph.work_graph_quality_score,
|
|
207
|
+
proof_level: graph.proof_level,
|
|
208
|
+
ast_parser_limitations: limitArray(graph.ast_parser_limitations, 100),
|
|
209
|
+
warnings: limitArray(graph.warnings, 200),
|
|
210
|
+
blockers: graph.blockers,
|
|
211
|
+
expanded_artifacts: {
|
|
212
|
+
symbol_ownership: 'agent-symbol-ownership-map.json',
|
|
213
|
+
route_ownership: 'agent-route-ownership-map.json',
|
|
214
|
+
command_ownership: 'agent-command-ownership-map.json',
|
|
215
|
+
test_ownership: 'agent-test-ownership-map.json',
|
|
216
|
+
source_test_ownership: 'agent-source-test-ownership-v2.json',
|
|
217
|
+
critical_path: 'agent-critical-path-v2.json',
|
|
218
|
+
integration_bottlenecks: 'agent-integration-bottlenecks-v2.json'
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
function limitArray(items, limit) {
|
|
223
|
+
return Array.isArray(items) ? items.slice(0, limit) : [];
|
|
224
|
+
}
|
|
183
225
|
function buildTestOwnershipMap(sourceFiles, testFiles, ast, dependencyGraph = {}) {
|
|
184
226
|
const ownerBySource = {};
|
|
185
227
|
const relations = [];
|
|
@@ -42,6 +42,8 @@ class NativeCliSessionSwarmRecorder {
|
|
|
42
42
|
parent_mission_id: this.input.missionId,
|
|
43
43
|
route: this.input.route,
|
|
44
44
|
backend: this.input.backend,
|
|
45
|
+
backend_explicit: this.input.backendExplicit === true,
|
|
46
|
+
no_ollama: this.input.noOllama === true || ctx.opts.noOllama === true,
|
|
45
47
|
agent_root: this.root,
|
|
46
48
|
agent: ctx.agent,
|
|
47
49
|
slice: ctx.slice,
|
|
@@ -51,6 +53,9 @@ class NativeCliSessionSwarmRecorder {
|
|
|
51
53
|
patch_envelope_path: patchRel,
|
|
52
54
|
service_tier: this.input.fastModePolicy.service_tier,
|
|
53
55
|
fast_mode: this.input.fastModePolicy.fast_mode,
|
|
56
|
+
ollama_enabled: ctx.opts.ollamaEnabled === true || this.input.backend === 'ollama',
|
|
57
|
+
ollama_model: ctx.opts.ollamaModel || null,
|
|
58
|
+
ollama_base_url: ctx.opts.ollamaBaseUrl || null,
|
|
54
59
|
source_intelligence_refs: ctx.agent.source_intelligence_refs || null,
|
|
55
60
|
goal_mode_ref: ctx.agent.goal_mode_ref || null,
|
|
56
61
|
strategy_refs: ctx.slice?.strategy_refs || null,
|
|
@@ -192,6 +197,8 @@ class NativeCliSessionSwarmRecorder {
|
|
|
192
197
|
SKS_AGENT_SESSION_ID: String(input.ctx.agent.session_id || ''),
|
|
193
198
|
SKS_AGENT_SLOT_ID: slotId,
|
|
194
199
|
SKS_AGENT_GENERATION_INDEX: String(input.ctx.agent.generation_index || 1),
|
|
200
|
+
...(input.ctx.opts.ollamaModel ? { SKS_OLLAMA_MODEL: String(input.ctx.opts.ollamaModel) } : {}),
|
|
201
|
+
...(input.ctx.opts.ollamaBaseUrl ? { SKS_OLLAMA_BASE_URL: String(input.ctx.opts.ollamaBaseUrl) } : {}),
|
|
195
202
|
SKS_ZELLIJ_WORKER_PANE: '1',
|
|
196
203
|
SKS_ZELLIJ_SESSION_NAME: sessionName
|
|
197
204
|
}
|
|
@@ -220,7 +227,7 @@ class NativeCliSessionSwarmRecorder {
|
|
|
220
227
|
serviceTier: this.input.fastModePolicy.service_tier
|
|
221
228
|
});
|
|
222
229
|
const launchBlockers = paneRecord.blockers || [];
|
|
223
|
-
input.record.command_line = ['zellij', '--session', sessionName, 'action', 'new-pane', '--name', paneRecord.pane_name, '--', 'sh', '-lc', '<native-cli-worker-command>'];
|
|
230
|
+
input.record.command_line = ['zellij', '--session', sessionName, 'action', 'new-pane', '--direction', paneRecord.direction_applied, '--name', paneRecord.pane_name, '--', 'sh', '-lc', '<native-cli-worker-command>'];
|
|
224
231
|
input.record.zellij_session_name = sessionName;
|
|
225
232
|
input.record.zellij_pane_id = paneRecord.pane_id || null;
|
|
226
233
|
input.record.zellij_pane_id_source = paneRecord.pane_id_source;
|
|
@@ -159,7 +159,7 @@ export async function runNativeCliWorker(input = {}) {
|
|
|
159
159
|
structured_output_valid: routed.report?.structured_output_valid === true,
|
|
160
160
|
backend_router_report: routed.report,
|
|
161
161
|
backend_child_process_ids: routed.report.child_process_ids,
|
|
162
|
-
backend_child_execution: routed.report.child_process_ids.length > 0 || Boolean(routed.report?.sdk_thread_id) || backend === 'fake',
|
|
162
|
+
backend_child_execution: routed.report.child_process_ids.length > 0 || Boolean(routed.report?.sdk_thread_id) || backend === 'fake' || backend === 'ollama',
|
|
163
163
|
recursion_guard_env: process.env.SKS_DISABLE_ROUTE_RECURSION === '1',
|
|
164
164
|
worker_env: process.env.SKS_AGENT_WORKER === '1',
|
|
165
165
|
exit_code: guard.ok ? 0 : 1
|