summaryrefslogtreecommitdiff
path: root/subagents/models.lua
diff options
context:
space:
mode:
authort <t@tjp.lol>2026-08-19 19:02:30 -0600
committert <t@tjp.lol>2026-08-19 19:03:52 -0600
commitd1306506aa7f504b0e91c9c6ed7314afbf99978e (patch)
treee5a7295dbc566a3679e99e14dae13376b0469e84 /subagents/models.lua
parent94e3fd8358bbdb5d6ed81aed475fab7fc73e2097 (diff)
Add background Lua workflows, inline child prompts, and layered config
subagents.lua now starts a workflow on its own coroutine and returns a session-scoped id immediately, so fan-out continues while the primary keeps working; completion wakes the primary, and later calls read immutable records from subagents.workflows. Every ctx:agent takes a workflow-unique name so those records are addressable. A session_start guidance message tells the primary when to reach for run vs lua. Children no longer inherit the primary's system context: a child starts from the fixed child-role instruction plus its profile, and subagents.run/ctx:agent accept an inline system_prompt instead of a profile. The now-redundant `agent` form of subagents.models is gone. Concurrency defaults to five and is configurable through [subagents] max_concurrent in any layered config.toml; turn boundaries reap only settled jobs so background workflows survive, while interrupt and session end cancel. Config roots come from panto.ext.dirs.layers rather than a hand-rolled XDG lookup, which picks up the base and git-ignored local layers for both agents/ and workflows/. TOML workflows tighten up: the subagents.workflow tool takes a discovered name only (inline `steps` duplicated subagents.lua at less power), an optional top-level `output` array chooses the reported steps and their order instead of the terminal set, a step with no workflow input gets no empty input heading, and a workflow naming an undiscovered agent is rejected at discovery rather than part-way through a run.
Diffstat (limited to 'subagents/models.lua')
-rw-r--r--subagents/models.lua56
1 files changed, 3 insertions, 53 deletions
diff --git a/subagents/models.lua b/subagents/models.lua
index 511aa51..7272298 100644
--- a/subagents/models.lua
+++ b/subagents/models.lua
@@ -1,17 +1,12 @@
-- The `subagents.models` tool: a bounded window onto the model catalog.
--
-- The catalog is far too large to inline into `subagents.run`'s description or
--- schema, so it is queried on demand instead. Four forms, chosen in this order:
+-- schema, so it is queried on demand instead. Three forms:
--
--- { agent = "reviewer" } what that profile will actually run on
-- { model = "anthropic:sonnet"} exact lookup: wire name, reasoning levels
-- { provider =, query =, limit=} bounded search
-- { } inherited model/reasoning + provider counts
--
--- The agent form is the join the primary actually wants before overriding a
--- profile: it reports the profile's own model, or says the profile inherits
--- the primary model and shows what that is.
---
-- Results are short readable lines, not JSON. A truncated search says so
-- explicitly so the primary refines the query instead of assuming it saw
-- everything; `limit` is clamped to 1..50 (default 10) so no query can dump
@@ -22,8 +17,6 @@
-- tool cannot confirm is still validated at spawn time — the catalog is
-- advice, the runtime is authoritative.
-local spawn = require("subagents.spawn")
-
local DEFAULT_LIMIT = 10
local MAX_LIMIT = 50
@@ -143,52 +136,13 @@ local function clamp_limit(value)
return limit
end
--- The agent form: report the profile's effective model, or say it inherits.
-local function describe_agent(name, profiles)
- profiles = spawn.profiles(profiles)
- local profile = (profiles.by_name or {})[name]
- if not profile then
- return string.format("Error: unknown agent '%s'; known: %s", name, spawn.agent_names(profiles))
- end
-
- local out = { "agent: " .. profile.name }
- if profile.description ~= "" then
- out[#out + 1] = "description: " .. profile.description
- end
-
- if profile.model then
- local result, err = ask({ model = profile.model })
- if not result then
- return "Error: " .. err
- end
- out[#out + 1] = format_exact(result, profile.model)
- else
- out[#out + 1] = "model: inherits the primary model"
- local result, err = ask({})
- if not result then
- return "Error: " .. err
- end
- out[#out + 1] = format_overview(result)
- end
-
- if profile.reasoning then
- out[#out + 1] = "profile reasoning: " .. profile.reasoning
- end
- return table.concat(out, "\n")
-end
-
-function M.handle(input, profiles)
+function M.handle(input)
input = input or {}
if type(input) ~= "table" then
return "Error: expected a table of arguments."
end
- local agent, err = optional_string(input.agent, "agent")
- if err then
- return err
- end
- local model
- model, err = optional_string(input.model, "model")
+ local model, err = optional_string(input.model, "model")
if err then
return err
end
@@ -203,10 +157,6 @@ function M.handle(input, profiles)
return err
end
- if agent then
- return describe_agent(agent, profiles)
- end
-
if model then
local result, ask_err = ask({ model = model })
if not result then