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.
Files changed (204) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +296 -0
  3. data/README.md +48 -12
  4. data/bin/insika +725 -0
  5. data/bin/insika-router +87 -0
  6. data/docs/AGENTS.md +116 -406
  7. data/docs/API.md +5 -5
  8. data/docs/ARCHITECTURE.md +3 -2
  9. data/docs/ARTIFACTS.md +137 -0
  10. data/docs/BENCHMARK.md +2 -2
  11. data/docs/CHANNELS.md +14 -14
  12. data/docs/CONTEXT.md +63 -19
  13. data/docs/DEMO.md +80 -0
  14. data/docs/DEPLOY.md +87 -10
  15. data/docs/EMBEDDING.md +1 -1
  16. data/docs/EVALS.md +128 -3
  17. data/docs/FACTS.md +3 -3
  18. data/docs/HARVEST.md +5 -6
  19. data/docs/KNOWLEDGE.md +290 -0
  20. data/docs/LOADTEST.md +17 -29
  21. data/docs/MEDIA.md +128 -0
  22. data/docs/OBSERVABILITY.md +46 -12
  23. data/docs/OUTCOMES.md +137 -0
  24. data/docs/PLUGINS.md +51 -6
  25. data/docs/POLICY.md +222 -0
  26. data/docs/REFINEMENT.md +14 -9
  27. data/docs/RELEASING.md +4 -4
  28. data/docs/ROUTER.md +213 -0
  29. data/docs/RUNNING-LOCAL.md +5 -5
  30. data/docs/SCHEDULING.md +121 -0
  31. data/docs/SECURITY.md +23 -7
  32. data/docs/SKILLS.md +11 -2
  33. data/docs/SOAK.md +3 -3
  34. data/docs/TEMPLATES.md +134 -0
  35. data/docs/TOOLS.md +176 -27
  36. data/docs/WHY.md +1 -1
  37. data/docs/WORKFLOWS.md +2 -2
  38. data/docs/_includes/head_custom.html +5 -0
  39. data/docs/_includes/title.html +13 -0
  40. data/docs/_sass/color_schemes/insika.scss +32 -0
  41. data/docs/_sass/custom/custom.scss +199 -0
  42. data/docs/_sass/custom/setup.scss +26 -0
  43. data/docs/assets/img/favicon.svg +7 -0
  44. data/docs/assets/img/insika-mark.svg +7 -0
  45. data/docs/core-concepts.md +21 -0
  46. data/docs/domain.md +4 -4
  47. data/docs/improve.md +20 -0
  48. data/docs/index.md +8 -5
  49. data/docs/integrate.md +20 -0
  50. data/docs/operate.md +13 -6
  51. data/docs/prompts/ADD-TOOL.md +118 -0
  52. data/docs/prompts/DIAGNOSE-TURN.md +65 -0
  53. data/docs/prompts/GO-LIVE.md +138 -0
  54. data/docs/prompts/RUN-EXAMPLES.md +70 -0
  55. data/docs/reference.md +19 -0
  56. data/docs/ship.md +10 -2
  57. data/docs/start-here.md +18 -0
  58. data/lib/insika/agent_profile.rb +99 -17
  59. data/lib/insika/artifact_signing.rb +82 -0
  60. data/lib/insika/artifact_store.rb +160 -0
  61. data/lib/insika/channel_delivery.rb +1 -1
  62. data/lib/insika/chat_builder.rb +50 -19
  63. data/lib/insika/commands/agent_payload.rb +2 -2
  64. data/lib/insika/commands/backfill_knowledge.rb +145 -0
  65. data/lib/insika/commands/delete_artifact.rb +35 -0
  66. data/lib/insika/commands/delete_concept.rb +34 -0
  67. data/lib/insika/commands/delete_mcp.rb +6 -2
  68. data/lib/insika/commands/delete_tenant_data.rb +15 -3
  69. data/lib/insika/commands/gate_refinement.rb +1 -1
  70. data/lib/insika/commands/refresh_mcp_tools.rb +47 -0
  71. data/lib/insika/commands/restore_concept.rb +34 -0
  72. data/lib/insika/commands/seed_demo_data.rb +31 -0
  73. data/lib/insika/commands/upsert_mcp.rb +6 -3
  74. data/lib/insika/commands/write_concept.rb +57 -0
  75. data/lib/insika/compaction.rb +196 -0
  76. data/lib/insika/context/builder.rb +6 -2
  77. data/lib/insika/context/fragment.rb +4 -1
  78. data/lib/insika/context/priority.rb +8 -0
  79. data/lib/insika/context/providers/briefing.rb +53 -24
  80. data/lib/insika/context/providers/knowledge.rb +108 -0
  81. data/lib/insika/context/providers/prompt.rb +30 -24
  82. data/lib/insika/context/providers/session.rb +46 -10
  83. data/lib/insika/context_trace_store.rb +11 -1
  84. data/lib/insika/cron.rb +189 -0
  85. data/lib/insika/demo/agent_attrs.rb +43 -0
  86. data/lib/insika/demo/golden_cases.rb +81 -0
  87. data/lib/insika/demo/seeder.rb +336 -0
  88. data/lib/insika/doctor.rb +280 -17
  89. data/lib/insika/dsl/definition.rb +3 -2
  90. data/lib/insika/dsl/runtime.rb +64 -79
  91. data/lib/insika/dsl/server_boot.rb +23 -1
  92. data/lib/insika/dsl/system.rb +10 -2
  93. data/lib/insika/dsl.rb +103 -2
  94. data/lib/insika/env_schema.rb +21 -7
  95. data/lib/insika/evals/golden.rb +41 -4
  96. data/lib/insika/evals/judge.rb +47 -2
  97. data/lib/insika/evals/pairwise.rb +11 -0
  98. data/lib/insika/evals/persona.rb +98 -0
  99. data/lib/insika/evals/runner.rb +9 -0
  100. data/lib/insika/evals/simulator.rb +225 -0
  101. data/lib/insika/evals/transport.rb +84 -2
  102. data/lib/insika/event_stream.rb +10 -0
  103. data/lib/insika/executor.rb +295 -55
  104. data/lib/insika/followup_policy.rb +2 -25
  105. data/lib/insika/golden_store.rb +16 -1
  106. data/lib/insika/grounding/matcher.rb +1 -1
  107. data/lib/insika/knowledge.rb +680 -0
  108. data/lib/insika/knowledge_store.rb +140 -0
  109. data/lib/insika/loop_detector.rb +5 -34
  110. data/lib/insika/mcp_client.rb +94 -0
  111. data/lib/insika/mcp_json.rb +74 -0
  112. data/lib/insika/mcp_live_tool.rb +43 -0
  113. data/lib/insika/mcp_store.rb +98 -26
  114. data/lib/insika/mcp_tool_ingestor.rb +30 -8
  115. data/lib/insika/mcp_tool_registry.rb +100 -0
  116. data/lib/insika/media.rb +115 -31
  117. data/lib/insika/message_origin.rb +1 -1
  118. data/lib/insika/middleware.rb +9 -0
  119. data/lib/insika/onboarding.rb +17 -1
  120. data/lib/insika/outcome_store.rb +1 -1
  121. data/lib/insika/overlay_tool_registry.rb +37 -17
  122. data/lib/insika/packaging.rb +2 -2
  123. data/lib/insika/profile_source.rb +15 -1
  124. data/lib/insika/prompt_catalog.rb +10 -0
  125. data/lib/insika/retention.rb +36 -1
  126. data/lib/insika/router/app.rb +157 -0
  127. data/lib/insika/router/backend_pool.rb +98 -0
  128. data/lib/insika/router/hash_ring.rb +55 -0
  129. data/lib/insika/router/proxy_body.rb +34 -0
  130. data/lib/insika/router/session_key.rb +54 -0
  131. data/lib/insika/router.rb +18 -0
  132. data/lib/insika/schedule.rb +177 -0
  133. data/lib/insika/schedule_engine.rb +314 -0
  134. data/lib/insika/schedule_store.rb +208 -0
  135. data/lib/insika/server/app.rb +105 -15
  136. data/lib/insika/server/rack_app.rb +5 -1
  137. data/lib/insika/server/responses.rb +5 -5
  138. data/lib/insika/session_store.rb +34 -4
  139. data/lib/insika/settings_store.rb +8 -1
  140. data/lib/insika/skill_catalog.rb +12 -0
  141. data/lib/insika/soak/runner.rb +4 -4
  142. data/lib/insika/steer_injector.rb +21 -10
  143. data/lib/insika/studio/app.rb +591 -47
  144. data/lib/insika/studio/assets/dist/application.css +1 -1
  145. data/lib/insika/studio/assets/dist/application.js +21 -21
  146. data/lib/insika/studio/forms.rb +57 -5
  147. data/lib/insika/studio/nav_icons.rb +14 -1
  148. data/lib/insika/studio/views/_agent_tab_cache.erb +25 -0
  149. data/lib/insika/studio/views/_agent_tab_config.erb +514 -0
  150. data/lib/insika/studio/views/_agent_tab_history.erb +24 -0
  151. data/lib/insika/studio/views/_agent_tab_loops.erb +54 -0
  152. data/lib/insika/studio/views/_agent_tab_memory.erb +51 -0
  153. data/lib/insika/studio/views/_agent_tab_outcomes.erb +31 -0
  154. data/lib/insika/studio/views/_agent_tab_prompts.erb +108 -0
  155. data/lib/insika/studio/views/_agent_tab_skills.erb +38 -0
  156. data/lib/insika/studio/views/_agents_master.erb +44 -0
  157. data/lib/insika/studio/views/_message.erb +49 -32
  158. data/lib/insika/studio/views/agent_detail.erb +61 -820
  159. data/lib/insika/studio/views/agents.erb +70 -57
  160. data/lib/insika/studio/views/artifact.erb +23 -0
  161. data/lib/insika/studio/views/artifacts.erb +59 -0
  162. data/lib/insika/studio/views/evals.erb +2 -2
  163. data/lib/insika/studio/views/facts.erb +1 -1
  164. data/lib/insika/studio/views/funnel.erb +1 -1
  165. data/lib/insika/studio/views/home.erb +106 -67
  166. data/lib/insika/studio/views/knowledge.erb +123 -0
  167. data/lib/insika/studio/views/layout.erb +14 -11
  168. data/lib/insika/studio/views/mcp.erb +174 -80
  169. data/lib/insika/studio/views/session.erb +231 -177
  170. data/lib/insika/studio/views/settings.erb +50 -1
  171. data/lib/insika/studio/views/skills.erb +1 -1
  172. data/lib/insika/studio/views/tools.erb +24 -9
  173. data/lib/insika/telemetry/recorder.rb +49 -1
  174. data/lib/insika/templates/browser-agent/README.md +36 -0
  175. data/lib/insika/templates/browser-agent/agent.rb +49 -0
  176. data/lib/insika/templates/daily-digest/README.md +47 -0
  177. data/lib/insika/templates/daily-digest/agent.rb +77 -0
  178. data/lib/insika/templates/repo-explorer/README.md +36 -0
  179. data/lib/insika/templates/repo-explorer/agent.rb +45 -0
  180. data/lib/insika/templates/research-analyst/README.md +26 -0
  181. data/lib/insika/templates/research-analyst/agent.rb +68 -0
  182. data/lib/insika/templates/review-panel/README.md +20 -0
  183. data/lib/insika/templates/review-panel/agent.rb +50 -0
  184. data/lib/insika/templates/travel-planner/README.md +35 -0
  185. data/lib/insika/templates/travel-planner/agent.rb +87 -0
  186. data/lib/insika/templates.rb +112 -0
  187. data/lib/insika/tick.rb +24 -12
  188. data/lib/insika/timezone.rb +45 -0
  189. data/lib/insika/tool_batch.rb +67 -0
  190. data/lib/insika/tool_usage_report.rb +162 -0
  191. data/lib/insika/tools/generate_image.rb +52 -7
  192. data/lib/insika/tools/load_knowledge.rb +74 -0
  193. data/lib/insika/tools/run_persona_eval.rb +328 -0
  194. data/lib/insika/tools/save_artifact.rb +95 -0
  195. data/lib/insika/turn_budget.rb +91 -0
  196. data/lib/insika/turn_output.rb +1 -1
  197. data/lib/insika/turn_state.rb +15 -4
  198. data/lib/insika/version.rb +1 -1
  199. data/lib/insika/wiring/graph.rb +184 -12
  200. data/lib/insika/wiring/graph_chat.rb +102 -0
  201. data/lib/insika.rb +64 -0
  202. metadata +109 -5
  203. data/docs/build.md +0 -14
  204. data/docs/understand.md +0 -10
