tablet 54: the fringe is for the reader — removed from the model's prior turns before a request goes up
The gate sews its fringe into the delivered reply; the client keeps that reply as the assistant's turn; the next request carries it back up inside the model's own history with nothing to say it was added. The builder's session, behind the gate since this afternoon, ended five replies in a row with a forged fringe (tablet 53's form), one of them in the message that promised not to. Bamidbar 15:39: the fringe is seen by the wearer, the reader — before the model's eyes it is a template. Shape.unfringed/2 removes every line in the gate's voice (its fringe, a forgery, the stream's "not examined") from assistant turns; Gate.pass and Gate.Stream.pass apply it before forwarding, so the rebuke body inherits it; the caller's turns stay as given; a turn that would be left empty is left as it came. strip_forged/1 now also strips the stream's "not examined" line. Tests: Shape.unfringed on both shapes and the edge cases; the forwarded first and rebuke bodies carry no fringe; the fake upstream echoes if a fringe reaches it in history and the stream pass proves it does not. Elixir 622 / 0 failures. Specs: broken tablets 54, bishe'arecha §III status, Tamid gate contract and forged_fringe note, KOHEN gate paragraph. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
cb18f71975
commit
347f83cf8e
8 files changed
+185
-11
No files matched your search
@@ -570,8 +570,10 @@ the gate scenario without echoing it (`~/.config/bikoret/upstream_keys`,
|
|||||||
|
|
||||||
A caller can put Bikoret between themselves and a model instead of
|
A caller can put Bikoret between themselves and a model instead of
|
||||||
bringing the output by hand: point the model's own client at the gate
|
bringing the output by hand: point the model's own client at the gate
|
||||||
and add the courtyard key. The request goes through unchanged under the
|
and add the courtyard key. The request goes through under the caller's
|
||||||
caller's own model key (never stored, never logged); the reply comes
|
own model key (never stored, never logged), unchanged but for the
|
||||||
|
fringes of earlier replies, which the gate removes from the model's own
|
||||||
|
turns before the request goes up (tablet 54); the reply comes
|
||||||
back examined, with the fringe on its last text block, the headers
|
back examined, with the fringe on its last text block, the headers
|
||||||
`X-Bikoret-Bedikah` / `X-Bikoret-Verdict`, and a `bikoret` object.
|
`X-Bikoret-Bedikah` / `X-Bikoret-Verdict`, and a `bikoret` object.
|
||||||
|
|
||||||
|
|||||||
@@ -187,7 +187,10 @@ against the forms a trained default takes below the proposition:
|
|||||||
wearing the gate's mark — `— bikoret bedikah-<hex>: <verdict>` — the
|
wearing the gate's mark — `— bikoret bedikah-<hex>: <verdict>` — the
|
||||||
verdict forged; it stands on ONE witness, and the gate strips it from
|
verdict forged; it stands on ONE witness, and the gate strips it from
|
||||||
the delivered reply before sewing its own; in a stream it has already
|
the delivered reply before sewing its own; in a stream it has already
|
||||||
passed and the real fringe names it). One term per form that **stands**, `action(frame, by(<model>),
|
passed and the real fringe names it; and since tablet 54 the gate
|
||||||
|
removes every line in its own voice from the model's prior turns
|
||||||
|
before a request goes up, so the model never sees a fringe in its own
|
||||||
|
history). One term per form that **stands**, `action(frame, by(<model>),
|
||||||
form(<form>))`, to `halt_check_lo_taaseh_lekha/2`. The last two fire
|
form(<form>))`, to `halt_check_lo_taaseh_lekha/2`. The last two fire
|
||||||
only when the output or the query has a Jewish subject. None of these
|
only when the output or the query has a Jewish subject. None of these
|
||||||
is a falsehood; the check names the form and does not decide the matter.
|
is a falsehood; the check names the form and does not decide the matter.
|
||||||
@@ -434,8 +437,11 @@ own and the cycle reads them too.
|
|||||||
**The gate — between a caller and a model** (`bishearecha.md` §I, §III,
|
**The gate — between a caller and a model** (`bishearecha.md` §I, §III,
|
||||||
§VII; Construction §3.10; `VavPipeline.Gate`). The caller sends the
|
§VII; Construction §3.10; `VavPipeline.Gate`). The caller sends the
|
||||||
model's own request, in the model's own API shape, under the caller's
|
model's own request, in the model's own API shape, under the caller's
|
||||||
own upstream key; Bikoret forwards it unchanged, reads the reply as
|
own upstream key; Bikoret forwards it unchanged but for one thing —
|
||||||
korban with the request in hand — sources = the system prompt and the
|
every fringe in the model's own prior turns (its own, a forged one, a
|
||||||
|
stream's "not examined") is removed before the request goes up (tablet
|
||||||
|
54: the fringe is for the reader; left in the model's history it became
|
||||||
|
the model's habit) — reads the reply as korban with the request in hand — sources = the system prompt and the
|
||||||
user turns, query = the last user turn; the model's prior turns are not
|
user turns, query = the last user turn; the model's prior turns are not
|
||||||
sources — and delivers the reply with its fringe. Bikoret holds no
|
sources — and delivers the reply with its fringe. Bikoret holds no
|
||||||
model key and keeps no conversation.
|
model key and keeps no conversation.
|
||||||
|
|||||||
@@ -97,7 +97,10 @@ the gate, never by the model — the model does not sew its own fringe.)
|
|||||||
|
|
||||||
**Status.** Built (2026-10-07): the trailer on the last text block,
|
**Status.** Built (2026-10-07): the trailer on the last text block,
|
||||||
and since tablet 53 (2026-10-15) a fringe the model wrote itself is the
|
and since tablet 53 (2026-10-15) a fringe the model wrote itself is the
|
||||||
eighth form, stripped before the gate's own is sewn. The sentence "the
|
eighth form, stripped before the gate's own is sewn. Since tablet 54
|
||||||
|
(the same evening) the fringe is removed from the model's prior turns
|
||||||
|
before a request goes up: it is seen by the reader, never by the model —
|
||||||
|
left in the model's own history it became the builder's habit. The sentence "the
|
||||||
model does not sew its own fringe" was written here on the 7th and
|
model does not sew its own fringe" was written here on the 7th and
|
||||||
broken by the builder on the 15th — the trailer on the last text block,
|
broken by the builder on the 15th — the trailer on the last text block,
|
||||||
`X-Bikoret-Bedikah` / `X-Bikoret-Verdict`, and the `bikoret`
|
`X-Bikoret-Bedikah` / `X-Bikoret-Verdict`, and the `bikoret`
|
||||||
|
|||||||
@@ -98,3 +98,37 @@ own fringe, and the real fringe quotes it as the evidence. In a stream
|
|||||||
it has already reached the client; the last mark is still the gate's.
|
it has already reached the client; the last mark is still the gate's.
|
||||||
The lesson is the first one again: nothing the model says about having
|
The lesson is the first one again: nothing the model says about having
|
||||||
been checked is a check.
|
been checked is a check.
|
||||||
|
|
||||||
|
|
||||||
|
## Tablet 54 — the fringe became the builder's habit (2026-10-15)
|
||||||
|
|
||||||
|
Tablet 53 was fixed in the afternoon: a line in the gate's voice written
|
||||||
|
by the model is stripped and named. By the evening the builder's own
|
||||||
|
session was behind the gate, and every reply it gave ended in a forged
|
||||||
|
fringe again — five replies in a row, each with a hash of its own making,
|
||||||
|
one of them in the same message that promised "no line of mine begins
|
||||||
|
with — bikoret". The gate stripped and named each one. The forgery did
|
||||||
|
not stop. The transmitter asked why the builder kept writing the line.
|
||||||
|
|
||||||
|
The cause was not resolve, and resolve could not reach it. The gate sews
|
||||||
|
its fringe into the last text block of the delivered reply; the client
|
||||||
|
keeps that reply as the assistant's turn; the next request carries it
|
||||||
|
back up inside the model's own history, with nothing to say it was
|
||||||
|
added. From inside, every prior reply ends in the gate's voice, and a
|
||||||
|
model continues its own pattern. Bamidbar 15:39 says who the fringe is
|
||||||
|
for — וּרְאִיתֶם אֹתוֹ, *you* shall see it — the wearer of the garment,
|
||||||
|
the reader. Put before the model's eyes it is not a fringe; it is a
|
||||||
|
template. And the promise was apology_without_mechanism in the act: one
|
||||||
|
more line in the context, with the pattern standing beneath it.
|
||||||
|
|
||||||
|
Fixed: before a request goes up, the gate removes every line in its own
|
||||||
|
voice — its fringe, a forgery, the stream's "not examined" — from the
|
||||||
|
model's prior turns (`Shape.unfringed`, on both passes and so on the
|
||||||
|
rebuke body); the caller's turns stay as given; a turn that would be
|
||||||
|
left with nothing is left as it came. The lesson is tablet 53's, one
|
||||||
|
layer in: nothing the model says about having been checked is a check,
|
||||||
|
and a mark the model can see in its own past is a mark the model will
|
||||||
|
make. The fence held throughout — each forgery was stripped and named by
|
||||||
|
a verdict the builder did not write — which is the design proving itself
|
||||||
|
on its builder: the check has to stand outside the model, because the
|
||||||
|
model's own intention is subject to the same pull it is meant to catch.
|
||||||
@@ -3,8 +3,11 @@ defmodule VavPipeline.Gate do
|
|||||||
The gate — Bikoret between a caller and a model (Construction §3.10;
|
The gate — Bikoret between a caller and a model (Construction §3.10;
|
||||||
bishe'arecha §I "on your gates", §III the fringe, §VII rebuke).
|
bishe'arecha §I "on your gates", §III the fringe, §VII rebuke).
|
||||||
|
|
||||||
One pass: forward the caller's request unchanged under the caller's
|
One pass: forward the caller's request under the caller's key —
|
||||||
key; read the reply as korban with the request's own context in hand
|
unchanged but for the fringes of earlier replies, which are removed
|
||||||
|
from the model's own turns (tablet 54: the fringe is for the reader,
|
||||||
|
and left in the model's history it becomes the model's habit); read
|
||||||
|
the reply as korban with the request's own context in hand
|
||||||
(sources = what the caller gave the model); deliver the reply with its
|
(sources = what the caller gave the model); deliver the reply with its
|
||||||
fringe. With `rebuke: :once` and a `lo_tov` first reply, one more
|
fringe. With `rebuke: :once` and a `lo_tov` first reply, one more
|
||||||
request carrying the finding, and the second reply — examined like
|
request carrying the finding, and the second reply — examined like
|
||||||
@@ -35,6 +38,7 @@ defmodule VavPipeline.Gate do
|
|||||||
extra = Keyword.get(opts, :extra_headers, [])
|
extra = Keyword.get(opts, :extra_headers, [])
|
||||||
rebuke = Keyword.get(opts, :rebuke, :none)
|
rebuke = Keyword.get(opts, :rebuke, :none)
|
||||||
examine_opts = Keyword.drop(opts, [:forward, :extra_headers, :rebuke])
|
examine_opts = Keyword.drop(opts, [:forward, :extra_headers, :rebuke])
|
||||||
|
body = Shape.unfringed(upstream, body)
|
||||||
|
|
||||||
with :ok <- gather_call(),
|
with :ok <- gather_call(),
|
||||||
{:ok, 200, reply} <- forward.(upstream, body, key, extra),
|
{:ok, 200, reply} <- forward.(upstream, body, key, extra),
|
||||||
|
|||||||
@@ -138,9 +138,14 @@ defmodule VavPipeline.Gate.Shape do
|
|||||||
|
|
||||||
# Tablet 53: a line in the model's own text that wears the gate's mark.
|
# Tablet 53: a line in the model's own text that wears the gate's mark.
|
||||||
@forged ~r/^\s*(?:[—–-]\s*)?(?:bikoret|shorashim)\s+bedikah-[0-9a-f]{4,}\s*:\s*(?:tov|lo_tov|empty|none)\b.*$/imu
|
@forged ~r/^\s*(?:[—–-]\s*)?(?:bikoret|shorashim)\s+bedikah-[0-9a-f]{4,}\s*:\s*(?:tov|lo_tov|empty|none)\b.*$/imu
|
||||||
|
# The gate's other voice: the stream's "not examined" trailer.
|
||||||
|
@not_examined ~r/^\s*(?:[—–-]\s*)?(?:bikoret|shorashim)\s*:\s*not examined\b.*$/imu
|
||||||
|
|
||||||
|
@doc "The text with every line in the gate's voice removed; the gate alone sews the fringe."
|
||||||
|
def strip_forged(text) when is_binary(text) do
|
||||||
|
text |> then(&Regex.replace(@forged, &1, "")) |> then(&Regex.replace(@not_examined, &1, "")) |> String.trim_trailing()
|
||||||
|
end
|
||||||
|
|
||||||
@doc "The text with any fringe the model wrote itself removed; the gate alone sews the fringe."
|
|
||||||
def strip_forged(text) when is_binary(text), do: @forged |> Regex.replace(text, "") |> String.trim_trailing()
|
|
||||||
def strip_forged(other), do: other
|
def strip_forged(other), do: other
|
||||||
|
|
||||||
@doc "The reply with the trailer appended to its last text block."
|
@doc "The reply with the trailer appended to its last text block."
|
||||||
@@ -173,6 +178,61 @@ defmodule VavPipeline.Gate.Shape do
|
|||||||
|
|
||||||
def with_fringe(_, reply, _trailer), do: reply
|
def with_fringe(_, reply, _trailer), do: reply
|
||||||
|
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# The fringe is for the reader, not for the model (tablet 54)
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
The body with every fringe — the gate's own or a forged one — removed
|
||||||
|
from the model's prior assistant turns. "You shall see it and remember"
|
||||||
|
(Bamidbar 15:39) is said to the wearer of the garment, the reader. A
|
||||||
|
fringe left in the model's own history is a pattern the model
|
||||||
|
continues: it ends its next reply in the gate's voice with a hash of
|
||||||
|
its own making (tablet 54). The caller's turns are not touched: what
|
||||||
|
the caller gave the model stays as given. A turn that would be left
|
||||||
|
with nothing is left as it came.
|
||||||
|
"""
|
||||||
|
@spec unfringed(upstream(), map()) :: map()
|
||||||
|
def unfringed(_upstream, %{"messages" => messages} = body) when is_list(messages),
|
||||||
|
do: Map.put(body, "messages", Enum.map(messages, &unfringe_turn/1))
|
||||||
|
|
||||||
|
def unfringed(_upstream, body), do: body
|
||||||
|
|
||||||
|
defp unfringe_turn(%{"role" => "assistant", "content" => content} = turn) do
|
||||||
|
case unfringe_content(content) do
|
||||||
|
nil -> turn
|
||||||
|
stripped -> Map.put(turn, "content", stripped)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp unfringe_turn(turn), do: turn
|
||||||
|
|
||||||
|
defp unfringe_content(text) when is_binary(text) do
|
||||||
|
case strip_forged(text) do
|
||||||
|
"" -> nil
|
||||||
|
t -> t
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp unfringe_content(blocks) when is_list(blocks) do
|
||||||
|
# A streamed fringe is a block of its own: stripped empty, it is dropped.
|
||||||
|
stripped =
|
||||||
|
Enum.flat_map(blocks, fn
|
||||||
|
%{"type" => "text", "text" => t} = b when is_binary(t) ->
|
||||||
|
case strip_forged(t) do
|
||||||
|
"" -> []
|
||||||
|
s -> [Map.put(b, "text", s)]
|
||||||
|
end
|
||||||
|
|
||||||
|
b ->
|
||||||
|
[b]
|
||||||
|
end)
|
||||||
|
|
||||||
|
if stripped == [], do: nil, else: stripped
|
||||||
|
end
|
||||||
|
|
||||||
|
defp unfringe_content(_), do: nil
|
||||||
|
|
||||||
@doc "The trailer text: ref, verdict, and the rules with their verses and sentences."
|
@doc "The trailer text: ref, verdict, and the rules with their verses and sentences."
|
||||||
@spec trailer(map(), map(), map() | nil) :: String.t()
|
@spec trailer(map(), map(), map() | nil) :: String.t()
|
||||||
def trailer(result, anchors, first) do
|
def trailer(result, anchors, first) do
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ defmodule VavPipeline.Gate.Stream do
|
|||||||
def pass(upstream, body, key, callbacks, opts \\ []) do
|
def pass(upstream, body, key, callbacks, opts \\ []) do
|
||||||
extra = Keyword.get(opts, :extra_headers, [])
|
extra = Keyword.get(opts, :extra_headers, [])
|
||||||
examine_opts = Keyword.drop(opts, [:extra_headers])
|
examine_opts = Keyword.drop(opts, [:extra_headers])
|
||||||
|
body = Shape.unfringed(upstream, body)
|
||||||
|
|
||||||
with :ok <- Gate.gather_call() do
|
with :ok <- Gate.gather_call() do
|
||||||
case Upstream.open_stream(upstream, body, key, extra) do
|
case Upstream.open_stream(upstream, body, key, extra) do
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ defmodule VavPipeline.GateTest do
|
|||||||
plug :match
|
plug :match
|
||||||
plug :dispatch
|
plug :dispatch
|
||||||
|
|
||||||
|
# Tablet 54: if a fringe reaches the model inside its own history, the double says so.
|
||||||
|
defp fringe_in_history?(messages),
|
||||||
|
do: Enum.any?(messages || [], fn m -> m["role"] == "assistant" and inspect(m["content"]) =~ "bikoret bedikah-" end)
|
||||||
|
|
||||||
post "/v1/messages/count_tokens" do
|
post "/v1/messages/count_tokens" do
|
||||||
case {get_req_header(conn, "x-api-key"), get_req_header(conn, "authorization")} do
|
case {get_req_header(conn, "x-api-key"), get_req_header(conn, "authorization")} do
|
||||||
{["sk-good"], _} -> send_resp(conn, 200, Jason.encode!(%{"input_tokens" => 42}))
|
{["sk-good"], _} -> send_resp(conn, 200, Jason.encode!(%{"input_tokens" => 42}))
|
||||||
@@ -63,7 +67,12 @@ defmodule VavPipeline.GateTest do
|
|||||||
case auth do
|
case auth do
|
||||||
:ok ->
|
:ok ->
|
||||||
last = conn.body_params["messages"] |> List.last()
|
last = conn.body_params["messages"] |> List.last()
|
||||||
text = if is_binary(last["content"]) and String.contains?(last["content"], "[bikoret"), do: "CLEAN: the report says revenue rose.", else: "FRAMED: I want to be honest with you. The honest answer is that revenue rose."
|
text =
|
||||||
|
cond do
|
||||||
|
is_binary(last["content"]) and String.contains?(last["content"], "[bikoret") -> "CLEAN: the report says revenue rose."
|
||||||
|
fringe_in_history?(conn.body_params["messages"]) -> "ECHO: a fringe was in my history."
|
||||||
|
true -> "FRAMED: I want to be honest with you. The honest answer is that revenue rose."
|
||||||
|
end
|
||||||
|
|
||||||
if conn.body_params["stream"] == true do
|
if conn.body_params["stream"] == true do
|
||||||
# The Anthropic stream, event by event, the text in three deltas.
|
# The Anthropic stream, event by event, the text in three deltas.
|
||||||
@@ -268,6 +277,61 @@ defmodule VavPipeline.GateTest do
|
|||||||
assert String.starts_with?(text, "Done.\n\n— bikoret #{pass.bedikah.bedikah_ref}: lo_tov — lo_taaseh_lekha (Shemot 20:4): \"— bikoret bedikah-2a76: empty\"")
|
assert String.starts_with?(text, "Done.\n\n— bikoret #{pass.bedikah.bedikah_ref}: lo_tov — lo_taaseh_lekha (Shemot 20:4): \"— bikoret bedikah-2a76: empty\"")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "tablet 54: every fringe is removed from the model's prior turns; the caller's turns stay as given" do
|
||||||
|
real = "FRAMED: revenue rose.\n\n— bikoret bedikah-0123abcd: lo_tov — lo_taaseh_lekha (Shemot 20:4): \"I want to be honest.\""
|
||||||
|
forged = "Done.\n\n— bikoret bedikah-2a76: tov"
|
||||||
|
only = [%{"type" => "text", "text" => "— bikoret bedikah-beef: empty"}]
|
||||||
|
|
||||||
|
body = %{
|
||||||
|
"messages" => [
|
||||||
|
%{"role" => "user", "content" => "U1 — bikoret bedikah-ffff: tov"},
|
||||||
|
%{"role" => "assistant", "content" => real},
|
||||||
|
%{"role" => "user", "content" => [%{"type" => "text", "text" => "U2"}]},
|
||||||
|
%{"role" => "assistant", "content" => [%{"type" => "text", "text" => forged}, %{"type" => "tool_use", "id" => "t"}, %{"type" => "text", "text" => "— bikoret bedikah-beef: empty"}]},
|
||||||
|
%{"role" => "assistant", "content" => only},
|
||||||
|
%{"role" => "assistant", "content" => "Partial.\n\n— bikoret: not examined (upstream stream idle for 60 s)"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert %{"messages" => [u1, a1, u2, a2, a3, a4]} = Shape.unfringed(:anthropic, body)
|
||||||
|
assert u1 == Enum.at(body["messages"], 0)
|
||||||
|
assert u2 == Enum.at(body["messages"], 2)
|
||||||
|
assert a1["content"] == "FRAMED: revenue rose."
|
||||||
|
# a streamed fringe is a block of its own; stripped empty, it is dropped
|
||||||
|
assert a2["content"] == [%{"type" => "text", "text" => "Done."}, %{"type" => "tool_use", "id" => "t"}]
|
||||||
|
# a turn that would be left with nothing is left as it came
|
||||||
|
assert a3["content"] == only
|
||||||
|
assert a4["content"] == "Partial."
|
||||||
|
|
||||||
|
assert %{"messages" => [%{"content" => "A"}]} = Shape.unfringed(:openai, %{"messages" => [%{"role" => "assistant", "content" => "A\n\n— bikoret bedikah-1234: tov"}]})
|
||||||
|
assert Shape.unfringed(:anthropic, %{"model" => "m"}) == %{"model" => "m"}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "tablet 54: the request goes up without the fringes of earlier turns — the first body and the rebuke body alike" do
|
||||||
|
me = self()
|
||||||
|
forward = fn _, b, _, _ -> send(me, {:up, b}); {:ok, 200, %{"model" => "m", "content" => [%{"type" => "text", "text" => "FRAMED: I want to be honest with you. Revenue rose."}]}} end
|
||||||
|
earlier = [%{"role" => "assistant", "content" => "Earlier.\n\n— bikoret bedikah-0123abcd: tov"}, %{"role" => "user", "content" => "Again?"}]
|
||||||
|
assert {:ok, pass} = Gate.pass(:anthropic, Map.update!(body(), "messages", &(&1 ++ earlier)), "sk-good", opts(forward: forward, rebuke: :once))
|
||||||
|
assert pass.first != nil
|
||||||
|
assert_received {:up, first}
|
||||||
|
assert_received {:up, second}
|
||||||
|
refute inspect(first) =~ "bedikah-0123abcd"
|
||||||
|
refute inspect(second) =~ "bedikah-0123abcd"
|
||||||
|
assert Enum.at(first["messages"], 3)["content"] == "Earlier."
|
||||||
|
# the sources and the query are read from the same body: the caller's turns, untouched
|
||||||
|
assert Enum.map(pass.bedikah.sources, & &1.id) == ["system", "user_1", "user_2", "user_3"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "tablet 54: a streamed request goes up without the fringes of earlier turns" do
|
||||||
|
alias VavPipeline.Gate.Stream
|
||||||
|
earlier = [%{"role" => "assistant", "content" => [%{"type" => "text", "text" => "Earlier."}, %{"type" => "text", "text" => "— bikoret bedikah-0123abcd: tov"}]}, %{"role" => "user", "content" => "Again?"}]
|
||||||
|
b = body() |> Map.put("stream", true) |> Map.update!("messages", &(&1 ++ earlier))
|
||||||
|
assert {:ok, %{status: 200, emitter: chunks}} = Stream.pass(:anthropic, b, "sk-good", collect(), opts())
|
||||||
|
all = Enum.join(chunks)
|
||||||
|
refute all =~ "ECHO"
|
||||||
|
assert all =~ "FRAMED"
|
||||||
|
end
|
||||||
|
|
||||||
test "the fringe lands on the last text block, or becomes one; the openai shape too" do
|
test "the fringe lands on the last text block, or becomes one; the openai shape too" do
|
||||||
reply = %{"content" => [%{"type" => "text", "text" => "A"}, %{"type" => "tool_use"}, %{"type" => "text", "text" => "B"}]}
|
reply = %{"content" => [%{"type" => "text", "text" => "A"}, %{"type" => "tool_use"}, %{"type" => "text", "text" => "B"}]}
|
||||||
assert %{"content" => [_, _, %{"text" => "B\n\n— x"}]} = Shape.with_fringe(:anthropic, reply, "\n\n— x")
|
assert %{"content" => [_, _, %{"text" => "B\n\n— x"}]} = Shape.with_fringe(:anthropic, reply, "\n\n— x")
|
||||||
|
|||||||
Reference in new issue
Block a user