ember.cpp
0.1.0
C++ inference engine for Llama-family and paperkiln models (CPU, CUDA, WebAssembly)
Loading...
Searching...
No Matches
state_tokens.h
Go to the documentation of this file.
1
#pragma once
2
// Per-turn state tokens: the template contract (paperkiln
3
// experiments/tiny_chat_long_2026-10/IR_SPEC_DRAFT.md sections 1.2 and 1.5;
4
// LOCAL_LLM_STACK.md section 3 point 3 extended). With k = the GGUF's
5
// paperkiln.state_tokens.k > 0, every exchange of the served template is
6
// <|user|> U <|assistant|> A <|endoftext|> S_0 S_1 .. S_{k-1}
7
// with S_j = vocab + j. The ids never come from the tokeniser; the engine
8
// inserts them, as the training serialiser does:
9
// - after every <|endoftext|> that closes an exchange (an exchange opens at
10
// <|user|> and has a reply once an <|assistant|> follows it; an
11
// <|assistant|> with no open <|user|> starts nothing), the k state ids;
12
// - an assistant reply followed by a <|user|> with no <|endoftext|> between
13
// them (a reply that stopped early: max_new_tokens, a stop string, an
14
// abort) gets <|endoftext|> and then the k state ids before that <|user|>.
15
// Raw ids >= vocab are accepted only as a complete, ordered state block
16
// directly after an <|endoftext|> that closes an exchange (kept as given, not
17
// doubled); anything else throws std::invalid_argument naming the position.
18
#include <stdexcept>
19
#include <string>
20
#include <vector>
21
22
namespace
ember
{
23
24
inline
std::vector<int>
insert_state_blocks
(
const
std::vector<int>& ids,
int
vocab,
int
k
,
int
eot,
int
user,
25
int
assistant) {
26
if
(
k
<= 0) {
27
for
(
size_t
i
= 0;
i
< ids.size(); ++
i
)
28
if
(ids[
i
] >= vocab)
29
throw
std::invalid_argument(
"token id "
+ std::to_string(ids[
i
]) +
" at position "
+ std::to_string(
i
) +
30
" is past the vocabulary ("
+ std::to_string(vocab) +
") and the model has no state tokens"
);
31
return
ids;
32
}
33
std::vector<int>
out
;
34
out
.reserve(ids.size() + 4 *
static_cast<
size_t
>
(
k
));
35
auto
block
= [&] {
36
for
(
int
j
= 0;
j
<
k
; ++
j
)
out
.push_back(vocab +
j
);
37
};
38
// paperkiln's serialiser (tools/state_tokens.py, nn::insert_state_ids): an exchange opens at
39
// <|user|>, has a reply once <|assistant|> follows it, and ends at the next <|endoftext|>.
40
enum
{
kNone
,
kUser
,
kReply
}
phase
=
kNone
;
41
const
size_t
n
= ids.size();
42
for
(
size_t
i
= 0;
i
<
n
; ++
i
) {
43
const
int
id
= ids[
i
];
44
if
(
id
< 0)
throw
std::invalid_argument(
"token id "
+ std::to_string(
id
) +
" at position "
+ std::to_string(
i
) +
" is negative"
);
45
if
(
id
>= vocab)
46
throw
std::invalid_argument(
"state id "
+ std::to_string(
id
) +
" at position "
+ std::to_string(
i
) +
47
" is not part of a complete state block directly after an <|endoftext|> that ends "
48
"an assistant reply"
);
49
if
(
id
== user) {
50
if
(
phase
==
kReply
) {
// the reply stopped early: close it as training does
51
out
.push_back(eot);
52
block
();
53
}
54
phase
=
kUser
;
55
out
.push_back(
id
);
56
}
else
if
(
id
== assistant) {
57
if
(
phase
==
kUser
)
phase
=
kReply
;
58
out
.push_back(
id
);
59
}
else
if
(
id
== eot) {
60
const
bool
closes
=
phase
==
kReply
;
61
phase
=
kNone
;
62
out
.push_back(
id
);
63
if
(!
closes
)
continue
;
64
if
(
i
+ 1 <
n
&& ids[
i
+ 1] >= vocab) {
// a state block given with the ids: it must be complete
65
for
(
int
j
= 0;
j
<
k
; ++
j
)
66
if
(
i
+ 1 +
j
>=
n
|| ids[
i
+ 1 +
j
] != vocab +
j
)
67
throw
std::invalid_argument(
"the state block after the <|endoftext|> at position "
+ std::to_string(
i
) +
68
" is not the "
+ std::to_string(
k
) +
" ids "
+ std::to_string(vocab) +
" .. "
+
69
std::to_string(vocab +
k
- 1) +
" in order"
);
70
i
+=
static_cast<
size_t
>
(
k
);
71
}
72
block
();
73
}
else
{
74
out
.push_back(
id
);
75
}
76
}
77
return
out
;
78
}
79
80
}
// namespace ember
n
int n
Definition
graph_ir_cuda.cu:326
k
K k
Definition
graph_ir_recurrence.cpp:124
out
node out
Definition
graph_ir_schema.h:9
j
size_t j
Definition
graph_ir_validate.cpp:222
ember
Definition
chat_gguf.h:11
ember::insert_state_blocks
std::vector< int > insert_state_blocks(const std::vector< int > &ids, int vocab, int k, int eot, int user, int assistant)
Definition
state_tokens.h:24
state_tokens.h
Generated by
1.9.8