Skip to content

Add language/location support: setup wizard, LLM matching, localization#651

Open
emooreatx wants to merge 21 commits intomainfrom
claude/amharic-language-support-F5j4O
Open

Add language/location support: setup wizard, LLM matching, localization#651
emooreatx wants to merge 21 commits intomainfrom
claude/amharic-language-support-F5j4O

Conversation

@emooreatx
Copy link
Copy Markdown
Contributor

@emooreatx emooreatx commented Mar 25, 2026

Summary

  • Agent was responding in English even when users wrote in other languages (e.g., Amharic)
  • Added language matching instruction to action selection PDMA so the LLM matches the user's language
  • Surfaced preferred_language from user profiles to LLM context
  • Added new "Preferences" step to setup wizard (CLI + Android) for language and location at user-chosen granularity
  • Created /localization/ folder with auto-generated translations for 15 languages

Changes

LLM Language Matching (commit 1)

  • action_selection_pdma.yml — LANGUAGE MATCHING instruction in closing_reminder
  • user_profiles.py — Include preferred_language in profile formatter output

Setup Wizard - Preferences Step (commit 2)

  • Backend: SetupCompleteRequest gains preferred_language, location_country, location_region, location_city, timezone fields
  • Backend: complete.py saves preferences to .env and stores in graph memory as a CONCEPT node
  • CLI wizard: New prompt_language_and_location() with 15-language picker and granularity-selectable location
  • Android: New 4-step flow (Welcome > Preferences > AI Config > Confirm)
    • SetupPreferencesFragment.kt — Language spinner + location radio group with dynamic fields
    • SetupViewModel.kt — Language/location state management
    • fragment_setup_preferences.xml — Layout with granularity-based visibility
    • activity_setup_wizard.xml — 4-step indicator
    • strings.xml — New preference string resources

Localization Folder (/localization/)

  • manifest.json — Tracks origin (auto-generated), addition dates, review status per language
  • 15 language files: en, am, ar, de, es, fr, hi, it, ja, ko, pt, ru, sw, tr, zh
  • Covers: setup wizard strings, common agent messages, status labels
  • All non-English files marked needs_native_review

Location Granularity

Users choose their own level of detail:

  • Prefer not to say (default)
  • Country only
  • Country + Region/State
  • Country + Region + City

Test plan

  • SetupCompleteRequest accepts new fields correctly
  • User profile formatter shows preferred language for non-English users
  • All 16 localization JSON files validate as valid JSON
  • CLI wizard language/location prompts work end-to-end
  • Android build with new fragment and 4-step flow
  • Manual: send Amharic message, verify Amharic response

https://claude.ai/code/session_01Kk7Kjgu8YRuZzB6X5RTgdQ

emooreatx and others added 13 commits March 23, 2026 21:41
ASPDMA Schema Fix:
- Remove tool_parameters from ASPDMALLMResult (only tool_name needed)
- Remove tool_parameters from TSASPDMAInputs (extracted by TSASPDMA)
- ASPDMA selects tool name; TSASPDMA extracts parameters from context

HA Adapter Fixes:
- Add missing parameter extraction (volume_level, temperature, hvac_mode, percentage)
- Fix misleading "Entity not found" error when media_play has no effect
- Error now explains media_play only resumes paused content
- Error now directs users to Music Assistant tools for playing new music

Documentation Updates:
- Clarify media_play ONLY resumes paused content
- Add critical gotcha: use ma_search/ma_play for new music playback
- Update quick_start and dma_guidance to direct to Music Assistant

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The mobile app's audit trail was showing limited details for TOOL and
PONDER entries because the API only extracted a subset of fields from
the parameters JSON.

Now extracts:
- TOOL: tool_name (also from "name" key), tool_parameters
- PONDER: ponder_questions (questions list)
- SPEAK: content
- DEFER: defer_reason, defer_until
- TASK_COMPLETE: completion_reason
- REJECT: reject_reason

This enables the mobile audit trail to show full details like:
- "Questions: What should I consider?; How do I proceed?"
- "Tool: ha_device_control → parameters: {entity_id: ..., action: ...}"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, if ANY SQLite entries existed, graph entries were skipped
entirely. This was wrong because:
- Handler actions (tool, ponder, speak) are stored in graph via log_action
- System events (agent_configured) go to SQLite
- Both sources are needed for a complete audit trail

Now both sources are always merged, giving the mobile app access to
all audit entries with their full metadata (ponder_questions, tool_name,
tool_parameters, tool_result, etc.)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added detailed logging to trace audit data flow:
- ActionDispatcher: Logs extracted params and full audit details
- Audit API: Logs graph entry conversion with metadata keys

This makes it clear what's being captured and returned:
- TOOL: tool_name, tool_parameters, tool_adapter, tool_result
- PONDER: ponder_questions, question_count

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…r enhancements

