phronomy 0.16.0 → 0.18.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 (123) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +8 -9
  3. data/CHANGELOG.md +151 -1134
  4. data/CONTRIBUTING.md +28 -16
  5. data/README.md +69 -1249
  6. data/benchmark/baseline.json +2 -3
  7. data/benchmark/bench_agent_invoke.rb +4 -4
  8. data/benchmark/bench_context_assembler.rb +134 -34
  9. data/benchmark/bench_regression.rb +26 -6
  10. data/benchmark/bench_tool_schema.rb +2 -35
  11. data/docs/changelog/0.14-and-earlier.md +1137 -0
  12. data/docs/decisions/005-static-knowledge-class-level-cache.md +12 -1
  13. data/docs/decisions/008-orchestrator-uses-os-threads.md +46 -48
  14. data/docs/decisions/010-cooperative-first-concurrency.md +155 -228
  15. data/docs/decisions/011-build-context-as-single-llm-input-authority.md +2 -2
  16. data/docs/decisions/013-journal-backed-knowledge-as-context-candidates.md +122 -0
  17. data/docs/features.md +87 -0
  18. data/docs/getting-started.md +351 -0
  19. data/docs/migrations/0.15.md +35 -0
  20. data/docs/migrations/0.16.md +43 -0
  21. data/docs/runtime-and-concurrency.md +258 -0
  22. data/examples/workflows/generic_task_event_mapping.rb +14 -6
  23. data/lib/phronomy/agent/agent_invocation.rb +2 -36
  24. data/lib/phronomy/agent/agent_invocation_session_builder.rb +157 -94
  25. data/lib/phronomy/agent/agent_root.rb +1 -2
  26. data/lib/phronomy/agent/async_event_api.rb +3 -3
  27. data/lib/phronomy/agent/base.rb +170 -333
  28. data/lib/phronomy/agent/context/capability/base.rb +177 -298
  29. data/lib/phronomy/agent/context_assembler.rb +65 -29
  30. data/lib/phronomy/agent/context_parts/unit_builders/dependency_aware_unit_builder.rb +19 -89
  31. data/lib/phronomy/agent/context_plan_validator.rb +0 -33
  32. data/lib/phronomy/agent/execution_coordinator.rb +6 -7
  33. data/lib/phronomy/agent/journal_projection.rb +28 -2
  34. data/lib/phronomy/agent/ruby_llm_materializer.rb +2 -111
  35. data/lib/phronomy/agent/shared_state.rb +48 -138
  36. data/lib/phronomy/agent/token_budget_resolver.rb +5 -4
  37. data/lib/phronomy/agent/tool_executor.rb +29 -71
  38. data/lib/phronomy/agent/tool_invocation.rb +180 -336
  39. data/lib/phronomy/agent/tool_invocation_session_builder.rb +55 -161
  40. data/lib/phronomy/agent.rb +6 -10
  41. data/lib/phronomy/configuration.rb +4 -171
  42. data/lib/phronomy/diagnostics.rb +12 -41
  43. data/lib/phronomy/engine/concurrency/async_queue.rb +5 -188
  44. data/lib/phronomy/engine/concurrency/cancellation_scope.rb +6 -7
  45. data/lib/phronomy/engine/concurrency/cancellation_token.rb +51 -79
  46. data/lib/phronomy/engine/concurrency/deadline.rb +2 -3
  47. data/lib/phronomy/engine/concurrency/offload_pool.rb +696 -0
  48. data/lib/phronomy/engine/concurrency/pool_registry.rb +5 -5
  49. data/lib/phronomy/engine/event_loop.rb +89 -190
  50. data/lib/phronomy/engine/runtime/timer_queue.rb +48 -71
  51. data/lib/phronomy/engine/runtime/timer_service.rb +13 -21
  52. data/lib/phronomy/engine/runtime.rb +49 -377
  53. data/lib/phronomy/engine/task.rb +136 -277
  54. data/lib/phronomy/llm_adapter/base.rb +14 -14
  55. data/lib/phronomy/llm_adapter/ruby_llm.rb +3 -4
  56. data/lib/phronomy/llm_adapter.rb +2 -2
  57. data/lib/phronomy/llm_context_window/token_budget.rb +8 -79
  58. data/lib/phronomy/metrics.rb +15 -30
  59. data/lib/phronomy/multi_agent/fan_out_invocation.rb +146 -0
  60. data/lib/phronomy/multi_agent/fan_out_session_builder.rb +125 -0
  61. data/lib/phronomy/multi_agent/handoff.rb +1 -0
  62. data/lib/phronomy/multi_agent/orchestrator.rb +252 -256
  63. data/lib/phronomy/multi_agent/team_coordinator.rb +44 -133
  64. data/lib/phronomy/testing/eval/comparison.rb +23 -0
  65. data/lib/phronomy/testing/eval/dataset.rb +27 -0
  66. data/lib/phronomy/testing/eval/eval_case.rb +13 -0
  67. data/lib/phronomy/testing/eval/eval_result.rb +16 -0
  68. data/lib/phronomy/testing/eval/metrics.rb +43 -0
  69. data/lib/phronomy/testing/eval/runner.rb +52 -0
  70. data/lib/phronomy/testing/eval/scorer/base.rb +15 -0
  71. data/lib/phronomy/testing/eval/scorer/exact_match.rb +25 -0
  72. data/lib/phronomy/testing/eval/scorer/includes_scorer.rb +25 -0
  73. data/lib/phronomy/testing/eval/scorer/llm_judge.rb +46 -0
  74. data/lib/phronomy/testing/eval/scorer.rb +10 -0
  75. data/lib/phronomy/testing/eval.rb +9 -0
  76. data/lib/phronomy/testing/fake_clock.rb +6 -53
  77. data/lib/phronomy/testing.rb +2 -6
  78. data/lib/phronomy/tools/agent.rb +141 -6
  79. data/lib/phronomy/vector_store/async_backend.rb +21 -17
  80. data/lib/phronomy/vector_store/base.rb +2 -2
  81. data/lib/phronomy/vector_store/embeddings/base.rb +6 -5
  82. data/lib/phronomy/vector_store/in_memory.rb +2 -2
  83. data/lib/phronomy/version.rb +1 -1
  84. data/lib/phronomy/workflow_runner.rb +2 -4
  85. data/lib/phronomy.rb +7 -121
  86. data/scripts/api_snapshot.rb +4 -15
  87. metadata +24 -38
  88. data/lib/phronomy/agent/context/knowledge/base.rb +0 -58
  89. data/lib/phronomy/agent/context/knowledge/entity_knowledge.rb +0 -102
  90. data/lib/phronomy/agent/context/knowledge/static_knowledge.rb +0 -58
  91. data/lib/phronomy/agent/fsm_runtime_adapter.rb +0 -210
  92. data/lib/phronomy/engine/concurrency/blocking_adapter_pool.rb +0 -561
  93. data/lib/phronomy/engine/runtime/deterministic_scheduler.rb +0 -439
  94. data/lib/phronomy/engine/runtime/fake_scheduler.rb +0 -165
  95. data/lib/phronomy/engine/runtime/runtime_metrics.rb +0 -116
  96. data/lib/phronomy/engine/runtime/scheduler.rb +0 -98
  97. data/lib/phronomy/engine/runtime/scheduler_timer_adapter.rb +0 -79
  98. data/lib/phronomy/engine/runtime/task_registry.rb +0 -95
  99. data/lib/phronomy/engine/runtime/thread_scheduler.rb +0 -30
  100. data/lib/phronomy/engine/task/backend.rb +0 -80
  101. data/lib/phronomy/engine/task/deferred_backend.rb +0 -73
  102. data/lib/phronomy/engine/task/fiber_backend.rb +0 -157
  103. data/lib/phronomy/engine/task/immediate_backend.rb +0 -89
  104. data/lib/phronomy/engine/task/mapped_backend.rb +0 -90
  105. data/lib/phronomy/engine/task/thread_backend.rb +0 -84
  106. data/lib/phronomy/engine/task_group.rb +0 -265
  107. data/lib/phronomy/eval/comparison.rb +0 -47
  108. data/lib/phronomy/eval/dataset.rb +0 -45
  109. data/lib/phronomy/eval/eval_case.rb +0 -17
  110. data/lib/phronomy/eval/eval_result.rb +0 -29
  111. data/lib/phronomy/eval/metrics.rb +0 -66
  112. data/lib/phronomy/eval/runner.rb +0 -94
  113. data/lib/phronomy/eval/scorer/base.rb +0 -22
  114. data/lib/phronomy/eval/scorer/exact_match.rb +0 -31
  115. data/lib/phronomy/eval/scorer/includes_scorer.rb +0 -32
  116. data/lib/phronomy/eval/scorer/llm_judge.rb +0 -72
  117. data/lib/phronomy/eval/scorer.rb +0 -9
  118. data/lib/phronomy/eval.rb +0 -7
  119. data/lib/phronomy/knowledge_source.rb +0 -12
  120. data/lib/phronomy/llm_context_window/assembler.rb +0 -191
  121. data/lib/phronomy/llm_context_window/context_version_cache.rb +0 -52
  122. data/lib/phronomy/testing/fake_scheduler.rb +0 -104
  123. data/lib/phronomy/testing/scheduler_helpers.rb +0 -68
