capacitor-native-agent 0.3.4 → 0.3.6

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.
Files changed (19) hide show
  1. package/Package.swift +3 -1
  2. package/android/build.gradle +1 -0
  3. package/android/src/main/java/com/t6x/plugins/nativeagent/LanceDBBridge.kt +27 -0
  4. package/android/src/main/java/com/t6x/plugins/nativeagent/MemoryProviderImpl.kt +177 -0
  5. package/android/src/main/java/com/t6x/plugins/nativeagent/NativeAgentPlugin.kt +6 -0
  6. package/android/src/main/java/uniffi/native_agent_ffi/native_agent_ffi.kt +230 -8
  7. package/android/src/main/jniLibs/arm64-v8a/libnative_agent_ffi.so +0 -0
  8. package/ios/Frameworks/NativeAgentFFI.xcframework/ios-arm64/Headers/{native_agent_ffiFFI → native_agent_ffi}/module.modulemap +1 -1
  9. package/ios/Frameworks/NativeAgentFFI.xcframework/ios-arm64/Headers/{native_agent_ffiFFI → native_agent_ffi}/native_agent_ffiFFI.h +152 -0
  10. package/ios/Frameworks/NativeAgentFFI.xcframework/ios-arm64/libnative_agent_ffi.a +0 -0
  11. package/ios/Frameworks/NativeAgentFFI.xcframework/ios-arm64-simulator/Headers/{native_agent_ffiFFI → native_agent_ffi}/module.modulemap +1 -1
  12. package/ios/Frameworks/NativeAgentFFI.xcframework/ios-arm64-simulator/Headers/{native_agent_ffiFFI → native_agent_ffi}/native_agent_ffiFFI.h +152 -0
  13. package/ios/Frameworks/NativeAgentFFI.xcframework/ios-arm64-simulator/libnative_agent_ffi.a +0 -0
  14. package/ios/Sources/NativeAgentPlugin/Generated/native_agent_ffi.swift +252 -7
  15. package/ios/Sources/NativeAgentPlugin/Generated/native_agent_ffiFFI.h +93 -0
  16. package/ios/Sources/NativeAgentPlugin/LanceDBBridge.swift +70 -0
  17. package/ios/Sources/NativeAgentPlugin/MemoryProviderImpl.swift +206 -0
  18. package/ios/Sources/NativeAgentPlugin/NativeAgentPlugin.swift +3 -0
  19. package/package.json +8 -2