## Audit Trail
- Fix audit API to merge graph and SQLite sources (handler actions stored in graph)
- Extract all action-specific metadata: ponder_questions, tool_parameters, tool_result
- Add comprehensive audit logging for debugging data flow

## ASPDMA Schema
- Remove tool_parameters from ASPDMALLMResult (ASPDMA only selects tool name)
- TSASPDMA now extracts parameters from context with full tool documentation

## Home Assistant Adapter
- Add missing parameter extraction (volume_level, temperature, hvac_mode)
- Fix misleading "Entity not found" error for media_play actions
- Clarify media_play only resumes paused content; use Music Assistant for new music
- Update tool documentation and gotchas

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add full ToolDocumentation (detailed_instructions, examples, gotchas) for:
  - ma_browse: Library browsing with media_type filtering
  - ma_queue: Queue viewing with player_id requirement
  - ma_players: Player discovery with entity_id patterns
- Previously added docs for: ha_device_control, ha_automation_trigger,
  ha_sensor_query, ha_list_entities, ha_notification, ha_camera_analyze,
  ma_search, ma_play
- Fix mypy: Remove invalid tool_parameters from ASPDMALLMResult (ASPDMA
  only selects tool name, TSASPDMA handles parameters)
- Fix audit tests: Update test expectations to match correct multi-source
  merge behavior (entries show all sources, dedup by timestamp+action)
- Add context enrichment logging for tool prompt debugging

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When an event is first seen in graph memory, seen_timestamps is populated
but dedup_to_entry is not (only SQLite populates dedup_to_entry). This
caused JSONL records matching by timestamp+action to not have "jsonl"
added to storage_sources.

Fix: When dedup_to_entry lookup fails, search merged entries by matching
the dedup_key (timestamp+action) to find and update the correct entry.

Added test: test_jsonl_source_added_when_graph_entry_exists

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The when_to_use field was extracted but not displayed in the tool
highlight section. Now it's included to help the LLM understand
when to use the highlighted tool.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- ma_get_players(): Add detection for mass_player_type attribute and
  app_id == "music_assistant" to correctly identify MA-controlled players
  (e.g., bedroom_nabu_media_player_2 vs bedroom_nabu_media_player)
- ma_play(): Remove config_entry_id parameter which causes HTTP 400
  when invalid/unavailable - it's not required for play_media service

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 1: Per-user email for public API services
- Add publicApiEmail and publicApiServicesEnabled to SetupState
- Add setters in SetupViewModel
- Add Navigation & Weather card to OptionalFeaturesStep with:
  - Feature explanation (OSM, NOAA public APIs)
  - Enable/disable toggle
  - Email input field (shown when enabled)
- Update weather/navigation services to use PUBLIC_API_CONTACT_EMAIL
  env var from wizard, falling back to legacy env vars
- Pass email to adapter_config in setup completion request

This enables users to use navigation:geocode to convert location names
to coordinates for weather tools, all powered by free public APIs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…zard support

## Cross-Platform CIRIS_HOME Setup
- Add ensure_ciris_home_env() in path_resolution.py for centralized env var setup
- Update main.py to call ensure_ciris_home_env() early before ciris_engine imports
- Update mobile_main.py (Android) to use centralized function
- Update ios_main.py (iOS) to use centralized function
- Fix Android path fallback bug (Path.home() / "ciris" not "files/ciris")

## Desktop App QA Infrastructure
- Add testable tags to all navigation menu items in CIRISApp.kt:
  - Category buttons: btn_adapters_menu, btn_config_menu, btn_data_menu, btn_governance_menu
  - Menu items: menu_tools, menu_settings, menu_config, menu_billing
  - Data menu: menu_memory, menu_sessions, menu_consent, menu_audit, menu_data_management
  - Governance: menu_wise_authority, menu_users
  - Advanced: menu_telemetry, menu_services, menu_logs, menu_system, menu_runtime, menu_tickets, menu_scheduler

## SetupScreen Test Automation
- Add TestAutomation.textInputRequests observer for programmatic text input
- Support automated input for: input_public_api_email, input_username, input_password, input_api_key, input_llm_model_text

## Adapter Wizard Integration
- Add adapter wizard state fields to SetupFormState for wizard-in-wizard support
- Add SetupViewModel methods for adapter configuration during setup
- Enable adapter configuration flow within the setup wizard

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extract 11 helper functions from _process_graph_entries and
_process_sqlite_entries to reduce cognitive complexity from 56
to approximately 15. Add 53 unit tests for comprehensive coverage.

