Skip to content

Commit ed55ba5

Browse files
Andrey Golovanovclaude
andcommitted
Load ngraph DSL skill as generation loop system prompt
Instead of maintaining a hand-written system prompt, load the netgraph-dsl SKILL.md from the skills directory. This gives the LLM the complete DSL reference including correct failure policy structure, workflow step format, and common pitfalls. Falls back to a built-in minimal reference if the skill file is not found. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 7f512ef commit ed55ba5

1 file changed

Lines changed: 78 additions & 33 deletions

File tree

netlab/autoresearch/generation_loop.py

Lines changed: 78 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -158,47 +158,92 @@ def _parse_int(s: str) -> int:
158158
return 0
159159

160160

161-
_GENERATION_SYSTEM_PROMPT = """\
161+
_GENERATION_SYSTEM_PROMPT_HEADER = """\
162162
You are a network topology engineer generating ngraph scenario YAML files.
163163
164164
You will receive a connectivity idea and must produce a complete ngraph
165165
scenario YAML. After each attempt, you will receive the ngraph inspect
166166
output showing what was actually built. Compare it against the original
167167
intent and fix any mismatches.
168168
169-
CRITICAL: The top-level keys must be: seed, network, risk_groups, demands,
170-
failures, workflow. Nodes and links go INSIDE the network key.
171-
172-
Minimal working example:
173-
174-
seed: 42
175-
network:
176-
nodes:
177-
A: {}
178-
B: {}
179-
links:
180-
- source: A
181-
target: B
182-
capacity: 100
183-
cost: 1
184-
demands:
185-
tm:
186-
- source: ^A$
187-
target: ^B$
188-
volume: 10
189-
mode: combine
190-
flow_policy: SHORTEST_PATHS_ECMP
191-
workflow:
192-
- type: MaximumSupportedDemand
193-
name: msd_baseline
194-
demand_set: tm
195-
resolution: 0.1
169+
Return ONLY valid YAML. No markdown fences, no explanation.
170+
"""
196171

197-
All links are bidirectional by default (ngraph adds reverse automatically).
198-
Use `risk_groups: [name]` on link definitions to assign to failure domains.
199-
Failure policies use `scope: node|link|risk_group` with `mode: choice` and
200-
`match.conditions` to select targets.
172+
# Loaded at module import from the skills directory if available,
173+
# otherwise falls back to a built-in minimal reference.
174+
_DSL_REFERENCE: str | None = None
175+
176+
177+
def _load_dsl_reference() -> str:
178+
"""Load the ngraph DSL skill reference for use as system prompt context."""
179+
global _DSL_REFERENCE
180+
if _DSL_REFERENCE is not None:
181+
return _DSL_REFERENCE
182+
183+
# Try loading from the skills directory
184+
from pathlib import Path
185+
186+
skill_paths = [
187+
Path(__file__).parent.parent.parent.parent
188+
/ "skills"
189+
/ "netgraph-dsl"
190+
/ "SKILL.md",
191+
Path.home()
192+
/ "ws"
193+
/ "project_netgraph"
194+
/ "skills"
195+
/ "netgraph-dsl"
196+
/ "SKILL.md",
197+
]
198+
for skill_path in skill_paths:
199+
if skill_path.exists():
200+
_DSL_REFERENCE = skill_path.read_text()
201+
return _DSL_REFERENCE
202+
203+
# Fallback: built-in minimal reference
204+
_DSL_REFERENCE = """\
205+
CRITICAL RULES:
206+
- Top-level keys: seed, network, risk_groups, demands, failures, workflow
207+
- nodes and links go INSIDE the network key
208+
- All links are bidirectional (ngraph adds reverse automatically)
209+
- Use risk_groups: [name] on link defs to assign failure domains
210+
- Node attrs enable failure targeting: {role: bb} matches scope: node
211+
212+
Failure policy structure (EXACT nesting required):
213+
failures:
214+
policy_name:
215+
modes:
216+
- weight: 1.0
217+
rules:
218+
- scope: node # node | link | risk_group
219+
mode: choice # choice | all | random
220+
count: 1
221+
match:
222+
conditions:
223+
- attr: role
224+
op: "==" # == | != | contains | in
225+
value: bb
226+
227+
TrafficMatrixPlacement workflow step (all fields required):
228+
- type: TrafficMatrixPlacement
229+
name: tm_step
230+
demand_set: tm
231+
failure_policy: policy_name
232+
iterations: 10
233+
parallelism: 1
234+
placement_rounds: auto
235+
seed: 42
236+
include_flow_details: true
237+
alpha_from_step: msd_baseline
238+
alpha_from_field: data.alpha_star
201239
"""
240+
return _DSL_REFERENCE
241+
242+
243+
def _get_generation_system_prompt() -> str:
244+
"""Build the full system prompt for scenario generation."""
245+
return _GENERATION_SYSTEM_PROMPT_HEADER + "\n" + _load_dsl_reference()
246+
202247

203248
_GENERATION_PROMPT_TEMPLATE = """\
204249
Generate a complete ngraph scenario YAML for this connectivity idea:
@@ -281,7 +326,7 @@ def run_generation_loop(
281326
validation_errors=validation_errors,
282327
)
283328

284-
response = backend.generate(prompt, system=_GENERATION_SYSTEM_PROMPT)
329+
response = backend.generate(prompt, system=_get_generation_system_prompt())
285330

286331
# Extract YAML from response
287332
yaml_text = _extract_yaml(response)

0 commit comments

Comments
 (0)