ask-core 0.8.0 → 0.10.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4a806c5e8835fe74ef4bf8941a314ed462fa39bd3d607e6de112b92df9a8bbb8
4
- data.tar.gz: a6301f23b50af2d5e508eb73e072951a2e3526a3c0c2776a92b24b281111ef93
3
+ metadata.gz: b2d67418e2412efacf4d0b5c35d1897826f0da1c0a52c159f7503e8b794d66f1
4
+ data.tar.gz: 2b39ea638d11e5147058a1f35e3aa3c130650972082330e2dd30a752eeb68a36
5
5
  SHA512:
6
- metadata.gz: 685fd487472dcb656e7b928e32d8e972ce27b963e78c8a64b167fe3a76691268878b87cf3079ff39d530cd23082d33ad919e36b01d209a790a9225c89d26b3bf
7
- data.tar.gz: ba3bae4f9839de021ac62c3aefb0e9675b159151e5d45c5b113e48c6ec042594c658568944e78075b0c38e9dc945c02be13c40dfd2cf6901ed181b7bf9184fe3
6
+ metadata.gz: 8910e469a984ca9f2758dc816b6b13714b5985fad2dbb0910b2d2d0b5313ff04abfcffad06e3fcf2de4a53eb2d3e34fda1292150867bae39d476b5ad4a3551e4
7
+ data.tar.gz: 6ed636a7ed4b15f423b5914708064e44ac286e6488b87857d271646e83fad113b8dec97a1a7082e95bbd598d1ee2c631a77bffa0d03595ebd7d10db9a965b2ab
data/CHANGELOG.md CHANGED
@@ -1,3 +1,40 @@
1
+ ## [0.10.0] - 2026-08-05
2
+
3
+ ### Added
4
+
5
+ - **`Ask::Result.pending`** — a new `:pending` status for async tool
6
+ execution. A tool returns pending to hand the turn back to the agent
7
+ (the interim message gets voiced) while the real work continues in the
8
+ background; the session completes it later. `Result#pending?` predicates
9
+ it; `to_h` keeps the tool shape.
10
+
11
+ ## [0.9.0] — 2026-08-03
12
+
13
+ ### Changed
14
+
15
+ - **`Ask::Result` is now the single result type for the whole ecosystem** — it
16
+ supports both the foundational API (`success`/`failure`/`aborted`/`blocked`
17
+ with `content` and `status`) and the tool API (`ok`/`error` with `ok?`,
18
+ `output`, and `error_message`), including both constructor keyword sets.
19
+ Previously `ask-tools` defined its own incompatible `Ask::Result`; whichever
20
+ gem loaded last won, so `Ask::Result.success` raised `ArgumentError` in any
21
+ app loading both (e.g. every ask-agent app), and `ask-rag`'s `raw.output`
22
+ call failed on provider embedding results. ask-tools now depends on
23
+ ask-core instead of redefining the class.
24
+ - `Result#to_h` now serializes to `{ok:, output:, error:, metadata:}` (the
25
+ tool shape). `Result#inspect` is `ok=true output=...` / `ok=false error=...`.
26
+
27
+ ```ruby
28
+ Ask::Result.success("Data processed").to_h
29
+ # => {ok: true, output: "Data processed", error: nil, metadata: {}}
30
+
31
+ Ask::Result.ok(data: "Data processed") # same class, same result
32
+ ```
33
+
34
+ ### Tested
35
+
36
+ - ask-core test suite: all pass.
37
+
1
38
  ## [0.8.0] — 2026-07-28
2
39
 
3
40
  ### Changed
data/README.md CHANGED
@@ -1,284 +1,89 @@
1
1
  # ask-core
2
2
 