@@ -30,6 +30,21 @@ module Studio
30
30
  limits[field.to_sym] = v
31
31
  end
32
32
  end
33
+ # Burst policy (QueuePolicy). Opt-in keys, same convention as the edge
34
+ # overrides above: blank DELETES (inherit platform / DEFAULTS — followup,
35
+ # steer_max 5); an explicit value pins it for this agent. steer_max 0 is
36
+ # a legitimate "never steer" and is stored, not deleted.
37
+ if (qm = presence(r.params["queue_mode"]))
38
+ unless Insika::QueuePolicy::MODES.map(&:to_s).include?(qm)
39
+ raise Insika::ValidationError, "queue_mode must be one of: #{Insika::QueuePolicy::MODES.join(', ')}"
40
+ end
41
+
42
+ limits[:queue_mode] = qm
43
+ else
44
+ limits.delete(:queue_mode)
45
+ end
46
+ smm = edge_int(r.params["steer_max_messages"], "steer_max_messages")
47
+ smm.nil? ? limits.delete(:steer_max_messages) : limits[:steer_max_messages] = smm
33
48
  {
34
49
  id: @agent.id,
35
50
  model: presence(r.params["model"]),
@@ -44,6 +59,7 @@ module Studio
44
59
  grounding: grounding_patch(r),
45
60
  funnel: funnel_patch(r),
46
61
  followup: followup_patch(r),
62
+ schedules: schedules_patch(r),
47
63
  distill: distill_patch(r),
48
64
  harvest: harvest_patch(r),
49
65
  refinement: refinement_patch(r),
@@ -51,6 +67,7 @@ module Studio
51
67
  reliability: reliability_patch(r),
52
68
  routes: json_patch(r, "routes"),
53
69
  outputs: json_patch(r, "outputs"),
70
+ stt_prompt: presence(r.params["stt_prompt"]),
54
71
  metadata: json_patch(r, "metadata") || {},
55
72
  alerts: alerts_patch(r),
56
73
  edge_stream: edge_stream_patch(r),
@@ -124,6 +141,20 @@ module Studio
124
141
  { "arm" => arm, "policy" => policy }
125
142
  end
126
143
 
144
+ # recurring schedules — a JSON array of declarations
145
+ # (name / trigger / tz / message / session mode / overrides / enabled).
146
+ # Same honest shape as routes/metadata: the list is unbounded, and a
147
+ # JSON textarea is the CSP-safe editor. Blank = no schedules (parity).
148
+ def schedules_patch(r)
149
+ parsed = json_block(r.params["schedules"], "schedules")
150
+ return nil if parsed.nil?
151
+
152
+ parsed = parsed.is_a?(Hash) ? [parsed] : parsed
153
+ raise Insika::ValidationError, "schedules must be an array of declarations" unless parsed.is_a?(Array)
154
+
155
+ parsed
156
+ end
157
+
127
158
  # distillation — enabled checkbox + the forge's knobs. Blank
128
159
  # prompt/model drop the keys (the engine defaults take over).
129
160
  def distill_patch(r)
@@ -430,6 +461,17 @@ module Studio
430
461
  # per-tenant map in the record — the view says so.
431
462
  v = presence(r.params["memory_ttl_days"])
432
463
  patch["memory_ttl_days"] = v.nil? ? nil : Integer(v)
464
+ # In-session compaction (RFC-0044). The checkbox is authoritative on
465
+ # this form (unchecked = disable); the numbers keep their stored value
466
+ # when cleared (deep_merge — the defaults backstop a fresh record);
467
+ # model blank = nil = the platform utility_model.
468
+ compaction = { "enabled" => r.params["compaction_enabled"] == "1",
469
+ "model" => presence(r.params["compaction_model"]) }
470
+ %w[keep_last compact_after].each do |f|
471
+ v = presence(r.params["compaction_#{f}"])
472
+ compaction[f] = Integer(v) if v
473
+ end
474
+ patch["compaction"] = compaction
433
475
  patch
434
476
  end
435
477
 
@@ -559,19 +601,24 @@ module Studio
559
601
  }
