insika 0.1.0 → 0.3.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 +199 -5
- data/README.md +8 -2
- data/bin/insika +231 -13
- data/docs/AGENTS.md +505 -6
- data/docs/API.md +56 -0
- data/docs/CHANNELS.md +100 -10
- data/docs/CONTEXT.md +147 -19
- data/docs/DEPLOY.md +34 -11
- data/docs/EMBEDDING.md +11 -7
- data/docs/EVALS.md +20 -1
- data/docs/FACTS.md +135 -0
- data/docs/HARVEST.md +117 -0
- data/docs/LOADTEST.md +17 -10
- data/docs/OBSERVABILITY.md +65 -2
- data/docs/REFINEMENT.md +9 -9
- data/docs/RELEASING.md +34 -7
- data/docs/RUNNING-LOCAL.md +4 -4
- data/docs/SECURITY.md +85 -11
- data/docs/SKILLS.md +189 -3
- data/docs/SOAK.md +127 -0
- data/docs/TOOLS.md +70 -2
- data/docs/WHY.md +1 -1
- data/docs/WORKFLOWS.md +2 -2
- data/docs/domain.md +115 -0
- data/docs/index.md +2 -2
- data/docs/onboarding/start.md +1 -1
- data/lib/insika/agent_profile.rb +228 -26
- data/lib/insika/alert_dispatcher.rb +139 -0
- data/lib/insika/balloon_splitter.rb +102 -0
- data/lib/insika/baseline_store.rb +2 -2
- data/lib/insika/budget_ledger.rb +166 -0
- data/lib/insika/cache_series_store.rb +49 -0
- data/lib/insika/channel_delivery.rb +132 -24
- data/lib/insika/channel_registry.rb +1 -1
- data/lib/insika/channels/relay.rb +80 -6
- data/lib/insika/channels/web/widget.js +2 -2
- data/lib/insika/channels/web.rb +9 -9
- data/lib/insika/channels/webhook.rb +58 -0
- data/lib/insika/chat_builder.rb +145 -13
- data/lib/insika/checkpoint_store.rb +16 -0
- data/lib/insika/circuit_state.rb +114 -0
- data/lib/insika/coercion.rb +8 -0
- data/lib/insika/commands/agent_payload.rb +6 -4
- data/lib/insika/commands/cancel_followup.rb +49 -0
- data/lib/insika/commands/create_agent.rb +2 -2
- data/lib/insika/commands/create_session.rb +1 -1
- data/lib/insika/commands/delete_llm_provider.rb +1 -1
- data/lib/insika/commands/delete_skill.rb +43 -0
- data/lib/insika/commands/delete_tenant_data.rb +95 -0
- data/lib/insika/commands/export_customer_memory.rb +48 -0
- data/lib/insika/commands/forget_customer.rb +117 -0
- data/lib/insika/commands/freeze_funnel_baseline.rb +113 -0
- data/lib/insika/commands/gate_harvest.rb +138 -0
- data/lib/insika/commands/gate_refinement.rb +12 -12
- data/lib/insika/commands/import_mcp_tools.rb +1 -1
- data/lib/insika/commands/import_tools.rb +4 -4
- data/lib/insika/commands/issue_tenant_token.rb +41 -0
- data/lib/insika/commands/judge_shadow_pairs.rb +124 -0
- data/lib/insika/commands/memory_forget_fact.rb +20 -4
- data/lib/insika/commands/memory_put_fact.rb +23 -4
- data/lib/insika/commands/promote_harvest.rb +130 -0
- data/lib/insika/commands/record_outcome.rb +46 -0
- data/lib/insika/commands/record_shadow_reply.rb +68 -0
- data/lib/insika/commands/reject_harvest.rb +38 -0
- data/lib/insika/commands/resolve_proposal.rb +108 -0
- data/lib/insika/commands/resolve_refinement.rb +1 -1
- data/lib/insika/commands/revoke_contact.rb +49 -0
- data/lib/insika/commands/revoke_token.rb +39 -0
- data/lib/insika/commands/rollback_harvest.rb +86 -0
- data/lib/insika/commands/rotate_tenant_token.rb +43 -0
- data/lib/insika/commands/run_distillation.rb +186 -0
- data/lib/insika/commands/run_harvest.rb +393 -0
- data/lib/insika/commands/run_refinement.rb +5 -5
- data/lib/insika/commands/send_message.rb +112 -15
- data/lib/insika/commands/session_purge.rb +67 -0
- data/lib/insika/commands/set_agent_tools.rb +1 -1
- data/lib/insika/commands/set_skill_agents.rb +60 -19
- data/lib/insika/commands/trigger_workflow.rb +1 -1
- data/lib/insika/commands/update_agent.rb +1 -1
- data/lib/insika/commands/write_data_tool.rb +1 -1
- data/lib/insika/commands/write_golden.rb +1 -1
- data/lib/insika/commands/write_skill.rb +19 -9
- data/lib/insika/config_store.rb +8 -4
- data/lib/insika/contact_store.rb +183 -0
- data/lib/insika/context/builder.rb +23 -5
- data/lib/insika/context/fragment.rb +31 -3
- data/lib/insika/context/priority.rb +6 -2
- data/lib/insika/context/provider.rb +17 -3
- data/lib/insika/context/providers/briefing.rb +96 -0
- data/lib/insika/context/providers/memory.rb +16 -7
- data/lib/insika/context/providers/prompt.rb +30 -2
- data/lib/insika/context/providers/request.rb +1 -1
- data/lib/insika/context/providers/session.rb +17 -2
- data/lib/insika/context/providers/skill.rb +7 -1
- data/lib/insika/context/providers/skill_trigger.rb +128 -0
- data/lib/insika/context/providers/tool_search.rb +2 -0
- data/lib/insika/context_trace_store.rb +128 -0
- data/lib/insika/delegation_store.rb +2 -2
- data/lib/insika/distill.rb +224 -0
- data/lib/insika/distill_engine.rb +169 -0
- data/lib/insika/doctor.rb +962 -7
- data/lib/insika/dsl/runtime.rb +20 -11
- data/lib/insika/dsl/server_boot.rb +74 -4
- data/lib/insika/dsl/system.rb +1 -1
- data/lib/insika/dsl.rb +152 -15
- data/lib/insika/edge_limiter.rb +167 -8
- data/lib/insika/egress_guard.rb +3 -3
- data/lib/insika/env_schema.rb +22 -12
- data/lib/insika/errors.rb +72 -5
- data/lib/insika/evals/assertions.rb +15 -14
- data/lib/insika/evals/baseline.rb +3 -3
- data/lib/insika/evals/golden.rb +8 -8
- data/lib/insika/evals/judge.rb +7 -7
- data/lib/insika/evals/pairwise.rb +21 -9
- data/lib/insika/evals/report.rb +2 -2
- data/lib/insika/evals/runner.rb +6 -6
- data/lib/insika/evals/transport.rb +2 -2
- data/lib/insika/event_stream.rb +23 -5
- data/lib/insika/evidence.rb +183 -0
- data/lib/insika/executor.rb +1092 -160
- data/lib/insika/followup_engine.rb +207 -0
- data/lib/insika/followup_policy.rb +221 -0
- data/lib/insika/followup_store.rb +306 -0
- data/lib/insika/frontmatter.rb +1 -1
- data/lib/insika/funnel_declaration.rb +106 -0
- data/lib/insika/funnel_fold.rb +179 -0
- data/lib/insika/funnel_store.rb +163 -0
- data/lib/insika/golden_store.rb +3 -3
- data/lib/insika/grounding/matcher.rb +69 -0
- data/lib/insika/grounding.rb +44 -0
- data/lib/insika/harvest/conversion_gate.rb +159 -0
- data/lib/insika/harvest/criterion.rb +98 -0
- data/lib/insika/harvest/gate.rb +194 -0
- data/lib/insika/harvest/negative_list.rb +199 -0
- data/lib/insika/harvest.rb +241 -0
- data/lib/insika/harvest_engine.rb +193 -0
- data/lib/insika/harvest_store.rb +548 -0
- data/lib/insika/http_client.rb +3 -3
- data/lib/insika/inbound_log.rb +1 -1
- data/lib/insika/llm_configurator.rb +3 -3
- data/lib/insika/loop_detector.rb +143 -0
- data/lib/insika/mcp_http_client.rb +4 -4
- data/lib/insika/mcp_tool_ingestor.rb +6 -6
- data/lib/insika/media.rb +298 -0
- data/lib/insika/memory_audit_store.rb +85 -0
- data/lib/insika/memory_store.rb +264 -23
- data/lib/insika/message_origin.rb +8 -3
- data/lib/insika/model_resolver.rb +1 -1
- data/lib/insika/model_selection.rb +5 -4
- data/lib/insika/model_visible.rb +87 -0
- data/lib/insika/model_visible_trace_store.rb +66 -0
- data/lib/insika/onboarding.rb +8 -3
- data/lib/insika/outbox_store.rb +44 -6
- data/lib/insika/outcome_store.rb +147 -0
- data/lib/insika/overlay_tool_registry.rb +3 -4
- data/lib/insika/pack.rb +3 -3
- data/lib/insika/pack_importer.rb +17 -15
- data/lib/insika/packaging.rb +163 -0
- data/lib/insika/parity/criterion.rb +79 -0
- data/lib/insika/parity/verdict.rb +318 -0
- data/lib/insika/pending_action_store.rb +1 -1
- data/lib/insika/plugin/loader.rb +2 -2
- data/lib/insika/policy/policy.rb +1 -1
- data/lib/insika/prefix_fingerprint.rb +58 -0
- data/lib/insika/profile_source.rb +34 -7
- data/lib/insika/proposal_store.rb +271 -0
- data/lib/insika/provider_error_classifier.rb +160 -0
- data/lib/insika/queue_policy.rb +6 -3
- data/lib/insika/recovery.rb +47 -6
- data/lib/insika/refinement/candidate.rb +4 -4
- data/lib/insika/refinement/evidence_collector.rb +6 -6
- data/lib/insika/refinement/gate.rb +7 -7
- data/lib/insika/refinement/panel.rb +7 -7
- data/lib/insika/refinement/proposer.rb +10 -10
- data/lib/insika/refinement_store.rb +12 -12
- data/lib/insika/reliability.rb +211 -0
- data/lib/insika/retention.rb +281 -0
- data/lib/insika/routing.rb +101 -0
- data/lib/insika/safety/config.rb +46 -6
- data/lib/insika/safety/corpus.rb +255 -0
- data/lib/insika/safety/detectors.rb +34 -115
- data/lib/insika/safety/factory.rb +18 -5
- data/lib/insika/safety/grounding_enforcer.rb +59 -0
- data/lib/insika/safety/grounding_validator.rb +49 -0
- data/lib/insika/safety/input_guardrail.rb +20 -5
- data/lib/insika/safety/moderator.rb +19 -11
- data/lib/insika/safety/output_filter.rb +10 -6
- data/lib/insika/safety/output_validator.rb +13 -7
- data/lib/insika/safety/safe_responses.rb +1 -1
- data/lib/insika/sandbox/boundary.rb +2 -2
- data/lib/insika/sandbox.rb +1 -1
- data/lib/insika/schema_guard.rb +35 -0
- data/lib/insika/server/app.rb +366 -54
- data/lib/insika/server/boot.rb +4 -4
- data/lib/insika/server/rack_app.rb +31 -7
- data/lib/insika/server/responses.rb +58 -9
- data/lib/insika/server/tenant_auth.rb +61 -0
- data/lib/insika/session_actor.rb +11 -7
- data/lib/insika/session_store.rb +66 -3
- data/lib/insika/settings_store.rb +15 -5
- data/lib/insika/shadow_pair_store.rb +258 -0
- data/lib/insika/shutdown.rb +4 -4
- data/lib/insika/skill_catalog.rb +131 -20
- data/lib/insika/skill_store.rb +70 -22
- data/lib/insika/soak/envelope.rb +140 -0
- data/lib/insika/soak/report.rb +392 -0
- data/lib/insika/soak/runner.rb +554 -0
- data/lib/insika/steer_injector.rb +1 -1
- data/lib/insika/store.rb +11 -2
- data/lib/insika/stores/memory.rb +6 -0
- data/lib/insika/stores/sqlite.rb +8 -0
- data/lib/insika/studio/app.rb +1058 -75
- data/lib/insika/studio/assets/dist/application.css +1 -1
- data/lib/insika/studio/assets/dist/application.js +27 -26
- data/lib/insika/studio/assets/dist/favicon.svg +6 -0
- data/lib/insika/studio/forms.rb +274 -22
- data/lib/insika/studio/nav_icons.rb +7 -2
- data/lib/insika/studio/views/_message.erb +2 -2
- data/lib/insika/studio/views/agent_detail.erb +629 -86
- data/lib/insika/studio/views/agents.erb +11 -7
- data/lib/insika/studio/views/approvals.erb +4 -1
- data/lib/insika/studio/views/chats.erb +4 -1
- data/lib/insika/studio/views/customer.erb +94 -0
- data/lib/insika/studio/views/customers.erb +32 -0
- data/lib/insika/studio/views/evals.erb +4 -1
- data/lib/insika/studio/views/facts.erb +133 -0
- data/lib/insika/studio/views/followups.erb +125 -0
- data/lib/insika/studio/views/funnel.erb +106 -0
- data/lib/insika/studio/views/harvest.erb +234 -0
- data/lib/insika/studio/views/home.erb +2 -1
- data/lib/insika/studio/views/layout.erb +1 -0
- data/lib/insika/studio/views/parity.erb +147 -0
- data/lib/insika/studio/views/playground.erb +7 -1
- data/lib/insika/studio/views/refinement.erb +4 -4
- data/lib/insika/studio/views/session.erb +133 -3
- data/lib/insika/studio/views/settings.erb +9 -12
- data/lib/insika/studio/views/skills.erb +66 -12
- data/lib/insika/studio/views/system_files.erb +1 -1
- data/lib/insika/studio/views/task.erb +13 -0
- data/lib/insika/studio/views/tasks.erb +4 -1
- data/lib/insika/studio/views/tools.erb +0 -1
- data/lib/insika/subagent_graph.rb +3 -3
- data/lib/insika/task_actor.rb +3 -3
- data/lib/insika/task_store.rb +22 -2
- data/lib/insika/telemetry/pricing.rb +3 -3
- data/lib/insika/telemetry/recorder.rb +1 -1
- data/lib/insika/telemetry.rb +2 -2
- data/lib/insika/testing/store_contract.rb +54 -33
- data/lib/insika/tick.rb +146 -0
- data/lib/insika/token_store.rb +168 -0
- data/lib/insika/tool_assembly.rb +5 -5
- data/lib/insika/tool_definition.rb +25 -15
- data/lib/insika/tool_envelope.rb +70 -1
- data/lib/insika/tool_manifest.rb +11 -7
- data/lib/insika/tool_output_compressor.rb +100 -0
- data/lib/insika/tool_store.rb +1 -1
- data/lib/insika/tool_trace_store.rb +1 -1
- data/lib/insika/tools/concurrency.rb +2 -2
- data/lib/insika/tools/data_defined_tool.rb +14 -5
- data/lib/insika/tools/generate_image.rb +44 -0
- data/lib/insika/tools/load_skill.rb +61 -3
- data/lib/insika/tools/schedule_followup.rb +164 -0
- data/lib/insika/tools/stuck_signal.rb +44 -0
- data/lib/insika/tools/subagent.rb +4 -4
- data/lib/insika/tools/subagents.rb +1 -1
- data/lib/insika/tools/tts.rb +47 -0
- data/lib/insika/tools/update_briefing.rb +126 -0
- data/lib/insika/turn_output.rb +2 -2
- data/lib/insika/turn_state.rb +54 -13
- data/lib/insika/turn_timing.rb +24 -4
- data/lib/insika/usage_ledger.rb +1 -1
- data/lib/insika/version.rb +1 -1
- data/lib/insika/vitals.rb +84 -0
- data/lib/insika/wiring/graph.rb +372 -34
- data/lib/insika/workflow.rb +1 -1
- data/lib/insika/workflow_registry.rb +1 -1
- data/lib/insika.rb +122 -16
- metadata +95 -2
- data/lib/insika/server/admin_auth.rb +0 -29
data/lib/insika/wiring/graph.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Insika
|
|
4
4
|
module Wiring
|
|
5
|
-
# SHARED composition core for both roots
|
|
5
|
+
# SHARED composition core for both roots: the minimal wiring
|
|
6
6
|
# (config/wiring.rb) and the concrete deployment (config/deployment.rb) were two
|
|
7
7
|
# near-identical composition roots. The duplication — backend→stores, event
|
|
8
8
|
# stream, registries + policy builtins, capability registry, hooks, the Executor,
|
|
@@ -28,7 +28,14 @@ module Insika
|
|
|
28
28
|
db && !db.empty? ? Insika::Stores::SQLite.new(path: db) : Insika::Stores::Memory.new
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
#
|
|
31
|
+
# an integer tick knob from the env, nil when unset (the caller's
|
|
32
|
+
# default wins). Dual-read honors the deprecated HARNESS_* alias.
|
|
33
|
+
def tick_env(name, env = ENV)
|
|
34
|
+
value = Insika::EnvSchema.read(name, env)
|
|
35
|
+
value&.to_i
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# the infra spine that is IDENTICAL across roots. `extra_policy_
|
|
32
39
|
# builtins` covers the one real divergence (the minimal wiring also registers
|
|
33
40
|
# :workflow_allowlist; the deployment does not expose workflows).
|
|
34
41
|
def spine(backend:, extra_policy_builtins: {})
|
|
@@ -38,17 +45,54 @@ module Insika
|
|
|
38
45
|
pending_action_store = Insika::PendingActionStore.new(store: backend)
|
|
39
46
|
delegation_store = Insika::DelegationStore.new(store: backend)
|
|
40
47
|
memory_store = Insika::MemoryStore.new(store: backend)
|
|
41
|
-
#
|
|
48
|
+
# the append-only, content-free audit of OPERATOR memory
|
|
49
|
+
# mutations. Built unconditionally (empty and free when nothing writes)
|
|
50
|
+
# so a deployment that turns it on later finds its audit already durable.
|
|
51
|
+
memory_audit_store = Insika::MemoryAuditStore.new(store: backend)
|
|
52
|
+
token_store = Insika::TokenStore.new(store: backend)
|
|
53
|
+
budget_ledger = Insika::BudgetLedger.new(store: backend)
|
|
54
|
+
circuit_state = Insika::CircuitState.new(store: backend)
|
|
55
|
+
# the two durable halves of a Shape B channel — the
|
|
42
56
|
# replies still owed to a platform, and the retry window that stops a
|
|
43
57
|
# redelivered webhook from becoming a second turn. Built unconditionally
|
|
44
58
|
# (they are empty and free when no channel is registered) so a deployment
|
|
45
59
|
# that turns a channel on later finds its state already durable.
|
|
46
60
|
outbox_store = Insika::OutboxStore.new(store: backend)
|
|
61
|
+
# the shadow pair store — one durable record per mirrored
|
|
62
|
+
# exchange, written by our half and the incumbent's. Built unconditionally
|
|
63
|
+
# (empty and free when shadow is off) so turning it on later finds the
|
|
64
|
+
# state already durable, beside the outbox on the same runtime backend.
|
|
65
|
+
shadow_pair_store = Insika::ShadowPairStore.new(store: backend)
|
|
47
66
|
inbound_log = Insika::InboundLog.new(store: backend)
|
|
48
|
-
#
|
|
67
|
+
# WS7: business outcomes per conversation, recorded by the operator or
|
|
68
|
+
# the integration (POST /v1/outcomes). Built unconditionally (empty and
|
|
69
|
+
# free when nothing records) so the Studio's scorecard always has a store.
|
|
70
|
+
outcome_store = Insika::OutcomeStore.new(store: backend)
|
|
71
|
+
# the funnel's durable aggregates — per-day stage counts,
|
|
72
|
+
# fold cursors and baseline snapshots. Built unconditionally (empty and
|
|
73
|
+
# free when no pack declares a funnel) so the fold, the doctor and the
|
|
74
|
+
# Studio always have a store to read/write.
|
|
75
|
+
funnel_store = Insika::FunnelStore.new(store: backend)
|
|
76
|
+
# the contact-state cells and the follow-up schedule
|
|
77
|
+
# records. Built unconditionally (empty and free when no pack declares
|
|
78
|
+
# followup) so the engine, the tools and the Studio always have stores.
|
|
79
|
+
contact_store = Insika::ContactStore.new(store: backend)
|
|
80
|
+
followup_store = Insika::FollowupStore.new(store: backend)
|
|
81
|
+
# the distilled proposals + the latched dedup ledger +
|
|
82
|
+
# the per-session markers. Built unconditionally (empty and free when
|
|
83
|
+
# no pack declares distill) so the wiki, the engine and the LGPD
|
|
84
|
+
# purges always have a store.
|
|
85
|
+
proposal_store = Insika::ProposalStore.new(store: backend)
|
|
86
|
+
# refinement RUNS (reports over real traffic). Runtime data,
|
|
49
87
|
# same backend as sessions/tasks — the collector and the command that write it
|
|
50
88
|
# are the root's business (deployment-only, like the memory commands).
|
|
51
89
|
refinement_store = Insika::RefinementStore.new(store: backend)
|
|
90
|
+
# the harvest's durable half — mining runs, the per-
|
|
91
|
+
# candidate lifecycle, the append-only promotion log, the snapshots
|
|
92
|
+
# and the per-session markers. Built unconditionally (empty and free
|
|
93
|
+
# when no pack declares harvest) so the engine, the Studio and the
|
|
94
|
+
# LGPD purges always have a store.
|
|
95
|
+
harvest_store = Insika::HarvestStore.new(store: backend)
|
|
52
96
|
|
|
53
97
|
code_tool_registry = Insika::ToolRegistry.new
|
|
54
98
|
workflow_registry = Insika::WorkflowRegistry.new
|
|
@@ -64,8 +108,17 @@ module Insika
|
|
|
64
108
|
session_store: session_store, task_store: task_store,
|
|
65
109
|
checkpoint_store: checkpoint_store, pending_action_store: pending_action_store,
|
|
66
110
|
delegation_store: delegation_store,
|
|
67
|
-
memory_store: memory_store,
|
|
68
|
-
|
|
111
|
+
memory_store: memory_store, memory_audit_store: memory_audit_store,
|
|
112
|
+
refinement_store: refinement_store,
|
|
113
|
+
harvest_store: harvest_store,
|
|
114
|
+
token_store: token_store, budget_ledger: budget_ledger, circuit_state: circuit_state,
|
|
115
|
+
outbox_store: outbox_store, shadow_pair_store: shadow_pair_store,
|
|
116
|
+
inbound_log: inbound_log,
|
|
117
|
+
outcome_store: outcome_store,
|
|
118
|
+
funnel_store: funnel_store,
|
|
119
|
+
contact_store: contact_store,
|
|
120
|
+
followup_store: followup_store,
|
|
121
|
+
proposal_store: proposal_store,
|
|
69
122
|
code_tool_registry: code_tool_registry,
|
|
70
123
|
workflow_registry: workflow_registry, policy_registry: policy_registry,
|
|
71
124
|
capability_registry: Insika::CapabilityRegistry.new, hooks: Insika::Hooks.new,
|
|
@@ -73,16 +126,16 @@ module Insika
|
|
|
73
126
|
)
|
|
74
127
|
end
|
|
75
128
|
|
|
76
|
-
#
|
|
129
|
+
# assemble the graph on top of a spine.
|
|
77
130
|
#
|
|
78
131
|
# tool_registry: effective registry the Executor uses (plain REGISTRY at the
|
|
79
132
|
# base; OverlayToolRegistry in the deployment).
|
|
80
133
|
# guardrails: a Safety::Factory — its input_guardrail becomes the single
|
|
81
134
|
# middleware and its output_validator the after-task hook, so
|
|
82
|
-
# both wirings compose
|
|
135
|
+
# both wirings compose identically.
|
|
83
136
|
# executor_extra: optional Executor kwargs a root adds (deployment passes
|
|
84
137
|
# settings_store + tool_trace_store; the base passes none).
|
|
85
|
-
# edge_limiter: optional EdgeLimiter
|
|
138
|
+
# edge_limiter: optional EdgeLimiter. It goes BEFORE
|
|
86
139
|
# the InputGuardrail so a flood can't spend the LLM
|
|
87
140
|
# moderator; nil = no edge (parity).
|
|
88
141
|
def build(spine:, profiles:, tool_registry:, tool_catalog:, skill_catalog:,
|
|
@@ -98,39 +151,171 @@ module Insika
|
|
|
98
151
|
policy_registry: spine.policy_registry, event_stream: spine.event_stream
|
|
99
152
|
)
|
|
100
153
|
|
|
101
|
-
#
|
|
154
|
+
# Always built: the registry starts empty, so `record` finds no
|
|
102
155
|
# channel and returns nil on every turn — the cost of wiring it is one nil
|
|
103
156
|
# check per completed turn, and the alternative is a second wiring path that
|
|
104
157
|
# only production exercises.
|
|
105
158
|
channel_delivery = Insika::ChannelDelivery.new(
|
|
106
159
|
channels: spine.channel_registry, outbox: spine.outbox_store,
|
|
107
|
-
session_store: spine.session_store, event_stream: spine.event_stream
|
|
160
|
+
session_store: spine.session_store, event_stream: spine.event_stream,
|
|
161
|
+
shadow_pairs: spine.shadow_pair_store
|
|
108
162
|
)
|
|
109
163
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
164
|
+
# WS3 provider reliability (retries/backoff/fallback/breaker) is ALWAYS wired —
|
|
165
|
+
# the profile's `reliability` data gates it, so the bare wiring is unchanged.
|
|
166
|
+
reliability = Insika::Reliability.new(circuit_store: spine.circuit_state,
|
|
167
|
+
event_stream: spine.event_stream)
|
|
168
|
+
executor = Insika::Executor.new(
|
|
169
|
+
context_builder: context_builder, policy_engine: policy_engine,
|
|
170
|
+
middleware: middleware, hooks: spine.hooks,
|
|
171
|
+
tool_registry: tool_registry, skill_catalog: skill_catalog, profiles: profiles,
|
|
172
|
+
session_store: spine.session_store, task_store: spine.task_store,
|
|
173
|
+
checkpoint_store: spine.checkpoint_store, event_stream: spine.event_stream,
|
|
174
|
+
workflow_registry: spine.workflow_registry, pending_action_store: spine.pending_action_store,
|
|
175
|
+
capability_registry: spine.capability_registry, tool_catalog: tool_catalog,
|
|
176
|
+
memory_store: spine.memory_store,
|
|
177
|
+
content_filter_factory: guardrails.content_filter_factory, # stream redaction
|
|
178
|
+
delegation_store: spine.delegation_store, # async delegation durability
|
|
179
|
+
channel_delivery: channel_delivery, # out-of-band reply delivery
|
|
180
|
+
reliability: reliability, # WS3: retries/fallback/breaker (data-gated)
|
|
181
|
+
grounding_enforcer: guardrails.grounding_enforcer, # :enforce cut
|
|
182
|
+
# the follow-up stores — the ChatBuilder wires the
|
|
183
|
+
# schedule/cancel_followup tools on them (parity when no pack declares).
|
|
184
|
+
contact_store: spine.contact_store,
|
|
185
|
+
followup_store: spine.followup_store,
|
|
186
|
+
# the model-visible trace rides executor_extra like the
|
|
187
|
+
# context trace — a module graph that omits it still builds (nil =
|
|
188
|
+
# parity). The base graph wires it over the same backend the context
|
|
189
|
+
# trace uses.
|
|
190
|
+
model_visible_trace_store: Insika::ModelVisibleTraceStore.new(store: spine.backend),
|
|
191
|
+
**executor_extra
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# the ONE path that writes proposals, shared by the
|
|
195
|
+
# automatic DistillEngine loop and the bus command behind the Studio's
|
|
196
|
+
# "Run distillation now" button (one code path for both).
|
|
197
|
+
run_distillation = Insika::Commands::RunDistillation.new(
|
|
198
|
+
profiles: profiles, proposal_store: spine.proposal_store,
|
|
199
|
+
session_store: spine.session_store, memory_store: spine.memory_store,
|
|
200
|
+
settings_store: executor_extra[:settings_store],
|
|
201
|
+
event_stream: spine.event_stream
|
|
123
202
|
)
|
|
124
203
|
|
|
125
|
-
bus = build_core_bus(spine: spine, profiles: profiles, executor: executor
|
|
204
|
+
bus = build_core_bus(spine: spine, profiles: profiles, executor: executor,
|
|
205
|
+
executor_extra: executor_extra, skill_catalog: skill_catalog,
|
|
206
|
+
run_distillation: run_distillation)
|
|
207
|
+
|
|
208
|
+
# the periodic tick (outbox drain + stale recovery sweep). Built
|
|
209
|
+
# here, after the bus, because its recovery half dispatches resume_task
|
|
210
|
+
# through it; handed to the Executor, which starts it as a child of the
|
|
211
|
+
# turn supervisor in serving mode. `INSIKA_TICK_INTERVAL=0` disables.
|
|
212
|
+
# WS8 retention rides the tick: always built, the settings knob
|
|
213
|
+
# (`retention_days`) gates it — the base graph (no settings_store)
|
|
214
|
+
# reads as OFF.
|
|
215
|
+
executor.tick = Insika::Tick.new(
|
|
216
|
+
store: spine.backend, channel_delivery: channel_delivery,
|
|
217
|
+
recovery: Insika::Recovery.new(
|
|
218
|
+
task_store: spine.task_store, checkpoint_store: spine.checkpoint_store, command_bus: bus
|
|
219
|
+
),
|
|
220
|
+
retention: Insika::Retention.new(
|
|
221
|
+
store: spine.backend, session_store: spine.session_store,
|
|
222
|
+
task_store: spine.task_store, checkpoint_store: spine.checkpoint_store,
|
|
223
|
+
memory_store: spine.memory_store, outcome_store: spine.outcome_store,
|
|
224
|
+
tool_trace_store: executor_extra[:tool_trace_store],
|
|
225
|
+
context_trace_store: executor_extra[:context_trace_store],
|
|
226
|
+
# the model-visible traces die with their checkpoints.
|
|
227
|
+
model_visible_trace_store: Insika::ModelVisibleTraceStore.new(store: spine.backend),
|
|
228
|
+
outbox_store: spine.outbox_store,
|
|
229
|
+
shadow_pair_store: spine.shadow_pair_store,
|
|
230
|
+
settings_store: executor_extra[:settings_store],
|
|
231
|
+
budget_ledger: spine.budget_ledger, # WS2 counter GC (retention-independent)
|
|
232
|
+
funnel_store: spine.funnel_store, # fold dies with its source
|
|
233
|
+
followup_store: spine.followup_store, # records age out too
|
|
234
|
+
contact_store: spine.contact_store, # cells age out too
|
|
235
|
+
proposal_store: spine.proposal_store, # proposals age out too
|
|
236
|
+
harvest_store: spine.harvest_store # candidates/log/snapshots too
|
|
237
|
+
),
|
|
238
|
+
interval: tick_env("INSIKA_TICK_INTERVAL") || Insika::Tick::DEFAULT_INTERVAL,
|
|
239
|
+
stale_after: tick_env("INSIKA_TICK_STALE_AFTER") || Insika::Tick::DEFAULT_STALE_AFTER
|
|
240
|
+
)
|
|
241
|
+
# the tick-driven outcome fold — wired here, after the
|
|
242
|
+
# Tick, because it reads the outcome/funnel stores of the spine and the
|
|
243
|
+
# profiles; the per-pair declaration gates it (nil funnel everywhere =
|
|
244
|
+
# an inert fold). Always built: a pack that declares a funnel later
|
|
245
|
+
# finds its fold already on the tick.
|
|
246
|
+
executor.tick.funnel = Insika::FunnelFold.new(
|
|
247
|
+
outcome_store: spine.outcome_store, funnel_store: spine.funnel_store,
|
|
248
|
+
profiles: profiles, store: spine.backend
|
|
249
|
+
)
|
|
250
|
+
# the tick-driven follow-up firer — the tick's third
|
|
251
|
+
# duty, wired here after the Tick, gated by its own claim window.
|
|
252
|
+
# Always built: a pack that declares followup later finds its firer
|
|
253
|
+
# already on the tick (inert when no profile declares followup).
|
|
254
|
+
executor.tick.followup = Insika::FollowupEngine.new(
|
|
255
|
+
store: spine.backend, followup_store: spine.followup_store,
|
|
256
|
+
contact_store: spine.contact_store, task_store: spine.task_store,
|
|
257
|
+
profiles: profiles, executor: executor, event_stream: spine.event_stream
|
|
258
|
+
)
|
|
259
|
+
# the distillation engine — the tick-duty that finds idle
|
|
260
|
+
# customer sessions and distills them on its own worker fiber (a
|
|
261
|
+
# supervisor child, started in serving mode next to the tick).
|
|
262
|
+
# Always built: a pack that declares `distill:` later finds its engine
|
|
263
|
+
# already wired — and INERT until one does (the engine gates its start
|
|
264
|
+
# and its passes on a declaring profile).
|
|
265
|
+
executor.distill_engine = Insika::DistillEngine.new(
|
|
266
|
+
store: spine.backend, proposal_store: spine.proposal_store,
|
|
267
|
+
session_store: spine.session_store,
|
|
268
|
+
runner: run_distillation,
|
|
269
|
+
profiles: profiles,
|
|
270
|
+
window: Insika::DistillEngine::DEFAULT_WINDOW
|
|
271
|
+
)
|
|
272
|
+
# the harvest engine — the tick-duty that finds idle,
|
|
273
|
+
# unmined sessions whose agent declares `harvest.enabled` and mines
|
|
274
|
+
# them on its own worker fiber (a supervisor child, started in serving
|
|
275
|
+
# mode next to the tick). Always built: INERT until a profile declares
|
|
276
|
+
# harvest (the engine gates its start and its passes on data). The
|
|
277
|
+
# runner is the same RunHarvest the bus serves, so the manual CLI and
|
|
278
|
+
# the automated loop share one code path.
|
|
279
|
+
run_harvest = Insika::Commands::RunHarvest.new(
|
|
280
|
+
profiles: profiles, harvest_store: spine.harvest_store,
|
|
281
|
+
session_store: spine.session_store, task_store: spine.task_store,
|
|
282
|
+
skill_store: skill_catalog.store, # the harvest's dedup reads the authored skills
|
|
283
|
+
tool_trace_store: executor_extra[:tool_trace_store],
|
|
284
|
+
settings_store: executor_extra[:settings_store],
|
|
285
|
+
negative_list: nil, miner_factory: nil,
|
|
286
|
+
event_stream: spine.event_stream
|
|
287
|
+
)
|
|
288
|
+
executor.harvest_engine = Insika::HarvestEngine.new(
|
|
289
|
+
store: spine.backend, harvest_store: spine.harvest_store,
|
|
290
|
+
session_store: spine.session_store, runner: run_harvest,
|
|
291
|
+
profiles: profiles, window: Insika::HarvestEngine::DEFAULT_WINDOW
|
|
292
|
+
)
|
|
293
|
+
# WS6 operator alerts: answers budget_warning / breaker_open /
|
|
294
|
+
# delivery_failed per agent (`alerts.webhook`) via the outbox+claim
|
|
295
|
+
# pipeline. Always wired — the per-agent data gates it (parity).
|
|
296
|
+
executor.alert_dispatcher = Insika::AlertDispatcher.new(
|
|
297
|
+
event_stream: spine.event_stream, outbox: spine.outbox_store,
|
|
298
|
+
channels: spine.channel_registry, profiles: profiles,
|
|
299
|
+
task_store: spine.task_store, http: Insika::HttpClient.new
|
|
300
|
+
)
|
|
126
301
|
|
|
127
302
|
Graph::Result.new(
|
|
128
303
|
backend: spine.backend, event_stream: spine.event_stream,
|
|
129
304
|
session_store: spine.session_store, task_store: spine.task_store,
|
|
130
305
|
checkpoint_store: spine.checkpoint_store, pending_action_store: spine.pending_action_store,
|
|
131
306
|
delegation_store: spine.delegation_store,
|
|
132
|
-
memory_store: spine.memory_store,
|
|
133
|
-
|
|
307
|
+
memory_store: spine.memory_store, memory_audit_store: spine.memory_audit_store,
|
|
308
|
+
refinement_store: spine.refinement_store,
|
|
309
|
+
harvest_store: spine.harvest_store,
|
|
310
|
+
outbox_store: spine.outbox_store, shadow_pair_store: spine.shadow_pair_store,
|
|
311
|
+
inbound_log: spine.inbound_log,
|
|
312
|
+
outcome_store: spine.outcome_store,
|
|
313
|
+
funnel_store: spine.funnel_store,
|
|
314
|
+
contact_store: spine.contact_store,
|
|
315
|
+
followup_store: spine.followup_store,
|
|
316
|
+
proposal_store: spine.proposal_store,
|
|
317
|
+
token_store: spine.token_store, budget_ledger: spine.budget_ledger,
|
|
318
|
+
circuit_state: spine.circuit_state,
|
|
134
319
|
channel_registry: spine.channel_registry, channel_delivery: channel_delivery,
|
|
135
320
|
code_tool_registry: spine.code_tool_registry,
|
|
136
321
|
tool_registry: tool_registry, workflow_registry: spine.workflow_registry,
|
|
@@ -144,8 +329,9 @@ module Insika
|
|
|
144
329
|
|
|
145
330
|
# The CORE command surface every root needs — turn essentials + the operator
|
|
146
331
|
# controls (pause/approve) the Studio dispatches. Registering pause_task/
|
|
147
|
-
# approve_action HERE is the crux of
|
|
148
|
-
def build_core_bus(spine:, profiles:, executor:
|
|
332
|
+
# approve_action HERE is the crux of: it retires the config.ru:28-34 patch.
|
|
333
|
+
def build_core_bus(spine:, profiles:, executor:, executor_extra: {}, skill_catalog: nil,
|
|
334
|
+
run_distillation: nil)
|
|
149
335
|
bus = Insika::CommandBus.new
|
|
150
336
|
bus.register(:create_session,
|
|
151
337
|
Insika::Commands::CreateSession.new(session_store: spine.session_store, event_stream: spine.event_stream))
|
|
@@ -159,10 +345,154 @@ module Insika
|
|
|
159
345
|
bus.register(:send_message,
|
|
160
346
|
Insika::Commands::SendMessage.new(profiles: profiles, session_store: spine.session_store,
|
|
161
347
|
task_store: spine.task_store, executor: executor,
|
|
162
|
-
inbound_log: spine.inbound_log
|
|
348
|
+
inbound_log: spine.inbound_log,
|
|
349
|
+
contact_store: spine.contact_store,
|
|
350
|
+
followup_store: spine.followup_store,
|
|
351
|
+
store: spine.backend))
|
|
163
352
|
bus.register(:resume_task,
|
|
164
353
|
Insika::Commands::ResumeTask.new(profiles: profiles, task_store: spine.task_store,
|
|
165
354
|
checkpoint_store: spine.checkpoint_store, executor: executor))
|
|
355
|
+
# WS1 multi-tenant credentials: per-tenant + operator tokens, stored as
|
|
356
|
+
# hashes. Operator-only BY CONSTRUCTION — the edge refuses a tenant
|
|
357
|
+
# principal on POST /v1/commands, and the handlers re-check meta.
|
|
358
|
+
bus.register(:issue_tenant_token,
|
|
359
|
+
Insika::Commands::IssueTenantToken.new(token_store: spine.token_store,
|
|
360
|
+
event_stream: spine.event_stream))
|
|
361
|
+
bus.register(:revoke_token,
|
|
362
|
+
Insika::Commands::RevokeToken.new(token_store: spine.token_store,
|
|
363
|
+
event_stream: spine.event_stream))
|
|
364
|
+
bus.register(:rotate_tenant_token,
|
|
365
|
+
Insika::Commands::RotateTenantToken.new(token_store: spine.token_store,
|
|
366
|
+
event_stream: spine.event_stream))
|
|
367
|
+
# WS7: a business outcome per conversation (operator or integration).
|
|
368
|
+
bus.register(:record_outcome,
|
|
369
|
+
Insika::Commands::RecordOutcome.new(outcome_store: spine.outcome_store,
|
|
370
|
+
event_stream: spine.event_stream))
|
|
371
|
+
# the incumbent's half of a shadow pair, one command behind
|
|
372
|
+
# both mirror shapes (the mirror call itself + the follow-up route).
|
|
373
|
+
bus.register(:record_shadow_reply,
|
|
374
|
+
Insika::Commands::RecordShadowReply.new(shadow_pairs: spine.shadow_pair_store,
|
|
375
|
+
event_stream: spine.event_stream))
|
|
376
|
+
# WS8 (LGPD): purge one customer's memory + the whole footprint of their
|
|
377
|
+
# sessions (traces, tasks, checkpoints, outbox). The trace stores are
|
|
378
|
+
# deployment components (nil at the base — skipped). the
|
|
379
|
+
# audit collaborator records a content-free purge line.
|
|
380
|
+
bus.register(:forget_customer,
|
|
381
|
+
Insika::Commands::ForgetCustomer.new(
|
|
382
|
+
memory_store: spine.memory_store, session_store: spine.session_store,
|
|
383
|
+
tool_trace_store: executor_extra[:tool_trace_store],
|
|
384
|
+
context_trace_store: executor_extra[:context_trace_store],
|
|
385
|
+
# the model-visible traces die with the
|
|
386
|
+
# checkpoints (the same SessionPurge list).
|
|
387
|
+
model_visible_trace_store: Insika::ModelVisibleTraceStore.new(store: spine.backend),
|
|
388
|
+
task_store: spine.task_store, checkpoint_store: spine.checkpoint_store,
|
|
389
|
+
outbox_store: spine.outbox_store,
|
|
390
|
+
shadow_pairs: spine.shadow_pair_store,
|
|
391
|
+
audit_store: spine.memory_audit_store,
|
|
392
|
+
followup_store: spine.followup_store,
|
|
393
|
+
contact_store: spine.contact_store,
|
|
394
|
+
proposal_store: spine.proposal_store,
|
|
395
|
+
event_stream: spine.event_stream
|
|
396
|
+
))
|
|
397
|
+
# the LGPD access right — export one customer's memory
|
|
398
|
+
# cell as content (the Studio download); the event stays counts-only.
|
|
399
|
+
bus.register(:export_customer_memory,
|
|
400
|
+
Insika::Commands::ExportCustomerMemory.new(
|
|
401
|
+
memory_store: spine.memory_store, event_stream: spine.event_stream
|
|
402
|
+
))
|
|
403
|
+
# WS8 (LGPD): purge ONE TENANT's data — sessions and their footprint,
|
|
404
|
+
# memory cells and outcomes. Operator-only by construction (ingress).
|
|
405
|
+
bus.register(:delete_tenant_data,
|
|
406
|
+
Insika::Commands::DeleteTenantData.new(
|
|
407
|
+
memory_store: spine.memory_store, session_store: spine.session_store,
|
|
408
|
+
tool_trace_store: executor_extra[:tool_trace_store],
|
|
409
|
+
context_trace_store: executor_extra[:context_trace_store],
|
|
410
|
+
# the model-visible traces die with the tenant.
|
|
411
|
+
model_visible_trace_store: Insika::ModelVisibleTraceStore.new(store: spine.backend),
|
|
412
|
+
outcome_store: spine.outcome_store,
|
|
413
|
+
funnel_store: spine.funnel_store, # the fold dies with the tenant
|
|
414
|
+
followup_store: spine.followup_store,
|
|
415
|
+
contact_store: spine.contact_store,
|
|
416
|
+
proposal_store: spine.proposal_store,
|
|
417
|
+
harvest_store: spine.harvest_store,
|
|
418
|
+
task_store: spine.task_store, checkpoint_store: spine.checkpoint_store,
|
|
419
|
+
outbox_store: spine.outbox_store,
|
|
420
|
+
shadow_pairs: spine.shadow_pair_store,
|
|
421
|
+
token_store: spine.token_store, # revoked BEFORE the sweep
|
|
422
|
+
event_stream: spine.event_stream
|
|
423
|
+
))
|
|
424
|
+
# the operator's baseline freeze — the number
|
|
425
|
+
# read. Synchronous control command, dispatched from the Studio.
|
|
426
|
+
bus.register(:freeze_funnel_baseline,
|
|
427
|
+
Insika::Commands::FreezeFunnelBaseline.new(
|
|
428
|
+
funnel_store: spine.funnel_store, profiles: profiles,
|
|
429
|
+
event_stream: spine.event_stream
|
|
430
|
+
))
|
|
431
|
+
# the follow-up mutations — the Studio's Cancel button
|
|
432
|
+
# and the channel opt-out event (a tenant principal never reaches the
|
|
433
|
+
# generic command ingress; these ride the same operator-grade path).
|
|
434
|
+
bus.register(:cancel_followup,
|
|
435
|
+
Insika::Commands::CancelFollowup.new(followup_store: spine.followup_store,
|
|
436
|
+
event_stream: spine.event_stream))
|
|
437
|
+
bus.register(:revoke_contact,
|
|
438
|
+
Insika::Commands::RevokeContact.new(contact_store: spine.contact_store,
|
|
439
|
+
followup_store: spine.followup_store,
|
|
440
|
+
store: spine.backend,
|
|
441
|
+
event_stream: spine.event_stream))
|
|
442
|
+
# the human's answer on a distilled proposal — the ONLY
|
|
443
|
+
# mutation behind the Facts (wiki) page. Synchronous control command.
|
|
444
|
+
bus.register(:resolve_proposal,
|
|
445
|
+
Insika::Commands::ResolveProposal.new(
|
|
446
|
+
proposal_store: spine.proposal_store,
|
|
447
|
+
memory_store: spine.memory_store,
|
|
448
|
+
event_stream: spine.event_stream
|
|
449
|
+
))
|
|
450
|
+
# /C10: the gated harvest — the mining pass, the double
|
|
451
|
+
# gate, the human's promote/rollback/dismiss. The BASE graph wires the
|
|
452
|
+
# nil factories (no eval surface, no criterion, no funnel): every flow
|
|
453
|
+
# refuses with a named reason or skips (parity). The deployment root
|
|
454
|
+
# re-registers with the real gate/criterion/negative list.
|
|
455
|
+
bus.register(:run_harvest,
|
|
456
|
+
Insika::Commands::RunHarvest.new(
|
|
457
|
+
profiles: profiles, harvest_store: spine.harvest_store,
|
|
458
|
+
session_store: spine.session_store, task_store: spine.task_store,
|
|
459
|
+
skill_store: skill_catalog.store,
|
|
460
|
+
tool_trace_store: executor_extra[:tool_trace_store],
|
|
461
|
+
settings_store: executor_extra[:settings_store],
|
|
462
|
+
negative_list: nil, miner_factory: nil,
|
|
463
|
+
event_stream: spine.event_stream
|
|
464
|
+
))
|
|
465
|
+
bus.register(:gate_harvest,
|
|
466
|
+
Insika::Commands::GateHarvest.new(
|
|
467
|
+
harvest_store: spine.harvest_store, gate: nil,
|
|
468
|
+
conversion_gate: nil, criterion: nil,
|
|
469
|
+
event_stream: spine.event_stream
|
|
470
|
+
))
|
|
471
|
+
bus.register(:promote_harvest,
|
|
472
|
+
Insika::Commands::PromoteHarvest.new(
|
|
473
|
+
harvest_store: spine.harvest_store,
|
|
474
|
+
skill_store: skill_catalog.store,
|
|
475
|
+
skill_catalog: skill_catalog,
|
|
476
|
+
profile_source: profiles, criterion: nil, conversion_gate: nil,
|
|
477
|
+
event_stream: spine.event_stream
|
|
478
|
+
))
|
|
479
|
+
bus.register(:rollback_harvest,
|
|
480
|
+
Insika::Commands::RollbackHarvest.new(
|
|
481
|
+
harvest_store: spine.harvest_store,
|
|
482
|
+
skill_store: skill_catalog.store,
|
|
483
|
+
skill_catalog: skill_catalog,
|
|
484
|
+
profile_source: profiles, event_stream: spine.event_stream
|
|
485
|
+
))
|
|
486
|
+
bus.register(:reject_harvest,
|
|
487
|
+
Insika::Commands::RejectHarvest.new(
|
|
488
|
+
harvest_store: spine.harvest_store, event_stream: spine.event_stream
|
|
489
|
+
))
|
|
490
|
+
# the ONE path that writes proposals, served to the
|
|
491
|
+
# Studio's "Run distillation now" button. The same instance the
|
|
492
|
+
# DistillEngine's loop uses, so the manual and the automatic share one
|
|
493
|
+
# code path; the engine keeps the automatic pass when the root does
|
|
494
|
+
# not pass a runner here (nil = the command is not on the bus).
|
|
495
|
+
bus.register(:run_distillation, run_distillation) if run_distillation
|
|
166
496
|
bus
|
|
167
497
|
end
|
|
168
498
|
|
|
@@ -170,9 +500,13 @@ module Insika
|
|
|
170
500
|
# them to their historic public constants (SESSION_STORE, REGISTRY, ...).
|
|
171
501
|
Spine = Struct.new(
|
|
172
502
|
:backend, :event_stream, :session_store, :task_store, :checkpoint_store,
|
|
173
|
-
:pending_action_store, :delegation_store, :memory_store, :
|
|
174
|
-
:
|
|
175
|
-
:
|
|
503
|
+
:pending_action_store, :delegation_store, :memory_store, :memory_audit_store,
|
|
504
|
+
:refinement_store,
|
|
505
|
+
:harvest_store,
|
|
506
|
+
:token_store, :budget_ledger, :circuit_state, :outbox_store, :shadow_pair_store,
|
|
507
|
+
:inbound_log, :outcome_store, :funnel_store,
|
|
508
|
+
:contact_store, :followup_store, :proposal_store,
|
|
509
|
+
:code_tool_registry, :workflow_registry, :policy_registry, :capability_registry, :hooks,
|
|
176
510
|
:channel_registry, keyword_init: true
|
|
177
511
|
)
|
|
178
512
|
|
|
@@ -182,7 +516,11 @@ module Insika
|
|
|
182
516
|
Result = Struct.new(
|
|
183
517
|
:backend, :event_stream,
|
|
184
518
|
:session_store, :task_store, :checkpoint_store, :pending_action_store, :delegation_store,
|
|
185
|
-
:memory_store, :refinement_store, :outbox_store, :
|
|
519
|
+
:memory_store, :memory_audit_store, :refinement_store, :outbox_store, :shadow_pair_store,
|
|
520
|
+
:inbound_log, :token_store,
|
|
521
|
+
:budget_ledger, :circuit_state, :outcome_store, :funnel_store,
|
|
522
|
+
:contact_store, :followup_store, :proposal_store,
|
|
523
|
+
:harvest_store,
|
|
186
524
|
:channel_registry, :channel_delivery,
|
|
187
525
|
:code_tool_registry, :tool_registry, :workflow_registry, :policy_registry, :capability_registry,
|
|
188
526
|
:tool_catalog, :skill_catalog, :prompt_catalog,
|
data/lib/insika/workflow.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Insika
|
|
4
|
-
# Workflow surface (
|
|
4
|
+
# Workflow surface (COMPETITIVE-ANALYSIS). A workflow is a Ruby
|
|
5
5
|
# callable orchestrating RubyLLM Agents/Workflows FROM WITHIN (RubyLLM First);
|
|
6
6
|
# its durable RUN is a Task (checkpointed, recoverable — stronger than Flue's
|
|
7
7
|
# at-most-once run record). This module adds the EXPOSED surface the consumer
|
|
@@ -8,7 +8,7 @@ module Insika
|
|
|
8
8
|
# checkpoint at the end. Nothing is validated at registration (the callable may come
|
|
9
9
|
# via a factory block). Consumed by the TriggerWorkflow handler.
|
|
10
10
|
#
|
|
11
|
-
#
|
|
11
|
+
# — the EXPOSED surface: a registration may carry `input_schema:` /
|
|
12
12
|
# `output_schema:` (a JSON Schema Hash or any dry-schema-compatible validator) and a
|
|
13
13
|
# `description:` in its metadata. `definition` bundles them with the factory into a
|
|
14
14
|
# Workflow::Definition (schemas resolved, factory left lazy); `catalog` is the
|