From fe7abf5fd5632a84ac46d15618c7befae607efce Mon Sep 17 00:00:00 2001 From: Fumito Ito Date: Thu, 28 Nov 2024 16:14:53 +0900 Subject: [PATCH 01/13] add base entities and response object --- .../Entity/Admin/Invitation.swift | 13 ++++++ .../Entity/Admin/OrganizationRole.swift | 17 +++++++ .../Entity/Admin/Registration.swift | 13 ++++++ .../Entity/Admin/WorkspaceRole.swift | 14 ++++++ .../Network/Response/APIKeyListResponse.swift | 13 ++++++ .../Network/Response/APIKeyResponse.swift | 45 +++++++++++++++++++ .../Response/InvitationListResponse.swift | 17 +++++++ .../Response/InvitationRemoveResponse.swift | 18 ++++++++ .../Network/Response/InvitationResponse.swift | 36 +++++++++++++++ .../OrganizationMemberListResponse.swift | 17 +++++++ .../OrganizationMemberRemoveResponse.swift | 18 ++++++++ .../Response/OrganizationMemberResponse.swift | 26 +++++++++++ .../Response/WorkspaceListResponse.swift | 17 +++++++ .../WorkspaceMemberListResponse.swift | 16 +++++++ .../WorkspaceMemberRemoveResponse.swift | 20 +++++++++ .../Response/WorkspaceMemberResponse.swift | 21 +++++++++ .../Network/Response/WorkspaceResponse.swift | 26 +++++++++++ 17 files changed, 347 insertions(+) create mode 100644 Sources/AnthropicSwiftSDK/Entity/Admin/Invitation.swift create mode 100644 Sources/AnthropicSwiftSDK/Entity/Admin/OrganizationRole.swift create mode 100644 Sources/AnthropicSwiftSDK/Entity/Admin/Registration.swift create mode 100644 Sources/AnthropicSwiftSDK/Entity/Admin/WorkspaceRole.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Response/APIKeyListResponse.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Response/APIKeyResponse.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Response/InvitationListResponse.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Response/InvitationRemoveResponse.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Response/InvitationResponse.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberListResponse.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberRemoveResponse.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberResponse.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Response/WorkspaceListResponse.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberListResponse.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberRemoveResponse.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberResponse.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Response/WorkspaceResponse.swift diff --git a/Sources/AnthropicSwiftSDK/Entity/Admin/Invitation.swift b/Sources/AnthropicSwiftSDK/Entity/Admin/Invitation.swift new file mode 100644 index 0000000..c3dadb3 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Entity/Admin/Invitation.swift @@ -0,0 +1,13 @@ +// +// Invitation.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +public struct Invitation { + /// Email of the User. + public let email: String + /// Role for the invited User. Cannot be "admin". + public let role: OrganizationRole +} diff --git a/Sources/AnthropicSwiftSDK/Entity/Admin/OrganizationRole.swift b/Sources/AnthropicSwiftSDK/Entity/Admin/OrganizationRole.swift new file mode 100644 index 0000000..c40e943 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Entity/Admin/OrganizationRole.swift @@ -0,0 +1,17 @@ +// +// OrganizationRole.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/27. +// + +public enum OrganizationRole: String, Decodable { + /// Can use Workbench + case user + /// Can use Workbench and manage API keys + case developer + /// Can use Workbench and manage billing details + case billing + /// Can do all of the above, plus manage users + case admin +} diff --git a/Sources/AnthropicSwiftSDK/Entity/Admin/Registration.swift b/Sources/AnthropicSwiftSDK/Entity/Admin/Registration.swift new file mode 100644 index 0000000..c09fa1c --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Entity/Admin/Registration.swift @@ -0,0 +1,13 @@ +// +// Registration.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +public struct Registration { + /// ID of the User. + public let userId: String + /// Role of the new Workspace Member. Cannot be "workspace_billing". + public let workspaceRole: WorkspaceRole +} diff --git a/Sources/AnthropicSwiftSDK/Entity/Admin/WorkspaceRole.swift b/Sources/AnthropicSwiftSDK/Entity/Admin/WorkspaceRole.swift new file mode 100644 index 0000000..91766dd --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Entity/Admin/WorkspaceRole.swift @@ -0,0 +1,14 @@ +// +// WorkspaceRole.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +/// workspace role for the user. +public enum WorkspaceRole: String, Decodable { + case user = "workspace_user" + case developer = "workspace_developer" + case admin = "workspace_admin" + case billing = "workspace_billing" +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/APIKeyListResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/APIKeyListResponse.swift new file mode 100644 index 0000000..d243fb5 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/APIKeyListResponse.swift @@ -0,0 +1,13 @@ +// +// APIKeyListResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +public struct APIKeyListResponse { + public let data: [APIKeyResponse] + public let hasMore: Bool + public let firstId: String? + public let lastId: String? +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/APIKeyResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/APIKeyResponse.swift new file mode 100644 index 0000000..a001ab9 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/APIKeyResponse.swift @@ -0,0 +1,45 @@ +// +// APIKeyResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +/// Object type for API Keys, this is always "api_key". +public enum APIKeyType: String, Decodable { + case apiKey = "api_key" +} + +/// The ID and type of the actor that created the API key. +public struct APIKeyActor: Decodable { + /// ID of the actor that created the object. + public let id: String + /// Type of the actor that created the object. + public let type: String +} + +/// Status of the API key. +public enum APIKeyStatus: String, Decodable { + case active + case inactive + case archived +} + +public struct APIKeyResponse: Decodable { + /// ID of the API key. + public let id: String + /// Object type for API Keys, this is always "api_key". + public let type: APIKeyType + /// Name of the API key. + public let name: String + /// ID of the Workspace associated with the API key, or null if the API key belongs to the default Workspace. + public let workspaceId: String? + /// RFC 3339 datetime string indicating when the API Key was created. + public let createdAt: String + /// The ID and type of the actor that created the API key. + public let createdBy: APIKeyActor + /// Partially redacted hint for the API key. + public let partialKeyHint: String? + /// Status of the API key. + public let status: APIKeyStatus +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/InvitationListResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/InvitationListResponse.swift new file mode 100644 index 0000000..ced8406 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/InvitationListResponse.swift @@ -0,0 +1,17 @@ +// +// InvitationListResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +public struct InvitationListResponse { + /// List of invitations + public let data: [InvitationResponse] + /// Indicates if there are more results in the requested page direction. + public let hasMore: Bool + /// First ID in the data list. Can be used as the before_id for the previous page. + public let firstId: String? + /// Last ID in the data list. Can be used as the after_id for the next page. + public let lastId: String? +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/InvitationRemoveResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/InvitationRemoveResponse.swift new file mode 100644 index 0000000..68121ea --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/InvitationRemoveResponse.swift @@ -0,0 +1,18 @@ +// +// InvitationRemoveResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +/// Deleted object type for Invites, this is always "invite_deleted". +public enum InvitationDeletedType: String, Decodable { + case deleted = "invite_deleted" +} + +public struct InvitationRemoveResponse: Decodable { + /// ID of the Invite. + public let id: String + /// Deleted object type for Invites, this is always "invite_deleted". + public let type: InvitationDeletedType +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/InvitationResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/InvitationResponse.swift new file mode 100644 index 0000000..1e4b8d5 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/InvitationResponse.swift @@ -0,0 +1,36 @@ +// +// InvitationResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +/// Object type for Invites, this is always "invite". +public enum InvitationType: String, Decodable { + case invite +} + +/// Status of the Invite. +public enum InvitationStatus: String, Decodable { + case accepted + case expired + case deleted + case pending +} + +public struct InvitationResponse: Decodable { + /// ID of the Invite. + public let id: String + /// Object type for Invites, this is always "invite". + public let type: InvitationType + /// Email of the User being invited. + public let email: String + /// Organization role of the User. + public let role: OrganizationRole + /// RFC 3339 datetime string indicating when the Invite was created. + public let invitedAt: String + /// RFC 3339 datetime string indicating when the Invite expires. + public let expiresAt: String + /// Status of the Invite. + public let status: InvitationStatus +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberListResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberListResponse.swift new file mode 100644 index 0000000..9dd5a02 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberListResponse.swift @@ -0,0 +1,17 @@ +// +// OrganizationMemberListResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +public struct OrganizationMemberListResponse { + /// List of organization members + public let data: [OrganizationMemberResponse] + /// Indicates if there are more results in the requested page direction. + public let hasMore: Bool + /// First ID in the data list. Can be used as the before_id for the previous page. + public let firstId: String? + /// Last ID in the data list. Can be used as the after_id for the next page. + public let lastId: String? +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberRemoveResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberRemoveResponse.swift new file mode 100644 index 0000000..2032256 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberRemoveResponse.swift @@ -0,0 +1,18 @@ +// +// OrganizationMemberRemoveResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +/// Deleted object type for Users, this is always "user_deleted". +public enum OrganizationMemberDeletedType: String, Decodable { + case deleted = "user_deleted" +} + +public struct OrganizationMemberRemoveResponse: Decodable { + /// ID of the User. + public let id: String + /// Deleted object type for Users, this is always "user_deleted". + public let type: OrganizationMemberDeletedType +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberResponse.swift new file mode 100644 index 0000000..3ace29a --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberResponse.swift @@ -0,0 +1,26 @@ +// +// OrganizationMemberResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +/// Object type for Users, this is always "user". +public enum OrganizationMemberType: String, Decodable { + case user +} + +public struct OrganizationMemberResponse: Decodable { + /// ID of the User. + public let id: String + /// Object type for Users, this is always "user". + public let type: OrganizationMemberType + /// Email of the User. + public let email: String + /// Name of the User. + public let name: String + /// Organization role of the User. + public let role: OrganizationRole + /// RFC 3339 datetime string indicating when the User joined the Organization. + public let addedAt: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceListResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceListResponse.swift new file mode 100644 index 0000000..82c4607 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceListResponse.swift @@ -0,0 +1,17 @@ +// +// WorkspaceListResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +public struct WorkspaceListResponse { + /// List of workspaces + public let data: [WorkspaceResponse] + /// Indicates if there are more results in the requested page direction. + public let hasMore: Bool + /// First ID in the data list. Can be used as the before_id for the previous page. + public let firstId: String? + /// Last ID in the data list. Can be used as the after_id for the next page. + public let afterId: String? +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberListResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberListResponse.swift new file mode 100644 index 0000000..fc97724 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberListResponse.swift @@ -0,0 +1,16 @@ +// +// WorkspaceMemberListResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +public struct WorkspaceMemberListResponse { + public let data: [WorkspaceMemberResponse] + /// Indicates if there are more results in the requested page direction. + public let hasMore: Bool + /// First ID in the data list. Can be used as the before_id for the previous page. + public let firstId: String? + /// Last ID in the data list. Can be used as the after_id for the next page. + public let lastId: String? +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberRemoveResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberRemoveResponse.swift new file mode 100644 index 0000000..61be82a --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberRemoveResponse.swift @@ -0,0 +1,20 @@ +// +// WorkspaceMemberRemoveResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +public struct WorkspaceMemberRemoveResponse: Decodable { + /// ID of the User. + public let userId: String + /// ID of the Workspace. + public let workspaceId: String + /// Deleted object type for Workspace Members, this is always + public let type: WorkspaceMemberDeletedType +} + +/// Deleted object type for Invites, this is always "invite_deleted". +public enum WorkspaceMemberDeletedType: String, Decodable { + case deleted = "workspace_member_deleted" +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberResponse.swift new file mode 100644 index 0000000..204ba90 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberResponse.swift @@ -0,0 +1,21 @@ +// +// WorkspaceMemberResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +public enum WorkspaceMemberType: String, Decodable { + case workspaceMember = "workspace_member" +} + +public struct WorkspaceMemberResponse: Decodable { + /// Object type for Workspace Members, this is always + public let type: WorkspaceMemberType + /// ID of the User. + public let userId: String + /// ID of the Workspace. + public let workspaceId: String + /// Role of the Workspace Member. + public let workspaceRole: WorkspaceRole +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceResponse.swift new file mode 100644 index 0000000..857e6dc --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceResponse.swift @@ -0,0 +1,26 @@ +// +// WorkspaceResponse.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// + +/// Object type for Workspaces, this is always "workspace". +public enum WorkspaceType: String, Decodable { + case workspace +} + +public struct WorkspaceResponse: Decodable { + /// ID of the Workspace. + public let id: String + /// Object type for Workspaces, this is always "workspace". + public let type: WorkspaceType + /// Name of the Workspace. + public let name: String + /// RFC 3339 datetime string indicating when the Workspace was created. + public let createdAt: String + /// RFC 3339 datetime string indicating when the Workspace was archived, or null if the Workspace is not archived. + public let archivedAt: String? + /// Hex color code representing the Workspace in the Anthropic Console. + public let displayColor: String +} From 00a6caf9148ee706e8b80e7d4c5db9ae1d71b069 Mon Sep 17 00:00:00 2001 From: Fumito Ito Date: Thu, 28 Nov 2024 16:15:16 +0900 Subject: [PATCH 02/13] add admin api interfaces --- .../AnthropicSwiftSDK/API/Admin/APIKeys.swift | 36 ++++++++++++++++++ .../AnthropicSwiftSDK/API/Admin/Admin.swift | 23 ++++++++++++ .../API/Admin/OrganizationInvites.swift | 33 +++++++++++++++++ .../API/Admin/OrganizationMembers.swift | 33 +++++++++++++++++ .../API/Admin/WorkspaceMembers.swift | 37 +++++++++++++++++++ .../API/Admin/Workspaces.swift | 37 +++++++++++++++++++ 6 files changed, 199 insertions(+) create mode 100644 Sources/AnthropicSwiftSDK/API/Admin/APIKeys.swift create mode 100644 Sources/AnthropicSwiftSDK/API/Admin/Admin.swift create mode 100644 Sources/AnthropicSwiftSDK/API/Admin/OrganizationInvites.swift create mode 100644 Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift create mode 100644 Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift create mode 100644 Sources/AnthropicSwiftSDK/API/Admin/Workspaces.swift diff --git a/Sources/AnthropicSwiftSDK/API/Admin/APIKeys.swift b/Sources/AnthropicSwiftSDK/API/Admin/APIKeys.swift new file mode 100644 index 0000000..fbdfe04 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/API/Admin/APIKeys.swift @@ -0,0 +1,36 @@ +// +// APIKeys.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// +import Foundation + +public struct APIKeys { + private let adminAPIKey: String + private let session: URLSession + + init(adminAPIKey: String, session: URLSession) { + self.adminAPIKey = adminAPIKey + self.session = session + } + + public func get(apiKeyId: String) async throws -> APIKeyResponse { + fatalError() + } + + public func list( + limit: Int = 20, + beforeId: String? = nil, + lastId: String? = nil, + status: APIKeyStatus? = nil, + workspaceId: String? = nil, + createdByUserId: String? = nil + ) async throws -> APIKeyListResponse { + fatalError() + } + + public func update(apiKeyId: String, name: String, status: APIKeyStatus? = nil) async throws -> APIKeyResponse { + fatalError() + } +} diff --git a/Sources/AnthropicSwiftSDK/API/Admin/Admin.swift b/Sources/AnthropicSwiftSDK/API/Admin/Admin.swift new file mode 100644 index 0000000..9caac26 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/API/Admin/Admin.swift @@ -0,0 +1,23 @@ +// +// Admin.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// +import Foundation + +public struct Admin { + public let organizationMembers: OrganizationMembers + public let organizationInvites: OrganizationInvites + public let workspaces: Workspaces + public let workspaceMembers: WorkspaceMembers + public let apiKeys: APIKeys + + init(adminAPIKey apiKey: String, session: URLSession = .shared) { + self.organizationMembers = OrganizationMembers(adminAPIKey: apiKey, session: session) + self.organizationInvites = OrganizationInvites(adminAPIKey: apiKey, session: session) + self.workspaces = Workspaces(adminAPIKey: apiKey, session: session) + self.workspaceMembers = WorkspaceMembers(adminAPIKey: apiKey, session: session) + self.apiKeys = APIKeys(adminAPIKey: apiKey, session: session) + } +} diff --git a/Sources/AnthropicSwiftSDK/API/Admin/OrganizationInvites.swift b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationInvites.swift new file mode 100644 index 0000000..f84219f --- /dev/null +++ b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationInvites.swift @@ -0,0 +1,33 @@ +// +// OrganizationInvites.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// +import Foundation + +public struct OrganizationInvites { + private let adminAPIKey: String + private let session: URLSession + + init(adminAPIKey: String, session: URLSession) { + self.adminAPIKey = adminAPIKey + self.session = session + } + + public func get(invitationId: String) async throws -> InvitationResponse { + fatalError() + } + + public func list(limit: Int = 20, beforeId: String? = nil, afterId: String? = nil) async throws -> InvitationListResponse { + fatalError() + } + + public func send(invitation: Invitation) async throws -> InvitationResponse { + fatalError() + } + + public func remove(invitationId: String) async throws -> InvitationRemoveResponse { + fatalError() + } +} diff --git a/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift new file mode 100644 index 0000000..d7bac8a --- /dev/null +++ b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift @@ -0,0 +1,33 @@ +// +// OrganizationMembers.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// +import Foundation + +public struct OrganizationMembers { + private let adminAPIKey: String + private let session: URLSession + + init(adminAPIKey: String, session: URLSession) { + self.adminAPIKey = adminAPIKey + self.session = session + } + + public func get(userId: String) async throws -> OrganizationMemberResponse { + fatalError() + } + + public func list(limit: Int = 20, beforeId: String? = nil, afterId: String? = nil) async throws -> OrganizationMemberListResponse { + fatalError() + } + + public func update(userId: String, role: OrganizationRole) async throws -> OrganizationMemberResponse { + fatalError() + } + + public func remove(userId: String) async throws -> OrganizationMemberRemoveResponse { + fatalError() + } +} diff --git a/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift b/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift new file mode 100644 index 0000000..3a25460 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift @@ -0,0 +1,37 @@ +// +// WorkspaceMembers.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// +import Foundation + +public struct WorkspaceMembers { + private let adminAPIKey: String + private let session: URLSession + + init(adminAPIKey: String, session: URLSession) { + self.adminAPIKey = adminAPIKey + self.session = session + } + + public func get(userId: String, workspaceId: String) async throws -> WorkspaceMemberResponse { + fatalError() + } + + public func list(workspaceId: String, limit: Int = 20, beforeId: String? = nil, afterId: String? = nil) async throws -> WorkspaceMemberListResponse { + fatalError() + } + + public func add(registration: Registration, wokspaceId: String) async throws -> WorkspaceMemberResponse { + fatalError() + } + + public func update(userId: String, workspaceId: String, as role: WorkspaceRole) async throws -> WorkspaceMemberResponse { + fatalError() + } + + public func delete(userId: String, workspaceId: String) async throws -> WorkspaceMemberRemoveResponse { + fatalError() + } +} diff --git a/Sources/AnthropicSwiftSDK/API/Admin/Workspaces.swift b/Sources/AnthropicSwiftSDK/API/Admin/Workspaces.swift new file mode 100644 index 0000000..b44e42e --- /dev/null +++ b/Sources/AnthropicSwiftSDK/API/Admin/Workspaces.swift @@ -0,0 +1,37 @@ +// +// Workspaces.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/28. +// +import Foundation + +public struct Workspaces { + private let adminAPIKey: String + private let session: URLSession + + init(adminAPIKey: String, session: URLSession) { + self.adminAPIKey = adminAPIKey + self.session = session + } + + public func get(workspaceId: String) async throws -> WorkspaceResponse { + fatalError() + } + + public func list(limit: Int = 20, includeArchive: Bool = false, beforeId: String? = nil, afterId: String? = nil) async throws -> WorkspaceListResponse { + fatalError() + } + + public func update(name: String, workspaceId: String) async throws -> WorkspaceResponse { + fatalError() + } + + public func create(name: String) async throws -> WorkspaceResponse { + fatalError() + } + + public func archive(_ workspaceId: String) async throws -> WorkspaceResponse { + fatalError() + } +} From 46537fc957691ccc18b3879a6699fc72721a1254 Mon Sep 17 00:00:00 2001 From: Fumito Ito Date: Thu, 28 Nov 2024 16:15:34 +0900 Subject: [PATCH 03/13] move current api interfaces --- Sources/AnthropicSwiftSDK/{ => API}/CountTokens.swift | 0 Sources/AnthropicSwiftSDK/{ => API}/MessageBatches.swift | 0 Sources/AnthropicSwiftSDK/{ => API}/Messages.swift | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename Sources/AnthropicSwiftSDK/{ => API}/CountTokens.swift (100%) rename Sources/AnthropicSwiftSDK/{ => API}/MessageBatches.swift (100%) rename Sources/AnthropicSwiftSDK/{ => API}/Messages.swift (100%) diff --git a/Sources/AnthropicSwiftSDK/CountTokens.swift b/Sources/AnthropicSwiftSDK/API/CountTokens.swift similarity index 100% rename from Sources/AnthropicSwiftSDK/CountTokens.swift rename to Sources/AnthropicSwiftSDK/API/CountTokens.swift diff --git a/Sources/AnthropicSwiftSDK/MessageBatches.swift b/Sources/AnthropicSwiftSDK/API/MessageBatches.swift similarity index 100% rename from Sources/AnthropicSwiftSDK/MessageBatches.swift rename to Sources/AnthropicSwiftSDK/API/MessageBatches.swift diff --git a/Sources/AnthropicSwiftSDK/Messages.swift b/Sources/AnthropicSwiftSDK/API/Messages.swift similarity index 100% rename from Sources/AnthropicSwiftSDK/Messages.swift rename to Sources/AnthropicSwiftSDK/API/Messages.swift From e2f4420aeafab0b5c29722ce3a4fcac0fe6ec0ce Mon Sep 17 00:00:00 2001 From: Fumito Ito Date: Fri, 29 Nov 2024 11:52:35 +0900 Subject: [PATCH 04/13] add request objects for admin api --- .../Entity/Admin/Invitation.swift | 2 +- .../Entity/Admin/OrganizationRole.swift | 2 +- .../Entity/Admin/Registration.swift | 2 +- .../Entity/Admin/WorkspaceRole.swift | 2 +- .../Request/APIKeys/GetAPIKeyRequest.swift | 17 ++++++++++++++ .../Request/APIKeys/UpdateAPIKeyRequest.swift | 23 +++++++++++++++++++ .../CancelMessageBatchRequest.swift | 0 .../MessageBatchesRequest.swift | 0 .../RetrieveMessageBatchResultsRequest.swift | 0 .../RetrieveMessageBatchesRequest.swift | 0 .../CreateOrganizationInviteRequest.swift | 16 +++++++++++++ .../DeleteOrganizationInviteRequest.swift | 17 ++++++++++++++ .../GetOrganizationInviteRequest.swift | 17 ++++++++++++++ .../GetOrganizationMemberRequest.swift | 19 +++++++++++++++ .../RemoveOrganizationMemberRequest.swift | 17 ++++++++++++++ .../UpdateOrganizationMemberRequest.swift | 19 +++++++++++++++ .../Network/Request/Request.swift | 15 +++++++++++- .../CreateWorkspaceMemberRequest.swift | 19 +++++++++++++++ .../DeleteWorkspaceMemberRequest.swift | 18 +++++++++++++++ .../GetWorkspaceMemberRequest.swift | 18 +++++++++++++++ .../UpdateWorkspaceMemberRequest.swift | 20 ++++++++++++++++ .../Workspaces/ArchiveWorkspaceRequest.swift | 17 ++++++++++++++ .../Workspaces/CreateWorkspaceRequest.swift | 16 +++++++++++++ .../Workspaces/GetWorkspaceRequest.swift | 17 ++++++++++++++ .../Workspaces/UpdateWorkspaceRequest.swift | 23 +++++++++++++++++++ .../Network/Response/APIKeyResponse.swift | 2 +- 26 files changed, 312 insertions(+), 6 deletions(-) create mode 100644 Sources/AnthropicSwiftSDK/Network/Request/APIKeys/GetAPIKeyRequest.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Request/APIKeys/UpdateAPIKeyRequest.swift rename Sources/AnthropicSwiftSDK/Network/Request/{ => MessageBatches}/CancelMessageBatchRequest.swift (100%) rename Sources/AnthropicSwiftSDK/Network/Request/{ => MessageBatches}/MessageBatchesRequest.swift (100%) rename Sources/AnthropicSwiftSDK/Network/Request/{ => MessageBatches}/RetrieveMessageBatchResultsRequest.swift (100%) rename Sources/AnthropicSwiftSDK/Network/Request/{ => MessageBatches}/RetrieveMessageBatchesRequest.swift (100%) create mode 100644 Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/CreateOrganizationInviteRequest.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/DeleteOrganizationInviteRequest.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/GetOrganizationInviteRequest.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/GetOrganizationMemberRequest.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/RemoveOrganizationMemberRequest.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/UpdateOrganizationMemberRequest.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/CreateWorkspaceMemberRequest.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/DeleteWorkspaceMemberRequest.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/GetWorkspaceMemberRequest.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/UpdateWorkspaceMemberRequest.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Request/Workspaces/ArchiveWorkspaceRequest.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Request/Workspaces/CreateWorkspaceRequest.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Request/Workspaces/GetWorkspaceRequest.swift create mode 100644 Sources/AnthropicSwiftSDK/Network/Request/Workspaces/UpdateWorkspaceRequest.swift diff --git a/Sources/AnthropicSwiftSDK/Entity/Admin/Invitation.swift b/Sources/AnthropicSwiftSDK/Entity/Admin/Invitation.swift index c3dadb3..eb960f7 100644 --- a/Sources/AnthropicSwiftSDK/Entity/Admin/Invitation.swift +++ b/Sources/AnthropicSwiftSDK/Entity/Admin/Invitation.swift @@ -5,7 +5,7 @@ // Created by 伊藤史 on 2024/11/28. // -public struct Invitation { +public struct Invitation: Encodable { /// Email of the User. public let email: String /// Role for the invited User. Cannot be "admin". diff --git a/Sources/AnthropicSwiftSDK/Entity/Admin/OrganizationRole.swift b/Sources/AnthropicSwiftSDK/Entity/Admin/OrganizationRole.swift index c40e943..67977a3 100644 --- a/Sources/AnthropicSwiftSDK/Entity/Admin/OrganizationRole.swift +++ b/Sources/AnthropicSwiftSDK/Entity/Admin/OrganizationRole.swift @@ -5,7 +5,7 @@ // Created by 伊藤史 on 2024/11/27. // -public enum OrganizationRole: String, Decodable { +public enum OrganizationRole: String, Codable { /// Can use Workbench case user /// Can use Workbench and manage API keys diff --git a/Sources/AnthropicSwiftSDK/Entity/Admin/Registration.swift b/Sources/AnthropicSwiftSDK/Entity/Admin/Registration.swift index c09fa1c..bead933 100644 --- a/Sources/AnthropicSwiftSDK/Entity/Admin/Registration.swift +++ b/Sources/AnthropicSwiftSDK/Entity/Admin/Registration.swift @@ -5,7 +5,7 @@ // Created by 伊藤史 on 2024/11/28. // -public struct Registration { +public struct Registration: Encodable { /// ID of the User. public let userId: String /// Role of the new Workspace Member. Cannot be "workspace_billing". diff --git a/Sources/AnthropicSwiftSDK/Entity/Admin/WorkspaceRole.swift b/Sources/AnthropicSwiftSDK/Entity/Admin/WorkspaceRole.swift index 91766dd..0505076 100644 --- a/Sources/AnthropicSwiftSDK/Entity/Admin/WorkspaceRole.swift +++ b/Sources/AnthropicSwiftSDK/Entity/Admin/WorkspaceRole.swift @@ -6,7 +6,7 @@ // /// workspace role for the user. -public enum WorkspaceRole: String, Decodable { +public enum WorkspaceRole: String, Codable { case user = "workspace_user" case developer = "workspace_developer" case admin = "workspace_admin" diff --git a/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/GetAPIKeyRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/GetAPIKeyRequest.swift new file mode 100644 index 0000000..6d554c9 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/GetAPIKeyRequest.swift @@ -0,0 +1,17 @@ +// +// GetAPIKeyRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct GetAPIKeyRequest: Request { + let method: HttpMethod = .get + var path: String { + "\(RequestType.apiKey.basePath)/\(apiKeyId)" + } + let queries: [String : any CustomStringConvertible]? = nil + let body: Never? = nil + + let apiKeyId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/UpdateAPIKeyRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/UpdateAPIKeyRequest.swift new file mode 100644 index 0000000..7fcef3e --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/UpdateAPIKeyRequest.swift @@ -0,0 +1,23 @@ +// +// UpdateAPIKeyRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct UpdateAPIKeyRequest: Request { + typealias Body = APIKeyRequestBody + let method: HttpMethod = .post + var path: String { + "\(RequestType.apiKey.basePath)/\(apiKeyId)" + } + let queries: [String : any CustomStringConvertible]? = nil + + let body: APIKeyRequestBody? + let apiKeyId: String +} + +struct APIKeyRequestBody: Encodable { + let name: String + let status: APIKeyStatus +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/CancelMessageBatchRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/MessageBatches/CancelMessageBatchRequest.swift similarity index 100% rename from Sources/AnthropicSwiftSDK/Network/Request/CancelMessageBatchRequest.swift rename to Sources/AnthropicSwiftSDK/Network/Request/MessageBatches/CancelMessageBatchRequest.swift diff --git a/Sources/AnthropicSwiftSDK/Network/Request/MessageBatchesRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/MessageBatches/MessageBatchesRequest.swift similarity index 100% rename from Sources/AnthropicSwiftSDK/Network/Request/MessageBatchesRequest.swift rename to Sources/AnthropicSwiftSDK/Network/Request/MessageBatches/MessageBatchesRequest.swift diff --git a/Sources/AnthropicSwiftSDK/Network/Request/RetrieveMessageBatchResultsRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/MessageBatches/RetrieveMessageBatchResultsRequest.swift similarity index 100% rename from Sources/AnthropicSwiftSDK/Network/Request/RetrieveMessageBatchResultsRequest.swift rename to Sources/AnthropicSwiftSDK/Network/Request/MessageBatches/RetrieveMessageBatchResultsRequest.swift diff --git a/Sources/AnthropicSwiftSDK/Network/Request/RetrieveMessageBatchesRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/MessageBatches/RetrieveMessageBatchesRequest.swift similarity index 100% rename from Sources/AnthropicSwiftSDK/Network/Request/RetrieveMessageBatchesRequest.swift rename to Sources/AnthropicSwiftSDK/Network/Request/MessageBatches/RetrieveMessageBatchesRequest.swift diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/CreateOrganizationInviteRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/CreateOrganizationInviteRequest.swift new file mode 100644 index 0000000..3a3c452 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/CreateOrganizationInviteRequest.swift @@ -0,0 +1,16 @@ +// +// CreateOrganizationInviteRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct CreateOrganizationInviteRequest: Request { + typealias Body = Invitation + + let method: HttpMethod = .post + let path: String = RequestType.organizationInvite.basePath + let queries: [String : any CustomStringConvertible]? = nil + + let body: Invitation? +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/DeleteOrganizationInviteRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/DeleteOrganizationInviteRequest.swift new file mode 100644 index 0000000..0b639cb --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/DeleteOrganizationInviteRequest.swift @@ -0,0 +1,17 @@ +// +// DeleteOrganizationInviteRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct DeleteOrganizationInviteRequest: Request { + let method: HttpMethod = .delete + var path: String { + "\(RequestType.organizationInvite.basePath)/\(invitationId)" + } + let queries: [String : any CustomStringConvertible]? = nil + let body: Never? = nil + + let invitationId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/GetOrganizationInviteRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/GetOrganizationInviteRequest.swift new file mode 100644 index 0000000..b1946ed --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/GetOrganizationInviteRequest.swift @@ -0,0 +1,17 @@ +// +// GetOrganizationInviteRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct GetOrganizationInviteRequest: Request { + let method: HttpMethod = .get + var path: String { + "\(RequestType.organizationInvite.basePath)/\(invitationId)" + } + let queries: [String : any CustomStringConvertible]? = nil + let body: Never? = nil + + let invitationId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/GetOrganizationMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/GetOrganizationMemberRequest.swift new file mode 100644 index 0000000..77fa477 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/GetOrganizationMemberRequest.swift @@ -0,0 +1,19 @@ +// +// GetOrganizationMemberRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +/// https://docs.anthropic.com/en/api/admin-api/users/get-user +struct GetOrganizationMemberRequest: Request { + let method: HttpMethod = .get + var path: String { + "\(RequestType.organizationMember.basePath)/\(userId)" + } + let queries: [String: CustomStringConvertible]? = nil + let body: Never? = nil + + /// ID of the User. + let userId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/RemoveOrganizationMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/RemoveOrganizationMemberRequest.swift new file mode 100644 index 0000000..45b3380 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/RemoveOrganizationMemberRequest.swift @@ -0,0 +1,17 @@ +// +// RemoveOrganizationMemberRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct RemoveOrganizationMemberRequest: Request { + let method: HttpMethod = .delete + var path: String { + "\(RequestType.organizationMember.basePath)/\(userId)" + } + let queries: [String : any CustomStringConvertible]? = nil + let body: Never? = nil + + let userId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/UpdateOrganizationMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/UpdateOrganizationMemberRequest.swift new file mode 100644 index 0000000..e033025 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/UpdateOrganizationMemberRequest.swift @@ -0,0 +1,19 @@ +// +// UpdateOrganizationMemberRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct UpdateOrganizationMemberRequest: Request { + typealias Body = OrganizationRole + + let method: HttpMethod = .post + var path: String { + "\(RequestType.organizationMember)/\(userId)" + } + let queries: [String : any CustomStringConvertible]? = nil + + let body: OrganizationRole? + let userId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/Request.swift b/Sources/AnthropicSwiftSDK/Network/Request/Request.swift index 80e7b8d..f08f388 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/Request.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/Request.swift @@ -10,12 +10,17 @@ import Foundation public enum HttpMethod: String { case post = "POST" case get = "GET" + case delete = "DELETE" } enum RequestType { case messages case batches case countTokens + case organizationMember + case organizationInvite + case workspace + case apiKey var basePath: String { switch self { @@ -24,7 +29,15 @@ enum RequestType { case .batches: return "/v1/messages/batches" case .countTokens: - return "v1/messages/count_tokens" + return "/v1/messages/count_tokens" + case .organizationMember: + return "/v1/organizations/users" + case .organizationInvite: + return "/v1/organizations/invites" + case .workspace: + return "/v1/organizations/workspaces" + case .apiKey: + return "/v1/organizations/api_keys" } } } diff --git a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/CreateWorkspaceMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/CreateWorkspaceMemberRequest.swift new file mode 100644 index 0000000..d8a05fb --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/CreateWorkspaceMemberRequest.swift @@ -0,0 +1,19 @@ +// +// CreateWorkspaceMemberRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct CreateWorkspaceMemberRequest: Request { + typealias Body = Registration + + let method: HttpMethod = .post + var path: String { + "\(RequestType.workspace.basePath)/\(workspaceId)/members" + } + let queries: [String : any CustomStringConvertible]? = nil + + let body: Registration? + let workspaceId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/DeleteWorkspaceMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/DeleteWorkspaceMemberRequest.swift new file mode 100644 index 0000000..a0e6dc4 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/DeleteWorkspaceMemberRequest.swift @@ -0,0 +1,18 @@ +// +// DeleteWorkspaceMemberRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct DeleteWorkspaceMemberRequest: Request { + let method: HttpMethod = .delete + var path: String { + "\(RequestType.workspace.basePath)/\(workspaceId)/members/\(userId)" + } + let queries: [String : any CustomStringConvertible]? = nil + let body: Never? = nil + + let userId: String + let workspaceId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/GetWorkspaceMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/GetWorkspaceMemberRequest.swift new file mode 100644 index 0000000..20739ad --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/GetWorkspaceMemberRequest.swift @@ -0,0 +1,18 @@ +// +// GetWorkspaceMemberRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct GetWorkspaceMemberRequest: Request { + let method: HttpMethod = .get + var path: String { + "\(RequestType.workspace.basePath)/\(workspaceId)/members/\(userId)" + } + let queries: [String : any CustomStringConvertible]? = nil + let body: Never? = nil + + let workspaceId: String + let userId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/UpdateWorkspaceMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/UpdateWorkspaceMemberRequest.swift new file mode 100644 index 0000000..ffc1bc5 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/UpdateWorkspaceMemberRequest.swift @@ -0,0 +1,20 @@ +// +// UpdateWorkspaceMemberRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct UpdateWorkspaceMemberRequest: Request { + typealias Body = WorkspaceRole + + let method: HttpMethod = .post + var path: String { + "\(RequestType.workspace.basePath)/\(workspaceId)/members/\(userId)" + } + let queries: [String : any CustomStringConvertible]? = nil + + let body: WorkspaceRole? + let userId: String + let workspaceId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/ArchiveWorkspaceRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/ArchiveWorkspaceRequest.swift new file mode 100644 index 0000000..dfb22b8 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/ArchiveWorkspaceRequest.swift @@ -0,0 +1,17 @@ +// +// ArchiveWorkspaceRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct ArchiveWorkspaceRequest: Request { + let method: HttpMethod = .post + var path: String { + "\(RequestType.workspace.basePath)/\(workspaceId)/archive" + } + var queries: [String : any CustomStringConvertible]? + let body: Never? = nil + + let workspaceId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/CreateWorkspaceRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/CreateWorkspaceRequest.swift new file mode 100644 index 0000000..25aef6a --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/CreateWorkspaceRequest.swift @@ -0,0 +1,16 @@ +// +// CreateWorkspaceRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct CreateWorkspaceRequest: Request { + typealias Body = WorkspaceRequestBody + + let method: HttpMethod = .post + let path: String = RequestType.workspace.basePath + let queries: [String : any CustomStringConvertible]? = nil + + let body: WorkspaceRequestBody? +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/GetWorkspaceRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/GetWorkspaceRequest.swift new file mode 100644 index 0000000..cd16747 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/GetWorkspaceRequest.swift @@ -0,0 +1,17 @@ +// +// GetWorkspaceRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct GetWorkspaceRequest: Request { + let method: HttpMethod = .get + var path: String { + "\(RequestType.workspace.basePath)/\(workspaceId)" + } + let queries: [String : any CustomStringConvertible]? = nil + let body: Never? = nil + + let workspaceId: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/UpdateWorkspaceRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/UpdateWorkspaceRequest.swift new file mode 100644 index 0000000..ded36b9 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/UpdateWorkspaceRequest.swift @@ -0,0 +1,23 @@ +// +// UpdateWorkspaceRequest.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/11/29. +// + +struct UpdateWorkspaceRequest: Request { + typealias Body = WorkspaceRequestBody + + let method: HttpMethod = .post + var path: String { + "\(RequestType.workspace.basePath)/\(workspaceId)" + } + let queries: [String : any CustomStringConvertible]? = nil + + let body: WorkspaceRequestBody? + let workspaceId: String +} + +struct WorkspaceRequestBody: Encodable { + let name: String +} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/APIKeyResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/APIKeyResponse.swift index a001ab9..2695127 100644 --- a/Sources/AnthropicSwiftSDK/Network/Response/APIKeyResponse.swift +++ b/Sources/AnthropicSwiftSDK/Network/Response/APIKeyResponse.swift @@ -19,7 +19,7 @@ public struct APIKeyActor: Decodable { } /// Status of the API key. -public enum APIKeyStatus: String, Decodable { +public enum APIKeyStatus: String, Codable { case active case inactive case archived From 827f892841f8fff397d6c87fe67a9a3916f7e141 Mon Sep 17 00:00:00 2001 From: Fumito Ito Date: Thu, 28 Nov 2024 16:21:24 +0900 Subject: [PATCH 05/13] use `ObjectListResponse` instead of *ListResponse --- .../AnthropicSwiftSDK/API/Admin/APIKeys.swift | 2 +- .../API/Admin/OrganizationInvites.swift | 2 +- .../API/Admin/OrganizationMembers.swift | 2 +- .../API/Admin/WorkspaceMembers.swift | 2 +- .../API/Admin/Workspaces.swift | 2 +- .../AnthropicSwiftSDK/API/MessageBatches.swift | 18 +++++++++--------- .../Network/Response/BatchListResponse.swift | 18 ------------------ .../Response/InvitationListResponse.swift | 17 ----------------- ...Response.swift => ObjectListResponse.swift} | 6 +++--- .../OrganizationMemberListResponse.swift | 17 ----------------- .../Response/WorkspaceListResponse.swift | 17 ----------------- .../Response/WorkspaceMemberListResponse.swift | 16 ---------------- .../Network/BatchListResponseTests.swift | 4 ++-- 13 files changed, 19 insertions(+), 104 deletions(-) delete mode 100644 Sources/AnthropicSwiftSDK/Network/Response/BatchListResponse.swift delete mode 100644 Sources/AnthropicSwiftSDK/Network/Response/InvitationListResponse.swift rename Sources/AnthropicSwiftSDK/Network/Response/{APIKeyListResponse.swift => ObjectListResponse.swift} (57%) delete mode 100644 Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberListResponse.swift delete mode 100644 Sources/AnthropicSwiftSDK/Network/Response/WorkspaceListResponse.swift delete mode 100644 Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberListResponse.swift diff --git a/Sources/AnthropicSwiftSDK/API/Admin/APIKeys.swift b/Sources/AnthropicSwiftSDK/API/Admin/APIKeys.swift index fbdfe04..a7a8a34 100644 --- a/Sources/AnthropicSwiftSDK/API/Admin/APIKeys.swift +++ b/Sources/AnthropicSwiftSDK/API/Admin/APIKeys.swift @@ -26,7 +26,7 @@ public struct APIKeys { status: APIKeyStatus? = nil, workspaceId: String? = nil, createdByUserId: String? = nil - ) async throws -> APIKeyListResponse { + ) async throws -> ObjectListResponse { fatalError() } diff --git a/Sources/AnthropicSwiftSDK/API/Admin/OrganizationInvites.swift b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationInvites.swift index f84219f..65bc0ef 100644 --- a/Sources/AnthropicSwiftSDK/API/Admin/OrganizationInvites.swift +++ b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationInvites.swift @@ -19,7 +19,7 @@ public struct OrganizationInvites { fatalError() } - public func list(limit: Int = 20, beforeId: String? = nil, afterId: String? = nil) async throws -> InvitationListResponse { + public func list(limit: Int = 20, beforeId: String? = nil, afterId: String? = nil) async throws -> ObjectListResponse { fatalError() } diff --git a/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift index d7bac8a..29acce0 100644 --- a/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift +++ b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift @@ -19,7 +19,7 @@ public struct OrganizationMembers { fatalError() } - public func list(limit: Int = 20, beforeId: String? = nil, afterId: String? = nil) async throws -> OrganizationMemberListResponse { + public func list(limit: Int = 20, beforeId: String? = nil, afterId: String? = nil) async throws -> ObjectListResponse { fatalError() } diff --git a/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift b/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift index 3a25460..6abf76b 100644 --- a/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift +++ b/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift @@ -19,7 +19,7 @@ public struct WorkspaceMembers { fatalError() } - public func list(workspaceId: String, limit: Int = 20, beforeId: String? = nil, afterId: String? = nil) async throws -> WorkspaceMemberListResponse { + public func list(workspaceId: String, limit: Int = 20, beforeId: String? = nil, afterId: String? = nil) async throws -> ObjectListResponse { fatalError() } diff --git a/Sources/AnthropicSwiftSDK/API/Admin/Workspaces.swift b/Sources/AnthropicSwiftSDK/API/Admin/Workspaces.swift index b44e42e..dbeef37 100644 --- a/Sources/AnthropicSwiftSDK/API/Admin/Workspaces.swift +++ b/Sources/AnthropicSwiftSDK/API/Admin/Workspaces.swift @@ -19,7 +19,7 @@ public struct Workspaces { fatalError() } - public func list(limit: Int = 20, includeArchive: Bool = false, beforeId: String? = nil, afterId: String? = nil) async throws -> WorkspaceListResponse { + public func list(limit: Int = 20, includeArchive: Bool = false, beforeId: String? = nil, afterId: String? = nil) async throws -> ObjectListResponse { fatalError() } diff --git a/Sources/AnthropicSwiftSDK/API/MessageBatches.swift b/Sources/AnthropicSwiftSDK/API/MessageBatches.swift index 2f745f0..da26f76 100644 --- a/Sources/AnthropicSwiftSDK/API/MessageBatches.swift +++ b/Sources/AnthropicSwiftSDK/API/MessageBatches.swift @@ -231,9 +231,9 @@ public struct MessageBatches { /// - beforeId: The ID to list batches before. /// - afterId: The ID to list batches after. /// - limit: The maximum number of batches to list. - /// - Returns: A `BatchListResponse` containing the list of batches. + /// - Returns: A `ObjectListResponse` containing the list of batches. /// - Throws: An error if the request fails. - public func list(beforeId: String? = nil, afterId: String? = nil, limit: Int = 20) async throws -> BatchListResponse { + public func list(beforeId: String? = nil, afterId: String? = nil, limit: Int = 20) async throws -> ObjectListResponse { try await list( beforeId: beforeId, afterId: afterId, @@ -251,7 +251,7 @@ public struct MessageBatches { /// - limit: The maximum number of batches to list. /// - anthropicHeaderProvider: The provider for Anthropic-specific headers. /// - authenticationHeaderProvider: The provider for authentication headers. - /// - Returns: A `BatchListResponse` containing the list of batches. + /// - Returns: A `ObjectListResponse` containing the list of batches. /// - Throws: An error if the request fails. public func list( beforeId: String?, @@ -259,7 +259,7 @@ public struct MessageBatches { limit: Int, anthropicHeaderProvider: AnthropicHeaderProvider, authenticationHeaderProvider: AuthenticationHeaderProvider - ) async throws -> BatchListResponse { + ) async throws -> ObjectListResponse { let client = APIClient( session: session, anthropicHeaderProvider: anthropicHeaderProvider, @@ -267,18 +267,18 @@ public struct MessageBatches { ) let queries: [String: CustomStringConvertible] = { - var queries: [String: CustomStringConvertible] = [ListMessageBatchesRequest.Parameter.limit.rawValue: limit] + var queries: [String: CustomStringConvertible] = [ListObjectRequest.Parameter.limit.rawValue: limit] if let beforeId { - queries[ListMessageBatchesRequest.Parameter.beforeId.rawValue] = beforeId + queries[ListObjectRequest.Parameter.beforeId.rawValue] = beforeId } if let afterId { - queries[ListMessageBatchesRequest.Parameter.afterId.rawValue] = afterId + queries[ListObjectRequest.Parameter.afterId.rawValue] = afterId } return queries }() - let request = ListMessageBatchesRequest(queries: queries) + let request = ListObjectRequest(queries: queries, type: .batches) let (data, response) = try await client.send(request: request) guard let httpResponse = response as? HTTPURLResponse else { @@ -289,7 +289,7 @@ public struct MessageBatches { throw AnthropicAPIError(fromHttpStatusCode: httpResponse.statusCode) } - return try anthropicJSONDecoder.decode(BatchListResponse.self, from: data) + return try anthropicJSONDecoder.decode(ObjectListResponse.self, from: data) } /// Cancels a specific message batch by its ID. diff --git a/Sources/AnthropicSwiftSDK/Network/Response/BatchListResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/BatchListResponse.swift deleted file mode 100644 index a73ca81..0000000 --- a/Sources/AnthropicSwiftSDK/Network/Response/BatchListResponse.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// BatchListResponse.swift -// AnthropicSwiftSDK -// -// Created by 伊藤史 on 2024/10/09. -// - -/// https://docs.anthropic.com/en/api/listing-message-batches -public struct BatchListResponse: Decodable { - /// List of `BatchResponse` object. - public let data: [BatchResponse] - /// Indicates if there are more results in the requested page direction. - public let hasMore: Bool - /// First ID in the `data` list. Can be used as the `before_id` for the previous page. - public let firstId: String? - /// Last ID in the `data` list. Can be used as the `after_id` for the next page. - public let lastId: String? -} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/InvitationListResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/InvitationListResponse.swift deleted file mode 100644 index ced8406..0000000 --- a/Sources/AnthropicSwiftSDK/Network/Response/InvitationListResponse.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// InvitationListResponse.swift -// AnthropicSwiftSDK -// -// Created by 伊藤史 on 2024/11/28. -// - -public struct InvitationListResponse { - /// List of invitations - public let data: [InvitationResponse] - /// Indicates if there are more results in the requested page direction. - public let hasMore: Bool - /// First ID in the data list. Can be used as the before_id for the previous page. - public let firstId: String? - /// Last ID in the data list. Can be used as the after_id for the next page. - public let lastId: String? -} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/APIKeyListResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/ObjectListResponse.swift similarity index 57% rename from Sources/AnthropicSwiftSDK/Network/Response/APIKeyListResponse.swift rename to Sources/AnthropicSwiftSDK/Network/Response/ObjectListResponse.swift index d243fb5..38cfe06 100644 --- a/Sources/AnthropicSwiftSDK/Network/Response/APIKeyListResponse.swift +++ b/Sources/AnthropicSwiftSDK/Network/Response/ObjectListResponse.swift @@ -1,12 +1,12 @@ // -// APIKeyListResponse.swift +// ObjectListResponse.swift // AnthropicSwiftSDK // // Created by 伊藤史 on 2024/11/28. // -public struct APIKeyListResponse { - public let data: [APIKeyResponse] +public struct ObjectListResponse: Decodable { + public let data: [Object] public let hasMore: Bool public let firstId: String? public let lastId: String? diff --git a/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberListResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberListResponse.swift deleted file mode 100644 index 9dd5a02..0000000 --- a/Sources/AnthropicSwiftSDK/Network/Response/OrganizationMemberListResponse.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// OrganizationMemberListResponse.swift -// AnthropicSwiftSDK -// -// Created by 伊藤史 on 2024/11/28. -// - -public struct OrganizationMemberListResponse { - /// List of organization members - public let data: [OrganizationMemberResponse] - /// Indicates if there are more results in the requested page direction. - public let hasMore: Bool - /// First ID in the data list. Can be used as the before_id for the previous page. - public let firstId: String? - /// Last ID in the data list. Can be used as the after_id for the next page. - public let lastId: String? -} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceListResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceListResponse.swift deleted file mode 100644 index 82c4607..0000000 --- a/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceListResponse.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// WorkspaceListResponse.swift -// AnthropicSwiftSDK -// -// Created by 伊藤史 on 2024/11/28. -// - -public struct WorkspaceListResponse { - /// List of workspaces - public let data: [WorkspaceResponse] - /// Indicates if there are more results in the requested page direction. - public let hasMore: Bool - /// First ID in the data list. Can be used as the before_id for the previous page. - public let firstId: String? - /// Last ID in the data list. Can be used as the after_id for the next page. - public let afterId: String? -} diff --git a/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberListResponse.swift b/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberListResponse.swift deleted file mode 100644 index fc97724..0000000 --- a/Sources/AnthropicSwiftSDK/Network/Response/WorkspaceMemberListResponse.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// WorkspaceMemberListResponse.swift -// AnthropicSwiftSDK -// -// Created by 伊藤史 on 2024/11/28. -// - -public struct WorkspaceMemberListResponse { - public let data: [WorkspaceMemberResponse] - /// Indicates if there are more results in the requested page direction. - public let hasMore: Bool - /// First ID in the data list. Can be used as the before_id for the previous page. - public let firstId: String? - /// Last ID in the data list. Can be used as the after_id for the next page. - public let lastId: String? -} diff --git a/Tests/AnthropicSwiftSDKTests/Network/BatchListResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/BatchListResponseTests.swift index 3d024f4..df61120 100644 --- a/Tests/AnthropicSwiftSDKTests/Network/BatchListResponseTests.swift +++ b/Tests/AnthropicSwiftSDKTests/Network/BatchListResponseTests.swift @@ -56,7 +56,7 @@ final class BatchListResponseTests: XCTestCase { let jsonData = json.data(using: .utf8)! - let response = try anthropicJSONDecoder.decode(BatchListResponse.self, from: jsonData) + let response = try anthropicJSONDecoder.decode(ObjectListResponse.self, from: jsonData) XCTAssertEqual(response.data.count, 2) @@ -96,4 +96,4 @@ final class BatchListResponseTests: XCTestCase { XCTAssertEqual(response.firstId, "batch_123") XCTAssertEqual(response.lastId, "batch_456") } -} \ No newline at end of file +} From 929be89cf501101b48b5b1cc9e3addb8abd0af75 Mon Sep 17 00:00:00 2001 From: Fumito Ito Date: Fri, 29 Nov 2024 11:55:49 +0900 Subject: [PATCH 06/13] use ListObjectRequest --- ...sRequest.swift => ListObjectRequest.swift} | 23 ++++++++++++------- .../ListMessageBatchesRequestTests.swift | 6 ++--- 2 files changed, 18 insertions(+), 11 deletions(-) rename Sources/AnthropicSwiftSDK/Network/Request/{ListMessageBatchesRequest.swift => ListObjectRequest.swift} (68%) diff --git a/Sources/AnthropicSwiftSDK/Network/Request/ListMessageBatchesRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/ListObjectRequest.swift similarity index 68% rename from Sources/AnthropicSwiftSDK/Network/Request/ListMessageBatchesRequest.swift rename to Sources/AnthropicSwiftSDK/Network/Request/ListObjectRequest.swift index 59fdcc5..2e0498d 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/ListMessageBatchesRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/ListObjectRequest.swift @@ -1,17 +1,11 @@ // -// ListMessageBatchesRequest.swift +// ListObjectRequest.swift // AnthropicSwiftSDK // // Created by 伊藤史 on 2024/10/16. // -/// List all Message Batches within a Workspace. Most recently created batches are returned first. -struct ListMessageBatchesRequest: Request { - let method: HttpMethod = .get - let path: String = RequestType.batches.basePath - let queries: [String: CustomStringConvertible]? - let body: Never? = nil - +struct ListObjectRequest: Request { enum Parameter: String { /// ID of the object to use as a cursor for pagination. When provided, returns the page of results immediately before this object. case beforeId = "before_id" @@ -22,4 +16,17 @@ struct ListMessageBatchesRequest: Request { /// Defaults to 20. Ranges from 1 to 100. case limit } + + /// HTTP method of request. It's always `GET` + let method: HttpMethod = .get + /// HTTP request path. It's always base path of `type`. + var path: String { + type.basePath + } + /// HTTP request body. It's always empty + let body: Never? = nil + + let queries: [String: CustomStringConvertible]? + /// type of objects + let type: RequestType } diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/ListMessageBatchesRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/ListMessageBatchesRequestTests.swift index e0f8018..0439c31 100644 --- a/Tests/AnthropicSwiftSDKTests/Network/Request/ListMessageBatchesRequestTests.swift +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/ListMessageBatchesRequestTests.swift @@ -8,15 +8,15 @@ import XCTest @testable import AnthropicSwiftSDK -final class ListMessageBatchesRequestTests: XCTestCase { +final class ListObjectRequestTests: XCTestCase { - func testListMessageBatchesRequestProperties() { + func testListObjectRequestProperties() { let queries: [String: CustomStringConvertible] = [ "before_id": "batch123", "after_id": "batch456", "limit": 10 ] - let request = ListMessageBatchesRequest(queries: queries) + let request = ListObjectRequest(queries: queries, type: .batches) XCTAssertEqual(request.method, .get) XCTAssertEqual(request.path, RequestType.batches.basePath) From 59b3105afa314105fabe10c5f24d72c1814f519d Mon Sep 17 00:00:00 2001 From: Fumito Ito Date: Fri, 29 Nov 2024 15:38:44 +0900 Subject: [PATCH 07/13] add admin api calls --- .../HTTPMock.swift | 1 + .../MessagesRequest+Extensions.swift | 2 +- .../AnthropicSwiftSDK/API/Admin/APIKeys.swift | 82 ++++++++++- .../AnthropicSwiftSDK/API/Admin/Admin.swift | 2 +- .../API/Admin/OrganizationInvites.swift | 101 ++++++++++++- .../API/Admin/OrganizationMembers.swift | 100 ++++++++++++- .../API/Admin/WorkspaceMembers.swift | 137 ++++++++++++++++-- .../API/Admin/Workspaces.swift | 128 +++++++++++++++- .../AnthropicSwiftSDK/API/CountTokens.swift | 12 +- .../API/MessageBatches.swift | 52 +------ Sources/AnthropicSwiftSDK/API/Messages.swift | 12 +- .../Network/AnthropicAPIClient.swift | 15 ++ .../Network/ObjectListable.swift | 44 ++++++ .../Request/APIKeys/GetAPIKeyRequest.swift | 2 +- .../Request/APIKeys/UpdateAPIKeyRequest.swift | 4 +- .../CreateOrganizationInviteRequest.swift | 2 +- .../DeleteOrganizationInviteRequest.swift | 2 +- .../GetOrganizationInviteRequest.swift | 2 +- .../RemoveOrganizationMemberRequest.swift | 2 +- .../UpdateOrganizationMemberRequest.swift | 2 +- .../Network/Request/Request.swift | 3 + .../CreateWorkspaceMemberRequest.swift | 4 +- .../DeleteWorkspaceMemberRequest.swift | 4 +- .../GetWorkspaceMemberRequest.swift | 4 +- .../UpdateWorkspaceMemberRequest.swift | 4 +- .../Workspaces/ArchiveWorkspaceRequest.swift | 2 +- .../Workspaces/CreateWorkspaceRequest.swift | 2 +- .../Workspaces/GetWorkspaceRequest.swift | 2 +- .../Workspaces/UpdateWorkspaceRequest.swift | 2 +- .../Network/AnthropicAPIClientTests.swift | 4 +- .../ListMessageBatchesRequestTests.swift | 6 +- 31 files changed, 607 insertions(+), 134 deletions(-) create mode 100644 Sources/AnthropicSwiftSDK/Network/ObjectListable.swift diff --git a/Sources/AnthropicSwiftSDK-TestUtils/HTTPMock.swift b/Sources/AnthropicSwiftSDK-TestUtils/HTTPMock.swift index 6044bfa..225a885 100644 --- a/Sources/AnthropicSwiftSDK-TestUtils/HTTPMock.swift +++ b/Sources/AnthropicSwiftSDK-TestUtils/HTTPMock.swift @@ -45,6 +45,7 @@ public class HTTPMock: URLProtocol { client?.urlProtocol(self, didLoad: getBasicJSONStringData()) case .request(_, nil), .requestHeader(_, nil): client?.urlProtocol(self, didReceive: succeedResponse, cacheStoragePolicy: .notAllowed) + client?.urlProtocol(self, didLoad: getBasicJSONStringData()) case .request(_, let jsonString), .requestHeader(_, let jsonString): client?.urlProtocol(self, didReceive: succeedResponse, cacheStoragePolicy: .notAllowed) guard let jsonString, let data = jsonString.data(using: .utf8) else { diff --git a/Sources/AnthropicSwiftSDK-TestUtils/MessagesRequest+Extensions.swift b/Sources/AnthropicSwiftSDK-TestUtils/MessagesRequest+Extensions.swift index 7744d4e..5db67cd 100644 --- a/Sources/AnthropicSwiftSDK-TestUtils/MessagesRequest+Extensions.swift +++ b/Sources/AnthropicSwiftSDK-TestUtils/MessagesRequest+Extensions.swift @@ -11,7 +11,7 @@ import AnthropicSwiftSDK public struct NopRequest: Request { public let method: HttpMethod public let path: String - public let queries: [String : any CustomStringConvertible]? = nil + public let queries: [String: any CustomStringConvertible]? = nil public let body: Never? = nil public init( diff --git a/Sources/AnthropicSwiftSDK/API/Admin/APIKeys.swift b/Sources/AnthropicSwiftSDK/API/Admin/APIKeys.swift index a7a8a34..aae31b7 100644 --- a/Sources/AnthropicSwiftSDK/API/Admin/APIKeys.swift +++ b/Sources/AnthropicSwiftSDK/API/Admin/APIKeys.swift @@ -7,30 +7,100 @@ import Foundation public struct APIKeys { - private let adminAPIKey: String + private let apiKey: String private let session: URLSession init(adminAPIKey: String, session: URLSession) { - self.adminAPIKey = adminAPIKey + self.apiKey = adminAPIKey self.session = session } public func get(apiKeyId: String) async throws -> APIKeyResponse { - fatalError() + try await get( + apiKeyId: apiKeyId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func get( + apiKeyId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> APIKeyResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: GetAPIKeyRequest(apiKeyId: apiKeyId)) } public func list( limit: Int = 20, beforeId: String? = nil, - lastId: String? = nil, + afterId: String? = nil, status: APIKeyStatus? = nil, workspaceId: String? = nil, createdByUserId: String? = nil ) async throws -> ObjectListResponse { - fatalError() + fatalError("not implemented") + } + + public func list( + limit: Int = 20, + beforeId: String? = nil, + afterId: String? = nil, + status: APIKeyStatus? = nil, + workspaceId: String? = nil, + createdByUserId: String? = nil, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> ObjectListResponse { + try await list( + session: session, + type: .apiKey, + limit: limit, + beforeId: beforeId, + afterId: afterId, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) } public func update(apiKeyId: String, name: String, status: APIKeyStatus? = nil) async throws -> APIKeyResponse { - fatalError() + try await update( + apiKeyId: apiKeyId, + name: name, + status: status, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func update( + apiKeyId: String, + name: String, + status: APIKeyStatus? = nil, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> APIKeyResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send( + request: UpdateAPIKeyRequest( + body: .init(name: name, status: status), + apiKeyId: apiKeyId + ) + ) } } + +extension APIKeys: ObjectListable { + typealias Object = APIKeyResponse +} diff --git a/Sources/AnthropicSwiftSDK/API/Admin/Admin.swift b/Sources/AnthropicSwiftSDK/API/Admin/Admin.swift index 9caac26..024e539 100644 --- a/Sources/AnthropicSwiftSDK/API/Admin/Admin.swift +++ b/Sources/AnthropicSwiftSDK/API/Admin/Admin.swift @@ -13,7 +13,7 @@ public struct Admin { public let workspaceMembers: WorkspaceMembers public let apiKeys: APIKeys - init(adminAPIKey apiKey: String, session: URLSession = .shared) { + public init(adminAPIKey apiKey: String, session: URLSession = .shared) { self.organizationMembers = OrganizationMembers(adminAPIKey: apiKey, session: session) self.organizationInvites = OrganizationInvites(adminAPIKey: apiKey, session: session) self.workspaces = Workspaces(adminAPIKey: apiKey, session: session) diff --git a/Sources/AnthropicSwiftSDK/API/Admin/OrganizationInvites.swift b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationInvites.swift index 65bc0ef..6f42a0e 100644 --- a/Sources/AnthropicSwiftSDK/API/Admin/OrganizationInvites.swift +++ b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationInvites.swift @@ -7,27 +7,116 @@ import Foundation public struct OrganizationInvites { - private let adminAPIKey: String + private let apiKey: String private let session: URLSession init(adminAPIKey: String, session: URLSession) { - self.adminAPIKey = adminAPIKey + self.apiKey = adminAPIKey self.session = session } public func get(invitationId: String) async throws -> InvitationResponse { - fatalError() + try await get( + invitationId: invitationId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func get( + invitationId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> InvitationResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: GetOrganizationInviteRequest(invitationId: invitationId)) } public func list(limit: Int = 20, beforeId: String? = nil, afterId: String? = nil) async throws -> ObjectListResponse { - fatalError() + try await list( + limit: limit, + beforeId: beforeId, + afterId: afterId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func list( + limit: Int = 20, + beforeId: String? = nil, + afterId: String? = nil, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> ObjectListResponse { + try await list( + session: session, + type: .organizationInvite, + limit: limit, + beforeId: beforeId, + afterId: afterId, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) } public func send(invitation: Invitation) async throws -> InvitationResponse { - fatalError() + try await send( + invitation: invitation, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func send( + invitation: Invitation, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> InvitationResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send( + request: CreateOrganizationInviteRequest( + body: .init( + email: invitation.email, + role: invitation.role + ) + ) + ) } public func remove(invitationId: String) async throws -> InvitationRemoveResponse { - fatalError() + try await remove( + invitationId: invitationId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func remove( + invitationId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> InvitationRemoveResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: DeleteOrganizationInviteRequest(invitationId: invitationId)) } } + +extension OrganizationInvites: ObjectListable { + typealias Object = InvitationResponse +} diff --git a/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift index 29acce0..393f399 100644 --- a/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift +++ b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift @@ -7,27 +7,111 @@ import Foundation public struct OrganizationMembers { - private let adminAPIKey: String - private let session: URLSession + let apiKey: String + let session: URLSession - init(adminAPIKey: String, session: URLSession) { - self.adminAPIKey = adminAPIKey + init(adminAPIKey apiKey: String, session: URLSession) { + self.apiKey = apiKey self.session = session } public func get(userId: String) async throws -> OrganizationMemberResponse { - fatalError() + try await get( + userId: userId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func get( + userId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> OrganizationMemberResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: GetOrganizationMemberRequest(userId: userId)) } public func list(limit: Int = 20, beforeId: String? = nil, afterId: String? = nil) async throws -> ObjectListResponse { - fatalError() + try await list( + limit: limit, + beforeId: beforeId, + afterId: afterId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func list( + limit: Int = 20, + beforeId: String? = nil, + afterId: String? = nil, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> ObjectListResponse { + try await list( + session: session, + type: .organizationMember, + limit: limit, + beforeId: beforeId, + afterId: afterId, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) } public func update(userId: String, role: OrganizationRole) async throws -> OrganizationMemberResponse { - fatalError() + try await update( + userId: userId, + role: role, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func update( + userId: String, + role: OrganizationRole, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> OrganizationMemberResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: UpdateOrganizationMemberRequest(body: role, userId: userId)) } public func remove(userId: String) async throws -> OrganizationMemberRemoveResponse { - fatalError() + try await remove( + userId: userId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func remove( + userId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> OrganizationMemberRemoveResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: RemoveOrganizationMemberRequest(userId: userId)) } } + +extension OrganizationMembers: ObjectListable { + typealias Object = OrganizationMemberResponse +} diff --git a/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift b/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift index 6abf76b..08007a4 100644 --- a/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift +++ b/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift @@ -7,31 +7,148 @@ import Foundation public struct WorkspaceMembers { - private let adminAPIKey: String + private let apiKey: String private let session: URLSession init(adminAPIKey: String, session: URLSession) { - self.adminAPIKey = adminAPIKey + self.apiKey = adminAPIKey self.session = session } public func get(userId: String, workspaceId: String) async throws -> WorkspaceMemberResponse { - fatalError() + try await get( + userId: userId, + workspaceId: workspaceId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func get( + userId: String, + workspaceId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> WorkspaceMemberResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: GetWorkspaceMemberRequest(workspaceId: workspaceId, userId: userId)) } public func list(workspaceId: String, limit: Int = 20, beforeId: String? = nil, afterId: String? = nil) async throws -> ObjectListResponse { - fatalError() + try await list( + workspaceId: workspaceId, + limit: limit, + beforeId: beforeId, + afterId: afterId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func list( + workspaceId: String, + limit: Int = 20, + beforeId: String? = nil, + afterId: String? = nil, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> ObjectListResponse { + try await list( + session: session, + type: .workspaceMember(workspaceId: workspaceId), + limit: limit, + beforeId: beforeId, + afterId: afterId, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + } + + public func add(registration: Registration, workspaceId: String) async throws -> WorkspaceMemberResponse { + try await add( + registration: registration, + workspaceId: workspaceId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func add( + registration: Registration, + workspaceId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> WorkspaceMemberResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send( + request: CreateWorkspaceMemberRequest( + body: registration, + workspaceId: workspaceId + ) + ) + } + + public func update(userId: String, workspaceId: String, role: WorkspaceRole) async throws -> WorkspaceMemberResponse { + try await update( + userId: userId, + workspaceId: workspaceId, + role: role, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) } - public func add(registration: Registration, wokspaceId: String) async throws -> WorkspaceMemberResponse { - fatalError() + public func update( + userId: String, + workspaceId: String, + role: WorkspaceRole, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> WorkspaceMemberResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: UpdateWorkspaceMemberRequest(body: role, userId: userId, workspaceId: workspaceId)) } - public func update(userId: String, workspaceId: String, as role: WorkspaceRole) async throws -> WorkspaceMemberResponse { - fatalError() + public func remove(userId: String, workspaceId: String) async throws -> WorkspaceMemberRemoveResponse { + try await remove( + userId: userId, + workspaceId: workspaceId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) } - public func delete(userId: String, workspaceId: String) async throws -> WorkspaceMemberRemoveResponse { - fatalError() + public func remove( + userId: String, + workspaceId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> WorkspaceMemberRemoveResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: DeleteWorkspaceMemberRequest(userId: userId, workspaceId: workspaceId)) } } + +extension WorkspaceMembers: ObjectListable { + typealias Object = WorkspaceMemberResponse +} diff --git a/Sources/AnthropicSwiftSDK/API/Admin/Workspaces.swift b/Sources/AnthropicSwiftSDK/API/Admin/Workspaces.swift index dbeef37..0e20a21 100644 --- a/Sources/AnthropicSwiftSDK/API/Admin/Workspaces.swift +++ b/Sources/AnthropicSwiftSDK/API/Admin/Workspaces.swift @@ -7,31 +7,145 @@ import Foundation public struct Workspaces { - private let adminAPIKey: String + private let apiKey: String private let session: URLSession init(adminAPIKey: String, session: URLSession) { - self.adminAPIKey = adminAPIKey + self.apiKey = adminAPIKey self.session = session } public func get(workspaceId: String) async throws -> WorkspaceResponse { - fatalError() + try await get( + workspaceId: workspaceId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func get( + workspaceId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> WorkspaceResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: GetWorkspaceRequest(workspaceId: workspaceId)) } public func list(limit: Int = 20, includeArchive: Bool = false, beforeId: String? = nil, afterId: String? = nil) async throws -> ObjectListResponse { - fatalError() + try await list( + limit: limit, + includeArchive: includeArchive, + beforeId: beforeId, + afterId: afterId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func list( + limit: Int = 20, + includeArchive: Bool = false, + beforeId: String? = nil, + afterId: String? = nil, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> ObjectListResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + let queries: [String: CustomStringConvertible] = { + var queries: [String: CustomStringConvertible] = [ListObjectRequest.Parameter.limit.rawValue: limit] + queries["include_archived"] = includeArchive + if let beforeId { + queries[ListObjectRequest.Parameter.beforeId.rawValue] = beforeId + } + if let afterId { + queries[ListObjectRequest.Parameter.afterId.rawValue] = afterId + } + return queries + }() + + return try await client.send(request: ListObjectRequest(queries: queries, type: .workspace)) } public func update(name: String, workspaceId: String) async throws -> WorkspaceResponse { - fatalError() + try await update( + name: name, + workspaceId: workspaceId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func update( + name: String, + workspaceId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> WorkspaceResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: UpdateWorkspaceRequest(body: .init(name: name), workspaceId: workspaceId)) } public func create(name: String) async throws -> WorkspaceResponse { - fatalError() + try await create( + name: name, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) + } + + public func create( + name: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> WorkspaceResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: CreateWorkspaceRequest(body: .init(name: name))) } public func archive(_ workspaceId: String) async throws -> WorkspaceResponse { - fatalError() + try await archive( + workspaceId, + anthropicHeaderProvider: DefaultAnthropicHeaderProvider(), + authenticationHeaderProvider: APIKeyAuthenticationHeaderProvider(apiKey: apiKey) + ) } + + public func archive( + _ workspaceId: String, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> WorkspaceResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + return try await client.send(request: ArchiveWorkspaceRequest(workspaceId: workspaceId)) + } +} + +extension Workspaces: ObjectListable { + typealias Object = WorkspaceResponse } diff --git a/Sources/AnthropicSwiftSDK/API/CountTokens.swift b/Sources/AnthropicSwiftSDK/API/CountTokens.swift index c2eb5cc..ca6cd50 100644 --- a/Sources/AnthropicSwiftSDK/API/CountTokens.swift +++ b/Sources/AnthropicSwiftSDK/API/CountTokens.swift @@ -90,16 +90,6 @@ public struct CountTokens { ) ) - let (data, response) = try await client.send(request: request) - - guard let httpResponse = response as? HTTPURLResponse else { - throw ClientError.cannotHandleURLResponse(response) - } - - guard httpResponse.statusCode == 200 else { - throw AnthropicAPIError(fromHttpStatusCode: httpResponse.statusCode) - } - - return try anthropicJSONDecoder.decode(CountTokenResponse.self, from: data) + return try await client.send(request: request) } } diff --git a/Sources/AnthropicSwiftSDK/API/MessageBatches.swift b/Sources/AnthropicSwiftSDK/API/MessageBatches.swift index da26f76..bcebfe3 100644 --- a/Sources/AnthropicSwiftSDK/API/MessageBatches.swift +++ b/Sources/AnthropicSwiftSDK/API/MessageBatches.swift @@ -59,18 +59,7 @@ public struct MessageBatches { authenticationHeaderProvider: authenticationHeaderProvider ) - let request = MessageBatchesRequest(body: .init(from: batches)) - let (data, response) = try await client.send(request: request) - - guard let httpResponse = response as? HTTPURLResponse else { - throw ClientError.cannotHandleURLResponse(response) - } - - guard httpResponse.statusCode == 200 else { - throw AnthropicAPIError(fromHttpStatusCode: httpResponse.statusCode) - } - - return try anthropicJSONDecoder.decode(BatchResponse.self, from: data) + return try await client.send(request: MessageBatchesRequest(body: .init(from: batches))) } /// Retrieves a specific message batch by its ID. @@ -105,18 +94,7 @@ public struct MessageBatches { authenticationHeaderProvider: authenticationHeaderProvider ) - let request = RetrieveMessageBatchesRequest(batchId: batchId) - let (data, response) = try await client.send(request: request) - - guard let httpResponse = response as? HTTPURLResponse else { - throw ClientError.cannotHandleURLResponse(response) - } - - guard httpResponse.statusCode == 200 else { - throw AnthropicAPIError(fromHttpStatusCode: httpResponse.statusCode) - } - - return try anthropicJSONDecoder.decode(BatchResponse.self, from: data) + return try await client.send(request: RetrieveMessageBatchesRequest(batchId: batchId)) } /// Retrieves the results of a specific message batch by its ID. @@ -278,18 +256,7 @@ public struct MessageBatches { return queries }() - let request = ListObjectRequest(queries: queries, type: .batches) - let (data, response) = try await client.send(request: request) - - guard let httpResponse = response as? HTTPURLResponse else { - throw ClientError.cannotHandleURLResponse(response) - } - - guard httpResponse.statusCode == 200 else { - throw AnthropicAPIError(fromHttpStatusCode: httpResponse.statusCode) - } - - return try anthropicJSONDecoder.decode(ObjectListResponse.self, from: data) + return try await client.send(request: ListObjectRequest(queries: queries, type: .batches)) } /// Cancels a specific message batch by its ID. @@ -324,18 +291,7 @@ public struct MessageBatches { authenticationHeaderProvider: authenticationHeaderProvider ) - let request = CancelMessageBatchRequest(batchId: batchId) - let (data, response) = try await client.send(request: request) - - guard let httpResponse = response as? HTTPURLResponse else { - throw ClientError.cannotHandleURLResponse(response) - } - - guard httpResponse.statusCode == 200 else { - throw AnthropicAPIError(fromHttpStatusCode: httpResponse.statusCode) - } - - return try anthropicJSONDecoder.decode(BatchResponse.self, from: data) + return try await client.send(request: CancelMessageBatchRequest(batchId: batchId)) } } diff --git a/Sources/AnthropicSwiftSDK/API/Messages.swift b/Sources/AnthropicSwiftSDK/API/Messages.swift index 536e941..0212f28 100644 --- a/Sources/AnthropicSwiftSDK/API/Messages.swift +++ b/Sources/AnthropicSwiftSDK/API/Messages.swift @@ -120,17 +120,7 @@ public struct Messages { ) ) - let (data, response) = try await client.send(request: request) - - guard let httpResponse = response as? HTTPURLResponse else { - throw ClientError.cannotHandleURLResponse(response) - } - - guard httpResponse.statusCode == 200 else { - throw AnthropicAPIError(fromHttpStatusCode: httpResponse.statusCode) - } - - return try anthropicJSONDecoder.decode(MessagesResponse.self, from: data) + return try await client.send(request: request) } /// Streams messages using the specified parameters and sends a request to the Anthropic API asynchronously. diff --git a/Sources/AnthropicSwiftSDK/Network/AnthropicAPIClient.swift b/Sources/AnthropicSwiftSDK/Network/AnthropicAPIClient.swift index 5cfcbcb..f4ff1db 100644 --- a/Sources/AnthropicSwiftSDK/Network/AnthropicAPIClient.swift +++ b/Sources/AnthropicSwiftSDK/Network/AnthropicAPIClient.swift @@ -52,6 +52,21 @@ struct APIClient { return try await session.data(for: urlRequest) } + func send(request: any Request) async throws -> Object { + let (data, response) = try await self.send(request: request) + + guard let httpResponse = response as? HTTPURLResponse else { + throw ClientError.cannotHandleURLResponse(response) + } + + guard httpResponse.statusCode == 200 else { + throw AnthropicAPIError(fromHttpStatusCode: httpResponse.statusCode) + } + + return try anthropicJSONDecoder.decode(Object.self, from: data) + } + + /// Send messages API request. This method read the API response sequentially. /// /// - Parameter request: request body for api request diff --git a/Sources/AnthropicSwiftSDK/Network/ObjectListable.swift b/Sources/AnthropicSwiftSDK/Network/ObjectListable.swift new file mode 100644 index 0000000..ceed9d7 --- /dev/null +++ b/Sources/AnthropicSwiftSDK/Network/ObjectListable.swift @@ -0,0 +1,44 @@ +// +// ObjectListable.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/03. +// +import Foundation + +protocol ObjectListable { + associatedtype Object: Decodable +} + +extension ObjectListable { + // swiftlint:disable:next function_parameter_count + func list( + session: URLSession, + type: RequestType, + limit: Int, + beforeId: String?, + afterId: String?, + anthropicHeaderProvider: AnthropicHeaderProvider, + authenticationHeaderProvider: AuthenticationHeaderProvider + ) async throws -> ObjectListResponse { + let client = APIClient( + session: session, + anthropicHeaderProvider: anthropicHeaderProvider, + authenticationHeaderProvider: authenticationHeaderProvider + ) + + let queries: [String: CustomStringConvertible] = { + var queries: [String: CustomStringConvertible] = [ListObjectRequest.Parameter.limit.rawValue: limit] + if let beforeId { + queries[ListObjectRequest.Parameter.beforeId.rawValue] = beforeId + } + if let afterId { + queries[ListObjectRequest.Parameter.afterId.rawValue] = afterId + } + + return queries + }() + + return try await client.send(request: ListObjectRequest(queries: queries, type: type)) + } +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/GetAPIKeyRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/GetAPIKeyRequest.swift index 6d554c9..a8d216e 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/GetAPIKeyRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/GetAPIKeyRequest.swift @@ -10,7 +10,7 @@ struct GetAPIKeyRequest: Request { var path: String { "\(RequestType.apiKey.basePath)/\(apiKeyId)" } - let queries: [String : any CustomStringConvertible]? = nil + let queries: [String: any CustomStringConvertible]? = nil let body: Never? = nil let apiKeyId: String diff --git a/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/UpdateAPIKeyRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/UpdateAPIKeyRequest.swift index 7fcef3e..b286d56 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/UpdateAPIKeyRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/APIKeys/UpdateAPIKeyRequest.swift @@ -11,7 +11,7 @@ struct UpdateAPIKeyRequest: Request { var path: String { "\(RequestType.apiKey.basePath)/\(apiKeyId)" } - let queries: [String : any CustomStringConvertible]? = nil + let queries: [String: any CustomStringConvertible]? = nil let body: APIKeyRequestBody? let apiKeyId: String @@ -19,5 +19,5 @@ struct UpdateAPIKeyRequest: Request { struct APIKeyRequestBody: Encodable { let name: String - let status: APIKeyStatus + let status: APIKeyStatus? } diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/CreateOrganizationInviteRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/CreateOrganizationInviteRequest.swift index 3a3c452..5a925ff 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/CreateOrganizationInviteRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/CreateOrganizationInviteRequest.swift @@ -10,7 +10,7 @@ struct CreateOrganizationInviteRequest: Request { let method: HttpMethod = .post let path: String = RequestType.organizationInvite.basePath - let queries: [String : any CustomStringConvertible]? = nil + let queries: [String: any CustomStringConvertible]? = nil let body: Invitation? } diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/DeleteOrganizationInviteRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/DeleteOrganizationInviteRequest.swift index 0b639cb..b7fbb1d 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/DeleteOrganizationInviteRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/DeleteOrganizationInviteRequest.swift @@ -10,7 +10,7 @@ struct DeleteOrganizationInviteRequest: Request { var path: String { "\(RequestType.organizationInvite.basePath)/\(invitationId)" } - let queries: [String : any CustomStringConvertible]? = nil + let queries: [String: any CustomStringConvertible]? = nil let body: Never? = nil let invitationId: String diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/GetOrganizationInviteRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/GetOrganizationInviteRequest.swift index b1946ed..8fd4eee 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/GetOrganizationInviteRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationInvites/GetOrganizationInviteRequest.swift @@ -10,7 +10,7 @@ struct GetOrganizationInviteRequest: Request { var path: String { "\(RequestType.organizationInvite.basePath)/\(invitationId)" } - let queries: [String : any CustomStringConvertible]? = nil + let queries: [String: any CustomStringConvertible]? = nil let body: Never? = nil let invitationId: String diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/RemoveOrganizationMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/RemoveOrganizationMemberRequest.swift index 45b3380..8333340 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/RemoveOrganizationMemberRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/RemoveOrganizationMemberRequest.swift @@ -10,7 +10,7 @@ struct RemoveOrganizationMemberRequest: Request { var path: String { "\(RequestType.organizationMember.basePath)/\(userId)" } - let queries: [String : any CustomStringConvertible]? = nil + let queries: [String: any CustomStringConvertible]? = nil let body: Never? = nil let userId: String diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/UpdateOrganizationMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/UpdateOrganizationMemberRequest.swift index e033025..106e230 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/UpdateOrganizationMemberRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/UpdateOrganizationMemberRequest.swift @@ -12,7 +12,7 @@ struct UpdateOrganizationMemberRequest: Request { var path: String { "\(RequestType.organizationMember)/\(userId)" } - let queries: [String : any CustomStringConvertible]? = nil + let queries: [String: any CustomStringConvertible]? = nil let body: OrganizationRole? let userId: String diff --git a/Sources/AnthropicSwiftSDK/Network/Request/Request.swift b/Sources/AnthropicSwiftSDK/Network/Request/Request.swift index f08f388..117c700 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/Request.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/Request.swift @@ -20,6 +20,7 @@ enum RequestType { case organizationMember case organizationInvite case workspace + case workspaceMember(workspaceId: String) case apiKey var basePath: String { @@ -36,6 +37,8 @@ enum RequestType { return "/v1/organizations/invites" case .workspace: return "/v1/organizations/workspaces" + case .workspaceMember(let workspaceId): + return "/v1/organizations/workspaces/\(workspaceId)/members" case .apiKey: return "/v1/organizations/api_keys" } diff --git a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/CreateWorkspaceMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/CreateWorkspaceMemberRequest.swift index d8a05fb..4ec0e65 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/CreateWorkspaceMemberRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/CreateWorkspaceMemberRequest.swift @@ -10,9 +10,9 @@ struct CreateWorkspaceMemberRequest: Request { let method: HttpMethod = .post var path: String { - "\(RequestType.workspace.basePath)/\(workspaceId)/members" + RequestType.workspaceMember(workspaceId: workspaceId).basePath } - let queries: [String : any CustomStringConvertible]? = nil + let queries: [String: any CustomStringConvertible]? = nil let body: Registration? let workspaceId: String diff --git a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/DeleteWorkspaceMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/DeleteWorkspaceMemberRequest.swift index a0e6dc4..7430460 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/DeleteWorkspaceMemberRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/DeleteWorkspaceMemberRequest.swift @@ -8,9 +8,9 @@ struct DeleteWorkspaceMemberRequest: Request { let method: HttpMethod = .delete var path: String { - "\(RequestType.workspace.basePath)/\(workspaceId)/members/\(userId)" + "\(RequestType.workspaceMember(workspaceId: workspaceId).basePath)/\(userId)" } - let queries: [String : any CustomStringConvertible]? = nil + let queries: [String: any CustomStringConvertible]? = nil let body: Never? = nil let userId: String diff --git a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/GetWorkspaceMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/GetWorkspaceMemberRequest.swift index 20739ad..7350a35 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/GetWorkspaceMemberRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/GetWorkspaceMemberRequest.swift @@ -8,9 +8,9 @@ struct GetWorkspaceMemberRequest: Request { let method: HttpMethod = .get var path: String { - "\(RequestType.workspace.basePath)/\(workspaceId)/members/\(userId)" + "\(RequestType.workspaceMember(workspaceId: workspaceId).basePath)/\(userId)" } - let queries: [String : any CustomStringConvertible]? = nil + let queries: [String: any CustomStringConvertible]? = nil let body: Never? = nil let workspaceId: String diff --git a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/UpdateWorkspaceMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/UpdateWorkspaceMemberRequest.swift index ffc1bc5..d433ce7 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/UpdateWorkspaceMemberRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/UpdateWorkspaceMemberRequest.swift @@ -10,9 +10,9 @@ struct UpdateWorkspaceMemberRequest: Request { let method: HttpMethod = .post var path: String { - "\(RequestType.workspace.basePath)/\(workspaceId)/members/\(userId)" + "\(RequestType.workspaceMember(workspaceId: workspaceId).basePath)/\(userId)" } - let queries: [String : any CustomStringConvertible]? = nil + let queries: [String: any CustomStringConvertible]? = nil let body: WorkspaceRole? let userId: String diff --git a/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/ArchiveWorkspaceRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/ArchiveWorkspaceRequest.swift index dfb22b8..206a2c2 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/ArchiveWorkspaceRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/ArchiveWorkspaceRequest.swift @@ -10,7 +10,7 @@ struct ArchiveWorkspaceRequest: Request { var path: String { "\(RequestType.workspace.basePath)/\(workspaceId)/archive" } - var queries: [String : any CustomStringConvertible]? + var queries: [String: any CustomStringConvertible]? let body: Never? = nil let workspaceId: String diff --git a/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/CreateWorkspaceRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/CreateWorkspaceRequest.swift index 25aef6a..bb8e728 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/CreateWorkspaceRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/CreateWorkspaceRequest.swift @@ -10,7 +10,7 @@ struct CreateWorkspaceRequest: Request { let method: HttpMethod = .post let path: String = RequestType.workspace.basePath - let queries: [String : any CustomStringConvertible]? = nil + let queries: [String: any CustomStringConvertible]? = nil let body: WorkspaceRequestBody? } diff --git a/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/GetWorkspaceRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/GetWorkspaceRequest.swift index cd16747..47444aa 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/GetWorkspaceRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/GetWorkspaceRequest.swift @@ -10,7 +10,7 @@ struct GetWorkspaceRequest: Request { var path: String { "\(RequestType.workspace.basePath)/\(workspaceId)" } - let queries: [String : any CustomStringConvertible]? = nil + let queries: [String: any CustomStringConvertible]? = nil let body: Never? = nil let workspaceId: String diff --git a/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/UpdateWorkspaceRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/UpdateWorkspaceRequest.swift index ded36b9..e6ab5ed 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/UpdateWorkspaceRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/Workspaces/UpdateWorkspaceRequest.swift @@ -12,7 +12,7 @@ struct UpdateWorkspaceRequest: Request { var path: String { "\(RequestType.workspace.basePath)/\(workspaceId)" } - let queries: [String : any CustomStringConvertible]? = nil + let queries: [String: any CustomStringConvertible]? = nil let body: WorkspaceRequestBody? let workspaceId: String diff --git a/Tests/AnthropicSwiftSDKTests/Network/AnthropicAPIClientTests.swift b/Tests/AnthropicSwiftSDKTests/Network/AnthropicAPIClientTests.swift index 3d73270..481d1d5 100644 --- a/Tests/AnthropicSwiftSDKTests/Network/AnthropicAPIClientTests.swift +++ b/Tests/AnthropicSwiftSDKTests/Network/AnthropicAPIClientTests.swift @@ -34,7 +34,7 @@ final class AnthropicAPIClientTests: XCTestCase { expectation.fulfill() }, nil) - let _ = try await client.send(request: NopRequest()) + let _: MessagesResponse = try await client.send(request: NopRequest()) await fulfillment(of: [expectation], timeout: 1.0) } @@ -74,7 +74,7 @@ final class AnthropicAPIClientTests: XCTestCase { expectation.fulfill() }, nil) - let _ = try await client.send(request: NopRequest()) + let _: MessagesResponse = try await client.send(request: NopRequest()) await fulfillment(of: [expectation], timeout: 1.0) } diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/ListMessageBatchesRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/ListMessageBatchesRequestTests.swift index 0439c31..dfd63c7 100644 --- a/Tests/AnthropicSwiftSDKTests/Network/Request/ListMessageBatchesRequestTests.swift +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/ListMessageBatchesRequestTests.swift @@ -27,8 +27,8 @@ final class ListObjectRequestTests: XCTestCase { } func testParameterRawValues() { - XCTAssertEqual(ListMessageBatchesRequest.Parameter.beforeId.rawValue, "before_id") - XCTAssertEqual(ListMessageBatchesRequest.Parameter.afterId.rawValue, "after_id") - XCTAssertEqual(ListMessageBatchesRequest.Parameter.limit.rawValue, "limit") + XCTAssertEqual(ListObjectRequest.Parameter.beforeId.rawValue, "before_id") + XCTAssertEqual(ListObjectRequest.Parameter.afterId.rawValue, "after_id") + XCTAssertEqual(ListObjectRequest.Parameter.limit.rawValue, "limit") } } From 347ebf512116122b43772723a9a5531a41231fa9 Mon Sep 17 00:00:00 2001 From: Fumito Ito Date: Fri, 6 Dec 2024 13:13:47 +0900 Subject: [PATCH 08/13] add iterface for Admin API --- Sources/AnthropicSwiftSDK/Anthropic.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Sources/AnthropicSwiftSDK/Anthropic.swift b/Sources/AnthropicSwiftSDK/Anthropic.swift index 24ab227..a6d200d 100644 --- a/Sources/AnthropicSwiftSDK/Anthropic.swift +++ b/Sources/AnthropicSwiftSDK/Anthropic.swift @@ -26,3 +26,15 @@ public final class Anthropic { self.countTokens = CountTokens(apiKey: apiKey, session: .shared) } } + +public final class AnthropicAdmin { + /// Admin API interface + public let admin: Admin + + /// Construction of Admin SDK + /// + /// - Parameter adminAPIKey: API key to access Anthropic Admin API + public init(adminAPIKey: String, session: URLSession = .shared) { + self.admin = Admin(adminAPIKey: adminAPIKey, session: session) + } +} From 507b7f2e041c8aaf56e0a8c9fb873e7351ca76de Mon Sep 17 00:00:00 2001 From: Fumito Ito Date: Fri, 6 Dec 2024 13:01:38 +0900 Subject: [PATCH 09/13] move test files --- .../{ => API}/MessageBatchesTests.swift | 0 Tests/AnthropicSwiftSDKTests/{ => API}/MessagesTests.swift | 0 .../Network/{ => Response}/BatchResponseTests.swift | 0 .../Network/{ => Response}/BatchResultResponseTests.swift | 0 .../Network/{ => Response}/MessagesResponseTests.swift | 0 .../ObjectListResponseTests.swift} | 4 ++-- 6 files changed, 2 insertions(+), 2 deletions(-) rename Tests/AnthropicSwiftSDKTests/{ => API}/MessageBatchesTests.swift (100%) rename Tests/AnthropicSwiftSDKTests/{ => API}/MessagesTests.swift (100%) rename Tests/AnthropicSwiftSDKTests/Network/{ => Response}/BatchResponseTests.swift (100%) rename Tests/AnthropicSwiftSDKTests/Network/{ => Response}/BatchResultResponseTests.swift (100%) rename Tests/AnthropicSwiftSDKTests/Network/{ => Response}/MessagesResponseTests.swift (100%) rename Tests/AnthropicSwiftSDKTests/Network/{BatchListResponseTests.swift => Response/ObjectListResponseTests.swift} (97%) diff --git a/Tests/AnthropicSwiftSDKTests/MessageBatchesTests.swift b/Tests/AnthropicSwiftSDKTests/API/MessageBatchesTests.swift similarity index 100% rename from Tests/AnthropicSwiftSDKTests/MessageBatchesTests.swift rename to Tests/AnthropicSwiftSDKTests/API/MessageBatchesTests.swift diff --git a/Tests/AnthropicSwiftSDKTests/MessagesTests.swift b/Tests/AnthropicSwiftSDKTests/API/MessagesTests.swift similarity index 100% rename from Tests/AnthropicSwiftSDKTests/MessagesTests.swift rename to Tests/AnthropicSwiftSDKTests/API/MessagesTests.swift diff --git a/Tests/AnthropicSwiftSDKTests/Network/BatchResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/BatchResponseTests.swift similarity index 100% rename from Tests/AnthropicSwiftSDKTests/Network/BatchResponseTests.swift rename to Tests/AnthropicSwiftSDKTests/Network/Response/BatchResponseTests.swift diff --git a/Tests/AnthropicSwiftSDKTests/Network/BatchResultResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/BatchResultResponseTests.swift similarity index 100% rename from Tests/AnthropicSwiftSDKTests/Network/BatchResultResponseTests.swift rename to Tests/AnthropicSwiftSDKTests/Network/Response/BatchResultResponseTests.swift diff --git a/Tests/AnthropicSwiftSDKTests/Network/MessagesResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/MessagesResponseTests.swift similarity index 100% rename from Tests/AnthropicSwiftSDKTests/Network/MessagesResponseTests.swift rename to Tests/AnthropicSwiftSDKTests/Network/Response/MessagesResponseTests.swift diff --git a/Tests/AnthropicSwiftSDKTests/Network/BatchListResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/ObjectListResponseTests.swift similarity index 97% rename from Tests/AnthropicSwiftSDKTests/Network/BatchListResponseTests.swift rename to Tests/AnthropicSwiftSDKTests/Network/Response/ObjectListResponseTests.swift index df61120..88203aa 100644 --- a/Tests/AnthropicSwiftSDKTests/Network/BatchListResponseTests.swift +++ b/Tests/AnthropicSwiftSDKTests/Network/Response/ObjectListResponseTests.swift @@ -1,5 +1,5 @@ // -// BatchListResponseTests.swift +// ObjectListResponseTests.swift // AnthropicSwiftSDK // // Created by 伊藤史 on 2024/10/18. @@ -8,7 +8,7 @@ import XCTest @testable import AnthropicSwiftSDK -final class BatchListResponseTests: XCTestCase { +final class ObjectListResponseTests: XCTestCase { func testDecodeBatchListResponse() throws { let json = """ { From 3e9c26dd0846347a8768c07b0da54b28cd1df161 Mon Sep 17 00:00:00 2001 From: Fumito Ito Date: Fri, 6 Dec 2024 13:01:52 +0900 Subject: [PATCH 10/13] add tests to decode for response objects of Admin API --- .../Response/APIKeyResponseTests.swift | 42 +++++++++++++++ .../OrganizationInviteResponseTests.swift | 51 +++++++++++++++++++ .../OrganizationMemberResponseTests.swift | 49 ++++++++++++++++++ .../WorkspaceMemberResponseTests.swift | 47 +++++++++++++++++ .../Response/WorkspaceResponseTests.swift | 34 +++++++++++++ 5 files changed, 223 insertions(+) create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Response/APIKeyResponseTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Response/OrganizationInviteResponseTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Response/OrganizationMemberResponseTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Response/WorkspaceMemberResponseTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Response/WorkspaceResponseTests.swift diff --git a/Tests/AnthropicSwiftSDKTests/Network/Response/APIKeyResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/APIKeyResponseTests.swift new file mode 100644 index 0000000..ac9588c --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Response/APIKeyResponseTests.swift @@ -0,0 +1,42 @@ +// +// APIKeyResponseTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/06. +// + +import XCTest +import AnthropicSwiftSDK + +final class APIKeyResponseTests: XCTestCase { + func testDecodeAPIKeyResponse() throws { + let json = """ + { + "id": "apikey_01Rj2N8SVvo6BePZj99NhmiT", + "type": "api_key", + "name": "Developer Key", + "workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "created_at": "2024-10-30T23:58:27.427722Z", + "created_by": { + "id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "type": "user" + }, + "partial_key_hint": "sk-ant-api03-R2D...igAA", + "status": "active" + } + """ + + let jsonData = json.data(using: .utf8)! + let response = try anthropicJSONDecoder.decode(APIKeyResponse.self, from: jsonData) + + XCTAssertEqual(response.id, "apikey_01Rj2N8SVvo6BePZj99NhmiT") + XCTAssertEqual(response.type, .apiKey) + XCTAssertEqual(response.name, "Developer Key") + XCTAssertEqual(response.workspaceId, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.createdAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.createdBy.id, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.createdBy.type, "user") + XCTAssertEqual(response.partialKeyHint, "sk-ant-api03-R2D...igAA") + XCTAssertEqual(response.status, .active) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Response/OrganizationInviteResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/OrganizationInviteResponseTests.swift new file mode 100644 index 0000000..98a2024 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Response/OrganizationInviteResponseTests.swift @@ -0,0 +1,51 @@ +// +// OrganizationInviteResponseTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/06. +// + +import XCTest +import AnthropicSwiftSDK + +final class OrganizationInviteResponseTests: XCTestCase { + func testDecodeOrganizationInviteResponse() throws { + let json = """ + { + "id": "invite_015gWxCN9Hfg2QhZwTK7Mdeu", + "type": "invite", + "email": "user@emaildomain.com", + "role": "user", + "invited_at": "2024-10-30T23:58:27.427722Z", + "expires_at": "2024-11-20T23:58:27.427722Z", + "status": "pending" + } + """ + + let jsonData = json.data(using: .utf8)! + let response = try anthropicJSONDecoder.decode(InvitationResponse.self, from: jsonData) + + XCTAssertEqual(response.id, "invite_015gWxCN9Hfg2QhZwTK7Mdeu") + XCTAssertEqual(response.type, .invite) + XCTAssertEqual(response.email, "user@emaildomain.com") + XCTAssertEqual(response.role, .user) + XCTAssertEqual(response.invitedAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.expiresAt, "2024-11-20T23:58:27.427722Z") + XCTAssertEqual(response.status, .pending) + } + + func testDecodeOrganizationInviteRemoveResponse() throws { + let json = """ + { + "id": "invite_015gWxCN9Hfg2QhZwTK7Mdeu", + "type": "invite_deleted" + } + """ + + let jsonData = json.data(using: .utf8)! + let response = try anthropicJSONDecoder.decode(InvitationRemoveResponse.self, from: jsonData) + + XCTAssertEqual(response.id, "invite_015gWxCN9Hfg2QhZwTK7Mdeu") + XCTAssertEqual(response.type, .deleted) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Response/OrganizationMemberResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/OrganizationMemberResponseTests.swift new file mode 100644 index 0000000..5c5cdb3 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Response/OrganizationMemberResponseTests.swift @@ -0,0 +1,49 @@ +// +// OrganizationMemberResponseTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/06. +// + +import XCTest +import AnthropicSwiftSDK + +final class OrganizationMemberResponseTests: XCTestCase { + func testDecodeOrganizationMemberResponse() throws { + let json = """ + { + "id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "type": "user", + "email": "user@emaildomain.com", + "name": "Jane Doe", + "role": "user", + "added_at": "2024-10-30T23:58:27.427722Z" + } + """ + + let jsonData = json.data(using: .utf8)! + let response = try anthropicJSONDecoder.decode(OrganizationMemberResponse.self, from: jsonData) + + XCTAssertEqual(response.id, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.type, .user) + XCTAssertEqual(response.email, "user@emaildomain.com") + XCTAssertEqual(response.name, "Jane Doe") + XCTAssertEqual(response.role, .user) + XCTAssertEqual(response.addedAt, "2024-10-30T23:58:27.427722Z") + } + + func testDecodeOrganizationMemberRemoveResponse() throws { + let json = """ + { + "id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "type": "user_deleted" + } + """ + + let jsonData = json.data(using: .utf8)! + let response = try anthropicJSONDecoder.decode(OrganizationMemberRemoveResponse.self, from: jsonData) + + XCTAssertEqual(response.id, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.type, .deleted) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Response/WorkspaceMemberResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/WorkspaceMemberResponseTests.swift new file mode 100644 index 0000000..98eab2b --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Response/WorkspaceMemberResponseTests.swift @@ -0,0 +1,47 @@ +// +// WorkspaceMemberResponseTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/06. +// + +import XCTest +import AnthropicSwiftSDK + +final class WorkspaceMemberResponseTests: XCTestCase { + func testDecodeWorkspaceMemberResponse() throws { + let json = """ + { + "type": "workspace_member", + "user_id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "workspace_role": "workspace_user" + } + """ + + let jsonData = json.data(using: .utf8)! + let response = try anthropicJSONDecoder.decode(WorkspaceMemberResponse.self, from: jsonData) + + XCTAssertEqual(response.type, .workspaceMember) + XCTAssertEqual(response.userId, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.workspaceId, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.workspaceRole, .user) + } + + func testDecodeWorkspaceMemberRemoveResponse() throws { + let json = """ + { + "user_id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "type": "workspace_member_deleted" + } + """ + + let jsonData = json.data(using: .utf8)! + let response = try anthropicJSONDecoder.decode(WorkspaceMemberRemoveResponse.self, from: jsonData) + + XCTAssertEqual(response.userId, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.workspaceId, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.type, .deleted) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Response/WorkspaceResponseTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Response/WorkspaceResponseTests.swift new file mode 100644 index 0000000..0b2fc25 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Response/WorkspaceResponseTests.swift @@ -0,0 +1,34 @@ +// +// WorkspaceResponseTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/06. +// + +import XCTest +import AnthropicSwiftSDK + +final class WorkspaceResponseTests: XCTestCase { + func testDecodeWorkspaceResponse() throws { + let json = """ + { + "id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "type": "workspace", + "name": "Workspace Name", + "created_at": "2024-10-30T23:58:27.427722Z", + "archived_at": "2024-11-01T23:59:27.427722Z", + "display_color": "#6C5BB9" + } + """ + + let jsonData = json.data(using: .utf8)! + let response = try anthropicJSONDecoder.decode(WorkspaceResponse.self, from: jsonData) + + XCTAssertEqual(response.id, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.type, .workspace) + XCTAssertEqual(response.name, "Workspace Name") + XCTAssertEqual(response.createdAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.archivedAt, "2024-11-01T23:59:27.427722Z") + XCTAssertEqual(response.displayColor, "#6C5BB9") + } +} From 07b2013c55ea7562f1a12cc949ccab9e12673d6b Mon Sep 17 00:00:00 2001 From: Fumito Ito Date: Tue, 10 Dec 2024 00:57:32 +0900 Subject: [PATCH 11/13] add request tests --- .../API/Admin/OrganizationMembers.swift | 2 +- .../API/Admin/WorkspaceMembers.swift | 2 +- .../UpdateOrganizationMemberRequest.swift | 10 ++++-- .../UpdateWorkspaceMemberRequest.swift | 8 +++-- .../Admin/ArchiveWorkspaceRequestTests.swift | 20 +++++++++++ ...CreateOrganizationInviteRequestTests.swift | 23 ++++++++++++ .../CreateWorkspaceMemberRequestTests.swift | 23 ++++++++++++ .../Admin/CreateWorkspaceRequestTests.swift | 21 +++++++++++ ...DeleteOrganizationInviteRequestTests.swift | 20 +++++++++++ .../DeleteWorkspaceMemberRequestTests.swift | 22 ++++++++++++ .../Request/Admin/GetAPIKeyRequestTests.swift | 20 +++++++++++ .../GetOrganizationInviteRequestTests.swift | 21 +++++++++++ .../GetOrganizationMemberRequestTests.swift | 21 +++++++++++ .../GetWorkspaceMemberRequestTests.swift | 22 ++++++++++++ .../Admin/GetWorkspaceRequestTests.swift | 21 +++++++++++ ...RemoveOrganizationMemberRequestTests.swift | 21 +++++++++++ .../Admin/UpdateAPIKeyRequestTests.swift | 24 +++++++++++++ ...UpdateOrganizationMemberRequestTests.swift | 23 ++++++++++++ .../UpdateWorkspaceMemberRequestTests.swift | 24 +++++++++++++ .../Admin/UpdateWorkspaceRequestTests.swift | 35 +++++++++++++++++++ 20 files changed, 376 insertions(+), 7 deletions(-) create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Request/Admin/ArchiveWorkspaceRequestTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateOrganizationInviteRequestTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateWorkspaceMemberRequestTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateWorkspaceRequestTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Request/Admin/DeleteOrganizationInviteRequestTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Request/Admin/DeleteWorkspaceMemberRequestTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetAPIKeyRequestTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetOrganizationInviteRequestTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetOrganizationMemberRequestTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetWorkspaceMemberRequestTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetWorkspaceRequestTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Request/Admin/RemoveOrganizationMemberRequestTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateAPIKeyRequestTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateOrganizationMemberRequestTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateWorkspaceMemberRequestTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateWorkspaceRequestTests.swift diff --git a/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift index 393f399..03be294 100644 --- a/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift +++ b/Sources/AnthropicSwiftSDK/API/Admin/OrganizationMembers.swift @@ -86,7 +86,7 @@ public struct OrganizationMembers { authenticationHeaderProvider: authenticationHeaderProvider ) - return try await client.send(request: UpdateOrganizationMemberRequest(body: role, userId: userId)) + return try await client.send(request: UpdateOrganizationMemberRequest(body: .init(role: role), userId: userId)) } public func remove(userId: String) async throws -> OrganizationMemberRemoveResponse { diff --git a/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift b/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift index 08007a4..ef1ab46 100644 --- a/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift +++ b/Sources/AnthropicSwiftSDK/API/Admin/WorkspaceMembers.swift @@ -121,7 +121,7 @@ public struct WorkspaceMembers { authenticationHeaderProvider: authenticationHeaderProvider ) - return try await client.send(request: UpdateWorkspaceMemberRequest(body: role, userId: userId, workspaceId: workspaceId)) + return try await client.send(request: UpdateWorkspaceMemberRequest(body: .init(role: role), userId: userId, workspaceId: workspaceId)) } public func remove(userId: String, workspaceId: String) async throws -> WorkspaceMemberRemoveResponse { diff --git a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/UpdateOrganizationMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/UpdateOrganizationMemberRequest.swift index 106e230..9289213 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/UpdateOrganizationMemberRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/OrganizationMembers/UpdateOrganizationMemberRequest.swift @@ -6,14 +6,18 @@ // struct UpdateOrganizationMemberRequest: Request { - typealias Body = OrganizationRole + typealias Body = OrganizationMememberRequestBody let method: HttpMethod = .post var path: String { - "\(RequestType.organizationMember)/\(userId)" + "\(RequestType.organizationMember.basePath)/\(userId)" } let queries: [String: any CustomStringConvertible]? = nil - let body: OrganizationRole? + let body: OrganizationMememberRequestBody? let userId: String } + +struct OrganizationMememberRequestBody: Encodable { + let role: OrganizationRole +} diff --git a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/UpdateWorkspaceMemberRequest.swift b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/UpdateWorkspaceMemberRequest.swift index d433ce7..b7a3d44 100644 --- a/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/UpdateWorkspaceMemberRequest.swift +++ b/Sources/AnthropicSwiftSDK/Network/Request/WorkspaceMembers/UpdateWorkspaceMemberRequest.swift @@ -6,7 +6,7 @@ // struct UpdateWorkspaceMemberRequest: Request { - typealias Body = WorkspaceRole + typealias Body = WorkspaceMemberRequestBody let method: HttpMethod = .post var path: String { @@ -14,7 +14,11 @@ struct UpdateWorkspaceMemberRequest: Request { } let queries: [String: any CustomStringConvertible]? = nil - let body: WorkspaceRole? + let body: WorkspaceMemberRequestBody? let userId: String let workspaceId: String } + +struct WorkspaceMemberRequestBody: Encodable { + let role: WorkspaceRole +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/ArchiveWorkspaceRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/ArchiveWorkspaceRequestTests.swift new file mode 100644 index 0000000..52b703a --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/ArchiveWorkspaceRequestTests.swift @@ -0,0 +1,20 @@ +// +// ArchiveWorkspaceRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class ArchiveWorkspaceRequestTests: XCTestCase { + func testArchiveWorkspaceRequest() throws { + let request = ArchiveWorkspaceRequest(workspaceId: "test-workspace-id") + + XCTAssertEqual(request.method, HttpMethod.post) + XCTAssertEqual(request.path, "\(RequestType.workspace.basePath)/test-workspace-id/archive") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateOrganizationInviteRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateOrganizationInviteRequestTests.swift new file mode 100644 index 0000000..fde6d41 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateOrganizationInviteRequestTests.swift @@ -0,0 +1,23 @@ +// +// CreateOrganizationInviteRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class CreateOrganizationInviteRequestTests: XCTestCase { + func testCreateOrganizationInviteRequest() throws { + let invite = Invitation(email: "test@example.com", role: .user) + let request = CreateOrganizationInviteRequest(body: invite) + + XCTAssertEqual(request.method, HttpMethod.post) + XCTAssertEqual(request.path, RequestType.organizationInvite.basePath) + XCTAssertNil(request.queries) + XCTAssertNotNil(request.body) + XCTAssertEqual(request.body?.email, invite.email) + XCTAssertEqual(request.body?.role, invite.role) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateWorkspaceMemberRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateWorkspaceMemberRequestTests.swift new file mode 100644 index 0000000..9b54fc9 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateWorkspaceMemberRequestTests.swift @@ -0,0 +1,23 @@ +// +// CreateWorkspaceMemberRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class CreateWorkspaceMemberRequestTests: XCTestCase { + func testCreateWorkspaceMemberRequest() throws { + let registration = Registration(userId: "1234wert", workspaceRole: .developer) + let request = CreateWorkspaceMemberRequest(body: registration, workspaceId: "test-workspace-id") + + XCTAssertEqual(request.method, HttpMethod.post) + XCTAssertEqual(request.path, RequestType.workspaceMember(workspaceId: "test-workspace-id").basePath) + XCTAssertNil(request.queries) + XCTAssertNotNil(request.body) + XCTAssertEqual(request.body?.userId, registration.userId) + XCTAssertEqual(request.body?.workspaceRole, registration.workspaceRole) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateWorkspaceRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateWorkspaceRequestTests.swift new file mode 100644 index 0000000..39c88df --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/CreateWorkspaceRequestTests.swift @@ -0,0 +1,21 @@ +// +// CreateWorkspaceRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class CreateWorkspaceRequestTests: XCTestCase { + func testCreateWorkspaceRequest() throws { + let request = CreateWorkspaceRequest(body: .init(name: "Test Workspace")) + + XCTAssertEqual(request.method, HttpMethod.post) + XCTAssertEqual(request.path, RequestType.workspace.basePath) + XCTAssertNil(request.queries) + XCTAssertNotNil(request.body) + XCTAssertEqual(request.body?.name, "Test Workspace") + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/DeleteOrganizationInviteRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/DeleteOrganizationInviteRequestTests.swift new file mode 100644 index 0000000..033c512 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/DeleteOrganizationInviteRequestTests.swift @@ -0,0 +1,20 @@ +// +// DeleteOrganizationInviteRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class DeleteOrganizationInviteRequestTests: XCTestCase { + func testDeleteOrganizationInviteRequest() throws { + let request = DeleteOrganizationInviteRequest(invitationId: "foo-bar") + + XCTAssertEqual(request.method, HttpMethod.delete) + XCTAssertEqual(request.path, "\(RequestType.organizationInvite.basePath)/foo-bar") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/DeleteWorkspaceMemberRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/DeleteWorkspaceMemberRequestTests.swift new file mode 100644 index 0000000..56c9bfb --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/DeleteWorkspaceMemberRequestTests.swift @@ -0,0 +1,22 @@ +// +// DeleteWorkspaceMemberRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class DeleteWorkspaceMemberRequestTests: XCTestCase { + func testDeleteWorkspaceMemberRequest() throws { + let userId = "test-user-id" + let workspaceId = "test-workspace-id" + let request = DeleteWorkspaceMemberRequest(userId: userId, workspaceId: workspaceId) + + XCTAssertEqual(request.method, HttpMethod.delete) + XCTAssertEqual(request.path, "\(RequestType.workspaceMember(workspaceId: workspaceId).basePath)/\(userId)") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetAPIKeyRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetAPIKeyRequestTests.swift new file mode 100644 index 0000000..3f88108 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetAPIKeyRequestTests.swift @@ -0,0 +1,20 @@ +// +// GetAPIKeyRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class GetAPIKeyRequestTests: XCTestCase { + func testGetAPIKeyRequest() throws { + let request = GetAPIKeyRequest(apiKeyId: "apikeyid") + + XCTAssertEqual(request.method, HttpMethod.get) + XCTAssertEqual(request.path, "\(RequestType.apiKey.basePath)/apikeyid") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetOrganizationInviteRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetOrganizationInviteRequestTests.swift new file mode 100644 index 0000000..ccda114 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetOrganizationInviteRequestTests.swift @@ -0,0 +1,21 @@ +// +// GetOrganizationInviteRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class GetOrganizationInviteRequestTests: XCTestCase { + func testGetOrganizationInviteRequest() throws { + let invitationId = "invite-id" + let request = GetOrganizationInviteRequest(invitationId: invitationId) + + XCTAssertEqual(request.method, HttpMethod.get) + XCTAssertEqual(request.path, "\(RequestType.organizationInvite.basePath)/\(invitationId)") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetOrganizationMemberRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetOrganizationMemberRequestTests.swift new file mode 100644 index 0000000..2fbebac --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetOrganizationMemberRequestTests.swift @@ -0,0 +1,21 @@ +// +// GetOrganizationMemberRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class GetOrganizationMemberRequestTests: XCTestCase { + func testGetOrganizationMemberRequest() throws { + let userId = "test-user-id" + let request = GetOrganizationMemberRequest(userId: userId) + + XCTAssertEqual(request.method, HttpMethod.get) + XCTAssertEqual(request.path, "\(RequestType.organizationMember.basePath)/\(userId)") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetWorkspaceMemberRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetWorkspaceMemberRequestTests.swift new file mode 100644 index 0000000..24b8695 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetWorkspaceMemberRequestTests.swift @@ -0,0 +1,22 @@ +// +// GetWorkspaceMemberRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class GetWorkspaceMemberRequestTests: XCTestCase { + func testGetWorkspaceMemberRequest() throws { + let userId = "test-user-id" + let workspaceId = "test-workspace-id" + let request = GetWorkspaceMemberRequest(workspaceId: workspaceId, userId: userId) + + XCTAssertEqual(request.method, HttpMethod.get) + XCTAssertEqual(request.path, "\(RequestType.workspaceMember(workspaceId: workspaceId).basePath)/\(userId)") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetWorkspaceRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetWorkspaceRequestTests.swift new file mode 100644 index 0000000..4914813 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/GetWorkspaceRequestTests.swift @@ -0,0 +1,21 @@ +// +// GetWorkspaceRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class GetWorkspaceRequestTests: XCTestCase { + func testGetWorkspaceRequest() throws { + let workspaceId = "test-workspace-id" + let request = GetWorkspaceRequest(workspaceId: workspaceId) + + XCTAssertEqual(request.method, HttpMethod.get) + XCTAssertEqual(request.path, "\(RequestType.workspace.basePath)/\(workspaceId)") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/RemoveOrganizationMemberRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/RemoveOrganizationMemberRequestTests.swift new file mode 100644 index 0000000..570b704 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/RemoveOrganizationMemberRequestTests.swift @@ -0,0 +1,21 @@ +// +// RemoveOrganizationMemberRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class RemoveOrganizationMemberRequestTests: XCTestCase { + func testRemoveOrganizationMemberRequest() throws { + let userId = "test-user-id" + let request = RemoveOrganizationMemberRequest(userId: userId) + + XCTAssertEqual(request.method, HttpMethod.delete) + XCTAssertEqual(request.path, "\(RequestType.organizationMember.basePath)/\(userId)") + XCTAssertNil(request.queries) + XCTAssertNil(request.body) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateAPIKeyRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateAPIKeyRequestTests.swift new file mode 100644 index 0000000..0b2a952 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateAPIKeyRequestTests.swift @@ -0,0 +1,24 @@ +// +// UpdateAPIKeyRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class UpdateAPIKeyRequestTests: XCTestCase { + func testUpdateAPIKeyRequest() throws { + let apiKeyId = "apikeyid" + let newKeyName = "newkeyname" + let request = UpdateAPIKeyRequest(body: .init(name: newKeyName, status: .inactive), apiKeyId: apiKeyId) + + XCTAssertEqual(request.method, .post) + XCTAssertEqual(request.path, "\(RequestType.apiKey.basePath)/\(apiKeyId)") + XCTAssertNil(request.queries) + XCTAssertNotNil(request.body) + XCTAssertEqual(request.body?.name, newKeyName) + XCTAssertEqual(request.body?.status, .inactive) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateOrganizationMemberRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateOrganizationMemberRequestTests.swift new file mode 100644 index 0000000..2fd75ae --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateOrganizationMemberRequestTests.swift @@ -0,0 +1,23 @@ +// +// UpdateOrganizationMemberRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class UpdateOrganizationMemberRequestTests: XCTestCase { + func testUpdateOrganizationMemberRequest() throws { + let userId = "test-user-id" + let role = OrganizationRole.admin + let request = UpdateOrganizationMemberRequest(body: .init(role: role), userId: userId) + + XCTAssertEqual(request.method, .post) + XCTAssertEqual(request.path, "\(RequestType.organizationMember.basePath)/\(userId)") + XCTAssertNil(request.queries) + XCTAssertNotNil(request.body) + XCTAssertEqual(request.body?.role, role) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateWorkspaceMemberRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateWorkspaceMemberRequestTests.swift new file mode 100644 index 0000000..129bffc --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateWorkspaceMemberRequestTests.swift @@ -0,0 +1,24 @@ +// +// UpdateWorkspaceMemberRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +@testable import AnthropicSwiftSDK + +final class UpdateWorkspaceMemberRequestTests: XCTestCase { + func testUpdateWorkspaceMemberRequest() throws { + let userId = "test-user-id" + let workspaceId = "test-workspace-id" + let role = WorkspaceRole.developer + let request = UpdateWorkspaceMemberRequest(body: .init(role: role), userId: userId, workspaceId: workspaceId) + + XCTAssertEqual(request.method, HttpMethod.post) + XCTAssertEqual(request.path, "\(RequestType.workspaceMember(workspaceId: workspaceId).basePath)/\(userId)") + XCTAssertNil(request.queries) + XCTAssertNotNil(request.body) + XCTAssertEqual(request.body?.role, role) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateWorkspaceRequestTests.swift b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateWorkspaceRequestTests.swift new file mode 100644 index 0000000..a47081e --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/Network/Request/Admin/UpdateWorkspaceRequestTests.swift @@ -0,0 +1,35 @@ +// +// UpdateWorkspaceRequestTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest + +final class UpdateWorkspaceRequestTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} From 9d14c77f59465710de6231e0ed0615e2d83bdbc3 Mon Sep 17 00:00:00 2001 From: Fumito Ito Date: Tue, 10 Dec 2024 01:27:35 +0900 Subject: [PATCH 12/13] add API tests --- .../API/APIKeysTests.swift | 94 +++++++++++++ .../API/OrganizationInvitesTests.swift | 100 ++++++++++++++ .../API/OrganizationMembersTests.swift | 95 +++++++++++++ .../API/WorkspaceMembersTests.swift | 89 ++++++++++++ .../API/WorkspacesTests.swift | 129 ++++++++++++++++++ 5 files changed, 507 insertions(+) create mode 100644 Tests/AnthropicSwiftSDKTests/API/APIKeysTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/API/OrganizationInvitesTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/API/OrganizationMembersTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/API/WorkspaceMembersTests.swift create mode 100644 Tests/AnthropicSwiftSDKTests/API/WorkspacesTests.swift diff --git a/Tests/AnthropicSwiftSDKTests/API/APIKeysTests.swift b/Tests/AnthropicSwiftSDKTests/API/APIKeysTests.swift new file mode 100644 index 0000000..22c239e --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/API/APIKeysTests.swift @@ -0,0 +1,94 @@ +// +// APIKeysTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +import AnthropicSwiftSDK_TestUtils +@testable import AnthropicSwiftSDK + +final class APIKeysTests: XCTestCase { + var session: URLSession! + var apiKeys: APIKeys! + + override func setUp() { + super.setUp() + let configuration = URLSessionConfiguration.default + configuration.protocolClasses = [HTTPMock.self] + session = URLSession(configuration: configuration) + + let apiKey = "test-api-key" + apiKeys = APIKeys(adminAPIKey: apiKey, session: session) + } + + func testGetAPIKey() async throws { + let expectation = XCTestExpectation(description: "Get API Key response") + + HTTPMock.inspectType = .response(""" + { + "id": "apikey_01Rj2N8SVvo6BePZj99NhmiT", + "type": "api_key", + "name": "Developer Key", + "workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "created_at": "2024-10-30T23:58:27.427722Z", + "created_by": { + "id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "type": "user" + }, + "partial_key_hint": "sk-ant-api03-R2D...igAA", + "status": "active" + } + """) + + let response = try await apiKeys.get(apiKeyId: "test-key-id") + XCTAssertEqual(response.id, "apikey_01Rj2N8SVvo6BePZj99NhmiT") + XCTAssertEqual(response.type, .apiKey) + XCTAssertEqual(response.name, "Developer Key") + XCTAssertEqual(response.workspaceId, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.createdAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.createdBy.id, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.createdBy.type, "user") + XCTAssertEqual(response.partialKeyHint, "sk-ant-api03-R2D...igAA") + XCTAssertEqual(response.status, .active) + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testUpdateAPIKey() async throws { + let expectation = XCTestExpectation(description: "Update API Key response") + + HTTPMock.inspectType = .response(""" + { + "id": "apikey_01Rj2N8SVvo6BePZj99NhmiT", + "type": "api_key", + "name": "Updated API Key", + "workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "created_at": "2024-10-30T23:58:27.427722Z", + "created_by": { + "id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "type": "user" + }, + "partial_key_hint": "sk-ant-api03-R2D...igAA", + "status": "inactive" + } + """) + + let updatedResponse = try await apiKeys.update(apiKeyId: "test-key-id", name: "Updated API Key", status: .inactive) + XCTAssertEqual(updatedResponse.id, "apikey_01Rj2N8SVvo6BePZj99NhmiT") + XCTAssertEqual(updatedResponse.type, .apiKey) + XCTAssertEqual(updatedResponse.name, "Updated API Key") + XCTAssertEqual(updatedResponse.workspaceId, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(updatedResponse.createdAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(updatedResponse.createdBy.id, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(updatedResponse.createdBy.type, "user") + XCTAssertEqual(updatedResponse.partialKeyHint, "sk-ant-api03-R2D...igAA") + XCTAssertEqual(updatedResponse.status, .inactive) + + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/API/OrganizationInvitesTests.swift b/Tests/AnthropicSwiftSDKTests/API/OrganizationInvitesTests.swift new file mode 100644 index 0000000..977e8a4 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/API/OrganizationInvitesTests.swift @@ -0,0 +1,100 @@ +// +// OrganizationInvitesTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +import AnthropicSwiftSDK_TestUtils +@testable import AnthropicSwiftSDK + +final class OrganizationInvitesTests: XCTestCase { + var session: URLSession! + var organizationInvites: OrganizationInvites! + + override func setUp() { + super.setUp() + let configuration = URLSessionConfiguration.default + configuration.protocolClasses = [HTTPMock.self] + session = URLSession(configuration: configuration) + + let apiKey = "test-api-key" + organizationInvites = OrganizationInvites(adminAPIKey: apiKey, session: session) + } + + func testGetOrganizationInvite() async throws { + let expectation = XCTestExpectation(description: "Get Organization Invite response") + + HTTPMock.inspectType = .response(""" + { + "id": "invite_015gWxCN9Hfg2QhZwTK7Mdeu", + "type": "invite", + "email": "user@emaildomain.com", + "role": "user", + "invited_at": "2024-10-30T23:58:27.427722Z", + "expires_at": "2024-11-20T23:58:27.427722Z", + "status": "pending" + } + """) + + let response = try await organizationInvites.get(invitationId: "invite_015gWxCN9Hfg2QhZwTK7Mdeu") + XCTAssertEqual(response.id, "invite_015gWxCN9Hfg2QhZwTK7Mdeu") + XCTAssertEqual(response.type, .invite) + XCTAssertEqual(response.email, "user@emaildomain.com") + XCTAssertEqual(response.role, .user) + XCTAssertEqual(response.invitedAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.expiresAt, "2024-11-20T23:58:27.427722Z") + XCTAssertEqual(response.status, .pending) + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testRemoveOrganizationInvite() async throws { + let expectation = XCTestExpectation(description: "Remove Organization Invite response") + + HTTPMock.inspectType = .response(""" + { + "id": "invite_015gWxCN9Hfg2QhZwTK7Mdeu", + "type": "invite_deleted" + } + """) + + let response = try await organizationInvites.remove(invitationId: "invite_015gWxCN9Hfg2QhZwTK7Mdeu") + XCTAssertEqual(response.id, "invite_015gWxCN9Hfg2QhZwTK7Mdeu") + XCTAssertEqual(response.type, .deleted) + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testSendOrganizationInvite() async throws { + let expectation = XCTestExpectation(description: "Send Organization Invite response") + + HTTPMock.inspectType = .response(""" + { + "id": "invite_015gWxCN9Hfg2QhZwTK7Mdeu", + "type": "invite", + "email": "user@emaildomain.com", + "role": "user", + "invited_at": "2024-10-30T23:58:27.427722Z", + "expires_at": "2024-11-20T23:58:27.427722Z", + "status": "pending" + } + """) + + let invite = Invitation(email: "user@emaildomain.com", role: .user) + let response = try await organizationInvites.send(invitation: invite) + XCTAssertEqual(response.id, "invite_015gWxCN9Hfg2QhZwTK7Mdeu") + XCTAssertEqual(response.type, .invite) + XCTAssertEqual(response.email, "user@emaildomain.com") + XCTAssertEqual(response.role, .user) + XCTAssertEqual(response.invitedAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.expiresAt, "2024-11-20T23:58:27.427722Z") + XCTAssertEqual(response.status, .pending) + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/API/OrganizationMembersTests.swift b/Tests/AnthropicSwiftSDKTests/API/OrganizationMembersTests.swift new file mode 100644 index 0000000..c9563b1 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/API/OrganizationMembersTests.swift @@ -0,0 +1,95 @@ +// +// OrganizationMembersTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +import AnthropicSwiftSDK_TestUtils +@testable import AnthropicSwiftSDK + +final class OrganizationMembersTests: XCTestCase { + var session: URLSession! + var organizationMembers: OrganizationMembers! + + override func setUp() { + super.setUp() + let configuration = URLSessionConfiguration.default + configuration.protocolClasses = [HTTPMock.self] + session = URLSession(configuration: configuration) + + let apiKey = "test-api-key" + organizationMembers = OrganizationMembers(adminAPIKey: apiKey, session: session) + } + + func testGetOrganizationMember() async throws { + let expectation = XCTestExpectation(description: "Get Organization Member response") + + HTTPMock.inspectType = .response(""" + { + "id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "type": "user", + "email": "user@emaildomain.com", + "name": "Jane Doe", + "role": "user", + "added_at": "2024-10-30T23:58:27.427722Z" + } + """) + + let response = try await organizationMembers.get(userId: "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.id, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.type, .user) + XCTAssertEqual(response.email, "user@emaildomain.com") + XCTAssertEqual(response.name, "Jane Doe") + XCTAssertEqual(response.role, .user) + XCTAssertEqual(response.addedAt, "2024-10-30T23:58:27.427722Z") + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testRemoveOrganizationMember() async throws { + let expectation = XCTestExpectation(description: "Remove Organization Member response") + + HTTPMock.inspectType = .response(""" + { + "id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "type": "user_deleted" + } + """) + + let response = try await organizationMembers.remove(userId: "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.id, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.type, .deleted) + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testUpdateOrganizationMember() async throws { + let expectation = XCTestExpectation(description: "Update Organization Member response") + + HTTPMock.inspectType = .response(""" + { + "id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "type": "user", + "email": "updated_user@emaildomain.com", + "name": "Updated Jane Doe", + "role": "admin", + "added_at": "2024-10-30T23:58:27.427722Z" + } + """) + + let response = try await organizationMembers.update(userId: "user_01WCz1FkmYMm4gnmykNKUu3Q", role: .admin) + XCTAssertEqual(response.id, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.type, .user) + XCTAssertEqual(response.email, "updated_user@emaildomain.com") + XCTAssertEqual(response.name, "Updated Jane Doe") + XCTAssertEqual(response.role, .admin) + XCTAssertEqual(response.addedAt, "2024-10-30T23:58:27.427722Z") + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/API/WorkspaceMembersTests.swift b/Tests/AnthropicSwiftSDKTests/API/WorkspaceMembersTests.swift new file mode 100644 index 0000000..3b87da4 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/API/WorkspaceMembersTests.swift @@ -0,0 +1,89 @@ +// +// WorkspaceMembersTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +import AnthropicSwiftSDK_TestUtils +@testable import AnthropicSwiftSDK + +final class WorkspaceMembersTests: XCTestCase { + var session: URLSession! + var workspaceMembers: WorkspaceMembers! + + override func setUp() { + super.setUp() + let configuration = URLSessionConfiguration.default + configuration.protocolClasses = [HTTPMock.self] + session = URLSession(configuration: configuration) + + let apiKey = "test-api-key" + workspaceMembers = WorkspaceMembers(adminAPIKey: apiKey, session: session) + } + + func testGetWorkspaceMember() async throws { + let expectation = XCTestExpectation(description: "Get Workspace Member response") + + HTTPMock.inspectType = .response(""" + { + "type": "workspace_member", + "user_id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "workspace_role": "workspace_user" + } + """) + + let response = try await workspaceMembers.get(userId: "user_01WCz1FkmYMm4gnmykNKUu3Q", workspaceId: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.userId, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.workspaceId, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.workspaceRole, .user) + XCTAssertEqual(response.type, .workspaceMember) + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testRemoveWorkspaceMember() async throws { + let expectation = XCTestExpectation(description: "Remove Workspace Member response") + + HTTPMock.inspectType = .response(""" + { + "user_id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "type": "workspace_member_deleted" + } + """) + + let response = try await workspaceMembers.remove(userId: "user_01WCz1FkmYMm4gnmykNKUu3Q", workspaceId: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.userId, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.workspaceId, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.type, .deleted) + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testUpdateWorkspaceMember() async throws { + let expectation = XCTestExpectation(description: "Update Workspace Member response") + + HTTPMock.inspectType = .response(""" + { + "type": "workspace_member", + "user_id": "user_01WCz1FkmYMm4gnmykNKUu3Q", + "workspace_id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "workspace_role": "workspace_admin" + } + """) + + let response = try await workspaceMembers.update(userId: "user_01WCz1FkmYMm4gnmykNKUu3Q", workspaceId: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", role: .admin) + XCTAssertEqual(response.userId, "user_01WCz1FkmYMm4gnmykNKUu3Q") + XCTAssertEqual(response.workspaceId, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.workspaceRole, .admin) + XCTAssertEqual(response.type, .workspaceMember) + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } +} diff --git a/Tests/AnthropicSwiftSDKTests/API/WorkspacesTests.swift b/Tests/AnthropicSwiftSDKTests/API/WorkspacesTests.swift new file mode 100644 index 0000000..52a7313 --- /dev/null +++ b/Tests/AnthropicSwiftSDKTests/API/WorkspacesTests.swift @@ -0,0 +1,129 @@ +// +// WorkspacesTests.swift +// AnthropicSwiftSDK +// +// Created by 伊藤史 on 2024/12/07. +// + +import XCTest +import AnthropicSwiftSDK_TestUtils +@testable import AnthropicSwiftSDK + +final class WorkspacesTests: XCTestCase { + var session: URLSession! + var workspaces: Workspaces! + + override func setUp() { + super.setUp() + let configuration = URLSessionConfiguration.default + configuration.protocolClasses = [HTTPMock.self] + session = URLSession(configuration: configuration) + + let apiKey = "test-api-key" + workspaces = Workspaces(adminAPIKey: apiKey, session: session) + } + + func testGetWorkspace() async throws { + let expectation = XCTestExpectation(description: "Get Workspace response") + + HTTPMock.inspectType = .response(""" + { + "id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "type": "workspace", + "name": "Workspace Name", + "created_at": "2024-10-30T23:58:27.427722Z", + "archived_at": "2024-11-01T23:59:27.427722Z", + "display_color": "#6C5BB9" + } + """) + + let response = try await workspaces.get(workspaceId: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.id, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.type, .workspace) + XCTAssertEqual(response.name, "Workspace Name") + XCTAssertEqual(response.createdAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.archivedAt, "2024-11-01T23:59:27.427722Z") + XCTAssertEqual(response.displayColor, "#6C5BB9") + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testCreateWorkspace() async throws { + let expectation = XCTestExpectation(description: "Create Workspace response") + + HTTPMock.inspectType = .response(""" + { + "id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "type": "workspace", + "name": "New Workspace", + "created_at": "2024-10-30T23:58:27.427722Z", + "archived_at": null, + "display_color": "#6C5BB9" + } + """) + + let response = try await workspaces.create(name: "New Workspace") + XCTAssertEqual(response.id, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.type, .workspace) + XCTAssertEqual(response.name, "New Workspace") + XCTAssertEqual(response.createdAt, "2024-10-30T23:58:27.427722Z") + XCTAssertNil(response.archivedAt) + XCTAssertEqual(response.displayColor, "#6C5BB9") + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testArchiveWorkspace() async throws { + let expectation = XCTestExpectation(description: "Archive Workspace response") + + HTTPMock.inspectType = .response(""" + { + "id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "type": "workspace", + "name": "Workspace Name", + "created_at": "2024-10-30T23:58:27.427722Z", + "archived_at": "2024-11-01T23:59:27.427722Z", + "display_color": "#6C5BB9" + } + """) + + let response = try await workspaces.archive("wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.id, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.type, .workspace) + XCTAssertEqual(response.name, "Workspace Name") + XCTAssertEqual(response.createdAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.archivedAt, "2024-11-01T23:59:27.427722Z") + XCTAssertEqual(response.displayColor, "#6C5BB9") + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } + + func testUpdateWorkspace() async throws { + let expectation = XCTestExpectation(description: "Update Workspace response") + + HTTPMock.inspectType = .response(""" + { + "id": "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ", + "type": "workspace", + "name": "Updated Workspace Name", + "created_at": "2024-10-30T23:58:27.427722Z", + "archived_at": "2024-11-01T23:59:27.427722Z", + "display_color": "#6C5BB9" + } + """) + + let response = try await workspaces.update(name: "Updated Workspace Name", workspaceId: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.id, "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") + XCTAssertEqual(response.type, .workspace) + XCTAssertEqual(response.name, "Updated Workspace Name") + XCTAssertEqual(response.createdAt, "2024-10-30T23:58:27.427722Z") + XCTAssertEqual(response.archivedAt, "2024-11-01T23:59:27.427722Z") + XCTAssertEqual(response.displayColor, "#6C5BB9") + + expectation.fulfill() + await fulfillment(of: [expectation], timeout: 1.0) + } +} \ No newline at end of file From b269538cedc78ae1929b47ee156f47c06b473fb7 Mon Sep 17 00:00:00 2001 From: Fumito Ito Date: Thu, 12 Dec 2024 01:33:53 +0900 Subject: [PATCH 13/13] update readme --- README.md | 185 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 131 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 2e48b44..dfe2460 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,137 @@ for try await chunk in stream { } ``` +### [Message Batches (beta)](https://docs.anthropic.com/en/docs/build-with-claude/message-batches) + +The Message Batches API is a powerful, cost-effective way to asynchronously process large volumes of [Messages](https://docs.anthropic.com/en/api/messages) requests. This approach is well-suited to tasks that do not require immediate responses, reducing costs by 50% while increasing throughput. + +This is especially useful for bulk operations that don’t require immediate results. + +Here's an example of how to process many messages with the Message Batches API: + +```swift +let anthropic = Anthropic(apiKey: "YOUR_OWN_API_KEY") + +let messages = [ + Message(role: .user, content: [.text("Write a haiku about robots.")]), + Message(role: .user, content: [.text("Write a haiku about robots. Skip the preamble; go straight into the poem.")]), + Message(role: .user, content: [.text("Who is the best basketball player of all time?")]), + Message(role: .user, content: [.text("Who is the best basketball player of all time? Yes, there are differing opinions, but if you absolutely had to pick one player, who would it be?")]) + // .... +] + +let batch = MessageBatch( + customId: "my-first-batch-request", + parameter: .init( + messages: messages, + maxTokens: 1024 + ) +) + +let response = try await anthropic.messageBatches.createBatches(batches: [batch]) +``` + +### [Admin API](https://docs.anthropic.com/en/docs/administration/administration-api) + +This library also supports an Admin API for managing workspaces and organization members. + +#### [Organization Members API](https://docs.anthropic.com/en/docs/administration/administration-api#organization-members) + +- **Get Organization Member**: Retrieve details about a specific organization member. +- **List Organization Members**: List organization members. +- **Remove Organization Member**: Remove a member from the organization. +- **Update Organization Member**: Update the role or details of an existing organization member. + +Example of updating an organization member: + +```swift +let admin = AnthropicAdmin(adminAPIKey: "YOUR_OWN_ADMIN_API_KEY") +try await admin.organizationMembers.get(userId: "user_01WCz1FkmYMm4gnmykNKUu3Q") +``` + +#### [Organization Invites API](https://docs.anthropic.com/en/docs/administration/administration-api#organization-invites) + +- **Get Organization Invites**: Retrieve details about a specific organization invitation. +- **List Organization Invites**: List organization invitations. +- **Remove Organization Invites**: Remove a invitation from the organization. +- **Create Organization Invites**: Create a new organization invitation. + +Example of updating an organization invitation: + +```swift +let admin = AnthropicAdmin(adminAPIKey: "YOUR_OWN_ADMIN_API_KEY") +try await admin.organizationInvites.list() +``` + +#### [Workspaces API](https://docs.anthropic.com/en/docs/administration/administration-api#workspaces) + +- **Get Workspace**: Retrieve details about a specific workspace. +- **List Workspaces**: List workspaces. +- **Create Workspace**: Create a new workspace. +- **Archive Workspace**: Archive an existing workspace. +- **Update Workspace**: Update the details of an existing workspace. + +Example of creating a workspace: + +```swift +let admin = AnthropicAdmin(adminAPIKey: "YOUR_OWN_ADMIN_API_KEY") +try await admin.workspaces.get(workspaceId: "wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ") +``` + +#### [Workspace Members API](https://docs.anthropic.com/en/docs/administration/administration-api#workspace-members) + +- **Get Workspace Member**: Retrieve details about a specific workspace member. +- **List Workspace Members**: List workspace members. +- **Create Workspace Member**: Add a new member for the workspace. +- **Remove Workspace Member**: Remove a member from the workspace. +- **Update Workspace Member**: Update the role or details of an existing workspace member. + +Example of updating an workspace member: + +```swift +let admin = AnthropicAdmin(adminAPIKey: "YOUR_OWN_ADMIN_API_KEY") +try await admin.workspaceMembers.get(userId: "user_01WCz1FkmYMm4gnmykNKUu3Q") +``` + +#### [API Keys API](https://docs.anthropic.com/en/docs/administration/administration-api#api-keys) + +- **Get Organization Member**: Retrieve details about a specific API key. +- **List Organization Members**: List API keys. +- **Update Organization Member**: Update the status or name of an existing API key. + +Example of updating an organization member: + +```swift +let admin = AnthropicAdmin(adminAPIKey: "YOUR_OWN_ADMIN_API_KEY") +try await admin.apiKeys.get(apiKeyId: "apikey_01Rj2N8SVvo6BePZj99NhmiT") +``` + +### [Token Counting](https://docs.anthropic.com/en/docs/build-with-claude/token-counting) + +Token counting enables you to determine the number of tokens in a message before sending it to Claude, helping you make informed decisions about your prompts and usage. With token counting, you can + +- Proactively manage rate limits and costs +- Make smart model routing decisions +- Optimize prompts to be a specific length + +```swift +let anthropic = Anthropic(apiKey: "YOUR_OWN_API_KEY") + +let message = Message(role: .user, content: [.text("Find flights from San Francisco to a place with warmer weather.")]) +let response = try await anthropic.countTokens.countTokens( + [message], + maxTokens: 1024, + tools: [ + .computer(.init(name: "my_computer", displayWidthPx: 1024, displayHeightPx: 768, displayNumber: 1), + .bash(.init(name: "bash")) + ] +) +``` + +The token counting endpoint accepts the same structured list of inputs for creating a message, including support for system prompts, tools, images, and PDFs. The response contains the total number of input tokens. + +## Supporting Features + ### [Tool Use](https://docs.anthropic.com/en/docs/build-with-claude/tool-use) Claude is capable of interacting with external client-side tools and functions, allowing you to equip Claude with your own custom tools to perform a wider variety of tasks. @@ -134,36 +265,6 @@ let response = try await anthropic.messages.createMessage( ) ``` -### [Message Batches (beta)](https://docs.anthropic.com/en/docs/build-with-claude/message-batches) - -The Message Batches API is a powerful, cost-effective way to asynchronously process large volumes of [Messages](https://docs.anthropic.com/en/api/messages) requests. This approach is well-suited to tasks that do not require immediate responses, reducing costs by 50% while increasing throughput. - -This is especially useful for bulk operations that don’t require immediate results. - -Here's an example of how to process many messages with the Message Bathches API: - -```swift -let anthropic = Anthropic(apiKey: "YOUR_OWN_API_KEY") - -let messages = [ - Message(role: .user, content: [.text("Write a haiku about robots.")]), - Message(role: .user, content: [.text("Write a haiku about robots. Skip the preamble; go straight into the poem.")]), - Message(role: .user, content: [.text("Who is the best basketball player of all time?")]), - Message(role: .user, content: [.text("Who is the best basketball player of all time? Yes, there are differing opinions, but if you absolutely had to pick one player, who would it be?")]) - // .... -] - -let batch = MessageBatch( - customId: "my-first-batch-request", - parameter: .init( - messages: messages, - maxTokens: 1024 - ) -) - -let response = try await anthropic.messageBatches.createBatches(batches: [batch]) -``` - ### [Computer Use (beta)](https://docs.anthropic.com/en/docs/build-with-claude/computer-use#computer-tool) The upgraded Claude 3.5 Sonnet model is capable of interacting with tools that can manipulate a computer desktop environment. @@ -184,30 +285,6 @@ let response = try await anthropic.messages.createMessage( ) ``` -### [Token Counting](https://docs.anthropic.com/en/docs/build-with-claude/token-counting) - -Token counting enables you to determine the number of tokens in a message before sending it to Claude, helping you make informed decisions about your prompts and usage. With token counting, you can - -- Proactively manage rate limits and costs -- Make smart model routing decisions -- Optimize prompts to be a specific length - -```swift -let anthropic = Anthropic(apiKey: "YOUR_OWN_API_KEY") - -let message = Message(role: .user, content: [.text("Find flights from San Francisco to a place with warmer weather.")]) -let response = try await anthropic.countTokens.countTokens( - [message], - maxTokens: 1024, - tools: [ - .computer(.init(name: "my_computer", displayWidthPx: 1024, displayHeightPx: 768, displayNumber: 1), - .bash(.init(name: "bash")) - ] -) -``` - -The token counting endpoint accepts the same structured list of inputs for creating a message, including support for system prompts, tools, images, and PDFs. The response contains the total number of input tokens. - ## Extensions By introducing an extension Swift package, it is possible to access the Anthropic Claude API through AWS Bedrock and Vertex AI. The supported services are as follows: