administrate-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +493 -0
  4. data/lib/administrate/base_model.rb +108 -0
  5. data/lib/administrate/client.rb +27 -0
  6. data/lib/administrate/configuration.rb +22 -0
  7. data/lib/administrate/cursor_iterator.rb +41 -0
  8. data/lib/administrate/errors.rb +42 -0
  9. data/lib/administrate/models/account.rb +24 -0
  10. data/lib/administrate/models/api_token.rb +16 -0
  11. data/lib/administrate/models/client_model.rb +16 -0
  12. data/lib/administrate/models/execution.rb +12 -0
  13. data/lib/administrate/models/instance.rb +17 -0
  14. data/lib/administrate/models/llm_cost.rb +37 -0
  15. data/lib/administrate/models/llm_project.rb +10 -0
  16. data/lib/administrate/models/llm_provider.rb +16 -0
  17. data/lib/administrate/models/pagination_meta.rb +9 -0
  18. data/lib/administrate/models/sync_run.rb +23 -0
  19. data/lib/administrate/models/user.rb +14 -0
  20. data/lib/administrate/models/webhook.rb +11 -0
  21. data/lib/administrate/models/workflow.rb +18 -0
  22. data/lib/administrate/page.rb +25 -0
  23. data/lib/administrate/resources/account.rb +24 -0
  24. data/lib/administrate/resources/api_tokens.rb +37 -0
  25. data/lib/administrate/resources/base_resource.rb +37 -0
  26. data/lib/administrate/resources/clients.rb +49 -0
  27. data/lib/administrate/resources/executions.rb +28 -0
  28. data/lib/administrate/resources/instances.rb +61 -0
  29. data/lib/administrate/resources/llm_costs.rb +70 -0
  30. data/lib/administrate/resources/llm_projects.rb +20 -0
  31. data/lib/administrate/resources/llm_providers.rb +47 -0
  32. data/lib/administrate/resources/sync_runs.rb +30 -0
  33. data/lib/administrate/resources/users.rb +33 -0
  34. data/lib/administrate/resources/webhooks.rb +43 -0
  35. data/lib/administrate/resources/workflows.rb +29 -0
  36. data/lib/administrate/transport.rb +101 -0
  37. data/lib/administrate/version.rb +5 -0
  38. data/lib/administrate-sdk.rb +3 -0
  39. data/lib/administrate.rb +42 -0
  40. metadata +123 -0
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ class CursorIterator
5
+ include Enumerable
6
+
7
+ def initialize(transport:, path:, model:, params: {})
8
+ @transport = transport
9
+ @path = path
10
+ @model = model
11
+ @params = params.dup
12
+ @start_page = @params.delete(:page) || 1
13
+ end
14
+
15
+ def each(&block)
16
+ page_num = @start_page
17
+ loop do
18
+ page = fetch_page(page_num)
19
+ page.data.each(&block)
20
+ break unless page.more?
21
+
22
+ page_num += 1
23
+ end
24
+ end
25
+
26
+ def first_page
27
+ fetch_page(@start_page)
28
+ end
29
+
30
+ private
31
+
32
+ def fetch_page(page_num)
33
+ params = @params.merge(page: page_num)
34
+ response = @transport.get(@path, params)
35
+ body = response.body
36
+ data = (body['data'] || []).map { |item| @model.new(item) }
37
+ meta = Models::PaginationMeta.new(body['meta'] || {})
38
+ Page.new(data: data, meta: meta)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ class Error < StandardError; end
5
+
6
+ class APIError < Error
7
+ attr_reader :status_code, :response, :body
8
+
9
+ def initialize(message, status_code:, response:, body:)
10
+ @status_code = status_code
11
+ @response = response
12
+ @body = body
13
+ super(message)
14
+ end
15
+ end
16
+
17
+ class AuthenticationError < APIError; end
18
+ class PermissionDeniedError < APIError; end
19
+ class NotFoundError < APIError; end
20
+ class ValidationError < APIError; end
21
+
22
+ class RateLimitError < APIError
23
+ attr_reader :retry_after
24
+
25
+ def initialize(message, status_code:, response:, body:, retry_after: nil)
26
+ @retry_after = retry_after
27
+ super(message, status_code: status_code, response: response, body: body)
28
+ end
29
+ end
30
+
31
+ class InternalServerError < APIError; end
32
+ class ConnectionError < Error; end
33
+ class TimeoutError < Error; end
34
+
35
+ STATUS_CODE_MAP = {
36
+ 401 => AuthenticationError,
37
+ 403 => PermissionDeniedError,
38
+ 404 => NotFoundError,
39
+ 422 => ValidationError,
40
+ 429 => RateLimitError
41
+ }.freeze
42
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Models
5
+ class TokenInfo < BaseModel
6
+ attribute :name, :permission, :expires_at
7
+ end
8
+
9
+ class AccountInfo < BaseModel
10
+ attribute :id, :name, :plan
11
+ end
12
+
13
+ class MeResponse < BaseModel
14
+ nested :token, TokenInfo
15
+ nested :account, AccountInfo
16
+ end
17
+
18
+ class Account < BaseModel
19
+ attribute :id, :name, :slug, :billing_email, :phone, :timezone,
20
+ :logo_url, :plan, :plan_name, :on_trial, :trial_ends_at,
21
+ :usage, :created_at, :updated_at
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Models
5
+ class ApiTokenCreatedBy < BaseModel
6
+ attribute :id, :name
7
+ end
8
+
9
+ class ApiToken < BaseModel
10
+ attribute :id, :name, :permission, :permission_label, :token_hint,
11
+ :ip_allowlist, :last_used_at, :expires_at, :revoked, :active,
12
+ :token, :created_at, :updated_at
13
+ nested :created_by, ApiTokenCreatedBy
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Models
5
+ class ClientMetrics < BaseModel
6
+ attribute :executions_count, :success_rate, :failure_count, :time_saved_minutes
7
+ end
8
+
9
+ class Client < BaseModel
10
+ attribute :id, :name, :code, :notes, :timezone, :effective_timezone,
11
+ :contact_first_name, :contact_last_name, :contact_email,
12
+ :contact_phone, :n8n_instances_count, :created_at, :updated_at
13
+ nested :metrics, ClientMetrics
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Models
5
+ class Execution < BaseModel
6
+ attribute :id, :workflow_id, :workflow_name, :instance_id, :instance_name,
7
+ :client_id, :client_name, :external_execution_id, :status,
8
+ :started_at, :finished_at, :duration_ms, :duration_seconds,
9
+ :error_category, :error_message, :error_payload, :created_at
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Models
5
+ class InstanceMetrics < BaseModel
6
+ attribute :executions_count, :success_rate
7
+ end
8
+
9
+ class Instance < BaseModel
10
+ attribute :id, :service_type, :company_id, :company_name, :name, :base_url,
11
+ :workflows_count, :sync_status, :last_synced_at,
12
+ :last_workflows_synced_at, :last_executions_synced_at,
13
+ :last_sync_error, :created_at, :updated_at
14
+ nested :metrics, InstanceMetrics
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Models
5
+ class LlmCostSummary < BaseModel
6
+ attribute :total_cost_cents, :total_tokens, :total_input_tokens,
7
+ :total_output_tokens, :total_requests, :providers_count
8
+ end
9
+
10
+ class LlmCostByProvider < BaseModel
11
+ attribute :id, :name, :provider_type, :cost_cents, :tokens, :requests
12
+ end
13
+
14
+ class LlmCostByClient < BaseModel
15
+ attribute :id, :name, :cost_cents, :tokens
16
+ end
17
+
18
+ class LlmCostModel < BaseModel
19
+ attribute :model, :cost_cents, :tokens, :requests
20
+ end
21
+
22
+ class LlmCostDaily < BaseModel
23
+ attribute :date, :cost_cents, :tokens
24
+ end
25
+
26
+ class LlmCostSummaryData < BaseModel
27
+ nested :summary, LlmCostSummary
28
+ nested :providers, LlmCostByProvider, array: true
29
+ nested :models, LlmCostModel, array: true
30
+ nested :daily, LlmCostDaily, array: true
31
+ end
32
+
33
+ class LlmCostSummaryMeta < BaseModel
34
+ attribute :start_date, :end_date
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Models
5
+ class LlmProject < BaseModel
6
+ attribute :id, :external_id, :name, :client_id, :client_name,
7
+ :total_cost_cents, :total_tokens, :created_at, :updated_at
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Models
5
+ class LlmProviderMetrics < BaseModel
6
+ attribute :total_cost_cents, :total_tokens, :total_requests
7
+ end
8
+
9
+ class LlmProvider < BaseModel
10
+ attribute :id, :name, :provider_type, :organization_id,
11
+ :projects_count, :sync_status, :last_synced_at,
12
+ :last_sync_error, :created_at, :updated_at
13
+ nested :metrics, LlmProviderMetrics
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Models
5
+ class PaginationMeta < BaseModel
6
+ attribute :page, :per_page, :total, :total_pages, :has_more
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Models
5
+ class SyncRun < BaseModel
6
+ attribute :id, :instance_id, :instance_name, :sync_type, :status,
7
+ :started_at, :finished_at, :duration_seconds,
8
+ :records_created, :records_updated, :error_message, :created_at
9
+ end
10
+
11
+ class SyncHealthSyncInfo < BaseModel
12
+ attribute :last_synced_at
13
+ nested :last_run, SyncRun
14
+ end
15
+
16
+ class SyncHealthEntry < BaseModel
17
+ attribute :instance_id, :instance_name, :client_id, :client_name,
18
+ :sync_status, :last_sync_error
19
+ nested :workflows, SyncHealthSyncInfo
20
+ nested :executions, SyncHealthSyncInfo
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Models
5
+ class User < BaseModel
6
+ attribute :id, :email, :name, :first_name, :last_name,
7
+ :phone, :timezone, :avatar_url, :role, :joined_at
8
+ end
9
+
10
+ class Invitation < BaseModel
11
+ attribute :id, :email, :role, :expires_at, :created_at
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Models
5
+ class Webhook < BaseModel
6
+ attribute :id, :url, :description, :events, :enabled,
7
+ :consecutive_failures, :last_triggered_at, :secret,
8
+ :created_at, :updated_at
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Models
5
+ class WorkflowMetrics < BaseModel
6
+ attribute :executions_count, :success_count, :failure_count,
7
+ :success_rate, :time_saved_minutes
8
+ end
9
+
10
+ class Workflow < BaseModel
11
+ attribute :id, :instance_id, :instance_name, :company_id, :company_name,
12
+ :external_workflow_id, :name, :is_active,
13
+ :minutes_saved_per_success, :minutes_saved_per_failure,
14
+ :created_at, :updated_at
15
+ nested :metrics, WorkflowMetrics
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ class Page
5
+ attr_reader :data, :meta
6
+
7
+ def initialize(data:, meta:)
8
+ @data = data
9
+ @meta = meta
10
+ end
11
+
12
+ def each(&)
13
+ @data.each(&)
14
+ end
15
+
16
+ def size
17
+ @data.size
18
+ end
19
+ alias length size
20
+
21
+ def more?
22
+ @meta.has_more
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Resources
5
+ class Account < BaseResource
6
+ def me
7
+ response = @transport.get('me')
8
+ Models::MeResponse.new(response.body)
9
+ end
10
+
11
+ def get
12
+ get_resource('account', Models::Account)
13
+ end
14
+
15
+ def update(name: nil, billing_email: nil, timezone: nil)
16
+ body = {}
17
+ body[:name] = name unless name.nil?
18
+ body[:billing_email] = billing_email unless billing_email.nil?
19
+ body[:timezone] = timezone unless timezone.nil?
20
+ update_resource('account', Models::Account, body)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Resources
5
+ class ApiTokens < BaseResource
6
+ def list(page: nil, per_page: nil)
7
+ params = {}
8
+ params[:page] = page unless page.nil?
9
+ params[:per_page] = per_page unless per_page.nil?
10
+ list_resource(path: 'api_tokens', model: Models::ApiToken, params: params)
11
+ end
12
+
13
+ def get(token_id)
14
+ get_resource("api_tokens/#{token_id}", Models::ApiToken)
15
+ end
16
+
17
+ def create(name:, permission: nil, ip_allowlist: nil, expires_in: nil)
18
+ body = { name: name }
19
+ body[:permission] = permission unless permission.nil?
20
+ body[:ip_allowlist] = ip_allowlist unless ip_allowlist.nil?
21
+ body[:expires_in] = expires_in unless expires_in.nil?
22
+ create_resource('api_tokens', Models::ApiToken, body)
23
+ end
24
+
25
+ def update(token_id, name: nil, ip_allowlist: nil)
26
+ body = {}
27
+ body[:name] = name unless name.nil?
28
+ body[:ip_allowlist] = ip_allowlist unless ip_allowlist.nil?
29
+ update_resource("api_tokens/#{token_id}", Models::ApiToken, body)
30
+ end
31
+
32
+ def delete(token_id)
33
+ delete_resource("api_tokens/#{token_id}")
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Resources
5
+ class BaseResource
6
+ def initialize(transport)
7
+ @transport = transport
8
+ end
9
+
10
+ private
11
+
12
+ def list_resource(path:, model:, params: {})
13
+ CursorIterator.new(transport: @transport, path: path, model: model, params: params)
14
+ end
15
+
16
+ def get_resource(path, model)
17
+ response = @transport.get(path)
18
+ model.new(response.body['data'])
19
+ end
20
+
21
+ def create_resource(path, model, body)
22
+ response = @transport.post(path, body)
23
+ model.new(response.body['data'])
24
+ end
25
+
26
+ def update_resource(path, model, body)
27
+ response = @transport.patch(path, body)
28
+ model.new(response.body['data'])
29
+ end
30
+
31
+ def delete_resource(path)
32
+ @transport.delete(path)
33
+ nil
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Resources
5
+ class Clients < BaseResource
6
+ def list(page: nil, per_page: nil)
7
+ params = {}
8
+ params[:page] = page unless page.nil?
9
+ params[:per_page] = per_page unless per_page.nil?
10
+ list_resource(path: 'clients', model: Models::Client, params: params)
11
+ end
12
+
13
+ def get(client_id)
14
+ get_resource("clients/#{client_id}", Models::Client)
15
+ end
16
+
17
+ def create(name:, code: nil, notes: nil, timezone: nil, contact_first_name: nil,
18
+ contact_last_name: nil, contact_email: nil, contact_phone: nil)
19
+ body = { name: name }
20
+ body[:code] = code unless code.nil?
21
+ body[:notes] = notes unless notes.nil?
22
+ body[:timezone] = timezone unless timezone.nil?
23
+ body[:contact_first_name] = contact_first_name unless contact_first_name.nil?
24
+ body[:contact_last_name] = contact_last_name unless contact_last_name.nil?
25
+ body[:contact_email] = contact_email unless contact_email.nil?
26
+ body[:contact_phone] = contact_phone unless contact_phone.nil?
27
+ create_resource('clients', Models::Client, body)
28
+ end
29
+
30
+ def update(client_id, name: nil, code: nil, notes: nil, timezone: nil,
31
+ contact_first_name: nil, contact_last_name: nil, contact_email: nil, contact_phone: nil)
32
+ body = {}
33
+ body[:name] = name unless name.nil?
34
+ body[:code] = code unless code.nil?
35
+ body[:notes] = notes unless notes.nil?
36
+ body[:timezone] = timezone unless timezone.nil?
37
+ body[:contact_first_name] = contact_first_name unless contact_first_name.nil?
38
+ body[:contact_last_name] = contact_last_name unless contact_last_name.nil?
39
+ body[:contact_email] = contact_email unless contact_email.nil?
40
+ body[:contact_phone] = contact_phone unless contact_phone.nil?
41
+ update_resource("clients/#{client_id}", Models::Client, body)
42
+ end
43
+
44
+ def delete(client_id)
45
+ delete_resource("clients/#{client_id}")
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Resources
5
+ class Executions < BaseResource
6
+ def list(client_id: nil, instance_id: nil, workflow_id: nil, status: nil,
7
+ error_category: nil, start_date: nil, end_date: nil, errors_only: nil,
8
+ page: nil, per_page: nil)
9
+ params = {}
10
+ params[:client_id] = client_id unless client_id.nil?
11
+ params[:instance_id] = instance_id unless instance_id.nil?
12
+ params[:workflow_id] = workflow_id unless workflow_id.nil?
13
+ params[:status] = status unless status.nil?
14
+ params[:error_category] = error_category unless error_category.nil?
15
+ params[:start_date] = start_date unless start_date.nil?
16
+ params[:end_date] = end_date unless end_date.nil?
17
+ params[:errors_only] = errors_only.to_s unless errors_only.nil?
18
+ params[:page] = page unless page.nil?
19
+ params[:per_page] = per_page unless per_page.nil?
20
+ list_resource(path: 'executions', model: Models::Execution, params: params)
21
+ end
22
+
23
+ def get(execution_id)
24
+ get_resource("executions/#{execution_id}", Models::Execution)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Resources
5
+ class Instances < BaseResource
6
+ def list(client_id: nil, service_type: nil, sync_status: nil, page: nil, per_page: nil)
7
+ params = {}
8
+ params[:company_id] = client_id unless client_id.nil?
9
+ params[:service_type] = service_type unless service_type.nil?
10
+ params[:sync_status] = sync_status unless sync_status.nil?
11
+ params[:page] = page unless page.nil?
12
+ params[:per_page] = per_page unless per_page.nil?
13
+ list_resource(path: 'instances', model: Models::Instance, params: params)
14
+ end
15
+
16
+ def get(instance_id)
17
+ get_resource("instances/#{instance_id}", Models::Instance)
18
+ end
19
+
20
+ def create(client_id:, name:, base_url:, api_key:, service_type: nil)
21
+ body = {
22
+ company_id: client_id,
23
+ name: name,
24
+ base_url: base_url,
25
+ api_key: api_key
26
+ }
27
+ body[:service_type] = service_type unless service_type.nil?
28
+ create_resource('instances', Models::Instance, body)
29
+ end
30
+
31
+ def update(instance_id, name: nil, base_url: nil, api_key: nil, service_type: nil)
32
+ body = {}
33
+ body[:name] = name unless name.nil?
34
+ body[:base_url] = base_url unless base_url.nil?
35
+ body[:api_key] = api_key unless api_key.nil?
36
+ body[:service_type] = service_type unless service_type.nil?
37
+ update_resource("instances/#{instance_id}", Models::Instance, body)
38
+ end
39
+
40
+ def delete(instance_id)
41
+ delete_resource("instances/#{instance_id}")
42
+ end
43
+
44
+ def sync(instance_id, sync_type: nil)
45
+ body = {}
46
+ body[:sync_type] = sync_type unless sync_type.nil?
47
+ response = @transport.post("instances/#{instance_id}/sync", body)
48
+ response.body
49
+ end
50
+
51
+ def sync_all(sync_type: nil, client_id: nil, service_type: nil)
52
+ body = {}
53
+ body[:sync_type] = sync_type unless sync_type.nil?
54
+ body[:company_id] = client_id unless client_id.nil?
55
+ body[:service_type] = service_type unless service_type.nil?
56
+ response = @transport.post('instances/sync_all', body)
57
+ response.body
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Administrate
4
+ module Resources
5
+ class LlmCosts < BaseResource
6
+ def summary(start_date: nil, end_date: nil)
7
+ response = @transport.get('llm_costs', date_params(start_date, end_date))
8
+ body = response.body
9
+ LlmCostSummaryResponse.new(
10
+ data: Models::LlmCostSummaryData.new(body['data']),
11
+ meta: Models::LlmCostSummaryMeta.new(body['meta'])
12
+ )
13
+ end
14
+
15
+ def by_client(start_date: nil, end_date: nil)
16
+ response = @transport.get('llm_costs/by_client', date_params(start_date, end_date))
17
+ body = response.body
18
+ LlmCostByClientResponse.new(
19
+ data: (body['data'] || []).map { |item| Models::LlmCostByClient.new(item) },
20
+ meta: Models::LlmCostSummaryMeta.new(body['meta'])
21
+ )
22
+ end
23
+
24
+ def by_provider(start_date: nil, end_date: nil)
25
+ response = @transport.get('llm_costs/by_provider', date_params(start_date, end_date))
26
+ body = response.body
27
+ LlmCostByProviderResponse.new(
28
+ data: (body['data'] || []).map { |item| Models::LlmCostByProvider.new(item) },
29
+ meta: Models::LlmCostSummaryMeta.new(body['meta'])
30
+ )
31
+ end
32
+
33
+ private
34
+
35
+ def date_params(start_date, end_date)
36
+ params = {}
37
+ params[:start_date] = start_date unless start_date.nil?
38
+ params[:end_date] = end_date unless end_date.nil?
39
+ params
40
+ end
41
+ end
42
+
43
+ class LlmCostSummaryResponse
44
+ attr_reader :data, :meta
45
+
46
+ def initialize(data:, meta:)
47
+ @data = data
48
+ @meta = meta
49
+ end
50
+ end
51
+
52
+ class LlmCostByClientResponse
53
+ attr_reader :data, :meta
54
+
55
+ def initialize(data:, meta:)
56
+ @data = data
57
+ @meta = meta
58
+ end
59
+ end
60
+
61
+ class LlmCostByProviderResponse
62
+ attr_reader :data, :meta
63
+
64
+ def initialize(data:, meta:)
65
+ @data = data
66
+ @meta = meta
67
+ end
68
+ end
69
+ end
70
+ end