This document summarizes NaviGo’s explainability and responsible AI practices based on the current repository implementation (src/**, tests/**, .github/workflows/**, scripts/**).
Every agent appends a decisionLog entry (makeDecisionLog) when outputting Partial<PlannerState>, including:
agentinputSummarykeyEvidenceoutputSummaryriskFlagstimestampThis means callers can see not only the final finalPlan, but also “what decision was made based on what evidence” at every step.
All LLM-requiring agents use withStructuredOutput(...) + Zod schema, preventing free text from directly entering state:
ExtractedRequestSchema (requirement_parser)FormCompletionSchema (form_completer)RiskGuardSchema (risk_guard)PreferencesSchema (preference_agent)DestinationSuggestionsSchema / DestinationCandidateSchema (destination_agent)ItineraryDraftSchema (itinerary_agent)BudgetAssessmentSchema (budget_agent)PackingListSchema (packing_agent)PlanSynthesisSchema (plan_synthesizer)Zod validation covers:
src/config/env.tssrc/interfaces/api/routes/plan.route.tsFinalPlanSchemapreference_agent, if the user explicitly provided interests in userRequest, they override model-extracted interests, reducing the risk of “the model silently rewriting user preferences.”destination_agent, the user’s explicitly provided destination (hint + city code + IATA) is prepended as a fallback candidate, ensuring user intent is not ignored.risk_guard writes detected risks to safetyFlags (dual-layer scanning: rules + LLM semantics).budget_agent writes BUDGET_EXCEEDED when over budget.plan_synthesizer carries safety flags into the final output.Even if planning can continue, risks are never hidden.
When prompt injection (BLOCKED_PROMPT_INJECTION) is detected, the router sends flow directly to plan_synthesizer to generate a safe refusal summary, rather than continuing the full planning chain.
form_completer does not silently guess or fill in missing required fields; instead, it generates 1–2 natural-language clarifying questions returned to the client, and only continues after user confirmation. This prevents the model from擅自 inferring user constraints that were not explicitly expressed.
Graph state is persisted via checkpointer; the API provides GET /plan/:threadId to read thread snapshots for:
valuesEnabled when LANGSMITH_TRACING=true; metadata is injected via buildTraceMetadata(...) with:
userIdthreadIdscenarioserviceIn the current implementation, userRequest (including userId) is part of PlannerState, so it enters checkpoint state (depending on the checkpointer used).
Therefore:
If the deployment has stricter data minimization requirements, it is recommended to anonymize/map userId before invocation, or introduce a minimal-field policy at the state layer.
All above boundaries can be directly observed from the existing codebase.