Class: AgentHarness::Providers::Kilocode
- Inherits:
-
Base
- Object
- Base
- AgentHarness::Providers::Kilocode
show all
- Defined in:
- lib/agent_harness/providers/kilocode.rb
Overview
Kilocode CLI provider
Provides integration with the Kilocode CLI tool.
Constant Summary
collapse
- PACKAGE_NAME =
"@kilocode/cli"
- DEFAULT_VERSION =
"7.4.16"
- SUPPORTED_VERSION_REQUIREMENT =
"= #{DEFAULT_VERSION}"
- STRUCTURED_EVENT_TYPES =
%w[text error step_finish result usage].freeze
- MODEL_NAMES =
%w[
glm-5
glm-5.1
glm-5.1-free
glm-5.1-thinking
glm-5.2
glm-5.2-fast
glm-5.2-flex
glm-5.2-free
glm-5.2-nitro
glm-5.2-short
glm-5.2-short-fast
glm-5.2-short-fast-flex
glm-5.2-short-flex
glm-5p1
glm-5p1-fast
glm-5p2
glm-5p2-fast
glm-5v-turbo
].freeze
- MODEL_CATALOG =
MODEL_NAMES.map do |name|
tier = name.include?("free") ? "free" : "standard"
tier = "advanced" if %w[glm-5.1 glm-5.1-thinking glm-5.2 glm-5p1 glm-5p2].include?(name)
{name: name, family: name, tier: tier, provider: "kilocode"}.freeze
end.freeze
- MODEL_FAMILY_PATTERN =
/\Aglm-5(?:[a-z][\w.-]*|[.-][\w.-]+)?\z/i
- DEFAULT_PERMISSION_EXTERNAL_DIRECTORY_PATTERNS =
Kilo CLI (an OpenCode fork) ships the same external_directory
permission category as OpenCode, defaulting to "ask" for anything
outside the project dir. In non-interactive execution there is no
human to answer the prompt, so dedicated read/write/edit tool calls
targeting paths outside the project dir are auto-rejected and the
agent silently loses access to its own scratch output or its own
config/data files, killing the run without a recoverable error.
This default rule broadens the allowlist to all of /tmp (so the agent
can read back files it or its sub-agents wrote there) and to the full
agent home directory (so the agent can inspect/maintain its own
config, cache, and data files such as ~/.config/kilocode,
~/.local/share/kilo, ~/.cache). The container is already isolated
(Docker, non-root user) and the agent runs with --auto which approves
everything inside the project dir. See #289 (precedent: #282/#277).
["/tmp/**", "/home/agent/**"].freeze
- DEFAULT_PERMISSION_CONFIG =
{
"external_directory" => DEFAULT_PERMISSION_EXTERNAL_DIRECTORY_PATTERNS
.to_h { |pattern| [pattern, "allow"] }
.freeze
}.freeze
- USAGE_EVENT_TYPES =
%w[result usage].freeze
- TOKEN_USAGE_KEYS =
%w[
input_tokens
output_tokens
total_tokens
total
reasoning_tokens
cache_creation_input_tokens
cache_read_input_tokens
cache_write_input_tokens
].freeze
Constants inherited
from Base
Base::COMMON_ERROR_PATTERNS, Base::DEFAULT_SMOKE_TEST_CONTRACT
Instance Attribute Summary
Attributes inherited from Base
#config, #executor, #logger
Class Method Summary
collapse
Instance Method Summary
collapse
Methods inherited from Base
#api_key_env_var_names, #api_key_unset_vars, #check_quota, #cli_env_overrides, #configure, #initialize, #parse_container_output, #parse_test_error, #plan_execution, #preflight_check, #sandboxed_environment?, #send_chat_message, #send_message, #subscription_unset_vars, #update_quota_from_headers
#parse_rate_limit_reset
Methods included from Adapter
#auth_lock_config, #auth_type, #build_mcp_flags, #chat_transport, #chat_transport_type, #configuration_schema, #dangerous_mode_flags, #error_classification_patterns, #fetch_mcp_servers, #health_status, included, metadata_package_name, #noisy_error_patterns, normalize_metadata_installation, normalize_metadata_runtime_requirements, normalize_metadata_source_type, normalize_metadata_version_requirement, #notify_hook_content, #parse_rate_limit_reset, #plan_execution, #preflight_check, #send_message, #session_flags, #smoke_test, #smoke_test_contract, #supported_mcp_transports, #supports_chat?, #supports_dangerous_mode?, #supports_mcp?, #supports_message_tool_injection?, #supports_sessions?, #supports_text_mode?, #supports_token_counting?, #supports_tool_control?, #token_usage_from_api_response, #translate_error, #validate_config, #validate_mcp_servers!
Class Method Details
.binary_name ⇒ Object
81
82
83
|
# File 'lib/agent_harness/providers/kilocode.rb', line 81
def binary_name
"kilo"
end
|
.discover_models ⇒ Object
101
102
103
104
105
|
# File 'lib/agent_harness/providers/kilocode.rb', line 101
def discover_models
return [] unless available?
MODEL_CATALOG.map(&:dup)
end
|
.firewall_requirements ⇒ Object
90
91
92
93
94
95
|
# File 'lib/agent_harness/providers/kilocode.rb', line 90
def firewall_requirements
{
domains: [],
ip_ranges: []
}
end
|
.install_command(version: DEFAULT_VERSION) ⇒ Object
136
137
138
|
# File 'lib/agent_harness/providers/kilocode.rb', line 136
def install_command(version: DEFAULT_VERSION)
installation_contract(version: version)[:install_command]
end
|
.installation_contract(version: DEFAULT_VERSION) ⇒ Object
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
# File 'lib/agent_harness/providers/kilocode.rb', line 119
def installation_contract(version: DEFAULT_VERSION)
version = version.strip if version.respond_to?(:strip)
validate_install_version!(version)
package_spec = "#{PACKAGE_NAME}@#{version}"
{
source: {
type: :npm,
package: PACKAGE_NAME
},
install_command: ["npm", "install", "-g", "--ignore-scripts", package_spec],
binary_name: binary_name,
default_version: DEFAULT_VERSION,
supported_version_requirement: SUPPORTED_VERSION_REQUIREMENT
}
end
|
.instruction_file_paths ⇒ Object
97
98
99
|
# File 'lib/agent_harness/providers/kilocode.rb', line 97
def instruction_file_paths
[]
end
|
.model_family(provider_model_name) ⇒ Object
107
108
109
|
# File 'lib/agent_harness/providers/kilocode.rb', line 107
def model_family(provider_model_name)
provider_model_name.to_s
end
|
.provider_model_name(family_name) ⇒ Object
111
112
113
|
# File 'lib/agent_harness/providers/kilocode.rb', line 111
def provider_model_name(family_name)
family_name.to_s
end
|
.provider_name ⇒ Object
77
78
79
|
# File 'lib/agent_harness/providers/kilocode.rb', line 77
def provider_name
:kilocode
end
|
.smoke_test_contract ⇒ Object
.supports_model_family?(family_name) ⇒ Boolean
115
116
117
|
# File 'lib/agent_harness/providers/kilocode.rb', line 115
def supports_model_family?(family_name)
MODEL_FAMILY_PATTERN.match?(family_name.to_s)
end
|
Instance Method Details
#capabilities ⇒ Object
182
183
184
185
186
187
188
189
190
191
192
|
# File 'lib/agent_harness/providers/kilocode.rb', line 182
def capabilities
{
streaming: false,
file_upload: false,
vision: false,
tool_use: false,
json_mode: false,
mcp: false,
dangerous_mode: false
}
end
|
#config_file_content(options = {}) ⇒ Object
227
228
229
230
231
232
233
234
235
236
237
238
239
|
# File 'lib/agent_harness/providers/kilocode.rb', line 227
def config_file_content(options = {})
provider_name = options[:provider_name] || "openai"
model_id = options[:model_id]
config = {"provider" => {provider_name => {}}}
config["model"] = "#{provider_name}/#{model_id}" if model_id
apply_default_external_directory_permission(config, options)
config.to_json
end
|
#display_name ⇒ Object
174
175
176
|
# File 'lib/agent_harness/providers/kilocode.rb', line 174
def display_name
"Kilocode CLI"
end
|
#error_patterns ⇒ Object
241
242
243
|
# File 'lib/agent_harness/providers/kilocode.rb', line 241
def error_patterns
COMMON_ERROR_PATTERNS
end
|
#execution_semantics ⇒ Object
245
246
247
248
249
250
251
252
253
254
255
256
|
# File 'lib/agent_harness/providers/kilocode.rb', line 245
def execution_semantics
{
prompt_delivery: :arg,
output_format: :json,
sandbox_aware: false,
uses_subcommand: true,
non_interactive_flag: nil,
legitimate_exit_codes: [0],
stderr_is_diagnostic: true,
parses_rate_limit_reset: true
}
end
|
#heartbeat_integration(heartbeat_file_path:) ⇒ Object
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
# File 'lib/agent_harness/providers/kilocode.rb', line 198
def heartbeat_integration(heartbeat_file_path:)
unless heartbeat_file_path.is_a?(String) && !heartbeat_file_path.strip.empty?
raise ArgumentError, "heartbeat_file_path must be a non-empty String"
end
unless heartbeat_file_path.start_with?("/")
raise ArgumentError, "heartbeat_file_path must be an absolute path (got #{heartbeat_file_path.inspect})"
end
hook_script = heartbeat_hook_script(heartbeat_file_path)
config_payload = merge_heartbeat_hooks(hook_script)
preparation = ExecutionPreparation.new(
file_writes: [
{
path: heartbeat_hook_config_path,
content: JSON.pretty_generate(config_payload),
mode: 0o600
}
]
)
{
supported: true,
env: {"KILO_HEARTBEAT_FILE" => heartbeat_file_path},
preparation: preparation,
granularity: :tool_call
}
end
|
#name ⇒ Object
170
171
172
|
# File 'lib/agent_harness/providers/kilocode.rb', line 170
def name
"kilocode"
end
|
#supports_activity_heartbeat? ⇒ Boolean
194
195
196
|
# File 'lib/agent_harness/providers/kilocode.rb', line 194
def supports_activity_heartbeat?
true
end
|
#test_command_overrides ⇒ Object
178
179
180
|
# File 'lib/agent_harness/providers/kilocode.rb', line 178
def test_command_overrides
["--auto", "--print-logs"]
end
|