@@ -4,6 +4,5 @@
4
4
  "tool_params_schema_definition": 19534379.159046534,
5
5
  "dispatch_parallel_10": 886.0,
6
6
  "cancellation_token_cancelled": 4335060.97443425,
7
- "cancellation_token_raise_if_cancelled_noop": 3566903.189098373,
8
- "trim_messages_2000": 2896552.0
9
- }
7
+ "cancellation_token_raise_if_cancelled_noop": 3566903.189098373
8
+ }
@@ -3,11 +3,11 @@
3
3
  # bench_agent_invoke.rb — Agent#invoke framework overhead benchmark.
4
4
  #
5
5
  # Measures the per-invoke cost of the Phronomy::Agent::Base framework path
6
- # (context assembly, guardrail checks, before_completion hooks, response
7
- # handling) with a fully stubbed LLM. No network calls are made.
6
+ # (context assembly, filter checks, before_llm_input hooks, response handling)
7
+ # with a fully stubbed LLM. No network calls are made.
8
8
  #
9
9
  # Scenarios:
10
- # 1. Minimal agent (no tools, no knowledge) — baseline framework overhead.
10
+ # 1. Minimal agent (no tools, no persistent Knowledge) — baseline framework overhead.
11
11
  # 2. Tool-aware agent with a registered stub Tool.
