insika 0.8.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +312 -2
  3. data/README.md +10 -6
  4. data/bin/insika +4 -1
  5. data/bin/insika-router +0 -1
  6. data/docs/AGENTS.md +142 -18
  7. data/docs/API.md +73 -0
  8. data/docs/ARCHITECTURE.md +56 -50
  9. data/docs/ARTIFACTS.md +33 -3
  10. data/docs/BENCHMARK.md +50 -7
  11. data/docs/CHANNELS.md +19 -2
  12. data/docs/CONTEXT.md +96 -27
  13. data/docs/CROSS-HARNESS-BENCH.md +157 -0
  14. data/docs/DEPLOY.md +70 -13
  15. data/docs/EMBEDDING.md +10 -0
  16. data/docs/EVALS.md +129 -10
  17. data/docs/FACTS.md +12 -6
  18. data/docs/HARVEST.md +8 -3
  19. data/docs/KNOWLEDGE.md +14 -0
  20. data/docs/MEDIA.md +6 -2
  21. data/docs/OBSERVABILITY.md +164 -28
  22. data/docs/PERFORMANCE.md +110 -0
  23. data/docs/PLUGINS.md +4 -4
  24. data/docs/POLICY.md +26 -14
  25. data/docs/RELEASING.md +9 -0
  26. data/docs/ROUTER.md +7 -0
  27. data/docs/RUBYLLM_2_MIGRATION.md +307 -0
  28. data/docs/SECURITY.md +34 -1
  29. data/docs/SHARED-CONVERSATIONS.md +40 -0
  30. data/docs/SKILLS.md +5 -3
  31. data/docs/STUDIO.md +122 -0
  32. data/docs/TOOLS.md +238 -42
  33. data/docs/operate.md +3 -0
  34. data/docs/prompts/ADD-TOOL.md +12 -2
  35. data/docs/prompts/DIAGNOSE-TURN.md +3 -0
  36. data/docs/prompts/GO-LIVE.md +3 -1
  37. data/lib/insika/agent_defaults.rb +140 -0
  38. data/lib/insika/agent_file_store.rb +12 -0
  39. data/lib/insika/agent_profile.rb +99 -17
  40. data/lib/insika/artifact_signing.rb +11 -0
  41. data/lib/insika/channels/web/widget.js +33 -0
  42. data/lib/insika/channels/web.rb +5 -2
  43. data/lib/insika/chat_builder.rb +124 -28
  44. data/lib/insika/checkpoint.rb +6 -1
  45. data/lib/insika/checkpoint_store.rb +59 -7
  46. data/lib/insika/commands/agent_payload.rb +3 -3
  47. data/lib/insika/commands/delete_kit.rb +26 -0
  48. data/lib/insika/commands/gate_harvest.rb +3 -0
  49. data/lib/insika/commands/review_guardrail_flag.rb +38 -0
  50. data/lib/insika/commands/run_distillation.rb +5 -8
  51. data/lib/insika/commands/run_harvest.rb +17 -1
  52. data/lib/insika/commands/seed_session.rb +128 -0
  53. data/lib/insika/commands/send_message.rb +9 -3
  54. data/lib/insika/commands/update_settings.rb +23 -1
  55. data/lib/insika/commands/write_kit.rb +27 -0
  56. data/lib/insika/compaction.rb +33 -7
  57. data/lib/insika/config_store.rb +87 -7
  58. data/lib/insika/context/builder.rb +29 -9
  59. data/lib/insika/context/priority.rb +5 -0
  60. data/lib/insika/context/provider.rb +7 -2
  61. data/lib/insika/context/providers/briefing.rb +11 -8
  62. data/lib/insika/context/providers/fence_notice.rb +27 -0
  63. data/lib/insika/context/providers/knowledge.rb +32 -6
  64. data/lib/insika/context/providers/memory.rb +61 -8
  65. data/lib/insika/context/providers/pending_confirmation.rb +52 -0
  66. data/lib/insika/context/providers/prompt.rb +17 -4
  67. data/lib/insika/context/providers/session.rb +46 -6
  68. data/lib/insika/context/reranker.rb +75 -0
  69. data/lib/insika/distill.rb +22 -13
  70. data/lib/insika/doctor.rb +142 -4
  71. data/lib/insika/dsl/runtime.rb +37 -4
  72. data/lib/insika/dsl/server_boot.rb +4 -12
  73. data/lib/insika/dsl.rb +19 -5
  74. data/lib/insika/edge_limiter.rb +27 -16
  75. data/lib/insika/egress_guard.rb +11 -3
  76. data/lib/insika/env_schema.rb +33 -73
  77. data/lib/insika/errors.rb +1 -0
  78. data/lib/insika/evals/assertions.rb +259 -18
  79. data/lib/insika/evals/golden.rb +230 -4
  80. data/lib/insika/evals/judge.rb +19 -10
  81. data/lib/insika/evals/moderator_compare.rb +47 -0
  82. data/lib/insika/evals/report.rb +61 -9
  83. data/lib/insika/evals/runner.rb +64 -4
  84. data/lib/insika/evals/simulator.rb +21 -3
  85. data/lib/insika/evals/transport.rb +317 -15
  86. data/lib/insika/event_stream.rb +63 -7
  87. data/lib/insika/evidence.rb +105 -17
  88. data/lib/insika/executor.rb +698 -164
  89. data/lib/insika/fence.rb +96 -0
  90. data/lib/insika/golden_store.rb +3 -0
  91. data/lib/insika/harvest.rb +26 -14
  92. data/lib/insika/harvest_engine.rb +1 -0
  93. data/lib/insika/harvest_store.rb +12 -0
  94. data/lib/insika/http_client.rb +87 -4
  95. data/lib/insika/kits.rb +54 -0
  96. data/lib/insika/knowledge.rb +34 -20
  97. data/lib/insika/llm_configurator.rb +46 -4
  98. data/lib/insika/llm_provider_store.rb +1 -3
  99. data/lib/insika/llm_trace_store.rb +54 -0
  100. data/lib/insika/mcp_client.rb +27 -63
  101. data/lib/insika/mcp_live_tool.rb +55 -9
  102. data/lib/insika/mcp_store.rb +37 -3
  103. data/lib/insika/mcp_tool_registry.rb +76 -26
  104. data/lib/insika/media.rb +38 -25
  105. data/lib/insika/memory_store.rb +16 -3
  106. data/lib/insika/memory_trim.rb +60 -0
  107. data/lib/insika/middleware.rb +12 -3
  108. data/lib/insika/model_metrics_store.rb +285 -0
  109. data/lib/insika/model_registry.rb +110 -0
  110. data/lib/insika/model_resolver.rb +1 -1
  111. data/lib/insika/model_selection.rb +14 -21
  112. data/lib/insika/model_visible.rb +17 -6
  113. data/lib/insika/onboarding.rb +1 -0
  114. data/lib/insika/outcome_store.rb +1 -1
  115. data/lib/insika/overlay_tool_registry.rb +30 -2
  116. data/lib/insika/pack_importer.rb +54 -9
  117. data/lib/insika/packaging.rb +14 -5
  118. data/lib/insika/pending_action_store.rb +45 -18
  119. data/lib/insika/plugin/loader.rb +4 -2
  120. data/lib/insika/prefix_fingerprint.rb +32 -27
  121. data/lib/insika/profile_source.rb +5 -0
  122. data/lib/insika/provider_error_classifier.rb +18 -3
  123. data/lib/insika/queue_policy.rb +7 -2
  124. data/lib/insika/refinement/proposer.rb +42 -17
  125. data/lib/insika/reliability.rb +12 -3
  126. data/lib/insika/router/app.rb +14 -5
  127. data/lib/insika/router/session_key.rb +35 -5
  128. data/lib/insika/safety/config.rb +20 -3
  129. data/lib/insika/safety/corpus.rb +10 -3
  130. data/lib/insika/safety/factory.rb +39 -1
  131. data/lib/insika/safety/input_guardrail.rb +21 -1
  132. data/lib/insika/safety/judge_moderator.rb +70 -0
  133. data/lib/insika/safety/output_validator.rb +29 -5
  134. data/lib/insika/safety/prompt_echo.rb +89 -0
  135. data/lib/insika/schema_guard.rb +53 -76
  136. data/lib/insika/server/app.rb +58 -7
  137. data/lib/insika/server/rack_app.rb +2 -0
  138. data/lib/insika/server/responses.rb +50 -5
  139. data/lib/insika/session_actor.rb +58 -28
  140. data/lib/insika/session_store.rb +163 -11
  141. data/lib/insika/settings_store.rb +57 -2
  142. data/lib/insika/shared_conversations.rb +305 -0
  143. data/lib/insika/skill_catalog.rb +28 -2
  144. data/lib/insika/skill_store.rb +6 -0
  145. data/lib/insika/soak/runner.rb +1 -1
  146. data/lib/insika/spoken_transcript.rb +31 -0
  147. data/lib/insika/steer_injector.rb +7 -48
  148. data/lib/insika/store.rb +29 -1
  149. data/lib/insika/stores/json_value.rb +37 -0
  150. data/lib/insika/stores/memory.rb +22 -35
  151. data/lib/insika/stores/postgres.rb +295 -0
  152. data/lib/insika/stores/sqlite.rb +257 -43
  153. data/lib/insika/stores/turn_counter.rb +25 -0
  154. data/lib/insika/studio/app.rb +1459 -163
  155. data/lib/insika/studio/assets/dist/application.css +1 -1
  156. data/lib/insika/studio/assets/dist/application.js +25 -25
  157. data/lib/insika/studio/assets/dist/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
  158. data/lib/insika/studio/assets/dist/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
  159. data/lib/insika/studio/assets/dist/fonts/ibm-plex-mono-latin-600-normal.woff2 +0 -0
  160. data/lib/insika/studio/assets/dist/fonts/ibm-plex-sans-latin-wght-normal.woff2 +0 -0
  161. data/lib/insika/studio/forms.rb +189 -12
  162. data/lib/insika/studio/nav_icons.rb +3 -0
  163. data/lib/insika/studio/views/_agent_config_retrieval.erb +73 -0
  164. data/lib/insika/studio/views/_agent_picker.erb +15 -0
  165. data/lib/insika/studio/views/_agent_tab_config.erb +83 -243
  166. data/lib/insika/studio/views/_agent_tab_history.erb +56 -1
  167. data/lib/insika/studio/views/_agent_tab_performance.erb +34 -0
  168. data/lib/insika/studio/views/_agent_tab_prompts.erb +7 -9
  169. data/lib/insika/studio/views/_agent_tab_skills.erb +16 -7
  170. data/lib/insika/studio/views/_agent_tab_tools.erb +90 -0
  171. data/lib/insika/studio/views/_agents_master.erb +8 -12
  172. data/lib/insika/studio/views/_cfg_alerts.erb +4 -0
  173. data/lib/insika/studio/views/_cfg_budget.erb +20 -0
  174. data/lib/insika/studio/views/_cfg_distill.erb +26 -0
  175. data/lib/insika/studio/views/_cfg_followup.erb +30 -0
  176. data/lib/insika/studio/views/_cfg_grounding.erb +21 -0
  177. data/lib/insika/studio/views/_cfg_guardrails.erb +47 -0
  178. data/lib/insika/studio/views/_cfg_harvest.erb +35 -0
  179. data/lib/insika/studio/views/_cfg_reliability.erb +32 -0
  180. data/lib/insika/studio/views/_chats_master.erb +66 -0
  181. data/lib/insika/studio/views/_customers_master.erb +37 -0
  182. data/lib/insika/studio/views/_empty.erb +15 -0
  183. data/lib/insika/studio/views/_facts_master.erb +42 -0
  184. data/lib/insika/studio/views/_harvest_candidate_detail.erb +14 -0
  185. data/lib/insika/studio/views/_identity.erb +16 -0
  186. data/lib/insika/studio/views/_kpi.erb +17 -0
  187. data/lib/insika/studio/views/_message.erb +40 -2
  188. data/lib/insika/studio/views/_model_chart.erb +82 -0
  189. data/lib/insika/studio/views/_refinement_master.erb +38 -0
  190. data/lib/insika/studio/views/{tool_edit.erb → _tool_edit.erb} +38 -11
  191. data/lib/insika/studio/views/_tool_users.erb +17 -0
  192. data/lib/insika/studio/views/_why.erb +53 -0
  193. data/lib/insika/studio/views/agent_detail.erb +17 -10
  194. data/lib/insika/studio/views/agents.erb +28 -16
  195. data/lib/insika/studio/views/approvals.erb +16 -11
  196. data/lib/insika/studio/views/artifact.erb +20 -7
  197. data/lib/insika/studio/views/artifacts.erb +19 -14
  198. data/lib/insika/studio/views/chats.erb +22 -29
  199. data/lib/insika/studio/views/customer.erb +88 -43
  200. data/lib/insika/studio/views/customers.erb +16 -26
  201. data/lib/insika/studio/views/evals.erb +49 -31
  202. data/lib/insika/studio/views/fact_detail.erb +114 -0
  203. data/lib/insika/studio/views/facts.erb +15 -116
  204. data/lib/insika/studio/views/followups.erb +63 -52
  205. data/lib/insika/studio/views/funnel.erb +104 -43
  206. data/lib/insika/studio/views/harvest.erb +85 -59
  207. data/lib/insika/studio/views/home.erb +138 -23
  208. data/lib/insika/studio/views/inbox.erb +36 -0
  209. data/lib/insika/studio/views/kits.erb +176 -0
  210. data/lib/insika/studio/views/knowledge.erb +92 -80
  211. data/lib/insika/studio/views/layout.erb +42 -11
  212. data/lib/insika/studio/views/live.erb +45 -0
  213. data/lib/insika/studio/views/mcp.erb +43 -13
  214. data/lib/insika/studio/views/models.erb +187 -0
  215. data/lib/insika/studio/views/parity.erb +38 -32
  216. data/lib/insika/studio/views/playground.erb +13 -9
  217. data/lib/insika/studio/views/refinement.erb +15 -224
  218. data/lib/insika/studio/views/refinement_detail.erb +243 -0
  219. data/lib/insika/studio/views/session.erb +153 -118
  220. data/lib/insika/studio/views/settings.erb +86 -22
  221. data/lib/insika/studio/views/skills.erb +53 -19
  222. data/lib/insika/studio/views/system_files.erb +7 -7
  223. data/lib/insika/studio/views/task.erb +45 -15
  224. data/lib/insika/studio/views/tasks.erb +35 -18
  225. data/lib/insika/studio/views/tools.erb +62 -73
  226. data/lib/insika/task_actor.rb +4 -1
  227. data/lib/insika/task_store.rb +67 -1
  228. data/lib/insika/telemetry/pricing.rb +16 -14
  229. data/lib/insika/telemetry/recorder.rb +115 -9
  230. data/lib/insika/telemetry/ruby_llm_instrumenter.rb +110 -0
  231. data/lib/insika/telemetry.rb +12 -2
  232. data/lib/insika/templates/daily-digest/README.md +13 -0
  233. data/lib/insika/templates/daily-digest/agent.rb +22 -11
  234. data/lib/insika/testing/store_contract.rb +65 -0
  235. data/lib/insika/text_tool_call.rb +66 -0
  236. data/lib/insika/tick.rb +7 -1
  237. data/lib/insika/token_store.rb +5 -0
  238. data/lib/insika/tool_assembly.rb +21 -13
  239. data/lib/insika/tool_batch.rb +1 -1
  240. data/lib/insika/tool_catalog.rb +12 -2
  241. data/lib/insika/tool_definition.rb +82 -13
  242. data/lib/insika/tool_envelope.rb +266 -29
  243. data/lib/insika/tool_manifest.rb +1 -0
  244. data/lib/insika/tool_store.rb +12 -4
  245. data/lib/insika/tool_trace_store.rb +15 -8
  246. data/lib/insika/tool_usage_report.rb +14 -4
  247. data/lib/insika/tools/a2a_remote.rb +1 -1
  248. data/lib/insika/tools/agent_enum.rb +1 -1
  249. data/lib/insika/tools/confirm_pending.rb +112 -0
  250. data/lib/insika/tools/data_defined_tool.rb +24 -15
  251. data/lib/insika/tools/generate_image.rb +2 -2
  252. data/lib/insika/tools/load_knowledge.rb +7 -3
  253. data/lib/insika/tools/load_skill.rb +3 -3
  254. data/lib/insika/tools/present.rb +115 -0
  255. data/lib/insika/tools/remember.rb +7 -2
  256. data/lib/insika/tools/run_persona_eval.rb +9 -6
  257. data/lib/insika/tools/save_artifact.rb +16 -6
  258. data/lib/insika/tools/schedule_followup.rb +3 -3
  259. data/lib/insika/tools/stuck_signal.rb +3 -3
  260. data/lib/insika/tools/subagent.rb +5 -5
  261. data/lib/insika/tools/subagents.rb +3 -3
  262. data/lib/insika/tools/tool_search.rb +11 -7
  263. data/lib/insika/tools/tts.rb +2 -2
  264. data/lib/insika/tools/update_briefing.rb +4 -4
  265. data/lib/insika/turn_output.rb +2 -2
  266. data/lib/insika/turn_state.rb +31 -1
  267. data/lib/insika/turn_timing.rb +51 -14
  268. data/lib/insika/version.rb +1 -1
  269. data/lib/insika/wiring/graph.rb +88 -16
  270. data/lib/insika/wiring/graph_chat.rb +4 -0
  271. data/lib/insika/workflow.rb +25 -64
  272. data/lib/insika.rb +23 -3
  273. metadata +74 -13
  274. data/lib/insika/commands/import_mcp_tools.rb +0 -48
  275. data/lib/insika/mcp_http_client.rb +0 -67
  276. data/lib/insika/mcp_tool_ingestor.rb +0 -165
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "json_schemer"
4
+
3
5
  module Insika