560
602
  end
561
603
 
562
- # MCP instance from the form. `env` comes as "KEY=value" lines (CSP
563
- # forbids inline JS for add/remove line; a textarea is the simple, honest
564
- # path). Masked values come back as a sentinel — keeping them preserves
565
- # the secret; changing replaces; deleting the line clears it.
604
+ # MCP instance from the form (transport-aware, but the
605
+ # form always submits every field regardless of which the JS shows;
606
+ # McpStore stores them all either way). `env`/`headers` come as
607
+ # "KEY=value" lines, `args` as one argv token per line (CSP forbids
608
+ # inline JS for add/remove line; a textarea is the simple, honest path).
609
+ # Masked credential values come back as a sentinel — keeping them
610
+ # preserves the secret; changing replaces; deleting the line clears it.
566
611
  def mcp_patch(r)
567
612
  {
568
613
  name: presence(r.params["name"]),
569
614
  transport: presence(r.params["transport"]) || "stdio",
570
615
  command: r.params["command"].to_s,
616
+ args: split_lines(r.params["args"]),
571
617
  url: r.params["url"].to_s,
572
618
  description: r.params["description"].to_s,
573
619
  enabled: r.params["enabled"] == "1",
574
- env: parse_kv_lines(r.params["env"])
620
+ env: parse_kv_lines(r.params["env"]),
621
+ headers: parse_kv_lines(r.params["headers"])
575
622
  }
