summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-09-08 23:33:08 -0600
committermo khan <mo@mokhan.ca>2025-09-08 23:33:08 -0600
commit59db135e1478c80203c834177831c2a43f481bde (patch)
treec6cfc0d494b312bce0f2340db182da69b38373f8
parent3b06f576b888048becf8a667b9d7cf2efa14a529 (diff)
refactor: simplify code
-rw-r--r--main.rb71
1 files changed, 27 insertions, 44 deletions
diff --git a/main.rb b/main.rb
index 80e44a7..72d9bba 100644
--- a/main.rb
+++ b/main.rb
@@ -1,15 +1,14 @@
#!/usr/bin/env ruby
# GPT-5 Action-Oriented Agent - pure stdlib
-require "net/http"
require "json"
-require "uri"
+require "net/http"
require "reline"
+require "uri"
API_KEY = ENV["OPENAI_API_KEY"] or abort("Set OPENAI_API_KEY")
-MODEL = "gpt-5"
+MODEL = ENV["MODEL"] || "gpt-5"
-# Tools GPT-5 can use
TOOLS = [
{
type: "function",
@@ -49,40 +48,26 @@ TOOLS = [
}
]
-# Execute tools
def run_tool(name, args)
case name
when "read_file"
- begin
- { content: File.read(args["path"]) }
- rescue => e
- { error: e.message }
- end
+ { content: File.read(args["path"]) }
when "write_file"
- begin
- File.write(args["path"], args["content"])
- { status: "ok" }
- rescue => e
- { error: e.message }
- end
+ { bytes_written: File.write(args["path"], args["content"]) }
when "run_command"
- begin
- { output: `#{args["command"]}`.strip }
- rescue => e
- { error: e.message }
- end
+ { output: `#{args["command"]}`.strip }
else
{ error: "unknown tool #{name}" }
end
+rescue => e
+ { error: e.message }
end
-# Call OpenAI
-def openai_chat(messages, tools)
+def openai_chat(messages, tools, timeout: 60)
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,
@@ -90,21 +75,21 @@ def openai_chat(messages, tools)
tool_choice: "auto"
}.to_json
- res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
+ http = Net::HTTP.new(uri.hostname, uri.port)
+ http.use_ssl = true
+ http.open_timeout = timeout
+ http.read_timeout = timeout
+ http.write_timeout = timeout if http.respond_to?(:write_timeout=)
+
+ res = http.start { |h| h.request(req) }
+ code = res.code.to_i
+
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
- }
-]
-
+messages = [{ role: "system", content: "You are a reasoning coding and system agent." }]
puts ">> Type instructions (or 'exit')"
loop do
@@ -113,20 +98,18 @@ loop do
messages << { role: "user", content: input }
loop do
- resp = openai_chat(messages, TOOLS)
- msg = resp.dig("choices", 0, "message")
- messages << msg
+ message = openai_chat(messages, TOOLS).dig("choices", 0, "message")
+ messages << message
- # Print reasoning content immediately
- if msg["content"] && !msg["content"].empty?
- puts "\nAssistant> #{msg['content']}"
+ if message["content"] && !message["content"].empty?
+ puts "\nAssistant> #{message['content']}"
end
- # Execute any tool calls
- if msg["tool_calls"]
- msg["tool_calls"].each do |call|
+ if message["tool_calls"]
+ message["tool_calls"].each do |call|
name = call.dig("function","name")
args = JSON.parse(call.dig("function","arguments"))
+ puts "Tool> ▶ #{name}(#{args})"
result = run_tool(name, args)
messages << { role: "tool", tool_call_id: call["id"], content: JSON.dump(result) }
end