4
6
  # Workflow surface (COMPETITIVE-ANALYSIS). A workflow is a Ruby
5
7
  # callable orchestrating RubyLLM Agents/Workflows FROM WITHIN (RubyLLM First);
@@ -13,9 +15,7 @@ module Insika
13
15
  # A schema is any dry-schema-compatible validator: `#call(value)` returning a
14
16
  # result that responds to `#success?` and `#errors` (dry-schema's own contract).
15
17
  # As a batteries-included default, a plain JSON Schema Hash (the interlingua the
16
- # ToolDefinition already speaks) is accepted and validated by the zero-dependency
17
- # Schema below — "config over convention": bring dry-schema for richer contracts,
18
- # or hand a JSON Schema for the common case.
18
+ # ToolDefinition already speaks) is accepted and validated by JSONSchemer.
19
19
  module Workflow
20
20
  # Bundles a registered workflow's callable factory with its metadata (schemas +
21
21
  # description). Built lazily by WorkflowRegistry#definition — it does NOT resolve
@@ -74,13 +74,8 @@ module Insika
74
74
  end
75
75
  end
76
76
 
77
- # Zero-dependency instance validator for a plain JSON Schema Hash, speaking the
78
- # same safe subset (object/array/string/number/integer/boolean + enum) the
79
- # ToolDefinition validates its parameters against. It implements the SAME
80
- # `#call(value) -> result{#success?, #errors}` contract as dry-schema, so the
81
- # Definition treats both uniformly. Not a full JSON Schema engine (no
82
- # composition/$ref — the subset the insika supports everywhere); permissive on
83
- # unknown keys (JSON Schema's additionalProperties default).
77
+ # JSON Schema validation with the same result contract as dry-schema.
78
+ # References may resolve within the supplied document, never over the network.
84
79
  class Schema