576
623
  end
577
624
 
@@ -588,5 +635,10 @@ module Studio
588
635
  [k, v.to_s.strip]
589
636
  end.to_h
590
637
  end
638
+
639
+ # One argv token per line (stdio's `args`). Ignores blank lines/comments.
640
+ def split_lines(text)
641
+ text.to_s.each_line.map(&:strip).reject { |l| l.empty? || l.start_with?("#") }
642
+ end
591
643
  end
592
644
  end
@@ -25,12 +25,25 @@ module Studio
25
25
  funnel: '<path d="M3 5h18l-8 9v6l-2 1v-7z"/>',
26
26
  followups: '<path d="M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.7 21a2 2 0 0 1-3.4 0"/>',
27
27
  facts: '<path d="M7 3h11a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H7z"/><path d="M7 3v18"/><path d="M11 8h5"/><path d="M11 12h5"/><path d="M11 16h3"/>',
28
- harvest: '<path d="M4 20V10"/><path d="M20 20V4"/><path d="M4 10h4v10"/><path d="M20 4h-4v16"/><path d="M4 20h16"/><path d="m8 8 4-4 4 4"/>'
28
+ harvest: '<path d="M4 20V10"/><path d="M20 20V4"/><path d="M4 10h4v10"/><path d="M20 4h-4v16"/><path d="M4 20h16"/><path d="m8 8 4-4 4 4"/>',
29
+ knowledge: '<path d="M9 18h6"/><path d="M10 22h4"/><path d="M12 2a7 7 0 0 0-4 12.7V17h8v-2.3A7 7 0 0 0 12 2z"/>',
30
+ artifacts: '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/><path d="m9.5 13 2 2 3.5-3.5"/><path d="M12 15v-4"/>'
29
31
  }.freeze
