Modularized channels and added a TUI channel as example#172
Modularized channels and added a TUI channel as example#172dagelf wants to merge 3 commits intoTinyAGI:mainfrom
Conversation
# Conflicts: # lib/common.sh # lib/daemon.sh # lib/messaging.sh # lib/setup-wizard.sh
Greptile SummaryThis PR replaces the hardcoded Key changes:
Confidence Score: 3/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
subgraph Boot["Boot sequence (tinyclaw.sh / setup-wizard.sh)"]
A[tinyclaw.sh starts] --> B[source lib/common.sh]
B --> C[load_channel_registry\nreads channels/*.json via jq]
C --> D{channels found?}
D -- no --> E[exit 1]
D -- yes --> F[ALL_CHANNELS array populated]
F --> G[load_settings\nreads settings.json]
G --> H[ACTIVE_CHANNELS populated\ntokens loaded per manifest key]
end
subgraph Manifest["Channel manifest resolution"]
M1[_channel_manifest_path\nchannel_id] --> M2{id.json exists?}
M2 -- yes --> M3[return direct path]
M2 -- no --> M4[scan all *.json\ncheck .id field]
M4 --> M3
M3 --> M5[_channel_manifest_value\njq query on file]
end
subgraph TUI["TUI client lifecycle"]
T1[node tui-client.js] --> T2[readline prompt on stdin]
T2 --> T3{user input}
T3 -- /command --> T4[handle locally]
T3 -- message --> T5{REQUIRE_PAIRING?}
T5 -- yes → not approved --> T6[print pairing code]
T5 -- no / approved --> T7[enqueueMessage\nQUEUE_INCOMING/tui_*.json]
T7 --> T8[setInterval 400ms\ncheckOutgoing]
T8 --> T9{response file\nQUEUE_OUTGOING/tui_*.json?}
T9 -- matched messageId --> T10[printResponse\ndelete file]
T9 -- timeout 60s --> T11[printResponse timeout]
end
Last reviewed commit: c1a2e5f |
| if (!data || data.channel !== CHANNEL_ID) continue; | ||
| if (!pending.has(data.messageId)) continue; |
There was a problem hiding this comment.
Orphaned outgoing response files are never cleaned up
Files that don't satisfy data.channel !== CHANNEL_ID or !pending.has(data.messageId) are silently skipped without being deleted. This means:
- Stale response files from a previous TUI session — responses that arrived after the previous session exited will be re-read and re-parsed on every 400 ms poll indefinitely.
- Responses produced for a different TUI instance (a different
senderId) — those files will never be consumed or removed either.
Over time, these accumulate in QUEUE_OUTGOING and add perpetual unnecessary I/O. Consider deleting files that pass the channel check but have no matching pending entry, since they clearly belong to a past session:
if (!data || data.channel !== CHANNEL_ID) continue;
if (!pending.has(data.messageId)) {
// Orphaned response from a previous session — clean it up
try { fs.unlinkSync(fullPath); } catch { /* ignore */ }
continue;
}| function makeMessageId(): string { | ||
| messageCounter += 1; | ||
| return `tui_${senderId}_${Date.now()}_${messageCounter}`; | ||
| } |
There was a problem hiding this comment.
Double tui_ prefix in message IDs and queue filenames
makeMessageId returns `tui_${senderId}_${Date.now()}_${messageCounter}`, and enqueueMessage then names the file `tui_${messageId}.json`. The result is a filename like tui_tui_local_1234_1741478400000_1.json — the tui_ prefix is duplicated.
Either remove the tui_ prefix from makeMessageId:
| function makeMessageId(): string { | |
| messageCounter += 1; | |
| return `tui_${senderId}_${Date.now()}_${messageCounter}`; | |
| } | |
| function makeMessageId(): string { | |
| messageCounter += 1; | |
| return `${senderId}_${Date.now()}_${messageCounter}`; | |
| } |
Or remove it from the filename construction in enqueueMessage (tui_${messageId}.json → ${messageId}.json). Keeping them consistent avoids confusion when reading the queue directory.
| for ch in "${ALL_CHANNELS[@]}"; do | ||
| token_key="$(channel_token_key "$ch")" | ||
| if [ -n "$token_key" ]; then | ||
| token_value="$(_get_token "$ch")" | ||
| CHANNEL_CONFIG_JSON="$CHANNEL_CONFIG_JSON\"${ch}\": { \"${token_key}\": \"${token_value}\" }," | ||
| else | ||
| CHANNEL_CONFIG_JSON="$CHANNEL_CONFIG_JSON\"${ch}\": {}," | ||
| fi | ||
| done |
There was a problem hiding this comment.
Config written for all channels, not just enabled ones
The loop iterates over ALL_CHANNELS (every discovered manifest in channels/) rather than ENABLED_CHANNELS (what the user actually selected). For any channel present on disk but not enabled by the user, _get_token returns an empty string — so the config entry written to settings.json will have a blank credential value. This clutters the settings file with stubs for channels the user never configured.
The loop variable on line 335 should be changed from "${ALL_CHANNELS[@]}" to "${ENABLED_CHANNELS[@]}" so that only channels the user opted into receive a config block.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c1a2e5fd1d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" | ||
| SCRIPT_DIR="$PROJECT_ROOT" |
There was a problem hiding this comment.
Restore executable bit on setup wizard
This script is invoked directly (e.g. tinyclaw setup and the auto-setup path in daemon startup), so it must remain executable; in this commit lib/setup-wizard.sh was changed from mode 100755 to 100644, which causes a Permission denied failure when users try to run setup on a normal shell. That blocks first-run configuration and reconfiguration flows.
Useful? React with 👍 / 👎.
| const queueFile = path.join(QUEUE_INCOMING, `tui_${messageId}.json`); | ||
| fs.writeFileSync(queueFile, JSON.stringify(payload, null, 2)); |
There was a problem hiding this comment.
Route TUI traffic through the API queue
The new TUI client writes requests to queue/incoming JSON files and polls queue/outgoing files, but the current queue processor path is DB/API-based (POST /api/message in src/server/routes/messages.ts and /api/responses/pending in src/server/routes/queue.ts), with no reader for those filesystem queue files. In practice, enabling the TUI channel lets users type messages that never get processed or answered.
Useful? React with 👍 / 👎.
|
thanks for making this modular, would this make adding a channel like voice trivial? |
|
I haven't looked at voice APIs but pretty sure it is part of the solution. There are a few minor regressions here, I will try to catch up with the codebase on the weekend, I just cherry picked the channel config from the previous refactor that also turned inference agents into config. |
No description provided.