Skip to content

Commit 9b5b17e

Browse files
committed
Add Simurgh turn intent routing frame
1 parent 5715ba5 commit 9b5b17e

10 files changed

Lines changed: 666 additions & 83 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ and this project uses simple two-part versioning: `X.Y` (Major.Minor).
1414
polish, and hover-only copy controls for a cleaner operator experience.
1515
- Simurgh documentation/context coverage for PX4-first MDS support boundaries,
1616
MAVLink routing, and read-only fleet/telemetry guidance.
17+
- Simurgh turn-level semantic intent frame for one coherent route decision per
18+
operator message before confirmation, action drafting, read-only tools, or
19+
provider fallback, with sanitized trace metadata for PM/test inspection.
1720
- Simurgh guarded action monitoring for long-running flight commands and SITL
1821
lifecycle operations, including same-session implicit target inference and
1922
conditional post-action cleanup after terminal success.
@@ -32,6 +35,10 @@ and this project uses simple two-part versioning: `X.Y` (Major.Minor).
3235
fields for dashboard progress rendering instead of requiring text scraping.
3336

3437
### Fixed
38+
- Simurgh no longer lets bare approval wording such as "go ahead" confirm an
39+
old pending action when the same message is actually a new read/status task.
40+
- Simurgh no longer drafts flight actions from advisory motion-status questions
41+
such as asking whether a drone should land or can RTL safely.
3542
- Simurgh no longer treats fresh action requests that contain approval-like
3643
wording such as "send it to test flight" as bare confirmations; PM-style
3744
takeoff-wait-move-return sequences now reach the guarded action planner.

docs/agent-context/generated/simurgh-docs-index.json

Lines changed: 61 additions & 41 deletions
Large diffs are not rendered by default.

docs/guides/simurgh-operator.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,43 @@ read-only operator slice plus selected guarded actions:
2828
- generated public docs/chunk index with MCP search and bounded chunk retrieval
2929
- read-only drone log and onboard PX4 ULog metadata summaries through approved
3030
GCS-side log endpoints, without raw ULog download/erase exposure
31+
- a provider-neutral turn-level semantic intent frame that produces one coherent
32+
routing decision before confirmation, action drafting, read-only tools, or
33+
provider fallback
3134
- guarded SITL lifecycle actions through canonical GCS SITL Control routes
3235
- guarded curated flight-command drafts through canonical GCS command routes
3336
- no direct drone API exposure
3437

38+
## Semantic Understanding Boundary
39+
40+
Simurgh should not rely on scattered keyword checks as the user-facing
41+
intelligence layer. Each assistant turn is first interpreted as one structured
42+
intent frame that records the adapted routing text, read-only plan, possible
43+
action draft, confirmation/rejection signal, confidence, and reasons. The route
44+
then consumes that single frame instead of independently asking several regex
45+
classifiers whether the message is a confirmation, action, read-only query, or
46+
provider turn.
47+
48+
The sanitized response trace exposes this frame under `trace.intent` so PM
49+
tests, dashboard UI, and future agent tooling can explain why a turn routed as a
50+
read-only check, action draft, confirmation, rejection, or provider fallback
51+
without scraping answer prose.
52+
53+
This frame is an interpretation layer, not an authority layer:
54+
55+
- semantic interpretation may decide that "go ahead and check SITL instances" is
56+
a read/status task instead of an approval;
57+
- semantic interpretation may preserve a multi-step action plan such as
58+
takeoff, wait, move north, then RTL;
59+
- deterministic enforcement still owns registry schema validation, runtime mode,
60+
approval, circuit breaker, auth, command submission, monitoring, and audit.
61+
62+
Future provider-backed structured-output classifiers should plug into this same
63+
frame contract. They may improve language, tone, paraphrase, and target-memory
64+
understanding, but they must still emit typed plans that the existing policy and
65+
executor layers validate. Provider prose must never be treated as approval or as
66+
proof that an action executed.
67+
3568
## Dashboard Chat UX Contract
3669

3770
The `/simurgh` dashboard surface should stay chat-first and low-noise:

docs/plans/2026-06-20-simurgh-language-intent-modernization.md

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,22 @@ Implemented:
3939

4040
- deterministic language/tone profile;
4141
- config-driven query adaptation in `config/agent_query_adaptation.yaml`;
42+
- provider-neutral turn-level semantic intent frame in
43+
`gcs-server/agent_runtime/turn_intent.py`, consumed by the dashboard
44+
assistant route before confirmation/action/read-only/provider branching;
4245
- local read-only tool routing and selected guarded actions;
4346
- provider composition for safe text turns;
4447
- optional public web-search lane for public/current facts;
4548
- action confirmation, circuit breaker, and audit enforcement outside provider
4649
prose;
4750
- dashboard prompt evals for PM-style conversations.
4851