Helper functions added:
- _entry_has_additional_metadata()
- _merge_graph_metadata_into_entry()
- _find_sqlite_entry_for_dedup_key()
- _infer_outcome_from_event()
- _extract_handler_metadata()
- _parse_event_payload_metadata()
- _extract_sqlite_entry_info()
- _track_sqlite_dedup_key()
- _handle_duplicate_graph_entry()
- _add_new_graph_entry()
- _add_new_sqlite_entry()

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The agent was always responding in English even when users wrote in other
languages. Two changes fix this:

1. Action selection PDMA now instructs the LLM to match the user's language
2. User profile formatter now surfaces preferred_language to LLM context

https://claude.ai/code/session_01Kk7Kjgu8YRuZzB6X5RTgdQ
@cla-assistant
Copy link
Copy Markdown

cla-assistant bot commented Mar 25, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ emooreatx
❌ claude
You have signed the CLA already but the status is still pending? Let us recheck it.

@cla-assistant
Copy link
Copy Markdown

cla-assistant bot commented Mar 25, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

…uide

WalletAdapter:
- Generic money tools: send_money, request_money, get_statement
- x402 provider for USDC on Base L2 (Ed25519 -> secp256k1 derivation)
- Chapa provider for Ethiopian Birr via Telebirr/CBE Birr
- Context enrichment for get_statement (balance awareness)
- DMA guidance with requires_approval for financial ops
- Provider-agnostic design for future providers (M-Pesa, etc.)

Documentation:
- FSD/WALLET_ADAPTER.md - Full functional specification
- FSD/ADAPTER_DEVELOPMENT_GUIDE.md - Guide for building adapters
- CLAUDE.md updated with adapter development quick reference

Design for global access: Ethiopian philosophers pay in ETB,
developers pay in USDC - same service, same dignity.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@sonarqubecloud
Copy link
Copy Markdown

Setup wizard changes (all platforms):
- New "Preferences" step (Step 2) for language and location selection
- Users choose location granularity: country only, +region, +city, or none
- 15 languages in picker, auto-detect timezone on Android
- Preferences saved to .env and graph memory for LLM context
- Backend SetupCompleteRequest gains preferred_language, location_*, timezone fields

Android (4-step wizard: Welcome > Preferences > AI Config > Confirm):
- New SetupPreferencesFragment with language spinner and location radio group
- Dynamic location fields appear based on chosen granularity
- SetupViewModel extended with language/location state
- Layout updated with 4-step indicator

Localization folder (/localization/):
- manifest.json tracking origin (auto-generated), dates, review status
- 15 language files: en, am, ar, de, es, fr, hi, it, ja, ko, pt, ru, sw, tr, zh
- Covers setup wizard strings, common agent messages, and status labels
- All marked as draft/needs_native_review except English base

https://claude.ai/code/session_01Kk7Kjgu8YRuZzB6X5RTgdQ
@emooreatx emooreatx changed the title Add language matching for non-English responses Add language/location support: setup wizard, LLM matching, localization Mar 25, 2026
emooreatx and others added 3 commits March 25, 2026 14:26
Key security improvement:
- Wallet address derived from Ed25519 PUBLIC key (not seed)
- Private key NEVER leaves CIRISVerify secure element
- Signing delegated via callback to CIRISVerify
- Every CIRIS agent has a wallet address from birth

Changes:
- x402_provider.py: Accept public_key + signing_callback
- adapter.py: Auto-load from CIRISVerify singleton
- Address derivation via HKDF from public key
- Receive-only mode if no signing callback

For receiving funds: Only need public key (immediate)
For sending funds: Need signing callback to CIRISVerify

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The en.json base file now includes every string the LLM receives:
- DMA prompts: PDMA ethical principles, CSDMA common sense, IDMA
  coherence analysis, DSDMA domain norms, ASPDMA action selection,
  TSASPDMA tool selection
- System formatters: snapshot headers, continuity awareness, resource
  usage, context enrichment, identity fields, user profile context
- Handler messages: speak/observe/defer/reject/forget/memorize/ponder
  follow-up thoughts injected into LLM context
- Escalation stages: early/mid/late/exhausted guidance
- Crisis resources: guidance text and disclaimers
- Error messages: all API and service errors shown to users
- Discord: embed field labels, deferral messages
- Engine overview template

Manifest updated to v2.0 with string category documentation.
Non-English files have setup/agent/status coverage; remaining
sections noted as pending in manifest.

https://claude.ai/code/session_01Kk7Kjgu8YRuZzB6X5RTgdQ
Read values from the attributes dict instead of the setup object to
avoid CodeQL taint tracking through SetupCompleteRequest password fields.

https://claude.ai/code/session_01Kk7Kjgu8YRuZzB6X5RTgdQ
add_graph_node(node, time_service, None)
lang = attributes.get("preferred_language", "not set")
loc = attributes.get("location", "not set")
logger.info(f"Stored user preferences for {user_id}: lang={lang}, location={loc}")

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

This expression logs
sensitive data (password)
as clear text.
This expression logs
sensitive data (password)
as clear text.