@@ -0,0 +1,206 @@
1
+ import Foundation
2
+
3
+ #if canImport(CapacitorLanceDB) || canImport(CapacitorLancedb) || canImport(LanceDBPlugin)
4
+ public final class MemoryProviderImpl: MemoryProvider {
5
+ public static func makeIfAvailable() -> MemoryProvider? {
6
+ guard LanceDBBridge.shared.getOrCreateHandle() != nil else {
7
+ return nil
8
+ }
9
+ return MemoryProviderImpl()
10
+ }
11
+
12
+ public func store(key: String, text: String, metadataJson: String?) -> String {
13
+ guard let handle = LanceDBBridge.shared.getOrCreateHandle() else {
14
+ return errorJson("Memory provider not configured")
15
+ }
16
+
17
+ let resolvedKey = key.isEmpty
18
+ ? "mem-\(Int(Date().timeIntervalSince1970 * 1000))-\(UUID().uuidString.prefix(8))"
19
+ : key
20
+ let embedding = localHashEmbed(text, dim: Int(LanceDBBridge.embeddingDim))
21
+
22
+ do {
23
+ try LanceDBBridge.awaitResult {
24
+ try await handle.store(
25
+ key: resolvedKey,
26
+ agentId: Self.defaultAgentId,
27
+ text: text,
28
+ embedding: embedding,
29
+ metadata: metadataJson
30
+ )
31
+ }
32
+ return jsonString([
33
+ "success": true,
34
+ "key": resolvedKey,
35
+ ])
36
+ } catch {
37
+ return errorJson(error.localizedDescription)
38
+ }
39
+ }
40
+
41
+ public func recall(query: String, limit: UInt32) -> String {
42
+ guard let handle = LanceDBBridge.shared.getOrCreateHandle() else {
43
+ return errorJson("Memory provider not configured")
44
+ }
45
+
46
+ let embedding = localHashEmbed(query, dim: Int(LanceDBBridge.embeddingDim))
47
+
48
+ do {
49
+ let results = try LanceDBBridge.awaitResult {
50
+ try await handle.search(
51
+ queryVector: embedding,
52
+ limit: limit,
53
+ filter: "agent_id = '\(Self.defaultAgentId)'"
54
+ )
55
+ }
56
+ return jsonString(results.map { result in
57
+ var object: [String: Any] = [
58
+ "key": result.key,
59
+ "text": result.text,
60
+ "score": result.score,
61
+ ]
62
+ if let metadata = result.metadata {
63
+ object["metadata"] = metadata
64
+ }
65
+ return object
66
+ })
67
+ } catch {
68
+ return errorJson(error.localizedDescription)
69
+ }
70
+ }
71
+
72
+ public func forget(key: String) -> String {
73
+ guard let handle = LanceDBBridge.shared.getOrCreateHandle() else {
74
+ return errorJson("Memory provider not configured")
75
+ }
76
+ guard !key.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
77
+ return errorJson("Provide query or key.")
78
+ }
79
+
80
+ do {
81
+ try LanceDBBridge.awaitResult {
82
+ try await handle.delete(key: key)
83
+ }
84
+ return jsonString([
85
+ "success": true,
86
+ "key": key,
87
+ ])
88
+ } catch {
89
+ return errorJson(error.localizedDescription)
90
+ }
91
+ }
92
+
93
+ public func search(query: String, maxResults: UInt32) -> String {
94
+ guard let handle = LanceDBBridge.shared.getOrCreateHandle() else {
95
+ return errorJson("Memory provider not configured")
96
+ }
97
+
98
+ let embedding = localHashEmbed(query, dim: Int(LanceDBBridge.embeddingDim))
99
+
100
+ do {
101
+ let results = try LanceDBBridge.awaitResult {
102
+ try await handle.search(
103
+ queryVector: embedding,
104
+ limit: maxResults,
105
+ filter: "agent_id = '\(Self.defaultAgentId)'"
106
+ )
107
+ }
108
+ return jsonString(results.map { result in
109
+ var object: [String: Any] = [
110
+ "key": result.key,
111
+ "text": result.text,
112
+ "score": result.score,
113
+ ]
114
+ if let metadata = result.metadata {
115
+ object["metadata"] = metadata
116
+ }
117
+ return object
118
+ })
119
+ } catch {
120
+ return errorJson(error.localizedDescription)
121
+ }
122
+ }
123
+
124
+ public func list(prefix: String?, limit: UInt32?) -> String {
125
+ guard let handle = LanceDBBridge.shared.getOrCreateHandle() else {
126
+ return errorJson("Memory provider not configured")
127
+ }
128
+
129
+ do {
130
+ let keys = try LanceDBBridge.awaitResult {
131
+ try await handle.list(prefix: prefix, limit: limit)
132
+ }
133
+ return jsonString(keys)
134
+ } catch {
135
+ return errorJson(error.localizedDescription)
136
+ }
137
+ }
138
+
139
+ private static let defaultAgentId = "main"
140
+ private static let whitespace = CharacterSet.whitespacesAndNewlines
141
+ private static let posixLocale = Locale(identifier: "en_US_POSIX")
142
+ private static let fnvOffset: UInt32 = 0x811c9dc5
143
+ private static let fnvPrime: UInt32 = 0x01000193
144
+ private static let goldenRatio: UInt32 = 2654435761
145
+ private static let mixConstant: UInt32 = 0x45d9f3b
146
+ private static let uintMaxDouble = Double(UInt32.max)
147
+
148
+ private func jsonString(_ value: Any) -> String {
149
+ guard JSONSerialization.isValidJSONObject(value),
150
+ let data = try? JSONSerialization.data(withJSONObject: value),
151
+ let string = String(data: data, encoding: .utf8) else {
152
+ return "{\"error\":\"Failed to encode JSON\"}"
153
+ }
154
+ return string
155
+ }
156
+
157
+ private func errorJson(_ message: String) -> String {
158
+ let escaped = message
159
+ .replacingOccurrences(of: "\\", with: "\\\\")
160
+ .replacingOccurrences(of: "\"", with: "\\\"")
161
+ return "{\"error\":\"\(escaped)\"}"
162
+ }
163
+
164
+ private func fnv1a(_ text: String) -> UInt32 {
165
+ var hash = Self.fnvOffset
166
+ for scalar in text.unicodeScalars {
167
+ hash ^= UInt32(scalar.value)
168
+ hash = hash &* Self.fnvPrime
169
+ }
170
+ return hash
171
+ }
172
+
173
+ private func seededRandom(seed: UInt32, dim: Int) -> Float {
174
+ var h = seed ^ (UInt32(dim) &* Self.goldenRatio)
175
+ h = ((h >> 16) ^ h) &* Self.mixConstant
176
+ h = ((h >> 16) ^ h) &* Self.mixConstant
177
+ h = (h >> 16) ^ h
178
+ return Float((Double(h) / Self.uintMaxDouble) * 2.0 - 1.0)
179
+ }
180
+
181
+ private func localHashEmbed(_ text: String, dim: Int) -> [Float] {
182
+ let tokens = text
183
+ .lowercased(with: Self.posixLocale)
184
+ .components(separatedBy: Self.whitespace)
185
+ .filter { !$0.isEmpty }
186
+ var vector = Array(repeating: 0.0, count: dim)
187
+
188
+ for token in tokens {
189
+ let hash = fnv1a(token)
190
+ for index in 0..<dim {
191
+ vector[index] += Double(seededRandom(seed: hash, dim: index))
192
+ }
193
+ }
194
+
195
+ let norm = sqrt(vector.reduce(0.0) { $0 + ($1 * $1) })
196
+ let divisor = norm > 0 ? norm : 1
197
+ return vector.map { Float($0 / divisor) }
198
+ }
199
+ }
200
+ #else
201
+ public final class MemoryProviderImpl {
202
+ public static func makeIfAvailable() -> MemoryProvider? {
203
+ nil
204
+ }
205
+ }
206
+ #endif
@@ -153,6 +153,9 @@ public class NativeAgentPlugin: CAPPlugin, CAPBridgedPlugin {
153
153
  let h = try NativeAgentHandle(config: config)
154
154
  try h.setEventCallback(callback: NativeAgentEventBridge(plugin: self))
155
155
  try h.setNotifier(notifier: NativeNotifierImpl())
156
+ if let memoryProvider = MemoryProviderImpl.makeIfAvailable() {
157
+ try h.setMemoryProvider(provider: memoryProvider)
158
+ }
156
159
  try h.persistConfig()
157
160
  self.handle = h
158
161
  UserDefaults.standard.set(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-native-agent",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
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",
@@ -56,7 +56,13 @@
56
56
  "url": "https://github.com/ArcadeLabsInc/capacitor-native-agent/issues"
57
57
  },
58
58
  "peerDependencies": {
59
- "@capacitor/core": "^6.0.0 || ^7.0.0 || ^8.0.0"
59
+ "@capacitor/core": "^6.0.0 || ^7.0.0 || ^8.0.0",
60
+ "capacitor-lancedb": "^0.2.0"
61
+ },
62
+ "peerDependenciesMeta": {
63
+ "capacitor-lancedb": {
64
+ "optional": true
65
+ }
60
66
  },
61
67
  "devDependencies": {
62
68
  "@capacitor/core": "^8.1.0",