mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-26 15:40:18 +00:00
feat: hot-activate WASM channels, channel-first prompts, unified artifact resolution (#297)
* refactor: unify WASM artifact resolution into registry/artifacts.rs Consolidate duplicated WASM find/build/install logic from 5+ files into a single src/registry/artifacts.rs module. This fixes two bugs: - registry/installer.rs now respects CARGO_TARGET_DIR (was hardcoded) - channels/wasm/bundled.rs now searches all WASM triples (was wasip2 only) Also includes: extension manager hot-activation for WASM channels, extension guidance in LLM prompts, channel manager hot-add support, webhook router channel lookup, and minor cleanups. Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: send approval prompts as messages on WASM channels (Telegram, Slack) WASM channels mapped ApprovalNeeded status to a typing indicator, so users on Telegram never saw tool approval prompts — the agent got stuck in AwaitingApproval and all subsequent messages failed with "Waiting for approval". - Intercept ApprovalNeeded in WasmChannel::handle_status_update and send the prompt as an actual message via call_on_respond, showing tool name, description, parameters, and yes/no/always instructions - Guard against empty LLM responses after clean_response() strips reasoning_content think-tags (defense-in-depth for reasoning models) - Add reasoning_content fallback to NearAiChatProvider::complete() for consistency with complete_with_tools() - Add debug logging when empty responses are suppressed - Improve error logging for channel respond() failures - Register WASM channel webhook routes before credential checks so platforms don't deactivate webhook URLs with 404s Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: address PR #297 review comments - ChannelManager::add: use async write().await instead of try_write() - resolve_target_dir: resolve relative CARGO_TARGET_DIR against crate_dir - install_wasm_files: log warning on capabilities copy failure - refresh_active_channel: load capabilities file for webhook secret name - activate_wasm_channel: validate name against path traversal - Fix cargo fmt formatting in nearai_chat.rs Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: wire up channel runtime for hot-activation and address PR review round 2 - Wire up set_channel_runtime() in main.rs so hot-activation actually works (with_channel_runtime was never called — hot-activation was dead code) - Change ExtensionManager channel runtime fields to RwLock<Option<...>> interior mutability so set_channel_runtime(&self) works after Arc wrapping - Fix artifact tests to use resolve_target_dir() instead of hardcoding "target/" (breaks when CARGO_TARGET_DIR is set) - Fix bundled.rs build hint: cargo component build (not cargo build --target) - Fix wasm_artifact_path doc: binary_name should not include .wasm extension Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: use char-aware truncation to prevent UTF-8 panic in approval prompt &s[..77] panics on multi-byte UTF-8 (CJK, emoji). Use s.chars().take(77) for safe truncation at character boundaries. Co-Authored-By: Claude Opus 4.6 <[email protected]> --------- Co-authored-by: Claude Opus 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
a320f265b3
commit
ea57447649
@@ -27,10 +27,8 @@ fn normalize(s: &str) -> String {
|
||||
/// Normalize typographic/smart punctuation to ASCII so tests match converter output
|
||||
/// regardless of apostrophe/quote variants (e.g. U+2019 ' → U+0027 ').
|
||||
fn normalize_smart_punctuation(s: &str) -> String {
|
||||
s.replace('\u{2019}', "'") // RIGHT SINGLE QUOTATION MARK
|
||||
.replace('\u{2018}', "'") // LEFT SINGLE QUOTATION MARK
|
||||
.replace('\u{201C}', "\"") // LEFT DOUBLE QUOTATION MARK
|
||||
.replace('\u{201D}', "\"") // RIGHT DOUBLE QUOTATION MARK
|
||||
s.replace(['\u{2019}', '\u{2018}'], "'")
|
||||
.replace(['\u{201C}', '\u{201D}'], "\"")
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -58,15 +56,13 @@ fn convert_test_pages_to_markdown() {
|
||||
.unwrap_or("unknown");
|
||||
let default_url = format!("https://example.com/test-pages/{}/", dir_name);
|
||||
|
||||
let metadata: PageMetadata = path
|
||||
.join("metadata.json")
|
||||
.is_file()
|
||||
.then(|| {
|
||||
let raw = std::fs::read_to_string(path.join("metadata.json"))
|
||||
.expect("read metadata.json");
|
||||
serde_json::from_str(&raw).expect("invalid metadata.json")
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let metadata: PageMetadata = if path.join("metadata.json").is_file() {
|
||||
let raw =
|
||||
std::fs::read_to_string(path.join("metadata.json")).expect("read metadata.json");
|
||||
serde_json::from_str(&raw).expect("invalid metadata.json")
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
let url = metadata.url.as_deref().unwrap_or(&default_url).to_string();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user