12
12
  # 3. Agent#stream setup latency (first-chunk time with stubbed stream).
13
13
 
@@ -81,7 +81,7 @@ end
81
81
  bench_tool_class = Class.new(Phronomy::Agent::Base) do
82
82
  agent_definition id: "bench-tool", version: 1
83
83
  model "stub-model"
84
- tools BenchNullTool
84
+ tools(BenchNullTool => nil)
85
85
 
86
86
  define_method(:build_chat) { |*| BenchStubChat.new(BENCH_RESP) }
87
87
  end
@@ -1,54 +1,154 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Benchmark: Context::Assembler#build
3
+ # Benchmark: Manifest-first Context assembly and Default Context Policy.
4
4
  #
5
- # Tests context assembly performance for varying numbers of messages and
6
- # knowledge chunks. This path is exercised on every agent turn.
5
+ # Usage:
6
+ # ruby benchmark/bench_context_assembler.rb
7
+ #
8
+ # Measures:
9
+ # 1. ContextPolicies::Default selection cost for growing canonical candidate sets.
10
+ # 2. ContextAssembler#build_initial end-to-end Manifest construction.
11
+ #
12
+ # No provider call is performed.
7
13
 
8
14
  require "benchmark"
9
15
  require_relative "../lib/phronomy"
10
16
 
11
- BenchAsmMessage = Struct.new(:content)
17
+ module BenchContextAssembler
18
+ module_function
12
19
 
