mirror of
https://github.com/SHOGGOTH-SECTOR/sica-fondt.git
synced 2026-08-01 16:40:24 +00:00
cerebellum: make the LLM seam async; add OpenHermesClient skeleton
A real model call is network/process IO, so the LLM seam is now a behaviour with a response callback (ResponseFn), not a synchronous function. StubLLM answers immediately; OpenHermesClient + OpenHermesConfig (OpenAI-compatible url/model) are the real plug, swappable for the stub. CerebellumHarness chains its passes through the async callback. Compiles on ponyc 0.64; demo green. Next: wire the actual chat/completions call behind OpenHermesClient. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015hmgREHNsxYCuim33yUF2c
This commit is contained in:
parent
ca0260692e
commit
a2a3a2d336
@ -4,19 +4,51 @@
|
|||||||
// the synthesis back through the bus (Brain-bound, so it crosses D1). This is
|
// the synthesis back through the bus (Brain-bound, so it crosses D1). This is
|
||||||
// the C1 integration spine ("plumbing + sequencing, not an organ").
|
// the C1 integration spine ("plumbing + sequencing, not an organ").
|
||||||
//
|
//
|
||||||
// Plug-and-play: the model is the `LLM` seam below. StubLLM stands in now; drop
|
// Plug-and-play: the model is the `LLM` seam. A real model call is network /
|
||||||
// a real OpenHermes client (HTTP / subprocess) in its place and nothing else
|
// process IO, so the seam is ASYNCHRONOUS -- `infer` is a behaviour that hands
|
||||||
// on the bus changes.
|
// its result to a callback. StubLLM answers immediately; OpenHermesClient is the
|
||||||
|
// real plug. Swap which one you register; nothing else on the bus changes.
|
||||||
|
|
||||||
// --- the model seam -------------------------------------------------------
|
// --- the model seam (async) ----------------------------------------------
|
||||||
interface val LLM
|
type ResponseFn is {(String)} val
|
||||||
"""One inference call. Implement this to plug a model into the cerebellum."""
|
"""Callback the model invokes with its output."""
|
||||||
fun infer(prompt: String): String
|
|
||||||
|
|
||||||
class val StubLLM is LLM
|
interface tag LLM
|
||||||
"""Stand-in until a real OpenHermes client is wired."""
|
be infer(prompt: String, respond: ResponseFn)
|
||||||
fun infer(prompt: String): String =>
|
|
||||||
"[stub-openhermes] " + prompt
|
// --- stub -----------------------------------------------------------------
|
||||||
|
actor StubLLM is LLM
|
||||||
|
new create() => None
|
||||||
|
|
||||||
|
be infer(prompt: String, respond: ResponseFn) =>
|
||||||
|
respond("[stub-openhermes] " + prompt)
|
||||||
|
|
||||||
|
// --- the OpenHermes plug --------------------------------------------------
|
||||||
|
class val OpenHermesConfig
|
||||||
|
"""Where to reach an OpenAI-compatible OpenHermes server."""
|
||||||
|
let url: String // base, e.g. http://localhost:8080/v1
|
||||||
|
let model: String
|
||||||
|
|
||||||
|
new val create(
|
||||||
|
url': String = "http://localhost:8080/v1",
|
||||||
|
model': String = "openhermes")
|
||||||
|
=>
|
||||||
|
url = url'
|
||||||
|
model = model'
|
||||||
|
|
||||||
|
actor OpenHermesClient is LLM
|
||||||
|
let _cfg: OpenHermesConfig
|
||||||
|
|
||||||
|
new create(cfg: OpenHermesConfig) =>
|
||||||
|
_cfg = cfg
|
||||||
|
|
||||||
|
be infer(prompt: String, respond: ResponseFn) =>
|
||||||
|
// TODO(loop next): POST an OpenAI-compatible chat/completions request to
|
||||||
|
// `_cfg.url`/chat/completions via the process seam (curl) or a Pony TCP
|
||||||
|
// client, parse choices[0].message.content, then call respond() with it.
|
||||||
|
// Until that IO is wired and testable in this env, surface intent rather
|
||||||
|
// than perform an untested network call.
|
||||||
|
respond("[openhermes " + _cfg.model + " @ " + _cfg.url + "] " + prompt)
|
||||||
|
|
||||||
// --- the harness ----------------------------------------------------------
|
// --- the harness ----------------------------------------------------------
|
||||||
actor CerebellumHarness is OrganReceiver
|
actor CerebellumHarness is OrganReceiver
|
||||||
@ -29,18 +61,19 @@ actor CerebellumHarness is OrganReceiver
|
|||||||
_out = out'
|
_out = out'
|
||||||
_bus = bus
|
_bus = bus
|
||||||
_llm = llm
|
_llm = llm
|
||||||
// C1 L3: pass count is the responsiveness knob (energy-gated later), the
|
// C1 L3: pass count is the responsiveness knob (energy-gated later); the
|
||||||
// 4+4 ordering itself is static. Clamp to >=1 so a turn always runs once.
|
// 4+4 ordering is static. Clamp to >=1 so a turn always runs once.
|
||||||
_passes = if passes' < 1 then 1 else passes' end
|
_passes = if passes' < 1 then 1 else passes' end
|
||||||
|
|
||||||
be receive(envl: Envelope) =>
|
be receive(envl: Envelope) =>
|
||||||
// A turn arrives off the bus. Sequence the passes through the model, then
|
// A turn arrives off the bus: sequence the passes, then emit.
|
||||||
// emit the synthesis back onto the bus toward the Brain.
|
_pass(envl.payload, 1)
|
||||||
var ctx: String = envl.payload
|
|
||||||
var pass: USize = 1
|
be _pass(ctx: String, n: USize) =>
|
||||||
while pass <= _passes do
|
if n > _passes then
|
||||||
ctx = _llm.infer(ctx)
|
_out.print("[cerebellum] " + _passes.string() + " passes -> " + ctx)
|
||||||
pass = pass + 1
|
_bus.route(Envelope(Cerebellum, Brain, OrganSecretion, ctx))
|
||||||
|
else
|
||||||
|
let self: CerebellumHarness tag = this
|
||||||
|
_llm.infer(ctx, {(out: String)(self, n) => self._pass(out, n + 1) } val)
|
||||||
end
|
end
|
||||||
_out.print("[cerebellum] " + _passes.string() + " passes -> " + ctx)
|
|
||||||
_bus.route(Envelope(Cerebellum, Brain, OrganSecretion, ctx))
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user