Commit f4b40ec
fix: address PR #472 review comments — 31 fixes across C++ commons, Swift SDK, and iOS app
**C++ commons (`sdk/runanywhere-commons/`):**
- `tool_calling.cpp`: Add `json_value_kind_t` enum + `extract_json_array_raw` helper;
flat-args fallback now emits numbers / booleans / null / arrays verbatim instead of
coercing them to strings. Track the matched tool-name key so only the specific alias
that produced `out_tool_name` is excluded from flat args (e.g. `run_shell`'s
`command` is no longer dropped). Return `false` on `out_args_json` malloc failure
instead of success-with-null. (QEF-1/15/16/29)
- `llamacpp_backend.cpp`: Cast `stop_window[safe_len]` to `uint8_t` before `& 0xC0`
mask so signed-char platforms don't invoke UB on UTF-8 continuation-byte detection
(both loops). Mirror `generate_stream`'s `partial_utf8_buffer` flush into
`generate_from_context` so trailing multi-byte codepoints aren't silently dropped
before the final stop_window emit. (QEF-28/31)
- `llm_component.cpp`: Special-case empty `ctx.full_text` so cancelled / no-op
streams report `completion_tokens = 0` instead of `estimate_tokens("") = 1`.
(QEF-26)
**Swift SDK (`sdk/runanywhere-swift/`):**
- `RunAnywhere+TextGeneration.swift`: Remove explicit
`Unmanaged<LLMStreamCallbackContext>.release()` in the non-SUCCESS branch —
C++ always calls `errorCallback` which consumes the retained ref via
`takeRetainedValue()`, so the explicit release was a double-free. Drop the
`Task.isCancelled` no-op in the C token callback (cancellation is atomic-flag
based in `llm_component.cpp`). Approximate `thinkingTokens` proportionally by
character ratio for both streaming and non-streaming paths instead of assigning
the whole `outputTokens`. (QEF-4/17/27)
- `RunAnywhere+ToolCalling.swift`: Re-apply `noThinkPrefix` at the top of every
follow-up tool-round prompt (was only preserved on the initial build), and pass
`cleanPrompt` (not the raw `prompt`) into `buildFollowUpPrompt`. (QEF-18)
- `RunAnywhere+VoiceSession.swift`: Move `emit(.turnCompleted(...))` inside the
`do` block so errors no longer overwrite `.error` UI state. Make
`resumeListening()` idempotent by guarding on `audioCapture.isRecording`.
Gate `/no_think` injection on `RunAnywhere.currentLLMModel?.supportsThinking`
so non-thinking models don't receive a stray slash command. Only swallow
`.playbackInterrupted`; rethrow other `AudioPlaybackError` cases so real TTS
failures aren't hidden. (QEF-2/20/21/22)
- `RunAnywhere+VoiceAgent.swift`: Use `defer { rac_free(ptr) }` in
`voiceAgentSynthesizeSpeech` instead of a bare `free(ptr)` — fixes both the
native-memory leak on empty audio and the deallocator mismatch (header contract
says use `rac_free`). (QEF-19)
- `CppBridge.swift` + `RunAnywhere.swift`: Make `CppBridge.shutdown()` and
`RunAnywhere.reset()` `async`, and `await` each component's `destroy()`
sequentially before `Telemetry.shutdown()` / `Events.unregister()` — removes
the fire-and-forget `Task` that raced with synchronous teardown. (QEF-30)
- Make `ThinkingContentParser` + its `extract(from:)` public, add a canonical
`strip(from:)` that handles multi-block + trailing-unclosed `<think>` tags so
the app doesn't duplicate three divergent stripping implementations. (QEF-5)
**iOS example app (`examples/ios/RunAnywhereAI/`):**
- `ChatInterfaceView.swift`: Replace `@AppStorage("thinkingModeEnabled")` with
`@ObservedObject SettingsViewModel.shared` so the badge and
`LLMViewModel.applyThinkingModePrefix()` read/write the same `@Published`
source. (QEF-3/7)
- `LLMViewModel.swift` + `RAGViewModel.swift`: Delegate `stripThinkTags` /
`extractThinkingContent` to the new public SDK `ThinkingContentParser`. (QEF-5)
- `LLMViewModel+ToolCalling.swift`: Extend `updateMessageWithToolResult(...)`
with `thinkingContent:` and wire SDK-provided thinking content through so the
tool-call path no longer silently drops it. (QEF-24)
- `LoraExamplePrompts.swift`: Replace the lock-picking prompt with a benign
smart-toaster review prompt that still showcases the abliterated LoRA's
unfiltered-opinion character. (QEF-6)
- `ModelListViewModel.swift` + `SimplifiedModelsView.swift`: Publish
`isLoadingModel` and `.disabled(...)` the model-selection rows while a load
is in-flight, instead of silently discarding later taps. (QEF-8)
- `SettingsViewModel.swift`: Reset `loadedModelSupportsThinking = false` on
registry-lookup miss so the Settings UI stops showing the previous model's
capability flag. (QEF-9)
- `ToolSettingsView.swift`: Calculator tool returns an error dict instead of
fabricating `"0"` when no `expression`/`input`/`expr` key is present; adds
`isValidMathExpression(_:)` pre-validation (balanced parens, no consecutive
operators, no trailing operator, no `..`) before `NSExpression(format:)` so
malformed input can't raise an uncatchable Objective-C exception. (QEF-10/11)
- `VLMCameraView.swift`: Snapshot `isAutoStreamingEnabled` on scenePhase ==
inactive/background and restore it on .active so LIVE mode survives
foregrounding. (QEF-12)
- `VoiceAgentViewModel.swift`: Drop the manual `sessionState = .listening`
after `resumeListening()`; handle the state transition in the session event
handler to avoid racing with the .listening event stream. (QEF-13)
- `VoiceAssistantView.swift`: Decide the mic tap / long-press action
synchronously before spawning `Task`, so fast state changes can't turn a
"send now" into `resumeListening()`. (QEF-25)
- `AdaptiveLayout.swift`: Add `.accessibilityAddTraits(.isButton)`,
`.accessibilityLabel`, `.accessibilityHint`, and `.accessibilityAction` on
both iOS-26 and legacy `AdaptiveMicButton` branches so the gesture-driven
button regains button semantics for VoiceOver / Switch Control. (QEF-14)
- `DemoLoRAAdapter.swift`: Set the abliterated LoRA `fileSize` to the real
HF-confirmed `17_620_224` bytes instead of `0`. (QEF-23)
Verification: `swift build` on the Swift SDK and
`cmake --build build --target rac_commons -j 4` on the C++ commons both succeed
with zero new warnings; all 5 commons unit test binaries (PlaceholderTest,
core_tests, extraction_tests, download_orchestrator_tests, rac_simple_tokenizer_test)
pass. The chunker / rag_backend_thread_safety test failures are pre-existing and
unrelated (missing `rag_chunker.h` / `rag_backend.h` headers from separate work).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>1 parent 5f3ba51 commit f4b40ec
23 files changed
Lines changed: 431 additions & 137 deletions
File tree
- examples/ios/RunAnywhereAI/RunAnywhereAI
- Features
- Chat
- Models
- ViewModels
- Views
- Models
- RAG/ViewModels
- Settings
- Vision
- Voice
- Helpers
- sdk
- runanywhere-commons/src
- backends/llamacpp
- features/llm
- runanywhere-swift/Sources/RunAnywhere
- Foundation/Bridge
- Public
- Extensions
- LLM
- VoiceAgent
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
79 | | - | |
| 79 | + | |
80 | 80 | | |
81 | 81 | | |
82 | 82 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
32 | | - | |
| 32 | + | |
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| |||
Lines changed: 7 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
69 | 69 | | |
70 | 70 | | |
71 | 71 | | |
72 | | - | |
73 | | - | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
74 | 76 | | |
75 | 77 | | |
76 | 78 | | |
77 | 79 | | |
78 | 80 | | |
| 81 | + | |
79 | 82 | | |
80 | 83 | | |
81 | 84 | | |
| |||
85 | 88 | | |
86 | 89 | | |
87 | 90 | | |
| 91 | + | |
88 | 92 | | |
89 | 93 | | |
90 | 94 | | |
| |||
103 | 107 | | |
104 | 108 | | |
105 | 109 | | |
106 | | - | |
| 110 | + | |
107 | 111 | | |
108 | 112 | | |
109 | 113 | | |
| |||
Lines changed: 3 additions & 12 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
575 | 575 | | |
576 | 576 | | |
577 | 577 | | |
| 578 | + | |
| 579 | + | |
578 | 580 | | |
579 | | - | |
580 | | - | |
581 | | - | |
582 | | - | |
583 | | - | |
584 | | - | |
585 | | - | |
586 | | - | |
587 | | - | |
588 | | - | |
589 | | - | |
590 | | - | |
| 581 | + | |
591 | 582 | | |
592 | 583 | | |
Lines changed: 4 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
35 | | - | |
| 35 | + | |
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
| |||
449 | 449 | | |
450 | 450 | | |
451 | 451 | | |
452 | | - | |
| 452 | + | |
453 | 453 | | |
454 | 454 | | |
455 | 455 | | |
| |||
465 | 465 | | |
466 | 466 | | |
467 | 467 | | |
468 | | - | |
| 468 | + | |
469 | 469 | | |
470 | 470 | | |
471 | 471 | | |
| |||
501 | 501 | | |
502 | 502 | | |
503 | 503 | | |
504 | | - | |
| 504 | + | |
505 | 505 | | |
506 | 506 | | |
507 | 507 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
129 | 129 | | |
130 | 130 | | |
131 | 131 | | |
132 | | - | |
| 132 | + | |
133 | 133 | | |
134 | 134 | | |
135 | 135 | | |
| |||
Lines changed: 4 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
137 | 137 | | |
138 | 138 | | |
139 | 139 | | |
| 140 | + | |
140 | 141 | | |
141 | 142 | | |
142 | 143 | | |
| |||
178 | 179 | | |
179 | 180 | | |
180 | 181 | | |
| 182 | + | |
181 | 183 | | |
182 | 184 | | |
183 | 185 | | |
| |||
299 | 301 | | |
300 | 302 | | |
301 | 303 | | |
302 | | - | |
| 304 | + | |
303 | 305 | | |
304 | 306 | | |
305 | 307 | | |
| |||
339 | 341 | | |
340 | 342 | | |
341 | 343 | | |
| 344 | + | |
342 | 345 | | |
343 | 346 | | |
344 | 347 | | |
| |||
Lines changed: 5 additions & 19 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
37 | 40 | | |
38 | 41 | | |
39 | 42 | | |
40 | | - | |
41 | | - | |
42 | | - | |
43 | | - | |
44 | | - | |
45 | | - | |
46 | | - | |
47 | | - | |
| 43 | + | |
48 | 44 | | |
49 | 45 | | |
50 | 46 | | |
51 | 47 | | |
52 | | - | |
53 | | - | |
54 | | - | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
60 | | - | |
61 | | - | |
62 | | - | |
| 48 | + | |
63 | 49 | | |
64 | 50 | | |
65 | 51 | | |
| |||
Lines changed: 3 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
122 | 122 | | |
123 | 123 | | |
124 | 124 | | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
125 | 128 | | |
126 | 129 | | |
127 | 130 | | |
| |||
Lines changed: 71 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
11 | 66 | | |
12 | 67 | | |
13 | 68 | | |
| |||
85 | 140 | | |
86 | 141 | | |
87 | 142 | | |
88 | | - | |
| 143 | + | |
89 | 144 | | |
90 | 145 | | |
91 | 146 | | |
| |||
98 | 153 | | |
99 | 154 | | |
100 | 155 | | |
101 | | - | |
| 156 | + | |
102 | 157 | | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
103 | 163 | | |
104 | 164 | | |
105 | 165 | | |
| |||
119 | 179 | | |
120 | 180 | | |
121 | 181 | | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
122 | 191 | | |
123 | 192 | | |
124 | 193 | | |
| |||
0 commit comments