insika 0.2.0 → 0.7.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 +325 -17
- data/README.md +52 -11
- data/bin/insika +895 -8
- data/bin/insika-router +87 -0
- data/docs/AGENTS.md +229 -163
- data/docs/API.md +56 -0
- data/docs/ARCHITECTURE.md +3 -2
- data/docs/ARTIFACTS.md +95 -0
- data/docs/BENCHMARK.md +2 -2
- data/docs/CHANNELS.md +111 -21
- data/docs/CONTEXT.md +132 -19
- data/docs/DEMO.md +80 -0
- data/docs/DEPLOY.md +75 -4
- data/docs/EMBEDDING.md +1 -1
- data/docs/EVALS.md +146 -2
- data/docs/FACTS.md +135 -0
- data/docs/HARVEST.md +116 -0
- data/docs/KNOWLEDGE.md +290 -0
- data/docs/LOADTEST.md +16 -10
- data/docs/MEDIA.md +128 -0
- data/docs/OBSERVABILITY.md +65 -6
- data/docs/OUTCOMES.md +137 -0
- data/docs/PLUGINS.md +51 -6
- data/docs/POLICY.md +216 -0
- data/docs/REFINEMENT.md +17 -12
- data/docs/RELEASING.md +27 -0
- data/docs/ROUTER.md +213 -0
- data/docs/RUNNING-LOCAL.md +6 -6
- data/docs/SCHEDULING.md +121 -0
- data/docs/SECURITY.md +79 -2
- data/docs/SKILLS.md +13 -4
- data/docs/SOAK.md +127 -0
- data/docs/TEMPLATES.md +134 -0
- data/docs/TOOLS.md +220 -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 +115 -0
- data/docs/improve.md +20 -0
- data/docs/index.md +9 -6
- 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 +202 -10
- data/lib/insika/artifact_signing.rb +82 -0
- data/lib/insika/artifact_store.rb +160 -0
- data/lib/insika/balloon_splitter.rb +102 -0
- data/lib/insika/budget_ledger.rb +34 -3
- data/lib/insika/cache_series_store.rb +49 -0
- data/lib/insika/channel_delivery.rb +119 -14
- data/lib/insika/channels/relay.rb +77 -3
- data/lib/insika/channels/web.rb +2 -2
- data/lib/insika/chat_builder.rb +105 -2
- data/lib/insika/checkpoint_store.rb +16 -0
- data/lib/insika/commands/agent_payload.rb +3 -3
- data/lib/insika/commands/backfill_knowledge.rb +145 -0
- data/lib/insika/commands/cancel_followup.rb +49 -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 +107 -0
- data/lib/insika/commands/export_customer_memory.rb +48 -0
- data/lib/insika/commands/forget_customer.rb +117 -0
- data/lib/insika/commands/freeze_funnel_baseline.rb +113 -0
- data/lib/insika/commands/gate_harvest.rb +138 -0
- data/lib/insika/commands/gate_refinement.rb +1 -1
- data/lib/insika/commands/judge_shadow_pairs.rb +124 -0
- data/lib/insika/commands/memory_forget_fact.rb +20 -4
- data/lib/insika/commands/memory_put_fact.rb +23 -4
- data/lib/insika/commands/promote_harvest.rb +130 -0
- data/lib/insika/commands/record_outcome.rb +46 -0
- data/lib/insika/commands/record_shadow_reply.rb +68 -0
- data/lib/insika/commands/refresh_mcp_tools.rb +47 -0
- data/lib/insika/commands/reject_harvest.rb +38 -0
- data/lib/insika/commands/resolve_proposal.rb +108 -0
- data/lib/insika/commands/restore_concept.rb +34 -0
- data/lib/insika/commands/revoke_contact.rb +49 -0
- data/lib/insika/commands/rollback_harvest.rb +86 -0
- data/lib/insika/commands/run_distillation.rb +186 -0
- data/lib/insika/commands/run_harvest.rb +393 -0
- data/lib/insika/commands/seed_demo_data.rb +31 -0
- data/lib/insika/commands/send_message.rb +103 -6
- data/lib/insika/commands/session_purge.rb +67 -0
- data/lib/insika/commands/upsert_mcp.rb +6 -3
- data/lib/insika/commands/write_concept.rb +57 -0
- data/lib/insika/contact_store.rb +183 -0
- data/lib/insika/context/builder.rb +21 -3
- data/lib/insika/context/fragment.rb +7 -3
- data/lib/insika/context/priority.rb +5 -0
- data/lib/insika/context/provider.rb +17 -3
- data/lib/insika/context/providers/briefing.rb +96 -0
- data/lib/insika/context/providers/knowledge.rb +108 -0
- data/lib/insika/context/providers/memory.rb +16 -7
- data/lib/insika/context/providers/prompt.rb +57 -23
- data/lib/insika/context/providers/skill.rb +2 -0
- data/lib/insika/context/providers/tool_search.rb +2 -0
- data/lib/insika/context_trace_store.rb +38 -2
- 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/distill.rb +224 -0
- data/lib/insika/distill_engine.rb +169 -0
- data/lib/insika/doctor.rb +889 -11
- data/lib/insika/dsl/definition.rb +3 -2
- data/lib/insika/dsl/runtime.rb +69 -82
- data/lib/insika/dsl/server_boot.rb +92 -1
- data/lib/insika/dsl/system.rb +10 -2
- data/lib/insika/dsl.rb +186 -5
- data/lib/insika/edge_limiter.rb +28 -7
- data/lib/insika/env_schema.rb +25 -3
- data/lib/insika/errors.rb +11 -0
- data/lib/insika/evals/assertions.rb +3 -2
- data/lib/insika/evals/golden.rb +41 -4
- data/lib/insika/evals/judge.rb +47 -2
- data/lib/insika/evals/pairwise.rb +29 -6
- 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 +83 -1
- data/lib/insika/event_stream.rb +10 -0
- data/lib/insika/evidence.rb +183 -0
- data/lib/insika/executor.rb +869 -76
- data/lib/insika/followup_engine.rb +207 -0
- data/lib/insika/followup_policy.rb +198 -0
- data/lib/insika/followup_store.rb +306 -0
- data/lib/insika/funnel_declaration.rb +106 -0
- data/lib/insika/funnel_fold.rb +179 -0
- data/lib/insika/funnel_store.rb +163 -0
- data/lib/insika/golden_store.rb +17 -2
- data/lib/insika/grounding/matcher.rb +69 -0
- data/lib/insika/grounding.rb +44 -0
- data/lib/insika/harvest/conversion_gate.rb +159 -0
- data/lib/insika/harvest/criterion.rb +98 -0
- data/lib/insika/harvest/gate.rb +194 -0
- data/lib/insika/harvest/negative_list.rb +199 -0
- data/lib/insika/harvest.rb +241 -0
- data/lib/insika/harvest_engine.rb +193 -0
- data/lib/insika/harvest_store.rb +548 -0
- data/lib/insika/knowledge.rb +680 -0
- data/lib/insika/knowledge_store.rb +140 -0
- 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 +382 -0
- data/lib/insika/memory_audit_store.rb +85 -0
- data/lib/insika/memory_store.rb +264 -23
- data/lib/insika/message_origin.rb +7 -2
- data/lib/insika/middleware.rb +9 -0
- data/lib/insika/model_visible.rb +87 -0
- data/lib/insika/model_visible_trace_store.rb +66 -0
- data/lib/insika/onboarding.rb +22 -1
- data/lib/insika/outbox_store.rb +42 -4
- data/lib/insika/outcome_store.rb +147 -0
- data/lib/insika/overlay_tool_registry.rb +37 -17
- data/lib/insika/packaging.rb +163 -0
- data/lib/insika/parity/criterion.rb +79 -0
- data/lib/insika/parity/verdict.rb +318 -0
- data/lib/insika/prefix_fingerprint.rb +58 -0
- data/lib/insika/profile_source.rb +29 -1
- data/lib/insika/prompt_catalog.rb +10 -0
- data/lib/insika/proposal_store.rb +271 -0
- data/lib/insika/queue_policy.rb +4 -1
- data/lib/insika/refinement/proposer.rb +1 -1
- data/lib/insika/reliability.rb +32 -6
- data/lib/insika/retention.rb +316 -0
- 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/routing.rb +101 -0
- data/lib/insika/safety/config.rb +44 -4
- data/lib/insika/safety/corpus.rb +255 -0
- data/lib/insika/safety/detectors.rb +32 -113
- data/lib/insika/safety/factory.rb +15 -2
- data/lib/insika/safety/grounding_enforcer.rb +59 -0
- data/lib/insika/safety/grounding_validator.rb +49 -0
- data/lib/insika/safety/input_guardrail.rb +1 -1
- data/lib/insika/safety/moderator.rb +1 -1
- data/lib/insika/safety/output_filter.rb +9 -5
- data/lib/insika/safety/output_validator.rb +11 -5
- 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/schema_guard.rb +35 -0
- data/lib/insika/server/app.rb +247 -17
- data/lib/insika/server/rack_app.rb +21 -1
- data/lib/insika/server/responses.rb +40 -1
- data/lib/insika/session_actor.rb +8 -4
- data/lib/insika/session_store.rb +65 -2
- data/lib/insika/settings_store.rb +10 -0
- data/lib/insika/shadow_pair_store.rb +258 -0
- data/lib/insika/skill_catalog.rb +16 -0
- data/lib/insika/soak/envelope.rb +140 -0
- data/lib/insika/soak/report.rb +392 -0
- data/lib/insika/soak/runner.rb +554 -0
- data/lib/insika/steer_injector.rb +21 -10
- data/lib/insika/store.rb +10 -1
- data/lib/insika/stores/memory.rb +6 -0
- data/lib/insika/stores/sqlite.rb +8 -0
- data/lib/insika/studio/app.rb +1437 -54
- data/lib/insika/studio/assets/dist/application.css +1 -1
- data/lib/insika/studio/assets/dist/application.js +23 -23
- data/lib/insika/studio/assets/dist/favicon.svg +6 -0
- data/lib/insika/studio/forms.rb +308 -10
- data/lib/insika/studio/nav_icons.rb +19 -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 +62 -278
- data/lib/insika/studio/views/agents.erb +71 -54
- data/lib/insika/studio/views/approvals.erb +4 -1
- data/lib/insika/studio/views/artifact.erb +23 -0
- data/lib/insika/studio/views/artifacts.erb +59 -0
- data/lib/insika/studio/views/chats.erb +4 -1
- data/lib/insika/studio/views/customer.erb +94 -0
- data/lib/insika/studio/views/customers.erb +32 -0
- data/lib/insika/studio/views/evals.erb +6 -3
- data/lib/insika/studio/views/facts.erb +133 -0
- data/lib/insika/studio/views/followups.erb +125 -0
- data/lib/insika/studio/views/funnel.erb +106 -0
- data/lib/insika/studio/views/harvest.erb +234 -0
- data/lib/insika/studio/views/home.erb +106 -66
- data/lib/insika/studio/views/knowledge.erb +123 -0
- data/lib/insika/studio/views/layout.erb +15 -11
- data/lib/insika/studio/views/mcp.erb +174 -80
- data/lib/insika/studio/views/parity.erb +147 -0
- data/lib/insika/studio/views/playground.erb +7 -1
- data/lib/insika/studio/views/session.erb +233 -124
- data/lib/insika/studio/views/settings.erb +41 -1
- data/lib/insika/studio/views/skills.erb +1 -2
- data/lib/insika/studio/views/system_files.erb +1 -1
- data/lib/insika/studio/views/task.erb +13 -0
- data/lib/insika/studio/views/tasks.erb +4 -1
- data/lib/insika/studio/views/tools.erb +24 -10
- data/lib/insika/task_store.rb +21 -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 +38 -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 +58 -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/testing/store_contract.rb +27 -6
- data/lib/insika/tick.rb +47 -11
- data/lib/insika/timezone.rb +45 -0
- data/lib/insika/tool_definition.rb +17 -7
- data/lib/insika/tool_envelope.rb +69 -0
- data/lib/insika/tool_manifest.rb +5 -1
- data/lib/insika/tools/data_defined_tool.rb +10 -0
- data/lib/insika/tools/generate_image.rb +89 -0
- 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/tools/schedule_followup.rb +164 -0
- data/lib/insika/tools/tts.rb +47 -0
- data/lib/insika/tools/update_briefing.rb +126 -0
- data/lib/insika/turn_output.rb +1 -1
- data/lib/insika/turn_state.rb +49 -1
- data/lib/insika/turn_timing.rb +22 -2
- data/lib/insika/version.rb +1 -1
- data/lib/insika/vitals.rb +84 -0
- data/lib/insika/wiring/graph.rb +472 -13
- data/lib/insika/wiring/graph_chat.rb +102 -0
- data/lib/insika.rb +149 -3
- metadata +181 -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: 5c2b2fbe064af45aa132f93de00954b24dc504e052db2e059b4f6daa151e248b
|
|
4
|
+
data.tar.gz: 50cabcc10d82eabdfd08de562bd61feddf1a9de68ee6427343c80c5cf6ad9d8c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3004e30a234349bcb91db185fcc31f9b52cbdeb7660c613b1fc229adf6bbbe717d9abc8ebcdc5bf9ecc125986694c0d2f3a82e1d48eb83105ff74db0467e4d91
|
|
7
|
+
data.tar.gz: ca4bec6a8b8cd03ee1a5c2df627e7da778d3dd157f30f848c70f8077ac467570284bf934e3a4c8040fb223503855d9cdcad111b9139ed093c702b6a8850ea1ff
|
data/CHANGELOG.md
CHANGED
|
@@ -8,44 +8,352 @@ it is released. Entries land with the pull request that makes the change.
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## [0.7.0] - 2026-08-29
|
|
12
|
+
|
|
13
|
+
The pre-1.0 consolidation: MCP servers as first-class tools, a template gallery,
|
|
14
|
+
the knowledge layer (extract → consolidate → retrieve → export), a session-sticky
|
|
15
|
+
router for N>1 capacity, and the Studio brought to visual parity. The `/v1`
|
|
16
|
+
contract is unchanged. The version jumps from 0.3 to 0.7 to say what the code
|
|
17
|
+
already says — the surface is the 1.0 surface; what remains is operational proof,
|
|
18
|
+
not features.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- **An agent's identity never falls back to another agent's.** An agent with
|
|
23
|
+
neither `prompt_files` nor `base_prompt` silently inherited the deployment-wide
|
|
24
|
+
default identity, so one agent could answer as another's persona (seen live,
|
|
25
|
+
deterministic, previously misdiagnosed as a concurrency bug). It now raises
|
|
26
|
+
`Insika::ContextError` and aborts the turn instead.
|
|
27
|
+
- **A text-only turn absorbs a burst of messages instead of leaking a follow-up.**
|
|
28
|
+
Steering only drained the mailbox at a tool-batch boundary; a turn with no tool
|
|
29
|
+
calls never had one, so a customer who sent four messages in a row got one
|
|
30
|
+
answer that only saw the first. The executor now runs one extra round in the
|
|
31
|
+
same turn when the mailbox is not empty.
|
|
32
|
+
- **The turn supervisor starts at boot, not on the first served turn** — a
|
|
33
|
+
deployment whose only agents are scheduled never fired tick/alert/distill
|
|
34
|
+
workers until unrelated traffic arrived.
|
|
35
|
+
- **Every Linux/Docker build was failing** on two independent packaging gaps:
|
|
36
|
+
`Gemfile.lock` only listed `arm64-darwin` (#185), and the Dockerfile's builder
|
|
37
|
+
stage did not copy `lib/insika/packaging.rb`, which the gemspec requires (#184;
|
|
38
|
+
a spec now parses the Dockerfile against the gemspec's `require_relative`s).
|
|
39
|
+
- **MCP**: `refresh` reused a permanently broken memoized client, so an edited
|
|
40
|
+
server config needed a full process restart; and ruby_llm-mcp sent a
|
|
41
|
+
spec-invalid `Origin` header (URL with a path) that Origin-checking servers
|
|
42
|
+
(GitHub, Grafana, Metabase) rejected on every request — now stripped.
|
|
43
|
+
- **Media**: STT and image-generation calls always raised past the RubyLLM
|
|
44
|
+
boundary (raw bytes where a path was expected, `assume_model_exists` with no
|
|
45
|
+
provider). Found live-validating against real audio/PDF fixtures; a contract
|
|
46
|
+
spec now guards the boundary.
|
|
47
|
+
- **`insika harvest`/`knowledge:backfill` never wired the CLI's provider
|
|
48
|
+
keys** — both build their own miner/extractor `ask` outside a full app
|
|
49
|
+
boot (no `LlmConfigurator`), so `RubyLLM.config` was empty and a real run
|
|
50
|
+
raised `RubyLLM::ConfigurationError` on the first live call, no matter how
|
|
51
|
+
the agent was configured. Found running `knowledge:backfill` against real
|
|
52
|
+
staging traffic for the first time. `configure_eval_llm!` (added for
|
|
53
|
+
`evals:simulate`, PR #190) is now `configure_cli_llm!` and both commands
|
|
54
|
+
call it before building their factory.
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- **MCP servers are first-class tools** (#178–#182). `Insika::McpClient` builds a
|
|
59
|
+
real stdio/http/sse client (ruby_llm-mcp, lazy-loaded) from an `McpStore`
|
|
60
|
+
record; `McpToolRegistry` executes live through it, merged into the overlay
|
|
61
|
+
registry as a third source (base > data-tools > mcp) so allowlists, traces,
|
|
62
|
+
budgets and checkpoints work unchanged. Config surfaces: JSON import/export in
|
|
63
|
+
the `mcpServers` format, `insika mcp list|add|remove|import|test|refresh`, the
|
|
64
|
+
`mcp` DSL declaration (which auto-grants `mcp:<name>` on the agent's allowlist),
|
|
65
|
+
`/v1/mcp`, and a transport-aware `/studio/mcp` page with per-instance status and
|
|
66
|
+
"Test connection". stdio is arbitrary command execution by config and stays
|
|
67
|
+
behind `INSIKA_MCP_STDIO=1`.
|
|
68
|
+
- **Template gallery** (#183). Six example agents ship inside the gem
|
|
69
|
+
(`lib/insika/templates/<name>/agent.rb` + README) — one DSL file is both doors:
|
|
70
|
+
`insika new` copies it, the Studio gallery instantiates it. Starter
|
|
71
|
+
(travel-planner, keyless public APIs), Advanced (research-analyst fan-out),
|
|
72
|
+
Always-on (daily-digest: schedule + artifact), Teams (review-panel) and more.
|
|
73
|
+
- **Session-sticky router** — `insika-router`, a standalone Async/Falcon proxy that
|
|
74
|
+
runs N engine backends (`WEB_CONCURRENCY=1` each) behind a consistent-hash ring
|
|
75
|
+
keyed on the session id, so per-session FIFO/collect/steer guarantees hold at
|
|
76
|
+
N>1 capacity with no change to the executor. Static (Railway) and DNS
|
|
77
|
+
(Kubernetes headless Service) backend discovery; an unreachable backend answers
|
|
78
|
+
the retry envelope. Opt-in.
|
|
79
|
+
- **Studio visual parity** — view transitions and motion (CSS only, reduced-motion
|
|
80
|
+
aware), the transcript as product (mono label rows, tool calls as pill chips,
|
|
81
|
+
three-zone session viewer), a live home over `/studio/events`, master-detail
|
|
82
|
+
lists.
|
|
83
|
+
- **`queue_mode` and `steer_max_messages` editable per agent** in the Studio
|
|
84
|
+
Config form — operations can switch steering on/off without touching the store.
|
|
85
|
+
Blank inherits the platform default; `steer_max_messages: 0` never steers.
|
|
86
|
+
- **Paste-prompt journeys for coding agents** — four skill-shaped prompts under
|
|
87
|
+
`docs/prompts/`, served at `GET /docs/<name>.md` next to `start.md`:
|
|
88
|
+
run-examples, add-tool, diagnose-turn and go-live.
|
|
89
|
+
- **`run_persona_eval` swaps side-effect tools instead of refusing** — a target
|
|
90
|
+
agent with a reachable POST tool gets a throwaway executor whose registry
|
|
91
|
+
resolves every side-effect name to a recorder, sharing every other collaborator
|
|
92
|
+
of the real graph.
|
|
93
|
+
- **`examples/analytics`** — MCP wired to a real, key-authenticated server
|
|
94
|
+
(OpenSEO over http, bearer via `OPENSEO_API_KEY`).
|
|
95
|
+
- **`insika knowledge:export`** — writes one `<name>.md` per learned concept
|
|
96
|
+
under a directory (`KnowledgeStore#export_dir`). The storage format IS the
|
|
97
|
+
export format, so it's a dump, not a converter, directly consumable by
|
|
98
|
+
okf-gem/graphify. Idempotent — nothing here is lossy, so there's no
|
|
99
|
+
`--force` to reason about. `--format graphml` writes one combined
|
|
100
|
+
`knowledge.graphml` instead — a node per concept, an edge per `[[link]]`
|
|
101
|
+
resolved against the same export set (a dangling link is dropped, never a
|
|
102
|
+
broken edge) — hand-built, hand-escaped XML, no new dependency.
|
|
103
|
+
|
|
104
|
+
- **Knowledge retrieval** — with `knowledge: {retrieve: true}`, every turn
|
|
105
|
+
the engine now searches the agent's learned concepts for the ones
|
|
106
|
+
relevant to the customer's message (`Insika::Knowledge::Index::Scan` —
|
|
107
|
+
pure term overlap × confidence × recency, no embeddings, no network call)
|
|
108
|
+
and injects the top few as a level-1 `<knowledge>` block (name/
|
|
109
|
+
description/confidence/provenance, new `Context::Priority::KNOWLEDGE =
|
|
110
|
+
77`, between skills and memory), expanding one hop through a concept's
|
|
111
|
+
`[[links]]`. A `load_knowledge` tool — outside `tools_allow`, wired
|
|
112
|
+
exactly like `load_skill` — loads a concept's full body on demand;
|
|
113
|
+
calling it fires `:knowledge_retrieved`, the adoption metric that
|
|
114
|
+
actually matters (a concept sitting unread in the prompt taught nothing).
|
|
115
|
+
`knowledge.index: "fts5"` is accepted but falls back to the built-in scan
|
|
116
|
+
index — deliberately not built yet: `scripts/bench_knowledge_index.rb`
|
|
117
|
+
measured `Index::Scan` at hundreds of milliseconds per search before a
|
|
118
|
+
read-cache fix (re-parsing a concept's frontmatter on every search was
|
|
119
|
+
~90% of the cost, not the store I/O); after the fix it's sub-1.5ms at the
|
|
120
|
+
concept counts this feature targets, and building the SQLite adapter is
|
|
121
|
+
deferred to a real, documented latency trigger (~1000 concepts/agent)
|
|
122
|
+
instead of being built speculatively.
|
|
123
|
+
|
|
124
|
+
- **Knowledge consolidation + the Studio page** — a repeat concept name no
|
|
125
|
+
longer blindly overwrites. The engine now decides same claim (bumps
|
|
126
|
+
occurrences/sources/confidence — `min(0.95, 0.5 + 0.1 × distinct_sources)`,
|
|
127
|
+
no model call), related claim (one extra model call merges the two
|
|
128
|
+
bodies — `Insika::Knowledge::Consolidator`/`ConsolidatorFactory`), or
|
|
129
|
+
contradicting claim (never merged — appended under a `## Contradiction`
|
|
130
|
+
heading, confidence dropped to `0.4`, `:knowledge_conflict` emitted). No
|
|
131
|
+
consolidator configured, or an unusable answer, defaults to contradicting —
|
|
132
|
+
the conservative choice. `/studio/knowledge` (single-agent-scoped like
|
|
133
|
+
Harvest) lists every concept with a conflict filter, the same CodeMirror
|
|
134
|
+
editor Skills uses (also how an operator hand-promotes `provenance:
|
|
135
|
+
observed` to `policy`), version history/restore, and delete — all through
|
|
136
|
+
three new bus commands (`write_concept`/`delete_concept`/`restore_concept`,
|
|
137
|
+
wired through every composition root).
|
|
138
|
+
|
|
139
|
+
- **Knowledge, layer 1 (extraction)** — the engine can now learn durable
|
|
140
|
+
**concepts** (facts, procedures, policies, objections) from finished
|
|
141
|
+
conversations, opt-in per agent via `knowledge extract: true`. After a turn
|
|
142
|
+
completes, off the critical path, the platform `utility_model` proposes
|
|
143
|
+
candidate concepts; the engine schema-validates the answer, drops any
|
|
144
|
+
model-authored `provenance`/`confidence`/`sources` (stamped by the engine
|
|
145
|
+
instead — every extracted concept is `provenance: observed`, never
|
|
146
|
+
`policy`), redacts the body for PII, and persists it as a markdown+
|
|
147
|
+
frontmatter record in the new `KnowledgeStore` (`Insika::KnowledgeStore`,
|
|
148
|
+
scoped per agent/tenant like `MemoryStore`, versioned like `SkillStore`).
|
|
149
|
+
Emits `:knowledge_learned` (name/type/agent only, never content). The
|
|
150
|
+
recovery path is `insika knowledge:backfill --agent ID [--since DATE]`,
|
|
151
|
+
replaying stored sessions through the same extractor. No retrieval into a
|
|
152
|
+
turn's prompt yet — see `docs/KNOWLEDGE.md` for what's shipped and what's
|
|
153
|
+
still planned.
|
|
154
|
+
|
|
155
|
+
- **Plugin loading is on in every root** — `Server::Boot`'s `load_plugins`
|
|
156
|
+
step was a no-op in both composition roots, so the tested
|
|
157
|
+
`Insika::Plugin::Loader` never ran outside the `insika-code`
|
|
158
|
+
example. It now runs at boot in the minimal wiring, the demo deployment
|
|
159
|
+
and DSL-run agents, via a shared `Wiring::Graph.load_plugins`. Discovery
|
|
160
|
+
roots: announced gems (default-enabled), `INSIKA_PLUGIN_DIR` (workspace)
|
|
161
|
+
and the repo's `plugins/` — the latter two gated by `INSIKA_PLUGINS`,
|
|
162
|
+
with `INSIKA_PLUGINS_DISABLED` as the absolute veto. Plugin skills and
|
|
163
|
+
prompts join the catalogs at the lowest precedence (a workspace or
|
|
164
|
+
authored skill still wins). The dead `OPENCLAW_PLUGIN_DIR` env spec
|
|
165
|
+
(nothing ever read it) is replaced by the three new keys.
|
|
166
|
+
|
|
167
|
+
- **Media parity** — three transport gaps closed, all additive:
|
|
168
|
+
`generate_image` can now EDIT as well as generate — `source_image_urls`
|
|
169
|
+
(or, absent those, the turn's own inbound photo by default) ride
|
|
170
|
+
`RubyLLM.paint(with:)`, an optional `mask_url` rides `paint(mask:)`; a
|
|
171
|
+
fourth inbound part type, `document` (`{ "type": "document", "url": … }`,
|
|
172
|
+
capped at 10 MB), attaches to the ask like an image and deposits
|
|
173
|
+
`{{ctx.document_url}}` for data tools; and audio transcription now carries
|
|
174
|
+
a vocabulary `prompt:` (per-agent `stt_prompt`, falling back to the
|
|
175
|
+
deployment-wide `INSIKA_STT_PROMPT`) so domain terms (product names, brand
|
|
176
|
+
terms) transcribe correctly instead of phonetically. Text-to-image and
|
|
177
|
+
plain audio transcription stay byte-identical when neither feature is used.
|
|
178
|
+
- **Demo data** — `insika demo:seed` (and a matching "Seed demo data" button
|
|
179
|
+
under Studio Settings) provisions a bundled `demo-store` agent and writes
|
|
180
|
+
enough realistic data to see every loop working at once: a funnel with a
|
|
181
|
+
frozen baseline, follow-ups in all four states, refinement runs across the
|
|
182
|
+
lifecycle, pending and resolved approvals, distillation proposals and a
|
|
183
|
+
memory fact, and a golden set with a mixed-result baseline. One code path
|
|
184
|
+
(`Insika::Demo::Seeder`) behind both front doors, same discipline as every
|
|
185
|
+
other Studio button. Fixed two pre-existing gaps this surfaced: `config.ru`
|
|
186
|
+
never wired `proposal_store`/`budget_ledger` into the Studio (the Facts page
|
|
187
|
+
and the funnel's spend pill were unreachable in production), and
|
|
188
|
+
`scripts/serve_real.rb` never wired the outcome/funnel/follow-up/proposal
|
|
189
|
+
stores at all.
|
|
190
|
+
|
|
191
|
+
## [0.3.0] - 2026-08-19
|
|
192
|
+
|
|
193
|
+
The proof-and-consultant wave: shadow parity against a frozen criterion, the
|
|
194
|
+
72h soak, perceived latency (progressive delivery), the session briefing,
|
|
195
|
+
evidence grounding, the layered identity cache, customer memory in the Studio,
|
|
196
|
+
the conversion ledger, `schedule()` with consent, human-gated facts, the gated
|
|
197
|
+
skill harvest — and a domain-free core: the e-commerce defaults are removable,
|
|
198
|
+
and what ships in the gem is asserted by the suite.
|
|
199
|
+
|
|
200
|
+
### Added
|
|
201
|
+
|
|
202
|
+
- **Shadow mode** — the relay channel can run every turn end to end and deliver
|
|
203
|
+
nothing: the incumbent keeps answering, the engine records what it *would*
|
|
204
|
+
have answered, and the two replies are judged pairwise against a **frozen,
|
|
205
|
+
pre-registered criterion** (the file `INSIKA_PARITY_CRITERION` points at; its
|
|
206
|
+
SHA-256 stamps every pair, and editing it mid-window turns the verdict
|
|
207
|
+
`invalid`, never stale). A panel of judges scores each pair twice with the
|
|
208
|
+
sides swapped, so a preference that flips with presentation order is recorded
|
|
209
|
+
as comparable, not as a preference. The Studio's Parity page folds the
|
|
210
|
+
running verdict on demand. No criterion, no shadow: boot refuses.
|
|
211
|
+
- **The 72h soak** — `insika soak` sustains a declared arrival rate for days and
|
|
212
|
+
asks whether the *process itself* degrades with uptime. A deployment-side
|
|
213
|
+
envelope freezes the load shape and the gated ceilings before the first hour
|
|
214
|
+
(its hash stamps every snapshot); `--preflight` refuses to start on a missing
|
|
215
|
+
precondition; the runner appends hourly vitals as they happen, so a crash at
|
|
216
|
+
hour 60 leaves 60 usable hours; `--verify` recomputes the whole verdict
|
|
217
|
+
offline from the raw records. A fail means *find the leak* — never cut, and
|
|
218
|
+
never loosen the envelope.
|
|
219
|
+
- **Progressive delivery** — the relay can flush the outbox one balloon per
|
|
220
|
+
paragraph (`INSIKA_RELAY_DELIVERY=progressive`), with the first balloon
|
|
221
|
+
posted as soon as the answer exists; the default `:at_end` is byte-identical
|
|
222
|
+
to before. Every channel turn records `first_balloon_ms` (inbound receipt →
|
|
223
|
+
first outbox flush) so the target is measured, not assumed.
|
|
224
|
+
- **Session briefing** — the pack can declare `briefing_fields`; the engine
|
|
225
|
+
keeps the session's working state as data (known fields, still-missing list,
|
|
226
|
+
next step), a tool updates it, and the context provider injects it into the
|
|
227
|
+
turn — the consultant stops re-asking what it already knows.
|
|
228
|
+
- **Grounding** — an `evidence:` contract on the tool envelope: a model claim
|
|
229
|
+
must cite ids that came out of a tool call, with `:enforce` / `:flag` / `:off`
|
|
230
|
+
modes and a per-turn ledger. A claim without evidence is refused or flagged —
|
|
231
|
+
never silently passed through.
|
|
232
|
+
- **Layered identity + observable cache** — context providers are split into
|
|
233
|
+
identity/volatile layers behind a byte-stable cache prefix; the per-agent
|
|
234
|
+
cache-hit series is recorded (`CacheSeriesStore`) and shown on the Studio
|
|
235
|
+
agent detail. Invalidations and hits are measurable, not guessed.
|
|
236
|
+
- **Customer memory in the Studio** — a Customers drill reads and edits the
|
|
237
|
+
per-customer memory cell, with an append-only operator-mutation audit trail
|
|
238
|
+
(content-free digests), provenance metadata, expiry, the LGPD export
|
|
239
|
+
(`/v1/commands/export_customer_memory`) and the existing right to be
|
|
240
|
+
forgotten.
|
|
241
|
+
- **The outcome funnel** — outcomes fold into a store-declared stage funnel
|
|
242
|
+
(`funnel:` on the pack) on the tick: idempotent cumulative counts, an
|
|
243
|
+
attribution window carried as data, a frozen baseline (`:freeze_funnel_baseline`)
|
|
244
|
+
and a Studio page per agent. The stage vocabulary is the deployment's; a bare
|
|
245
|
+
install shows no funnel at all.
|
|
246
|
+
- **Follow-ups** — the agent can book a future contact: `schedule()` and
|
|
247
|
+
`cancel_followup()` tools, a durable per-customer contact state
|
|
248
|
+
(`granted | revoked | unavailable`, where silence is not a refusal), a policy
|
|
249
|
+
engine over the tick (quiet hours, frequency ceilings, dedup, opt-out
|
|
250
|
+
keywords) and a Studio page per agent. A customer who opted out can never be
|
|
251
|
+
rescheduled; blocking happens at fire time, never at schedule time.
|
|
252
|
+
- **Distilled facts** — finished conversations are read back as proposed
|
|
253
|
+
customer facts; a human approves/rejects/dismisses each on the Studio Facts
|
|
254
|
+
page, with a latched dedup ledger (a dismissed tuple is never proposed again),
|
|
255
|
+
optimistic CAS writes and LGPD-friendly retention. Nothing is ever applied
|
|
256
|
+
automatically.
|
|
257
|
+
- **Gated skill harvest** — finished traffic can be mined for skill proposals
|
|
258
|
+
behind a versioned negative list and an evidence ledger (product claims must
|
|
259
|
+
reference ids the origin sessions actually saw); promotion requires the eval
|
|
260
|
+
replay **and** the store's conversion ruler not to regress, with an
|
|
261
|
+
append-only log and snapshot rollback. Nothing is ever applied automatically.
|
|
262
|
+
- **A domain-free core** — the gem payload is a spec-asserted boundary
|
|
263
|
+
(`lib/` + `docs/` + the four root files; `deploy/`, `packs/`, `examples/`,
|
|
264
|
+
`evals/`, `scripts/` and `spec/` never ship, even when tracked). The pt-BR
|
|
265
|
+
guardrail corpus is language-tagged removable data, and `insika doctor --domain`
|
|
266
|
+
inventories what a deployment declares. A bare install names no store.
|
|
267
|
+
- **Model-visible conformance** — every byte that reaches the provider is
|
|
268
|
+
reconstructable from checkpoints + traces, proven byte-for-byte by the
|
|
269
|
+
conformance suite (`spec/insika/conformance/`): what the chat held == the
|
|
270
|
+
checkpoint transcript == the model trace, across plain, tool-calling, steered,
|
|
271
|
+
subagent, scheduled and resuming turns.
|
|
272
|
+
- **Intent routing** — `AgentProfile#routes` classifies the turn's
|
|
273
|
+
message into one configured route with a cheap model before the ask, from a
|
|
274
|
+
prompt auto-generated out of the route descriptions. The route rides the
|
|
275
|
+
turn (`state.route`, the `:route_classified` event, the terminal event), its
|
|
276
|
+
provider cost is counted in the usage, and a route can `delegate` to an
|
|
277
|
+
existing agent (its answer becomes the parent's) or end the turn with the
|
|
278
|
+
stuck outcome (`stuck: true`). Deterministic `default` fallback;
|
|
279
|
+
classifier failure leaves the turn unrouted (additive).
|
|
280
|
+
- **Outcomes** — `POST /v1/outcomes` records a conversation's business
|
|
281
|
+
outcome (`conversion`/`escalation`/`deflected`/…, optional monetary value)
|
|
282
|
+
from the operator or the integration — additive, outside the response
|
|
283
|
+
contract, tenant-stamped. `GET /v1/outcomes` serves the last outcome
|
|
284
|
+
per agent + per-day series; the Studio's agent grid shows the last-outcome
|
|
285
|
+
pill and the agent detail shows the per-day series.
|
|
286
|
+
- **Customer-scoped memory + right to be forgotten** — a message
|
|
287
|
+
carrying a `customer` key moves the memory scope to the `[tenant:]customer`
|
|
288
|
+
cell: two customers under one tenant never read each other (phase 1), and
|
|
289
|
+
the `<request_context>` merchant label stays untouched. Facts gained an
|
|
290
|
+
optimistic CAS write (`replace_if_revision`, microsecond revisions).
|
|
291
|
+
`POST /v1/commands/forget_customer` (phase 2, LGPD) purges one customer's
|
|
292
|
+
memory cell, their sessions and per-session traces — nothing else's.
|
|
293
|
+
- **Tenant deletion + retention** —
|
|
294
|
+
`POST /v1/commands/delete_tenant_data` purges everything the engine holds
|
|
295
|
+
about one tenant (sessions, traces, every memory cell under the tenant and
|
|
296
|
+
its outcome records); the `retention_days` settings key turns on the tick's
|
|
297
|
+
daily age-based sweep (sessions + traces, terminal tasks + checkpoints,
|
|
298
|
+
memory cells and outcomes — OFF by default). The KV store contract gained
|
|
299
|
+
an additive `scopes(prefix)` enumeration.
|
|
300
|
+
- **Media in the message contract** — messages accept
|
|
301
|
+
additive content parts (`text`/`image`/`audio` with a URL). Audio is
|
|
302
|
+
transcribed via RubyLLM STT (model/language via `INSIKA_STT_MODEL`/
|
|
303
|
+
`INSIKA_STT_LANGUAGE`) and the text enters the turn marked
|
|
304
|
+
`source: "voice"` on the terminal event; images attach to the model's ask
|
|
305
|
+
(provider-billed, usage flows) and the first image URL is
|
|
306
|
+
`{{ctx.image_url}}` for data/HTTP tools; media URLs pass the egress guard. The
|
|
307
|
+
OpenAI multimodal `input` array shape works on `/v1/responses`.
|
|
308
|
+
- **Generated media as outputs** — the turn can produce an
|
|
309
|
+
image or a voice clip when BOTH gates agree: the agent opts in
|
|
310
|
+
(`AgentProfile#outputs` — per-kind model/voice/size config) and the request
|
|
311
|
+
declares the channel can receive it (`channel.capabilities`, one of
|
|
312
|
+
`image_output`/`audio_output`; unknown values are a 422 — the abstraction
|
|
313
|
+
admits only what leaks). The `generate_image`/`tts` system tools are wired
|
|
314
|
+
only then, the media rides the envelope additively (`output_parts` on the
|
|
315
|
+
terminal event and the `/v1/responses` completed frame — base64 parts, never
|
|
316
|
+
the answer text), image tokens merge into the turn's usage and every call
|
|
317
|
+
adds an honest `usage.media` counter (the speech API reports no tokens; the
|
|
318
|
+
part carries the model for consumer-side pricing). Generators are injectable
|
|
319
|
+
seams; the defaults are lazy (RubyLLM paint; a thin POST to the
|
|
320
|
+
OpenAI-compatible `/audio/speech` using the same provider config).
|
|
12
321
|
|
|
13
322
|
## [0.2.0] - 2026-08-13
|
|
14
323
|
|
|
15
324
|
The workstreams between the first release and the one the gem actually became:
|
|
16
|
-
multi-tenancy at the edge
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
safe to ship.
|
|
325
|
+
multi-tenancy at the edge, calendar budgets, provider reliability, the stuck
|
|
326
|
+
signal, operator alerts + live TTFB, and the failure-classification core — plus
|
|
327
|
+
the two fix rounds that made them safe to ship.
|
|
20
328
|
|
|
21
329
|
### Added
|
|
22
330
|
|
|
23
|
-
- **Multi-tenant at the edge
|
|
331
|
+
- **Multi-tenant at the edge** — `INSIKA_TENANCY=multi_tenant` resolves the
|
|
24
332
|
Bearer to a principal before the routes: per-tenant + operator tokens stored
|
|
25
333
|
only as SHA-256 hashes, a tenant's sessions/tasks/streams living under its own
|
|
26
334
|
`<tenant>:` namespace (fail-closed: another tenant's reads as `404`), and every
|
|
27
335
|
authoring/config surface refused to a tenant.
|
|
28
|
-
- **Calendar budgets
|
|
336
|
+
- **Calendar budgets** — `AgentProfile#budget` caps the billed spend
|
|
29
337
|
(input + output + cached + cache-creation) per calendar day/month and
|
|
30
338
|
(tenant, agent): HARD (default) fails the turn with the typed
|
|
31
339
|
`Insika::BudgetExceeded` + `retry_after`; `soft: true` runs the turn and warns
|
|
32
340
|
once per window — with the `alert_at` (`0.8`) crossing and the real cap
|
|
33
341
|
crossing as separate events.
|
|
34
|
-
- **Reliability
|
|
342
|
+
- **Reliability** — retries with backoff, mid-turn rotation to the
|
|
35
343
|
fallback chain, a per-`(tenant, provider/model)` circuit breaker with
|
|
36
344
|
half-open trials (a failed trial reopens), and a per-attempt `timeout`
|
|
37
345
|
(default 30s) counted as retryable. A `:fatal` provider error is never
|
|
38
346
|
retried.
|
|
39
|
-
- **Stuck signal
|
|
347
|
+
- **Stuck signal** — an agent declared stuck ends its turn with
|
|
40
348
|
`outcome: "stuck"` on the envelope and a dedicated `:turn_stuck` event — the
|
|
41
349
|
deterministic point a consumer escalates on.
|
|
42
|
-
- **Operator alerts + live TTFB
|
|
350
|
+
- **Operator alerts + live TTFB** — `budget_warning`, `breaker_open` and
|
|
43
351
|
`delivery_failed` POSTed to a per-agent `alerts.webhook` over the at-most-once
|
|
44
352
|
outbox pipeline (boot-recoverable); under `INSIKA_TURN_TIMING` the first
|
|
45
353
|
content chunk emits a live `:ttft` on the streaming envelope.
|
|
46
|
-
- **Failure classification
|
|
354
|
+
- **Failure classification** — provider/transport failures classified by
|
|
47
355
|
action (`:fatal` / `:retryable` / `:rate_limited_*`) and wrapped with the
|
|
48
|
-
provider's `retry_after`; mechanical tool-output dedupe
|
|
356
|
+
provider's `retry_after`; mechanical tool-output dedupe back-references a
|
|
49
357
|
byte-identical repeat only when the reference is genuinely shorter.
|
|
50
358
|
- **The periodic tick** — durability no longer waits for a reboot. Serving
|
|
51
359
|
workers run a tick every `INSIKA_TICK_INTERVAL` (default 60s, `0` disables)
|
|
@@ -58,7 +366,7 @@ safe to ship.
|
|
|
58
366
|
|
|
59
367
|
### Fixed
|
|
60
368
|
|
|
61
|
-
- **
|
|
369
|
+
- **Budget/reliability/alerts criticals** — the budget alert marker no longer returns inside
|
|
62
370
|
the store transaction (a leaked `BEGIN IMMEDIATE` locked SQLite on the 2nd
|
|
63
371
|
over-threshold turn); the monthly reset is December-safe and UTC-aligned; an
|
|
64
372
|
unset reliability timeout is 30s, not 1s, and a timeout retries/rotates
|
|
@@ -66,10 +374,10 @@ safe to ship.
|
|
|
66
374
|
webhook deliveries pass the egress guard (SSRF); `:ttft` is emitted once per
|
|
67
375
|
turn; webhook channels pre-register so the boot sweep recovers pending alerts;
|
|
68
376
|
the alert dispatcher subscribes typed and re-subscribes on overflow.
|
|
69
|
-
- **
|
|
377
|
+
- **Tenancy** — `#revoke` rides the store transaction; a `tenant_id` containing
|
|
70
378
|
`:` is refused (the session-namespace delimiter); `POST /v1/sessions` mints a
|
|
71
379
|
tenant's session under its own prefix.
|
|
72
|
-
- **
|
|
380
|
+
- **Budget and reliability softs** — a failed turn's consumed tokens count against the budget;
|
|
73
381
|
`:breaker_open` alerts only on the closed→open transition; the fallback chain
|
|
74
382
|
dedupes `"model"` vs `"provider/model"` spellings.
|
|
75
383
|
|
|
@@ -143,7 +451,7 @@ The first release: `gem install insika`.
|
|
|
143
451
|
- **The gate refuses to grade a judged baseline without a judge** — a rubric'd case
|
|
144
452
|
with no verdict counts as a pass, so replaying without a judge against a baseline
|
|
145
453
|
recorded with one does not measure less, it measures backwards. Found by running the
|
|
146
|
-
panel against
|
|
454
|
+
panel against real traffic: the gate reported *6/6, no regression* against a
|
|
147
455
|
baseline the same corpus had just scored *2/6*, and both candidates cleared. With the
|
|
148
456
|
judge configured, the same two candidates were correctly rejected on judge-score
|
|
149
457
|
drops. Third member of the same family as the missing and all-red baseline refusals.
|
|
@@ -151,7 +459,7 @@ The first release: `gem install insika`.
|
|
|
151
459
|
input + output and excludes the cached prefix (a 27 KB pack reports `88` total against
|
|
152
460
|
`26624` cached), so a ceiling built on it alone let a run send hundreds of times what
|
|
153
461
|
it said. Cost now bills `total + cached` and records the cached share, which on a real
|
|
154
|
-
|
|
462
|
+
run was 95% of the spend. A run that cannot be gated is also refused **before**
|
|
155
463
|
the proposal is paid for, not after.
|
|
156
464
|
- **The eval baseline is a per-agent record, not only a file** — `evals/baseline.json`
|
|
157
465
|
works from a checkout; the refinement gate runs inside a deployment that has none.
|
data/README.md
CHANGED
|
@@ -22,6 +22,10 @@ deployment.
|
|
|
22
22
|
- **Safe by default** — content-safety guardrails, an egress guard, confined execution, approvals, edge limits.
|
|
23
23
|
- **Observable** — an event stream, per-session tool-call traces, optional OpenTelemetry.
|
|
24
24
|
- **~0.4 ms of engine per turn** — p50 overhead on a neutral, key-free benchmark you can rerun yourself ([methodology](docs/BENCHMARK.md)).
|
|
25
|
+
- **Domain-free core** — the gem carries no store vocabulary, no persona and no fixed
|
|
26
|
+
conversation language: the built-in pt-BR guardrail corpus is removable data, a
|
|
27
|
+
deployment declares what it is, and the payload boundary is a spec the suite asserts
|
|
28
|
+
on ([the domain-free map](docs/domain.md)).
|
|
25
29
|
|
|
26
30
|
## Your first agent
|
|
27
31
|
|
|
@@ -37,7 +41,7 @@ require "insika"
|
|
|
37
41
|
assistant = Insika.agent("assistant") do
|
|
38
42
|
model "deepseek-v4-flash"
|
|
39
43
|
provider :deepseek
|
|
40
|
-
instructions "You are
|
|
44
|
+
instructions "You are a concise and friendly assistant. Answer briefly."
|
|
41
45
|
end
|
|
42
46
|
|
|
43
47
|
puts assistant.reply("hi, what can you do?") # one turn, in-process
|
|
@@ -76,39 +80,76 @@ served — no secrets) and **`GET /docs`** + **`GET /docs/<name>.md`** (these do
|
|
|
76
80
|
markdown). Public and on by default when you `serve`; opt-in in production
|
|
77
81
|
(`INSIKA_ONBOARDING=1`).
|
|
78
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
|
+
|
|
79
93
|
## Docs by goal
|
|
80
94
|
|
|
81
|
-
|
|
95
|
+
The groups below are the same six the [site](https://guizaols.github.io/insika/)
|
|
96
|
+
navigates by.
|
|
97
|
+
|
|
98
|
+
**Start here**
|
|
82
99
|
|
|
83
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.
|
|
84
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.
|
|
85
104
|
|
|
86
|
-
**
|
|
105
|
+
**Core concepts**
|
|
87
106
|
|
|
88
|
-
- [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.
|
|
89
109
|
- [Tools](docs/TOOLS.md) — code vs data vs MCP tools, manifests, egress troubleshooting.
|
|
90
110
|
- [Skills](docs/SKILLS.md) — the SKILL.md format and progressive loading.
|
|
91
111
|
- [Context](docs/CONTEXT.md) — what fills a turn's prompt; budget, eviction, memory.
|
|
92
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.
|
|
93
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.
|
|
94
121
|
- [Plugins](docs/PLUGINS.md) — the two extension tiers: config-only, or a gem the engine loads.
|
|
95
|
-
- [
|
|
96
|
-
- [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.
|
|
97
123
|
|
|
98
124
|
**Ship it**
|
|
99
125
|
|
|
100
126
|
- [Security](docs/SECURITY.md) — guardrails, egress, approvals, edge limits, secrets.
|
|
101
127
|
- [Sandbox](docs/SANDBOX.md) — the confined-execution primitive.
|
|
102
|
-
- [Deploy](docs/DEPLOY.md) — Falcon, a durable SQLite volume, tokens.
|
|
103
|
-
- [
|
|
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.
|
|
104
131
|
|
|
105
|
-
**Operate
|
|
132
|
+
**Operate**
|
|
106
133
|
|
|
107
|
-
- [Observability](docs/OBSERVABILITY.md) —
|
|
108
|
-
- [
|
|
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.
|
|
109
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
|
+
|
|
110
143
|
- [Evals](docs/EVALS.md) — the cases that grade an agent: rubrics, the judge panel, and the pre-merge gate.
|
|
111
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 (retrieval and consolidation are not shipped yet).
|
|
147
|
+
- [Facts](docs/FACTS.md) — distill finished customer conversations into proposed facts; a human approves them into memory (nothing is ever applied automatically).
|
|
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).
|
|
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.
|
|
112
153
|
|
|
113
154
|
All of the above is also browsable, searchable and cross-linked at
|
|
114
155
|
**[guizaols.github.io/insika](https://guizaols.github.io/insika/)** — the same files,
|