Class: Insika::Server::AppBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/insika/server/rack_app.rb

Overview

Assembles Server::App from a graph. Also answers the two questions the boot banner asks (workflows?/channels?), so registering the env channels happens exactly once and in one place.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(handle, token: nil, **config) ⇒ AppBuilder

Fixed local token: gates /v1 (Bearer) — and, under serve, logs into the Studio (cookie). Never a real secret; override with token:/ADMIN_TOKEN.



37
38
39
40
41
42
# File 'lib/insika/server/rack_app.rb', line 37

def initialize(handle, token: nil, **config)
  @rt = handle.respond_to?(:runtime) ? handle.runtime : handle
  @graph = @rt.graph
  @token = token || ENV.fetch("ADMIN_TOKEN", "local-demo")
  @config = config
end

Instance Attribute Details

#tokenObject (readonly)

Returns the value of attribute token.



44
45
46
# File 'lib/insika/server/rack_app.rb', line 44

def token
  @token
end

Instance Method Details

#appObject



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/insika/server/rack_app.rb', line 46

def app
  tenancy = @config[:tenancy] || ENV["INSIKA_TENANCY"] || "single_tenant"
  # WS1: the token store is handed over ONLY in multi_tenant mode — in
  # single_tenant the classic gateway token is the only credential
  # (passing the store would silently widen the surface).
  store = tenancy == "multi_tenant" ? @graph.token_store : nil
  @app ||= Insika::Server::App.new(
    command_bus: @graph.bus, event_stream: @graph.event_stream,
    session_store: @graph.session_store, task_store: @graph.task_store,
    pending_action_store: @graph.pending_action_store,
    provisioner: Insika::PackImporter.new(bus: @graph.bus, profiles: @graph.profiles),
    # GET /v1/agents/:id — the read-only capability view a case's `requires`
    # resolves against.
    profiles: @graph.profiles,
    # the OSS onboarding surface (start.md + models.json + docs).
    # This is the primary "build my first agent" target — models.json reports the
    # DSL's stores + the agents this process serves (each id IS the `model`).
    onboarding: build_onboarding,
    # GET /v1/workflows + POST /v1/workflows/:name, opt-in by
    # injection like every other edge — nil when the system declares none,
    # so the routes simply do not exist (404, parity).
    workflow_registry: (@graph.workflow_registry if workflows?),
    # the bundled relay, when the env turns it on. Same rule as the
    # OTEL bridge — a feature only `config.ru` can reach is a feature the
    # docs are half-true about.
    channels: (@graph.channel_registry if channels?),
    config: { gateway_token: @token, tenancy: tenancy }.merge(@config),
    token_store: store,
    # a 500's error_ref must be findable in the process log.
    logger: $stdout
  )
end

#channels?Boolean

Registers the env-configured channels once, and reports whether any exist.

Returns:

  • (Boolean)


82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/insika/server/rack_app.rb', line 82

def channels?
  unless defined?(@channels_ready)
    @channels_ready = true
    relay = Insika::Channels::Relay.from_env(
      http: Insika::HttpClient.new,
      allow_http: Insika::EnvSchema.truthy?(ENV["INSIKA_EGRESS_ALLOW_HTTP"]),
      allow_private: Insika::EnvSchema.truthy?(ENV["INSIKA_EGRESS_ALLOW_PRIVATE"])
    )
    @graph.channel_registry.register(relay.id, relay) if relay

    widget = Insika::Channels::Web.from_env(
      chat_rate_limit: Insika::Channels::Web.limit_resolver(
        profiles: @graph.profiles, settings_store: @rt.component(:settings_store)
      )
    )
    @graph.channel_registry.register(widget.id, widget) if widget
  end
  !@graph.channel_registry.names.empty?
end

#workflows?Boolean

Returns:

  • (Boolean)


79
# File 'lib/insika/server/rack_app.rb', line 79

def workflows? = !@graph.workflow_registry.names.empty?