A small helpdesk system: an office Pixel running a patched GrapheneOS Dialer answers technician calls, records both call legs as separate channels, and a Ruby backend transcribes them through Whisper and files an AI summary against the caller. Squashed to a single commit for sharing. No credentials are included; secrets live outside the repo in /etc/helpdesk/env on the server or a gitignored .claude/env.local locally. See .claude/env.local.example for the shape. Start at README.md, then docs/architecture.md.
44 lines
2.2 KiB
Ruby
44 lines
2.2 KiB
Ruby
# frozen_string_literal: true
|
|
require_relative "../context_maintainer"
|
|
require "json"
|
|
$pass = 0; $fail = 0
|
|
def ok(d); $pass += 1; puts " ok #{d}"; end
|
|
def bad(d, g = nil); $fail += 1; puts " FAIL #{d}#{g.nil? ? '' : " (#{g.inspect})"}"; end
|
|
def eq(a, b, d); a == b ? ok(d) : bad(d, a); end
|
|
def truthy(x, d); x ? ok(d) : bad(d, x); end
|
|
|
|
def env(summary:, other:)
|
|
JSON.generate("choices" => [{ "message" => { "content" =>
|
|
JSON.generate("summary" => summary, "other_context" => other) } }], "usage" => { "cost" => 0.001 })
|
|
end
|
|
|
|
puts "maintainer: builds {summary, other_context}"
|
|
m = Helpdesk::ContextMaintainer.new(api_key: "x",
|
|
transport: ->(_u, _h, _b) { [200, env(summary: "Souhrn.", other: ["A", "B"])] })
|
|
r = m.build(mode: :incremental, old_ai_context: { "summary" => "", "other_context" => [] },
|
|
digests: ["digest"], ledger: [])
|
|
truthy(r[:ok], "ok")
|
|
eq(r[:ai_context]["summary"], "Souhrn.", "summary rendered")
|
|
eq(r[:ai_context]["other_context"], ["A", "B"], "other_context rendered")
|
|
|
|
puts "maintainer: pinned section forced verbatim + flags divergence"
|
|
r2 = m.build(mode: :incremental, old_ai_context: { "summary" => "PIN", "other_context" => [] },
|
|
pinned_sections: { "summary" => "PIN" }, digests: ["d"])
|
|
eq(r2[:ai_context]["summary"], "PIN", "pinned summary is the operator text, not the LLM's")
|
|
truthy(r2[:needs_review], "LLM diverged from the pin -> needs_review")
|
|
|
|
puts "maintainer: model selection per mode"
|
|
seen = []
|
|
m2 = Helpdesk::ContextMaintainer.new(api_key: "x",
|
|
transport: ->(_u, _h, b) { seen << JSON.parse(b)["model"]; [200, env(summary: "s", other: [])] })
|
|
m2.build(mode: :incremental, old_ai_context: {}, digests: [])
|
|
m2.build(mode: :rebuild, old_ai_context: {}, digests: [])
|
|
eq(seen[0], "google/gemini-3.6-flash", "incremental uses the configured model")
|
|
eq(seen[1], "google/gemini-3.6-flash", "rebuild uses the configured model")
|
|
|
|
puts "maintainer: no key -> graceful no-op"
|
|
truthy(Helpdesk::ContextMaintainer.new(api_key: "").respond_to?(:build), "constructs without a key")
|
|
r3 = Helpdesk::ContextMaintainer.new(api_key: "").build(mode: :incremental, old_ai_context: {})
|
|
truthy(!r3[:ok], "no key + no transport -> ok:false (no crash)")
|
|
|
|
puts "\n#{$pass} passed, #{$fail} failed"; exit($fail.zero? ? 0 : 1)
|