85
80
  # dry-schema-compatible result. `errors` is { "field.path" => ["message", …] }.
86
81
  Result = Data.define(:errors) do
@@ -104,66 +99,33 @@ module Insika
104
99
  end
105
100
 
106
101
  @json_schema = Insika::Coercion.deep_stringify(json_schema)
102
+ @validator = JSONSchemer.schema(@json_schema, ref_resolver: ->(uri) {
103
+ raise Insika::ValidationError, "external schema reference is not allowed: #{uri}"
104
+ })
107
105
  end
108
106
 
109
107
  def call(value)
110
- Result.new(errors: collect(@json_schema, value, "").freeze)
111
- end
112
-
113
- private
114
-
115
- # -> { path => [messages] }. Empty = valid.
116
- def collect(schema, value, path)
117
- type = schema["type"].to_s
118
- return { key(path) => ["must be #{type}, got #{ruby_type(value)}"] } unless type.empty? || matches?(type, value)
119
-
120
108
  errors = {}
121
- case type
122
- when "object" then check_object(schema, value, path, errors)
123
- when "array" then check_array(schema, value, path, errors)
124
- end
125
- check_enum(schema, value, path, errors)
126
- errors
127
- end
128
-
129
- def check_object(schema, value, path, errors)
130
- props = schema["properties"] || {}
131
- Array(schema["required"]).each do |name|
132
- errors[key(join(path, name))] = ["is required"] unless value.key?(name.to_s) || value.key?(name.to_sym)
133
- end
134
- props.each do |name, subschema|
135
- next unless value.key?(name.to_s) || value.key?(name.to_sym)
136
-
137
- sub = value[name.to_s] || value[name.to_sym]
138
- errors.merge!(collect(subschema || {}, sub, join(path, name)))
109
+ @validator.validate(Insika::Coercion.deep_stringify(value)).each do |error|
110
+ path = error["data_pointer"].split("/").drop(1).map { |part| part.gsub("~1", "/").gsub("~0", "~") }.join(".")
111
+ if error["type"] == "required"
112
+ error.fetch("details").fetch("missing_keys").each do |name|
113
+ (errors[join(path, name)] ||= []) << "is required"
114
+ end
115
+ else
116
+ message = case error["type"]
117
+ when "object", "array", "string", "integer", "number", "boolean", "null"
118
+ "must be #{error['type']}, got #{ruby_type(error['data'])}"
119
+ when "enum" then "must be one of #{error['schema']['enum'].inspect}"
120
+ else error["error"]
121
+ end
122
+ (errors[path.empty? ? "(root)" : path] ||= []) << message
123
+ end
139
124
  end
