Files
bikoret/vav_pipeline/lib/vav_pipeline/talmudic_engine_client.ex
T
Scott KarpandClaude Opus 4.6 546cb9d105 Step 14: Connect components — chamishim karsay zahav
Three connections built and tested:
- Haskell Shoresh Engine via Erlang Port (JSON lines over stdin/stdout)
- Prolog Talmudic Engine via Unix domain socket (JSON over /tmp/shorashim/talmudic.sock)
- Erlang Sanhedrin via native BEAM calls

New: Server.hs (JSON-line server loop), json_bridge.pl + socket_server.pl
(Prolog socket interface), ShoreshEnginePort + TalmudicEngineSocket +
SanhedrinClient (Elixir GenServer wrappers). BereishitCycle now routes
unresolved cases through Talmudic Engine and Sanhedrin. All connections
gracefully degrade — pipeline falls back to L1 data when engines unavailable.

46 Elixir tests, 33 Haskell tests, 57 Prolog tests — 0 failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 17:39:21 -04:00

106 lines
2.7 KiB
Elixir

defmodule VavPipeline.TalmudicEngineClient do
@moduledoc """
Client interface to the SWI-Prolog Talmudic Engine.
Construction spec §3.3:
Protocol: JSON over Unix domain socket
Delegates to TalmudicEngineSocket (the live Prolog process).
Falls back to stub responses if socket is unavailable.
"""
require Logger
@doc """
Send an interpretation request to the Talmudic Engine.
"""
@spec interpret(String.t(), map()) :: {:ok, map()} | {:error, String.t()}
def interpret(case_ref, context) do
case call_socket(:interpret, case_ref, context) do
{:ok, result} ->
{:ok, result}
{:error, reason} ->
Logger.warning("TalmudicEngineClient: socket unavailable (#{reason}), using stub")
{:ok, stub_interpretation(case_ref)}
end
end
@doc """
Send a challenge request.
"""
@spec challenge(String.t(), map()) :: {:ok, map()} | {:error, String.t()}
def challenge(case_ref, context) do
case call_socket(:challenge, case_ref, context) do
{:ok, result} ->
{:ok, result}
{:error, reason} ->
Logger.warning("TalmudicEngineClient: socket unavailable (#{reason}), using stub")
{:ok, stub_challenge(case_ref)}
end
end
@doc """
Send a resolution request.
"""
@spec resolve(String.t(), map()) :: {:ok, map()} | {:error, String.t()}
def resolve(case_ref, context) do
case call_socket(:resolve, case_ref, context) do
{:ok, result} ->
{:ok, result}
{:error, reason} ->
Logger.warning("TalmudicEngineClient: socket unavailable (#{reason}), using stub")
{:ok, stub_resolution(case_ref)}
end
end
# --- Private ---
defp call_socket(operation, case_ref, context) do
if Process.whereis(VavPipeline.TalmudicEngineSocket) do
apply(VavPipeline.TalmudicEngineSocket, operation, [case_ref, context])
else
{:error, "socket not started"}
end
end
defp stub_interpretation(case_ref) do
%{
"status" => "teiku",
"interpretation" => %{
"text" => "Talmudic Engine not connected — teiku",
"prolog_form" => "stub(#{case_ref})",
"grounding" => [],
"confidence" => "low"
},
"challenge" => nil
}
end
defp stub_challenge(_case_ref) do
%{
"status" => "teiku",
"challenge" => %{
"kushya" => "No challenge generated — engine not connected",
"contradicting" => "",
"strength" => "weak"
}
}
end
defp stub_resolution(case_ref) do
%{
"status" => "teiku",
"interpretation" => %{
"text" => "Resolution deferred — engine not connected",
"prolog_form" => "stub(#{case_ref})",
"grounding" => [],
"confidence" => "low"
},
"challenge" => nil
}
end
end