49-
Gap:
52+
Remaining gap:
5053

51-
- route selection still leans too heavily on deterministic wording rules;
52-
- multi-step action intent can collapse to the last command when the planner
53-
misses sequence semantics;
54-
- target memory is not yet treated as a first-class structured input/output;
54+
- provider-backed structured-output semantic classification is not yet enabled
55+
in the action path; the current frame is provider-neutral and testable;
56+
- target memory is partially structured through last action/result context, but
57+
broader live-fleet target inference still needs careful safety review;
5558
- some failures still answer from docs instead of running the most relevant
5659
local evidence tool;
5760
- answer localization and tone adaptation are not yet uniformly available for
@@ -188,12 +191,26 @@ understanding, target memory, planner, executor, answer composition, or UI.
188191
- New failures add evals first; aliases are added only when they meet the rule
189192
boundary above.
190193

191-
## Current Handoff Note
194+
## Current Implementation Checkpoint
192195

193-
This document does not change runtime behavior. The deployed `v5.5.96` fix for
194-
SITL-created-drone readiness follow-ups remains the current PM-test baseline.
195-
The next Simurgh slice should implement semantic-understanding dry-run and
196-
evals before more alias expansion.
196+
The first implementation slice adds a structured, provider-neutral
197+
`TurnIntentFrame`, routes dashboard assistant turns through it, and exposes the
198+
sanitized interpretation under `trace.intent`. The frame prevents two PM-visible
199+
failures:
200+
201+
- approval-like wording with a new read/status task, such as "go ahead and
202+
check SITL instances now", no longer confirms an old pending action;
203+
- advisory motion questions, such as "tell me if drone 1 should land", no
204+
longer draft guarded flight commands.
205+
206+
Regression coverage now includes frame-level tests and dashboard-route tests for
207+
PM-style compound action plans, exact draft confirmations, read/status task
208+
arbitration, and advisory-vs-command flight wording.
209+
210+
The next Simurgh slice should use the same frame contract for optional
211+
provider-backed structured semantic classification, broader target memory, and
212+
multilingual/tone-sensitive evals. Do not add broad alias lists as a substitute
213+
for this frame.
197214

198215
## References Reviewed
199216

gcs-server/agent_runtime/action_planner.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,19 @@ def _extract_sitl_instance_names(normalized: str) -> list[str]:
657657

658658

659659
def _looks_conceptual(normalized: str) -> bool:
660+
flight_action_terms = r"land|landing|rtl|return|take\s*off|takeoff"
661+
advisory_terms = r"status|ready|safe|safely|should|whether|if"
662+
if re.search(
663+
rf"\b(tell\s+me|show\s+me|check|report)\b.{{0,80}}\b(?:{flight_action_terms})\b.{{0,80}}\b(?:{advisory_terms})\b",
664+
normalized,
665+
):
666+
return True
667+
if re.search(rf"\b(?:{advisory_terms})\b.{{0,80}}\b(?:{flight_action_terms})\b", normalized):
668+
return True
669+
if re.search(rf"\b(?:{flight_action_terms})\b.{{0,80}}\b(?:{advisory_terms})\b", normalized):
670+
return True
671+
if re.search(r"\bcan\s+(?:drone|vehicle|aircraft)\s+\d+\b.{0,80}\b(land|rtl|return)\b", normalized):
672+
return True
660673
instructional = (
661674
"how to",
662675
"how do i",

gcs-server/agent_runtime/assistant.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2855,6 +2855,11 @@ def create_assistant_turn(
28552855
"provider_composed_from_previous_evidence": provider_composed_from_previous_evidence,
28562856
"evidence_followup_kind": evidence_followup_kind if tool_intent == "evidence_followup" else None,
28572857
"provider_composition_error": provider_composition_error,
2858+
"turn_intent": (
2859+
dict(metadata.get("turn_intent") or {})
2860+
if isinstance(metadata, Mapping) and isinstance(metadata.get("turn_intent"), Mapping)
2861+
else {}
2862+
),
28582863
"query_adaptation": query_adaptation.public_metadata(),
28592864
"routing_strategy": query_adaptation.strategy,
28602865
"routing_language": query_adaptation.routing_language,

0 commit comments

Comments
 (0)