125
+ Result.new(errors: errors.freeze)
140
126
  end
141
127
 
142
- def check_array(schema, value, path, errors)
143
- items = schema["items"]
144
- return if items.nil?
145
-
146
- value.each_with_index { |el, i| errors.merge!(collect(items, el, "#{join(path, i)}")) }
147
- end
148
-
149
- def check_enum(schema, value, path, errors)
150
- return unless schema.key?("enum")
151
-
152
- allowed = Array(schema["enum"])
153
- errors[key(path)] = ["must be one of #{allowed.inspect}"] unless allowed.include?(value)
154
- end
155
-
156
- def matches?(type, value)
157
- case type
158
- when "object" then value.is_a?(Hash)
159
- when "array" then value.is_a?(Array)
160
- when "string" then value.is_a?(String)
161
- when "integer" then value.is_a?(Integer) && !value.is_a?(TrueClass) && !value.is_a?(FalseClass)
162
- when "number" then value.is_a?(Numeric) && !value.is_a?(TrueClass) && !value.is_a?(FalseClass)
163
- when "boolean" then value == true || value == false
164
- else true # unknown type in the schema -> do not block (permissive)
165
- end
166
- end
128
+ private
167
129
 
168
130
  def ruby_type(value)
169
131
  case value
@@ -179,7 +141,6 @@ module Insika
179
141
  end
180
142
 
181
143
  def join(path, segment) = path.empty? ? segment.to_s : "#{path}.#{segment}"
182
- def key(path) = path.empty? ? "(root)" : path
183
144
  end
184
145
  end
185
146
  end
data/lib/insika.rb CHANGED
@@ -45,6 +45,7 @@ require_relative "insika/cron"
45
45
  require_relative "insika/schedule"
46
46
  require_relative "insika/schedule_store"
47
47
  require_relative "insika/schedule_engine"
48
+ require_relative "insika/model_registry"
48
49
  # the report destination — one record per run, no
49
50
  # versioning; the signing half of the sharing link (HMAC, no secret stored).
50
51
  require_relative "insika/artifact_store"
@@ -72,6 +73,7 @@ require_relative "insika/checkpoint"
72
73
  require_relative "insika/command"
73
74
  require_relative "insika/hooks"
74
75
  require_relative "insika/middleware"
76
+ require_relative "insika/memory_trim"
75
77
  # Production edge: windowed counters + the rate-limit/cost
76
78
  # Middleware. Both inert until configured (nil/0 = off).
77
79
  require_relative "insika/usage_ledger"
@@ -85,9 +87,11 @@ require_relative "insika/tool_output_compressor"
85
87
  # lazily, like the Executor's create_chat.
86
88
  require_relative "insika/safety/corpus"
87
89
  require_relative "insika/safety/detectors"
90
+ require_relative "insika/safety/prompt_echo"
88
91
  require_relative "insika/safety/safe_responses"
89
92
  require_relative "insika/safety/config"
90
93
  require_relative "insika/safety/moderator"
94
+ require_relative "insika/safety/judge_moderator"
91
95
  require_relative "insika/safety/output_filter"
92
96
  require_relative "insika/safety/input_guardrail"
93
97
  require_relative "insika/safety/output_validator"
@@ -99,13 +103,16 @@ require_relative "insika/context/catalog_provider"
99
103
  require_relative "insika/context/builder"
100
104
  require_relative "insika/context/providers/request"
101
105
  require_relative "insika/context/providers/prompt"
106
+ require_relative "insika/context/providers/fence_notice"
102
107
  require_relative "insika/context/providers/skill"
103
108
  require_relative "insika/context/providers/skill_trigger"
104
109
  require_relative "insika/context/providers/tool_search"
105
110
  require_relative "insika/context/providers/memory"
111
+ require_relative "insika/context/reranker"
106
112
  require_relative "insika/context/providers/knowledge"
107
113
  require_relative "insika/context/providers/session"
108
114
  require_relative "insika/context/providers/briefing"
115
+ require_relative "insika/context/providers/pending_confirmation"
109
116
  # the cache-prefix hash chain + the per-agent cache-hit series.
110
117
  # Both are referenced by the Executor at runtime, so they load before it.
111
118
  require_relative "insika/prefix_fingerprint"
@@ -122,8 +129,11 @@ require_relative "insika/prompt_catalog"
122
129
  require_relative "insika/plugin"
123
130
  require_relative "insika/plugin/loader"
124
131
  require_relative "insika/store"
132
+ require_relative "insika/stores/json_value"
125
133
  require_relative "insika/stores/memory"
134
+ require_relative "insika/stores/turn_counter"
126
135
  require_relative "insika/stores/sqlite"
136
+ require_relative "insika/stores/postgres"
127
137
  require_relative "insika/session_store"
128
138
  require_relative "insika/task_store"
129
139
  require_relative "insika/checkpoint_store"
@@ -146,6 +156,8 @@ require_relative "insika/skill_store"
146
156
  require_relative "insika/secret_masking"
147
157
  require_relative "insika/tool_store"
148
158
  require_relative "insika/tool_trace_store"
159
+ require_relative "insika/llm_trace_store"
160
+ require_relative "insika/model_metrics_store"
149
161
  require_relative "insika/tool_usage_report"
150
162
  require_relative "insika/context_trace_store"
151
163
  # the model-visible payload of one ask + its durable trace —
@@ -181,6 +193,8 @@ require_relative "insika/overlay_tool_registry"
181
193
  require_relative "insika/settings_store"
182
194
  require_relative "insika/llm_provider_store"
183
195
  require_relative "insika/llm_configurator"
196
+ require_relative "insika/agent_defaults"
197
+ require_relative "insika/kits"
184
198
  # LLM-first onboarding surface: serves start.md + models.json + the
185
199
  # public docs. Reads the settings/provider stores above at call-time (order is free).
186
200
  require_relative "insika/onboarding"
@@ -192,6 +206,7 @@ require_relative "insika/onboarding"
192
206
  require_relative "insika/evals/golden"
193
207
  require_relative "insika/evals/assertions"
194
208
  require_relative "insika/evals/judge"
209
+ require_relative "insika/evals/moderator_compare"
195
210
  require_relative "insika/evals/pairwise"
196
211
  require_relative "insika/evals/runner"
197
212
  require_relative "insika/evals/report"
@@ -216,8 +231,6 @@ require_relative "insika/refinement/gate"
216
231
  # candidate format and the gate's Report shape, so it loads after both.
217
232
  require_relative "insika/refinement/panel"
218
233
  require_relative "insika/mcp_store"
219
- require_relative "insika/mcp_http_client"
220
- require_relative "insika/mcp_tool_ingestor"
221
234
  # require "ruby_llm/mcp" itself is LAZY, inside .for — this require_relative only
222
235
  # loads the thin factory (see spec/insika/load_guard_spec.rb).
223
236
  require_relative "insika/mcp_client"
@@ -230,6 +243,7 @@ require_relative "insika/system_file_store"
230
243
  require_relative "insika/recovery"
231
244
  require_relative "insika/command_bus"
232
245
  require_relative "insika/commands/create_session"
246
+ require_relative "insika/commands/seed_session"
233
247
  require_relative "insika/commands/cancel_task"
234
248
  require_relative "insika/commands/pause_task"
235
249
  require_relative "insika/commands/approve_action"
@@ -255,6 +269,8 @@ require_relative "insika/commands/gate_refinement"
255
269
  require_relative "insika/commands/resolve_refinement"
256
270
  require_relative "insika/commands/write_golden"
257
271
  require_relative "insika/commands/update_settings"
272
+ require_relative "insika/commands/write_kit"
273
+ require_relative "insika/commands/delete_kit"
258
274
  require_relative "insika/commands/upsert_llm_provider"
259
275
  require_relative "insika/commands/delete_llm_provider"
260
276
  require_relative "insika/commands/issue_tenant_token"
@@ -276,6 +292,7 @@ require_relative "insika/commands/revoke_contact"
276
292
  # the report destination's Studio mutation — delete one artifact
277
293
  # (a bus command, like every Studio mutation).
278
294
  require_relative "insika/commands/delete_artifact"
295
+ require_relative "insika/commands/review_guardrail_flag"
279
296
  # in-session compaction (RFC-0044) — the summarizer (pure, injected
280
297
  # ask) and the boundary math; the trigger lives in the Executor, the
281
298
  # persistence in SessionStore, the read path in the Session provider.
@@ -321,7 +338,6 @@ require_relative "insika/commands/write_data_tool"
321
338
  require_relative "insika/commands/delete_data_tool"
322
339
  require_relative "insika/commands/restore_data_tool"
323
340
  require_relative "insika/commands/import_tools"
324
- require_relative "insika/commands/import_mcp_tools"
325
341
  require_relative "insika/commands/refresh_mcp_tools"
326
342
  # the demo seed (OSS onboarding): one bundled agent + golden
327
343
  # set + the Seeder that populates every loop's stores at once, and its bus
@@ -342,12 +358,16 @@ require_relative "insika/loop_detector"
342
358
  require_relative "insika/turn_budget"
343
359
  require_relative "insika/balloon_splitter"
344
360
  require_relative "insika/turn_output"
361
+ require_relative "insika/text_tool_call"
345
362
  require_relative "insika/turn_state"
346
363
  require_relative "insika/turn_timing"
