arcp 1.0.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 (83) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +31 -0
  3. data/CONFORMANCE.md +71 -0
  4. data/LICENSE +202 -0
  5. data/README.md +135 -0
  6. data/lib/arcp/auth/auth_scheme.rb +16 -0
  7. data/lib/arcp/auth/bearer.rb +38 -0
  8. data/lib/arcp/auth.rb +4 -0
  9. data/lib/arcp/client.rb +354 -0
  10. data/lib/arcp/clock.rb +35 -0
  11. data/lib/arcp/credential.rb +65 -0
  12. data/lib/arcp/credential_provisioner.rb +132 -0
  13. data/lib/arcp/envelope.rb +115 -0
  14. data/lib/arcp/errors.rb +154 -0
  15. data/lib/arcp/ids.rb +18 -0
  16. data/lib/arcp/job/accepted.rb +37 -0
  17. data/lib/arcp/job/agent_ref.rb +18 -0
  18. data/lib/arcp/job/cancel.rb +18 -0
  19. data/lib/arcp/job/event.rb +68 -0
  20. data/lib/arcp/job/event_body/delegate.rb +24 -0
  21. data/lib/arcp/job/event_body/log.rb +20 -0
  22. data/lib/arcp/job/event_body/metric.rb +20 -0
  23. data/lib/arcp/job/event_body/progress.rb +27 -0
  24. data/lib/arcp/job/event_body/result_chunk.rb +42 -0
  25. data/lib/arcp/job/event_body/status.rb +25 -0
  26. data/lib/arcp/job/event_body/thought.rb +12 -0
  27. data/lib/arcp/job/event_body/tool_call.rb +16 -0
  28. data/lib/arcp/job/event_body/tool_result.rb +23 -0
  29. data/lib/arcp/job/event_body/trace_span.rb +30 -0
  30. data/lib/arcp/job/handle.rb +16 -0
  31. data/lib/arcp/job/job_error.rb +31 -0
  32. data/lib/arcp/job/result.rb +30 -0
  33. data/lib/arcp/job/submit.rb +32 -0
  34. data/lib/arcp/job/subscribe.rb +22 -0
  35. data/lib/arcp/job/subscribed.rb +14 -0
  36. data/lib/arcp/job/summary.rb +27 -0
  37. data/lib/arcp/job/unsubscribe.rb +10 -0
  38. data/lib/arcp/job.rb +15 -0
  39. data/lib/arcp/lease.rb +212 -0
  40. data/lib/arcp/message_types.rb +35 -0
  41. data/lib/arcp/runtime/credential_registry.rb +67 -0
  42. data/lib/arcp/runtime/event_log.rb +62 -0
  43. data/lib/arcp/runtime/job_context.rb +167 -0
  44. data/lib/arcp/runtime/job_manager.rb +256 -0
  45. data/lib/arcp/runtime/lease_manager.rb +88 -0
  46. data/lib/arcp/runtime/runtime.rb +125 -0
  47. data/lib/arcp/runtime/session_actor.rb +300 -0
  48. data/lib/arcp/runtime/subscription_manager.rb +57 -0
  49. data/lib/arcp/runtime.rb +10 -0
  50. data/lib/arcp/serializer.rb +43 -0
  51. data/lib/arcp/session/ack.rb +14 -0
  52. data/lib/arcp/session/agent_inventory.rb +51 -0
  53. data/lib/arcp/session/bye.rb +10 -0
  54. data/lib/arcp/session/capability_set.rb +29 -0
  55. data/lib/arcp/session/feature.rb +25 -0
  56. data/lib/arcp/session/hello.rb +34 -0
  57. data/lib/arcp/session/jobs_response.rb +18 -0
  58. data/lib/arcp/session/list_jobs.rb +19 -0
  59. data/lib/arcp/session/ping.rb +14 -0
  60. data/lib/arcp/session/pong.rb +14 -0
  61. data/lib/arcp/session/session_error.rb +23 -0
  62. data/lib/arcp/session/welcome.rb +38 -0
  63. data/lib/arcp/session.rb +26 -0
  64. data/lib/arcp/trace.rb +51 -0
  65. data/lib/arcp/transport/base.rb +29 -0
  66. data/lib/arcp/transport/memory_transport.rb +54 -0
  67. data/lib/arcp/transport/stdio_transport.rb +56 -0
  68. data/lib/arcp/transport/websocket_transport.rb +47 -0
  69. data/lib/arcp/transport.rb +6 -0
  70. data/lib/arcp/version.rb +7 -0
  71. data/lib/arcp.rb +19 -0
  72. data/sig/arcp/client.rbs +16 -0
  73. data/sig/arcp/credential.rbs +51 -0
  74. data/sig/arcp/envelope.rbs +25 -0
  75. data/sig/arcp/errors.rbs +40 -0
  76. data/sig/arcp/job.rbs +83 -0
  77. data/sig/arcp/lease.rbs +41 -0
  78. data/sig/arcp/runtime.rbs +41 -0
  79. data/sig/arcp/serializer.rbs +8 -0
  80. data/sig/arcp/session.rbs +56 -0
  81. data/sig/arcp/transport.rbs +18 -0
  82. data/sig/arcp.rbs +5 -0
  83. metadata +226 -0
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arcp
4
+ module Session
5
+ Welcome = Data.define(
6
+ :runtime_name, :runtime_version, :capabilities,
7
+ :heartbeat_interval_sec, :resume_token, :resume_window_sec
8
+ ) do
9
+ def self.from_h(h)
10
+ h = h.transform_keys(&:to_s)
11
+ caps = h['capabilities'] || {}
12
+ new(
13
+ runtime_name: h['runtime_name'],
14
+ runtime_version: h['runtime_version'],
15
+ capabilities: CapabilitySet.new(
16
+ features: Array(caps['features']).freeze,
17
+ encodings: Array(caps['encodings']).freeze,
18
+ agents: caps['agents'] ? AgentInventory.from_array(caps['agents']) : nil
19
+ ),
20
+ heartbeat_interval_sec: h['heartbeat_interval_sec'],
21
+ resume_token: h['resume_token'],
22
+ resume_window_sec: h['resume_window_sec']
23
+ )
24
+ end
25
+
26
+ def to_h
27
+ {
28
+ 'runtime_name' => runtime_name,
29
+ 'runtime_version' => runtime_version,
30
+ 'capabilities' => capabilities.to_h,
31
+ 'heartbeat_interval_sec' => heartbeat_interval_sec,
32
+ 'resume_token' => resume_token,
33
+ 'resume_window_sec' => resume_window_sec
34
+ }
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'session/feature'
4
+ require_relative 'session/capability_set'
5
+ require_relative 'session/agent_inventory'
6
+ require_relative 'session/hello'
7
+ require_relative 'session/welcome'
8
+ require_relative 'session/bye'
9
+ require_relative 'session/session_error'
10
+ require_relative 'session/ping'
11
+ require_relative 'session/pong'
12
+ require_relative 'session/ack'
13
+ require_relative 'session/list_jobs'
14
+ require_relative 'session/jobs_response'
15
+
16
+ module Arcp
17
+ module Session
18
+ # Immutable snapshot of session state after the welcome envelope.
19
+ Info = Data.define(
20
+ :id, :runtime_version, :capabilities, :agents,
21
+ :heartbeat_interval_sec, :resume_token, :resume_window_sec
22
+ ) do
23
+ def supports?(feature) = capabilities.supports?(feature)
24
+ end
25
+ end
26
+ end
data/lib/arcp/trace.rb ADDED
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'ids'
4
+
5
+ module Arcp
6
+ module Trace
7
+ KEY = :arcp_trace_context
8
+
9
+ Context = Data.define(:trace_id, :span_id, :attributes)
10
+
11
+ module_function
12
+
13
+ def current
14
+ Fiber[KEY] || Context.new(trace_id: nil, span_id: nil, attributes: {}.freeze)
15
+ end
16
+
17
+ def current=(ctx)
18
+ Fiber[KEY] = ctx
19
+ end
20
+
21
+ def with(trace_id: nil, span_id: nil, attributes: {})
22
+ prev = current
23
+ Fiber[KEY] = Context.new(
24
+ trace_id: trace_id || prev.trace_id || Arcp::Ids.trace_id,
25
+ span_id: span_id || Arcp::Ids.span_id,
26
+ attributes: prev.attributes.merge(attributes).freeze
27
+ )
28
+ yield current
29
+ ensure
30
+ Fiber[KEY] = prev
31
+ end
32
+
33
+ # @return [String] new 32-hex trace id.
34
+ def new_trace_id = Arcp::Ids.trace_id
35
+
36
+ def in_span(name, attributes: {}, &)
37
+ tracer = begin
38
+ require 'opentelemetry'
39
+ OpenTelemetry.tracer_provider.tracer('arcp')
40
+ rescue LoadError
41
+ nil
42
+ end
43
+
44
+ if tracer
45
+ tracer.in_span(name, attributes: attributes, &)
46
+ else
47
+ with(attributes: attributes, &)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../envelope'
4
+
5
+ module Arcp
6
+ module Transport
7
+ # Abstract transport interface. Implementations carry frames, not
8
+ # message types — decoding is `Arcp::Envelope.from_h`.
9
+ #
10
+ # `#send` accepts an `Arcp::Envelope` and serializes it.
11
+ # `#receive` suspends the calling fiber until an envelope arrives,
12
+ # then returns it (or nil on clean close).
13
+ class Base
14
+ def send(envelope)
15
+ raise NotImplementedError
16
+ end
17
+
18
+ def receive
19
+ raise NotImplementedError
20
+ end
21
+
22
+ def close(reason: nil)
23
+ raise NotImplementedError
24
+ end
25
+
26
+ def closed? = false
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'async/queue'
4
+
5
+ module Arcp
6
+ module Transport
7
+ # In-process transport backed by a pair of `Async::Queue`s. Used for
8
+ # tests and same-process server/client wiring.
9
+ class MemoryTransport < Base
10
+ attr_reader :sent
11
+
12
+ def initialize(incoming:, outgoing:)
13
+ super()
14
+ @incoming = incoming
15
+ @outgoing = outgoing
16
+ @sent = []
17
+ @closed = false
18
+ end
19
+
20
+ def self.pair
21
+ a = Async::Queue.new
22
+ b = Async::Queue.new
23
+ [new(incoming: a, outgoing: b), new(incoming: b, outgoing: a)]
24
+ end
25
+
26
+ def send(envelope)
27
+ raise IOError, 'transport closed' if @closed
28
+
29
+ @sent << envelope
30
+ @outgoing.enqueue(envelope)
31
+ nil
32
+ end
33
+
34
+ def receive
35
+ return nil if @closed && @incoming.empty?
36
+
37
+ value = @incoming.dequeue
38
+ return nil if value.equal?(:__arcp_close__)
39
+
40
+ value
41
+ end
42
+
43
+ def close(reason: nil)
44
+ return if @closed
45
+
46
+ @closed = true
47
+ @outgoing.enqueue(:__arcp_close__)
48
+ @incoming.enqueue(:__arcp_close__) if @incoming.empty?
49
+ end
50
+
51
+ def closed? = @closed
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../serializer'
4
+
5
+ module Arcp
6
+ module Transport
7
+ # Newline-delimited JSON over a pair of IOs. The child process reads
8
+ # from stdin and writes to stdout; the parent connects with its
9
+ # pipe ends. Exit on EOF.
10
+ class StdioTransport < Base
11
+ def initialize(input: $stdin, output: $stdout)
12
+ super()
13
+ @input = input
14
+ @output = output
15
+ @closed = false
16
+ @write_mutex = Mutex.new
17
+ end
18
+
19
+ def send(envelope)
20
+ raise IOError, 'transport closed' if @closed
21
+
22
+ line = Arcp::Serializer.dump(envelope.to_h)
23
+ @write_mutex.synchronize do
24
+ @output.write(line)
25
+ @output.write("\n")
26
+ @output.flush
27
+ end
28
+ nil
29
+ end
30
+
31
+ def receive
32
+ return nil if @closed
33
+
34
+ line = @input.gets
35
+ if line.nil?
36
+ @closed = true
37
+ return nil
38
+ end
39
+
40
+ Arcp::Envelope.from_json(line)
41
+ end
42
+
43
+ def close(reason: nil)
44
+ return if @closed
45
+
46
+ @closed = true
47
+ @output.close unless @output.closed? || @output == $stdout
48
+ @input.close unless @input.closed? || @input == $stdin
49
+ rescue IOError
50
+ nil
51
+ end
52
+
53
+ def closed? = @closed
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../serializer'
4
+
5
+ module Arcp
6
+ module Transport
7
+ # WebSocket transport built on `async-websocket`. The `connection`
8
+ # argument is an open `Async::WebSocket::Connection`.
9
+ class WebSocketTransport < Base
10
+ def initialize(connection:)
11
+ super()
12
+ @connection = connection
13
+ @closed = false
14
+ end
15
+
16
+ def send(envelope)
17
+ raise IOError, 'transport closed' if @closed
18
+
19
+ @connection.write(envelope.to_json)
20
+ @connection.flush if @connection.respond_to?(:flush)
21
+ nil
22
+ end
23
+
24
+ def receive
25
+ message = @connection.read
26
+ return nil if message.nil?
27
+
28
+ bytes = message.respond_to?(:buffer) ? message.buffer : message.to_s
29
+ Arcp::Envelope.from_json(bytes)
30
+ rescue EOFError
31
+ @closed = true
32
+ nil
33
+ end
34
+
35
+ def close(reason: nil)
36
+ return if @closed
37
+
38
+ @closed = true
39
+ @connection.close if @connection.respond_to?(:close)
40
+ rescue StandardError
41
+ nil
42
+ end
43
+
44
+ def closed? = @closed
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'transport/base'
4
+ require_relative 'transport/memory_transport'
5
+ require_relative 'transport/stdio_transport'
6
+ require_relative 'transport/websocket_transport'
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arcp
4
+ VERSION = '1.0.0'
5
+ PROTOCOL_VERSION = '1.1'
6
+ SUBPROTOCOL = 'arcp.v1'
7
+ end
data/lib/arcp.rb ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'arcp/version'
4
+ require_relative 'arcp/ids'
5
+ require_relative 'arcp/clock'
6
+ require_relative 'arcp/errors'
7
+ require_relative 'arcp/serializer'
8
+ require_relative 'arcp/message_types'
9
+ require_relative 'arcp/envelope'
10
+ require_relative 'arcp/trace'
11
+ require_relative 'arcp/lease'
12
+ require_relative 'arcp/credential'
13
+ require_relative 'arcp/credential_provisioner'
14
+ require_relative 'arcp/session'
15
+ require_relative 'arcp/job'
16
+ require_relative 'arcp/auth'
17
+ require_relative 'arcp/transport'
18
+ require_relative 'arcp/client'
19
+ require_relative 'arcp/runtime'
@@ -0,0 +1,16 @@
1
+ module Arcp
2
+ class Client
3
+ attr_reader session: Arcp::Session::Info
4
+ attr_reader transport: Arcp::Transport::Base
5
+
6
+ def self.open: (transport: Arcp::Transport::Base, auth: Hash[String, untyped], ?client_name: String, ?client_version: String, ?capabilities: Arcp::Session::CapabilitySet?, ?resume: Hash[String, untyped]?, ?clock: untyped) -> Client
7
+
8
+ def list_jobs: (?status: untyped, ?agent: String?, ?created_after: String?, ?limit: Integer?, ?cursor: String?) -> Enumerator::Lazy[Arcp::Job::Summary, untyped]
9
+ def submit_job: (agent: String, ?input: untyped, ?lease_request: Arcp::Lease::LeaseRequest?, ?lease_constraints: Arcp::Lease::LeaseConstraints?, ?idempotency_key: String?, ?max_runtime_sec: Integer?) -> Arcp::Job::Handle
10
+ def subscribe_job: (job_id: String, ?from_event_seq: Integer?, ?history: bool) -> Enumerator[Arcp::Job::Event, void]
11
+ def cancel_job: (job_id: String, ?reason: String?) -> Arcp::Envelope
12
+ def get_result: (job_id: String) -> Arcp::Job::Result
13
+ def ack: (Integer) -> void
14
+ def close: (?reason: String?) -> void
15
+ end
16
+ end
@@ -0,0 +1,51 @@
1
+ module Arcp
2
+ class Credential
3
+ SCHEME_BEARER: String
4
+
5
+ attr_reader id: String
6
+ attr_reader scheme: String
7
+ attr_reader value: String
8
+ attr_reader endpoint: String
9
+ attr_reader profile: String?
10
+ attr_reader constraints: Hash[String, untyped]
11
+
12
+ def self.from_h: (Hash[String | Symbol, untyped]) -> Credential
13
+ def to_h: () -> Hash[String, untyped]
14
+ def to_redacted_h: () -> Hash[String, untyped]
15
+ end
16
+
17
+ module ModelPattern
18
+ def self.match?: (Array[String]?, String) -> bool
19
+ def self.implied_by?: (Array[String]?, String) -> bool
20
+ end
21
+
22
+ module CredentialProvisioner
23
+ def issue: (lease: Arcp::Lease::Lease?, job_id: String, agent: String, principal_id: String) -> Array[Credential]
24
+ def revoke: (credential_id: String) -> void
25
+ end
26
+
27
+ module Credentials
28
+ def self.translate_upstream_error: (StandardError) -> StandardError
29
+ def self.budget_exhausted?: (StandardError) -> bool
30
+
31
+ class InMemoryProvisioner
32
+ include CredentialProvisioner
33
+
34
+ attr_reader issued: Array[Hash[Symbol, untyped]]
35
+ attr_reader revoked: Array[String]
36
+
37
+ def initialize: (?endpoint: String, ?profile: String) -> void
38
+ end
39
+
40
+ class CredentialStore
41
+ def record: (job_id: String, credential_id: String) -> void
42
+ def forget: (job_id: String, credential_id: String) -> void
43
+ def outstanding: (job_id: String) -> Array[String]
44
+ def all_outstanding: () -> Hash[String, Array[String]]
45
+ end
46
+
47
+ class InMemoryStore < CredentialStore
48
+ def initialize: () -> void
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,25 @@
1
+ module Arcp
2
+ class Envelope
3
+ attr_reader arcp: String
4
+ attr_reader id: String
5
+ attr_reader type: String
6
+ attr_reader session_id: String
7
+ attr_reader trace_id: String?
8
+ attr_reader job_id: String?
9
+ attr_reader event_seq: Integer?
10
+ attr_reader payload: Hash[String, untyped]
11
+
12
+ def self.build: (type: String, session_id: String, payload: Hash[String | Symbol, untyped], ?trace_id: String?, ?job_id: String?, ?event_seq: Integer?, ?id: String?) -> Envelope
13
+ def self.from_h: (Hash[String | Symbol, untyped]) -> Envelope
14
+ def self.from_json: (String) -> Envelope
15
+ def to_h: () -> Hash[String, untyped]
16
+ def to_json: (*untyped) -> String
17
+ def known?: () -> bool
18
+ end
19
+
20
+ class UnknownEnvelope
21
+ attr_reader envelope: Envelope
22
+ def type: () -> String
23
+ def payload: () -> Hash[String, untyped]
24
+ end
25
+ end
@@ -0,0 +1,40 @@
1
+ module Arcp
2
+ class Error < StandardError
3
+ CODE: String
4
+ attr_reader details: Hash[untyped, untyped]
5
+ def initialize: (?String?, ?details: Hash[untyped, untyped]) -> void
6
+ def code: () -> String
7
+ def retryable?: () -> bool
8
+ def to_payload: (?trace_id: String?) -> Hash[Symbol, untyped]
9
+ end
10
+
11
+ module Errors
12
+ class Cancelled < Arcp::Error end
13
+ class InvalidRequest < Arcp::Error end
14
+ class Unauthenticated < Arcp::Error end
15
+ class PermissionDenied < Arcp::Error end
16
+ class JobNotFound < Arcp::Error end
17
+ class AgentNotAvailable < Arcp::Error end
18
+ class DuplicateKey < Arcp::Error end
19
+ class RateLimited < Arcp::Error end
20
+ class Internal < Arcp::Error end
21
+ class HeartbeatLost < Arcp::Error end
22
+ class Backpressure < Arcp::Error end
23
+ class ProtocolViolation < Arcp::Error end
24
+ class Timeout < Arcp::Error end
25
+ class ResumeWindowExpired < Arcp::Error end
26
+ class LeaseSubsetViolation < Arcp::Error end
27
+ class AgentVersionNotAvailable < Arcp::Error end
28
+ class LeaseExpired < Arcp::Error end
29
+ class BudgetExhausted < Arcp::Error end
30
+ class UnnegotiatedFeature < Arcp::Error end
31
+
32
+ ALL: Array[singleton(Arcp::Error)]
33
+ WIRE_CODES: Array[String]
34
+ BY_CODE: Hash[String, singleton(Arcp::Error)]
35
+ RETRYABLE_BY_DEFAULT: Array[String]
36
+ NON_RETRYABLE_BY_DEFAULT: Array[String]
37
+
38
+ def self.for: (String, ?message: String?, ?details: Hash[untyped, untyped]) -> Arcp::Error
39
+ end
40
+ end
data/sig/arcp/job.rbs ADDED
@@ -0,0 +1,83 @@
1
+ module Arcp
2
+ module Job
3
+ module EventKind
4
+ PROGRESS: String
5
+ RESULT_CHUNK: String
6
+ LOG: String
7
+ THOUGHT: String
8
+ TOOL_CALL: String
9
+ TOOL_RESULT: String
10
+ STATUS: String
11
+ METRIC: String
12
+ TRACE_SPAN: String
13
+ DELEGATE: String
14
+ ALL: Array[String]
15
+ end
16
+
17
+ class AgentRef
18
+ attr_reader name: String
19
+ attr_reader version: String?
20
+ def self.parse: (String?) -> AgentRef?
21
+ def to_s: () -> String
22
+ end
23
+
24
+ class Event
25
+ attr_reader kind: String
26
+ attr_reader body: untyped
27
+ def self.from_h: (Hash[String | Symbol, untyped]) -> Event
28
+ def to_h: () -> Hash[String, untyped]
29
+ def known?: () -> bool
30
+ end
31
+
32
+ class Handle
33
+ attr_reader job_id: String
34
+ attr_reader agent: String
35
+ attr_reader submitted_at: String?
36
+ attr_reader lease: Arcp::Lease::Lease?
37
+ attr_reader credentials: Array[Arcp::Credential]?
38
+ def subscribe: (client: Arcp::Client, **untyped) -> Enumerator[Event, void]
39
+ def cancel: (client: Arcp::Client, ?reason: String?) -> Envelope
40
+ def get_result: (client: Arcp::Client) -> Result
41
+ def credential_for: (endpoint: String) -> Arcp::Credential?
42
+ end
43
+
44
+ class Accepted
45
+ attr_reader job_id: String
46
+ attr_reader agent: String
47
+ attr_reader accepted_at: String?
48
+ attr_reader lease: Arcp::Lease::Lease?
49
+ attr_reader credentials: Array[Arcp::Credential]?
50
+ def self.from_h: (Hash[String | Symbol, untyped]) -> Accepted
51
+ def to_h: () -> Hash[String, untyped]
52
+ end
53
+
54
+ class Summary
55
+ attr_reader job_id: String
56
+ attr_reader agent: String
57
+ attr_reader status: String
58
+ attr_reader created_at: String?
59
+ attr_reader lease_expires_at: String?
60
+ attr_reader budget_remaining: Hash[String, String]?
61
+ end
62
+
63
+ class Result
64
+ attr_reader job_id: String
65
+ attr_reader final_status: String
66
+ attr_reader result: untyped
67
+ attr_reader result_id: String?
68
+ attr_reader result_size: Integer?
69
+ attr_reader completed_at: String?
70
+ def chunked?: () -> bool
71
+ end
72
+
73
+ class JobError
74
+ attr_reader job_id: String
75
+ attr_reader final_status: String
76
+ attr_reader code: String
77
+ attr_reader message: String?
78
+ attr_reader retryable: bool
79
+ attr_reader details: Hash[String, untyped]
80
+ def to_exception: () -> Arcp::Error
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,41 @@
1
+ module Arcp
2
+ module Lease
3
+ class LeaseConstraints
4
+ attr_reader expires_at: String?
5
+ attr_reader max_budget: Hash[String, untyped]?
6
+ def self.from_h: (Hash[String | Symbol, untyped]?) -> LeaseConstraints?
7
+ def to_h: () -> Hash[String, untyped]
8
+ def validate!: () -> void
9
+ end
10
+
11
+ class CostBudget
12
+ attr_reader per_currency: Hash[String, BigDecimal]
13
+ def self.parse: (Array[String]) -> CostBudget
14
+ def to_a: () -> Array[String]
15
+ def to_h: () -> Hash[String, untyped]
16
+ def remaining: (String) -> BigDecimal
17
+ def currencies: () -> Array[String]
18
+ end
19
+
20
+ class LeaseRequest
21
+ attr_reader capabilities: Array[String]
22
+ attr_reader budget: CostBudget?
23
+ attr_reader model_use: Array[String]?
24
+ attr_reader expires_at: String?
25
+ def self.from_h: (Hash[String | Symbol, untyped]?) -> LeaseRequest?
26
+ def to_h: () -> Hash[String, untyped]
27
+ end
28
+
29
+ class Lease
30
+ attr_reader id: String
31
+ attr_reader capabilities: Array[String]
32
+ attr_reader budget: CostBudget?
33
+ attr_reader model_use: Array[String]?
34
+ attr_reader expires_at: String?
35
+ attr_reader issued_at: String
36
+ def self.from_h: (Hash[String | Symbol, untyped]) -> Lease
37
+ def to_h: () -> Hash[String, untyped]
38
+ def expired?: (Time) -> bool
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ module Arcp
2
+ module Runtime
3
+ class Runtime
4
+ attr_reader auth_verifier: untyped
5
+ attr_reader name: String
6
+ attr_reader version: String
7
+ attr_reader heartbeat_interval_sec: Integer?
8
+ attr_reader resume_window_sec: Integer
9
+ attr_reader clock: untyped
10
+ attr_reader job_manager: JobManager
11
+ attr_reader lease_manager: LeaseManager
12
+ attr_reader subscription_manager: SubscriptionManager
13
+ attr_reader event_log: EventLog
14
+ attr_reader credential_registry: CredentialRegistry?
15
+ attr_reader enforce_model_use: bool
16
+
17
+ def initialize: (auth_verifier: untyped, ?name: String, ?version: String, ?heartbeat_interval_sec: Integer?, ?resume_window_sec: Integer, ?clock: untyped, ?credential_provisioner: Arcp::CredentialProvisioner?, ?credential_store: Arcp::Credentials::CredentialStore?, ?require_durable_store: bool, ?enforce_model_use: bool) -> void
18
+ def register_agent: (name: String, versions: Array[String], default: String, handler: ^(JobContext) -> void) -> void
19
+ def local_capabilities: (?agents_inventory: bool) -> Arcp::Session::CapabilitySet
20
+ def accept: (Arcp::Transport::Base) -> untyped
21
+ def shutdown: (?reason: String?) -> void
22
+ end
23
+
24
+ class JobManager end
25
+ class LeaseManager
26
+ def check_model!: (String, model_id: String) -> bool
27
+ end
28
+ class CredentialRegistry
29
+ def issue_for: (job_id: String, lease: Arcp::Lease::Lease?, agent: String, principal_id: String) -> Array[Arcp::Credential]
30
+ def rotate: (job_id: String, credential_id: String, new_value: String) -> String
31
+ def revoke_all: (job_id: String) -> Integer
32
+ def reconcile_on_startup!: () -> void
33
+ end
34
+ class SubscriptionManager end
35
+ class EventLog end
36
+ class JobContext
37
+ def rotate_credential: (id: String, new_value: String) -> untyped
38
+ end
39
+ class SessionActor end
40
+ end
41
+ end
@@ -0,0 +1,8 @@
1
+ module Arcp
2
+ module Serializer
3
+ def self.backend: () -> Symbol
4
+ def self.backend=: (Symbol) -> Symbol
5
+ def self.dump: (untyped) -> String
6
+ def self.load: (String?) -> untyped
7
+ end
8
+ end