18 Commits
Author SHA1 Message Date
m1saka 22d78c4576 Add recent API request recorder with admin tab and /api/recent endpoint
build / build (push) Successful in 2m31s
Record the last 10 /v1/ API requests (including errors) in an in-memory
ring buffer. Each entry captures request headers (Authorization masked),
request body, response status, and response body — all up to 1 MB.

- recorder.go: RecentRecorder ring buffer, recordingResponseWriter,
  withRecording middleware, getRecent handler
- server.go: add recorder to Server, wrap /v1/ routes, add /api/recent
- admin.html: new 最近请求 tab with lazy-load and expandable cards
- recorder_test.go: 5 tests (ring buffer, ordering, capture, errors, API)
v0.2.0
2026-08-23 14:52:33 +08:00
m1saka f988c47fec Fix silent data loss in function_call arguments/output non-string JSON parsing
build / build (push) Successful in 2m29s
responsesInputToMessages unmarshaled function_call.arguments and
function_call_output.output as bare strings, silently dropping the
value when it arrived as an object or content-parts array. This
caused the model to lose tool-call context in multi-turn
conversations, increasing the likelihood of malformed tool-call JSON.

Add rawJSONToString (re-encodes non-string values as JSON strings)
and outputToString (extracts text from content-parts arrays, re-encodes
other non-string values). Add 3 regression tests covering object
arguments, array output, and object output.
v0.1.5
2026-08-23 14:15:01 +08:00
m1saka f51ec09a09 gofmt: remove trailing blank lines in client.go
build / build (push) Successful in 2m31s
v0.1.4
2026-08-21 15:25:06 +08:00
m1saka b9a3f8d5cd Mirror Zhanlu client: GLM tool_stream, shared v4 UUID request id, drop chat state:ERROR
build / build (push) Successful in 2m26s
2026-08-21 14:27:37 +08:00
m1saka a0a2049440 Add 1d/7d/all time-range filter to admin by-model stats
build / build (push) Successful in 2m32s
By-model panel gains a segmented 1天/7天/全部 control. Selecting a
range fetches /api/stats?since=<RFC3339> and re-renders only that table
client-side, replicating the human/rate template helpers in JS; the
existing /api/stats since param already drives the server-side filter.

- internal/server/templates/admin.html: filter UI + JS, empty/loading states
- internal/server/server_test.go: render test for the filter controls
- scripts/test-instance.sh: build→start→stop→clean test-instance helper
v0.1.3
2026-08-20 17:08:39 +08:00
m1saka 9aba511abe Refactor server: extract shared helpers, fix tool-call ordering and finish_reason mapping
- Extract callUpstream helper to deduplicate ~30 lines between chatCompletions and responses
- Move HTML templates to internal/server/templates/ via go:embed (server.go 1749→1192 lines)
- Consolidate 4 copies of firstNonEmpty into util.FirstNonEmpty
- Extract chatStreamChunk named type shared by aggregateStream and aggregateResponsesStream
- Fix tool-call ordering: iterate sorted map keys instead of sequential 0..N
- Map upstream finish_reason to Responses API status (length/content_filter → incomplete)
- Surface /v1/models errors as 401/502 instead of silently returning empty 200
- Add Secure cookie flag via isTLSRequest helper
- forEachSSEChunk: use sseDataPayload parser, drop redundant json.Valid, distinguish bufio.ErrTooLong
- Fix StreamIdleTimout typo → StreamIdleTimeout
- sso.go: single Read → io.ReadAll(io.LimitReader), explicit unknown error fallback
2026-08-20 15:46:47 +08:00
m1saka 2517b4f730 Add OpenAI Responses API (/v1/responses) endpoint
Translate Responses API requests (input→messages, instructions→system,
max_output_tokens→max_tokens, text.format→response_format, flat tools→nested
{function:{…}}) to upstream chat/completions, then convert responses back to
Responses format (streaming SSE event lifecycle + non-streaming JSON).

