Add Ed Swift package

Co-Authored-By: siGit Code <noreply@sigit.si>

Seto Elkahfi committed Sep 9, 2026 at 23:11 UTC 9dd887472e1ec0620f18e0897f94ceb6001f84f0
15 files changed +4473 -1
.gitignore new
+8
@@ -0,0 +1,8 @@
1 +.DS_Store
2 +.build/
3 +.local/
4 +build/
5 +DerivedData/
6 +EdFramework.xcframework/
7 +Examples/EdExample/*.xcodeproj/
8 +*.xcresult
Examples/EdExample/ChatViewModel.swift new
+107
@@ -0,0 +1,107 @@
1 +import Ed
2 +import Foundation
3 +import UIKit
4 +
5 +@MainActor
6 +final class ChatViewModel: ObservableObject {
7 + @Published var input = "What is my battery level?"
8 + @Published var transcript = ""
9 + @Published var status = "Not loaded"
10 + @Published var isLoaded = false
11 + @Published var isBusy = false
12 + @Published var showApproval = false
13 + @Published var approvalSummary = ""
14 +
15 + private let notes = NotesStore()
16 + private lazy var agent = EdAgent { [weak self] call in
17 + guard let self else { return .deny }
18 + return await self.requestApproval(for: call)
19 + }
20 + private var approvalContinuation: CheckedContinuation<EdApprovalDecision, Never>?
21 +
22 + func load() async {
23 + isBusy = true
24 + defer { isBusy = false }
25 + do {
26 + try await agent.register(BatteryTool())
27 + try await agent.register(SaveNoteTool(notes: notes))
28 + _ = try await agent.loadDefaultAgentModel(
29 + systemPrompt: "You are a concise assistant inside an iOS app. Use tools when useful."
30 + )
31 + isLoaded = true
32 + status = "Ready"
33 + } catch {
34 + status = "Load failed: \(error.localizedDescription)"
35 + }
36 + }
37 +
38 + func send() async {
39 + let message = input
40 + input = ""
41 + isBusy = true
42 + defer { isBusy = false }
43 + do {
44 + let reply = try await agent.run(message)
45 + transcript += "You: \(message)\n\nEd: \(reply.text)\n\n"
46 + status = "Finished in \(reply.duration) with \(reply.toolRounds) tool round(s)"
47 + } catch {
48 + status = "Turn failed: \(error.localizedDescription)"
49 + }
50 + }
51 +
52 + func resolveApproval(_ decision: EdApprovalDecision) {
53 + showApproval = false
54 + approvalContinuation?.resume(returning: decision)
55 + approvalContinuation = nil
56 + }
57 +
58 + private func requestApproval(for call: EdToolCall) async -> EdApprovalDecision {
59 + approvalSummary = "\(call.name) wants to run with: \(call.arguments)"
60 + showApproval = true
61 + return await withCheckedContinuation { continuation in
62 + approvalContinuation = continuation
63 + }
64 + }
65 +}
66 +
67 +private struct BatteryTool: EdTool {
68 + let definition = EdToolDefinition.readOnly(
69 + name: "battery_level",
70 + description: "Read the device battery percentage",
71 + parametersSchema: #"{"type":"object","properties":{},"additionalProperties":false}"#
72 + )
73 +
74 + func execute(arguments: String) async throws -> String {
75 + await MainActor.run {
76 + UIDevice.current.isBatteryMonitoringEnabled = true
77 + let level = UIDevice.current.batteryLevel
78 + return level < 0 ? "Battery level is unavailable." : "Battery is at \(Int(level * 100)) percent."
79 + }
80 + }
81 +}
82 +
83 +private actor NotesStore {
84 + private var notes: [String] = []
85 +
86 + func save(_ note: String) -> Int {
87 + notes.append(note)
88 + return notes.count
89 + }
90 +}
91 +
92 +private struct SaveNoteTool: EdTool {
93 + struct Arguments: Decodable { let text: String }
94 +
95 + let notes: NotesStore
96 + let definition = EdToolDefinition.mutating(
97 + name: "save_note",
98 + description: "Save a note in the app",
99 + parametersSchema: #"{"type":"object","properties":{"text":{"type":"string"}},"required":["text"],"additionalProperties":false}"#
100 + )
101 +
102 + func execute(arguments: String) async throws -> String {
103 + let decoded = try JSONDecoder().decode(Arguments.self, from: Data(arguments.utf8))
104 + let count = await notes.save(decoded.text)
105 + return "Saved note number \(count)."
106 + }
107 +}
Examples/EdExample/ContentView.swift new
+50
@@ -0,0 +1,50 @@
1 +import Ed
2 +import SwiftUI
3 +
4 +struct ContentView: View {
5 + @StateObject private var model = ChatViewModel()
6 +
7 + var body: some View {
8 + NavigationStack {
9 + VStack(spacing: 16) {
10 + ScrollView {
11 + Text(model.transcript.isEmpty ? "Load Ed, then ask about the battery or save a note." : model.transcript)
12 + .frame(maxWidth: .infinity, alignment: .leading)
13 + }
14 +
15 + TextField("Message Ed", text: $model.input)
16 + .textFieldStyle(.roundedBorder)
17 +
18 + HStack {
19 + Button(model.isLoaded ? "Loaded" : "Load Ed") {
20 + Task { await model.load() }
21 + }
22 + .disabled(model.isBusy || model.isLoaded)
23 +
24 + Button("Send") {
25 + Task { await model.send() }
26 + }
27 + .buttonStyle(.borderedProminent)
28 + .disabled(model.isBusy || !model.isLoaded || model.input.isEmpty)
29 + }
30 +
31 + Text(model.status)
32 + .font(.caption)
33 + .foregroundStyle(.secondary)
34 + }
35 + .padding()
36 + .navigationTitle("Ed")
37 + .confirmationDialog(
38 + "Allow Ed to change app data?",
39 + isPresented: $model.showApproval,
40 + titleVisibility: .visible
41 + ) {
42 + Button("Allow once") { model.resolveApproval(.allowOnce) }
43 + Button("Allow for this session") { model.resolveApproval(.allowForSession) }
44 + Button("Deny", role: .cancel) { model.resolveApproval(.deny) }
45 + } message: {
46 + Text(model.approvalSummary)
47 + }
48 + }
49 + }
50 +}
Examples/EdExample/EdExampleApp.swift new
+10
@@ -0,0 +1,10 @@
1 +import SwiftUI
2 +
3 +@main
4 +struct EdExampleApp: App {
5 + var body: some Scene {
6 + WindowGroup {
7 + ContentView()
8 + }
9 + }
10 +}
Examples/EdExample/README.md new
+9
@@ -0,0 +1,9 @@
1 +# EdExample
2 +
3 +1. Run `make ios` from the repository root.
4 +2. Install XcodeGen if needed (`brew install xcodegen`).
5 +3. Run `xcodegen generate` in this directory.
6 +4. Open `EdExample.xcodeproj` and run on an arm64 simulator or device.
7 +
8 +The battery tool is read-only and runs automatically. The note tool is
9 +mutating, so Ed pauses and asks the user before Swift executes it.
Examples/EdExample/project.yml new
+32
@@ -0,0 +1,32 @@
1 +name: EdExample
2 +options:
3 + bundleIdPrefix: com.ondeinference
4 + deploymentTarget:
5 + iOS: "16.0"
6 + xcodeVersion: "16.0"
7 +
8 +packages:
9 + Ed:
10 + path: ../..
11 +
12 +targets:
13 + EdExample:
14 + type: application
15 + platform: iOS
16 + sources:
17 + - path: .
18 + excludes:
19 + - project.yml
20 + - "*.xcodeproj"
21 + dependencies:
22 + - package: Ed
23 + product: Ed
24 + settings:
25 + base:
26 + PRODUCT_BUNDLE_IDENTIFIER: com.ondeinference.EdExample
27 + GENERATE_INFOPLIST_FILE: YES
28 + INFOPLIST_KEY_CFBundleDisplayName: Ed Example
29 + INFOPLIST_KEY_UIApplicationSceneManifest_Generation: YES
30 + INFOPLIST_KEY_UILaunchScreen_Generation: YES
31 + SWIFT_VERSION: "6.0"
32 + "EXCLUDED_ARCHS[sdk=iphonesimulator*]": x86_64
LICENSE-APACHE new
+202
@@ -0,0 +1,202 @@
1 +
2 + Apache License
3 + Version 2.0, January 2004
4 + http://www.apache.org/licenses/
5 +
6 + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 +
8 + 1. Definitions.
9 +
10 + "License" shall mean the terms and conditions for use, reproduction,
11 + and distribution as defined by Sections 1 through 9 of this document.
12 +
13 + "Licensor" shall mean the copyright owner or entity authorized by
14 + the copyright owner that is granting the License.
15 +
16 + "Legal Entity" shall mean the union of the acting entity and all
17 + other entities that control, are controlled by, or are under common
18 + control with that entity. For the purposes of this definition,
19 + "control" means (i) the power, direct or indirect, to cause the
20 + direction or management of such entity, whether by contract or
21 + otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 + outstanding shares, or (iii) beneficial ownership of such entity.
23 +
24 + "You" (or "Your") shall mean an individual or Legal Entity
25 + exercising permissions granted by this License.
26 +
27 + "Source" form shall mean the preferred form for making modifications,
28 + including but not limited to software source code, documentation
29 + source, and configuration files.
30 +
31 + "Object" form shall mean any form resulting from mechanical
32 + transformation or translation of a Source form, including but
33 + not limited to compiled object code, generated documentation,
34 + and conversions to other media types.
35 +
36 + "Work" shall mean the work of authorship, whether in Source or
37 + Object form, made available under the License, as indicated by a
38 + copyright notice that is included in or attached to the work
39 + (an example is provided in the Appendix below).
40 +
41 + "Derivative Works" shall mean any work, whether in Source or Object
42 + form, that is based on (or derived from) the Work and for which the
43 + editorial revisions, annotations, elaborations, or other modifications
44 + represent, as a whole, an original work of authorship. For the purposes
45 + of this License, Derivative Works shall not include works that remain
46 + separable from, or merely link (or bind by name) to the interfaces of,
47 + the Work and Derivative Works thereof.
48 +
49 + "Contribution" shall mean any work of authorship, including
50 + the original version of the Work and any modifications or additions
51 + to that Work or Derivative Works thereof, that is intentionally
52 + submitted to Licensor for inclusion in the Work by the copyright owner
53 + or by an individual or Legal Entity authorized to submit on behalf of
54 + the copyright owner. For the purposes of this definition, "submitted"
55 + means any form of electronic, verbal, or written communication sent
56 + to the Licensor or its representatives, including but not limited to
57 + communication on electronic mailing lists, source code control systems,
58 + and issue tracking systems that are managed by, or on behalf of, the
59 + Licensor for the purpose of discussing and improving the Work, but
60 + excluding communication that is conspicuously marked or otherwise
61 + designated in writing by the copyright owner as "Not a Contribution."
62 +
63 + "Contributor" shall mean Licensor and any individual or Legal Entity
64 + on behalf of whom a Contribution has been received by Licensor and
65 + subsequently incorporated within the Work.
66 +
67 + 2. Grant of Copyright License. Subject to the terms and conditions of
68 + this License, each Contributor hereby grants to You a perpetual,
69 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 + copyright license to reproduce, prepare Derivative Works of,
71 + publicly display, publicly perform, sublicense, and distribute the
72 + Work and such Derivative Works in Source or Object form.
73 +
74 + 3. Grant of Patent License. Subject to the terms and conditions of
75 + this License, each Contributor hereby grants to You a perpetual,
76 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 + (except as stated in this section) patent license to make, have made,
78 + use, offer to sell, sell, import, and otherwise transfer the Work,
79 + where such license applies only to those patent claims licensable
80 + by such Contributor that are necessarily infringed by their
81 + Contribution(s) alone or by combination of their Contribution(s)
82 + with the Work to which such Contribution(s) was submitted. If You
83 + institute patent litigation against any entity (including a
84 + cross-claim or counterclaim in a lawsuit) alleging that the Work
85 + or a Contribution incorporated within the Work constitutes direct
86 + or contributory patent infringement, then any patent licenses
87 + granted to You under this License for that Work shall terminate
88 + as of the date such litigation is filed.
89 +
90 + 4. Redistribution. You may reproduce and distribute copies of the
91 + Work or Derivative Works thereof in any medium, with or without
92 + modifications, and in Source or Object form, provided that You
93 + meet the following conditions:
94 +
95 + (a) You must give any other recipients of the Work or
96 + Derivative Works a copy of this License; and
97 +
98 + (b) You must cause any modified files to carry prominent notices
99 + stating that You changed the files; and
100 +
101 + (c) You must retain, in the Source form of any Derivative Works
102 + that You distribute, all copyright, patent, trademark, and
103 + attribution notices from the Source form of the Work,
104 + excluding those notices that do not pertain to any part of
105 + the Derivative Works; and
106 +
107 + (d) If the Work includes a "NOTICE" text file as part of its
108 + distribution, then any Derivative Works that You distribute must
109 + include a readable copy of the attribution notices contained
110 + within such NOTICE file, excluding those notices that do not
111 + pertain to any part of the Derivative Works, in at least one
112 + of the following places: within a NOTICE text file distributed
113 + as part of the Derivative Works; within the Source form or
114 + documentation, if provided along with the Derivative Works; or,
115 + within a display generated by the Derivative Works, if and
116 + wherever such third-party notices normally appear. The contents
117 + of the NOTICE file are for informational purposes only and
118 + do not modify the License. You may add Your own attribution
119 + notices within Derivative Works that You distribute, alongside
120 + or as an addendum to the NOTICE text from the Work, provided
121 + that such additional attribution notices cannot be construed
122 + as modifying the License.
123 +
124 + You may add Your own copyright statement to Your modifications and
125 + may provide additional or different license terms and conditions
126 + for use, reproduction, or distribution of Your modifications, or
127 + for any such Derivative Works as a whole, provided Your use,
128 + reproduction, and distribution of the Work otherwise complies with
129 + the conditions stated in this License.
130 +
131 + 5. Submission of Contributions. Unless You explicitly state otherwise,
132 + any Contribution intentionally submitted for inclusion in the Work
133 + by You to the Licensor shall be under the terms and conditions of
134 + this License, without any additional terms or conditions.
135 + Notwithstanding the above, nothing herein shall supersede or modify
136 + the terms of any separate license agreement you may have executed
137 + with Licensor regarding such Contributions.
138 +
139 + 6. Trademarks. This License does not grant permission to use the trade
140 + names, trademarks, service marks, or product names of the Licensor,
141 + except as required for reasonable and customary use in describing the
142 + origin of the Work and reproducing the content of the NOTICE file.
143 +
144 + 7. Disclaimer of Warranty. Unless required by applicable law or
145 + agreed to in writing, Licensor provides the Work (and each
146 + Contributor provides its Contributions) on an "AS IS" BASIS,
147 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 + implied, including, without limitation, any warranties or conditions
149 + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 + PARTICULAR PURPOSE. You are solely responsible for determining the
151 + appropriateness of using or redistributing the Work and assume any
152 + risks associated with Your exercise of permissions under this License.
153 +
154 + 8. Limitation of Liability. In no event and under no legal theory,
155 + whether in tort (including negligence), contract, or otherwise,
156 + unless required by applicable law (such as deliberate and grossly
157 + negligent acts) or agreed to in writing, shall any Contributor be
158 + liable to You for damages, including any direct, indirect, special,
159 + incidental, or consequential damages of any character arising as a
160 + result of this License or out of the use or inability to use the
161 + Work (including but not limited to damages for loss of goodwill,
162 + work stoppage, computer failure or malfunction, or any and all
163 + other commercial damages or losses), even if such Contributor
164 + has been advised of the possibility of such damages.
165 +
166 + 9. Accepting Warranty or Additional Liability. While redistributing
167 + the Work or Derivative Works thereof, You may choose to offer,
168 + and charge a fee for, acceptance of support, warranty, indemnity,
169 + or other liability obligations and/or rights consistent with this
170 + License. However, in accepting such obligations, You may act only
171 + on Your own behalf and on Your sole responsibility, not on behalf
172 + of any other Contributor, and only if You agree to indemnify,
173 + defend, and hold each Contributor harmless for any liability
174 + incurred by, or claims asserted against, such Contributor by reason
175 + of your accepting any such warranty or additional liability.
176 +
177 + END OF TERMS AND CONDITIONS
178 +
179 + APPENDIX: How to apply the Apache License to your work.
180 +
181 + To apply the Apache License to your work, attach the following
182 + boilerplate notice, with the fields enclosed by brackets "[]"
183 + replaced with your own identifying information. (Don't include
184 + the brackets!) The text should be enclosed in the appropriate
185 + comment syntax for the file format. We also recommend that a
186 + file or class name and description of purpose be included on the
187 + same "printed page" as the copyright notice for easier
188 + identification within third-party archives.
189 +
190 + Copyright 2026 Splitfire AB (Onde Inference)
191 +
192 + Licensed under the Apache License, Version 2.0 (the "License");
193 + you may not use this file except in compliance with the License.
194 + You may obtain a copy of the License at
195 +
196 + http://www.apache.org/licenses/LICENSE-2.0
197 +
198 + Unless required by applicable law or agreed to in writing, software
199 + distributed under the License is distributed on an "AS IS" BASIS,
200 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 + See the License for the specific language governing permissions and
202 + limitations under the License.
LICENSE-MIT new
+21
@@ -0,0 +1,21 @@
1 +MIT License
2 +
3 +Copyright (c) 2026 Splitfire AB (Onde Inference)
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy
6 +of this software and associated documentation files (the "Software"), to deal
7 +in the Software without restriction, including without limitation the rights
8 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 +copies of the Software, and to permit persons to whom the Software is
10 +furnished to do so, subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in all
13 +copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 +SOFTWARE.
Makefile new
+92
@@ -0,0 +1,92 @@
1 +SHELL := /bin/sh
2 +
3 +SWIFT_REPO := $(CURDIR)
4 +ED_REPO ?= $(abspath ../onde-ed)
5 +MANIFEST := $(ED_REPO)/crates/ed-agent-ffi/Cargo.toml
6 +BINDGEN_MANIFEST := $(ED_REPO)/uniffi-bindgen/Cargo.toml
7 +BINDGEN := $(ED_REPO)/target/release/uniffi-bindgen
8 +APPLE_TARGET_DIR := $(ED_REPO)/target/apple
9 +
10 +IOS_DEPLOYMENT_TARGET ?= 16.0
11 +MACOS_DEPLOYMENT_TARGET ?= 14.0
12 +TVOS_DEPLOYMENT_TARGET ?= 16.0
13 +VISIONOS_DEPLOYMENT_TARGET ?= 1.0
14 +WATCHOS_DEPLOYMENT_TARGET ?= 9.0
15 +
16 +LOCAL_DIR := $(SWIFT_REPO)/.local
17 +GENERATED_DIR := $(LOCAL_DIR)/generated/Ed
18 +HEADERS_DIR := $(LOCAL_DIR)/Headers
19 +FRAMEWORK_DIR := $(SWIFT_REPO)/EdFramework.xcframework
20 +SWIFT_GLUE := $(SWIFT_REPO)/Sources/Ed/ed_agent_ffi.swift
21 +
22 +.PHONY: help ios macos tvos visionos watchos build-bindgen prepare generate-swift clean
23 +
24 +help:
25 + @printf '%s\n' \
26 + 'Ed Swift local builds' \
27 + '' \
28 + 'make ios | macos | tvos | visionos | watchos' \
29 + 'Set ED_REPO=/path/to/onde-ed when the repositories are not siblings.'
30 +
31 +validate:
32 + @test -f "$(MANIFEST)" || { echo "Could not find onde-ed at $(ED_REPO)"; exit 1; }
33 +
34 +build-bindgen: validate
35 + cargo build --manifest-path "$(BINDGEN_MANIFEST)" --release
36 +
37 +prepare:
38 + @rm -rf "$(FRAMEWORK_DIR)" "$(GENERATED_DIR)" "$(HEADERS_DIR)"
39 + @mkdir -p "$(GENERATED_DIR)" "$(HEADERS_DIR)"
40 +
41 +generate-swift:
42 + @test -n "$(BINDGEN_INPUT)" || { echo "BINDGEN_INPUT is required"; exit 1; }
43 + cd "$(ED_REPO)" && "$(BINDGEN)" generate "$(BINDGEN_INPUT)" --crate ed_agent_ffi --language swift --out-dir "$(GENERATED_DIR)"
44 + cp "$(GENERATED_DIR)/ed_agent_ffi.swift" "$(SWIFT_GLUE)"
45 + cp "$(GENERATED_DIR)/ed_agent_ffiFFI.h" "$(HEADERS_DIR)/ed_agent_ffiFFI.h"
46 + cp "$(GENERATED_DIR)/ed_agent_ffiFFI.modulemap" "$(HEADERS_DIR)/module.modulemap"
47 +
48 +ios: build-bindgen prepare
49 + IPHONEOS_DEPLOYMENT_TARGET=$(IOS_DEPLOYMENT_TARGET) cargo rustc --target-dir "$(APPLE_TARGET_DIR)" --manifest-path "$(MANIFEST)" --target aarch64-apple-ios --release --lib --crate-type staticlib
50 + IPHONEOS_DEPLOYMENT_TARGET=$(IOS_DEPLOYMENT_TARGET) cargo rustc --target-dir "$(APPLE_TARGET_DIR)" --manifest-path "$(MANIFEST)" --target aarch64-apple-ios-sim --release --lib --crate-type staticlib
51 + $(MAKE) generate-swift BINDGEN_INPUT="$(APPLE_TARGET_DIR)/aarch64-apple-ios/release/libed_agent_ffi.a"
52 + xcodebuild -create-xcframework \
53 + -library "$(APPLE_TARGET_DIR)/aarch64-apple-ios/release/libed_agent_ffi.a" -headers "$(HEADERS_DIR)" \
54 + -library "$(APPLE_TARGET_DIR)/aarch64-apple-ios-sim/release/libed_agent_ffi.a" -headers "$(HEADERS_DIR)" \
55 + -output "$(FRAMEWORK_DIR)"
56 +
57 +macos: build-bindgen prepare
58 + MACOSX_DEPLOYMENT_TARGET=$(MACOS_DEPLOYMENT_TARGET) cargo rustc --target-dir "$(APPLE_TARGET_DIR)" --manifest-path "$(MANIFEST)" --target aarch64-apple-darwin --release --lib --crate-type staticlib
59 + $(MAKE) generate-swift BINDGEN_INPUT="$(APPLE_TARGET_DIR)/aarch64-apple-darwin/release/libed_agent_ffi.a"
60 + xcodebuild -create-xcframework \
61 + -library "$(APPLE_TARGET_DIR)/aarch64-apple-darwin/release/libed_agent_ffi.a" -headers "$(HEADERS_DIR)" \
62 + -output "$(FRAMEWORK_DIR)"
63 +
64 +tvos: build-bindgen prepare
65 + TVOS_DEPLOYMENT_TARGET=$(TVOS_DEPLOYMENT_TARGET) cargo +nightly rustc -Z build-std --target-dir "$(APPLE_TARGET_DIR)" --manifest-path "$(MANIFEST)" --target aarch64-apple-tvos --release --lib --crate-type staticlib
66 + TVOS_DEPLOYMENT_TARGET=$(TVOS_DEPLOYMENT_TARGET) cargo +nightly rustc -Z build-std --target-dir "$(APPLE_TARGET_DIR)" --manifest-path "$(MANIFEST)" --target aarch64-apple-tvos-sim --release --lib --crate-type staticlib
67 + $(MAKE) generate-swift BINDGEN_INPUT="$(APPLE_TARGET_DIR)/aarch64-apple-tvos/release/libed_agent_ffi.a"
68 + xcodebuild -create-xcframework \
69 + -library "$(APPLE_TARGET_DIR)/aarch64-apple-tvos/release/libed_agent_ffi.a" -headers "$(HEADERS_DIR)" \
70 + -library "$(APPLE_TARGET_DIR)/aarch64-apple-tvos-sim/release/libed_agent_ffi.a" -headers "$(HEADERS_DIR)" \
71 + -output "$(FRAMEWORK_DIR)"
72 +
73 +visionos: build-bindgen prepare
74 + XROS_DEPLOYMENT_TARGET=$(VISIONOS_DEPLOYMENT_TARGET) cargo +nightly rustc -Z build-std --target-dir "$(APPLE_TARGET_DIR)" --manifest-path "$(MANIFEST)" --target aarch64-apple-visionos --release --lib --crate-type staticlib
75 + XROS_DEPLOYMENT_TARGET=$(VISIONOS_DEPLOYMENT_TARGET) cargo +nightly rustc -Z build-std --target-dir "$(APPLE_TARGET_DIR)" --manifest-path "$(MANIFEST)" --target aarch64-apple-visionos-sim --release --lib --crate-type staticlib
76 + $(MAKE) generate-swift BINDGEN_INPUT="$(APPLE_TARGET_DIR)/aarch64-apple-visionos/release/libed_agent_ffi.a"
77 + xcodebuild -create-xcframework \
78 + -library "$(APPLE_TARGET_DIR)/aarch64-apple-visionos/release/libed_agent_ffi.a" -headers "$(HEADERS_DIR)" \
79 + -library "$(APPLE_TARGET_DIR)/aarch64-apple-visionos-sim/release/libed_agent_ffi.a" -headers "$(HEADERS_DIR)" \
80 + -output "$(FRAMEWORK_DIR)"
81 +
82 +watchos: build-bindgen prepare
83 + WATCHOS_DEPLOYMENT_TARGET=$(WATCHOS_DEPLOYMENT_TARGET) cargo +nightly rustc -Z build-std --target-dir "$(APPLE_TARGET_DIR)" --manifest-path "$(MANIFEST)" --target aarch64-apple-watchos --release --lib --crate-type staticlib
84 + WATCHOS_DEPLOYMENT_TARGET=$(WATCHOS_DEPLOYMENT_TARGET) cargo +nightly rustc -Z build-std --target-dir "$(APPLE_TARGET_DIR)" --manifest-path "$(MANIFEST)" --target aarch64-apple-watchos-sim --release --lib --crate-type staticlib
85 + $(MAKE) generate-swift BINDGEN_INPUT="$(APPLE_TARGET_DIR)/aarch64-apple-watchos/release/libed_agent_ffi.a"
86 + xcodebuild -create-xcframework \
87 + -library "$(APPLE_TARGET_DIR)/aarch64-apple-watchos/release/libed_agent_ffi.a" -headers "$(HEADERS_DIR)" \
88 + -library "$(APPLE_TARGET_DIR)/aarch64-apple-watchos-sim/release/libed_agent_ffi.a" -headers "$(HEADERS_DIR)" \
89 + -output "$(FRAMEWORK_DIR)"
90 +
91 +clean:
92 + rm -rf "$(FRAMEWORK_DIR)" "$(LOCAL_DIR)"
Package.swift new
+70
@@ -0,0 +1,70 @@
1 +// swift-tools-version:6.2
2 +import Foundation
3 +import PackageDescription
4 +
5 +let packageRoot = URL(fileURLWithPath: #filePath).deletingLastPathComponent()
6 +let localFrameworkPath = "EdFramework.xcframework"
7 +let localFrameworkAbsolutePath = packageRoot.appendingPathComponent(localFrameworkPath).path
8 +
9 +// Updated automatically by onde-ed's release-sdk-swift workflow.
10 +let releaseFrameworkURL =
11 + "https://github.com/ondeinference/onde-ed/releases/download/0.1.0/EdFramework.xcframework.zip"
12 +let releaseFrameworkChecksum =
13 + "0000000000000000000000000000000000000000000000000000000000000000"
14 +
15 +let edFrameworkTarget: Target
16 +if FileManager.default.fileExists(atPath: localFrameworkAbsolutePath) {
17 + edFrameworkTarget = .binaryTarget(
18 + name: "EdFramework",
19 + path: localFrameworkPath
20 + )
21 +} else {
22 + edFrameworkTarget = .binaryTarget(
23 + name: "EdFramework",
24 + url: releaseFrameworkURL,
25 + checksum: releaseFrameworkChecksum
26 + )
27 +}
28 +
29 +let package = Package(
30 + name: "Ed",
31 + platforms: [
32 + .iOS(.v16),
33 + .macOS(.v14),
34 + .tvOS(.v16),
35 + .visionOS(.v1),
36 + .watchOS(.v9),
37 + ],
38 + products: [
39 + .library(name: "Ed", targets: ["Ed"]),
40 + ],
41 + targets: [
42 + edFrameworkTarget,
43 + .target(
44 + name: "Ed",
45 + dependencies: [.target(name: "EdFramework")],
46 + path: "Sources/Ed",
47 + linkerSettings: [
48 + .linkedFramework("CoreFoundation"),
49 + .linkedFramework("Foundation"),
50 + .linkedFramework("IOKit", .when(platforms: [.macOS])),
51 + .linkedFramework("Metal"),
52 + .linkedFramework("Security"),
53 + .linkedFramework("SystemConfiguration"),
54 + .linkedLibrary("c++"),
55 + .linkedLibrary("iconv"),
56 + .linkedLibrary("resolv"),
57 + .linkedLibrary("z"),
58 + ]
59 + ),
60 + .testTarget(
61 + name: "EdTests",
62 + dependencies: ["Ed"],
63 + path: "Tests/EdTests"
64 + ),
65 + ],
66 + // UniFFI 0.31's generated async callback shim predates Swift 6's region
67 + // isolation checks. The hand-written Ed API remains concurrency-safe; the
68 + // generated bridge compiles in Swift 5 language mode until UniFFI updates.
69 + swiftLanguageModes: [.v5]
70 +)
README.md new
+116
@@ -0,0 +1,116 @@
1 +# Ed for Swift
2 +
3 +Ed is a private, on-device agent for Swift apps. Onde runs the language model;
4 +Ed gives that model a safe way to ask your app to do things.
5 +
6 +It runs on iPhone, iPad, Mac, Apple TV, Apple Vision Pro, and Apple Watch. Model
7 +input, conversation history, and tool results stay on the device unless a tool
8 +you write deliberately sends data elsewhere.
9 +
10 +## The mental model
11 +
12 +If you are new to agents, think of Ed as a loop:
13 +
14 +1. Your app sends a message to the model.
15 +2. The model either answers, or requests one of your registered tools.
16 +3. Ed checks the tool's risk level.
17 +4. Your Swift code runs the approved tool and returns text.
18 +5. The model reads that result and writes the final answer.
19 +
20 +The model cannot call arbitrary Swift APIs. It only sees tools your app
21 +registers.
22 +
23 +## Installation
24 +
25 +In Xcode, choose **File > Add Package Dependencies** and enter:
26 +
27 +```text
28 +https://github.com/ondeinference/onde-ed-swift
29 +```
30 +
31 +Then add the `Ed` product to your target and import it:
32 +
33 +```swift
34 +import Ed
35 +```
36 +
37 +## Quick start
38 +
39 +First, describe a tool and implement it. A JSON schema tells the model which
40 +arguments it may provide:
41 +
42 +```swift
43 +import Ed
44 +
45 +struct BatteryTool: EdTool {
46 + let definition = EdToolDefinition.readOnly(
47 + name: "battery_level",
48 + description: "Read the device battery percentage",
49 + parametersSchema: #"{"type":"object","properties":{}}"#
50 + )
51 +
52 + func execute(arguments: String) async throws -> String {
53 + // Read the real value from your platform API here.
54 + "The battery is at 73 percent."
55 + }
56 +}
57 +```
58 +
59 +Then create the agent, register the tool, and load the default model:
60 +
61 +```swift
62 +let ed = EdAgent { call in
63 + // This callback is used only for mutating tools.
64 + let userApproved = await showApproval(for: call)
65 + return userApproved ? .allowOnce : .deny
66 +}
67 +
68 +try await ed.register(BatteryTool())
69 +try await ed.loadDefaultAgentModel(
70 + systemPrompt: "You are a concise assistant inside my app."
71 +)
72 +
73 +let reply = try await ed.run("How much battery do I have?")
74 +print(reply.text)
75 +```
76 +
77 +Use `.readOnly` for tools that only inspect state. Use `.mutating` for tools
78 +that save, send, purchase, delete, unlock, or otherwise change something. Ed
79 +runs read-only tools automatically and sends every mutating call through your
80 +approval callback.
81 +
82 +Observe progress and tool activity with an async stream:
83 +
84 +```swift
85 +for await event in ed.events() {
86 + print(event)
87 +}
88 +```
89 +
90 +Cancelling the Swift task also cancels the active Ed turn:
91 +
92 +```swift
93 +let task = Task { try await ed.run("Do the task") }
94 +task.cancel()
95 +```
96 +
97 +See [`Examples/EdExample`](Examples/EdExample) for a complete SwiftUI example
98 +with a read-only device tool and an approval-gated mutating tool.
99 +
100 +## Local development
101 +
102 +Keep `onde`, `onde-ed`, and `onde-ed-swift` next to one another, then build a
103 +local framework before running Swift tests:
104 +
105 +```sh
106 +make macos
107 +swift test
108 +```
109 +
110 +Use `make ios`, `make tvos`, `make visionos`, or `make watchos` for another
111 +Apple platform. The package automatically uses `EdFramework.xcframework` when
112 +that local file exists. Without it, SwiftPM downloads the signed release asset.
113 +
114 +## Licence
115 +
116 +Ed is available under either the MIT License or Apache License 2.0.
Sources/Ed/EdAgent.swift new
+582
@@ -0,0 +1,582 @@
1 +import Foundation
2 +
3 +/// A capability your app makes available to the local model.
4 +///
5 +/// Ed never invents native capabilities. Your app registers each tool and
6 +/// remains responsible for executing it.
7 +public protocol EdTool: Sendable {
8 + var definition: EdToolDefinition { get }
9 +
10 + /// Executes the tool with the JSON object produced by the model.
11 + func execute(arguments: String) async throws -> String
12 +}
13 +
14 +public enum EdToolRisk: Sendable {
15 + /// Safe to run without asking, such as reading app state.
16 + case readOnly
17 +
18 + /// Changes state and must be approved first, such as saving or deleting.
19 + case mutating
20 +}
21 +
22 +public struct EdToolDefinition: Sendable {
23 + public let name: String
24 + public let description: String
25 + public let parametersSchema: String
26 + public let risk: EdToolRisk
27 +
28 + public init(
29 + name: String,
30 + description: String,
31 + parametersSchema: String,
32 + risk: EdToolRisk
33 + ) {
34 + self.name = name
35 + self.description = description
36 + self.parametersSchema = parametersSchema
37 + self.risk = risk
38 + }
39 +
40 + public static func readOnly(
41 + name: String,
42 + description: String,
43 + parametersSchema: String
44 + ) -> Self {
45 + Self(
46 + name: name,
47 + description: description,
48 + parametersSchema: parametersSchema,
49 + risk: .readOnly
50 + )
51 + }
52 +
53 + public static func mutating(
54 + name: String,
55 + description: String,
56 + parametersSchema: String
57 + ) -> Self {
58 + Self(
59 + name: name,
60 + description: description,
61 + parametersSchema: parametersSchema,
62 + risk: .mutating
63 + )
64 + }
65 +}
66 +
67 +public struct EdToolCall: Sendable, Equatable {
68 + public let id: String
69 + public let name: String
70 + public let arguments: String
71 +}
72 +
73 +public enum EdApprovalDecision: Sendable {
74 + case allowOnce
75 + case allowForSession
76 + case deny
77 +}
78 +
79 +public typealias EdApprovalHandler = @Sendable (EdToolCall) async -> EdApprovalDecision
80 +
81 +public struct EdAgentConfiguration: Sendable {
82 + public var maxToolRounds: UInt8
83 + public var maxToolOutputCharacters: UInt64
84 +
85 + public init(maxToolRounds: UInt8 = 8, maxToolOutputCharacters: UInt64 = 10_000) {
86 + self.maxToolRounds = maxToolRounds
87 + self.maxToolOutputCharacters = maxToolOutputCharacters
88 + }
89 +}
90 +
91 +public struct EdAgentReply: Sendable, Equatable {
92 + public let text: String
93 + public let durationSeconds: Double
94 + public let duration: String
95 + public let toolRounds: UInt8
96 +}
97 +
98 +public struct EdReply: Sendable, Equatable {
99 + public let text: String
100 + public let duration: String
101 +}
102 +
103 +public enum EdEngineStatus: Sendable {
104 + case unloaded
105 + case loading
106 + case ready
107 + case generating
108 + case error
109 +}
110 +
111 +public struct EdEngineInfo: Sendable {
112 + public let status: EdEngineStatus
113 + public let modelName: String?
114 + public let approximateMemory: String?
115 + public let historyLength: UInt64
116 +}
117 +
118 +public enum EdChatRole: Sendable {
119 + case system
120 + case user
121 + case assistant
122 +}
123 +
124 +public struct EdChatMessage: Sendable {
125 + public let role: EdChatRole
126 + public let content: String
127 +}
128 +
129 +public enum EdEvent: Sendable {
130 + case statusChanged(status: EdEngineStatus, modelName: String?, error: String?)
131 + case toolRequested(EdToolCall)
132 + case approvalRequested(EdToolCall)
133 + case toolStarted(EdToolCall)
134 + case toolFinished(callID: String, content: String, isError: Bool)
135 + case agentReplied(EdAgentReply)
136 + case warning(String)
137 +}
138 +
139 +public struct EdSamplingConfiguration: Sendable {
140 + public var temperature: Double?
141 + public var topP: Double?
142 + public var topK: UInt64?
143 + public var minP: Double?
144 + public var maxTokens: UInt64?
145 + public var frequencyPenalty: Float?
146 + public var presencePenalty: Float?
147 +
148 + public init(
149 + temperature: Double? = nil,
150 + topP: Double? = nil,
151 + topK: UInt64? = nil,
152 + minP: Double? = nil,
153 + maxTokens: UInt64? = nil,
154 + frequencyPenalty: Float? = nil,
155 + presencePenalty: Float? = nil
156 + ) {
157 + self.temperature = temperature
158 + self.topP = topP
159 + self.topK = topK
160 + self.minP = minP
161 + self.maxTokens = maxTokens
162 + self.frequencyPenalty = frequencyPenalty
163 + self.presencePenalty = presencePenalty
164 + }
165 +}
166 +
167 +public struct EdGGUFModelConfiguration: Sendable {
168 + public var modelID: String
169 + public var files: [String]
170 + public var tokenizerModelID: String?
171 + public var displayName: String
172 + public var approximateMemory: String
173 + public var chatTemplate: String?
174 +
175 + public init(
176 + modelID: String,
177 + files: [String],
178 + tokenizerModelID: String? = nil,
179 + displayName: String,
180 + approximateMemory: String,
181 + chatTemplate: String? = nil
182 + ) {
183 + self.modelID = modelID
184 + self.files = files
185 + self.tokenizerModelID = tokenizerModelID
186 + self.displayName = displayName
187 + self.approximateMemory = approximateMemory
188 + self.chatTemplate = chatTemplate
189 + }
190 +}
191 +
192 +public struct EdUQFFModelConfiguration: Sendable {
193 + public var modelID: String
194 + public var files: [String]
195 + public var displayName: String
196 + public var approximateMemory: String
197 + public var chatTemplate: String?
198 +
199 + public init(
200 + modelID: String,
201 + files: [String],
202 + displayName: String,
203 + approximateMemory: String,
204 + chatTemplate: String? = nil
205 + ) {
206 + self.modelID = modelID
207 + self.files = files
208 + self.displayName = displayName
209 + self.approximateMemory = approximateMemory
210 + self.chatTemplate = chatTemplate
211 + }
212 +}
213 +
214 +public enum EdEnvironment: Sendable {
215 + case development
216 + case production
217 +}
218 +
219 +/// A local agent powered by Onde.
220 +///
221 +/// The actor protects model history, the tool registry, and inference so your
222 +/// UI can call it safely from Swift concurrency.
223 +public actor EdAgent {
224 + private let core: FfiEdAgent
225 + private let tools: ToolDispatcher
226 + private let approvals: ApprovalAdapter
227 + private nonisolated let eventHub: EventHub
228 +
229 + public init(
230 + configuration: EdAgentConfiguration = .init(),
231 + approvalHandler: @escaping EdApprovalHandler = { _ in .deny }
232 + ) {
233 + let tools = ToolDispatcher()
234 + let approvals = ApprovalAdapter(handler: approvalHandler)
235 + let eventHub = EventHub()
236 +
237 + self.tools = tools
238 + self.approvals = approvals
239 + self.eventHub = eventHub
240 + self.core = FfiEdAgent(
241 + executor: tools,
242 + approvals: approvals,
243 + events: eventHub,
244 + config: FfiAgentConfig(
245 + maxToolRounds: configuration.maxToolRounds,
246 + maxToolOutputChars: configuration.maxToolOutputCharacters
247 + )
248 + )
249 + }
250 +
251 + /// A separate stream for each observer. Stop its task to unsubscribe.
252 + public nonisolated func events() -> AsyncStream<EdEvent> {
253 + eventHub.makeStream()
254 + }
255 +
256 + public func register(_ tool: any EdTool) async throws {
257 + try await core.registerTool(tool: tool.definition.ffi)
258 + tools.set(tool)
259 + }
260 +
261 + @discardableResult
262 + public func unregisterTool(named name: String) async -> Bool {
263 + let removed = await core.unregisterTool(name: name)
264 + if removed {
265 + tools.remove(named: name)
266 + }
267 + return removed
268 + }
269 +
270 + public func removeAllTools() async {
271 + await core.removeAllTools()
272 + tools.removeAll()
273 + }
274 +
275 + /// Runs the full agent loop: model -> tool calls -> tool results -> model.
276 + public func run(_ message: String) async throws -> EdAgentReply {
277 + try await withTaskCancellationHandler {
278 + try await core.run(message: message).swift
279 + } onCancel: {
280 + core.cancel()
281 + }
282 + }
283 +
284 + /// Sends one ordinary chat turn without exposing tools to the model.
285 + public func send(_ message: String) async throws -> EdReply {
286 + let reply = try await core.send(message: message)
287 + return EdReply(text: reply.text, duration: reply.duration)
288 + }
289 +
290 + /// Loads a small tool-capable model chosen for the current Apple device.
291 + @discardableResult
292 + public func loadDefaultAgentModel(systemPrompt: String? = nil) async throws -> Double {
293 + try await core.loadDefaultAgentModel(systemPrompt: systemPrompt)
294 + }
295 +
296 + @discardableResult
297 + public func load(
298 + gguf config: EdGGUFModelConfiguration,
299 + systemPrompt: String? = nil,
300 + sampling: EdSamplingConfiguration? = nil
301 + ) async throws -> Double {
302 + try await core.loadGgufModel(
303 + config: config.ffi,
304 + systemPrompt: systemPrompt,
305 + sampling: sampling?.ffi
306 + )
307 + }
308 +
309 + @discardableResult
310 + public func load(
311 + uqff config: EdUQFFModelConfiguration,
312 + systemPrompt: String? = nil,
313 + sampling: EdSamplingConfiguration? = nil
314 + ) async throws -> Double {
315 + try await core.loadUqffModel(
316 + config: config.ffi,
317 + systemPrompt: systemPrompt,
318 + sampling: sampling?.ffi
319 + )
320 + }
321 +
322 + @discardableResult
323 + public func loadAssignedModel(
324 + environment: EdEnvironment,
325 + appID: String,
326 + appSecret: String,
327 + systemPrompt: String? = nil,
328 + sampling: EdSamplingConfiguration? = nil
329 + ) async throws -> Double {
330 + try await core.loadAssignedModel(
331 + environment: environment.ffi,
332 + appId: appID,
333 + appSecret: appSecret,
334 + systemPrompt: systemPrompt,
335 + sampling: sampling?.ffi
336 + )
337 + }
338 +
339 + public nonisolated func cancel() {
340 + core.cancel()
341 + }
342 +
343 + @discardableResult
344 + public func unload() async -> String? {
345 + await core.unload()
346 + }
347 +
348 + public func isLoaded() async -> Bool {
349 + await core.isLoaded()
350 + }
351 +
352 + public func info() async -> EdEngineInfo {
353 + let info = await core.info()
354 + return EdEngineInfo(
355 + status: info.status.swift,
356 + modelName: info.modelName,
357 + approximateMemory: info.approxMemory,
358 + historyLength: info.historyLength
359 + )
360 + }
361 +
362 + public func history() async -> [EdChatMessage] {
363 + await core.history().map(\.swift)
364 + }
365 +
366 + @discardableResult
367 + public func clearHistory() async -> UInt64 {
368 + await core.clearHistory()
369 + }
370 +
371 + public static func configureCacheDirectory(_ url: URL) {
372 + configureCacheDir(path: url.path)
373 + }
374 +
375 + public static func defaultAgentModelConfiguration() -> EdGGUFModelConfiguration {
376 + defaultAgentModelConfig().swift
377 + }
378 +}
379 +
380 +private final class ToolDispatcher: FfiToolExecutor, @unchecked Sendable {
381 + private let lock = NSLock()
382 + private var tools: [String: any EdTool] = [:]
383 +
384 + func set(_ tool: any EdTool) {
385 + lock.withLock { tools[tool.definition.name] = tool }
386 + }
387 +
388 + func remove(named name: String) {
389 + lock.withLock { _ = tools.removeValue(forKey: name) }
390 + }
391 +
392 + func removeAll() {
393 + lock.withLock { tools.removeAll() }
394 + }
395 +
396 + func execute(toolName: String, arguments: String) async -> FfiToolOutput {
397 + let tool = lock.withLock { tools[toolName] }
398 + guard let tool else {
399 + return FfiToolOutput(content: "", error: "Unknown tool: \(toolName)")
400 + }
401 +
402 + do {
403 + return FfiToolOutput(
404 + content: try await tool.execute(arguments: arguments),
405 + error: nil
406 + )
407 + } catch {
408 + return FfiToolOutput(content: "", error: String(describing: error))
409 + }
410 + }
411 +}
412 +
413 +private final class ApprovalAdapter: FfiApprovalHandler, @unchecked Sendable {
414 + private let handler: EdApprovalHandler
415 +
416 + init(handler: @escaping EdApprovalHandler) {
417 + self.handler = handler
418 + }
419 +
420 + func approve(call: FfiToolCall) async -> FfiApprovalDecision {
421 + await handler(call.swift).ffi
422 + }
423 +}
424 +
425 +private final class EventHub: FfiEventListener, @unchecked Sendable {
426 + private let lock = NSLock()
427 + private var continuations: [UUID: AsyncStream<EdEvent>.Continuation] = [:]
428 +
429 + func makeStream() -> AsyncStream<EdEvent> {
430 + let id = UUID()
431 + return AsyncStream { continuation in
432 + lock.withLock { continuations[id] = continuation }
433 + continuation.onTermination = { [weak self] _ in
434 + self?.lock.withLock { _ = self?.continuations.removeValue(forKey: id) }
435 + }
436 + }
437 + }
438 +
439 + func statusChanged(update: FfiStatusUpdate) {
440 + emit(.statusChanged(
441 + status: update.status.swift,
442 + modelName: update.modelName,
443 + error: update.error
444 + ))
445 + }
446 +
447 + func toolRequested(call: FfiToolCall) { emit(.toolRequested(call.swift)) }
448 + func approvalRequested(call: FfiToolCall) { emit(.approvalRequested(call.swift)) }
449 + func toolStarted(call: FfiToolCall) { emit(.toolStarted(call.swift)) }
450 +
451 + func toolFinished(toolCallId: String, content: String, isError: Bool) {
452 + emit(.toolFinished(callID: toolCallId, content: content, isError: isError))
453 + }
454 +
455 + func agentReplied(reply: FfiAgentReply) { emit(.agentReplied(reply.swift)) }
456 + func warning(message: String) { emit(.warning(message)) }
457 +
458 + private func emit(_ event: EdEvent) {
459 + let current = lock.withLock { Array(continuations.values) }
460 + current.forEach { $0.yield(event) }
461 + }
462 +}
463 +
464 +private extension EdToolDefinition {
465 + var ffi: FfiToolDefinition {
466 + FfiToolDefinition(
467 + name: name,
468 + description: description,
469 + parametersSchema: parametersSchema,
470 + risk: risk == .readOnly ? .readOnly : .mutating
471 + )
472 + }
473 +}
474 +
475 +private extension FfiToolCall {
476 + var swift: EdToolCall { EdToolCall(id: id, name: name, arguments: arguments) }
477 +}
478 +
479 +private extension EdApprovalDecision {
480 + var ffi: FfiApprovalDecision {
481 + switch self {
482 + case .allowOnce: .allowOnce
483 + case .allowForSession: .allowForSession
484 + case .deny: .deny
485 + }
486 + }
487 +}
488 +
489 +private extension FfiAgentReply {
490 + var swift: EdAgentReply {
491 + EdAgentReply(
492 + text: text,
493 + durationSeconds: durationSeconds,
494 + duration: duration,
495 + toolRounds: toolRounds
496 + )
497 + }
498 +}
499 +
500 +private extension FfiEngineStatus {
501 + var swift: EdEngineStatus {
502 + switch self {
503 + case .unloaded: .unloaded
504 + case .loading: .loading
505 + case .ready: .ready
506 + case .generating: .generating
507 + case .error: .error
508 + }
509 + }
510 +}
511 +
512 +private extension FfiChatMessage {
513 + var swift: EdChatMessage {
514 + let role: EdChatRole = switch self.role {
515 + case .system: .system
516 + case .user: .user
517 + case .assistant: .assistant
518 + }
519 + return EdChatMessage(role: role, content: content)
520 + }
521 +}
522 +
523 +private extension EdSamplingConfiguration {
524 + var ffi: FfiSamplingConfig {
525 + FfiSamplingConfig(
526 + temperature: temperature,
527 + topP: topP,
528 + topK: topK,
529 + minP: minP,
530 + maxTokens: maxTokens,
531 + frequencyPenalty: frequencyPenalty,
532 + presencePenalty: presencePenalty
533 + )
534 + }
535 +}
536 +
537 +private extension EdGGUFModelConfiguration {
538 + var ffi: FfiGgufModelConfig {
539 + FfiGgufModelConfig(
540 + modelId: modelID,
541 + files: files,
542 + tokModelId: tokenizerModelID,
543 + displayName: displayName,
544 + approxMemory: approximateMemory,
545 + chatTemplate: chatTemplate
546 + )
547 + }
548 +}
549 +
550 +private extension FfiGgufModelConfig {
551 + var swift: EdGGUFModelConfiguration {
552 + EdGGUFModelConfiguration(
553 + modelID: modelId,
554 + files: files,
555 + tokenizerModelID: tokModelId,
556 + displayName: displayName,
557 + approximateMemory: approxMemory,
558 + chatTemplate: chatTemplate
559 + )
560 + }
561 +}
562 +
563 +private extension EdUQFFModelConfiguration {
564 + var ffi: FfiUqffModelConfig {
565 + FfiUqffModelConfig(
566 + modelId: modelID,
567 + files: files,
568 + displayName: displayName,
569 + approxMemory: approximateMemory,
570 + chatTemplate: chatTemplate
571 + )
572 + }
573 +}
574 +
575 +private extension EdEnvironment {
576 + var ffi: FfiEnvironment {
577 + switch self {
578 + case .development: .development
579 + case .production: .production
580 + }
581 + }
582 +}
Sources/Ed/ed_agent_ffi.swift new
+3155
@@ -0,0 +1,3155 @@
1 +// This file was autogenerated by some hot garbage in the `uniffi` crate.
2 +// Trust me, you don't want to mess with it!
3 +
4 +// swiftlint:disable all
5 +import Foundation
6 +
7 +// Depending on the consumer's build setup, the low-level FFI code
8 +// might be in a separate module, or it might be compiled inline into
9 +// this module. This is a bit of light hackery to work with both.
10 +#if canImport(ed_agent_ffiFFI)
11 +import ed_agent_ffiFFI
12 +#endif
13 +
14 +fileprivate extension RustBuffer {
15 + // Allocate a new buffer, copying the contents of a `UInt8` array.
16 + init(bytes: [UInt8]) {
17 + let rbuf = bytes.withUnsafeBufferPointer { ptr in
18 + RustBuffer.from(ptr)
19 + }
20 + self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data)
21 + }
22 +
23 + static func empty() -> RustBuffer {
24 + RustBuffer(capacity: 0, len:0, data: nil)
25 + }
26 +
27 + static func from(_ ptr: UnsafeBufferPointer<UInt8>) -> RustBuffer {
28 + try! rustCall { ffi_ed_agent_ffi_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) }
29 + }
30 +
31 + // Frees the buffer in place.
32 + // The buffer must not be used after this is called.
33 + func deallocate() {
34 + try! rustCall { ffi_ed_agent_ffi_rustbuffer_free(self, $0) }
35 + }
36 +}
37 +
38 +fileprivate extension ForeignBytes {
39 + init(bufferPointer: UnsafeBufferPointer<UInt8>) {
40 + self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress)
41 + }
42 +}
43 +
44 +// For every type used in the interface, we provide helper methods for conveniently
45 +// lifting and lowering that type from C-compatible data, and for reading and writing
46 +// values of that type in a buffer.
47 +
48 +// Helper classes/extensions that don't change.
49 +// Someday, this will be in a library of its own.
50 +
51 +fileprivate extension Data {
52 + init(rustBuffer: RustBuffer) {
53 + self.init(
54 + bytesNoCopy: rustBuffer.data!,
55 + count: Int(rustBuffer.len),
56 + deallocator: .none
57 + )
58 + }
59 +}
60 +
61 +// Define reader functionality. Normally this would be defined in a class or
62 +// struct, but we use standalone functions instead in order to make external
63 +// types work.
64 +//
65 +// With external types, one swift source file needs to be able to call the read
66 +// method on another source file's FfiConverter, but then what visibility
67 +// should Reader have?
68 +// - If Reader is fileprivate, then this means the read() must also
69 +// be fileprivate, which doesn't work with external types.
70 +// - If Reader is internal/public, we'll get compile errors since both source
71 +// files will try define the same type.
72 +//
73 +// Instead, the read() method and these helper functions input a tuple of data
74 +
75 +fileprivate func createReader(data: Data) -> (data: Data, offset: Data.Index) {
76 + (data: data, offset: 0)
77 +}
78 +
79 +// Reads an integer at the current offset, in big-endian order, and advances
80 +// the offset on success. Throws if reading the integer would move the
81 +// offset past the end of the buffer.
82 +fileprivate func readInt<T: FixedWidthInteger>(_ reader: inout (data: Data, offset: Data.Index)) throws -> T {
83 + let range = reader.offset..<reader.offset + MemoryLayout<T>.size
84 + guard reader.data.count >= range.upperBound else {
85 + throw UniffiInternalError.bufferOverflow
86 + }
87 + if T.self == UInt8.self {
88 + let value = reader.data[reader.offset]
89 + reader.offset += 1
90 + return value as! T
91 + }
92 + var value: T = 0
93 + let _ = withUnsafeMutableBytes(of: &value, { reader.data.copyBytes(to: $0, from: range)})
94 + reader.offset = range.upperBound
95 + return value.bigEndian
96 +}
97 +
98 +// Reads an arbitrary number of bytes, to be used to read
99 +// raw bytes, this is useful when lifting strings
100 +fileprivate func readBytes(_ reader: inout (data: Data, offset: Data.Index), count: Int) throws -> Array<UInt8> {
101 + let range = reader.offset..<(reader.offset+count)
102 + guard reader.data.count >= range.upperBound else {
103 + throw UniffiInternalError.bufferOverflow
104 + }
105 + var value = [UInt8](repeating: 0, count: count)
106 + value.withUnsafeMutableBufferPointer({ buffer in
107 + reader.data.copyBytes(to: buffer, from: range)
108 + })
109 + reader.offset = range.upperBound
110 + return value
111 +}
112 +
113 +// Reads a float at the current offset.
114 +fileprivate func readFloat(_ reader: inout (data: Data, offset: Data.Index)) throws -> Float {
115 + return Float(bitPattern: try readInt(&reader))
116 +}
117 +
118 +// Reads a float at the current offset.
119 +fileprivate func readDouble(_ reader: inout (data: Data, offset: Data.Index)) throws -> Double {
120 + return Double(bitPattern: try readInt(&reader))
121 +}
122 +
123 +// Indicates if the offset has reached the end of the buffer.
124 +fileprivate func hasRemaining(_ reader: (data: Data, offset: Data.Index)) -> Bool {
125 + return reader.offset < reader.data.count
126 +}
127 +
128 +// Define writer functionality. Normally this would be defined in a class or
129 +// struct, but we use standalone functions instead in order to make external
130 +// types work. See the above discussion on Readers for details.
131 +
132 +fileprivate func createWriter() -> [UInt8] {
133 + return []
134 +}
135 +
136 +fileprivate func writeBytes<S>(_ writer: inout [UInt8], _ byteArr: S) where S: Sequence, S.Element == UInt8 {
137 + writer.append(contentsOf: byteArr)
138 +}
139 +
140 +// Writes an integer in big-endian order.
141 +//
142 +// Warning: make sure what you are trying to write
143 +// is in the correct type!
144 +fileprivate func writeInt<T: FixedWidthInteger>(_ writer: inout [UInt8], _ value: T) {
145 + var value = value.bigEndian
146 + withUnsafeBytes(of: &value) { writer.append(contentsOf: $0) }
147 +}
148 +
149 +fileprivate func writeFloat(_ writer: inout [UInt8], _ value: Float) {
150 + writeInt(&writer, value.bitPattern)
151 +}
152 +
153 +fileprivate func writeDouble(_ writer: inout [UInt8], _ value: Double) {
154 + writeInt(&writer, value.bitPattern)
155 +}
156 +
157 +// Protocol for types that transfer other types across the FFI. This is
158 +// analogous to the Rust trait of the same name.
159 +fileprivate protocol FfiConverter {
160 + associatedtype FfiType
161 + associatedtype SwiftType
162 +
163 + static func lift(_ value: FfiType) throws -> SwiftType
164 + static func lower(_ value: SwiftType) -> FfiType
165 + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType
166 + static func write(_ value: SwiftType, into buf: inout [UInt8])
167 +}
168 +
169 +// Types conforming to `Primitive` pass themselves directly over the FFI.
170 +fileprivate protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType { }
171 +
172 +extension FfiConverterPrimitive {
173 +#if swift(>=5.8)
174 + @_documentation(visibility: private)
175 +#endif
176 + public static func lift(_ value: FfiType) throws -> SwiftType {
177 + return value
178 + }
179 +
180 +#if swift(>=5.8)
181 + @_documentation(visibility: private)
182 +#endif
183 + public static func lower(_ value: SwiftType) -> FfiType {
184 + return value
185 + }
186 +}
187 +
188 +// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`.
189 +// Used for complex types where it's hard to write a custom lift/lower.
190 +fileprivate protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {}
191 +
192 +extension FfiConverterRustBuffer {
193 +#if swift(>=5.8)
194 + @_documentation(visibility: private)
195 +#endif
196 + public static func lift(_ buf: RustBuffer) throws -> SwiftType {
197 + var reader = createReader(data: Data(rustBuffer: buf))
198 + let value = try read(from: &reader)
199 + if hasRemaining(reader) {
200 + throw UniffiInternalError.incompleteData
201 + }
202 + buf.deallocate()
203 + return value
204 + }
205 +
206 +#if swift(>=5.8)
207 + @_documentation(visibility: private)
208 +#endif
209 + public static func lower(_ value: SwiftType) -> RustBuffer {
210 + var writer = createWriter()
211 + write(value, into: &writer)
212 + return RustBuffer(bytes: writer)
213 + }
214 +}
215 +// An error type for FFI errors. These errors occur at the UniFFI level, not
216 +// the library level.
217 +fileprivate enum UniffiInternalError: LocalizedError {
218 + case bufferOverflow
219 + case incompleteData
220 + case unexpectedOptionalTag
221 + case unexpectedEnumCase
222 + case unexpectedNullPointer
223 + case unexpectedRustCallStatusCode
224 + case unexpectedRustCallError
225 + case unexpectedStaleHandle
226 + case rustPanic(_ message: String)
227 +
228 + public var errorDescription: String? {
229 + switch self {
230 + case .bufferOverflow: return "Reading the requested value would read past the end of the buffer"
231 + case .incompleteData: return "The buffer still has data after lifting its containing value"
232 + case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1"
233 + case .unexpectedEnumCase: return "Raw enum value doesn't match any cases"
234 + case .unexpectedNullPointer: return "Raw pointer value was null"
235 + case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code"
236 + case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified"
237 + case .unexpectedStaleHandle: return "The object in the handle map has been dropped already"
238 + case let .rustPanic(message): return message
239 + }
240 + }
241 +}
242 +
243 +fileprivate extension NSLock {
244 + func withLock<T>(f: () throws -> T) rethrows -> T {
245 + self.lock()
246 + defer { self.unlock() }
247 + return try f()
248 + }
249 +}
250 +
251 +fileprivate let CALL_SUCCESS: Int8 = 0
252 +fileprivate let CALL_ERROR: Int8 = 1
253 +fileprivate let CALL_UNEXPECTED_ERROR: Int8 = 2
254 +fileprivate let CALL_CANCELLED: Int8 = 3
255 +
256 +fileprivate extension RustCallStatus {
257 + init() {
258 + self.init(
259 + code: CALL_SUCCESS,
260 + errorBuf: RustBuffer.init(
261 + capacity: 0,
262 + len: 0,
263 + data: nil
264 + )
265 + )
266 + }
267 +}
268 +
269 +private func rustCall<T>(_ callback: (UnsafeMutablePointer<RustCallStatus>) -> T) throws -> T {
270 + let neverThrow: ((RustBuffer) throws -> Never)? = nil
271 + return try makeRustCall(callback, errorHandler: neverThrow)
272 +}
273 +
274 +private func rustCallWithError<T, E: Swift.Error>(
275 + _ errorHandler: @escaping (RustBuffer) throws -> E,
276 + _ callback: (UnsafeMutablePointer<RustCallStatus>) -> T) throws -> T {
277 + try makeRustCall(callback, errorHandler: errorHandler)
278 +}
279 +
280 +private func makeRustCall<T, E: Swift.Error>(
281 + _ callback: (UnsafeMutablePointer<RustCallStatus>) -> T,
282 + errorHandler: ((RustBuffer) throws -> E)?
283 +) throws -> T {
284 + uniffiEnsureEdAgentFfiInitialized()
285 + var callStatus = RustCallStatus.init()
286 + let returnedVal = callback(&callStatus)
287 + try uniffiCheckCallStatus(callStatus: callStatus, errorHandler: errorHandler)
288 + return returnedVal
289 +}
290 +
291 +private func uniffiCheckCallStatus<E: Swift.Error>(
292 + callStatus: RustCallStatus,
293 + errorHandler: ((RustBuffer) throws -> E)?
294 +) throws {
295 + switch callStatus.code {
296 + case CALL_SUCCESS:
297 + return
298 +
299 + case CALL_ERROR:
300 + if let errorHandler = errorHandler {
301 + throw try errorHandler(callStatus.errorBuf)
302 + } else {
303 + callStatus.errorBuf.deallocate()
304 + throw UniffiInternalError.unexpectedRustCallError
305 + }
306 +
307 + case CALL_UNEXPECTED_ERROR:
308 + // When the rust code sees a panic, it tries to construct a RustBuffer
309 + // with the message. But if that code panics, then it just sends back
310 + // an empty buffer.
311 + if callStatus.errorBuf.len > 0 {
312 + throw UniffiInternalError.rustPanic(try FfiConverterString.lift(callStatus.errorBuf))
313 + } else {
314 + callStatus.errorBuf.deallocate()
315 + throw UniffiInternalError.rustPanic("Rust panic")
316 + }
317 +
318 + case CALL_CANCELLED:
319 + fatalError("Cancellation not supported yet")
320 +
321 + default:
322 + throw UniffiInternalError.unexpectedRustCallStatusCode
323 + }
324 +}
325 +
326 +private func uniffiTraitInterfaceCall<T>(
327 + callStatus: UnsafeMutablePointer<RustCallStatus>,
328 + makeCall: () throws -> T,
329 + writeReturn: (T) -> ()
330 +) {
331 + do {
332 + try writeReturn(makeCall())
333 + } catch let error {
334 + callStatus.pointee.code = CALL_UNEXPECTED_ERROR
335 + callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error))
336 + }
337 +}
338 +
339 +private func uniffiTraitInterfaceCallWithError<T, E>(
340 + callStatus: UnsafeMutablePointer<RustCallStatus>,
341 + makeCall: () throws -> T,
342 + writeReturn: (T) -> (),
343 + lowerError: (E) -> RustBuffer
344 +) {
345 + do {
346 + try writeReturn(makeCall())
347 + } catch let error as E {
348 + callStatus.pointee.code = CALL_ERROR
349 + callStatus.pointee.errorBuf = lowerError(error)
350 + } catch {
351 + callStatus.pointee.code = CALL_UNEXPECTED_ERROR
352 + callStatus.pointee.errorBuf = FfiConverterString.lower(String(describing: error))
353 + }
354 +}
355 +// Initial value and increment amount for handles.
356 +// These ensure that SWIFT handles always have the lowest bit set
357 +fileprivate let UNIFFI_HANDLEMAP_INITIAL: UInt64 = 1
358 +fileprivate let UNIFFI_HANDLEMAP_DELTA: UInt64 = 2
359 +
360 +fileprivate final class UniffiHandleMap<T>: @unchecked Sendable {
361 + // All mutation happens with this lock held, which is why we implement @unchecked Sendable.
362 + private let lock = NSLock()
363 + private var map: [UInt64: T] = [:]
364 + private var currentHandle: UInt64 = UNIFFI_HANDLEMAP_INITIAL
365 +
366 + func insert(obj: T) -> UInt64 {
367 + lock.withLock {
368 + return doInsert(obj)
369 + }
370 + }
371 +
372 + // Low-level insert function, this assumes `lock` is held.
373 + private func doInsert(_ obj: T) -> UInt64 {
374 + let handle = currentHandle
375 + currentHandle += UNIFFI_HANDLEMAP_DELTA
376 + map[handle] = obj
377 + return handle
378 + }
379 +
380 + func get(handle: UInt64) throws -> T {
381 + try lock.withLock {
382 + guard let obj = map[handle] else {
383 + throw UniffiInternalError.unexpectedStaleHandle
384 + }
385 + return obj
386 + }
387 + }
388 +
389 + func clone(handle: UInt64) throws -> UInt64 {
390 + try lock.withLock {
391 + guard let obj = map[handle] else {
392 + throw UniffiInternalError.unexpectedStaleHandle
393 + }
394 + return doInsert(obj)
395 + }
396 + }
397 +
398 + @discardableResult
399 + func remove(handle: UInt64) throws -> T {
400 + try lock.withLock {
401 + guard let obj = map.removeValue(forKey: handle) else {
402 + throw UniffiInternalError.unexpectedStaleHandle
403 + }
404 + return obj
405 + }
406 + }
407 +
408 + var count: Int {
409 + get {
410 + map.count
411 + }
412 + }
413 +}
414 +
415 +
416 +// Public interface members begin here.
417 +// Magic number for the Rust proxy to call using the same mechanism as every other method,
418 +// to free the callback once it's dropped by Rust.
419 +private let IDX_CALLBACK_FREE: Int32 = 0
420 +// Callback return codes
421 +private let UNIFFI_CALLBACK_SUCCESS: Int32 = 0
422 +private let UNIFFI_CALLBACK_ERROR: Int32 = 1
423 +private let UNIFFI_CALLBACK_UNEXPECTED_ERROR: Int32 = 2
424 +
425 +#if swift(>=5.8)
426 +@_documentation(visibility: private)
427 +#endif
428 +fileprivate struct FfiConverterUInt8: FfiConverterPrimitive {
429 + typealias FfiType = UInt8
430 + typealias SwiftType = UInt8
431 +
432 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt8 {
433 + return try lift(readInt(&buf))
434 + }
435 +
436 + public static func write(_ value: UInt8, into buf: inout [UInt8]) {
437 + writeInt(&buf, lower(value))
438 + }
439 +}
440 +
441 +#if swift(>=5.8)
442 +@_documentation(visibility: private)
443 +#endif
444 +fileprivate struct FfiConverterUInt64: FfiConverterPrimitive {
445 + typealias FfiType = UInt64
446 + typealias SwiftType = UInt64
447 +
448 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> UInt64 {
449 + return try lift(readInt(&buf))
450 + }
451 +
452 + public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
453 + writeInt(&buf, lower(value))
454 + }
455 +}
456 +
457 +#if swift(>=5.8)
458 +@_documentation(visibility: private)
459 +#endif
460 +fileprivate struct FfiConverterFloat: FfiConverterPrimitive {
461 + typealias FfiType = Float
462 + typealias SwiftType = Float
463 +
464 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Float {
465 + return try lift(readFloat(&buf))
466 + }
467 +
468 + public static func write(_ value: Float, into buf: inout [UInt8]) {
469 + writeFloat(&buf, lower(value))
470 + }
471 +}
472 +
473 +#if swift(>=5.8)
474 +@_documentation(visibility: private)
475 +#endif
476 +fileprivate struct FfiConverterDouble: FfiConverterPrimitive {
477 + typealias FfiType = Double
478 + typealias SwiftType = Double
479 +
480 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Double {
481 + return try lift(readDouble(&buf))
482 + }
483 +
484 + public static func write(_ value: Double, into buf: inout [UInt8]) {
485 + writeDouble(&buf, lower(value))
486 + }
487 +}
488 +
489 +#if swift(>=5.8)
490 +@_documentation(visibility: private)
491 +#endif
492 +fileprivate struct FfiConverterBool : FfiConverter {
493 + typealias FfiType = Int8
494 + typealias SwiftType = Bool
495 +
496 + public static func lift(_ value: Int8) throws -> Bool {
497 + return value != 0
498 + }
499 +
500 + public static func lower(_ value: Bool) -> Int8 {
501 + return value ? 1 : 0
502 + }
503 +
504 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> Bool {
505 + return try lift(readInt(&buf))
506 + }
507 +
508 + public static func write(_ value: Bool, into buf: inout [UInt8]) {
509 + writeInt(&buf, lower(value))
510 + }
511 +}
512 +
513 +#if swift(>=5.8)
514 +@_documentation(visibility: private)
515 +#endif
516 +fileprivate struct FfiConverterString: FfiConverter {
517 + typealias SwiftType = String
518 + typealias FfiType = RustBuffer
519 +
520 + public static func lift(_ value: RustBuffer) throws -> String {
521 + defer {
522 + value.deallocate()
523 + }
524 + if value.data == nil {
525 + return String()
526 + }
527 + let bytes = UnsafeBufferPointer<UInt8>(start: value.data!, count: Int(value.len))
528 + return String(bytes: bytes, encoding: String.Encoding.utf8)!
529 + }
530 +
531 + public static func lower(_ value: String) -> RustBuffer {
532 + return value.utf8CString.withUnsafeBufferPointer { ptr in
533 + // The swift string gives us int8_t, we want uint8_t.
534 + ptr.withMemoryRebound(to: UInt8.self) { ptr in
535 + // The swift string gives us a trailing null byte, we don't want it.
536 + let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1))
537 + return RustBuffer.from(buf)
538 + }
539 + }
540 + }
541 +
542 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> String {
543 + let len: Int32 = try readInt(&buf)
544 + return String(bytes: try readBytes(&buf, count: Int(len)), encoding: String.Encoding.utf8)!
545 + }
546 +
547 + public static func write(_ value: String, into buf: inout [UInt8]) {
548 + let len = Int32(value.utf8.count)
549 + writeInt(&buf, len)
550 + writeBytes(&buf, value.utf8)
551 + }
552 +}
553 +
554 +
555 +
556 +
557 +public protocol FfiEdAgentProtocol: AnyObject, Sendable {
558 +
559 + func cancel()
560 +
561 + func clearHistory() async -> UInt64
562 +
563 + func history() async -> [FfiChatMessage]
564 +
565 + func info() async -> FfiEngineInfo
566 +
567 + func isLoaded() async -> Bool
568 +
569 + func loadAssignedModel(environment: FfiEnvironment, appId: String, appSecret: String, systemPrompt: String?, sampling: FfiSamplingConfig?) async throws -> Double
570 +
571 + func loadDefaultAgentModel(systemPrompt: String?) async throws -> Double
572 +
573 + func loadGgufModel(config: FfiGgufModelConfig, systemPrompt: String?, sampling: FfiSamplingConfig?) async throws -> Double
574 +
575 + func loadUqffModel(config: FfiUqffModelConfig, systemPrompt: String?, sampling: FfiSamplingConfig?) async throws -> Double
576 +
577 + func registerTool(tool: FfiToolDefinition) async throws
578 +
579 + func removeAllTools() async
580 +
581 + func run(message: String) async throws -> FfiAgentReply
582 +
583 + func send(message: String) async throws -> FfiReply
584 +
585 + func unload() async -> String?
586 +
587 + func unregisterTool(name: String) async -> Bool
588 +
589 +}
590 +open class FfiEdAgent: FfiEdAgentProtocol, @unchecked Sendable {
591 + fileprivate let handle: UInt64
592 +
593 + /// Used to instantiate a [FFIObject] without an actual handle, for fakes in tests, mostly.
594 +#if swift(>=5.8)
595 + @_documentation(visibility: private)
596 +#endif
597 + public struct NoHandle {
598 + public init() {}
599 + }
600 +
601 + // TODO: We'd like this to be `private` but for Swifty reasons,
602 + // we can't implement `FfiConverter` without making this `required` and we can't
603 + // make it `required` without making it `public`.
604 +#if swift(>=5.8)
605 + @_documentation(visibility: private)
606 +#endif
607 + required public init(unsafeFromHandle handle: UInt64) {
608 + self.handle = handle
609 + }
610 +
611 + // This constructor can be used to instantiate a fake object.
612 + // - Parameter noHandle: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject].
613 + //
614 + // - Warning:
615 + // Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing handle the FFI lower functions will crash.
616 +#if swift(>=5.8)
617 + @_documentation(visibility: private)
618 +#endif
619 + public init(noHandle: NoHandle) {
620 + self.handle = 0
621 + }
622 +
623 +#if swift(>=5.8)
624 + @_documentation(visibility: private)
625 +#endif
626 + public func uniffiCloneHandle() -> UInt64 {
627 + return try! rustCall { uniffi_ed_agent_ffi_fn_clone_ffiedagent(self.handle, $0) }
628 + }
629 +public convenience init(executor: FfiToolExecutor, approvals: FfiApprovalHandler, events: FfiEventListener, config: FfiAgentConfig?) {
630 + let handle =
631 + try! rustCall() {
632 + uniffi_ed_agent_ffi_fn_constructor_ffiedagent_new(
633 + FfiConverterCallbackInterfaceFfiToolExecutor_lower(executor),
634 + FfiConverterCallbackInterfaceFfiApprovalHandler_lower(approvals),
635 + FfiConverterCallbackInterfaceFfiEventListener_lower(events),
636 + FfiConverterOptionTypeFfiAgentConfig.lower(config),$0
637 + )
638 +}
639 + self.init(unsafeFromHandle: handle)
640 +}
641 +
642 + deinit {
643 + if handle == 0 {
644 + // Mock objects have handle=0 don't try to free them
645 + return
646 + }
647 +
648 + try! rustCall { uniffi_ed_agent_ffi_fn_free_ffiedagent(handle, $0) }
649 + }
650 +
651 +
652 +
653 +
654 +open func cancel() {try! rustCall() {
655 + uniffi_ed_agent_ffi_fn_method_ffiedagent_cancel(
656 + self.uniffiCloneHandle(),$0
657 + )
658 +}
659 +}
660 +
661 +open func clearHistory()async -> UInt64 {
662 + return
663 + try! await uniffiRustCallAsync(
664 + rustFutureFunc: {
665 + uniffi_ed_agent_ffi_fn_method_ffiedagent_clear_history(
666 + self.uniffiCloneHandle()
667 +
668 + )
669 + },
670 + pollFunc: ffi_ed_agent_ffi_rust_future_poll_u64,
671 + completeFunc: ffi_ed_agent_ffi_rust_future_complete_u64,
672 + freeFunc: ffi_ed_agent_ffi_rust_future_free_u64,
673 + liftFunc: FfiConverterUInt64.lift,
674 + errorHandler: nil
675 +
676 + )
677 +}
678 +
679 +open func history()async -> [FfiChatMessage] {
680 + return
681 + try! await uniffiRustCallAsync(
682 + rustFutureFunc: {
683 + uniffi_ed_agent_ffi_fn_method_ffiedagent_history(
684 + self.uniffiCloneHandle()
685 +
686 + )
687 + },
688 + pollFunc: ffi_ed_agent_ffi_rust_future_poll_rust_buffer,
689 + completeFunc: ffi_ed_agent_ffi_rust_future_complete_rust_buffer,
690 + freeFunc: ffi_ed_agent_ffi_rust_future_free_rust_buffer,
691 + liftFunc: FfiConverterSequenceTypeFfiChatMessage.lift,
692 + errorHandler: nil
693 +
694 + )
695 +}
696 +
697 +open func info()async -> FfiEngineInfo {
698 + return
699 + try! await uniffiRustCallAsync(
700 + rustFutureFunc: {
701 + uniffi_ed_agent_ffi_fn_method_ffiedagent_info(
702 + self.uniffiCloneHandle()
703 +
704 + )
705 + },
706 + pollFunc: ffi_ed_agent_ffi_rust_future_poll_rust_buffer,
707 + completeFunc: ffi_ed_agent_ffi_rust_future_complete_rust_buffer,
708 + freeFunc: ffi_ed_agent_ffi_rust_future_free_rust_buffer,
709 + liftFunc: FfiConverterTypeFfiEngineInfo_lift,
710 + errorHandler: nil
711 +
712 + )
713 +}
714 +
715 +open func isLoaded()async -> Bool {
716 + return
717 + try! await uniffiRustCallAsync(
718 + rustFutureFunc: {
719 + uniffi_ed_agent_ffi_fn_method_ffiedagent_is_loaded(
720 + self.uniffiCloneHandle()
721 +
722 + )
723 + },
724 + pollFunc: ffi_ed_agent_ffi_rust_future_poll_i8,
725 + completeFunc: ffi_ed_agent_ffi_rust_future_complete_i8,
726 + freeFunc: ffi_ed_agent_ffi_rust_future_free_i8,
727 + liftFunc: FfiConverterBool.lift,
728 + errorHandler: nil
729 +
730 + )
731 +}
732 +
733 +open func loadAssignedModel(environment: FfiEnvironment, appId: String, appSecret: String, systemPrompt: String?, sampling: FfiSamplingConfig?)async throws -> Double {
734 + return
735 + try await uniffiRustCallAsync(
736 + rustFutureFunc: {
737 + uniffi_ed_agent_ffi_fn_method_ffiedagent_load_assigned_model(
738 + self.uniffiCloneHandle(),
739 + FfiConverterTypeFfiEnvironment_lower(environment),FfiConverterString.lower(appId),FfiConverterString.lower(appSecret),FfiConverterOptionString.lower(systemPrompt),FfiConverterOptionTypeFfiSamplingConfig.lower(sampling)
740 + )
741 + },
742 + pollFunc: ffi_ed_agent_ffi_rust_future_poll_f64,
743 + completeFunc: ffi_ed_agent_ffi_rust_future_complete_f64,
744 + freeFunc: ffi_ed_agent_ffi_rust_future_free_f64,
745 + liftFunc: FfiConverterDouble.lift,
746 + errorHandler: FfiConverterTypeFfiEdError_lift
747 + )
748 +}
749 +
750 +open func loadDefaultAgentModel(systemPrompt: String?)async throws -> Double {
751 + return
752 + try await uniffiRustCallAsync(
753 + rustFutureFunc: {
754 + uniffi_ed_agent_ffi_fn_method_ffiedagent_load_default_agent_model(
755 + self.uniffiCloneHandle(),
756 + FfiConverterOptionString.lower(systemPrompt)
757 + )
758 + },
759 + pollFunc: ffi_ed_agent_ffi_rust_future_poll_f64,
760 + completeFunc: ffi_ed_agent_ffi_rust_future_complete_f64,
761 + freeFunc: ffi_ed_agent_ffi_rust_future_free_f64,
762 + liftFunc: FfiConverterDouble.lift,
763 + errorHandler: FfiConverterTypeFfiEdError_lift
764 + )
765 +}
766 +
767 +open func loadGgufModel(config: FfiGgufModelConfig, systemPrompt: String?, sampling: FfiSamplingConfig?)async throws -> Double {
768 + return
769 + try await uniffiRustCallAsync(
770 + rustFutureFunc: {
771 + uniffi_ed_agent_ffi_fn_method_ffiedagent_load_gguf_model(
772 + self.uniffiCloneHandle(),
773 + FfiConverterTypeFfiGgufModelConfig_lower(config),FfiConverterOptionString.lower(systemPrompt),FfiConverterOptionTypeFfiSamplingConfig.lower(sampling)
774 + )
775 + },
776 + pollFunc: ffi_ed_agent_ffi_rust_future_poll_f64,
777 + completeFunc: ffi_ed_agent_ffi_rust_future_complete_f64,
778 + freeFunc: ffi_ed_agent_ffi_rust_future_free_f64,
779 + liftFunc: FfiConverterDouble.lift,
780 + errorHandler: FfiConverterTypeFfiEdError_lift
781 + )
782 +}
783 +
784 +open func loadUqffModel(config: FfiUqffModelConfig, systemPrompt: String?, sampling: FfiSamplingConfig?)async throws -> Double {
785 + return
786 + try await uniffiRustCallAsync(
787 + rustFutureFunc: {
788 + uniffi_ed_agent_ffi_fn_method_ffiedagent_load_uqff_model(
789 + self.uniffiCloneHandle(),
790 + FfiConverterTypeFfiUqffModelConfig_lower(config),FfiConverterOptionString.lower(systemPrompt),FfiConverterOptionTypeFfiSamplingConfig.lower(sampling)
791 + )
792 + },
793 + pollFunc: ffi_ed_agent_ffi_rust_future_poll_f64,
794 + completeFunc: ffi_ed_agent_ffi_rust_future_complete_f64,
795 + freeFunc: ffi_ed_agent_ffi_rust_future_free_f64,
796 + liftFunc: FfiConverterDouble.lift,
797 + errorHandler: FfiConverterTypeFfiEdError_lift
798 + )
799 +}
800 +
801 +open func registerTool(tool: FfiToolDefinition)async throws {
802 + return
803 + try await uniffiRustCallAsync(
804 + rustFutureFunc: {
805 + uniffi_ed_agent_ffi_fn_method_ffiedagent_register_tool(
806 + self.uniffiCloneHandle(),
807 + FfiConverterTypeFfiToolDefinition_lower(tool)
808 + )
809 + },
810 + pollFunc: ffi_ed_agent_ffi_rust_future_poll_void,
811 + completeFunc: ffi_ed_agent_ffi_rust_future_complete_void,
812 + freeFunc: ffi_ed_agent_ffi_rust_future_free_void,
813 + liftFunc: { $0 },
814 + errorHandler: FfiConverterTypeFfiEdError_lift
815 + )
816 +}
817 +
818 +open func removeAllTools()async {
819 + return
820 + try! await uniffiRustCallAsync(
821 + rustFutureFunc: {
822 + uniffi_ed_agent_ffi_fn_method_ffiedagent_remove_all_tools(
823 + self.uniffiCloneHandle()
824 +
825 + )
826 + },
827 + pollFunc: ffi_ed_agent_ffi_rust_future_poll_void,
828 + completeFunc: ffi_ed_agent_ffi_rust_future_complete_void,
829 + freeFunc: ffi_ed_agent_ffi_rust_future_free_void,
830 + liftFunc: { $0 },
831 + errorHandler: nil
832 +
833 + )
834 +}
835 +
836 +open func run(message: String)async throws -> FfiAgentReply {
837 + return
838 + try await uniffiRustCallAsync(
839 + rustFutureFunc: {
840 + uniffi_ed_agent_ffi_fn_method_ffiedagent_run(
841 + self.uniffiCloneHandle(),
842 + FfiConverterString.lower(message)
843 + )
844 + },
845 + pollFunc: ffi_ed_agent_ffi_rust_future_poll_rust_buffer,
846 + completeFunc: ffi_ed_agent_ffi_rust_future_complete_rust_buffer,
847 + freeFunc: ffi_ed_agent_ffi_rust_future_free_rust_buffer,
848 + liftFunc: FfiConverterTypeFfiAgentReply_lift,
849 + errorHandler: FfiConverterTypeFfiEdError_lift
850 + )
851 +}
852 +
853 +open func send(message: String)async throws -> FfiReply {
854 + return
855 + try await uniffiRustCallAsync(
856 + rustFutureFunc: {
857 + uniffi_ed_agent_ffi_fn_method_ffiedagent_send(
858 + self.uniffiCloneHandle(),
859 + FfiConverterString.lower(message)
860 + )
861 + },
862 + pollFunc: ffi_ed_agent_ffi_rust_future_poll_rust_buffer,
863 + completeFunc: ffi_ed_agent_ffi_rust_future_complete_rust_buffer,
864 + freeFunc: ffi_ed_agent_ffi_rust_future_free_rust_buffer,
865 + liftFunc: FfiConverterTypeFfiReply_lift,
866 + errorHandler: FfiConverterTypeFfiEdError_lift
867 + )
868 +}
869 +
870 +open func unload()async -> String? {
871 + return
872 + try! await uniffiRustCallAsync(
873 + rustFutureFunc: {
874 + uniffi_ed_agent_ffi_fn_method_ffiedagent_unload(
875 + self.uniffiCloneHandle()
876 +
877 + )
878 + },
879 + pollFunc: ffi_ed_agent_ffi_rust_future_poll_rust_buffer,
880 + completeFunc: ffi_ed_agent_ffi_rust_future_complete_rust_buffer,
881 + freeFunc: ffi_ed_agent_ffi_rust_future_free_rust_buffer,
882 + liftFunc: FfiConverterOptionString.lift,
883 + errorHandler: nil
884 +
885 + )
886 +}
887 +
888 +open func unregisterTool(name: String)async -> Bool {
889 + return
890 + try! await uniffiRustCallAsync(
891 + rustFutureFunc: {
892 + uniffi_ed_agent_ffi_fn_method_ffiedagent_unregister_tool(
893 + self.uniffiCloneHandle(),
894 + FfiConverterString.lower(name)
895 + )
896 + },
897 + pollFunc: ffi_ed_agent_ffi_rust_future_poll_i8,
898 + completeFunc: ffi_ed_agent_ffi_rust_future_complete_i8,
899 + freeFunc: ffi_ed_agent_ffi_rust_future_free_i8,
900 + liftFunc: FfiConverterBool.lift,
901 + errorHandler: nil
902 +
903 + )
904 +}
905 +
906 +
907 +
908 +}
909 +
910 +
911 +#if swift(>=5.8)
912 +@_documentation(visibility: private)
913 +#endif
914 +public struct FfiConverterTypeFfiEdAgent: FfiConverter {
915 + typealias FfiType = UInt64
916 + typealias SwiftType = FfiEdAgent
917 +
918 + public static func lift(_ handle: UInt64) throws -> FfiEdAgent {
919 + return FfiEdAgent(unsafeFromHandle: handle)
920 + }
921 +
922 + public static func lower(_ value: FfiEdAgent) -> UInt64 {
923 + return value.uniffiCloneHandle()
924 + }
925 +
926 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiEdAgent {
927 + let handle: UInt64 = try readInt(&buf)
928 + return try lift(handle)
929 + }
930 +
931 + public static func write(_ value: FfiEdAgent, into buf: inout [UInt8]) {
932 + writeInt(&buf, lower(value))
933 + }
934 +}
935 +
936 +
937 +#if swift(>=5.8)
938 +@_documentation(visibility: private)
939 +#endif
940 +public func FfiConverterTypeFfiEdAgent_lift(_ handle: UInt64) throws -> FfiEdAgent {
941 + return try FfiConverterTypeFfiEdAgent.lift(handle)
942 +}
943 +
944 +#if swift(>=5.8)
945 +@_documentation(visibility: private)
946 +#endif
947 +public func FfiConverterTypeFfiEdAgent_lower(_ value: FfiEdAgent) -> UInt64 {
948 + return FfiConverterTypeFfiEdAgent.lower(value)
949 +}
950 +
951 +
952 +
953 +
954 +public struct FfiAgentConfig: Equatable, Hashable {
955 + public var maxToolRounds: UInt8
956 + public var maxToolOutputChars: UInt64
957 +
958 + // Default memberwise initializers are never public by default, so we
959 + // declare one manually.
960 + public init(maxToolRounds: UInt8, maxToolOutputChars: UInt64) {
961 + self.maxToolRounds = maxToolRounds
962 + self.maxToolOutputChars = maxToolOutputChars
963 + }
964 +
965 +
966 +
967 +
968 +}
969 +
970 +#if compiler(>=6)
971 +extension FfiAgentConfig: Sendable {}
972 +#endif
973 +
974 +#if swift(>=5.8)
975 +@_documentation(visibility: private)
976 +#endif
977 +public struct FfiConverterTypeFfiAgentConfig: FfiConverterRustBuffer {
978 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiAgentConfig {
979 + return
980 + try FfiAgentConfig(
981 + maxToolRounds: FfiConverterUInt8.read(from: &buf),
982 + maxToolOutputChars: FfiConverterUInt64.read(from: &buf)
983 + )
984 + }
985 +
986 + public static func write(_ value: FfiAgentConfig, into buf: inout [UInt8]) {
987 + FfiConverterUInt8.write(value.maxToolRounds, into: &buf)
988 + FfiConverterUInt64.write(value.maxToolOutputChars, into: &buf)
989 + }
990 +}
991 +
992 +
993 +#if swift(>=5.8)
994 +@_documentation(visibility: private)
995 +#endif
996 +public func FfiConverterTypeFfiAgentConfig_lift(_ buf: RustBuffer) throws -> FfiAgentConfig {
997 + return try FfiConverterTypeFfiAgentConfig.lift(buf)
998 +}
999 +
1000 +#if swift(>=5.8)
1001 +@_documentation(visibility: private)
1002 +#endif
1003 +public func FfiConverterTypeFfiAgentConfig_lower(_ value: FfiAgentConfig) -> RustBuffer {
1004 + return FfiConverterTypeFfiAgentConfig.lower(value)
1005 +}
1006 +
1007 +
1008 +public struct FfiAgentReply: Equatable, Hashable {
1009 + public var text: String
1010 + public var durationSeconds: Double
1011 + public var duration: String
1012 + public var toolRounds: UInt8
1013 +
1014 + // Default memberwise initializers are never public by default, so we
1015 + // declare one manually.
1016 + public init(text: String, durationSeconds: Double, duration: String, toolRounds: UInt8) {
1017 + self.text = text
1018 + self.durationSeconds = durationSeconds
1019 + self.duration = duration
1020 + self.toolRounds = toolRounds
1021 + }
1022 +
1023 +
1024 +
1025 +
1026 +}
1027 +
1028 +#if compiler(>=6)
1029 +extension FfiAgentReply: Sendable {}
1030 +#endif
1031 +
1032 +#if swift(>=5.8)
1033 +@_documentation(visibility: private)
1034 +#endif
1035 +public struct FfiConverterTypeFfiAgentReply: FfiConverterRustBuffer {
1036 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiAgentReply {
1037 + return
1038 + try FfiAgentReply(
1039 + text: FfiConverterString.read(from: &buf),
1040 + durationSeconds: FfiConverterDouble.read(from: &buf),
1041 + duration: FfiConverterString.read(from: &buf),
1042 + toolRounds: FfiConverterUInt8.read(from: &buf)
1043 + )
1044 + }
1045 +
1046 + public static func write(_ value: FfiAgentReply, into buf: inout [UInt8]) {
1047 + FfiConverterString.write(value.text, into: &buf)
1048 + FfiConverterDouble.write(value.durationSeconds, into: &buf)
1049 + FfiConverterString.write(value.duration, into: &buf)
1050 + FfiConverterUInt8.write(value.toolRounds, into: &buf)
1051 + }
1052 +}
1053 +
1054 +
1055 +#if swift(>=5.8)
1056 +@_documentation(visibility: private)
1057 +#endif
1058 +public func FfiConverterTypeFfiAgentReply_lift(_ buf: RustBuffer) throws -> FfiAgentReply {
1059 + return try FfiConverterTypeFfiAgentReply.lift(buf)
1060 +}
1061 +
1062 +#if swift(>=5.8)
1063 +@_documentation(visibility: private)
1064 +#endif
1065 +public func FfiConverterTypeFfiAgentReply_lower(_ value: FfiAgentReply) -> RustBuffer {
1066 + return FfiConverterTypeFfiAgentReply.lower(value)
1067 +}
1068 +
1069 +
1070 +public struct FfiChatMessage: Equatable, Hashable {
1071 + public var role: FfiChatRole
1072 + public var content: String
1073 +
1074 + // Default memberwise initializers are never public by default, so we
1075 + // declare one manually.
1076 + public init(role: FfiChatRole, content: String) {
1077 + self.role = role
1078 + self.content = content
1079 + }
1080 +
1081 +
1082 +
1083 +
1084 +}
1085 +
1086 +#if compiler(>=6)
1087 +extension FfiChatMessage: Sendable {}
1088 +#endif
1089 +
1090 +#if swift(>=5.8)
1091 +@_documentation(visibility: private)
1092 +#endif
1093 +public struct FfiConverterTypeFfiChatMessage: FfiConverterRustBuffer {
1094 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiChatMessage {
1095 + return
1096 + try FfiChatMessage(
1097 + role: FfiConverterTypeFfiChatRole.read(from: &buf),
1098 + content: FfiConverterString.read(from: &buf)
1099 + )
1100 + }
1101 +
1102 + public static func write(_ value: FfiChatMessage, into buf: inout [UInt8]) {
1103 + FfiConverterTypeFfiChatRole.write(value.role, into: &buf)
1104 + FfiConverterString.write(value.content, into: &buf)
1105 + }
1106 +}
1107 +
1108 +
1109 +#if swift(>=5.8)
1110 +@_documentation(visibility: private)
1111 +#endif
1112 +public func FfiConverterTypeFfiChatMessage_lift(_ buf: RustBuffer) throws -> FfiChatMessage {
1113 + return try FfiConverterTypeFfiChatMessage.lift(buf)
1114 +}
1115 +
1116 +#if swift(>=5.8)
1117 +@_documentation(visibility: private)
1118 +#endif
1119 +public func FfiConverterTypeFfiChatMessage_lower(_ value: FfiChatMessage) -> RustBuffer {
1120 + return FfiConverterTypeFfiChatMessage.lower(value)
1121 +}
1122 +
1123 +
1124 +public struct FfiEngineInfo: Equatable, Hashable {
1125 + public var status: FfiEngineStatus
1126 + public var modelName: String?
1127 + public var approxMemory: String?
1128 + public var historyLength: UInt64
1129 +
1130 + // Default memberwise initializers are never public by default, so we
1131 + // declare one manually.
1132 + public init(status: FfiEngineStatus, modelName: String?, approxMemory: String?, historyLength: UInt64) {
1133 + self.status = status
1134 + self.modelName = modelName
1135 + self.approxMemory = approxMemory
1136 + self.historyLength = historyLength
1137 + }
1138 +
1139 +
1140 +
1141 +
1142 +}
1143 +
1144 +#if compiler(>=6)
1145 +extension FfiEngineInfo: Sendable {}
1146 +#endif
1147 +
1148 +#if swift(>=5.8)
1149 +@_documentation(visibility: private)
1150 +#endif
1151 +public struct FfiConverterTypeFfiEngineInfo: FfiConverterRustBuffer {
1152 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiEngineInfo {
1153 + return
1154 + try FfiEngineInfo(
1155 + status: FfiConverterTypeFfiEngineStatus.read(from: &buf),
1156 + modelName: FfiConverterOptionString.read(from: &buf),
1157 + approxMemory: FfiConverterOptionString.read(from: &buf),
1158 + historyLength: FfiConverterUInt64.read(from: &buf)
1159 + )
1160 + }
1161 +
1162 + public static func write(_ value: FfiEngineInfo, into buf: inout [UInt8]) {
1163 + FfiConverterTypeFfiEngineStatus.write(value.status, into: &buf)
1164 + FfiConverterOptionString.write(value.modelName, into: &buf)
1165 + FfiConverterOptionString.write(value.approxMemory, into: &buf)
1166 + FfiConverterUInt64.write(value.historyLength, into: &buf)
1167 + }
1168 +}
1169 +
1170 +
1171 +#if swift(>=5.8)
1172 +@_documentation(visibility: private)
1173 +#endif
1174 +public func FfiConverterTypeFfiEngineInfo_lift(_ buf: RustBuffer) throws -> FfiEngineInfo {
1175 + return try FfiConverterTypeFfiEngineInfo.lift(buf)
1176 +}
1177 +
1178 +#if swift(>=5.8)
1179 +@_documentation(visibility: private)
1180 +#endif
1181 +public func FfiConverterTypeFfiEngineInfo_lower(_ value: FfiEngineInfo) -> RustBuffer {
1182 + return FfiConverterTypeFfiEngineInfo.lower(value)
1183 +}
1184 +
1185 +
1186 +public struct FfiGgufModelConfig: Equatable, Hashable {
1187 + public var modelId: String
1188 + public var files: [String]
1189 + public var tokModelId: String?
1190 + public var displayName: String
1191 + public var approxMemory: String
1192 + public var chatTemplate: String?
1193 +
1194 + // Default memberwise initializers are never public by default, so we
1195 + // declare one manually.
1196 + public init(modelId: String, files: [String], tokModelId: String?, displayName: String, approxMemory: String, chatTemplate: String?) {
1197 + self.modelId = modelId
1198 + self.files = files
1199 + self.tokModelId = tokModelId
1200 + self.displayName = displayName
1201 + self.approxMemory = approxMemory
1202 + self.chatTemplate = chatTemplate
1203 + }
1204 +
1205 +
1206 +
1207 +
1208 +}
1209 +
1210 +#if compiler(>=6)
1211 +extension FfiGgufModelConfig: Sendable {}
1212 +#endif
1213 +
1214 +#if swift(>=5.8)
1215 +@_documentation(visibility: private)
1216 +#endif
1217 +public struct FfiConverterTypeFfiGgufModelConfig: FfiConverterRustBuffer {
1218 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiGgufModelConfig {
1219 + return
1220 + try FfiGgufModelConfig(
1221 + modelId: FfiConverterString.read(from: &buf),
1222 + files: FfiConverterSequenceString.read(from: &buf),
1223 + tokModelId: FfiConverterOptionString.read(from: &buf),
1224 + displayName: FfiConverterString.read(from: &buf),
1225 + approxMemory: FfiConverterString.read(from: &buf),
1226 + chatTemplate: FfiConverterOptionString.read(from: &buf)
1227 + )
1228 + }
1229 +
1230 + public static func write(_ value: FfiGgufModelConfig, into buf: inout [UInt8]) {
1231 + FfiConverterString.write(value.modelId, into: &buf)
1232 + FfiConverterSequenceString.write(value.files, into: &buf)
1233 + FfiConverterOptionString.write(value.tokModelId, into: &buf)
1234 + FfiConverterString.write(value.displayName, into: &buf)
1235 + FfiConverterString.write(value.approxMemory, into: &buf)
1236 + FfiConverterOptionString.write(value.chatTemplate, into: &buf)
1237 + }
1238 +}
1239 +
1240 +
1241 +#if swift(>=5.8)
1242 +@_documentation(visibility: private)
1243 +#endif
1244 +public func FfiConverterTypeFfiGgufModelConfig_lift(_ buf: RustBuffer) throws -> FfiGgufModelConfig {
1245 + return try FfiConverterTypeFfiGgufModelConfig.lift(buf)
1246 +}
1247 +
1248 +#if swift(>=5.8)
1249 +@_documentation(visibility: private)
1250 +#endif
1251 +public func FfiConverterTypeFfiGgufModelConfig_lower(_ value: FfiGgufModelConfig) -> RustBuffer {
1252 + return FfiConverterTypeFfiGgufModelConfig.lower(value)
1253 +}
1254 +
1255 +
1256 +public struct FfiReply: Equatable, Hashable {
1257 + public var text: String
1258 + public var duration: String
1259 +
1260 + // Default memberwise initializers are never public by default, so we
1261 + // declare one manually.
1262 + public init(text: String, duration: String) {
1263 + self.text = text
1264 + self.duration = duration
1265 + }
1266 +
1267 +
1268 +
1269 +
1270 +}
1271 +
1272 +#if compiler(>=6)
1273 +extension FfiReply: Sendable {}
1274 +#endif
1275 +
1276 +#if swift(>=5.8)
1277 +@_documentation(visibility: private)
1278 +#endif
1279 +public struct FfiConverterTypeFfiReply: FfiConverterRustBuffer {
1280 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiReply {
1281 + return
1282 + try FfiReply(
1283 + text: FfiConverterString.read(from: &buf),
1284 + duration: FfiConverterString.read(from: &buf)
1285 + )
1286 + }
1287 +
1288 + public static func write(_ value: FfiReply, into buf: inout [UInt8]) {
1289 + FfiConverterString.write(value.text, into: &buf)
1290 + FfiConverterString.write(value.duration, into: &buf)
1291 + }
1292 +}
1293 +
1294 +
1295 +#if swift(>=5.8)
1296 +@_documentation(visibility: private)
1297 +#endif
1298 +public func FfiConverterTypeFfiReply_lift(_ buf: RustBuffer) throws -> FfiReply {
1299 + return try FfiConverterTypeFfiReply.lift(buf)
1300 +}
1301 +
1302 +#if swift(>=5.8)
1303 +@_documentation(visibility: private)
1304 +#endif
1305 +public func FfiConverterTypeFfiReply_lower(_ value: FfiReply) -> RustBuffer {
1306 + return FfiConverterTypeFfiReply.lower(value)
1307 +}
1308 +
1309 +
1310 +public struct FfiSamplingConfig: Equatable, Hashable {
1311 + public var temperature: Double?
1312 + public var topP: Double?
1313 + public var topK: UInt64?
1314 + public var minP: Double?
1315 + public var maxTokens: UInt64?
1316 + public var frequencyPenalty: Float?
1317 + public var presencePenalty: Float?
1318 +
1319 + // Default memberwise initializers are never public by default, so we
1320 + // declare one manually.
1321 + public init(temperature: Double?, topP: Double?, topK: UInt64?, minP: Double?, maxTokens: UInt64?, frequencyPenalty: Float?, presencePenalty: Float?) {
1322 + self.temperature = temperature
1323 + self.topP = topP
1324 + self.topK = topK
1325 + self.minP = minP
1326 + self.maxTokens = maxTokens
1327 + self.frequencyPenalty = frequencyPenalty
1328 + self.presencePenalty = presencePenalty
1329 + }
1330 +
1331 +
1332 +
1333 +
1334 +}
1335 +
1336 +#if compiler(>=6)
1337 +extension FfiSamplingConfig: Sendable {}
1338 +#endif
1339 +
1340 +#if swift(>=5.8)
1341 +@_documentation(visibility: private)
1342 +#endif
1343 +public struct FfiConverterTypeFfiSamplingConfig: FfiConverterRustBuffer {
1344 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiSamplingConfig {
1345 + return
1346 + try FfiSamplingConfig(
1347 + temperature: FfiConverterOptionDouble.read(from: &buf),
1348 + topP: FfiConverterOptionDouble.read(from: &buf),
1349 + topK: FfiConverterOptionUInt64.read(from: &buf),
1350 + minP: FfiConverterOptionDouble.read(from: &buf),
1351 + maxTokens: FfiConverterOptionUInt64.read(from: &buf),
1352 + frequencyPenalty: FfiConverterOptionFloat.read(from: &buf),
1353 + presencePenalty: FfiConverterOptionFloat.read(from: &buf)
1354 + )
1355 + }
1356 +
1357 + public static func write(_ value: FfiSamplingConfig, into buf: inout [UInt8]) {
1358 + FfiConverterOptionDouble.write(value.temperature, into: &buf)
1359 + FfiConverterOptionDouble.write(value.topP, into: &buf)
1360 + FfiConverterOptionUInt64.write(value.topK, into: &buf)
1361 + FfiConverterOptionDouble.write(value.minP, into: &buf)
1362 + FfiConverterOptionUInt64.write(value.maxTokens, into: &buf)
1363 + FfiConverterOptionFloat.write(value.frequencyPenalty, into: &buf)
1364 + FfiConverterOptionFloat.write(value.presencePenalty, into: &buf)
1365 + }
1366 +}
1367 +
1368 +
1369 +#if swift(>=5.8)
1370 +@_documentation(visibility: private)
1371 +#endif
1372 +public func FfiConverterTypeFfiSamplingConfig_lift(_ buf: RustBuffer) throws -> FfiSamplingConfig {
1373 + return try FfiConverterTypeFfiSamplingConfig.lift(buf)
1374 +}
1375 +
1376 +#if swift(>=5.8)
1377 +@_documentation(visibility: private)
1378 +#endif
1379 +public func FfiConverterTypeFfiSamplingConfig_lower(_ value: FfiSamplingConfig) -> RustBuffer {
1380 + return FfiConverterTypeFfiSamplingConfig.lower(value)
1381 +}
1382 +
1383 +
1384 +public struct FfiStatusUpdate: Equatable, Hashable {
1385 + public var status: FfiEngineStatus
1386 + public var modelName: String?
1387 + public var error: String?
1388 +
1389 + // Default memberwise initializers are never public by default, so we
1390 + // declare one manually.
1391 + public init(status: FfiEngineStatus, modelName: String?, error: String?) {
1392 + self.status = status
1393 + self.modelName = modelName
1394 + self.error = error
1395 + }
1396 +
1397 +
1398 +
1399 +
1400 +}
1401 +
1402 +#if compiler(>=6)
1403 +extension FfiStatusUpdate: Sendable {}
1404 +#endif
1405 +
1406 +#if swift(>=5.8)
1407 +@_documentation(visibility: private)
1408 +#endif
1409 +public struct FfiConverterTypeFfiStatusUpdate: FfiConverterRustBuffer {
1410 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiStatusUpdate {
1411 + return
1412 + try FfiStatusUpdate(
1413 + status: FfiConverterTypeFfiEngineStatus.read(from: &buf),
1414 + modelName: FfiConverterOptionString.read(from: &buf),
1415 + error: FfiConverterOptionString.read(from: &buf)
1416 + )
1417 + }
1418 +
1419 + public static func write(_ value: FfiStatusUpdate, into buf: inout [UInt8]) {
1420 + FfiConverterTypeFfiEngineStatus.write(value.status, into: &buf)
1421 + FfiConverterOptionString.write(value.modelName, into: &buf)
1422 + FfiConverterOptionString.write(value.error, into: &buf)
1423 + }
1424 +}
1425 +
1426 +
1427 +#if swift(>=5.8)
1428 +@_documentation(visibility: private)
1429 +#endif
1430 +public func FfiConverterTypeFfiStatusUpdate_lift(_ buf: RustBuffer) throws -> FfiStatusUpdate {
1431 + return try FfiConverterTypeFfiStatusUpdate.lift(buf)
1432 +}
1433 +
1434 +#if swift(>=5.8)
1435 +@_documentation(visibility: private)
1436 +#endif
1437 +public func FfiConverterTypeFfiStatusUpdate_lower(_ value: FfiStatusUpdate) -> RustBuffer {
1438 + return FfiConverterTypeFfiStatusUpdate.lower(value)
1439 +}
1440 +
1441 +
1442 +public struct FfiToolCall: Equatable, Hashable {
1443 + public var id: String
1444 + public var name: String
1445 + public var arguments: String
1446 +
1447 + // Default memberwise initializers are never public by default, so we
1448 + // declare one manually.
1449 + public init(id: String, name: String, arguments: String) {
1450 + self.id = id
1451 + self.name = name
1452 + self.arguments = arguments
1453 + }
1454 +
1455 +
1456 +
1457 +
1458 +}
1459 +
1460 +#if compiler(>=6)
1461 +extension FfiToolCall: Sendable {}
1462 +#endif
1463 +
1464 +#if swift(>=5.8)
1465 +@_documentation(visibility: private)
1466 +#endif
1467 +public struct FfiConverterTypeFfiToolCall: FfiConverterRustBuffer {
1468 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiToolCall {
1469 + return
1470 + try FfiToolCall(
1471 + id: FfiConverterString.read(from: &buf),
1472 + name: FfiConverterString.read(from: &buf),
1473 + arguments: FfiConverterString.read(from: &buf)
1474 + )
1475 + }
1476 +
1477 + public static func write(_ value: FfiToolCall, into buf: inout [UInt8]) {
1478 + FfiConverterString.write(value.id, into: &buf)
1479 + FfiConverterString.write(value.name, into: &buf)
1480 + FfiConverterString.write(value.arguments, into: &buf)
1481 + }
1482 +}
1483 +
1484 +
1485 +#if swift(>=5.8)
1486 +@_documentation(visibility: private)
1487 +#endif
1488 +public func FfiConverterTypeFfiToolCall_lift(_ buf: RustBuffer) throws -> FfiToolCall {
1489 + return try FfiConverterTypeFfiToolCall.lift(buf)
1490 +}
1491 +
1492 +#if swift(>=5.8)
1493 +@_documentation(visibility: private)
1494 +#endif
1495 +public func FfiConverterTypeFfiToolCall_lower(_ value: FfiToolCall) -> RustBuffer {
1496 + return FfiConverterTypeFfiToolCall.lower(value)
1497 +}
1498 +
1499 +
1500 +public struct FfiToolDefinition: Equatable, Hashable {
1501 + public var name: String
1502 + public var description: String
1503 + public var parametersSchema: String
1504 + public var risk: FfiToolRisk
1505 +
1506 + // Default memberwise initializers are never public by default, so we
1507 + // declare one manually.
1508 + public init(name: String, description: String, parametersSchema: String, risk: FfiToolRisk) {
1509 + self.name = name
1510 + self.description = description
1511 + self.parametersSchema = parametersSchema
1512 + self.risk = risk
1513 + }
1514 +
1515 +
1516 +
1517 +
1518 +}
1519 +
1520 +#if compiler(>=6)
1521 +extension FfiToolDefinition: Sendable {}
1522 +#endif
1523 +
1524 +#if swift(>=5.8)
1525 +@_documentation(visibility: private)
1526 +#endif
1527 +public struct FfiConverterTypeFfiToolDefinition: FfiConverterRustBuffer {
1528 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiToolDefinition {
1529 + return
1530 + try FfiToolDefinition(
1531 + name: FfiConverterString.read(from: &buf),
1532 + description: FfiConverterString.read(from: &buf),
1533 + parametersSchema: FfiConverterString.read(from: &buf),
1534 + risk: FfiConverterTypeFfiToolRisk.read(from: &buf)
1535 + )
1536 + }
1537 +
1538 + public static func write(_ value: FfiToolDefinition, into buf: inout [UInt8]) {
1539 + FfiConverterString.write(value.name, into: &buf)
1540 + FfiConverterString.write(value.description, into: &buf)
1541 + FfiConverterString.write(value.parametersSchema, into: &buf)
1542 + FfiConverterTypeFfiToolRisk.write(value.risk, into: &buf)
1543 + }
1544 +}
1545 +
1546 +
1547 +#if swift(>=5.8)
1548 +@_documentation(visibility: private)
1549 +#endif
1550 +public func FfiConverterTypeFfiToolDefinition_lift(_ buf: RustBuffer) throws -> FfiToolDefinition {
1551 + return try FfiConverterTypeFfiToolDefinition.lift(buf)
1552 +}
1553 +
1554 +#if swift(>=5.8)
1555 +@_documentation(visibility: private)
1556 +#endif
1557 +public func FfiConverterTypeFfiToolDefinition_lower(_ value: FfiToolDefinition) -> RustBuffer {
1558 + return FfiConverterTypeFfiToolDefinition.lower(value)
1559 +}
1560 +
1561 +
1562 +public struct FfiToolOutput: Equatable, Hashable {
1563 + public var content: String
1564 + public var error: String?
1565 +
1566 + // Default memberwise initializers are never public by default, so we
1567 + // declare one manually.
1568 + public init(content: String, error: String?) {
1569 + self.content = content
1570 + self.error = error
1571 + }
1572 +
1573 +
1574 +
1575 +
1576 +}
1577 +
1578 +#if compiler(>=6)
1579 +extension FfiToolOutput: Sendable {}
1580 +#endif
1581 +
1582 +#if swift(>=5.8)
1583 +@_documentation(visibility: private)
1584 +#endif
1585 +public struct FfiConverterTypeFfiToolOutput: FfiConverterRustBuffer {
1586 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiToolOutput {
1587 + return
1588 + try FfiToolOutput(
1589 + content: FfiConverterString.read(from: &buf),
1590 + error: FfiConverterOptionString.read(from: &buf)
1591 + )
1592 + }
1593 +
1594 + public static func write(_ value: FfiToolOutput, into buf: inout [UInt8]) {
1595 + FfiConverterString.write(value.content, into: &buf)
1596 + FfiConverterOptionString.write(value.error, into: &buf)
1597 + }
1598 +}
1599 +
1600 +
1601 +#if swift(>=5.8)
1602 +@_documentation(visibility: private)
1603 +#endif
1604 +public func FfiConverterTypeFfiToolOutput_lift(_ buf: RustBuffer) throws -> FfiToolOutput {
1605 + return try FfiConverterTypeFfiToolOutput.lift(buf)
1606 +}
1607 +
1608 +#if swift(>=5.8)
1609 +@_documentation(visibility: private)
1610 +#endif
1611 +public func FfiConverterTypeFfiToolOutput_lower(_ value: FfiToolOutput) -> RustBuffer {
1612 + return FfiConverterTypeFfiToolOutput.lower(value)
1613 +}
1614 +
1615 +
1616 +public struct FfiUqffModelConfig: Equatable, Hashable {
1617 + public var modelId: String
1618 + public var files: [String]
1619 + public var displayName: String
1620 + public var approxMemory: String
1621 + public var chatTemplate: String?
1622 +
1623 + // Default memberwise initializers are never public by default, so we
1624 + // declare one manually.
1625 + public init(modelId: String, files: [String], displayName: String, approxMemory: String, chatTemplate: String?) {
1626 + self.modelId = modelId
1627 + self.files = files
1628 + self.displayName = displayName
1629 + self.approxMemory = approxMemory
1630 + self.chatTemplate = chatTemplate
1631 + }
1632 +
1633 +
1634 +
1635 +
1636 +}
1637 +
1638 +#if compiler(>=6)
1639 +extension FfiUqffModelConfig: Sendable {}
1640 +#endif
1641 +
1642 +#if swift(>=5.8)
1643 +@_documentation(visibility: private)
1644 +#endif
1645 +public struct FfiConverterTypeFfiUqffModelConfig: FfiConverterRustBuffer {
1646 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiUqffModelConfig {
1647 + return
1648 + try FfiUqffModelConfig(
1649 + modelId: FfiConverterString.read(from: &buf),
1650 + files: FfiConverterSequenceString.read(from: &buf),
1651 + displayName: FfiConverterString.read(from: &buf),
1652 + approxMemory: FfiConverterString.read(from: &buf),
1653 + chatTemplate: FfiConverterOptionString.read(from: &buf)
1654 + )
1655 + }
1656 +
1657 + public static func write(_ value: FfiUqffModelConfig, into buf: inout [UInt8]) {
1658 + FfiConverterString.write(value.modelId, into: &buf)
1659 + FfiConverterSequenceString.write(value.files, into: &buf)
1660 + FfiConverterString.write(value.displayName, into: &buf)
1661 + FfiConverterString.write(value.approxMemory, into: &buf)
1662 + FfiConverterOptionString.write(value.chatTemplate, into: &buf)
1663 + }
1664 +}
1665 +
1666 +
1667 +#if swift(>=5.8)
1668 +@_documentation(visibility: private)
1669 +#endif
1670 +public func FfiConverterTypeFfiUqffModelConfig_lift(_ buf: RustBuffer) throws -> FfiUqffModelConfig {
1671 + return try FfiConverterTypeFfiUqffModelConfig.lift(buf)
1672 +}
1673 +
1674 +#if swift(>=5.8)
1675 +@_documentation(visibility: private)
1676 +#endif
1677 +public func FfiConverterTypeFfiUqffModelConfig_lower(_ value: FfiUqffModelConfig) -> RustBuffer {
1678 + return FfiConverterTypeFfiUqffModelConfig.lower(value)
1679 +}
1680 +
1681 +// Note that we don't yet support `indirect` for enums.
1682 +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion.
1683 +
1684 +public enum FfiApprovalDecision: Equatable, Hashable {
1685 +
1686 + case allowOnce
1687 + case allowForSession
1688 + case deny
1689 +
1690 +
1691 +
1692 +
1693 +
1694 +}
1695 +
1696 +#if compiler(>=6)
1697 +extension FfiApprovalDecision: Sendable {}
1698 +#endif
1699 +
1700 +#if swift(>=5.8)
1701 +@_documentation(visibility: private)
1702 +#endif
1703 +public struct FfiConverterTypeFfiApprovalDecision: FfiConverterRustBuffer {
1704 + typealias SwiftType = FfiApprovalDecision
1705 +
1706 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiApprovalDecision {
1707 + let variant: Int32 = try readInt(&buf)
1708 + switch variant {
1709 +
1710 + case 1: return .allowOnce
1711 +
1712 + case 2: return .allowForSession
1713 +
1714 + case 3: return .deny
1715 +
1716 + default: throw UniffiInternalError.unexpectedEnumCase
1717 + }
1718 + }
1719 +
1720 + public static func write(_ value: FfiApprovalDecision, into buf: inout [UInt8]) {
1721 + switch value {
1722 +
1723 +
1724 + case .allowOnce:
1725 + writeInt(&buf, Int32(1))
1726 +
1727 +
1728 + case .allowForSession:
1729 + writeInt(&buf, Int32(2))
1730 +
1731 +
1732 + case .deny:
1733 + writeInt(&buf, Int32(3))
1734 +
1735 + }
1736 + }
1737 +}
1738 +
1739 +
1740 +#if swift(>=5.8)
1741 +@_documentation(visibility: private)
1742 +#endif
1743 +public func FfiConverterTypeFfiApprovalDecision_lift(_ buf: RustBuffer) throws -> FfiApprovalDecision {
1744 + return try FfiConverterTypeFfiApprovalDecision.lift(buf)
1745 +}
1746 +
1747 +#if swift(>=5.8)
1748 +@_documentation(visibility: private)
1749 +#endif
1750 +public func FfiConverterTypeFfiApprovalDecision_lower(_ value: FfiApprovalDecision) -> RustBuffer {
1751 + return FfiConverterTypeFfiApprovalDecision.lower(value)
1752 +}
1753 +
1754 +
1755 +// Note that we don't yet support `indirect` for enums.
1756 +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion.
1757 +
1758 +public enum FfiChatRole: Equatable, Hashable {
1759 +
1760 + case system
1761 + case user
1762 + case assistant
1763 +
1764 +
1765 +
1766 +
1767 +
1768 +}
1769 +
1770 +#if compiler(>=6)
1771 +extension FfiChatRole: Sendable {}
1772 +#endif
1773 +
1774 +#if swift(>=5.8)
1775 +@_documentation(visibility: private)
1776 +#endif
1777 +public struct FfiConverterTypeFfiChatRole: FfiConverterRustBuffer {
1778 + typealias SwiftType = FfiChatRole
1779 +
1780 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiChatRole {
1781 + let variant: Int32 = try readInt(&buf)
1782 + switch variant {
1783 +
1784 + case 1: return .system
1785 +
1786 + case 2: return .user
1787 +
1788 + case 3: return .assistant
1789 +
1790 + default: throw UniffiInternalError.unexpectedEnumCase
1791 + }
1792 + }
1793 +
1794 + public static func write(_ value: FfiChatRole, into buf: inout [UInt8]) {
1795 + switch value {
1796 +
1797 +
1798 + case .system:
1799 + writeInt(&buf, Int32(1))
1800 +
1801 +
1802 + case .user:
1803 + writeInt(&buf, Int32(2))
1804 +
1805 +
1806 + case .assistant:
1807 + writeInt(&buf, Int32(3))
1808 +
1809 + }
1810 + }
1811 +}
1812 +
1813 +
1814 +#if swift(>=5.8)
1815 +@_documentation(visibility: private)
1816 +#endif
1817 +public func FfiConverterTypeFfiChatRole_lift(_ buf: RustBuffer) throws -> FfiChatRole {
1818 + return try FfiConverterTypeFfiChatRole.lift(buf)
1819 +}
1820 +
1821 +#if swift(>=5.8)
1822 +@_documentation(visibility: private)
1823 +#endif
1824 +public func FfiConverterTypeFfiChatRole_lower(_ value: FfiChatRole) -> RustBuffer {
1825 + return FfiConverterTypeFfiChatRole.lower(value)
1826 +}
1827 +
1828 +
1829 +
1830 +public enum FfiEdError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError {
1831 +
1832 +
1833 +
1834 + case Failure(reason: String
1835 + )
1836 +
1837 +
1838 +
1839 +
1840 +
1841 +
1842 + public var errorDescription: String? {
1843 + String(reflecting: self)
1844 + }
1845 +
1846 +}
1847 +
1848 +#if compiler(>=6)
1849 +extension FfiEdError: Sendable {}
1850 +#endif
1851 +
1852 +#if swift(>=5.8)
1853 +@_documentation(visibility: private)
1854 +#endif
1855 +public struct FfiConverterTypeFfiEdError: FfiConverterRustBuffer {
1856 + typealias SwiftType = FfiEdError
1857 +
1858 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiEdError {
1859 + let variant: Int32 = try readInt(&buf)
1860 + switch variant {
1861 +
1862 +
1863 +
1864 +
1865 + case 1: return .Failure(
1866 + reason: try FfiConverterString.read(from: &buf)
1867 + )
1868 +
1869 + default: throw UniffiInternalError.unexpectedEnumCase
1870 + }
1871 + }
1872 +
1873 + public static func write(_ value: FfiEdError, into buf: inout [UInt8]) {
1874 + switch value {
1875 +
1876 +
1877 +
1878 +
1879 +
1880 + case let .Failure(reason):
1881 + writeInt(&buf, Int32(1))
1882 + FfiConverterString.write(reason, into: &buf)
1883 +
1884 + }
1885 + }
1886 +}
1887 +
1888 +
1889 +#if swift(>=5.8)
1890 +@_documentation(visibility: private)
1891 +#endif
1892 +public func FfiConverterTypeFfiEdError_lift(_ buf: RustBuffer) throws -> FfiEdError {
1893 + return try FfiConverterTypeFfiEdError.lift(buf)
1894 +}
1895 +
1896 +#if swift(>=5.8)
1897 +@_documentation(visibility: private)
1898 +#endif
1899 +public func FfiConverterTypeFfiEdError_lower(_ value: FfiEdError) -> RustBuffer {
1900 + return FfiConverterTypeFfiEdError.lower(value)
1901 +}
1902 +
1903 +// Note that we don't yet support `indirect` for enums.
1904 +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion.
1905 +
1906 +public enum FfiEngineStatus: Equatable, Hashable {
1907 +
1908 + case unloaded
1909 + case loading
1910 + case ready
1911 + case generating
1912 + case error
1913 +
1914 +
1915 +
1916 +
1917 +
1918 +}
1919 +
1920 +#if compiler(>=6)
1921 +extension FfiEngineStatus: Sendable {}
1922 +#endif
1923 +
1924 +#if swift(>=5.8)
1925 +@_documentation(visibility: private)
1926 +#endif
1927 +public struct FfiConverterTypeFfiEngineStatus: FfiConverterRustBuffer {
1928 + typealias SwiftType = FfiEngineStatus
1929 +
1930 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiEngineStatus {
1931 + let variant: Int32 = try readInt(&buf)
1932 + switch variant {
1933 +
1934 + case 1: return .unloaded
1935 +
1936 + case 2: return .loading
1937 +
1938 + case 3: return .ready
1939 +
1940 + case 4: return .generating
1941 +
1942 + case 5: return .error
1943 +
1944 + default: throw UniffiInternalError.unexpectedEnumCase
1945 + }
1946 + }
1947 +
1948 + public static func write(_ value: FfiEngineStatus, into buf: inout [UInt8]) {
1949 + switch value {
1950 +
1951 +
1952 + case .unloaded:
1953 + writeInt(&buf, Int32(1))
1954 +
1955 +
1956 + case .loading:
1957 + writeInt(&buf, Int32(2))
1958 +
1959 +
1960 + case .ready:
1961 + writeInt(&buf, Int32(3))
1962 +
1963 +
1964 + case .generating:
1965 + writeInt(&buf, Int32(4))
1966 +
1967 +
1968 + case .error:
1969 + writeInt(&buf, Int32(5))
1970 +
1971 + }
1972 + }
1973 +}
1974 +
1975 +
1976 +#if swift(>=5.8)
1977 +@_documentation(visibility: private)
1978 +#endif
1979 +public func FfiConverterTypeFfiEngineStatus_lift(_ buf: RustBuffer) throws -> FfiEngineStatus {
1980 + return try FfiConverterTypeFfiEngineStatus.lift(buf)
1981 +}
1982 +
1983 +#if swift(>=5.8)
1984 +@_documentation(visibility: private)
1985 +#endif
1986 +public func FfiConverterTypeFfiEngineStatus_lower(_ value: FfiEngineStatus) -> RustBuffer {
1987 + return FfiConverterTypeFfiEngineStatus.lower(value)
1988 +}
1989 +
1990 +
1991 +// Note that we don't yet support `indirect` for enums.
1992 +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion.
1993 +
1994 +public enum FfiEnvironment: Equatable, Hashable {
1995 +
1996 + case development
1997 + case production
1998 +
1999 +
2000 +
2001 +
2002 +
2003 +}
2004 +
2005 +#if compiler(>=6)
2006 +extension FfiEnvironment: Sendable {}
2007 +#endif
2008 +
2009 +#if swift(>=5.8)
2010 +@_documentation(visibility: private)
2011 +#endif
2012 +public struct FfiConverterTypeFfiEnvironment: FfiConverterRustBuffer {
2013 + typealias SwiftType = FfiEnvironment
2014 +
2015 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiEnvironment {
2016 + let variant: Int32 = try readInt(&buf)
2017 + switch variant {
2018 +
2019 + case 1: return .development
2020 +
2021 + case 2: return .production
2022 +
2023 + default: throw UniffiInternalError.unexpectedEnumCase
2024 + }
2025 + }
2026 +
2027 + public static func write(_ value: FfiEnvironment, into buf: inout [UInt8]) {
2028 + switch value {
2029 +
2030 +
2031 + case .development:
2032 + writeInt(&buf, Int32(1))
2033 +
2034 +
2035 + case .production:
2036 + writeInt(&buf, Int32(2))
2037 +
2038 + }
2039 + }
2040 +}
2041 +
2042 +
2043 +#if swift(>=5.8)
2044 +@_documentation(visibility: private)
2045 +#endif
2046 +public func FfiConverterTypeFfiEnvironment_lift(_ buf: RustBuffer) throws -> FfiEnvironment {
2047 + return try FfiConverterTypeFfiEnvironment.lift(buf)
2048 +}
2049 +
2050 +#if swift(>=5.8)
2051 +@_documentation(visibility: private)
2052 +#endif
2053 +public func FfiConverterTypeFfiEnvironment_lower(_ value: FfiEnvironment) -> RustBuffer {
2054 + return FfiConverterTypeFfiEnvironment.lower(value)
2055 +}
2056 +
2057 +
2058 +// Note that we don't yet support `indirect` for enums.
2059 +// See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion.
2060 +
2061 +public enum FfiToolRisk: Equatable, Hashable {
2062 +
2063 + case readOnly
2064 + case mutating
2065 +
2066 +
2067 +
2068 +
2069 +
2070 +}
2071 +
2072 +#if compiler(>=6)
2073 +extension FfiToolRisk: Sendable {}
2074 +#endif
2075 +
2076 +#if swift(>=5.8)
2077 +@_documentation(visibility: private)
2078 +#endif
2079 +public struct FfiConverterTypeFfiToolRisk: FfiConverterRustBuffer {
2080 + typealias SwiftType = FfiToolRisk
2081 +
2082 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> FfiToolRisk {
2083 + let variant: Int32 = try readInt(&buf)
2084 + switch variant {
2085 +
2086 + case 1: return .readOnly
2087 +
2088 + case 2: return .mutating
2089 +
2090 + default: throw UniffiInternalError.unexpectedEnumCase
2091 + }
2092 + }
2093 +
2094 + public static func write(_ value: FfiToolRisk, into buf: inout [UInt8]) {
2095 + switch value {
2096 +
2097 +
2098 + case .readOnly:
2099 + writeInt(&buf, Int32(1))
2100 +
2101 +
2102 + case .mutating:
2103 + writeInt(&buf, Int32(2))
2104 +
2105 + }
2106 + }
2107 +}
2108 +
2109 +
2110 +#if swift(>=5.8)
2111 +@_documentation(visibility: private)
2112 +#endif
2113 +public func FfiConverterTypeFfiToolRisk_lift(_ buf: RustBuffer) throws -> FfiToolRisk {
2114 + return try FfiConverterTypeFfiToolRisk.lift(buf)
2115 +}
2116 +
2117 +#if swift(>=5.8)
2118 +@_documentation(visibility: private)
2119 +#endif
2120 +public func FfiConverterTypeFfiToolRisk_lower(_ value: FfiToolRisk) -> RustBuffer {
2121 + return FfiConverterTypeFfiToolRisk.lower(value)
2122 +}
2123 +
2124 +
2125 +
2126 +
2127 +
2128 +public protocol FfiApprovalHandler: AnyObject, Sendable {
2129 +
2130 + func approve(call: FfiToolCall) async -> FfiApprovalDecision
2131 +
2132 +}
2133 +
2134 +
2135 +// Put the implementation in a struct so we don't pollute the top-level namespace
2136 +fileprivate struct UniffiCallbackInterfaceFfiApprovalHandler {
2137 +
2138 + // Create the VTable using a series of closures.
2139 + // Swift automatically converts these into C callback functions.
2140 + //
2141 + // This creates 1-element array, since this seems to be the only way to construct a const
2142 + // pointer that we can pass to the Rust code.
2143 + static let vtable: [UniffiVTableCallbackInterfaceFfiApprovalHandler] = [UniffiVTableCallbackInterfaceFfiApprovalHandler(
2144 + uniffiFree: { (uniffiHandle: UInt64) -> () in
2145 + do {
2146 + try FfiConverterCallbackInterfaceFfiApprovalHandler.handleMap.remove(handle: uniffiHandle)
2147 + } catch {
2148 + print("Uniffi callback interface FfiApprovalHandler: handle missing in uniffiFree")
2149 + }
2150 + },
2151 + uniffiClone: { (uniffiHandle: UInt64) -> UInt64 in
2152 + do {
2153 + return try FfiConverterCallbackInterfaceFfiApprovalHandler.handleMap.clone(handle: uniffiHandle)
2154 + } catch {
2155 + fatalError("Uniffi callback interface FfiApprovalHandler: handle missing in uniffiClone")
2156 + }
2157 + },
2158 + approve: { (
2159 + uniffiHandle: UInt64,
2160 + call: RustBuffer,
2161 + uniffiFutureCallback: @escaping UniffiForeignFutureCompleteRustBuffer,
2162 + uniffiCallbackData: UInt64,
2163 + uniffiOutDroppedCallback: UnsafeMutablePointer<UniffiForeignFutureDroppedCallbackStruct>
2164 + ) in
2165 + let makeCall = {
2166 + () async throws -> FfiApprovalDecision in
2167 + guard let uniffiObj = try? FfiConverterCallbackInterfaceFfiApprovalHandler.handleMap.get(handle: uniffiHandle) else {
2168 + throw UniffiInternalError.unexpectedStaleHandle
2169 + }
2170 + return await uniffiObj.approve(
2171 + call: try FfiConverterTypeFfiToolCall_lift(call)
2172 + )
2173 + }
2174 +
2175 + let uniffiHandleSuccess = { (returnValue: FfiApprovalDecision) in
2176 + uniffiFutureCallback(
2177 + uniffiCallbackData,
2178 + UniffiForeignFutureResultRustBuffer(
2179 + returnValue: FfiConverterTypeFfiApprovalDecision_lower(returnValue),
2180 + callStatus: RustCallStatus()
2181 + )
2182 + )
2183 + }
2184 + let uniffiHandleError = { (statusCode, errorBuf) in
2185 + uniffiFutureCallback(
2186 + uniffiCallbackData,
2187 + UniffiForeignFutureResultRustBuffer(
2188 + returnValue: RustBuffer.empty(),
2189 + callStatus: RustCallStatus(code: statusCode, errorBuf: errorBuf)
2190 + )
2191 + )
2192 + }
2193 + uniffiTraitInterfaceCallAsync(
2194 + makeCall: makeCall,
2195 + handleSuccess: uniffiHandleSuccess,
2196 + handleError: uniffiHandleError,
2197 + droppedCallback: uniffiOutDroppedCallback
2198 + )
2199 + }
2200 + )]
2201 +}
2202 +
2203 +private func uniffiCallbackInitFfiApprovalHandler() {
2204 + uniffi_ed_agent_ffi_fn_init_callback_vtable_ffiapprovalhandler(UniffiCallbackInterfaceFfiApprovalHandler.vtable)
2205 +}
2206 +
2207 +// FfiConverter protocol for callback interfaces
2208 +#if swift(>=5.8)
2209 +@_documentation(visibility: private)
2210 +#endif
2211 +fileprivate struct FfiConverterCallbackInterfaceFfiApprovalHandler {
2212 + fileprivate static let handleMap = UniffiHandleMap<FfiApprovalHandler>()
2213 +}
2214 +
2215 +#if swift(>=5.8)
2216 +@_documentation(visibility: private)
2217 +#endif
2218 +extension FfiConverterCallbackInterfaceFfiApprovalHandler : FfiConverter {
2219 + typealias SwiftType = FfiApprovalHandler
2220 + typealias FfiType = UInt64
2221 +
2222 +#if swift(>=5.8)
2223 + @_documentation(visibility: private)
2224 +#endif
2225 + public static func lift(_ handle: UInt64) throws -> SwiftType {
2226 + try handleMap.get(handle: handle)
2227 + }
2228 +
2229 +#if swift(>=5.8)
2230 + @_documentation(visibility: private)
2231 +#endif
2232 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
2233 + let handle: UInt64 = try readInt(&buf)
2234 + return try lift(handle)
2235 + }
2236 +
2237 +#if swift(>=5.8)
2238 + @_documentation(visibility: private)
2239 +#endif
2240 + public static func lower(_ v: SwiftType) -> UInt64 {
2241 + return handleMap.insert(obj: v)
2242 + }
2243 +
2244 +#if swift(>=5.8)
2245 + @_documentation(visibility: private)
2246 +#endif
2247 + public static func write(_ v: SwiftType, into buf: inout [UInt8]) {
2248 + writeInt(&buf, lower(v))
2249 + }
2250 +}
2251 +
2252 +
2253 +#if swift(>=5.8)
2254 +@_documentation(visibility: private)
2255 +#endif
2256 +public func FfiConverterCallbackInterfaceFfiApprovalHandler_lift(_ handle: UInt64) throws -> FfiApprovalHandler {
2257 + return try FfiConverterCallbackInterfaceFfiApprovalHandler.lift(handle)
2258 +}
2259 +
2260 +#if swift(>=5.8)
2261 +@_documentation(visibility: private)
2262 +#endif
2263 +public func FfiConverterCallbackInterfaceFfiApprovalHandler_lower(_ v: FfiApprovalHandler) -> UInt64 {
2264 + return FfiConverterCallbackInterfaceFfiApprovalHandler.lower(v)
2265 +}
2266 +
2267 +
2268 +
2269 +
2270 +public protocol FfiEventListener: AnyObject, Sendable {
2271 +
2272 + func statusChanged(update: FfiStatusUpdate)
2273 +
2274 + func toolRequested(call: FfiToolCall)
2275 +
2276 + func approvalRequested(call: FfiToolCall)
2277 +
2278 + func toolStarted(call: FfiToolCall)
2279 +
2280 + func toolFinished(toolCallId: String, content: String, isError: Bool)
2281 +
2282 + func agentReplied(reply: FfiAgentReply)
2283 +
2284 + func warning(message: String)
2285 +
2286 +}
2287 +
2288 +
2289 +// Put the implementation in a struct so we don't pollute the top-level namespace
2290 +fileprivate struct UniffiCallbackInterfaceFfiEventListener {
2291 +
2292 + // Create the VTable using a series of closures.
2293 + // Swift automatically converts these into C callback functions.
2294 + //
2295 + // This creates 1-element array, since this seems to be the only way to construct a const
2296 + // pointer that we can pass to the Rust code.
2297 + static let vtable: [UniffiVTableCallbackInterfaceFfiEventListener] = [UniffiVTableCallbackInterfaceFfiEventListener(
2298 + uniffiFree: { (uniffiHandle: UInt64) -> () in
2299 + do {
2300 + try FfiConverterCallbackInterfaceFfiEventListener.handleMap.remove(handle: uniffiHandle)
2301 + } catch {
2302 + print("Uniffi callback interface FfiEventListener: handle missing in uniffiFree")
2303 + }
2304 + },
2305 + uniffiClone: { (uniffiHandle: UInt64) -> UInt64 in
2306 + do {
2307 + return try FfiConverterCallbackInterfaceFfiEventListener.handleMap.clone(handle: uniffiHandle)
2308 + } catch {
2309 + fatalError("Uniffi callback interface FfiEventListener: handle missing in uniffiClone")
2310 + }
2311 + },
2312 + statusChanged: { (
2313 + uniffiHandle: UInt64,
2314 + update: RustBuffer,
2315 + uniffiOutReturn: UnsafeMutableRawPointer,
2316 + uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
2317 + ) in
2318 + let makeCall = {
2319 + () throws -> () in
2320 + guard let uniffiObj = try? FfiConverterCallbackInterfaceFfiEventListener.handleMap.get(handle: uniffiHandle) else {
2321 + throw UniffiInternalError.unexpectedStaleHandle
2322 + }
2323 + return uniffiObj.statusChanged(
2324 + update: try FfiConverterTypeFfiStatusUpdate_lift(update)
2325 + )
2326 + }
2327 +
2328 +
2329 + let writeReturn = { () }
2330 + uniffiTraitInterfaceCall(
2331 + callStatus: uniffiCallStatus,
2332 + makeCall: makeCall,
2333 + writeReturn: writeReturn
2334 + )
2335 + },
2336 + toolRequested: { (
2337 + uniffiHandle: UInt64,
2338 + call: RustBuffer,
2339 + uniffiOutReturn: UnsafeMutableRawPointer,
2340 + uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
2341 + ) in
2342 + let makeCall = {
2343 + () throws -> () in
2344 + guard let uniffiObj = try? FfiConverterCallbackInterfaceFfiEventListener.handleMap.get(handle: uniffiHandle) else {
2345 + throw UniffiInternalError.unexpectedStaleHandle
2346 + }
2347 + return uniffiObj.toolRequested(
2348 + call: try FfiConverterTypeFfiToolCall_lift(call)
2349 + )
2350 + }
2351 +
2352 +
2353 + let writeReturn = { () }
2354 + uniffiTraitInterfaceCall(
2355 + callStatus: uniffiCallStatus,
2356 + makeCall: makeCall,
2357 + writeReturn: writeReturn
2358 + )
2359 + },
2360 + approvalRequested: { (
2361 + uniffiHandle: UInt64,
2362 + call: RustBuffer,
2363 + uniffiOutReturn: UnsafeMutableRawPointer,
2364 + uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
2365 + ) in
2366 + let makeCall = {
2367 + () throws -> () in
2368 + guard let uniffiObj = try? FfiConverterCallbackInterfaceFfiEventListener.handleMap.get(handle: uniffiHandle) else {
2369 + throw UniffiInternalError.unexpectedStaleHandle
2370 + }
2371 + return uniffiObj.approvalRequested(
2372 + call: try FfiConverterTypeFfiToolCall_lift(call)
2373 + )
2374 + }
2375 +
2376 +
2377 + let writeReturn = { () }
2378 + uniffiTraitInterfaceCall(
2379 + callStatus: uniffiCallStatus,
2380 + makeCall: makeCall,
2381 + writeReturn: writeReturn
2382 + )
2383 + },
2384 + toolStarted: { (
2385 + uniffiHandle: UInt64,
2386 + call: RustBuffer,
2387 + uniffiOutReturn: UnsafeMutableRawPointer,
2388 + uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
2389 + ) in
2390 + let makeCall = {
2391 + () throws -> () in
2392 + guard let uniffiObj = try? FfiConverterCallbackInterfaceFfiEventListener.handleMap.get(handle: uniffiHandle) else {
2393 + throw UniffiInternalError.unexpectedStaleHandle
2394 + }
2395 + return uniffiObj.toolStarted(
2396 + call: try FfiConverterTypeFfiToolCall_lift(call)
2397 + )
2398 + }
2399 +
2400 +
2401 + let writeReturn = { () }
2402 + uniffiTraitInterfaceCall(
2403 + callStatus: uniffiCallStatus,
2404 + makeCall: makeCall,
2405 + writeReturn: writeReturn
2406 + )
2407 + },
2408 + toolFinished: { (
2409 + uniffiHandle: UInt64,
2410 + toolCallId: RustBuffer,
2411 + content: RustBuffer,
2412 + isError: Int8,
2413 + uniffiOutReturn: UnsafeMutableRawPointer,
2414 + uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
2415 + ) in
2416 + let makeCall = {
2417 + () throws -> () in
2418 + guard let uniffiObj = try? FfiConverterCallbackInterfaceFfiEventListener.handleMap.get(handle: uniffiHandle) else {
2419 + throw UniffiInternalError.unexpectedStaleHandle
2420 + }
2421 + return uniffiObj.toolFinished(
2422 + toolCallId: try FfiConverterString.lift(toolCallId),
2423 + content: try FfiConverterString.lift(content),
2424 + isError: try FfiConverterBool.lift(isError)
2425 + )
2426 + }
2427 +
2428 +
2429 + let writeReturn = { () }
2430 + uniffiTraitInterfaceCall(
2431 + callStatus: uniffiCallStatus,
2432 + makeCall: makeCall,
2433 + writeReturn: writeReturn
2434 + )
2435 + },
2436 + agentReplied: { (
2437 + uniffiHandle: UInt64,
2438 + reply: RustBuffer,
2439 + uniffiOutReturn: UnsafeMutableRawPointer,
2440 + uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
2441 + ) in
2442 + let makeCall = {
2443 + () throws -> () in
2444 + guard let uniffiObj = try? FfiConverterCallbackInterfaceFfiEventListener.handleMap.get(handle: uniffiHandle) else {
2445 + throw UniffiInternalError.unexpectedStaleHandle
2446 + }
2447 + return uniffiObj.agentReplied(
2448 + reply: try FfiConverterTypeFfiAgentReply_lift(reply)
2449 + )
2450 + }
2451 +
2452 +
2453 + let writeReturn = { () }
2454 + uniffiTraitInterfaceCall(
2455 + callStatus: uniffiCallStatus,
2456 + makeCall: makeCall,
2457 + writeReturn: writeReturn
2458 + )
2459 + },
2460 + warning: { (
2461 + uniffiHandle: UInt64,
2462 + message: RustBuffer,
2463 + uniffiOutReturn: UnsafeMutableRawPointer,
2464 + uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
2465 + ) in
2466 + let makeCall = {
2467 + () throws -> () in
2468 + guard let uniffiObj = try? FfiConverterCallbackInterfaceFfiEventListener.handleMap.get(handle: uniffiHandle) else {
2469 + throw UniffiInternalError.unexpectedStaleHandle
2470 + }
2471 + return uniffiObj.warning(
2472 + message: try FfiConverterString.lift(message)
2473 + )
2474 + }
2475 +
2476 +
2477 + let writeReturn = { () }
2478 + uniffiTraitInterfaceCall(
2479 + callStatus: uniffiCallStatus,
2480 + makeCall: makeCall,
2481 + writeReturn: writeReturn
2482 + )
2483 + }
2484 + )]
2485 +}
2486 +
2487 +private func uniffiCallbackInitFfiEventListener() {
2488 + uniffi_ed_agent_ffi_fn_init_callback_vtable_ffieventlistener(UniffiCallbackInterfaceFfiEventListener.vtable)
2489 +}
2490 +
2491 +// FfiConverter protocol for callback interfaces
2492 +#if swift(>=5.8)
2493 +@_documentation(visibility: private)
2494 +#endif
2495 +fileprivate struct FfiConverterCallbackInterfaceFfiEventListener {
2496 + fileprivate static let handleMap = UniffiHandleMap<FfiEventListener>()
2497 +}
2498 +
2499 +#if swift(>=5.8)
2500 +@_documentation(visibility: private)
2501 +#endif
2502 +extension FfiConverterCallbackInterfaceFfiEventListener : FfiConverter {
2503 + typealias SwiftType = FfiEventListener
2504 + typealias FfiType = UInt64
2505 +
2506 +#if swift(>=5.8)
2507 + @_documentation(visibility: private)
2508 +#endif
2509 + public static func lift(_ handle: UInt64) throws -> SwiftType {
2510 + try handleMap.get(handle: handle)
2511 + }
2512 +
2513 +#if swift(>=5.8)
2514 + @_documentation(visibility: private)
2515 +#endif
2516 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
2517 + let handle: UInt64 = try readInt(&buf)
2518 + return try lift(handle)
2519 + }
2520 +
2521 +#if swift(>=5.8)
2522 + @_documentation(visibility: private)
2523 +#endif
2524 + public static func lower(_ v: SwiftType) -> UInt64 {
2525 + return handleMap.insert(obj: v)
2526 + }
2527 +
2528 +#if swift(>=5.8)
2529 + @_documentation(visibility: private)
2530 +#endif
2531 + public static func write(_ v: SwiftType, into buf: inout [UInt8]) {
2532 + writeInt(&buf, lower(v))
2533 + }
2534 +}
2535 +
2536 +
2537 +#if swift(>=5.8)
2538 +@_documentation(visibility: private)
2539 +#endif
2540 +public func FfiConverterCallbackInterfaceFfiEventListener_lift(_ handle: UInt64) throws -> FfiEventListener {
2541 + return try FfiConverterCallbackInterfaceFfiEventListener.lift(handle)
2542 +}
2543 +
2544 +#if swift(>=5.8)
2545 +@_documentation(visibility: private)
2546 +#endif
2547 +public func FfiConverterCallbackInterfaceFfiEventListener_lower(_ v: FfiEventListener) -> UInt64 {
2548 + return FfiConverterCallbackInterfaceFfiEventListener.lower(v)
2549 +}
2550 +
2551 +
2552 +
2553 +
2554 +public protocol FfiToolExecutor: AnyObject, Sendable {
2555 +
2556 + func execute(toolName: String, arguments: String) async -> FfiToolOutput
2557 +
2558 +}
2559 +
2560 +
2561 +// Put the implementation in a struct so we don't pollute the top-level namespace
2562 +fileprivate struct UniffiCallbackInterfaceFfiToolExecutor {
2563 +
2564 + // Create the VTable using a series of closures.
2565 + // Swift automatically converts these into C callback functions.
2566 + //
2567 + // This creates 1-element array, since this seems to be the only way to construct a const
2568 + // pointer that we can pass to the Rust code.
2569 + static let vtable: [UniffiVTableCallbackInterfaceFfiToolExecutor] = [UniffiVTableCallbackInterfaceFfiToolExecutor(
2570 + uniffiFree: { (uniffiHandle: UInt64) -> () in
2571 + do {
2572 + try FfiConverterCallbackInterfaceFfiToolExecutor.handleMap.remove(handle: uniffiHandle)
2573 + } catch {
2574 + print("Uniffi callback interface FfiToolExecutor: handle missing in uniffiFree")
2575 + }
2576 + },
2577 + uniffiClone: { (uniffiHandle: UInt64) -> UInt64 in
2578 + do {
2579 + return try FfiConverterCallbackInterfaceFfiToolExecutor.handleMap.clone(handle: uniffiHandle)
2580 + } catch {
2581 + fatalError("Uniffi callback interface FfiToolExecutor: handle missing in uniffiClone")
2582 + }
2583 + },
2584 + execute: { (
2585 + uniffiHandle: UInt64,
2586 + toolName: RustBuffer,
2587 + arguments: RustBuffer,
2588 + uniffiFutureCallback: @escaping UniffiForeignFutureCompleteRustBuffer,
2589 + uniffiCallbackData: UInt64,
2590 + uniffiOutDroppedCallback: UnsafeMutablePointer<UniffiForeignFutureDroppedCallbackStruct>
2591 + ) in
2592 + let makeCall = {
2593 + () async throws -> FfiToolOutput in
2594 + guard let uniffiObj = try? FfiConverterCallbackInterfaceFfiToolExecutor.handleMap.get(handle: uniffiHandle) else {
2595 + throw UniffiInternalError.unexpectedStaleHandle
2596 + }
2597 + return await uniffiObj.execute(
2598 + toolName: try FfiConverterString.lift(toolName),
2599 + arguments: try FfiConverterString.lift(arguments)
2600 + )
2601 + }
2602 +
2603 + let uniffiHandleSuccess = { (returnValue: FfiToolOutput) in
2604 + uniffiFutureCallback(
2605 + uniffiCallbackData,
2606 + UniffiForeignFutureResultRustBuffer(
2607 + returnValue: FfiConverterTypeFfiToolOutput_lower(returnValue),
2608 + callStatus: RustCallStatus()
2609 + )
2610 + )
2611 + }
2612 + let uniffiHandleError = { (statusCode, errorBuf) in
2613 + uniffiFutureCallback(
2614 + uniffiCallbackData,
2615 + UniffiForeignFutureResultRustBuffer(
2616 + returnValue: RustBuffer.empty(),
2617 + callStatus: RustCallStatus(code: statusCode, errorBuf: errorBuf)
2618 + )
2619 + )
2620 + }
2621 + uniffiTraitInterfaceCallAsync(
2622 + makeCall: makeCall,
2623 + handleSuccess: uniffiHandleSuccess,
2624 + handleError: uniffiHandleError,
2625 + droppedCallback: uniffiOutDroppedCallback
2626 + )
2627 + }
2628 + )]
2629 +}
2630 +
2631 +private func uniffiCallbackInitFfiToolExecutor() {
2632 + uniffi_ed_agent_ffi_fn_init_callback_vtable_ffitoolexecutor(UniffiCallbackInterfaceFfiToolExecutor.vtable)
2633 +}
2634 +
2635 +// FfiConverter protocol for callback interfaces
2636 +#if swift(>=5.8)
2637 +@_documentation(visibility: private)
2638 +#endif
2639 +fileprivate struct FfiConverterCallbackInterfaceFfiToolExecutor {
2640 + fileprivate static let handleMap = UniffiHandleMap<FfiToolExecutor>()
2641 +}
2642 +
2643 +#if swift(>=5.8)
2644 +@_documentation(visibility: private)
2645 +#endif
2646 +extension FfiConverterCallbackInterfaceFfiToolExecutor : FfiConverter {
2647 + typealias SwiftType = FfiToolExecutor
2648 + typealias FfiType = UInt64
2649 +
2650 +#if swift(>=5.8)
2651 + @_documentation(visibility: private)
2652 +#endif
2653 + public static func lift(_ handle: UInt64) throws -> SwiftType {
2654 + try handleMap.get(handle: handle)
2655 + }
2656 +
2657 +#if swift(>=5.8)
2658 + @_documentation(visibility: private)
2659 +#endif
2660 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
2661 + let handle: UInt64 = try readInt(&buf)
2662 + return try lift(handle)
2663 + }
2664 +
2665 +#if swift(>=5.8)
2666 + @_documentation(visibility: private)
2667 +#endif
2668 + public static func lower(_ v: SwiftType) -> UInt64 {
2669 + return handleMap.insert(obj: v)
2670 + }
2671 +
2672 +#if swift(>=5.8)
2673 + @_documentation(visibility: private)
2674 +#endif
2675 + public static func write(_ v: SwiftType, into buf: inout [UInt8]) {
2676 + writeInt(&buf, lower(v))
2677 + }
2678 +}
2679 +
2680 +
2681 +#if swift(>=5.8)
2682 +@_documentation(visibility: private)
2683 +#endif
2684 +public func FfiConverterCallbackInterfaceFfiToolExecutor_lift(_ handle: UInt64) throws -> FfiToolExecutor {
2685 + return try FfiConverterCallbackInterfaceFfiToolExecutor.lift(handle)
2686 +}
2687 +
2688 +#if swift(>=5.8)
2689 +@_documentation(visibility: private)
2690 +#endif
2691 +public func FfiConverterCallbackInterfaceFfiToolExecutor_lower(_ v: FfiToolExecutor) -> UInt64 {
2692 + return FfiConverterCallbackInterfaceFfiToolExecutor.lower(v)
2693 +}
2694 +
2695 +#if swift(>=5.8)
2696 +@_documentation(visibility: private)
2697 +#endif
2698 +fileprivate struct FfiConverterOptionUInt64: FfiConverterRustBuffer {
2699 + typealias SwiftType = UInt64?
2700 +
2701 + public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
2702 + guard let value = value else {
2703 + writeInt(&buf, Int8(0))
2704 + return
2705 + }
2706 + writeInt(&buf, Int8(1))
2707 + FfiConverterUInt64.write(value, into: &buf)
2708 + }
2709 +
2710 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
2711 + switch try readInt(&buf) as Int8 {
2712 + case 0: return nil
2713 + case 1: return try FfiConverterUInt64.read(from: &buf)
2714 + default: throw UniffiInternalError.unexpectedOptionalTag
2715 + }
2716 + }
2717 +}
2718 +
2719 +#if swift(>=5.8)
2720 +@_documentation(visibility: private)
2721 +#endif
2722 +fileprivate struct FfiConverterOptionFloat: FfiConverterRustBuffer {
2723 + typealias SwiftType = Float?
2724 +
2725 + public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
2726 + guard let value = value else {
2727 + writeInt(&buf, Int8(0))
2728 + return
2729 + }
2730 + writeInt(&buf, Int8(1))
2731 + FfiConverterFloat.write(value, into: &buf)
2732 + }
2733 +
2734 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
2735 + switch try readInt(&buf) as Int8 {
2736 + case 0: return nil
2737 + case 1: return try FfiConverterFloat.read(from: &buf)
2738 + default: throw UniffiInternalError.unexpectedOptionalTag
2739 + }
2740 + }
2741 +}
2742 +
2743 +#if swift(>=5.8)
2744 +@_documentation(visibility: private)
2745 +#endif
2746 +fileprivate struct FfiConverterOptionDouble: FfiConverterRustBuffer {
2747 + typealias SwiftType = Double?
2748 +
2749 + public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
2750 + guard let value = value else {
2751 + writeInt(&buf, Int8(0))
2752 + return
2753 + }
2754 + writeInt(&buf, Int8(1))
2755 + FfiConverterDouble.write(value, into: &buf)
2756 + }
2757 +
2758 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
2759 + switch try readInt(&buf) as Int8 {
2760 + case 0: return nil
2761 + case 1: return try FfiConverterDouble.read(from: &buf)
2762 + default: throw UniffiInternalError.unexpectedOptionalTag
2763 + }
2764 + }
2765 +}
2766 +
2767 +#if swift(>=5.8)
2768 +@_documentation(visibility: private)
2769 +#endif
2770 +fileprivate struct FfiConverterOptionString: FfiConverterRustBuffer {
2771 + typealias SwiftType = String?
2772 +
2773 + public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
2774 + guard let value = value else {
2775 + writeInt(&buf, Int8(0))
2776 + return
2777 + }
2778 + writeInt(&buf, Int8(1))
2779 + FfiConverterString.write(value, into: &buf)
2780 + }
2781 +
2782 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
2783 + switch try readInt(&buf) as Int8 {
2784 + case 0: return nil
2785 + case 1: return try FfiConverterString.read(from: &buf)
2786 + default: throw UniffiInternalError.unexpectedOptionalTag
2787 + }
2788 + }
2789 +}
2790 +
2791 +#if swift(>=5.8)
2792 +@_documentation(visibility: private)
2793 +#endif
2794 +fileprivate struct FfiConverterOptionTypeFfiAgentConfig: FfiConverterRustBuffer {
2795 + typealias SwiftType = FfiAgentConfig?
2796 +
2797 + public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
2798 + guard let value = value else {
2799 + writeInt(&buf, Int8(0))
2800 + return
2801 + }
2802 + writeInt(&buf, Int8(1))
2803 + FfiConverterTypeFfiAgentConfig.write(value, into: &buf)
2804 + }
2805 +
2806 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
2807 + switch try readInt(&buf) as Int8 {
2808 + case 0: return nil
2809 + case 1: return try FfiConverterTypeFfiAgentConfig.read(from: &buf)
2810 + default: throw UniffiInternalError.unexpectedOptionalTag
2811 + }
2812 + }
2813 +}
2814 +
2815 +#if swift(>=5.8)
2816 +@_documentation(visibility: private)
2817 +#endif
2818 +fileprivate struct FfiConverterOptionTypeFfiSamplingConfig: FfiConverterRustBuffer {
2819 + typealias SwiftType = FfiSamplingConfig?
2820 +
2821 + public static func write(_ value: SwiftType, into buf: inout [UInt8]) {
2822 + guard let value = value else {
2823 + writeInt(&buf, Int8(0))
2824 + return
2825 + }
2826 + writeInt(&buf, Int8(1))
2827 + FfiConverterTypeFfiSamplingConfig.write(value, into: &buf)
2828 + }
2829 +
2830 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType {
2831 + switch try readInt(&buf) as Int8 {
2832 + case 0: return nil
2833 + case 1: return try FfiConverterTypeFfiSamplingConfig.read(from: &buf)
2834 + default: throw UniffiInternalError.unexpectedOptionalTag
2835 + }
2836 + }
2837 +}
2838 +
2839 +#if swift(>=5.8)
2840 +@_documentation(visibility: private)
2841 +#endif
2842 +fileprivate struct FfiConverterSequenceString: FfiConverterRustBuffer {
2843 + typealias SwiftType = [String]
2844 +
2845 + public static func write(_ value: [String], into buf: inout [UInt8]) {
2846 + let len = Int32(value.count)
2847 + writeInt(&buf, len)
2848 + for item in value {
2849 + FfiConverterString.write(item, into: &buf)
2850 + }
2851 + }
2852 +
2853 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [String] {
2854 + let len: Int32 = try readInt(&buf)
2855 + var seq = [String]()
2856 + seq.reserveCapacity(Int(len))
2857 + for _ in 0 ..< len {
2858 + seq.append(try FfiConverterString.read(from: &buf))
2859 + }
2860 + return seq
2861 + }
2862 +}
2863 +
2864 +#if swift(>=5.8)
2865 +@_documentation(visibility: private)
2866 +#endif
2867 +fileprivate struct FfiConverterSequenceTypeFfiChatMessage: FfiConverterRustBuffer {
2868 + typealias SwiftType = [FfiChatMessage]
2869 +
2870 + public static func write(_ value: [FfiChatMessage], into buf: inout [UInt8]) {
2871 + let len = Int32(value.count)
2872 + writeInt(&buf, len)
2873 + for item in value {
2874 + FfiConverterTypeFfiChatMessage.write(item, into: &buf)
2875 + }
2876 + }
2877 +
2878 + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [FfiChatMessage] {
2879 + let len: Int32 = try readInt(&buf)
2880 + var seq = [FfiChatMessage]()
2881 + seq.reserveCapacity(Int(len))
2882 + for _ in 0 ..< len {
2883 + seq.append(try FfiConverterTypeFfiChatMessage.read(from: &buf))
2884 + }
2885 + return seq
2886 + }
2887 +}
2888 +private let UNIFFI_RUST_FUTURE_POLL_READY: Int8 = 0
2889 +private let UNIFFI_RUST_FUTURE_POLL_WAKE: Int8 = 1
2890 +
2891 +fileprivate let uniffiContinuationHandleMap = UniffiHandleMap<UnsafeContinuation<Int8, Never>>()
2892 +
2893 +fileprivate func uniffiRustCallAsync<F, T>(
2894 + rustFutureFunc: () -> UInt64,
2895 + pollFunc: (UInt64, @escaping UniffiRustFutureContinuationCallback, UInt64) -> (),
2896 + completeFunc: (UInt64, UnsafeMutablePointer<RustCallStatus>) -> F,
2897 + freeFunc: (UInt64) -> (),
2898 + liftFunc: (F) throws -> T,
2899 + errorHandler: ((RustBuffer) throws -> Swift.Error)?
2900 +) async throws -> T {
2901 + // Make sure to call the ensure init function since future creation doesn't have a
2902 + // RustCallStatus param, so doesn't use makeRustCall()
2903 + uniffiEnsureEdAgentFfiInitialized()
2904 + let rustFuture = rustFutureFunc()
2905 + defer {
2906 + freeFunc(rustFuture)
2907 + }
2908 + var pollResult: Int8;
2909 + repeat {
2910 + pollResult = await withUnsafeContinuation {
2911 + pollFunc(
2912 + rustFuture,
2913 + { handle, pollResult in
2914 + uniffiFutureContinuationCallback(handle: handle, pollResult: pollResult)
2915 + },
2916 + uniffiContinuationHandleMap.insert(obj: $0)
2917 + )
2918 + }
2919 + } while pollResult != UNIFFI_RUST_FUTURE_POLL_READY
2920 +
2921 + return try liftFunc(makeRustCall(
2922 + { completeFunc(rustFuture, $0) },
2923 + errorHandler: errorHandler
2924 + ))
2925 +}
2926 +
2927 +// Callback handlers for an async calls. These are invoked by Rust when the future is ready. They
2928 +// lift the return value or error and resume the suspended function.
2929 +fileprivate func uniffiFutureContinuationCallback(handle: UInt64, pollResult: Int8) {
2930 + if let continuation = try? uniffiContinuationHandleMap.remove(handle: handle) {
2931 + continuation.resume(returning: pollResult)
2932 + } else {
2933 + print("uniffiFutureContinuationCallback invalid handle")
2934 + }
2935 +}
2936 +private func uniffiTraitInterfaceCallAsync<T>(
2937 + makeCall: @escaping () async throws -> T,
2938 + handleSuccess: @escaping (T) -> (),
2939 + handleError: @escaping (Int8, RustBuffer) -> (),
2940 + droppedCallback: UnsafeMutablePointer<UniffiForeignFutureDroppedCallbackStruct>
2941 +) {
2942 + let task = Task {
2943 + // Note: it's important we call either `handleSuccess` or `handleError` exactly once. Each
2944 + // call consumes an Arc reference, which means there should be no possibility of a double
2945 + // call. The following code is structured so that will will never call both `handleSuccess`
2946 + // and `handleError`, even in the face of weird errors.
2947 + //
2948 + // On platforms that need extra machinery to make C-ABI calls, like JNA or ctypes, it's
2949 + // possible that we fail to make either call. However, it doesn't seem like this is
2950 + // possible on Swift since swift can just make the C call directly.
2951 + var callResult: T
2952 + do {
2953 + callResult = try await makeCall()
2954 + } catch {
2955 + handleError(CALL_UNEXPECTED_ERROR, FfiConverterString.lower(String(describing: error)))
2956 + return
2957 + }
2958 + handleSuccess(callResult)
2959 + }
2960 + let handle = UNIFFI_FOREIGN_FUTURE_HANDLE_MAP.insert(obj: task)
2961 + droppedCallback.pointee = UniffiForeignFutureDroppedCallbackStruct(
2962 + handle: handle,
2963 + free: uniffiForeignFutureDroppedCallback
2964 + )
2965 +}
2966 +
2967 +private func uniffiTraitInterfaceCallAsyncWithError<T, E>(
2968 + makeCall: @escaping () async throws -> T,
2969 + handleSuccess: @escaping (T) -> (),
2970 + handleError: @escaping (Int8, RustBuffer) -> (),
2971 + lowerError: @escaping (E) -> RustBuffer,
2972 + droppedCallback: UnsafeMutablePointer<UniffiForeignFutureDroppedCallbackStruct>
2973 +) {
2974 + let task = Task {
2975 + // See the note in uniffiTraitInterfaceCallAsync for details on `handleSuccess` and
2976 + // `handleError`.
2977 + var callResult: T
2978 + do {
2979 + callResult = try await makeCall()
2980 + } catch let error as E {
2981 + handleError(CALL_ERROR, lowerError(error))
2982 + return
2983 + } catch {
2984 + handleError(CALL_UNEXPECTED_ERROR, FfiConverterString.lower(String(describing: error)))
2985 + return
2986 + }
2987 + handleSuccess(callResult)
2988 + }
2989 + let handle = UNIFFI_FOREIGN_FUTURE_HANDLE_MAP.insert(obj: task)
2990 + droppedCallback.pointee = UniffiForeignFutureDroppedCallbackStruct(
2991 + handle: handle,
2992 + free: uniffiForeignFutureDroppedCallback
2993 + )
2994 +}
2995 +
2996 +// Borrow the callback handle map implementation to store foreign future handles
2997 +// TODO: consolidate the handle-map code (https://github.com/mozilla/uniffi-rs/pull/1823)
2998 +fileprivate let UNIFFI_FOREIGN_FUTURE_HANDLE_MAP = UniffiHandleMap<UniffiForeignFutureTask>()
2999 +
3000 +// Protocol for tasks that handle foreign futures.
3001 +//
3002 +// Defining a protocol allows all tasks to be stored in the same handle map. This can't be done
3003 +// with the task object itself, since has generic parameters.
3004 +fileprivate protocol UniffiForeignFutureTask {
3005 + func cancel()
3006 +}
3007 +
3008 +extension Task: UniffiForeignFutureTask {}
3009 +
3010 +private func uniffiForeignFutureDroppedCallback(handle: UInt64) {
3011 + do {
3012 + let task = try UNIFFI_FOREIGN_FUTURE_HANDLE_MAP.remove(handle: handle)
3013 + // Set the cancellation flag on the task. If it's still running, the code can check the
3014 + // cancellation flag or call `Task.checkCancellation()`. If the task has completed, this is
3015 + // a no-op.
3016 + task.cancel()
3017 + } catch {
3018 + print("uniffiForeignFutureDroppedCallback: handle missing from handlemap")
3019 + }
3020 +}
3021 +
3022 +// For testing
3023 +public func uniffiForeignFutureHandleCountEdAgentFfi() -> Int {
3024 + UNIFFI_FOREIGN_FUTURE_HANDLE_MAP.count
3025 +}
3026 +public func configureCacheDir(path: String) {try! rustCall() {
3027 + uniffi_ed_agent_ffi_fn_func_configure_cache_dir(
3028 + FfiConverterString.lower(path),$0
3029 + )
3030 +}
3031 +}
3032 +public func defaultAgentModelConfig() -> FfiGgufModelConfig {
3033 + return try! FfiConverterTypeFfiGgufModelConfig_lift(try! rustCall() {
3034 + uniffi_ed_agent_ffi_fn_func_default_agent_model_config($0
3035 + )
3036 +})
3037 +}
3038 +
3039 +private enum InitializationResult {
3040 + case ok
3041 + case contractVersionMismatch
3042 + case apiChecksumMismatch
3043 +}
3044 +// Use a global variable to perform the versioning checks. Swift ensures that
3045 +// the code inside is only computed once.
3046 +private let initializationResult: InitializationResult = {
3047 + // Get the bindings contract version from our ComponentInterface
3048 + let bindings_contract_version = 30
3049 + // Get the scaffolding contract version by calling the into the dylib
3050 + let scaffolding_contract_version = ffi_ed_agent_ffi_uniffi_contract_version()
3051 + if bindings_contract_version != scaffolding_contract_version {
3052 + return InitializationResult.contractVersionMismatch
3053 + }
3054 + if (uniffi_ed_agent_ffi_checksum_func_configure_cache_dir() != 30620) {
3055 + return InitializationResult.apiChecksumMismatch
3056 + }
3057 + if (uniffi_ed_agent_ffi_checksum_func_default_agent_model_config() != 44321) {
3058 + return InitializationResult.apiChecksumMismatch
3059 + }
3060 + if (uniffi_ed_agent_ffi_checksum_method_ffiedagent_cancel() != 42085) {
3061 + return InitializationResult.apiChecksumMismatch
3062 + }
3063 + if (uniffi_ed_agent_ffi_checksum_method_ffiedagent_clear_history() != 19615) {
3064 + return InitializationResult.apiChecksumMismatch
3065 + }
3066 + if (uniffi_ed_agent_ffi_checksum_method_ffiedagent_history() != 36014) {
3067 + return InitializationResult.apiChecksumMismatch
3068 + }
3069 + if (uniffi_ed_agent_ffi_checksum_method_ffiedagent_info() != 9944) {
3070 + return InitializationResult.apiChecksumMismatch
3071 + }
3072 + if (uniffi_ed_agent_ffi_checksum_method_ffiedagent_is_loaded() != 28871) {
3073 + return InitializationResult.apiChecksumMismatch
3074 + }
3075 + if (uniffi_ed_agent_ffi_checksum_method_ffiedagent_load_assigned_model() != 60966) {
3076 + return InitializationResult.apiChecksumMismatch
3077 + }
3078 + if (uniffi_ed_agent_ffi_checksum_method_ffiedagent_load_default_agent_model() != 47518) {
3079 + return InitializationResult.apiChecksumMismatch
3080 + }
3081 + if (uniffi_ed_agent_ffi_checksum_method_ffiedagent_load_gguf_model() != 17854) {
3082 + return InitializationResult.apiChecksumMismatch
3083 + }
3084 + if (uniffi_ed_agent_ffi_checksum_method_ffiedagent_load_uqff_model() != 11023) {
3085 + return InitializationResult.apiChecksumMismatch
3086 + }
3087 + if (uniffi_ed_agent_ffi_checksum_method_ffiedagent_register_tool() != 34863) {
3088 + return InitializationResult.apiChecksumMismatch
3089 + }
3090 + if (uniffi_ed_agent_ffi_checksum_method_ffiedagent_remove_all_tools() != 36535) {
3091 + return InitializationResult.apiChecksumMismatch
3092 + }
3093 + if (uniffi_ed_agent_ffi_checksum_method_ffiedagent_run() != 39233) {
3094 + return InitializationResult.apiChecksumMismatch
3095 + }
3096 + if (uniffi_ed_agent_ffi_checksum_method_ffiedagent_send() != 839) {
3097 + return InitializationResult.apiChecksumMismatch
3098 + }
3099 + if (uniffi_ed_agent_ffi_checksum_method_ffiedagent_unload() != 29612) {
3100 + return InitializationResult.apiChecksumMismatch
3101 + }
3102 + if (uniffi_ed_agent_ffi_checksum_method_ffiedagent_unregister_tool() != 63973) {
3103 + return InitializationResult.apiChecksumMismatch
3104 + }
3105 + if (uniffi_ed_agent_ffi_checksum_constructor_ffiedagent_new() != 19584) {
3106 + return InitializationResult.apiChecksumMismatch
3107 + }
3108 + if (uniffi_ed_agent_ffi_checksum_method_ffiapprovalhandler_approve() != 12591) {
3109 + return InitializationResult.apiChecksumMismatch
3110 + }
3111 + if (uniffi_ed_agent_ffi_checksum_method_ffieventlistener_status_changed() != 50680) {
3112 + return InitializationResult.apiChecksumMismatch
3113 + }
3114 + if (uniffi_ed_agent_ffi_checksum_method_ffieventlistener_tool_requested() != 58928) {
3115 + return InitializationResult.apiChecksumMismatch
3116 + }
3117 + if (uniffi_ed_agent_ffi_checksum_method_ffieventlistener_approval_requested() != 54477) {
3118 + return InitializationResult.apiChecksumMismatch
3119 + }
3120 + if (uniffi_ed_agent_ffi_checksum_method_ffieventlistener_tool_started() != 23754) {
3121 + return InitializationResult.apiChecksumMismatch
3122 + }
3123 + if (uniffi_ed_agent_ffi_checksum_method_ffieventlistener_tool_finished() != 4350) {
3124 + return InitializationResult.apiChecksumMismatch
3125 + }
3126 + if (uniffi_ed_agent_ffi_checksum_method_ffieventlistener_agent_replied() != 33842) {
3127 + return InitializationResult.apiChecksumMismatch
3128 + }
3129 + if (uniffi_ed_agent_ffi_checksum_method_ffieventlistener_warning() != 43170) {
3130 + return InitializationResult.apiChecksumMismatch
3131 + }
3132 + if (uniffi_ed_agent_ffi_checksum_method_ffitoolexecutor_execute() != 36465) {
3133 + return InitializationResult.apiChecksumMismatch
3134 + }
3135 +
3136 + uniffiCallbackInitFfiApprovalHandler()
3137 + uniffiCallbackInitFfiEventListener()
3138 + uniffiCallbackInitFfiToolExecutor()
3139 + return InitializationResult.ok
3140 +}()
3141 +
3142 +// Make the ensure init function public so that other modules which have external type references to
3143 +// our types can call it.
3144 +public func uniffiEnsureEdAgentFfiInitialized() {
3145 + switch initializationResult {
3146 + case .ok:
3147 + break
3148 + case .contractVersionMismatch:
3149 + fatalError("UniFFI contract version mismatch: try cleaning and rebuilding your project")
3150 + case .apiChecksumMismatch:
3151 + fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
3152 + }
3153 +}
3154 +
3155 +// swiftlint:enable all
\ No newline at end of file
Tests/EdTests/EdPublicTypesTests.swift new
+19
@@ -0,0 +1,19 @@
1 +import Testing
2 +@testable import Ed
3 +
4 +@Test func readOnlyDefinitionKeepsItsSchema() {
5 + let definition = EdToolDefinition.readOnly(
6 + name: "current_battery",
7 + description: "Read the current battery percentage",
8 + parametersSchema: #"{"type":"object","properties":{}}"#
9 + )
10 +
11 + #expect(definition.name == "current_battery")
12 + #expect(definition.parametersSchema.contains("properties"))
13 +}
14 +
15 +@Test func configurationHasSafeDefaults() {
16 + let configuration = EdAgentConfiguration()
17 + #expect(configuration.maxToolRounds == 8)
18 + #expect(configuration.maxToolOutputCharacters == 10_000)
19 +}
readme.md deleted
-1
@@ -1 +0,0 @@
1 -# Ed Swift