mojentic 0.8.4__py3-none-any.whl → 1.0.0__py3-none-any.whl
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.
- _examples/async_dispatcher_example.py +12 -4
- _examples/async_llm_example.py +1 -2
- _examples/broker_as_tool.py +42 -17
- _examples/broker_examples.py +5 -7
- _examples/broker_image_examples.py +1 -1
- _examples/characterize_ollama.py +3 -3
- _examples/characterize_openai.py +1 -1
- _examples/chat_session.py +2 -2
- _examples/chat_session_with_tool.py +2 -2
- _examples/coding_file_tool.py +16 -18
- _examples/current_datetime_tool_example.py +2 -2
- _examples/embeddings.py +1 -1
- _examples/ephemeral_task_manager_example.py +15 -11
- _examples/fetch_openai_models.py +10 -3
- _examples/file_deduplication.py +6 -6
- _examples/file_tool.py +5 -5
- _examples/image_analysis.py +2 -3
- _examples/image_broker.py +1 -1
- _examples/image_broker_splat.py +1 -1
- _examples/iterative_solver.py +3 -3
- _examples/model_characterization.py +2 -0
- _examples/openai_gateway_enhanced_demo.py +15 -5
- _examples/raw.py +1 -1
- _examples/react/agents/decisioning_agent.py +173 -15
- _examples/react/agents/summarization_agent.py +89 -0
- _examples/react/agents/thinking_agent.py +84 -14
- _examples/react/agents/tool_call_agent.py +83 -0
- _examples/react/formatters.py +38 -4
- _examples/react/models/base.py +60 -11
- _examples/react/models/events.py +76 -8
- _examples/react.py +71 -21
- _examples/recursive_agent.py +2 -2
- _examples/simple_llm.py +3 -3
- _examples/simple_llm_repl.py +1 -1
- _examples/simple_structured.py +1 -1
- _examples/simple_tool.py +2 -2
- _examples/solver_chat_session.py +5 -11
- _examples/streaming.py +36 -18
- _examples/tell_user_example.py +4 -4
- _examples/tracer_demo.py +18 -20
- _examples/tracer_qt_viewer.py +49 -46
- _examples/working_memory.py +1 -1
- mojentic/__init__.py +3 -3
- mojentic/agents/__init__.py +26 -8
- mojentic/agents/{agent_broker.py → agent_event_adapter.py} +3 -3
- mojentic/agents/async_aggregator_agent_spec.py +32 -33
- mojentic/agents/async_llm_agent.py +9 -5
- mojentic/agents/async_llm_agent_spec.py +21 -22
- mojentic/agents/base_async_agent.py +2 -2
- mojentic/agents/base_llm_agent.py +6 -2
- mojentic/agents/iterative_problem_solver.py +11 -5
- mojentic/agents/simple_recursive_agent.py +11 -10
- mojentic/agents/simple_recursive_agent_spec.py +423 -0
- mojentic/async_dispatcher.py +0 -1
- mojentic/async_dispatcher_spec.py +1 -1
- mojentic/context/__init__.py +0 -2
- mojentic/dispatcher.py +7 -8
- mojentic/llm/__init__.py +5 -5
- mojentic/llm/gateways/__init__.py +19 -18
- mojentic/llm/gateways/anthropic.py +1 -0
- mojentic/llm/gateways/anthropic_messages_adapter.py +0 -1
- mojentic/llm/gateways/llm_gateway.py +1 -1
- mojentic/llm/gateways/ollama.py +23 -18
- mojentic/llm/gateways/openai.py +243 -44
- mojentic/llm/gateways/openai_message_adapter_spec.py +3 -3
- mojentic/llm/gateways/openai_model_registry.py +7 -6
- mojentic/llm/gateways/openai_model_registry_spec.py +1 -2
- mojentic/llm/gateways/openai_temperature_handling_spec.py +2 -2
- mojentic/llm/llm_broker.py +162 -2
- mojentic/llm/llm_broker_spec.py +76 -2
- mojentic/llm/message_composers.py +6 -3
- mojentic/llm/message_composers_spec.py +5 -1
- mojentic/llm/registry/__init__.py +0 -3
- mojentic/llm/registry/populate_registry_from_ollama.py +2 -2
- mojentic/llm/tools/__init__.py +0 -9
- mojentic/llm/tools/ask_user_tool.py +11 -5
- mojentic/llm/tools/current_datetime.py +9 -6
- mojentic/llm/tools/date_resolver.py +10 -4
- mojentic/llm/tools/date_resolver_spec.py +0 -1
- mojentic/llm/tools/ephemeral_task_manager/append_task_tool.py +4 -1
- mojentic/llm/tools/ephemeral_task_manager/ephemeral_task_list.py +1 -1
- mojentic/llm/tools/ephemeral_task_manager/insert_task_after_tool.py +4 -1
- mojentic/llm/tools/ephemeral_task_manager/prepend_task_tool.py +5 -2
- mojentic/llm/tools/file_manager.py +131 -28
- mojentic/llm/tools/file_manager_spec.py +0 -3
- mojentic/llm/tools/llm_tool.py +1 -1
- mojentic/llm/tools/llm_tool_spec.py +0 -2
- mojentic/llm/tools/organic_web_search.py +4 -2
- mojentic/llm/tools/tell_user_tool.py +6 -2
- mojentic/llm/tools/tool_wrapper.py +2 -2
- mojentic/tracer/__init__.py +1 -10
- mojentic/tracer/event_store.py +7 -8
- mojentic/tracer/event_store_spec.py +1 -2
- mojentic/tracer/null_tracer.py +37 -43
- mojentic/tracer/tracer_events.py +8 -2
- mojentic/tracer/tracer_events_spec.py +6 -7
- mojentic/tracer/tracer_system.py +37 -36
- mojentic/tracer/tracer_system_spec.py +21 -6
- mojentic/utils/__init__.py +1 -1
- mojentic/utils/formatting.py +1 -0
- {mojentic-0.8.4.dist-info → mojentic-1.0.0.dist-info}/METADATA +76 -27
- mojentic-1.0.0.dist-info/RECORD +149 -0
- mojentic-0.8.4.dist-info/RECORD +0 -146
- {mojentic-0.8.4.dist-info → mojentic-1.0.0.dist-info}/WHEEL +0 -0
- {mojentic-0.8.4.dist-info → mojentic-1.0.0.dist-info}/licenses/LICENSE.md +0 -0
- {mojentic-0.8.4.dist-info → mojentic-1.0.0.dist-info}/top_level.txt +0 -0
_examples/react/models/base.py
CHANGED
|
@@ -1,29 +1,78 @@
|
|
|
1
|
+
"""Base data models for the ReAct pattern.
|
|
2
|
+
|
|
3
|
+
This module defines the core data structures used throughout the ReAct
|
|
4
|
+
implementation, including actions, plans, observations, and context.
|
|
5
|
+
"""
|
|
1
6
|
from enum import Enum
|
|
2
7
|
from typing import List
|
|
3
8
|
|
|
4
|
-
from pydantic import
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
5
10
|
|
|
6
11
|
|
|
7
12
|
class NextAction(str, Enum):
|
|
13
|
+
"""Enumeration of possible next actions in the ReAct loop."""
|
|
14
|
+
|
|
8
15
|
PLAN = "PLAN"
|
|
9
16
|
ACT = "ACT"
|
|
10
17
|
FINISH = "FINISH"
|
|
11
18
|
|
|
12
19
|
|
|
13
20
|
class ThoughtActionObservation(BaseModel):
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
21
|
+
"""A single step in the ReAct loop capturing thought, action, and observation.
|
|
22
|
+
|
|
23
|
+
This model represents one iteration of the ReAct pattern where the agent:
|
|
24
|
+
1. Thinks about what to do
|
|
25
|
+
2. Takes an action
|
|
26
|
+
3. Observes the result
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
thought: str = Field(
|
|
30
|
+
...,
|
|
31
|
+
description="The thought process behind the action taken in the current context."
|
|
32
|
+
)
|
|
33
|
+
action: str = Field(
|
|
34
|
+
...,
|
|
35
|
+
description="The action taken in the current context."
|
|
36
|
+
)
|
|
37
|
+
observation: str = Field(
|
|
38
|
+
...,
|
|
39
|
+
description="The observation made after the action taken in the current context."
|
|
40
|
+
)
|
|
17
41
|
|
|
18
42
|
|
|
19
43
|
class Plan(BaseModel):
|
|
20
|
-
|
|
21
|
-
|
|
44
|
+
"""A structured plan for solving a user query.
|
|
45
|
+
|
|
46
|
+
Contains a list of steps that outline how to approach answering the query.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
steps: List[str] = Field(
|
|
50
|
+
[],
|
|
51
|
+
description="How to answer the query, step by step, each step outlining an action to take."
|
|
52
|
+
)
|
|
22
53
|
|
|
23
54
|
|
|
24
55
|
class CurrentContext(BaseModel):
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
56
|
+
"""The complete context for a ReAct session.
|
|
57
|
+
|
|
58
|
+
This model tracks everything needed to maintain state throughout the
|
|
59
|
+
reasoning and acting loop, including the user's query, the plan,
|
|
60
|
+
the history of actions, and the iteration count.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
user_query: str = Field(
|
|
64
|
+
...,
|
|
65
|
+
description="The user query to which we are responding."
|
|
66
|
+
)
|
|
67
|
+
plan: Plan = Field(
|
|
68
|
+
Plan(steps=[]),
|
|
69
|
+
description="The current plan of action for the current context."
|
|
70
|
+
)
|
|
71
|
+
history: List[ThoughtActionObservation] = Field(
|
|
72
|
+
[],
|
|
73
|
+
description="The history of actions taken and observations made in the current context."
|
|
74
|
+
)
|
|
75
|
+
iteration: int = Field(
|
|
76
|
+
0,
|
|
77
|
+
description="The number of iterations taken in the current context."
|
|
78
|
+
)
|
_examples/react/models/events.py
CHANGED
|
@@ -1,28 +1,96 @@
|
|
|
1
|
+
"""Event definitions for the ReAct pattern.
|
|
2
|
+
|
|
3
|
+
This module defines all event types used to coordinate the ReAct loop,
|
|
4
|
+
including thinking, decisioning, tool calls, completion, and failure events.
|
|
5
|
+
"""
|
|
1
6
|
from pydantic import Field
|
|
2
7
|
|
|
3
8
|
from mojentic import Event
|
|
9
|
+
|
|
4
10
|
from .base import CurrentContext, NextAction
|
|
5
11
|
|
|
6
12
|
|
|
7
13
|
class InvokeThinking(Event):
|
|
8
|
-
|
|
14
|
+
"""Event to trigger the thinking/planning phase.
|
|
15
|
+
|
|
16
|
+
This event initiates the planning process where the agent creates
|
|
17
|
+
or refines a plan for answering the user's query.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
context: CurrentContext = Field(
|
|
21
|
+
...,
|
|
22
|
+
description="The current context as we work through our response."
|
|
23
|
+
)
|
|
9
24
|
|
|
10
25
|
|
|
11
26
|
class InvokeDecisioning(Event):
|
|
12
|
-
|
|
27
|
+
"""Event to trigger the decision-making phase.
|
|
28
|
+
|
|
29
|
+
This event initiates the decision process where the agent evaluates
|
|
30
|
+
the current plan and history to decide on the next action.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
context: CurrentContext = Field(
|
|
34
|
+
...,
|
|
35
|
+
description="The current context as we work through our response."
|
|
36
|
+
)
|
|
13
37
|
|
|
14
38
|
|
|
15
39
|
class InvokeToolCall(Event):
|
|
16
|
-
|
|
17
|
-
|
|
40
|
+
"""Event to trigger a tool invocation.
|
|
41
|
+
|
|
42
|
+
This event carries the information needed to execute a specific tool
|
|
43
|
+
with given arguments, along with the reasoning behind the decision.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
context: CurrentContext = Field(
|
|
47
|
+
...,
|
|
48
|
+
description="The current context as we work through our response."
|
|
49
|
+
)
|
|
50
|
+
thought: str = Field(
|
|
51
|
+
...,
|
|
52
|
+
description="The reasoning behind the decision."
|
|
53
|
+
)
|
|
18
54
|
action: NextAction
|
|
55
|
+
tool: object = Field(
|
|
56
|
+
...,
|
|
57
|
+
description="The tool instance to invoke."
|
|
58
|
+
)
|
|
59
|
+
tool_arguments: dict = Field(
|
|
60
|
+
default_factory=dict,
|
|
61
|
+
description="Arguments to pass to the tool."
|
|
62
|
+
)
|
|
19
63
|
|
|
20
64
|
|
|
21
65
|
class FinishAndSummarize(Event):
|
|
22
|
-
|
|
23
|
-
|
|
66
|
+
"""Event to trigger the completion and summarization phase.
|
|
67
|
+
|
|
68
|
+
This event indicates that the agent has gathered sufficient information
|
|
69
|
+
to answer the user's query and should generate a final response.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
context: CurrentContext = Field(
|
|
73
|
+
...,
|
|
74
|
+
description="The current context as we work through our response."
|
|
75
|
+
)
|
|
76
|
+
thought: str = Field(
|
|
77
|
+
...,
|
|
78
|
+
description="The reasoning behind the decision."
|
|
79
|
+
)
|
|
24
80
|
|
|
25
81
|
|
|
26
82
|
class FailureOccurred(Event):
|
|
27
|
-
|
|
28
|
-
|
|
83
|
+
"""Event to signal a failure in the ReAct loop.
|
|
84
|
+
|
|
85
|
+
This event captures errors or unrecoverable situations that prevent
|
|
86
|
+
the agent from continuing to process the user's query.
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
context: CurrentContext = Field(
|
|
90
|
+
...,
|
|
91
|
+
description="The current context as we work through our response."
|
|
92
|
+
)
|
|
93
|
+
reason: str = Field(
|
|
94
|
+
...,
|
|
95
|
+
description="The reason for the failure."
|
|
96
|
+
)
|
_examples/react.py
CHANGED
|
@@ -1,32 +1,82 @@
|
|
|
1
|
+
"""ReAct Pattern Example.
|
|
2
|
+
|
|
3
|
+
This example demonstrates a Reasoning and Acting (ReAct) loop where agents
|
|
4
|
+
iteratively plan, decide, act, and summarize to answer user queries.
|
|
5
|
+
|
|
6
|
+
The ReAct pattern consists of:
|
|
7
|
+
1. Thinking Agent - Creates plans
|
|
8
|
+
2. Decisioning Agent - Decides next actions
|
|
9
|
+
3. Tool Call Agent - Executes tools
|
|
10
|
+
4. Summarization Agent - Generates final answers
|
|
11
|
+
"""
|
|
1
12
|
from _examples.react.agents.decisioning_agent import DecisioningAgent
|
|
13
|
+
from _examples.react.agents.summarization_agent import SummarizationAgent
|
|
2
14
|
from _examples.react.agents.thinking_agent import ThinkingAgent
|
|
15
|
+
from _examples.react.agents.tool_call_agent import ToolCallAgent
|
|
3
16
|
from _examples.react.models.base import CurrentContext
|
|
4
|
-
from _examples.react.models.events import
|
|
5
|
-
|
|
6
|
-
|
|
17
|
+
from _examples.react.models.events import (
|
|
18
|
+
FailureOccurred,
|
|
19
|
+
FinishAndSummarize,
|
|
20
|
+
InvokeDecisioning,
|
|
21
|
+
InvokeThinking,
|
|
22
|
+
InvokeToolCall,
|
|
23
|
+
)
|
|
24
|
+
from mojentic import Dispatcher, Router
|
|
25
|
+
from mojentic.agents.output_agent import OutputAgent
|
|
7
26
|
from mojentic.llm import LLMBroker
|
|
8
27
|
|
|
9
|
-
# llm = LLMBroker("llama3.3-70b-32k")
|
|
10
|
-
llm = LLMBroker("deepseek-r1:70b")
|
|
11
|
-
thinking_agent = ThinkingAgent(llm)
|
|
12
|
-
decisioning_agent = DecisioningAgent(llm)
|
|
13
28
|
|
|
14
|
-
|
|
29
|
+
def main():
|
|
30
|
+
"""Run the ReAct pattern example."""
|
|
31
|
+
# Initialize LLM broker - using qwen3:32b as it's widely available
|
|
32
|
+
llm = LLMBroker("qwen3:32b")
|
|
33
|
+
# Alternative models (uncomment if available):
|
|
34
|
+
# llm = LLMBroker("deepseek-r1:70b")
|
|
35
|
+
# llm = LLMBroker("qwen3:8b")
|
|
15
36
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
37
|
+
# Create agents
|
|
38
|
+
thinking_agent = ThinkingAgent(llm)
|
|
39
|
+
decisioning_agent = DecisioningAgent(llm)
|
|
40
|
+
tool_call_agent = ToolCallAgent()
|
|
41
|
+
summarization_agent = SummarizationAgent(llm)
|
|
42
|
+
output_agent = OutputAgent()
|
|
20
43
|
|
|
21
|
-
|
|
44
|
+
# Configure router - maps event types to agent handlers
|
|
45
|
+
router = Router({
|
|
46
|
+
InvokeThinking: [thinking_agent, output_agent],
|
|
47
|
+
InvokeDecisioning: [decisioning_agent, output_agent],
|
|
48
|
+
InvokeToolCall: [tool_call_agent, output_agent],
|
|
49
|
+
FinishAndSummarize: [summarization_agent, output_agent],
|
|
50
|
+
FailureOccurred: [output_agent],
|
|
51
|
+
})
|
|
22
52
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
53
|
+
# Create dispatcher
|
|
54
|
+
dispatcher = Dispatcher(router)
|
|
55
|
+
|
|
56
|
+
# Create initial context
|
|
57
|
+
initial_context = CurrentContext(
|
|
58
|
+
user_query="What is the date next Friday?"
|
|
29
59
|
)
|
|
30
|
-
)
|
|
31
60
|
|
|
32
|
-
|
|
61
|
+
# Start the ReAct loop
|
|
62
|
+
print("\n" + "=" * 80)
|
|
63
|
+
print("Starting ReAct Pattern Example")
|
|
64
|
+
print("=" * 80)
|
|
65
|
+
print(f"User Query: {initial_context.user_query}")
|
|
66
|
+
print("=" * 80 + "\n")
|
|
67
|
+
|
|
68
|
+
# Create and dispatch initial thinking event
|
|
69
|
+
initial_event = InvokeThinking(
|
|
70
|
+
source=type(main),
|
|
71
|
+
context=initial_context
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
dispatcher.dispatch(initial_event)
|
|
75
|
+
|
|
76
|
+
print("\n" + "=" * 80)
|
|
77
|
+
print("ReAct Pattern Example Complete")
|
|
78
|
+
print("=" * 80 + "\n")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
if __name__ == "__main__":
|
|
82
|
+
main()
|
_examples/recursive_agent.py
CHANGED
|
@@ -21,7 +21,7 @@ async def demonstrate_async():
|
|
|
21
21
|
3. Running multiple problem-solving tasks concurrently
|
|
22
22
|
"""
|
|
23
23
|
# Initialize the LLM broker with your preferred model
|
|
24
|
-
# llm = LLMBroker(model="
|
|
24
|
+
# llm = LLMBroker(model="qwen3:32b")
|
|
25
25
|
llm = LLMBroker(model="qwen3:30b-a3b-q4_K_M")
|
|
26
26
|
|
|
27
27
|
# Create the agent with a maximum of 3 iterations
|
|
@@ -78,7 +78,7 @@ async def demonstrate_async():
|
|
|
78
78
|
|
|
79
79
|
# Create tasks for all problems and run them concurrently
|
|
80
80
|
tasks = [solve_and_print(problem) for problem in problems]
|
|
81
|
-
|
|
81
|
+
await asyncio.gather(*tasks)
|
|
82
82
|
|
|
83
83
|
print("\nAll concurrent problems have been solved!")
|
|
84
84
|
|
_examples/simple_llm.py
CHANGED
|
@@ -25,9 +25,9 @@ class RequestAgent(BaseLLMAgent):
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
# llm = LLMBroker("deepseek-r1:70b")
|
|
28
|
-
# llm = LLMBroker("
|
|
29
|
-
llm = LLMBroker("
|
|
30
|
-
# llm = LLMBroker("
|
|
28
|
+
# llm = LLMBroker("qwen3:14b")
|
|
29
|
+
llm = LLMBroker("qwen3:0.5b")
|
|
30
|
+
# llm = LLMBroker("qwen3:7b", gateway=OllamaGateway(host="http://odin.local:11434"))
|
|
31
31
|
request_agent = RequestAgent(llm)
|
|
32
32
|
output_agent = OutputAgent()
|
|
33
33
|
|
_examples/simple_llm_repl.py
CHANGED
_examples/simple_structured.py
CHANGED
|
@@ -32,7 +32,7 @@ class RequestAgent(BaseLLMAgent):
|
|
|
32
32
|
return [ResponseEvent(source=type(self), correlation_id=event.correlation_id, capitol=response)]
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
llm = LLMBroker("
|
|
35
|
+
llm = LLMBroker("qwen3:14b")
|
|
36
36
|
request_agent = RequestAgent(llm)
|
|
37
37
|
output_agent = OutputAgent()
|
|
38
38
|
|
_examples/simple_tool.py
CHANGED
|
@@ -33,8 +33,8 @@ class RequestAgent(BaseLLMAgent):
|
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
# llm = LLMBroker("deepseek-r1:70b")
|
|
36
|
-
# llm = LLMBroker("
|
|
37
|
-
llm = LLMBroker("
|
|
36
|
+
# llm = LLMBroker("qwen3:32b")
|
|
37
|
+
llm = LLMBroker("qwen3:7b")
|
|
38
38
|
request_agent = RequestAgent(llm)
|
|
39
39
|
output_agent = OutputAgent()
|
|
40
40
|
|
_examples/solver_chat_session.py
CHANGED
|
@@ -4,11 +4,10 @@ from typing import List
|
|
|
4
4
|
from mojentic.agents import IterativeProblemSolver
|
|
5
5
|
from mojentic.llm.tools.date_resolver import ResolveDateTool
|
|
6
6
|
from mojentic.llm.tools.llm_tool import LLMTool
|
|
7
|
+
from mojentic.llm import LLMBroker, ChatSession
|
|
7
8
|
|
|
8
9
|
logging.basicConfig(level=logging.WARN)
|
|
9
10
|
|
|
10
|
-
from mojentic.llm import LLMBroker, ChatSession
|
|
11
|
-
|
|
12
11
|
|
|
13
12
|
class IterativeProblemSolverTool(LLMTool):
|
|
14
13
|
def __init__(self, llm: LLMBroker, tools: List[LLMTool]):
|
|
@@ -43,17 +42,12 @@ class IterativeProblemSolverTool(LLMTool):
|
|
|
43
42
|
|
|
44
43
|
def main():
|
|
45
44
|
# llm = LLMBroker(model="MFDoom/deepseek-r1-tool-calling:14b")
|
|
46
|
-
# llm = LLMBroker(model="
|
|
47
|
-
# llm = LLMBroker(model="
|
|
48
|
-
# llm = LLMBroker(model="
|
|
45
|
+
# llm = LLMBroker(model="qwen3:14b")
|
|
46
|
+
# llm = LLMBroker(model="qwen3:14b")
|
|
47
|
+
# llm = LLMBroker(model="qwen3:7b")
|
|
49
48
|
llm = LLMBroker(model="qwq")
|
|
50
49
|
# llm = LLMBroker(model="qwq:32b-fp16")
|
|
51
|
-
# llm = LLMBroker(model="
|
|
52
|
-
|
|
53
|
-
tools = [
|
|
54
|
-
ResolveDateTool(),
|
|
55
|
-
IterativeProblemSolverTool(llm=llm, tools=[ResolveDateTool()])
|
|
56
|
-
]
|
|
50
|
+
# llm = LLMBroker(model="qwen3:32b")
|
|
57
51
|
|
|
58
52
|
chat_session = ChatSession(llm, tools=[IterativeProblemSolverTool(llm=llm, tools=[ResolveDateTool()])])
|
|
59
53
|
|
_examples/streaming.py
CHANGED
|
@@ -1,34 +1,52 @@
|
|
|
1
|
+
from mojentic.llm.llm_broker import LLMBroker
|
|
1
2
|
from mojentic.llm.gateways.models import LLMMessage
|
|
2
3
|
from mojentic.llm.gateways.ollama import OllamaGateway
|
|
3
4
|
from mojentic.llm.tools.date_resolver import ResolveDateTool
|
|
4
5
|
|
|
5
|
-
#
|
|
6
|
-
# This is here 2025-02-21 to demonstrate a deficiency in Ollama/llama tool calling
|
|
7
|
-
# using the Stream option. We can't get chunk by chunk responses from the LLM
|
|
8
|
-
# when using tools. This limits our ability to explore streaming capabilities
|
|
9
|
-
# in the mojentic API, so I'm pausing this work for now until this is resolved.
|
|
10
|
-
# https://github.com/ollama/ollama/issues/7886
|
|
11
|
-
#
|
|
12
|
-
|
|
13
6
|
|
|
14
7
|
def main():
|
|
15
|
-
|
|
8
|
+
"""
|
|
9
|
+
Demonstrates streaming text generation with tool calling support.
|
|
10
|
+
|
|
11
|
+
This example shows how generate_stream() handles tool calls seamlessly:
|
|
12
|
+
1. Streams content as it arrives
|
|
13
|
+
2. Detects tool calls in the stream
|
|
14
|
+
3. Executes tools
|
|
15
|
+
4. Recursively streams the LLM's response after tool execution
|
|
16
|
+
"""
|
|
17
|
+
gateway = OllamaGateway()
|
|
18
|
+
# gateway = OpenAIGateway(api_key=os.getenv("OPENAI_API_KEY"))
|
|
19
|
+
broker = LLMBroker(
|
|
20
|
+
model="qwen3:32b",
|
|
21
|
+
# model="gpt-5",
|
|
22
|
+
gateway=gateway
|
|
23
|
+
)
|
|
24
|
+
|
|
16
25
|
date_tool = ResolveDateTool()
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
|
|
27
|
+
print("Streaming response with tool calling enabled...\n")
|
|
28
|
+
|
|
29
|
+
stream = broker.generate_stream(
|
|
20
30
|
messages=[
|
|
21
|
-
LLMMessage(
|
|
22
|
-
|
|
31
|
+
LLMMessage(
|
|
32
|
+
content=(
|
|
33
|
+
"Tell me a short story about a dragon. "
|
|
34
|
+
"In your story, reference several dates relative to today, "
|
|
35
|
+
"like 'three days from now' or 'last week'."
|
|
36
|
+
)
|
|
37
|
+
)
|
|
23
38
|
],
|
|
24
39
|
tools=[date_tool],
|
|
25
|
-
temperature=0.
|
|
40
|
+
temperature=0.7,
|
|
26
41
|
num_ctx=32768,
|
|
27
42
|
num_predict=-1
|
|
28
43
|
)
|
|
29
|
-
|
|
44
|
+
|
|
30
45
|
for chunk in stream:
|
|
31
|
-
print(chunk
|
|
46
|
+
print(chunk, end='', flush=True)
|
|
47
|
+
|
|
48
|
+
print("\n\nDone!")
|
|
49
|
+
|
|
32
50
|
|
|
33
51
|
if __name__ == "__main__":
|
|
34
|
-
main()
|
|
52
|
+
main()
|
_examples/tell_user_example.py
CHANGED
|
@@ -7,17 +7,17 @@ to display messages to the user without expecting a response.
|
|
|
7
7
|
|
|
8
8
|
import logging
|
|
9
9
|
|
|
10
|
-
logging.basicConfig(level=logging.WARN)
|
|
11
|
-
|
|
12
10
|
from mojentic.agents.iterative_problem_solver import IterativeProblemSolver
|
|
13
11
|
from mojentic.llm.tools.tell_user_tool import TellUserTool
|
|
14
12
|
from mojentic.llm import LLMBroker
|
|
15
13
|
|
|
14
|
+
logging.basicConfig(level=logging.WARN)
|
|
15
|
+
|
|
16
16
|
|
|
17
17
|
def main():
|
|
18
18
|
# Initialize the LLM broker with your preferred model
|
|
19
19
|
# Uncomment one of the following lines or modify as needed:
|
|
20
|
-
# llm = LLMBroker(model="
|
|
20
|
+
# llm = LLMBroker(model="qwen3:32b") # Ollama model
|
|
21
21
|
# llm = LLMBroker(model="gpt-4o") # OpenAI model
|
|
22
22
|
llm = LLMBroker(model="qwq") # Default model for example
|
|
23
23
|
|
|
@@ -40,4 +40,4 @@ def main():
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
if __name__ == "__main__":
|
|
43
|
-
main()
|
|
43
|
+
main()
|
_examples/tracer_demo.py
CHANGED
|
@@ -1,31 +1,29 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Example script demonstrating the tracer system with ChatSession and tools.
|
|
3
3
|
|
|
4
|
-
This example shows how to use the tracer system to monitor an interactive
|
|
5
|
-
chat session with LLMBroker and tools. When the user exits the session,
|
|
4
|
+
This example shows how to use the tracer system to monitor an interactive
|
|
5
|
+
chat session with LLMBroker and tools. When the user exits the session,
|
|
6
6
|
the script displays a summary of all traced events.
|
|
7
7
|
|
|
8
8
|
It also demonstrates how correlation_id is used to trace related events
|
|
9
9
|
across the system, allowing you to track the flow of a request from start to finish.
|
|
10
10
|
"""
|
|
11
11
|
import uuid
|
|
12
|
-
from datetime import datetime
|
|
13
12
|
|
|
14
13
|
from mojentic.tracer import TracerSystem
|
|
15
14
|
from mojentic.tracer.tracer_events import LLMCallTracerEvent, LLMResponseTracerEvent, ToolCallTracerEvent
|
|
16
15
|
from mojentic.llm import ChatSession, LLMBroker
|
|
17
|
-
from mojentic.llm.gateways.models import LLMMessage, MessageRole
|
|
18
16
|
from mojentic.llm.tools.date_resolver import ResolveDateTool
|
|
19
17
|
|
|
20
18
|
|
|
21
19
|
def print_tracer_events(events):
|
|
22
20
|
"""Print tracer events using their printable_summary method."""
|
|
23
|
-
print(
|
|
21
|
+
print("\n{'-'*80}")
|
|
24
22
|
print("Tracer Events:")
|
|
25
|
-
print(
|
|
23
|
+
print("{'-'*80}")
|
|
26
24
|
|
|
27
25
|
for i, event in enumerate(events, 1):
|
|
28
|
-
print(
|
|
26
|
+
print("{i}. {event.printable_summary()}")
|
|
29
27
|
print()
|
|
30
28
|
|
|
31
29
|
|
|
@@ -35,7 +33,7 @@ def main():
|
|
|
35
33
|
tracer = TracerSystem()
|
|
36
34
|
|
|
37
35
|
# Create an LLM broker with the tracer
|
|
38
|
-
llm_broker = LLMBroker(model="
|
|
36
|
+
llm_broker = LLMBroker(model="gpt-oss:20b", tracer=tracer)
|
|
39
37
|
|
|
40
38
|
# Create a date resolver tool that will also use the tracer
|
|
41
39
|
date_tool = ResolveDateTool(llm_broker=llm_broker, tracer=tracer)
|
|
@@ -69,7 +67,7 @@ def main():
|
|
|
69
67
|
turn_counter += 1
|
|
70
68
|
conversation_correlation_ids[turn_counter] = correlation_id
|
|
71
69
|
|
|
72
|
-
print(
|
|
70
|
+
print("[Turn {turn_counter}, correlation_id: {correlation_id[:8]}...]")
|
|
73
71
|
print("Assistant: ", end="")
|
|
74
72
|
|
|
75
73
|
# For demonstration purposes, we'll use the chat_session normally
|
|
@@ -85,30 +83,30 @@ def main():
|
|
|
85
83
|
# After the user exits, display tracer event summary
|
|
86
84
|
print("\nTracer System Summary")
|
|
87
85
|
print("=" * 80)
|
|
88
|
-
print(
|
|
86
|
+
print("You just had a conversation with an LLM, and the tracer recorded everything!")
|
|
89
87
|
|
|
90
88
|
# Get all events
|
|
91
89
|
all_events = tracer.get_events()
|
|
92
|
-
print(
|
|
90
|
+
print("Total events recorded: {len(all_events)}")
|
|
93
91
|
print_tracer_events(all_events)
|
|
94
92
|
|
|
95
93
|
# Show how to filter events by type
|
|
96
94
|
print("\nYou can filter events by type:")
|
|
97
95
|
|
|
98
96
|
llm_calls = tracer.get_events(event_type=LLMCallTracerEvent)
|
|
99
|
-
print(
|
|
97
|
+
print("LLM Call Events: {len(llm_calls)}")
|
|
100
98
|
if llm_calls:
|
|
101
|
-
print(
|
|
99
|
+
print("Example: {llm_calls[0].printable_summary()}")
|
|
102
100
|
|
|
103
101
|
llm_responses = tracer.get_events(event_type=LLMResponseTracerEvent)
|
|
104
|
-
print(
|
|
102
|
+
print("LLM Response Events: {len(llm_responses)}")
|
|
105
103
|
if llm_responses:
|
|
106
|
-
print(
|
|
104
|
+
print("Example: {llm_responses[0].printable_summary()}")
|
|
107
105
|
|
|
108
106
|
tool_calls = tracer.get_events(event_type=ToolCallTracerEvent)
|
|
109
|
-
print(
|
|
107
|
+
print("Tool Call Events: {len(tool_calls)}")
|
|
110
108
|
if tool_calls:
|
|
111
|
-
print(
|
|
109
|
+
print("Example: {tool_calls[0].printable_summary()}")
|
|
112
110
|
|
|
113
111
|
# Show the last few events
|
|
114
112
|
print("\nThe last few events:")
|
|
@@ -130,7 +128,7 @@ def main():
|
|
|
130
128
|
first_correlation_id = conversation_correlation_ids.get(first_turn_id)
|
|
131
129
|
|
|
132
130
|
if first_correlation_id:
|
|
133
|
-
print(
|
|
131
|
+
print("\nEvents for conversation turn {first_turn_id} (correlation_id: {first_correlation_id[:8]}...):")
|
|
134
132
|
|
|
135
133
|
# Define a filter function that checks the correlation_id
|
|
136
134
|
def filter_by_correlation_id(event):
|
|
@@ -140,7 +138,7 @@ def main():
|
|
|
140
138
|
related_events = tracer.get_events(filter_func=filter_by_correlation_id)
|
|
141
139
|
|
|
142
140
|
if related_events:
|
|
143
|
-
print(
|
|
141
|
+
print("Found {len(related_events)} related events")
|
|
144
142
|
print_tracer_events(related_events)
|
|
145
143
|
|
|
146
144
|
# Show how this helps trace the flow of a request
|
|
@@ -163,7 +161,7 @@ def main():
|
|
|
163
161
|
|
|
164
162
|
print("Tool usage frequency:")
|
|
165
163
|
for tool_name, count in tool_names.items():
|
|
166
|
-
print(
|
|
164
|
+
print(" - {tool_name}: {count} calls")
|
|
167
165
|
|
|
168
166
|
|
|
169
167
|
if __name__ == "__main__":
|