Skip to content

Admin API support #68

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Dec 12, 2024
185 changes: 131 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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:
Expand Down
1 change: 1 addition & 0 deletions Sources/AnthropicSwiftSDK-TestUtils/HTTPMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
106 changes: 106 additions & 0 deletions Sources/AnthropicSwiftSDK/API/Admin/APIKeys.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//
// APIKeys.swift
// AnthropicSwiftSDK
//
// Created by 伊藤史 on 2024/11/28.
//
import Foundation

public struct APIKeys {
private let apiKey: String
private let session: URLSession

init(adminAPIKey: String, session: URLSession) {
self.apiKey = adminAPIKey
self.session = session
}

public func get(apiKeyId: String) async throws -> APIKeyResponse {
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,
afterId: String? = nil,
status: APIKeyStatus? = nil,
workspaceId: String? = nil,
createdByUserId: String? = nil
) async throws -> ObjectListResponse<APIKeyResponse> {
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<APIKeyResponse> {
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 {
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
}
23 changes: 23 additions & 0 deletions Sources/AnthropicSwiftSDK/API/Admin/Admin.swift
Original file line number Diff line number Diff line change
@@ -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

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)
self.workspaceMembers = WorkspaceMembers(adminAPIKey: apiKey, session: session)
self.apiKeys = APIKeys(adminAPIKey: apiKey, session: session)
}
}
Loading