13
- def make_assembler(n_messages:, n_chunks:, with_budget: false)
14
- budget = if with_budget
15
- Phronomy::LlmContextWindow::TokenBudget.new(context_window: 4096, max_output_tokens: 512)
16
- end
17
- asm = Phronomy::LlmContextWindow::Assembler.new(budget: budget)
18
- asm.add_instruction("You are a helpful assistant. Answer the user's question.")
19
- n_chunks.times do |i|
20
- asm.add_knowledge("Fact #{i}: The capital of country #{i} is City #{i}.", type: :entity, trusted: true)
20
+ def candidate(index)
21
+ category, role = if (index % 10).zero?
22
+ [:knowledge, :user]
23
+ elsif index.even?
24
+ [:assistant_message, :assistant]
25
+ else
26
+ [:external_message, :user]
27
+ end
28
+
29
+ Phronomy::Agent::ContextCandidate.new(
30
+ candidate_id: "candidate-#{index}",
31
+ source_kind: :journal,
32
+ category: category,
33
+ role: role,
34
+ content_ref: "content-#{index}",
35
+ record_id: "record-#{index}",
36
+ agent_id: "bench-agent",
37
+ execution_id: "execution-#{index / 4}",
38
+ llm_call_id: nil,
39
+ tool_call_id: nil,
40
+ sequence: index,
41
+ requirement: :optional,
42
+ priority: 0,
43
+ metadata: {
44
+ "estimated_tokens" => 8,
45
+ "source_sequence" => index
46
+ }
47
+ )
21
48
  end
22
- msgs = Array.new(n_messages) { BenchAsmMessage.new("This is a conversation message.") }
23
- asm.add_messages(msgs)
24
- asm
25
- end
26
49
 
27
- BENCH_ASM_ITERATIONS = 1_000
50
+ def parts
51
+ {
52
+ unit_builder:
53
+ Phronomy::Agent::ContextParts::UnitBuilders::DependencyAwareUnitBuilder.new,
54
+ required_context_resolver:
55
+ Phronomy::Agent::ContextParts::Requirements::RequiredContextResolver.new,
56
+ recent_first_selector:
57
+ Phronomy::Agent::ContextParts::Selectors::RecentFirstSelector.new,
58
+ token_budget_packer:
59
+ Phronomy::Agent::ContextParts::Budget::TokenBudgetPacker.new
60
+ }.freeze
61
+ end
28
62
 
29
- puts "=== bench_context_assembler ==="
30
- Benchmark.bm(40) do |x|
31
- x.report("build(10 msgs, 0 chunks)") do
32
- BENCH_ASM_ITERATIONS.times { make_assembler(n_messages: 10, n_chunks: 0).build }
63
+ def request(candidate_count)
64
+ candidates = Array.new(candidate_count) { |i| candidate(i) }
65
+ Phronomy::Agent::ContextRequest.new(
66
+ agent_id: "bench-agent",
67
+ execution_id: "bench-execution",
68
+ call_sequence: 2,
69
+ call_mode: :complete,
70
+ candidates: candidates,
71
+ token_budget: Phronomy::LlmContextWindow::TokenBudget.new(
72
+ context_window: [candidate_count * 16, 4_096].max,
73
+ max_output_tokens: 512
74
+ ),
75
+ model_config: {},
76
+ previous_manifest: nil,
77
+ required_coverage: [],
78
+ parts: parts,
79
+ metadata: {"mandatory_token_estimate" => 32}
80
+ )
33
81
  end
34
82
 
35
- x.report("build(100 msgs, 5 chunks)") do
36
- BENCH_ASM_ITERATIONS.times { make_assembler(n_messages: 100, n_chunks: 5).build }
83
+ def assembler_fixture
84
+ persistence = Phronomy::Persistence::InMemory.new
85
+ agent_class = Class.new(Phronomy::Agent::Base) do
86
+ agent_definition id: "bench-manifest-context-assembler", version: 1
87
+ model "local-model"
88
+ context_window 16_384
89
+ max_output_tokens 1_024
90
+ instructions "Benchmark instruction"
91
+ end
92
+ agent = agent_class.new(
93
+ persistence: persistence,
94
+ knowledge: ["Persistent benchmark knowledge"]
95
+ )
96
+ root = agent.agent_root
97
+ input_ref = persistence.contents.put_text("benchmark input")
98
+ input_record = Phronomy::Agent::JournalRecord.new(
99
+ agent_id: agent.agent_id,
100
+ kind: :external_message,
101
+ channel: :external,
102
+ role: :user,
103
+ content_ref: input_ref,
104
+ context_generation: root.transcript_generation,
105
+ context_candidate: true
106
+ )
107
+ execution = Phronomy::Agent::AgentExecution.start(
108
+ agent_root: root,
109
+ input_record: input_record,
110
+ metadata: {
111
+ "current_input_ref" => input_ref,
112
+ "current_input_record_id" => input_record.record_id
113
+ }
114
+ ).with(
115
+ execution_revision: 0,
116
+ working_records: [input_record]
117
+ )
118
+
119
+ [
120
+ Phronomy::Agent::ContextAssembler.new(agent: agent, persistence: persistence),
121
+ root,
122
+ execution
123
+ ]
37
124
  end
