insika 0.3.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 +296 -0
- data/README.md +48 -12
- data/bin/insika +725 -0
- data/bin/insika-router +87 -0
- data/docs/AGENTS.md +116 -406
- data/docs/API.md +5 -5
- data/docs/ARCHITECTURE.md +3 -2
- data/docs/ARTIFACTS.md +137 -0
- data/docs/BENCHMARK.md +2 -2
- data/docs/CHANNELS.md +14 -14
- data/docs/CONTEXT.md +63 -19
- data/docs/DEMO.md +80 -0
- data/docs/DEPLOY.md +87 -10
- data/docs/EMBEDDING.md +1 -1
- data/docs/EVALS.md +128 -3
- data/docs/FACTS.md +3 -3
- data/docs/HARVEST.md +5 -6
- data/docs/KNOWLEDGE.md +290 -0
- data/docs/LOADTEST.md +17 -29
- data/docs/MEDIA.md +128 -0
- data/docs/OBSERVABILITY.md +46 -12
- data/docs/OUTCOMES.md +137 -0
- data/docs/PLUGINS.md +51 -6
- data/docs/POLICY.md +222 -0
- data/docs/REFINEMENT.md +14 -9
- data/docs/RELEASING.md +4 -4
- data/docs/ROUTER.md +213 -0
- data/docs/RUNNING-LOCAL.md +5 -5
- data/docs/SCHEDULING.md +121 -0
- data/docs/SECURITY.md +23 -7
- data/docs/SKILLS.md +11 -2
- data/docs/SOAK.md +3 -3
- data/docs/TEMPLATES.md +134 -0
- data/docs/TOOLS.md +176 -27
- data/docs/WHY.md +1 -1
- data/docs/WORKFLOWS.md +2 -2
- data/docs/_includes/head_custom.html +5 -0
- data/docs/_includes/title.html +13 -0
- data/docs/_sass/color_schemes/insika.scss +32 -0
- data/docs/_sass/custom/custom.scss +199 -0
- data/docs/_sass/custom/setup.scss +26 -0
- data/docs/assets/img/favicon.svg +7 -0
- data/docs/assets/img/insika-mark.svg +7 -0
- data/docs/core-concepts.md +21 -0
- data/docs/domain.md +4 -4
- data/docs/improve.md +20 -0
- data/docs/index.md +8 -5
- data/docs/integrate.md +20 -0
- data/docs/operate.md +13 -6
- data/docs/prompts/ADD-TOOL.md +118 -0
- data/docs/prompts/DIAGNOSE-TURN.md +65 -0
- data/docs/prompts/GO-LIVE.md +138 -0
- data/docs/prompts/RUN-EXAMPLES.md +70 -0
- data/docs/reference.md +19 -0
- data/docs/ship.md +10 -2
- data/docs/start-here.md +18 -0
- data/lib/insika/agent_profile.rb +99 -17
- data/lib/insika/artifact_signing.rb +82 -0
- data/lib/insika/artifact_store.rb +160 -0
- data/lib/insika/channel_delivery.rb +1 -1
- data/lib/insika/chat_builder.rb +50 -19
- data/lib/insika/commands/agent_payload.rb +2 -2
- data/lib/insika/commands/backfill_knowledge.rb +145 -0
- data/lib/insika/commands/delete_artifact.rb +35 -0
- data/lib/insika/commands/delete_concept.rb +34 -0
- data/lib/insika/commands/delete_mcp.rb +6 -2
- data/lib/insika/commands/delete_tenant_data.rb +15 -3
- data/lib/insika/commands/gate_refinement.rb +1 -1
- data/lib/insika/commands/refresh_mcp_tools.rb +47 -0
- data/lib/insika/commands/restore_concept.rb +34 -0
- data/lib/insika/commands/seed_demo_data.rb +31 -0
- data/lib/insika/commands/upsert_mcp.rb +6 -3
- data/lib/insika/commands/write_concept.rb +57 -0
- 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 +8 -0
- data/lib/insika/context/providers/briefing.rb +53 -24
- data/lib/insika/context/providers/knowledge.rb +108 -0
- data/lib/insika/context/providers/prompt.rb +30 -24
- data/lib/insika/context/providers/session.rb +46 -10
- data/lib/insika/context_trace_store.rb +11 -1
- data/lib/insika/cron.rb +189 -0
- data/lib/insika/demo/agent_attrs.rb +43 -0
- data/lib/insika/demo/golden_cases.rb +81 -0
- data/lib/insika/demo/seeder.rb +336 -0
- data/lib/insika/doctor.rb +280 -17
- data/lib/insika/dsl/definition.rb +3 -2
- data/lib/insika/dsl/runtime.rb +64 -79
- data/lib/insika/dsl/server_boot.rb +23 -1
- data/lib/insika/dsl/system.rb +10 -2
- data/lib/insika/dsl.rb +103 -2
- data/lib/insika/env_schema.rb +21 -7
- data/lib/insika/evals/golden.rb +41 -4
- data/lib/insika/evals/judge.rb +47 -2
- data/lib/insika/evals/pairwise.rb +11 -0
- data/lib/insika/evals/persona.rb +98 -0
- data/lib/insika/evals/runner.rb +9 -0
- data/lib/insika/evals/simulator.rb +225 -0
- data/lib/insika/evals/transport.rb +84 -2
- data/lib/insika/event_stream.rb +10 -0
- data/lib/insika/executor.rb +295 -55
- data/lib/insika/followup_policy.rb +2 -25
- data/lib/insika/golden_store.rb +16 -1
- data/lib/insika/grounding/matcher.rb +1 -1
- data/lib/insika/knowledge.rb +680 -0
- data/lib/insika/knowledge_store.rb +140 -0
- data/lib/insika/loop_detector.rb +5 -34
- data/lib/insika/mcp_client.rb +94 -0
- data/lib/insika/mcp_json.rb +74 -0
- data/lib/insika/mcp_live_tool.rb +43 -0
- data/lib/insika/mcp_store.rb +98 -26
- data/lib/insika/mcp_tool_ingestor.rb +30 -8
- data/lib/insika/mcp_tool_registry.rb +100 -0
- data/lib/insika/media.rb +115 -31
- data/lib/insika/message_origin.rb +1 -1
- data/lib/insika/middleware.rb +9 -0
- data/lib/insika/onboarding.rb +17 -1
- data/lib/insika/outcome_store.rb +1 -1
- data/lib/insika/overlay_tool_registry.rb +37 -17
- data/lib/insika/packaging.rb +2 -2
- data/lib/insika/profile_source.rb +15 -1
- data/lib/insika/prompt_catalog.rb +10 -0
- data/lib/insika/retention.rb +36 -1
- data/lib/insika/router/app.rb +157 -0
- data/lib/insika/router/backend_pool.rb +98 -0
- data/lib/insika/router/hash_ring.rb +55 -0
- data/lib/insika/router/proxy_body.rb +34 -0
- data/lib/insika/router/session_key.rb +54 -0
- data/lib/insika/router.rb +18 -0
- data/lib/insika/schedule.rb +177 -0
- data/lib/insika/schedule_engine.rb +314 -0
- data/lib/insika/schedule_store.rb +208 -0
- data/lib/insika/server/app.rb +105 -15
- data/lib/insika/server/rack_app.rb +5 -1
- data/lib/insika/server/responses.rb +5 -5
- data/lib/insika/session_store.rb +34 -4
- data/lib/insika/settings_store.rb +8 -1
- data/lib/insika/skill_catalog.rb +12 -0
- data/lib/insika/soak/runner.rb +4 -4
- data/lib/insika/steer_injector.rb +21 -10
- data/lib/insika/studio/app.rb +591 -47
- data/lib/insika/studio/assets/dist/application.css +1 -1
- data/lib/insika/studio/assets/dist/application.js +21 -21
- data/lib/insika/studio/forms.rb +57 -5
- data/lib/insika/studio/nav_icons.rb +14 -1
- data/lib/insika/studio/views/_agent_tab_cache.erb +25 -0
- data/lib/insika/studio/views/_agent_tab_config.erb +514 -0
- data/lib/insika/studio/views/_agent_tab_history.erb +24 -0
- data/lib/insika/studio/views/_agent_tab_loops.erb +54 -0
- data/lib/insika/studio/views/_agent_tab_memory.erb +51 -0
- data/lib/insika/studio/views/_agent_tab_outcomes.erb +31 -0
- data/lib/insika/studio/views/_agent_tab_prompts.erb +108 -0
- data/lib/insika/studio/views/_agent_tab_skills.erb +38 -0
- data/lib/insika/studio/views/_agents_master.erb +44 -0
- data/lib/insika/studio/views/_message.erb +49 -32
- data/lib/insika/studio/views/agent_detail.erb +61 -820
- data/lib/insika/studio/views/agents.erb +70 -57
- data/lib/insika/studio/views/artifact.erb +23 -0
- data/lib/insika/studio/views/artifacts.erb +59 -0
- data/lib/insika/studio/views/evals.erb +2 -2
- data/lib/insika/studio/views/facts.erb +1 -1
- data/lib/insika/studio/views/funnel.erb +1 -1
- data/lib/insika/studio/views/home.erb +106 -67
- data/lib/insika/studio/views/knowledge.erb +123 -0
- data/lib/insika/studio/views/layout.erb +14 -11
- data/lib/insika/studio/views/mcp.erb +174 -80
- data/lib/insika/studio/views/session.erb +231 -177
- data/lib/insika/studio/views/settings.erb +50 -1
- data/lib/insika/studio/views/skills.erb +1 -1
- data/lib/insika/studio/views/tools.erb +24 -9
- data/lib/insika/telemetry/recorder.rb +49 -1
- data/lib/insika/templates/browser-agent/README.md +36 -0
- data/lib/insika/templates/browser-agent/agent.rb +49 -0
- data/lib/insika/templates/daily-digest/README.md +47 -0
- data/lib/insika/templates/daily-digest/agent.rb +77 -0
- data/lib/insika/templates/repo-explorer/README.md +36 -0
- data/lib/insika/templates/repo-explorer/agent.rb +45 -0
- data/lib/insika/templates/research-analyst/README.md +26 -0
- data/lib/insika/templates/research-analyst/agent.rb +68 -0
- data/lib/insika/templates/review-panel/README.md +20 -0
- data/lib/insika/templates/review-panel/agent.rb +50 -0
- data/lib/insika/templates/travel-planner/README.md +35 -0
- data/lib/insika/templates/travel-planner/agent.rb +87 -0
- data/lib/insika/templates.rb +112 -0
- data/lib/insika/tick.rb +24 -12
- data/lib/insika/timezone.rb +45 -0
- data/lib/insika/tool_batch.rb +67 -0
- data/lib/insika/tool_usage_report.rb +162 -0
- data/lib/insika/tools/generate_image.rb +52 -7
- data/lib/insika/tools/load_knowledge.rb +74 -0
- data/lib/insika/tools/run_persona_eval.rb +328 -0
- data/lib/insika/tools/save_artifact.rb +95 -0
- data/lib/insika/turn_budget.rb +91 -0
- data/lib/insika/turn_output.rb +1 -1
- data/lib/insika/turn_state.rb +15 -4
- data/lib/insika/version.rb +1 -1
- data/lib/insika/wiring/graph.rb +184 -12
- data/lib/insika/wiring/graph_chat.rb +102 -0
- data/lib/insika.rb +64 -0
- metadata +109 -5
- data/docs/build.md +0 -14
- data/docs/understand.md +0 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 345e57c18a277e8ecd49b2481300c1474c60b2e0c3c384a086740e0de5ec3a2e
|
|
4
|
+
data.tar.gz: 800794431e279fec34f135e4e203a0488b04066b667bc691806ea5f575d81530
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 199cc16b9ea651ec2da1d2e6f7ddea5020194882da00cf96981e8d5d44086233862873d14640d11cd1d445f9d202992ed46691210f9fb1699b1a3d56a99b3145
|
|
7
|
+
data.tar.gz: 44d24bc53036da3803ee6eba6203d1addc8ccf0bd27c1aa15d1e9acfe763bca807ede55c2b7136ee2c245e5cd725541c719baa018c99e09638e964803bf688a9
|
data/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,302 @@ it is released. Entries land with the pull request that makes the change.
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.8.0] - 2026-08-31
|
|
12
|
+
|
|
13
|
+
The post-consolidation hardening wave: the last two OpenClaw-era names are gone
|
|
14
|
+
from the wire (**breaking** — `insika:<agent>` / `X-Insika-Agent` and
|
|
15
|
+
`INSIKA_GATEWAY_TOKEN`, no aliases), and the engine learned to manage its own
|
|
16
|
+
long conversations — in-session compaction (RFC-0044), a tool budget that warns
|
|
17
|
+
before it kills, goal recitation at the tail of the context, and a tool-usage
|
|
18
|
+
audit report. Update `/v1` consumers and the gateway-token variable together
|
|
19
|
+
with this upgrade.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **In-session compaction (RFC-0044).** When a session's uncompacted
|
|
24
|
+
transcript grows past `compact_after` messages (default 40), everything but
|
|
25
|
+
the last `keep_last` (default 20) is summarized by a cheap model
|
|
26
|
+
(`compaction.model` → platform `utility_model`) into one
|
|
27
|
+
`<conversation_summary>` history fragment; the tail stays verbatim and the
|
|
28
|
+
boundary is stable between compactions, so the prompt cache holds after it.
|
|
29
|
+
Runs post-turn, off the critical path, best-effort; persisted on the session
|
|
30
|
+
record with a monotonic boundary. Opt-in via the long-reserved Settings
|
|
31
|
+
`compaction` hash (the Studio general form is back), `insika doctor` warns
|
|
32
|
+
when it is enabled with no model, and every compaction is observable:
|
|
33
|
+
`:context_compacted` event, `insika.context.compacted` counter, `{upto,
|
|
34
|
+
runs}` + its own category in the context trace. See
|
|
35
|
+
[Context](docs/CONTEXT.md).
|
|
36
|
+
|
|
37
|
+
- **`insika tools:report` — the tool audit.** The per-session trace never
|
|
38
|
+
aggregated, so "which tools does this agent carry and never use?" had no
|
|
39
|
+
answer. The new CLI report reads the stored traces per agent (tasks →
|
|
40
|
+
sessions → `tool_traces`) and flags allowlisted-but-never-called tools,
|
|
41
|
+
tools over 30% errors in the window, and tools not called in N days
|
|
42
|
+
(default 14). Read-only — the operator removes. `--agent`, `--days`,
|
|
43
|
+
`--json`. See [Tools](docs/TOOLS.md).
|
|
44
|
+
|
|
45
|
+
- **Two series promoted to OTEL metrics.** `insika.cache.hit_rate` (histogram,
|
|
46
|
+
`%` — cache reads over the billed prompt, per turn, same arithmetic as the
|
|
47
|
+
Studio's per-agent series) and `insika.tool.loop_intervened` (counter — the
|
|
48
|
+
loop detector's one-shot warning, labelled by tool). Both computed in the
|
|
49
|
+
telemetry bridge from events that already existed: zero cost when OTEL is
|
|
50
|
+
off, no engine change. See [Observability](docs/OBSERVABILITY.md).
|
|
51
|
+
|
|
52
|
+
- **The doctor warns on a prompt file that outgrew a prompt.** The
|
|
53
|
+
`prompt-files` sweep now WARNs (never errors) past ~6 000 estimated tokens
|
|
54
|
+
or 600 lines, with the actual counts — the LLM-generated merchant-pack
|
|
55
|
+
shape that costs 20%+ extra tokens per turn. Corrupted-wrapper detection
|
|
56
|
+
is unchanged.
|
|
57
|
+
|
|
58
|
+
- **The tool budget is announced before it kills.** `max_tool_calls` was
|
|
59
|
+
enforced but silent: the model met the ceiling only when the turn died with
|
|
60
|
+
`stage: :tool_limit`, having delivered nothing. At **10 / 5 / 2** calls
|
|
61
|
+
remaining the engine now appends a short, escalating notice at the next
|
|
62
|
+
tool-batch boundary and emits `:tool_budget_warned`. It is a `user` message,
|
|
63
|
+
never a system one, so the cacheable system prefix stays byte-stable.
|
|
64
|
+
Verified live (DeepSeek): a turn asking for 30 lookups on a budget of 20 used
|
|
65
|
+
to die at `tool_limit`; it now stops at 18 and answers with what it has. The
|
|
66
|
+
turn's counter, the notices and the abort are one object (`TurnBudget`), and
|
|
67
|
+
the batch-boundary arithmetic it shares with the loop detector moved into
|
|
68
|
+
`ToolBatch`.
|
|
69
|
+
|
|
70
|
+
### Changed
|
|
71
|
+
|
|
72
|
+
- **The briefing recites the goal at the TAIL of the context.** `<briefing>`
|
|
73
|
+
used to carry known facts, the still-missing list and the next step in one
|
|
74
|
+
`:system` block at the top. The goal half was **moved** (not copied) into a
|
|
75
|
+
new `<recitation>` block rendered after the whole history, as the last thing
|
|
76
|
+
the model reads before the current message — attention is strongest at the
|
|
77
|
+
end, and a goal stated only at the top is the first thing a 30-call turn
|
|
78
|
+
forgets. New `:tail` fragment placement; the head keeps the durable facts.
|
|
79
|
+
|
|
80
|
+
- **The `/v1/responses` wire names are insika-native**: the agent arrives as
|
|
81
|
+
`model: "insika:<agent>"` and the fallback header is `X-Insika-Agent`. Hard
|
|
82
|
+
rename, no alias — a consumer still sending `openclaw:<agent>` gets
|
|
83
|
+
"model/agent missing". Update every `/v1` consumer together with this upgrade.
|
|
84
|
+
- **`INSIKA_GATEWAY_TOKEN` replaces `OPENCLAW_GATEWAY_TOKEN`** as the Bearer for
|
|
85
|
+
`/v1` + `/a2a`. Hard rename, no alias: the old name was a leftover of the
|
|
86
|
+
OpenClaw migration and is now a foreign var the engine ignores. Update the
|
|
87
|
+
variable on every deployment before upgrading. The dead `OPENCLAW_AGENTS_DIR`
|
|
88
|
+
env spec (nothing read it) is gone.
|
|
89
|
+
|
|
90
|
+
### Fixed
|
|
91
|
+
|
|
92
|
+
- **The Studio home charts went blank for three hours every day.** The activity
|
|
93
|
+
buckets key on calendar parts (date, hour) of `updated_at`, which the engine
|
|
94
|
+
writes in UTC, but `render_home` read `Time.now` in the host's local zone. On a
|
|
95
|
+
UTC-3 host, from 21:00 local onward "today" was already tomorrow in UTC: the
|
|
96
|
+
14-day chart matched no session and the 24h sparkline's floor was set three
|
|
97
|
+
hours in the future, dropping the newest buckets. Stamps are now read through
|
|
98
|
+
one `utc_time` helper and `now` is UTC. Instant comparisons (`active_now`)
|
|
99
|
+
never had the bug — only the calendar arithmetic did.
|
|
100
|
+
- **The Conversations trend showed "−1" for the day's first conversation.** The
|
|
101
|
+
14-day series is oldest-first and ends at today, so its last pair reads
|
|
102
|
+
`[yesterday, today]`; it was destructured the other way round, inverting the
|
|
103
|
+
sign on every conversations delta. The Messages card was always correct.
|
|
104
|
+
- **Declaring a tool allow/deny list now opts the profile into the policy.** The
|
|
105
|
+
lists are applied by exactly one policy — the builtin `tool_allowlist` — and
|
|
106
|
+
the policy engine runs only the policies a profile *names*. So an agent with
|
|
107
|
+
`tools_allow: ["a", "b"]` and no `policies` sent **every registered tool** to
|
|
108
|
+
the model, silently: 508 tools / 52 405 tokens of schemas per request against
|
|
109
|
+
an allowlist of 2, observed on a real run. `tools_deny` was ignored the same
|
|
110
|
+
way. `AgentProfile.build` now appends `tool_allowlist` whenever `tools_allow`,
|
|
111
|
+
`tools_deny` or `tools_allow_groups` is declared — presence, not emptiness, so
|
|
112
|
+
`tools_allow: []` still means "no tools". A stored record left in the old
|
|
113
|
+
state is repaired on read but stays wrong on disk, so `doctor` gained a
|
|
114
|
+
`tool-allowlist` **error** naming each agent to re-save.
|
|
115
|
+
- **A DSL agent could write its briefing and never read it back.** The
|
|
116
|
+
`Insika.agent`/`Insika.system` runtime wired every context provider except
|
|
117
|
+
`Briefing`, so `update_briefing` / `set_next_step` persisted state that never
|
|
118
|
+
reached a prompt. Now wired, before `Session`, like `config/wiring.rb`.
|
|
119
|
+
- **Docker image shipped without `docs/`, so `GET /start.md` was a 500 with
|
|
120
|
+
`INSIKA_ONBOARDING=1`.** `.dockerignore` excluded the whole tree; the onboarding
|
|
121
|
+
surface reads `docs/onboarding/start.md`, `docs/prompts/` and the public
|
|
122
|
+
`docs/*.md` from disk at request time. Only the Jekyll build output and the
|
|
123
|
+
internal notes are excluded now, and a spec asserts `.dockerignore` never drops
|
|
124
|
+
a file `Insika::Onboarding` serves. Found on the first Railway deploy with
|
|
125
|
+
onboarding on; the gem was never affected (its payload keeps `docs/`).
|
|
126
|
+
|
|
127
|
+
## [0.7.0] - 2026-08-29
|
|
128
|
+
|
|
129
|
+
The pre-1.0 consolidation: MCP servers as first-class tools, a template gallery,
|
|
130
|
+
the knowledge layer (extract → consolidate → retrieve → export), a session-sticky
|
|
131
|
+
router for N>1 capacity, and the Studio brought to visual parity. The `/v1`
|
|
132
|
+
contract is unchanged. The version jumps from 0.3 to 0.7 to say what the code
|
|
133
|
+
already says — the surface is the 1.0 surface; what remains is operational proof,
|
|
134
|
+
not features.
|
|
135
|
+
|
|
136
|
+
### Fixed
|
|
137
|
+
|
|
138
|
+
- **An agent's identity never falls back to another agent's.** An agent with
|
|
139
|
+
neither `prompt_files` nor `base_prompt` silently inherited the deployment-wide
|
|
140
|
+
default identity, so one agent could answer as another's persona (seen live,
|
|
141
|
+
deterministic, previously misdiagnosed as a concurrency bug). It now raises
|
|
142
|
+
`Insika::ContextError` and aborts the turn instead.
|
|
143
|
+
- **A text-only turn absorbs a burst of messages instead of leaking a follow-up.**
|
|
144
|
+
Steering only drained the mailbox at a tool-batch boundary; a turn with no tool
|
|
145
|
+
calls never had one, so a customer who sent four messages in a row got one
|
|
146
|
+
answer that only saw the first. The executor now runs one extra round in the
|
|
147
|
+
same turn when the mailbox is not empty.
|
|
148
|
+
- **The turn supervisor starts at boot, not on the first served turn** — a
|
|
149
|
+
deployment whose only agents are scheduled never fired tick/alert/distill
|
|
150
|
+
workers until unrelated traffic arrived.
|
|
151
|
+
- **Every Linux/Docker build was failing** on two independent packaging gaps:
|
|
152
|
+
`Gemfile.lock` only listed `arm64-darwin` (#185), and the Dockerfile's builder
|
|
153
|
+
stage did not copy `lib/insika/packaging.rb`, which the gemspec requires (#184;
|
|
154
|
+
a spec now parses the Dockerfile against the gemspec's `require_relative`s).
|
|
155
|
+
- **MCP**: `refresh` reused a permanently broken memoized client, so an edited
|
|
156
|
+
server config needed a full process restart; and ruby_llm-mcp sent a
|
|
157
|
+
spec-invalid `Origin` header (URL with a path) that Origin-checking servers
|
|
158
|
+
(GitHub, Grafana, Metabase) rejected on every request — now stripped.
|
|
159
|
+
- **Media**: STT and image-generation calls always raised past the RubyLLM
|
|
160
|
+
boundary (raw bytes where a path was expected, `assume_model_exists` with no
|
|
161
|
+
provider). Found live-validating against real audio/PDF fixtures; a contract
|
|
162
|
+
spec now guards the boundary.
|
|
163
|
+
- **`insika harvest`/`knowledge:backfill` never wired the CLI's provider
|
|
164
|
+
keys** — both build their own miner/extractor `ask` outside a full app
|
|
165
|
+
boot (no `LlmConfigurator`), so `RubyLLM.config` was empty and a real run
|
|
166
|
+
raised `RubyLLM::ConfigurationError` on the first live call, no matter how
|
|
167
|
+
the agent was configured. Found running `knowledge:backfill` against real
|
|
168
|
+
staging traffic for the first time. `configure_eval_llm!` (added for
|
|
169
|
+
`evals:simulate`, PR #190) is now `configure_cli_llm!` and both commands
|
|
170
|
+
call it before building their factory.
|
|
171
|
+
|
|
172
|
+
### Added
|
|
173
|
+
|
|
174
|
+
- **MCP servers are first-class tools** (#178–#182). `Insika::McpClient` builds a
|
|
175
|
+
real stdio/http/sse client (ruby_llm-mcp, lazy-loaded) from an `McpStore`
|
|
176
|
+
record; `McpToolRegistry` executes live through it, merged into the overlay
|
|
177
|
+
registry as a third source (base > data-tools > mcp) so allowlists, traces,
|
|
178
|
+
budgets and checkpoints work unchanged. Config surfaces: JSON import/export in
|
|
179
|
+
the `mcpServers` format, `insika mcp list|add|remove|import|test|refresh`, the
|
|
180
|
+
`mcp` DSL declaration (which auto-grants `mcp:<name>` on the agent's allowlist),
|
|
181
|
+
`/v1/mcp`, and a transport-aware `/studio/mcp` page with per-instance status and
|
|
182
|
+
"Test connection". stdio is arbitrary command execution by config and stays
|
|
183
|
+
behind `INSIKA_MCP_STDIO=1`.
|
|
184
|
+
- **Template gallery** (#183). Six example agents ship inside the gem
|
|
185
|
+
(`lib/insika/templates/<name>/agent.rb` + README) — one DSL file is both doors:
|
|
186
|
+
`insika new` copies it, the Studio gallery instantiates it. Starter
|
|
187
|
+
(travel-planner, keyless public APIs), Advanced (research-analyst fan-out),
|
|
188
|
+
Always-on (daily-digest: schedule + artifact), Teams (review-panel) and more.
|
|
189
|
+
- **Session-sticky router** — `insika-router`, a standalone Async/Falcon proxy that
|
|
190
|
+
runs N engine backends (`WEB_CONCURRENCY=1` each) behind a consistent-hash ring
|
|
191
|
+
keyed on the session id, so per-session FIFO/collect/steer guarantees hold at
|
|
192
|
+
N>1 capacity with no change to the executor. Static (Railway) and DNS
|
|
193
|
+
(Kubernetes headless Service) backend discovery; an unreachable backend answers
|
|
194
|
+
the retry envelope. Opt-in.
|
|
195
|
+
- **Studio visual parity** — view transitions and motion (CSS only, reduced-motion
|
|
196
|
+
aware), the transcript as product (mono label rows, tool calls as pill chips,
|
|
197
|
+
three-zone session viewer), a live home over `/studio/events`, master-detail
|
|
198
|
+
lists.
|
|
199
|
+
- **`queue_mode` and `steer_max_messages` editable per agent** in the Studio
|
|
200
|
+
Config form — operations can switch steering on/off without touching the store.
|
|
201
|
+
Blank inherits the platform default; `steer_max_messages: 0` never steers.
|
|
202
|
+
- **Paste-prompt journeys for coding agents** — four skill-shaped prompts under
|
|
203
|
+
`docs/prompts/`, served at `GET /docs/<name>.md` next to `start.md`:
|
|
204
|
+
run-examples, add-tool, diagnose-turn and go-live.
|
|
205
|
+
- **`run_persona_eval` swaps side-effect tools instead of refusing** — a target
|
|
206
|
+
agent with a reachable POST tool gets a throwaway executor whose registry
|
|
207
|
+
resolves every side-effect name to a recorder, sharing every other collaborator
|
|
208
|
+
of the real graph.
|
|
209
|
+
- **`examples/analytics`** — MCP wired to a real, key-authenticated server
|
|
210
|
+
(OpenSEO over http, bearer via `OPENSEO_API_KEY`).
|
|
211
|
+
- **`insika knowledge:export`** — writes one `<name>.md` per learned concept
|
|
212
|
+
under a directory (`KnowledgeStore#export_dir`). The storage format IS the
|
|
213
|
+
export format, so it's a dump, not a converter, directly consumable by
|
|
214
|
+
okf-gem/graphify. Idempotent — nothing here is lossy, so there's no
|
|
215
|
+
`--force` to reason about. `--format graphml` writes one combined
|
|
216
|
+
`knowledge.graphml` instead — a node per concept, an edge per `[[link]]`
|
|
217
|
+
resolved against the same export set (a dangling link is dropped, never a
|
|
218
|
+
broken edge) — hand-built, hand-escaped XML, no new dependency.
|
|
219
|
+
|
|
220
|
+
- **Knowledge retrieval** — with `knowledge: {retrieve: true}`, every turn
|
|
221
|
+
the engine now searches the agent's learned concepts for the ones
|
|
222
|
+
relevant to the customer's message (`Insika::Knowledge::Index::Scan` —
|
|
223
|
+
pure term overlap × confidence × recency, no embeddings, no network call)
|
|
224
|
+
and injects the top few as a level-1 `<knowledge>` block (name/
|
|
225
|
+
description/confidence/provenance, new `Context::Priority::KNOWLEDGE =
|
|
226
|
+
77`, between skills and memory), expanding one hop through a concept's
|
|
227
|
+
`[[links]]`. A `load_knowledge` tool — outside `tools_allow`, wired
|
|
228
|
+
exactly like `load_skill` — loads a concept's full body on demand;
|
|
229
|
+
calling it fires `:knowledge_retrieved`, the adoption metric that
|
|
230
|
+
actually matters (a concept sitting unread in the prompt taught nothing).
|
|
231
|
+
`knowledge.index: "fts5"` is accepted but falls back to the built-in scan
|
|
232
|
+
index — deliberately not built yet: `scripts/bench_knowledge_index.rb`
|
|
233
|
+
measured `Index::Scan` at hundreds of milliseconds per search before a
|
|
234
|
+
read-cache fix (re-parsing a concept's frontmatter on every search was
|
|
235
|
+
~90% of the cost, not the store I/O); after the fix it's sub-1.5ms at the
|
|
236
|
+
concept counts this feature targets, and building the SQLite adapter is
|
|
237
|
+
deferred to a real, documented latency trigger (~1000 concepts/agent)
|
|
238
|
+
instead of being built speculatively.
|
|
239
|
+
|
|
240
|
+
- **Knowledge consolidation + the Studio page** — a repeat concept name no
|
|
241
|
+
longer blindly overwrites. The engine now decides same claim (bumps
|
|
242
|
+
occurrences/sources/confidence — `min(0.95, 0.5 + 0.1 × distinct_sources)`,
|
|
243
|
+
no model call), related claim (one extra model call merges the two
|
|
244
|
+
bodies — `Insika::Knowledge::Consolidator`/`ConsolidatorFactory`), or
|
|
245
|
+
contradicting claim (never merged — appended under a `## Contradiction`
|
|
246
|
+
heading, confidence dropped to `0.4`, `:knowledge_conflict` emitted). No
|
|
247
|
+
consolidator configured, or an unusable answer, defaults to contradicting —
|
|
248
|
+
the conservative choice. `/studio/knowledge` (single-agent-scoped like
|
|
249
|
+
Harvest) lists every concept with a conflict filter, the same CodeMirror
|
|
250
|
+
editor Skills uses (also how an operator hand-promotes `provenance:
|
|
251
|
+
observed` to `policy`), version history/restore, and delete — all through
|
|
252
|
+
three new bus commands (`write_concept`/`delete_concept`/`restore_concept`,
|
|
253
|
+
wired through every composition root).
|
|
254
|
+
|
|
255
|
+
- **Knowledge, layer 1 (extraction)** — the engine can now learn durable
|
|
256
|
+
**concepts** (facts, procedures, policies, objections) from finished
|
|
257
|
+
conversations, opt-in per agent via `knowledge extract: true`. After a turn
|
|
258
|
+
completes, off the critical path, the platform `utility_model` proposes
|
|
259
|
+
candidate concepts; the engine schema-validates the answer, drops any
|
|
260
|
+
model-authored `provenance`/`confidence`/`sources` (stamped by the engine
|
|
261
|
+
instead — every extracted concept is `provenance: observed`, never
|
|
262
|
+
`policy`), redacts the body for PII, and persists it as a markdown+
|
|
263
|
+
frontmatter record in the new `KnowledgeStore` (`Insika::KnowledgeStore`,
|
|
264
|
+
scoped per agent/tenant like `MemoryStore`, versioned like `SkillStore`).
|
|
265
|
+
Emits `:knowledge_learned` (name/type/agent only, never content). The
|
|
266
|
+
recovery path is `insika knowledge:backfill --agent ID [--since DATE]`,
|
|
267
|
+
replaying stored sessions through the same extractor. No retrieval into a
|
|
268
|
+
turn's prompt yet — see `docs/KNOWLEDGE.md` for what's shipped and what's
|
|
269
|
+
still planned.
|
|
270
|
+
|
|
271
|
+
- **Plugin loading is on in every root** — `Server::Boot`'s `load_plugins`
|
|
272
|
+
step was a no-op in both composition roots, so the tested
|
|
273
|
+
`Insika::Plugin::Loader` never ran outside the `insika-code`
|
|
274
|
+
example. It now runs at boot in the minimal wiring, the demo deployment
|
|
275
|
+
and DSL-run agents, via a shared `Wiring::Graph.load_plugins`. Discovery
|
|
276
|
+
roots: announced gems (default-enabled), `INSIKA_PLUGIN_DIR` (workspace)
|
|
277
|
+
and the repo's `plugins/` — the latter two gated by `INSIKA_PLUGINS`,
|
|
278
|
+
with `INSIKA_PLUGINS_DISABLED` as the absolute veto. Plugin skills and
|
|
279
|
+
prompts join the catalogs at the lowest precedence (a workspace or
|
|
280
|
+
authored skill still wins). The dead `OPENCLAW_PLUGIN_DIR` env spec
|
|
281
|
+
(nothing ever read it) is replaced by the three new keys.
|
|
282
|
+
|
|
283
|
+
- **Media parity** — three transport gaps closed, all additive:
|
|
284
|
+
`generate_image` can now EDIT as well as generate — `source_image_urls`
|
|
285
|
+
(or, absent those, the turn's own inbound photo by default) ride
|
|
286
|
+
`RubyLLM.paint(with:)`, an optional `mask_url` rides `paint(mask:)`; a
|
|
287
|
+
fourth inbound part type, `document` (`{ "type": "document", "url": … }`,
|
|
288
|
+
capped at 10 MB), attaches to the ask like an image and deposits
|
|
289
|
+
`{{ctx.document_url}}` for data tools; and audio transcription now carries
|
|
290
|
+
a vocabulary `prompt:` (per-agent `stt_prompt`, falling back to the
|
|
291
|
+
deployment-wide `INSIKA_STT_PROMPT`) so domain terms (product names, brand
|
|
292
|
+
terms) transcribe correctly instead of phonetically. Text-to-image and
|
|
293
|
+
plain audio transcription stay byte-identical when neither feature is used.
|
|
294
|
+
- **Demo data** — `insika demo:seed` (and a matching "Seed demo data" button
|
|
295
|
+
under Studio Settings) provisions a bundled `demo-store` agent and writes
|
|
296
|
+
enough realistic data to see every loop working at once: a funnel with a
|
|
297
|
+
frozen baseline, follow-ups in all four states, refinement runs across the
|
|
298
|
+
lifecycle, pending and resolved approvals, distillation proposals and a
|
|
299
|
+
memory fact, and a golden set with a mixed-result baseline. One code path
|
|
300
|
+
(`Insika::Demo::Seeder`) behind both front doors, same discipline as every
|
|
301
|
+
other Studio button. Fixed two pre-existing gaps this surfaced: `config.ru`
|
|
302
|
+
never wired `proposal_store`/`budget_ledger` into the Studio (the Facts page
|
|
303
|
+
and the funnel's spend pill were unreachable in production), and
|
|
304
|
+
`scripts/serve_real.rb` never wired the outcome/funnel/follow-up/proposal
|
|
305
|
+
stores at all.
|
|
306
|
+
|
|
11
307
|
## [0.3.0] - 2026-08-19
|
|
12
308
|
|
|
13
309
|
The proof-and-consultant wave: shadow parity against a frozen criterion, the
|
data/README.md
CHANGED
|
@@ -80,42 +80,77 @@ served — no secrets) and **`GET /docs`** + **`GET /docs/<name>.md`** (these do
|
|
|
80
80
|
markdown). Public and on by default when you `serve`; opt-in in production
|
|
81
81
|
(`INSIKA_ONBOARDING=1`).
|
|
82
82
|
|
|
83
|
+
Three more paste-prompts cover the steps after that, served and structured the same way
|
|
84
|
+
(one file each under `docs/prompts/`):
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
Read http://localhost:9292/docs/add-tool.md then add a currency tool to my agent
|
|
88
|
+
Read http://localhost:9292/docs/diagnose-turn.md — this turn failed, investigate
|
|
89
|
+
Read http://localhost:9292/docs/run-examples.md then run every example for me
|
|
90
|
+
Read http://localhost:9292/docs/go-live.md then take this agent to production
|
|
91
|
+
```
|
|
92
|
+
|
|
83
93
|
## Docs by goal
|
|
84
94
|
|
|
85
|
-
|
|
95
|
+
The groups below are the same six the [site](https://guizaols.github.io/insika/)
|
|
96
|
+
navigates by.
|
|
97
|
+
|
|
98
|
+
**Start here**
|
|
86
99
|
|
|
87
100
|
- [Why Insika](docs/WHY.md) — a runtime vs a DIY loop, an assembled framework, or a hosted gateway.
|
|
101
|
+
- [Running locally](docs/RUNNING-LOCAL.md) — the local demo, the control UI, wiring tools to your own backend.
|
|
88
102
|
- [Architecture](docs/ARCHITECTURE.md) — the turn pipeline, the tool-loop, checkpoint recovery, composition roots, diagrams.
|
|
103
|
+
- [Demo data](docs/DEMO.md) — `insika demo:seed` populates one agent with a funnel, follow-ups, refinement runs, approvals, facts and evals at once, so a fresh instance shows every loop working before you build your own.
|
|
89
104
|
|
|
90
|
-
**
|
|
105
|
+
**Core concepts**
|
|
91
106
|
|
|
92
|
-
- [Agents](docs/AGENTS.md) — the AgentProfile and
|
|
107
|
+
- [Agents](docs/AGENTS.md) — the AgentProfile and every key on it; create and edit at runtime.
|
|
108
|
+
- [Limits and policy](docs/POLICY.md) — the five layers: allowed tools, approvals, guardrails, edge limits, reasoning.
|
|
93
109
|
- [Tools](docs/TOOLS.md) — code vs data vs MCP tools, manifests, egress troubleshooting.
|
|
94
110
|
- [Skills](docs/SKILLS.md) — the SKILL.md format and progressive loading.
|
|
95
111
|
- [Context](docs/CONTEXT.md) — what fills a turn's prompt; budget, eviction, memory.
|
|
96
112
|
- [Workflows](docs/WORKFLOWS.md) — deterministic orchestration of several agents: the five patterns, and when to let the model choose instead.
|
|
113
|
+
- [examples/](examples/) — one small runnable project per capability.
|
|
114
|
+
|
|
115
|
+
**Integrate**
|
|
116
|
+
|
|
117
|
+
- [The /v1 API](docs/API.md) — the frozen compatibility contract: the surface, the additive-only rule, the version gate.
|
|
97
118
|
- [Channels](docs/CHANNELS.md) — how people reach the agent: a widget on your site in one `<script>` tag, or keep your own WhatsApp/Slack stack (relay).
|
|
119
|
+
- [Media](docs/MEDIA.md) — photos, voice notes and documents through the message contract; generated images back out.
|
|
120
|
+
- [Embedding](docs/EMBEDDING.md) — mount Insika into the Ruby app you already have: `Insika.embed(backend:)` and a Rack app for your router.
|
|
98
121
|
- [Plugins](docs/PLUGINS.md) — the two extension tiers: config-only, or a gem the engine loads.
|
|
99
|
-
- [
|
|
100
|
-
- [examples/](examples/) — one small runnable project per capability.
|
|
122
|
+
- [Templates](docs/TEMPLATES.md) — example agents shipped in the gem: `insika new <name>` or a Studio click gets you a running, editable app in one command.
|
|
101
123
|
|
|
102
124
|
**Ship it**
|
|
103
125
|
|
|
104
126
|
- [Security](docs/SECURITY.md) — guardrails, egress, approvals, edge limits, secrets.
|
|
105
127
|
- [Sandbox](docs/SANDBOX.md) — the confined-execution primitive.
|
|
106
|
-
- [Deploy](docs/DEPLOY.md) — Falcon, a durable SQLite volume, tokens.
|
|
107
|
-
- [
|
|
128
|
+
- [Deploy](docs/DEPLOY.md) — Falcon, a durable SQLite volume, tokens, the process model.
|
|
129
|
+
- [Router](docs/ROUTER.md) — the session-sticky proxy that keeps per-session guarantees past one worker.
|
|
130
|
+
- [Releasing](docs/RELEASING.md) — how the gem is cut, and the install proof that runs before it is published.
|
|
108
131
|
|
|
109
|
-
**Operate
|
|
132
|
+
**Operate**
|
|
110
133
|
|
|
111
|
-
- [Observability](docs/OBSERVABILITY.md) —
|
|
112
|
-
- [
|
|
134
|
+
- [Observability](docs/OBSERVABILITY.md) — the event stream, plus opt-in OpenTelemetry: turns as traces and metrics, the attribute convention, dashboard recipes.
|
|
135
|
+
- [Schedules](docs/SCHEDULING.md) — recurring turns the engine fires on its own tick, with no cron on another box.
|
|
136
|
+
- [Artifacts](docs/ARTIFACTS.md) — a report the agent can hand you a URL to.
|
|
113
137
|
- [Load test](docs/LOADTEST.md) — load-testing and data topology.
|
|
138
|
+
- [Soak](docs/SOAK.md) — the long run that finds what a short one cannot.
|
|
139
|
+
- [Benchmark](docs/BENCHMARK.md) — the neutral, reproducible, provider-free engine benchmark.
|
|
140
|
+
|
|
141
|
+
**Improve**
|
|
142
|
+
|
|
114
143
|
- [Evals](docs/EVALS.md) — the cases that grade an agent: rubrics, the judge panel, and the pre-merge gate.
|
|
115
144
|
- [Refinement](docs/REFINEMENT.md) — read an agent's own traffic back as a ranked report of what broke.
|
|
145
|
+
- [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
|
+
- [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.
|
|
116
147
|
- [Facts](docs/FACTS.md) — distill finished customer conversations into proposed facts; a human approves them into memory (nothing is ever applied automatically).
|
|
117
148
|
- [Harvest](docs/HARVEST.md) — mine real traffic for SKILL proposals; the negative list, the evidence-ledger grounding filter and the double gate hold every proposal to a human approval and the append-only log (nothing is ever applied automatically).
|
|
118
149
|
|
|
150
|
+
**Reference**
|
|
151
|
+
|
|
152
|
+
- [The domain-free core](docs/domain.md) — what the gem ships, what a deployment declares, and how to clear it.
|
|
153
|
+
|
|
119
154
|
All of the above is also browsable, searchable and cross-linked at
|
|
120
155
|
**[guizaols.github.io/insika](https://guizaols.github.io/insika/)** — the same files,
|
|
121
156
|
rendered. Reading this repo as an agent? [llms.txt](llms.txt) indexes the docs;
|
|
@@ -141,5 +176,6 @@ and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). Vulnerabilities go through
|
|
|
141
176
|
|
|
142
177
|
## Status
|
|
143
178
|
|
|
144
|
-
Pre-
|
|
145
|
-
([CHANGELOG.md](CHANGELOG.md)). Licensed
|
|
179
|
+
Pre-1.0 — published on [RubyGems](https://rubygems.org/gems/insika); APIs may
|
|
180
|
+
still change between minor versions ([CHANGELOG.md](CHANGELOG.md)). Licensed
|
|
181
|
+
**MIT** ([LICENSE](LICENSE)).
|