Class: Insika::DSL::Runtime

Inherits:
Object
  • Object
show all
Defined in:
lib/insika/dsl/runtime.rb

Overview

The live graph behind a Definition: it assembles the SAME authoring graph a concrete deployment does (Insika::Wiring::Graph + the runtime-authoring command surface), configures RubyLLM, and imports the definition's pack via the standard PackImporter. From there the agent is indistinguishable from one provisioned by any other pack — chat and serve just drive the normal path.

Built lazily by Definition#runtime, so require "insika" never pays for ruby_llm or the HTTP server.

Constant Summary collapse

TERMINAL =
%i[task_completed task_failed task_cancelled].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(definition, backend: nil) ⇒ Runtime

definition is a Definition (one agent) or a System (N agents). Both answer #pack/#id; a System also answers #packs. Duck-typed on purpose: the runtime does not care how many agents it hosts, only that each one arrives as an ordinary Pack.

backend: the store this graph owns (RFC-0017 A1). nil = the historic path, INSIKA_DB or memory — ENV is a default, never a requirement (the embed contract, item 5). An injected backend wins and is never widened back to the environment.



33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/insika/dsl/runtime.rb', line 33

def initialize(definition, backend: nil)
  @definition = definition
  @injected_backend = backend
  @packs = (definition.respond_to?(:packs) ? Array(definition.packs) : [definition.pack]).freeze
  @pack = @packs.first
  # RFC-0017 A2: the graph's OWN RubyLLM config, built before the graph so
  # every collaborator that talks to a provider is handed it at wiring time
  # rather than reading a process-wide singleton at call time.
  @llm = build_llm_context
  @graph = build_graph
  seed_default_model
  import_packs
end

Instance Attribute Details

#graphObject (readonly)

graph: the assembled Wiring::Graph::Result; pack: the PRIMARY imported Pack; packs: every imported Pack (one per agent — a System has N, a Definition has one). All read by the server boot and the specs.



22
23
24
# File 'lib/insika/dsl/runtime.rb', line 22

def graph
  @graph
end

#llmObject (readonly)

The graph's RubyLLM context (RFC-0017 A2) — an isolated config dup that answers #chat. nil only under the test stub, where the fallback is the RubyLLM constant itself. Read by the specs and by anything a host wires alongside this graph.



51
52
53
# File 'lib/insika/dsl/runtime.rb', line 51

def llm
  @llm
end

#packObject (readonly)

graph: the assembled Wiring::Graph::Result; pack: the PRIMARY imported Pack; packs: every imported Pack (one per agent — a System has N, a Definition has one). All read by the server boot and the specs.



22
23
24
# File 'lib/insika/dsl/runtime.rb', line 22

def pack
  @pack
end

#packsObject (readonly)

graph: the assembled Wiring::Graph::Result; pack: the PRIMARY imported Pack; packs: every imported Pack (one per agent — a System has N, a Definition has one). All read by the server boot and the specs.



22
23
24
# File 'lib/insika/dsl/runtime.rb', line 22

def packs
  @packs
end

Instance Method Details

#chat(message, session_id: nil, timeout: nil, agent: nil) ⇒ Object

One turn, in-process → the assistant's text. session_id nil = stateless one-shot; a value threads multi-turn memory (created on first use). agent: targets one agent of a system (default: the primary).



64
65
66
67
68
69
70
71
# File 'lib/insika/dsl/runtime.rb', line 64

def chat(message, session_id: nil, timeout: nil, agent: nil)
  command = Insika::Command.build(
    :send_message,
    { agent: (agent || @definition.id).to_s, message: message, session_id: session_id },
    transport: :cli
  )
  run_command(command, session_id: session_id, timeout: timeout)[:text]
end

#component(name) ⇒ Object

A named collaborator (settings_store, tool_store, …) the server boot reads.



92
# File 'lib/insika/dsl/runtime.rb', line 92

def component(name) = @components.fetch(name)

#profile(agent_id = nil) ⇒ Object

An imported profile, read back from the store (config-over-code round-trip). Defaults to the primary agent.



55
56
57
58
59
# File 'lib/insika/dsl/runtime.rb', line 55

def profile(agent_id = nil)
  id = (agent_id || @definition.id).to_s
  @graph.profiles.fetch(id) ||
    (raise Insika::Error, "agent '#{id}' was not imported")
end

#run_workflow(name, input:, agent:, timeout: nil) ⇒ Object

Triggers a declared workflow and returns its OUTPUT (the typed value the workflow returned), not the turn text. A schema violation on the input raises here, synchronously, with no run created — same contract as POST /v1/workflows/:name.



77
78
79
80
81
82
83
# File 'lib/insika/dsl/runtime.rb', line 77

def run_workflow(name, input:, agent:, timeout: nil)
  command = Insika::Command.build(
    :trigger_workflow, { workflow: name, agent: agent, input: input }, transport: :cli
  )
  outcome = run_command(command, session_id: nil, timeout: timeout)
  outcome.key?(:output) ? outcome[:output] : outcome[:text]
end

#serve(port:, host:, token:, **_opts) ⇒ Object

Boot the control UI (/studio) + drop-in API (/v1). Blocks on the reactor.



86
87
88
89
# File 'lib/insika/dsl/runtime.rb', line 86

def serve(port:, host:, token:, **_opts)
  require_relative "server_boot"
  ServerBoot.new(self, port: port, host: host, token: token).run
end