kairos-chain 3.28.1 → 3.28.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/kairos_mcp/tool_registry.rb +1 -0
- data/lib/kairos_mcp/tools/knowledge_update.rb +16 -3
- data/lib/kairos_mcp/tools/resource_render.rb +187 -0
- data/lib/kairos_mcp/version.rb +1 -1
- data/templates/knowledge/multi_llm_review_workflow/multi_llm_review_workflow.md +5 -5
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1ff86076f5769d3e1a773ad792416fddb4198df5c979159fafc353ec49a57bc0
|
|
4
|
+
data.tar.gz: b05464fc1d1830246de471e5964444035de03249638c1bb2b8746d272e51f506
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4ad7dc9c3f4bad3714e56698f4e97b797e084869ae207203f077b4d2fe8eb9295f763f82b832371c990a3cd157a8b051d95aae4ea9986560a1d8ac7820bc8661
|
|
7
|
+
data.tar.gz: 3a30fbbad2d529c1f3910e902baf8117faac9516e1b8361047c47800492657a2b7ec219a961e266360b9ace6031b86ccfd85ea60584006a1ddd614e55f681bbf
|
|
@@ -215,6 +215,7 @@ module KairosMcp
|
|
|
215
215
|
# Resource tools (unified access to L0/L1/L2 resources)
|
|
216
216
|
register_if_defined('KairosMcp::Tools::ResourceList')
|
|
217
217
|
register_if_defined('KairosMcp::Tools::ResourceRead')
|
|
218
|
+
register_if_defined('KairosMcp::Tools::ResourceRender')
|
|
218
219
|
|
|
219
220
|
# L1: knowledge/ (Anthropic skills format with hash-only blockchain record)
|
|
220
221
|
register_if_defined('KairosMcp::Tools::KnowledgeList')
|
|
@@ -12,7 +12,9 @@ module KairosMcp
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def description
|
|
15
|
-
'Create, update, or delete L1 knowledge skills. Changes are recorded with hash references to the blockchain.'
|
|
15
|
+
'Create, update, or delete L1 knowledge skills. Changes are recorded with hash references to the blockchain. ' \
|
|
16
|
+
'NOTE: MCP stdio transport may silently drop large arguments. Keep combined content + reason under ~2 KB. ' \
|
|
17
|
+
'For larger L1 entries, trim prose or split into multiple entries.'
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
def category
|
|
@@ -105,14 +107,14 @@ module KairosMcp
|
|
|
105
107
|
private
|
|
106
108
|
|
|
107
109
|
def handle_create(provider, name, content, reason, create_subdirs)
|
|
108
|
-
return text_content("
|
|
110
|
+
return text_content(content_missing_error("create", content)) unless content && !content.empty?
|
|
109
111
|
|
|
110
112
|
result = provider.create(name, content, reason: reason, create_subdirs: create_subdirs)
|
|
111
113
|
format_result(result, 'created')
|
|
112
114
|
end
|
|
113
115
|
|
|
114
116
|
def handle_update(provider, name, content, reason)
|
|
115
|
-
return text_content("
|
|
117
|
+
return text_content(content_missing_error("update", content)) unless content && !content.empty?
|
|
116
118
|
|
|
117
119
|
result = provider.update(name, content, reason: reason)
|
|
118
120
|
format_result(result, 'updated')
|
|
@@ -123,6 +125,17 @@ module KairosMcp
|
|
|
123
125
|
format_result(result, 'deleted')
|
|
124
126
|
end
|
|
125
127
|
|
|
128
|
+
def content_missing_error(command, content)
|
|
129
|
+
if content.nil?
|
|
130
|
+
"Error: content is required for #{command}. " \
|
|
131
|
+
"The content argument arrived as nil — this often means the MCP transport silently dropped it " \
|
|
132
|
+
"because the combined argument size exceeded the client limit (~2 KB for stdio). " \
|
|
133
|
+
"Try trimming content and reason, or split into smaller entries."
|
|
134
|
+
else
|
|
135
|
+
"Error: content is required for #{command} (received empty string)"
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
126
139
|
def format_result(result, action)
|
|
127
140
|
if result[:success]
|
|
128
141
|
output = "SUCCESS: Knowledge #{action}\n\n"
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'open3'
|
|
4
|
+
require 'timeout'
|
|
5
|
+
require_relative 'base_tool'
|
|
6
|
+
require_relative '../anthropic_skill_parser'
|
|
7
|
+
|
|
8
|
+
module KairosMcp
|
|
9
|
+
module Tools
|
|
10
|
+
class ResourceRender < BaseTool
|
|
11
|
+
RENDER_TIMEOUT = 30
|
|
12
|
+
|
|
13
|
+
def name
|
|
14
|
+
'resource_render'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def description
|
|
18
|
+
'Execute a render script from a knowledge entry to generate an HTML asset. ' \
|
|
19
|
+
'Scripts live in knowledge/{name}/scripts/ and output HTML to assets/. ' \
|
|
20
|
+
'Data is passed via stdin as JSON. Convention: scripts named render_*.rb.'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def category
|
|
24
|
+
:resource
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def usecase_tags
|
|
28
|
+
%w[render html visualize dashboard asset generate]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def examples
|
|
32
|
+
[
|
|
33
|
+
{
|
|
34
|
+
title: 'Generate review dashboard',
|
|
35
|
+
code: 'resource_render(knowledge: "multi_llm_review_workflow", ' \
|
|
36
|
+
'script: "render_dashboard.rb", data: "{...}", open: true)'
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
title: 'Generate with custom output name',
|
|
40
|
+
code: 'resource_render(knowledge: "multi_llm_review_workflow", ' \
|
|
41
|
+
'script: "render_dashboard.rb", data: "{...}", output: "round2.html")'
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def related_tools
|
|
47
|
+
%w[resource_list resource_read knowledge_get]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def input_schema
|
|
51
|
+
{
|
|
52
|
+
type: 'object',
|
|
53
|
+
properties: {
|
|
54
|
+
knowledge: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
description: 'L1 knowledge entry name (e.g., "multi_llm_review_workflow")'
|
|
57
|
+
},
|
|
58
|
+
script: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
description: 'Script filename in the knowledge scripts/ directory (e.g., "render_dashboard.rb")'
|
|
61
|
+
},
|
|
62
|
+
data: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
description: 'JSON data to pass to the script via stdin'
|
|
65
|
+
},
|
|
66
|
+
output: {
|
|
67
|
+
type: 'string',
|
|
68
|
+
description: 'Output filename in assets/ (default: derived from script name, e.g., render_dashboard.rb -> dashboard.html)'
|
|
69
|
+
},
|
|
70
|
+
open: {
|
|
71
|
+
type: 'boolean',
|
|
72
|
+
description: 'Open the generated HTML in the default browser (default: false)'
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
required: %w[knowledge script data]
|
|
76
|
+
}
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def call(arguments)
|
|
80
|
+
knowledge_name = arguments['knowledge']
|
|
81
|
+
script_name = arguments['script']
|
|
82
|
+
data = arguments['data']
|
|
83
|
+
output_name = arguments['output']
|
|
84
|
+
open_after = arguments['open'] || false
|
|
85
|
+
|
|
86
|
+
return text_content("Error: knowledge is required") unless knowledge_name && !knowledge_name.empty?
|
|
87
|
+
return text_content("Error: script is required") unless script_name && !script_name.empty?
|
|
88
|
+
return text_content("Error: data is required") unless data && !data.empty?
|
|
89
|
+
|
|
90
|
+
# Validate JSON
|
|
91
|
+
begin
|
|
92
|
+
JSON.parse(data)
|
|
93
|
+
rescue JSON::ParserError => e
|
|
94
|
+
return text_content("Error: invalid JSON data — #{e.message}")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Resolve knowledge directory
|
|
98
|
+
knowledge_dir = File.join(KairosMcp.knowledge_dir(user_context: @safety&.current_user), knowledge_name)
|
|
99
|
+
unless File.directory?(knowledge_dir)
|
|
100
|
+
return text_content("Error: knowledge '#{knowledge_name}' not found")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Security: normalize script name to prevent path traversal
|
|
104
|
+
safe_script = File.basename(script_name)
|
|
105
|
+
script_path = File.join(knowledge_dir, 'scripts', safe_script)
|
|
106
|
+
unless File.exist?(script_path)
|
|
107
|
+
return text_content("Error: script '#{safe_script}' not found in #{knowledge_name}/scripts/")
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Derive output filename
|
|
111
|
+
if output_name
|
|
112
|
+
safe_output = File.basename(output_name)
|
|
113
|
+
else
|
|
114
|
+
safe_output = safe_script
|
|
115
|
+
.sub(/\Arender_/, '')
|
|
116
|
+
.sub(/\.rb\z/, '.html')
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Ensure assets/ directory exists
|
|
120
|
+
assets_dir = File.join(knowledge_dir, 'assets')
|
|
121
|
+
FileUtils.mkdir_p(assets_dir)
|
|
122
|
+
|
|
123
|
+
# Execute script with data on stdin
|
|
124
|
+
stdout, stderr, status = execute_script(script_path, data, knowledge_dir)
|
|
125
|
+
|
|
126
|
+
unless status.success?
|
|
127
|
+
error_msg = "Error: script exited with code #{status.exitstatus}"
|
|
128
|
+
error_msg += "\n\nstderr:\n```\n#{stderr}\n```" unless stderr.empty?
|
|
129
|
+
return text_content(error_msg)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
if stdout.nil? || stdout.empty?
|
|
133
|
+
return text_content("Error: script produced no output")
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Write output to assets/
|
|
137
|
+
output_path = File.join(assets_dir, safe_output)
|
|
138
|
+
AnthropicSkillParser.atomic_write(output_path, stdout)
|
|
139
|
+
|
|
140
|
+
# Open in browser if requested
|
|
141
|
+
if open_after
|
|
142
|
+
system('open', output_path)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
uri = "knowledge://#{knowledge_name}/assets/#{safe_output}"
|
|
146
|
+
build_success_response(uri, output_path, stdout.bytesize, open_after)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
private
|
|
150
|
+
|
|
151
|
+
def execute_script(script_path, data, working_dir)
|
|
152
|
+
Timeout.timeout(RENDER_TIMEOUT) do
|
|
153
|
+
Open3.capture3(
|
|
154
|
+
'ruby', script_path,
|
|
155
|
+
stdin_data: data,
|
|
156
|
+
chdir: working_dir
|
|
157
|
+
)
|
|
158
|
+
end
|
|
159
|
+
rescue Timeout::Error
|
|
160
|
+
["", "Script execution timed out after #{RENDER_TIMEOUT}s", OpenStruct.new(success?: false, exitstatus: 124)]
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def build_success_response(uri, path, size, opened)
|
|
164
|
+
output = "## Resource Rendered\n\n"
|
|
165
|
+
output += "| Property | Value |\n"
|
|
166
|
+
output += "|----------|-------|\n"
|
|
167
|
+
output += "| **URI** | `#{uri}` |\n"
|
|
168
|
+
output += "| **Path** | `#{path}` |\n"
|
|
169
|
+
output += "| **Size** | #{format_size(size)} |\n"
|
|
170
|
+
output += "| **Opened** | #{opened ? 'Yes' : 'No'} |\n\n"
|
|
171
|
+
output += "Use `resource_read(uri: \"#{uri}\")` to read the generated content.\n"
|
|
172
|
+
output += "Use `open #{path}` to view in browser." unless opened
|
|
173
|
+
text_content(output)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def format_size(bytes)
|
|
177
|
+
if bytes < 1024
|
|
178
|
+
"#{bytes} B"
|
|
179
|
+
elsif bytes < 1024 * 1024
|
|
180
|
+
"#{(bytes / 1024.0).round(1)} KB"
|
|
181
|
+
else
|
|
182
|
+
"#{(bytes / (1024.0 * 1024)).round(1)} MB"
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
data/lib/kairos_mcp/version.rb
CHANGED
|
@@ -193,7 +193,7 @@ starting** and verify each against `config/multi_llm_review.yml`:
|
|
|
193
193
|
- [ ] Your model (orchestrator): ___
|
|
194
194
|
- [ ] Agent Team Personas model: = orchestrator model (NOT a different model)
|
|
195
195
|
- [ ] Subprocess CLI model: opposite Opus (4.6 if you are 4.7, vice versa)
|
|
196
|
-
- [ ] Codex models: gpt-5.
|
|
196
|
+
- [ ] Codex models: gpt-5.5 (default) AND gpt-5.4 (both, not either/or)
|
|
197
197
|
- [ ] Cursor model: default (composer-2.5, no --model flag)
|
|
198
198
|
- [ ] Total reviewer count: 5 (or 4 after orchestrator exclusion from subprocess)
|
|
199
199
|
- [ ] Convergence rule: 3/5 APPROVE (full) or 3/4 APPROVE (after exclusion)
|
|
@@ -410,7 +410,7 @@ which claude 2>/dev/null && echo "claude: available" || echo "claude: NOT FOUND"
|
|
|
410
410
|
|
|
411
411
|
| Tool | Command | Prompt Input | Output Collection | Model |
|
|
412
412
|
|------|---------|-------------|-------------------|-------|
|
|
413
|
-
| **Codex** | `codex exec` | stdin pipe: `cat prompt.md \| codex exec -` | `-o /path/output.md` | GPT-5.
|
|
413
|
+
| **Codex** | `codex exec` | stdin pipe: `cat prompt.md \| codex exec -` | `-o /path/output.md` | GPT-5.5 (default) |
|
|
414
414
|
| **Cursor Agent** | `agent -p` | File reference (stdin NOT supported) | stdout redirect: `> output.md` | Composer-2.5 (default) |
|
|
415
415
|
| **Claude Code** | Agent tool (internal) | Direct prompt string | Write to workspace file | Opus 4.6 (session) |
|
|
416
416
|
| **Claude CLI (4.7)** | `claude -p --model claude-opus-4-7 --bare` | stdin pipe: `cat prompt.md \| claude -p --model claude-opus-4-7 --bare` | stdout redirect: `> output.md` | Opus 4.7 |
|
|
@@ -426,7 +426,7 @@ Based on cross-evaluation experiment (7 models × 4 tasks + Nomic, 518 CLI calls
|
|
|
426
426
|
| **Reviewer: Claude CLI** | Opus 4.7 | `--effort low` | Evaluator quality is effort-independent (low≈high: 8.35 vs 8.16) |
|
|
427
427
|
| **Coding sub-agent** | Opus 4.7 | `--effort medium` | Cost-effective default; use `high` for complex tasks |
|
|
428
428
|
| **Design sub-agent** | Opus 4.7 | `--effort medium` | Cost-effective default; use `high` for complex tasks |
|
|
429
|
-
| **Codex** | GPT-5.
|
|
429
|
+
| **Codex** | GPT-5.5 (default) | (no flag) | Fixed effort |
|
|
430
430
|
| **Cursor Agent** | Composer-2.5 | (no flag) | Fixed effort |
|
|
431
431
|
|
|
432
432
|
Key findings:
|
|
@@ -709,7 +709,7 @@ Step 1: Generate review prompt
|
|
|
709
709
|
Step 2: Detect environment and models
|
|
710
710
|
- Run: which codex && which agent && which claude
|
|
711
711
|
- Detect default models
|
|
712
|
-
- Report: "Auto mode: Codex (gpt-5.
|
|
712
|
+
- Report: "Auto mode: Codex (gpt-5.5), Agent (composer-2.5), Claude (opus-4.6), Claude CLI (opus-4.7)"
|
|
713
713
|
|
|
714
714
|
Step 3: Execute N reviews in parallel (default 4 reviewers)
|
|
715
715
|
- Bash(background): cat prompt.md | codex exec -C workspace -o log/review_codex.md -
|
|
@@ -753,7 +753,7 @@ log/{artifact}_review{N}_consensus_{date}.md # Consensus analysis
|
|
|
753
753
|
```
|
|
754
754
|
|
|
755
755
|
LLM identifiers: `claude_opus4.6`, `claude_team_opus4.6`,
|
|
756
|
-
`claude_cli_opus4.7`, `codex_gpt5.4`, `cursor_composer2`, `cursor_gpt5.4`,
|
|
756
|
+
`claude_cli_opus4.7`, `codex_gpt5.5`, `codex_gpt5.4`, `cursor_composer2`, `cursor_gpt5.4`,
|
|
757
757
|
`cursor_premium`
|
|
758
758
|
|
|
759
759
|
## Internal Agent Team Review
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kairos-chain
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.28.
|
|
4
|
+
version: 3.28.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Masaomi Hatakeyama
|
|
@@ -194,6 +194,7 @@ files:
|
|
|
194
194
|
- lib/kairos_mcp/tools/knowledge_update.rb
|
|
195
195
|
- lib/kairos_mcp/tools/resource_list.rb
|
|
196
196
|
- lib/kairos_mcp/tools/resource_read.rb
|
|
197
|
+
- lib/kairos_mcp/tools/resource_render.rb
|
|
197
198
|
- lib/kairos_mcp/tools/skills_audit.rb
|
|
198
199
|
- lib/kairos_mcp/tools/skills_dsl_get.rb
|
|
199
200
|
- lib/kairos_mcp/tools/skills_dsl_list.rb
|