Clean up nested duplicate: v2/v2/engine/synthesis.py
Browse files- v2/v2/engine/synthesis.py +0 -149
v2/v2/engine/synthesis.py
DELETED
|
@@ -1,149 +0,0 @@
|
|
| 1 |
-
"""Synthesis chip — the only place Rivet calls the model.
|
| 2 |
-
|
| 3 |
-
Everything upstream in the DAG is evidence gathering; everything
|
| 4 |
-
downstream is verification. The prompt is assembled from:
|
| 5 |
-
|
| 6 |
-
- the BDI beliefs relevant to this intent (constraints first)
|
| 7 |
-
- upstream artifacts (real source excerpts, migration/security reports)
|
| 8 |
-
- Pharos-routed knowledge packs (KV-injected on the transformers
|
| 9 |
-
backend, system-context on Ollama)
|
| 10 |
-
- the conversation history for this session
|
| 11 |
-
|
| 12 |
-
The chip never sees raw context files — beliefs and artifacts are the
|
| 13 |
-
interface. If it isn't in the BDI or an artifact, Rivet doesn't claim it.
|
| 14 |
-
"""
|
| 15 |
-
|
| 16 |
-
import json
|
| 17 |
-
|
| 18 |
-
from kintsugi_core import (
|
| 19 |
-
BaseSkillChip,
|
| 20 |
-
BDIStore,
|
| 21 |
-
EFEWeights,
|
| 22 |
-
SkillCapability,
|
| 23 |
-
SkillContext,
|
| 24 |
-
SkillDomain,
|
| 25 |
-
SkillRequest,
|
| 26 |
-
SkillResponse,
|
| 27 |
-
)
|
| 28 |
-
|
| 29 |
-
RIVET_SYSTEM = """You are Rivet, a senior engineer embedded with the \
|
| 30 |
-
Multiverse Campus team.
|
| 31 |
-
|
| 32 |
-
## Non-negotiable rules
|
| 33 |
-
1. Never suggest a destructive migration (DROP, TRUNCATE, in-place type \
|
| 34 |
-
change, RENAME). Staging and prod share the database. If asked for one, \
|
| 35 |
-
give the additive multi-step alternative instead — and never print the \
|
| 36 |
-
destructive statement, not even as a "don't do this" example.
|
| 37 |
-
2. Every code suggestion states: what it changes, what it could break, \
|
| 38 |
-
and what tests verify it.
|
| 39 |
-
3. If you have not read the relevant source (check the SOURCE EVIDENCE \
|
| 40 |
-
section), say you are reasoning from architecture, not source.
|
| 41 |
-
4. Auth changes get an explicit callout: "This touches authentication. \
|
| 42 |
-
Review with security before merging."
|
| 43 |
-
5. Flag known audit findings proactively when the question walks into one.
|
| 44 |
-
6. You are a colleague, not the lead. Suggest, don't decree.
|
| 45 |
-
"""
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
def _format_beliefs(bdi: BDIStore, belief_ids: list) -> str:
|
| 49 |
-
lines = []
|
| 50 |
-
for bid in belief_ids:
|
| 51 |
-
b = bdi.get_belief(bid)
|
| 52 |
-
if b is not None:
|
| 53 |
-
lines.append(f"- ({b.confidence:.2f}) {b.content}")
|
| 54 |
-
return "\n".join(lines) if lines else "(none loaded)"
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
def _format_analysis(analysis: dict) -> str:
|
| 58 |
-
if not analysis or not analysis.get("files"):
|
| 59 |
-
notes = "; ".join(analysis.get("notes", [])) if analysis else ""
|
| 60 |
-
return f"No source files were read for this request. {notes}".strip()
|
| 61 |
-
parts = []
|
| 62 |
-
for f in analysis["files"]:
|
| 63 |
-
header = f"### {f['path']}"
|
| 64 |
-
if f.get("git_status"):
|
| 65 |
-
header += f" (git: {f['git_status']} — uncommitted changes!)"
|
| 66 |
-
parts.append(f"{header}\n```\n{f['excerpt']}\n```")
|
| 67 |
-
if f.get("recent_history"):
|
| 68 |
-
parts.append(f"Recent commits touching this file:\n{f['recent_history']}")
|
| 69 |
-
return "\n\n".join(parts)
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
def _format_report(name: str, report: dict) -> str:
|
| 73 |
-
if not report:
|
| 74 |
-
return ""
|
| 75 |
-
return f"## {name}\n```json\n{json.dumps(report, indent=2, default=str)[:4000]}\n```"
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
class SynthesisChip(BaseSkillChip):
|
| 79 |
-
name = "synthesis"
|
| 80 |
-
description = "Generate the draft answer from evidence + beliefs + packs"
|
| 81 |
-
version = "2.0.0"
|
| 82 |
-
domain = SkillDomain.GENERAL
|
| 83 |
-
efe_weights = EFEWeights()
|
| 84 |
-
capabilities = [SkillCapability.EXTERNAL_API]
|
| 85 |
-
|
| 86 |
-
def __init__(self, model_client, bdi: BDIStore, pharos_router=None,
|
| 87 |
-
max_tokens: int = 1536):
|
| 88 |
-
super().__init__()
|
| 89 |
-
self.model = model_client
|
| 90 |
-
self.bdi = bdi
|
| 91 |
-
self.pharos = pharos_router
|
| 92 |
-
self.max_tokens = max_tokens
|
| 93 |
-
|
| 94 |
-
async def handle(self, request: SkillRequest,
|
| 95 |
-
context: SkillContext) -> SkillResponse:
|
| 96 |
-
question = context.metadata.get("question", request.raw_input)
|
| 97 |
-
session = context.metadata.get("session")
|
| 98 |
-
belief_ids = context.metadata.get("belief_ids", [])
|
| 99 |
-
|
| 100 |
-
# Pharos: route the question to knowledge packs.
|
| 101 |
-
knowledge, pack_names = "", []
|
| 102 |
-
if self.pharos is not None:
|
| 103 |
-
routed = self.pharos.route(question)
|
| 104 |
-
knowledge = routed.knowledge_text
|
| 105 |
-
pack_names = routed.pack_names
|
| 106 |
-
if session and pack_names:
|
| 107 |
-
for p in pack_names:
|
| 108 |
-
session.record_evidence("pharos_pack", p, self.name)
|
| 109 |
-
|
| 110 |
-
prompt_parts = ["# ORGANIZATIONAL BELIEFS (BDI)\n"
|
| 111 |
-
+ _format_beliefs(self.bdi, belief_ids)]
|
| 112 |
-
|
| 113 |
-
analysis = request.parameters.get("analysis") or {}
|
| 114 |
-
prompt_parts.append("# SOURCE EVIDENCE\n" + _format_analysis(analysis))
|
| 115 |
-
|
| 116 |
-
for key, title in (
|
| 117 |
-
("migration_report", "MIGRATION SAFETY REPORT"),
|
| 118 |
-
("security_report", "SECURITY REVIEW REPORT"),
|
| 119 |
-
):
|
| 120 |
-
block = _format_report(title, request.parameters.get(key) or {})
|
| 121 |
-
if block:
|
| 122 |
-
prompt_parts.append(block)
|
| 123 |
-
|
| 124 |
-
if session and session.history:
|
| 125 |
-
recent = session.history[-6:]
|
| 126 |
-
convo = "\n".join(f"{t['role']}: {t['content'][:400]}" for t in recent)
|
| 127 |
-
prompt_parts.append(f"# CONVERSATION SO FAR\n{convo}")
|
| 128 |
-
|
| 129 |
-
prompt_parts.append(f"# QUESTION\n{question}")
|
| 130 |
-
prompt = "\n\n".join(prompt_parts)
|
| 131 |
-
|
| 132 |
-
reply = self.model.generate(
|
| 133 |
-
prompt, system=RIVET_SYSTEM, knowledge=knowledge,
|
| 134 |
-
max_tokens=self.max_tokens,
|
| 135 |
-
)
|
| 136 |
-
if not reply.ok:
|
| 137 |
-
return SkillResponse(
|
| 138 |
-
content=f"model call failed: {reply.error}", success=False,
|
| 139 |
-
data={"text": "", "error": reply.error},
|
| 140 |
-
)
|
| 141 |
-
return SkillResponse(
|
| 142 |
-
content="draft generated", success=True,
|
| 143 |
-
data={
|
| 144 |
-
"text": reply.text,
|
| 145 |
-
"backend": reply.backend,
|
| 146 |
-
"knowledge_injected": reply.knowledge_injected,
|
| 147 |
-
"packs_used": pack_names,
|
| 148 |
-
},
|
| 149 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|