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
138
|
#!/usr/bin/env ruby
# GPT-5 Action-Oriented Agent - pure stdlib
require "net/http"
require "json"
require "uri"
API_KEY = ENV["OPENAI_API_KEY"] or abort("Set OPENAI_API_KEY")
MODEL = "gpt-5-mini"
# Tools GPT-5 can use
TOOLS = [
{
type: "function",
function: {
name: "read_file",
description: "Read contents of a file",
parameters: {
type: "object",
properties: { path: { type: "string" } },
required: ["path"]
}
}
},
{
type: "function",
function: {
name: "write_file",
description: "Write contents to a file",
parameters: {
type: "object",
properties: { path: { type: "string" }, content: { type: "string" } },
required: ["path","content"]
}
}
},
{
type: "function",
function: {
name: "run_command",
description: "Run a shell command and return output",
parameters: {
type: "object",
properties: { command: { type: "string" } },
required: ["command"]
}
}
}
]
# Execute tools
def run_tool(name, args)
case name
when "read_file"
begin
{ content: File.read(args["path"]) }
rescue => e
{ error: e.message }
end
when "write_file"
begin
File.write(args["path"], args["content"])
{ status: "ok" }
rescue => e
{ error: e.message }
end
when "run_command"
begin
{ output: `#{args["command"]}`.strip }
rescue => e
{ error: e.message }
end
else
{ error: "unknown tool #{name}" }
end
end
# Call OpenAI
def openai_chat(messages, tools)
uri = URI("https://api.openai.com/v1/chat/completions")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{API_KEY}"
req["Content-Type"] = "application/json"
req.body = {
model: MODEL,
messages: messages,
tools: tools,
tool_choice: "auto"
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
raise "HTTP #{res.code}: #{res.body}" unless res.is_a?(Net::HTTPSuccess)
JSON.parse(res.body)
end
# Conversation with bias-for-action
messages = [
{ role: "system", content: <<~MSG
You are a reasoning coding and system agent. Prioritize taking practical actions whenever possible.
Use read_file, write_file, and run_command proactively to achieve user goals.
Explain your reasoning briefly in content. Avoid unnecessary delays; act whenever sufficient info is available.
MSG
}
]
puts ">> Type instructions (or 'exit')"
loop do
print "\nUser> "
input = STDIN.gets&.strip
break if input.nil? || input.downcase == "exit"
messages << { role: "user", content: input }
loop do
resp = openai_chat(messages, TOOLS)
msg = resp.dig("choices", 0, "message")
messages << msg
# Print reasoning content immediately
if msg["content"] && !msg["content"].empty?
puts "\nAssistant> #{msg['content']}"
end
# Execute any tool calls
if msg["tool_calls"]
msg["tool_calls"].each do |call|
name = call.dig("function","name")
args = JSON.parse(call.dig("function","arguments"))
result = run_tool(name, args)
messages << { role: "tool", tool_call_id: call["id"], content: JSON.dump(result) }
end
next # continue reasoning on tool results
end
break # no tool calls left, turn is done
end
end
|