Copilot Autofix

AI 20 days ago

To fix the problem, avoid logging the tainted user_id (derived from canonical_user_id) and instead either (a) remove the log line, or (b) log only non-sensitive metadata such as the fact that preferences were stored and possibly the language/location, without any stable identifier. This preserves observability while preventing sensitive or potentially sensitive identifiers from reaching the logs.

The minimal-change, best fix here is to adjust the log message in _store_user_preferences (lines 305–310) so it no longer includes user_id. The function’s behavior—storing preferences via add_graph_node—remains unchanged; we only change what is logged. Concretely, in ciris_engine/logic/adapters/api/routes/setup/complete.py, replace:

logger.info(f"Stored user preferences for {user_id}: lang={lang}, location={loc}")

with something like:

logger.info(f"Stored user preferences: lang={lang}, location={loc}")

This removes the tainted user_id from the log sink, which resolves all CodeQL variants tied to that flow. No new methods or imports are needed; only this single line is updated.


Suggested changeset 1
ciris_engine/logic/adapters/api/routes/setup/complete.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/ciris_engine/logic/adapters/api/routes/setup/complete.py b/ciris_engine/logic/adapters/api/routes/setup/complete.py
--- a/ciris_engine/logic/adapters/api/routes/setup/complete.py
+++ b/ciris_engine/logic/adapters/api/routes/setup/complete.py
@@ -306,7 +306,7 @@
     add_graph_node(node, time_service, None)
     lang = attributes.get("preferred_language", "not set")
     loc = attributes.get("location", "not set")
-    logger.info(f"Stored user preferences for {user_id}: lang={lang}, location={loc}")
+    logger.info(f"Stored user preferences: lang={lang}, location={loc}")
 
 
 async def _log_wa_list(auth_service: Any, phase: str) -> None:
EOF
@@ -306,7 +306,7 @@
add_graph_node(node, time_service, None)
lang = attributes.get("preferred_language", "not set")
loc = attributes.get("location", "not set")
logger.info(f"Stored user preferences for {user_id}: lang={lang}, location={loc}")
logger.info(f"Stored user preferences: lang={lang}, location={loc}")


async def _log_wa_list(auth_service: Any, phase: str) -> None:
Copilot is powered by AI and may make mistakes. Always verify output.
claude added 3 commits March 25, 2026 20:12
All 14 non-English files now have the complete key structure matching
en.json (290-303 entries each). Untranslated strings are prefixed with
[EN] for easy identification and batch translation.

Coverage per file:
- setup/agent/status sections: fully translated (existing)
- prompts/handlers/errors/discord: [EN] fallback (pending)

The [EN] prefix convention allows:
- grep -r "\[EN\]" localization/ to find all pending translations
- Batch translation tools to target only [EN]-prefixed values
- Runtime fallback to English for untranslated strings

https://claude.ai/code/session_01Kk7Kjgu8YRuZzB6X5RTgdQ
Merged release/2.3 and added all new user-facing strings:

New adapter sections:
- adapters.wallet: send_money, request_money, get_statement tool docs,
  currency/provider mapping, spending limits, error messages (Chapa ETB,
  x402 USDC, M-Pesa/Flutterwave future)
- adapters.navigation: geocode, reverse geocode, route calculation tool
  docs, OpenStreetMap rate limit notes, error messages
- adapters.weather: current/forecast/alerts tool docs, NOAA/OWM data
  sources, US-only gotchas, safety disclaimers

New mobile section:
- Setup wizard: agent registration, portal connect, node auth flow,
  validation errors, setup state labels
- Interact screen: action type labels, outcome labels, hallucination
  warning, welcome text, sender labels, field names

en.json: ~511 entries (up from ~298)
All 14 translations updated with [EN] fallbacks for new keys.
Manifest bumped to v2.1.0.

https://claude.ai/code/session_01Kk7Kjgu8YRuZzB6X5RTgdQ

import json
from datetime import datetime, timezone
from typing import Any, Dict
from typing import Any, Dict
from unittest.mock import MagicMock

import pytest
import uuid
from datetime import datetime, timezone
from decimal import Decimal
from typing import Any, Callable, Dict, List, Optional
# =============================================================================
from ciris_engine.logic.utils.path_resolution import ensure_ciris_home_env

_ciris_home = ensure_ciris_home_env()

Examples: 'x402', 'chapa', 'mpesa', 'flutterwave'
"""
...
- Chapa: ['ETB']
- M-Pesa: ['KES']
"""
...
Returns:
True if initialization successful, False otherwise.
"""
...
Called during adapter shutdown. Should close connections,
flush pending operations, etc.
"""
...
Raises:
ValueError: If currency not supported or parameters invalid
"""
...
Returns:
PaymentRequest with request ID, checkout URL, etc.
"""
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants