mirror of
https://github.com/OpenSquawk/OpenSquawk
synced 2026-08-04 16:22:48 +08:00
docs: align CLAUDE.md/AGENTS.md/README with the two-repo architecture; drop dead LLM routing
The LLM decision routing moved to the external Python backend (OpenSquawk-LiveATC-api), but the core docs still described the old in-Nuxt path (routeDecision(), /api/llm/decide, a Nuxt /api/decision-flows/runtime route) — none of which exist. Every agent session started with a wrong mental model. - Rewrite CLAUDE.md to describe the real /pm flow (useRadioBackend -> Python backend owns authoritative state; Nuxt owns STT/TTS/audio/auth/editor) and fix stale commands (bun -> yarn). - Fix the two stale AGENTS.md lines (openai.ts is getOpenAIClient() only; decisionFlowService is editor-only, no Nuxt runtime route). - README: note the Python backend is required for /pm; correct server/ desc. - Remove dead shared/utils/openaiDecision.ts (called the non-existent /api/llm/decide) and the now-orphaned LLM decision contract types in shared/types/llm.ts. Trace types used by pm.vue are kept. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -10,8 +10,8 @@
|
||||
## Key Files
|
||||
- `/shared/utils/communicationsEngine.ts` — Core state machine composable (used by `/pm` live ATC). Drives local cursor and TTS; Python backend owns the authoritative state.
|
||||
- `/app/composables/useRadioBackend.ts` — Typed wrapper around the Python backend REST API (`createSession`, `transmit`, `deleteSession`, `fetchFlows`)
|
||||
- `/server/utils/openai.ts` — Legacy LLM decision router (`routeDecision()`). No longer called by `/pm`; may still be used by other routes.
|
||||
- `/server/services/decisionFlowService.ts` — Builds runtime decision trees from MongoDB (used by Nuxt `/api/decision-flows/runtime`; `/pm` now fetches directly from the Python backend)
|
||||
- `/server/utils/openai.ts` — `getOpenAIClient()` only (TTS via `/api/atc/say`, STT via `/api/atc/ptt`). The old `routeDecision()` LLM router has been removed; routing lives in the Python backend.
|
||||
- `/server/services/decisionFlowService.ts` — Builds/edits MongoDB-backed decision trees for the flow editor (`/server/api/editor/flows*`). There is no Nuxt `/api/decision-flows/runtime` route — `/pm` fetches the runtime flow directly from the Python backend.
|
||||
- `/app/pages/pm.vue` — Live ATC page (speech-to-text, PTT, text input)
|
||||
- `/app/pages/classroom.vue` — Classroom learning mode (separate system, does NOT use communicationsEngine)
|
||||
|
||||
|
||||
63
CLAUDE.md
63
CLAUDE.md
@@ -5,26 +5,59 @@
|
||||
- **H3 server** handlers in `/server`
|
||||
- **Shared types/utils** in `/shared`
|
||||
- MongoDB models in `/server/models`
|
||||
- **Python backend** — a separate repo, `OpenSquawk-LiveATC-api`, owns the authoritative
|
||||
Live ATC (`/pm`) session state and routing decisions. It runs as its own service
|
||||
(default `http://127.0.0.1:8000`). This Nuxt app owns STT, TTS, client audio, auth,
|
||||
the flow editor, and account/admin features.
|
||||
|
||||
> The LLM decision routing that used to live in this repo (`routeDecision()`,
|
||||
> `/api/llm/decide`, a Nuxt `/api/decision-flows/runtime` route) has been removed.
|
||||
> Decision routing now happens in the Python backend. Don't reintroduce it here.
|
||||
|
||||
## Key Files
|
||||
- `/shared/utils/communicationsEngine.ts` — Core state machine composable (used by `/pm` live ATC)
|
||||
- `/server/utils/openai.ts` — LLM decision router (`routeDecision()`)
|
||||
- `/server/services/decisionFlowService.ts` — Builds runtime decision trees from MongoDB
|
||||
- `/app/pages/pm.vue` — Live ATC page (speech-to-text, PTT, text input)
|
||||
- `/app/pages/classroom.vue` — Classroom learning mode (separate system, does NOT use communicationsEngine)
|
||||
- `/app/composables/useRadioBackend.ts` — Typed client for the Python backend REST API
|
||||
(`createSession`, `transmit`, `deleteSession`, `fetchFlows`). This is how `/pm` talks
|
||||
to the decision engine.
|
||||
- `/shared/utils/communicationsEngine.ts` — Local state-machine composable used by `/pm`.
|
||||
It mirrors the flow for cursor tracking and TTS scheduling; the **Python backend owns the
|
||||
authoritative state**. `fetchRuntimeTree()` loads the flow definition from the backend's
|
||||
`/api/decision-flows/runtime`.
|
||||
- `/server/services/decisionFlowService.ts` — Builds/edits MongoDB-backed decision trees.
|
||||
Used **only by the flow editor** (`/server/api/editor/flows*`), not by `/pm`.
|
||||
- `/server/utils/openai.ts` — `getOpenAIClient()` only. Used for TTS (`/api/atc/say`) and
|
||||
STT (`/api/atc/ptt`). It is **not** a decision router anymore.
|
||||
- `/app/pages/pm.vue` — Live ATC page (speech-to-text, PTT, text input).
|
||||
- `/app/pages/classroom.vue` — Classroom learning mode (separate system, does NOT use
|
||||
communicationsEngine).
|
||||
|
||||
## Live ATC Flow (/pm)
|
||||
1. User inputs (PTT or text) → `handlePilotTransmission()`
|
||||
2. `processPilotTransmission()` logs the pilot message
|
||||
3. `buildLLMContext()` builds candidates from `nextCandidates`
|
||||
4. POST `/api/llm/decide` → `routeDecision()` selects next state
|
||||
5. `applyLLMDecision()` moves to next state, updates vars/flags
|
||||
6. `collectAtcStatesUntilPilotTurn()` advances through ATC/system states
|
||||
7. Each ATC `say_tpl` is spoken via TTS (`scheduleControllerSpeech`)
|
||||
1. `startMonitoring()` → `fetchRuntimeTree('icao_atc_decision_tree', radioBackendUrl)`
|
||||
loads the flow definition from the Python backend into the local engine (cursor / TTS).
|
||||
2. `startMonitoring()` → `radioBackend.createSession(...)` creates the authoritative
|
||||
server-side session and stores `backendSessionId`.
|
||||
3. User input (PTT or text) → `handlePilotTransmission()`.
|
||||
PTT audio is transcribed first via Nuxt `POST /api/atc/ptt` (Whisper).
|
||||
4. `radioBackend.transmit(backendSessionId, transcript)` → the Python backend runs regex
|
||||
routing, readback evaluation, side effects, and flow chaining; it returns
|
||||
`next_state_id`, `controller_say_template`, `auto_advanced_states`, `flags`,
|
||||
and `session_complete`.
|
||||
5. `moveToSilent(stateId)` is called for each auto-advanced state and the final state —
|
||||
advances the local cursor without re-triggering auto-transitions.
|
||||
6. `scheduleControllerSpeech(...)` speaks the ATC reply via TTS (`/api/atc/say`).
|
||||
|
||||
## Decision Tree States
|
||||
States have `role: 'pilot' | 'atc' | 'system'`. ATC states have `say_tpl` (what controller says). Pilot states have `utterance_tpl` (expected pilot response). Transitions: `next`, `ok_next`, `bad_next`, `timer_next`.
|
||||
States have `role: 'pilot' | 'atc' | 'system'`. The local engine handles two template
|
||||
schemas transparently (via `stateSayTpl()` / `stateUtteranceTpl()`):
|
||||
- Legacy (MongoDB editor): `say_tpl`, `utterance_tpl`, vars as `{var}`
|
||||
- Python backend YAML: `say_template`, `expected_pilot_template`, vars as `{{var}}`
|
||||
|
||||
Both `{{var}}` and `{var}` are rendered by `renderTpl()`. Transition fields seen across
|
||||
schemas: `next`, `ok_next`, `bad_next`, `timer_next`, `auto_transitions`.
|
||||
|
||||
## Environment Variables
|
||||
- `NUXT_PUBLIC_RADIO_BACKEND_URL` — URL of the Python backend (default `http://127.0.0.1:8000`)
|
||||
|
||||
## Commands
|
||||
- `bun run dev` — dev server
|
||||
- Decision trees are stored in MongoDB and fetched via `/api/decision-flows/runtime`
|
||||
- `yarn dev` — dev server (Nuxt)
|
||||
- `yarn test` — runs the `tsx --test` suite (`tests/`, `server/`, `shared/`)
|
||||
- Python backend: see `OpenSquawk-LiveATC-api/README.md`
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
import type { DecisionNodeCondition, DecisionNodeTrigger } from './decision'
|
||||
|
||||
export interface LLMDecisionInput {
|
||||
state_id: string
|
||||
state: any
|
||||
candidates: Array<{ id: string; state: any; flow?: string }>
|
||||
variables: Record<string, any>
|
||||
flags: Record<string, any>
|
||||
pilot_utterance: string
|
||||
flow_slug?: string
|
||||
}
|
||||
|
||||
export type FlowActivationMode = 'main' | 'parallel' | 'linear'
|
||||
|
||||
export interface FlowActivationInstruction {
|
||||
@@ -17,14 +7,6 @@ export interface FlowActivationInstruction {
|
||||
mode?: FlowActivationMode
|
||||
}
|
||||
|
||||
export interface ActiveNodeSummary {
|
||||
flow: string
|
||||
state: string
|
||||
role?: string
|
||||
say_tpl?: string
|
||||
controller_say_tpl?: string
|
||||
}
|
||||
|
||||
export interface CandidateTraceEntry {
|
||||
id: string
|
||||
flow: string
|
||||
@@ -81,17 +63,6 @@ export interface DecisionCandidateTimeline {
|
||||
autoSelected?: CandidateTraceEntry | null
|
||||
}
|
||||
|
||||
export interface LLMDecision {
|
||||
next_state: string
|
||||
updates?: Record<string, any>
|
||||
flags?: Record<string, any>
|
||||
controller_say_tpl?: string
|
||||
off_schema?: boolean
|
||||
radio_check?: boolean
|
||||
activate_flow?: string | FlowActivationInstruction
|
||||
resume_previous?: boolean
|
||||
}
|
||||
|
||||
export interface LLMDecisionTraceCall {
|
||||
stage: 'readback-check' | 'decision'
|
||||
request: Record<string, any>
|
||||
@@ -116,10 +87,3 @@ export interface LLMDecisionTrace {
|
||||
reason?: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface LLMDecisionResult {
|
||||
decision: LLMDecision
|
||||
trace?: LLMDecisionTrace
|
||||
active_nodes?: ActiveNodeSummary[]
|
||||
pilot_intent?: string | null
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user