phronomy 0.7.1 → 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 +4 -4
- data/README.md +35 -45
- data/benchmark/baseline.json +1 -1
- data/benchmark/bench_agent_invoke.rb +1 -1
- data/benchmark/bench_context_assembler.rb +11 -3
- data/benchmark/bench_regression.rb +11 -11
- data/benchmark/bench_token_estimator.rb +5 -5
- data/benchmark/bench_tool_schema.rb +2 -2
- data/docs/decisions/011-build-context-as-single-llm-input-authority.md +224 -0
- data/lib/phronomy/agent/base.rb +268 -403
- data/lib/phronomy/agent/checkpoint.rb +118 -0
- data/lib/phronomy/agent/concerns/suspendable.rb +6 -6
- data/lib/phronomy/agent/context/capability/base.rb +689 -0
- data/lib/phronomy/agent/context/capability/scope_policy.rb +54 -0
- data/lib/phronomy/agent/context/instruction/prompt_template.rb +102 -0
- data/lib/phronomy/agent/context/knowledge/base.rb +58 -0
- data/lib/phronomy/agent/context/knowledge/entity_knowledge.rb +102 -0
- data/lib/phronomy/agent/context/knowledge/static_knowledge.rb +58 -0
- data/lib/phronomy/agent/fsm.rb +1 -1
- data/lib/phronomy/agent/invocation_pipeline.rb +108 -0
- data/lib/phronomy/agent/lifecycle/fsm_session.rb +251 -0
- data/lib/phronomy/agent/lifecycle/phase_machine_builder.rb +249 -0
- data/lib/phronomy/agent/react_agent.rb +43 -37
- data/lib/phronomy/agent/runner.rb +2 -2
- data/lib/phronomy/agent/shared_state.rb +2 -2
- data/lib/phronomy/agent/tool_executor.rb +108 -0
- data/lib/phronomy/concurrency/async_queue.rb +157 -0
- data/lib/phronomy/concurrency/blocking_adapter_pool.rb +443 -0
- data/lib/phronomy/concurrency/cancellation_scope.rb +125 -0
- data/lib/phronomy/concurrency/cancellation_token.rb +140 -0
- data/lib/phronomy/concurrency/concurrency_gate.rb +157 -0
- data/lib/phronomy/concurrency/deadline.rb +65 -0
- data/lib/phronomy/{runtime → concurrency}/gate_registry.rb +1 -2
- data/lib/phronomy/{runtime → concurrency}/pool_registry.rb +1 -1
- data/lib/phronomy/configuration.rb +0 -6
- data/lib/phronomy/context.rb +2 -8
- data/lib/phronomy/eval/runner.rb +4 -0
- data/lib/phronomy/eval/scorer/llm_judge.rb +12 -1
- data/lib/phronomy/event_loop.rb +7 -7
- data/lib/phronomy/invocation_context.rb +3 -3
- data/lib/phronomy/knowledge_source.rb +0 -5
- data/lib/phronomy/llm_adapter/ruby_llm.rb +17 -11
- data/lib/phronomy/llm_context_window/assembler.rb +191 -0
- data/lib/phronomy/{context → llm_context_window}/context_version_cache.rb +1 -1
- data/lib/phronomy/{context → llm_context_window}/token_budget.rb +7 -4
- data/lib/phronomy/{context → llm_context_window}/token_estimator.rb +3 -3
- data/lib/phronomy/{agent → multi_agent}/handoff.rb +6 -6
- data/lib/phronomy/{agent → multi_agent}/orchestrator.rb +7 -7
- data/lib/phronomy/{agent → multi_agent}/parallel_tool_chat.rb +4 -4
- data/lib/phronomy/{agent → multi_agent}/team_coordinator.rb +4 -4
- data/lib/phronomy/runtime/runtime_metrics.rb +0 -1
- data/lib/phronomy/runtime.rb +20 -6
- data/lib/phronomy/task_group.rb +1 -1
- data/lib/phronomy/tool.rb +3 -4
- data/lib/phronomy/{tool/agent_tool.rb → tools/agent.rb} +6 -6
- data/lib/phronomy/{tool/mcp_tool.rb → tools/mcp.rb} +9 -9
- data/lib/phronomy/tools/vector_search.rb +70 -0
- data/lib/phronomy/tracing/null_tracer.rb +3 -1
- data/lib/phronomy/vector_store/async_backend.rb +4 -4
- data/lib/phronomy/vector_store/base.rb +2 -2
- data/lib/phronomy/vector_store/embeddings/base.rb +41 -0
- data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +47 -0
- data/lib/phronomy/vector_store/in_memory.rb +12 -2
- data/lib/phronomy/vector_store/loader/base.rb +27 -0
- data/lib/phronomy/vector_store/loader/csv_loader.rb +58 -0
- data/lib/phronomy/vector_store/loader/markdown_loader.rb +78 -0
- data/lib/phronomy/vector_store/loader/plain_text_loader.rb +24 -0
- data/lib/phronomy/vector_store/pgvector.rb +2 -2
- data/lib/phronomy/vector_store/redis_search.rb +2 -2
- data/lib/phronomy/vector_store/splitter/base.rb +49 -0
- data/lib/phronomy/vector_store/splitter/fixed_size_splitter.rb +53 -0
- data/lib/phronomy/vector_store/splitter/recursive_splitter.rb +107 -0
- data/lib/phronomy/vector_store.rb +14 -2
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy/workflow_context.rb +8 -0
- data/lib/phronomy/workflow_runner.rb +11 -131
- data/lib/phronomy.rb +2 -0
- data/scripts/api_snapshot.rb +11 -9
- metadata +44 -46
- data/lib/phronomy/async_queue.rb +0 -155
- data/lib/phronomy/blocking_adapter_pool.rb +0 -435
- data/lib/phronomy/cancellation_scope.rb +0 -123
- data/lib/phronomy/cancellation_token.rb +0 -133
- data/lib/phronomy/concurrency_gate.rb +0 -155
- data/lib/phronomy/context/assembler.rb +0 -143
- data/lib/phronomy/context/compaction_context.rb +0 -111
- data/lib/phronomy/context/trigger_context.rb +0 -39
- data/lib/phronomy/context/trim_context.rb +0 -75
- data/lib/phronomy/deadline.rb +0 -63
- data/lib/phronomy/embeddings/base.rb +0 -39
- data/lib/phronomy/embeddings/ruby_llm_embeddings.rb +0 -45
- data/lib/phronomy/embeddings.rb +0 -11
- data/lib/phronomy/fsm_session.rb +0 -247
- data/lib/phronomy/knowledge_source/base.rb +0 -54
- data/lib/phronomy/knowledge_source/entity_knowledge.rb +0 -96
- data/lib/phronomy/knowledge_source/rag_knowledge.rb +0 -57
- data/lib/phronomy/knowledge_source/static_knowledge.rb +0 -52
- data/lib/phronomy/loader/base.rb +0 -25
- data/lib/phronomy/loader/csv_loader.rb +0 -56
- data/lib/phronomy/loader/markdown_loader.rb +0 -76
- data/lib/phronomy/loader/plain_text_loader.rb +0 -22
- data/lib/phronomy/loader.rb +0 -13
- data/lib/phronomy/prompt_template.rb +0 -96
- data/lib/phronomy/splitter/base.rb +0 -47
- data/lib/phronomy/splitter/fixed_size_splitter.rb +0 -51
- data/lib/phronomy/splitter/recursive_splitter.rb +0 -105
- data/lib/phronomy/splitter.rb +0 -12
- data/lib/phronomy/tool/base.rb +0 -644
- data/lib/phronomy/tool/scope_policy.rb +0 -50
- data/lib/phronomy/tool_executor.rb +0 -106
|
@@ -56,6 +56,124 @@ module Phronomy
|
|
|
56
56
|
@pending_tool_args = pending_tool_args
|
|
57
57
|
@pending_tool_call_id = pending_tool_call_id
|
|
58
58
|
end
|
|
59
|
+
|
|
60
|
+
# Converts this checkpoint to a plain Hash suitable for JSON / Marshal serialization.
|
|
61
|
+
#
|
|
62
|
+
# All values are plain Ruby objects (String, Symbol, Hash, Array, Numeric,
|
|
63
|
+
# nil). +RubyLLM::Message+ objects in +:messages+ are deep-converted so that
|
|
64
|
+
# any embedded +RubyLLM::ToolCall+ objects are also serialized as plain hashes.
|
|
65
|
+
#
|
|
66
|
+
# @example Round-trip via JSON
|
|
67
|
+
# json = JSON.generate(checkpoint.to_h)
|
|
68
|
+
# checkpoint2 = Phronomy::Agent::Checkpoint.from_h(JSON.parse(json))
|
|
69
|
+
#
|
|
70
|
+
# @return [Hash]
|
|
71
|
+
# @api public
|
|
72
|
+
def to_h
|
|
73
|
+
{
|
|
74
|
+
thread_id: @thread_id,
|
|
75
|
+
original_input: @original_input,
|
|
76
|
+
messages: @messages.map { |m| serialize_message(m) },
|
|
77
|
+
pending_tool_name: @pending_tool_name,
|
|
78
|
+
pending_tool_args: @pending_tool_args,
|
|
79
|
+
pending_tool_call_id: @pending_tool_call_id
|
|
80
|
+
}
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Reconstructs a +Checkpoint+ from a plain Hash (e.g. produced by {#to_h}
|
|
84
|
+
# and deserialized from JSON or Marshal).
|
|
85
|
+
#
|
|
86
|
+
# Hash keys may be either Symbols or Strings; both are accepted.
|
|
87
|
+
# +RubyLLM::ToolCall+ objects inside message +:tool_calls+ arrays are
|
|
88
|
+
# reconstructed from their hash representations.
|
|
89
|
+
#
|
|
90
|
+
# @param h [Hash] a hash previously produced by {#to_h}
|
|
91
|
+
# @return [Checkpoint]
|
|
92
|
+
# @api public
|
|
93
|
+
def self.from_h(h)
|
|
94
|
+
h = h.transform_keys { |k|
|
|
95
|
+
begin
|
|
96
|
+
k.to_sym
|
|
97
|
+
rescue
|
|
98
|
+
k
|
|
99
|
+
end
|
|
100
|
+
}
|
|
101
|
+
messages = Array(h[:messages]).map { |m| deserialize_message(m) }
|
|
102
|
+
new(
|
|
103
|
+
thread_id: h[:thread_id],
|
|
104
|
+
original_input: h[:original_input],
|
|
105
|
+
messages: messages,
|
|
106
|
+
pending_tool_name: h[:pending_tool_name]&.to_s,
|
|
107
|
+
pending_tool_args: h[:pending_tool_args] ? h[:pending_tool_args].transform_keys { |k|
|
|
108
|
+
begin
|
|
109
|
+
k.to_sym
|
|
110
|
+
rescue
|
|
111
|
+
k
|
|
112
|
+
end
|
|
113
|
+
} : {},
|
|
114
|
+
pending_tool_call_id: h[:pending_tool_call_id]&.to_s
|
|
115
|
+
)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
private
|
|
119
|
+
|
|
120
|
+
# Converts a +RubyLLM::Message+ to a plain Hash, ensuring that any
|
|
121
|
+
# embedded +RubyLLM::ToolCall+ objects in +:tool_calls+ are also converted.
|
|
122
|
+
#
|
|
123
|
+
# @param msg [RubyLLM::Message]
|
|
124
|
+
# @return [Hash]
|
|
125
|
+
# @api private
|
|
126
|
+
def serialize_message(msg)
|
|
127
|
+
h = msg.to_h
|
|
128
|
+
return h unless h[:tool_calls]
|
|
129
|
+
|
|
130
|
+
h.merge(tool_calls: h[:tool_calls].map { |tc|
|
|
131
|
+
tc.respond_to?(:to_h) ? tc.to_h : tc
|
|
132
|
+
})
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Reconstructs a +RubyLLM::Message+ from a plain Hash.
|
|
136
|
+
# +RubyLLM::ToolCall+ entries in +:tool_calls+ are re-instantiated.
|
|
137
|
+
#
|
|
138
|
+
# @param h [Hash]
|
|
139
|
+
# @return [RubyLLM::Message]
|
|
140
|
+
# @api private
|
|
141
|
+
def self.deserialize_message(h)
|
|
142
|
+
h = h.transform_keys { |k|
|
|
143
|
+
begin
|
|
144
|
+
k.to_sym
|
|
145
|
+
rescue
|
|
146
|
+
k
|
|
147
|
+
end
|
|
148
|
+
}
|
|
149
|
+
if h[:tool_calls]
|
|
150
|
+
h = h.merge(tool_calls: Array(h[:tool_calls]).map { |tc|
|
|
151
|
+
next tc if tc.is_a?(RubyLLM::ToolCall)
|
|
152
|
+
|
|
153
|
+
tc = tc.transform_keys { |k|
|
|
154
|
+
begin
|
|
155
|
+
k.to_sym
|
|
156
|
+
rescue
|
|
157
|
+
k
|
|
158
|
+
end
|
|
159
|
+
}
|
|
160
|
+
RubyLLM::ToolCall.new(
|
|
161
|
+
id: tc[:id].to_s,
|
|
162
|
+
name: tc[:name].to_s,
|
|
163
|
+
arguments: (tc[:arguments] || {}).transform_keys { |k|
|
|
164
|
+
begin
|
|
165
|
+
k.to_sym
|
|
166
|
+
rescue
|
|
167
|
+
k
|
|
168
|
+
end
|
|
169
|
+
},
|
|
170
|
+
thought_signature: tc[:thought_signature]
|
|
171
|
+
)
|
|
172
|
+
})
|
|
173
|
+
end
|
|
174
|
+
RubyLLM::Message.new(h)
|
|
175
|
+
end
|
|
176
|
+
private_class_method :deserialize_message
|
|
59
177
|
end
|
|
60
178
|
end
|
|
61
179
|
end
|
|
@@ -65,12 +65,12 @@ module Phronomy
|
|
|
65
65
|
# Build a fresh chat with all tools registered.
|
|
66
66
|
chat = build_chat
|
|
67
67
|
|
|
68
|
-
# Re-apply system instructions so the LLM has the
|
|
69
|
-
# as the original invocation.
|
|
70
|
-
#
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
# Re-apply system instructions and register tools so the LLM has the
|
|
69
|
+
# same persona/context as the original invocation. build_context
|
|
70
|
+
# includes all tool classes (static + handoff) via add_capability.
|
|
71
|
+
context = build_context(checkpoint.original_input, messages: [])
|
|
72
|
+
apply_instructions(chat, context[:system]) if context[:system]
|
|
73
|
+
(context[:tool_classes] || []).each { |tc| chat.with_tool(prepare_tool_class(tc)) }
|
|
74
74
|
|
|
75
75
|
# Restore the full conversation (history + user + assistant with tool call).
|
|
76
76
|
checkpoint.messages.each { |msg| chat.messages << msg }
|