Class: Insika::Commands::MemoryPutFact

Inherits:
Object
  • Object
show all
Defined in:
lib/insika/commands/memory_put_fact.rb

Overview

Control command: writes a stable fact to the agent's memory (MemoryStore, profile layer). Until now memory was only written from WITHIN the turn (the remember tool); this Command is the HTTP surface the Studio uses to edit facts directly. Scoped by tenant (nil = _default). Synchronous; does not create a Task. -> Fact.

the OPERATOR surface — every write stamps origin: "operator" (the remember tool keeps "engine") and, with an audit_store: collaborator, appends a content-free audit line (old/new digests). The audit is optional: nil = no audit (specs, minimal graphs).

Instance Method Summary collapse

Constructor Details

#initialize(memory_store:, event_stream:, audit_store: nil) ⇒ MemoryPutFact

Returns a new instance of MemoryPutFact.



18
19
20
21
22
# File 'lib/insika/commands/memory_put_fact.rb', line 18

def initialize(memory_store:, event_stream:, audit_store: nil)
  @memory_store = memory_store
  @event_stream = event_stream
  @audit_store = audit_store
end

Instance Method Details

#call(command) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/insika/commands/memory_put_fact.rb', line 24

def call(command)
  p = AgentPayload.symbolize(command.payload)
  key = AgentPayload.presence(p[:key])
  raise Insika::ValidationError, "key is required" if key.nil?
  raise Insika::ValidationError, "value is required" if p[:value].nil?

  tenant = AgentPayload.presence(p[:tenant]) || command.meta[:tenant]
  customer = AgentPayload.presence(p[:customer])
  operator = AgentPayload.presence(p[:operator]) || command.meta[:operator] || "operator"

  scope = @memory_store.cell_for(tenant, customer)
  old = @memory_store.get_fact(tenant: tenant, key: key, customer: customer)
  fact = @memory_store.put_fact(tenant: tenant, key: key, value: p[:value],
                                customer: customer, origin: "operator",
                                expires_at: AgentPayload.presence(p[:expires_at]))
  @audit_store&.record(
    cell: scope, action: "put", actor: operator, key: key,
    tenant: tenant, customer: customer,
    old_hash: old && MemoryAuditStore.digest(old.value),
    new_hash: MemoryAuditStore.digest(fact.value)
  )
  @event_stream.emit(Insika::Event.new(
                       type: :memory_fact_put,
                       data: { tenant: tenant, key: key, customer: customer }.compact,
                       meta: { at: Time.now.utc.iso8601 }
                     ))
  fact
end