347
364
  require_relative "insika/capability/resolved_tool"
365
+ require_relative "insika/fence"
366
+ require_relative "insika/spoken_transcript"
348
367
  require_relative "insika/tool_envelope"
349
368
  require_relative "insika/tool_assembly"
350
369
  require_relative "insika/chat_builder"
370
+ require_relative "insika/shared_conversations"
351
371
  require_relative "insika/executor"
352
372
  require_relative "insika/shutdown"
353
373
  require_relative "insika/tick"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: insika
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guilherme Lages Santos
@@ -24,33 +24,33 @@ dependencies:
24
24
  - !ruby/object:Gem::Version
25
25
  version: '2.0'
26
26
  - !ruby/object:Gem::Dependency
27
- name: ruby_llm
27
+ name: json_schemer
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - ">="
30
+ - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '1.15'
32
+ version: '2.5'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - ">="
37
+ - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '1.15'
39
+ version: '2.5'
40
40
  - !ruby/object:Gem::Dependency
41
- name: ruby_llm-mcp
41
+ name: ruby_llm
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '1.0'
46
+ version: '2.1'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '1.0'
53
+ version: '2.1'
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: falcon
56
56
  requirement: !ruby/object:Gem::Requirement
@@ -173,6 +173,7 @@ files:
173
173
  - docs/BENCHMARK.md
174
174
  - docs/CHANNELS.md
175
175
  - docs/CONTEXT.md
176
+ - docs/CROSS-HARNESS-BENCH.md
176
177
  - docs/DEMO.md
177
178
  - docs/DEPLOY.md
178
179
  - docs/EMBEDDING.md
@@ -184,17 +185,21 @@ files:
184
185
  - docs/MEDIA.md
185
186
  - docs/OBSERVABILITY.md
186
187
  - docs/OUTCOMES.md
188
+ - docs/PERFORMANCE.md
187
189
  - docs/PLUGINS.md
188
190
  - docs/POLICY.md
189
191
  - docs/REFINEMENT.md
190
192
  - docs/RELEASING.md
191
193
  - docs/ROUTER.md
194
+ - docs/RUBYLLM_2_MIGRATION.md
192
195
  - docs/RUNNING-LOCAL.md
193
196
  - docs/SANDBOX.md
194
197
  - docs/SCHEDULING.md
195
198
  - docs/SECURITY.md
199
+ - docs/SHARED-CONVERSATIONS.md
196
200
  - docs/SKILLS.md
197
201
  - docs/SOAK.md
202
+ - docs/STUDIO.md
198
203
  - docs/TEMPLATES.md
199
204
  - docs/TOOLS.md
200
205
  - docs/WHY.md
@@ -221,6 +226,7 @@ files:
221
226
  - docs/ship.md
222
227
  - docs/start-here.md
223
228
  - lib/insika.rb
229
+ - lib/insika/agent_defaults.rb
224
230
  - lib/insika/agent_file_store.rb
225
231
  - lib/insika/agent_profile.rb
226
232
  - lib/insika/alert_dispatcher.rb
@@ -258,6 +264,7 @@ files:
258
264
  - lib/insika/commands/delete_artifact.rb
259
265
  - lib/insika/commands/delete_concept.rb
260
266
  - lib/insika/commands/delete_data_tool.rb
267
+ - lib/insika/commands/delete_kit.rb
261
268
  - lib/insika/commands/delete_llm_provider.rb
262
269
  - lib/insika/commands/delete_mcp.rb
263
270
  - lib/insika/commands/delete_skill.rb
@@ -268,7 +275,6 @@ files:
268
275
  - lib/insika/commands/freeze_funnel_baseline.rb
269
276
  - lib/insika/commands/gate_harvest.rb
270
277
  - lib/insika/commands/gate_refinement.rb
271
- - lib/insika/commands/import_mcp_tools.rb
272
278
  - lib/insika/commands/import_tools.rb
273
279
  - lib/insika/commands/issue_tenant_token.rb
274
280
  - lib/insika/commands/judge_shadow_pairs.rb
@@ -288,6 +294,7 @@ files:
288
294
  - lib/insika/commands/restore_data_tool.rb
289
295
  - lib/insika/commands/restore_system_file.rb
290
296
  - lib/insika/commands/resume_task.rb
297
+ - lib/insika/commands/review_guardrail_flag.rb
291
298
  - lib/insika/commands/revoke_contact.rb
292
299
  - lib/insika/commands/revoke_token.rb
293
300
  - lib/insika/commands/rollback_harvest.rb
@@ -296,6 +303,7 @@ files:
296
303
  - lib/insika/commands/run_harvest.rb
297
304
  - lib/insika/commands/run_refinement.rb
298
305
  - lib/insika/commands/seed_demo_data.rb
306
+ - lib/insika/commands/seed_session.rb
299
307
  - lib/insika/commands/send_message.rb
300
308
  - lib/insika/commands/session_purge.rb
301
309
  - lib/insika/commands/set_agent_tools.rb
@@ -309,6 +317,7 @@ files:
309
317
  - lib/insika/commands/write_concept.rb
310
318
  - lib/insika/commands/write_data_tool.rb
311
319
  - lib/insika/commands/write_golden.rb
320
+ - lib/insika/commands/write_kit.rb
312
321
  - lib/insika/commands/write_skill.rb
313
322
  - lib/insika/commands/write_system_file.rb
314
323
  - lib/insika/compaction.rb
@@ -320,14 +329,17 @@ files:
320
329
  - lib/insika/context/priority.rb
321
330
  - lib/insika/context/provider.rb
322
331
  - lib/insika/context/providers/briefing.rb
332
+ - lib/insika/context/providers/fence_notice.rb
323
333
  - lib/insika/context/providers/knowledge.rb
324
334
  - lib/insika/context/providers/memory.rb
335
+ - lib/insika/context/providers/pending_confirmation.rb
325
336
  - lib/insika/context/providers/prompt.rb
326
337
  - lib/insika/context/providers/request.rb
327
338
  - lib/insika/context/providers/session.rb
328
339
  - lib/insika/context/providers/skill.rb
329
340
  - lib/insika/context/providers/skill_trigger.rb
330
341
  - lib/insika/context/providers/tool_search.rb
342
+ - lib/insika/context/reranker.rb
331
343
  - lib/insika/context_trace_store.rb
332
344
  - lib/insika/cron.rb
