Skip to content

Commit 9302251

Browse files
committed
examples: schedule-extract.py update
1 parent 7358c50 commit 9302251

File tree

4 files changed

+146
-22
lines changed

4 files changed

+146
-22
lines changed

examples/basic/chat-azure-client.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22
Example showing how to use Langroid with Azure OpenAI and Entra ID
33
authentication by providing a custom client.
44
5+
NOTE: this example is ONLY meant for those who are trying to use a custom
6+
Azure client, as in this scenario:
7+
https://langroid.github.io/langroid/notes/custom-azure-client/
8+
This NOT TYPICAL for most users, and should be ignored if you are not using such a
9+
custom client.
10+
11+
For typical usage of Azure-deployed models with Langroid, see
12+
the [`test_azure_openai.py`](https://github.com/langroid/langroid/blob/main/tests/main/test_azure_openai.py) and
13+
[`example/basic/chat.py`](https://github.com/langroid/langroid/blob/main/examples/basic/chat.py)
14+
15+
516
For an async version of this example, see chat-azure-async-client.py.
617
718
For more details see here:

examples/basic/chat.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ def main(
7171
load_dotenv()
7272

7373
# use the appropriate config instance depending on model name
74+
# NOTE: when using Azure, change this to `lm.AzureConfig`
7475
llm_config = lm.OpenAIGPTConfig(
7576
chat_model=model or lm.OpenAIChatModel.GPT4o,
7677
chat_context_length=4096,
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
"""
2+
Agent that uses a python code execution tool to execute code.
3+
4+
CAUTION - this is a security risk, as it allows arbitrary code execution.
5+
This is a bare-bones example. For a real application, you would want to restrict
6+
the code in various ways, e.g. by using a sandboxed environment, or by restricting
7+
the modules that can be imported.
8+
9+
Run like this (leave model empty to use default GPT4o)
10+
11+
uv run examples/basic/python-code-exec-tool.py -m gpt4o-mini
12+
"""
13+
14+
import io
15+
import contextlib
16+
from fire import Fire
17+
from rich.prompt import Prompt
18+
from langroid.agent.tools.orchestration import ResultTool
19+
import langroid as lr
20+
import langroid.language_models as lm
21+
from langroid.mytypes import NonToolAction
22+
23+
24+
def execute_code(code_string):
25+
"""
26+
A minimal function to execute Python code and capture its output.
27+
28+
Args:
29+
code_string: The Python code to execute
30+
31+
Returns:
32+
Tuple of (output, local_variables)
33+
"""
34+
# Create dictionary for local variables
35+
local_vars = {}
36+
37+
# Capture stdout
38+
buffer = io.StringIO()
39+
40+
# Execute code with stdout redirection
41+
with contextlib.redirect_stdout(buffer):
42+
try:
43+
exec(code_string, globals(), local_vars)
44+
success = True
45+
except Exception as e:
46+
print(f"Error: {str(e)}")
47+
success = False
48+
49+
output = buffer.getvalue()
50+
return output, local_vars, success
51+
52+
53+
class PyCodeTool(lr.ToolMessage):
54+
request: str = "py_code_tool"
55+
purpose: str = "To execute a python <code_block> and return results"
56+
57+
code_block: str
58+
59+
def handle(self):
60+
output, local_vars, success = execute_code(self.code_block)
61+
if success:
62+
print("Successfully ran code. Results:")
63+
print(output)
64+
print("Local variables:")
65+
print(local_vars)
66+
else:
67+
print("Failed to run code.")
68+
return ResultTool(output=output, local_vars=local_vars, success=success)
69+
70+
71+
def main(model: str = ""):
72+
llm_config = lm.OpenAIGPTConfig(
73+
chat_model=model or lm.OpenAIChatModel.GPT4o,
74+
)
75+
agent = lr.ChatAgent(
76+
lr.ChatAgentConfig(
77+
llm=llm_config,
78+
# LLM non-tool msg -> treat as task done
79+
handle_llm_no_tool=NonToolAction.DONE,
80+
system_message=f"""
81+
You are an expert python coder. When you get a user's message,
82+
respond as follows:
83+
- if you think the user's message requires you to write code,
84+
then use the TOOL `{PyCodeTool.name()}` to perform the task.
85+
- otherwise simply respond to the user's message.
86+
""",
87+
)
88+
)
89+
agent.enable_message(PyCodeTool)
90+
# task specialized to return ResultTool
91+
task = lr.Task(agent, interactive=False)[ResultTool]
92+
93+
while True:
94+
user_input = Prompt.ask("User")
95+
if user_input.lower() in ["x", "q"]:
96+
break
97+
result: ResultTool | None = task.run(user_input)
98+
if result is not None:
99+
# code was run; do something with the output if any
100+
if result.success:
101+
print("Output:", result.output)
102+
else:
103+
print("Code execution failed.")
104+
105+
106+
if __name__ == "__main__":
107+
Fire(main)

examples/basic/schedule-extract.py

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,25 @@
44
Enter vague, unstructured info like:
55
66
M-F 8-3pm at home or Tue/Wed 9-1030am at daycare
7+
8+
Run like this -- (omit the -m arg for default gpt-4o-mini LLM)
9+
10+
```bash
11+
uv run examples/basic/schedule-extract.py -m gpt-4o
712
"""
813

914
import langroid as lr
1015
import langroid.language_models as lm
11-
from enum import Enum
1216
from langroid.agent.tools.orchestration import FinalResultTool
13-
from typing import List, Dict, Tuple
17+
from typing import List, Dict, Literal, Tuple
1418
from langroid.pydantic_v1 import BaseModel, Field
1519
from rich.prompt import Prompt
1620
from fire import Fire
1721

1822

1923
class Slot(BaseModel):
20-
start_time: float = Field(..., description="start time of the slot, e.g. 11:30AM")
21-
duration: float = Field(..., description="duration of the slot in MINUTES")
24+
start_time: str = Field(..., description="start time of the slot, e.g. 11:30AM")
25+
end_time: str = Field(..., description="end time of the slot, e.g. 12:30PM")
2226
location: str = Field(..., description="location of the slot or UNKNOWN")
2327

2428

@@ -30,28 +34,19 @@ class DaySchedule(BaseModel):
3034
slots: List[Slot] = Field(..., description="List of time slots for the day")
3135

3236

33-
class Weekday(int, Enum):
34-
"""
35-
A class to represent a weekday.
36-
"""
37-
38-
MON = 0
39-
TUE = 1
40-
WED = 2
41-
THU = 3
42-
FRI = 4
37+
Weekday = Literal["Mon", "Tue", "Wed", "Thu", "Fri"]
4338

4439

4540
class Availability(BaseModel):
4641
"""
4742
A class to represent schedule information.
4843
"""
4944

50-
week_availability: Dict[int, DaySchedule] = Field(
45+
week_availability: Dict[Weekday, DaySchedule] = Field(
5146
...,
5247
description="""
5348
Dictionary mapping weekday to DaySchedule,
54-
where 0 = Monday, 1 = Tuesday, ... 4 = Friday
49+
where weekday is one of "Mon", "Tue", "Wed", "Thu", "Fri"
5550
""",
5651
)
5752

@@ -77,17 +72,27 @@ def examples(cls) -> List["lr.ToolMessage" | Tuple[str, "lr.ToolMessage"]]:
7772
cls(
7873
availabilities=Availability(
7974
week_availability={
80-
Weekday.MON: DaySchedule(
75+
"Mon": DaySchedule(
8176
slots=[
82-
Slot(start_time=10, duration=360, location="home"),
8377
Slot(
84-
start_time=15, duration=60, location="daycare"
78+
start_time="10:00",
79+
end_time="16:00",
80+
location="home",
81+
),
82+
Slot(
83+
start_time="15:00",
84+
end_time="16:00",
85+
location="daycare",
8586
),
8687
]
8788
),
88-
Weekday.WED: DaySchedule(
89+
"Wed": DaySchedule(
8990
slots=[
90-
Slot(start_time=10, duration=360, location="home")
91+
Slot(
92+
start_time="10:00",
93+
end_time="16:00",
94+
location="home",
95+
)
9196
]
9297
),
9398
}
@@ -110,7 +115,7 @@ def handle(self) -> str:
110115

111116
def make_schedule_task(model: str = ""):
112117
llm_config = lm.OpenAIGPTConfig(
113-
chat_model=model or lm.GeminiModel.GEMINI_2_FLASH_LITE,
118+
chat_model=model or lm.OpenAIChatModel.GPT4o_MINI,
114119
)
115120
agent = lr.ChatAgent(
116121
lr.ChatAgentConfig(

0 commit comments

Comments
 (0)