feat(config)!: one AGENTIC_KIT_ knob header, one SDK-wide log ceiling - #38
Merged
Merged
Conversation
heshaoqiong-tuya
marked this pull request as draft
September 16, 2026 06:27
heshaoqiong-tuya
force-pushed
the
feature/unified-config-header
branch
3 times, most recently
from
September 17, 2026 09:44
2990947 to
ee5bb6d
Compare
heshaoqiong-tuya
marked this pull request as ready for review
September 17, 2026 09:46
heshaoqiong-tuya
force-pushed
the
feature/unified-config-header
branch
6 times, most recently
from
September 20, 2026 05:54
5dc8cd7 to
41a7602
Compare
heshaoqiong-tuya
added a commit
that referenced
this pull request
Sep 20, 2026
…VEL) Master's log story was split three ways and all three parts were broken: `-DLOG_LEVEL` was a dead knob (no file referenced it), rtc-tcp-client alone had a compile gate (`TAI_LOG_LEVEL`), and every other module called `log_emit()` directly with no compile-time control at all. This stacks on the config rename (#38 branch) and replaces all of it with one two-layer model: - `common/log.h` gains the `log_tag_*` facade (error/warn/info/debug), each macro folded away entirely when `AGENTIC_KIT_LOG_LEVEL < n`, and the ceiling default lives next to the override pickup. Runtime filtering via `log_set_level()` still applies on top of the ceiling. - Every module re-tags its direct `log_emit()` calls onto the facade: common/tls.c, common/rng.c, common/core_mqtt_config.h, common/core_http_config.h, pal/pal_posix.c, pal/pal_freertos.c, the iot-client log family, tuya_ble_bigdata.c. coreMQTT/coreHTTP keep routing into the facade through their custom-config indirection. - rtc-tcp-client's private `TAI_LOG_LEVEL` gate and `TAI_LOG_` helpers are absorbed: tuya_internal.h now maps `TAI_LOGE/W/I/D` onto the facade, so existing `-DTAI_LOG_LEVEL=N` users must move to `-DAGENTIC_KIT_LOG_LEVEL=N` (BREAKING) -- which now also silences the rest of the SDK, not just this module. - Enforcement is layered where it costs: tai_pkt_log.c compiles its whole JSON formatter out below INFO, and packet-log emission dispatches over the gated macros by its two runtime levels (the last raw `log_emit()` call site). Output bytes are unchanged at default ceilings. - test_core.c gains test_compile_time_log_ceiling, which builds a TU at AGENTIC_KIT_LOG_LEVEL=0 and asserts zero log calls and zero argument-evaluation side effects; the `test` CI job now greps the tree for raw log_emit/printf call sites outside common/log.{h,c} and the test trees, so a new one fails the pipeline. - Docs: the compile-time-knobs guide gains the Logging section, the SDK-wide table row and the LOG_LEVEL / TAI_LOG_LEVEL migration rows in both locales; the rtc-tcp-client reference documents the two-layer model; AGENTS.md swaps the dead-knob gotcha for the ceiling story. Verified: ctest 16/16 (incl. the new ceiling test); the CI leak grep passes clean on this tree and flags an injected probe line (while fprintf/snprintf-style libc calls stay unflagged); ceiling probes on tai_pkt_log.c (cc -DAGENTIC_KIT_LOG_LEVEL=0/2 -> 0 log refs and 0 formatter strings, 3/4 -> exactly one of each); `git diff 63c038e` shows only the CHANGELOG restructure, so the tree is the previously-reviewed work plus this branch split; docs-site builds clean in both locales. Co-Authored-By: Claude Code <[email protected]> Co-Authored-By: Codex <[email protected]>
heshaoqiong-tuya
added a commit
that referenced
this pull request
Sep 20, 2026
…VEL) Master's log story was split three ways and all three parts were broken: `-DLOG_LEVEL` was a dead knob (no file referenced it), rtc-tcp-client alone had a compile gate (`TAI_LOG_LEVEL`), and every other module called `log_emit()` directly with no compile-time control at all. This stacks on the config rename (#38 branch) and replaces all of it with one two-layer model: - `common/log.h` gains the `log_tag_*` facade (error/warn/info/debug), each macro folded away entirely when `AGENTIC_KIT_LOG_LEVEL < n`, and the ceiling default lives next to the override pickup. Runtime filtering via `log_set_level()` still applies on top of the ceiling. - Every module re-tags its direct `log_emit()` calls onto the facade: common/tls.c, common/rng.c, common/core_mqtt_config.h, common/core_http_config.h, pal/pal_posix.c, pal/pal_freertos.c, the iot-client log family, tuya_ble_bigdata.c. coreMQTT/coreHTTP keep routing into the facade through their custom-config indirection. - rtc-tcp-client's private `TAI_LOG_LEVEL` gate and `TAI_LOG_` helpers are absorbed: tuya_internal.h now maps `TAI_LOGE/W/I/D` onto the facade, so existing `-DTAI_LOG_LEVEL=N` users must move to `-DAGENTIC_KIT_LOG_LEVEL=N` (BREAKING) -- which now also silences the rest of the SDK, not just this module. - Enforcement is layered where it costs: tai_pkt_log.c compiles its whole JSON formatter out below INFO, and packet-log emission dispatches over the gated macros by its two runtime levels (the last raw `log_emit()` call site). Output bytes are unchanged at default ceilings. - test_core.c gains test_compile_time_log_ceiling, which builds a TU at AGENTIC_KIT_LOG_LEVEL=0 and asserts zero log calls and zero argument-evaluation side effects; the `test` CI job now greps the tree for raw log_emit/printf call sites outside common/log.{h,c} and the test trees, so a new one fails the pipeline. - Docs: the compile-time-knobs guide gains the Logging section, the SDK-wide table row and the LOG_LEVEL / TAI_LOG_LEVEL migration rows in both locales; the rtc-tcp-client reference documents the two-layer model; AGENTS.md swaps the dead-knob gotcha for the ceiling story. Verified: ctest 16/16 (incl. the new ceiling test); the CI leak grep passes clean on this tree and flags an injected probe line (while fprintf/snprintf-style libc calls stay unflagged); ceiling probes on tai_pkt_log.c (cc -DAGENTIC_KIT_LOG_LEVEL=0/2 -> 0 log refs and 0 formatter strings, 3/4 -> exactly one of each); `git diff 63c038e` shows only the CHANGELOG restructure, so the tree is the previously-reviewed work plus this branch split; docs-site builds clean in both locales. Co-Authored-By: Claude Code <[email protected]> Co-Authored-By: Codex <[email protected]>
Every build-time knob now has its default and rationale in its owning
subsystem's config file -- no central entry file:
- common/log.h carries the integrator-override pickup
(__has_include("agentic_kit_config.h") / AGENTIC_KIT_USER_CONFIG). It is
the one header every SDK translation unit includes, so overrides run
before every #ifndef default, whichever file that default lives in;
each defaults file includes log.h first for exactly that reason. The
SDK owns no file named agentic_kit_config.h: a quoted include searches
the includer's own directory (common/) before the -I path, so the plain
name must stay the integrator's (lwIP lwipopts.h / mbedTLS
mbedtls_config.h / FreeRTOS FreeRTOSConfig.h pattern).
- pal/pal_config_defaults.h: the PAL_FR_TASK_* knobs, included directly
by pal_freertos.c.
- modules/iot-client/include/iot_client_config_defaults.h (MQTT +
ATOP-over-HTTP) and modules/rtc-tcp-client/include/tai_config_defaults.h
(TAI buffers & scheduling), beside each module's public headers.
tuya-ble ships no defaults file at all: it has zero knobs -- its
public-struct sizing constants and protocol geometry are port API, not
build knobs (why, in the tuya_ble_prov.h banner beside those
constants); the first real tuya-ble knob recreates
include/tuya_ble_config_defaults.h as AGENTIC_KIT_TUYA_BLE_*.
The iot-client layout mirrors tai's two-header split: the include/
defaults file holds only the AGENTIC_KIT_* #ifndef knob defaults
(log.h first), while the non-knob module data -- release-managed
version strings, the per-region ATOP/MQTT service endpoints,
get_default_pal(), the module's log_* binding and pal_strdup() --
lives in src/iot_internal.h (the former src/iot_config_defaults.h,
restored under its new name and merged with the former 28-line
iot_client_internal.h, so the module keeps one internal header).
Module sources and host tests include iot_internal.h, which pulls the
knob file in like tai_internal.h does. The version data and endpoints
ride releases or the Tuya cloud, not the override mechanism (called
out in the guide). tools/bump_version and the README/guide references
follow the path change; iot_dns.h and iot_on_boarding.h, which leaned
on the old header's transitive includes, now include what they use
directly (iot_client.h, tls.h).
Integrators override per product by: dropping their own
agentic_kit_config.h (only the changed #defines, one file for every
subsystem) on the include path; -D<NAME>=<value> as before; or
-DAGENTIC_KIT_USER_CONFIG='"my_opts.h"' for toolchains without
__has_include (when set it wins and the include-path search is skipped).
BREAKING: the 18 build-time knobs are renamed with an AGENTIC_KIT_
prefix. The old names collided for real: coreMQTT's own
core_mqtt_config_defaults.h defines a same-named MQTT_SEND_TIMEOUT_MS
(20000U) that fought the SDK's 2000U default by include order, and
LOG_LEVEL is claimed by several platform SDKs. Migration is a mechanical
rename of -D flags and override headers; the old->new table is in the
guide below.
The log knobs are deliberately untouched in this change: the dead
LOG_LEVEL knob keeps its name, and TAI_LOG_LEVEL keeps working exactly
as on master (rtc-tcp-client compile gate over direct log_emit calls).
The log_* macros in src/iot_internal.h likewise keep their master form
(direct log_emit, no new gate). Both are absorbed into an SDK-wide
AGENTIC_KIT_LOG_LEVEL by the stacked follow-up branch.
Also derives the DP publish gate (DP_MQTT_MAX_PAYLOAD in iot_dp.c) from
AGENTIC_KIT_MQTT_MAX_PACKET_SIZE instead of mirroring the number, so
raising the knob lifts the gate automatically.
Also removes the dead IOT_DO_NOT_USE_CUSTOM_CONFIG flag from the ESP-IDF
component.
Documents it: docs-site/docs/guides/compile-time-knobs.md (the three
override mechanisms with ESP-IDF/CMake wiring, the all-targets
consistency rule, the design rationale, an 18-knob quick reference and
the migration table), wired into sidebars; the porting guide, ATOP
guide, Unreleased CHANGELOG bullet and the ESP-IDF example's CMakeLists
comment point at the final layout; the guide's English mirror ships with
the same anchors under docs-site/i18n/en/.
Verified: the 18 knob #defines are byte-identical to the pre-split
state (git grep diff, empty); an integrator agentic_kit_config.h
overriding MQTT/TAI knobs simultaneously is picked up (cc probe through
both defaults headers); a C++ TU compiles against the new log.h (pickup
outside extern "C"); no reference to the old header names remains (git
grep, empty) and all former include sites build unchanged; full host
build including examples; ctest 15/15; the docs-site builds clean in
both locales (check:i18n included).
Co-Authored-By: Claude Code <[email protected]>
Co-Authored-By: Codex <[email protected]>
heshaoqiong-tuya
force-pushed
the
feature/unified-config-header
branch
from
September 20, 2026 09:57
41a7602 to
408aba9
Compare
heshaoqiong-tuya
added a commit
that referenced
this pull request
Sep 24, 2026
…ader split SDK_VERSION moved out of include/iot_client_config_defaults.h into src/iot_internal.h (#38), so show/next/release all died on the default path with "no '#define SDK_VERSION' line found". Verified with show/next --minor/release against the new default header. Co-Authored-By: Claude Code <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Every build-time knob in the SDK now lives behind an
AGENTIC_KIT_prefix, with itsdefault and rationale in its owning subsystem's config file — there is no central
entry file. Logging collapses to one compile-time ceiling for the whole SDK.
common/log.hpal/pal_config_defaults.hmodules/iot-client/include/iot_client_config_defaults.hmodules/rtc-tcp-client/include/tai_config_defaults.hmodules/tuya-ble/include/tuya_ble_config_defaults.hThe override pickup lives in
common/log.hbecause every SDK translation unit includesit: whichever defaults header a TU reaches first, the integrator's overrides are applied
before any
#ifndefdefault. Each*_config_defaults.hincludeslog.hfirst forexactly that reason, so include order can never matter.
Breaking changes
1. All 20 knob macros renamed with the
AGENTIC_KIT_prefix. The old names collidedfor real: coreMQTT's own
core_mqtt_config_defaults.hdefines a same-namedMQTT_SEND_TIMEOUT_MS(20000U) that fought the SDK's 2000U default by include order, andLOG_LEVELis claimed by several platform SDKs. Migration is a mechanical rename:LOG_LEVEL/TAI_LOG_LEVELAGENTIC_KIT_LOG_LEVEL(one ceiling for the whole SDK)MQTT_MAX_PACKET_SIZEAGENTIC_KIT_MQTT_MAX_PACKET_SIZEMQTT_SEND_TIMEOUT_MSAGENTIC_KIT_MQTT_SEND_TIMEOUT_MSMQTT_RECV_TIMEOUT_MSAGENTIC_KIT_MQTT_RECV_TIMEOUT_MSMQTT_CONNECT_TIMEOUT_MSAGENTIC_KIT_MQTT_CONNECT_TIMEOUT_MSREQUEST_HEADER_BUFFER_SIZEAGENTIC_KIT_REQUEST_HEADER_BUFFER_SIZERESPONSE_BUFFER_SIZEAGENTIC_KIT_RESPONSE_BUFFER_SIZETAI_FRAG_BUF_SIZEAGENTIC_KIT_TAI_FRAG_BUF_SIZETAI_MAX_FRAGMENT_PAYLOADAGENTIC_KIT_TAI_MAX_FRAGMENT_PAYLOADTAI_TX_HDR_BUF_SIZEAGENTIC_KIT_TAI_TX_HDR_BUF_SIZETAI_FRAME_COALESCE_LIMITAGENTIC_KIT_TAI_FRAME_COALESCE_LIMITTAI_TX_CTRL_BUF_SIZEAGENTIC_KIT_TAI_TX_CTRL_BUF_SIZETAI_MAX_ATTRSAGENTIC_KIT_TAI_MAX_ATTRSTAI_DRAIN_BUDGET_MSAGENTIC_KIT_TAI_DRAIN_BUDGET_MSTAI_WORKER_POLL_CAP_MSAGENTIC_KIT_TAI_WORKER_POLL_CAP_MSTAI_LOG_MEDIA_SAMPLE_NAGENTIC_KIT_TAI_LOG_MEDIA_SAMPLE_NPAL_FR_TASK_STACK_WORDSAGENTIC_KIT_PAL_FR_TASK_STACK_WORDSPAL_FR_TASK_PRIORITYAGENTIC_KIT_PAL_FR_TASK_PRIORITYPAL_FR_TASK_NAMEAGENTIC_KIT_PAL_FR_TASK_NAME2. One compile-time log ceiling.
AGENTIC_KIT_LOG_LEVEL(0=none … 4=debug, default 4)gates every SDK log macro — iot-client's
log_*family,TAI_LOG*,TUYA_BLE_HAL_LOG*, and the coreMQTT/coreHTTP log routing. Above the ceiling a log linecompiles out entirely: no call, no argument evaluation, no format string in the image.
Below it, the existing runtime filter (
log_set_level()) still applies. Module macronames and output bytes are unchanged (thin re-tags).
-DTAI_LOG_LEVEL=Nmoves to-DAGENTIC_KIT_LOG_LEVEL=N, noting it now silences the whole SDK.Also removes the dead
IOT_DO_NOT_USE_CUSTOM_CONFIGflag from the ESP-IDF component.How integrators override (unchanged story, one file reaches everything)
agentic_kit_config.hholding only the knobs youwant to change (plain
#define, no#ifndef), put its directory on the include pathof every target that compiles SDK sources. Picked up automatically via
__has_include,before every default — the lwIP
lwipopts.h/ mbedTLSmbedtls_config.hpattern.-D<NAME>=<value>per knob.-DAGENTIC_KIT_USER_CONFIG='"my_opts.h"'— arbitrary file name, for toolchainswithout
__has_include; when set it wins and the include-path search is skipped.The SDK never owns a file named
agentic_kit_config.h: a quoted include searches theincluder's own directory before the
-Ipath, so the plain name must stay theintegrator's. All knob defaults use
#ifndef, so unlisted knobs follow SDK defaults andupgrades merge cleanly.
Why this shape
length) — the defaults now sit in the subsystem a reviewer audits for them, each with
its full rationale (units, couplings, war stories) in the file's comments.
common/log.h) keeps the "one override file for everything" storywhile the defaults themselves are distributed — no per-module override files needed.
sources (struct layouts and buffer sizes depend on them; mismatches fail silently).
Full guide — mechanisms, ESP-IDF/CMake wiring, two-layer log model, per-knob tables,
migration:
docs-site/docs/guides/compile-time-knobs.md.Verification
cc -dM: all 19 knob macros byte-identical to the pre-change single header (onlyinclude guards differ); knob values and rationale comments preserved.
agentic_kit_config.hon the include path overridesLOG_LEVEL/ MQTT / TAI /ATOP / PAL knobs simultaneously;
AGENTIC_KIT_USER_CONFIGwins over it; C++ TUcompiles and links (config sits outside
extern "C").ctest: 15/15 at defaults and with an integrator overridefile on the include path;
LOG_LEVEL0–3 compile warning-free, level 0 strips every_log_emitreference and log tag string from every object (sole documented exception:the
tai_pkt_log.cmedia sampler).behavior preservation) — all findings addressed.