ask-agent 0.8.0 → 0.9.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: f95edab12d96da68593e426829ac2507682b4b5620b5ec0b09269062bf168bd9
4
- data.tar.gz: 7353fff33dba2ebff749df32d4c079759f1f4b2eca9193a5299fe9ec7238966c
3
+ metadata.gz: 82d7ec2cb06f4ce9cbaa41ece0ac4800772b44dcbe54c33e46f6edefb863f1b2
4
+ data.tar.gz: b8b5cfec092ae7b0117f0a4ec3b441becc0ea21c806107cb0ae9c51c5b215618
5
5
  SHA512:
6
- metadata.gz: 3e3dc6f6cae44b0c2f36e12c9253b3f21e97a17634907754cc1d2ea8930bd8bcc54b2f65ef2194dae9e1e60d4a721d8071a677f3f0bbfa0d99d68515c0da82b9
7
- data.tar.gz: ab443967abf274b113b9ebd8f2901feffa1cf2d7e1436e6a14df8d1dbb87fa1f204d0cb97d2d567858e89631c0b08ed97bf4183174c6ffce97aee363ffa0f724
6
+ metadata.gz: d9a3dd55f214105d58858f31122a0064a9a94165f37d5b8fc8d1f202ce87fe19ff8ad4f0c6e52de1d66bf115940e3c48e8673762d16912514668b82cabd8daa3
7
+ data.tar.gz: ecaecabad77df46494a9ee0f99840cbeeaf59163cecaf1ccb8af8810e98bfa8333455c1ed3b50d1bc66c106c38e74b98329d28fea3d2e4393cacdd9453213c23
data/CHANGELOG.md CHANGED
@@ -1,3 +1,38 @@
1
+ ## [0.9.0] — 2026-07-21
2
+
3
+ ### Added
4
+
5
+ - **Prompt caching support** — `prompt_caching` option enables provider-native prompt caching for significant cost savings on repeated conversation prefixes. Works with both Anthropic and OpenAI.
6
+
7
+ ```ruby
8
+ # Global config
9
+ Ask::Agent.configure do |c|
10
+ c.prompt_caching = true
11
+ end
12
+
13
+ # Or per-session
14
+ session = Ask::Agent::Session.new(model: "claude-sonnet-4", prompt_caching: true)
15
+ ```
16
+
17
+ **Anthropic**: Caches the system prompt and the last user message content. The provider automatically returns cached reads instead of processing the full context on repeated calls. Response metadata includes `cache_creation_input_tokens` and `cache_read_input_tokens`.
18
+
19
+ **OpenAI**: Caching is automatic for prompts exceeding 1024 tokens. Response metadata includes `cached_tokens` from `usage.prompt_tokens_details.cached_tokens`.
20
+
21
+ - **Prompt caching capability** — Both `Ask::Providers::Anthropic` and `Ask::Providers::OpenAI` now advertise `prompt_caching: true` in their capabilities.
22
+
23
+ ## [0.8.1] — 2026-07-21
24
+
25
+ ### Added
26
+
27
+ - **Per-agent skills via `agent_dir:`** — `Session` now accepts `agent_dir:` parameter. When set, `Ask::Skills.discover(agent_dir:)` discovers skills scoped to that agent directory, loading them alongside shared skills.
28
+
29
+ - **Agent definitions pass `agent_dir` automatically** — `Ask::Agent.new("name")` passes the agent's directory path to `Session`, enabling per-agent skill discovery without any configuration.
30
+
31
+ ### Changed
32
+
33
+ - `Ask::Agent::Session#initialize` now accepts optional `agent_dir:` keyword.
34
+ - Skills discovery in Session uses `Ask::Skills.discover(agent_dir: @agent_dir)` instead of the plain `Ask::Skills.discover`, enabling the new per-agent and shared skills paths from ask-skills 0.3.0.
35
+
1
36
  ## [0.8.0] — 2026-07-21
2
37
 
3
38
  ### Added
@@ -33,7 +33,7 @@ module Ask
33
33
 
34
34
  attr_writer :test_provider
35
35
 
36
- def initialize(model:, tools: [], temperature: nil, schema: nil, provider: nil, **)
36
+ def initialize(model:, tools: [], temperature: nil, schema: nil, provider: nil, prompt_caching: nil, **)
37
37
  @model_id = model.respond_to?(:id) ? model.id : model.to_s
38
38
  @model_info = Ask::ModelCatalog.find(@model_id)
39
39
  @tools = tools
