insika 0.8.0 → 1.0.1
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 +312 -2
- data/README.md +10 -6
- data/bin/insika +4 -1
- data/bin/insika-router +0 -1
- data/docs/AGENTS.md +142 -18
- data/docs/API.md +73 -0
- data/docs/ARCHITECTURE.md +56 -50
- data/docs/ARTIFACTS.md +33 -3
- data/docs/BENCHMARK.md +50 -7
- data/docs/CHANNELS.md +19 -2
- data/docs/CONTEXT.md +96 -27
- data/docs/CROSS-HARNESS-BENCH.md +157 -0
- data/docs/DEPLOY.md +70 -13
- data/docs/EMBEDDING.md +10 -0
- data/docs/EVALS.md +129 -10
- data/docs/FACTS.md +12 -6
- data/docs/HARVEST.md +8 -3
- data/docs/KNOWLEDGE.md +14 -0
- data/docs/MEDIA.md +6 -2
- data/docs/OBSERVABILITY.md +164 -28
- data/docs/PERFORMANCE.md +110 -0
- data/docs/PLUGINS.md +4 -4
- data/docs/POLICY.md +26 -14
- data/docs/RELEASING.md +9 -0
- data/docs/ROUTER.md +7 -0
- data/docs/RUBYLLM_2_MIGRATION.md +307 -0
- data/docs/SECURITY.md +34 -1
- data/docs/SHARED-CONVERSATIONS.md +40 -0
- data/docs/SKILLS.md +5 -3
- data/docs/STUDIO.md +122 -0
- data/docs/TOOLS.md +238 -42
- data/docs/operate.md +3 -0
- data/docs/prompts/ADD-TOOL.md +12 -2
- data/docs/prompts/DIAGNOSE-TURN.md +3 -0
- data/docs/prompts/GO-LIVE.md +3 -1
- data/lib/insika/agent_defaults.rb +140 -0
- data/lib/insika/agent_file_store.rb +12 -0
- data/lib/insika/agent_profile.rb +99 -17
- data/lib/insika/artifact_signing.rb +11 -0
- data/lib/insika/channels/web/widget.js +33 -0
- data/lib/insika/channels/web.rb +5 -2
- data/lib/insika/chat_builder.rb +124 -28
- data/lib/insika/checkpoint.rb +6 -1
- data/lib/insika/checkpoint_store.rb +59 -7
- data/lib/insika/commands/agent_payload.rb +3 -3
- data/lib/insika/commands/delete_kit.rb +26 -0
- data/lib/insika/commands/gate_harvest.rb +3 -0
- data/lib/insika/commands/review_guardrail_flag.rb +38 -0
- data/lib/insika/commands/run_distillation.rb +5 -8
- data/lib/insika/commands/run_harvest.rb +17 -1
- data/lib/insika/commands/seed_session.rb +128 -0
- data/lib/insika/commands/send_message.rb +9 -3
- data/lib/insika/commands/update_settings.rb +23 -1
- data/lib/insika/commands/write_kit.rb +27 -0
- data/lib/insika/compaction.rb +33 -7
- data/lib/insika/config_store.rb +87 -7
- data/lib/insika/context/builder.rb +29 -9
- data/lib/insika/context/priority.rb +5 -0
- data/lib/insika/context/provider.rb +7 -2
- data/lib/insika/context/providers/briefing.rb +11 -8
- data/lib/insika/context/providers/fence_notice.rb +27 -0
- data/lib/insika/context/providers/knowledge.rb +32 -6
- data/lib/insika/context/providers/memory.rb +61 -8
- data/lib/insika/context/providers/pending_confirmation.rb +52 -0
- data/lib/insika/context/providers/prompt.rb +17 -4
- data/lib/insika/context/providers/session.rb +46 -6
- data/lib/insika/context/reranker.rb +75 -0
- data/lib/insika/distill.rb +22 -13
- data/lib/insika/doctor.rb +142 -4
- data/lib/insika/dsl/runtime.rb +37 -4
- data/lib/insika/dsl/server_boot.rb +4 -12
- data/lib/insika/dsl.rb +19 -5
- data/lib/insika/edge_limiter.rb +27 -16
- data/lib/insika/egress_guard.rb +11 -3
- data/lib/insika/env_schema.rb +33 -73
- data/lib/insika/errors.rb +1 -0
- data/lib/insika/evals/assertions.rb +259 -18
- data/lib/insika/evals/golden.rb +230 -4
- data/lib/insika/evals/judge.rb +19 -10
- data/lib/insika/evals/moderator_compare.rb +47 -0
- data/lib/insika/evals/report.rb +61 -9
- data/lib/insika/evals/runner.rb +64 -4
- data/lib/insika/evals/simulator.rb +21 -3
- data/lib/insika/evals/transport.rb +317 -15
- data/lib/insika/event_stream.rb +63 -7
- data/lib/insika/evidence.rb +105 -17
- data/lib/insika/executor.rb +698 -164
- data/lib/insika/fence.rb +96 -0
- data/lib/insika/golden_store.rb +3 -0
- data/lib/insika/harvest.rb +26 -14
- data/lib/insika/harvest_engine.rb +1 -0
- data/lib/insika/harvest_store.rb +12 -0
- data/lib/insika/http_client.rb +87 -4
- data/lib/insika/kits.rb +54 -0
- data/lib/insika/knowledge.rb +34 -20
- data/lib/insika/llm_configurator.rb +46 -4
- data/lib/insika/llm_provider_store.rb +1 -3
- data/lib/insika/llm_trace_store.rb +54 -0
- data/lib/insika/mcp_client.rb +27 -63
- data/lib/insika/mcp_live_tool.rb +55 -9
- data/lib/insika/mcp_store.rb +37 -3
- data/lib/insika/mcp_tool_registry.rb +76 -26
- data/lib/insika/media.rb +38 -25
- data/lib/insika/memory_store.rb +16 -3
- data/lib/insika/memory_trim.rb +60 -0
- data/lib/insika/middleware.rb +12 -3
- data/lib/insika/model_metrics_store.rb +285 -0
- data/lib/insika/model_registry.rb +110 -0
- data/lib/insika/model_resolver.rb +1 -1
- data/lib/insika/model_selection.rb +14 -21
- data/lib/insika/model_visible.rb +17 -6
- data/lib/insika/onboarding.rb +1 -0
- data/lib/insika/outcome_store.rb +1 -1
- data/lib/insika/overlay_tool_registry.rb +30 -2
- data/lib/insika/pack_importer.rb +54 -9
- data/lib/insika/packaging.rb +14 -5
- data/lib/insika/pending_action_store.rb +45 -18
- data/lib/insika/plugin/loader.rb +4 -2
- data/lib/insika/prefix_fingerprint.rb +32 -27
- data/lib/insika/profile_source.rb +5 -0
- data/lib/insika/provider_error_classifier.rb +18 -3
- data/lib/insika/queue_policy.rb +7 -2
- data/lib/insika/refinement/proposer.rb +42 -17
- data/lib/insika/reliability.rb +12 -3
- data/lib/insika/router/app.rb +14 -5
- data/lib/insika/router/session_key.rb +35 -5
- data/lib/insika/safety/config.rb +20 -3
- data/lib/insika/safety/corpus.rb +10 -3
- data/lib/insika/safety/factory.rb +39 -1
- data/lib/insika/safety/input_guardrail.rb +21 -1
- data/lib/insika/safety/judge_moderator.rb +70 -0
- data/lib/insika/safety/output_validator.rb +29 -5
- data/lib/insika/safety/prompt_echo.rb +89 -0
- data/lib/insika/schema_guard.rb +53 -76
- data/lib/insika/server/app.rb +58 -7
- data/lib/insika/server/rack_app.rb +2 -0
- data/lib/insika/server/responses.rb +50 -5
- data/lib/insika/session_actor.rb +58 -28
- data/lib/insika/session_store.rb +163 -11
- data/lib/insika/settings_store.rb +57 -2
- data/lib/insika/shared_conversations.rb +305 -0
- data/lib/insika/skill_catalog.rb +28 -2
- data/lib/insika/skill_store.rb +6 -0
- data/lib/insika/soak/runner.rb +1 -1
- data/lib/insika/spoken_transcript.rb +31 -0
- data/lib/insika/steer_injector.rb +7 -48
- data/lib/insika/store.rb +29 -1
- data/lib/insika/stores/json_value.rb +37 -0
- data/lib/insika/stores/memory.rb +22 -35
- data/lib/insika/stores/postgres.rb +295 -0
- data/lib/insika/stores/sqlite.rb +257 -43
- data/lib/insika/stores/turn_counter.rb +25 -0
- data/lib/insika/studio/app.rb +1459 -163
- data/lib/insika/studio/assets/dist/application.css +1 -1
- data/lib/insika/studio/assets/dist/application.js +25 -25
- data/lib/insika/studio/assets/dist/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
- data/lib/insika/studio/assets/dist/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
- data/lib/insika/studio/assets/dist/fonts/ibm-plex-mono-latin-600-normal.woff2 +0 -0
- data/lib/insika/studio/assets/dist/fonts/ibm-plex-sans-latin-wght-normal.woff2 +0 -0
- data/lib/insika/studio/forms.rb +189 -12
- data/lib/insika/studio/nav_icons.rb +3 -0
- data/lib/insika/studio/views/_agent_config_retrieval.erb +73 -0
- data/lib/insika/studio/views/_agent_picker.erb +15 -0
- data/lib/insika/studio/views/_agent_tab_config.erb +83 -243
- data/lib/insika/studio/views/_agent_tab_history.erb +56 -1
- data/lib/insika/studio/views/_agent_tab_performance.erb +34 -0
- data/lib/insika/studio/views/_agent_tab_prompts.erb +7 -9
- data/lib/insika/studio/views/_agent_tab_skills.erb +16 -7
- data/lib/insika/studio/views/_agent_tab_tools.erb +90 -0
- data/lib/insika/studio/views/_agents_master.erb +8 -12
- data/lib/insika/studio/views/_cfg_alerts.erb +4 -0
- data/lib/insika/studio/views/_cfg_budget.erb +20 -0
- data/lib/insika/studio/views/_cfg_distill.erb +26 -0
- data/lib/insika/studio/views/_cfg_followup.erb +30 -0
- data/lib/insika/studio/views/_cfg_grounding.erb +21 -0
- data/lib/insika/studio/views/_cfg_guardrails.erb +47 -0
- data/lib/insika/studio/views/_cfg_harvest.erb +35 -0
- data/lib/insika/studio/views/_cfg_reliability.erb +32 -0
- data/lib/insika/studio/views/_chats_master.erb +66 -0
- data/lib/insika/studio/views/_customers_master.erb +37 -0
- data/lib/insika/studio/views/_empty.erb +15 -0
- data/lib/insika/studio/views/_facts_master.erb +42 -0
- data/lib/insika/studio/views/_harvest_candidate_detail.erb +14 -0
- data/lib/insika/studio/views/_identity.erb +16 -0
- data/lib/insika/studio/views/_kpi.erb +17 -0
- data/lib/insika/studio/views/_message.erb +40 -2
- data/lib/insika/studio/views/_model_chart.erb +82 -0
- data/lib/insika/studio/views/_refinement_master.erb +38 -0
- data/lib/insika/studio/views/{tool_edit.erb → _tool_edit.erb} +38 -11
- data/lib/insika/studio/views/_tool_users.erb +17 -0
- data/lib/insika/studio/views/_why.erb +53 -0
- data/lib/insika/studio/views/agent_detail.erb +17 -10
- data/lib/insika/studio/views/agents.erb +28 -16
- data/lib/insika/studio/views/approvals.erb +16 -11
- data/lib/insika/studio/views/artifact.erb +20 -7
- data/lib/insika/studio/views/artifacts.erb +19 -14
- data/lib/insika/studio/views/chats.erb +22 -29
- data/lib/insika/studio/views/customer.erb +88 -43
- data/lib/insika/studio/views/customers.erb +16 -26
- data/lib/insika/studio/views/evals.erb +49 -31
- data/lib/insika/studio/views/fact_detail.erb +114 -0
- data/lib/insika/studio/views/facts.erb +15 -116
- data/lib/insika/studio/views/followups.erb +63 -52
- data/lib/insika/studio/views/funnel.erb +104 -43
- data/lib/insika/studio/views/harvest.erb +85 -59
- data/lib/insika/studio/views/home.erb +138 -23
- data/lib/insika/studio/views/inbox.erb +36 -0
- data/lib/insika/studio/views/kits.erb +176 -0
- data/lib/insika/studio/views/knowledge.erb +92 -80
- data/lib/insika/studio/views/layout.erb +42 -11
- data/lib/insika/studio/views/live.erb +45 -0
- data/lib/insika/studio/views/mcp.erb +43 -13
- data/lib/insika/studio/views/models.erb +187 -0
- data/lib/insika/studio/views/parity.erb +38 -32
- data/lib/insika/studio/views/playground.erb +13 -9
- data/lib/insika/studio/views/refinement.erb +15 -224
- data/lib/insika/studio/views/refinement_detail.erb +243 -0
- data/lib/insika/studio/views/session.erb +153 -118
- data/lib/insika/studio/views/settings.erb +86 -22
- data/lib/insika/studio/views/skills.erb +53 -19
- data/lib/insika/studio/views/system_files.erb +7 -7
- data/lib/insika/studio/views/task.erb +45 -15
- data/lib/insika/studio/views/tasks.erb +35 -18
- data/lib/insika/studio/views/tools.erb +62 -73
- data/lib/insika/task_actor.rb +4 -1
- data/lib/insika/task_store.rb +67 -1
- data/lib/insika/telemetry/pricing.rb +16 -14
- data/lib/insika/telemetry/recorder.rb +115 -9
- data/lib/insika/telemetry/ruby_llm_instrumenter.rb +110 -0
- data/lib/insika/telemetry.rb +12 -2
- data/lib/insika/templates/daily-digest/README.md +13 -0
- data/lib/insika/templates/daily-digest/agent.rb +22 -11
- data/lib/insika/testing/store_contract.rb +65 -0
- data/lib/insika/text_tool_call.rb +66 -0
- data/lib/insika/tick.rb +7 -1
- data/lib/insika/token_store.rb +5 -0
- data/lib/insika/tool_assembly.rb +21 -13
- data/lib/insika/tool_batch.rb +1 -1
- data/lib/insika/tool_catalog.rb +12 -2
- data/lib/insika/tool_definition.rb +82 -13
- data/lib/insika/tool_envelope.rb +266 -29
- data/lib/insika/tool_manifest.rb +1 -0
- data/lib/insika/tool_store.rb +12 -4
- data/lib/insika/tool_trace_store.rb +15 -8
- data/lib/insika/tool_usage_report.rb +14 -4
- data/lib/insika/tools/a2a_remote.rb +1 -1
- data/lib/insika/tools/agent_enum.rb +1 -1
- data/lib/insika/tools/confirm_pending.rb +112 -0
- data/lib/insika/tools/data_defined_tool.rb +24 -15
- data/lib/insika/tools/generate_image.rb +2 -2
- data/lib/insika/tools/load_knowledge.rb +7 -3
- data/lib/insika/tools/load_skill.rb +3 -3
- data/lib/insika/tools/present.rb +115 -0
- data/lib/insika/tools/remember.rb +7 -2
- data/lib/insika/tools/run_persona_eval.rb +9 -6
- data/lib/insika/tools/save_artifact.rb +16 -6
- data/lib/insika/tools/schedule_followup.rb +3 -3
- data/lib/insika/tools/stuck_signal.rb +3 -3
- data/lib/insika/tools/subagent.rb +5 -5
- data/lib/insika/tools/subagents.rb +3 -3
- data/lib/insika/tools/tool_search.rb +11 -7
- data/lib/insika/tools/tts.rb +2 -2
- data/lib/insika/tools/update_briefing.rb +4 -4
- data/lib/insika/turn_output.rb +2 -2
- data/lib/insika/turn_state.rb +31 -1
- data/lib/insika/turn_timing.rb +51 -14
- data/lib/insika/version.rb +1 -1
- data/lib/insika/wiring/graph.rb +88 -16
- data/lib/insika/wiring/graph_chat.rb +4 -0
- data/lib/insika/workflow.rb +25 -64
- data/lib/insika.rb +23 -3
- metadata +74 -13
- data/lib/insika/commands/import_mcp_tools.rb +0 -48
- data/lib/insika/mcp_http_client.rb +0 -67
- data/lib/insika/mcp_tool_ingestor.rb +0 -165
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b98a9d84df7cda373881cc11d0658bc3dd208ceb4bc52c23ed4fed4bd641fbb4
|
|
4
|
+
data.tar.gz: cecc0e4671a335efc5670f297aaf53ebafd5f1662f25a3121894825582494b30
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 332d1cea74cdbee9e3241dfefc73538824643fe3b65964fb2584ed57fb4d85c7b1cb547c7d2ccf3ff2acd4893d49063bed60fbf6e94ed6968e1c30bbd9671b30
|
|
7
|
+
data.tar.gz: d203a16b2954fb36829ed074a463ebac6dce26fea980e546debf5e908e4bf6bfb77c7d04b2e703816254022eaf3da9dbbce1a09c845525454dc6126996ce00b0
|
data/CHANGELOG.md
CHANGED
|
@@ -3,11 +3,321 @@
|
|
|
3
3
|
All notable changes to this project are documented here.
|
|
4
4
|
|
|
5
5
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the
|
|
6
|
-
project
|
|
7
|
-
it is released. Entries land with the pull request that makes the change.
|
|
6
|
+
project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html) from 1.0.0 on. Entries land with the pull request that makes the change.
|
|
8
7
|
|
|
9
8
|
## [Unreleased]
|
|
10
9
|
|
|
10
|
+
## [1.0.1] - 2026-10-23
|
|
11
|
+
|
|
12
|
+
### Removed
|
|
13
|
+
|
|
14
|
+
- Internal planning notes (`docs/superpowers/`) are no longer in the repository or the
|
|
15
|
+
gem. 1.0.0 shipped them by mistake; the packaging now never ships that directory.
|
|
16
|
+
|
|
17
|
+
## [1.0.0] - 2026-10-23
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Harvest page: each pending or blocked candidate shows its skill text, rationale and origin conversation; a blocked one can be re-gated once the missing piece is fixed; the page says when the loop skips an agent (harvest off, or no grounding matcher).
|
|
22
|
+
- Studio screens for watching conversations and what waits on a person (see
|
|
23
|
+
[Studio](docs/STUDIO.md)):
|
|
24
|
+
- **Live** (`/studio/live`): one card per recent conversation, moved by the
|
|
25
|
+
event stream (tools in the running turn, "agent is writing…", guardrail
|
|
26
|
+
flags), with an event ticker. `?agent=` shows one agent's conversations.
|
|
27
|
+
- **Why this reply**: under each agent reply, its turn's context by category,
|
|
28
|
+
skills injected and why, tool calls with timing and guardrail flags, plus
|
|
29
|
+
Replay in Playground and Save as eval case.
|
|
30
|
+
- **Inbox** (`/studio/inbox`): approvals, fact proposals, mined skills,
|
|
31
|
+
refinement runs and guardrail false-positive reports in one list, oldest
|
|
32
|
+
first, with tabs per type.
|
|
33
|
+
- **Guardrail false positives**: a flag can be marked as a false positive,
|
|
34
|
+
then resolved or undone (`:review_guardrail_flag`). The verdict lives on the
|
|
35
|
+
flag inside the session.
|
|
36
|
+
- **Agent History**: outcomes per day over 30 days with a marker per change
|
|
37
|
+
to a prompt file or to the agent's own skills, and per change a short diff
|
|
38
|
+
and the outcomes 7 days after vs 7 days before.
|
|
39
|
+
- **Funnel drops**: the biggest loss between stages, and per loss the
|
|
40
|
+
conversations that stopped there, grouped by the last thing that happened.
|
|
41
|
+
- Chats tabs (All / Active now / Guardrail flagged), a customer card on the
|
|
42
|
+
session, a tool-call waterfall per turn, an Overview "Needs attention" row,
|
|
43
|
+
a `⌘K` palette, and a sidebar grouped as Operate / Review / Build /
|
|
44
|
+
Insights / Platform with a count badge on each Review page.
|
|
45
|
+
- Markup tags in message text (`<carrossel/>`, `<vitrine formato="lista">`)
|
|
46
|
+
show as highlighted tokens, escaped and never rendered.
|
|
47
|
+
- `Store#amend(scope, key, value)`: overwrites a key without moving it in
|
|
48
|
+
`#recent`. The default is `#set`; a backend whose `#recent` follows its own
|
|
49
|
+
write order overrides both (the contract suite checks it). Memory, SQLite and
|
|
50
|
+
Postgres implement it.
|
|
51
|
+
- Persisted turn messages and tool-call traces carry `task_id`, so the Studio
|
|
52
|
+
ties each message to its own turn.
|
|
53
|
+
|
|
54
|
+
- `scripts/migrate_openclaw.rb seed`: carries recent OpenClaw conversations into
|
|
55
|
+
Insika sessions (`POST /v1/conversations/:id/seed`) so a returning customer
|
|
56
|
+
keeps the context. Reads root and per-process SQLite transcripts, follows the
|
|
57
|
+
active branch from the last compaction, keeps only customer text and agent
|
|
58
|
+
replies, and skips conversations that already have messages. `--only`/`--as`
|
|
59
|
+
rehearse one conversation on a test chat.
|
|
60
|
+
Each session is stamped with `--agent`, so the Studio lists it under that
|
|
61
|
+
agent; re-running stamps sessions seeded before (they still answer 409).
|
|
62
|
+
- Platform agent defaults (Studio › Settings › Agent defaults, or
|
|
63
|
+
`update_settings` with `agent_defaults`): an agent with no value of its own
|
|
64
|
+
for reliability, knowledge, memory retrieval, budget, alerts, guardrails,
|
|
65
|
+
grounding, follow-ups, distillation or harvest runs with the platform's. The
|
|
66
|
+
agent's own value wins whole. Each of those sections in the agent config has
|
|
67
|
+
a "use the platform default" box; saving with it checked keeps the agent
|
|
68
|
+
inheriting. A default is validated on save, and one that stops building
|
|
69
|
+
later leaves agents on their own values instead of failing turns. Agents
|
|
70
|
+
saved in the Studio before this have their own knowledge, guardrails,
|
|
71
|
+
distillation and harvest values (the form always wrote them): check the box
|
|
72
|
+
to make them inherit.
|
|
73
|
+
|
|
74
|
+
- **Optional Postgres store** (`INSIKA_DATABASE_URL`, `INSIKA_DATABASE_POOL`). It passes the
|
|
75
|
+
same store contract as SQLite; `pg` is not a gem dependency and loads only when the
|
|
76
|
+
variable is set. `scripts/store_copy.rb` moves an existing store. See
|
|
77
|
+
[Postgres store](docs/DEPLOY.md#postgres-store-optional) for when it pays off.
|
|
78
|
+
- `Store#entries` and `Store#recent`: a whole scope, or its most recently written keys, in
|
|
79
|
+
one call. The default implementation keeps third-party backends working; SQLite and
|
|
80
|
+
Postgres answer each in one query. The Studio's session and task lists use them.
|
|
81
|
+
- `INSIKA_SLOW_STORE_MS` also logs each slow write batch: its size, bytes, scopes, and how
|
|
82
|
+
long it waited for the lock versus how long its commit took.
|
|
83
|
+
|
|
84
|
+
### Changed
|
|
85
|
+
- Session stats are versioned (`"v" => 2`, adds the guardrail flagged and
|
|
86
|
+
reported counts). `scripts/backfill_session_stats.rb` now also rewrites stats
|
|
87
|
+
older than the current version, not only missing ones.
|
|
88
|
+
- Reviewing a guardrail flag no longer moves the session to the top of the
|
|
89
|
+
recent lists.
|
|
90
|
+
- **MCP tools are named after their instance**: `<instance>__<tool>` (e.g.
|
|
91
|
+
`shop_staging__list_products`). Two instances offering the same tool used to share
|
|
92
|
+
one name, and every call went to whichever instance came first. Agents that allowed
|
|
93
|
+
MCP tools by name must select them again; per-tool overrides keep the server's name.
|
|
94
|
+
- `INSIKA_EGRESS_HOSTS` pins an MCP server only when its host resolves to a private
|
|
95
|
+
address. The operator registers the URL and the model cannot change it, so adding a
|
|
96
|
+
public server needs no redeploy. HTTPS still applies, and a private server still needs
|
|
97
|
+
`INSIKA_EGRESS_ALLOW_PRIVATE` and a listed host.
|
|
98
|
+
|
|
99
|
+
- An input guardrail injection hit no longer replaces the turn with the canned
|
|
100
|
+
refusal by default. The message reaches the model with a per-turn
|
|
101
|
+
`<security_notice>` (never persisted) and an audit `guardrail_flagged` with
|
|
102
|
+
`action: "flag"`, so a legitimate request in the same message is still served.
|
|
103
|
+
Sexual and abuse hits still block, now also when the message carries an
|
|
104
|
+
injection too. `guardrails.injection: "block"` (Studio › Guardrails › on
|
|
105
|
+
injection) restores the old behavior.
|
|
106
|
+
- `Store#recent` takes an optional fourth argument, `offset`, to read the next page; a
|
|
107
|
+
backend that implements the three-argument form keeps working (the stores pass
|
|
108
|
+
`offset` only when paging). SQLite reads a page's keys from the index and then only
|
|
109
|
+
their values, instead of reading every value in the range to sort it.
|
|
110
|
+
- Studio: the tasks list shows 50 tasks per page, newest first, instead of every task.
|
|
111
|
+
The home reads only the sessions of the last 14 days; its messages card counts that
|
|
112
|
+
window (and says so), and the conversations total comes from the keys alone.
|
|
113
|
+
- Every session write also writes a small stats record (last update, message count,
|
|
114
|
+
agent) in the `session_stats` scope, and the Studio home reads those instead of whole
|
|
115
|
+
sessions (every stat, filtered by date, so the order they were written in does not
|
|
116
|
+
matter). Sessions stored before this change have no stats until
|
|
117
|
+
`scripts/backfill_session_stats.rb` runs once (idempotent, safe with the app running;
|
|
118
|
+
it also removes stats whose session is gone).
|
|
119
|
+
- RubyLLM is pinned to a newer `2.0.0` commit: streamed responses are priced once when
|
|
120
|
+
read instead of on every chunk, and HTTP connections are shared per process and
|
|
121
|
+
settings. Specs stub LLM HTTP with `stub_llm_http`, because swapping the adapter on an
|
|
122
|
+
already-built connection no longer takes effect.
|
|
123
|
+
|
|
124
|
+
- Studio tools are grouped by origin and MCP server, with name/server filtering,
|
|
125
|
+
collapsible sections and per-section select/deselect actions. Selection keeps
|
|
126
|
+
denied tools blocked and requires saving before permissions change.
|
|
127
|
+
|
|
128
|
+
- Workflow and tool argument validation now use JSONSchemer. Explicit nulls and
|
|
129
|
+
declared constraints are enforced; existing tool scalar leniency remains.
|
|
130
|
+
- Distillation, harvest, knowledge and refinement use native structured responses.
|
|
131
|
+
Retired MCP import delegates to live discovery instead of generating HTTP snapshots.
|
|
132
|
+
|
|
133
|
+
- RubyLLM 2 migration: native loop control, tool schemas, cache markers, and usage
|
|
134
|
+
readers. MCP now uses the native RubyLLM client, replacing `ruby_llm-mcp` and the
|
|
135
|
+
Origin-header patch. Legacy SSE requires migration to Streamable HTTP. See
|
|
136
|
+
[migration results](docs/RUBYLLM_2_MIGRATION.md).
|
|
137
|
+
- Requires RubyLLM `~> 2.1` from RubyGems; the Git pin is gone. A provider's 400
|
|
138
|
+
quota message ("quota exceeded", "wait before trying again") now arrives as
|
|
139
|
+
`RubyLLM::RateLimitError` and is retried and rotated instead of failing the turn.
|
|
140
|
+
|
|
141
|
+
- SQLite writes from concurrent turns share one transaction and one commit (group commit),
|
|
142
|
+
so N worker processes take the file's write lock far less often. A turn opens and
|
|
143
|
+
closes its task record in one write each, and skips an empty evidence write.
|
|
144
|
+
- Litestream 0.5 with its blocking checkpoint disabled (`truncate-page-n: 0`); it restores
|
|
145
|
+
backups made by 0.3.
|
|
146
|
+
- Less CPU per turn: the prompt reads an agent's files once per build, the prompt-echo
|
|
147
|
+
check caches each squeezed prompt, and streamed events are matched only against their
|
|
148
|
+
own session's subscriptions.
|
|
149
|
+
|
|
150
|
+
### Removed
|
|
151
|
+
|
|
152
|
+
- **The `HARNESS_*` environment variables (breaking).** Only the `INSIKA_*` names are
|
|
153
|
+
read. A leftover `HARNESS_*` key is no longer honored: it is reported as an error
|
|
154
|
+
naming its `INSIKA_*` replacement (a warning at boot, fatal under
|
|
155
|
+
`INSIKA_CONFIG_STRICT`, and an error in `insika doctor`), so a stale `HARNESS_DB`
|
|
156
|
+
cannot silently boot the engine on the memory backend. `EnvSchema.reconcile_legacy!`
|
|
157
|
+
is gone, and the bundled `insika-code` plugin and example read `INSIKA_CODE_*`.
|
|
158
|
+
- **The `plugin.yml` manifest name (breaking).** Only `insika.plugin.yml` loads. A
|
|
159
|
+
leftover `plugin.yml` is not loaded and warns to rename it.
|
|
160
|
+
- `Insika::LLMHTTPAdapter` (`faraday_adapter = :insika_net_http`). RubyLLM 2.1 shares
|
|
161
|
+
one connection per process and settings, so the stock `:net_http` no longer builds a
|
|
162
|
+
CA store per chat. A deployment that set `:insika_net_http` drops that line.
|
|
163
|
+
|
|
164
|
+
### Fixed
|
|
165
|
+
|
|
166
|
+
- Skills written in one worker (pack import, Studio edit, `write_skill`) now reach the other workers within 2 s. The catalog only reloaded in the worker that handled the write, so the others kept the skills they booted with until a restart — in the Studio and in customer turns.
|
|
167
|
+
- Harvest no longer mines simulator/eval sessions (`sim-…`, `eval-…`), and the miner sees the candidates still open so it stops re-proposing the same idea under new names.
|
|
168
|
+
- Harvest: a bare `miner.model` ref (no `provider/`) now uses the agent's provider; it used to fail every run with `Provider must be specified`.
|
|
169
|
+
- Studio: `/studio` without a trailing slash answered 404; it now opens the
|
|
170
|
+
Overview.
|
|
171
|
+
- Studio: the agent History chart and arm conversions counted outcome kinds
|
|
172
|
+
against the primary stage name, so they read 0 whenever the kind and stage
|
|
173
|
+
names differ; they now map kinds through `advance_on`.
|
|
174
|
+
- Studio: a negative message or flag index on a guardrail review counted from
|
|
175
|
+
the end and reviewed the wrong flag; it is now not found.
|
|
176
|
+
- An error that is fatal only for one model or account no longer kills the turn:
|
|
177
|
+
no balance (402), a bad key or missing access (401/403) and a model the provider
|
|
178
|
+
does not have (404) move straight to the next fallback node — no retry on that
|
|
179
|
+
node, no backoff, and no circuit-breaker count (an open primary circuit fails
|
|
180
|
+
fast without rotating). On the last node it still raises; a 400 still never
|
|
181
|
+
rotates.
|
|
182
|
+
- Studio model fields are type-to-search pickers over the configured providers'
|
|
183
|
+
`provider/model` refs (their declared models, plus the chat models of key-only
|
|
184
|
+
providers): the agent model, a new agent, the playground pin and Settings'
|
|
185
|
+
default, fallback (one slot per position) and utility models. The server
|
|
186
|
+
refuses a ref outside the list — a typed `openai/gpt-x` under provider `openai`
|
|
187
|
+
used to reach the API as `openai/openai/gpt-x`. A stored value outside the list
|
|
188
|
+
is shown marked "not configured" and may be saved back unchanged. The plain
|
|
189
|
+
`model`/`provider` fields still pass as given for API clients.
|
|
190
|
+
The same pickers cover the reliability fallback chain (agent and Agent
|
|
191
|
+
defaults) and the refinement proposers, one slot per position, and the
|
|
192
|
+
knowledge, distill, harvest-miner and compaction models.
|
|
193
|
+
- Data-tools imported or edited in one worker now reach the others: the tool
|
|
194
|
+
registry checks the config version token (at most every 2 s) and rebuilds when
|
|
195
|
+
it moved, and the tool catalog follows. Before, the other workers kept the
|
|
196
|
+
catalog they booted with until a restart.
|
|
197
|
+
- LLM providers authored at runtime reach every worker process, and survive a
|
|
198
|
+
restart: each chat re-applies the stored providers when they changed. Before,
|
|
199
|
+
only the worker that served the edit had the key, so a fallback on that
|
|
200
|
+
provider failed as unconfigured. A cleared key stops being used; a key from
|
|
201
|
+
the environment is never cleared by it.
|
|
202
|
+
- Deleting an LLM provider authored at runtime puts back the key and base the
|
|
203
|
+
process started with (for example from the environment) instead of leaving
|
|
204
|
+
the provider without credentials; a worker that never applied the provider
|
|
205
|
+
leaves its config alone. Delete no longer disables a provider that also has a
|
|
206
|
+
key from the environment.
|
|
207
|
+
- Native chat usage includes tool rounds and retries, and failed turns expose
|
|
208
|
+
recorded usage. Responses projects cache-inclusive totals; negotiated pricing
|
|
209
|
+
no longer subtracts cache reads from already non-cached input.
|
|
210
|
+
- Reliability honors session model pins and model allowlists without multiplying
|
|
211
|
+
its attempt budget by RubyLLM transport retries.
|
|
212
|
+
- Speech response reads stop at the byte limit before buffering the entire body.
|
|
213
|
+
- Workflow schemas accept valid `false` values.
|
|
214
|
+
|
|
215
|
+
- **A merged fragment is framed by `steer_join`, like a steered one already was.** The
|
|
216
|
+
two burst doors disagreed on what the model sees: a steered message becomes its OWN
|
|
217
|
+
`user` message in the transcript (framed by `steer_join`), while a merged one was
|
|
218
|
+
concatenated into the queued turn's single payload by a bare `\n`. A burst therefore
|
|
219
|
+
reached the model as one run-on paragraph with no boundary between the asks, and a
|
|
220
|
+
trailing constraint could be answered by nothing (staging, Acme Beauty,
|
|
221
|
+
2026-09-18: five messages merged 4/4, and the answer never mentioned the fifth).
|
|
222
|
+
`steer_join` now applies to both doors; the default `nil` returns the text untouched,
|
|
223
|
+
so a wiring that never set it is unchanged.
|
|
224
|
+
|
|
225
|
+
- **The door is open for as long as a turn is queued, not only during a debounce
|
|
226
|
+
window.** `collect`/`steer` merged a fragment only while a turn sat in a
|
|
227
|
+
`debounce_ms` window; a message that arrived while a turn waited behind the one in
|
|
228
|
+
flight joined nothing and became a turn of its own, third in line. A
|
|
229
|
+
`POST /v1/messages?stream=false` caller then held its connection through TWO turns
|
|
230
|
+
and timed out — on the WhatsApp integration that surfaced as a technical apology
|
|
231
|
+
to the customer, once per excess message of a burst. A queued turn is now mergeable
|
|
232
|
+
with or without a window, so every burst message answers immediately with `merged`
|
|
233
|
+
or `steered`. `followup` (the default) is untouched.
|
|
234
|
+
- **Re-importing a pack no longer erases the knobs it did not send.** `limits` and
|
|
235
|
+
`params` now MERGE per key on an update (`PackImporter::KNOB_BAGS`); everything
|
|
236
|
+
else keeps replacing. A provisioning client that publishes
|
|
237
|
+
`limits: {turn_timeout:, context_budget:}` used to drop every other knob on the
|
|
238
|
+
agent — `queue_mode`, `debounce_ms`, `chat_rate_limit` — so an unrelated playbook
|
|
239
|
+
publish silently reset the queue policy an operator had set in the Studio. The
|
|
240
|
+
authoritative allowlists (`prompt_files`/`skills`/`tools_allow`) are unchanged: a
|
|
241
|
+
name that left the pack still leaves the agent.
|
|
242
|
+
- One door per queued turn: with two turns waiting, the second used to take over the
|
|
243
|
+
first's fragment count, and the first then ran from a message snapshot the store had
|
|
244
|
+
already grown past.
|
|
245
|
+
|
|
246
|
+
## [0.9.0] - 2026-09-07
|
|
247
|
+
|
|
248
|
+
The commerce-agent wave: the engine now enforces what the prompt used to ask for —
|
|
249
|
+
a write names only IDs a lookup returned, the model picks which cards to show and
|
|
250
|
+
the engine shows them, third-party text can be fenced before the model reads it,
|
|
251
|
+
and an eval case can start from a seeded snapshot. Additive on the wire: `/v1`
|
|
252
|
+
gains frames and keys, none change meaning.
|
|
253
|
+
|
|
254
|
+
### Added
|
|
255
|
+
|
|
256
|
+
- **Write provenance** — `requires_evidence` on HTTP data tools checks declared
|
|
257
|
+
ID parameters against the session evidence ledger before approval or execution.
|
|
258
|
+
Unknown IDs and an unavailable ledger return `blocked` with gate `provenance`.
|
|
259
|
+
Studio editing, Doctor diagnostics, session traces, `tool_blocked`, the
|
|
260
|
+
`insika.tool.blocked` counter and `insika tools:report` expose the gate.
|
|
261
|
+
See [Tools](docs/TOOLS.md#provenance-checking-ids-before-a-write).
|
|
262
|
+
- **Snapshot evals** — cases can seed evidence IDs, memory, user/assistant history
|
|
263
|
+
and briefing before the first turn. The authenticated seed endpoint is disabled
|
|
264
|
+
by default (`evals.seeding`); Doctor warns when enabled. New assertions cover
|
|
265
|
+
forbidden/alternative/first calls, call limits, reply text and blocked gates.
|
|
266
|
+
Responses SSE now carries tool arguments, completion status and the provider's
|
|
267
|
+
`call_id` on both item frames, so a consumer pairs `added` with `done`.
|
|
268
|
+
See [Evals](docs/EVALS.md#state--a-case-starts-from-a-snapshot).
|
|
269
|
+
- **Presentation tools** — data tools with `presentation` instead of `request`
|
|
270
|
+
select evidence cards by known ID — this turn's, or the last 64 the session
|
|
271
|
+
ledger kept (snapshots seed them as `evidence.cards`). They report shown/dropped IDs,
|
|
272
|
+
emit `insika.ui` (web channel: `ui`) and select the outbox attachments. Evidence
|
|
273
|
+
cards carry IDs; empty selections suppress automatic card delivery. Includes
|
|
274
|
+
`ui_components` / `no_ui` eval assertions and Doctor diagnostics.
|
|
275
|
+
See [Tools](docs/TOOLS.md#presentation-tools-the-model-picks-ids-the-engine-shows-the-cards).
|
|
276
|
+
- **Fencing** — opt-in per agent through the DSL, payload or Studio. Sanitizes
|
|
277
|
+
ordinary tool result strings, memory text and injected knowledge summaries, and adds a fixed
|
|
278
|
+
identity-layer notice. The tool-string cap `fencing.max_chars` defaults to 12,000; the agent flag
|
|
279
|
+
defaults to off — and stays off in this release: flipping the default waits for the
|
|
280
|
+
golden-case comparison with fencing on ([Releasing](docs/RELEASING.md), gate 4).
|
|
281
|
+
Doctor warns for unfenced agents exposed by relay/widget env configuration.
|
|
282
|
+
See [Agents](docs/AGENTS.md#fencing--third-party-text-is-data-never-instructions).
|
|
283
|
+
|
|
284
|
+
### Changed
|
|
285
|
+
|
|
286
|
+
- **Cache boundary** — explicit Anthropic cache control ends at the identity layer;
|
|
287
|
+
volatile system text follows in a separate block. Prefix fingerprints cover
|
|
288
|
+
identity and tool schemas; memory/knowledge/request changes retain separate
|
|
289
|
+
diagnostic digests without reporting identity-prefix invalidation.
|
|
290
|
+
See [Context](docs/CONTEXT.md#the-provider-prefix-cache).
|
|
291
|
+
- **Serial writes in parallel batches** — tools marked `side_effect` acquire a
|
|
292
|
+
per-session serial gate before the shared concurrency slot. Independent reads
|
|
293
|
+
can overlap writes; queued writes do not consume that shared slot. MCP tools
|
|
294
|
+
annotated `readOnlyHint` are reads.
|
|
295
|
+
- Memory and knowledge extraction read only nonblank user/assistant text, preserving
|
|
296
|
+
original transcript indexes. Direct tool messages are excluded; assistant
|
|
297
|
+
paraphrases can still reach extraction. This applies regardless of `fencing`.
|
|
298
|
+
- A tool's own `{"status":"blocked"}` answer is a call that ran: only the engine's
|
|
299
|
+
gate refusal reports `blocked` on `:tool_result`, the trace and `tools:report`.
|
|
300
|
+
- A Studio save that changes a tool's HTTP method re-derives `side_effect`.
|
|
301
|
+
|
|
302
|
+
### Fixed
|
|
303
|
+
|
|
304
|
+
- Data tools declaring `evidence` no longer fail when the envelope parses an
|
|
305
|
+
already-parsed `Evidence::Spec`.
|
|
306
|
+
- Studio tool saves preserve `evidence` and `presentation` declarations.
|
|
307
|
+
- `scripts/serve_real.rb` passes channel and settings stores to the edge, enabling
|
|
308
|
+
configured relay/widget routes and the eval seeding setting in the demo server.
|
|
309
|
+
- Fencing: the notice ships with the flag regardless of the `context_providers`
|
|
310
|
+
allowlist; briefing values and the compaction summary are sanitized too; evidence
|
|
311
|
+
item ids stay byte-exact for the model (only the line is sanitized).
|
|
312
|
+
- Provenance: a schema-optional parameter the model omits is not checked; a blocked
|
|
313
|
+
call on a one-shot turn no longer fails emitting `tool_blocked`.
|
|
314
|
+
- `POST /v1/conversations/:id/seed` decodes a percent-encoded conversation id.
|
|
315
|
+
- Widget `ui` cards link only `http(s)` urls.
|
|
316
|
+
- The evidence ledger reads the session row once per turn, not once per gated call.
|
|
317
|
+
- Studio reads its templates as UTF-8 regardless of the process locale: a host with
|
|
318
|
+
no `LANG` answered 500 on the login page (found by the release install proof).
|
|
319
|
+
|
|
320
|
+
|
|
11
321
|
## [0.8.0] - 2026-08-31
|
|
12
322
|
|
|
13
323
|
The post-consolidation hardening wave: the last two OpenClaw-era names are gone
|
data/README.md
CHANGED
|
@@ -16,9 +16,11 @@ web control UI. Point an existing Responses client at it and serve many agents f
|
|
|
16
16
|
deployment.
|
|
17
17
|
|
|
18
18
|
- **Drop-in `/v1/responses`** — SSE streaming and usage, the shape existing clients already speak.
|
|
19
|
-
- **Durable & resumable** — every turn checkpoints;
|
|
19
|
+
- **Durable & resumable** — every turn checkpoints; recorded side-effect calls are deduplicated on replay. External writes still need idempotency.
|
|
20
20
|
- **Agents as data** — agents, prompts, skills and tools are editable at runtime (UI or API), no redeploy.
|
|
21
|
-
- **Tools & skills** — code
|
|
21
|
+
- **Tools & skills** — code, HTTP data and live MCP tools; skills load on demand.
|
|
22
|
+
- **Evidence-backed actions** — ID checks before writes, serial side effects per session, and selected evidence cards ([Tools](docs/TOOLS.md)).
|
|
23
|
+
- **Snapshot evals** — seed a case's starting state and check calls, refusals, replies and cards ([Evals](docs/EVALS.md)).
|
|
22
24
|
- **Safe by default** — content-safety guardrails, an egress guard, confined execution, approvals, edge limits.
|
|
23
25
|
- **Observable** — an event stream, per-session tool-call traces, optional OpenTelemetry.
|
|
24
26
|
- **~0.4 ms of engine per turn** — p50 overhead on a neutral, key-free benchmark you can rerun yourself ([methodology](docs/BENCHMARK.md)).
|
|
@@ -106,7 +108,7 @@ navigates by.
|
|
|
106
108
|
|
|
107
109
|
- [Agents](docs/AGENTS.md) — the AgentProfile and every key on it; create and edit at runtime.
|
|
108
110
|
- [Limits and policy](docs/POLICY.md) — the five layers: allowed tools, approvals, guardrails, edge limits, reasoning.
|
|
109
|
-
- [Tools](docs/TOOLS.md) — code
|
|
111
|
+
- [Tools](docs/TOOLS.md) — code, HTTP, MCP and presentation tools; evidence gates and serial writes.
|
|
110
112
|
- [Skills](docs/SKILLS.md) — the SKILL.md format and progressive loading.
|
|
111
113
|
- [Context](docs/CONTEXT.md) — what fills a turn's prompt; budget, eviction, memory.
|
|
112
114
|
- [Workflows](docs/WORKFLOWS.md) — deterministic orchestration of several agents: the five patterns, and when to let the model choose instead.
|
|
@@ -137,10 +139,11 @@ navigates by.
|
|
|
137
139
|
- [Load test](docs/LOADTEST.md) — load-testing and data topology.
|
|
138
140
|
- [Soak](docs/SOAK.md) — the long run that finds what a short one cannot.
|
|
139
141
|
- [Benchmark](docs/BENCHMARK.md) — the neutral, reproducible, provider-free engine benchmark.
|
|
142
|
+
- [Performance](docs/PERFORMANCE.md) — what keeps a turn cheap (fibers, SQLite group commit, memory trim) and what was tried and left out.
|
|
140
143
|
|
|
141
144
|
**Improve**
|
|
142
145
|
|
|
143
|
-
- [Evals](docs/EVALS.md) —
|
|
146
|
+
- [Evals](docs/EVALS.md) — snapshot cases, tool/UI assertions, rubrics, the judge panel and the pre-merge gate.
|
|
144
147
|
- [Refinement](docs/REFINEMENT.md) — read an agent's own traffic back as a ranked report of what broke.
|
|
145
148
|
- [Outcomes and follow-ups](docs/OUTCOMES.md) — what the traffic was worth in business terms, and the tool that comes back on a promise.
|
|
146
149
|
- [Knowledge](docs/KNOWLEDGE.md) — extract durable concepts from finished conversations into a per-agent knowledge base; provenance-stamped, PII-redacted, best-effort with a re-scan recovery path.
|
|
@@ -176,6 +179,7 @@ and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). Vulnerabilities go through
|
|
|
176
179
|
|
|
177
180
|
## Status
|
|
178
181
|
|
|
179
|
-
|
|
180
|
-
|
|
182
|
+
Published on [RubyGems](https://rubygems.org/gems/insika) and follows
|
|
183
|
+
[Semantic Versioning](https://semver.org/) from 1.0.0: a breaking change only lands in
|
|
184
|
+
a new major version ([CHANGELOG.md](CHANGELOG.md)). Licensed
|
|
181
185
|
**MIT** ([LICENSE](LICENSE)).
|
data/bin/insika
CHANGED
|
@@ -390,7 +390,7 @@ def evals_simulate(argv)
|
|
|
390
390
|
# paired comparison, which it silently invalidates.
|
|
391
391
|
require "securerandom"
|
|
392
392
|
conv = opts[:conv] || "sim-#{golden.id}-#{SecureRandom.hex(4)}"
|
|
393
|
-
run = simulator.run(persona: golden.persona, agent: target_agent, conv: conv)
|
|
393
|
+
run = simulator.run(persona: golden.persona, agent: target_agent, conv: conv, state: golden.state)
|
|
394
394
|
|
|
395
395
|
verdict = judge && judge.score_conversation(
|
|
396
396
|
rubric: golden.rubric, transcript: run.transcript, policy: golden.policy,
|
|
@@ -505,6 +505,9 @@ def local_side_effect_tools(agent)
|
|
|
505
505
|
profile = Insika::StoredProfileSource.new(config_store: config_store).fetch(agent)
|
|
506
506
|
return nil if profile.nil?
|
|
507
507
|
|
|
508
|
+
# Kits add reachable tools at turn time; the swap list must count them too.
|
|
509
|
+
profile = Insika::Kits.apply(profile, Insika::SettingsStore.new(config_store: config_store).kits)
|
|
510
|
+
|
|
508
511
|
registry = Insika::OverlayToolRegistry.new(
|
|
509
512
|
base: Insika::ToolRegistry.new, tool_store: Insika::ToolStore.new(config_store: config_store),
|
|
510
513
|
http: Insika::HttpClient.new
|