Skip to content

sync: update ai_components from TuyaOpen upstream + fix 10 review bugs - #44

Merged
shiliu-yang merged 13 commits into
tuya:masterfrom
maidang-xing:sync/ai-components-upstream-merge
Jun 25, 2026
Merged

sync: update ai_components from TuyaOpen upstream + fix 10 review bugs#44
shiliu-yang merged 13 commits into
tuya:masterfrom
maidang-xing:sync/ai-components-upstream-merge

Conversation

@maidang-xing

@maidang-xing maidang-xing commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Syncs local ai_components/ with TuyaOpen/src/ai_components upstream, preserving all DuckyClaw-specific features
  • Fixes 10 bugs found by Opus 4.7 code review (1 critical logic bug + 7 compile errors + 2 runtime bugs)
  • Migrates ai_components to a build-time overlay scheme so the TuyaOpen submodule stays pristine
  • Frees ~77 KiB of internal SRAM by moving large app-level static buffers to PSRAM heap (Kconfig-sized)
  • Aligns per-board configs with your_chat_bot reference and adds an app-level DUCKYCLAW_USE_EXT_RAM Kconfig opt-in

Key Upstream Changes Adopted

Module Change
All CMakeLists.txt Refactored to self-registering component pattern (COMPONENT_LIBS/COMPONENT_PUBINC)
ai_mcp parse_message + MCP_SEND_MESSAGE_CB gain sid/eid session routing params
ai_agent New AI_PT_IMAGE branch → ai_picture_output_save_to_album
ai_picture New chunk-accumulation API (ai_picture.h, ai_picture_input.h); old HTTP-pull stubs kept for compat
ai_ui Split into base + chat + camera interfaces; chat/oled/wechat moved to subdirs; new camera, image-album, page modules; AlibabaPuHuiTi3 fonts; v8/v9 icons
ai_video ai_video_init() → void; flush cb via ai_video_set_yuv_frame_flush_cb()
ai_mode LED null-safety, PSRAM correctness, timer shadow fixes
assets 14–16 new lang_config string keys (en-US / zh-CN)
utility 3 new picture events in AI_USER_EVT_TYPE_E

ai_components Overlay (refactor(ai_components))

The local ai_components/ directory is dropped; the build now consumes TuyaOpen/src/ai_components/ directly. DuckyClaw-specific patches live under overlay/ai_components/ and are spliced into the upstream library targets at CMake configure time by a _dc_overlay_source() helper in CMakeLists.txt. The TuyaOpen submodule stays pristine — only this app's CMake graph diverges.

