typesafe-sdk 0.2.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 (42) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +11 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +359 -0
  5. data/lib/typesafe/sdk/answer_parser.rb +36 -0
  6. data/lib/typesafe/sdk/api_error.rb +43 -0
  7. data/lib/typesafe/sdk/api_error_factory.rb +36 -0
  8. data/lib/typesafe/sdk/api_response_validation_error.rb +20 -0
  9. data/lib/typesafe/sdk/api_timeout_error.rb +14 -0
  10. data/lib/typesafe/sdk/body_decoder.rb +18 -0
  11. data/lib/typesafe/sdk/choice.rb +39 -0
  12. data/lib/typesafe/sdk/choice_answer.rb +45 -0
  13. data/lib/typesafe/sdk/client.rb +108 -0
  14. data/lib/typesafe/sdk/configuration.rb +66 -0
  15. data/lib/typesafe/sdk/connection_pool.rb +82 -0
  16. data/lib/typesafe/sdk/error_message.rb +51 -0
  17. data/lib/typesafe/sdk/field_reader.rb +76 -0
  18. data/lib/typesafe/sdk/http_request.rb +30 -0
  19. data/lib/typesafe/sdk/http_response.rb +24 -0
  20. data/lib/typesafe/sdk/invalid_response_field.rb +14 -0
  21. data/lib/typesafe/sdk/json_value.rb +51 -0
  22. data/lib/typesafe/sdk/list_models_response.rb +41 -0
  23. data/lib/typesafe/sdk/model_metadata.rb +39 -0
  24. data/lib/typesafe/sdk/models.rb +37 -0
  25. data/lib/typesafe/sdk/net_http_transport.rb +53 -0
  26. data/lib/typesafe/sdk/noul.rb +49 -0
  27. data/lib/typesafe/sdk/noul_answer.rb +39 -0
  28. data/lib/typesafe/sdk/question_set.rb +55 -0
  29. data/lib/typesafe/sdk/rate_limit_error.rb +14 -0
  30. data/lib/typesafe/sdk/request_builder.rb +58 -0
  31. data/lib/typesafe/sdk/request_logger.rb +68 -0
  32. data/lib/typesafe/sdk/requester.rb +92 -0
  33. data/lib/typesafe/sdk/retry_after.rb +46 -0
  34. data/lib/typesafe/sdk/retry_policy.rb +96 -0
  35. data/lib/typesafe/sdk/score.rb +40 -0
  36. data/lib/typesafe/sdk/score_answer.rb +53 -0
  37. data/lib/typesafe/sdk/stderr_logger.rb +42 -0
  38. data/lib/typesafe/sdk/system_one_response.rb +48 -0
  39. data/lib/typesafe/sdk/usage.rb +37 -0
  40. data/lib/typesafe/sdk/version.rb +7 -0
  41. data/lib/typesafe/sdk.rb +47 -0
  42. metadata +108 -0
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Typesafe
4
+ module SDK
5
+ class SystemOneResponse
6
+ attr_reader :model, :usage, :answers, :nouls, :choices, :scores, :http_response
7
+
8
+ class << self
9
+ def from_body(body, request_logger: RequestLogger.new(nil), http_response: nil)
10
+ root = FieldReader.object(body, path: "")
11
+ new(
12
+ model: FieldReader.string(hash: root, key: "model", path: ""),
13
+ usage: Usage.from_hash(FieldReader.object(FieldReader.fetch(hash: root, key: "usage", path: ""), path: "usage")),
14
+ answers: AnswerParser.new(request_logger).parse(FieldReader.fetch(hash: root, key: "answers", path: "")),
15
+ http_response: http_response
16
+ )
17
+ end
18
+ end
19
+
20
+ def initialize(model:, usage:, answers:, http_response: nil)
21
+ @model = model
22
+ @usage = usage
23
+ @answers = answers.freeze
24
+ @nouls = select_answers(NoulAnswer)
25
+ @choices = select_answers(ChoiceAnswer)
26
+ @scores = select_answers(ScoreAnswer)
27
+ @http_response = http_response
28
+ freeze
29
+ end
30
+
31
+ def [](name)
32
+ answers[name.to_s]
33
+ end
34
+
35
+ def request_id
36
+ return unless http_response
37
+
38
+ http_response.headers[REQUEST_ID_HEADER]
39
+ end
40
+
41
+ private
42
+
43
+ def select_answers(answer_class)
44
+ answers.select { |_name, answer| answer.is_a?(answer_class) }.freeze
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Typesafe
4
+ module SDK
5
+ class Usage
6
+ attr_reader :input_tokens, :output_tokens
7
+
8
+ class << self
9
+ def from_hash(hash, path: "usage")
10
+ new(
11
+ input_tokens: FieldReader.optional_integer(hash: hash, key: "input_tokens", path: path),
12
+ output_tokens: FieldReader.optional_integer(hash: hash, key: "output_tokens", path: path)
13
+ )
14
+ end
15
+ end
16
+
17
+ def initialize(input_tokens: nil, output_tokens: nil)
18
+ @input_tokens = input_tokens
19
+ @output_tokens = output_tokens
20
+ freeze
21
+ end
22
+
23
+ def to_h
24
+ { input_tokens: input_tokens, output_tokens: output_tokens }
25
+ end
26
+
27
+ def ==(other)
28
+ other.is_a?(self.class) && other.to_h == to_h
29
+ end
30
+ alias eql? ==
31
+
32
+ def hash
33
+ [self.class, to_h].hash
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Typesafe
4
+ module SDK
5
+ VERSION = "0.2.0"
6
+ end
7
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "net/http"
5
+ require "openssl"
6
+ require "time"
7
+ require "uri"
8
+ require "zlib"
9
+ require "zeitwerk"
10
+
11
+ module Typesafe
12
+ end
13
+
14
+ loader = Zeitwerk::Loader.for_gem_extension(Typesafe)
15
+ loader.inflector.inflect(
16
+ "sdk" => "SDK",
17
+ "api_error" => "APIError",
18
+ "api_error_factory" => "APIErrorFactory",
19
+ "api_response_validation_error" => "APIResponseValidationError",
20
+ "api_timeout_error" => "APITimeoutError",
21
+ "http_request" => "HTTPRequest",
22
+ "http_response" => "HTTPResponse"
23
+ )
24
+ loader.setup
25
+
26
+ module Typesafe
27
+ module SDK
28
+ DEFAULT_BASE_URL = "https://api.typesafe.ai"
29
+ DEFAULT_MODEL = "jev-latest"
30
+ DEFAULT_TIMEOUT = 10.0
31
+ SYSTEM_ONE_PATH = "/v1/systemone"
32
+ MODELS_PATH = "/v1/models"
33
+ SDK_NAME = "typesafe-sdk-ruby"
34
+ DEFAULT_USER_AGENT = "#{SDK_NAME}/#{VERSION}"
35
+ REQUEST_ID_HEADER = "x-typesafe-request-id"
36
+ RETRY_COUNT_HEADER = "X-TypeSafe-Retry-Count"
37
+
38
+ class Error < StandardError; end
39
+ class APIConnectionError < Error; end
40
+ class BadRequestError < APIError; end
41
+ class AuthenticationError < APIError; end
42
+ class PermissionDeniedError < APIError; end
43
+ class NotFoundError < APIError; end
44
+ class UnprocessableEntityError < APIError; end
45
+ class InternalServerError < APIError; end
46
+ end
47
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: typesafe-sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Josh
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2026-09-16 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: zeitwerk
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 2.6.2
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '3'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: 2.6.2
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '3'
32
+ description: Ask TypeSafe models typed Noul, Choice, and Score questions about text
33
+ or structured state and get calibrated, structured answers back. Built on the Ruby
34
+ standard library, with Zeitwerk for loading.
35
+ email:
36
+ - git@josh.mn
37
+ executables: []
38
+ extensions: []
39
+ extra_rdoc_files: []
40
+ files:
41
+ - CHANGELOG.md
42
+ - LICENSE.txt
43
+ - README.md
44
+ - lib/typesafe/sdk.rb
45
+ - lib/typesafe/sdk/answer_parser.rb
46
+ - lib/typesafe/sdk/api_error.rb
47
+ - lib/typesafe/sdk/api_error_factory.rb
48
+ - lib/typesafe/sdk/api_response_validation_error.rb
49
+ - lib/typesafe/sdk/api_timeout_error.rb
50
+ - lib/typesafe/sdk/body_decoder.rb
51
+ - lib/typesafe/sdk/choice.rb
52
+ - lib/typesafe/sdk/choice_answer.rb
53
+ - lib/typesafe/sdk/client.rb
54
+ - lib/typesafe/sdk/configuration.rb
55
+ - lib/typesafe/sdk/connection_pool.rb
56
+ - lib/typesafe/sdk/error_message.rb
57
+ - lib/typesafe/sdk/field_reader.rb
58
+ - lib/typesafe/sdk/http_request.rb
59
+ - lib/typesafe/sdk/http_response.rb
60
+ - lib/typesafe/sdk/invalid_response_field.rb
61
+ - lib/typesafe/sdk/json_value.rb
62
+ - lib/typesafe/sdk/list_models_response.rb
63
+ - lib/typesafe/sdk/model_metadata.rb
64
+ - lib/typesafe/sdk/models.rb
65
+ - lib/typesafe/sdk/net_http_transport.rb
66
+ - lib/typesafe/sdk/noul.rb
67
+ - lib/typesafe/sdk/noul_answer.rb
68
+ - lib/typesafe/sdk/question_set.rb
69
+ - lib/typesafe/sdk/rate_limit_error.rb
70
+ - lib/typesafe/sdk/request_builder.rb
71
+ - lib/typesafe/sdk/request_logger.rb
72
+ - lib/typesafe/sdk/requester.rb
73
+ - lib/typesafe/sdk/retry_after.rb
74
+ - lib/typesafe/sdk/retry_policy.rb
75
+ - lib/typesafe/sdk/score.rb
76
+ - lib/typesafe/sdk/score_answer.rb
77
+ - lib/typesafe/sdk/stderr_logger.rb
78
+ - lib/typesafe/sdk/system_one_response.rb
79
+ - lib/typesafe/sdk/usage.rb
80
+ - lib/typesafe/sdk/version.rb
81
+ homepage: https://github.com/joshmn/typesafe-sdk
82
+ licenses:
83
+ - MIT
84
+ metadata:
85
+ allowed_push_host: https://rubygems.org
86
+ homepage_uri: https://github.com/joshmn/typesafe-sdk
87
+ source_code_uri: https://github.com/joshmn/typesafe-sdk
88
+ changelog_uri: https://github.com/joshmn/typesafe-sdk/blob/main/CHANGELOG.md
89
+ documentation_uri: https://docs.typesafe.ai/
90
+ rubygems_mfa_required: 'true'
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: 3.2.0
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubygems_version: 3.6.2
106
+ specification_version: 4
107
+ summary: Ruby client for the TypeSafe System One API
108
+ test_files: []