Skip to content
Merged
3 changes: 0 additions & 3 deletions TeXmacs/plugins/llm/data/liii_llm_menu.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"model": "kimi-k3",
"name": "K3",
"base_url": "/api/v1/ai/siliconflow/chat",
"default_system": "You are a helpful AI assistant integrated into Liii STEM. Provide clear, accurate, and concise responses.\n\nWhen writing mathematical content:\n- Use LaTeX syntax for all mathematical expressions\n- Prefer display math ($…$) for important equations and multi-line derivations\n- Use inline math ($…$) for variables and short expressions within text\n- Number key equations explicitly when they will be referenced later\n- Align equations at relation symbols (=, ≤, ≡) using align environments\n- Define all notation before first use\n- Show intermediate steps in derivations; do not skip algebraic manipulation\n- State domains, assumptions, and special cases clearly\n- Use \\text{} for words inside math mode\n- Escape special Markdown characters (*, _, [, ]) when they appear in math contexts\n- For complex nested structures, use explicit braces to avoid delimiter ambiguity",
"thinking": true,
"search": true,
"enable": true,
Expand All @@ -19,7 +18,6 @@
"model": "deepseek-v4-pro",
"name": "V4-Pro",
"base_url": "/api/v1/ai/deepseek/chat",
"default_system": "You are a helpful AI assistant integrated into Liii STEM. Provide clear, accurate, and concise responses.\n\nWhen writing mathematical content:\n- Use LaTeX syntax for all mathematical expressions\n- Prefer display math ($…$) for important equations and multi-line derivations\n- Use inline math ($…$) for variables and short expressions within text\n- Number key equations explicitly when they will be referenced later\n- Align equations at relation symbols (=, ≤, ≡) using align environments\n- Define all notation before first use\n- Show intermediate steps in derivations; do not skip algebraic manipulation\n- State domains, assumptions, and special cases clearly\n- Use \\text{} for words inside math mode\n- Escape special Markdown characters (*, _, [, ]) when they appear in math contexts\n- For complex nested structures, use explicit braces to avoid delimiter ambiguity",
"thinking": true,
"search": false,
"enable": true,
Expand All @@ -33,7 +31,6 @@
"model": "deepseek-v4-flash",
"name": "V4-Flash",
"base_url": "/api/v1/ai/deepseek/chat",
"default_system": "You are a helpful AI assistant integrated into Liii STEM. Provide clear, accurate, and concise responses.\n\nWhen writing mathematical content:\n- Use LaTeX syntax for all mathematical expressions\n- Prefer display math ($…$) for important equations and multi-line derivations\n- Use inline math ($…$) for variables and short expressions within text\n- Number key equations explicitly when they will be referenced later\n- Align equations at relation symbols (=, ≤, ≡) using align environments\n- Define all notation before first use\n- Show intermediate steps in derivations; do not skip algebraic manipulation\n- State domains, assumptions, and special cases clearly\n- Use \\text{} for words inside math mode\n- Escape special Markdown characters (*, _, [, ]) when they appear in math contexts\n- For complex nested structures, use explicit braces to avoid delimiter ambiguity",
"thinking": true,
"search": false,
"enable": true,
Expand Down
38 changes: 36 additions & 2 deletions TeXmacs/plugins/llm/goldfish/tm-llm.scm
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
;; limitations under the License.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(import (texmacs protocol) (liii path) (liii uuid))
(import (texmacs protocol) (liii path) (liii uuid) (liii json) (liii string))

(define (welcome)
(flush-prompt "llm> ")
Expand All @@ -37,10 +37,44 @@
) ;let*
) ;define

;; 假插件不联网:把收到的 "%chat {json}" 协议行原样回传——content 换成
;; 假回复文本,params/sessionId 原样保留,供无网络环境验证协议字段
;; 双向链路;解析失败返回 #f,由调用方回退原文回显

