chaincompiler 0.3.0__py3-none-any.whl

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.
@@ -0,0 +1,31 @@
1
+ """chaincompiler — the ChainCompiler BASE: the generic compiler-compiler (DESIGN.md §2).
2
+
3
+ This package imports only DOWN (APE + honeyc + rulecatcher). It is the machine the *CC are MADE FROM:
4
+ - forge : the generic "forge a language" core (Language / forge / gate_language / grammar / package_skill)
5
+ - bridge : the HoneyC compile seam + the rulecatcher grammar seam (learn / gate, re-exported from APE)
6
+ - prime : build_prime — the re-injectable prime block
7
+ - skillpack / persona : SKILL.md packaging + the glyph-persona-program compiler
8
+
9
+ ACCC / CORCC / SCCC build ON this base (they import CC). CC NEVER imports the *CC. The Bandit AIOS
10
+ application that orchestrates AC+CoR+SC (construct_language / GBA / HBA / COG) lives ABOVE the *CC in the
11
+ `chainaios` package — it was extracted out of here precisely so this base no longer imports the *CC.
12
+ """
13
+ from __future__ import annotations
14
+
15
+ __version__ = "0.3.0"
16
+
17
+ from .bridge import compile_chain, gate, learn
18
+ from .prime import build_prime
19
+ from .skillpack import skill_markdown, slugify, write_skill
20
+ # the generic compiler-compiler core — the machine the *CC are MADE FROM (DESIGN.md §2). Imports only APE.
21
+ from .forge import Language, forge, gate_language, grammar, package_skill
22
+ # re-export the APE cognition helper the *CC need, so they route through CC (not around it to APE):
23
+ from prompt_engineering import cor_skeleton
24
+
25
+ __all__ = [
26
+ "learn", "gate", "compile_chain", "build_prime",
27
+ "write_skill", "skill_markdown", "slugify",
28
+ # the forge core (ACCC/CORCC/SCCC import these DOWN from here):
29
+ "Language", "forge", "gate_language", "grammar", "package_skill", "cor_skeleton",
30
+ "__version__",
31
+ ]
@@ -0,0 +1,36 @@
1
+ """The HoneyC seam (compile a gated chain into lenses) + re-exports of the rulecatcher seam.
2
+
3
+ The rulecatcher seam — `learn` / `gate` / `grammar_lines` / `foreign_tokens` — MOVED DOWN to
4
+ `prompt_engineering.grammar` (REBUILD-SPEC.md §4 — single source of truth, D1). chaincompiler keeps the
5
+ HoneyC-wrapping `compile_chain` (HoneyC is chaincompiler's concern, §6) and RE-EXPORTS the grammar seam,
6
+ so `from chaincompiler.bridge import learn, gate, grammar_lines` and `from chaincompiler import learn,
7
+ gate` stay byte-stable.
8
+ """
9
+ from __future__ import annotations
10
+
11
+ from honeyc.normalize import normalize
12
+ from honeyc.parser import parse_text
13
+ from honeyc.render import render
14
+
15
+ # the rulecatcher seam now lives in the base (DOWN edge):
16
+ from prompt_engineering.grammar import (
17
+ ForeignToken,
18
+ foreign_tokens,
19
+ gate,
20
+ grammar_lines,
21
+ learn,
22
+ )
23
+
24
+
25
+ def compile_chain(chain: str) -> dict:
26
+ """Compile a chain through HoneyC into semantic lenses."""
27
+ program = parse_text(chain)
28
+ return {
29
+ "readable": render(program, "readable"),
30
+ "triples": render(program, "triples"),
31
+ "prose": render(program, "prose"),
32
+ "statements": normalize(program),
33
+ }
34
+
35
+
36
+ __all__ = ["compile_chain", "learn", "gate", "grammar_lines", "foreign_tokens", "ForeignToken"]
chaincompiler/forge.py ADDED
@@ -0,0 +1,59 @@
1
+ """forge.py — the generic compiler-compiler core (the "forge a language" move).
2
+
3
+ This is the machine the *CC are *made FROM* (DESIGN.md §2: ACCC/CORCC/SCCC import CC). A forged
4
+ language = a rulecatcher SCOPE holding a ratified grammar; `forge` mints one, `gate_language` enforces it,
5
+ `grammar` reads it back, `package_skill` wraps a compiled body as a publishable `<name>/SKILL.md`. Each
6
+ *CC calls these with its own chain-kind prefix + render/parse and adds nothing to the mechanism.
7
+
8
+ CC imports only DOWN (APE + rulecatcher); it never imports the *CC.
9
+ """
10
+ from __future__ import annotations
11
+
12
+ from dataclasses import dataclass
13
+
14
+ from prompt_engineering import write_skill, grammar_lines, learn
15
+ from prompt_engineering.grammar import gate as _gate
16
+ from rulecatcher.db import connect, list_rules
17
+
18
+
19
+ @dataclass
20
+ class Language:
21
+ """A forged language: a rulecatcher scope holding a ratified grammar."""
22
+ name: str
23
+ scope: str
24
+ db: str
25
+ rule_count: int
26
+
27
+
28
+ def forge(kind: str, name: str, examples: list[str], *, db: str, strict: bool = False) -> Language:
29
+ """Mint a `kind` language for `name` from example chains (scope = `<kind>:<name>`).
30
+
31
+ strict=False → learn the SHAPE only (next_kind): any vocabulary is allowed.
32
+ strict=True → also pin the vocabulary (next_token): the gate enforces domain-specific tokens.
33
+ """
34
+ scope = f"{kind}:{name}"
35
+ rule_types = ("next_kind", "next_token") if strict else ("next_kind",)
36
+ with connect(db) as cx:
37
+ adopted = learn(cx, examples, scope=scope, rule_types=rule_types, label=f"forge:{name}")
38
+ return Language(name=name, scope=scope, db=db, rule_count=len(adopted))
39
+
40
+
41
+ def gate_language(language: Language, candidate: str) -> tuple[list, list]:
42
+ """Lint a candidate chain against a forged language's ratified grammar."""
43
+ with connect(language.db) as cx:
44
+ return _gate(cx, candidate, scope=language.scope)
45
+
46
+
47
+ def grammar(language: Language) -> list[str]:
48
+ """The ratified grammar lines of a forged language."""
49
+ with connect(language.db) as cx:
50
+ return grammar_lines(list_rules(cx, "adopted", scope=language.scope))
51
+
52
+
53
+ def package_skill(name: str, body: str, *, out_dir: str, description: str,
54
+ extra: dict | None = None):
55
+ """Wrap a compiled chain body as a publishable `<name>/SKILL.md` package."""
56
+ return write_skill(name, description, body, out_dir=out_dir, extra=extra)
57
+
58
+
59
+ __all__ = ["Language", "forge", "gate_language", "grammar", "package_skill"]
@@ -0,0 +1,157 @@
1
+ """Persona compiler — the front-end that ingests a glyph-persona-program and emits
2
+ the artifacts the rest of ChainCompiler already eats.
3
+
4
+ A BizziBee-style prompt is not prose: it is a program in a cognition-DSL with three
5
+ layers, each of which a ChainCompiler tool already compiles —
6
+
7
+ [VarDefs]{ [🌸‍💧]=NectarWF, 📃=drilldown, … } → a glyphsteer LEGEND (glyph↔meaning)
8
+ 🌸‍💧 → 🍯 → 🍹 (dense-rune chains) → HoneyC compiles / rulecatcher gates
9
+ ⚙️0–5 (if / while / for / 🔁 / terminal) → a workflow (the SI executes; here: extracted)
10
+ [ROLE]…[/ROLE] (the persona wrapper) → a SKILL.md (the one type)
11
+
12
+ So this module parses the human-authored glyph-persona into: a `legend.json`, a list of
13
+ workflow steps, and a `<cogid>/SKILL.md` — putting the persona INSIDE the closed algebra.
14
+ Full execution of the ⚙️ control flow is the SI's job (ASPIRATIONAL: `persona run`).
15
+ """
16
+ from __future__ import annotations
17
+
18
+ import re
19
+ from dataclasses import dataclass, field
20
+ from pathlib import Path
21
+
22
+ from .skillpack import slugify, write_skill
23
+
24
+ # operator glyphs that are NOT vocabulary entries (arrows / connectors)
25
+ _OPERATORS = set("→⇒⇔↔⟶⇄⟷=+/")
26
+ _NONASCII = re.compile(r"[^\x00-\x7f]+")
27
+ _IDENT = re.compile(r"[A-Za-z][A-Za-z0-9]*")
28
+ _HEADER = re.compile(r"^\[([A-Za-z][A-Za-z0-9]*)\]:\s*(.*)$", re.M)
29
+ _VARDEFS = re.compile(r"\[VarDefs\]:\s*\{(.*?)\}\s*(?:\n|$)", re.S)
30
+ _STEP = re.compile(r"⚙️([0-9][0-9.]*)\)\s*`?(.*)")
31
+ _CTRL = re.compile(r"\b(if|while|for|end)\b|🔁", re.I)
32
+
33
+
34
+ @dataclass
35
+ class Persona:
36
+ name: str
37
+ description: str
38
+ fields: dict[str, str] = field(default_factory=dict)
39
+ legend: object = None # a glyphsteer.Vocabulary
40
+ steps: list[dict] = field(default_factory=list)
41
+
42
+
43
+ # ---- block parsing ----------------------------------------------------------
44
+ def parse_header(text: str) -> dict[str, str]:
45
+ """The `[TAG]: value` header fields (ROLE, CogID, LAW, Mission, …)."""
46
+ return {k: v.strip() for k, v in _HEADER.findall(text)}
47
+
48
+
49
+ def vardefs_text(text: str) -> str:
50
+ m = _VARDEFS.search(text)
51
+ return m.group(1) if m else ""
52
+
53
+
54
+ # ---- VarDefs → legend -------------------------------------------------------
55
+ def _clean_glyph(run: str) -> str:
56
+ return "".join(ch for ch in run if ch not in _OPERATORS).strip()
57
+
58
+
59
+ def extract_legend(text: str):
60
+ """Parse the VarDefs glyph↔name pairs into a glyphsteer Vocabulary (best-effort)."""
61
+ from glyphsteer import Axis, Vocabulary, author
62
+ raw = vardefs_text(text) or text
63
+ specs, gseen, nseen = [], set(), set()
64
+ for piece in re.split(r"[,\n]", raw):
65
+ glyph_runs = [g for g in (_clean_glyph(r) for r in _NONASCII.findall(piece)) if g]
66
+ names = _IDENT.findall(piece)
67
+ if not glyph_runs or not names:
68
+ continue
69
+ glyph, name = glyph_runs[0], names[0]
70
+ if glyph in gseen or name in nseen:
71
+ continue
72
+ try:
73
+ Vocabulary([Axis(name, glyph)]) # validates clean glyph + derivable tag
74
+ except ValueError:
75
+ continue
76
+ gseen.add(glyph); nseen.add(name)
77
+ specs.append({"name": name, "glyph": glyph, "description": piece.strip()})
78
+ return author(specs)
79
+
80
+
81
+ # ---- ⚙️ steps → workflow ----------------------------------------------------
82
+ def extract_workflow(text: str) -> list[dict]:
83
+ """The numbered ⚙️N) steps, in order, with detected control-flow keywords."""
84
+ steps = []
85
+ for num, body in _STEP.findall(text):
86
+ body = body.strip().rstrip("`").strip()
87
+ ctrl = sorted({m.group(0).lower() for m in _CTRL.finditer(body)})
88
+ steps.append({"step": num, "ctrl": ctrl, "body": body[:140]})
89
+ return steps
90
+
91
+
92
+ # ---- compile ----------------------------------------------------------------
93
+ def parse_persona(text: str) -> Persona:
94
+ h = parse_header(text)
95
+ name = h.get("CogID") or h.get("ROLE") or "persona"
96
+ name = re.sub(r"[*]+$", "", name).strip()
97
+ return Persona(
98
+ name=name,
99
+ description=h.get("Mission", f"{name} persona"),
100
+ fields=h,
101
+ legend=extract_legend(text),
102
+ steps=extract_workflow(text),
103
+ )
104
+
105
+
106
+ def _render_body(p: Persona) -> str:
107
+ from glyphsteer import render_legend
108
+ h = p.fields
109
+ out = [f"# {h.get('ROLE', p.name)} — compiled persona", ""]
110
+ for key in ("LAW", "Mission", "FnMx", "ActsLike", "OutputWrapper"):
111
+ if h.get(key):
112
+ out.append(f"- **{key}**: {h[key]}")
113
+ out += ["", "## Legend (the glyph vocabulary)", "```", render_legend(p.legend), "```", ""]
114
+ out += ["## Workflow (⚙️ steps)", ""]
115
+ for s in p.steps:
116
+ ctrl = f" _[{', '.join(s['ctrl'])}]_" if s["ctrl"] else ""
117
+ out.append(f"{s['step']}. {s['body']}{ctrl}")
118
+ out += ["", "> Terminal output is reached only after a multi-round sequence of the "
119
+ "looping steps (the ⚙️ workflow is executable via the SI — ASPIRATIONAL)."]
120
+ return "\n".join(out)
121
+
122
+
123
+ def lint_pipeline(p: Persona) -> dict | None:
124
+ """If the legend + ChainCompiler grammar gate are available, lint a glyph chain
125
+ drawn from the legend (rulecatcher syntax gate). Returns a verdict or None."""
126
+ try:
127
+ from glyphsteer import GlyphGrammar
128
+ except Exception:
129
+ return None
130
+ glyphs = p.legend.glyphs
131
+ if len(glyphs) < 2:
132
+ return None
133
+ code = p.legend.code(glyphs[:3])
134
+ try:
135
+ with GlyphGrammar(p.legend, scope=f"persona_{slugify(p.name)}") as gg:
136
+ lint = gg.lint(code)
137
+ return {"chain": code, "verdict": lint.verdict}
138
+ except Exception:
139
+ return None
140
+
141
+
142
+ def compile_persona(text: str, out_dir: str | Path) -> dict:
143
+ """Compile a glyph-persona-program → `<cogid>/SKILL.md` + `legend.json`."""
144
+ from glyphsteer import save_legend
145
+ p = parse_persona(text)
146
+ skill_path = write_skill(p.name, p.description, _render_body(p), out_dir=out_dir,
147
+ extra={"glyphs": p.legend.code(p.legend.glyphs[:1]) or ""})
148
+ legend_path = skill_path.parent / "legend.json"
149
+ save_legend(p.legend, legend_path)
150
+ return {
151
+ "name": p.name,
152
+ "skill": str(skill_path),
153
+ "legend": str(legend_path),
154
+ "axes": len(p.legend.axes),
155
+ "steps": len(p.steps),
156
+ "gate": lint_pipeline(p),
157
+ }
chaincompiler/prime.py ADDED
@@ -0,0 +1,41 @@
1
+ """Build the re-injectable PRIME block — the output that closes the loop.
2
+
3
+ A prime is a context block that (a) tells the LLM the ratified grammar of the
4
+ notation so it generates in-shape, and (b) shows a compiled example so it knows
5
+ what the notation MEANS. Re-injecting the prime self-primes the model; every
6
+ chain it then emits is gated by the same grammar (bridge.gate).
7
+ """
8
+ from __future__ import annotations
9
+
10
+ from .bridge import compile_chain, grammar_lines
11
+
12
+
13
+ def build_prime(scope: str, adopted_rows: list, example_chain: str) -> str:
14
+ compiled = compile_chain(example_chain)
15
+ g = grammar_lines(adopted_rows)
16
+
17
+ sections = [
18
+ f'# PRIME — "{scope}" cognition-chain notation',
19
+ "",
20
+ "You think in this notation. Write cognition chains in the shape below; "
21
+ "every chain you emit is gated against the grammar (fix violations before continuing).",
22
+ "",
23
+ f"## Ratified grammar ({len(g)} rules, learned from examples)",
24
+ *(g or ["(none ratified yet)"]),
25
+ "",
26
+ "## A compiled chain (what one MEANS)",
27
+ f"chain: {example_chain.strip()}",
28
+ f"readable: {compiled['readable']}",
29
+ "",
30
+ "triples:",
31
+ *(f" {line}" for line in compiled["triples"].splitlines()),
32
+ ]
33
+ if compiled["prose"].strip():
34
+ sections += ["", "prose:", f" {compiled['prose']}"]
35
+ sections += [
36
+ "",
37
+ "## Directive",
38
+ "Emit chains of this form. End a reasoning chain with a bounded |Predict| "
39
+ "(the kill-criterion). Stay inside the grammar; the gate will reject drift.",
40
+ ]
41
+ return "\n".join(sections)
@@ -0,0 +1,12 @@
1
+ """chaincompiler.skillpack — the skill-packager, now living in the BASE.
2
+
3
+ MOVED DOWN to `prompt_engineering.skillpack` (REBUILD-SPEC.md §7 — single source of truth, D1). This
4
+ module now just re-exports it, so `from chaincompiler.skillpack import write_skill` and
5
+ `from chaincompiler import write_skill, slugify, skill_markdown` stay byte-stable for existing consumers
6
+ (archetype, the *CC tests).
7
+ """
8
+ from __future__ import annotations
9
+
10
+ from prompt_engineering.skillpack import slugify, skill_markdown, write_skill
11
+
12
+ __all__ = ["slugify", "skill_markdown", "write_skill"]
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.4
2
+ Name: chaincompiler
3
+ Version: 0.3.0
4
+ Summary: The printing press for agent cognition chains: learn → gate → compile → prime
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: honeyc==0.3.0
7
+ Requires-Dist: rulecatcher==0.3.0
8
+ Requires-Dist: agent-skilltree>=0.4.0
9
+ Requires-Dist: agent-prompt-engineering>=0.2.0
10
+ Provides-Extra: persona
11
+ Requires-Dist: glyphsteer==0.3.0; extra == "persona"
@@ -0,0 +1,10 @@
1
+ chaincompiler/__init__.py,sha256=R8JOQ24tFq7VExtGIgocDKHiy5gN7OYHSkUsA1qB-y4,1681
2
+ chaincompiler/bridge.py,sha256=uc75cN4IurAiq5Ec0o6Y_pLitmmoyybEeTdFkUS23kk,1294
3
+ chaincompiler/forge.py,sha256=kSOHwGgYexrY2vJqzhBz56XkaSZDuzQElF-PYMRx-6o,2486
4
+ chaincompiler/persona.py,sha256=2ZGI4zcAUuKYBY0DOdWHesU2oTuBeDaww4d2KTyXGno,6342
5
+ chaincompiler/prime.py,sha256=jqpN1mHO9cp_0iLDnNK7ynBy2OEtD755pTRqJJbv4so,1630
6
+ chaincompiler/skillpack.py,sha256=SEjy1XqXeDYUP-tSE0ObNhuQ9I1qGbtToFgSdOy9Oj4,575
7
+ chaincompiler-0.3.0.dist-info/METADATA,sha256=rzMK5NySvCUiXXCKEe2kHhRyGmVooG8KT8KCU0_XVjc,399
8
+ chaincompiler-0.3.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
9
+ chaincompiler-0.3.0.dist-info/top_level.txt,sha256=YqHPev5jmDAlZqEahcPBrvKEv02NYNUjUFacgVw-DSM,14
10
+ chaincompiler-0.3.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ chaincompiler