@jaggerxtrm/specialists 3.17.0 → 3.18.1
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 +268 -134
- package/config/mandatory-rules/executor-delivery.md +4 -0
- package/config/mandatory-rules/json-only-final-output.md +13 -0
- package/config/mandatory-rules/service-skills-diff-scan-mandatory.md +26 -0
- package/config/mandatory-rules/service-skills-gitnexus-triage.md +5 -0
- package/config/mandatory-rules/test-runner-execution-scope.md +4 -0
- package/config/skills/setup-specialists/SKILL.md +556 -0
- package/config/skills/specialists-creator/SKILL.md +132 -4
- package/config/skills/specialists-creator/scripts/audit-spec-uniformity.mjs +1 -1
- package/config/skills/using-specialists-v3/SKILL.md +80 -20
- package/config/specialists/bare.specialist.json +3 -3
- package/config/specialists/changelog-drafter.specialist.json +5 -4
- package/config/specialists/changelog-keeper.specialist.json +7 -6
- package/config/specialists/debugger.specialist.json +2 -2
- package/config/specialists/executor.specialist.json +2 -2
- package/config/specialists/explorer.specialist.json +4 -4
- package/config/specialists/memory-processor.specialist.json +3 -3
- package/config/specialists/node-coordinator.specialist.json +3 -3
- package/config/specialists/obligations-scanner.specialist.json +67 -17
- package/config/specialists/overthinker.specialist.json +3 -3
- package/config/specialists/planner.specialist.json +4 -4
- package/config/specialists/quant-methodologist.specialist.json +145 -0
- package/config/specialists/quant-researcher.specialist.json +144 -0
- package/config/specialists/researcher.specialist.json +5 -5
- package/config/specialists/reviewer.specialist.json +1 -1
- package/config/specialists/seconder.specialist.json +2 -2
- package/config/specialists/security-auditor.specialist.json +2 -2
- package/config/specialists/service-skills-sync.specialist.json +90 -75
- package/config/specialists/specialists-creator.specialist.json +4 -4
- package/config/specialists/sync-docs.specialist.json +4 -4
- package/config/specialists/test-engineer.specialist.json +3 -3
- package/config/specialists/test-runner.specialist.json +7 -7
- package/config/specialists/transcriber.specialist.json +3 -3
- package/config/specialists/xt-merge.specialist.json +4 -4
- package/dist/asset-contract.json +22 -3
- package/dist/index.js +28711 -18517
- package/dist/lib.js +10020 -6150
- package/dist/types/cli/console/components.d.ts +83 -0
- package/dist/types/cli/console/components.d.ts.map +1 -0
- package/dist/types/cli/console/config-source.d.ts +58 -0
- package/dist/types/cli/console/config-source.d.ts.map +1 -0
- package/dist/types/cli/console/forensic.d.ts +11 -0
- package/dist/types/cli/console/forensic.d.ts.map +1 -0
- package/dist/types/cli/console/git.d.ts +28 -0
- package/dist/types/cli/console/git.d.ts.map +1 -0
- package/dist/types/cli/console/help.d.ts +2 -0
- package/dist/types/cli/console/help.d.ts.map +1 -0
- package/dist/types/cli/console/log.d.ts +13 -0
- package/dist/types/cli/console/log.d.ts.map +1 -0
- package/dist/types/cli/console/repo-config.d.ts +26 -0
- package/dist/types/cli/console/repo-config.d.ts.map +1 -0
- package/dist/types/cli/console/repo-discovery.d.ts +12 -0
- package/dist/types/cli/console/repo-discovery.d.ts.map +1 -0
- package/dist/types/cli/console/runtime.d.ts +12 -0
- package/dist/types/cli/console/runtime.d.ts.map +1 -0
- package/dist/types/cli/console/subscribe-prototype.d.ts +18 -0
- package/dist/types/cli/console/subscribe-prototype.d.ts.map +1 -0
- package/dist/types/cli/console/theme.d.ts +91 -0
- package/dist/types/cli/console/theme.d.ts.map +1 -0
- package/dist/types/cli/console/types.d.ts +231 -0
- package/dist/types/cli/console/types.d.ts.map +1 -0
- package/dist/types/cli/console/view-model.d.ts +252 -0
- package/dist/types/cli/console/view-model.d.ts.map +1 -0
- package/dist/types/cli/console.d.ts +2 -0
- package/dist/types/cli/console.d.ts.map +1 -0
- package/dist/types/cli/db.d.ts.map +1 -1
- package/dist/types/cli/doctor.d.ts.map +1 -1
- package/dist/types/cli/edit.d.ts.map +1 -1
- package/dist/types/cli/epic.d.ts.map +1 -1
- package/dist/types/cli/feed.d.ts.map +1 -1
- package/dist/types/cli/forensic.d.ts +2 -0
- package/dist/types/cli/forensic.d.ts.map +1 -0
- package/dist/types/cli/format-helpers.d.ts +4 -2
- package/dist/types/cli/format-helpers.d.ts.map +1 -1
- package/dist/types/cli/help.d.ts.map +1 -1
- package/dist/types/cli/init.d.ts +10 -0
- package/dist/types/cli/init.d.ts.map +1 -1
- package/dist/types/cli/list.d.ts.map +1 -1
- package/dist/types/cli/log.d.ts.map +1 -1
- package/dist/types/cli/merge.d.ts.map +1 -1
- package/dist/types/cli/metrics.d.ts +2 -0
- package/dist/types/cli/metrics.d.ts.map +1 -0
- package/dist/types/cli/ps.d.ts.map +1 -1
- package/dist/types/cli/result.d.ts.map +1 -1
- package/dist/types/cli/run.d.ts +20 -0
- package/dist/types/cli/run.d.ts.map +1 -1
- package/dist/types/cli/script.d.ts +3 -0
- package/dist/types/cli/script.d.ts.map +1 -1
- package/dist/types/cli/serve.d.ts.map +1 -1
- package/dist/types/cli/setup.d.ts +19 -1
- package/dist/types/cli/setup.d.ts.map +1 -1
- package/dist/types/cli/status.d.ts.map +1 -1
- package/dist/types/cli/version-check.d.ts +1 -0
- package/dist/types/cli/version-check.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/pi/session.d.ts +12 -1
- package/dist/types/pi/session.d.ts.map +1 -1
- package/dist/types/server.d.ts +15 -0
- package/dist/types/server.d.ts.map +1 -1
- package/dist/types/specialist/benchmarks.d.ts +37 -0
- package/dist/types/specialist/benchmarks.d.ts.map +1 -0
- package/dist/types/specialist/chain-identity.d.ts +7 -1
- package/dist/types/specialist/chain-identity.d.ts.map +1 -1
- package/dist/types/specialist/control.d.ts.map +1 -1
- package/dist/types/specialist/dead-job-audit.d.ts +20 -0
- package/dist/types/specialist/dead-job-audit.d.ts.map +1 -0
- package/dist/types/specialist/forensic-events.d.ts +138 -0
- package/dist/types/specialist/forensic-events.d.ts.map +1 -0
- package/dist/types/specialist/forensic-renderer.d.ts +34 -0
- package/dist/types/specialist/forensic-renderer.d.ts.map +1 -0
- package/dist/types/specialist/git-diff-evidence.d.ts +28 -0
- package/dist/types/specialist/git-diff-evidence.d.ts.map +1 -0
- package/dist/types/specialist/global-config.d.ts +389 -0
- package/dist/types/specialist/global-config.d.ts.map +1 -0
- package/dist/types/specialist/launch.d.ts +9 -0
- package/dist/types/specialist/launch.d.ts.map +1 -1
- package/dist/types/specialist/live-aggregates.d.ts +46 -0
- package/dist/types/specialist/live-aggregates.d.ts.map +1 -0
- package/dist/types/specialist/loader.d.ts +50 -1
- package/dist/types/specialist/loader.d.ts.map +1 -1
- package/dist/types/specialist/model-chain.d.ts +7 -0
- package/dist/types/specialist/model-chain.d.ts.map +1 -0
- package/dist/types/specialist/model-probes.d.ts +28 -0
- package/dist/types/specialist/model-probes.d.ts.map +1 -0
- package/dist/types/specialist/node-contract.d.ts +18 -18
- package/dist/types/specialist/node-supervisor.d.ts.map +1 -1
- package/dist/types/specialist/observability-db.d.ts +1 -1
- package/dist/types/specialist/observability-db.d.ts.map +1 -1
- package/dist/types/specialist/observability-sqlite.d.ts +101 -0
- package/dist/types/specialist/observability-sqlite.d.ts.map +1 -1
- package/dist/types/specialist/pr-drift-refresh.d.ts +17 -0
- package/dist/types/specialist/pr-drift-refresh.d.ts.map +1 -0
- package/dist/types/specialist/preset-resolver.d.ts +56 -0
- package/dist/types/specialist/preset-resolver.d.ts.map +1 -0
- package/dist/types/specialist/prometheus-projection.d.ts +25 -0
- package/dist/types/specialist/prometheus-projection.d.ts.map +1 -0
- package/dist/types/specialist/runner.d.ts +29 -1
- package/dist/types/specialist/runner.d.ts.map +1 -1
- package/dist/types/specialist/schema.d.ts +163 -54
- package/dist/types/specialist/schema.d.ts.map +1 -1
- package/dist/types/specialist/script-runner.d.ts +5 -1
- package/dist/types/specialist/script-runner.d.ts.map +1 -1
- package/dist/types/specialist/snapshot-diff.d.ts +8 -0
- package/dist/types/specialist/snapshot-diff.d.ts.map +1 -0
- package/dist/types/specialist/source-queue.d.ts +13 -0
- package/dist/types/specialist/source-queue.d.ts.map +1 -0
- package/dist/types/specialist/status-load.d.ts.map +1 -1
- package/dist/types/specialist/supervisor.d.ts +25 -1
- package/dist/types/specialist/supervisor.d.ts.map +1 -1
- package/dist/types/specialist/timeline-events.d.ts +70 -1
- package/dist/types/specialist/timeline-events.d.ts.map +1 -1
- package/dist/types/tools/specialist/resume_specialist.tool.d.ts +4 -4
- package/dist/types/tools/specialist/specialist_status.tool.d.ts +1 -1
- package/dist/types/tools/specialist/steer_specialist.tool.d.ts +4 -4
- package/dist/types/tools/specialist/use_specialist.tool.d.ts +16 -16
- package/docs/ARCHITECTURE.md +1176 -0
- package/docs/TODO.md +9 -0
- package/docs/architecture.md +11 -0
- package/docs/archive/2026-03-13-bd-decision-context-template-plan.md +96 -0
- package/docs/archive/AGENT-HANDOFF.md +351 -0
- package/docs/archive/PARITY-ANALYSIS.md +296 -0
- package/docs/archive/SPECIALISTS_REFACTOR.md.md +30 -0
- package/docs/archive/cc-programmatic.md +216 -0
- package/docs/archive/claude-agent-sdk.md +594 -0
- package/docs/archive/decision-specialist-directory.md +41 -0
- package/docs/archive/discoveries.md +148 -0
- package/docs/archive/executor-benchmark-protocol.md +198 -0
- package/docs/archive/future-features.md +66 -0
- package/docs/archive/gzrx-completion-critique.md +183 -0
- package/docs/archive/gzrx-research-notes.md +401 -0
- package/docs/archive/gzrx-tool-catalog.md +760 -0
- package/docs/archive/iron-review-hardening-qa-chain-substrate.md +322 -0
- package/docs/archive/iron-review-hardening.html +1004 -0
- package/docs/archive/issuetracking.md +312 -0
- package/docs/archive/qa-v3.0.2.md +220 -0
- package/docs/archive/restructure.md +231 -0
- package/docs/archive/script-specialists.md +1254 -0
- package/docs/archive/spec-v3.md +792 -0
- package/docs/archive/specialist-stats.md +127 -0
- package/docs/archive/specialists-friction-audit.md +1347 -0
- package/docs/archive/specialists-runtime-critique.md +170 -0
- package/docs/archive/specialists-service-evaluation.md +713 -0
- package/docs/archive/specialists-substrate-alignment.md +255 -0
- package/docs/archive/substrate-review.md +1288 -0
- package/docs/archive/test-writer-specialist.md +254 -0
- package/docs/archive/using-specialists-v3-improvements-2026-05-09.md +600 -0
- package/docs/archive/xtrm-specialists-analysis.md +314 -0
- package/docs/authoring.md +701 -0
- package/docs/background-jobs.md +203 -0
- package/docs/bare-specialists.md +83 -0
- package/docs/benchmarks/executor-benchmark-runner.md +66 -0
- package/docs/bootstrap.md +161 -0
- package/docs/cli-reference.md +1645 -0
- package/docs/deploying-alongside.md +155 -0
- package/docs/design/README.md +36 -0
- package/docs/design/darth-feedor-migration.md +290 -0
- package/docs/design/roadmap/README.md +32 -0
- package/docs/design/roadmap/chain-templates/README.md +146 -0
- package/docs/design/roadmap/chain-templates/code-quick.formula.json +27 -0
- package/docs/design/roadmap/chain-templates/code-standard.formula.json +126 -0
- package/docs/design/roadmap/chain-templates/code-with-advisors.formula.json +128 -0
- package/docs/design/roadmap/chain-templates/code-with-tests.formula.json +76 -0
- package/docs/design/roadmap/chain-templates/debug.formula.json +128 -0
- package/docs/design/roadmap/chain-templates/doc-sync.formula.json +28 -0
- package/docs/design/roadmap/chain-templates/memory-hygiene.formula.json +27 -0
- package/docs/design/roadmap/chain-templates/planning.formula.json +27 -0
- package/docs/design/roadmap/chain-templates/premortem.formula.json +26 -0
- package/docs/design/roadmap/chain-templates/release-prep.formula.json +36 -0
- package/docs/design/roadmap/chain-templates/research-only.formula.json +28 -0
- package/docs/design/roadmap/chain-templates/restitch.formula.json +125 -0
- package/docs/design/roadmap/chain-templates/security-deep.formula.json +161 -0
- package/docs/design/roadmap/chain-templates/test-only.formula.json +52 -0
- package/docs/design/roadmap/chain-templates/triage.formula.json +35 -0
- package/docs/design/roadmap/history/handoff-from-substrate-design.md +87 -0
- package/docs/design/roadmap/history/substrate-reconciliation.md +105 -0
- package/docs/design/roadmap/specialists-roadmap.md +1261 -0
- package/docs/design/sp-console-subscribe-via-materializer.md +231 -0
- package/docs/design/sp-console-tui-mock-v2.html +293 -0
- package/docs/design/sp-console-tui-mock.html +120 -0
- package/docs/design/sp-console-tui.md +340 -0
- package/docs/design/specialist-agentops-suite.md +323 -0
- package/docs/design/substrate/channels.md +14 -0
- package/docs/design/substrate/devops-platform-engineering-prd.md +446 -0
- package/docs/design/substrate/html-design-example.md +339 -0
- package/docs/design/xtrm-tiers-architecture.svg +132 -0
- package/docs/devops/dependency-verdict-materialization.md +46 -0
- package/docs/epic-readiness.md +75 -0
- package/docs/examples/mercury-atomic-summarizer.specialist.json +26 -0
- package/docs/examples/smoke-echo-text-expected-keys.specialist.json +25 -0
- package/docs/examples/smoke-echo.specialist.json +25 -0
- package/docs/features.md +1577 -0
- package/docs/hooks.md +81 -0
- package/docs/installation.md +142 -0
- package/docs/manifest.md +184 -0
- package/docs/mcp-servers.md +73 -0
- package/docs/mcp-tools.md +71 -0
- package/docs/nodes.md +231 -0
- package/docs/observability-metrics.md +152 -0
- package/docs/operator/sp-console-v2-walkthrough.md +410 -0
- package/docs/overrides-guide.md +306 -0
- package/docs/pi-rpc-boundary.md +118 -0
- package/docs/pi-session.md +195 -0
- package/docs/release.md +22 -0
- package/docs/skills.md +132 -0
- package/docs/specialists/handoff-schema.md +181 -0
- package/docs/specialists-catalog.md +99 -0
- package/docs/specialists-service-install.md +226 -0
- package/docs/specialists-service.md +363 -0
- package/docs/surface-ownership.md +138 -0
- package/docs/upgrade-notes/kan-90-global-user-config.md +114 -0
- package/docs/upgrade-notes/kan-91-expanded-overrides.md +261 -0
- package/docs/workflow.md +114 -0
- package/docs/worktree.md +71 -0
- package/docs/worktrees.md +309 -0
- package/package.json +7 -4
|
@@ -0,0 +1,1254 @@
|
|
|
1
|
+
# Script-Specialists Architecture Report
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-04-24
|
|
4
|
+
**Scope:** Current legacy "script-specialists" design used by services and scripts in this repo
|
|
5
|
+
**Status:** Active in production-facing Python services, but conceptually superseded by the newer `.specialists/*.specialist.json` orchestration system
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Executive Summary
|
|
10
|
+
|
|
11
|
+
This repository currently contains **two different specialist systems**:
|
|
12
|
+
|
|
13
|
+
1. **Legacy script-specialists system** — YAML-defined prompt/config artifacts used directly by Python services and scripts.
|
|
14
|
+
2. **Newer orchestration specialists system** — JSON-defined agent/runtime specialists under `.specialists/` with hooks, jobs, nodes, and background execution.
|
|
15
|
+
|
|
16
|
+
This report describes the **legacy script-specialists system**, because that is what the ingestion and squawk services still run today.
|
|
17
|
+
|
|
18
|
+
At a high level, the script-specialists design is:
|
|
19
|
+
|
|
20
|
+
- a **YAML prompt/config registry** in `specialists/`
|
|
21
|
+
- a **Pydantic-backed loader** in `shared/specialist_system/`
|
|
22
|
+
- several **Python service consumers** that load a named specialist at startup
|
|
23
|
+
- a centralized **qwen-service** HTTP gateway (`llm_gateway/`) that executes the actual LLM request
|
|
24
|
+
|
|
25
|
+
The system is best understood as a **configuration-driven prompt layer for scripts/services**, not as a complete specialist runtime. The specialist YAML provides metadata, prompt templates, and nominal execution settings, but only part of that configuration is enforced at runtime.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Naming and Scope Clarification
|
|
30
|
+
|
|
31
|
+
### What "script-specialists" means here
|
|
32
|
+
|
|
33
|
+
In this report, **script-specialists** means the older system built around:
|
|
34
|
+
|
|
35
|
+
- `specialists/**/*.specialist.yaml`
|
|
36
|
+
- `shared/specialist_system/schema.py`
|
|
37
|
+
- `shared/specialist_system/loader.py`
|
|
38
|
+
|
|
39
|
+
It is called "script-specialists" because it is consumed directly by application code and service scripts.
|
|
40
|
+
|
|
41
|
+
### What it is *not*
|
|
42
|
+
|
|
43
|
+
It is **not** the newer orchestrated agent system found in:
|
|
44
|
+
|
|
45
|
+
- `.specialists/default/*.specialist.json`
|
|
46
|
+
- `.specialists/default/nodes/*.node.json`
|
|
47
|
+
- `.claude/hooks/specialists-session-start.mjs`
|
|
48
|
+
- `.claude/hooks/specialists-complete.mjs`
|
|
49
|
+
|
|
50
|
+
That newer system has jobs, background execution, keep-alive sessions, nodes, reviewers, worktrees, and hook-driven UX. The script-specialists system has none of that.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Repository Map
|
|
55
|
+
|
|
56
|
+
### Core legacy script-specialists files
|
|
57
|
+
|
|
58
|
+
- `specialists/ingestion/mercury-atomic-summarizer.specialist.yaml`
|
|
59
|
+
- `specialists/ingestion/official-document-analyzer.specialist.yaml`
|
|
60
|
+
- `specialists/ingestion/squawk-rolling-context.specialist.yaml`
|
|
61
|
+
- `specialists/ingestion/squawk-event-curator.specialist.yaml`
|
|
62
|
+
- `specialists/ingestion/squawk-session-analyst.specialist.yaml`
|
|
63
|
+
- `shared/specialist_system/schema.py`
|
|
64
|
+
- `shared/specialist_system/loader.py`
|
|
65
|
+
- `shared/specialist_system/__init__.py`
|
|
66
|
+
|
|
67
|
+
### Runtime consumers
|
|
68
|
+
|
|
69
|
+
- `ingestion/summarizer.py`
|
|
70
|
+
- `ingestion/official_docs.py`
|
|
71
|
+
- `squawks/rolling_context.py`
|
|
72
|
+
|
|
73
|
+
### LLM transport / execution layer
|
|
74
|
+
|
|
75
|
+
- `shared/qwen_client.py`
|
|
76
|
+
- `llm_gateway/src/llm_gateway/main.py`
|
|
77
|
+
- `llm_gateway/src/llm_gateway/wrapper.py`
|
|
78
|
+
- `llm_gateway/src/llm_gateway/manager.py`
|
|
79
|
+
- `llm_gateway/infra/docker-compose.yml`
|
|
80
|
+
|
|
81
|
+
### Infra wiring
|
|
82
|
+
|
|
83
|
+
- `ingestion/infra/docker-compose.yml`
|
|
84
|
+
|
|
85
|
+
### Tests and implementation notes
|
|
86
|
+
|
|
87
|
+
- `specialists/SPECIALIST_SYSTEM_IMPLEMENTATION.md`
|
|
88
|
+
- `specialists/test/test_specialist_system.py`
|
|
89
|
+
- `tests/test_qwen_client.py`
|
|
90
|
+
- `tests/test_rolling_context_specialists.py`
|
|
91
|
+
- `llm_gateway/tests/test_wrapper.py`
|
|
92
|
+
- `.serena/memories/specialist-system_ssot.md`
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## High-Level Architecture
|
|
97
|
+
|
|
98
|
+
```mermaid
|
|
99
|
+
flowchart TD
|
|
100
|
+
Y[Specialist YAML files<br/>specialists/**/*.specialist.yaml] --> L[SpecialistLoader<br/>shared/specialist_system/loader.py]
|
|
101
|
+
S[Schema / Pydantic models<br/>shared/specialist_system/schema.py] --> L
|
|
102
|
+
|
|
103
|
+
L --> A1[QwenSummarizer<br/>ingestion/summarizer.py]
|
|
104
|
+
L --> A2[OfficialDocumentsImporter<br/>ingestion/official_docs.py]
|
|
105
|
+
L --> A3[RollingContextAgent<br/>squawks/rolling_context.py]
|
|
106
|
+
|
|
107
|
+
A1 --> QC[shared/qwen_client.py]
|
|
108
|
+
A3 --> QC
|
|
109
|
+
A2 --> HTTP[direct HTTP POST]
|
|
110
|
+
|
|
111
|
+
QC --> QS[qwen-service / llm_gateway<br/>POST /generate]
|
|
112
|
+
HTTP --> QS
|
|
113
|
+
|
|
114
|
+
QS --> W[QwenWrapper<br/>CLI invocation + retries]
|
|
115
|
+
W --> M[AccountManager<br/>credential rotation]
|
|
116
|
+
W --> CLI[qwen CLI]
|
|
117
|
+
|
|
118
|
+
M --> QDIR[~/.qwen<br/>oauth_creds.json + accounts/*]
|
|
119
|
+
|
|
120
|
+
A1 --> DB1[(articles table)]
|
|
121
|
+
A2 --> DB1
|
|
122
|
+
A3 --> DB2[(squawk_rolling_context)]
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Design Goals of the Legacy System
|
|
128
|
+
|
|
129
|
+
The legacy system was built to move prompt logic out of code and into editable config files.
|
|
130
|
+
|
|
131
|
+
Primary intended benefits:
|
|
132
|
+
|
|
133
|
+
- prompt changes without code edits
|
|
134
|
+
- prompt changes without rebuilding images
|
|
135
|
+
- discoverable specialists via filesystem scanning
|
|
136
|
+
- startup validation with Pydantic
|
|
137
|
+
- reusable prompt templates across multiple services
|
|
138
|
+
- lighter-weight experimentation than hardcoding prompts in Python
|
|
139
|
+
|
|
140
|
+
Operationally, the workflow is:
|
|
141
|
+
|
|
142
|
+
1. define a specialist YAML file
|
|
143
|
+
2. mount `specialists/` into a container
|
|
144
|
+
3. service loads the specialist by name at startup
|
|
145
|
+
4. service renders prompt variables into `task_template`
|
|
146
|
+
5. service sends the rendered prompt to `qwen-service`
|
|
147
|
+
6. service parses/validates the result and persists it
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Specialist File Format
|
|
152
|
+
|
|
153
|
+
All legacy specialists are rooted under a top-level `specialist:` key.
|
|
154
|
+
|
|
155
|
+
Example structure:
|
|
156
|
+
|
|
157
|
+
```yaml
|
|
158
|
+
specialist:
|
|
159
|
+
metadata:
|
|
160
|
+
name: mercury-atomic-summarizer
|
|
161
|
+
version: 1.1.0
|
|
162
|
+
description: "..."
|
|
163
|
+
category: ingestion/summarization
|
|
164
|
+
created: 2026-02-08T00:00:00Z
|
|
165
|
+
updated: 2026-02-11T02:00:00Z
|
|
166
|
+
author: jagger
|
|
167
|
+
|
|
168
|
+
validation:
|
|
169
|
+
files_to_watch:
|
|
170
|
+
- ingestion/summarizer.py
|
|
171
|
+
references:
|
|
172
|
+
- type: code
|
|
173
|
+
path: ingestion/summarizer.py
|
|
174
|
+
symbol: QwenSummarizer.generate_summary
|
|
175
|
+
purpose: "Integration point"
|
|
176
|
+
stale_threshold_days: 30
|
|
177
|
+
|
|
178
|
+
execution:
|
|
179
|
+
model: qwen-coder
|
|
180
|
+
temperature: 0.3
|
|
181
|
+
max_tokens: 2000
|
|
182
|
+
response_format: json
|
|
183
|
+
fallback_model: gemini-2.0-flash-thinking
|
|
184
|
+
|
|
185
|
+
prompt:
|
|
186
|
+
system: |
|
|
187
|
+
...
|
|
188
|
+
task_template: |
|
|
189
|
+
... $title ... $content ...
|
|
190
|
+
normalize_template: |
|
|
191
|
+
... optional second-stage template ...
|
|
192
|
+
output_schema:
|
|
193
|
+
type: object
|
|
194
|
+
required: [...]
|
|
195
|
+
properties: ...
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Field groups
|
|
199
|
+
|
|
200
|
+
#### `metadata`
|
|
201
|
+
Descriptive information used for identification and traceability.
|
|
202
|
+
|
|
203
|
+
#### `validation`
|
|
204
|
+
Operational metadata for drift/staleness awareness:
|
|
205
|
+
|
|
206
|
+
- `files_to_watch`
|
|
207
|
+
- `references`
|
|
208
|
+
- `stale_threshold_days`
|
|
209
|
+
|
|
210
|
+
#### `execution`
|
|
211
|
+
Nominal runtime settings:
|
|
212
|
+
|
|
213
|
+
- `model`
|
|
214
|
+
- `temperature`
|
|
215
|
+
- `max_tokens`
|
|
216
|
+
- `response_format`
|
|
217
|
+
- `fallback_model`
|
|
218
|
+
|
|
219
|
+
#### `prompt`
|
|
220
|
+
The actual behavioral contract:
|
|
221
|
+
|
|
222
|
+
- `system`
|
|
223
|
+
- `task_template`
|
|
224
|
+
- `normalize_template` (optional)
|
|
225
|
+
- `output_schema`
|
|
226
|
+
- `examples`
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Schema Layer
|
|
231
|
+
|
|
232
|
+
File:
|
|
233
|
+
|
|
234
|
+
- `shared/specialist_system/schema.py`
|
|
235
|
+
|
|
236
|
+
This is the authoritative typed schema for the legacy system.
|
|
237
|
+
|
|
238
|
+
### Main models
|
|
239
|
+
|
|
240
|
+
- `SpecialistConfig`
|
|
241
|
+
- `SpecialistMetadata`
|
|
242
|
+
- `ValidationConfig`
|
|
243
|
+
- `ExecutionConfig`
|
|
244
|
+
- `PromptConfig`
|
|
245
|
+
- `FileReference`
|
|
246
|
+
- `SpecialistCategory`
|
|
247
|
+
|
|
248
|
+
### Important constraints enforced at load time
|
|
249
|
+
|
|
250
|
+
Examples of actual schema constraints:
|
|
251
|
+
|
|
252
|
+
- `metadata.name` must match `^[a-z0-9-]+$`
|
|
253
|
+
- `metadata.version` must match semantic version pattern
|
|
254
|
+
- `description` has length bounds
|
|
255
|
+
- `prompt.task_template` must be non-empty and at least 10 chars
|
|
256
|
+
- `execution.temperature` is bounded
|
|
257
|
+
- `execution.max_tokens` is bounded
|
|
258
|
+
- `validation.stale_threshold_days` is bounded
|
|
259
|
+
- `metadata.updated >= metadata.created`
|
|
260
|
+
|
|
261
|
+
### Category model
|
|
262
|
+
|
|
263
|
+
The enum in `schema.py` is still narrow and oriented around the original ingestion/analysis use case:
|
|
264
|
+
|
|
265
|
+
- `ingestion/summarization`
|
|
266
|
+
- `ingestion/processing`
|
|
267
|
+
- `monitoring/health`
|
|
268
|
+
- `monitoring/diagnostics`
|
|
269
|
+
- `analysis/macro`
|
|
270
|
+
- `analysis/technical`
|
|
271
|
+
|
|
272
|
+
That reflects the age of the system: it was designed first for service prompts, not for general-purpose agent orchestration.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Loader Layer
|
|
277
|
+
|
|
278
|
+
File:
|
|
279
|
+
|
|
280
|
+
- `shared/specialist_system/loader.py`
|
|
281
|
+
|
|
282
|
+
`SpecialistLoader` is the central runtime for the legacy system.
|
|
283
|
+
|
|
284
|
+
### Responsibilities
|
|
285
|
+
|
|
286
|
+
1. discover YAML files recursively
|
|
287
|
+
2. parse YAML
|
|
288
|
+
3. validate specialist configs via Pydantic
|
|
289
|
+
4. cache loaded specialists in memory
|
|
290
|
+
5. render prompt templates using variables
|
|
291
|
+
6. perform lightweight runtime output validation
|
|
292
|
+
7. warn about stale/missing watched files
|
|
293
|
+
|
|
294
|
+
### Startup discovery
|
|
295
|
+
|
|
296
|
+
On initialization:
|
|
297
|
+
|
|
298
|
+
- `SpecialistLoader()` defaults to `Path("specialists")`
|
|
299
|
+
- `_scan_specialists()` recursively scans for `*.specialist.yaml`
|
|
300
|
+
- each file is loaded via `_load_yaml_file()`
|
|
301
|
+
- valid specialists are cached by `metadata.name`
|
|
302
|
+
|
|
303
|
+
### Cache model
|
|
304
|
+
|
|
305
|
+
The cache is an in-memory dict:
|
|
306
|
+
|
|
307
|
+
- key = specialist name
|
|
308
|
+
- value = validated `SpecialistConfig`
|
|
309
|
+
|
|
310
|
+
No persistent index exists. Discovery is filesystem-based.
|
|
311
|
+
|
|
312
|
+
### Loading behavior
|
|
313
|
+
|
|
314
|
+
`load(name)`:
|
|
315
|
+
|
|
316
|
+
- looks up the cached config
|
|
317
|
+
- runs `_check_health()`
|
|
318
|
+
- returns the `SpecialistConfig`
|
|
319
|
+
|
|
320
|
+
### Health checks
|
|
321
|
+
|
|
322
|
+
`_check_health()` currently does basic checks only:
|
|
323
|
+
|
|
324
|
+
- warn if specialist age exceeds `stale_threshold_days`
|
|
325
|
+
- warn if a watched file path does not exist
|
|
326
|
+
|
|
327
|
+
It does **not** currently implement deeper semantic drift detection.
|
|
328
|
+
|
|
329
|
+
### Prompt rendering
|
|
330
|
+
|
|
331
|
+
`render_prompt()`:
|
|
332
|
+
|
|
333
|
+
- prepends `prompt.system` if present
|
|
334
|
+
- renders `prompt.task_template` using `string.Template`
|
|
335
|
+
- raises `KeyError` if a required template variable is missing
|
|
336
|
+
|
|
337
|
+
This means all prompt variables are strict string-template substitutions like:
|
|
338
|
+
|
|
339
|
+
- `$title`
|
|
340
|
+
- `$content`
|
|
341
|
+
- `$sender`
|
|
342
|
+
- `$controlled_tags`
|
|
343
|
+
|
|
344
|
+
### Runtime output validation
|
|
345
|
+
|
|
346
|
+
`validate_output()` is intentionally lightweight.
|
|
347
|
+
|
|
348
|
+
What it actually does today:
|
|
349
|
+
|
|
350
|
+
1. if there is no `output_schema`, returns `True`
|
|
351
|
+
2. if response format is not `json`, skips strict checking
|
|
352
|
+
3. strips `<think>...</think>` blocks
|
|
353
|
+
4. extracts the outermost JSON object from the output text
|
|
354
|
+
5. parses JSON
|
|
355
|
+
6. checks only presence of fields listed in `output_schema.required`
|
|
356
|
+
|
|
357
|
+
What it does **not** fully enforce:
|
|
358
|
+
|
|
359
|
+
- nested schema types
|
|
360
|
+
- enum validity
|
|
361
|
+
- array cardinality
|
|
362
|
+
- string length limits
|
|
363
|
+
- `properties` shape correctness
|
|
364
|
+
|
|
365
|
+
So the loader gives **strong config validation** but only **shallow runtime payload validation**.
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Runtime Consumers
|
|
370
|
+
|
|
371
|
+
## 1. `ingestion/summarizer.py`
|
|
372
|
+
|
|
373
|
+
Class:
|
|
374
|
+
|
|
375
|
+
- `QwenSummarizer`
|
|
376
|
+
|
|
377
|
+
Specialist used:
|
|
378
|
+
|
|
379
|
+
- `mercury-atomic-summarizer`
|
|
380
|
+
|
|
381
|
+
### Role
|
|
382
|
+
|
|
383
|
+
This service processes pending articles and generates structured summaries.
|
|
384
|
+
|
|
385
|
+
### Startup flow
|
|
386
|
+
|
|
387
|
+
At initialization it:
|
|
388
|
+
|
|
389
|
+
1. constructs `QwenClient()`
|
|
390
|
+
2. constructs `SpecialistLoader()`
|
|
391
|
+
3. loads `mercury-atomic-summarizer`
|
|
392
|
+
4. logs success or fails hard on `SpecialistLoadError`
|
|
393
|
+
|
|
394
|
+
### Prompt construction
|
|
395
|
+
|
|
396
|
+
For each article, `generate_summary()`:
|
|
397
|
+
|
|
398
|
+
- truncates content to 40,000 chars
|
|
399
|
+
- optionally injects extracted table markdown
|
|
400
|
+
- injects source-specific context
|
|
401
|
+
- injects controlled tags vocabulary
|
|
402
|
+
- renders the specialist prompt
|
|
403
|
+
|
|
404
|
+
Variables passed include:
|
|
405
|
+
|
|
406
|
+
- `sender`
|
|
407
|
+
- `source_type`
|
|
408
|
+
- `title`
|
|
409
|
+
- `content`
|
|
410
|
+
- `truncation_notice`
|
|
411
|
+
- `tables_section`
|
|
412
|
+
- `is_truncated`
|
|
413
|
+
- `controlled_tags`
|
|
414
|
+
|
|
415
|
+
### LLM call path
|
|
416
|
+
|
|
417
|
+
It uses:
|
|
418
|
+
|
|
419
|
+
- `shared.qwen_client.QwenClient.generate(prompt)`
|
|
420
|
+
|
|
421
|
+
### Result handling
|
|
422
|
+
|
|
423
|
+
After response:
|
|
424
|
+
|
|
425
|
+
- extracts JSON by first `{` and last `}`
|
|
426
|
+
- calls `validate_output()`
|
|
427
|
+
- saves even if schema validation warns
|
|
428
|
+
- normalizes tags before writing to `articles.summary`
|
|
429
|
+
|
|
430
|
+
### Architectural note
|
|
431
|
+
|
|
432
|
+
This is the cleanest expression of the script-specialists pattern: YAML defines the prompt contract; Python provides domain variables and persistence.
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
## 2. `ingestion/official_docs.py`
|
|
437
|
+
|
|
438
|
+
Class:
|
|
439
|
+
|
|
440
|
+
- `OfficialDocumentsImporter`
|
|
441
|
+
|
|
442
|
+
Specialist used:
|
|
443
|
+
|
|
444
|
+
- `official-document-analyzer`
|
|
445
|
+
|
|
446
|
+
### Role
|
|
447
|
+
|
|
448
|
+
This service ingests official government documents from Gmail and produces policy-analysis summaries.
|
|
449
|
+
|
|
450
|
+
### Startup flow
|
|
451
|
+
|
|
452
|
+
At initialization it:
|
|
453
|
+
|
|
454
|
+
1. resolves `QWEN_SERVICE_URL`
|
|
455
|
+
2. constructs `SpecialistLoader()`
|
|
456
|
+
3. loads `official-document-analyzer`
|
|
457
|
+
4. stores the specialist for later prompt rendering
|
|
458
|
+
|
|
459
|
+
### Prompt construction
|
|
460
|
+
|
|
461
|
+
`generate_summary()` renders prompt variables such as:
|
|
462
|
+
|
|
463
|
+
- `sender`
|
|
464
|
+
- `title`
|
|
465
|
+
- `content`
|
|
466
|
+
- `truncation_notice`
|
|
467
|
+
- `is_truncated`
|
|
468
|
+
|
|
469
|
+
### LLM call path
|
|
470
|
+
|
|
471
|
+
Unlike `QwenSummarizer`, this module performs **direct HTTP POST** to qwen-service.
|
|
472
|
+
|
|
473
|
+
It posts:
|
|
474
|
+
|
|
475
|
+
```json
|
|
476
|
+
{
|
|
477
|
+
"prompt": "...",
|
|
478
|
+
"model": "...",
|
|
479
|
+
"temperature": 0.1,
|
|
480
|
+
"max_tokens": 2500
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### Architectural note
|
|
485
|
+
|
|
486
|
+
This consumer reveals an important mismatch:
|
|
487
|
+
|
|
488
|
+
- the specialist execution block is read and forwarded
|
|
489
|
+
- but the current qwen-service request model only formally defines `prompt` and `timeout`
|
|
490
|
+
|
|
491
|
+
So the intent is richer than the actually enforced contract.
|
|
492
|
+
|
|
493
|
+
---
|
|
494
|
+
|
|
495
|
+
## 3. `squawks/rolling_context.py`
|
|
496
|
+
|
|
497
|
+
Class:
|
|
498
|
+
|
|
499
|
+
- `RollingContextAgent`
|
|
500
|
+
|
|
501
|
+
Specialists used:
|
|
502
|
+
|
|
503
|
+
- `squawk-rolling-context`
|
|
504
|
+
- `squawk-event-curator`
|
|
505
|
+
- `squawk-session-analyst`
|
|
506
|
+
|
|
507
|
+
### Role
|
|
508
|
+
|
|
509
|
+
This is the most evolved consumer of the legacy system. It uses **multiple specialists in a staged pipeline**.
|
|
510
|
+
|
|
511
|
+
### Startup flow
|
|
512
|
+
|
|
513
|
+
At initialization it:
|
|
514
|
+
|
|
515
|
+
1. constructs `SpecialistLoader()`
|
|
516
|
+
2. loads extractor specialist
|
|
517
|
+
3. loads curator specialist
|
|
518
|
+
4. loads analyst specialist
|
|
519
|
+
5. derives `llm_model` from analyst execution config
|
|
520
|
+
|
|
521
|
+
### Pipeline stages
|
|
522
|
+
|
|
523
|
+
#### Stage 1 — Extraction
|
|
524
|
+
Method:
|
|
525
|
+
|
|
526
|
+
- `_run_extraction()`
|
|
527
|
+
|
|
528
|
+
Uses:
|
|
529
|
+
|
|
530
|
+
- `squawk-rolling-context.prompt.task_template`
|
|
531
|
+
|
|
532
|
+
Behavior:
|
|
533
|
+
|
|
534
|
+
- scans raw squawks from the last 30 minutes
|
|
535
|
+
- asks the LLM to emit `new_events`
|
|
536
|
+
- retries once on invalid output
|
|
537
|
+
- resolves authoritative timestamps from source squawk indices
|
|
538
|
+
|
|
539
|
+
#### Stage 2 — Event curation
|
|
540
|
+
Method:
|
|
541
|
+
|
|
542
|
+
- `_run_event_curation()`
|
|
543
|
+
|
|
544
|
+
Uses:
|
|
545
|
+
|
|
546
|
+
- `squawk-event-curator.prompt.task_template`
|
|
547
|
+
|
|
548
|
+
Behavior:
|
|
549
|
+
|
|
550
|
+
- compares new events against existing memory
|
|
551
|
+
- asks the LLM to consolidate / enrich / suppress duplicates
|
|
552
|
+
- returns:
|
|
553
|
+
- `curated_events`
|
|
554
|
+
- `change_summary`
|
|
555
|
+
- `material_change_hint`
|
|
556
|
+
- falls back to extracted events on curator failure/emptiness
|
|
557
|
+
|
|
558
|
+
#### Stage 3 — Session synthesis
|
|
559
|
+
Method:
|
|
560
|
+
|
|
561
|
+
- `_run_synthesis()`
|
|
562
|
+
|
|
563
|
+
Uses:
|
|
564
|
+
|
|
565
|
+
- `squawk-session-analyst.prompt.normalize_template`
|
|
566
|
+
|
|
567
|
+
Behavior:
|
|
568
|
+
|
|
569
|
+
- builds a richer synthesis prompt from:
|
|
570
|
+
- curated events
|
|
571
|
+
- change summary
|
|
572
|
+
- previous-day summary
|
|
573
|
+
- LSEG digest context
|
|
574
|
+
- economic calendar context
|
|
575
|
+
- market snapshot context
|
|
576
|
+
- trusted article context
|
|
577
|
+
- asks the LLM for:
|
|
578
|
+
- `thesis`
|
|
579
|
+
- `overview`
|
|
580
|
+
- `what_changed`
|
|
581
|
+
- `contradictions`
|
|
582
|
+
- `watch_items`
|
|
583
|
+
- `mechanisms`
|
|
584
|
+
- `key_data`
|
|
585
|
+
- `session_themes`
|
|
586
|
+
- optional `previous_day_summary`
|
|
587
|
+
- rejects weak candidates that fail topical grounding heuristics
|
|
588
|
+
- computes degraded input metadata and confidence
|
|
589
|
+
|
|
590
|
+
### Why this consumer matters
|
|
591
|
+
|
|
592
|
+
This is where the legacy design stretched beyond its original shape.
|
|
593
|
+
|
|
594
|
+
The script-specialists system started as:
|
|
595
|
+
|
|
596
|
+
- one YAML specialist
|
|
597
|
+
- one script
|
|
598
|
+
- one prompt
|
|
599
|
+
|
|
600
|
+
But `rolling_context.py` now uses it as a **multi-stage LLM orchestration framework**, even though the loader/runtime itself was never upgraded into a full orchestration system.
|
|
601
|
+
|
|
602
|
+
---
|
|
603
|
+
|
|
604
|
+
## qwen-service Integration
|
|
605
|
+
|
|
606
|
+
The script-specialists design does not execute models directly. It relies on a shared qwen HTTP gateway.
|
|
607
|
+
|
|
608
|
+
## Shared client
|
|
609
|
+
|
|
610
|
+
File:
|
|
611
|
+
|
|
612
|
+
- `shared/qwen_client.py`
|
|
613
|
+
|
|
614
|
+
### Responsibilities
|
|
615
|
+
|
|
616
|
+
- resolve `QWEN_SERVICE_URL`
|
|
617
|
+
- send prompt to `/generate`
|
|
618
|
+
- expose `health_check()`
|
|
619
|
+
- emit Prometheus metrics
|
|
620
|
+
- normalize connection failures into a simple result dict
|
|
621
|
+
|
|
622
|
+
### Effective request contract
|
|
623
|
+
|
|
624
|
+
`QwenClient.generate(prompt, timeout=...)` sends:
|
|
625
|
+
|
|
626
|
+
```json
|
|
627
|
+
{
|
|
628
|
+
"prompt": "...",
|
|
629
|
+
"timeout": 60
|
|
630
|
+
}
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
This is the main path used by:
|
|
634
|
+
|
|
635
|
+
- `ingestion/summarizer.py`
|
|
636
|
+
- `squawks/utils.py`
|
|
637
|
+
- `ext_mcp/server.py`
|
|
638
|
+
- effectively most non-direct callers
|
|
639
|
+
|
|
640
|
+
---
|
|
641
|
+
|
|
642
|
+
## qwen-service server
|
|
643
|
+
|
|
644
|
+
Files:
|
|
645
|
+
|
|
646
|
+
- `llm_gateway/src/llm_gateway/main.py`
|
|
647
|
+
- `llm_gateway/src/llm_gateway/wrapper.py`
|
|
648
|
+
- `llm_gateway/src/llm_gateway/manager.py`
|
|
649
|
+
|
|
650
|
+
Container:
|
|
651
|
+
|
|
652
|
+
- `qwen-service`
|
|
653
|
+
|
|
654
|
+
### API surface
|
|
655
|
+
|
|
656
|
+
#### `GET /health`
|
|
657
|
+
Returns:
|
|
658
|
+
|
|
659
|
+
- `status`
|
|
660
|
+
- `current_account`
|
|
661
|
+
- `total_switches`
|
|
662
|
+
|
|
663
|
+
#### `POST /generate`
|
|
664
|
+
Consumes a request model with:
|
|
665
|
+
|
|
666
|
+
- `prompt`
|
|
667
|
+
- `timeout`
|
|
668
|
+
|
|
669
|
+
Returns:
|
|
670
|
+
|
|
671
|
+
- `success`
|
|
672
|
+
- `output`
|
|
673
|
+
- `error`
|
|
674
|
+
- `error_type`
|
|
675
|
+
- `attempts`
|
|
676
|
+
- `accounts_tried`
|
|
677
|
+
|
|
678
|
+
#### Additional endpoints
|
|
679
|
+
|
|
680
|
+
- `POST /switch-next`
|
|
681
|
+
- `GET /accounts`
|
|
682
|
+
- `POST /accounts/{account_id}/reset`
|
|
683
|
+
- `GET /metrics`
|
|
684
|
+
|
|
685
|
+
### Concurrency and resilience
|
|
686
|
+
|
|
687
|
+
`main.py` enforces:
|
|
688
|
+
|
|
689
|
+
- semaphore with concurrency limit = 2
|
|
690
|
+
- circuit breaker after repeated all-account failures
|
|
691
|
+
- HTTP 503 while breaker is open
|
|
692
|
+
|
|
693
|
+
---
|
|
694
|
+
|
|
695
|
+
## qwen CLI wrapper and account rotation
|
|
696
|
+
|
|
697
|
+
### Wrapper
|
|
698
|
+
|
|
699
|
+
File:
|
|
700
|
+
|
|
701
|
+
- `llm_gateway/src/llm_gateway/wrapper.py`
|
|
702
|
+
|
|
703
|
+
The wrapper shells out to the installed CLI:
|
|
704
|
+
|
|
705
|
+
```bash
|
|
706
|
+
qwen <prompt> --output-format text --auth-type qwen-oauth --model qwen3-coder-plus --yolo
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
It classifies failures into:
|
|
710
|
+
|
|
711
|
+
- quota
|
|
712
|
+
- auth
|
|
713
|
+
- safety
|
|
714
|
+
- timeout
|
|
715
|
+
- network/unknown
|
|
716
|
+
|
|
717
|
+
### Rotation manager
|
|
718
|
+
|
|
719
|
+
File:
|
|
720
|
+
|
|
721
|
+
- `llm_gateway/src/llm_gateway/manager.py`
|
|
722
|
+
|
|
723
|
+
Responsibilities:
|
|
724
|
+
|
|
725
|
+
- discover account files under `~/.qwen/accounts/`
|
|
726
|
+
- physically swap active credentials into `~/.qwen/oauth_creds.json`
|
|
727
|
+
- persist state in `~/.qwen/state.yaml`
|
|
728
|
+
- write rotation events to `~/.qwen/rotation.log`
|
|
729
|
+
- avoid races with file lock
|
|
730
|
+
|
|
731
|
+
### Storage assumptions
|
|
732
|
+
|
|
733
|
+
The design assumes the following layout:
|
|
734
|
+
|
|
735
|
+
- `~/.qwen/oauth_creds.json` — active credential
|
|
736
|
+
- `~/.qwen/accounts/oauth_creds_<n>.json` — account pool
|
|
737
|
+
- `~/.qwen/state.yaml` — rotation state
|
|
738
|
+
- `/tmp/qwen_rotation.lock` — lock file used by account manager
|
|
739
|
+
|
|
740
|
+
### Why this matters for script-specialists
|
|
741
|
+
|
|
742
|
+
Every script-specialist consumer ultimately depends on this wrapper behavior. If the Qwen CLI changes:
|
|
743
|
+
|
|
744
|
+
- flags
|
|
745
|
+
- output patterns
|
|
746
|
+
- auth file layout
|
|
747
|
+
- refresh behavior
|
|
748
|
+
- model naming
|
|
749
|
+
|
|
750
|
+
then the legacy specialist stack breaks even if the YAML files remain valid.
|
|
751
|
+
|
|
752
|
+
---
|
|
753
|
+
|
|
754
|
+
## Container / Infra Wiring
|
|
755
|
+
|
|
756
|
+
File:
|
|
757
|
+
|
|
758
|
+
- `ingestion/infra/docker-compose.yml`
|
|
759
|
+
|
|
760
|
+
### Volume mount contract
|
|
761
|
+
|
|
762
|
+
The legacy specialist registry is mounted into consuming containers as:
|
|
763
|
+
|
|
764
|
+
```yaml
|
|
765
|
+
- ../../specialists:/app/specialists:ro
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
This appears on:
|
|
769
|
+
|
|
770
|
+
- `ext-official-documents`
|
|
771
|
+
- `ext-summarizer`
|
|
772
|
+
- `ext-squawk-summarizer`
|
|
773
|
+
- some adjacent services
|
|
774
|
+
|
|
775
|
+
### qwen-service contract
|
|
776
|
+
|
|
777
|
+
Consuming services rely on:
|
|
778
|
+
|
|
779
|
+
```yaml
|
|
780
|
+
- QWEN_SERVICE_URL=http://qwen-service:8000
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
### Operational pattern
|
|
784
|
+
|
|
785
|
+
The legacy system is therefore **volume-driven** and **restart-applied**:
|
|
786
|
+
|
|
787
|
+
1. edit YAML on host
|
|
788
|
+
2. container sees file via read-only mount
|
|
789
|
+
3. restart service/container
|
|
790
|
+
4. service reloads specialist at startup
|
|
791
|
+
|
|
792
|
+
This is often described as "hot reload", but it is not live in-process auto-reload.
|
|
793
|
+
|
|
794
|
+
---
|
|
795
|
+
|
|
796
|
+
## Detailed End-to-End Flows
|
|
797
|
+
|
|
798
|
+
## Flow A — Article summarization
|
|
799
|
+
|
|
800
|
+
```mermaid
|
|
801
|
+
sequenceDiagram
|
|
802
|
+
participant DB as articles table
|
|
803
|
+
participant S as ingestion/summarizer.py
|
|
804
|
+
participant L as SpecialistLoader
|
|
805
|
+
participant Y as mercury-atomic-summarizer YAML
|
|
806
|
+
participant Q as shared.qwen_client
|
|
807
|
+
participant G as qwen-service
|
|
808
|
+
participant C as qwen CLI
|
|
809
|
+
|
|
810
|
+
S->>L: load("mercury-atomic-summarizer")
|
|
811
|
+
L->>Y: parse + validate
|
|
812
|
+
S->>DB: fetch pending articles
|
|
813
|
+
S->>L: render_prompt(sender,title,content,...)
|
|
814
|
+
S->>Q: generate(prompt)
|
|
815
|
+
Q->>G: POST /generate
|
|
816
|
+
G->>C: run qwen CLI
|
|
817
|
+
C-->>G: output
|
|
818
|
+
G-->>Q: JSON result
|
|
819
|
+
Q-->>S: {success, output, error_type}
|
|
820
|
+
S->>L: validate_output(cleaned_json)
|
|
821
|
+
S->>DB: save summary JSONB
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
## Flow B — Official document analysis
|
|
825
|
+
|
|
826
|
+
```mermaid
|
|
827
|
+
sequenceDiagram
|
|
828
|
+
participant M as Gmail messages
|
|
829
|
+
participant O as ingestion/official_docs.py
|
|
830
|
+
participant L as SpecialistLoader
|
|
831
|
+
participant Y as official-document-analyzer YAML
|
|
832
|
+
participant G as qwen-service
|
|
833
|
+
participant DB as articles table
|
|
834
|
+
|
|
835
|
+
O->>L: load("official-document-analyzer")
|
|
836
|
+
L->>Y: parse + validate
|
|
837
|
+
O->>M: fetch and parse emails
|
|
838
|
+
O->>L: render_prompt(sender,title,content,...)
|
|
839
|
+
O->>G: POST /generate (direct HTTP)
|
|
840
|
+
G-->>O: JSON result
|
|
841
|
+
O->>L: validate_output(output)
|
|
842
|
+
O->>DB: save article and summary
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
## Flow C — Rolling context multi-stage pipeline
|
|
846
|
+
|
|
847
|
+
```mermaid
|
|
848
|
+
sequenceDiagram
|
|
849
|
+
participant RC as RollingContextAgent
|
|
850
|
+
participant L as SpecialistLoader
|
|
851
|
+
participant E as squawk-rolling-context YAML
|
|
852
|
+
participant C as squawk-event-curator YAML
|
|
853
|
+
participant A as squawk-session-analyst YAML
|
|
854
|
+
participant G as qwen-service
|
|
855
|
+
participant DB as squawk_rolling_context
|
|
856
|
+
|
|
857
|
+
RC->>L: load extractor, curator, analyst
|
|
858
|
+
RC->>DB: fetch recent squawks + last context
|
|
859
|
+
RC->>L: extractor task_template render
|
|
860
|
+
RC->>G: extraction prompt
|
|
861
|
+
G-->>RC: new_events JSON
|
|
862
|
+
RC->>L: validate_output(extractor)
|
|
863
|
+
RC->>L: curator task_template render
|
|
864
|
+
RC->>G: curation prompt
|
|
865
|
+
G-->>RC: curated_events/change_summary
|
|
866
|
+
RC->>L: validate_output(curator)
|
|
867
|
+
RC->>L: analyst normalize_template render
|
|
868
|
+
RC->>G: synthesis prompt
|
|
869
|
+
G-->>RC: thesis/overview/... JSON
|
|
870
|
+
RC->>L: validate_output(analyst)
|
|
871
|
+
RC->>DB: save processed context row
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
---
|
|
875
|
+
|
|
876
|
+
## Strengths of the Legacy Design
|
|
877
|
+
|
|
878
|
+
## 1. Clear separation of prompt logic from application logic
|
|
879
|
+
|
|
880
|
+
Service code owns:
|
|
881
|
+
|
|
882
|
+
- data retrieval
|
|
883
|
+
- truncation
|
|
884
|
+
- variable assembly
|
|
885
|
+
- persistence
|
|
886
|
+
|
|
887
|
+
Specialist YAML owns:
|
|
888
|
+
|
|
889
|
+
- system prompt
|
|
890
|
+
- task instructions
|
|
891
|
+
- output contract
|
|
892
|
+
|
|
893
|
+
## 2. Fast iteration on prompts
|
|
894
|
+
|
|
895
|
+
Because `specialists/` is mounted into containers, prompt changes do not require code changes.
|
|
896
|
+
|
|
897
|
+
## 3. Startup-time safety via Pydantic
|
|
898
|
+
|
|
899
|
+
Malformed YAML fails early.
|
|
900
|
+
|
|
901
|
+
## 4. Good fit for domain-specific scripted tasks
|
|
902
|
+
|
|
903
|
+
The pattern works well for:
|
|
904
|
+
|
|
905
|
+
- article summarization
|
|
906
|
+
- policy document analysis
|
|
907
|
+
- structured extraction
|
|
908
|
+
- deterministic script pipelines that need prompt externalization
|
|
909
|
+
|
|
910
|
+
## 5. Rolling context proved the concept can scale to multi-stage prompting
|
|
911
|
+
|
|
912
|
+
Even though the runtime is simple, the staged use in `rolling_context.py` demonstrates that a specialist registry can support richer chains.
|
|
913
|
+
|
|
914
|
+
---
|
|
915
|
+
|
|
916
|
+
## Real Design Limits and Mismatches
|
|
917
|
+
|
|
918
|
+
## 1. `execution` is mostly declarative, not operative
|
|
919
|
+
|
|
920
|
+
This is the biggest architectural mismatch.
|
|
921
|
+
|
|
922
|
+
The YAML exposes:
|
|
923
|
+
|
|
924
|
+
- `model`
|
|
925
|
+
- `temperature`
|
|
926
|
+
- `max_tokens`
|
|
927
|
+
- `fallback_model`
|
|
928
|
+
|
|
929
|
+
But in the main runtime path:
|
|
930
|
+
|
|
931
|
+
- `shared.qwen_client.QwenClient.generate()` only sends `prompt` and `timeout`
|
|
932
|
+
|
|
933
|
+
That means the specialist execution block is largely **not enforced** for the main consumers.
|
|
934
|
+
|
|
935
|
+
### Consequence
|
|
936
|
+
|
|
937
|
+
The system *looks* like a full execution config layer, but operationally it is mostly a prompt/config registry.
|
|
938
|
+
|
|
939
|
+
## 2. Direct and shared call paths diverge
|
|
940
|
+
|
|
941
|
+
There are two LLM transport patterns:
|
|
942
|
+
|
|
943
|
+
- shared client (`QwenClient`)
|
|
944
|
+
- direct `requests.post()`
|
|
945
|
+
|
|
946
|
+
That means behavior is not fully centralized.
|
|
947
|
+
|
|
948
|
+
## 3. Runtime output validation is shallow
|
|
949
|
+
|
|
950
|
+
The loader checks required fields, but not the full JSON schema contract.
|
|
951
|
+
|
|
952
|
+
### Consequence
|
|
953
|
+
|
|
954
|
+
Specialists can declare rich schemas, but runtime enforcement is weaker than the YAML suggests.
|
|
955
|
+
|
|
956
|
+
## 4. Hot reload is restart-based, not live
|
|
957
|
+
|
|
958
|
+
The implementation supports:
|
|
959
|
+
|
|
960
|
+
- edit YAML
|
|
961
|
+
- restart process/container
|
|
962
|
+
- reload at startup
|
|
963
|
+
|
|
964
|
+
It does not provide live watches or in-process reload triggers.
|
|
965
|
+
|
|
966
|
+
## 5. The design is tightly coupled to qwen-service internals
|
|
967
|
+
|
|
968
|
+
The entire stack assumes:
|
|
969
|
+
|
|
970
|
+
- qwen CLI exists
|
|
971
|
+
- CLI flags remain stable
|
|
972
|
+
- CLI output patterns are classifiable by substring checks
|
|
973
|
+
- OAuth files live in the expected shape
|
|
974
|
+
- model names remain stable
|
|
975
|
+
|
|
976
|
+
When Qwen changes behavior, script-specialists break at the transport layer even if the specialist configs are fine.
|
|
977
|
+
|
|
978
|
+
## 6. The schema/doc story has drifted ahead of the actual implementation
|
|
979
|
+
|
|
980
|
+
`.serena/memories/specialist-system_ssot.md` describes a richer pipeline:
|
|
981
|
+
|
|
982
|
+
- normalize phase
|
|
983
|
+
- field-drift correction
|
|
984
|
+
- word-count checks
|
|
985
|
+
- more advanced validation semantics
|
|
986
|
+
|
|
987
|
+
But `shared/specialist_system/loader.py` is much simpler.
|
|
988
|
+
|
|
989
|
+
### Consequence
|
|
990
|
+
|
|
991
|
+
The conceptual docs describe a more mature system than the actual loader/runtime currently implements.
|
|
992
|
+
|
|
993
|
+
## 7. The repo now contains two overlapping specialist concepts
|
|
994
|
+
|
|
995
|
+
Legacy:
|
|
996
|
+
|
|
997
|
+
- `specialists/*.specialist.yaml`
|
|
998
|
+
|
|
999
|
+
New:
|
|
1000
|
+
|
|
1001
|
+
- `.specialists/*.specialist.json`
|
|
1002
|
+
|
|
1003
|
+
There is also UX overlap: hooks and docs increasingly describe the newer system, while runtime services still depend on the older one.
|
|
1004
|
+
|
|
1005
|
+
---
|
|
1006
|
+
|
|
1007
|
+
## Testing and Operational Evidence
|
|
1008
|
+
|
|
1009
|
+
## Specialist system tests
|
|
1010
|
+
|
|
1011
|
+
File:
|
|
1012
|
+
|
|
1013
|
+
- `specialists/test/test_specialist_system.py`
|
|
1014
|
+
|
|
1015
|
+
Confirms the legacy loader can:
|
|
1016
|
+
|
|
1017
|
+
- load specialists
|
|
1018
|
+
- render prompts
|
|
1019
|
+
- validate basic output
|
|
1020
|
+
- list specialists
|
|
1021
|
+
|
|
1022
|
+
## Rolling-context specialist tests
|
|
1023
|
+
|
|
1024
|
+
File:
|
|
1025
|
+
|
|
1026
|
+
- `tests/test_rolling_context_specialists.py`
|
|
1027
|
+
|
|
1028
|
+
This is important because it shows the intended boundary behavior of the legacy multi-specialist pipeline:
|
|
1029
|
+
|
|
1030
|
+
- multiple specialists load together
|
|
1031
|
+
- invalid curator output falls back safely
|
|
1032
|
+
- extraction retries once on invalid output
|
|
1033
|
+
- synthesis candidate validation enforces topical grounding
|
|
1034
|
+
- source-coverage and degraded input metadata are computed
|
|
1035
|
+
|
|
1036
|
+
## qwen client tests
|
|
1037
|
+
|
|
1038
|
+
File:
|
|
1039
|
+
|
|
1040
|
+
- `tests/test_qwen_client.py`
|
|
1041
|
+
|
|
1042
|
+
Confirms:
|
|
1043
|
+
|
|
1044
|
+
- URL configuration
|
|
1045
|
+
- HTTP request shape
|
|
1046
|
+
- timeout behavior
|
|
1047
|
+
- health check behavior
|
|
1048
|
+
- Prometheus metric emission
|
|
1049
|
+
|
|
1050
|
+
## qwen wrapper tests
|
|
1051
|
+
|
|
1052
|
+
File:
|
|
1053
|
+
|
|
1054
|
+
- `llm_gateway/tests/test_wrapper.py`
|
|
1055
|
+
|
|
1056
|
+
Confirms:
|
|
1057
|
+
|
|
1058
|
+
- quota/auth/safety error classification
|
|
1059
|
+
- rotation logic
|
|
1060
|
+
- retry behavior
|
|
1061
|
+
- auth-failure clearing
|
|
1062
|
+
|
|
1063
|
+
---
|
|
1064
|
+
|
|
1065
|
+
## Architectural Interpretation
|
|
1066
|
+
|
|
1067
|
+
The legacy script-specialists design should be interpreted as a **four-layer system**:
|
|
1068
|
+
|
|
1069
|
+
### Layer 1 — Config registry
|
|
1070
|
+
Filesystem YAML specialists.
|
|
1071
|
+
|
|
1072
|
+
### Layer 2 — Local runtime adapter
|
|
1073
|
+
`SpecialistLoader` parses, validates, renders, and lightly validates outputs.
|
|
1074
|
+
|
|
1075
|
+
### Layer 3 — Service-specific orchestration
|
|
1076
|
+
Each Python service decides:
|
|
1077
|
+
|
|
1078
|
+
- what variables to inject
|
|
1079
|
+
- when to call the LLM
|
|
1080
|
+
- how to parse results
|
|
1081
|
+
- how to handle fallbacks
|
|
1082
|
+
- how to persist output
|
|
1083
|
+
|
|
1084
|
+
### Layer 4 — Shared LLM gateway
|
|
1085
|
+
`qwen-service` abstracts CLI execution and credential rotation.
|
|
1086
|
+
|
|
1087
|
+
This means the legacy system is **not** a standalone runtime platform. It is a **thin config layer embedded into service code**.
|
|
1088
|
+
|
|
1089
|
+
---
|
|
1090
|
+
|
|
1091
|
+
## Contrast With the Newer `.specialists` System
|
|
1092
|
+
|
|
1093
|
+
The newer system under `.specialists/` introduces concepts absent from the script-specialists design:
|
|
1094
|
+
|
|
1095
|
+
- specialist jobs
|
|
1096
|
+
- background runs
|
|
1097
|
+
- keep-alive interactions
|
|
1098
|
+
- worktree isolation
|
|
1099
|
+
- nodes and coordinators
|
|
1100
|
+
- hook-driven notifications
|
|
1101
|
+
- reusable reviewer/executor patterns
|
|
1102
|
+
- JSON specialist definitions aligned to an agent platform
|
|
1103
|
+
|
|
1104
|
+
By contrast, legacy script-specialists provide only:
|
|
1105
|
+
|
|
1106
|
+
- config file discovery
|
|
1107
|
+
- template rendering
|
|
1108
|
+
- shallow schema checking
|
|
1109
|
+
|
|
1110
|
+
### Practical implication
|
|
1111
|
+
|
|
1112
|
+
A migration from script-specialists to the new system is **not** just a file-format rewrite. It is a shift from:
|
|
1113
|
+
|
|
1114
|
+
- prompt templates consumed by services
|
|
1115
|
+
|
|
1116
|
+
to:
|
|
1117
|
+
|
|
1118
|
+
- a richer specialist runtime/orchestration platform
|
|
1119
|
+
|
|
1120
|
+
That migration requires decisions about:
|
|
1121
|
+
|
|
1122
|
+
- how services invoke specialists
|
|
1123
|
+
- whether specialists remain in-process/config-driven or become external runtime entities
|
|
1124
|
+
- how execution config is actually enforced
|
|
1125
|
+
- whether qwen-service remains the transport layer or is replaced
|
|
1126
|
+
|
|
1127
|
+
---
|
|
1128
|
+
|
|
1129
|
+
## Key Findings for Refactor Planning
|
|
1130
|
+
|
|
1131
|
+
## Finding 1
|
|
1132
|
+
The legacy system is still structurally important.
|
|
1133
|
+
|
|
1134
|
+
It is not dead code. It is active in:
|
|
1135
|
+
|
|
1136
|
+
- `ingestion/summarizer.py`
|
|
1137
|
+
- `ingestion/official_docs.py`
|
|
1138
|
+
- `squawks/rolling_context.py`
|
|
1139
|
+
|
|
1140
|
+
## Finding 2
|
|
1141
|
+
The biggest hidden debt is the **illusion of execution control**.
|
|
1142
|
+
|
|
1143
|
+
Specialists declare execution parameters that are not consistently honored.
|
|
1144
|
+
|
|
1145
|
+
## Finding 3
|
|
1146
|
+
The main fragility is now **qwen-service coupling**, not YAML itself.
|
|
1147
|
+
|
|
1148
|
+
The YAML loader is simple and stable. The unstable piece is the Qwen transport/execution substrate.
|
|
1149
|
+
|
|
1150
|
+
## Finding 4
|
|
1151
|
+
Rolling context is the hardest migration case.
|
|
1152
|
+
|
|
1153
|
+
It already behaves like a multi-stage orchestration pipeline while still using the simple legacy loader.
|
|
1154
|
+
|
|
1155
|
+
## Finding 5
|
|
1156
|
+
The repository has a **conceptual split-brain** around the word "specialists".
|
|
1157
|
+
|
|
1158
|
+
Any refactor should explicitly resolve the distinction between:
|
|
1159
|
+
|
|
1160
|
+
- runtime script/service specialists
|
|
1161
|
+
- agent/orchestration specialists
|
|
1162
|
+
|
|
1163
|
+
---
|
|
1164
|
+
|
|
1165
|
+
## Recommended Mental Model
|
|
1166
|
+
|
|
1167
|
+
If you need one sentence to explain the current script-specialists design:
|
|
1168
|
+
|
|
1169
|
+
> The current script-specialists system is a YAML-backed prompt/config registry for Python services, loaded via a lightweight Pydantic/Template runtime, with actual LLM execution delegated to qwen-service.
|
|
1170
|
+
|
|
1171
|
+
And if you need one sentence about its main limitation:
|
|
1172
|
+
|
|
1173
|
+
> It looks like a full specialist execution framework, but in reality it is mostly a prompt registry layered on top of service code and a fragile qwen-service transport.
|
|
1174
|
+
|
|
1175
|
+
---
|
|
1176
|
+
|
|
1177
|
+
## Appendix A — Active Legacy Specialists
|
|
1178
|
+
|
|
1179
|
+
### `mercury-atomic-summarizer`
|
|
1180
|
+
Used by article summarization pipeline.
|
|
1181
|
+
|
|
1182
|
+
### `official-document-analyzer`
|
|
1183
|
+
Used by official government document importer.
|
|
1184
|
+
|
|
1185
|
+
### `squawk-rolling-context`
|
|
1186
|
+
Extractor stage for rolling context.
|
|
1187
|
+
|
|
1188
|
+
### `squawk-event-curator`
|
|
1189
|
+
Event curation stage for rolling context.
|
|
1190
|
+
|
|
1191
|
+
### `squawk-session-analyst`
|
|
1192
|
+
Session synthesis stage for rolling context.
|
|
1193
|
+
|
|
1194
|
+
---
|
|
1195
|
+
|
|
1196
|
+
## Appendix B — Current Consumer Matrix
|
|
1197
|
+
|
|
1198
|
+
| Consumer | Specialist(s) | Call path | Output target |
|
|
1199
|
+
|---|---|---|---|
|
|
1200
|
+
| `ingestion/summarizer.py` | `mercury-atomic-summarizer` | `shared.qwen_client.QwenClient` | `articles.summary` |
|
|
1201
|
+
| `ingestion/official_docs.py` | `official-document-analyzer` | direct HTTP to qwen-service | article summary / DB |
|
|
1202
|
+
| `squawks/rolling_context.py` | `squawk-rolling-context`, `squawk-event-curator`, `squawk-session-analyst` | direct HTTP helper to qwen-service | `squawk_rolling_context.processed_data` |
|
|
1203
|
+
|
|
1204
|
+
---
|
|
1205
|
+
|
|
1206
|
+
## Appendix C — Current Runtime Reality vs Declared Model
|
|
1207
|
+
|
|
1208
|
+
| Area | Declared by design | Actual current behavior |
|
|
1209
|
+
|---|---|---|
|
|
1210
|
+
| Specialist config | full structured runtime config | mostly prompt + metadata + nominal execution hints |
|
|
1211
|
+
| Execution settings | model/temperature/max_tokens specialist-specific | mostly ignored on main client path |
|
|
1212
|
+
| Output schema validation | JSON-schema-like contract | required-fields-only check in practice |
|
|
1213
|
+
| Hot reload | implied quick prompt iteration | edit + container restart |
|
|
1214
|
+
| Orchestration | specialist-defined behavior | still owned mostly by Python service code |
|
|
1215
|
+
| LLM backend independence | specialist abstracted from model transport | tightly coupled to qwen-service/qwen CLI assumptions |
|
|
1216
|
+
|
|
1217
|
+
---
|
|
1218
|
+
|
|
1219
|
+
## Appendix D — Files Most Relevant to Any Migration
|
|
1220
|
+
|
|
1221
|
+
### Must-read
|
|
1222
|
+
|
|
1223
|
+
- `shared/specialist_system/loader.py`
|
|
1224
|
+
- `shared/specialist_system/schema.py`
|
|
1225
|
+
- `shared/qwen_client.py`
|
|
1226
|
+
- `ingestion/summarizer.py`
|
|
1227
|
+
- `ingestion/official_docs.py`
|
|
1228
|
+
- `squawks/rolling_context.py`
|
|
1229
|
+
- `llm_gateway/src/llm_gateway/main.py`
|
|
1230
|
+
- `llm_gateway/src/llm_gateway/wrapper.py`
|
|
1231
|
+
- `llm_gateway/src/llm_gateway/manager.py`
|
|
1232
|
+
- `ingestion/infra/docker-compose.yml`
|
|
1233
|
+
|
|
1234
|
+
### Useful context
|
|
1235
|
+
|
|
1236
|
+
- `specialists/SPECIALIST_SYSTEM_IMPLEMENTATION.md`
|
|
1237
|
+
- `docs/guides/qwen-service-integration-guide.md`
|
|
1238
|
+
- `tests/test_rolling_context_specialists.py`
|
|
1239
|
+
- `.serena/memories/specialist-system_ssot.md`
|
|
1240
|
+
|
|
1241
|
+
---
|
|
1242
|
+
|
|
1243
|
+
## Closing Assessment
|
|
1244
|
+
|
|
1245
|
+
The script-specialists design was a strong and pragmatic step: it externalized prompt logic, enabled fast iteration, and proved especially useful in ingestion and rolling-context services. But the system has now outgrown its original shape.
|
|
1246
|
+
|
|
1247
|
+
Today it sits in an in-between state:
|
|
1248
|
+
|
|
1249
|
+
- more structured than hardcoded prompts
|
|
1250
|
+
- less capable than the newer specialist runtime
|
|
1251
|
+
- increasingly constrained by qwen-service assumptions
|
|
1252
|
+
- partially mismatched between declared configuration and actual execution behavior
|
|
1253
|
+
|
|
1254
|
+
That makes this a good moment to replace or adapt it — especially because the brittle part is no longer the YAML concept itself, but the old execution substrate and the conceptual split with the newer `.specialists` platform.
|