333
345
  - lib/insika/delegation_store.rb
@@ -351,6 +363,7 @@ files:
351
363
  - lib/insika/evals/baseline.rb
352
364
  - lib/insika/evals/golden.rb
353
365
  - lib/insika/evals/judge.rb
366
+ - lib/insika/evals/moderator_compare.rb
354
367
  - lib/insika/evals/pairwise.rb
355
368
  - lib/insika/evals/persona.rb
356
369
  - lib/insika/evals/report.rb
@@ -361,6 +374,7 @@ files:
361
374
  - lib/insika/event_stream.rb
362
375
  - lib/insika/evidence.rb
363
376
  - lib/insika/executor.rb
377
+ - lib/insika/fence.rb
364
378
  - lib/insika/followup_engine.rb
365
379
  - lib/insika/followup_policy.rb
366
380
  - lib/insika/followup_store.rb
@@ -381,24 +395,27 @@ files:
381
395
  - lib/insika/hooks.rb
382
396
  - lib/insika/http_client.rb
383
397
  - lib/insika/inbound_log.rb
398
+ - lib/insika/kits.rb
384
399
  - lib/insika/knowledge.rb
385
400
  - lib/insika/knowledge_store.rb
386
401
  - lib/insika/llm_configurator.rb
387
402
  - lib/insika/llm_provider_store.rb
403
+ - lib/insika/llm_trace_store.rb
388
404
  - lib/insika/loop_detector.rb
389
405
  - lib/insika/mcp_client.rb
390
- - lib/insika/mcp_http_client.rb
391
406
  - lib/insika/mcp_json.rb
392
407
  - lib/insika/mcp_live_tool.rb
393
408
  - lib/insika/mcp_store.rb
394
- - lib/insika/mcp_tool_ingestor.rb
395
409
  - lib/insika/mcp_tool_registry.rb
396
410
  - lib/insika/media.rb
397
411
  - lib/insika/memory_audit_store.rb
398
412
  - lib/insika/memory_store.rb
413
+ - lib/insika/memory_trim.rb
399
414
  - lib/insika/message_origin.rb
400
415
  - lib/insika/middleware.rb
416
+ - lib/insika/model_metrics_store.rb
401
417
  - lib/insika/model_policy.rb
418
+ - lib/insika/model_registry.rb
402
419
  - lib/insika/model_resolver.rb
403
420
  - lib/insika/model_selection.rb
404
421
  - lib/insika/model_visible.rb
@@ -448,9 +465,11 @@ files:
448
465
  - lib/insika/safety/grounding_enforcer.rb
449
466
  - lib/insika/safety/grounding_validator.rb
450
467
  - lib/insika/safety/input_guardrail.rb
468
+ - lib/insika/safety/judge_moderator.rb
451
469
  - lib/insika/safety/moderator.rb
452
470
  - lib/insika/safety/output_filter.rb
453
471
  - lib/insika/safety/output_validator.rb
472
+ - lib/insika/safety/prompt_echo.rb
454
473
  - lib/insika/safety/safe_responses.rb
455
474
  - lib/insika/sandbox.rb
456
475
  - lib/insika/sandbox/boundary.rb
@@ -481,32 +500,65 @@ files:
481
500
  - lib/insika/session_store.rb
482
501
  - lib/insika/settings_store.rb
483
502
  - lib/insika/shadow_pair_store.rb
503
+ - lib/insika/shared_conversations.rb
484
504
  - lib/insika/shutdown.rb
485
505
  - lib/insika/skill_catalog.rb
486
506
  - lib/insika/skill_store.rb
487
507
  - lib/insika/soak/envelope.rb
488
508
  - lib/insika/soak/report.rb
489
509
  - lib/insika/soak/runner.rb
510
+ - lib/insika/spoken_transcript.rb
490
511
  - lib/insika/steer_injector.rb
491
512
  - lib/insika/store.rb
513
+ - lib/insika/stores/json_value.rb
492
514
  - lib/insika/stores/memory.rb
515
+ - lib/insika/stores/postgres.rb
493
516
  - lib/insika/stores/sqlite.rb
517
+ - lib/insika/stores/turn_counter.rb
494
518
  - lib/insika/studio/app.rb
495
519
  - lib/insika/studio/assets/dist/application.css
496
520
  - lib/insika/studio/assets/dist/application.js
497
521
  - lib/insika/studio/assets/dist/favicon.svg
522
+ - lib/insika/studio/assets/dist/fonts/ibm-plex-mono-latin-400-normal.woff2
523
+ - lib/insika/studio/assets/dist/fonts/ibm-plex-mono-latin-500-normal.woff2
524
+ - lib/insika/studio/assets/dist/fonts/ibm-plex-mono-latin-600-normal.woff2
525
+ - lib/insika/studio/assets/dist/fonts/ibm-plex-sans-latin-wght-normal.woff2
498
526
  - lib/insika/studio/forms.rb
499
527
  - lib/insika/studio/nav_icons.rb
528
+ - lib/insika/studio/views/_agent_config_retrieval.erb
529
+ - lib/insika/studio/views/_agent_picker.erb
500
530
  - lib/insika/studio/views/_agent_tab_cache.erb
501
531
  - lib/insika/studio/views/_agent_tab_config.erb
502
532
  - lib/insika/studio/views/_agent_tab_history.erb
503
533
  - lib/insika/studio/views/_agent_tab_loops.erb
504
534
  - lib/insika/studio/views/_agent_tab_memory.erb
505
535
  - lib/insika/studio/views/_agent_tab_outcomes.erb
536
+ - lib/insika/studio/views/_agent_tab_performance.erb
506
537
  - lib/insika/studio/views/_agent_tab_prompts.erb
507
538
  - lib/insika/studio/views/_agent_tab_skills.erb
539
+ - lib/insika/studio/views/_agent_tab_tools.erb
508
540
  - lib/insika/studio/views/_agents_master.erb
