parser_test.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. package parser
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "strings"
  7. "testing"
  8. "github.com/stretchr/testify/assert"
  9. )
  10. func TestParser(t *testing.T) {
  11. input := `
  12. FROM model1
  13. ADAPTER adapter1
  14. LICENSE MIT
  15. PARAMETER param1 value1
  16. PARAMETER param2 value2
  17. TEMPLATE template1
  18. `
  19. reader := strings.NewReader(input)
  20. commands, err := Parse(reader)
  21. assert.Nil(t, err)
  22. expectedCommands := []Command{
  23. {Name: "model", Args: "model1"},
  24. {Name: "adapter", Args: "adapter1"},
  25. {Name: "license", Args: "MIT"},
  26. {Name: "param1", Args: "value1"},
  27. {Name: "param2", Args: "value2"},
  28. {Name: "template", Args: "template1"},
  29. }
  30. assert.Equal(t, expectedCommands, commands)
  31. }
  32. func TestParserFrom(t *testing.T) {
  33. var cases = []struct {
  34. input string
  35. expected []Command
  36. err error
  37. }{
  38. {
  39. "FROM foo",
  40. []Command{{Name: "model", Args: "foo"}},
  41. nil,
  42. },
  43. {
  44. "FROM /path/to/model",
  45. []Command{{Name: "model", Args: "/path/to/model"}},
  46. nil,
  47. },
  48. {
  49. "FROM /path/to/model/fp16.bin",
  50. []Command{{Name: "model", Args: "/path/to/model/fp16.bin"}},
  51. nil,
  52. },
  53. {
  54. "FROM llama3:latest",
  55. []Command{{Name: "model", Args: "llama3:latest"}},
  56. nil,
  57. },
  58. {
  59. "FROM llama3:7b-instruct-q4_K_M",
  60. []Command{{Name: "model", Args: "llama3:7b-instruct-q4_K_M"}},
  61. nil,
  62. },
  63. {
  64. "", nil, errMissingFrom,
  65. },
  66. {
  67. "PARAMETER param1 value1",
  68. nil,
  69. errMissingFrom,
  70. },
  71. {
  72. "PARAMETER param1 value1\nFROM foo",
  73. []Command{{Name: "param1", Args: "value1"}, {Name: "model", Args: "foo"}},
  74. nil,
  75. },
  76. }
  77. for _, c := range cases {
  78. t.Run("", func(t *testing.T) {
  79. commands, err := Parse(strings.NewReader(c.input))
  80. assert.ErrorIs(t, err, c.err)
  81. assert.Equal(t, c.expected, commands)
  82. })
  83. }
  84. }
  85. func TestParserParametersMissingValue(t *testing.T) {
  86. input := `
  87. FROM foo
  88. PARAMETER param1
  89. `
  90. reader := strings.NewReader(input)
  91. _, err := Parse(reader)
  92. assert.ErrorIs(t, err, io.ErrUnexpectedEOF)
  93. }
  94. func TestParserMessages(t *testing.T) {
  95. var cases = []struct {
  96. input string
  97. expected []Command
  98. err error
  99. }{
  100. {
  101. `
  102. FROM foo
  103. MESSAGE system You are a Parser. Always Parse things.
  104. `,
  105. []Command{
  106. {Name: "model", Args: "foo"},
  107. {Name: "message", Args: "system: You are a Parser. Always Parse things."},
  108. },
  109. nil,
  110. },
  111. {
  112. `
  113. FROM foo
  114. MESSAGE system You are a Parser. Always Parse things.`,
  115. []Command{
  116. {Name: "model", Args: "foo"},
  117. {Name: "message", Args: "system: You are a Parser. Always Parse things."},
  118. },
  119. nil,
  120. },
  121. {
  122. `
  123. FROM foo
  124. MESSAGE system You are a Parser. Always Parse things.
  125. MESSAGE user Hey there!
  126. MESSAGE assistant Hello, I want to parse all the things!
  127. `,
  128. []Command{
  129. {Name: "model", Args: "foo"},
  130. {Name: "message", Args: "system: You are a Parser. Always Parse things."},
  131. {Name: "message", Args: "user: Hey there!"},
  132. {Name: "message", Args: "assistant: Hello, I want to parse all the things!"},
  133. },
  134. nil,
  135. },
  136. {
  137. `
  138. FROM foo
  139. MESSAGE system """
  140. You are a multiline Parser. Always Parse things.
  141. """
  142. `,
  143. []Command{
  144. {Name: "model", Args: "foo"},
  145. {Name: "message", Args: "system: \nYou are a multiline Parser. Always Parse things.\n"},
  146. },
  147. nil,
  148. },
  149. {
  150. `
  151. FROM foo
  152. MESSAGE badguy I'm a bad guy!
  153. `,
  154. nil,
  155. errInvalidRole,
  156. },
  157. {
  158. `
  159. FROM foo
  160. MESSAGE system
  161. `,
  162. nil,
  163. io.ErrUnexpectedEOF,
  164. },
  165. {
  166. `
  167. FROM foo
  168. MESSAGE system`,
  169. nil,
  170. io.ErrUnexpectedEOF,
  171. },
  172. }
  173. for _, c := range cases {
  174. t.Run("", func(t *testing.T) {
  175. commands, err := Parse(strings.NewReader(c.input))
  176. assert.ErrorIs(t, err, c.err)
  177. assert.Equal(t, c.expected, commands)
  178. })
  179. }
  180. }
  181. func TestParserQuoted(t *testing.T) {
  182. var cases = []struct {
  183. multiline string
  184. expected []Command
  185. err error
  186. }{
  187. {
  188. `
  189. FROM foo
  190. SYSTEM """
  191. This is a
  192. multiline system.
  193. """
  194. `,
  195. []Command{
  196. {Name: "model", Args: "foo"},
  197. {Name: "system", Args: "\nThis is a\nmultiline system.\n"},
  198. },
  199. nil,
  200. },
  201. {
  202. `
  203. FROM foo
  204. SYSTEM """
  205. This is a
  206. multiline system."""
  207. `,
  208. []Command{
  209. {Name: "model", Args: "foo"},
  210. {Name: "system", Args: "\nThis is a\nmultiline system."},
  211. },
  212. nil,
  213. },
  214. {
  215. `
  216. FROM foo
  217. SYSTEM """This is a
  218. multiline system."""
  219. `,
  220. []Command{
  221. {Name: "model", Args: "foo"},
  222. {Name: "system", Args: "This is a\nmultiline system."},
  223. },
  224. nil,
  225. },
  226. {
  227. `
  228. FROM foo
  229. SYSTEM """This is a multiline system."""
  230. `,
  231. []Command{
  232. {Name: "model", Args: "foo"},
  233. {Name: "system", Args: "This is a multiline system."},
  234. },
  235. nil,
  236. },
  237. {
  238. `
  239. FROM foo
  240. SYSTEM """This is a multiline system.""
  241. `,
  242. nil,
  243. io.ErrUnexpectedEOF,
  244. },
  245. {
  246. `
  247. FROM foo
  248. SYSTEM "
  249. `,
  250. nil,
  251. io.ErrUnexpectedEOF,
  252. },
  253. {
  254. `
  255. FROM foo
  256. SYSTEM """
  257. This is a multiline system with "quotes".
  258. """
  259. `,
  260. []Command{
  261. {Name: "model", Args: "foo"},
  262. {Name: "system", Args: "\nThis is a multiline system with \"quotes\".\n"},
  263. },
  264. nil,
  265. },
  266. {
  267. `
  268. FROM foo
  269. SYSTEM """"""
  270. `,
  271. []Command{
  272. {Name: "model", Args: "foo"},
  273. {Name: "system", Args: ""},
  274. },
  275. nil,
  276. },
  277. {
  278. `
  279. FROM foo
  280. SYSTEM ""
  281. `,
  282. []Command{
  283. {Name: "model", Args: "foo"},
  284. {Name: "system", Args: ""},
  285. },
  286. nil,
  287. },
  288. {
  289. `
  290. FROM foo
  291. SYSTEM "'"
  292. `,
  293. []Command{
  294. {Name: "model", Args: "foo"},
  295. {Name: "system", Args: "'"},
  296. },
  297. nil,
  298. },
  299. {
  300. `
  301. FROM foo
  302. SYSTEM """''"'""'""'"'''''""'""'"""
  303. `,
  304. []Command{
  305. {Name: "model", Args: "foo"},
  306. {Name: "system", Args: `''"'""'""'"'''''""'""'`},
  307. },
  308. nil,
  309. },
  310. {
  311. `
  312. FROM foo
  313. TEMPLATE """
  314. {{ .Prompt }}
  315. """`,
  316. []Command{
  317. {Name: "model", Args: "foo"},
  318. {Name: "template", Args: "\n{{ .Prompt }}\n"},
  319. },
  320. nil,
  321. },
  322. }
  323. for _, c := range cases {
  324. t.Run("", func(t *testing.T) {
  325. commands, err := Parse(strings.NewReader(c.multiline))
  326. assert.ErrorIs(t, err, c.err)
  327. assert.Equal(t, c.expected, commands)
  328. })
  329. }
  330. }
  331. func TestParserParameters(t *testing.T) {
  332. var cases = map[string]struct {
  333. name, value string
  334. }{
  335. "numa true": {"numa", "true"},
  336. "num_ctx 1": {"num_ctx", "1"},
  337. "num_batch 1": {"num_batch", "1"},
  338. "num_gqa 1": {"num_gqa", "1"},
  339. "num_gpu 1": {"num_gpu", "1"},
  340. "main_gpu 1": {"main_gpu", "1"},
  341. "low_vram true": {"low_vram", "true"},
  342. "f16_kv true": {"f16_kv", "true"},
  343. "logits_all true": {"logits_all", "true"},
  344. "vocab_only true": {"vocab_only", "true"},
  345. "use_mmap true": {"use_mmap", "true"},
  346. "use_mlock true": {"use_mlock", "true"},
  347. "num_thread 1": {"num_thread", "1"},
  348. "num_keep 1": {"num_keep", "1"},
  349. "seed 1": {"seed", "1"},
  350. "num_predict 1": {"num_predict", "1"},
  351. "top_k 1": {"top_k", "1"},
  352. "top_p 1.0": {"top_p", "1.0"},
  353. "tfs_z 1.0": {"tfs_z", "1.0"},
  354. "typical_p 1.0": {"typical_p", "1.0"},
  355. "repeat_last_n 1": {"repeat_last_n", "1"},
  356. "temperature 1.0": {"temperature", "1.0"},
  357. "repeat_penalty 1.0": {"repeat_penalty", "1.0"},
  358. "presence_penalty 1.0": {"presence_penalty", "1.0"},
  359. "frequency_penalty 1.0": {"frequency_penalty", "1.0"},
  360. "mirostat 1": {"mirostat", "1"},
  361. "mirostat_tau 1.0": {"mirostat_tau", "1.0"},
  362. "mirostat_eta 1.0": {"mirostat_eta", "1.0"},
  363. "penalize_newline true": {"penalize_newline", "true"},
  364. "stop ### User:": {"stop", "### User:"},
  365. "stop ### User: ": {"stop", "### User: "},
  366. "stop \"### User:\"": {"stop", "### User:"},
  367. "stop \"### User: \"": {"stop", "### User: "},
  368. "stop \"\"\"### User:\"\"\"": {"stop", "### User:"},
  369. "stop \"\"\"### User:\n\"\"\"": {"stop", "### User:\n"},
  370. "stop <|endoftext|>": {"stop", "<|endoftext|>"},
  371. "stop <|eot_id|>": {"stop", "<|eot_id|>"},
  372. "stop </s>": {"stop", "</s>"},
  373. }
  374. for k, v := range cases {
  375. t.Run(k, func(t *testing.T) {
  376. var b bytes.Buffer
  377. fmt.Fprintln(&b, "FROM foo")
  378. fmt.Fprintln(&b, "PARAMETER", k)
  379. commands, err := Parse(&b)
  380. assert.Nil(t, err)
  381. assert.Equal(t, []Command{
  382. {Name: "model", Args: "foo"},
  383. {Name: v.name, Args: v.value},
  384. }, commands)
  385. })
  386. }
  387. }
  388. func TestParserComments(t *testing.T) {
  389. var cases = []struct {
  390. input string
  391. expected []Command
  392. }{
  393. {
  394. `
  395. # comment
  396. FROM foo
  397. `,
  398. []Command{
  399. {Name: "model", Args: "foo"},
  400. },
  401. },
  402. }
  403. for _, c := range cases {
  404. t.Run("", func(t *testing.T) {
  405. commands, err := Parse(strings.NewReader(c.input))
  406. assert.Nil(t, err)
  407. assert.Equal(t, c.expected, commands)
  408. })
  409. }
  410. }
  411. func TestParseFormatParse(t *testing.T) {
  412. var cases = []string{
  413. `
  414. FROM foo
  415. ADAPTER adapter1
  416. LICENSE MIT
  417. PARAMETER param1 value1
  418. PARAMETER param2 value2
  419. TEMPLATE template1
  420. MESSAGE system You are a Parser. Always Parse things.
  421. MESSAGE user Hey there!
  422. MESSAGE assistant Hello, I want to parse all the things!
  423. `,
  424. `
  425. FROM foo
  426. ADAPTER adapter1
  427. LICENSE MIT
  428. PARAMETER param1 value1
  429. PARAMETER param2 value2
  430. TEMPLATE template1
  431. MESSAGE system """
  432. You are a store greeter. Always responsed with "Hello!".
  433. """
  434. MESSAGE user Hey there!
  435. MESSAGE assistant Hello, I want to parse all the things!
  436. `,
  437. `
  438. FROM foo
  439. ADAPTER adapter1
  440. LICENSE """
  441. Very long and boring legal text.
  442. Blah blah blah.
  443. "Oh look, a quote!"
  444. """
  445. PARAMETER param1 value1
  446. PARAMETER param2 value2
  447. TEMPLATE template1
  448. MESSAGE system """
  449. You are a store greeter. Always responsed with "Hello!".
  450. """
  451. MESSAGE user Hey there!
  452. MESSAGE assistant Hello, I want to parse all the things!
  453. `,
  454. }
  455. for _, c := range cases {
  456. t.Run("", func(t *testing.T) {
  457. commands, err := Parse(strings.NewReader(c))
  458. assert.NoError(t, err)
  459. commands2, err := Parse(strings.NewReader(Format(commands)))
  460. assert.NoError(t, err)
  461. assert.Equal(t, commands, commands2)
  462. })
  463. }
  464. }