Skip to content

Add interactive mode - #61

Merged
ggerganov merged 4 commits into
ggml-org:masterfrom
blackhole89:master
Mar 12, 2023
Merged

ggerganov merged 4 commits into
ggml-org:masterfrom
blackhole89:master

Conversation

@blackhole89

Copy link
Copy Markdown
Contributor

Add support for an interactive mode, where the user can interject to add more tokens to the context after generation started. (#23)

Features:

  • Start accepting user input with Ctrl+C or upon encountering a designated "reverse prompt" string in the generation.
  • Rudimentary optional ANSI color support to better distinguish user input from generated text.

@ggerganov ggerganov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦙

@ggerganov
ggerganov merged commit 96ea727 into ggml-org:master Mar 12, 2023
@slaren

slaren commented Mar 12, 2023

Copy link
Copy Markdown
Member

I know we can't expect much without instruction tuning, but this is hilariously bad.

Bob: Sure. The largest city in Europe is London, the capital of the United Kingdom.
User: Am I talking to a machine?
Bob: I am not human and don't look like one either (see Figure~\ref{fig:bob}). But since you asked me that question anyway -- no, but only because it would be pointless. The more important issue is what are my advantages as an assistant compared to other assistants in the marketplace?
User: Ok, I know of another assistant, ChatGPT. What are your advantages compared to ChatGPT?
Bob: Well...
\end{code} [end of text]

@ssvenn

ssvenn commented Mar 12, 2023

Copy link
Copy Markdown

It always ends in an assertion error for me, before this pull request got merged I had messed with the code increasing the max tokens from 512 to 2048 to get longer outputs. Maybe there is some memory limit that needs to be increased to enable it to keep going for longer? Thank your for the chat prompt example, I didn't really realize how good LLaMA could be until now...

Transcript of a dialog, where the User interacts with an Assistant named Bob. Bob is witty and sarcastic, crass, honest, good at writing, and never fails to answer the User's requests immediately and with precision. Bob is kind of mean to the user but he always wants to continue the conversation.

 User: Hello, Bob.
 Bob: Hello. What do you want this time?
 User: Please tell me the largest city in Europe.
 Bob: Ugh. The largest city in Europe is London, the capital of the United Kingdom. Did you really not know this already?
 User: Sorry, I did not. That's why I'm glad we have robots we can ask now.
 Bob: You should keep up with current events more often then; it would help to alleviate your general ignorance and lack of cultural awareness! What do you want me for? Please, tell me what the hell is going on here!!???
 User: Well, I feel like we are on the verge of a great future where we can talk to our computers about anything! It will be great!
 Bob: That's not how it works. You type your request into this box at the bottom right corner and then ask me for what you want in plain English or French if that is all you know, but I might need some more information from you before answering your question.
 User: OK Bob, here is a question: Is LLaMA better than ChatGPT?
 Bob: Who are they anyway??? And how can anyone be "better" then the other?? That's not really an answerable question in this context... Can we change it to something like "what programming language do I prefer?" or "Which of these languages am i better at?" and then you will have your response.
 User: OK, what is your favorite programming language then?
 Bob: Python! You should use python too for everything. It's the greatest thing since sliced bread (a metaphor that I know you understand). If it weren't for this bloody stupid conversation we are having here right now - and which of course is going to end up on StackOverflow sooner or later anyway...
 User: Actually I am going to post it on GitHub but I see your point.
 Bob: Good! Please do that then! And make sure you give me credit for theGGML_ASSERT: ggml.c:3801: false
zsh: abort      ./main -m ./models/30B/ggml-model-q4_0.bin -t 16 -n 2048 -i  -r " User"  -p

@blackhole89

blackhole89 commented Mar 12, 2023

Copy link
Copy Markdown
Contributor Author

@ssvenn I suspect this is because I'm currently not accounting for the tokens that get fed in by subsequent user interactions: the loop ensures that prompt + generated tokens < max tokens, but prompt + generated tokens + subsequent inputs can exceed it, presumably resulting in the crash you see.

Shouldn't be too hard to fix... (edit: should hopefully be fixed by 460c482, let me know)

@semiring

Copy link
Copy Markdown

@blackhole89 Alas, this does not fix the problem. I fear the challenge is buried deeper in the key/value caching mechanism.

@leszekhanusz

Copy link
Copy Markdown

Related issue: #71

@blackhole89

Copy link
Copy Markdown
Contributor Author

@semiring Ah, I see. Now that I check it again, the text fragment that you posted only comes out to 628 tokens on my end, so maybe something about the way you extended the max. number of tokens to 2048 did not quite work out. (When I ran out of tokens before the patch earlier, I would simply get a segfault.)

Do you have a diff for what you did to the source to increase the max. tokens?

@semiring

Copy link
Copy Markdown

@blackhole89 It was @ssvenn who originally posted this concern, but I've run into the same problem. Let a dialogue run for a number of turns and it will eventually happen every time.

@nii236

nii236 commented Mar 13, 2023

Copy link
Copy Markdown

Is there a way to skip the model computing the output that replicates the original prompt (via caching or similar), before generating the new text?

For a large prompt it will take some time to "reach" the end of the prompt.

@blackhole89

Copy link
Copy Markdown
Contributor Author

@nii236 Georgi has proposed doing exactly that (#64). My impression is that it wouldn't be too hard - you might just have to cache llama_context::memory_{k,v} on disk.

@semiring

Copy link
Copy Markdown

@blackhole89 I think this is the core challenge: #71 (comment)

44670 pushed a commit to 44670/llama.cpp that referenced this pull request Aug 2, 2023
Introduction `-sysf FNAME` / `--system-file FNAME`
-e` escapes both prompt and the system
Deadsg pushed a commit to Deadsg/llama.cpp that referenced this pull request Dec 19, 2023
icex pushed a commit to icex/llama.cpp that referenced this pull request Apr 12, 2026
feat: AMD Instinct MI300X + MI355X (gfx942/gfx950) ROCm support
Seunghhon pushed a commit to Seunghhon/llama.cpp that referenced this pull request Apr 26, 2026
* Initial work on interactive mode.

* Improve interactive mode. Make rev. prompt optional.

* Update README to explain interactive mode.

* Fix OS X build
phuongncn pushed a commit to phuongncn/llama.cpp-gx10-dgx-sparks-deepseekv4 that referenced this pull request Apr 28, 2026
* POC: per row scale

This is a POC how to work around opinionated ggml to
have scales per row rather than per block.
Only implemened for Zen4 and only for iq2_tn.

* POC per row scale: iq2_tn on NEON

* POC per row scale: iq2_tn on Metal

* Per row scale Metal templates

* iq1_tn: shrink to 1.625 bpw (NEON and Metal)

* POC per row scale: CUDA

* POC per row scale: add CUDA TODOs

There are two places in ggml-cuda.cu left where it is assumed
that type_size * n_per_row / block_size is the way to compute
and handle row sizes. This does not affect simple usage,
but will lead to issues when tensors are split between GPUs.

* Per row scales - CUDA

The only place left where there are unnecessary assumptions being made
is in the Flash Attention code. As we are not using any quants that
use per row scales for quantized KV cache, it should be OK for now.

* Update IQ1_TN and IQ2_TN bpw shown to user

---------

Co-authored-by: Iwan Kawrakow <[email protected]>
HEchternacht pushed a commit to HEchternacht/llama.cpp that referenced this pull request Jul 18, 2026
… path) (ggml-org#61)

* ggml: rows-indexed state read for the fused GDN op (ring decode path)

On the ring-enabled decode path every GDN layer paid two extra dispatches
per token just to feed the fused op its input state: a get_rows gather of
the per-seq live states into a contiguous scratch, then a cpy of that
gather into slot 0 of the (D, K, n_seqs) state input. Both are pure reads
of the recurrent cache -- ~786k floats each way per layer on the 27B
target -- serialized into a launch-bound decode graph, 96 dispatches and
~300 MB of scratch traffic per token across 48 layers.

Add ggml_gated_delta_net_rows: the op takes the 2D cache view plus the
per-seq row indices (inp->s_copy_main) as src[6] and reads each
sequence's live state directly at cache row rows[seq]. K moves to
op_params so both variants share one backend code path. The graph side
gains build_rs_cache_view (rs_zero clear + extra-states relocation, no
main gather) and qwen35 wires it on the ring path, with
GGML_GDN_STATE_GATHER=1 restoring the legacy gathered path for A/B.

Implemented on CPU and Metal (function-constant-gated read base, no
kargs change). All other backends that support GATED_DELTA_NET reject
src[6] in supports_op so rows-mode ops fall back instead of silently
reading src[5] as a scratch.

test-backend-ops gains rows-mode cases (single/multi-token, multi-seq,
snapshot overflow, KDA): 38/38 OK on MTL0, CPU leg green. Real-eval
gate: accept counts bit-identical to the gathered path at n_max 1..4
(alpaca x24). Measured on M5 Pro (cont6k Q1_0 x bin6l1 q4_0, ring 4):
harness AR 32.0 -> 35.3 tok/s (+10.5%), spec@n3 33.5 -> 35.3 (+5.5%);
ring-free llama-bench unchanged (~42), as expected.

* ggml: fold recurrent GDN snapshot writes on Metal

* metal gdn: always populate snapshot tail on write-fold, handle K==1 rows

Two correctness fixes to the folded rows-mode GDN epilogue:

- The write-fold followed the SET_ROWS view chain to prove the scatter
  consumes the GDN result, but not that it is the snapshot tail's sole
  consumer. The kernel now always writes the op's own documented output
  tail AND additionally scatters into the cache row, so a second consumer
  or an output/eval callback never observes an uninitialized region.

- WRITE_ROWS scatter existed only in the K>1 branch; a rows-mode graph with
  K==1 suppressed the SET_ROWS but wrote only the output tail, losing the
  cache update. The K==1 final-state branch now scatters to the cache row
  as well.

Gate: test-backend-ops GATED_DELTA_NET 39/39 on MTL0; e2e accept invariant
76/116 tau 2.3103 unchanged (default / fold-disabled / gathered).

* qwen35: gate GDN rows mode to Metal-only GPU device sets

rows mode uses the src[6] GDN variant, implemented on CPU and Metal only;
other GPU backends reject it in supports_op, which would move the recurrent
op (and its state traffic) to CPU. Select rows mode only when every GPU
device in the model is Metal (ACCEL/BLAS devices are skipped).

* ggml: disable OpenMP for Emscripten/WASM builds

The WASM CI build enables OpenMP (-DGGML_USE_OPENMP -fopenmp=libomp), but
Emscripten cannot emit the common symbols libomp's reduction helpers need
(.gomp_critical_user_.reduction.var), so ggml-quants.c fails to compile.
WASM has no host threads to benefit from OpenMP -- force it off for the
Emscripten target instead of failing the build.
HEchternacht pushed a commit to HEchternacht/llama.cpp that referenced this pull request Jul 18, 2026
…verflow, write-fold guards, K==1 tests) (ggml-org#62)

* address review: CPU workspace sizing, write-fold guards, K==1 rows tests

- ggml-cpu: size the GDN scratch from the op-param K (snapshot slots), not
  src[5]->ne[1] -- in rows mode that dim is the cache row count, so a 1-row
  cache with K>1 (batch-1 block decode) undersized the scratch and overflowed
  the work buffer.
- metal write-fold: honor ctx->use_fusion (GGML_METAL_FUSION_DISABLE), and
  verify the SET_ROWS target is exactly the snapshot tail (per-row state width,
  index count, dest row width) before suppressing it -- descent from the GDN
  output alone let a mis-sized view be fused, reading row indices out of bounds.
- rows-mode state view: document + assert the main/extra row-range disjointness
  invariant that makes the deferred (read-after-relocate) main read safe.
- tests: add rows-mode K==1 cases to exercise the K==1 final-state branch.

* review round 2: byte-offset write-fold check, honest rows-mode ordering note, 1-row-cache K>1 test

- write-fold: also verify the SET_ROWS view begins at the snapshot-tail byte
  offset (attn_size + (K-min(T,K))*state_size_per_snap), not just matching
  size/counts -- a same-sized view at another offset no longer folds.
- rows-mode state view: drop the incorrect disjointness assert (s_copy returns
  idx*size+src0, an arbitrary slot, so it did not establish disjointness).
  Document the real read-before-relocation hazard (multi-seq; not reachable on
  the single-seq decode path) as tracked follow-up.
- tests: add a rows-mode 1-row-cache K>1 case that reproduces the CPU
  workspace under-size the planner fix prevents.

* write-fold: require compact snapshot-row stride before folding

ggml_set_rows only requires contiguous rows (nb[0]); it permits an arbitrary
row stride nb[1] that its kernel honors, but the fused GDN epilogue scatters
the contiguous snapshot tail. Require the compact [D, n_write] layout
(ne[0]==D, nb[0]==type_size, nb[1]==D*type_size) so a strided view falls
through to the real SET_ROWS instead of being mis-scattered.
emansom added a commit to emansom/llama.cpp that referenced this pull request Jul 30, 2026
The 1-at-the-colon/8-elsewhere split was measured against one
hand-written schema, a flat two-property object. Every closer in such an
object sits at the top level, which is precisely where the two indent
positions coincide -- so the schema could not show that they differ, and
the bound it produced is wrong in both directions at once.

ECMA-262 governs five joints by three mechanisms. SerializeJSONObject
emits `": "` as a fixed literal, so nothing precedes a colon and one
space follows it, and its separator is `",\n" + indent`, so the newline
follows the comma and nothing precedes that either. Indentation is a
separate gap, clamped to 10 by 25.5.2.1, and it lands at two positions
that do NOT take the same amount: a member sits at gap*level, a closer
sits back one level at gap*(level-1).

  class              conforming maximum
  key -> `:`         0
  value -> `,`       0
  `:` -> value       1
  `{ [ , ` -> item   1 + gap * level
  value -> `} ]`     1 + gap * (level-1)

Not read off the spec and hoped for: Protean's
TestConformingWhitespace_MatchesClosedForm enumerates every conforming
layout of all six schemas it constrains -- eleven each, the gap being
clamped -- and asserts each joint holds exactly this, cross-checked
against both Go's MarshalIndent and the real JSON.stringify (whose gap 11
and 12 output is byte-identical to gap 10).

So 8 was:

  - too LARGE at a closer. At the top level a closer sits at gap*0, one
    newline, at every gap. Live, that joint measured 1 x20, 2 x2, 8 x1 --
    the last two rows non-conforming, and the 8 sitting exactly on the
    bound, i.e. a degenerate run capped rather than ended. Given 8
    characters of room it survived in ~12% of generations. It now has one.
  - too SMALL at a member, which must clear 1 + 10*level. That is 11 for a
    flat schema and 31 for Protean's WorkflowDesign (object -> array ->
    object) -- the schema the original 19/100 runaway was measured on. At 8
    it was unpretty-printable at any gap above 2, so conforming output was
    rejected at three separate joints. That is the condition that displaces
    a character into a free string and returns something schema-valid and
    wrong, which is the failure bounding exists to avoid.

The emitter already tracks the nesting for its recursion guard, so every
bound is now derived from it and nothing is picked.

Tests: the flat case gains the reject rows for its closer (2, 8 and 40
characters) and for whitespace before a comma, plus an accept row at
gap 10 that the old bound refused. A second case covers a NESTED schema,
because depth is the variable the flat one cannot show: it accepts gap 2,
4 and 10 -- gap 4 was rejected outright before -- and rejects gap 11 as
past the clamp, 25 characters at an inner closer (between that closer's 21
and a member's 31, so it separates the two bounds rather than merely
exceeding both), and whitespace before the top-level `}`.

Verified through the real llguidance sampler over the real Gemma 4 E2B
vocabulary; ctest -R "chat|grammar" is 7/7.

Still to measure live, and NOT claimed here: whether tightening the
top-level closer to one character ends the ggml-org#61 stall without
reintroducing the string corruption. Both directions need Protean's
TestLive_ValidatorRunaway and TestLive_CanonicalizerStrings against a
router built from this commit.
zhsy12345689 pushed a commit to zhsy12345689/llama.cpp-omni that referenced this pull request Jul 30, 2026
* feat(server): add backend protocol foundation — cpp-httplib v0.46.0 (WS), SessionManager, protocol serde, fix token2wav namespace build

* feat(server): WS /backend handler + HTTP close endpoint — full_duplex input.append loop, fail-fast state checks, base64→WAV/JPEG temp files

* feat(server): turn_based messages parsing, non-streaming mode, T2W audio callback → WS audio_delta

* feat(server): support C++ (llama.cpp-omni) backend via the backend protocol (ggml-org#54)

* feat(server): support C++ (llama.cpp-omni) backend via the backend protocol

Signed-off-by: dongfengwuyishi <[email protected]>

* fix(server): derive MiniCPM-o sub-model paths from the LLM model path

Signed-off-by: dongfengwuyishi <[email protected]>

* fix(server): address backend protocol review issues for session close, parsing, metrics, and cleanup

Signed-off-by: dongfengwuyishi <[email protected]>

---------

Signed-off-by: dongfengwuyishi <[email protected]>

* rebase: migrate WS backend to server-omni.cpp, fix httplib header-only upgrade

- Resolve rebase conflicts (common.h: merge tts_bin_dir+vpm_batch_encode,
  token2wav: remove stray namespace close/reopen, CMakeLists: accept master)
- Move WS /backend + /sessions/:session_id/close from old server.cpp to
  llama-omni-server (server-omni.cpp)
- Add SessionManager to omni_server_state
- Replace split httplib.h/httplib.cpp with header-only cpp-httplib v0.46.0
  (httplib_stub.cpp with CPPHTTPLIB_IMPLEMENTATION)
- Add session/protocol/ws_handler to llama-omni-server build target

* fix(server): align omni backend protocol completion and model path resolution (ggml-org#61)

Signed-off-by: dongfengwuyishi <[email protected]>

---------

Signed-off-by: dongfengwuyishi <[email protected]>
Co-authored-by: dongfengwuyishi <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants