@capgo/capacitor-llm 8.0.19 → 8.1.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/CapgoCapacitorLlm.podspec +1 -9
- package/Package.swift +21 -3
- package/README.md +137 -163
- package/android/build.gradle +3 -2
- package/android/src/main/java/ee/forgr/capgo_llm/LLM.java +605 -283
- package/android/src/main/java/ee/forgr/capgo_llm/LLMPlugin.java +36 -63
- package/dist/docs.json +66 -35
- package/dist/esm/definitions.d.ts +28 -20
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +6 -0
- package/dist/esm/web.js +68 -39
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +68 -39
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +68 -39
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/LLMPlugin/LLMPlugin.swift +384 -613
- package/ios/Sources/LiteRTLM/Benchmark.swift +83 -0
- package/ios/Sources/LiteRTLM/Capabilities.swift +41 -0
- package/ios/Sources/LiteRTLM/Config.swift +172 -0
- package/ios/Sources/LiteRTLM/Conversation.swift +472 -0
- package/ios/Sources/LiteRTLM/Engine.swift +208 -0
- package/ios/Sources/LiteRTLM/ExperimentalFlags.swift +142 -0
- package/ios/Sources/LiteRTLM/LiteRTLMError.swift +156 -0
- package/ios/Sources/LiteRTLM/Message.swift +225 -0
- package/ios/Sources/LiteRTLM/Tool.swift +291 -0
- package/ios/Sources/LiteRTLM/ToolManager.swift +152 -0
- package/package.json +6 -5
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Copyright 2026 Google LLC
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import Foundation
|
|
16
|
+
import OSLog
|
|
17
|
+
import CLiteRTLM
|
|
18
|
+
|
|
19
|
+
/// Data struct to hold benchmark information. Note that this is an experimental API and may change
|
|
20
|
+
/// in the future.
|
|
21
|
+
public struct BenchmarkInfo {
|
|
22
|
+
/// The time in seconds to initialize the engine and the conversation.
|
|
23
|
+
public let initTimeInSecond: Double
|
|
24
|
+
|
|
25
|
+
/// The time in seconds to the first token.
|
|
26
|
+
public let timeToFirstTokenInSecond: Double
|
|
27
|
+
|
|
28
|
+
/// The number of tokens in the last prefill turn.
|
|
29
|
+
public let lastPrefillTokenCount: Int
|
|
30
|
+
|
|
31
|
+
/// The number of tokens in the last decode turn.
|
|
32
|
+
public let lastDecodeTokenCount: Int
|
|
33
|
+
|
|
34
|
+
/// The number of tokens processed per second in the last prefill.
|
|
35
|
+
public let lastPrefillTokensPerSecond: Double
|
|
36
|
+
|
|
37
|
+
/// The number of tokens processed per second in the last decode.
|
|
38
|
+
public let lastDecodeTokensPerSecond: Double
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// Runs a benchmark on the LiteRT-LM engine.
|
|
42
|
+
///
|
|
43
|
+
/// **Note:** This function can take a significant amount of time depending on the model size,
|
|
44
|
+
/// device hardware, and the number of prefill and decode tokens. It is strongly recommended to
|
|
45
|
+
/// call this method on a background thread to avoid blocking the main thread.
|
|
46
|
+
///
|
|
47
|
+
/// - Parameters:
|
|
48
|
+
/// - modelPath: The path to the model file.
|
|
49
|
+
/// - backend: The backend to use for the engine.
|
|
50
|
+
/// - prefillTokens: The number of tokens to prefill.
|
|
51
|
+
/// - decodeTokens: The number of tokens to decode.
|
|
52
|
+
/// - cacheDir: The directory for placing cache files. Set to ":nocache" to disable caching.
|
|
53
|
+
/// - Returns: The benchmark info.
|
|
54
|
+
/// - Throws: A `LiteRTLMError` if the engine fails to initialize or generate benchmark info.
|
|
55
|
+
public func benchmark(
|
|
56
|
+
modelPath: String,
|
|
57
|
+
backend: Backend,
|
|
58
|
+
prefillTokens: Int = 256,
|
|
59
|
+
decodeTokens: Int = 256,
|
|
60
|
+
cacheDir: String? = nil
|
|
61
|
+
) async throws -> BenchmarkInfo {
|
|
62
|
+
ExperimentalFlags.optIntoExperimentalAPIs()
|
|
63
|
+
|
|
64
|
+
// temporarily enable benchmark flag so that Conversation API correctly passes checks later
|
|
65
|
+
let previousBenchmarkFlag = ExperimentalFlags.enableBenchmark
|
|
66
|
+
ExperimentalFlags.enableBenchmark = true
|
|
67
|
+
defer {
|
|
68
|
+
ExperimentalFlags.enableBenchmark = previousBenchmarkFlag
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let engineConfig = try EngineConfig(
|
|
72
|
+
modelPath: modelPath,
|
|
73
|
+
backend: backend,
|
|
74
|
+
maxNumTokens: max(prefillTokens, decodeTokens) + 32,
|
|
75
|
+
cacheDir: cacheDir
|
|
76
|
+
)
|
|
77
|
+
let engine = Engine(engineConfig: engineConfig)
|
|
78
|
+
try await engine.initializeForBenchmark(prefillTokens: prefillTokens, decodeTokens: decodeTokens)
|
|
79
|
+
|
|
80
|
+
let conversation = try await engine.createConversation()
|
|
81
|
+
_ = try await conversation.sendMessage(Message("Engine ignore this message in this mode."))
|
|
82
|
+
return try conversation.getBenchmarkInfo()
|
|
83
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Copyright 2026 Google LLC
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import Foundation
|
|
16
|
+
import CLiteRTLM
|
|
17
|
+
|
|
18
|
+
/// Provides information about capabilities and features supported by a LiteRT-LM file.
|
|
19
|
+
public class Capabilities {
|
|
20
|
+
private let handle: OpaquePointer?
|
|
21
|
+
|
|
22
|
+
/// Loads a LiteRT-LM file from the given path.
|
|
23
|
+
/// Returns nil if the file cannot be opened.
|
|
24
|
+
public init?(modelPath: String) {
|
|
25
|
+
guard let handle = litert_lm_loaded_file_create(modelPath) else {
|
|
26
|
+
return nil
|
|
27
|
+
}
|
|
28
|
+
self.handle = handle
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/// Checks if the loaded LiteRT-LM file supports speculative decoding.
|
|
32
|
+
public func hasSpeculativeDecodingSupport() -> Bool {
|
|
33
|
+
return litert_lm_loaded_file_has_speculative_decoding_support(handle)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
deinit {
|
|
37
|
+
if let handle = handle {
|
|
38
|
+
litert_lm_loaded_file_delete(handle)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// Copyright 2026 Google LLC
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import Foundation
|
|
16
|
+
|
|
17
|
+
/// The backend to use for the LiteRT-LM engine.
|
|
18
|
+
///
|
|
19
|
+
/// Swift version of the C++'s `litert::lm::Backend`.
|
|
20
|
+
public enum Backend: Equatable {
|
|
21
|
+
/// CPU LiteRT backend.
|
|
22
|
+
case cpu(threadCount: Int? = nil)
|
|
23
|
+
/// GPU LiteRT backend.
|
|
24
|
+
case gpu
|
|
25
|
+
|
|
26
|
+
public var rawValue: String {
|
|
27
|
+
switch self {
|
|
28
|
+
case .cpu: return "cpu"
|
|
29
|
+
case .gpu: return "gpu"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public init?(rawValue: String) {
|
|
34
|
+
switch rawValue {
|
|
35
|
+
case "cpu": self = .cpu()
|
|
36
|
+
case "gpu": self = .gpu
|
|
37
|
+
default: return nil
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// Configuration for the LiteRT-LM engine.
|
|
43
|
+
public struct EngineConfig {
|
|
44
|
+
/// The file path to the LiteRT-LM model.
|
|
45
|
+
public let modelPath: String
|
|
46
|
+
/// The backend to use for the engine.
|
|
47
|
+
public let backend: Backend
|
|
48
|
+
/// The backend to use for the vision executor. If `nil`, vision executor will
|
|
49
|
+
/// not be initialized.
|
|
50
|
+
public let visionBackend: Backend?
|
|
51
|
+
/// The backend to use for the audio executor. If `nil`, audio executor will
|
|
52
|
+
/// not be initialized.
|
|
53
|
+
public let audioBackend: Backend?
|
|
54
|
+
/// The maximum number of the sum of input and output tokens. It is equivalent
|
|
55
|
+
/// to the size of the kv-cache. When `nil`, use the default value from the model or the engine.
|
|
56
|
+
public let maxNumTokens: Int?
|
|
57
|
+
/// The directory for placing cache files. It should be a directory where the
|
|
58
|
+
/// application has write access. If `nil`, it uses the directory of the `modelPath`.
|
|
59
|
+
public let cacheDir: String?
|
|
60
|
+
|
|
61
|
+
/// - Parameters:
|
|
62
|
+
/// - modelPath: The file path to the LiteRT-LM model.
|
|
63
|
+
/// - backend: The backend to use for the engine.
|
|
64
|
+
/// - visionBackend: The backend to use for the vision executor. If `nil`, vision executor
|
|
65
|
+
/// will not be initialized.
|
|
66
|
+
/// - audioBackend: The backend to use for the audio executor. If `nil`, audio executor will
|
|
67
|
+
/// not be initialized.
|
|
68
|
+
/// - maxNumTokens: The maximum number of the sum of input and output tokens. It is
|
|
69
|
+
/// equivalent to the size of the kv-cache. When `nil`, use the default value from the
|
|
70
|
+
/// model or the engine.
|
|
71
|
+
/// - cacheDir: The directory for placing cache files. It should be a directory where the
|
|
72
|
+
/// application has write access. If `nil`, it uses the directory of the `modelPath`.
|
|
73
|
+
/// - Throws: `LiteRTLMError` if `maxNumTokens` is less than or equal to 0.
|
|
74
|
+
public init(
|
|
75
|
+
modelPath: String, backend: Backend = .cpu(), visionBackend: Backend? = nil,
|
|
76
|
+
audioBackend: Backend? = nil,
|
|
77
|
+
maxNumTokens: Int? = nil,
|
|
78
|
+
cacheDir: String? = nil
|
|
79
|
+
) throws {
|
|
80
|
+
if let maxNumTokens, maxNumTokens <= 0 {
|
|
81
|
+
throw LiteRTLMError.config(.invalidMaxNumTokens)
|
|
82
|
+
}
|
|
83
|
+
self.modelPath = modelPath
|
|
84
|
+
self.backend = backend
|
|
85
|
+
self.visionBackend = visionBackend
|
|
86
|
+
self.audioBackend = audioBackend
|
|
87
|
+
self.maxNumTokens = maxNumTokens
|
|
88
|
+
self.cacheDir = cacheDir
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// Configuration for the sampling process.
|
|
93
|
+
public struct SamplerConfig {
|
|
94
|
+
|
|
95
|
+
/// The number of most likely tokens (top logits) to consider at each step of sampling.
|
|
96
|
+
public let topK: Int
|
|
97
|
+
|
|
98
|
+
/// The cumulative probability threshold for nucleus sampling.
|
|
99
|
+
public let topP: Float
|
|
100
|
+
|
|
101
|
+
/// The temperature to use for sampling.
|
|
102
|
+
public let temperature: Float
|
|
103
|
+
|
|
104
|
+
/// The seed to use for randomization. Default to 0 (same default as engine code).
|
|
105
|
+
public let seed: Int
|
|
106
|
+
|
|
107
|
+
/// - Parameters:
|
|
108
|
+
/// - topK: The number of most likely tokens (top logits) to consider at each step of sampling.
|
|
109
|
+
/// - topP: The cumulative probability threshold for nucleus sampling.
|
|
110
|
+
/// - temperature: The temperature to use for sampling.
|
|
111
|
+
/// - seed: The seed to use for randomization. Default to 0 (same default as engine code).
|
|
112
|
+
/// - Throws: `LiteRTLMError` if `topK` is less than or equal to 0, `topP` is not in [0, 1], or
|
|
113
|
+
/// `temperature` is less than 0.
|
|
114
|
+
public init(
|
|
115
|
+
topK: Int,
|
|
116
|
+
topP: Float,
|
|
117
|
+
temperature: Float,
|
|
118
|
+
seed: Int = 0
|
|
119
|
+
) throws {
|
|
120
|
+
if topK <= 0 {
|
|
121
|
+
throw LiteRTLMError.config(.invalidTopK)
|
|
122
|
+
}
|
|
123
|
+
if topP < 0 || topP > 1 {
|
|
124
|
+
throw LiteRTLMError.config(.invalidTopP)
|
|
125
|
+
}
|
|
126
|
+
if temperature < 0 {
|
|
127
|
+
throw LiteRTLMError.config(.invalidTemperature)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
self.topK = topK
|
|
131
|
+
self.topP = topP
|
|
132
|
+
self.temperature = temperature
|
|
133
|
+
self.seed = seed
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/// Configuration fo the LiteRT-LM `Conversation`.
|
|
138
|
+
public struct ConversationConfig {
|
|
139
|
+
// The system message to be used in the conversation.
|
|
140
|
+
public let systemMessage: Message?
|
|
141
|
+
|
|
142
|
+
// The initial messages to populate the conversation history.
|
|
143
|
+
public let initialMessages: [Message]
|
|
144
|
+
|
|
145
|
+
// The list of tool instances to be used in the conversation.
|
|
146
|
+
public let tools: [Tool]
|
|
147
|
+
|
|
148
|
+
// Configuration for the sampling process.
|
|
149
|
+
// If `nil`, then uses the engine's default values.
|
|
150
|
+
public let samplerConfig: SamplerConfig?
|
|
151
|
+
|
|
152
|
+
/// - Parameters:
|
|
153
|
+
/// - systemMessage: The system message to be used in the conversation.
|
|
154
|
+
/// - initialMessages: The initial messages to populate the conversation history.
|
|
155
|
+
/// - tools: The list of tool instances to be used in the conversation.
|
|
156
|
+
/// - samplerConfig: Configuration for the sampling process. If `nil`, then uses the engine's
|
|
157
|
+
/// default values.
|
|
158
|
+
public init(
|
|
159
|
+
systemMessage: Message? = nil,
|
|
160
|
+
initialMessages: [Message] = [],
|
|
161
|
+
tools: [Tool] = [],
|
|
162
|
+
samplerConfig: SamplerConfig? = nil
|
|
163
|
+
) {
|
|
164
|
+
self.systemMessage = systemMessage.map { msg in
|
|
165
|
+
msg.role == .system
|
|
166
|
+
? msg : Message(contents: msg.contents, role: .system, channels: msg.channels)
|
|
167
|
+
}
|
|
168
|
+
self.initialMessages = initialMessages
|
|
169
|
+
self.tools = tools
|
|
170
|
+
self.samplerConfig = samplerConfig
|
|
171
|
+
}
|
|
172
|
+
}
|