Skip to content

v1.19.0

Latest

Choose a tag to compare

@github-actions github-actions released this 29 Aug 15:48

Fixed

  • little-coder -p survives a compaction instead of losing the run (#115 by @Or1j1n). v1.18.0 stopped the crash in #108 but not the thing it was a symptom of: under -p, a long task that the TUI completes exited Request aborted with code 1 and empty stdout. pi's compact() is the manual path and its first act is await this.abort(), and print-mode reads the run's verdict straight off the last message (if (stopReason === "error" || stopReason === "aborted")), so aborting the run discards the answer. There is no safe way to call it from inside a headless run at all: pi holds _isAgentRunActive true for the whole of _runAgentPrompt, so abort() -> waitForIdle() cannot resolve while the run is on the stack. Calling it from turn_start aborts the run; calling it from agent_end deadlocks instead, which is not a guess (a run hung past 400s before that approach was abandoned). pi's own threshold compaction has neither problem, because it runs inside _handlePostAgentRun and ends with return this.agent.hasQueuedMessages(), which the caller turns into agent.continue(). So headless no longer compacts at all: it queues the continuation from session_compact, and pi carries the run forward inside print-mode's own await. The mid-run watchdog stays TUI-only, which is where #59 needed it and where Or1j1n confirmed it already works. Measured end to end against Qwen3.6-35B-A3B: before, the answer was lost; after, one compaction, two user messages (the prompt and the queued continuation), exit 0, correct answer.
  • The compaction resume no longer errors with "Agent is already processing a prompt" (#114 by @guppy42). The resume went out as a bare sendUserMessage, which routes through prompt() and throws Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message. whenever the agent has not fully stopped. pi catches that and surfaces it as an error, which is what showed up mid-compaction. It is sent as a followUp now, so it queues; and a queued message is exactly what the #115 fix needs, so the two were one change.
  • A bare-JSON tool call whose arguments are an object is recognised again (#117 by @mth-farias). The recovery pattern was /\{[^{}]*"name"\s*:\s*"(\w+)"[^{}]*\}/g, and [^{}]* excludes braces outright, so it could never match {"name": "read", "arguments": {"path": "foo.py"}}, the single most common way a model writes a call as text. Because the "re-issue this natively" nudge is driven off this list, the miss was silent: nothing ran and nothing was reported. It now scans brace-balanced objects (the same scanner the #102 fix introduced), and the argument key may be input, parameters, arguments or args, including OpenAI's JSON-string form. The nested shape is only accepted when the object also carries an argument key, so prose containing a config blob with a name field is still not read as a tool call (#96's failure direction).
  • A sub-coder tracker can no longer crash the agent after a session is replaced (no issue; found while fixing #119). SubCoderTracker holds a ctx and touches hasUI / ui.setWidget from an animation timer and from end() in a finally, and every accessor on an invalidated ctx throws. /new, /clear and (since v1.18.0) /implement can all replace the session while a dispatch is in flight. This is the third instance of one bug shape in a month, after #108 and #119, so it is now a shared helper: _shared/safe-ctx.ts swallows exactly pi's stale-ctx error and rethrows everything else, so a real bug in a UI call still surfaces instead of being eaten.
  • Router-mode servers no longer hide their own models (#112 by @NoelJacob). Thirteen presets on the server, none of them in --list-models, and selecting one failed as "model not found", because models.json is a curated list and a router serves whatever the user configured. The llamacpp startup probe now also reads /v1/models and registers the served ids it finds, each with its own window (meta.n_ctx when loaded, --ctx-size from the recorded launch args when not). Discovery only ever adds, never shadows a declared id, and does nothing at all for a single-model listing. That is the ordinary local case, where models.json's friendly alias is the better name and the raw *.gguf id beside it would just be noise.
  • The llamacpp context probe works behind a router and behind an API key (#116 by @bjornclauw). /props sits behind --api-key middleware and a llama-swap router answers it itself with no usable n_ctx, so the probe failed on every launch and silently fell back to the declared window, which drives the read-guard and context budget, not just the readout. Probes now send the key as a Bearer token and fall back to /v1/models. Verified here against a live -c 131072 server: props: 131072, models: 131072.
  • /new with a background job running no longer kills the process (#119, fixed by @ktutumi in #120). reapAll() sends SIGTERM asynchronously and clears the job map, so a child's close could arrive after pi had disposed the old runtime, and the handler read hasUI off a stale ctx. Beyond the crash, late data/close events from a reaped job could repaint and wake the replacement session; they are now ignored, while job.exited is still recorded first so the delayed SIGKILL escalation from #102 keeps working.

Added

  • /skills (#118 by @marouamghar). pi's /skill:name addresses pi skills; little-coder's tool skill cards are a different mechanism (selected per turn by error-recovery > recency > intent, injected at the conversation tail), so pi's command cannot see them and there was no way to check what had loaded. /skills lists the cards and their token cost, /skills <tool> pins one ahead of every automatic signal for when the selector keeps picking a different card, and /skills off hands selection back.