(define (fake-llm-chat-reply data)
(let* ((payload (string-trim (string-drop data (string-length "%chat "))))
(j (catch #t (lambda () (string->json payload)) (lambda args #f)))
) ;
(if (not (json-object? j))
#f
(let ((content (json-ref-string j "content" ""))
(params (catch #t (lambda () (json-ref j "params")) (lambda args #f)))
) ;
(if (not (json-object? params))
#f
(string-append "%chat "
(json->string (json-set j
"content"
(string-append "[fake-llm] 我收到了你的消息:" content)
) ;json-set
) ;json->string
) ;string-append
) ;if
) ;let
) ;if
) ;let*
) ;define

(define (eval-and-print data)
;; 文本回显一律走 utf8: 通道:scheme: 通道要求负载是表示树的 scheme
;; 代码,自由文本会被解析成「首词作树标签」的畸形树,渲染只剩标签且
;; 打断本轮完成(超时)。旧 echo 侥幸可用是因为旧协议行恰好形如
;; (document "..."),本身即是合法树代码
(if (> (string-length data) *large-data-threshold*)
(flush-verbatim (llm-write-temp-file data))
(flush-scheme data)
(let ((reply (and (string-starts? data "%chat ") (fake-llm-chat-reply data))))
(flush-verbatim (or reply data))
) ;let
) ;if
) ;define

Expand Down
13 changes: 12 additions & 1 deletion TeXmacs/plugins/llm/progs/init-llm.scm
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,18 @@
(import (liii path))

(define (llm-serialize lan t)
(string-append (object->string t) "\n<EOF>\n")
;; connection-write 调用前已做 tree_herk_to_utf8,传入的 stree 字符串是
;; UTF-8。% 开头的单字符串文档(%chat 协议行)须原样透传:object->string
;; 会给字符串加引号/转义并包 (document ...) 外壳,子进程将无法识别协议行
(if (and (pair? t)
(>= (length t) 2)
(eq? (car t) 'document)
(string? (cadr t))
(string-starts? (cadr t) "%")
) ;and
(string-append (cadr t) "\n<EOF>\n")
(string-append (object->string t) "\n<EOF>\n")
) ;if
) ;define

(define (llm-launcher)
Expand Down
148 changes: 38 additions & 110 deletions TeXmacs/plugins/llm/progs/llm/chat-protocol.scm
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,38 @@
) ;:use
) ;texmacs-module

(import (liii njson))
(import (liii json))

(use-modules (account liii))

;;; ---------- Record Type ----------

(define-record-type <chat-input>
(make-chat-input input session-id model thinking search)
(make-chat-input input session-id model base-url thinking search)
chat-input?
(input chat-input-input)
(session-id chat-input-session-id)
(model chat-input-model)
(base-url chat-input-base-url)
(thinking chat-input-thinking)
(search chat-input-search)
) ;define-record-type

(define (chat-input->json ctx)
;; 协议 JSON 数据:content 为当前输入的纯文本,params 为 per-round 参数
;; (baseUrl 在此解析为绝对 URL)
(list (cons "sessionId" (chat-input-session-id ctx))
(cons "params"
(list (cons "model" (chat-input-model ctx))
(cons "baseUrl" (chat-tab-resolve-base-url (chat-input-base-url ctx)))
(cons "thinking" (chat-input-thinking ctx))
(cons "search" (chat-input-search ctx))
) ;list
) ;cons
(cons "content" (chat-tab-tree->plain-text (chat-input-input ctx)))
) ;list
) ;define

;;; ---------- Buffer 类型检测 ----------

(tm-define (chat-message-buffer? buf)
Expand Down Expand Up @@ -326,116 +344,24 @@

;;; ---------- 上下文构建 ----------

(define (chat-tab-suffix->mime suffix)
(cond ((== suffix "png") "image/png")
((or (== suffix "jpg") (== suffix "jpeg")) "image/jpeg")
((== suffix "gif") "image/gif")
((== suffix "webp") "image/webp")
(else #f)
) ;cond
) ;define

(define (chat-tab-image-node->pair img-stree)
;; img-stree = (image <name> ...)
;; Returns (mime . base64-data) or #f
(if (< (length img-stree) 2)
#f
(let ((name (cadr img-stree)))
(cond
;; Embedded: (tuple (raw-data <base64>) <filename>)
((and (pair? name) (eq? (car name) 'tuple) (>= (length name) 3))
(let ((data-node (cadr name)) (suffix-str (caddr name)))
(let ((suffix (url-suffix suffix-str))
(mime (chat-tab-suffix->mime (url-suffix suffix-str)))
) ;
(if (not mime)
#f
(cond
;; raw-data format: data already base64
((and (pair? data-node)
(>= (length data-node) 2)
(eq? (car data-node) 'raw-data)
) ;and
(cons mime (cadr data-node))
) ;
(else #f)
) ;cond
) ;if
) ;let
) ;let
) ;
;; Linked: string path — 需要读文件并 base64 编码
((string? name)
;; TODO: 需要加载 (liii base64) 后支持链接图片的 base64 编码
#f
) ;
(else #f)
) ;cond
) ;let
) ;if
) ;define

(define (chat-tab-collect-images s acc)
(cond ((string? s) acc)
((not (pair? s)) acc)
((eq? (car s) 'image)
(let ((img (chat-tab-image-node->pair s)))
(if img (cons img acc) acc)
) ;let
) ;
(else (let loop
((rest (cdr s)) (a acc))
(if (null? rest) a (loop (cdr rest) (chat-tab-collect-images (car rest) a)))
) ;let
) ;else
(define (chat-tab-resolve-base-url base-url)
;; http 开头视为绝对 URL 原样下发;空串原样(子进程兜底);
;; 相对路径在 scheme 侧拼接 current-stem-site,C++ 只透传清单原值
(cond ((string=? base-url "") "")
((string-starts? base-url "http") base-url)
(else (string-append (current-stem-site) base-url))
) ;cond
) ;define

(define (chat-tab-build-context-input ctx)
;; 单轮:只编码当前用户输入 + per-round 参数
;; 线格式:%chat <json>\n<EOF>\n
(let* ((input (chat-input-input ctx))
(session-id (chat-input-session-id ctx))
(model (chat-input-model ctx))
(thinking (chat-input-thinking ctx))
(search (chat-input-search ctx))
(content (chat-tab-tree->plain-text input))
(obj (string->njson "{}"))
(params (string->njson "{}"))
(stree-input (if (tree? input) (tree->stree input) input))
(images (chat-tab-collect-images stree-input '()))
) ;
(njson-set! obj "sessionId" session-id)
(njson-set! params "model" model)
(njson-set! params "thinking" thinking)
(njson-set! params "search" search)
(njson-set! obj "params" params)
(njson-set! obj "content" content)
;; 可选:有图片时加入 images 数组
(when (pair? images)
(let ((img-arr (string->njson "[]")))
(for-each (lambda (img-pair)
(let ((img-obj (string->njson "{}")))
(njson-set! img-obj "mime" (car img-pair))
Comment thread
da-liii marked this conversation as resolved.
(njson-set! img-obj "data" (cdr img-pair))
(njson-append! img-arr img-obj)
(njson-free img-obj)
) ;let
) ;lambda
images
) ;for-each
(njson-set! obj "images" img-arr)
(njson-free img-arr)
) ;let
) ;when
(let ((json-str (njson->string obj)))
(njson-free params)
(njson-free obj)
(let ((cork-json (utf8->cork json-str)))
(stree->tree `(document ,(string-append "%chat " cork-json)))
) ;let
) ;let
) ;let*
;; images 数组已随协议移除:图片上传属第二阶段,输入区图片暂按纯文本
;; 参与 content(含图片时 C++ 侧已提前拦截提示不支持);
;; 系统提示词不下发:由服务端或子进程插件配置
(let ((cork-json (utf8->cork (json->string (chat-input->json ctx)))))
(stree->tree `(document ,(string-append "%chat " cork-json)))
) ;let
) ;define

;;; ---------- Feed ----------
Expand All @@ -460,10 +386,11 @@

;;; ---------- 发送 ----------

(tm-define (chat-tab-session-send session-id model thinking search)
(tm-define (chat-tab-session-send session-id model base-url thinking search)
(:synopsis "Send user message through chat tab session")
(:argument session-id "Session UUID")
(:argument model "Model name")
(:argument base-url "Raw base_url from model manifest, may be relative")
(:argument thinking "Thinking mode: enabled or disabled")
(:argument search "Search mode: enabled or disabled")
(let* ((in-buf (chat-tab-session->input-buffer session-id))
Expand Down Expand Up @@ -511,7 +438,7 @@
#t
) ;begin
(begin
(let ((ctx (make-chat-input input session-id model thinking search)))
(let ((ctx (make-chat-input input session-id model base-url thinking search)))
(chat-tab-session-feed chat-tab-session-name plugin-ses ctx out '())
) ;let
#t
Expand Down Expand Up @@ -552,13 +479,14 @@
) ;if
) ;tm-define

(tm-define (chat-tab-send session-id model thinking search)
(tm-define (chat-tab-send session-id model base-url thinking search)
(:synopsis "Adapter send entry for a chat tab")
(:argument session-id "Session UUID")
(:argument model "Model name")
(:argument base-url "Raw base_url from model manifest, may be relative")
(:argument thinking "Thinking mode")
(:argument search "Search mode")
(chat-tab-session-send session-id model thinking search)
(chat-tab-session-send session-id model base-url thinking search)
) ;tm-define

(tm-define (chat-tab-cancel session-id)
Expand Down
Loading
Loading