feat(godot-companion): Introduce Companion singleton with network synchronization, event handling, and UI integration for companion module

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Claude Code 2026-03-29 10:05:35 -07:00
parent d9caffdd63
commit f6501bf24d

View file

@ -22,7 +22,7 @@ const AvatarHitboxScript = preload("res://src/avatar/avatar_hitbox.gd")
const AvatarRotateScript = preload("res://src/avatar/avatar_rotate.gd")
const DuplexClientScript = preload("res://src/conversation/duplex_client.gd")
const NodeUtilsScript = preload("res://src/core/node_utils.gd")
const ServiceHealthScript = preload("res://src/core/service_health.gd")
const ServiceRegistryScript = preload("res://src/core/service_registry.gd")
const MODEL_DIR: String = "res://models/"
const PREFERRED_MODELS: Array[String] = [
@ -131,7 +131,6 @@ func setup_conversation() -> void:
_chat_window = ChatWindowScript.new()
_chat_window.name = "ChatWindow"
get_tree().root.add_child.call_deferred(_chat_window)
_chat_window.setup()
_chat_window.hide()
EventBus.avatar_tapped.connect(_toggle_chat_window)
EventBus.chat_opened.connect(_on_chat_opened)
@ -140,7 +139,7 @@ func setup_conversation() -> void:
EventBus.conversation_switch_requested.connect(_on_switch_conversation)
_restore_or_create_conversation()
_run_health_check()
_startup_services()
func play_startup_sound() -> void:
@ -261,19 +260,32 @@ func _deferred_replay(messages: Variant) -> void:
_chat_window.replay_messages(typed)
func _run_health_check() -> void:
var health := ServiceHealthScript.new()
health.name = "ServiceHealth"
add_child(health)
var results: Array[Dictionary] = await health.check_all()
health.queue_free()
func _startup_services() -> void:
var registry := ServiceRegistryScript.new()
registry.name = "ServiceRegistry"
add_child(registry)
(
registry
. configure(
CompanionConfig.llm_url,
CompanionConfig.llm_model,
CompanionConfig.speech_url,
CompanionConfig.tts_enabled,
CompanionConfig.stt_enabled,
)
)
registry.startup_complete.connect(_on_startup_complete)
registry.run_startup()
var failures: Array[String] = []
for result: Dictionary in results:
if not result.get("ok", false):
failures.append("%s: %s" % [result.get("label", "?"), result.get("reason", "unknown")])
if not failures.is_empty():
var msg := "Services unavailable — %s" % ", ".join(failures)
FlightRecorder.record("health.failed", msg)
_chat_window.show_error(msg)
func retry_services() -> void:
var old: Node = get_node_or_null("ServiceRegistry")
if old != null:
old.queue_free()
_startup_services()
func _on_startup_complete(failures: Array[String]) -> void:
if failures.is_empty():
return
_chat_window.show_error("Services unavailable — %s" % ", ".join(failures))