insika 0.0.1 → 0.1.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 +295 -0
- data/LICENSE +21 -0
- data/README.md +136 -2
- data/bin/insika +351 -0
- data/docs/AGENTS.md +494 -0
- data/docs/ARCHITECTURE.md +333 -0
- data/docs/BENCHMARK.md +114 -0
- data/docs/CHANNELS.md +453 -0
- data/docs/CONTEXT.md +100 -0
- data/docs/DEPLOY.md +334 -0
- data/docs/EMBEDDING.md +194 -0
- data/docs/EVALS.md +273 -0
- data/docs/LOADTEST.md +231 -0
- data/docs/OBSERVABILITY.md +365 -0
- data/docs/PLUGINS.md +211 -0
- data/docs/REFINEMENT.md +477 -0
- data/docs/RELEASING.md +70 -0
- data/docs/RUNNING-LOCAL.md +153 -0
- data/docs/SANDBOX.md +114 -0
- data/docs/SECURITY.md +362 -0
- data/docs/SKILLS.md +98 -0
- data/docs/TOOLS.md +302 -0
- data/docs/WHY.md +137 -0
- data/docs/WORKFLOWS.md +225 -0
- data/docs/build.md +14 -0
- data/docs/index.md +68 -0
- data/docs/onboarding/start.md +126 -0
- data/docs/operate.md +12 -0
- data/docs/ship.md +10 -0
- data/docs/understand.md +10 -0
- data/lib/insika/agent_file_store.rb +125 -0
- data/lib/insika/agent_profile.rb +188 -0
- data/lib/insika/allowlist.rb +28 -0
- data/lib/insika/baseline_store.rb +74 -0
- data/lib/insika/capability/resolved_tool.rb +34 -0
- data/lib/insika/capability_registry.rb +112 -0
- data/lib/insika/channel_delivery.rb +150 -0
- data/lib/insika/channel_registry.rb +30 -0
- data/lib/insika/channels/relay.rb +178 -0
- data/lib/insika/channels/web/widget.js +283 -0
- data/lib/insika/channels/web.rb +211 -0
- data/lib/insika/chat_builder.rb +254 -0
- data/lib/insika/checkpoint.rb +13 -0
- data/lib/insika/checkpoint_store.rb +153 -0
- data/lib/insika/coercion.rb +50 -0
- data/lib/insika/command.rb +32 -0
- data/lib/insika/command_bus.rb +39 -0
- data/lib/insika/commands/agent_payload.rb +41 -0
- data/lib/insika/commands/approve_action.rb +46 -0
- data/lib/insika/commands/cancel_task.rb +33 -0
- data/lib/insika/commands/create_agent.rb +54 -0
- data/lib/insika/commands/create_session.rb +67 -0
- data/lib/insika/commands/delete_agent.rb +33 -0
- data/lib/insika/commands/delete_agent_file.rb +50 -0
- data/lib/insika/commands/delete_data_tool.rb +33 -0
- data/lib/insika/commands/delete_llm_provider.rb +36 -0
- data/lib/insika/commands/delete_mcp.rb +30 -0
- data/lib/insika/commands/delete_system_file.rb +29 -0
- data/lib/insika/commands/gate_refinement.rb +245 -0
- data/lib/insika/commands/import_mcp_tools.rb +48 -0
- data/lib/insika/commands/import_tools.rb +81 -0
- data/lib/insika/commands/memory_add_note.rb +32 -0
- data/lib/insika/commands/memory_forget_fact.rb +32 -0
- data/lib/insika/commands/memory_put_fact.rb +35 -0
- data/lib/insika/commands/pause_task.rb +29 -0
- data/lib/insika/commands/resolve_refinement.rb +126 -0
- data/lib/insika/commands/restore_agent_file.rb +36 -0
- data/lib/insika/commands/restore_data_tool.rb +34 -0
- data/lib/insika/commands/restore_system_file.rb +31 -0
- data/lib/insika/commands/resume_task.rb +85 -0
- data/lib/insika/commands/run_refinement.rb +133 -0
- data/lib/insika/commands/send_message.rb +150 -0
- data/lib/insika/commands/set_agent_tools.rb +39 -0
- data/lib/insika/commands/set_skill_agents.rb +71 -0
- data/lib/insika/commands/trigger_workflow.rb +80 -0
- data/lib/insika/commands/update_agent.rb +49 -0
- data/lib/insika/commands/update_settings.rb +33 -0
- data/lib/insika/commands/upsert_llm_provider.rb +34 -0
- data/lib/insika/commands/upsert_mcp.rb +32 -0
- data/lib/insika/commands/write_agent_file.rb +57 -0
- data/lib/insika/commands/write_data_tool.rb +43 -0
- data/lib/insika/commands/write_golden.rb +58 -0
- data/lib/insika/commands/write_skill.rb +50 -0
- data/lib/insika/commands/write_system_file.rb +31 -0
- data/lib/insika/config_store.rb +85 -0
- data/lib/insika/context/builder.rb +166 -0
- data/lib/insika/context/catalog_provider.rb +23 -0
- data/lib/insika/context/fragment.rb +19 -0
- data/lib/insika/context/priority.rb +29 -0
- data/lib/insika/context/provider.rb +19 -0
- data/lib/insika/context/providers/memory.rb +60 -0
- data/lib/insika/context/providers/prompt.rb +105 -0
- data/lib/insika/context/providers/request.rb +32 -0
- data/lib/insika/context/providers/session.rb +108 -0
- data/lib/insika/context/providers/skill.rb +20 -0
- data/lib/insika/context/providers/tool_search.rb +20 -0
- data/lib/insika/delegation_store.rb +153 -0
- data/lib/insika/doctor.rb +294 -0
- data/lib/insika/dsl/definition.rb +55 -0
- data/lib/insika/dsl/runtime.rb +379 -0
- data/lib/insika/dsl/server_boot.rb +97 -0
- data/lib/insika/dsl/system.rb +93 -0
- data/lib/insika/dsl/workflow_adapter.rb +59 -0
- data/lib/insika/dsl.rb +307 -0
- data/lib/insika/edge_limiter.rb +130 -0
- data/lib/insika/egress_guard.rb +75 -0
- data/lib/insika/env_schema.rb +246 -0
- data/lib/insika/errors.rb +145 -0
- data/lib/insika/evals/assertions.rb +247 -0
- data/lib/insika/evals/baseline.rb +69 -0
- data/lib/insika/evals/golden.rb +172 -0
- data/lib/insika/evals/judge.rb +225 -0
- data/lib/insika/evals/pairwise.rb +178 -0
- data/lib/insika/evals/report.rb +115 -0
- data/lib/insika/evals/runner.rb +141 -0
- data/lib/insika/evals/transport.rb +178 -0
- data/lib/insika/event.rb +18 -0
- data/lib/insika/event_stream.rb +114 -0
- data/lib/insika/executor.rb +1680 -0
- data/lib/insika/frontmatter.rb +42 -0
- data/lib/insika/golden_store.rb +145 -0
- data/lib/insika/hooks.rb +48 -0
- data/lib/insika/http_client.rb +63 -0
- data/lib/insika/inbound_log.rb +84 -0
- data/lib/insika/llm_configurator.rb +99 -0
- data/lib/insika/llm_provider_store.rb +83 -0
- data/lib/insika/mcp_http_client.rb +67 -0
- data/lib/insika/mcp_store.rb +115 -0
- data/lib/insika/mcp_tool_ingestor.rb +143 -0
- data/lib/insika/memory_store.rb +93 -0
- data/lib/insika/message_origin.rb +76 -0
- data/lib/insika/middleware.rb +36 -0
- data/lib/insika/model_policy.rb +52 -0
- data/lib/insika/model_resolver.rb +176 -0
- data/lib/insika/model_selection.rb +114 -0
- data/lib/insika/onboarding.rb +208 -0
- data/lib/insika/outbox_store.rb +166 -0
- data/lib/insika/overlay_tool_registry.rb +103 -0
- data/lib/insika/pack.rb +102 -0
- data/lib/insika/pack_importer.rb +121 -0
- data/lib/insika/pending_action_store.rb +120 -0
- data/lib/insika/plugin/loader.rb +356 -0
- data/lib/insika/plugin.rb +35 -0
- data/lib/insika/policy/engine.rb +83 -0
- data/lib/insika/policy/policy.rb +120 -0
- data/lib/insika/policy_registry.rb +23 -0
- data/lib/insika/profile_source.rb +137 -0
- data/lib/insika/prompt_catalog.rb +61 -0
- data/lib/insika/queue_policy.rb +167 -0
- data/lib/insika/recovery.rb +127 -0
- data/lib/insika/refinement/candidate.rb +159 -0
- data/lib/insika/refinement/evidence_collector.rb +371 -0
- data/lib/insika/refinement/gate.rb +234 -0
- data/lib/insika/refinement/panel.rb +222 -0
- data/lib/insika/refinement/proposer.rb +262 -0
- data/lib/insika/refinement_store.rb +295 -0
- data/lib/insika/registry.rb +59 -0
- data/lib/insika/safety/config.rb +109 -0
- data/lib/insika/safety/detectors.rb +176 -0
- data/lib/insika/safety/factory.rb +102 -0
- data/lib/insika/safety/input_guardrail.rb +87 -0
- data/lib/insika/safety/moderator.rb +86 -0
- data/lib/insika/safety/output_filter.rb +79 -0
- data/lib/insika/safety/output_validator.rb +101 -0
- data/lib/insika/safety/safe_responses.rb +47 -0
- data/lib/insika/sandbox/boundary.rb +93 -0
- data/lib/insika/sandbox/docker.rb +74 -0
- data/lib/insika/sandbox/local.rb +33 -0
- data/lib/insika/sandbox/runner.rb +80 -0
- data/lib/insika/sandbox.rb +85 -0
- data/lib/insika/schema_guard.rb +147 -0
- data/lib/insika/secret_masking.rb +34 -0
- data/lib/insika/server/a2a/agent_card.rb +27 -0
- data/lib/insika/server/a2a/app.rb +112 -0
- data/lib/insika/server/a2a/client.rb +101 -0
- data/lib/insika/server/a2a/errors.rb +32 -0
- data/lib/insika/server/a2a/http.rb +42 -0
- data/lib/insika/server/a2a/message.rb +27 -0
- data/lib/insika/server/a2a/protocol.rb +45 -0
- data/lib/insika/server/a2a/remotes.rb +25 -0
- data/lib/insika/server/a2a/task_projection.rb +40 -0
- data/lib/insika/server/admin_auth.rb +29 -0
- data/lib/insika/server/app.rb +850 -0
- data/lib/insika/server/boot.rb +119 -0
- data/lib/insika/server/rack_app.rb +110 -0
- data/lib/insika/server/responses.rb +155 -0
- data/lib/insika/server/sse_body.rb +96 -0
- data/lib/insika/session_actor.rb +162 -0
- data/lib/insika/session_store.rb +143 -0
- data/lib/insika/settings_store.rb +154 -0
- data/lib/insika/shutdown.rb +125 -0
- data/lib/insika/skill_catalog.rb +113 -0
- data/lib/insika/skill_store.rb +79 -0
- data/lib/insika/steer_injector.rb +110 -0
- data/lib/insika/store.rb +52 -0
- data/lib/insika/stores/memory.rb +123 -0
- data/lib/insika/stores/sqlite.rb +183 -0
- data/lib/insika/studio/app.rb +1571 -0
- data/lib/insika/studio/assets/dist/application.css +1 -0
- data/lib/insika/studio/assets/dist/application.js +69 -0
- data/lib/insika/studio/forms.rb +340 -0
- data/lib/insika/studio/nav_icons.rb +31 -0
- data/lib/insika/studio/views/_message.erb +44 -0
- data/lib/insika/studio/views/agent_detail.erb +285 -0
- data/lib/insika/studio/views/agents.erb +63 -0
- data/lib/insika/studio/views/approvals.erb +41 -0
- data/lib/insika/studio/views/chats.erb +34 -0
- data/lib/insika/studio/views/evals.erb +83 -0
- data/lib/insika/studio/views/home.erb +72 -0
- data/lib/insika/studio/views/layout.erb +94 -0
- data/lib/insika/studio/views/login.erb +17 -0
- data/lib/insika/studio/views/mcp.erb +91 -0
- data/lib/insika/studio/views/not_found.erb +5 -0
- data/lib/insika/studio/views/playground.erb +47 -0
- data/lib/insika/studio/views/refinement.erb +234 -0
- data/lib/insika/studio/views/session.erb +62 -0
- data/lib/insika/studio/views/settings.erb +173 -0
- data/lib/insika/studio/views/skills.erb +86 -0
- data/lib/insika/studio/views/system_files.erb +65 -0
- data/lib/insika/studio/views/task.erb +105 -0
- data/lib/insika/studio/views/tasks.erb +33 -0
- data/lib/insika/studio/views/tool_edit.erb +107 -0
- data/lib/insika/studio/views/tools.erb +89 -0
- data/lib/insika/subagent_graph.rb +96 -0
- data/lib/insika/system_file_store.rb +96 -0
- data/lib/insika/task_actor.rb +128 -0
- data/lib/insika/task_store.rb +250 -0
- data/lib/insika/telemetry/pricing.rb +104 -0
- data/lib/insika/telemetry/recorder.rb +228 -0
- data/lib/insika/telemetry.rb +127 -0
- data/lib/insika/testing/store_contract.rb +270 -0
- data/lib/insika/token_estimator.rb +16 -0
- data/lib/insika/tool_assembly.rb +140 -0
- data/lib/insika/tool_catalog.rb +89 -0
- data/lib/insika/tool_definition.rb +518 -0
- data/lib/insika/tool_envelope.rb +140 -0
- data/lib/insika/tool_manifest.rb +218 -0
- data/lib/insika/tool_registry.rb +21 -0
- data/lib/insika/tool_store.rb +135 -0
- data/lib/insika/tool_trace_store.rb +92 -0
- data/lib/insika/tools/a2a_remote.rb +48 -0
- data/lib/insika/tools/agent_enum.rb +68 -0
- data/lib/insika/tools/concurrency.rb +54 -0
- data/lib/insika/tools/data_defined_tool.rb +220 -0
- data/lib/insika/tools/load_skill.rb +41 -0
- data/lib/insika/tools/remember.rb +53 -0
- data/lib/insika/tools/subagent.rb +75 -0
- data/lib/insika/tools/subagents.rb +77 -0
- data/lib/insika/tools/tool_search.rb +94 -0
- data/lib/insika/turn_output.rb +139 -0
- data/lib/insika/turn_state.rb +158 -0
- data/lib/insika/turn_timing.rb +56 -0
- data/lib/insika/usage_ledger.rb +47 -0
- data/lib/insika/version.rb +3 -1
- data/lib/insika/wiring/graph.rb +198 -0
- data/lib/insika/workflow.rb +185 -0
- data/lib/insika/workflow_registry.rb +33 -0
- data/lib/insika.rb +203 -4
- metadata +395 -8
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Insika
|
|
4
|
+
# Workflow surface (item 22 / COMPETITIVE-ANALYSIS §4.4). A workflow is a Ruby
|
|
5
|
+
# callable orchestrating RubyLLM Agents/Workflows FROM WITHIN (RubyLLM First);
|
|
6
|
+
# its durable RUN is a Task (checkpointed, recoverable — stronger than Flue's
|
|
7
|
+
# at-most-once run record). This module adds the EXPOSED surface the consumer
|
|
8
|
+
# asked for, matching the honest Flue scope (not Temporal):
|
|
9
|
+
# · runId — the run id (== task id; the Task IS the run record).
|
|
10
|
+
# · event stream — :workflow_started / :workflow_completed on the task stream.
|
|
11
|
+
# · I/O by schema — optional input_schema / output_schema validated at the edges.
|
|
12
|
+
#
|
|
13
|
+
# A schema is any dry-schema-compatible validator: `#call(value)` returning a
|
|
14
|
+
# result that responds to `#success?` and `#errors` (dry-schema's own contract).
|
|
15
|
+
# 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.
|
|
19
|
+
module Workflow
|
|
20
|
+
# Bundles a registered workflow's callable factory with its metadata (schemas +
|
|
21
|
+
# description). Built lazily by WorkflowRegistry#definition — it does NOT resolve
|
|
22
|
+
# the factory (the Executor resolves inside the fiber; the contract forbids
|
|
23
|
+
# instantiating outside it). Schema validation touches only the schemas.
|
|
24
|
+
Definition = Data.define(:name, :description, :input_schema, :output_schema, :factory) do
|
|
25
|
+
# Raises WorkflowSchemaError (< ValidationError) when the input does not
|
|
26
|
+
# conform. No-op without an input_schema (parity). Called synchronously by
|
|
27
|
+
# TriggerWorkflow -> a bad input is a 422 with no run created.
|
|
28
|
+
def validate_input!(input) = enforce!(input_schema, input, :input)
|
|
29
|
+
|
|
30
|
+
# Raises WorkflowSchemaError when the RETURN does not conform. No-op without an
|
|
31
|
+
# output_schema. Called inside the fiber after the workflow returns -> a bad
|
|
32
|
+
# output fails the run at the :workflow_schema stage.
|
|
33
|
+
def validate_output!(output) = enforce!(output_schema, output, :output)
|
|
34
|
+
|
|
35
|
+
# Resolves the factory (INSIDE the fiber) and invokes the orchestrator with the
|
|
36
|
+
# canonical signature `#call(input, context:, tools:)`.
|
|
37
|
+
def call(input, context:, tools:)
|
|
38
|
+
factory.call.call(input, context: context, tools: tools)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Discovery view (GET /v1/workflows): name + description + the I/O contract.
|
|
42
|
+
# A JSON-Schema-backed schema exposes its schema Hash; a duck-typed validator
|
|
43
|
+
# (dry-schema etc.) is opaque to introspection -> "opaque".
|
|
44
|
+
def catalog_entry
|
|
45
|
+
{
|
|
46
|
+
"name" => name,
|
|
47
|
+
"description" => description,
|
|
48
|
+
"input_schema" => schema_view(input_schema),
|
|
49
|
+
"output_schema" => schema_view(output_schema)
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def enforce!(schema, value, phase)
|
|
56
|
+
return if schema.nil?
|
|
57
|
+
|
|
58
|
+
result = schema.call(value)
|
|
59
|
+
return if result.success?
|
|
60
|
+
|
|
61
|
+
raise Insika::WorkflowSchemaError.new(
|
|
62
|
+
"workflow '#{name}' #{phase}", phase: phase, errors: normalize_errors(result.errors)
|
|
63
|
+
)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# dry-schema returns a MessageSet (responds to #to_h); the built-in Schema
|
|
67
|
+
# already returns a Hash.
|
|
68
|
+
def normalize_errors(errors) = errors.respond_to?(:to_h) ? errors.to_h : errors
|
|
69
|
+
|
|
70
|
+
def schema_view(schema)
|
|
71
|
+
return nil if schema.nil?
|
|
72
|
+
|
|
73
|
+
schema.respond_to?(:json_schema) ? schema.json_schema : "opaque"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
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).
|
|
84
|
+
class Schema
|
|
85
|
+
# dry-schema-compatible result. `errors` is { "field.path" => ["message", …] }.
|
|
86
|
+
Result = Data.define(:errors) do
|
|
87
|
+
def success? = errors.empty?
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# nil -> nil; a callable (dry-schema / proc) -> as-is; a JSON Schema Hash ->
|
|
91
|
+
# wrapped. Idempotent for an existing Schema (it is callable).
|
|
92
|
+
def self.coerce(schema)
|
|
93
|
+
return nil if schema.nil?
|
|
94
|
+
return schema if schema.respond_to?(:call)
|
|
95
|
+
|
|
96
|
+
new(schema)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
attr_reader :json_schema
|
|
100
|
+
|
|
101
|
+
def initialize(json_schema)
|
|
102
|
+
unless json_schema.is_a?(Hash)
|
|
103
|
+
raise Insika::ValidationError, "workflow schema must be a JSON Schema object or a #call-able validator"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
@json_schema = Insika::Coercion.deep_stringify(json_schema)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
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
|
+
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)))
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
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
|
|
167
|
+
|
|
168
|
+
def ruby_type(value)
|
|
169
|
+
case value
|
|
170
|
+
when Hash then "object"
|
|
171
|
+
when Array then "array"
|
|
172
|
+
when String then "string"
|
|
173
|
+
when Integer then "integer"
|
|
174
|
+
when Numeric then "number"
|
|
175
|
+
when true, false then "boolean"
|
|
176
|
+
when nil then "null"
|
|
177
|
+
else value.class.name.downcase
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def join(path, segment) = path.empty? ? segment.to_s : "#{path}.#{segment}"
|
|
182
|
+
def key(path) = path.empty? ? "(root)" : path
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Insika
|
|
4
|
+
# Workflow registry. A workflow is a Ruby callable with the signature
|
|
5
|
+
# `#call(input, context:, tools:)` that orchestrates RubyLLM Agents/Workflows FROM
|
|
6
|
+
# WITHIN (RubyLLM First): `context:` is the ContextPackage, `tools:` are
|
|
7
|
+
# instances already filtered by the Resolution. Execution = one logical turn;
|
|
8
|
+
# checkpoint at the end. Nothing is validated at registration (the callable may come
|
|
9
|
+
# via a factory block). Consumed by the TriggerWorkflow handler.
|
|
10
|
+
#
|
|
11
|
+
# Item 22 / §4.4 — the EXPOSED surface: a registration may carry `input_schema:` /
|
|
12
|
+
# `output_schema:` (a JSON Schema Hash or any dry-schema-compatible validator) and a
|
|
13
|
+
# `description:` in its metadata. `definition` bundles them with the factory into a
|
|
14
|
+
# Workflow::Definition (schemas resolved, factory left lazy); `catalog` is the
|
|
15
|
+
# discovery view (GET /v1/workflows).
|
|
16
|
+
class WorkflowRegistry < Registry
|
|
17
|
+
# -> Workflow::Definition (does NOT resolve the factory — the Executor resolves
|
|
18
|
+
# inside the fiber). Raises NotFoundError for an unregistered name.
|
|
19
|
+
def definition(name)
|
|
20
|
+
e = entry(name)
|
|
21
|
+
Insika::Workflow::Definition.new(
|
|
22
|
+
name: e.name,
|
|
23
|
+
description: e.metadata[:description],
|
|
24
|
+
input_schema: Insika::Workflow::Schema.coerce(e.metadata[:input_schema]),
|
|
25
|
+
output_schema: Insika::Workflow::Schema.coerce(e.metadata[:output_schema]),
|
|
26
|
+
factory: e.factory
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Discovery: [{ "name", "description", "input_schema", "output_schema" }, …].
|
|
31
|
+
def catalog = entries.map { |e| definition(e.name).catalog_entry }
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/insika.rb
CHANGED
|
@@ -1,7 +1,206 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "insika/version"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
require_relative "insika/errors"
|
|
5
|
+
require_relative "insika/coercion"
|
|
6
|
+
require_relative "insika/message_origin"
|
|
7
|
+
require_relative "insika/env_schema"
|
|
8
|
+
require_relative "insika/allowlist"
|
|
9
|
+
require_relative "insika/event"
|
|
10
|
+
require_relative "insika/agent_profile"
|
|
11
|
+
require_relative "insika/subagent_graph"
|
|
12
|
+
require_relative "insika/model_policy"
|
|
13
|
+
require_relative "insika/model_selection"
|
|
14
|
+
require_relative "insika/model_resolver"
|
|
15
|
+
require_relative "insika/tool_definition"
|
|
16
|
+
require_relative "insika/tool_manifest"
|
|
17
|
+
require_relative "insika/frontmatter"
|
|
18
|
+
require_relative "insika/token_estimator"
|
|
19
|
+
require_relative "insika/checkpoint"
|
|
20
|
+
require_relative "insika/command"
|
|
21
|
+
require_relative "insika/hooks"
|
|
22
|
+
require_relative "insika/middleware"
|
|
23
|
+
# Production edge (item 33 / §12 G7): windowed counters + the rate-limit/cost
|
|
24
|
+
# Middleware. Both inert until configured (nil/0 = off).
|
|
25
|
+
require_relative "insika/usage_ledger"
|
|
26
|
+
require_relative "insika/edge_limiter"
|
|
27
|
+
# Content safety / guardrails (RFC-0009). detectors.rb is self-contained (the eval
|
|
28
|
+
# requires it directly, D4); the rest hang off Middleware/hooks seams. No ruby_llm
|
|
29
|
+
# at load-time — Factory requires the gem lazily, like the Executor's create_chat.
|
|
30
|
+
require_relative "insika/safety/detectors"
|
|
31
|
+
require_relative "insika/safety/safe_responses"
|
|
32
|
+
require_relative "insika/safety/config"
|
|
33
|
+
require_relative "insika/safety/moderator"
|
|
34
|
+
require_relative "insika/safety/output_filter"
|
|
35
|
+
require_relative "insika/safety/input_guardrail"
|
|
36
|
+
require_relative "insika/safety/output_validator"
|
|
37
|
+
require_relative "insika/safety/factory"
|
|
38
|
+
require_relative "insika/context/fragment"
|
|
39
|
+
require_relative "insika/context/priority"
|
|
40
|
+
require_relative "insika/context/provider"
|
|
41
|
+
require_relative "insika/context/catalog_provider"
|
|
42
|
+
require_relative "insika/context/builder"
|
|
43
|
+
require_relative "insika/context/providers/request"
|
|
44
|
+
require_relative "insika/context/providers/prompt"
|
|
45
|
+
require_relative "insika/context/providers/skill"
|
|
46
|
+
require_relative "insika/context/providers/tool_search"
|
|
47
|
+
require_relative "insika/context/providers/memory"
|
|
48
|
+
require_relative "insika/context/providers/session"
|
|
49
|
+
require_relative "insika/policy/policy"
|
|
50
|
+
require_relative "insika/policy/engine"
|
|
51
|
+
require_relative "insika/registry"
|
|
52
|
+
require_relative "insika/tool_registry"
|
|
53
|
+
require_relative "insika/workflow"
|
|
54
|
+
require_relative "insika/workflow_registry"
|
|
55
|
+
require_relative "insika/policy_registry"
|
|
56
|
+
require_relative "insika/capability_registry"
|
|
57
|
+
require_relative "insika/prompt_catalog"
|
|
58
|
+
require_relative "insika/plugin"
|
|
59
|
+
require_relative "insika/plugin/loader"
|
|
60
|
+
require_relative "insika/store"
|
|
61
|
+
require_relative "insika/stores/memory"
|
|
62
|
+
require_relative "insika/stores/sqlite"
|
|
63
|
+
require_relative "insika/session_store"
|
|
64
|
+
require_relative "insika/task_store"
|
|
65
|
+
require_relative "insika/checkpoint_store"
|
|
66
|
+
require_relative "insika/pending_action_store"
|
|
67
|
+
require_relative "insika/delegation_store"
|
|
68
|
+
# Channels (RFC-0011): the outbound record + the inbound retry window. Both are
|
|
69
|
+
# plain stores; the channel objects themselves come after the HTTP client.
|
|
70
|
+
require_relative "insika/outbox_store"
|
|
71
|
+
require_relative "insika/inbound_log"
|
|
72
|
+
require_relative "insika/memory_store"
|
|
73
|
+
require_relative "insika/config_store"
|
|
74
|
+
require_relative "insika/profile_source"
|
|
75
|
+
require_relative "insika/agent_file_store"
|
|
76
|
+
require_relative "insika/skill_store"
|
|
77
|
+
require_relative "insika/secret_masking"
|
|
78
|
+
require_relative "insika/tool_store"
|
|
79
|
+
require_relative "insika/tool_trace_store"
|
|
80
|
+
# Refinement (RFC-0013 phase A): the run record + the evidence half of the loop.
|
|
81
|
+
# Reads sessions/tasks/traces above; requires Safety::Detectors (loaded earlier) for
|
|
82
|
+
# the PII redaction of the snippets it puts in a report.
|
|
83
|
+
require_relative "insika/refinement_store"
|
|
84
|
+
require_relative "insika/refinement/evidence_collector"
|
|
85
|
+
# The candidate format is pure data + validation, so it loads with the collector;
|
|
86
|
+
# the GATE needs the evals module and the stores, so it waits for them below.
|
|
87
|
+
require_relative "insika/refinement/candidate"
|
|
88
|
+
# The proposer only needs the candidate format and an injected `ask` — the provider
|
|
89
|
+
# gem is required lazily, inside the factory, so requiring Insika still loads nothing.
|
|
90
|
+
require_relative "insika/refinement/proposer"
|
|
91
|
+
require_relative "insika/egress_guard"
|
|
92
|
+
require_relative "insika/schema_guard"
|
|
93
|
+
require_relative "insika/sandbox"
|
|
94
|
+
require_relative "insika/http_client"
|
|
95
|
+
# Channels (RFC-0011 §4/§6): the registry, the bundled relay adapter and the
|
|
96
|
+
# out-of-band dispatcher. After http_client and egress_guard — the relay POSTs
|
|
97
|
+
# through both — and after registry.rb, which ChannelRegistry extends.
|
|
98
|
+
require_relative "insika/channel_registry"
|
|
99
|
+
require_relative "insika/channels/relay"
|
|
100
|
+
require_relative "insika/channels/web"
|
|
101
|
+
require_relative "insika/channel_delivery"
|
|
102
|
+
require_relative "insika/overlay_tool_registry"
|
|
103
|
+
require_relative "insika/settings_store"
|
|
104
|
+
require_relative "insika/llm_provider_store"
|
|
105
|
+
require_relative "insika/llm_configurator"
|
|
106
|
+
# LLM-first onboarding surface (item 20 / §5.6): serves start.md + models.json + the
|
|
107
|
+
# public docs. Reads the settings/provider stores above at call-time (order is free).
|
|
108
|
+
require_relative "insika/onboarding"
|
|
109
|
+
# Evals (RFC-0008) — the quality harness, moved under lib/ so the engine can call it
|
|
110
|
+
# (the RFC-0013 refinement gate scores a candidate agent with the SAME judge the CLI
|
|
111
|
+
# uses; a second copy would be the worst outcome). It stays a CLIENT of the engine:
|
|
112
|
+
# HttpTransport talks to a running deployment, nothing here reads a store. Pure Ruby +
|
|
113
|
+
# stdlib; the judge's provider call is injected, so no ruby_llm at load time.
|
|
114
|
+
require_relative "insika/evals/golden"
|
|
115
|
+
require_relative "insika/evals/assertions"
|
|
116
|
+
require_relative "insika/evals/judge"
|
|
117
|
+
require_relative "insika/evals/pairwise"
|
|
118
|
+
require_relative "insika/evals/runner"
|
|
119
|
+
require_relative "insika/evals/report"
|
|
120
|
+
require_relative "insika/evals/baseline"
|
|
121
|
+
require_relative "insika/evals/transport"
|
|
122
|
+
# Authored eval cases (RFC-0013 §3.7): the corpus becomes editable without a
|
|
123
|
+
# checkout. Requires the loader above (it is the one validator).
|
|
124
|
+
require_relative "insika/golden_store"
|
|
125
|
+
require_relative "insika/baseline_store"
|
|
126
|
+
# RFC-0013 §3.5: scores a candidate by REPLAYING it. After evals (the runner and
|
|
127
|
+
# the baseline comparison) and after the stores it clones an agent through.
|
|
128
|
+
require_relative "insika/refinement/gate"
|
|
129
|
+
# RFC-0013 §3.9 (phase D): the proposer PANEL and the run's token budget. Needs the
|
|
130
|
+
# candidate format and the gate's Report shape, so it loads after both.
|
|
131
|
+
require_relative "insika/refinement/panel"
|
|
132
|
+
require_relative "insika/mcp_store"
|
|
133
|
+
require_relative "insika/mcp_http_client"
|
|
134
|
+
require_relative "insika/mcp_tool_ingestor"
|
|
135
|
+
require_relative "insika/system_file_store"
|
|
136
|
+
require_relative "insika/recovery"
|
|
137
|
+
require_relative "insika/command_bus"
|
|
138
|
+
require_relative "insika/commands/create_session"
|
|
139
|
+
require_relative "insika/commands/cancel_task"
|
|
140
|
+
require_relative "insika/commands/pause_task"
|
|
141
|
+
require_relative "insika/commands/approve_action"
|
|
142
|
+
require_relative "insika/commands/send_message"
|
|
143
|
+
require_relative "insika/commands/resume_task"
|
|
144
|
+
require_relative "insika/commands/trigger_workflow"
|
|
145
|
+
require_relative "insika/commands/agent_payload"
|
|
146
|
+
require_relative "insika/commands/create_agent"
|
|
147
|
+
require_relative "insika/commands/update_agent"
|
|
148
|
+
require_relative "insika/commands/delete_agent"
|
|
149
|
+
require_relative "insika/commands/set_agent_tools"
|
|
150
|
+
require_relative "insika/commands/write_agent_file"
|
|
151
|
+
require_relative "insika/commands/delete_agent_file"
|
|
152
|
+
require_relative "insika/commands/restore_agent_file"
|
|
153
|
+
require_relative "insika/commands/write_skill"
|
|
154
|
+
require_relative "insika/commands/set_skill_agents"
|
|
155
|
+
require_relative "insika/commands/memory_put_fact"
|
|
156
|
+
require_relative "insika/commands/memory_forget_fact"
|
|
157
|
+
require_relative "insika/commands/memory_add_note"
|
|
158
|
+
require_relative "insika/commands/run_refinement"
|
|
159
|
+
require_relative "insika/commands/gate_refinement"
|
|
160
|
+
require_relative "insika/commands/resolve_refinement"
|
|
161
|
+
require_relative "insika/commands/write_golden"
|
|
162
|
+
require_relative "insika/commands/update_settings"
|
|
163
|
+
require_relative "insika/commands/upsert_llm_provider"
|
|
164
|
+
require_relative "insika/commands/delete_llm_provider"
|
|
165
|
+
require_relative "insika/commands/upsert_mcp"
|
|
166
|
+
require_relative "insika/commands/delete_mcp"
|
|
167
|
+
require_relative "insika/commands/write_system_file"
|
|
168
|
+
require_relative "insika/commands/delete_system_file"
|
|
169
|
+
require_relative "insika/commands/restore_system_file"
|
|
170
|
+
require_relative "insika/commands/write_data_tool"
|
|
171
|
+
require_relative "insika/commands/delete_data_tool"
|
|
172
|
+
require_relative "insika/commands/restore_data_tool"
|
|
173
|
+
require_relative "insika/commands/import_tools"
|
|
174
|
+
require_relative "insika/commands/import_mcp_tools"
|
|
175
|
+
require_relative "insika/event_stream"
|
|
176
|
+
require_relative "insika/task_actor"
|
|
177
|
+
require_relative "insika/queue_policy"
|
|
178
|
+
require_relative "insika/session_actor"
|
|
179
|
+
require_relative "insika/skill_catalog"
|
|
180
|
+
require_relative "insika/tool_catalog"
|
|
181
|
+
require_relative "insika/steer_injector"
|
|
182
|
+
require_relative "insika/turn_output"
|
|
183
|
+
require_relative "insika/turn_state"
|
|
184
|
+
require_relative "insika/turn_timing"
|
|
185
|
+
require_relative "insika/capability/resolved_tool"
|
|
186
|
+
require_relative "insika/tool_envelope"
|
|
187
|
+
require_relative "insika/tool_assembly"
|
|
188
|
+
require_relative "insika/chat_builder"
|
|
189
|
+
require_relative "insika/executor"
|
|
190
|
+
require_relative "insika/shutdown"
|
|
191
|
+
require_relative "insika/pack"
|
|
192
|
+
require_relative "insika/pack_importer"
|
|
193
|
+
require_relative "insika/telemetry"
|
|
194
|
+
# Strict config + diagnosis (item 23 / §8.1). Doctor reads the config stores above;
|
|
195
|
+
# EnvSchema (required at the top) is its env layer.
|
|
196
|
+
require_relative "insika/doctor"
|
|
197
|
+
# Shared composition core for both roots (config/wiring.rb + config/deployment.rb).
|
|
198
|
+
# Only references the classes above at call-time, so require order is unconstrained.
|
|
199
|
+
require_relative "insika/wiring/graph"
|
|
200
|
+
# Public Ruby DSL (item 36): Insika.agent { … }. The Builder is gem-free (it only
|
|
201
|
+
# generates a Pack); the runtime (chat/serve) is required lazily by Definition, so
|
|
202
|
+
# `require "insika"` stays free of ruby_llm and the HTTP server.
|
|
203
|
+
require_relative "insika/dsl"
|
|
204
|
+
# Do NOT require "insika/tools/load_skill" here: it does `require "ruby_llm"` at
|
|
205
|
+
# the top (inherits from RubyLLM::Tool) and would pull the gem in at load-time. The
|
|
206
|
+
# Executor loads it lazily inside create_chat (D9).
|