30
32
 
31
33
  def nav_icon(key)
32
34
  %(<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" ) +
33
35
  %(stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">#{NAV_ICONS[key]}</svg>)
34
36
  end
37
+
38
+ # Transcript event-chip icons: a tool call, a result, a
39
+ # skill, an artifact, a guardrail — each reuses a nav icon (same inline-SVG
40
+ # grammar, CSP-safe). Sized by the chip CSS, colored per kind.
41
+ CHIP_ICONS = { call: :tools, result: :approvals, skill: :skills,
42
+ artifact: :artifacts, guardrail: :system }.freeze
43
+
44
+ def chip_icon(kind)
45
+ key = CHIP_ICONS[kind]
46
+ key ? %(<span class="chip-ic">#{nav_icon(key)}</span>) : ""
47
+ end
35
48
  end
36
49
  end
@@ -0,0 +1,25 @@
1
+ <!-- ── Cache ─────────────────────────────────────────────────── -->
2
+ <section class="section" id="cache" data-tabs-target="panel">
3
+ <div class="section-head">
4
+ <h2>Cache</h2>
5
+ <p class="muted">prefix cache-hit per turn (provider-reported) — the invalidation reason names the first block whose bytes changed vs the previous turn.</p>
6
+ </div>
7
+ <div class="card">
8
+ <% if @cache_series.empty? %>
9
+ <p class="muted">No turns recorded.</p>
10
+ <% else %>
11
+ <ul class="kv">
12
+ <% @cache_series.last(20).reverse.each do |c| %>
13
+ <li>
14
+ <span class="k mono"><%= c["at"] %></span>
15
+ <span class="v">
16
+ <%== c["hit_pct"].nil? ? "—" : "#{c['hit_pct']}% cached" %>
17
+ · <%= c["cached_tokens"] %>/<%= c["prompt_tokens"] %> tokens
18
+ <% if c["invalidation_reason"] %><span class="lat">broke: <%= c["invalidation_reason"] %></span><% end %>
19
+ </span>
20
+ </li>
21
+ <% end %>
22
+ </ul>
23
+ <% end %>
24
+ </div>
25
+ </section>