541
+ - lib/insika/studio/views/_cfg_alerts.erb
542
+ - lib/insika/studio/views/_cfg_budget.erb
543
+ - lib/insika/studio/views/_cfg_distill.erb
544
+ - lib/insika/studio/views/_cfg_followup.erb
545
+ - lib/insika/studio/views/_cfg_grounding.erb
546
+ - lib/insika/studio/views/_cfg_guardrails.erb
547
+ - lib/insika/studio/views/_cfg_harvest.erb
548
+ - lib/insika/studio/views/_cfg_reliability.erb
549
+ - lib/insika/studio/views/_chats_master.erb
550
+ - lib/insika/studio/views/_customers_master.erb
551
+ - lib/insika/studio/views/_empty.erb
552
+ - lib/insika/studio/views/_facts_master.erb
553
+ - lib/insika/studio/views/_harvest_candidate_detail.erb
554
+ - lib/insika/studio/views/_identity.erb
555
+ - lib/insika/studio/views/_kpi.erb
509
556
  - lib/insika/studio/views/_message.erb
557
+ - lib/insika/studio/views/_model_chart.erb
558
+ - lib/insika/studio/views/_refinement_master.erb
559
+ - lib/insika/studio/views/_tool_edit.erb
560
+ - lib/insika/studio/views/_tool_users.erb
561
+ - lib/insika/studio/views/_why.erb
510
562
  - lib/insika/studio/views/agent_detail.erb
511
563
  - lib/insika/studio/views/agents.erb
512
564
  - lib/insika/studio/views/approvals.erb
@@ -516,26 +568,31 @@ files:
516
568
  - lib/insika/studio/views/customer.erb
517
569
  - lib/insika/studio/views/customers.erb
518
570
  - lib/insika/studio/views/evals.erb
571
+ - lib/insika/studio/views/fact_detail.erb
519
572
  - lib/insika/studio/views/facts.erb
520
573
  - lib/insika/studio/views/followups.erb
521
574
  - lib/insika/studio/views/funnel.erb
522
575
  - lib/insika/studio/views/harvest.erb
523
576
  - lib/insika/studio/views/home.erb
577
+ - lib/insika/studio/views/inbox.erb
578
+ - lib/insika/studio/views/kits.erb
524
579
  - lib/insika/studio/views/knowledge.erb
525
580
  - lib/insika/studio/views/layout.erb
581
+ - lib/insika/studio/views/live.erb
526
582
  - lib/insika/studio/views/login.erb
527
583
  - lib/insika/studio/views/mcp.erb
584
+ - lib/insika/studio/views/models.erb
528
585
  - lib/insika/studio/views/not_found.erb
529
586
  - lib/insika/studio/views/parity.erb
530
587
  - lib/insika/studio/views/playground.erb
531
588
  - lib/insika/studio/views/refinement.erb
589
+ - lib/insika/studio/views/refinement_detail.erb
532
590
  - lib/insika/studio/views/session.erb
533
591
  - lib/insika/studio/views/settings.erb
534
592
  - lib/insika/studio/views/skills.erb
535
593
  - lib/insika/studio/views/system_files.erb
536
594
  - lib/insika/studio/views/task.erb
537
595
  - lib/insika/studio/views/tasks.erb
538
- - lib/insika/studio/views/tool_edit.erb
539
596
  - lib/insika/studio/views/tools.erb
540
597
  - lib/insika/subagent_graph.rb
541
598
  - lib/insika/system_file_store.rb
@@ -544,6 +601,7 @@ files:
544
601
  - lib/insika/telemetry.rb
545
602
  - lib/insika/telemetry/pricing.rb
546
603
  - lib/insika/telemetry/recorder.rb
604
+ - lib/insika/telemetry/ruby_llm_instrumenter.rb
547
605
  - lib/insika/templates.rb
548
606
  - lib/insika/templates/browser-agent/README.md
549
607
  - lib/insika/templates/browser-agent/agent.rb
@@ -558,6 +616,7 @@ files:
558
616
  - lib/insika/templates/travel-planner/README.md
559
617
  - lib/insika/templates/travel-planner/agent.rb
560
618
  - lib/insika/testing/store_contract.rb
619
+ - lib/insika/text_tool_call.rb
561
620
  - lib/insika/tick.rb
562
621
  - lib/insika/timezone.rb
563
622
  - lib/insika/token_estimator.rb
@@ -576,10 +635,12 @@ files:
576
635
  - lib/insika/tools/a2a_remote.rb
577
636
  - lib/insika/tools/agent_enum.rb
578
637
  - lib/insika/tools/concurrency.rb
638
+ - lib/insika/tools/confirm_pending.rb
579
639
  - lib/insika/tools/data_defined_tool.rb
580
640
  - lib/insika/tools/generate_image.rb
581
641
  - lib/insika/tools/load_knowledge.rb
582
642
  - lib/insika/tools/load_skill.rb
643
+ - lib/insika/tools/present.rb
583
644
  - lib/insika/tools/remember.rb
584
645
  - lib/insika/tools/run_persona_eval.rb
585
646
  - lib/insika/tools/save_artifact.rb
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "time"
4
-
5
- module Insika
6
- module Commands
7
- # Control command: LIVE MCP ingestion. Receives the NAME of
8
- # an MCP instance, delegates to McpToolIngestor (discovers via an injectable client
9
- # -> builds the manifest -> reuses :import_tools: batch upsert + hot reload)
10
- # and returns the per-tool report in the shape of :import_tools, plus
11
- # `instance:`. Idempotent (re-ingesting reconciles). A per-tool failure is isolated
12
- # in `errors[]` (R4); an absent/disabled/url-less instance raises.
13
- # -> { instance, version, created: [names], updated: [names], errors: [{tool,error}] }
14
- class ImportMcpTools
15
- def initialize(ingestor:, event_stream:)
16
- @ingestor = ingestor
17
- @event_stream = event_stream
18
- end
19
-
20
- def call(command)
21
- p = symbolize(command.payload)
22
- name = Insika::Coercion.presence(p[:name]) ||
23
- (raise Insika::ValidationError, "import_mcp_tools: 'name' (MCP instance) is required")
24
-
25
- report = @ingestor.ingest(name)
26
- emit(report)
27
- report
28
- end
29
-
30
- private
31
-
32
- # Emits only COUNTS + the instance name (never headers/env/secrets): 0 leakage.
33
- def emit(report)
34
- @event_stream.emit(Insika::Event.new(
35
- type: :mcp_tools_imported,
36
- data: { instance: report[:instance],
37
- created: report[:created].size, updated: report[:updated].size,
38
- errors: report[:errors].size },
39
- meta: { at: Time.now.utc.iso8601 }
40
- ))
41
- end
42
-
43
- def symbolize(payload)
44
- (payload || {}).each_with_object({}) { |(k, v), acc| acc[k.to_sym] = v }
45
- end
46
- end
47
- end
48
- end