@@ -43,10 +43,11 @@ module Ask
43
43
  @provider_override = provider
44
44
  @provider = nil
45
45
 
46
- # Read configured middleware and stream transforms from global config
46
+ # Read configured middleware, transforms, and caching from global config
47
47
  config = Ask::Agent.configuration
48
48
  @middleware_pipeline = config.middleware.configured? ? config.middleware : nil
49
49
  @transform_pipeline = config.stream_transforms.configured? ? config.stream_transforms : nil
50
+ @prompt_caching = prompt_caching.nil? ? config.prompt_caching : prompt_caching
50
51
  end
51
52
 
52
53
  def ask(message = nil, &block)
@@ -142,6 +143,9 @@ module Ask
142
143
  # Build the request hash for the provider call.
143
144
  # Middleware can mutate this hash to inject defaults, modify params, etc.
144
145
  def build_request(stream)
146
+ extra = (@extra_params || {}).dup
147
+ extra[:prompt_caching] = true if @prompt_caching
148
+
145
149
  {
146
150
  messages: @messages.map(&:to_h),
147
151
  model: @model_id,
@@ -149,7 +153,7 @@ module Ask
149
153
  temperature: @temperature,
150
154
  stream: stream,
151
155
  schema: @schema&.respond_to?(:to_json_schema) ? @schema.to_json_schema : @schema,
152
- extra_params: (@extra_params || {}).dup
156
+ extra_params: extra
153
157
  }
154
158
  end
155
159
 
@@ -4,7 +4,8 @@ module Ask
4
4
  module Agent
5
5
  class Configuration
6
6
  attr_accessor :default_model, :default_max_turns, :compactor_enabled,
7
- :compactor_threshold, :parallel_tool_execution, :max_tool_retries
7
+ :compactor_threshold, :parallel_tool_execution, :max_tool_retries,
8
+ :prompt_caching
8
9
 
9
10
  # @return [Middleware::Pipeline] the middleware pipeline for provider calls
10
11
  attr_reader :middleware
@@ -19,6 +20,7 @@ module Ask
19
20
  @compactor_threshold = 0.8
20
21
  @parallel_tool_execution = true
21
22
  @max_tool_retries = 3
23
+ @prompt_caching = false
22
24
 
23
25
  @middleware = Middleware::Pipeline.new
24
26
  @stream_transforms = StreamTransforms::Pipeline.new
@@ -20,8 +20,10 @@ module Ask
20
20
  def initialize(model:, tools: [], max_turns: 25, max_tool_retries: 3,
21
21
  compactor: nil, hooks: {}, persistence: nil,
22
22
  id: nil, system_prompt: nil, parallel_tools: true,
23
- reflector: nil, telemetry: true, meta_agent: nil, **chat_options)
23
+ reflector: nil, telemetry: true, meta_agent: nil,
24
+ agent_dir: nil, **chat_options)
24
25
  @id = id || SecureRandom.uuid
26
+ @agent_dir = agent_dir
25
27
  @max_turns = max_turns
26
28
  @max_tool_retries = max_tool_retries
27
29
  @parallel_tools = parallel_tools
@@ -46,8 +48,8 @@ module Ask
46
48
  @compactor = compactor ? build_compactor(compactor) : nil
47
49
  @hooks = Hooks.new(hooks)
48
50
 
49
- # Auto-discover skills and inject into system prompt
50
- @skills_registry = Ask::Skills.discover rescue nil
51
+ # Auto-discover skills (shared + per-agent if agent_dir is given)
52
+ @skills_registry = Ask::Skills.discover(agent_dir: @agent_dir) rescue nil
51
53
  if @skills_registry && !@skills_registry.names.empty?
52
54
  skill_text = @skills_registry.format_for_prompt
53
55
  if !skill_text.empty? && @chat.messages.any? { |m| m.role == :system }
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ask
4
4
  module Agent
5
- VERSION = "0.8.0"
5
+ VERSION = "0.9.0"
6
6
  end
7
7
  end
data/lib/ask/agent.rb CHANGED
@@ -145,6 +145,9 @@ module Ask
145
145
  config = klass._config
146
146
  session_opts = { model: config[:model] || Ask::Agent.configuration.default_model }
147
147
 
148
+ # Pass agent directory for per-agent skills discovery
149
+ session_opts[:agent_dir] = dir
150
+
148
151
  # Resolve tools
149
152
  tools = resolve_definition_tools(config[:tools], dir)
150
153
  session_opts[:tools] = tools if tools.any?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ask-agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kaka Ruto