QFWFUWBE35PB7IKKX5QNVDTVGHR6ZB43MEDRX3F4NFQBG5BKXLBQC
// Copyright © 2024 Ryan Booker. All rights reserved.
import ArgumentParser
import Foundation
extension URL: ExpressibleByArgument {
public init?(argument: String) {
self.init(string: argument)
}
public var defaultValueDescription: String {
absoluteString
}
}
// Copyright © 2024 Ryan Booker. All rights reserved.
import ArgumentParser
import Foundation
extension Kagi {
struct Search: AsyncParsableCommand {
static let configuration = CommandConfiguration(
commandName: "search",
abstract: "Search for something (Beta, requires Kagi Business (Team) plan).",
usage: "kg search \"Do androids dream of electric sheep?\""
)
@Argument(help: "Something to search for") var query: String
@Option(help: "The maximum number of search results") var limit: Int?
mutating func run() async throws {
do {
let response = try await process(query, limit: limit)
print(response)
} catch {
throw ValidationError(error.localizedDescription)
}
}
}
}
// MARK: - Processing
extension Kagi.Search {
func process(_ query: String, limit: Int?) async throws -> Kagi.Response<[Either<SearchResult, RelatedResults>]> {
var queryItems: [URLQueryItem] = [.init(name: "q", value: query)]
if let limit {
queryItems.append(.init(name: "limit", value: "\(limit)"))
}
var request = try Kagi.Endpoint.search.authorizedRequest
request.url?.append(queryItems: queryItems)
let (data, response) = try await URLSession.shared.data(for: request)
do {
return try JSONDecoder().decode(Kagi.Response.self, from: data)
} catch {
#if DEBUG
print(response)
print(error)
print("-----")
#endif
throw error
}
}
}
// MARK: - Response
extension Kagi.Search {
struct SearchResult: CustomStringConvertible, Decodable {
struct Thumbnail: Decodable {
var url: URL
var height: Int
var width: Int
}
var rank: Int
var url: URL
var title: String
var snippet: String?
var published: Date?
var thumbnail: Thumbnail?
var description: String {
[
"""
\(rank): \(title)
\(url)
-----
""",
snippet.map {
"""
\($0)
-----
"""
},
published.map {
"""
\($0.formatted(date: .long, time: .shortened))
-----
"""
}
]
.compactMap { $0 }
.joined(separator: "\n")
}
}
struct RelatedResults: CustomStringConvertible, Decodable {
var list: [String]
var description: String {
"""
Possibly related searches:
\(list.map { "- \($0)" })
"""
}
}
}
extension Array where Element == Either<Kagi.Search.SearchResult, Kagi.Search.RelatedResults> {
var description: String {
"""
Results:
\(map(\.description).joined(separator: "\n\n"))
"""
}
}
// Copyright © 2024 Ryan Booker. All rights reserved.
import ArgumentParser
import Foundation
extension Kagi {
struct Summarize: AsyncParsableCommand {
static let configuration = CommandConfiguration(
commandName: "summarize",
abstract: "Summarize something.",
usage: "kg summarize \"Some text or a url to summarize.\""
)
@Argument(help: "Some text or a url to summarize") var query: Either<URL, String>
@Option(help: Engine.help) var engine: Engine?
@Option(help: SummaryType.help) var summaryType: SummaryType?
mutating func run() async throws {
do {
let response = try await process(query, engine: engine, summaryType: summaryType)
print(response)
} catch {
throw ValidationError(error.localizedDescription)
}
}
}
}
// MARK: - Processing
extension Kagi.Summarize {
func process(_ query: Either<URL, String>, engine: Engine?, summaryType: SummaryType?) async throws -> Kagi.Response<Summarization> {
var body: [String: Any] = query.reduce(first: { ["url": $0.absoluteString] }, second: { ["text": $0] })
if let engine {
body["engine"] = engine.rawValue
}
if let summaryType {
body["summary_type"] = summaryType.rawValue
}
request.httpBody = try JSONSerialization.data(withJSONObject: body)
let (data, response) = try await URLSession.shared.data(for: request)
do {
return try JSONDecoder().decode(Kagi.Response.self, from: data)
} catch {
#if DEBUG
print(response)
print(error)
print("-----")
#endif
throw error
}
}
}
// MARK: - Response
extension Kagi.Summarize {
enum Engine: String, CaseIterable, CustomStringConvertible, ExpressibleByArgument {
case cecil
case agnes
case daphne
case muriel
var description: String {
switch self {
case .cecil:
"Friendly, descriptive, fast summary (default)"
case .agnes:
"Formal, technical, analytical summary"
case .daphne:
"Informal, creative, friendly summary"
case .muriel:
"Best-in-class summary using our enterprise-grade model"
}
}
static var help: ArgumentHelp? {
.init(
allCases.map { "- \($0.rawValue): \($0.description)" }.joined(separator: "\n") + "\n"
)
}
var defaultValueDescription: String {
Self.cecil.rawValue
}
}
enum SummaryType: String, CaseIterable, CustomStringConvertible, ExpressibleByArgument {
case summary
case takeaway
var description: String {
switch self {
case .summary:
"Paragraph(s) of summary prose (default)"
case .takeaway:
"Bulleted list of key points"
}
}
static var help: ArgumentHelp? {
.init(
allCases.map { "- \($0.rawValue): \($0.description)" }.joined(separator: "\n") + "\n"
)
}
var defaultValueDescription: String {
Self.summary.rawValue
}
}
struct Summarization: CustomStringConvertible, Decodable {
var output: String
var tokens: Int
var description: String {
"""
Summary:
\(output)
"""
}
}
}
var request = try Kagi.Endpoint.summarize.authorizedRequest
// Copyright © 2024 Ryan Booker. All rights reserved.
import Foundation
extension Result {
func reduce<T>(
success successResult: (Success) -> T,
failure failureResult: (Failure) -> T
) -> T {
switch self {
case let .success(value):
successResult(value)
case let .failure(error):
failureResult(error)
}
}
static func <|> <T, E>(lhs: Result<T, E>, rhs: Result<T, E>) -> Result<T, E> {
lhs.flatMapError { _ in
rhs
}
}
}
infix operator <|> : NilCoalescingPrecedence
// Copyright © 2024 Ryan Booker. All rights reserved.
import Foundation
extension Kagi {
struct Response<T>: CustomStringConvertible, Decodable where T: CustomStringConvertible & Decodable {
let meta: Metadata
let data: Result<T, Failure>
var description: String {
data.reduce(success: \.description, failure: \.description)
}
enum CodingKeys: CodingKey {
case meta, data, error
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.meta = try container.decode(Metadata.self, forKey: .meta)
do {
let data = try container.decode(T.self, forKey: .data)
self.data = .success(data)
} catch {
let reasons = try container.decode([Failure.Reason].self, forKey: .error)
self.data = .failure(.init(reasons: reasons))
}
}
}
}
// MARK: - Repsonse types
extension Kagi.Response {
struct Failure: CustomStringConvertible, Decodable, Error {
struct Reason: CustomStringConvertible, Decodable {
let code: Int
let msg: String
var description: String {
"\(code): \(msg)"
}
}
let reasons: [Reason]
var description: String {
"""
Whoops!
\(reasons.map(\.description).joined(separator: "\n\n"))
"""
}
}
struct Metadata: Decodable {
let id: String
let node: String
let ms: Int
}
}
// The Swift Programming Language
// https://docs.swift.org/swift-book
//
// Swift Argument Parser
// https://swiftpackageindex.com/apple/swift-argument-parser/documentation
import ArgumentParser
import Foundation
@main
struct Kagi: AsyncParsableCommand {
static let configuration = CommandConfiguration(
commandName: "kg",
abstract: "Interact with Kagi services.",
subcommands: [FastGPT.self, Search.self, Summarize.self]
)
}
// Copyright © 2024 Ryan Booker. All rights reserved.
import ArgumentParser
import Foundation
extension Kagi {
struct FastGPT: AsyncParsableCommand {
static let configuration = CommandConfiguration(
commandName: "fastgpt",
abstract: "Ask FastGPT something.",
usage: "kg fastgpt \"What is the answer to life, the universe, and everything?\""
)
@Argument(help: "A query for FastGPT") var query: String
mutating func run() async throws {
do {
let response = try await process(query)
print(response)
} catch {
throw ValidationError(error.localizedDescription)
}
}
}
}
// MARK: - Processing
extension Kagi.FastGPT {
func process(_ query: String) async throws -> Kagi.Response<Answer> {
var request = try Kagi.Endpoint.fastGPT.authorizedRequest
request.httpBody = try JSONSerialization.data(withJSONObject: ["query": query])
let (data, response) = try await URLSession.shared.data(for: request)
do {
return try JSONDecoder().decode(Kagi.Response.self, from: data)
} catch {
#if DEBUG
print(response)
print(error)
print("-----")
#endif
throw error
}
}
}
// MARK: - Response
extension Kagi.FastGPT {
struct Answer: CustomStringConvertible, Decodable {
struct Reference: CustomStringConvertible, Decodable {
var title: String
var snippet: String
var url: URL
var description: String {
"""
- \(title)
\(url)
\(snippet.trimmingCharacters(in: .whitespaces))
"""
}
}
var output: String
var tokens: Int
var references: [Reference]
var description: String {
"""
Answer:
\(output)
References:
\(references.map(\.description).joined(separator: "\n\n"))
"""
}
}
}
// Copyright © 2024 Ryan Booker. All rights reserved.
import ArgumentParser
import Foundation
extension Kagi {
enum Endpoint: String {
static let baseUrl = URL(string: "https://kagi.com/api/v0/")!
case fastGPT
case summarize
var url: URL {
URL(string: rawValue.lowercased(), relativeTo: Self.baseUrl)!
}
var authorizedRequest: URLRequest {
get throws {
guard let apiToken = ProcessInfo.processInfo.environment["FASTGPT_API_TOKEN"] else {
throw ValidationError("API key is missing. Set the environment variable FASTGPT_API_TOKEN.")
}
var request = self.request
request.setValue("Bot \(apiToken)", forHTTPHeaderField: "Authorization")
return request
}
}
}
}
}
var request: URLRequest {
var request = URLRequest(url: url)
request.httpMethod = httpMethod
if httpMethod == "POST" {
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
}
return request
var httpMethod: String {
switch self {
case .search:
return "GET"
case .fastGPT, .summarize:
return "POST"
}
}
case search
// Copyright © 2024 Ryan Booker. All rights reserved.
import ArgumentParser
import Foundation
enum Either<First, Second> {
case first(First)
case second(Second)
func reduce<T>(
first firstResult: (First) -> T,
second secondResult: (Second) -> T
) -> T {
switch self {
case let .first(value):
firstResult(value)
case let .second(error):
secondResult(error)
}
}
}
extension Either: ExpressibleByArgument
where First: ExpressibleByArgument, Second: ExpressibleByArgument {
init?(argument: String) {
if let value = First(argument: argument) {
self = .first(value)
} else if let value = Second(argument: argument) {
self = .second(value)
} else {
return nil
}
}
}
extension Array: Error where Element: Error {}
}
}
}
func tryBoth<A, First, Second>(
_ value: A,
first: (A) throws -> First,
second: (A) throws -> Second
) throws -> Either<First, Second> {
do {
return try .first(first(value))
} catch let firstError {
do {
return try .second(second(value))
} catch let secondError {
throw [firstError, secondError]
}
}
extension Either: CustomStringConvertible
where First: CustomStringConvertible, Second: CustomStringConvertible {
var description: String {
reduce(first: \.description, second: \.description)
}
}
extension Either: Decodable
where First: Decodable, Second: Decodable {
init(from decoder: Decoder) throws {
self = try tryBoth(decoder, first: First.init, second: Second.init)
// Copyright © 2024 Ryan Booker. All rights reserved.
import ArgumentParser
import Foundation
extension URL: ExpressibleByArgument {
public init?(argument: String) {
self.init(string: argument)
}
public var defaultValueDescription: String {
absoluteString
}
}
// Copyright © 2024 Ryan Booker. All rights reserved.
import Foundation
public extension Result {
func reduce<T>(
success successResult: (Success) -> T,
failure failureResult: (Failure) -> T
) -> T {
switch self {
case let .success(value):
successResult(value)
case let .failure(error):
failureResult(error)
}
}
}
// Copyright © 2024 Ryan Booker. All rights reserved.
import ArgumentParser
import Foundation
public enum Either<First, Second> {
case first(First)
case second(Second)
public func reduce<T>(
first firstResult: (First) -> T,
second secondResult: (Second) -> T
) -> T {
switch self {
case let .first(value):
firstResult(value)
case let .second(error):
secondResult(error)
}
}
}
extension Either: CustomStringConvertible
where First: CustomStringConvertible, Second: CustomStringConvertible {
public var description: String {
reduce(first: \.description, second: \.description)
}
}
extension Either: Decodable
where First: Decodable, Second: Decodable {
public init(from decoder: Decoder) throws {
self = try tryBoth(decoder, first: First.init, second: Second.init)
}
}
extension Either: ExpressibleByArgument
where First: ExpressibleByArgument, Second: ExpressibleByArgument {
public init?(argument: String) {
if let value = First(argument: argument) {
self = .first(value)
} else if let value = Second(argument: argument) {
self = .second(value)
} else {
return nil
}
}
}
public func tryBoth<A, First, Second>(
_ value: A,
first: (A) throws -> First,
second: (A) throws -> Second
) throws -> Either<First, Second> {
do {
return try .first(first(value))
} catch let firstError {
do {
return try .second(second(value))
} catch let secondError {
throw [firstError, secondError]
}
}
}
extension Array: Error where Element: Error {}
// Copyright © 2024 Ryan Booker. All rights reserved.
import ArgumentParser
import Domain
import Foundation
import Toolbox
public struct Summarize: AsyncParsableCommand {
public static let configuration = CommandConfiguration(
commandName: "summarize",
abstract: "Summarize something.",
usage: "kg summarize \"Some text or a url to summarize.\""
)
@Argument(help: "Some text or a url to summarize")
public var query: Either<URL, String>
@Option(help: Engine.help)
public var engine: Engine?
@Option(help: SummaryType.help)
public var summaryType: SummaryType?
public init() {
// Intentionally left empty
}
public mutating func run() async throws {
do {
let response = try await Client.liveValue.run(query: query, engine: engine, summaryType: summaryType)
print(response)
} catch {
throw ValidationError(error.localizedDescription)
}
}
}
// MARK: - Processing
extension Summarize {
struct Client {
var run: (
_ query: Either<URL, String>,
_ engine: Engine?,
_ summaryType: SummaryType?
) async throws -> Response<Summarization>
func run(
query: Either<URL, String>,
engine: Engine?,
summaryType: SummaryType?
) async throws -> Response<Summarization> {
try await run(query, engine, summaryType)
}
}
}
extension Summarize.Client {
static let liveValue = Self(
run: { query, engine, summaryType in
var body: [String: Any] = query.reduce(first: { ["url": $0.absoluteString] }, second: { ["text": $0] })
if let engine {
body["engine"] = engine.rawValue
}
if let summaryType {
body["summary_type"] = summaryType.rawValue
}
var request = try Endpoint.summarize.authorizedRequest
request.httpBody = try JSONSerialization.data(withJSONObject: body)
let (data, response) = try await URLSession.shared.data(for: request)
do {
return try JSONDecoder().decode(Response.self, from: data)
} catch {
#if DEBUG
print(response)
print(error)
print("-----")
#endif
throw error
}
}
)
}
// MARK: - Response
extension Summarize {
public enum Engine: String, CaseIterable, CustomStringConvertible, ExpressibleByArgument {
case cecil
case agnes
case daphne
case muriel
public var description: String {
switch self {
case .cecil:
"Friendly, descriptive, fast summary (default)"
case .agnes:
"Formal, technical, analytical summary"
case .daphne:
"Informal, creative, friendly summary"
case .muriel:
"Best-in-class summary using our enterprise-grade model"
}
}
public static var help: ArgumentHelp? {
.init(
allCases.map { "- \($0.rawValue): \($0.description)" }.joined(separator: "\n") + "\n"
)
}
public var defaultValueDescription: String {
Self.cecil.rawValue
}
}
public enum SummaryType: String, CaseIterable, CustomStringConvertible, ExpressibleByArgument {
case summary
case takeaway
public var description: String {
switch self {
case .summary:
"Paragraph(s) of summary prose (default)"
case .takeaway:
"Bulleted list of key points"
}
}
public static var help: ArgumentHelp? {
.init(
allCases.map { "- \($0.rawValue): \($0.description)" }.joined(separator: "\n") + "\n"
)
}
public var defaultValueDescription: String {
Self.summary.rawValue
}
}
public struct Summarization: CustomStringConvertible, Decodable {
public var output: String
public var tokens: Int
public var description: String {
"""
Summary:
\(output)
"""
}
}
}
// Copyright © 2024 Ryan Booker. All rights reserved.
import ArgumentParser
import Domain
import Foundation
import Toolbox
public struct Search: AsyncParsableCommand {
public static let configuration = CommandConfiguration(
commandName: "search",
abstract: "Search for something (Beta, requires Kagi Business (Team) plan).",
usage: "kg search \"Do androids dream of electric sheep?\""
)
@Argument(help: "Something to search for")
public var query: String
@Option(help: "The maximum number of search results")
public var limit: Int?
public init() {
// Intentionally left empty
}
public mutating func run() async throws {
do {
let response = try await Client.liveValue.run(query: query, limit: limit)
print(response)
} catch {
throw ValidationError(error.localizedDescription)
}
}
}
// MARK: - Processing
extension Search {
struct Client {
var run: (
_ query: String,
_ limit: Int?
) async throws -> Response<[Either<SearchResult, RelatedResults>]>
func run(
query: String,
limit: Int?
) async throws -> Response<[Either<SearchResult, RelatedResults>]> {
try await run(query, limit)
}
}
}
extension Search.Client {
static let liveValue = Self(
run: { query, limit in
var queryItems: [URLQueryItem] = [.init(name: "q", value: query)]
if let limit {
queryItems.append(.init(name: "limit", value: "\(limit)"))
}
var request = try Endpoint.search.authorizedRequest
request.url?.append(queryItems: queryItems)
let (data, response) = try await URLSession.shared.data(for: request)
do {
return try JSONDecoder().decode(Response.self, from: data)
} catch {
#if DEBUG
print(response)
print(error)
print("-----")
#endif
throw error
}
}
)
}
// MARK: - Response
extension Search {
public struct SearchResult: CustomStringConvertible, Decodable {
public struct Thumbnail: Decodable {
public var url: URL
public var height: Int
public var width: Int
}
public var rank: Int
public var url: URL
public var title: String
public var snippet: String?
public var published: Date?
public var thumbnail: Thumbnail?
public var description: String {
[
"""
\(rank): \(title)
\(url)
-----
""",
snippet.map {
"""
\($0)
-----
"""
},
published.map {
"""
\($0.formatted(date: .long, time: .shortened))
-----
"""
}
]
.compactMap { $0 }
.joined(separator: "\n")
}
}
public struct RelatedResults: CustomStringConvertible, Decodable {
public var list: [String]
public var description: String {
"""
Possibly related searches:
\(list.map { "- \($0)" })
"""
}
}
}
extension Array where Element == Either<Search.SearchResult, Search.RelatedResults> {
public var description: String {
"""
Results:
\(map(\.description).joined(separator: "\n\n"))
"""
}
}
// The Swift Programming Language
// https://docs.swift.org/swift-book
//
// Swift Argument Parser
// https://swiftpackageindex.com/apple/swift-argument-parser/documentation
import ArgumentParser
import FastGPT
import Foundation
import Search
import Summarize
@main
struct Kagi: AsyncParsableCommand {
static let configuration = CommandConfiguration(
commandName: "kg",
abstract: "Interact with Kagi services.",
subcommands: [FastGPT.self, Search.self, Summarize.self]
)
}
// Copyright © 2024 Ryan Booker. All rights reserved.
import ArgumentParser
import Domain
import Foundation
public struct FastGPT: AsyncParsableCommand {
public static let configuration = CommandConfiguration(
commandName: "fastgpt",
abstract: "Ask FastGPT something.",
usage: "kg fastgpt \"What is the answer to life, the universe, and everything?\""
)
@Argument(help: "A query for FastGPT")
public var query: String
public init() {
// Intentionally left empty
}
public mutating func run() async throws {
do {
let response = try await Client.liveValue.run(query: query)
print(response)
} catch {
throw ValidationError(error.localizedDescription)
}
}
}
// MARK: - Processing
extension FastGPT {
struct Client {
var run: (
_ query: String
) async throws -> Response<Answer>
func run(
query: String
) async throws -> Response<Answer> {
try await run(query)
}
}
}
extension FastGPT.Client {
static let liveValue = Self(
run: { query in
var request = try Endpoint.fastGPT.authorizedRequest
request.httpBody = try JSONSerialization.data(withJSONObject: ["query": query])
let (data, response) = try await URLSession.shared.data(for: request)
do {
return try JSONDecoder().decode(Response.self, from: data)
} catch {
#if DEBUG
print(response)
print(error)
print("-----")
#endif
throw error
}
}
)
}
// MARK: - Response
extension FastGPT {
public struct Answer: CustomStringConvertible, Decodable {
public struct Reference: CustomStringConvertible, Decodable {
public var title: String
public var snippet: String
public var url: URL
public var description: String {
"""
- \(title)
\(url)
\(snippet.trimmingCharacters(in: .whitespaces))
"""
}
}
public var output: String
public var tokens: Int
public var references: [Reference]
public var description: String {
"""
\(output)
References:
\(references.map(\.description).joined(separator: "\n\n"))
"""
}
}
}
// Copyright © 2024 Ryan Booker. All rights reserved.
import Foundation
import Toolbox
public struct Response<T>: CustomStringConvertible, Decodable where T: CustomStringConvertible & Decodable {
public let meta: Metadata
public let data: Result<T, Failure>
public var description: String {
data.reduce(success: \.description, failure: \.description)
}
public enum CodingKeys: CodingKey {
case meta, data, error
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.meta = try container.decode(Metadata.self, forKey: .meta)
do {
let data = try container.decode(T.self, forKey: .data)
self.data = .success(data)
} catch {
let reasons = try container.decode([Failure.Reason].self, forKey: .error)
self.data = .failure(.init(reasons: reasons))
}
}
}
// MARK: - Repsonse types
extension Response {
public struct Failure: CustomStringConvertible, Decodable, Error {
public struct Reason: CustomStringConvertible, Decodable {
public let code: Int
public let msg: String
public var description: String {
"\(code): \(msg)"
}
}
public let reasons: [Reason]
public var description: String {
"""
Whoops!
\(reasons.map(\.description).joined(separator: "\n\n"))
"""
}
}
public struct Metadata: Decodable {
public let id: String
public let node: String
public let ms: Int
}
}
// Copyright © 2024 Ryan Booker. All rights reserved.
import ArgumentParser
import Foundation
public enum Endpoint: String {
static let baseUrl = URL(string: "https://kagi.com/api/v0/")!
case fastGPT
case search
case summarize
var httpMethod: String {
switch self {
case .search:
return "GET"
case .fastGPT, .summarize:
return "POST"
}
}
var url: URL {
URL(string: rawValue.lowercased(), relativeTo: Self.baseUrl)!
}
var request: URLRequest {
var request = URLRequest(url: url)
request.httpMethod = httpMethod
if httpMethod == "POST" {
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
}
return request
}
public var authorizedRequest: URLRequest {
get throws {
guard let apiToken = ProcessInfo.processInfo.environment["FASTGPT_API_TOKEN"] else {
throw ValidationError("API key is missing. Set the environment variable FASTGPT_API_TOKEN.")
}
var request = self.request
request.setValue("Bot \(apiToken)", forHTTPHeaderField: "Authorization")
return request
}
}
}
products: [
.executable(name: "kg", targets: ["Kagi"]),
.library(name: "FastGPT", targets: ["FastGPT"]),
.library(name: "Search", targets: ["Search"]),
.library(name: "Summarize", targets: ["Summarize"]),
.library(name: "Domain", targets: ["Domain"]),
.library(name: "Toolbox", targets: ["Toolbox"]),
],
name: "kg",
name: "Kagi",
dependencies: [
"FastGPT",
"Search",
"Summarize",
.product(name: "ArgumentParser", package: "swift-argument-parser"),
]
),
// MARK: - Commands
.target(
name: "FastGPT",
dependencies: [
"Domain",
]
),
.target(
name: "Search",
dependencies: [
"Domain",
"Toolbox",
]
),
.target(
name: "Summarize",
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1520"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "kg"
BuildableName = "kg"
BlueprintName = "kg"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "kg"
BuildableName = "kg"
BlueprintName = "kg"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "kg"
BuildableName = "kg"
BlueprintName = "kg"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1520"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Summarize"
BuildableName = "Summarize"
BlueprintName = "Summarize"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Summarize"
BuildableName = "Summarize"
BlueprintName = "Summarize"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1520"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Search"
BuildableName = "Search"
BlueprintName = "Search"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Search"
BuildableName = "Search"
BlueprintName = "Search"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1520"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Domain"
BuildableName = "Domain"
BlueprintName = "Domain"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FastGPT"
BuildableName = "FastGPT"
BlueprintName = "FastGPT"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Search"
BuildableName = "Search"
BlueprintName = "Search"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Summarize"
BuildableName = "Summarize"
BlueprintName = "Summarize"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "kg"
BuildableName = "kg"
BlueprintName = "kg"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Toolbox"
BuildableName = "Toolbox"
BlueprintName = "Toolbox"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "kg"
BuildableName = "kg"
BlueprintName = "kg"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "kg"
BuildableName = "kg"
BlueprintName = "kg"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1520"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FastGPT"
BuildableName = "FastGPT"
BlueprintName = "FastGPT"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FastGPT"
BuildableName = "FastGPT"
BlueprintName = "FastGPT"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1520"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Domain"
BuildableName = "Domain"
BlueprintName = "Domain"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Domain"
BuildableName = "Domain"
BlueprintName = "Domain"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>