125
+ end
126
+
127
+ puts "Manifest-first Context benchmark"
128
+ puts "Ruby #{RUBY_VERSION} on #{RUBY_PLATFORM}"
129
+ puts "=" * 72
38
130
 
39
- x.report("build(1000 msgs, 10 chunks, no budget)") do
40
- (BENCH_ASM_ITERATIONS / 10).times { make_assembler(n_messages: 1000, n_chunks: 10).build }
131
+ policy = Phronomy::Agent::ContextPolicies::Default.new
132
+ policy_requests = [10, 100, 1_000].to_h do |count|
133
+ [count, BenchContextAssembler.request(count)]
134
+ end
135
+
136
+ Benchmark.bm(46) do |x|
137
+ policy_requests.each do |count, request|
138
+ iterations = (count >= 1_000) ? 200 : 1_000
139
+ x.report("DefaultContextPolicy #{count} candidates x#{iterations}") do
140
+ iterations.times { policy.call(request) }
141
+ end
41
142
  end
42
143
 
43
- x.report("build(1000 msgs, 10 chunks, budgeted)") do
44
- (BENCH_ASM_ITERATIONS / 10).times do
45
- # Assembler raises ContextLengthError when messages exceed the budget;
46
- # callers (e.g. Agent::Base#build_context) are expected to pre-trim via
47
- # trim_to_budget before calling build. The rescue here keeps the benchmark
48
- # measuring build's fast path without triggering the error path.
49
- make_assembler(n_messages: 1000, n_chunks: 10, with_budget: true).build
50
- rescue Phronomy::ContextLengthError
51
- # expected — budget exceeded
144
+ assembler, root, execution = BenchContextAssembler.assembler_fixture
145
+ x.report("ContextAssembler#build_initial x500") do
146
+ 500.times do
147
+ assembler.build_initial(
148
+ input: "benchmark input",
149
+ agent_root: root,
150
+ execution: execution
151
+ )
52
152
  end
53
153
  end
54
154
  end
@@ -2,12 +2,19 @@
2
2
 
3
3
  # bench_regression.rb — Targeted regression benchmarks.
4
4
  #
5
- # Measures the five minimum regression targets defined in Issue #232:
5
+ # Measures the six minimum regression targets:
6
6
  # 1. WorkflowContext#merge throughput
7
7
  # 2. Workflow.define (graph build) time
8
8
  # 3. Tool::Base#params_schema generation (10 params)
9
9
  # 4. Orchestrator#dispatch_parallel overhead (10 stub agents, no LLM)
10
- # 5. CancellationToken#cancelled? throughput (shared token, 8 threads)
10
+ # 5. CancellationToken#cancelled? throughput under deliberate Thread contention
11
+ # 6. CancellationToken#raise_if_cancelled! hot path
12
+ #
13
+ # Target 4 deliberately uses thread-free completion handles so the benchmark
14
+ # measures EventLoop/FanOut coordination rather than fake per-child Thread.new
15
+ # overhead. Target 5 intentionally uses Threads because cross-thread token access
16
+ # is the behavior being measured there; it is not a Phronomy runtime execution
17
+ # path.
11
18
  #
12
19
  # Results are stored in a global REGRESSION_RESULTS hash (keyed by metric name,
13
20
  # value = iterations per second) for use by run_all.rb baseline comparison.
@@ -89,10 +96,20 @@ end
89
96
  # ---------------------------------------------------------------------------
90
97
  stub_agent_class = Class.new(Phronomy::Agent::Base) do
91
98
  agent_definition id: "bench-stub", version: 1
92
- define_method(:invoke) do |_input, messages: [], thread_id: nil, config: {}|
99
+
100
+ define_method(:invoke) do |_input, thread_id: nil, config: {}|
93
101
  {output: "stub", messages: []}
94
102
  end
95
- define_method(:invoke_async) { |input, **_kw| Phronomy::Runtime.instance.spawn(name: "bench-stub") { invoke(input) } }
103
+
104
+ define_method(:invoke_async) do |input, **_kw|
105
+ task = Phronomy::Task.deferred(name: "bench-stub")
106
+ begin
107
+ task.complete(invoke(input))
108
+ rescue => error
109
+ task.fail(error)
110
+ end
111
+ task
112
+ end
96
113
  end
