insika 0.7.0 → 0.8.0
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 +116 -0
- data/README.md +4 -3
- data/bin/insika +43 -2
- data/docs/AGENTS.md +22 -3
- data/docs/ARTIFACTS.md +42 -0
- data/docs/CONTEXT.md +54 -12
- data/docs/DEPLOY.md +16 -7
- data/docs/LOADTEST.md +15 -27
- data/docs/MEDIA.md +1 -1
- data/docs/OBSERVABILITY.md +31 -2
- data/docs/POLICY.md +10 -4
- data/docs/RUNNING-LOCAL.md +2 -2
- data/docs/SECURITY.md +1 -1
- data/docs/SOAK.md +1 -1
- data/docs/TOOLS.md +24 -0
- data/docs/prompts/GO-LIVE.md +3 -3
- data/lib/insika/agent_profile.rb +26 -1
- data/lib/insika/chat_builder.rb +28 -17
- data/lib/insika/compaction.rb +196 -0
- data/lib/insika/context/builder.rb +6 -2
- data/lib/insika/context/fragment.rb +4 -1
- data/lib/insika/context/priority.rb +6 -0
- data/lib/insika/context/providers/briefing.rb +53 -24
- data/lib/insika/context/providers/session.rb +46 -10
- data/lib/insika/context_trace_store.rb +11 -1
- data/lib/insika/doctor.rb +105 -10
- data/lib/insika/dsl/runtime.rb +4 -0
- data/lib/insika/env_schema.rb +5 -6
- data/lib/insika/evals/transport.rb +1 -1
- data/lib/insika/executor.rb +64 -0
- data/lib/insika/loop_detector.rb +5 -34
- data/lib/insika/profile_source.rb +7 -0
- data/lib/insika/server/responses.rb +4 -4
- data/lib/insika/session_store.rb +34 -4
- data/lib/insika/settings_store.rb +8 -1
- data/lib/insika/soak/runner.rb +4 -4
- data/lib/insika/studio/app.rb +28 -6
- data/lib/insika/studio/forms.rb +11 -0
- data/lib/insika/studio/views/settings.erb +11 -0
- data/lib/insika/telemetry/recorder.rb +49 -1
- data/lib/insika/templates/daily-digest/README.md +9 -0
- data/lib/insika/templates/research-analyst/agent.rb +10 -0
- data/lib/insika/tool_batch.rb +67 -0
- data/lib/insika/tool_usage_report.rb +162 -0
- data/lib/insika/turn_budget.rb +91 -0
- data/lib/insika/version.rb +1 -1
- data/lib/insika.rb +7 -0
- metadata +5 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Insika
|
|
4
|
+
# The turn's tool-call counter — one object, three jobs: count, warn, abort.
|
|
5
|
+
#
|
|
6
|
+
# `max_tool_calls` was enforced but never announced: the model learned of the
|
|
7
|
+
# ceiling only when the turn DIED with `stage: :tool_limit`. A real run in
|
|
8
|
+
# `round1.db` (task d0421891) burned all 50 calls summing a 40-number list one
|
|
9
|
+
# `calc` at a time and delivered nothing — the model had no way to know it was
|
|
10
|
+
# spending a budget at all.
|
|
11
|
+
#
|
|
12
|
+
# So the budget speaks before it kills: at 10 / 5 / 2 calls remaining the
|
|
13
|
+
# engine appends a short notice and the model gets to converge on an answer.
|
|
14
|
+
#
|
|
15
|
+
# · **User turn, never system.** The system prefix stays byte-stable, so the
|
|
16
|
+
# Anthropic cache breakpoint (`chat_builder.rb`'s `apply_instructions`) keeps
|
|
17
|
+
# hitting. A notice in the prompt would bill a cache WRITE every turn.
|
|
18
|
+
# · **Batch boundary only** (ToolBatch), and **a halted batch receives
|
|
19
|
+
# nothing** — the two rules SteerInjector established for mid-turn appends.
|
|
20
|
+
# · **Off when there is no limit.** `max: nil` = count nothing, warn nothing,
|
|
21
|
+
# abort never.
|
|
22
|
+
#
|
|
23
|
+
# KNOWN REACH (measured against DeepSeek, 2026-08-30): a model that announces
|
|
24
|
+
# ONE batch bigger than the whole budget — 30 independent tool calls in a single
|
|
25
|
+
# assistant message — never reaches a boundary before the abort, so it gets no
|
|
26
|
+
# notice. Nothing can be appended mid-batch, so that shape is out of reach by
|
|
27
|
+
# construction; it is also the shape where the model already knows what it asked
|
|
28
|
+
# for. What this catches is the SEQUENTIAL burn, which is the one `round1.db`
|
|
29
|
+
# actually shows: 46 `calc` calls, one per step.
|
|
30
|
+
class TurnBudget
|
|
31
|
+
# The three notices, verbatim and escalating — one constant, so a transcript
|
|
32
|
+
# reader can recognize an engine sentence without an origin stamp (chat
|
|
33
|
+
# messages carry none). Keyed by calls REMAINING after the call being made.
|
|
34
|
+
NOTICES = {
|
|
35
|
+
10 => "Tool budget: 10 of your %<max>d tool calls for this turn are left. " \
|
|
36
|
+
"Start converging — prefer one call that answers the question over several that circle it.",
|
|
37
|
+
5 => "Tool budget: 5 tool calls left in this turn. " \
|
|
38
|
+
"Drop anything optional and gather only what the answer actually needs.",
|
|
39
|
+
2 => "Tool budget: 2 tool calls left in this turn. " \
|
|
40
|
+
"Consolidate what you already have and answer now — do not start new work."
|
|
41
|
+
}.freeze
|
|
42
|
+
|
|
43
|
+
def self.notice(remaining, max) = format(NOTICES.fetch(remaining), max: max)
|
|
44
|
+
|
|
45
|
+
# chat: the turn's chat — must answer #add_message (the boundary append).
|
|
46
|
+
# max: the profile's max_tool_calls. nil = no budget: no notice, no abort.
|
|
47
|
+
# emit: ->(type, data) — the Executor's emitter, bound to the task.
|
|
48
|
+
def initialize(chat:, max:, emit:)
|
|
49
|
+
@chat = chat
|
|
50
|
+
@max = max
|
|
51
|
+
@emit = emit
|
|
52
|
+
@calls = 0
|
|
53
|
+
@batch = ToolBatch.new
|
|
54
|
+
@pending = nil # a threshold was crossed; waiting for the batch boundary
|
|
55
|
+
@warned = [] # thresholds already spent (each fires at most once a turn)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# From ChatBuilder's before_tool_call, FIRST thing: counts the call about to
|
|
59
|
+
# run and raises when it is past the ceiling. The raise is the pre-existing
|
|
60
|
+
# guard-rail, moved here so the count has exactly one owner.
|
|
61
|
+
def tool_call
|
|
62
|
+
return if @max.nil?
|
|
63
|
+
|
|
64
|
+
@calls += 1
|
|
65
|
+
if @calls > @max
|
|
66
|
+
raise Insika::TimeoutError.new("tool call limit exceeded (#{@max})", stage: :tool_limit)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
remaining = @max - @calls
|
|
70
|
+
@pending = remaining if NOTICES.key?(remaining) && !@warned.include?(remaining)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# From ChatBuilder's after_tool_result, with the RAW result.
|
|
74
|
+
def tool_result(result) = @batch.halt!(result)
|
|
75
|
+
|
|
76
|
+
# RubyLLM after_message: delivers the armed notice the moment the batch of
|
|
77
|
+
# tool results closes.
|
|
78
|
+
def message_ended(message)
|
|
79
|
+
return unless @batch.closed?(message)
|
|
80
|
+
return if @pending.nil?
|
|
81
|
+
|
|
82
|
+
remaining = @pending
|
|
83
|
+
@pending = nil
|
|
84
|
+
return if @batch.halted? # nothing will read it (halt_when): drop, never deliver
|
|
85
|
+
|
|
86
|
+
@warned << remaining
|
|
87
|
+
@chat.add_message(role: :user, content: self.class.notice(remaining, @max))
|
|
88
|
+
@emit.call(:tool_budget_warned, { remaining: remaining, max: @max })
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
data/lib/insika/version.rb
CHANGED
data/lib/insika.rb
CHANGED
|
@@ -146,6 +146,7 @@ require_relative "insika/skill_store"
|
|
|
146
146
|
require_relative "insika/secret_masking"
|
|
147
147
|
require_relative "insika/tool_store"
|
|
148
148
|
require_relative "insika/tool_trace_store"
|
|
149
|
+
require_relative "insika/tool_usage_report"
|
|
149
150
|
require_relative "insika/context_trace_store"
|
|
150
151
|
# the model-visible payload of one ask + its durable trace —
|
|
151
152
|
# "model-visible means logged" (the conformance suite's reconstruction half).
|
|
@@ -275,6 +276,10 @@ require_relative "insika/commands/revoke_contact"
|
|
|
275
276
|
# the report destination's Studio mutation — delete one artifact
|
|
276
277
|
# (a bus command, like every Studio mutation).
|
|
277
278
|
require_relative "insika/commands/delete_artifact"
|
|
279
|
+
# in-session compaction (RFC-0044) — the summarizer (pure, injected
|
|
280
|
+
# ask) and the boundary math; the trigger lives in the Executor, the
|
|
281
|
+
# persistence in SessionStore, the read path in the Session provider.
|
|
282
|
+
require_relative "insika/compaction"
|
|
278
283
|
# session distillation — the distiller (pure, injected ask)
|
|
279
284
|
# and the proposal store (proposals + the latched dedup ledger + the
|
|
280
285
|
# per-session distilled marker).
|
|
@@ -332,7 +337,9 @@ require_relative "insika/session_actor"
|
|
|
332
337
|
require_relative "insika/skill_catalog"
|
|
333
338
|
require_relative "insika/tool_catalog"
|
|
334
339
|
require_relative "insika/steer_injector"
|
|
340
|
+
require_relative "insika/tool_batch"
|
|
335
341
|
require_relative "insika/loop_detector"
|
|
342
|
+
require_relative "insika/turn_budget"
|
|
336
343
|
require_relative "insika/balloon_splitter"
|
|
337
344
|
require_relative "insika/turn_output"
|
|
338
345
|
require_relative "insika/turn_state"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: insika
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Guilherme Lages Santos
|
|
@@ -311,6 +311,7 @@ files:
|
|
|
311
311
|
- lib/insika/commands/write_golden.rb
|
|
312
312
|
- lib/insika/commands/write_skill.rb
|
|
313
313
|
- lib/insika/commands/write_system_file.rb
|
|
314
|
+
- lib/insika/compaction.rb
|
|
314
315
|
- lib/insika/config_store.rb
|
|
315
316
|
- lib/insika/contact_store.rb
|
|
316
317
|
- lib/insika/context/builder.rb
|
|
@@ -562,6 +563,7 @@ files:
|
|
|
562
563
|
- lib/insika/token_estimator.rb
|
|
563
564
|
- lib/insika/token_store.rb
|
|
564
565
|
- lib/insika/tool_assembly.rb
|
|
566
|
+
- lib/insika/tool_batch.rb
|
|
565
567
|
- lib/insika/tool_catalog.rb
|
|
566
568
|
- lib/insika/tool_definition.rb
|
|
567
569
|
- lib/insika/tool_envelope.rb
|
|
@@ -570,6 +572,7 @@ files:
|
|
|
570
572
|
- lib/insika/tool_registry.rb
|
|
571
573
|
- lib/insika/tool_store.rb
|
|
572
574
|
- lib/insika/tool_trace_store.rb
|
|
575
|
+
- lib/insika/tool_usage_report.rb
|
|
573
576
|
- lib/insika/tools/a2a_remote.rb
|
|
574
577
|
- lib/insika/tools/agent_enum.rb
|
|
575
578
|
- lib/insika/tools/concurrency.rb
|
|
@@ -587,6 +590,7 @@ files:
|
|
|
587
590
|
- lib/insika/tools/tool_search.rb
|
|
588
591
|
- lib/insika/tools/tts.rb
|
|
589
592
|
- lib/insika/tools/update_briefing.rb
|
|
593
|
+
- lib/insika/turn_budget.rb
|
|
590
594
|
- lib/insika/turn_output.rb
|
|
591
595
|
- lib/insika/turn_state.rb
|
|
592
596
|
- lib/insika/turn_timing.rb
|