Merge pull request 'feat(drafting): טיוטת-ביניים דטרמיניסטית — Opus 4.8 + effort per-בלוק (#204)' (#356) from worktree-agent-a0d2502e8308bc27c into main
This commit was merged in pull request #356.
This commit is contained in:
@@ -480,11 +480,38 @@ Conclusion → Rule → Explanation → Application → Conclusion.
|
|||||||
|
|
||||||
## 3. כללי גזירת פרמטרים
|
## 3. כללי גזירת פרמטרים
|
||||||
|
|
||||||
פרמטרי העיבוד נגזרים ממאפייני התוכן, לא נקבעים שרירותית:
|
פרמטרי העיבוד נגזרים ממאפייני התוכן, לא נקבעים שרירותית.
|
||||||
|
|
||||||
### Temperature — נגזר מסוג הייצור
|
> **⚠️ עדכון מנגנון-הייצור (#204 / WS5).** מסלול-הייצור הוא `claude_session.query` →
|
||||||
|
> `claude -p` (מנוי claude.ai, עלות-שולית-אפס, מקומי-בלבד — ראה
|
||||||
|
> `reference_claude_generation_path`). ב-**Opus 4.7/4.8 הפרמטר `temperature` (וגם
|
||||||
|
> `top_p`/`top_k`) הוסר — שליחתו מחזירה HTTP 400**. הידית היחידה היא **`effort`**
|
||||||
|
> (low/medium/high/xhigh/max; ברירת-מחדל high). **המודל נעוץ ל-`claude-opus-4-8`
|
||||||
|
> לכל הבלוקים** ב-`block_writer.GENERATION_MODEL` — אין עוד פיצול sonnet/opus.
|
||||||
|
> טבלת ה-Temperature והעמודה `decision_blocks.temperature` הן **מטא-דאטה-מת
|
||||||
|
> (deprecated, תמיד 0)** ונשמרות רק לתאימות-עמודה; אל תקראו מהן. הטבלאות למטה
|
||||||
|
> נשמרות כתיעוד-המקור-הקונספטואלי בלבד — `effort` מחליף את "Thinking budget".
|
||||||
|
|
||||||
| Generation type | Temperature | נימוק |
|
### Effort — נגזר ממורכבות קוגניטיבית (הידית החיה)
|
||||||
|
|
||||||
|
מיפוי ה-`effort` בפועל ב-`block_writer.BLOCK_CONFIG` (#204):
|
||||||
|
|
||||||
|
| בלוק | gen_type | effort | נימוק |
|
||||||
|
|------|----------|--------|-------|
|
||||||
|
| ה (פתיחה) | paraphrase | medium | פתיחה קצרה, מבנה קבוע |
|
||||||
|
| ו (רקע) | reproduction | medium | שעתוק ניטרלי מרובה-מקורות |
|
||||||
|
| ז (טענות) | paraphrase | high | קיבוץ/סינתזת-טענות לפי-נושא |
|
||||||
|
| ח (הליכים) | reproduction | medium | תיעוד כרונולוגי |
|
||||||
|
| ט (תכניות) | guided-synthesis | high | ציטוט-תכניות מדויק (INV-AH) |
|
||||||
|
| י (דיון) | rhetorical-construction | xhigh | חשיבה רב-שלבית CREAC (מחוץ-לתחום-WS5) |
|
||||||
|
| יא (סיכום) | paraphrase | high | סינתזה אופרטיבית |
|
||||||
|
| א–ד, יב | template-fill | — (script) | מילוי-שדות, ללא LLM |
|
||||||
|
|
||||||
|
### Temperature — (DEPRECATED) נגזר היסטורית מסוג הייצור
|
||||||
|
|
||||||
|
> מסמך-מקור בלבד — לא נשלח ל-API (ראה האזהרה למעלה).
|
||||||
|
|
||||||
|
| Generation type | Temperature (היסטורי) | נימוק |
|
||||||
|----------------|-------------|-------|
|
|----------------|-------------|-------|
|
||||||
| template-fill | 0 | אין צורך בשפה — מילוי שדות |
|
| template-fill | 0 | אין צורך בשפה — מילוי שדות |
|
||||||
| reproduction | 0 | נאמנות מוחלטת למקור. אפס יצירתיות |
|
| reproduction | 0 | נאמנות מוחלטת למקור. אפס יצירתיות |
|
||||||
@@ -493,18 +520,11 @@ Conclusion → Rule → Explanation → Application → Conclusion.
|
|||||||
| analytical-reasoning | 0.3-0.4 | צריך ליצור קשרים בין עקרונות משפטיים |
|
| analytical-reasoning | 0.3-0.4 | צריך ליצור קשרים בין עקרונות משפטיים |
|
||||||
| rhetorical-construction | 0.4-0.5 | טווח ביטוי רחב לכתיבה משכנעת ואלגנטית |
|
| rhetorical-construction | 0.4-0.5 | טווח ביטוי רחב לכתיבה משכנעת ואלגנטית |
|
||||||
|
|
||||||
### Thinking budget — נגזר ממורכבות קוגניטיבית
|
### Model — (DEPRECATED) נגזר היסטורית מדרישת דיוק
|
||||||
|
|
||||||
| Cognitive task | Budget | נימוק |
|
> כעת נעוץ `claude-opus-4-8` לכל בלוקי-ה-AI (`GENERATION_MODEL`). הטבלה היסטורית.
|
||||||
|---------------|--------|-------|
|
|
||||||
| template-fill / lookup | off | אין צורך בחשיבה |
|
|
||||||
| sequential-extraction | low | חילוץ מידע חד-שלבי |
|
|
||||||
| multi-source-integration | medium | צריך להצליב מקורות |
|
|
||||||
| legal-analysis-with-CREAC | max (16K+) | חשיבה רב-שלבית: מסקנה → כלל → הסבר → יישום |
|
|
||||||
|
|
||||||
### Model — נגזר מדרישת דיוק
|
| Accuracy profile | Model (היסטורי) | נימוק |
|
||||||
|
|
||||||
| Accuracy profile | Model | נימוק |
|
|
||||||
|-----------------|-------|-------|
|
|-----------------|-------|-------|
|
||||||
| factual-precision | sonnet | מהיר, מדויק לחילוץ עובדות |
|
| factual-precision | sonnet | מהיר, מדויק לחילוץ עובדות |
|
||||||
| precision + interpretation | opus | נדרש לפרשנות תכנית / ציטוט מובנה |
|
| precision + interpretation | opus | נדרש לפרשנות תכנית / ציטוט מובנה |
|
||||||
|
|||||||
@@ -43,6 +43,16 @@
|
|||||||
> וגם **טיוטת-ביניים** (`mode="interim"` — תת-קבוצת בלוקים בסדר חדש: רקע→תכניות→טענות→הליכים,
|
> וגם **טיוטת-ביניים** (`mode="interim"` — תת-קבוצת בלוקים בסדר חדש: רקע→תכניות→טענות→הליכים,
|
||||||
> `export_interim_draft`, `drafting.py:511`). שני המצבים שולפים מאותה טבלה — וריאציית-תצוגה
|
> `export_interim_draft`, `drafting.py:511`). שני המצבים שולפים מאותה טבלה — וריאציית-תצוגה
|
||||||
> של אותו מקור-אמת, לא מסלול שני.
|
> של אותו מקור-אמת, לא מסלול שני.
|
||||||
|
>
|
||||||
|
> **דטרמיניזם-מבני של טיוטת-הביניים (#204 / WS5).** סדר-בלוקי-הביניים בייצוא קבוע
|
||||||
|
> ב-`docx_exporter._INTERIM_BLOCK_ORDER` (רקע→תכניות→טענות→הליכים, עם בלוקי-תבנית א–ה
|
||||||
|
> אופציונליים בתחילה). הבלוקים עצמם נכתבים דרך **אותו מסלול-כתיבה קנוני** של ההחלטה
|
||||||
|
> המלאה (`block_writer.write_and_store_block` → `write_block`, G2 — אין מסלול-ייצור
|
||||||
|
> מקביל), אך כעת **נעוצים למודל יחיד (`claude-opus-4-8`) עם `effort` per-בלוק ובפרומפט-
|
||||||
|
> מבני קבוע** (למשל בלוק-ה פותח תמיד ב"לפנינו ערר…"). התוצאה: אותו תיק מפיק את אותו
|
||||||
|
> **מבנה** בכל ריצה (אי-עקביות-הניסוח הקודמת נבעה מפרומפט-חופשי + מודל-ברירת-מחדל לא-נעוץ).
|
||||||
|
> טמפרטורה אינה במסלול (Opus 4.7/4.8 דוחים אותה); ראה `block_writer.GENERATION_MODEL`
|
||||||
|
> + `BLOCK_CONFIG[*].effort`.
|
||||||
> - `analysis_docx_exporter.py` (`build_analysis_docx`, `:401`) — מייצא את מסמך **הניתוח
|
> - `analysis_docx_exporter.py` (`build_analysis_docx`, `:401`) — מייצא את מסמך **הניתוח
|
||||||
> המשפטי** (`analysis-and-research.md`) שכתב `legal-analyst`, לא את בלוקי-ההחלטה. זהו תוצר-עזר
|
> המשפטי** (`analysis-and-research.md`) שכתב `legal-analyst`, לא את בלוקי-ההחלטה. זהו תוצר-עזר
|
||||||
> שונה (שלב ניתוח, לא החלטה) — והוא המסלול שהסקיל מתעד בעיקר. שניהם חולקים את **אותו טמפלט
|
> שונה (שלב ניתוח, לא החלטה) — והוא המסלול שהסקיל מתעד בעיקר. שניהם חולקים את **אותו טמפלט
|
||||||
|
|||||||
@@ -35,29 +35,53 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
# ── Block configuration ───────────────────────────────────────────
|
# ── Block configuration ───────────────────────────────────────────
|
||||||
|
|
||||||
# Output token limits per Anthropic docs:
|
# Generation is structurally deterministic (#204 / WS5): every AI block is
|
||||||
# Opus 4.7: up to 128K output tokens (new tokenizer — ~35% more tokens)
|
# pinned to ONE model (Opus 4.8) with a per-block reasoning `effort`. The
|
||||||
# Sonnet 4.6: up to 64K output tokens
|
# generation path is claude_session.query → `claude -p` (subscription, near-zero
|
||||||
# Streaming required when max_tokens > 21,333
|
# cost; local-only — see reference_claude_generation_path / claude_session
|
||||||
|
# docstring). Opus 4.7/4.8 REMOVED temperature/top_p/top_k (sending them → HTTP
|
||||||
|
# 400); the only knob is `effort` (low/medium/high/xhigh/max; default high).
|
||||||
|
#
|
||||||
|
# DEPRECATED FIELDS — DO NOT REINTRODUCE: earlier revisions carried per-block
|
||||||
|
# `temp` (0/0.1/0.4) and `model` ("sonnet"/"opus"/"script"). Both were DEAD
|
||||||
|
# METADATA: write_block called claude_session.query(prompt, …) WITHOUT model/
|
||||||
|
# temp/effort, so generation ran on the CLI's default model with no temperature
|
||||||
|
# knob at all (the table only stored a number in decision_blocks.temperature and
|
||||||
|
# fed MODEL_MAP→timeout). They are removed here so the table no longer misleads.
|
||||||
|
# The conceptual origin (gen_type → thinking-budget) now lives in `effort`; see
|
||||||
|
# docs/block-schema.md §3.
|
||||||
|
#
|
||||||
|
# `gen_type` is retained (documentation/UI metadata + audit `generation_type`).
|
||||||
|
# `model` below is the DISPATCH key only: "script" = template-fill (no LLM),
|
||||||
|
# "ai" = generated via the pinned Opus model. It is NOT a model alias anymore.
|
||||||
|
#
|
||||||
|
# Output token note (Anthropic): Opus 4.8 supports large outputs; streaming is
|
||||||
|
# handled by the CLI. `max_tokens` is advisory context for callers, not sent.
|
||||||
|
GENERATION_MODEL = "claude-opus-4-8" # single pinned model for every AI block (#204)
|
||||||
|
|
||||||
BLOCK_CONFIG = {
|
BLOCK_CONFIG = {
|
||||||
"block-alef": {"index": 1, "title": "כותרת מוסדית", "gen_type": "template-fill", "temp": 0, "model": "script"},
|
"block-alef": {"index": 1, "title": "כותרת מוסדית", "gen_type": "template-fill", "model": "script"},
|
||||||
"block-bet": {"index": 2, "title": "הרכב הוועדה", "gen_type": "template-fill", "temp": 0, "model": "script"},
|
"block-bet": {"index": 2, "title": "הרכב הוועדה", "gen_type": "template-fill", "model": "script"},
|
||||||
"block-gimel":{"index": 3, "title": "צדדים", "gen_type": "template-fill", "temp": 0, "model": "script"},
|
"block-gimel":{"index": 3, "title": "צדדים", "gen_type": "template-fill", "model": "script"},
|
||||||
"block-dalet":{"index": 4, "title": "החלטה", "gen_type": "template-fill", "temp": 0, "model": "script"},
|
"block-dalet":{"index": 4, "title": "החלטה", "gen_type": "template-fill", "model": "script"},
|
||||||
"block-he": {"index": 5, "title": "פתיחה", "gen_type": "paraphrase", "temp": 0.2, "model": "sonnet", "max_tokens": 4096},
|
"block-he": {"index": 5, "title": "פתיחה", "gen_type": "paraphrase", "model": "ai", "effort": "medium", "max_tokens": 4096},
|
||||||
"block-vav": {"index": 6, "title": "רקע עובדתי", "gen_type": "reproduction", "temp": 0, "model": "sonnet", "max_tokens": 16384},
|
"block-vav": {"index": 6, "title": "רקע עובדתי", "gen_type": "reproduction", "model": "ai", "effort": "medium", "max_tokens": 16384},
|
||||||
"block-zayin":{"index": 7, "title": "טענות הצדדים", "gen_type": "paraphrase", "temp": 0.1, "model": "sonnet", "max_tokens": 16384},
|
"block-zayin":{"index": 7, "title": "טענות הצדדים", "gen_type": "paraphrase", "model": "ai", "effort": "high", "max_tokens": 16384},
|
||||||
"block-chet": {"index": 8, "title": "הליכים", "gen_type": "reproduction", "temp": 0, "model": "sonnet", "max_tokens": 8192},
|
"block-chet": {"index": 8, "title": "הליכים", "gen_type": "reproduction", "model": "ai", "effort": "medium", "max_tokens": 8192},
|
||||||
"block-tet": {"index": 9, "title": "תכניות חלות", "gen_type": "guided-synthesis", "temp": 0.2, "model": "opus", "max_tokens": 16384},
|
"block-tet": {"index": 9, "title": "תכניות חלות", "gen_type": "guided-synthesis", "model": "ai", "effort": "high", "max_tokens": 16384},
|
||||||
"block-yod": {"index": 10, "title": "דיון והכרעה", "gen_type": "rhetorical-construction", "temp": 0.4, "model": "opus", "max_tokens": 16384},
|
"block-yod": {"index": 10, "title": "דיון והכרעה", "gen_type": "rhetorical-construction", "model": "ai", "effort": "xhigh", "max_tokens": 16384},
|
||||||
"block-yod-alef": {"index": 11, "title": "סיכום", "gen_type": "paraphrase", "temp": 0.1, "model": "sonnet", "max_tokens": 8192},
|
"block-yod-alef": {"index": 11, "title": "סיכום", "gen_type": "paraphrase", "model": "ai", "effort": "high", "max_tokens": 8192},
|
||||||
"block-yod-bet": {"index": 12, "title": "חתימות", "gen_type": "template-fill", "temp": 0, "model": "script"},
|
"block-yod-bet": {"index": 12, "title": "חתימות", "gen_type": "template-fill", "model": "script"},
|
||||||
}
|
}
|
||||||
|
|
||||||
MODEL_MAP = {
|
# Default effort when a block lacks an explicit one (defensive; every AI block
|
||||||
"sonnet": "claude-sonnet-4-20250514",
|
# above sets one). High is the safe default per the generation-path reference.
|
||||||
"opus": "claude-opus-4-7",
|
DEFAULT_EFFORT = "high"
|
||||||
}
|
|
||||||
|
# Blocks that take longer (deep reasoning) get the LONG timeout. The interim set
|
||||||
|
# [he, vav, tet, zayin, chet] and the discussion block all run on the same pinned
|
||||||
|
# Opus model, so timeout is driven by effort, not by a model split.
|
||||||
|
_LONG_EFFORTS = frozenset({"high", "xhigh", "max"})
|
||||||
|
|
||||||
|
|
||||||
# ── Template blocks (א-ד, יב) ────────────────────────────────────
|
# ── Template blocks (א-ד, יב) ────────────────────────────────────
|
||||||
@@ -120,11 +144,14 @@ TEMPLATE_WRITERS = {
|
|||||||
BLOCK_PROMPTS = {
|
BLOCK_PROMPTS = {
|
||||||
"block-he": """כתוב את בלוק הפתיחה (בלוק ה) של החלטת ועדת ערר.
|
"block-he": """כתוב את בלוק הפתיחה (בלוק ה) של החלטת ועדת ערר.
|
||||||
|
|
||||||
## כללים:
|
## מבנה קבוע (חובה — אותו מבנה בכל תיק):
|
||||||
- פתח ב"לפנינו ערר..." או "עניינה של החלטה זו..."
|
- **המשפט הראשון פותח תמיד במילה "לפנינו"** — נוסח קבוע: "לפנינו ערר על החלטת
|
||||||
- הגדר "להלן" מרכזיים: הוועדה המקומית, התכנית/הבקשה, המגרש
|
[הוועדה המקומית] מיום [תאריך] בעניין [נושא הבקשה/התכנית]." (אל תשתמש ב"עניינה של
|
||||||
- 1-2 סעיפים בלבד
|
החלטה זו" או בכל פתיח חלופי — הפתיח אחיד.)
|
||||||
- אין ניתוח, אין ערכי שיפוט, אין ציטוטים מצדדים
|
- סעיף 1: הצגת הערר במשפט הקבוע לעיל + הגדרת ה"להלן" המרכזיים בסדר קבוע:
|
||||||
|
הוועדה המקומית → התכנית/הבקשה → המגרש/המקרקעין.
|
||||||
|
- סעיף 2 (רק אם נדרש להשלמת "להלן" נוספים): הגדרות-נוספות בלבד.
|
||||||
|
- **בדיוק 1-2 סעיפים.** אין ניתוח, אין ערכי שיפוט, אין ציטוטים מצדדים.
|
||||||
- מספור: 1.
|
- מספור: 1.
|
||||||
|
|
||||||
## פרטי התיק:
|
## פרטי התיק:
|
||||||
@@ -441,10 +468,19 @@ async def write_block(
|
|||||||
f"Reduce documents or call extract_appraiser_facts first."
|
f"Reduce documents or call extract_appraiser_facts first."
|
||||||
)
|
)
|
||||||
|
|
||||||
# Call Claude via Claude Code session (no API)
|
# Call Claude via Claude Code session (no API). #204: pin the model + per-block
|
||||||
model_key = block_cfg["model"]
|
# reasoning effort so generation is structurally deterministic — these were
|
||||||
timeout = claude_session.LONG_TIMEOUT if model_key == "opus" else claude_session.DEFAULT_TIMEOUT
|
# previously NOT forwarded (the source of inconsistency). model/effort flow
|
||||||
content = await claude_session.query(prompt, timeout=timeout, tools="") # prose gen — no tool_use → no error_max_turns
|
# through claude_session.query → `claude -p --model … --effort …`.
|
||||||
|
effort = block_cfg.get("effort", DEFAULT_EFFORT)
|
||||||
|
timeout = claude_session.LONG_TIMEOUT if effort in _LONG_EFFORTS else claude_session.DEFAULT_TIMEOUT
|
||||||
|
content = await claude_session.query(
|
||||||
|
prompt,
|
||||||
|
timeout=timeout,
|
||||||
|
model=GENERATION_MODEL,
|
||||||
|
effort=effort,
|
||||||
|
tools="", # prose gen — no tool_use → no error_max_turns
|
||||||
|
)
|
||||||
|
|
||||||
sources = await _collect_block_sources(case_id, block_id)
|
sources = await _collect_block_sources(case_id, block_id)
|
||||||
sources["case_law_ids"] = _precedent_case_law_ids
|
sources["case_law_ids"] = _precedent_case_law_ids
|
||||||
@@ -455,6 +491,7 @@ async def write_block(
|
|||||||
|
|
||||||
def _build_result(block_id: str, content: str, block_cfg: dict) -> dict:
|
def _build_result(block_id: str, content: str, block_cfg: dict) -> dict:
|
||||||
word_count = len(content.split())
|
word_count = len(content.split())
|
||||||
|
is_ai = block_cfg["model"] == "ai"
|
||||||
return {
|
return {
|
||||||
"block_id": block_id,
|
"block_id": block_id,
|
||||||
"block_index": block_cfg["index"],
|
"block_index": block_cfg["index"],
|
||||||
@@ -462,8 +499,14 @@ def _build_result(block_id: str, content: str, block_cfg: dict) -> dict:
|
|||||||
"content": content,
|
"content": content,
|
||||||
"word_count": word_count,
|
"word_count": word_count,
|
||||||
"generation_type": block_cfg["gen_type"],
|
"generation_type": block_cfg["gen_type"],
|
||||||
"model_used": block_cfg["model"],
|
# AI blocks record the pinned model; template blocks record "script".
|
||||||
"temperature": block_cfg["temp"],
|
"model_used": GENERATION_MODEL if is_ai else block_cfg["model"],
|
||||||
|
# The real generation knob (#204). None for template/script blocks.
|
||||||
|
"effort": block_cfg.get("effort", DEFAULT_EFFORT) if is_ai else None,
|
||||||
|
# DEPRECATED: temperature is not a real knob on Opus 4.7/4.8 (sending it
|
||||||
|
# → HTTP 400). Kept only to satisfy decision_blocks.temperature
|
||||||
|
# NUMERIC(3,2); always 0. Read `effort` instead.
|
||||||
|
"temperature": 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -516,9 +516,18 @@ async def export_docx(case_number: str, output_path: str = "") -> str:
|
|||||||
|
|
||||||
# ── Interim draft (pre-ruling) ────────────────────────────────────
|
# ── Interim draft (pre-ruling) ────────────────────────────────────
|
||||||
|
|
||||||
# Blocks written for the interim draft, in display order.
|
# Blocks written for the interim draft, in a FIXED order.
|
||||||
# This is the same content the chair sees in the final decision (same template,
|
# This is the same content the chair sees in the final decision (same template,
|
||||||
# same skill, same prompts) — minus opening, ruling, summary, signatures.
|
# same skill, same prompts, same single canonical write path — block_writer) —
|
||||||
|
# minus ruling, summary, signatures.
|
||||||
|
#
|
||||||
|
# Determinism (#204 / WS5): the interim draft is STRUCTURALLY deterministic.
|
||||||
|
# Each block is generated by block_writer.write_block, which now pins the model
|
||||||
|
# (Opus 4.8) and a per-block reasoning effort, and uses fixed structural prompts
|
||||||
|
# (e.g. block-he's opening is always "לפנינו ערר…"). The display order on export
|
||||||
|
# is fixed separately by docx_exporter._INTERIM_BLOCK_ORDER. There is no parallel
|
||||||
|
# generation path (G2): write_interim_draft is a thin orchestrator over the same
|
||||||
|
# write_and_store_block used by the full decision.
|
||||||
_INTERIM_BLOCKS = ["block-he", "block-vav", "block-tet", "block-zayin", "block-chet"]
|
_INTERIM_BLOCKS = ["block-he", "block-vav", "block-tet", "block-zayin", "block-chet"]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ function BlockRow({ block }: { block: McpBlock }) {
|
|||||||
<Badge variant="outline" className="text-[0.7rem] font-mono" dir="ltr">
|
<Badge variant="outline" className="text-[0.7rem] font-mono" dir="ltr">
|
||||||
{block.model}
|
{block.model}
|
||||||
</Badge>
|
</Badge>
|
||||||
{isLLM && block.temperature !== null && (
|
{isLLM && block.effort !== null && (
|
||||||
<Badge variant="outline" className="text-[0.7rem]">
|
<Badge variant="outline" className="text-[0.7rem]" dir="ltr">
|
||||||
temp <span className="tabular-nums">{block.temperature}</span>
|
effort <span className="tabular-nums">{block.effort}</span>
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
{block.max_tokens !== null && (
|
{block.max_tokens !== null && (
|
||||||
|
|||||||
@@ -176,7 +176,9 @@ export type McpBlock = {
|
|||||||
title: string;
|
title: string;
|
||||||
gen_type: string;
|
gen_type: string;
|
||||||
model: string;
|
model: string;
|
||||||
temperature: number | null;
|
// The live generation knob (#204). Replaces the deprecated `temperature` —
|
||||||
|
// Opus 4.7/4.8 have no temperature param. null for template ("script") blocks.
|
||||||
|
effort: string | null;
|
||||||
max_tokens: number | null;
|
max_tokens: number | null;
|
||||||
creac_role: string | null;
|
creac_role: string | null;
|
||||||
jwm_purpose: string | null;
|
jwm_purpose: string | null;
|
||||||
|
|||||||
10
web/app.py
10
web/app.py
@@ -4626,15 +4626,21 @@ async def api_mcp_blocks():
|
|||||||
"block-yod-alef": "Disposition",
|
"block-yod-alef": "Disposition",
|
||||||
"block-yod-bet": "Disposition (signatures)",
|
"block-yod-bet": "Disposition (signatures)",
|
||||||
}
|
}
|
||||||
|
from legal_mcp.services.block_writer import GENERATION_MODEL
|
||||||
|
|
||||||
blocks = []
|
blocks = []
|
||||||
for block_id, cfg in sorted(BLOCK_CONFIG.items(), key=lambda kv: kv[1]["index"]):
|
for block_id, cfg in sorted(BLOCK_CONFIG.items(), key=lambda kv: kv[1]["index"]):
|
||||||
|
is_ai = cfg["model"] == "ai"
|
||||||
blocks.append({
|
blocks.append({
|
||||||
"id": block_id,
|
"id": block_id,
|
||||||
"index": cfg["index"],
|
"index": cfg["index"],
|
||||||
"title": cfg["title"],
|
"title": cfg["title"],
|
||||||
"gen_type": cfg["gen_type"],
|
"gen_type": cfg["gen_type"],
|
||||||
"model": cfg["model"],
|
# AI blocks are pinned to one model (#204); template blocks = "script".
|
||||||
"temperature": cfg.get("temp"),
|
"model": GENERATION_MODEL if is_ai else cfg["model"],
|
||||||
|
# The live generation knob (replaces the deprecated `temperature`,
|
||||||
|
# which is not a real param on Opus 4.7/4.8). None for template blocks.
|
||||||
|
"effort": cfg.get("effort") if is_ai else None,
|
||||||
"max_tokens": cfg.get("max_tokens"),
|
"max_tokens": cfg.get("max_tokens"),
|
||||||
"creac_role": CREAC_ROLE.get(block_id),
|
"creac_role": CREAC_ROLE.get(block_id),
|
||||||
"jwm_purpose": JWM_PURPOSE.get(block_id),
|
"jwm_purpose": JWM_PURPOSE.get(block_id),
|
||||||
|
|||||||
Reference in New Issue
Block a user