From 29304163e0ab97d335cba9daaabc4ccb0ea6e7a7 Mon Sep 17 00:00:00 2001 From: Jay Leaton <58495321+jayleaton@users.noreply.github.com> Date: Mon, 12 Oct 2026 02:33:05 +0700 Subject: [PATCH] Share the server JSON values through a named module Extract the family-neutral JSON module wiring from #702. Server files import the shared module, whose own parser/writer tests run separately, and build helpers and direct CPU harnesses provide the named import. Expose wtf8Encode through that shared surface. Ported from 4efa5725e030255d49a5bdd9893cd6b913ae0244. No DeepSeek serving code, fixtures or backend dependencies are included. --- build.zig | 5 +++++ zig/build/cortheon_fuzz.zig | 1 + zig/build/cuda.zig | 10 ++++++++-- zig/build/server.zig | 14 ++++++++++++++ zig/src/server/anthropic.zig | 2 +- zig/src/server/anthropic_translate.zig | 2 +- zig/src/server/chat.zig | 2 +- zig/src/server/chunk_plan.zig | 2 +- zig/src/server/compact.zig | 2 +- zig/src/server/compact_mem.zig | 2 +- zig/src/server/compact_test.zig | 2 +- zig/src/server/completion_prompt_test.zig | 2 +- zig/src/server/cortheon/checks.zig | 2 +- zig/src/server/cortheon/cortheon.zig | 2 +- zig/src/server/cortheon/cortheon_test.zig | 2 +- zig/src/server/cortheon/loop.zig | 2 +- zig/src/server/cortheon/memory.zig | 2 +- zig/src/server/cortheon/research.zig | 2 +- zig/src/server/cortheon/search.zig | 2 +- zig/src/server/cortheon/tools.zig | 2 +- zig/src/server/decisions.zig | 2 +- zig/src/server/decisions_test.zig | 2 +- zig/src/server/fields.zig | 2 +- zig/src/server/grammar.zig | 2 +- zig/src/server/hf_text.zig | 2 +- zig/src/server/http_body.zig | 2 +- zig/src/server/json.zig | 1 + zig/src/server/live.zig | 2 +- zig/src/server/logprobs.zig | 2 +- zig/src/server/main.zig | 2 +- zig/src/server/memory_routes.zig | 2 +- zig/src/server/messages.zig | 2 +- zig/src/server/model_text.zig | 2 +- zig/src/server/openai.zig | 2 +- zig/src/server/prompt.zig | 2 +- zig/src/server/pyrepr.zig | 2 +- zig/src/server/request_log.zig | 2 +- zig/src/server/responses.zig | 2 +- zig/src/server/responses_include_test.zig | 2 +- zig/src/server/responses_translate.zig | 2 +- zig/src/server/root.zig | 4 ++-- zig/src/server/routes.zig | 2 +- zig/src/server/serve.zig | 2 +- zig/src/server/server.zig | 2 +- zig/src/server/server_init_test.zig | 2 +- zig/src/server/slide.zig | 2 +- zig/src/server/slide_ask.zig | 2 +- zig/src/server/slide_graph.zig | 2 +- zig/src/server/slide_lesson.zig | 2 +- zig/src/server/slide_model.zig | 2 +- zig/src/server/slide_teacher.zig | 2 +- zig/src/server/slide_think.zig | 2 +- zig/src/server/sse.zig | 2 +- zig/src/server/status_routes.zig | 2 +- zig/src/server/tokens.zig | 2 +- zig/src/server/tool_grammar.zig | 2 +- zig/src/server/tool_params.zig | 4 ++-- zig/src/server/tool_parse.zig | 2 +- zig/src/server/tool_parse_test.zig | 2 +- zig/src/server/tool_specs.zig | 2 +- zig/src/server/tool_stream.zig | 2 +- zig/src/server/tool_stream_test.zig | 2 +- zig/src/server/tool_streaming.zig | 2 +- zig/src/server/warm.zig | 2 +- zig/tests/server/build.sh | 6 +++--- zig/tests/server/zig_test.sh | 4 +++- 66 files changed, 96 insertions(+), 67 deletions(-) create mode 100644 zig/build/server.zig diff --git a/build.zig b/build.zig index 08765bd1df..24a3a88f28 100644 --- a/build.zig +++ b/build.zig @@ -11,6 +11,7 @@ const grammar_build = @import("zig/build/grammar.zig"); const counters_build = @import("zig/build/metal_counters.zig"); const exl3_build = @import("zig/build/exl3.zig"); const exlr8_build = @import("zig/build/exlr8.zig"); +const server_build = @import("zig/build/server.zig"); const golden_build = @import("zig/build/golden.zig"); comptime { @@ -204,6 +205,7 @@ fn nativeServer(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.b .imports = &.{ .{ .name = "engine_api", .module = api }, .{ .name = "tokenizer", .module = tokenizer }, .{ .name = "template", .module = template }, .{ .name = "native_engines", .module = engines }, .{ .name = "checkpoint_cli", .module = b.createModule(.{ .root_source_file = b.path("zig/src/cli/cli.zig"), .target = target, .optimize = .ReleaseSafe, .link_libc = true, .imports = &.{ .{ .name = "native_engines", .module = engines }, exlr8_build.cliImport(b, target, .ReleaseSafe, engine) } }) } }, }) }); exe.root_module.addOptions("build_options", build_options); + _ = server_build.addTo(b, exe.root_module, target, .ReleaseSafe); if (test_step == null) { exe.root_module.strip = true; return exe; @@ -221,10 +223,13 @@ fn nativeServer(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.b .link_libc = true, .imports = &.{ .{ .name = "engine_api", .module = api }, .{ .name = "tokenizer", .module = tokenizer }, .{ .name = "template", .module = template } }, }); + const server_json = server_build.addTo(b, server_tests, target, .Debug); test_step.?.dependOn(&b.addRunArtifact(b.addTest(.{ .root_module = server_tests })).step); + test_step.?.dependOn(&b.addRunArtifact(b.addTest(.{ .root_module = server_json })).step); @import("zig/build/cortheon_fuzz.zig").add(b, target, api, tokenizer, template); // the parse half's tests, as their own test binary (zig/src/server/tool_parse_test.zig) const tool_parse_tests = b.addTest(.{ .root_module = b.createModule(.{ .root_source_file = b.path("zig/src/server/tool_parse_test.zig"), .target = target, .optimize = .Debug, .link_libc = true, .imports = &.{ .{ .name = "engine_api", .module = api }, .{ .name = "tokenizer", .module = tokenizer }, .{ .name = "template", .module = template } } }) }); + _ = server_build.addTo(b, tool_parse_tests.root_module, target, .Debug); test_step.?.dependOn(&b.addRunArtifact(tool_parse_tests).step); // the chat-template engine's tests (zig/src/core/template/tests.zig), which no other test binary reaches test_step.?.dependOn(&b.addRunArtifact(b.addTest(.{ .root_module = b.createModule(.{ .root_source_file = b.path("zig/src/core/template/tests.zig"), .target = target, .optimize = .Debug, .link_libc = true }) })).step); diff --git a/zig/build/cortheon_fuzz.zig b/zig/build/cortheon_fuzz.zig index b17d0e99d0..709bf01f37 100644 --- a/zig/build/cortheon_fuzz.zig +++ b/zig/build/cortheon_fuzz.zig @@ -20,6 +20,7 @@ pub fn add(b: *std.Build, target: std.Build.ResolvedTarget, api: *Module, tokeni }), .filters = &.{"cortheon.fuzz."}, }); + _ = @import("server.zig").addTo(b, harness.root_module, target, optimize); const step = b.step("fuzz-cortheon", "Cortheon's page, link, search and filter readers under the fuzz harness"); step.dependOn(&b.addRunArtifact(harness).step); } diff --git a/zig/build/cuda.zig b/zig/build/cuda.zig index eac681628c..a05e74ccd0 100644 --- a/zig/build/cuda.zig +++ b/zig/build/cuda.zig @@ -173,6 +173,7 @@ fn nativeServer(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.b .imports = &.{ .{ .name = "engine_api", .module = m.api }, .{ .name = "tokenizer", .module = tokenizer }, .{ .name = "template", .module = template }, .{ .name = "native_engines", .module = m.engines }, .{ .name = "checkpoint_cli", .module = checkpointCli(b, target, .ReleaseSafe, null, m.engines, core) } }, }) }); exe.root_module.addOptions("build_options", build_options); + _ = @import("server.zig").addTo(b, exe.root_module, target, .ReleaseSafe); if (!install_native) { exe.root_module.strip = true; return exe; @@ -201,9 +202,14 @@ pub fn hostTests(b: *std.Build, draft_ids: *std.Build.Module, build_options: *st .link_libc = true, .imports = &.{ .{ .name = "engine_api", .module = native_modules.api }, .{ .name = "tokenizer", .module = mods.tokenizer }, .{ .name = "template", .module = template } }, }); + const server_json = @import("server.zig").addTo(b, server_tests, host, .debug); const server_test = b.addRunArtifact(b.addTest(.{ .root_module = server_tests })); - step.dependOn(&server_test.step); - b.step("test-server-cpu", "The HTTP server's unit tests (routes, templates, tool parsing) without a GPU").dependOn(&server_test.step); + const json_test = b.addRunArtifact(b.addTest(.{ .root_module = server_json })); + const server_step = b.step("test-server-cpu", "The HTTP server's unit tests (routes, templates, tool parsing) without a GPU"); + for ([_]*std.Build.Step.Run{ server_test, json_test }) |run| { + step.dependOn(&run.step); + server_step.dependOn(&run.step); + } // the server goldens and Cortheon's fuzz step here when the target is not macOS, whose Metal build defines them if (server_steps) { golden_build.step(b, host, server_tests, native_modules.api, mods.tokenizer, template); diff --git a/zig/build/server.zig b/zig/build/server.zig new file mode 100644 index 0000000000..54b94bbe16 --- /dev/null +++ b/zig/build/server.zig @@ -0,0 +1,14 @@ +//! The server's shared JSON values, available to server and family modules. +const std = @import("std"); + +/// The server's JSON values as a module (zig/src/server/json.zig), so a family's serving code shares them. +pub fn json(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Module { + return b.createModule(.{ .root_source_file = b.path("zig/src/server/json.zig"), .target = target, .optimize = optimize }); +} + +/// Attach a server's shared JSON module; its tests run separately from the server's root. +pub fn addTo(b: *std.Build, m: *std.Build.Module, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Module { + const j = json(b, target, optimize); + m.addImport("json", j); + return j; +} diff --git a/zig/src/server/anthropic.zig b/zig/src/server/anthropic.zig index bf465e7ac2..c283689367 100644 --- a/zig/src/server/anthropic.zig +++ b/zig/src/server/anthropic.zig @@ -1,6 +1,6 @@ //! Anthropic's Messages routes over the chat handler: typed SSE events, tool_use blocks, count_tokens. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const http_body = @import("http_body.zig"); const fields = @import("fields.zig"); diff --git a/zig/src/server/anthropic_translate.zig b/zig/src/server/anthropic_translate.zig index f70b6a112c..095ad66c0a 100644 --- a/zig/src/server/anthropic_translate.zig +++ b/zig/src/server/anthropic_translate.zig @@ -1,6 +1,6 @@ //! Anthropic Messages requests as the chat requests that run them (``anthropic_translate.translate``). const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const fields = @import("fields.zig"); const pyrepr = @import("pyrepr.zig"); diff --git a/zig/src/server/chat.zig b/zig/src/server/chat.zig index 7c702ef432..4921b742b0 100644 --- a/zig/src/server/chat.zig +++ b/zig/src/server/chat.zig @@ -1,7 +1,7 @@ //! One reply, as ``ChatApp.chat`` makes it: render, submit to the engine, stream text, reasoning and calls. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const fields_mod = @import("fields.zig"); const reply_text = @import("reply_text.zig"); diff --git a/zig/src/server/chunk_plan.zig b/zig/src/server/chunk_plan.zig index 2a4505cdca..9c2ab0e3f3 100644 --- a/zig/src/server/chunk_plan.zig +++ b/zig/src/server/chunk_plan.zig @@ -1,6 +1,6 @@ //! Where a prompt's prefill chunks start (Python's PrefillPlan and message_markers): prompts that agree up to a start cut alike up to it. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const prompt = @import("prompt.zig"); const Server = @import("server.zig").Server; diff --git a/zig/src/server/compact.zig b/zig/src/server/compact.zig index a295aba25b..fce4234e7b 100644 --- a/zig/src/server/compact.zig +++ b/zig/src/server/compact.zig @@ -1,6 +1,6 @@ //! Note and reply are ordinary greedy or keyed generations, so the same request compacts and answers the same way. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const chat = @import("chat.zig"); const stored = @import("compact_mem.zig"); const server_mod = @import("server.zig"); diff --git a/zig/src/server/compact_mem.zig b/zig/src/server/compact_mem.zig index eca242ed0f..b45513bad6 100644 --- a/zig/src/server/compact_mem.zig +++ b/zig/src/server/compact_mem.zig @@ -1,6 +1,6 @@ //! The compaction note file and the hash of the messages a note already covers. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const Server = @import("server.zig").Server; const Value = json.Value; const Allocator = std.mem.Allocator; diff --git a/zig/src/server/compact_test.zig b/zig/src/server/compact_test.zig index b78bf4eff2..986fd10922 100644 --- a/zig/src/server/compact_test.zig +++ b/zig/src/server/compact_test.zig @@ -1,7 +1,7 @@ //! Host checks for opt-in compaction. The fake engine records each prompt and answers OK. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const model_text = @import("model_text.zig"); const chat = @import("chat.zig"); diff --git a/zig/src/server/completion_prompt_test.zig b/zig/src/server/completion_prompt_test.zig index ae32cef584..51fc932caf 100644 --- a/zig/src/server/completion_prompt_test.zig +++ b/zig/src/server/completion_prompt_test.zig @@ -1,7 +1,7 @@ //! Token ids in a completion prompt, top-level or nested: ids in the vocabulary are served, other values get a 400. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const model_text = @import("model_text.zig"); const openai = @import("openai.zig"); const Server = @import("server.zig").Server; diff --git a/zig/src/server/cortheon/checks.zig b/zig/src/server/cortheon/checks.zig index 90a754c665..d6e7b53f76 100644 --- a/zig/src/server/cortheon/checks.zig +++ b/zig/src/server/cortheon/checks.zig @@ -1,6 +1,6 @@ //! Cortheon's checks before a reply ends: changed files tested before "done", researched answers naming sources. const std = @import("std"); -const json = @import("../json.zig"); +const json = @import("json"); const tools = @import("tools.zig"); const Value = json.Value; diff --git a/zig/src/server/cortheon/cortheon.zig b/zig/src/server/cortheon/cortheon.zig index fd51addf2d..665c4f5a68 100644 --- a/zig/src/server/cortheon/cortheon.zig +++ b/zig/src/server/cortheon/cortheon.zig @@ -1,6 +1,6 @@ //! Cortheon in the server (--cortheon): its reasoning program, web research before building, server-run web tools. const std = @import("std"); -const json = @import("../json.zig"); +const json = @import("json"); const chat = @import("../chat.zig"); const grammar = @import("../grammar.zig"); const prompt_mod = @import("../prompt.zig"); diff --git a/zig/src/server/cortheon/cortheon_test.zig b/zig/src/server/cortheon/cortheon_test.zig index 019fcf7f1d..2287eaac82 100644 --- a/zig/src/server/cortheon/cortheon_test.zig +++ b/zig/src/server/cortheon/cortheon_test.zig @@ -1,7 +1,7 @@ //! Cortheon end to end on a scripted engine and a stand-in web: rounds, research, streams, splices and checks. const std = @import("std"); const api = @import("engine_api"); -const json = @import("../json.zig"); +const json = @import("json"); const model_text = @import("../model_text.zig"); const openai = @import("../openai.zig"); const server_mod = @import("../server.zig"); diff --git a/zig/src/server/cortheon/loop.zig b/zig/src/server/cortheon/loop.zig index 6939e14580..52eb5db2cc 100644 --- a/zig/src/server/cortheon/loop.zig +++ b/zig/src/server/cortheon/loop.zig @@ -1,6 +1,6 @@ //! Cortheon's reply loop: rounds with the model's server tool calls run between them, checks at the end, one reply. const std = @import("std"); -const json = @import("../json.zig"); +const json = @import("json"); const errors = @import("../errors.zig"); const chat = @import("../chat.zig"); const tool_parse = @import("../tool_parse.zig"); diff --git a/zig/src/server/cortheon/memory.zig b/zig/src/server/cortheon/memory.zig index f90a11aa44..b067e8b255 100644 --- a/zig/src/server/cortheon/memory.zig +++ b/zig/src/server/cortheon/memory.zig @@ -1,6 +1,6 @@ //! What a reply's client never saw (server tool rounds, Cortheon notes), kept to splice back in front of it next turn. const std = @import("std"); -const json = @import("../json.zig"); +const json = @import("json"); const Value = json.Value; const Allocator = std.mem.Allocator; diff --git a/zig/src/server/cortheon/research.zig b/zig/src/server/cortheon/research.zig index ef07c1af5e..7483b53e32 100644 --- a/zig/src/server/cortheon/research.zig +++ b/zig/src/server/cortheon/research.zig @@ -1,6 +1,6 @@ //! Research before building: the model names searches, the server runs them and reads the best pages, as hidden rounds. const std = @import("std"); -const json = @import("../json.zig"); +const json = @import("json"); const errors = @import("../errors.zig"); const chat = @import("../chat.zig"); const ids = @import("../ids.zig"); diff --git a/zig/src/server/cortheon/search.zig b/zig/src/server/cortheon/search.zig index 36fadd40cf..590a216f30 100644 --- a/zig/src/server/cortheon/search.zig +++ b/zig/src/server/cortheon/search.zig @@ -1,6 +1,6 @@ //! Web search for Cortheon: DuckDuckGo's keyless HTML results, or Brave's search API when a key is set. const std = @import("std"); -const json = @import("../json.zig"); +const json = @import("json"); const html = @import("html.zig"); const Allocator = std.mem.Allocator; diff --git a/zig/src/server/cortheon/tools.zig b/zig/src/server/cortheon/tools.zig index 376706ee19..8901629781 100644 --- a/zig/src/server/cortheon/tools.zig +++ b/zig/src/server/cortheon/tools.zig @@ -1,6 +1,6 @@ //! Cortheon's server-run tools: their specs, which calls are theirs, and each call run into the text the model reads. const std = @import("std"); -const json = @import("../json.zig"); +const json = @import("json"); const search = @import("search.zig"); const Seen = @import("seen.zig").Seen; const Value = json.Value; diff --git a/zig/src/server/decisions.zig b/zig/src/server/decisions.zig index b3bd3b64fa..ad87626352 100644 --- a/zig/src/server/decisions.zig +++ b/zig/src/server/decisions.zig @@ -1,6 +1,6 @@ //! /v1/decisions checks a body the way 0.6.6 checks it, then scores through the engine hook when a family sets one. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const fields = @import("fields.zig"); const pyrepr = @import("pyrepr.zig"); diff --git a/zig/src/server/decisions_test.zig b/zig/src/server/decisions_test.zig index 160622e9a9..ca3dc87acb 100644 --- a/zig/src/server/decisions_test.zig +++ b/zig/src/server/decisions_test.zig @@ -1,7 +1,7 @@ //! Request checks for /v1/decisions, and a fake engine hook that scores one choice. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const openai = @import("openai.zig"); const model_text = @import("model_text.zig"); diff --git a/zig/src/server/fields.zig b/zig/src/server/fields.zig index cd2a9d7340..0ccdc64f18 100644 --- a/zig/src/server/fields.zig +++ b/zig/src/server/fields.zig @@ -1,6 +1,6 @@ //! Request field checks shared by every route: numbers, stops, thinking switches, efforts, probabilities. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const Value = json.Value; const Cx = errors.Cx; diff --git a/zig/src/server/grammar.zig b/zig/src/server/grammar.zig index c8a68b5c97..543f08a265 100644 --- a/zig/src/server/grammar.zig +++ b/zig/src/server/grammar.zig @@ -1,7 +1,7 @@ //! Structured-output fields checked as ``engine.grammar.request_spec`` checks them; the engine enforces them. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const pyrepr = @import("pyrepr.zig"); const tool_specs = @import("tool_specs.zig"); diff --git a/zig/src/server/hf_text.zig b/zig/src/server/hf_text.zig index 65c3a474d5..8a912a29e1 100644 --- a/zig/src/server/hf_text.zig +++ b/zig/src/server/hf_text.zig @@ -2,7 +2,7 @@ const std = @import("std"); const tokenizer = @import("tokenizer"); const template = @import("template"); -const json = @import("json.zig"); +const json = @import("json"); const model_text = @import("model_text.zig"); const Value = json.Value; const Allocator = std.mem.Allocator; diff --git a/zig/src/server/http_body.zig b/zig/src/server/http_body.zig index ad2951ebcc..257d11e1be 100644 --- a/zig/src/server/http_body.zig +++ b/zig/src/server/http_body.zig @@ -1,6 +1,6 @@ //! Bounded request bodies, fixed-length or chunked, refused as the Python server refuses them. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const Conn = @import("http_conn.zig").Conn; const Allocator = std.mem.Allocator; diff --git a/zig/src/server/json.zig b/zig/src/server/json.zig index 2b69a19fc6..c0a035874f 100644 --- a/zig/src/server/json.zig +++ b/zig/src/server/json.zig @@ -5,6 +5,7 @@ const Allocator = std.mem.Allocator; pub const parse = @import("json_parse.zig").parse; pub const parseText = @import("json_parse.zig").parseText; pub const ParseResult = @import("json_parse.zig").Result; +pub const wtf8Encode = @import("json_parse.zig").wtf8Encode; pub const write = @import("json_write.zig").write; pub const writeString = @import("json_write.zig").writeString; pub const Options = @import("json_write.zig").Options; diff --git a/zig/src/server/live.zig b/zig/src/server/live.zig index cb0cbaf640..8a1f7df742 100644 --- a/zig/src/server/live.zig +++ b/zig/src/server/live.zig @@ -1,7 +1,7 @@ //! The live status line (connections, decode and prefill tok/s), redrawn in a terminal, and /health's copy of it. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const log = @import("log.zig"); const Allocator = std.mem.Allocator; diff --git a/zig/src/server/logprobs.zig b/zig/src/server/logprobs.zig index 669c07f060..549ec9ea15 100644 --- a/zig/src/server/logprobs.zig +++ b/zig/src/server/logprobs.zig @@ -1,7 +1,7 @@ //! OpenAI ``logprobs`` (who may ask, ``choices[0].logprobs`` from the engine's rows) and vLLM's ``prompt_logprobs``. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const reply_text = @import("reply_text.zig"); const Server = @import("server.zig").Server; diff --git a/zig/src/server/main.zig b/zig/src/server/main.zig index 4b85fca8cd..b2e0b971b5 100644 --- a/zig/src/server/main.zig +++ b/zig/src/server/main.zig @@ -1,6 +1,6 @@ //! ``tensorfold-native``: ``capabilities --json`` for the Python switch, and ``serve MODEL [flags]`` with no Python. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const cli = @import("cli.zig"); const log = @import("log.zig"); const hub = @import("hub.zig"); diff --git a/zig/src/server/memory_routes.zig b/zig/src/server/memory_routes.zig index 5a168451b5..a8fa319137 100644 --- a/zig/src/server/memory_routes.zig +++ b/zig/src/server/memory_routes.zig @@ -1,7 +1,7 @@ //! Authenticated, read-only sizing diagnostics; unknown counters and plans are omitted rather than guessed. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const process = @import("process_memory.zig"); const routes = @import("routes.zig"); const Server = @import("server.zig").Server; diff --git a/zig/src/server/messages.zig b/zig/src/server/messages.zig index 9559ed784b..978eb98aa3 100644 --- a/zig/src/server/messages.zig +++ b/zig/src/server/messages.zig @@ -1,6 +1,6 @@ //! Chat messages as the template sees them: leading instructions merged, text parts joined, call arguments as objects. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const fields = @import("fields.zig"); const Value = json.Value; diff --git a/zig/src/server/model_text.zig b/zig/src/server/model_text.zig index 0b36055a7f..d7b56167ca 100644 --- a/zig/src/server/model_text.zig +++ b/zig/src/server/model_text.zig @@ -1,6 +1,6 @@ //! The tokenizer and chat template a server renders prompts and replies with (the tok and jinja branches plug in here). const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const Allocator = std.mem.Allocator; pub const RenderOptions = struct { diff --git a/zig/src/server/openai.zig b/zig/src/server/openai.zig index b8782aaf96..157ade230b 100644 --- a/zig/src/server/openai.zig +++ b/zig/src/server/openai.zig @@ -1,6 +1,6 @@ //! POST /v1/chat/completions and /v1/completions, JSON or SSE, as ``server.http`` answers them. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const fields = @import("fields.zig"); const chat = @import("chat.zig"); diff --git a/zig/src/server/prompt.zig b/zig/src/server/prompt.zig index e68363bfe7..f02c112a39 100644 --- a/zig/src/server/prompt.zig +++ b/zig/src/server/prompt.zig @@ -1,6 +1,6 @@ //! Prompt ids from a request, as ``prepare_prompt`` and ``render_prompt_ids`` make them. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const messages_mod = @import("messages.zig"); const model_text = @import("model_text.zig"); diff --git a/zig/src/server/pyrepr.zig b/zig/src/server/pyrepr.zig index d560773580..255232af62 100644 --- a/zig/src/server/pyrepr.zig +++ b/zig/src/server/pyrepr.zig @@ -1,6 +1,6 @@ //! Python's ``repr`` of decoded JSON, for refusal messages that quote a request's value. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const Value = json.Value; const Allocator = std.mem.Allocator; diff --git a/zig/src/server/request_log.zig b/zig/src/server/request_log.zig index ea4c8b7997..7abf7e022e 100644 --- a/zig/src/server/request_log.zig +++ b/zig/src/server/request_log.zig @@ -1,6 +1,6 @@ //! TENSORFOLD_REQUEST_LOG: each chat and completion body appended as one JSON line, images redacted, for replays. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const Value = json.Value; const Allocator = std.mem.Allocator; diff --git a/zig/src/server/responses.zig b/zig/src/server/responses.zig index 2e096025b5..e84a74d0a9 100644 --- a/zig/src/server/responses.zig +++ b/zig/src/server/responses.zig @@ -1,6 +1,6 @@ //! OpenAI's Responses API: each request runs as its chat completion, translated item by item and event by event. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const http_body = @import("http_body.zig"); const openai = @import("openai.zig"); diff --git a/zig/src/server/responses_include_test.zig b/zig/src/server/responses_include_test.zig index e117f116b5..3039b8907b 100644 --- a/zig/src/server/responses_include_test.zig +++ b/zig/src/server/responses_include_test.zig @@ -1,6 +1,6 @@ //! Responses' include: OpenAI's values accepted and ignored, anything else refused by name. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const responses_translate = @import("responses_translate.zig"); diff --git a/zig/src/server/responses_translate.zig b/zig/src/server/responses_translate.zig index 8b1b2b17f3..6a5f4c8282 100644 --- a/zig/src/server/responses_translate.zig +++ b/zig/src/server/responses_translate.zig @@ -1,6 +1,6 @@ //! A Responses request as the chat completion that runs it (``responses_translate.translate``). const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const fields = @import("fields.zig"); const pyrepr = @import("pyrepr.zig"); diff --git a/zig/src/server/root.zig b/zig/src/server/root.zig index 7630f5217a..29e2fecdde 100644 --- a/zig/src/server/root.zig +++ b/zig/src/server/root.zig @@ -1,5 +1,5 @@ //! The native HTTP server's surface: what main and the test servers build a server from. -pub const json = @import("json.zig"); +pub const json = @import("json"); pub const errors = @import("errors.zig"); pub const auth = @import("auth.zig"); pub const cli = @import("cli.zig"); @@ -17,7 +17,7 @@ pub const Config = server.Config; test { @import("std").testing.refAllDecls(@This()); - _ = @import("json.zig"); + _ = @import("json"); _ = @import("std_options.zig"); _ = @import("fields.zig"); _ = @import("reply_text.zig"); diff --git a/zig/src/server/routes.zig b/zig/src/server/routes.zig index 44981cdda9..35186a5eca 100644 --- a/zig/src/server/routes.zig +++ b/zig/src/server/routes.zig @@ -1,6 +1,6 @@ //! Method and path dispatch, as ``do_GET``, ``do_POST`` and ``do_DELETE`` route them. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const http_conn = @import("http_conn.zig"); const http_body = @import("http_body.zig"); const auth = @import("auth.zig"); diff --git a/zig/src/server/serve.zig b/zig/src/server/serve.zig index da27cb6b0e..b5e73ed53b 100644 --- a/zig/src/server/serve.zig +++ b/zig/src/server/serve.zig @@ -1,7 +1,7 @@ //! A server's life: keys, the listening socket, the startup lines, the live line, and a clean stop on SIGTERM or SIGINT. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const auth = @import("auth.zig"); const cli = @import("cli.zig"); const log = @import("log.zig"); diff --git a/zig/src/server/server.zig b/zig/src/server/server.zig index 011734ee9a..97ab3e9c0c 100644 --- a/zig/src/server/server.zig +++ b/zig/src/server/server.zig @@ -1,7 +1,7 @@ //! The server: one engine and tokenizer behind the HTTP routes, one thread a connection. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const fields = @import("fields.zig"); const auth = @import("auth.zig"); diff --git a/zig/src/server/server_init_test.zig b/zig/src/server/server_init_test.zig index 627d8a7691..0a4872b177 100644 --- a/zig/src/server/server_init_test.zig +++ b/zig/src/server/server_init_test.zig @@ -1,7 +1,7 @@ //! A server init that fails after its idle keepalive started stops that ticker and frees all it took. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const model_text = @import("model_text.zig"); const server = @import("server.zig"); const Allocator = std.mem.Allocator; diff --git a/zig/src/server/slide.zig b/zig/src/server/slide.zig index 0312840011..c57ddf819f 100644 --- a/zig/src/server/slide.zig +++ b/zig/src/server/slide.zig @@ -1,7 +1,7 @@ //! Sliding Weights over HTTP: /v1/slide/learn streams learning, /v1/slide/graph lists or clears facts, /slide draws. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const sse = @import("sse.zig"); const http_body = @import("http_body.zig"); const routes = @import("routes.zig"); diff --git a/zig/src/server/slide_ask.zig b/zig/src/server/slide_ask.zig index fca6c989ef..57e3c8aa16 100644 --- a/zig/src/server/slide_ask.zig +++ b/zig/src/server/slide_ask.zig @@ -1,7 +1,7 @@ //! What a lesson asks the model and how replies become examples: chat replies, continuations, token ids. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const chat = @import("chat.zig"); const prompt = @import("prompt.zig"); const errors = @import("errors.zig"); diff --git a/zig/src/server/slide_graph.zig b/zig/src/server/slide_graph.zig index 596da2b110..e975f5b081 100644 --- a/zig/src/server/slide_graph.zig +++ b/zig/src/server/slide_graph.zig @@ -1,7 +1,7 @@ //! The Sliding Weights fact graph: what was taught, how far each lesson is, where its neurons went; never the weights. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const slide_model = @import("slide_model.zig"); const Allocator = std.mem.Allocator; const Io = std.Io; diff --git a/zig/src/server/slide_lesson.zig b/zig/src/server/slide_lesson.zig index fbcb5eb609..cb0784abca 100644 --- a/zig/src/server/slide_lesson.zig +++ b/zig/src/server/slide_lesson.zig @@ -1,7 +1,7 @@ //! A fact's lesson written by the model itself: the teller's questions, short answers, near misses, keep prompts. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const chat = @import("chat.zig"); const prompt = @import("prompt.zig"); const errors = @import("errors.zig"); diff --git a/zig/src/server/slide_model.zig b/zig/src/server/slide_model.zig index 274f9bb59b..014fcca7c1 100644 --- a/zig/src/server/slide_model.zig +++ b/zig/src/server/slide_model.zig @@ -1,6 +1,6 @@ //! The served model as the Sliding Weights view draws it: its layers, its pockets, and the shards that hold them. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const Allocator = std.mem.Allocator; const Io = std.Io; diff --git a/zig/src/server/slide_teacher.zig b/zig/src/server/slide_teacher.zig index a6743a0ce2..7d1534e111 100644 --- a/zig/src/server/slide_teacher.zig +++ b/zig/src/server/slide_teacher.zig @@ -1,7 +1,7 @@ //! What every lesson shares, written once: keep prompts with the model's answers, the personal bank, the turn's end. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const log = @import("log.zig"); const prompts = @import("slide_prompts.zig"); const slide_ask = @import("slide_ask.zig"); diff --git a/zig/src/server/slide_think.zig b/zig/src/server/slide_think.zig index dce2cb1ba6..26f361597b 100644 --- a/zig/src/server/slide_think.zig +++ b/zig/src/server/slide_think.zig @@ -1,7 +1,7 @@ //! A lesson with thinking on: the model's reasoning to where it restates the question, then a learned recall line. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const chat = @import("chat.zig"); const prompt = @import("prompt.zig"); const errors = @import("errors.zig"); diff --git a/zig/src/server/sse.zig b/zig/src/server/sse.zig index de30ac1212..0942a7e145 100644 --- a/zig/src/server/sse.zig +++ b/zig/src/server/sse.zig @@ -1,6 +1,6 @@ //! Server-sent events as the Python server frames them: the head, ``data:`` frames, typed ``event:`` frames, ``[DONE]``. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const Conn = @import("http_conn.zig").Conn; const Allocator = std.mem.Allocator; diff --git a/zig/src/server/status_routes.zig b/zig/src/server/status_routes.zig index 89ee5c8488..9c220f4445 100644 --- a/zig/src/server/status_routes.zig +++ b/zig/src/server/status_routes.zig @@ -1,7 +1,7 @@ //! GET /health, /v1/models, /metrics, and the opt-in dashboard. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const live = @import("live.zig"); const routes = @import("routes.zig"); const Server = @import("server.zig").Server; diff --git a/zig/src/server/tokens.zig b/zig/src/server/tokens.zig index 3a2e351921..81a3deed62 100644 --- a/zig/src/server/tokens.zig +++ b/zig/src/server/tokens.zig @@ -1,6 +1,6 @@ //! vLLM's /tokenize and /detokenize (the ids the chat and completion routes would run), and a reply's token SHA. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const fields = @import("fields.zig"); const messages = @import("messages.zig"); diff --git a/zig/src/server/tool_grammar.zig b/zig/src/server/tool_grammar.zig index 27b76df1c9..f087833d5e 100644 --- a/zig/src/server/tool_grammar.zig +++ b/zig/src/server/tool_grammar.zig @@ -1,7 +1,7 @@ //! tool_choice "required" or a named function as a grammar: calls in the template's markup, arguments in their schema. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const prompt = @import("prompt.zig"); const tool_specs = @import("tool_specs.zig"); diff --git a/zig/src/server/tool_params.zig b/zig/src/server/tool_params.zig index c59d11cfbe..51352dc5ec 100644 --- a/zig/src/server/tool_params.zig +++ b/zig/src/server/tool_params.zig @@ -1,6 +1,6 @@ //! Typed tool parameters: XML parameter text decoded by the offered schema (``tool_parameters.py``). const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const reply_text = @import("reply_text.zig"); const tool_specs = @import("tool_specs.zig"); const Value = json.Value; @@ -324,7 +324,7 @@ const Literal = struct { fn appendCode(a: Allocator, out: *std.ArrayList(u8), v: u21) Error!void { if (v > 0x10ffff) return error.Invalid; var buf: [4]u8 = undefined; - const n = @import("json_parse.zig").wtf8Encode(v, &buf); + const n = @import("json").wtf8Encode(v, &buf); try out.appendSlice(a, buf[0..n]); } diff --git a/zig/src/server/tool_parse.zig b/zig/src/server/tool_parse.zig index b660b3b73d..b496d0851a 100644 --- a/zig/src/server/tool_parse.zig +++ b/zig/src/server/tool_parse.zig @@ -1,6 +1,6 @@ //! Tool calls in a finished reply, every family's markup, as OpenAI tool_calls (``tools.parse_tool_calls_from_content``). const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const ids = @import("ids.zig"); const reply_text = @import("reply_text.zig"); const tool_params = @import("tool_params.zig"); diff --git a/zig/src/server/tool_parse_test.zig b/zig/src/server/tool_parse_test.zig index 7481f1e311..f503f88006 100644 --- a/zig/src/server/tool_parse_test.zig +++ b/zig/src/server/tool_parse_test.zig @@ -1,6 +1,6 @@ //! The tool_parse tests, as their own test binary: whole-reply parses and the close-call helpers. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const tool_parse = @import("tool_parse.zig"); const parse = tool_parse.parse; const closeCall = tool_parse.closeCall; diff --git a/zig/src/server/tool_specs.zig b/zig/src/server/tool_specs.zig index 1a20f48025..cca2610dd8 100644 --- a/zig/src/server/tool_specs.zig +++ b/zig/src/server/tool_specs.zig @@ -1,6 +1,6 @@ //! Offered tools and tool_choice as the template should see them (``tools.active_tool_specs``). const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const Value = json.Value; const Cx = errors.Cx; diff --git a/zig/src/server/tool_stream.zig b/zig/src/server/tool_stream.zig index 74b8610e7b..b55659c239 100644 --- a/zig/src/server/tool_stream.zig +++ b/zig/src/server/tool_stream.zig @@ -1,6 +1,6 @@ //! Tool calls while they are written: XML calls as argument deltas, and the one-call policy's text filter. const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const ids = @import("ids.zig"); const reply_text = @import("reply_text.zig"); const tool_params = @import("tool_params.zig"); diff --git a/zig/src/server/tool_stream_test.zig b/zig/src/server/tool_stream_test.zig index e1ed215f02..d33ef34813 100644 --- a/zig/src/server/tool_stream_test.zig +++ b/zig/src/server/tool_stream_test.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const tool_params = @import("tool_params.zig"); const stream = @import("tool_stream.zig"); const Streamer = stream.Streamer; diff --git a/zig/src/server/tool_streaming.zig b/zig/src/server/tool_streaming.zig index 700caedd7c..48fe167eea 100644 --- a/zig/src/server/tool_streaming.zig +++ b/zig/src/server/tool_streaming.zig @@ -1,6 +1,6 @@ //! The streaming half of tool calls: each finished call's opening delta, then its arguments (``stream_tool_call_deltas``). const std = @import("std"); -const json = @import("json.zig"); +const json = @import("json"); const tool_specs = @import("tool_specs.zig"); const Value = json.Value; const Allocator = std.mem.Allocator; diff --git a/zig/src/server/warm.zig b/zig/src/server/warm.zig index f02f8a0c7d..1bf80ce4b2 100644 --- a/zig/src/server/warm.zig +++ b/zig/src/server/warm.zig @@ -1,7 +1,7 @@ //! After a chat reply, the next turn's shared prompt prefilled in the background, so that turn resumes past the reply. const std = @import("std"); const api = @import("engine_api"); -const json = @import("json.zig"); +const json = @import("json"); const errors = @import("errors.zig"); const prompt_mod = @import("prompt.zig"); const chat = @import("chat.zig"); diff --git a/zig/tests/server/build.sh b/zig/tests/server/build.sh index 63dfaa28c2..b3587d521c 100755 --- a/zig/tests/server/build.sh +++ b/zig/tests/server/build.sh @@ -11,10 +11,10 @@ version="$(sed -n 's/^[[:space:]]*\.version = "\([0-9]*\.[0-9]*\.[0-9]*\)",$/\1/ options="$out/build_options.zig" printf 'pub const version = "%s";\n' "$version" > "$options" core=(--dep lanes "-Mengine_api=$root/zig/src/core/engine_api.zig" "-Mlanes=$root/zig/src/core/lanes/lanes.zig" - "-Mtokenizer=$root/zig/src/core/tokenizer/tokenizer.zig" "-Mtemplate=$root/zig/src/core/template/template.zig") + "-Mtokenizer=$root/zig/src/core/tokenizer/tokenizer.zig" "-Mtemplate=$root/zig/src/core/template/template.zig" "-Mjson=$root/zig/src/server/json.zig") "$zig" build-exe -lc -O "${OPT:-ReleaseSafe}" --dep server --dep engine_api "-Mroot=$root/zig/tests/server/fake_serve.zig" \ - --dep engine_api --dep tokenizer --dep template "-Mserver=$root/zig/src/server/root.zig" "${core[@]}" \ + --dep engine_api --dep tokenizer --dep template --dep json "-Mserver=$root/zig/src/server/root.zig" "${core[@]}" \ --name fake_serve -femit-bin="$out/fake_serve" -"$zig" build-exe -lc -O "${OPT:-ReleaseSafe}" --dep engine_api --dep tokenizer --dep template --dep native_engines --dep build_options \ +"$zig" build-exe -lc -O "${OPT:-ReleaseSafe}" --dep engine_api --dep tokenizer --dep template --dep json --dep native_engines --dep build_options \ "-Mroot=$root/zig/src/server/main.zig" --dep engine_api "-Mnative_engines=$root/zig/src/native/none.zig" "${core[@]}" \ "-Mbuild_options=$options" --name tensorfold-native -femit-bin="$out/tensorfold-native" diff --git a/zig/tests/server/zig_test.sh b/zig/tests/server/zig_test.sh index 4f583f439c..687071980d 100755 --- a/zig/tests/server/zig_test.sh +++ b/zig/tests/server/zig_test.sh @@ -3,10 +3,12 @@ set -euo pipefail zig="${ZIG:-zig}" root="$(cd "$(dirname "$0")/../../.." && pwd)" -"$zig" test -lc --dep engine_api --dep tokenizer --dep template \ +"$zig" test -lc --dep engine_api --dep tokenizer --dep template --dep json \ "-Mroot=$root/zig/src/server/root.zig" \ + "-Mjson=$root/zig/src/server/json.zig" \ --dep lanes "-Mengine_api=$root/zig/src/core/engine_api.zig" \ "-Mlanes=$root/zig/src/core/lanes/lanes.zig" \ "-Mtokenizer=$root/zig/src/core/tokenizer/tokenizer.zig" \ "-Mtemplate=$root/zig/src/core/template/template.zig" "$@" +"$zig" test "$root/zig/src/server/json.zig" "$zig" test -lc --dep lanes "-Mroot=$root/zig/src/core/engine_api.zig" "-Mlanes=$root/zig/src/core/lanes/lanes.zig"