97
114
 
98
115
  orchestrator_class = Class.new(Phronomy::MultiAgent::Orchestrator)
@@ -108,8 +125,11 @@ t4 = Benchmark.measure("Orchestrator#dispatch_parallel (10 agents)") do
108
125
  end
109
126
 
110
127
  # ---------------------------------------------------------------------------
111
- # Target 5: CancellationToken#cancelled? throughput (8 threads)
128
+ # Target 5: CancellationToken#cancelled? throughput (8 application Threads)
112
129
  # ---------------------------------------------------------------------------
130
+ # Threads are intentional here: the benchmark specifically measures concurrent
131
+ # access to one shared CancellationToken. They are not used to execute Phronomy
132
+ # Agent/Workflow/Tool lifecycle work.
113
133
  CANCEL_TOKEN = Phronomy::Concurrency::CancellationToken.new
114
134
  CANCEL_ITERATIONS = 10_000
115
135
 
@@ -123,7 +143,7 @@ end
123
143
  # ---------------------------------------------------------------------------
124
144
  # Target 6: CancellationToken#raise_if_cancelled! hot path (no-op, single thread)
125
145
  # ---------------------------------------------------------------------------
126
- RAISE_TOKEN = Phronomy::Concurrency::CancellationToken.new # not cancelled — no-op path
146
+ RAISE_TOKEN = Phronomy::Concurrency::CancellationToken.new # not cancelled — no-op path
127
147
  RAISE_ITERATIONS = 200_000
128
148
 
129
149
  t6 = Benchmark.measure("CancellationToken#raise_if_cancelled! (no-op)") do
@@ -1,16 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Benchmark: Tool::Base params_schema generation and static_knowledge_chunks cache
3
+ # Benchmark: Tool::Base params_schema generation.
4
4
  #
5
- # Tool schema generation happens once per tool class (lazily memoised).
6
- # static_knowledge_chunks is cached at the class level; cache-hit overhead
7
- # should be negligible compared to cache-miss (which calls the knowledge source).
5
+ # Tool schema generation happens once per tool class and is lazily memoized.
8
6
 
9
7
  require "benchmark"
10
8
  require_relative "../lib/phronomy"
11
9
 
12
- # --- Tool schema ---
13
-
14
10
  class BenchTool10Params < Phronomy::Agent::Context::Capability::Base
15
11
  description "A tool with 10 parameters for benchmarking purposes"
16
12
  param :param1, type: :string, desc: "First parameter"
@@ -29,7 +25,6 @@ class BenchTool10Params < Phronomy::Agent::Context::Capability::Base
29
25
  end
30
26
  end
31
27
 
32
- # Warm up memoisation
33
28
  BenchTool10Params.params_schema_definition
34
29
 
35
30
  BENCH_TOOL_ITERATIONS = 50_000
@@ -40,31 +35,3 @@ Benchmark.bm(35) do |x|
40
35
  BENCH_TOOL_ITERATIONS.times { BenchTool10Params.params_schema_definition }
41
36
  end
42
37
  end
43
-
44
- # --- static_knowledge_chunks cache ---
45
-
46
- class BenchKnowledgeSource < Phronomy::Agent::Context::Knowledge::Base
47
- def fetch(query: nil)
48
- [{content: "Cached knowledge fact.", type: :static}]
49
- end
50
-
51
- def static?
52
- true
53
- end
54
- end
55
-
56
- class BenchAgentWithKnowledge < Phronomy::Agent::Base
57
- agent_definition id: "bench-knowledge", version: 1
58
- model "gpt-4o-mini"
59
- static_knowledge BenchKnowledgeSource.new
60
- end
61
-
62
- # Warm up cache
63
- BenchAgentWithKnowledge.static_knowledge_chunks
64
-
65
- puts "\n=== bench_static_knowledge_cache ==="
66
- Benchmark.bm(35) do |x|
67
- x.report("static_knowledge_chunks (hit)") do
68
- BENCH_TOOL_ITERATIONS.times { BenchAgentWithKnowledge.static_knowledge_chunks }
69
- end
70
- end