From d2cab4198beed68929a5b1642a30c8336be219e6 Mon Sep 17 00:00:00 2001 From: worldmozara Date: Wed, 15 Jul 2026 10:52:58 +0800 Subject: [PATCH] core/cli: show estimated context tokens and usage source tags /status adds context_tokens~=(est); docs note api/estimate/mixed labels. --- CLAUDE.md | 4 ++-- src/plyngent/cli/repl.py | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e254ef5..d253eed 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -58,7 +58,7 @@ Async SQLAlchemy + aiosqlite. `MemoryStore`: schema init (+ lightweight SQLite ` - **`ChatAgent`**: optional `MemoryStore` (persist on success only); `stream`; system prompt; `pending_retry_text` + `retry()`. - **`/compact`**: soft-compact tool dumps → model summary (no tools) → **new** session seeded with summary message. - Events: text_delta, assistant_message, tool_call/result, max_rounds, **error** (`retryable`/`source`), **cancelled** (`reason`), **usage** (`TokenUsage`). -- Usage: API `usage` from completions (stream with `include_usage`); `ChatAgent.session_usage` / `last_turn_usage`; CLI end-of-turn + `/status`. +- Usage: API `usage` from completions (stream with `include_usage`); **char≈token fallback** (~4 chars/token) when omitted; `ChatAgent.session_usage` / `last_turn_usage`; CLI end-of-turn + `/status` (marks `(est)` / `(api+est)`). - Config ``[agent]``: `system_prompt`, `max_tool_result_chars`, `parallel_tools`, `confirm_destructive`, `path_denylist`, `max_context_chars`. ### Tools (`tools/`) @@ -101,7 +101,7 @@ Basedpyright `recommended`. Ruff includes `ANN` (private return types `ANN202` i - **Phase D (context quality)**: soft char budget, request compact, `/compact`, richer errors/cancel, workspace sessions. Context size is **char estimate** plus optional API usage when reported. - **No local tokenizer stage** for now. - **Phase E**: tooling depth (grep/glob, VCS backends; prefer `edit_replace` / `edit_lineno` over model-generated patches). -- **Phase F (providers + usage v2)**: capture response/stream `usage` — **in progress / landing**; session/turn totals; `/status` + end-of-turn line. Optional later: cost, tokenizer-backed estimates. +- **Phase F (providers + usage v2)**: API `usage` + char-based estimate fallback; session/turn totals; `/status` + end-of-turn. Optional later: cost, real tokenizer. - **Phase G–H**: CLI polish, hardening; then multi-tenant platform (`router/`, auth, sandboxed tools). ## Commit messages diff --git a/src/plyngent/cli/repl.py b/src/plyngent/cli/repl.py index 1c536a4..c43fe33 100644 --- a/src/plyngent/cli/repl.py +++ b/src/plyngent/cli/repl.py @@ -60,8 +60,11 @@ def _cmd_status(state: ReplState) -> None: pending_disp = "yes" if pending else "no" ctx_chars = estimate_messages_chars(state.agent.messages) ctx_budget = state.agent.max_context_chars + from plyngent.agent.usage import chars_to_tokens + session_u = state.agent.session_usage last_u = state.agent.last_turn_usage + ctx_est_tokens = chars_to_tokens(ctx_chars) click.echo( f"provider={state.provider_name} model={state.model}\n" f"session={state.session_id} messages={len(state.agent.messages)} " @@ -69,6 +72,7 @@ def _cmd_status(state: ReplState) -> None: f"tools={'on' if state.tools_enabled else 'off'} " f"rounds={state.max_rounds} stream={'on' if state.agent.stream else 'off'}\n" f"context_chars={ctx_chars}/{ctx_budget} " + f"context_tokens~={ctx_est_tokens} (est) " f"tool_result_max={state.agent.max_tool_result_chars}\n" f"usage_session={session_u.format_line()}\n" f"usage_last_turn={last_u.format_line()}\n"