Verified against OpenAI migration guide and Python SDK Response model:
- Echo back required fields parallel_tool_calls/tool_choice/tools
- Include content:[] in reasoning items, logprobs:[] in output_text parts
- Support function_call/function_call_output multi-turn input items
- Map usage fields prompt_tokens→input_tokens, completion_tokens→output_tokens
2026-08-20 10:02:11 +08:00
m1saka c8938cb514 Add available-models admin tab with live model list and latency probing
build / build (push) Successful in 2m29s
v0.1.2
2026-08-19 20:23:21 +08:00
root 8a1cf4d61f Redesign admin UI: unified tabbed console, humanized and paginated stats
build / build (push) Successful in 2m32s
- Unify /admin/login and /admin/stats into a single /admin page with tabs
  (Token stats default, credential login); old paths redirect to /admin.
- Restyle from dark glass-morphism to a clean light theme (single accent,
  system font stack, 1px-bordered cards, generous whitespace).
- Humanize token counts with K/M/B suffixes via a humanNum template func.
- Paginate recent requests client-side (10 per page) with a compact pager.
- Drop the database path from the UI.
- Fix mobile horizontal overflow caused by grid min-width:auto.
v0.1.1
2026-08-19 17:12:30 +08:00
m1saka fa9640d919 Add token usage stats and consolidate credentials in SQLite
build / build (push) Successful in 2m34s
- New internal/stats (types) and internal/store (SQLite owner: requests + credentials tables, WAL); store implements stats.Recorder.
- Stream (SSE tee) and non-stream chat paths parse upstream usage incl. cached_tokens and record per-request; add /api/stats, /api/stats/reset, /admin/stats HTML with cache hit rate.
- Drop credentials.json: remove auth file I/O and ZHANLU_CREDENTIALS_FILE; credential precedence is env vars > db row.
v0.1.0
2026-08-19 15:52:00 +08:00
root dd5c560b64 Build Windows release binaries
build / build (push) Successful in 1m52s
v0.0.5
2026-08-14 15:48:52 +08:00
m1saka 2e402934ea Polish login pages with glass-morphism design
build / build (push) Successful in 1m4s
Redesign the login and login-result pages within the existing dark glass
palette: layered star-dot/grid/gradient background, gradient hairline panel
borders, gradient headline text, primary/ghost button split, and tri-state
status dots (ok/err/busy). Fix zero vertical spacing inside the login form
(the form element had no gap between fields and the submit button).
v0.0.4
2026-08-05 19:56:53 +08:00
m1saka df19ced538 Drop ZHANLU_MODELS and ZHANLU_DEFAULT_MODEL config
build / build (push) Successful in 1m5s
Model list is always fetched live from the gateway model-info endpoint, so the
static fallback list was dead config with stale IDs (GLM-4.7 vs zhanlu/glm-4.7).
Default to zhanlu/auto when the request omits model.
v0.0.3
2026-08-05 15:06:38 +08:00
m1saka 7d8a5b6f74 Update proxy to Zhanlu v1.4.2 provider flow
The 1.4.2 extension replaced the old signed/encrypted chat gateway with an
OpenAI-compatible aigateway. Align the proxy with the new flow:

- Use ecloud.10086.cn login/model base URLs, zhanlu_ide plugin headers and
  v1.4.2 plugin version
- Provision the model API key via SM2-signed get-or-create after v1/login
  profile fetch; store api_key/model_base_url/email in credentials
- Chat via Bearer apiKey against {modelBaseUrl}/chat/completions with plain
  OpenAI SSE passthrough; fetch /v1/models from the gateway model-info endpoint
- Force HTTP/1.1 upstream (gateway drops HTTP/2 ALPN negotiation with EOF)
- Drop obsolete AES body encryption, model name mapping and vscode headers
2026-08-05 14:55:28 +08:00
m1saka c3af3caa5b Add admin login session flow
build / build (push) Successful in 58s
v0.0.2
2026-07-09 00:22:27 +08:00
m1saka b146ccb7ac Document systemd service setup
build / build (push) Successful in 51s
v0.0.1
2026-07-08 09:24:56 +08:00
m1saka e26579c63c Increase upstream timeout default
build / build (push) Successful in 52s
2026-07-08 09:19:01 +08:00
M1saka d4dd3a0f1b Initial zhanlu OpenAI proxy
build / build (push) Successful in 53s
2026-07-08 09:13:45 +08:00