kairos-chain 3.42.0 → 3.42.2
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/CHANGELOG.md +43 -0
- data/lib/kairos_mcp/version.rb +1 -1
- data/templates/knowledge/loop_engineering_patterns/loop_engineering_patterns.md +5 -2
- data/templates/skillsets/document_authoring/lib/document_authoring/section_writer.rb +26 -22
- data/templates/skillsets/document_authoring/test/test_document_authoring.rb +34 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 45fd1079aa951da3ac40d0dcd9763e02c2a15413753d5452dab4fc07e928a3cb
|
|
4
|
+
data.tar.gz: 93e3969307c08b26782c81804c9b5b10c475407e4770962a04ec29ab227a7951
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e0d95027c4457cb89a1dee063b3637dc568fce57735e2be211119ace92d684b42451b03b176887202bc2eb797d71cb49af9e3ca49f0e0e9e00689c88ff74c177
|
|
7
|
+
data.tar.gz: fd1ac48f63e671ce7df974bab3efd35e2f3af8b626aeba655f56d3bffa933903d269f3d5775ae877203f9ef3050c66c5a3d5cbf69811ec113b9f5235b35d6574
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,49 @@ All notable changes to the `kairos-chain` gem will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
This project follows [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [3.42.2] - 2026-07-14
|
|
8
|
+
|
|
9
|
+
### Knowledge — loop_engineering_patterns §B: Model/Effort budget allocation
|
|
10
|
+
|
|
11
|
+
Extended the `loop_engineering_patterns` L1 entry (0.3 → 0.4) with a §B
|
|
12
|
+
design-craft note distilled from Anthropic's *Model and Effort in Claude Code*
|
|
13
|
+
post:
|
|
14
|
+
|
|
15
|
+
- Model (intelligence ceiling) and effort (per-request thoroughness) are
|
|
16
|
+
distinct levers; raise model when logic/knowledge is the wall, raise effort
|
|
17
|
+
when the loop skips steps.
|
|
18
|
+
- Because a loop compounds turns, uniform high effort multiplies latency —
|
|
19
|
+
concentrate high effort on the verify/judgment/decision gates, keep mechanical
|
|
20
|
+
dispatch turns low.
|
|
21
|
+
- The lever is the *orchestrator's*; a worker in a separate process (hermes body
|
|
22
|
+
subprocess, `agent`-skillset step) carries its own config and is unaffected.
|
|
23
|
+
- KairosChain delta: the non-bypassable gates (Prop 10 consent/audit floor,
|
|
24
|
+
INV-5 layer guard, verdict track) are where effort must not be cut — a stop
|
|
25
|
+
there is an irreversible Kairos moment (Prop 5), not a throughput step.
|
|
26
|
+
|
|
27
|
+
Added the `effort-allocation` tag and a "high/low effort for a long run?"
|
|
28
|
+
entry-point line. No code or behavior change.
|
|
29
|
+
|
|
30
|
+
## [3.42.1] - 2026-07-14
|
|
31
|
+
|
|
32
|
+
### Fixed — SectionWriter auto-chunk completeness & duplicate tail
|
|
33
|
+
|
|
34
|
+
Two follow-ups to the v3.42.0 auto-chunk on output-uncapped providers
|
|
35
|
+
(e.g. the `claude_code` CLI):
|
|
36
|
+
|
|
37
|
+
- **Completeness.** v3.42.0 added a per-chunk "rewrite ONLY these paragraphs"
|
|
38
|
+
bound to avoid a trailing duplicate. On `claude_code` that bound backfired —
|
|
39
|
+
the model under-produced and dropped the section tail, leaving long sections
|
|
40
|
+
incomplete. Removed the bound.
|
|
41
|
+
- **Duplicate tail (provider-agnostic).** Some providers "finish the section"
|
|
42
|
+
from the first chunk; the remaining passes then appended duplicate content.
|
|
43
|
+
`SectionWriter` now stops chunking once the assembled output already covers
|
|
44
|
+
~the whole source (`section_complete_fraction`, default 0.85). Providers that
|
|
45
|
+
rewrite each chunk faithfully (e.g. API adapters, where `max_tokens` is
|
|
46
|
+
honoured) never trip this and still run every chunk. Net: a single clean,
|
|
47
|
+
complete section on both provider kinds. `chunks` in the result now reports
|
|
48
|
+
the number of passes actually run.
|
|
49
|
+
|
|
7
50
|
## [3.42.0] - 2026-07-14
|
|
8
51
|
|
|
9
52
|
### Fixed / Improved — agent SkillSet self-drive on long document sections
|
data/lib/kairos_mcp/version.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: loop_engineering_patterns
|
|
3
3
|
description: Use before designing or classifying an agent loop in KairosChain — to pick a loop type, apply loop-design craft, and place each loop at the right layer under the Prop 10 floor. Claude Code's four loop types + design principles, extended with the governance constraint Anthropic omits.
|
|
4
|
-
version: "0.
|
|
5
|
-
tags: [loops, agent, autonomy, taxonomy, layer-placement, provenance]
|
|
4
|
+
version: "0.4"
|
|
5
|
+
tags: [loops, agent, autonomy, taxonomy, layer-placement, provenance, effort-allocation]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Loop Engineering Patterns
|
|
@@ -14,6 +14,7 @@ Open *before* designing or classifying an agent loop — not a runtime tool:
|
|
|
14
14
|
- New agent loop / autonomous cycle → pick a §A type, apply §B craft, then place it via §C.
|
|
15
15
|
- "Which layer owns this loop?" (harness vs gem/SkillSet, plus the cross-cutting L0 governance floor) → §C table + the L0 note below it.
|
|
16
16
|
- Strengthening the `agent` OODA loop (self-verification, semantic stop) → §B + §C evaluator/verifier notes.
|
|
17
|
+
- "High/low effort for a long run?" → §B budget-allocation note (concentrate effort on §C's non-bypassable gates).
|
|
17
18
|
- Explaining why KairosChain's autonomous mode keeps human checkpoints → §C Prop 10 floor.
|
|
18
19
|
- Not for: skill lifecycle/maturation → [[agent_skill_evolution_guide]]; general layer rules → [[layer_placement_guide]].
|
|
19
20
|
|
|
@@ -29,6 +30,8 @@ Micro (small) and macro (broad) loops compose; match loop complexity to problem
|
|
|
29
30
|
## B. Design craft (universal — adopt as-is)
|
|
30
31
|
Output quality tracks the surrounding harness, not the model alone. Keep the codebase clean so the loop follows existing patterns. **Encode verification as a skill with quantitative checks** so the loop measures its own work. Keep docs accessible/current. **Use a second, independent agent for review** (fresh context, separate session/model). Set explicit success/stop criteria and max-turn caps to bound cost; script deterministic steps instead of re-reasoning them; monitor token spend.
|
|
31
32
|
|
|
33
|
+
**Allocate reasoning budget by phase, not uniformly.** Model and effort are distinct levers ([Model and Effort in Claude Code](https://claude.com/blog/claude-model-and-effort-level-in-claude-code), Anthropic, 2026): model sets the intelligence ceiling — raise it when logic or knowledge is the wall; effort sets per-request thoroughness (files read, tests run, verification passes) — raise it when the loop skips steps, not when it lacks intelligence. Because a loop compounds turns, uniform high effort multiplies latency across every cycle: concentrate high effort on the verify / judgment / decision gates and keep mechanical dispatch turns low. Note this is the *orchestrator's* lever — it governs how carefully the loop monitors, verifies, and decides; it does not raise the quality of a worker running in a separate process (e.g. a hermes body subprocess or an `agent`-skillset step), which carries its own model/effort config. In KairosChain the non-bypassable gates — the Prop 10 consent/audit floor, the INV-5 layer guard, the verdict track — are exactly where effort must not be cut, since a stop there is an irreversible Kairos moment (§C, Prop 5), not a throughput step.
|
|
34
|
+
|
|
32
35
|
## C. KairosChain reading (layer placement + the floor Anthropic omits)
|
|
33
36
|
The four types are harness-framed (`/goal`, `/loop`, `/schedule`, `/usage`, auto mode are Claude Code mechanisms). KairosChain already implements most of the substance across layers — so the work is mostly *placement*, not adoption; one item is still design-stage (flagged in the table):
|
|
34
37
|
|
|
@@ -23,20 +23,27 @@ module KairosMcp
|
|
|
23
23
|
# paragraph boundaries and generate each chunk in its own pass, appending the
|
|
24
24
|
# results. Short contexts stay a single pass (chunks == [context_text]).
|
|
25
25
|
chunks = split_context(context_text, chunk_target)
|
|
26
|
+
source_chars = context_text.to_s.gsub(/\s+/, '').length
|
|
27
|
+
complete_at = (source_chars * complete_fraction).ceil
|
|
26
28
|
|
|
27
29
|
total_units = 0
|
|
28
30
|
total_chars = 0
|
|
31
|
+
chunks_written = 0
|
|
29
32
|
chunks.each_with_index do |chunk, idx|
|
|
30
33
|
first = idx.zero?
|
|
34
|
+
# Provider-agnostic de-duplication: some output-uncapped providers (e.g. the
|
|
35
|
+
# claude_code CLI) "finish the section" from the first chunk. Once the assembled
|
|
36
|
+
# output already covers ~the whole source, stop — further passes would only
|
|
37
|
+
# append duplicate content. Providers that rewrite each chunk faithfully never
|
|
38
|
+
# trip this (their per-chunk output tracks per-chunk input), so all chunks run.
|
|
39
|
+
break if !first && total_chars >= complete_at
|
|
40
|
+
|
|
41
|
+
# Continuation chunks must not repeat the section heading. (A stronger
|
|
42
|
+
# "rewrite only these paragraphs" bound was tried but backfired on the
|
|
43
|
+
# claude_code CLI — it then under-produced and dropped the section tail.)
|
|
31
44
|
chunk_instructions =
|
|
32
|
-
if chunks.length > 1
|
|
33
|
-
#
|
|
34
|
-
# "finish the section" (e.g. claude_code) regenerate the whole section from
|
|
35
|
-
# the first chunk, so later chunks duplicate content. Continuation chunks
|
|
36
|
-
# also must not repeat the heading.
|
|
37
|
-
notes = [bounded_note(language)]
|
|
38
|
-
notes << continuation_note(language) unless first
|
|
39
|
-
"#{instructions}\n\n#{notes.join("\n")}"
|
|
45
|
+
if chunks.length > 1 && !first
|
|
46
|
+
"#{instructions}\n\n#{continuation_note(language)}"
|
|
40
47
|
else
|
|
41
48
|
instructions
|
|
42
49
|
end
|
|
@@ -49,6 +56,7 @@ module KairosMcp
|
|
|
49
56
|
write_chunk(output_file, gen['content'], first ? append_mode : true)
|
|
50
57
|
total_units += count_units(gen['content'], language)
|
|
51
58
|
total_chars += gen['content'].gsub(/\s+/, '').length
|
|
59
|
+
chunks_written += 1
|
|
52
60
|
end
|
|
53
61
|
|
|
54
62
|
{
|
|
@@ -60,7 +68,7 @@ module KairosMcp
|
|
|
60
68
|
# non-whitespace char count so callers never size output from a bogus metric.
|
|
61
69
|
'word_count' => total_units,
|
|
62
70
|
'char_count' => total_chars,
|
|
63
|
-
'chunks' =>
|
|
71
|
+
'chunks' => chunks_written
|
|
64
72
|
}
|
|
65
73
|
end
|
|
66
74
|
|
|
@@ -167,24 +175,20 @@ module KairosMcp
|
|
|
167
175
|
end
|
|
168
176
|
|
|
169
177
|
# Auto-chunk threshold. Sized so each pass is small enough that output-uncapped
|
|
170
|
-
# providers (e.g. claude_code CLI) emit
|
|
178
|
+
# providers (e.g. claude_code CLI) emit a full section without stopping early —
|
|
171
179
|
# empirically a larger single pass truncates, while ~3000-char passes complete.
|
|
172
|
-
#
|
|
180
|
+
# On such providers the first chunk may "finish the section", so the output can
|
|
181
|
+
# carry a trailing duplicate fragment; completeness is favoured over that cosmetic
|
|
182
|
+
# cost. API providers (with max_tokens honoured) produce a clean single section.
|
|
183
|
+
# Overridable via config.
|
|
173
184
|
def chunk_target
|
|
174
185
|
(@config['section_chunk_target_chars'] || 3000).to_i
|
|
175
186
|
end
|
|
176
187
|
|
|
177
|
-
#
|
|
178
|
-
#
|
|
179
|
-
def
|
|
180
|
-
|
|
181
|
-
'重要: 以下に与えた段落だけを推敲せよ。節はいくつかに分けて処理される。' \
|
|
182
|
-
'与えられていない段落を書き足したり、節の続きをここで完成させたりしてはならない。'
|
|
183
|
-
else
|
|
184
|
-
'IMPORTANT: Rewrite ONLY the paragraphs given below. The section is processed ' \
|
|
185
|
-
'in several passes; do NOT add paragraphs that are not in this input or ' \
|
|
186
|
-
'finish the rest of the section here.'
|
|
187
|
-
end
|
|
188
|
+
# Fraction of the source (by non-whitespace chars) at which the assembled output is
|
|
189
|
+
# considered to already cover the whole section, so remaining chunks are skipped.
|
|
190
|
+
def complete_fraction
|
|
191
|
+
(@config['section_complete_fraction'] || 0.85).to_f
|
|
188
192
|
end
|
|
189
193
|
|
|
190
194
|
# Appended to a continuation chunk's instructions so the model does not repeat the
|
|
@@ -468,6 +468,40 @@ assert("T18g: append_mode applies only to the first chunk; later chunks append")
|
|
|
468
468
|
content.start_with?('PRE') && content.include?("c1\n\nc2\n\nc3")
|
|
469
469
|
end
|
|
470
470
|
|
|
471
|
+
assert("T18h: stops chunking once output already covers the whole source (no duplicate tail)") do
|
|
472
|
+
caller = MockCallerTool.new
|
|
473
|
+
calls = 0
|
|
474
|
+
caller.define_singleton_method(:invoke_tool) do |tool_name, arguments = {}, context: nil|
|
|
475
|
+
calls += 1
|
|
476
|
+
# First pass "finishes the section" (output >= source); a later pass would be a dup.
|
|
477
|
+
body = calls == 1 ? ('な' * 500) : 'DUPLICATE'
|
|
478
|
+
[{ text: JSON.generate({ 'status' => 'ok', 'response' => { 'content' => body }, 'snapshot' => {} }) }]
|
|
479
|
+
end
|
|
480
|
+
writer = SW.new(caller, { 'section_chunk_target_chars' => 100 })
|
|
481
|
+
ctx = (1..5).map { ('あ' * 80) }.join("\n\n") # ~400 non-ws source chars, would be 5 chunks
|
|
482
|
+
out = File.join(TMPDIR, 'earlystop.md')
|
|
483
|
+
r = writer.write(section_name: 's', instructions: 'i', context_text: ctx,
|
|
484
|
+
output_file: out, max_words: 100, language: 'ja', append_mode: false)
|
|
485
|
+
# chunk1 output (500) >= 0.85 * 400 = 340 → stop after the first pass
|
|
486
|
+
r['chunks'] == 1 && calls == 1 && !File.read(out).include?('DUPLICATE')
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
assert("T18i: faithful per-chunk provider still runs all chunks (no premature stop)") do
|
|
490
|
+
caller = MockCallerTool.new
|
|
491
|
+
calls = 0
|
|
492
|
+
caller.define_singleton_method(:invoke_tool) do |tool_name, arguments = {}, context: nil|
|
|
493
|
+
calls += 1
|
|
494
|
+
[{ text: JSON.generate({ 'status' => 'ok', 'response' => { 'content' => "p#{calls}" }, 'snapshot' => {} }) }]
|
|
495
|
+
end
|
|
496
|
+
writer = SW.new(caller, { 'section_chunk_target_chars' => 100 })
|
|
497
|
+
ctx = (1..4).map { ('あ' * 80) }.join("\n\n")
|
|
498
|
+
out = File.join(TMPDIR, 'faithful.md')
|
|
499
|
+
r = writer.write(section_name: 's', instructions: 'i', context_text: ctx,
|
|
500
|
+
output_file: out, max_words: 100, language: 'ja', append_mode: false)
|
|
501
|
+
# short per-chunk output never reaches the completeness threshold → all chunks run
|
|
502
|
+
r['chunks'] > 1 && calls == r['chunks'] && File.read(out).include?("p#{calls}")
|
|
503
|
+
end
|
|
504
|
+
|
|
471
505
|
assert("T18d: max_tokens respects config ceiling override") do
|
|
472
506
|
caller = MockCallerTool.new
|
|
473
507
|
captured = {}
|