更新godot ai 到最新版本
This commit is contained in:
+57
-23
@@ -24,6 +24,7 @@ extends VBoxContainer
|
||||
const ServerStateScript := preload("res://addons/godot_ai/utils/mcp_server_state.gd")
|
||||
const ClientRefreshStateScript := preload("res://addons/godot_ai/utils/mcp_client_refresh_state.gd")
|
||||
const Client := preload("res://addons/godot_ai/clients/_base.gd")
|
||||
const PortResolver := preload("res://addons/godot_ai/utils/port_resolver.gd")
|
||||
const ClientConfigurator := preload("res://addons/godot_ai/client_configurator.gd")
|
||||
const ClientRegistry := preload("res://addons/godot_ai/clients/_registry.gd")
|
||||
const ToolCatalog := preload("res://addons/godot_ai/tool_catalog.gd")
|
||||
@@ -54,6 +55,7 @@ static var COLOR_AMBER := Color(1.0, 0.75, 0.25)
|
||||
|
||||
signal update_requested
|
||||
signal client_action_requested(client_id: String, action: String)
|
||||
signal client_action_cancel_requested(client_id: String)
|
||||
signal client_status_refresh_requested(client_ids: Array[String], force: bool)
|
||||
signal status_snapshot_requested
|
||||
signal live_server_probe_requested(port: int)
|
||||
@@ -457,7 +459,7 @@ func _build_ui() -> void:
|
||||
|
||||
_crash_docs_btn = Button.new()
|
||||
_crash_docs_btn.text = "How to change the port"
|
||||
_crash_docs_btn.tooltip_text = "Open the guide: change godot_ai/http_port and reconfigure your MCP clients"
|
||||
_crash_docs_btn.tooltip_text = "Open the guide: change ports in Godot AI settings and reconfigure your MCP clients"
|
||||
_crash_docs_btn.visible = false
|
||||
_crash_docs_btn.pressed.connect(func(): OS.shell_open(_port_conflict_docs_url()))
|
||||
_crash_panel.add_child(_crash_docs_btn)
|
||||
@@ -720,13 +722,13 @@ func _build_client_row(client_id: String) -> void:
|
||||
|
||||
var configure_btn := Button.new()
|
||||
configure_btn.text = "Configure"
|
||||
configure_btn.pressed.connect(_on_configure_client.bind(client_id))
|
||||
configure_btn.pressed.connect(_on_client_action_button_pressed.bind(client_id, "configure"))
|
||||
row.add_child(configure_btn)
|
||||
|
||||
var remove_btn := Button.new()
|
||||
remove_btn.text = "Remove"
|
||||
remove_btn.visible = false
|
||||
remove_btn.pressed.connect(_on_remove_client.bind(client_id))
|
||||
remove_btn.pressed.connect(_on_client_action_button_pressed.bind(client_id, "remove"))
|
||||
row.add_child(remove_btn)
|
||||
|
||||
# F-3-4: use the authoritative facade so Open/Reveal land on the same
|
||||
@@ -827,6 +829,13 @@ func _update_status() -> void:
|
||||
elif bool(server_status.get("handoff_retry_pending", false)):
|
||||
status_text = "Recovering after update…"
|
||||
status_color = COLOR_AMBER
|
||||
elif state == ServerStateScript.UNSUPPORTED_CONFIG:
|
||||
status_text = "Unsupported remote access configuration"
|
||||
status_color = Color.RED
|
||||
elif state == ServerStateScript.CRASHED and str(server_status.get("reason", "")) == "endpoint_lost":
|
||||
var recovery_pending := bool(server_status.get("recovery_pending", false))
|
||||
status_text = "Connection lost; reconnecting..." if recovery_pending else "Connection lost"
|
||||
status_color = COLOR_AMBER if recovery_pending else Color.RED
|
||||
elif state == ServerStateScript.CRASHED:
|
||||
var exit_ms: int = server_status.get("exit_ms", 0)
|
||||
status_text = "Server exited after %.1fs" % (exit_ms / 1000.0)
|
||||
@@ -843,7 +852,10 @@ func _update_status() -> void:
|
||||
var conflict_port: int = int(server_status.get("conflict_port", 0))
|
||||
if conflict_port <= 0:
|
||||
conflict_port = ClientConfigurator.http_port()
|
||||
status_text = "Port %d held by another process" % conflict_port
|
||||
status_text = (
|
||||
"Windows port discovery unavailable" if str(server_status.get("episode_reason", "")) == "port_occupancy_unknown"
|
||||
else "Port %d held by another process" % conflict_port
|
||||
)
|
||||
status_color = Color.RED
|
||||
elif state == ServerStateScript.NO_COMMAND:
|
||||
status_text = "No server command found"
|
||||
@@ -980,6 +992,8 @@ static func _crash_body_for_state(state: int, server_status: Dictionary = {}) ->
|
||||
## problem; don't repeat it here. This copy answers "what do I do?".
|
||||
var port := ClientConfigurator.http_port()
|
||||
match state:
|
||||
ServerStateScript.UNSUPPORTED_CONFIG:
|
||||
return str(server_status.get("message", "Use an IPv4 allowlist or clear Allow remote hosts, then reload the plugin."))
|
||||
ServerStateScript.PORT_EXCLUDED:
|
||||
return "Windows (Hyper-V / WSL2 / Docker) reserved port %d. Pick a free port or try `net stop winnat; net start winnat` in an admin shell." % port
|
||||
ServerStateScript.INCOMPATIBLE:
|
||||
@@ -1056,8 +1070,11 @@ static func _crash_body_for_state(state: int, server_status: Dictionary = {}) ->
|
||||
## the client's attach command, so clients must be reconfigured afterwards.
|
||||
## The per-client reconfigure steps live behind the crash panel's docs link.
|
||||
static func _free_port_hint(port: int) -> String:
|
||||
var free_http := ClientConfigurator.suggest_free_port(port + 1)
|
||||
var free_ws := ClientConfigurator.suggest_free_port(ClientConfigurator.ws_port() + 1)
|
||||
var occupancy := PortResolver.windows_listener_snapshot() if OS.get_name() == "Windows" else {}
|
||||
var free_http := ClientConfigurator.suggest_free_port(port + 1, 2048, occupancy)
|
||||
var free_ws := ClientConfigurator.suggest_free_port(ClientConfigurator.ws_port() + 1, 2048, occupancy)
|
||||
if free_http == 0 or free_ws == 0:
|
||||
return "Automatic port selection is unavailable. Choose HTTP and WS ports manually below, or retry."
|
||||
return "Suggested ports: %d (HTTP) and %d (WS). Choose both ports below, click Apply + Reload, then Configure your AI clients to use the new pair." % [free_http, free_ws]
|
||||
|
||||
|
||||
@@ -1745,8 +1762,13 @@ func _on_configure_client(client_id: String) -> void:
|
||||
_dispatch_client_action(client_id, "configure")
|
||||
|
||||
|
||||
func _on_remove_client(client_id: String) -> void:
|
||||
_dispatch_client_action(client_id, "remove")
|
||||
func _on_client_action_button_pressed(client_id: String, action: String) -> void:
|
||||
if _is_self_update_in_progress():
|
||||
return
|
||||
if _client_work_snapshot.get("action_phases", {}).get(client_id, "") == "queued":
|
||||
client_action_cancel_requested.emit(client_id)
|
||||
return
|
||||
_dispatch_client_action(client_id, action)
|
||||
|
||||
|
||||
## Emit a value intent; plugin.gd routes it to the plugin-lifetime job owner.
|
||||
@@ -1771,6 +1793,12 @@ func present_client_action_result(
|
||||
) -> void:
|
||||
_report_prewarm_outcome(client_id, prewarm)
|
||||
_finalize_action_buttons(client_id)
|
||||
if result.get("status") == "cancelled":
|
||||
var row: Dictionary = _client_rows.get(client_id, {})
|
||||
if not row.is_empty():
|
||||
_apply_row_status(client_id, row.get("status", Client.Status.NOT_CONFIGURED))
|
||||
_refresh_clients_summary()
|
||||
return
|
||||
var success_status := Client.Status.NOT_CONFIGURED if action == "remove" else Client.Status.CONFIGURED
|
||||
if result.get("status") == "ok":
|
||||
## #877: Remove targets only the selected scope, so a configure is the
|
||||
@@ -1805,7 +1833,11 @@ func present_client_work_snapshot(snapshot: Dictionary) -> void:
|
||||
var id := String(client_id)
|
||||
if busy.has(id):
|
||||
_set_row_action_in_flight(id, String(names.get(id, "configure")))
|
||||
if String(phases.get(id, "")) == "prewarm":
|
||||
if String(phases.get(id, "")) == "queued":
|
||||
var button := "remove_btn" if String(names.get(id, "configure")) == "remove" else "configure_btn"
|
||||
(_client_rows[id][button] as Button).text = "Cancel queued"
|
||||
(_client_rows[id][button] as Button).disabled = false
|
||||
elif String(phases.get(id, "")) == "prewarm":
|
||||
(_client_rows[id]["configure_btn"] as Button).text = "Installing…"
|
||||
else:
|
||||
_finalize_action_buttons(id)
|
||||
@@ -2335,9 +2367,19 @@ func _build_settings_tab(tabs: TabContainer) -> void:
|
||||
## `_reset_tools_pending_from_setting` / `_on_open_clients_window`).
|
||||
var settings_tab := VBoxContainer.new()
|
||||
settings_tab.add_theme_constant_override("separation", 8)
|
||||
settings_tab.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
## The section stack below (Vision Routing + Remote access) can outgrow
|
||||
## the window's minimum height, especially at larger editor scales —
|
||||
## scroll instead of growing the window, same idiom as the Clients and
|
||||
## Tools tabs (#1090).
|
||||
var settings_scroll := ScrollContainer.new()
|
||||
settings_scroll.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
settings_scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
settings_scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
||||
settings_scroll.add_child(settings_tab)
|
||||
var settings_margin := _build_margin_container()
|
||||
settings_margin.name = "Settings"
|
||||
settings_margin.add_child(settings_tab)
|
||||
settings_margin.add_child(settings_scroll)
|
||||
tabs.add_child(settings_margin)
|
||||
|
||||
## Vision Routing is configuration, not status — it lives here rather
|
||||
@@ -2448,25 +2490,17 @@ func _on_allow_hosts_text_changed(_new_text: String) -> void:
|
||||
func _refresh_allow_hosts_ui_state() -> void:
|
||||
if _allow_hosts_edit == null or _allow_hosts_apply_btn == null:
|
||||
return
|
||||
var invalid := McpAllowHosts.invalid_tokens(_allow_hosts_edit.text)
|
||||
if invalid.is_empty():
|
||||
_allow_hosts_hint.visible = false
|
||||
else:
|
||||
## Name the accepted syntax in the hint — matches the server's
|
||||
## `parse_allow_hosts` (CIDR / bare IP, comma-separated).
|
||||
_allow_hosts_hint.text = (
|
||||
"Invalid entries (must be a CIDR like 192.168.1.0/24 or a bare IP, comma-separated): %s"
|
||||
% ", ".join(invalid)
|
||||
)
|
||||
_allow_hosts_hint.visible = true
|
||||
_allow_hosts_apply_btn.disabled = not _allow_hosts_is_dirty() or not invalid.is_empty()
|
||||
var error := McpAllowHosts.configuration_error(_allow_hosts_edit.text)
|
||||
_allow_hosts_hint.text = error
|
||||
_allow_hosts_hint.visible = not error.is_empty()
|
||||
_allow_hosts_apply_btn.disabled = not _allow_hosts_is_dirty() or not error.is_empty()
|
||||
|
||||
|
||||
func _on_allow_hosts_apply() -> void:
|
||||
if _allow_hosts_edit == null:
|
||||
return
|
||||
var normalized := McpAllowHosts.normalize(_allow_hosts_edit.text)
|
||||
if not McpAllowHosts.invalid_tokens(normalized).is_empty():
|
||||
if not McpAllowHosts.configuration_error(normalized).is_empty():
|
||||
return
|
||||
_allow_hosts_saved = normalized
|
||||
_allow_hosts_edit.text = normalized
|
||||
|
||||
Reference in New Issue
Block a user