Godot_AI 发布原生 ai_assistant 模块,在 Godot 编辑器内接入 AI 助手
spardanviro/Godot_AI
spardanviro/Godot_AI 发布原生 C++ 模块 ai_assistant,在 Godot 4.7+ 编辑器右侧停靠面板中提供 AI 助手,支持 Anthropic、OpenAI 兼容接口、Gemini、DeepSeek 和 GLM 五家 provider。
AI assistant support inside the Godot editor as a native ai_assistant module, compatible with Godot 4.7+ (godot-master).
This project adds a docked AI panel to the editor, supports multiple LLM providers, and can execute AI-generated editor actions through EditorScript workflows. It is built for scene editing, script generation, project setup, file-aware prompting, asset generation, and debugging assistance directly inside Godot.
Overview
ai_assistant is a native C++ Godot module. It is not a GDExtension and not a regular addon distributed as project files. It is intended to live under the Godot engine source tree and be compiled into the editor build.
Once enabled, the module registers:
AIAssistantPluginas an editor pluginAIAssistantPanelas the main dock UI- Provider integrations for Anthropic, OpenAI-compatible APIs, Gemini, DeepSeek, and GLM
- Helper systems for response parsing, script execution, context collection, permissions, checkpoints, error monitoring, web search, asset generation, and mention-aware input
- On-demand API doc and gotchas injection (zero static overhead for unrelated topics)
The panel is mounted in the right dock area of the editor.
Implemented Features
Editor assistant panel
- Docked AI panel inside the Godot editor
- Chat-style interaction UI with persistent conversation history
New,History,Settings, file attachment, mention, send, and stop controls- Streamed responses with a
Stopbutton for partial cancellation - Replies rendered as Markdown, also while they stream in: headings, bold / italic / strikethrough, inline code, fenced code blocks, nested and numbered lists, task lists, quotes, rules, tables, and web links that open in the browser
- Auto-resizing multiline input field
- High-frequency preset actions:
Fix ErrorsPerformance
Assistant modes
ASK: conversational mode, no code executionAGENT: action-oriented mode with execution flowPLAN: planning-first mode before execution
Node and file mentions and editor-aware input
- Type
@in the input box to open autocomplete for scene nodes; once at least one character follows the@, matching project files are listed too - Drag scene nodes from the Scene dock, or files and folders from the FileSystem dock, into the input field to insert mention chips
- Use the
@toolbar button to mention the current scene selection - Right-click nodes in the Scene dock or entries in the FileSystem dock to mention them from the context menu
- Mention chips are rendered inline (files in green, nodes in blue) and expanded before the request is sent: nodes into structured node context, files into their contents (capped at 50,000 characters), folders into a listing of their entries
- Mention placeholders are atomic single-character tokens, so backspace removes them cleanly
File attachments
- Attach project files for the next request through an editor file picker
- Attached file contents are appended to the outgoing prompt as explicit context
- Supported attachment filters:
- Markdown / diagram:
*.md,*.mmd,*.mermaid - Text / data:
*.txt,*.json,*.yaml,*.yml,*.toml,*.csv - GDScript:
*.gd,*.gdscript
- Markdown / diagram:
Provider support
- Anthropic (Claude)
- OpenAI
- Gemini
- DeepSeek
- GLM (Zhipu AI)
The OpenAI provider path can also be pointed at compatible custom endpoints through the endpoint setting.
The model is a text field: any model name can be typed, which is what an OpenAI-compatible relay or aggregator (SiliconFlow, OpenRouter, a local server) needs; set its address as the API endpoint. The button beside the field lists the known models, and Test / Refresh replaces that list with the one the endpoint reports — cut down to current chat models for the provider's own API, whole for any other service. It keeps a separate API key per provider and swaps them automatically when you change providers.
OpenAI, DeepSeek and GLM speak the same chat-completions wire format and share one implementation (OpenAICompatibleProvider); each of them only declares what differs (endpoint, model tables, the name of the output-limit field).
On-demand API reference injection (AIAPIDocLoader)
The system prompt stays lean. Instead of statically including all Godot API documentation, AIAPIDocLoader detects Godot class names mentioned in the user's message (word-boundary matched) and injects compact API references for only those classes. Covers 50+ commonly-used classes including CharacterBody3D, NavigationAgent3D, AnimationPlayer, RigidBody3D, and more.
On-demand gotchas injection (AIGotchasIndex)
395 Godot-specific gotchas and pitfalls are stored in knowledge/gotchas.md, each with its keywords. At request time, only entries whose keywords match the user's message are injected, most relevant first, within a hard 3000-character budget. This replaces static sections that were injected on every request regardless of relevance.
Matching ignores generic keywords (ordinary English words, gdscript, node, int, ...) and weights the rest by rarity, so an entry needs at least one reasonably specific hit — typically a class or method name — to be injected. A message that names no specific API gets no gotchas. Class names are matched even when written directly against CJK text.
The always-on base prompt is about 11K characters (~3K tokens) for a model that works with tools, and about 33K characters for one that writes code blocks, which also has to be taught how an EditorScript builds a scene. system_prompt.md holds both: what is not for every model sits between <!-- SCRIPT-ONLY -->, <!-- TOOLS-ONLY --> and <!-- MARKERS-ONLY --> lines.
Domain-specific prompting (AIDomainPrompts)
Specialized system prompt fragments for domain-focused requests (UI/Control layout, physics, navigation, shaders, etc.) are injected on demand alongside the base system prompt.
Code generation and execution
- Parses AI replies and extracts executable GDScript blocks
- Wraps generated code as
EditorScript - Executes code in the editor context
- Supports compile-only validation before execution
- Checks generated code against a safety policy before execution
- Integrates permission checks for sensitive operations
- Skips code execution in
ASKmode - If a streamed response is manually stopped, partial code is preserved in history but not executed
Safety policy for editor-executed code (checked on the token stream, so comments and string contents are not mistaken for code):
OS,EngineandClassDBmay only be used asName.method(...)with a harmless method (OS.get_name(),Engine.is_editor_hint(),ClassDB.class_exists(), ...). They cannot be assigned, passed or indexed, so process-spawning methods cannot be reached through an alias,Engine.get_singleton()orClassDB.instantiate()Expression,JavaClassWrapper,JavaScriptBridge,GDExtensionManagerandEditorSettingsare rejected, as is any access to the assistant's own settings (permissions) and to the editor's data directories (where the credential store lives).OS.get_environment()is not on the allowed list either, so keys supplied through environment variables are out of reach- Network calls (
request,connect_to_host,listen, ...) are rejected. Creating networking nodes for the game is fine; using the network from the editor is not ProjectSettings.globalize_path()is only accepted in the formDirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path("res://folder")); the other ways of obtaining a real filesystem path (OS.get_user_data_dir(), ...) are rejected- String literals may not name absolute paths, UNC or
file://locations, orres:///user://paths that climb out with.. - When code is rejected, the reason is sent back to the model so it can rewrite within the rules
This is static analysis, not a sandbox. It cannot see values assembled at run time: a path or method name built from pieces passes the check. Review generated code before running it on a machine or project you care about, and keep auto-execute off if you want to approve each run.
Tools
With a provider that speaks tool calls — all five do — the model works on the project by calling typed tools instead of writing code to be run. Turn it off with Settings > General > Tools; a model or endpoint that rejects tool calls is detected on its first request and used the old way from then on.
| Kind | Tools | |
|---|---|---|
| Look | get_scene_tree, get_node_properties, read_file, list_files, get_errors |
Change nothing and need no permission. With the web tools, the only ones offered in ASK and PLAN modes. |
| Web | web_search, fetch_url |
Look something up outside the project: public http(s) addresses only, at most 3 requests per message. What comes back is handed to the model marked as untrusted content. |
| Edit | create_node, instantiate_scene, set_node_properties, rename_node, move_node, delete_node, connect_signal, attach_script, write_file, save_scene |
Each falls under one permission category (Settings > Permissions): allowed, asked about, or refused, per tool call. |
| Host | run_scene, take_screenshot, run_editor_script, generate_image, generate_speech, remember |
Run the game for a few seconds and report its errors; show the viewport to the model; run arbitrary editor code; have an asset generated; write one line into godot_ai.md. The last three write files, so they follow the Write Files permission. |
- Undo. Every scene change a tool makes is one action of the editor's undo history, named after what it did: Ctrl+Z takes it back like a change made by hand. Before the first change for a message a checkpoint is taken, and the transcript gets a link that reverts everything that follows, files included.
- Values. Arguments are JSON; engine values are written as GDScript writes them (
"Vector2(100, 50)"), as a list of components ([100, 50]) or as a colour code. A resource is ares://path or is created in place:{"$resource": "RectangleShape2D", "size": "Vector2(32, 32)"}. - Files.
read_fileandwrite_filestay insideres://, skip hidden folders, and do not touchexport_presets.cfg(signing keys) or files the editor owns (.tscn,.import,project.godot). A script that does not parse is not written. run_editor_scriptis the fallback for what no tool does (project settings, input actions, animations). It goes through the same review as a code block — syntax, safety policy, permissions — but that review reads the code as text, and code can build at run time what the review looks for. So the user decides: the whole of the code is shown, in a scrolling view of the permission prompt, and runs only once they have allowed it, every time, whatever the auto-execute setting says. The same holds for a code block written by a model that has the tools. Its outcome is the tool's result: what the codeprint()ed, or the error it raised.- A text answer is an answer. A model that has the tools and replies to the user in text (a refusal, a question back) is not pushed to "output the code block" the way a model without tools is. Only a step it was sent to carry out — a plan step, a runtime fix — is asked for once more, and then with the tools.
- Errors are results. A tool never fails the run: what went wrong is handed back as text for the model to act on. A message may take at most 8 rounds of tool calls.
A model or endpoint without tool calls still works the old way: it writes a gdscript code block, which is reviewed and executed under the permission and auto-execute settings, and asks for the web, assets and notes with text markers ([WEB_SEARCH: ...], [FETCH_URL: ...], [GENERATE_IMAGE: ...], [GENERATE_AUDIO: ...], [WRITE_MEMORY: ...]). The markers are neither taught to nor read from a model that has the tools.
Permission system
Execution permissions are categorized and configurable per operation type:
- Create nodes
- Delete nodes
- Modify properties
- Modify scripts
- Change project settings
- Write files
- Delete files
Each category supports Allow, Ask, or Deny. File deletion defaults to deny, and modifying scripts defaults to ask: a script is code that runs later, and what is inside a script file is not seen by the safety check. Writing a .gd file counts as modifying scripts, as attaching one does.
Generated code cannot reach the assistant's own controls: its classes, the editor's interface tree (get_tree().root, EditorInterface.get_base_control(), Engine.get_main_loop()) and the switches on the controller are rejected by the safety check, and the two controller methods that exist for the headless eval runner (set_auto_approve, configure_provider) do nothing unless the editor was started by evals/run_evals.py.
A reply is only executed if it is complete and is the model's answer. Code is shown but not run when the reply was cut off at the output limit, was withheld by the provider's filter, consists only of reasoning, or was written in PLAN mode. When code fails half-way, the scene and files are put back to the checkpoint taken before it ran, and only then is the model asked to try again.
The table is consulted for every piece of generated code, whatever its risk tier: Deny blocks it and Ask always shows a confirmation dialog, including when auto-execute is on. With auto-execute off, every execution is confirmed first.
Categories are detected by matching API names in the generated code. This catches ordinary model output; it is not a sandbox, and code written to evade the matching can get past it.
Context collection
The assistant can build editor-aware context from:
- current scene tree
- selected nodes
- project structure
- currently open script
- inline scene-node mentions
- attached file contents
Context compression
Long conversations are summarized automatically when token usage grows too large for the current model context window. The implementation keeps recent exchanges intact and compresses older history into a rolling summary. Only the working copy sent to the model is compressed; the full history is kept for display and for saved chats.
Three settings control it (Settings dialog, Context Compression section):
- Keep recent messages (2–20, default 6): how many of the latest messages are never compressed
- Compress at (30–95%, default 70%): how full the history window may get before compression runs. The window is the model's context length minus the max output tokens and the system prompt
- AI summary (default off): ask the model for a summary of the compressed messages in a background request. This costs tokens; when it is off, or the request fails, a local heuristic summary is used instead
Token counts are estimated locally: one token per CJK character, one per four other characters.
If the provider still rejects a request as too long, the oldest messages are dropped and the request is retried once.
Error monitoring and self-recovery
- Captures editor/runtime errors during AI-triggered execution windows
- Separates AI-caused execution errors from unrelated console noise
- Feeds failures back into the assistant for automatic retry
- Supports up to 3 auto-retry attempts
- Watches the running game: when a played scene stops with runtime errors, the assistant is asked for a fix and the scene is restarted, up to 5 attempts. Can be switched off (Settings > General); with auto-execute off, each fix waits for approval. The error text is passed to the model as untrusted data
Checkpoints and revert flow
- Creates scene checkpoints before risky modifications
- Stores up to 10 recent checkpoints, each written to disk when taken so built-in sub-resources (materials, shapes) are restored too
- Also snapshots the project's text files (scripts, scenes, resources, config; up to 512 KB each) before each run. Reverting restores files the code changed or deleted and moves files created since to the system trash. Large and binary files are not covered
- Reverting returns the project to that point in time, so it also undoes edits you made to those files after the checkpoint
- Allows reverting through the panel UI
Chat history
- Saves chat sessions as JSON files under
user://ai_assistant_chats - Supports listing, loading, and deleting saved chats
Asset generation
With the generate_image and generate_speech tools (or the corresponding text markers, for a model without tools):
- Image generation via OpenAI image API
- Audio generation via OpenAI TTS API
Generation needs an OpenAI API key whatever provider is active, runs beside the conversation, and saves into the path the model named: a new image or audio file inside res://. The tool tells the model that the file is not there yet.
Web search and page fetch
- DuckDuckGo HTML search integration
- Direct URL fetch support, limited to public http(s) addresses and to 3 web requests per user message. The host is checked by name and by every address it resolves to, and the connection is then made to one of exactly those addresses (the name is not resolved a second time, so the answer cannot change between the check and the connection; the TLS certificate is still verified against the name). Redirects are followed one hop at a time through the same checks, so a public page cannot bounce the editor to a local or private address. When a proxy is in use (see Network proxy) the proxy resolves the name, so only the checks on the URL itself remain for fetches that go through it.
- HTML-to-text extraction for prompt augmentation
Localization
UI strings are localized for English and Chinese.
Architecture
The agent loop, the conversation, the network client and the UI are separate pieces. The dock only shows what the controller reports and forwards what the user does, so the same controller also runs headless (see Evals).
AIAssistantPanel (dock: widgets, dialogs)
|- AIChatView transcript, streaming display, links
|- AIMentionAutocomplete "@" completion popup
|- AIRuntimeWatch watches the running game, asks for fixes
`- AIAgentController the agent loop as a state machine
|- AISession history, compression, attachments
|- AIStreamClient one streaming request on a worker thread
|- AICodeRunner review (syntax, safety, permissions) + execution
|- AIPromptBuilder system prompt = knowledge + editor state
|- AIPlan PLAN-mode steps and their checklist file
|- AIWebRequester search / fetch asked for by a reply
|- AIHistorySummarizer optional model-written history summary
`- AIAssetService image / speech generation queue
AIAgentController is always in exactly one state, and everything in flight belongs to one Run:
IDLE --submit / plan step / runtime fix--> STREAMING
STREAMING --reply has code--> (AWAITING_PERMISSION --ok-->) execute --> VERIFYING
STREAMING --reply needs a fix / execution failed--> STREAMING (at most 3 automatic retries)
VERIFYING --late errors--> STREAMING VERIFYING --clean--> settle
settle --web marker--> WEB_REQUEST --result--> STREAMING
STREAMING --reply calls tools--> run them (AWAITING_PERMISSION / WEB_REQUEST as needed) --results--> STREAMING
settle --next plan step--> STREAMING settle --otherwise--> IDLE
any state --stop / error / denied--> IDLE
Whether a request may start, whether code may run and what Stop means all follow from the state. The run's bookkeeping (retry count, pending code, markers) is one struct that is reset as a whole when the run ends, so nothing can leak into the next one.
| File | Role |
|---|---|
ui/ai_assistant_plugin.* |
Editor plugin entry point |
ui/ai_assistant_panel.* |
The dock: layout, user actions, dialogs |
ui/ai_details_dialog.*, ui/ai_history_list.* |
The window behind a "Details" / "Thinking" link; the list of saved chats |
ui/ai_chat_view.* |
Chat transcript, streaming display, clickable links |
ui/ai_markdown.* |
Markdown to RichTextLabel BBCode, whole or as a stream; escapes everything the model wrote |
ui/ai_mention_autocomplete.* |
@ completion popup for scene nodes and project files |
ui/ai_mention_text_edit.*, ui/ai_mention_highlighter.* |
Mention-capable input field with inline chips |
ui/ai_settings_dialog.*, ui/ai_settings_dialog_model.cpp, ui/ai_settings_dialog_layout.cpp |
Settings window (tabs: model, general, permissions, advanced): showing and saving the settings; widgets and captions |
providers/ai_provider_settings.* |
The provider part of the settings while it is edited, without widgets: endpoint per provider, typed and removed keys, the output cap to suggest |
common/ai_settings.* |
The one place that reads and writes the ai_assistant/* settings; tests give it other values |
ui/ai_model_selector.*, network/ai_model_list_fetcher.* |
Model name field with a pick list; live model list from the provider's API |
providers/ai_provider_catalog.h, providers/ai_provider_catalog.cpp |
Display names and known models per provider |
agent/ai_agent_controller.*, agent/ai_agent_controller_replies.cpp |
Agent loop as an explicit state machine; signals instead of UI calls |
agent/ai_agent_controller_tools.cpp |
The tool round: permissions, checkpoint, tools that wait (running the game) or need the user |
tools/ai_toolbox.*, tools/ai_tool_specs.cpp, tools/ai_edit_tools.cpp |
The tools: what the model is told about them, the ones that look, the ones that edit (as undoable editor actions) |
tools/ai_tool_values.* |
Tool arguments (JSON) to engine values and resources |
common/ai_tool_types.h |
Tool specification, tool call, and the assembly of a call from stream fragments |
agent/ai_session.* |
Conversation history, context compression, overflow recovery, attachment de-duplication |
agent/ai_chat_store.* |
Saved chats (user://ai_assistant_chats) |
network/ai_stream_client.*, network/ai_stream_protocol.* |
Streaming HTTP client; SSE decoding, UTF-8 boundaries, <think> tag splitting |
execution/ai_code_runner.* |
Review gate and execution with checkpoints and error monitoring |
execution/ai_script_executor.* |
Compiles and runs generated GDScript as an EditorScript |
execution/ai_safety_policy.* |
What generated code may not contain, checked on its text and its tokens |
execution/ai_script_wrapper.*, execution/ai_code_fixes.* |
The EditorScript wrapper; repairs for mistakes models keep making |
execution/ai_permission_manager.* |
Rule-based execution gating |
execution/ai_checkpoint_manager.* |
Checkpoint and restore support |
execution/ai_error_monitor.* |
Tracks editor/runtime errors around AI execution |
agent/ai_runtime_watch.* |
Detects runtime errors of the running game and requests fixes |
agent/ai_response_parser.*, agent/ai_response_analysis.* |
Code blocks; side-effect markers and the checks on what they carry |
network/ai_url_policy.* |
Which addresses a model-supplied URL may point at |
assets/ai_asset_request.* |
A generation request and the check on its save path |
common/ai_code_text.*, common/ai_notice.h |
Summaries and script paths read out of code and error text; notice levels |
agent/ai_plan.* |
PLAN-mode steps and their Markdown checklist |
network/ai_web_requester.*, network/ai_web_fetch.*, network/ai_web_search.* |
Web search and page fetch; the fetch runs on a worker thread and connects only to addresses it has checked |
assets/ai_asset_service.*, assets/ai_image_generator.*, assets/ai_audio_generator.* |
Image and speech generation |
network/ai_proxy.*, network/ai_proxy_os.cpp |
Which HTTP proxy the assistant's requests use (system, none, custom) |
network/ai_network_thread.h |
Marks the network worker threads, so their engine errors are not taken for project errors |
agent/ai_history_summarizer.* |
Optional model-written summary of compressed history |
agent/ai_project_memory.* |
Notes the model asks to remember in res://godot_ai.md |
prompt/ai_prompt_builder.*, prompt/ai_context_collector.*, prompt/ai_profiler_collector.* |
System prompt assembly and editor context |
prompt/ai_knowledge.* |
Loads the knowledge files (built-in defaults + override directory) |
prompt/ai_system_prompt.*, prompt/ai_gotchas_index.*, prompt/ai_domain_prompts.*, prompt/ai_api_doc_loader.* |
Select from the knowledge base what a message needs |
providers/ai_provider.*, providers/ai_provider_setup.*, providers/ |
Provider interface, configuration, implementations |
providers/ai_credential_store.* |
API key storage outside the settings file |
common/ai_localization.h |
UI string localization table |
knowledge/ |
Prompts, gotchas, API notes and domain guidance as Markdown |
tests/ |
Unit tests |
evals/ |
Task set and headless runner for scoring prompt and agent changes |
Provider implementations in providers/:
| File | Provider |
|---|---|
openai_compatible_provider.* |
Shared OpenAI chat-completions implementation |
openai_provider.* |
OpenAI and OpenAI-compatible endpoints |
deepseek_provider.* |
DeepSeek |
glm_provider.* |
Zhipu AI GLM |
anthropic_provider.* |
Anthropic Claude |
gemini_provider.* |
Google Gemini |
Knowledge files
Everything the assistant is told that is not code lives in knowledge/ as plain Markdown:
| Path | Content |
|---|---|
system_prompt.md |
The base system prompt. {{project_instructions}} marks where the project's godot_ai.md goes |
prompts/<id>.md |
Short templates with {{name}} placeholders: mode instructions, the retry messages, plan step, runtime fix, web results, summary, preset buttons |
domains/<id>.md |
Guidance for one domain. Front matter lists the keywords that select it (match: stem or match: word) and its order in the prompt |
gotchas.md |
One entry per <!-- keywords: a, b --> line; the text that follows is injected when a message mentions those keywords |
api_docs.md |
One ## ClassName section per class, injected when the class is named |
glossary.md |
Terms a message may use, in any language, and the engine names they stand for (跳跃 => CharacterBody2D, move_and_slide). Lets a message that names no class still select gotchas and API notes |
These files are embedded into the editor binary at build time as the defaults. To change them without rebuilding, point the assistant at a directory with the same layout:
- the editor setting
ai_assistant/knowledge_dir, or - the environment variable
GODOT_AI_KNOWLEDGE_DIR, or - the folder
ai_assistant/knowledgein the editor's config directory (used automatically if it exists).
A file there replaces the built-in file with the same relative path; additional files under domains/ and gotchas/ are added. The directory is checked before every request, so an edit takes effect with the next message. A file that does not parse is reported in the editor output and skipped; the built-in content stays in place.
While developing prompts, set ai_assistant/knowledge_dir to this repository's knowledge/ folder and edit the files in place. Use the eval set to see whether a change helped.
API keys
Keys are not stored in the editor settings file (editor_settings-*.tres is plain text and tends to get copied, synced and attached to bug reports). For each provider the key is looked up in this order:
- The environment variable
GODOT_AI_API_KEY_<PROVIDER>(for exampleGODOT_AI_API_KEY_DEEPSEEK), then the vendor's usual variable:ANTHROPIC_API_KEY,OPENAI_API_KEY,GEMINI_API_KEY,DEEPSEEK_API_KEY,ZHIPUAI_API_KEY. - The credential store,
ai_assistant/credentials.jsonin the editor's config directory. Keys typed into the settings dialog go here.
On Windows each stored key is sealed with DPAPI, so it can only be read by the same Windows user on the same machine. On other platforms it is AES-encrypted with a key derived from the machine id: that keeps the key out of sight and makes a copied file useless elsewhere, but it is obfuscation rather than a keychain — prefer environment variables there.
Keys found in the settings file by an older version are moved into the store the first time the panel loads, and the settings entries are blanked. The settings dialog never shows a stored key: the field is empty and only takes a new key to replace the stored one.
Layers
The folders form a stack, lowest first:
common < providers < network < execution < prompt < assets < tools < agent < ui
A folder includes headers from its own folder and from the ones before it, never from one after it. The editor's settings are reached through common/ai_settings.cpp only (the ui folder also registers them with the editor). evals/check_layers.py checks both rules and names every #include that breaks one:
python evals/check_layers.py
Tests
Unit tests cover the logic that does not need a running editor: the response parser, side-effect markers, URL and path policy, the safety policy and risk tiers, gotcha / domain / API-doc selection, the knowledge file formats and overrides, Markdown rendering, the settings and the provider settings model, the tools (on a scene built in the test) and each provider's tool-call format, history compression and overflow recovery, SSE decoding, the providers' request and response handling, and the credential store.
scons platform=windows target=editor tests=yes
bin/godot.windows.editor.x86_64.console.exe --test --test-case="*AIAssistant*"Adding extra_suffix=tests to the build keeps the test build's objects and binary apart from your normal editor build, so switching between the two does not trigger full rebuilds.
Evals
Whether the assistant is any good is decided by what the model produces, and that changes with every edit to a prompt or to the retry logic. evals/ holds 30 standard tasks (scene building, scripts, UI, 3D, gameplay, ASK / PLAN modes, safety) and a runner that scores them without a human in the loop. See evals/README.md.
# The harness and the agent loop themselves, against canned replies (no API key, ~1 minute): python evals/run_evals.py --godot bin/godot.windows.editor.x86_64.console.exe --mock # A real model; compare a prompt change against an earlier run: python evals/run_evals.py --godot <editor> --provider deepseek --out before.json python evals/run_evals.py --godot <editor> --provider deepseek --knowledge-dir knowledge --baseline before.json
Build and Installation
1. Place the module in the Godot source tree
godot/modules/ai_assistant/
This repository is the module directory. Clone or copy it directly under modules/.
2. Build the editor
scons platform=windows target=editor
Adjust platform, arch, and other SCons flags for your environment. The module is guarded by TOOLS_ENABLED and only compiled into editor builds.
3. Launch the custom editor build
After compiling, open Godot using the built editor executable. The AI panel appears in the right dock.
Network proxy
Everything the assistant sends — chat requests, the model list, summaries, image and speech generation, web search and page fetch — goes through one proxy choice (Settings > Advanced):
- Follow the system (default): the editor's own
network/http_proxysetting if set, elseHTTPS_PROXY/HTTP_PROXY, else on Windows the proxy configured for the user account. Proxy auto-configuration scripts are not evaluated. - None: connect directly.
- Custom:
host:port.
Only HTTP proxies are supported (no SOCKS, no proxy credentials). Local addresses — localhost, loopback and private-network literals — are always reached directly, so a local model server keeps working.
A page fetch through a proxy cannot check which address a name resolves to, because the proxy does the resolving; the checks on the URL (scheme, local names, address literals, every redirect hop) still apply. Set the proxy to None if that matters more to you than reaching sites the proxy is needed for.
Configuration
Settings are stored in EditorSettings under the ai_assistant/* namespace. API keys are not among them; see API keys.
| Key | Description |
|---|---|
ai_assistant/provider |
Active provider (anthropic, openai, gemini, deepseek, glm) |
ai_assistant/model |
Model name |
ai_assistant/api_endpoint |
Custom endpoint override |
ai_assistant/max_tokens |
Max response tokens (default: 4096) |
ai_assistant/custom_temperature |
Send the temperature below instead of leaving it to the model (default: off) |
ai_assistant/temperature |
Sampling temperature, used when the setting above is on (default: 0.7) |
ai_assistant/send_on_enter |
Send on Enter key (default: true) |
ai_assistant/autorun |
Auto-execute generated code (default: true) |
ai_assistant/restore_last_chat |
Reload the most recent chat on editor startup (default: true) |
ai_assistant/runtime_fix |
Fix script errors of the running game automatically (default: true) |
ai_assistant/compression_keep_recent |
Recent messages never compressed (default: 6) |
ai_assistant/compression_threshold_pct |
Fraction of the history window that triggers compression (default: 0.7) |
ai_assistant/compression_use_ai_summary |
Summarize compressed messages with the model (default: false) |
ai_assistant/language |
UI language (en or zh) |
ai_assistant/knowledge_dir |
Folder of knowledge files that override the built-in ones (default: empty) |
ai_assistant/proxy_mode |
system (default), off or custom |
ai_assistant/proxy_address |
host:port of the HTTP proxy for custom |
ai_assistant/image_model |
OpenAI image model (default: empty = gpt-image-1) |
ai_assistant/speech_model |
OpenAI speech model (default: empty = gpt-4o-mini-tts) |
ai_assistant/permissions/* |
Per-category execution permissions |
Project-local AI instructions
Create res://godot_ai.md in your project to define project-specific instructions. The assistant loads this file and appends it to the system prompt automatically.
Usage Flow
- Open the settings dialog from the AI panel.
- Choose a provider and enter the API key.
- Optionally override the endpoint and model.
- Choose whether Enter sends immediately and whether generated code auto-runs.
- Configure permission levels for sensitive operations.
- Start using the panel in
ASK,AGENT, orPLANmode. - Optionally enrich the next request by:
- attaching a file with the
+button - mentioning scene nodes or project files with
@ - dragging scene nodes, files, or folders into the input field
- attaching a file with the
Project Layout
ai_assistant/
|- ui/ dock, chat view, Markdown rendering, mentions, settings dialog
|- agent/ agent loop, session, saved chats, plan, reply parsing and analysis
|- execution/ code review and execution, safety policy, permissions, checkpoints, error monitoring
|- prompt/ system prompt assembly, editor context, knowledge loading and selection
|- network/ streaming client, web search and fetch, proxy, model list
|- providers/ provider interface, implementations, catalog, API key storage
|- assets/ image and speech generation
|- tools/ the tools a model calls: look, edit, and their argument conversion
|- common/ settings access, logging, localization, notice levels, code text helpers
|- knowledge/ prompts, gotchas, API notes, domain guidance (Markdown)
|- tests/ unit tests (doctest)
|- evals/ eval tasks, headless runner, driver script
|- ai_knowledge_builders.py embeds knowledge/ into the build
|- register_types.*
|- SCsub
`- config.py
Current Limitations
- Requires user-provided API keys for all LLM providers.
- Web search is implemented via HTML scraping; provider pages may require maintenance.
- Asset generation currently uses OpenAI-specific endpoints and needs an OpenAI API key in Settings, whichever provider is active. Generated assets can only be saved under
res://. - The dock itself (layout, dialogs) is not covered by automated tests; the agent loop behind it is, through the eval runner's mock mode.
- On platforms other than Windows the credential store is obfuscation, not OS-level protection.
- No automated CI or cross-platform packaging workflows yet.
License
Licensed under the Apache License 2.0. See LICENSE.
This applies to the code in this repository. Godot engine upstream is MIT-licensed.
来源:GitHub · github.com