3
- Foundation gem for the ask-rb ecosystem. Provides the types and interfaces that every provider gem builds on.
3
+ [![Gem Version](https://badge.fury.io/rb/ask-core.svg)](https://badge.fury.io/rb/ask-core)
4
4
 
5
- **Zero external dependencies.** Uses only Ruby stdlib (`json`, `net/http`, `date`, `time`).
5
+ Foundation gem for the ask-rb ecosystem. Provides the value objects and interfaces every other gem builds on: messages, conversations, streaming primitives, the provider contract, model catalog, tool definitions, and structured errors. Zero external dependencies, Ruby stdlib only (`json`, `net/http`, `date`, `time`).
6
6
 
7
7
  ## Installation
8
8
 
9
9
  ```ruby
10
- # In your Gemfile
11
10
  gem "ask-core"
12
11
  ```
13
12
 
14
- ## What it provides
15
-
16
- | Component | File | Purpose |
17
- |---|---|---|
18
- | `Ask::Provider` | `lib/ask/provider.rb` | Abstract base class for all LLM providers |
19
- | `Ask::Conversation` | `lib/ask/conversation.rb` | Message container with role normalization |
20
- | `Ask::Stream` / `Ask::Chunk` | `lib/ask/stream.rb` | Streaming primitives |
21
- | `Ask::ModelCatalog` | `lib/ask/models.rb` | Model name to provider resolution |
22
- | `Ask::ToolDef` | `lib/ask/tool_def.rb` | Immutable tool metadata struct |
23
- | `Ask::Result` | `lib/ask/result.rb` | Standardized tool return value |
24
- | `Ask::Error` | `lib/ask/errors.rb` | Structured error types |
25
-
26
- ## Usage
27
-
28
- ### Provider (abstract base class)
29
-
30
- Provider gems subclass `Ask::Provider` and implement the abstract methods:
13
+ ## Quick Start
31
14
 
32
15
  ```ruby
33
- class MyProvider < Ask::Provider
34
- def api_base
35
- "https://api.example.com/v1"
36
- end
37
-
38
- def headers
39
- { "Authorization" => "Bearer #{@config.api_key}" }
40
- end
41
-
42
- def chat(messages, model:, tools: nil, temperature: nil, stream: nil, schema: nil, **params, &block)
43
- # Return an Ask::Message or yield Ask::Chunks
44
- end
45
-
46
- def embed(text, model:)
47
- # Return an array of floats
48
- end
49
-
50
- def list_models
51
- # Return an array of Ask::ModelInfo
52
- end
53
-
54
- class << self
55
- def configuration_options
56
- [:api_key, :api_base]
57
- end
58
-
59
- def configuration_requirements
60
- [:api_key]
61
- end
62
- end
63
- end
64
-
65
- # Register the provider
66
- Ask::Provider.register(:my_provider, MyProvider)
67
-
68
- # Resolve by name
69
- Ask::Provider.resolve(:my_provider) # => MyProvider
70
- ```
71
-
72
- ### Conversation
73
-
74
- Build and manipulate conversations with role-normalized messages:
16
+ require "ask-core"
75
17
 
76
- ```ruby
77
18
  conv = Ask::Conversation.new
78
-
79
- # Convenience methods
80
19
  conv.system("You are a helpful assistant.")
81
20
  conv.user("What's the weather in Tokyo?")
82
- conv.assistant("Let me check...", tool_calls: [{ name: "get_weather", arguments: { location: "Tokyo" } }])
83
- conv.tool_result("72°F, sunny", tool_call_id: "call_123")
84
-
85
- # Iteration
86
- conv.each { |msg| puts "#{msg.role}: #{msg.content}" }
87
21
 
88
- # Filtering by role
89
- conv.user_messages # => [Ask::Message, ...]
90
- conv.system_messages # => [Ask::Message, ...]
22
+ conv.last.role # => :user
23
+ conv.last.user? # => true
91
24
 
92
- # Serialization
93
- conv.to_a # => [{ role: :user, content: "..." }, ...]
25
+ # Serialize for a provider API
26
+ conv.to_a # => [{ role: :user, content: "..." }, ...]
94
27
  ```
95
28
 
96
- ### Messages
29
+ ## The core types
97
30
 
98
- ```ruby
99
- msg = Ask::Message.new(role: :user, content: "Hello")
100
- msg.user? # => true
101
- msg.system? # => false
102
- msg.assistant? # => false
103
- msg.tool? # => false
31
+ | Type | Purpose |
32
+ |---|---|
33
+ | `Ask::Conversation`, `Ask::Message` | Message container with role normalization (`:system`, `:user`, `:assistant`, `:tool`) and immutable message value objects |
34
+ | `Ask::Stream`, `Ask::Chunk` | Streaming primitives with text accumulation and usage tracking |
35
+ | `Ask::Provider` | Abstract base class for LLM providers, with a thread-safe registry (`register` / `resolve`) |
36
+ | `Ask::ModelCatalog`, `Ask::ModelInfo` | Model metadata: find by ID/provider, filter by family, refresh from models.dev |
37
+ | `Ask::ToolDef` | Immutable tool metadata for provider function calling |
38
+ | `Ask::Result` | Standardized tool return value: `success`, `failure`, `aborted`, `blocked` |
39
+ | `Ask::Content` | Multi-modal content blocks: `Text`, `Image`, `Audio`, `Video`, `File` |
40
+ | `Ask::Document` | Text + metadata value object for RAG pipelines |
41
+ | `Ask::ProviderTool` | Provider-executed tools (e.g. `web_search`, `file_search`) |
42
+ | `Ask::State::Adapter` | Abstract contract for state backends (implemented by ask-state-providers) |
43
+ | `Ask::Error` and subclasses | Structured errors (`ConfigurationError`, `RateLimitError`, `ProviderError`, and more) |
104
44
 
105
- msg = Ask::Message.new(role: :assistant, tool_calls: [{ name: "f", arguments: {} }])
106
- msg.tool_call? # => true
45
+ ## Defining a provider
107
46
 
108
- msg = Ask::Message.new(role: :tool, content: "result", tool_call_id: "call_1")
109
- msg.tool_result? # => true
110
- ```
111
-
112
- Valid roles: `:system`, `:user`, `:assistant`, `:tool`
113
-
114
- ### Streaming
47
+ Provider gems subclass `Ask::Provider`, implement the abstract methods, and register themselves:
115
48
 
116
49
  ```ruby
117
- stream = Ask::Stream.new
118
-
119
- # Add chunks as they arrive from the provider
120
- stream.add(Ask::Chunk.new(content: "Hello "))
121
- stream.add(Ask::Chunk.new(content: "World"))
122
- stream.add(Ask::Chunk.new(content: "", finish_reason: "stop"))
123
- stream.finish!
124
-
125
- # Accumulate the full response
126
- stream.accumulated_text # => "Hello World"
127
- stream.to_s # => "Hello World"
128
-
129
- # Track token usage
130
- stream.accumulated_usage # => { input_tokens: 10, output_tokens: 20 }
131
-
132
- # Iterate
133
- stream.each { |chunk| print chunk.content }
134
- ```
135
-
136
- ### Chunks
137
-
138
- ```ruby
139
- chunk = Ask::Chunk.new(content: "Hello")
140
- chunk.content # => "Hello"
141
- chunk.finished? # => false
142
- chunk.tool_call? # => false
143
- chunk.finish_reason # => nil (or "stop", "length", "tool_calls")
144
-
145
- chunk = Ask::Chunk.new(tool_calls: [{ name: "get_weather" }])
146
- chunk.tool_call? # => true
147
-
148
- chunk = Ask::Chunk.new(usage: { input_tokens: 10, output_tokens: 20 })
149
- chunk.usage # => { input_tokens: 10, output_tokens: 20 }
150
- ```
151
-
152
- ### Model Catalog
153
-
154
- Query available models from the registry:
155
-
156
- ```ruby
157
- catalog = Ask::ModelCatalog.new([
158
- Ask::ModelInfo.new(id: "gpt-4o", provider: "openai", capabilities: ["function_calling", "vision"]),
159
- Ask::ModelInfo.new(id: "claude-sonnet-4", provider: "anthropic", capabilities: ["function_calling", "reasoning"])
160
- ])
161
-
162
- # Find by ID (prefers most common provider)
163
- catalog.find("gpt-4o")
164
-
165
- # Find with specific provider
166
- catalog.find("gpt-4o", "openai")
167
-
168
- # Filter by type
169
- catalog.chat_models
170
- catalog.embedding_models
171
-
172
- # Filter by provider or family
173
- catalog.by_provider("openai")
174
- catalog.by_family("gpt")
175
-
176
- # Singleton instance
177
- Ask::ModelCatalog.instance
178
- Ask::ModelCatalog.find("gpt-4o")
179
- ```
180
-
181
- ### ModelInfo
182
-
183
- ```ruby
184
- info = Ask::ModelInfo.new(
185
- id: "gpt-4o",
186
- provider: "openai",
187
- capabilities: ["function_calling", "vision"],
188
- context_window: 128_000,
189
- pricing: { text_tokens: { standard: { input_per_million: 2.5, output_per_million: 10 } } }
190
- )
191
-
192
- info.supports?(:function_calling) # => true
193
- info.chat? # => true
194
- info.embedding? # => false
195
- info.context_window # => 128_000
196
- ```
197
-
198
- ### Tool Definitions
199
-
200
- Immutable tool metadata for provider function calling:
201
-
202
- ```ruby
203
- tool = Ask::ToolDef.new(
204
- name: "get_weather",
205
- description: "Get current weather for a location",
206
- parameters: {
207
- type: "object",
208
- properties: {
209
- location: { type: "string", description: "City name" },
210
- unit: { type: "string", enum: ["celsius", "fahrenheit"] }
211
- },
212
- required: ["location"]
213
- }
214
- )
215
-
216
- tool.name # => "get_weather"
217
- tool.description # => "Get current weather for a location"
50
+ class MyProvider < Ask::Provider
51
+ def api_base = "https://api.example.com/v1"
52
+ def chat(messages, model:, **opts) = Ask::Message.new(role: :assistant, content: "Hello")
53
+ def embed(text, model:) = [0.1, 0.2, 0.3]
54
+ def list_models = [Ask::ModelInfo.new(id: "my-model", provider: "my_provider")]
55
+ end
218
56
 
219
- # Provider-specific format
220
- tool.to_provider_format { |t| { type: "function", function: t.to_h } }
57
+ Ask::Provider.register(:my_provider, MyProvider)
58
+ Ask::Provider.resolve(:my_provider) # => MyProvider
221
59
  ```
222
60
 
223
- ### Tool Results
61
+ ## Architecture & ownership
224
62
 
225
- Standardized return values from tool execution:
63
+ ask-core owns the shared value objects and base contracts (`Ask::Message`,
64
+ `Ask::Conversation`, `Ask::Content`, `Ask::Stream`, `Ask::Provider`,
65
+ `Ask::Result`, `Ask::ModelCatalog`, `Ask::ToolDef`, `Ask::Document`, the
66
+ `Ask::Error` hierarchy). It is zero-dependency on purpose: `ask-llm-providers`,
67
+ `ask-rag`, `ask-graph`, and `ask-state-providers` depend on it *without*
68
+ pulling in the tool framework.
226
69
 
227
- ```ruby
228
- Ask::Result.success("Data processed")
229
- Ask::Result.success(updated_record, metadata: { duration: 1.2 })
230
- Ask::Result.failure("API returned 500", error: "Timeout")
231
- Ask::Result.aborted("Cancelled by sibling failure")
232
- Ask::Result.blocked("Permission denied")
70
+ Feature gems extend what ask-core provides — they never redefine it.
71
+ `Ask::Result` is the single result type for the whole ecosystem: foundational
72
+ API (`success`/`failure`/`aborted`/`blocked`) and tool API (`ok`/`error`) in
73
+ one class. See
74
+ [Architecture & Ownership](https://ask-rb.github.io/ask-docs/reference/architecture).
233
75
 
234
- result = Ask::Result.success("OK")
235
- result.success? # => true
236
- result.error? # => false
237
- result.aborted? # => false
238
- result.blocked? # => false
239
- result.to_s # => "OK"
240
- result.to_h # => { content: "OK", status: :success, metadata: {} }
241
- ```
76
+ ## Full documentation
242
77
 
243
- ### Error Types
244
-
245
- ```ruby
246
- Ask::Error # Base class (rescue Ask::Error to catch all)
247
- Ask::ConfigurationError # Missing/incorrect configuration
248
- Ask::UnknownProvider # Provider not registered
249
- Ask::ModelNotFound # Model not in catalog
250
- Ask::InvalidRole # Invalid message role
251
- Ask::InvalidToolDefinition # Invalid tool name/definition
252
- Ask::ProviderError # Provider API error (with status_code, response_body)
253
- Ask::ContextLengthExceeded # Context window exceeded
254
- Ask::RateLimitError # Rate limited
255
- Ask::Unauthorized # Authentication failure
256
- Ask::ServerError # 5xx server error
257
- Ask::ServiceUnavailable # Service temporarily unavailable
258
- Ask::UnsupportedFeature # Feature not supported by provider/model
259
- Ask::MissingCredential # Required credential not found
260
- Ask::InvalidCredential # Credential is invalid/expired
261
- ```
78
+ The full ask-rb documentation lives at https://ask-rb.github.io/ask-docs. [ask-core in depth](https://ask-rb.github.io/ask-docs/core/ask-core) covers the types, streaming, and the provider contract. API reference: https://ask-rb.github.io/ask-docs/reference/api.
262
79
 
263
80
  ## Development
264
81
 
265
- ```bash
82
+ ```
83
+ bundle install
266
84
  bundle exec rake test
267
85
  ```
268
86
 
269
- ## Testing
270
-
271
- - Uses Minitest (not RSpec) — consistent with the ask-rb ecosystem.
272
- - Unit tests for every public method.
273
- - Run the full suite before every commit: `bundle exec rake test`.
274
-
275
- ## Design Principles
276
-
277
- 1. **Zero runtime dependencies** — stdlib only. Provider gems add their own HTTP clients.
278
- 2. **Immutable value objects** — `Message`, `ToolDef`, `Result`, `Chunk`, and `ModelInfo` are frozen after construction.
279
- 3. **Abstract interface** — `Ask::Provider` defines the contract. Provider gems implement the wire format.
280
- 4. **Provider registry** — providers register themselves for runtime resolution by name.
281
-
282
87
  ## License
283
88
 
284
89
  MIT
data/lib/ask/result.rb CHANGED
@@ -1,14 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ask
4
- # Standardized return value from tool execution. Wraps the outcome of a tool
5
- # call with status, content, and optional error metadata.
4
+ # Standardized return value from tool execution.
5
+ #
6
+ # This is the single +Ask::Result+ for the whole ecosystem. It supports both
7
+ # the foundational API (+success+/+failure+/+aborted+/+blocked+ with
8
+ # +content+ and +status+) and the tool API (+ok+/+error+ with +ok?+,
9
+ # +output+, and +error_message+):
6
10
  #
7
11
  # Ask::Result.success("Data processed")
8
- # Ask::Result.failure("API returned 500")
12
+ # Ask::Result.ok(data: "Data processed")
13
+ #
14
+ # Both are the same class and share the same +to_h+ shape, so a result
15
+ # created by a provider's +embed+ or a tool's +execute+ can be inspected
16
+ # uniformly.
9
17
  #
18
+ # Feature gems extend this class or build on it — they never redefine it.
19
+ # See ask-docs "Architecture & ownership" for the rule.
10
20
  class Result
11
- STATUSES = %i[success error aborted blocked short_circuited].freeze
21
+ STATUSES = %i[success error aborted blocked short_circuited pending].freeze
12
22
 
13
23
  class << self
14
24
  # @!group Factory Methods
@@ -23,11 +33,12 @@ module Ask
23
33
 
24
34
  # Create a failure result.
25
35
  # @param message [String] the error description
26
- # @param error [Object, nil] the underlying error object
36
+ # @param error [Object, nil] the underlying error object (defaults to
37
+ # +message+ so `failure(msg).error` reads as the message)
27
38
  # @param metadata [Hash] additional metadata
28
39
  # @return [Ask::Result]
29
40
  def failure(message, error: nil, metadata: {})
30
- new(content: message, status: :error, error: error, metadata: metadata)
41
+ new(content: message, status: :error, error: error.nil? ? message : error, metadata: metadata)
31
42
  end
32
43
 
33
44
  # Create an aborted result (cancelled by sibling failure).
@@ -43,24 +54,69 @@ module Ask
43
54
  def blocked(reason)
44
55
  new(content: reason, status: :blocked)
45
56
  end
57
+
58
+ # Create a pending result (async tool): the work continues in the
59
+ # background and the session completes it later via
60
+ # +Ask::Agent::Session#complete_pending_tool+. The agent voices the
61
+ # tool's interim message immediately and keeps talking.
62
+ # @param message [String] interim status the model can voice
63
+ # @param metadata [Hash] additional metadata
64
+ # @return [Ask::Result]
65
+ def pending(message, metadata: {})
66
+ new(content: message, status: :pending, metadata: metadata)
67
+ end
68
+
69
+ # Create a successful result (tool API — alias for +success+).
70
+ # @param data [Object] the tool's output
71
+ # @param metadata [Hash] optional metadata
72
+ # @return [Ask::Result]
73
+ def ok(data:, metadata: {})
74
+ new(content: data, status: :success, metadata: metadata)
75
+ end
76
+
77
+ # Create a failed result (tool API).
78
+ # @param message [String] description of the failure
79
+ # @param metadata [Hash] optional metadata
80
+ # @return [Ask::Result]
81
+ def error(message:, metadata: {})
82
+ new(content: message, status: :error, error: message, metadata: metadata)
83
+ end
46
84
  # @!endgroup
47
85
  end
48
86
 
49
- # @return [Object, nil] the result content
87
+ # @return [Object, nil] the result content (for +success+/+ok+ results,
88
+ # this is the payload; for +failure+ it is the error message)
50
89
  attr_reader :content
51
90
 
52
91
  # @return [Symbol] the status (:success, :error, :aborted, :blocked, :short_circuited)
53
92
  attr_reader :status
54
93
 
55
- # @return [Object, nil] the underlying error, if any
94
+ # @return [Object, nil] the error message or underlying error object, if any
56
95
  attr_reader :error
57
96
 
58
97
  # @return [Hash] additional metadata
59
98
  attr_reader :metadata
60
99
 
61
- def initialize(content: nil, status: :success, error: nil, metadata: {})
62
- @content = content
63
- @status = validate_status!(status)
100
+ # Accepts both the foundational keywords (+content+, +status+) and the
101
+ # tool keywords (+ok+, +output+). +ok:+ derives the status: +true+ means
102
+ # +:success+, +false+ means +:error+.
103
+ #
104
+ # @param content [Object, nil] result content
105
+ # @param output [Object, nil] tool output (takes precedence over +content+)
106
+ # @param status [Symbol] result status
107
+ # @param ok [Boolean, nil] whether the result is a success (derives status)
108
+ # @param error [Object, nil] error message or underlying error object
109
+ # @param metadata [Hash] additional metadata
110
+ def initialize(content: nil, output: nil, status: :success, ok: nil, error: nil, metadata: {})
111
+ @content = output.nil? ? content : output
112
+ @status = if ok == true
113
+ :success
114
+ elsif ok == false
115
+ :error
116
+ else
117
+ status
118
+ end
119
+ @status = validate_status!(@status)
64
120
  @error = error
65
121
  @metadata = metadata.dup.freeze
66
122
  freeze
@@ -69,6 +125,15 @@ module Ask
69
125
  # @return [Boolean] true if status is :success
70
126
  def success? = @status == :success
71
127
 
128
+ # @return [Boolean] true if the result is a success (tool API)
129
+ def ok? = @status == :success
130
+
131
+ # @return [Boolean] true if the result is pending (async tool running)
132
+ def pending? = @status == :pending
133
+
134
+ # @return [Boolean] true if the result is a success (tool API)
135
+ def ok = @status == :success
136
+
72
137
  # @return [Boolean] true if status is :error
73
138
  def error? = @status == :error
74
139
 
@@ -78,7 +143,13 @@ module Ask
78
143
  # @return [Boolean] true if status is :blocked
79
144
  def blocked? = @status == :blocked
80
145
 
81
- # @return [String] the content as a string
146
+ # @return [Object, nil] the output data when successful, nil otherwise (tool API)
147
+ def output = @status == :success ? @content : nil
148
+
149
+ # @return [Object, nil] the error message or underlying error object
150
+ def error_message = @error
151
+
152
+ # @return [String] the content as a string (for failures, the message)
82
153
  def to_s
83
154
  @content.to_s
84
155
  end
@@ -86,16 +157,20 @@ module Ask
86
157
  # @return [Hash] serialized representation
87
158
  def to_h
88
159
  {
89
- content: @content,
90
- status: @status,
160
+ ok: @status == :success,
161
+ output: @status == :success ? @content : nil,
91
162
  error: @error,
92
163
  metadata: @metadata
93
- }.compact
164
+ }
94
165
  end
95
166
 
96
167
  # @return [String] human-readable representation
97
168
  def inspect
98
- "#<Ask::Result status=#{@status.inspect} content=#{@content.inspect}>"
169
+ if @status == :success
170
+ "#<Ask::Result ok=true output=#{@content.inspect}>"
171
+ else
172
+ "#<Ask::Result ok=false error=#{@error.inspect} status=#{@status.inspect}>"
173
+ end
99
174
  end
100
175
 
101
176
  private
data/lib/ask/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ask
4
- VERSION = "0.8.0"
4
+ VERSION = "0.10.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ask-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kaka Ruto