-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathanthropic_tool_use.py
executable file
·137 lines (120 loc) · 5.05 KB
/
anthropic_tool_use.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# export ANTHROPIC_API_KEY=...
# python -m examples.anthropic_tool_use
from __future__ import annotations
from typing import cast
from anthropic import Anthropic
from anthropic.types import ToolParam, MessageParam
import gitpod.lib as util
from gitpod import AsyncGitpod
from gitpod.types.environment_initializer_param import Spec
from .scm_auth import verify_context_url # type: ignore
gpclient = AsyncGitpod()
llmclient = Anthropic()
user_message: MessageParam = {
"role": "user",
"content": "What is the test coverage for this repository: https://github.com/gitpod-io/gitpod-sdk-go",
}
tools: list[ToolParam] = [
{
"name": "create_environment",
"description": "Create a new environment for a given context URL. This will create a new environment and return the ID of the environment.",
"input_schema": {
"type": "object",
"properties": {"context_url": {"type": "string"}},
},
},
{
"name": "execute_command",
"description": "Execute a command in a given environment ID. This will execute the command in the given environment and return the output of the command.",
"input_schema": {
"type": "object",
"properties": {"environment_id": {"type": "string"}, "command": {"type": "string"}},
},
},
]
async def create_environment(args: dict[str, str], cleanup: util.Disposables) -> str:
env_class = await util.find_most_used_environment_class(gpclient)
if not env_class:
raise Exception("No environment class found. Please create one first.")
await verify_context_url(gpclient, args["context_url"], env_class.runner_id)
environment = (await gpclient.environments.create(
spec={
"desired_phase": "ENVIRONMENT_PHASE_RUNNING",
"content": {
"initializer": {"specs": [Spec(
context_url={
"url": args["context_url"]
}
)]},
},
"machine": {"class": env_class.id},
}
)).environment
cleanup.adda(lambda: gpclient.environments.delete(environment_id=environment.id))
print(f"\nCreated environment: {environment.id} - waiting for it to be ready...")
await util.wait_for_environment_running(gpclient, environment.id)
print(f"\nEnvironment is ready: {environment.id}")
return environment.id
async def execute_command(args: dict[str, str]) -> str:
lines_iter = await util.run_command(gpclient, args["environment_id"], args["command"])
lines: list[str] = []
async for line in lines_iter:
lines.append(line)
return "\n".join(lines)
async def main(cleanup: util.Disposables) -> None:
messages = [user_message]
while True:
message = llmclient.messages.create(
model="claude-3-5-sonnet-latest",
max_tokens=1024,
messages=messages,
tools=tools,
)
print(f"\nResponse: {message.model_dump_json(indent=2)}")
if message.stop_reason != "tool_use":
print(f"\nFinal response reached! {message.model_dump_json(indent=2)}")
break
messages.extend([
{"role": message.role, "content": message.content}
])
# Handle all tool calls in this response
for tool in (c for c in message.content if c.type == "tool_use"):
try:
if tool.name == "create_environment":
args = cast(dict[str, str], tool.input)
environment_id = await create_environment(args, cleanup)
messages.append({
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": tool.id,
"content": [{"type": "text", "text": f"The environment ID is {environment_id}"}],
}],
})
elif tool.name == "execute_command":
args = cast(dict[str, str], tool.input)
output = await execute_command(args)
messages.append({
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": tool.id,
"content": [{"type": "text", "text": output}],
}],
})
else:
raise Exception(f"Unknown tool: {tool.name}")
except Exception as e:
messages.append({
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": tool.id,
"is_error": True,
"content": [{"type": "text", "text": f"Error: {e}"}],
}],
})
print("\nFinal response reached!")
if __name__ == "__main__":
import asyncio
asyncio.run(util.with_disposables(main))