capacitor-native-agent 0.7.4 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -7
- package/android/src/main/java/com/t6x/plugins/nativeagent/NativeAgentPlugin.kt +10 -0
- package/android/src/main/java/uniffi/native_agent_ffi/native_agent_ffi.kt +291 -8
- package/android/src/main/jniLibs/arm64-v8a/libnative_agent_ffi.so +0 -0
- package/ios/Sources/NativeAgentPlugin/NativeAgentPlugin.swift +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,6 +20,16 @@ npm install capacitor-native-agent
|
|
|
20
20
|
npx cap sync
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
## Cloning this repository
|
|
24
|
+
|
|
25
|
+
The Rust FFI crate lives in a separate GitLab repository and is pulled in as a git submodule. After cloning:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git submodule update --init --recursive
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Upstream URL: https://gitlab.k8s.t6x.io/rruiz/native-agent-ffi
|
|
32
|
+
|
|
23
33
|
## Android Setup
|
|
24
34
|
|
|
25
35
|
The npm package includes the Kotlin plugin source and UniFFI bindings, but **not** the compiled Rust shared library. You must build and place it yourself:
|
|
@@ -27,10 +37,11 @@ The npm package includes the Kotlin plugin source and UniFFI bindings, but **not
|
|
|
27
37
|
### 1. Build the Rust .so
|
|
28
38
|
|
|
29
39
|
```bash
|
|
30
|
-
|
|
31
|
-
cargo ndk -t arm64-v8a build --release
|
|
40
|
+
scripts/build-android.sh
|
|
32
41
|
```
|
|
33
42
|
|
|
43
|
+
This runs `cargo ndk -t arm64-v8a build --release` on the submodule and copies the result into `android/src/main/jniLibs/arm64-v8a/`.
|
|
44
|
+
|
|
34
45
|
### 2. Place the .so in your app
|
|
35
46
|
|
|
36
47
|
Copy the built library to your Android app's jniLibs:
|
|
@@ -154,13 +165,40 @@ Events are emitted via `addListener('nativeAgentEvent', handler)`:
|
|
|
154
165
|
- `heartbeat.*` — Heartbeat lifecycle
|
|
155
166
|
- `scheduler.status` — Scheduler state updates
|
|
156
167
|
|
|
168
|
+
## Supported LLM providers
|
|
169
|
+
|
|
170
|
+
The `provider` argument is a free string. The Rust agent loop currently accepts:
|
|
171
|
+
|
|
172
|
+
| Provider string | Default model | Endpoint |
|
|
173
|
+
|---|---|---|
|
|
174
|
+
| `anthropic` | `claude-sonnet-4-20250514` | Anthropic Messages API |
|
|
175
|
+
| `openai` | `gpt-4o` | OpenAI Chat Completions |
|
|
176
|
+
| `openrouter` | `anthropic/claude-sonnet-4.5` | OpenRouter |
|
|
177
|
+
| `kimi` (aliases `kimi-coding`, `kimi-code`) | `kimi-for-coding` | Kimi Coding (Anthropic-messages-compatible, https://api.kimi.com/coding) |
|
|
178
|
+
|
|
179
|
+
> **Note (0.9.0 — iOS):** Kimi is fully wired in the Android `.so` shipped with this version. The iOS `xcframework` in this release is the pre-existing `0.8.x` build and has **not** been rebuilt against `native-agent-ffi 9946e0f`. iOS callers using `provider: 'kimi'` will receive `Unsupported provider`. Track [#TODO-ios-0.9.1](#known-limitations) for the 0.9.1 iOS rebuild.
|
|
180
|
+
|
|
157
181
|
## Platform Support
|
|
158
182
|
|
|
159
|
-
| Platform | Status |
|
|
160
|
-
|
|
161
|
-
| Android | Supported |
|
|
162
|
-
| iOS |
|
|
163
|
-
| Web | N/A (throws unavailable error) |
|
|
183
|
+
| Platform | Status (this release: **0.9.0**) |
|
|
184
|
+
|----------|-----------------------------------|
|
|
185
|
+
| Android | Supported. Rust pinned to `native-agent-ffi@9946e0f` (Kimi, SSE no-space fix, session-context fix, AgentStore refactor, runtime-drop fix). |
|
|
186
|
+
| iOS | Stale binary — `xcframework` is pre-`0.9.0` and will be refreshed in `0.9.1`. See *Known limitations* below. |
|
|
187
|
+
| Web | N/A (throws unavailable error). |
|
|
188
|
+
|
|
189
|
+
## Known limitations
|
|
190
|
+
|
|
191
|
+
### 0.9.0 — iOS xcframework not rebuilt
|
|
192
|
+
|
|
193
|
+
The Mac build host was unreachable when `0.9.0` was cut, so `ios/Frameworks/NativeAgentFFI.xcframework/` was **not** rebuilt against `native-agent-ffi@9946e0f`. iOS users on `0.9.0` are missing the following upstream changes (Android users have them):
|
|
194
|
+
|
|
195
|
+
- `ba8c97e` `feat(llm): add kimi (Kimi Code) provider` — `provider: 'kimi'` will fail on iOS until `0.9.1`.
|
|
196
|
+
- `2cb34be` `fix(llm): tolerate "data:" SSE without space` — Anthropic-compatible streaming endpoints that omit the space after `data:` will return empty messages on iOS.
|
|
197
|
+
- `9735f4d` `ffi: keep session context across send_message` — after a cold-boot resume, the next `sendMessage` may start without prior history on iOS.
|
|
198
|
+
- `02b1955` `feat(store): extract AgentStore trait` — internal refactor only; mobile `SqliteStore` default behavior unchanged, so no user-visible iOS impact.
|
|
199
|
+
- `9946e0f` `ffi: detach inner runtime on drop` — server-side concern only (handle dropped from inside another tokio runtime); does not affect Capacitor.
|
|
200
|
+
|
|
201
|
+
Action plan: rebuild `xcframework` on the Mac under `~/choreruiz/` via `scripts/build-ios.sh`, rsync `ios/Frameworks/` and `ios/Sources/NativeAgentPlugin/Generated/` back, bump to `0.9.1`, republish.
|
|
164
202
|
|
|
165
203
|
## License
|
|
166
204
|
|
|
@@ -113,6 +113,16 @@ class NativeAgentPlugin : Plugin() {
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
// ── Governance (native-to-native, not a @PluginMethod) ──────────
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Register an optional governance provider for taint, audit, loop-guard, and cost tracking.
|
|
120
|
+
* Called by capacitor-agent-os at init time — not exposed to JavaScript.
|
|
121
|
+
*/
|
|
122
|
+
fun registerGovernance(provider: uniffi.native_agent_ffi.GovernanceProvider) {
|
|
123
|
+
handle?.setGovernanceProvider(provider)
|
|
124
|
+
}
|
|
125
|
+
|
|
116
126
|
// ── Agent ──────────────────────────────────────────────────────────
|
|
117
127
|
|
|
118
128
|
@PluginMethod
|
|
@@ -654,6 +654,24 @@ internal open class UniffiForeignFutureStructVoid(
|
|
|
654
654
|
internal interface UniffiForeignFutureCompleteVoid : com.sun.jna.Callback {
|
|
655
655
|
fun callback(`callbackData`: Long,`result`: UniffiForeignFutureStructVoid.UniffiByValue,)
|
|
656
656
|
}
|
|
657
|
+
internal interface UniffiCallbackInterfaceGovernanceProviderMethod0 : com.sun.jna.Callback {
|
|
658
|
+
fun callback(`uniffiHandle`: Long,`toolName`: RustBuffer.ByValue,`paramsJson`: RustBuffer.ByValue,`uniffiOutReturn`: RustBuffer,uniffiCallStatus: UniffiRustCallStatus,)
|
|
659
|
+
}
|
|
660
|
+
internal interface UniffiCallbackInterfaceGovernanceProviderMethod1 : com.sun.jna.Callback {
|
|
661
|
+
fun callback(`uniffiHandle`: Long,`toolName`: RustBuffer.ByValue,`paramsJson`: RustBuffer.ByValue,`result`: RustBuffer.ByValue,`uniffiOutReturn`: RustBuffer,uniffiCallStatus: UniffiRustCallStatus,)
|
|
662
|
+
}
|
|
663
|
+
internal interface UniffiCallbackInterfaceGovernanceProviderMethod2 : com.sun.jna.Callback {
|
|
664
|
+
fun callback(`uniffiHandle`: Long,`agentId`: RustBuffer.ByValue,`action`: RustBuffer.ByValue,`detail`: RustBuffer.ByValue,`outcome`: RustBuffer.ByValue,`uniffiOutReturn`: Pointer,uniffiCallStatus: UniffiRustCallStatus,)
|
|
665
|
+
}
|
|
666
|
+
internal interface UniffiCallbackInterfaceGovernanceProviderMethod3 : com.sun.jna.Callback {
|
|
667
|
+
fun callback(`uniffiHandle`: Long,`sinkType`: RustBuffer.ByValue,`content`: RustBuffer.ByValue,`uniffiOutReturn`: RustBuffer,uniffiCallStatus: UniffiRustCallStatus,)
|
|
668
|
+
}
|
|
669
|
+
internal interface UniffiCallbackInterfaceGovernanceProviderMethod4 : com.sun.jna.Callback {
|
|
670
|
+
fun callback(`uniffiHandle`: Long,`uniffiOutReturn`: Pointer,uniffiCallStatus: UniffiRustCallStatus,)
|
|
671
|
+
}
|
|
672
|
+
internal interface UniffiCallbackInterfaceGovernanceProviderMethod5 : com.sun.jna.Callback {
|
|
673
|
+
fun callback(`uniffiHandle`: Long,`modelId`: RustBuffer.ByValue,`inputTokens`: Int,`outputTokens`: Int,`uniffiOutReturn`: Pointer,uniffiCallStatus: UniffiRustCallStatus,)
|
|
674
|
+
}
|
|
657
675
|
internal interface UniffiCallbackInterfaceMemoryProviderMethod0 : com.sun.jna.Callback {
|
|
658
676
|
fun callback(`uniffiHandle`: Long,`key`: RustBuffer.ByValue,`text`: RustBuffer.ByValue,`metadataJson`: RustBuffer.ByValue,`uniffiOutReturn`: RustBuffer,uniffiCallStatus: UniffiRustCallStatus,)
|
|
659
677
|
}
|
|
@@ -675,6 +693,37 @@ internal interface UniffiCallbackInterfaceNativeEventCallbackMethod0 : com.sun.j
|
|
|
675
693
|
internal interface UniffiCallbackInterfaceNativeNotifierMethod0 : com.sun.jna.Callback {
|
|
676
694
|
fun callback(`uniffiHandle`: Long,`title`: RustBuffer.ByValue,`body`: RustBuffer.ByValue,`dataJson`: RustBuffer.ByValue,`uniffiOutReturn`: RustBuffer,uniffiCallStatus: UniffiRustCallStatus,)
|
|
677
695
|
}
|
|
696
|
+
@Structure.FieldOrder("checkLoop", "recordOutcome", "recordAudit", "checkSink", "reset", "recordUsage", "uniffiFree")
|
|
697
|
+
internal open class UniffiVTableCallbackInterfaceGovernanceProvider(
|
|
698
|
+
@JvmField internal var `checkLoop`: UniffiCallbackInterfaceGovernanceProviderMethod0? = null,
|
|
699
|
+
@JvmField internal var `recordOutcome`: UniffiCallbackInterfaceGovernanceProviderMethod1? = null,
|
|
700
|
+
@JvmField internal var `recordAudit`: UniffiCallbackInterfaceGovernanceProviderMethod2? = null,
|
|
701
|
+
@JvmField internal var `checkSink`: UniffiCallbackInterfaceGovernanceProviderMethod3? = null,
|
|
702
|
+
@JvmField internal var `reset`: UniffiCallbackInterfaceGovernanceProviderMethod4? = null,
|
|
703
|
+
@JvmField internal var `recordUsage`: UniffiCallbackInterfaceGovernanceProviderMethod5? = null,
|
|
704
|
+
@JvmField internal var `uniffiFree`: UniffiCallbackInterfaceFree? = null,
|
|
705
|
+
) : Structure() {
|
|
706
|
+
class UniffiByValue(
|
|
707
|
+
`checkLoop`: UniffiCallbackInterfaceGovernanceProviderMethod0? = null,
|
|
708
|
+
`recordOutcome`: UniffiCallbackInterfaceGovernanceProviderMethod1? = null,
|
|
709
|
+
`recordAudit`: UniffiCallbackInterfaceGovernanceProviderMethod2? = null,
|
|
710
|
+
`checkSink`: UniffiCallbackInterfaceGovernanceProviderMethod3? = null,
|
|
711
|
+
`reset`: UniffiCallbackInterfaceGovernanceProviderMethod4? = null,
|
|
712
|
+
`recordUsage`: UniffiCallbackInterfaceGovernanceProviderMethod5? = null,
|
|
713
|
+
`uniffiFree`: UniffiCallbackInterfaceFree? = null,
|
|
714
|
+
): UniffiVTableCallbackInterfaceGovernanceProvider(`checkLoop`,`recordOutcome`,`recordAudit`,`checkSink`,`reset`,`recordUsage`,`uniffiFree`,), Structure.ByValue
|
|
715
|
+
|
|
716
|
+
internal fun uniffiSetValue(other: UniffiVTableCallbackInterfaceGovernanceProvider) {
|
|
717
|
+
`checkLoop` = other.`checkLoop`
|
|
718
|
+
`recordOutcome` = other.`recordOutcome`
|
|
719
|
+
`recordAudit` = other.`recordAudit`
|
|
720
|
+
`checkSink` = other.`checkSink`
|
|
721
|
+
`reset` = other.`reset`
|
|
722
|
+
`recordUsage` = other.`recordUsage`
|
|
723
|
+
`uniffiFree` = other.`uniffiFree`
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
}
|
|
678
727
|
@Structure.FieldOrder("store", "recall", "forget", "search", "list", "uniffiFree")
|
|
679
728
|
internal open class UniffiVTableCallbackInterfaceMemoryProvider(
|
|
680
729
|
@JvmField internal var `store`: UniffiCallbackInterfaceMemoryProviderMethod0? = null,
|
|
@@ -895,6 +944,15 @@ internal open class UniffiVTableCallbackInterfaceNativeNotifier(
|
|
|
895
944
|
|
|
896
945
|
|
|
897
946
|
|
|
947
|
+
|
|
948
|
+
|
|
949
|
+
|
|
950
|
+
|
|
951
|
+
|
|
952
|
+
|
|
953
|
+
|
|
954
|
+
|
|
955
|
+
|
|
898
956
|
|
|
899
957
|
|
|
900
958
|
|
|
@@ -915,6 +973,7 @@ internal interface UniffiLib : Library {
|
|
|
915
973
|
.also { lib: UniffiLib ->
|
|
916
974
|
uniffiCheckContractApiVersion(lib)
|
|
917
975
|
uniffiCheckApiChecksums(lib)
|
|
976
|
+
uniffiCallbackInterfaceGovernanceProvider.register(lib)
|
|
918
977
|
uniffiCallbackInterfaceMemoryProvider.register(lib)
|
|
919
978
|
uniffiCallbackInterfaceNativeEventCallback.register(lib)
|
|
920
979
|
uniffiCallbackInterfaceNativeNotifier.register(lib)
|
|
@@ -1007,6 +1066,8 @@ internal interface UniffiLib : Library {
|
|
|
1007
1066
|
): Unit
|
|
1008
1067
|
fun uniffi_native_agent_ffi_fn_method_nativeagenthandle_set_event_callback(`ptr`: Pointer,`callback`: Long,uniffi_out_err: UniffiRustCallStatus,
|
|
1009
1068
|
): Unit
|
|
1069
|
+
fun uniffi_native_agent_ffi_fn_method_nativeagenthandle_set_governance_provider(`ptr`: Pointer,`provider`: Long,uniffi_out_err: UniffiRustCallStatus,
|
|
1070
|
+
): Unit
|
|
1010
1071
|
fun uniffi_native_agent_ffi_fn_method_nativeagenthandle_set_heartbeat_config(`ptr`: Pointer,`configJson`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus,
|
|
1011
1072
|
): Unit
|
|
1012
1073
|
fun uniffi_native_agent_ffi_fn_method_nativeagenthandle_set_memory_provider(`ptr`: Pointer,`provider`: Long,uniffi_out_err: UniffiRustCallStatus,
|
|
@@ -1027,6 +1088,8 @@ internal interface UniffiLib : Library {
|
|
|
1027
1088
|
): Unit
|
|
1028
1089
|
fun uniffi_native_agent_ffi_fn_method_nativeagenthandle_update_skill(`ptr`: Pointer,`id`: RustBuffer.ByValue,`patchJson`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus,
|
|
1029
1090
|
): Unit
|
|
1091
|
+
fun uniffi_native_agent_ffi_fn_init_callback_vtable_governanceprovider(`vtable`: UniffiVTableCallbackInterfaceGovernanceProvider,
|
|
1092
|
+
): Unit
|
|
1030
1093
|
fun uniffi_native_agent_ffi_fn_init_callback_vtable_memoryprovider(`vtable`: UniffiVTableCallbackInterfaceMemoryProvider,
|
|
1031
1094
|
): Unit
|
|
1032
1095
|
fun uniffi_native_agent_ffi_fn_init_callback_vtable_nativeeventcallback(`vtable`: UniffiVTableCallbackInterfaceNativeEventCallback,
|
|
@@ -1227,6 +1290,8 @@ internal interface UniffiLib : Library {
|
|
|
1227
1290
|
): Short
|
|
1228
1291
|
fun uniffi_native_agent_ffi_checksum_method_nativeagenthandle_set_event_callback(
|
|
1229
1292
|
): Short
|
|
1293
|
+
fun uniffi_native_agent_ffi_checksum_method_nativeagenthandle_set_governance_provider(
|
|
1294
|
+
): Short
|
|
1230
1295
|
fun uniffi_native_agent_ffi_checksum_method_nativeagenthandle_set_heartbeat_config(
|
|
1231
1296
|
): Short
|
|
1232
1297
|
fun uniffi_native_agent_ffi_checksum_method_nativeagenthandle_set_memory_provider(
|
|
@@ -1249,6 +1314,18 @@ internal interface UniffiLib : Library {
|
|
|
1249
1314
|
): Short
|
|
1250
1315
|
fun uniffi_native_agent_ffi_checksum_constructor_nativeagenthandle_new(
|
|
1251
1316
|
): Short
|
|
1317
|
+
fun uniffi_native_agent_ffi_checksum_method_governanceprovider_check_loop(
|
|
1318
|
+
): Short
|
|
1319
|
+
fun uniffi_native_agent_ffi_checksum_method_governanceprovider_record_outcome(
|
|
1320
|
+
): Short
|
|
1321
|
+
fun uniffi_native_agent_ffi_checksum_method_governanceprovider_record_audit(
|
|
1322
|
+
): Short
|
|
1323
|
+
fun uniffi_native_agent_ffi_checksum_method_governanceprovider_check_sink(
|
|
1324
|
+
): Short
|
|
1325
|
+
fun uniffi_native_agent_ffi_checksum_method_governanceprovider_reset(
|
|
1326
|
+
): Short
|
|
1327
|
+
fun uniffi_native_agent_ffi_checksum_method_governanceprovider_record_usage(
|
|
1328
|
+
): Short
|
|
1252
1329
|
fun uniffi_native_agent_ffi_checksum_method_memoryprovider_store(
|
|
1253
1330
|
): Short
|
|
1254
1331
|
fun uniffi_native_agent_ffi_checksum_method_memoryprovider_recall(
|
|
@@ -1397,6 +1474,9 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) {
|
|
|
1397
1474
|
if (lib.uniffi_native_agent_ffi_checksum_method_nativeagenthandle_set_event_callback() != 56165.toShort()) {
|
|
1398
1475
|
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
|
1399
1476
|
}
|
|
1477
|
+
if (lib.uniffi_native_agent_ffi_checksum_method_nativeagenthandle_set_governance_provider() != 45093.toShort()) {
|
|
1478
|
+
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
|
1479
|
+
}
|
|
1400
1480
|
if (lib.uniffi_native_agent_ffi_checksum_method_nativeagenthandle_set_heartbeat_config() != 33968.toShort()) {
|
|
1401
1481
|
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
|
1402
1482
|
}
|
|
@@ -1430,6 +1510,24 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) {
|
|
|
1430
1510
|
if (lib.uniffi_native_agent_ffi_checksum_constructor_nativeagenthandle_new() != 18383.toShort()) {
|
|
1431
1511
|
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
|
1432
1512
|
}
|
|
1513
|
+
if (lib.uniffi_native_agent_ffi_checksum_method_governanceprovider_check_loop() != 64194.toShort()) {
|
|
1514
|
+
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
|
1515
|
+
}
|
|
1516
|
+
if (lib.uniffi_native_agent_ffi_checksum_method_governanceprovider_record_outcome() != 15801.toShort()) {
|
|
1517
|
+
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
|
1518
|
+
}
|
|
1519
|
+
if (lib.uniffi_native_agent_ffi_checksum_method_governanceprovider_record_audit() != 34049.toShort()) {
|
|
1520
|
+
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
|
1521
|
+
}
|
|
1522
|
+
if (lib.uniffi_native_agent_ffi_checksum_method_governanceprovider_check_sink() != 37338.toShort()) {
|
|
1523
|
+
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
|
1524
|
+
}
|
|
1525
|
+
if (lib.uniffi_native_agent_ffi_checksum_method_governanceprovider_reset() != 57214.toShort()) {
|
|
1526
|
+
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
|
1527
|
+
}
|
|
1528
|
+
if (lib.uniffi_native_agent_ffi_checksum_method_governanceprovider_record_usage() != 907.toShort()) {
|
|
1529
|
+
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
|
1530
|
+
}
|
|
1433
1531
|
if (lib.uniffi_native_agent_ffi_checksum_method_memoryprovider_store() != 49136.toShort()) {
|
|
1434
1532
|
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
|
1435
1533
|
}
|
|
@@ -1977,6 +2075,12 @@ public interface NativeAgentHandleInterface {
|
|
|
1977
2075
|
*/
|
|
1978
2076
|
fun `setEventCallback`(`callback`: NativeEventCallback)
|
|
1979
2077
|
|
|
2078
|
+
/**
|
|
2079
|
+
* Set the optional governance provider (taint, audit, loop-guard, cost tracking).
|
|
2080
|
+
* Typically called by capacitor-agent-os when it auto-registers at init time.
|
|
2081
|
+
*/
|
|
2082
|
+
fun `setGovernanceProvider`(`provider`: GovernanceProvider)
|
|
2083
|
+
|
|
1980
2084
|
/**
|
|
1981
2085
|
* Set heartbeat config.
|
|
1982
2086
|
*/
|
|
@@ -2696,6 +2800,22 @@ open class NativeAgentHandle: Disposable, AutoCloseable, NativeAgentHandleInterf
|
|
|
2696
2800
|
|
|
2697
2801
|
|
|
2698
2802
|
|
|
2803
|
+
/**
|
|
2804
|
+
* Set the optional governance provider (taint, audit, loop-guard, cost tracking).
|
|
2805
|
+
* Typically called by capacitor-agent-os when it auto-registers at init time.
|
|
2806
|
+
*/
|
|
2807
|
+
@Throws(NativeAgentException::class)override fun `setGovernanceProvider`(`provider`: GovernanceProvider)
|
|
2808
|
+
=
|
|
2809
|
+
callWithPointer {
|
|
2810
|
+
uniffiRustCallWithError(NativeAgentException) { _status ->
|
|
2811
|
+
UniffiLib.INSTANCE.uniffi_native_agent_ffi_fn_method_nativeagenthandle_set_governance_provider(
|
|
2812
|
+
it, FfiConverterTypeGovernanceProvider.lower(`provider`),_status)
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
|
|
2816
|
+
|
|
2817
|
+
|
|
2818
|
+
|
|
2699
2819
|
/**
|
|
2700
2820
|
* Set heartbeat config.
|
|
2701
2821
|
*/
|
|
@@ -3333,20 +3453,45 @@ public object FfiConverterTypeNativeAgentError : FfiConverterRustBuffer<NativeAg
|
|
|
3333
3453
|
|
|
3334
3454
|
|
|
3335
3455
|
/**
|
|
3336
|
-
*
|
|
3337
|
-
* Implemented by Kotlin/Swift
|
|
3456
|
+
* Optional governance provider for security, audit, and loop-guard checks.
|
|
3457
|
+
* Implemented by Kotlin/Swift — typically backed by capacitor-agent-os when
|
|
3458
|
+
* that plugin is installed. When absent, the agent loop runs without
|
|
3459
|
+
* governance checks.
|
|
3338
3460
|
*/
|
|
3339
|
-
public interface
|
|
3461
|
+
public interface GovernanceProvider {
|
|
3340
3462
|
|
|
3341
|
-
|
|
3463
|
+
/**
|
|
3464
|
+
* Check if a tool call should proceed. Returns JSON verdict:
|
|
3465
|
+
* `{"type":"Allow"}` | `{"type":"Warn","reason":"..."}` |
|
|
3466
|
+
* `{"type":"Block","reason":"..."}` | `{"type":"CircuitBreak","reason":"..."}`
|
|
3467
|
+
*/
|
|
3468
|
+
fun `checkLoop`(`toolName`: kotlin.String, `paramsJson`: kotlin.String): kotlin.String
|
|
3342
3469
|
|
|
3343
|
-
|
|
3470
|
+
/**
|
|
3471
|
+
* Record tool outcome for loop detection. Returns optional warning string.
|
|
3472
|
+
*/
|
|
3473
|
+
fun `recordOutcome`(`toolName`: kotlin.String, `paramsJson`: kotlin.String, `result`: kotlin.String): kotlin.String?
|
|
3344
3474
|
|
|
3345
|
-
|
|
3475
|
+
/**
|
|
3476
|
+
* Record an audit trail entry.
|
|
3477
|
+
*/
|
|
3478
|
+
fun `recordAudit`(`agentId`: kotlin.String, `action`: kotlin.String, `detail`: kotlin.String, `outcome`: kotlin.String)
|
|
3346
3479
|
|
|
3347
|
-
|
|
3480
|
+
/**
|
|
3481
|
+
* Check if content is tainted before passing to LLM. Returns JSON:
|
|
3482
|
+
* `{"blocked":true/false,"reason":"...","matchedLabels":[...]}`
|
|
3483
|
+
*/
|
|
3484
|
+
fun `checkSink`(`sinkType`: kotlin.String, `content`: kotlin.String): kotlin.String
|
|
3348
3485
|
|
|
3349
|
-
|
|
3486
|
+
/**
|
|
3487
|
+
* Reset loop guard state (e.g. on new session).
|
|
3488
|
+
*/
|
|
3489
|
+
fun `reset`()
|
|
3490
|
+
|
|
3491
|
+
/**
|
|
3492
|
+
* Record token usage for cost tracking.
|
|
3493
|
+
*/
|
|
3494
|
+
fun `recordUsage`(`modelId`: kotlin.String, `inputTokens`: kotlin.UInt, `outputTokens`: kotlin.UInt)
|
|
3350
3495
|
|
|
3351
3496
|
companion object
|
|
3352
3497
|
}
|
|
@@ -3384,6 +3529,144 @@ public abstract class FfiConverterCallbackInterface<CallbackInterface: Any>: Ffi
|
|
|
3384
3529
|
}
|
|
3385
3530
|
}
|
|
3386
3531
|
|
|
3532
|
+
// Put the implementation in an object so we don't pollute the top-level namespace
|
|
3533
|
+
internal object uniffiCallbackInterfaceGovernanceProvider {
|
|
3534
|
+
internal object `checkLoop`: UniffiCallbackInterfaceGovernanceProviderMethod0 {
|
|
3535
|
+
override fun callback(`uniffiHandle`: Long,`toolName`: RustBuffer.ByValue,`paramsJson`: RustBuffer.ByValue,`uniffiOutReturn`: RustBuffer,uniffiCallStatus: UniffiRustCallStatus,) {
|
|
3536
|
+
val uniffiObj = FfiConverterTypeGovernanceProvider.handleMap.get(uniffiHandle)
|
|
3537
|
+
val makeCall = { ->
|
|
3538
|
+
uniffiObj.`checkLoop`(
|
|
3539
|
+
FfiConverterString.lift(`toolName`),
|
|
3540
|
+
FfiConverterString.lift(`paramsJson`),
|
|
3541
|
+
)
|
|
3542
|
+
}
|
|
3543
|
+
val writeReturn = { value: kotlin.String -> uniffiOutReturn.setValue(FfiConverterString.lower(value)) }
|
|
3544
|
+
uniffiTraitInterfaceCall(uniffiCallStatus, makeCall, writeReturn)
|
|
3545
|
+
}
|
|
3546
|
+
}
|
|
3547
|
+
internal object `recordOutcome`: UniffiCallbackInterfaceGovernanceProviderMethod1 {
|
|
3548
|
+
override fun callback(`uniffiHandle`: Long,`toolName`: RustBuffer.ByValue,`paramsJson`: RustBuffer.ByValue,`result`: RustBuffer.ByValue,`uniffiOutReturn`: RustBuffer,uniffiCallStatus: UniffiRustCallStatus,) {
|
|
3549
|
+
val uniffiObj = FfiConverterTypeGovernanceProvider.handleMap.get(uniffiHandle)
|
|
3550
|
+
val makeCall = { ->
|
|
3551
|
+
uniffiObj.`recordOutcome`(
|
|
3552
|
+
FfiConverterString.lift(`toolName`),
|
|
3553
|
+
FfiConverterString.lift(`paramsJson`),
|
|
3554
|
+
FfiConverterString.lift(`result`),
|
|
3555
|
+
)
|
|
3556
|
+
}
|
|
3557
|
+
val writeReturn = { value: kotlin.String? -> uniffiOutReturn.setValue(FfiConverterOptionalString.lower(value)) }
|
|
3558
|
+
uniffiTraitInterfaceCall(uniffiCallStatus, makeCall, writeReturn)
|
|
3559
|
+
}
|
|
3560
|
+
}
|
|
3561
|
+
internal object `recordAudit`: UniffiCallbackInterfaceGovernanceProviderMethod2 {
|
|
3562
|
+
override fun callback(`uniffiHandle`: Long,`agentId`: RustBuffer.ByValue,`action`: RustBuffer.ByValue,`detail`: RustBuffer.ByValue,`outcome`: RustBuffer.ByValue,`uniffiOutReturn`: Pointer,uniffiCallStatus: UniffiRustCallStatus,) {
|
|
3563
|
+
val uniffiObj = FfiConverterTypeGovernanceProvider.handleMap.get(uniffiHandle)
|
|
3564
|
+
val makeCall = { ->
|
|
3565
|
+
uniffiObj.`recordAudit`(
|
|
3566
|
+
FfiConverterString.lift(`agentId`),
|
|
3567
|
+
FfiConverterString.lift(`action`),
|
|
3568
|
+
FfiConverterString.lift(`detail`),
|
|
3569
|
+
FfiConverterString.lift(`outcome`),
|
|
3570
|
+
)
|
|
3571
|
+
}
|
|
3572
|
+
val writeReturn = { _: Unit -> Unit }
|
|
3573
|
+
uniffiTraitInterfaceCall(uniffiCallStatus, makeCall, writeReturn)
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
internal object `checkSink`: UniffiCallbackInterfaceGovernanceProviderMethod3 {
|
|
3577
|
+
override fun callback(`uniffiHandle`: Long,`sinkType`: RustBuffer.ByValue,`content`: RustBuffer.ByValue,`uniffiOutReturn`: RustBuffer,uniffiCallStatus: UniffiRustCallStatus,) {
|
|
3578
|
+
val uniffiObj = FfiConverterTypeGovernanceProvider.handleMap.get(uniffiHandle)
|
|
3579
|
+
val makeCall = { ->
|
|
3580
|
+
uniffiObj.`checkSink`(
|
|
3581
|
+
FfiConverterString.lift(`sinkType`),
|
|
3582
|
+
FfiConverterString.lift(`content`),
|
|
3583
|
+
)
|
|
3584
|
+
}
|
|
3585
|
+
val writeReturn = { value: kotlin.String -> uniffiOutReturn.setValue(FfiConverterString.lower(value)) }
|
|
3586
|
+
uniffiTraitInterfaceCall(uniffiCallStatus, makeCall, writeReturn)
|
|
3587
|
+
}
|
|
3588
|
+
}
|
|
3589
|
+
internal object `reset`: UniffiCallbackInterfaceGovernanceProviderMethod4 {
|
|
3590
|
+
override fun callback(`uniffiHandle`: Long,`uniffiOutReturn`: Pointer,uniffiCallStatus: UniffiRustCallStatus,) {
|
|
3591
|
+
val uniffiObj = FfiConverterTypeGovernanceProvider.handleMap.get(uniffiHandle)
|
|
3592
|
+
val makeCall = { ->
|
|
3593
|
+
uniffiObj.`reset`(
|
|
3594
|
+
)
|
|
3595
|
+
}
|
|
3596
|
+
val writeReturn = { _: Unit -> Unit }
|
|
3597
|
+
uniffiTraitInterfaceCall(uniffiCallStatus, makeCall, writeReturn)
|
|
3598
|
+
}
|
|
3599
|
+
}
|
|
3600
|
+
internal object `recordUsage`: UniffiCallbackInterfaceGovernanceProviderMethod5 {
|
|
3601
|
+
override fun callback(`uniffiHandle`: Long,`modelId`: RustBuffer.ByValue,`inputTokens`: Int,`outputTokens`: Int,`uniffiOutReturn`: Pointer,uniffiCallStatus: UniffiRustCallStatus,) {
|
|
3602
|
+
val uniffiObj = FfiConverterTypeGovernanceProvider.handleMap.get(uniffiHandle)
|
|
3603
|
+
val makeCall = { ->
|
|
3604
|
+
uniffiObj.`recordUsage`(
|
|
3605
|
+
FfiConverterString.lift(`modelId`),
|
|
3606
|
+
FfiConverterUInt.lift(`inputTokens`),
|
|
3607
|
+
FfiConverterUInt.lift(`outputTokens`),
|
|
3608
|
+
)
|
|
3609
|
+
}
|
|
3610
|
+
val writeReturn = { _: Unit -> Unit }
|
|
3611
|
+
uniffiTraitInterfaceCall(uniffiCallStatus, makeCall, writeReturn)
|
|
3612
|
+
}
|
|
3613
|
+
}
|
|
3614
|
+
|
|
3615
|
+
internal object uniffiFree: UniffiCallbackInterfaceFree {
|
|
3616
|
+
override fun callback(handle: Long) {
|
|
3617
|
+
FfiConverterTypeGovernanceProvider.handleMap.remove(handle)
|
|
3618
|
+
}
|
|
3619
|
+
}
|
|
3620
|
+
|
|
3621
|
+
internal var vtable = UniffiVTableCallbackInterfaceGovernanceProvider.UniffiByValue(
|
|
3622
|
+
`checkLoop`,
|
|
3623
|
+
`recordOutcome`,
|
|
3624
|
+
`recordAudit`,
|
|
3625
|
+
`checkSink`,
|
|
3626
|
+
`reset`,
|
|
3627
|
+
`recordUsage`,
|
|
3628
|
+
uniffiFree,
|
|
3629
|
+
)
|
|
3630
|
+
|
|
3631
|
+
// Registers the foreign callback with the Rust side.
|
|
3632
|
+
// This method is generated for each callback interface.
|
|
3633
|
+
internal fun register(lib: UniffiLib) {
|
|
3634
|
+
lib.uniffi_native_agent_ffi_fn_init_callback_vtable_governanceprovider(vtable)
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
|
|
3638
|
+
/**
|
|
3639
|
+
* The ffiConverter which transforms the Callbacks in to handles to pass to Rust.
|
|
3640
|
+
*
|
|
3641
|
+
* @suppress
|
|
3642
|
+
*/
|
|
3643
|
+
public object FfiConverterTypeGovernanceProvider: FfiConverterCallbackInterface<GovernanceProvider>()
|
|
3644
|
+
|
|
3645
|
+
|
|
3646
|
+
|
|
3647
|
+
|
|
3648
|
+
|
|
3649
|
+
/**
|
|
3650
|
+
* Callback interface for memory operations (LanceDB or any vector store).
|
|
3651
|
+
* Implemented by Kotlin/Swift, which bridges to the actual memory backend.
|
|
3652
|
+
*/
|
|
3653
|
+
public interface MemoryProvider {
|
|
3654
|
+
|
|
3655
|
+
fun `store`(`key`: kotlin.String, `text`: kotlin.String, `metadataJson`: kotlin.String?): kotlin.String
|
|
3656
|
+
|
|
3657
|
+
fun `recall`(`query`: kotlin.String, `limit`: kotlin.UInt): kotlin.String
|
|
3658
|
+
|
|
3659
|
+
fun `forget`(`key`: kotlin.String): kotlin.String
|
|
3660
|
+
|
|
3661
|
+
fun `search`(`query`: kotlin.String, `maxResults`: kotlin.UInt): kotlin.String
|
|
3662
|
+
|
|
3663
|
+
fun `list`(`prefix`: kotlin.String?, `limit`: kotlin.UInt?): kotlin.String
|
|
3664
|
+
|
|
3665
|
+
companion object
|
|
3666
|
+
}
|
|
3667
|
+
|
|
3668
|
+
|
|
3669
|
+
|
|
3387
3670
|
// Put the implementation in an object so we don't pollute the top-level namespace
|
|
3388
3671
|
internal object uniffiCallbackInterfaceMemoryProvider {
|
|
3389
3672
|
internal object `store`: UniffiCallbackInterfaceMemoryProviderMethod0 {
|
|
Binary file
|
|
@@ -176,6 +176,14 @@ public class NativeAgentPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
// ── Governance (native-to-native, not a plugin method) ─────────────────
|
|
180
|
+
|
|
181
|
+
/// Register an optional governance provider for taint, audit, loop-guard, and cost tracking.
|
|
182
|
+
/// Called by capacitor-agent-os at init time — not exposed to JavaScript.
|
|
183
|
+
public func registerGovernance(_ provider: GovernanceProvider) {
|
|
184
|
+
try? handle?.setGovernanceProvider(provider: provider)
|
|
185
|
+
}
|
|
186
|
+
|
|
179
187
|
// ── Agent ────────────────────────────────────────────────────────────────
|
|
180
188
|
|
|
181
189
|
@objc func sendMessage(_ call: CAPPluginCall) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "capacitor-native-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Native AI agent loop for Capacitor — runs LLM completions, tool execution, and cron jobs in native Rust, enabling background execution.",
|
|
5
5
|
"main": "dist/esm/index.js",
|
|
6
6
|
"types": "dist/esm/index.d.ts",
|