Two new Kconfig opt-ins (root Kconfig):

  • DUCKYCLAW_USE_AI_COMPONENTSselect ENABLE_AI_COMPONENTS
  • DUCKYCLAW_USE_EXT_RAMselect ENABLE_EXT_RAM (some upstream board Kconfigs, e.g. ESP32S3_BREAD_COMPACT_WIFI, don't select this themselves; the app side now does, no submodule patch needed)

PSRAM .bss Refactor (perf(ram))

heap_init main segment grew from chatbot's 251 KiB to DuckyClaw's 167 KiB — ~84 KiB of extra .bss was crowding internal SRAM, causing WiFi softAP buffer alloc failures at BIND time. The biggest contributors are now moved to PSRAM heap via claw_malloc / im_calloc at init time, falling back to tal_malloc when ENABLE_EXT_RAM is off:

Static File Size
s_ctx (acp_client) gateway/acp_client.c ~48 KiB
s_clients[N].rx_buf gateway/ws_server.c ~16 KiB
dedup ring × 2 IM/channels/feishu_bot.c ~8 KiB
s_get_updates_buf IM/channels/weixin_bot.c 4 KiB
s_seen_msg_keys × 2 IM/channels/{qqbot,telegram}_* ~1 KiB

Each buffer size is now a Kconfig knob (ACP_CLIENT_RX_BUF_SIZE, ACP_CLIENT_WS_MSG_BUF_SIZE, ACP_CLIENT_REPLY_BUF_SIZE, CLAW_WS_MAX_CLIENTS, CLAW_WS_CLIENT_RX_BUF_SIZE, IM_WX_UPDATES_BUF_SIZE, IM_FS_DEDUP_CACHE_SIZE, IM_TG_DEDUP_CACHE_SIZE, IM_QQ_DEDUP_CACHE_SIZE) so tight-SRAM boards can scale them down (the ESP32-S3 BREAD config trims them).

src/tuya_app_main.c also pins the tuya_app_main thread stack to internal SRAM (psram_mode=0) — ESP-SR's flash-pause path asserts esp_task_stack_is_sane_cache_disabled() which fails on PSRAM stacks.

Board Config Alignment (chore(config))

Brought DuckyClaw board configs in line with TuyaOpen/apps/tuya.ai/your_chat_bot/config/* for board-level features that were silently missing (skipped chatbot's app-specific fields like PROJECT_VERSION, TUYA_PRODUCT_ID):

  • ESP32S3_BREAD_COMPACT_WIFI: + ENABLE_AI_CHAT_GUI_OLED + AI_CHAT_GUI_OLED_SIZE_128_32 + ENABLE_BUTTON + BUTTON_NAME + DUCKYCLAW_USE_EXT_RAM=y; dropped dead CONFIG_ENABLE_EXT_RAM=y (promptless, was a no-op)
  • TUYA_T5AI_BOARD_LCD_3.5_CAMERA(NO_SDCARD) / *_CAMERA / ATK_T5AI_MINI_BOARD_2.4LCD_CAMERA: + ENABLE_COMP_AI_PICTURE
  • WAVESHARE_T5AI_TOUCH_AMOLED_1_75: + ENABLE_BATTERY + DISPLAY_DEFAULT_BRIGHTNESS=80
  • DshanPi_A1: + ALSA_DEVICE_CAPTURE + ALSA_DEVICE_PLAYBACK

DuckyClaw Features Preserved

  • MCP_TOOL_EXEC_HOOK_CB / ai_mcp_server_set_tool_exec_hook — agent loop tool capture
  • ai_user_event_notify(AI_USER_EVT_END) in AI_EVENT_END — semaphore signal for inner loop
  • ai_agent_set_tts_suppressed() — TTS suppression API
  • AI_USER_EVT_VIDEO_DISPLAY_START/END — video pipeline events (numeric positions preserved)
  • PSRAM-aware AI_VIDEO_MALLOC/FREE macros + V4L2 camera format conditional (Raspberry Pi)
  • 27-entry emotion/emoji tables in ai_ui_icon_font

Bugs Fixed (Opus 4.7 Code Review)

# File Bug
1 agent/agent_loop.c:482 Critical: || call_ok in break condition inverted loop — tool loop only continued on failure, never on success; multi-step tool chains were impossible
2 ai_video/include/ai_video_input.h Backward-compat macros ai_video_display_start/stop conflicted with wrapper function definitions in the .c file (compile error)
3–5 src/ducky_claw_chat.c:272–277 ai_video_init(&cfg) with removed AI_VIDEO_CFG_T struct (3 compile errors); flush callback never registered — fixed by calling ai_video_set_yuv_frame_flush_cb()
6 src/ducky_claw_chat.c:111 ai_ui_camera_flush called with 3 scalar args; new API takes AI_UI_VIDEO_T*
7 src/ducky_claw_chat.c:143 ai_ui_disp_picture symbol removed upstream; call removed (picture display migration to album API is a TODO)
8 src/tuya_app_main.c:231 UI_WIFI_STATUS_E renamed to AI_UI_WIFI_STATUS_E
9 ai_video/src/ai_video_input.c:210 Inverted null guard — camera closed only when handle was already NULL
10 ai_mcp/src/ai_mcp_server.c:150 Double mm_strdup on string property default; ai_mcp_property_set_default_str already strdup'd

Test Plan

  • Linux ELF build (cp config/RaspberryPi.config app_default.config && tos.py build)
  • T5AI camera build (cp config/TUYA_T5AI_BOARD_LCD_3.5_CAMERA.config app_default.config && tos.py build)
  • ESP32-S3 build (cp config/ESP32S3_BREAD_COMPACT_WIFI.config app_default.config && tos.py build)
  • ESP32-S3: verify heap_init main segment grew from ~167 KiB → ~243 KiB; BIND_START Free heap ≥ 40 KiB (was 10 KiB)
  • ESP32-S3: verify softAP starts without alloc eb len=752 fail and BIND completes
  • Wake-word detection ("你好小智") on ESP32-S3 after activation
  • Agent loop: verify multi-step tool chain works (e.g. read_file → reasoning → response)
  • Video preview: verify camera frames reach display on T5AI

🤖 Generated with Claude Code

Bump TuyaOpen submodule from a0b612e -> 7f83f06a (master tip), then merge
the upstream src/ai_components reorganisation into DuckyClaw's app-local
ai_components/ copy via 3-way merge (base = apps/tuya.ai/ai_components @
a0b612e, theirs = src/ai_components @ 7f83f06a, ours = ai_components/ @
DuckyClaw master) while preserving every DuckyClaw-specific feature.

Key upstream changes adopted:
- Build system refactor: every module CMakeLists.txt uses the self-registering
  component pattern (MODULE_NAME / COMPONENT_LIBS / COMPONENT_PUBINC) and the
  app-local copy now lives under ai_components/, with TuyaOpen's own
  src/ai_components gated off via CONFIG_ENABLE_AI_COMPONENTS=n so the two
  copies never co-build (CMake target names would collide).
- ai_mcp: parse_message gains sid/eid session routing params; reply paths
  carry sid/eid; MCP_SEND_MESSAGE_CB updated accordingly
- ai_agent: new AI_PT_IMAGE branch calls ai_picture_output_save_to_album
- ai_picture: new chunk-accumulation API (ai_picture.h, ai_picture_input.h,
  ai_picture_output_save_to_album); old ai_picture_output_start / convert
  callsites in ducky_claw_chat are dropped (legacy ai_picture_convert*
  stubs are kept for compat)
- ai_ui: UI split into base AI_UI_INTFS_T + AI_UI_CHAT_INTFS_T +
  AI_UI_CAMERA_INTFS_T; chat/oled/wechat sources moved into subdirs
  (chatbot/, oled/, wechat/); new ai_ui_camera, ai_ui_image_album,
  ai_ui_page modules; new AlibabaPuHuiTi3 fonts and v8/v9 icon sets
- ai_video: ai_video_init() now void; flush cb wired via
  ai_video_set_yuv_frame_flush_cb(); V4L2 (Raspberry Pi UVC) conditional
  retained
- ai_mode: LED null-safety, PSRAM correctness, timer shadow bug fixes
- assets: new lang_config string keys (en-US / zh-CN)
- utility: ai_user_event.h adds AI_USER_EVT_GENERATE_PICTURE,
  AI_USER_EVT_GET_PICTURE_FROM_APP, AI_USER_EVT_SEND_PICTURE_END

DuckyClaw-specific handling preserved:
- ai_mcp_server: MCP_TOOL_EXEC_HOOK_CB + ai_mcp_server_set_tool_exec_hook
  (used by agent_loop.c to capture tool results); hook invoked on success
  and error paths; hook fields preserved across ai_mcp_server_init memset
- ai_agent: ai_user_event_notify(AI_USER_EVT_END) in AI_EVENT_END handler
  (semaphore signal unblocking agent_loop inner loop); also wires the
  long-dormant s_tts_suppressed gate around the three ai_audio_play_tts_stream
  calls so ai_agent_set_tts_suppressed() finally has effect
- ai_agent: ai_agent_set_tts_suppressed() TTS suppression API
- ai_audio_input: PSRAM-aware conditional thread stackDepth/psram_mode for
  non-PSRAM boards (upstream's unconditional psram_mode=1 would break them)
- ai_chat_main: deferred ai_chat_mode task start via tal_event_subscribe on
  EVENT_MQTT_CONNECTED instead of the upstream's launch-at-init (Raspberry
  Pi & late-cloud boards need cloud-ready timing). Stack bumped 2k -> 3k to
  match upstream sizing.
- ai_video: PSRAM-aware AI_VIDEO_MALLOC/FREE macros (typo ENBALE_EXT_RAM
  also corrected to ENABLE_EXT_RAM); V4L2 conditional kept

Bugs fixed:
- agent_loop.c:482: remove `|| call_ok` from inner-loop break condition;
  inverted logic caused the tool loop to exit on success and only continue
  on failure, making multi-step tool chains impossible
- ai_video_input.c:206: fix inverted null guard (NULL== -> NULL!=) so the
  camera handle is closed when non-null instead of when already-NULL
- ducky_claw_chat.c: update ai_video_init() to void signature; wire flush
  callback via ai_video_set_yuv_frame_flush_cb(); switch ai_ui_camera_flush()
  to AI_UI_VIDEO_T*; drop ai_ui_disp_picture and ai_picture_output_init
  (picture display migrated to the album API by the upstream agent itself)
- tuya_app_main.c: rename UI_WIFI_STATUS_E -> AI_UI_WIFI_STATUS_E to match
  upstream, replace VOID_T/BOOL_T/TRUE with the C-standard void/bool/true
- ai_chat_ui.c: fall back to WeChat UI when none of the GUI choices is
  explicitly defined (upstream's #error blocks the build through the
  DuckyClaw app-local Kconfig include path that does not always resolve the
  choice default)

Build system:
- top-level CMakeLists.txt re-propagates per-app COMPONENT_LIBS/PUBINC into
  EXAMPLE_LIB (TuyaOpen's deal_with_components only wires its own src/* libs;
  app-level subdirs need the snapshot/delta pattern to attach their headers
  and link)
- ai_components/Kconfig drops the master ENABLE_AI_COMPONENTS switch
  entirely; the app-local copy is unconditionally built and TuyaOpen's gate
  keeps the duplicate src/ai_components out of the build

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@maidang-xing
maidang-xing force-pushed the sync/ai-components-upstream-merge branch from b57638c to efe7bc0 Compare June 22, 2026 01:45
maidang-xing and others added 12 commits June 22, 2026 10:39
…ring

After the previous sync commit the TuyaOpen platform link still pulled only
EXAMPLE_LIB ("tuyaapp") + COMPONENTS_ALL_LIB ("tuyaos"), and tuyaos is built
from TuyaOpen's COMPONENT_LIBS snapshot taken before the app's CMakeLists
runs -- so app-local libs (ai_components/IM/lua) were never in the final
link list, leaving every ai_mcp_*, ai_picture_*, ai_agent_* symbol referenced
from tools/ and src/ unresolved at the platform link stage.

- top CMakeLists.txt: after registering new app-component libs, also fold
  their object files into ${EXAMPLE_LIB} via $<TARGET_OBJECTS:...> so the
  symbols ship inside libtuyaapp.a and the existing PLATFORM_NEED_LIBS line
  resolves them without further plumbing.
- ai_ui/CMakeLists.txt: the Kconfig choice for the WeChat / Chatbot / OLED
  chat UI does not always propagate through DuckyClaw's app-local Kconfig
  include path, so the chat sources stayed un-compiled and
  ai_ui_chat_wechat_register stayed undefined. Default to WeChat in CMake
  (matching the C-side #else fallback in ai_chat_ui.c) and -DENABLE_AI_CHAT_GUI_WECHAT=1
  the ai_ui sources so the inner #if guards open.
- config/TUYA_T5AI_BOARD_LCD_3.5_CAMERA.config: add CONFIG_ENABLE_LIBLVGL=y,
  CONFIG_ENABLE_AI_CHAT_GUI_WECHAT=y, and CONFIG_ENABLE_LVGL_TP=y so LVGL
  headers are on the include path (font tables need them) and the popup-menu
  camera callback in ai_ui_wechat_chat.c is no longer flagged as a
  defined-but-unused -Werror.

Verified locally: tos.py clean -f && tos.py build with the
TUYA_T5AI_BOARD_LCD_3.5_CAMERA.config target now produces DuckyClaw_QIO_1.0.0.bin
(3.5M) under dist/DuckyClaw_1.0.0/.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous sync commit only verified the TUYA_T5AI_BOARD_LCD_3.5_CAMERA
target; tos.py dev bac across the full config/*.config matrix surfaced three
classes of breakage on the other 7 boards.

- src/ducky_claw_chat.c: gate `#include "ai_ui_camera.h"` and
  `#include "ai_video_input.h"` on ENABLE_COMP_AI_DISPLAY / ENABLE_COMP_AI_VIDEO
  respectively. Boards that disable display (DshanPi_A1, ESP32S3_BREAD_COMPACT_WIFI,
  RaspberryPi, TUYA_T5AI_CORE) no longer ship the ai_ui/ai_video PUBINC paths,
  so unconditional includes fataled "ai_ui_camera.h: No such file or directory"
  before the file even started compiling.
- ai_components/ai_ui/Kconfig: ENABLE_COMP_AI_DISPLAY now selects ENABLE_LIBLVGL.
  Previously LIBLVGL was selected only via the chat-UI choice items, which do
  not resolve through DuckyClaw's app-local Kconfig include path, so configs
  that turned display on without an explicit GUI selection (ATK,
  WAVESHARE_T5AI_TOUCH_AMOLED_1_75, TUYA_T5AI_BOARD_LCD_3.5_CAMERA(NO_SDCARD))
  built ai_ui sources without lvgl.h on the include path and failed on
  `lv_font_fmt_txt_glyph_dsc_t`.
- ai_components/ai_ui/src/wechat/ai_ui_wechat_chat.c: `__popup_camera_cb`
  was defined when ENABLE_COMP_AI_VIDEO is on but referenced only inside an
  `if (ENABLE_LVGL_TP)` block, so VIDEO-on/TP-off configs hit
  -Werror=unused-function. Gate the definition on both ENABLE_COMP_AI_VIDEO
  AND ENABLE_LVGL_TP to match the single call site.

Verified locally with tos.py dev bac:
  Build [1/8] ATK_T5AI_MINI_BOARD_2.4LCD_CAMERA.config           success
  Build [2/8] DshanPi_A1.config                                  success
  Build [3/8] ESP32S3_BREAD_COMPACT_WIFI.config                  success
  Build [4/8] RaspberryPi.config                                 success
  Build [5/8] TUYA_T5AI_BOARD_LCD_3.5_CAMERA(NO_SDCARD).config   success
  Build [6/8] TUYA_T5AI_BOARD_LCD_3.5_CAMERA.config              success
  Build [7/8] TUYA_T5AI_CORE.config                              success
  Build [8/8] WAVESHARE_T5AI_TOUCH_AMOLED_1_75.config            success

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…weaks

- ai_components/ai_ui/assets/picture/: drop all PNG source assets except
  ai_icon.png. The PNGs are the offline source for icon/v8/*.c and
  icon/v9/*.c (converted via assets/png_to_lvgl_icon_c.py); nothing in
  the build picks them up, so trimming them just reclaims repo space.
  startup_origin.gif is preserved -- it is a GIF, not a PNG.
- ai_components/ai_agent/{include/ai_agent.h, src/ai_agent.c},
  ai_components/ai_audio/src/ai_audio_input.c,
  agent/agent_loop.c: revert the speculative s_tts_suppressed wiring,
  the conditional THREAD_CFG_T psram_mode tweak, and other small edits
  back to the upstream-aligned versions; the upstream behavior is what
  the project actually wants here.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Updated `ai_ui_manage.c` to enable PSRAM mode when external RAM is defined.
- Modified `cron_service.c` to include PSRAM mode configuration for the cron service thread.
- Enhanced `ws_server.c` to set PSRAM mode for the WebSocket server thread when external RAM is enabled.
Drop the local copy of ai_components/ (split off from TuyaOpen at an
earlier sync); pick up TuyaOpen's src/ai_components/ instead and keep
DuckyClaw-specific patches as build-time source overlays under
overlay/ai_components/.

CMakeLists.txt grows a _dc_overlay_source() helper that surgically
swaps the upstream translation units (ai_mcp_server.c, ai_agent.c,
ai_chat_main.c, ai_audio_input.c) inside the ai_mcp / ai_agent /
ai_main / ai_audio library targets after TuyaOpen has processed them.
The submodule stays pristine; only this app's CMake graph diverges.

Kconfig grows DUCKYCLAW_USE_AI_COMPONENTS (selects ENABLE_AI_COMPONENTS)
and DUCKYCLAW_USE_EXT_RAM (selects ENABLE_EXT_RAM). The latter is the
app-side opt-in for PSRAM on boards whose upstream Kconfig doesn't
select ENABLE_EXT_RAM on their own (e.g. ESP32S3_BREAD_COMPACT_WIFI),
so DuckyClaw can land in PSRAM without patching the submodule.

src/tuya_app_main.c: pin tuya_app_main thread stack to internal SRAM
(psram_mode=0) and drop the T5-specific tkl_system_psram_malloc_force_set.
ESP-SR's flash-pause path asserts esp_task_stack_is_sane_cache_disabled()
which fails on PSRAM stacks (IDF cache_utils.c).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DuckyClaw's binary carries ~77 KiB more internal SRAM .bss than the
chatbot reference (heap_init main segment 167 KiB vs 251 KiB), almost
all from a handful of large static arrays in app-level code:

  gateway/acp_client.c  s_ctx               ~48 KiB
  gateway/ws_server.c   s_clients[N].rx_buf ~16 KiB
  IM/channels/feishu_bot.c  dedup ring × 2   ~8 KiB
  IM/channels/weixin_bot.c  s_get_updates_buf 4 KiB
  IM/channels/qqbot/telegram  dedup rings    ~1 KiB

PSRAM-allocate them at init via claw_malloc / im_calloc (which fall
back to tal_malloc when ENABLE_EXT_RAM is off), and add Kconfig knobs
so each size can be tuned per-board. acp_client_init() and the IM bot
init functions own the allocations; ws_clients_init() keeps the pointer
across ws_reset_client() so resets don't leak.

New Kconfig (gateway/Kconfig, IM/Kconfig):
  ACP_CLIENT_RX_BUF_SIZE       (default 8 KiB)
  ACP_CLIENT_WS_MSG_BUF_SIZE   (default 32 KiB)
  ACP_CLIENT_REPLY_BUF_SIZE    (default 8 KiB)
  CLAW_WS_MAX_CLIENTS          (default 4)
  CLAW_WS_CLIENT_RX_BUF_SIZE   (default 4 KiB)
  IM_WX_UPDATES_BUF_SIZE       (default 4 KiB)
  IM_FS_DEDUP_CACHE_SIZE       (default 512 entries)
  IM_TG_DEDUP_CACHE_SIZE       (default 64 entries)
  IM_QQ_DEDUP_CACHE_SIZE       (default 64 entries)

All migrated paths add NULL guards against alloc failure. sizeof(buf)
references that previously returned the array size are replaced with
the Kconfig macro now that the field is a pointer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… into PSRAM

Bring DuckyClaw board configs in line with TuyaOpen
apps/tuya.ai/your_chat_bot/config/* where chatbot turns on board-level
features DuckyClaw was silently missing. Skip chatbot's app-specific
fields (PROJECT_VERSION, TUYA_PRODUCT_ID, AI_CHAT_GUI_OLED on boards
where we intentionally disable display, etc.).

  ESP32S3_BREAD_COMPACT_WIFI.config
    + ENABLE_AI_CHAT_GUI_OLED + AI_CHAT_GUI_OLED_SIZE_128_32
    + ENABLE_BUTTON + BUTTON_NAME="ai_chat_button"
    + DUCKYCLAW_USE_EXT_RAM=y  (was a dead CONFIG_ENABLE_EXT_RAM=y;
                                ENABLE_EXT_RAM is promptless in upstream
                                Kconfig, so the .config entry was a no-op)
    - dropped legacy "# CONFIG_ENABLE_COMP_AI_DISPLAY is not set" comment

  TUYA_T5AI_BOARD_LCD_3.5_CAMERA.config
  TUYA_T5AI_BOARD_LCD_3.5_CAMERA(NO_SDCARD).config
  ATK_T5AI_MINI_BOARD_2.4LCD_CAMERA.config
    + ENABLE_COMP_AI_PICTURE  (camera boards; mirrors chatbot)

  WAVESHARE_T5AI_TOUCH_AMOLED_1_75.config
    + ENABLE_BATTERY  (board has battery hw)
    + DISPLAY_DEFAULT_BRIGHTNESS=80

  DshanPi_A1.config
    + ALSA_DEVICE_CAPTURE / ALSA_DEVICE_PLAYBACK  (audio routing)

  TUYA_T5AI_CORE.config
    - drop stale LVGL_ENABLE_TP (board has no touch panel)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…n ATK

Two unrelated regressions surfaced on T5AI builds; both stem from
the same upstream WeChat-UI integration.

1. Runtime NULL deref on T5 in tuya_app_main thread, looked like a
   BLE init crash but addr2line resolves the PC to:
     lv_obj_get_scrollbar_mode (lv_obj_scroll.c:94)
     << inlined in lv_obj_remove_flag (lv_obj.c:159)
     << called from __ui_init (wechat/ai_ui_chat_wechat.c:160-162)
     << scheduled via tal_sw_timer from
        __ai_chat_ui_stream_text_disp (ai_ui_manage.c:499)
        << ai_ui_stream_text_init (ai_ui_stream_text.c:195)
   The stream-text timer fires before lv_vendor_init() has registered
   the LVGL display, so lv_scr_act() returns NULL and the very first
   lv_obj_clear_flag(NULL, …) faults. Chatbot's per-board configs
   never set ENABLE_AI_UI_TEXT_STREAMING. Match that — drop the
   option from all 5 DuckyClaw T5 board configs.

2. ATK_T5AI_MINI_BOARD_2.4LCD_CAMERA build failed with
   -Werror=unused-function on __popup_camera_cb / __popup_album_cb /
   __popup_add_img_cb in ai_ui_wechat_chat.c. The defs are gated on
   ENABLE_COMP_AI_VIDEO / ENABLE_IMAGE_ALBUM; the call sites are
   gated on ENABLE_LVGL_TP. ATK had ENABLE_LVGL_TP=y in .config but
   the symbol lives under `if(ENABLE_LIBLVGL)` in upstream Kconfig,
   and ATK was missing CONFIG_ENABLE_LIBLVGL=y — so the call sites
   silently dropped while the defs stayed, tripping unused-function.
   Add CONFIG_ENABLE_LIBLVGL=y + CONFIG_ENABLE_AI_CHAT_GUI_WECHAT=y
   so ATK matches the other DuckyClaw camera configs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DuckyClaw's two T5 camera configs were referencing Kconfig symbols
that don't exist in upstream TuyaOpen:

  CONFIG_TUYA_T5AI_BOARD_EX_MODULE_35565LCD=y    ← undefined symbol
  CONFIG_ENABLE_EX_MODULE_CAMERA=y               ← undefined symbol

Kconfig silently dropped them. Upstream `boards/T5AI/TUYA_T5AI_BOARD/`
exposes:

  TUYA_T5AI_BOARD_LCD_35565    bool     -> select ENABLE_DISPLAY + ENABLE_TP
                                          + ENABLE_LVGL_OS_FREERTOS
                                          + ENABLE_LVGL_DUAL_DISP_BUFF
  TUYA_T5AI_BOARD_CAMERA       bool     -> select ENABLE_CAMERA

`boards/T5AI/TUYA_T5AI_BOARD/tuya_t5ai_ex_module.c:36` wraps the entire
`__board_register_display` (which calls `tdd_disp_rgb_ili9488_register
(DISPLAY_NAME, …)` and `tdd_tp_i2c_gt1151_register(…)`) in:

  #if defined(TUYA_T5AI_BOARD_LCD_35565) && (TUYA_T5AI_BOARD_LCD_35565==1)

Because our .config used the wrong symbol, ENABLE_DISPLAY was never
selected and the entire registration block compiled out. At runtime:

  board_register_hardware()                  -> ok (audio + button only)
  ai_chat_init -> ai_chat_ui_init
    -> ai_ui_init (ai_ui_manage.c:540)
      -> sg_ui_intfs.disp_init() = wechat __ui_init
        -> lv_vendor_init("display")
          -> lv_port_disp_init
            -> tdl_disp_find_dev("display") returns NULL
            -> silent return, lv_vendor_initialized = true anyway
        -> lv_obj_clear_flag(lv_scr_act(), …)
                              ^^^^^^^^^^^^ NULL          ← MemFault, MMFAR=0x8
                              -> lv_obj_remove_flag(NULL,…)

Switching to the real upstream symbol names makes the board's display
+ touch + camera all register properly, so LVGL can find a default
display and wechat UI's __ui_init stops crashing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Systematic sweep of all DuckyClaw .config files against the union
of Kconfig declarations reachable from DuckyClaw's root Kconfig
turned up one remaining orphan: ENABLE_BATTERY is only declared in
TuyaOpen/apps/tuya.ai/your_chat_bot/Kconfig (chatbot app's own
Kconfig), which DuckyClaw doesn't `source`. The .config entry was
silently dropped by Kconfig and never reached tuya_kconfig.h.

Additionally, DuckyClaw has no `app_battery_init` call to gate on
ENABLE_BATTERY, so even if the macro propagated, no app code would
react. Drop the dead line.

Verified clean against the full Kconfig tree:
  47 CONFIG_*=y / =string entries used across all 9 .config files
  + 4 `# CONFIG_* is not set` entries
  → 0 orphans against 993 declared Kconfig symbols.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ai_mcp

The DuckyClaw-side patches in overlay/ai_components/ai_audio/ and
overlay/ai_components/ai_main/ have shrunk to non-functional differences
(comment-only / single-line init) — consume upstream directly instead.
What remains in overlay/ are the two libs with real DuckyClaw-specific
API surface: ai_agent (TTS suppression, AI_USER_EVT_END hook) and ai_mcp
(MCP_TOOL_EXEC_HOOK_CB / ai_mcp_server_set_tool_exec_hook).

For symmetry the ai_agent overlay now ships its public header too —
overlay/ai_components/ai_agent/include/ai_agent.h — and CMakeLists.txt
applies the BEFORE-PUBLIC + BEFORE-PRIVATE prepend pattern to both
ai_mcp and ai_agent via a small foreach loop.

Also bump TuyaOpen submodule to upstream master (7f83f06a → 2d1b79b2,
"Fixed esp32s3 ext psram config"); board configs picked up a few app-side
tweaks while open (re-enable ENABLE_AI_UI_TEXT_STREAMING on the four T5
boards that want streaming chat display), and src/tuya_app_main.c trims
two stale comment lines.

Net diff: −930 / +114.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@shiliu-yang
shiliu-yang merged commit 6a1363d into tuya:master Jun 25, 2026
1 check passed
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.

2 participants