Commit 8b0dd11
2026-08-31 01:55:45
1 parent
9bf1b90
.elelem/plugins/git.rb
@@ -5,7 +5,7 @@ Elelem::Plugins.register(:git) do |agent|
agent.toolbox.add("git",
description: "Run git command",
- params: { command: { type: "string" }, args: { type: "array" } },
+ params: { command: { type: "string" }, args: { type: "array", items: { type: "string" } } },
required: ["command"]
) do |a|
cmd = a["command"]
lib/elelem/tool.rb
@@ -7,7 +7,7 @@ module Elelem
def initialize(name, description:, params: {}, required: [], aliases: [], &fn)
@name = name
@description = description
- @params = params.freeze
+ @params = self.class.with_array_items(params).freeze
@required = required.freeze
@aliases = aliases.freeze
@fn = fn
@@ -15,6 +15,25 @@ module Elelem
@schema = JSONSchemer.schema(@schema_hash)
end
+ # gpt-oss's chat template throws when rendering an "array" param with no
+ # "items" (Jinja's `if param_spec['items']` isn't tolerant of a missing
+ # key there). Tools can be registered at runtime with arbitrary params
+ # (see the `eval` plugin), so default this here rather than only at each
+ # call site -- one place, covers every caller.
+ def self.with_array_items(params)
+ params.transform_values do |spec|
+ next spec unless spec.is_a?(Hash)
+
+ string_keyed = spec.key?("type")
+ type = string_keyed ? spec["type"] : spec[:type]
+ has_items = spec.key?(:items) || spec.key?("items")
+ next spec unless type == "array" && !has_items
+
+ default = string_keyed ? { "items" => { "type" => "string" } } : { items: { type: "string" } }
+ spec.merge(default)
+ end
+ end
+
def call(args)
@fn.call(args)
end