insika 0.3.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +296 -0
- data/README.md +48 -12
- data/bin/insika +725 -0
- data/bin/insika-router +87 -0
- data/docs/AGENTS.md +116 -406
- data/docs/API.md +5 -5
- data/docs/ARCHITECTURE.md +3 -2
- data/docs/ARTIFACTS.md +137 -0
- data/docs/BENCHMARK.md +2 -2
- data/docs/CHANNELS.md +14 -14
- data/docs/CONTEXT.md +63 -19
- data/docs/DEMO.md +80 -0
- data/docs/DEPLOY.md +87 -10
- data/docs/EMBEDDING.md +1 -1
- data/docs/EVALS.md +128 -3
- data/docs/FACTS.md +3 -3
- data/docs/HARVEST.md +5 -6
- data/docs/KNOWLEDGE.md +290 -0
- data/docs/LOADTEST.md +17 -29
- data/docs/MEDIA.md +128 -0
- data/docs/OBSERVABILITY.md +46 -12
- data/docs/OUTCOMES.md +137 -0
- data/docs/PLUGINS.md +51 -6
- data/docs/POLICY.md +222 -0
- data/docs/REFINEMENT.md +14 -9
- data/docs/RELEASING.md +4 -4
- data/docs/ROUTER.md +213 -0
- data/docs/RUNNING-LOCAL.md +5 -5
- data/docs/SCHEDULING.md +121 -0
- data/docs/SECURITY.md +23 -7
- data/docs/SKILLS.md +11 -2
- data/docs/SOAK.md +3 -3
- data/docs/TEMPLATES.md +134 -0
- data/docs/TOOLS.md +176 -27
- data/docs/WHY.md +1 -1
- data/docs/WORKFLOWS.md +2 -2
- data/docs/_includes/head_custom.html +5 -0
- data/docs/_includes/title.html +13 -0
- data/docs/_sass/color_schemes/insika.scss +32 -0
- data/docs/_sass/custom/custom.scss +199 -0
- data/docs/_sass/custom/setup.scss +26 -0
- data/docs/assets/img/favicon.svg +7 -0
- data/docs/assets/img/insika-mark.svg +7 -0
- data/docs/core-concepts.md +21 -0
- data/docs/domain.md +4 -4
- data/docs/improve.md +20 -0
- data/docs/index.md +8 -5
- data/docs/integrate.md +20 -0
- data/docs/operate.md +13 -6
- data/docs/prompts/ADD-TOOL.md +118 -0
- data/docs/prompts/DIAGNOSE-TURN.md +65 -0
- data/docs/prompts/GO-LIVE.md +138 -0
- data/docs/prompts/RUN-EXAMPLES.md +70 -0
- data/docs/reference.md +19 -0
- data/docs/ship.md +10 -2
- data/docs/start-here.md +18 -0
- data/lib/insika/agent_profile.rb +99 -17
- data/lib/insika/artifact_signing.rb +82 -0
- data/lib/insika/artifact_store.rb +160 -0
- data/lib/insika/channel_delivery.rb +1 -1
- data/lib/insika/chat_builder.rb +50 -19
- data/lib/insika/commands/agent_payload.rb +2 -2
- data/lib/insika/commands/backfill_knowledge.rb +145 -0
- data/lib/insika/commands/delete_artifact.rb +35 -0
- data/lib/insika/commands/delete_concept.rb +34 -0
- data/lib/insika/commands/delete_mcp.rb +6 -2
- data/lib/insika/commands/delete_tenant_data.rb +15 -3
- data/lib/insika/commands/gate_refinement.rb +1 -1
- data/lib/insika/commands/refresh_mcp_tools.rb +47 -0
- data/lib/insika/commands/restore_concept.rb +34 -0
- data/lib/insika/commands/seed_demo_data.rb +31 -0
- data/lib/insika/commands/upsert_mcp.rb +6 -3
- data/lib/insika/commands/write_concept.rb +57 -0
- data/lib/insika/compaction.rb +196 -0
- data/lib/insika/context/builder.rb +6 -2
- data/lib/insika/context/fragment.rb +4 -1
- data/lib/insika/context/priority.rb +8 -0
- data/lib/insika/context/providers/briefing.rb +53 -24
- data/lib/insika/context/providers/knowledge.rb +108 -0
- data/lib/insika/context/providers/prompt.rb +30 -24
- data/lib/insika/context/providers/session.rb +46 -10
- data/lib/insika/context_trace_store.rb +11 -1
- data/lib/insika/cron.rb +189 -0
- data/lib/insika/demo/agent_attrs.rb +43 -0
- data/lib/insika/demo/golden_cases.rb +81 -0
- data/lib/insika/demo/seeder.rb +336 -0
- data/lib/insika/doctor.rb +280 -17
- data/lib/insika/dsl/definition.rb +3 -2
- data/lib/insika/dsl/runtime.rb +64 -79
- data/lib/insika/dsl/server_boot.rb +23 -1
- data/lib/insika/dsl/system.rb +10 -2
- data/lib/insika/dsl.rb +103 -2
- data/lib/insika/env_schema.rb +21 -7
- data/lib/insika/evals/golden.rb +41 -4
- data/lib/insika/evals/judge.rb +47 -2
- data/lib/insika/evals/pairwise.rb +11 -0
- data/lib/insika/evals/persona.rb +98 -0
- data/lib/insika/evals/runner.rb +9 -0
- data/lib/insika/evals/simulator.rb +225 -0
- data/lib/insika/evals/transport.rb +84 -2
- data/lib/insika/event_stream.rb +10 -0
- data/lib/insika/executor.rb +295 -55
- data/lib/insika/followup_policy.rb +2 -25
- data/lib/insika/golden_store.rb +16 -1
- data/lib/insika/grounding/matcher.rb +1 -1
- data/lib/insika/knowledge.rb +680 -0
- data/lib/insika/knowledge_store.rb +140 -0
- data/lib/insika/loop_detector.rb +5 -34
- data/lib/insika/mcp_client.rb +94 -0
- data/lib/insika/mcp_json.rb +74 -0
- data/lib/insika/mcp_live_tool.rb +43 -0
- data/lib/insika/mcp_store.rb +98 -26
- data/lib/insika/mcp_tool_ingestor.rb +30 -8
- data/lib/insika/mcp_tool_registry.rb +100 -0
- data/lib/insika/media.rb +115 -31
- data/lib/insika/message_origin.rb +1 -1
- data/lib/insika/middleware.rb +9 -0
- data/lib/insika/onboarding.rb +17 -1
- data/lib/insika/outcome_store.rb +1 -1
- data/lib/insika/overlay_tool_registry.rb +37 -17
- data/lib/insika/packaging.rb +2 -2
- data/lib/insika/profile_source.rb +15 -1
- data/lib/insika/prompt_catalog.rb +10 -0
- data/lib/insika/retention.rb +36 -1
- data/lib/insika/router/app.rb +157 -0
- data/lib/insika/router/backend_pool.rb +98 -0
- data/lib/insika/router/hash_ring.rb +55 -0
- data/lib/insika/router/proxy_body.rb +34 -0
- data/lib/insika/router/session_key.rb +54 -0
- data/lib/insika/router.rb +18 -0
- data/lib/insika/schedule.rb +177 -0
- data/lib/insika/schedule_engine.rb +314 -0
- data/lib/insika/schedule_store.rb +208 -0
- data/lib/insika/server/app.rb +105 -15
- data/lib/insika/server/rack_app.rb +5 -1
- data/lib/insika/server/responses.rb +5 -5
- data/lib/insika/session_store.rb +34 -4
- data/lib/insika/settings_store.rb +8 -1
- data/lib/insika/skill_catalog.rb +12 -0
- data/lib/insika/soak/runner.rb +4 -4
- data/lib/insika/steer_injector.rb +21 -10
- data/lib/insika/studio/app.rb +591 -47
- data/lib/insika/studio/assets/dist/application.css +1 -1
- data/lib/insika/studio/assets/dist/application.js +21 -21
- data/lib/insika/studio/forms.rb +57 -5
- data/lib/insika/studio/nav_icons.rb +14 -1
- data/lib/insika/studio/views/_agent_tab_cache.erb +25 -0
- data/lib/insika/studio/views/_agent_tab_config.erb +514 -0
- data/lib/insika/studio/views/_agent_tab_history.erb +24 -0
- data/lib/insika/studio/views/_agent_tab_loops.erb +54 -0
- data/lib/insika/studio/views/_agent_tab_memory.erb +51 -0
- data/lib/insika/studio/views/_agent_tab_outcomes.erb +31 -0
- data/lib/insika/studio/views/_agent_tab_prompts.erb +108 -0
- data/lib/insika/studio/views/_agent_tab_skills.erb +38 -0
- data/lib/insika/studio/views/_agents_master.erb +44 -0
- data/lib/insika/studio/views/_message.erb +49 -32
- data/lib/insika/studio/views/agent_detail.erb +61 -820
- data/lib/insika/studio/views/agents.erb +70 -57
- data/lib/insika/studio/views/artifact.erb +23 -0
- data/lib/insika/studio/views/artifacts.erb +59 -0
- data/lib/insika/studio/views/evals.erb +2 -2
- data/lib/insika/studio/views/facts.erb +1 -1
- data/lib/insika/studio/views/funnel.erb +1 -1
- data/lib/insika/studio/views/home.erb +106 -67
- data/lib/insika/studio/views/knowledge.erb +123 -0
- data/lib/insika/studio/views/layout.erb +14 -11
- data/lib/insika/studio/views/mcp.erb +174 -80
- data/lib/insika/studio/views/session.erb +231 -177
- data/lib/insika/studio/views/settings.erb +50 -1
- data/lib/insika/studio/views/skills.erb +1 -1
- data/lib/insika/studio/views/tools.erb +24 -9
- data/lib/insika/telemetry/recorder.rb +49 -1
- data/lib/insika/templates/browser-agent/README.md +36 -0
- data/lib/insika/templates/browser-agent/agent.rb +49 -0
- data/lib/insika/templates/daily-digest/README.md +47 -0
- data/lib/insika/templates/daily-digest/agent.rb +77 -0
- data/lib/insika/templates/repo-explorer/README.md +36 -0
- data/lib/insika/templates/repo-explorer/agent.rb +45 -0
- data/lib/insika/templates/research-analyst/README.md +26 -0
- data/lib/insika/templates/research-analyst/agent.rb +68 -0
- data/lib/insika/templates/review-panel/README.md +20 -0
- data/lib/insika/templates/review-panel/agent.rb +50 -0
- data/lib/insika/templates/travel-planner/README.md +35 -0
- data/lib/insika/templates/travel-planner/agent.rb +87 -0
- data/lib/insika/templates.rb +112 -0
- data/lib/insika/tick.rb +24 -12
- data/lib/insika/timezone.rb +45 -0
- data/lib/insika/tool_batch.rb +67 -0
- data/lib/insika/tool_usage_report.rb +162 -0
- data/lib/insika/tools/generate_image.rb +52 -7
- data/lib/insika/tools/load_knowledge.rb +74 -0
- data/lib/insika/tools/run_persona_eval.rb +328 -0
- data/lib/insika/tools/save_artifact.rb +95 -0
- data/lib/insika/turn_budget.rb +91 -0
- data/lib/insika/turn_output.rb +1 -1
- data/lib/insika/turn_state.rb +15 -4
- data/lib/insika/version.rb +1 -1
- data/lib/insika/wiring/graph.rb +184 -12
- data/lib/insika/wiring/graph_chat.rb +102 -0
- data/lib/insika.rb +64 -0
- metadata +109 -5
- data/docs/build.md +0 -14
- data/docs/understand.md +0 -10
data/lib/insika/wiring/graph.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "graph_chat"
|
|
4
|
+
|
|
3
5
|
module Insika
|
|
4
6
|
module Wiring
|
|
5
7
|
# SHARED composition core for both roots: the minimal wiring
|
|
@@ -78,11 +80,21 @@ module Insika
|
|
|
78
80
|
# followup) so the engine, the tools and the Studio always have stores.
|
|
79
81
|
contact_store = Insika::ContactStore.new(store: backend)
|
|
80
82
|
followup_store = Insika::FollowupStore.new(store: backend)
|
|
83
|
+
# the recurring-schedule rows: one row per
|
|
84
|
+
# declared schedule, declaration + runtime state. Built unconditionally
|
|
85
|
+
# (empty and free when no pack declares schedules) so the engine, the
|
|
86
|
+
# doctor and the Studio always have a store.
|
|
87
|
+
schedule_store = Insika::ScheduleStore.new(store: backend)
|
|
81
88
|
# the distilled proposals + the latched dedup ledger +
|
|
82
89
|
# the per-session markers. Built unconditionally (empty and free when
|
|
83
90
|
# no pack declares distill) so the wiki, the engine and the LGPD
|
|
84
91
|
# purges always have a store.
|
|
85
92
|
proposal_store = Insika::ProposalStore.new(store: backend)
|
|
93
|
+
# concepts extracted from finished turns. Built
|
|
94
|
+
# unconditionally (empty and free when no pack declares knowledge)
|
|
95
|
+
# so the extractor, the Studio and the LGPD purges always have a
|
|
96
|
+
# store.
|
|
97
|
+
knowledge_store = Insika::KnowledgeStore.new(store: backend)
|
|
86
98
|
# refinement RUNS (reports over real traffic). Runtime data,
|
|
87
99
|
# same backend as sessions/tasks — the collector and the command that write it
|
|
88
100
|
# are the root's business (deployment-only, like the memory commands).
|
|
@@ -93,6 +105,11 @@ module Insika
|
|
|
93
105
|
# when no pack declares harvest) so the engine, the Studio and the
|
|
94
106
|
# LGPD purges always have a store.
|
|
95
107
|
harvest_store = Insika::HarvestStore.new(store: backend)
|
|
108
|
+
# the report destination — one record per run, no
|
|
109
|
+
# versioning. Built unconditionally (empty and free when nothing saves)
|
|
110
|
+
# so the tool, the routes, the retention sweep and the tenant purge
|
|
111
|
+
# always have a store.
|
|
112
|
+
artifact_store = Insika::ArtifactStore.new(store: backend)
|
|
96
113
|
|
|
97
114
|
code_tool_registry = Insika::ToolRegistry.new
|
|
98
115
|
workflow_registry = Insika::WorkflowRegistry.new
|
|
@@ -118,7 +135,10 @@ module Insika
|
|
|
118
135
|
funnel_store: funnel_store,
|
|
119
136
|
contact_store: contact_store,
|
|
120
137
|
followup_store: followup_store,
|
|
138
|
+
schedule_store: schedule_store,
|
|
121
139
|
proposal_store: proposal_store,
|
|
140
|
+
knowledge_store: knowledge_store,
|
|
141
|
+
artifact_store: artifact_store,
|
|
122
142
|
code_tool_registry: code_tool_registry,
|
|
123
143
|
workflow_registry: workflow_registry, policy_registry: policy_registry,
|
|
124
144
|
capability_registry: Insika::CapabilityRegistry.new, hooks: Insika::Hooks.new,
|
|
@@ -141,6 +161,13 @@ module Insika
|
|
|
141
161
|
def build(spine:, profiles:, tool_registry:, tool_catalog:, skill_catalog:,
|
|
142
162
|
prompt_catalog:, guardrails:, context_providers:, edge_limiter: nil,
|
|
143
163
|
executor_extra: {})
|
|
164
|
+
# the save_artifact tool: a REGISTRY tool registered OPTIONAL (the
|
|
165
|
+
# per-agent allowlist is the switch — an agent that did not name it
|
|
166
|
+
# cannot call it). Registered in the shared code registry, so both
|
|
167
|
+
# roots (base registry + the deployment's overlay, which composes it)
|
|
168
|
+
# expose it. The gem's require lives IN the factory block (loaded on
|
|
169
|
+
# the 1st instance, turn time -> wiring-load stays gem-free).
|
|
170
|
+
register_artifact_tool(spine)
|
|
144
171
|
spine.hooks.register(:task, after: guardrails.output_validator)
|
|
145
172
|
middleware = Insika::MiddlewareStack.new([edge_limiter, guardrails.input_guardrail].compact)
|
|
146
173
|
|
|
@@ -188,6 +215,9 @@ module Insika
|
|
|
188
215
|
# parity). The base graph wires it over the same backend the context
|
|
189
216
|
# trace uses.
|
|
190
217
|
model_visible_trace_store: Insika::ModelVisibleTraceStore.new(store: spine.backend),
|
|
218
|
+
# the per-turn extraction hook (nil = the loop is off,
|
|
219
|
+
# parity). Gated per-agent by `profile.knowledge`.
|
|
220
|
+
knowledge_store: spine.knowledge_store,
|
|
191
221
|
**executor_extra
|
|
192
222
|
)
|
|
193
223
|
|
|
@@ -233,7 +263,8 @@ module Insika
|
|
|
233
263
|
followup_store: spine.followup_store, # records age out too
|
|
234
264
|
contact_store: spine.contact_store, # cells age out too
|
|
235
265
|
proposal_store: spine.proposal_store, # proposals age out too
|
|
236
|
-
harvest_store: spine.harvest_store # candidates/log/snapshots too
|
|
266
|
+
harvest_store: spine.harvest_store, # candidates/log/snapshots too
|
|
267
|
+
artifact_store: spine.artifact_store # reports expire on their own TTL
|
|
237
268
|
),
|
|
238
269
|
interval: tick_env("INSIKA_TICK_INTERVAL") || Insika::Tick::DEFAULT_INTERVAL,
|
|
239
270
|
stale_after: tick_env("INSIKA_TICK_STALE_AFTER") || Insika::Tick::DEFAULT_STALE_AFTER
|
|
@@ -256,6 +287,16 @@ module Insika
|
|
|
256
287
|
contact_store: spine.contact_store, task_store: spine.task_store,
|
|
257
288
|
profiles: profiles, executor: executor, event_stream: spine.event_stream
|
|
258
289
|
)
|
|
290
|
+
# the recurring-schedule firer — the tick's
|
|
291
|
+
# fourth duty, wired here after the Tick, gated by its own claim
|
|
292
|
+
# window. Always built: a pack that declares `schedules` later finds
|
|
293
|
+
# its firer already on the tick (inert when no profile declares one).
|
|
294
|
+
executor.tick.schedule = Insika::ScheduleEngine.new(
|
|
295
|
+
store: spine.backend, schedule_store: spine.schedule_store,
|
|
296
|
+
task_store: spine.task_store, session_store: spine.session_store,
|
|
297
|
+
profiles: profiles, executor: executor, budget_ledger: spine.budget_ledger,
|
|
298
|
+
event_stream: spine.event_stream
|
|
299
|
+
)
|
|
259
300
|
# the distillation engine — the tick-duty that finds idle
|
|
260
301
|
# customer sessions and distills them on its own worker fiber (a
|
|
261
302
|
# supervisor child, started in serving mode next to the tick).
|
|
@@ -307,13 +348,16 @@ module Insika
|
|
|
307
348
|
memory_store: spine.memory_store, memory_audit_store: spine.memory_audit_store,
|
|
308
349
|
refinement_store: spine.refinement_store,
|
|
309
350
|
harvest_store: spine.harvest_store,
|
|
351
|
+
artifact_store: spine.artifact_store,
|
|
310
352
|
outbox_store: spine.outbox_store, shadow_pair_store: spine.shadow_pair_store,
|
|
311
353
|
inbound_log: spine.inbound_log,
|
|
312
354
|
outcome_store: spine.outcome_store,
|
|
313
355
|
funnel_store: spine.funnel_store,
|
|
314
356
|
contact_store: spine.contact_store,
|
|
315
357
|
followup_store: spine.followup_store,
|
|
358
|
+
schedule_store: spine.schedule_store,
|
|
316
359
|
proposal_store: spine.proposal_store,
|
|
360
|
+
knowledge_store: spine.knowledge_store,
|
|
317
361
|
token_store: spine.token_store, budget_ledger: spine.budget_ledger,
|
|
318
362
|
circuit_state: spine.circuit_state,
|
|
319
363
|
channel_registry: spine.channel_registry, channel_delivery: channel_delivery,
|
|
@@ -327,6 +371,49 @@ module Insika
|
|
|
327
371
|
)
|
|
328
372
|
end
|
|
329
373
|
|
|
374
|
+
# The boot step behind every root's `load_plugins` (Server::Boot's first
|
|
375
|
+
# named step). Discovers plugin manifests, validates them, requires the
|
|
376
|
+
# entries and registers their contributions into the ALREADY-BUILT graph —
|
|
377
|
+
# which is safe by construction: every seam the Loader touches resolves at
|
|
378
|
+
# turn time (registries and hooks by name, the middleware stack and the
|
|
379
|
+
# provider list per call, the catalogs on reload), and the step runs
|
|
380
|
+
# single-fiber before the server accepts connections.
|
|
381
|
+
#
|
|
382
|
+
# Roots, highest precedence first (duplicate id -> first root wins):
|
|
383
|
+
# 1. workspace — INSIKA_PLUGIN_DIR (the operator's override spot);
|
|
384
|
+
# 2. gems — whatever called Insika::Plugin.announce (default-enabled);
|
|
385
|
+
# 3. bundled — `bundled_root` (the repo's plugins/; requires enabling).
|
|
386
|
+
# INSIKA_PLUGINS enables workspace/bundled ids; INSIKA_PLUGINS_DISABLED is
|
|
387
|
+
# the absolute veto (deny wins, like every allowlist in the engine).
|
|
388
|
+
def load_plugins(graph, env: ENV, bundled_root: nil)
|
|
389
|
+
announced = Insika::Plugin.announced_roots
|
|
390
|
+
workspace = Insika::EnvSchema.read("INSIKA_PLUGIN_DIR", env)
|
|
391
|
+
roots = ([workspace] + announced + [bundled_root]).compact.map { |d| File.expand_path(d.to_s) }
|
|
392
|
+
|
|
393
|
+
result = Insika::Plugin::Loader.new(
|
|
394
|
+
roots: roots,
|
|
395
|
+
registries: {
|
|
396
|
+
tools: graph.code_tool_registry, workflows: graph.workflow_registry,
|
|
397
|
+
policies: graph.policy_registry, capabilities: graph.capability_registry,
|
|
398
|
+
channels: graph.channel_registry, hooks: graph.hooks,
|
|
399
|
+
middleware: graph.middleware, context_providers: graph.context_providers
|
|
400
|
+
},
|
|
401
|
+
enabled: plugin_csv(Insika::EnvSchema.read("INSIKA_PLUGINS", env)),
|
|
402
|
+
disabled: plugin_csv(Insika::EnvSchema.read("INSIKA_PLUGINS_DISABLED", env)),
|
|
403
|
+
announced_roots: announced, event_stream: graph.event_stream
|
|
404
|
+
).load_all
|
|
405
|
+
|
|
406
|
+
# Plugin knowledge joins at the LOWEST precedence: an operator's
|
|
407
|
+
# workspace/authored skill always beats a same-named plugin one.
|
|
408
|
+
graph.skill_catalog.add_roots(result[:skill_dirs])
|
|
409
|
+
graph.prompt_catalog.add_roots(result[:prompt_dirs])
|
|
410
|
+
result
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
def plugin_csv(value)
|
|
414
|
+
value.to_s.split(",").map(&:strip).reject(&:empty?)
|
|
415
|
+
end
|
|
416
|
+
|
|
330
417
|
# The CORE command surface every root needs — turn essentials + the operator
|
|
331
418
|
# controls (pause/approve) the Studio dispatches. Registering pause_task/
|
|
332
419
|
# approve_action HERE is the crux of: it retires the config.ru:28-34 patch.
|
|
@@ -411,16 +498,18 @@ module Insika
|
|
|
411
498
|
model_visible_trace_store: Insika::ModelVisibleTraceStore.new(store: spine.backend),
|
|
412
499
|
outcome_store: spine.outcome_store,
|
|
413
500
|
funnel_store: spine.funnel_store, # the fold dies with the tenant
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
501
|
+
followup_store: spine.followup_store,
|
|
502
|
+
contact_store: spine.contact_store,
|
|
503
|
+
proposal_store: spine.proposal_store,
|
|
504
|
+
harvest_store: spine.harvest_store,
|
|
505
|
+
schedule_store: spine.schedule_store,
|
|
506
|
+
artifact_store: spine.artifact_store,
|
|
507
|
+
task_store: spine.task_store, checkpoint_store: spine.checkpoint_store,
|
|
508
|
+
outbox_store: spine.outbox_store,
|
|
509
|
+
shadow_pairs: spine.shadow_pair_store,
|
|
510
|
+
token_store: spine.token_store, # revoked BEFORE the sweep
|
|
511
|
+
event_stream: spine.event_stream
|
|
512
|
+
))
|
|
424
513
|
# the operator's baseline freeze — the number
|
|
425
514
|
# read. Synchronous control command, dispatched from the Studio.
|
|
426
515
|
bus.register(:freeze_funnel_baseline,
|
|
@@ -434,6 +523,12 @@ module Insika
|
|
|
434
523
|
bus.register(:cancel_followup,
|
|
435
524
|
Insika::Commands::CancelFollowup.new(followup_store: spine.followup_store,
|
|
436
525
|
event_stream: spine.event_stream))
|
|
526
|
+
# the report destination's Studio mutation — delete one
|
|
527
|
+
# artifact (the only write on the Artifacts tab; a bus command, like
|
|
528
|
+
# every Studio mutation).
|
|
529
|
+
bus.register(:delete_artifact,
|
|
530
|
+
Insika::Commands::DeleteArtifact.new(artifact_store: spine.artifact_store,
|
|
531
|
+
event_stream: spine.event_stream))
|
|
437
532
|
bus.register(:revoke_contact,
|
|
438
533
|
Insika::Commands::RevokeContact.new(contact_store: spine.contact_store,
|
|
439
534
|
followup_store: spine.followup_store,
|
|
@@ -493,6 +588,23 @@ module Insika
|
|
|
493
588
|
# code path; the engine keeps the automatic pass when the root does
|
|
494
589
|
# not pass a runner here (nil = the command is not on the bus).
|
|
495
590
|
bus.register(:run_distillation, run_distillation) if run_distillation
|
|
591
|
+
# the demo seed's ONE path — the CLI's `insika demo:seed` builds
|
|
592
|
+
# the same Insika::Demo::Seeder itself (no executor, no bus, from
|
|
593
|
+
# Graph.spine alone), and the Studio's "Seed demo data" button
|
|
594
|
+
# dispatches this bus command; nothing else writes the demo agent.
|
|
595
|
+
config_store = Insika::ConfigStore.new(store: spine.backend)
|
|
596
|
+
demo_seeder = Insika::Demo::Seeder.new(
|
|
597
|
+
profiles: profiles, store: spine.backend, session_store: spine.session_store,
|
|
598
|
+
task_store: spine.task_store, outcome_store: spine.outcome_store,
|
|
599
|
+
funnel_store: spine.funnel_store, followup_store: spine.followup_store,
|
|
600
|
+
refinement_store: spine.refinement_store, pending_action_store: spine.pending_action_store,
|
|
601
|
+
proposal_store: spine.proposal_store, memory_store: spine.memory_store,
|
|
602
|
+
golden_store: Insika::GoldenStore.new(config_store: config_store),
|
|
603
|
+
baseline_store: Insika::BaselineStore.new(config_store: config_store),
|
|
604
|
+
event_stream: spine.event_stream
|
|
605
|
+
)
|
|
606
|
+
bus.register(:seed_demo_data,
|
|
607
|
+
Insika::Commands::SeedDemoData.new(seeder: demo_seeder, event_stream: spine.event_stream))
|
|
496
608
|
bus
|
|
497
609
|
end
|
|
498
610
|
|
|
@@ -505,7 +617,9 @@ module Insika
|
|
|
505
617
|
:harvest_store,
|
|
506
618
|
:token_store, :budget_ledger, :circuit_state, :outbox_store, :shadow_pair_store,
|
|
507
619
|
:inbound_log, :outcome_store, :funnel_store,
|
|
508
|
-
:contact_store, :followup_store, :proposal_store,
|
|
620
|
+
:contact_store, :followup_store, :schedule_store, :proposal_store,
|
|
621
|
+
:knowledge_store,
|
|
622
|
+
:artifact_store,
|
|
509
623
|
:code_tool_registry, :workflow_registry, :policy_registry, :capability_registry, :hooks,
|
|
510
624
|
:channel_registry, keyword_init: true
|
|
511
625
|
)
|
|
@@ -520,7 +634,10 @@ module Insika
|
|
|
520
634
|
:inbound_log, :token_store,
|
|
521
635
|
:budget_ledger, :circuit_state, :outcome_store, :funnel_store,
|
|
522
636
|
:contact_store, :followup_store, :proposal_store,
|
|
637
|
+
:schedule_store,
|
|
523
638
|
:harvest_store,
|
|
639
|
+
:knowledge_store,
|
|
640
|
+
:artifact_store,
|
|
524
641
|
:channel_registry, :channel_delivery,
|
|
525
642
|
:code_tool_registry, :tool_registry, :workflow_registry, :policy_registry, :capability_registry,
|
|
526
643
|
:tool_catalog, :skill_catalog, :prompt_catalog,
|
|
@@ -531,6 +648,61 @@ module Insika
|
|
|
531
648
|
) do
|
|
532
649
|
def durable? = backend.is_a?(Insika::Stores::SQLite)
|
|
533
650
|
end
|
|
651
|
+
|
|
652
|
+
# The save_artifact tool, registered OPTIONAL on the shared code registry
|
|
653
|
+
# (the per-agent allowlist is the switch). The signing/base config is
|
|
654
|
+
# bound at registration time from the environment — the tool instance is
|
|
655
|
+
# per-deployment, and the tenant/agent/task bindings arrive per-turn via
|
|
656
|
+
# the deposited turn context.
|
|
657
|
+
# `run_persona_eval` (C3.1): a QA agent's own probe against a SIBLING
|
|
658
|
+
# agent of THIS SAME graph. Registered OPTIONAL on the shared code
|
|
659
|
+
# registry, same switch as `save_artifact` — but unlike that one, this
|
|
660
|
+
# is NOT called unconditionally from `build`: it needs a `golden_store`
|
|
661
|
+
# and a `settings_store` (the persona model + judge panel), and neither
|
|
662
|
+
# lives on the spine (the base/minimal wiring builds without either, the
|
|
663
|
+
# same way it builds without a Studio) — so each root calls this itself,
|
|
664
|
+
# once it has both. `config/deployment.rb` (round1, and the actual
|
|
665
|
+
# production `config.ru` root) and `DSL::Runtime` both do.
|
|
666
|
+
#
|
|
667
|
+
# `graph` is the ALREADY-RETURNED `Graph::Result` — bus/executor fully
|
|
668
|
+
# assembled by the time a caller has it to pass here, so `GraphChat.new`
|
|
669
|
+
# needs no laziness of its own (the tool's own factory block is what is
|
|
670
|
+
# lazy — this method just registers it).
|
|
671
|
+
# `llm:` — the caller's own RubyLLM::Context, when it has one
|
|
672
|
+
# (DSL::Runtime does; config/deployment.rb does not, and reads the
|
|
673
|
+
# process-wide RubyLLM constant like the rest of that root already
|
|
674
|
+
# does). Forwarded as-is so the tool's OWN persona/judge calls spend
|
|
675
|
+
# the right credentials instead of silently defaulting to nil.
|
|
676
|
+
def register_persona_eval_tool(graph, golden_store:, settings_store:, llm: nil)
|
|
677
|
+
graph.code_tool_registry.register("run_persona_eval", optional: true) do
|
|
678
|
+
require "ruby_llm"
|
|
679
|
+
require_relative "../tools/run_persona_eval"
|
|
680
|
+
Insika::Tools::RunPersonaEval.new(
|
|
681
|
+
golden_store: golden_store, profiles: graph.profiles, tool_registry: graph.tool_registry,
|
|
682
|
+
runtime: GraphChat.new(graph: graph), graph: graph, settings_store: settings_store,
|
|
683
|
+
budget_ledger: graph.budget_ledger, event_stream: graph.event_stream, llm: llm
|
|
684
|
+
)
|
|
685
|
+
end
|
|
686
|
+
end
|
|
687
|
+
|
|
688
|
+
def register_artifact_tool(spine)
|
|
689
|
+
signing_key = Insika::EnvSchema.read("INSIKA_ARTIFACT_SIGNING_KEY")
|
|
690
|
+
signing_ttl = Insika::EnvSchema.read("INSIKA_ARTIFACT_SIGNING_TTL")
|
|
691
|
+
max_bytes = Insika::EnvSchema.read("INSIKA_ARTIFACT_MAX_BYTES")
|
|
692
|
+
base_url = Insika::Coercion.presence(Insika::EnvSchema.read("INSIKA_PUBLIC_URL"))
|
|
693
|
+
spine.code_tool_registry.register("save_artifact", optional: true) do
|
|
694
|
+
require "ruby_llm"
|
|
695
|
+
require_relative "../tools/save_artifact"
|
|
696
|
+
Insika::Tools::SaveArtifact.new(
|
|
697
|
+
artifact_store: spine.artifact_store,
|
|
698
|
+
base_url: base_url,
|
|
699
|
+
signing_key: signing_key,
|
|
700
|
+
signing_ttl: signing_ttl&.to_i,
|
|
701
|
+
max_bytes: max_bytes&.to_i,
|
|
702
|
+
event_stream: spine.event_stream
|
|
703
|
+
)
|
|
704
|
+
end
|
|
705
|
+
end
|
|
534
706
|
end
|
|
535
707
|
end
|
|
536
708
|
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Insika
|
|
4
|
+
module Wiring
|
|
5
|
+
# A synchronous, in-process "chat" seam over an assembled `Graph::Result`:
|
|
6
|
+
# dispatch a Command, drain the event stream to its terminal event, hand
|
|
7
|
+
# back the outcome. Extracted from `DSL::Runtime#chat`/`#run_workflow`
|
|
8
|
+
# (C3.1) so a graph built OUTSIDE the DSL — `config/deployment.rb`, the
|
|
9
|
+
# actual production/round1 composition root `config.ru` boots — can hand a
|
|
10
|
+
# `#chat`-capable object to anything that needs one (today:
|
|
11
|
+
# `run_persona_eval`'s `Evals::GraphTransport` seam), without a second copy
|
|
12
|
+
# of this dispatch+drain plumbing. `DSL::Runtime` now delegates here too —
|
|
13
|
+
# one implementation, exercised by both roots.
|
|
14
|
+
class GraphChat
|
|
15
|
+
TERMINAL = %i[task_completed task_failed task_cancelled].freeze
|
|
16
|
+
|
|
17
|
+
def initialize(graph:)
|
|
18
|
+
@graph = graph
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# One turn, in-process -> the assistant's text. `agent:` is REQUIRED —
|
|
22
|
+
# this seam has no notion of "the default agent" (that is a DSL::Runtime
|
|
23
|
+
# concept, filled in by its own caller before delegating here). Raises
|
|
24
|
+
# Insika::Error on a failed/cancelled turn, or the command's own
|
|
25
|
+
# rejection (unknown agent, bad schema) verbatim.
|
|
26
|
+
def chat(message, agent:, session_id: nil, timeout: nil)
|
|
27
|
+
command = Insika::Command.build(
|
|
28
|
+
:send_message, { agent: agent.to_s, message: message, session_id: session_id },
|
|
29
|
+
transport: :cli
|
|
30
|
+
)
|
|
31
|
+
run_command(command, session_id: session_id, timeout: timeout)[:text]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Dispatch + drain, generic over any Command — the seam a workflow run
|
|
35
|
+
# also needs (a :trigger_workflow Command carries :output, not :text).
|
|
36
|
+
# Subscribes BEFORE dispatching (the fiber may emit eagerly) and binds to
|
|
37
|
+
# the dispatched task. A synchronous handler error (unknown agent/
|
|
38
|
+
# workflow, bad input against the schema) propagates untouched — the
|
|
39
|
+
# caller sees the real ValidationError/NotFoundError, not a turn failure.
|
|
40
|
+
def run_command(command, session_id:, timeout:)
|
|
41
|
+
require "async"
|
|
42
|
+
outcome = {}
|
|
43
|
+
rejected = nil
|
|
44
|
+
Async do |task|
|
|
45
|
+
serving = !session_id.nil?
|
|
46
|
+
@graph.executor.supervised = true if serving
|
|
47
|
+
ensure_session(session_id) if session_id
|
|
48
|
+
sub = @graph.event_stream.subscribe
|
|
49
|
+
res = begin
|
|
50
|
+
@graph.bus.dispatch(command)
|
|
51
|
+
rescue StandardError => e
|
|
52
|
+
# CAPTURED, not re-raised inside the reactor: letting it escape the
|
|
53
|
+
# Async block logs "Task may have ended with unhandled exception" —
|
|
54
|
+
# alarming noise for a DOCUMENTED rejection (a schema violation, an
|
|
55
|
+
# unknown agent). Re-raised verbatim below, outside the reactor.
|
|
56
|
+
sub.close
|
|
57
|
+
rejected = e
|
|
58
|
+
next
|
|
59
|
+
end
|
|
60
|
+
sub.bind(task_id: res[:task_id])
|
|
61
|
+
drain(sub, outcome, task, timeout)
|
|
62
|
+
teardown_serving if serving
|
|
63
|
+
end.wait
|
|
64
|
+
raise rejected if rejected
|
|
65
|
+
raise Insika::Error, "turn #{outcome[:error]}" if outcome[:error]
|
|
66
|
+
|
|
67
|
+
outcome
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
# Reads the stream until this turn reaches a terminal event, then stops.
|
|
73
|
+
# A workflow run also carries its typed OUTPUT, which is not the turn text.
|
|
74
|
+
def drain(sub, outcome, task, timeout)
|
|
75
|
+
reader = task.async do
|
|
76
|
+
sub.each do |ev|
|
|
77
|
+
case ev.type
|
|
78
|
+
when :task_completed then outcome[:text] = ev.data[:content].to_s
|
|
79
|
+
when :workflow_completed then outcome[:output] = ev.data[:output]
|
|
80
|
+
when :task_failed then outcome[:error] = "failed: #{ev.data[:message] || ev.data[:error]}"
|
|
81
|
+
when :task_cancelled then outcome[:error] = "cancelled"
|
|
82
|
+
end
|
|
83
|
+
sub.close if TERMINAL.include?(ev.type)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
timeout ? task.with_timeout(timeout) { reader.wait } : reader.wait
|
|
87
|
+
rescue Async::TimeoutError
|
|
88
|
+
outcome[:error] = "timed out after #{timeout}s"
|
|
89
|
+
sub.close
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def ensure_session(session_id)
|
|
93
|
+
@graph.session_store.find(session_id) || @graph.session_store.create(id: session_id, vars: {})
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def teardown_serving
|
|
97
|
+
@graph.executor.stop_session_actors
|
|
98
|
+
@graph.executor.instance_variable_get(:@supervisor)&.stop
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
data/lib/insika.rb
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Templates under lib/insika/templates/*/agent.rb open with a bare
|
|
4
|
+
# `require "insika"` (the line a standalone `ruby agent.rb` run needs) and
|
|
5
|
+
# Templates.evaluate instance_evals that same source in-process — so this
|
|
6
|
+
# file's own directory must be on $LOAD_PATH, or that require raises
|
|
7
|
+
# LoadError whenever nothing else already activated the "insika" gem
|
|
8
|
+
# (no Bundler.setup, no globally installed gem).
|
|
9
|
+
$LOAD_PATH.unshift(__dir__) unless $LOAD_PATH.include?(__dir__)
|
|
10
|
+
|
|
3
11
|
require_relative "insika/version"
|
|
4
12
|
require_relative "insika/errors"
|
|
5
13
|
# the payload selection + the domain-boundary audit yardstick.
|
|
@@ -27,6 +35,20 @@ require_relative "insika/contact_store"
|
|
|
27
35
|
require_relative "insika/followup_store"
|
|
28
36
|
# the tick-driven firer — rides the same tick as retention/funnel.
|
|
29
37
|
require_relative "insika/followup_engine"
|
|
38
|
+
# IANA zone resolution through the OS tz database — the stdlib-only route
|
|
39
|
+
# to a zone NAME (Follow-up quiet hours, the cron scheduler, the doctor).
|
|
40
|
+
require_relative "insika/timezone"
|
|
41
|
+
# the recurring schedule: the five-field cron subset + next-fire
|
|
42
|
+
# materialization, the declaration parse, the per-agent rows, and the
|
|
43
|
+
# tick-driven firer (the recurring half of the tick).
|
|
44
|
+
require_relative "insika/cron"
|
|
45
|
+
require_relative "insika/schedule"
|
|
46
|
+
require_relative "insika/schedule_store"
|
|
47
|
+
require_relative "insika/schedule_engine"
|
|
48
|
+
# the report destination — one record per run, no
|
|
49
|
+
# versioning; the signing half of the sharing link (HMAC, no secret stored).
|
|
50
|
+
require_relative "insika/artifact_store"
|
|
51
|
+
require_relative "insika/artifact_signing"
|
|
30
52
|
require_relative "insika/commands/freeze_funnel_baseline"
|
|
31
53
|
require_relative "insika/channels/webhook"
|
|
32
54
|
require_relative "insika/coercion"
|
|
@@ -81,6 +103,7 @@ require_relative "insika/context/providers/skill"
|
|
|
81
103
|
require_relative "insika/context/providers/skill_trigger"
|
|
82
104
|
require_relative "insika/context/providers/tool_search"
|
|
83
105
|
require_relative "insika/context/providers/memory"
|
|
106
|
+
require_relative "insika/context/providers/knowledge"
|
|
84
107
|
require_relative "insika/context/providers/session"
|
|
85
108
|
require_relative "insika/context/providers/briefing"
|
|
86
109
|
# the cache-prefix hash chain + the per-agent cache-hit series.
|
|
@@ -112,6 +135,7 @@ require_relative "insika/outbox_store"
|
|
|
112
135
|
require_relative "insika/shadow_pair_store"
|
|
113
136
|
require_relative "insika/inbound_log"
|
|
114
137
|
require_relative "insika/memory_store"
|
|
138
|
+
require_relative "insika/knowledge_store"
|
|
115
139
|
# the operator-mutation audit trail. After memory_store (no
|
|
116
140
|
# mutual deps). Pure stdlib — `load_guard_spec` stays green.
|
|
117
141
|
require_relative "insika/memory_audit_store"
|
|
@@ -122,6 +146,7 @@ require_relative "insika/skill_store"
|
|
|
122
146
|
require_relative "insika/secret_masking"
|
|
123
147
|
require_relative "insika/tool_store"
|
|
124
148
|
require_relative "insika/tool_trace_store"
|
|
149
|
+
require_relative "insika/tool_usage_report"
|
|
125
150
|
require_relative "insika/context_trace_store"
|
|
126
151
|
# the model-visible payload of one ask + its durable trace —
|
|
127
152
|
# "model-visible means logged" (the conformance suite's reconstruction half).
|
|
@@ -172,6 +197,10 @@ require_relative "insika/evals/runner"
|
|
|
172
197
|
require_relative "insika/evals/report"
|
|
173
198
|
require_relative "insika/evals/baseline"
|
|
174
199
|
require_relative "insika/evals/transport"
|
|
200
|
+
# simulated users: the persona data + the conversation driver.
|
|
201
|
+
# Pure — the persona model is an injected ask, the target rides the Transport.
|
|
202
|
+
require_relative "insika/evals/persona"
|
|
203
|
+
require_relative "insika/evals/simulator"
|
|
175
204
|
# shadow parity: the frozen criterion and the mechanical
|
|
176
205
|
# fold over the pair store (C6). Pure — no store, no provider gem.
|
|
177
206
|
require_relative "insika/parity/criterion"
|
|
@@ -189,6 +218,14 @@ require_relative "insika/refinement/panel"
|
|
|
189
218
|
require_relative "insika/mcp_store"
|
|
190
219
|
require_relative "insika/mcp_http_client"
|
|
191
220
|
require_relative "insika/mcp_tool_ingestor"
|
|
221
|
+
# require "ruby_llm/mcp" itself is LAZY, inside .for — this require_relative only
|
|
222
|
+
# loads the thin factory (see spec/insika/load_guard_spec.rb).
|
|
223
|
+
require_relative "insika/mcp_client"
|
|
224
|
+
# insika/mcp_live_tool (< RubyLLM::Tool) is NOT required here — McpToolRegistry
|
|
225
|
+
# require_relative's it lazily on the 1st instance (turn time), same as
|
|
226
|
+
# OverlayToolRegistry does for tools/data_defined_tool.
|
|
227
|
+
require_relative "insika/mcp_tool_registry"
|
|
228
|
+
require_relative "insika/mcp_json"
|
|
192
229
|
require_relative "insika/system_file_store"
|
|
193
230
|
require_relative "insika/recovery"
|
|
194
231
|
require_relative "insika/command_bus"
|
|
@@ -236,6 +273,13 @@ require_relative "insika/commands/export_customer_memory"
|
|
|
236
273
|
# record; revoke a contact + fall its pending records atomically).
|
|
237
274
|
require_relative "insika/commands/cancel_followup"
|
|
238
275
|
require_relative "insika/commands/revoke_contact"
|
|
276
|
+
# the report destination's Studio mutation — delete one artifact
|
|
277
|
+
# (a bus command, like every Studio mutation).
|
|
278
|
+
require_relative "insika/commands/delete_artifact"
|
|
279
|
+
# in-session compaction (RFC-0044) — the summarizer (pure, injected
|
|
280
|
+
# ask) and the boundary math; the trigger lives in the Executor, the
|
|
281
|
+
# persistence in SessionStore, the read path in the Session provider.
|
|
282
|
+
require_relative "insika/compaction"
|
|
239
283
|
# session distillation — the distiller (pure, injected ask)
|
|
240
284
|
# and the proposal store (proposals + the latched dedup ledger + the
|
|
241
285
|
# per-session distilled marker).
|
|
@@ -259,6 +303,15 @@ require_relative "insika/commands/promote_harvest"
|
|
|
259
303
|
require_relative "insika/commands/rollback_harvest"
|
|
260
304
|
require_relative "insika/commands/reject_harvest"
|
|
261
305
|
require_relative "insika/harvest_engine"
|
|
306
|
+
# post-turn learning — the extractor (pure, injected ask) and the
|
|
307
|
+
# concept format itself (markdown + YAML frontmatter, the SkillCatalog
|
|
308
|
+
# split). The provider touch stays inside ExtractorFactory's lazy ask
|
|
309
|
+
# (load_guard stays green).
|
|
310
|
+
require_relative "insika/knowledge"
|
|
311
|
+
require_relative "insika/commands/backfill_knowledge"
|
|
312
|
+
require_relative "insika/commands/write_concept"
|
|
313
|
+
require_relative "insika/commands/delete_concept"
|
|
314
|
+
require_relative "insika/commands/restore_concept"
|
|
262
315
|
require_relative "insika/commands/upsert_mcp"
|
|
263
316
|
require_relative "insika/commands/delete_mcp"
|
|
264
317
|
require_relative "insika/commands/write_system_file"
|
|
@@ -269,6 +322,14 @@ require_relative "insika/commands/delete_data_tool"
|
|
|
269
322
|
require_relative "insika/commands/restore_data_tool"
|
|
270
323
|
require_relative "insika/commands/import_tools"
|
|
271
324
|
require_relative "insika/commands/import_mcp_tools"
|
|
325
|
+
require_relative "insika/commands/refresh_mcp_tools"
|
|
326
|
+
# the demo seed (OSS onboarding): one bundled agent + golden
|
|
327
|
+
# set + the Seeder that populates every loop's stores at once, and its bus
|
|
328
|
+
# adapter for `insika demo:seed` and the Studio's "Seed demo data" button.
|
|
329
|
+
require_relative "insika/demo/agent_attrs"
|
|
330
|
+
require_relative "insika/demo/golden_cases"
|
|
331
|
+
require_relative "insika/demo/seeder"
|
|
332
|
+
require_relative "insika/commands/seed_demo_data"
|
|
272
333
|
require_relative "insika/event_stream"
|
|
273
334
|
require_relative "insika/task_actor"
|
|
274
335
|
require_relative "insika/queue_policy"
|
|
@@ -276,7 +337,9 @@ require_relative "insika/session_actor"
|
|
|
276
337
|
require_relative "insika/skill_catalog"
|
|
277
338
|
require_relative "insika/tool_catalog"
|
|
278
339
|
require_relative "insika/steer_injector"
|
|
340
|
+
require_relative "insika/tool_batch"
|
|
279
341
|
require_relative "insika/loop_detector"
|
|
342
|
+
require_relative "insika/turn_budget"
|
|
280
343
|
require_relative "insika/balloon_splitter"
|
|
281
344
|
require_relative "insika/turn_output"
|
|
282
345
|
require_relative "insika/turn_state"
|
|
@@ -290,6 +353,7 @@ require_relative "insika/shutdown"
|
|
|
290
353
|
require_relative "insika/tick"
|
|
291
354
|
require_relative "insika/pack"
|
|
292
355
|
require_relative "insika/pack_importer"
|
|
356
|
+
require_relative "insika/templates"
|
|
293
357
|
require_relative "insika/telemetry"
|
|
294
358
|
# Strict config + diagnosis. Doctor reads the config stores above;
|
|
295
359
|
# EnvSchema (required at the top) is its env layer.
|