summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/simple-agent.lua103
1 files changed, 103 insertions, 0 deletions
diff --git a/examples/simple-agent.lua b/examples/simple-agent.lua
new file mode 100644
index 0000000..baf00b5
--- /dev/null
+++ b/examples/simple-agent.lua
@@ -0,0 +1,103 @@
+#!/usr/bin/env lua
+-- A tiny standalone libpanto-lua app: one prompt in, streamed text out.
+--
+-- Run with Lua 5.4 after building/installing libpanto-lua, for example:
+-- LUA_CPATH='./libpanto-lua/zig-out/lib/?.so;;' lua examples/simple-agent.lua "list the files"
+--
+-- Required environment:
+-- PANTO_API_STYLE=openai_chat|anthropic_messages
+-- PANTO_API_KEY=...
+-- PANTO_BASE_URL=...
+-- PANTO_MODEL=...
+
+local panto = require("panto")
+
+local function getenv(name, default)
+ local value = os.getenv(name)
+ if value == nil or value == "" then return default end
+ return value
+end
+
+local function require_env(name)
+ local value = getenv(name)
+ if value == nil then error("missing required env var: " .. name, 0) end
+ return value
+end
+
+local function shell_quote(s)
+ return "'" .. tostring(s):gsub("'", "'\\''") .. "'"
+end
+
+local function read_all(pipe)
+ local chunks = {}
+ while true do
+ local chunk = pipe:read(8192)
+ if chunk == nil then break end
+ chunks[#chunks + 1] = chunk
+ end
+ return table.concat(chunks)
+end
+
+local function run_bash(command)
+ local wrapped = "bash -lc " .. shell_quote(command) .. " 2>&1; printf '\\n__panto_exit_code:%s\\n' $?"
+ local pipe = assert(io.popen(wrapped, "r"))
+ local output = read_all(pipe)
+ pipe:close()
+
+ local body, code = output:match("^(.*)\n__panto_exit_code:(%-?%d+)\n$")
+ return string.format("exit_code=%s\n%s", code or "unknown", body or output)
+end
+
+local prompt = table.concat(arg, " ")
+if prompt == "" then
+ io.stderr:write("usage: lua examples/simple-agent.lua <prompt>\n")
+ os.exit(2)
+end
+
+local agent = panto.agent {
+ api_style = require_env("PANTO_API_STYLE"),
+ api_key = require_env("PANTO_API_KEY"),
+ base_url = require_env("PANTO_BASE_URL"),
+ model = require_env("PANTO_MODEL"),
+ max_tokens = tonumber(getenv("PANTO_MAX_TOKENS", "4096")),
+}
+
+agent:set_system_prompt(table.concat({
+ "You are a very small coding agent.",
+ "Use the bash tool when you need to inspect or change the local workspace.",
+ "Keep final answers concise.",
+}, "\n"))
+
+agent:register_tool {
+ name = "bash",
+ description = "Run a shell command with bash -lc and return combined stdout/stderr plus the exit code.",
+ schema = {
+ type = "object",
+ properties = {
+ command = {
+ type = "string",
+ description = "The command to run.",
+ },
+ },
+ required = { "command" },
+ },
+ handler = function(input)
+ if type(input.command) ~= "string" or input.command == "" then
+ error("bash.command must be a non-empty string")
+ end
+ return run_bash(input.command)
+ end,
+}
+
+for ev in agent:run(prompt):events() do
+ if ev.type == "content_delta" then
+ io.write(ev.delta)
+ io.flush()
+ elseif ev.type == "tool_dispatch_start" then
+ io.stderr:write(string.format("\n[bash: running %d tool call(s)]\n", ev.count))
+ elseif ev.type == "tool_dispatch_complete" then
+ io.stderr:write("[bash: done]\n")
+ end
+end
+
+io.write("\n")