From b8fd52b77f0e5046e92310e5905debf8287d6b15 Mon Sep 17 00:00:00 2001 From: tiye Date: Thu, 17 Sep 2026 19:45:30 +0800 Subject: [PATCH 1/3] fix message model routing --- calcit.cirru | 9 ++++++- package.json | 4 +-- yarn.lock | 75 ++++++++++++++++++++++++++++++++++++---------------- 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/calcit.cirru b/calcit.cirru index 63a924e..d401922 100644 --- a/calcit.cirru +++ b/calcit.cirru @@ -1429,10 +1429,17 @@ :args $ [] 'Dynamic 'app.schema/MessageBoxState 'Dynamic 'pick-model $ %{} 'CodeEntry (:doc |) :code $ quote $ defn pick-model (variant) - case-default variant |gemini-3.5-flash (:gemini-3.5-flash-lite |gemini-3.1-flash-lite) (:gemini-3.6-flash |gemini-3.5-flash) (:gemini-3.7-flash |gemini-3.7-flash) (:gemini-3.8-flash |gemini-3.8-flash) (:gemini-3.5-flash-lite |gemini-3.1-flash-lite) (:gemini-3.1-flash-lite-preview |gemini-3.1-flash-lite) (:gemini-pro |gemini-3.1-pro-preview) (:gemma |gemma-3-27b-it) + case-default variant |gemini-3.5-flash-lite (:gemini-3.5-flash-lite |gemini-3.5-flash-lite) (:gemini-3.6-flash |gemini-3.6-flash) (:gemini-3.7-flash |gemini-3.7-flash) (:gemini-3.8-flash |gemini-3.8-flash) (:gemini-flash |gemini-3-flash-preview) (:gemini-3.5-flash |gemini-3.5-flash) (:gemini-3.1-flash-lite-preview |gemini-3.1-flash-lite) (:gemini-pro |gemini-3.1-pro-preview) (:gemma |gemma-3-27b-it) :examples $ [] :schema $ :: 'Fn $ {} (:return 'String) :args $ [] 'Tag + :tests $ [] $ %{} 'TestEntry (:name |routes-current-gemini-models) + :code $ quote $ do + assert= |gemini-3.5-flash-lite $ pick-model :gemini + assert= |gemini-3.5-flash-lite $ pick-model :gemini-3.5-flash-lite + assert= |gemini-3.6-flash $ pick-model :gemini-3.6-flash + assert= |gemini-3-flash-preview $ pick-model :gemini-flash + assert= |gemini-3.1-pro-preview $ pick-model :gemini-pro 'required-key! $ %{} 'CodeEntry (:doc |) :code $ quote $ defn required-key! (storage-key prompt-text) let diff --git a/package.json b/package.json index 0cdef44..fa6f793 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "dependencies": { "@calcit/procs": "0.15.3", - "@google/genai": "^2.20.0", + "@google/genai": "2.23.0", "@tiye/main-fonts": "0.0.1", - "axios": "^1.15.0", + "axios": "1.20.0", "cirru-color": "^0.2.4", "copy-text-to-clipboard": "^3.2.2", "dayjs": "^1.11.18", diff --git a/yarn.lock b/yarn.lock index 2af1866..6175240 100644 --- a/yarn.lock +++ b/yarn.lock @@ -37,9 +37,9 @@ __metadata: languageName: node linkType: hard -"@google/genai@npm:^2.20.0": - version: 2.20.0 - resolution: "@google/genai@npm:2.20.0" +"@google/genai@npm:2.23.0": + version: 2.23.0 + resolution: "@google/genai@npm:2.23.0" dependencies: google-auth-library: "npm:^10.3.0" p-retry: "npm:^4.6.2" @@ -50,7 +50,7 @@ __metadata: peerDependenciesMeta: "@modelcontextprotocol/sdk": optional: true - checksum: 10c0/828cbca6d112a378209a4cdc49c55122de498a0809ac5546e65b236a53aa032da953b0d08f8e0df1d6f51b92ba20ee192ea823521135744fca25b0a55778dd56 + checksum: 10c0/32bcd0bc6129080fe2d02bf31aed9e917b5a67ca6547ce90a0426cbb03e2ef4e3368c9f1c2c4ffa32b10338df5c3dc45336b9fe582c104f06ca23cb85fb13b97 languageName: node linkType: hard @@ -307,6 +307,15 @@ __metadata: languageName: node linkType: hard +"agent-base@npm:6": + version: 6.0.2 + resolution: "agent-base@npm:6.0.2" + dependencies: + debug: "npm:4" + checksum: 10c0/dc4f757e40b5f3e3d674bc9beb4f1048f4ee83af189bae39be99f57bf1f48dde166a8b0a5342a84b5944ee8e6ed1e5a9d801858f4ad44764e84957122fe46261 + languageName: node + linkType: hard + "agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": version: 7.1.4 resolution: "agent-base@npm:7.1.4" @@ -321,14 +330,15 @@ __metadata: languageName: node linkType: hard -"axios@npm:^1.15.0": - version: 1.15.0 - resolution: "axios@npm:1.15.0" +"axios@npm:1.20.0": + version: 1.20.0 + resolution: "axios@npm:1.20.0" dependencies: - follow-redirects: "npm:^1.15.11" - form-data: "npm:^4.0.5" + follow-redirects: "npm:^1.16.0" + form-data: "npm:^4.0.6" + https-proxy-agent: "npm:^5.0.1" proxy-from-env: "npm:^2.1.0" - checksum: 10c0/47e0f860e98d4d7aa145e89ce0cae00e1fb0f1d2485f065c21fce955ddb1dba4103a46bd0e47acd18a27208a7f62c96249e620db575521b92a968619ab133409 + checksum: 10c0/976088acf532286356f4c2e65df1ef47ba7da3936d83e928d0d64357bbf5370456abd3eb5826c15df322335fcb1fe200d4a84b4fcf20ffccdd63b40d80fa495c languageName: node linkType: hard @@ -632,26 +642,26 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.15.11": - version: 1.15.11 - resolution: "follow-redirects@npm:1.15.11" +"follow-redirects@npm:^1.16.0": + version: 1.16.0 + resolution: "follow-redirects@npm:1.16.0" peerDependenciesMeta: debug: optional: true - checksum: 10c0/d301f430542520a54058d4aeeb453233c564aaccac835d29d15e050beb33f339ad67d9bddbce01739c5dc46a6716dbe3d9d0d5134b1ca203effa11a7ef092343 + checksum: 10c0/a1e2900163e6f1b4d1ed5c221b607f41decbab65534c63fe7e287e40a5d552a6496e7d9d7d976fa4ba77b4c51c11e5e9f683f10b43011ea11e442ff128d0e181 languageName: node linkType: hard -"form-data@npm:^4.0.5": - version: 4.0.5 - resolution: "form-data@npm:4.0.5" +"form-data@npm:^4.0.6": + version: 4.0.6 + resolution: "form-data@npm:4.0.6" dependencies: asynckit: "npm:^0.4.0" combined-stream: "npm:^1.0.8" es-set-tostringtag: "npm:^2.1.0" - hasown: "npm:^2.0.2" - mime-types: "npm:^2.1.12" - checksum: 10c0/dd6b767ee0bbd6d84039db12a0fa5a2028160ffbfaba1800695713b46ae974a5f6e08b3356c3195137f8530dcd9dfcb5d5ae1eeff53d0db1e5aad863b619ce3b + hasown: "npm:^2.0.4" + mime-types: "npm:^2.1.35" + checksum: 10c0/43947a77bf0ff45c6ceed789778982d47a3f3e720a74b71721174ebf3310a5f1a8be1d6b38a3ee3688e8a18a2c4273073ec0844cd37efda3eaf46d41c9c318ff languageName: node linkType: hard @@ -841,6 +851,15 @@ __metadata: languageName: node linkType: hard +"hasown@npm:^2.0.4": + version: 2.0.4 + resolution: "hasown@npm:2.0.4" + dependencies: + function-bind: "npm:^1.1.2" + checksum: 10c0/2d8de939e270b70618f8cebb69746620db10617dbb495bc66ddad326955ea24d3ca4af133aff3eb7c1853e0218f867bc2b050ec26fe02e3aea58f880ffc5e506 + languageName: node + linkType: hard + "http-cache-semantics@npm:^4.1.1": version: 4.2.0 resolution: "http-cache-semantics@npm:4.2.0" @@ -858,6 +877,16 @@ __metadata: languageName: node linkType: hard +"https-proxy-agent@npm:^5.0.1": + version: 5.0.1 + resolution: "https-proxy-agent@npm:5.0.1" + dependencies: + agent-base: "npm:6" + debug: "npm:4" + checksum: 10c0/6dd639f03434003577c62b27cafdb864784ef19b2de430d8ae2a1d45e31c4fd60719e5637b44db1a88a046934307da7089e03d6089ec3ddacc1189d8de8897d1 + languageName: node + linkType: hard + "https-proxy-agent@npm:^7.0.1": version: 7.0.6 resolution: "https-proxy-agent@npm:7.0.6" @@ -1102,7 +1131,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:^2.1.12": +"mime-types@npm:^2.1.35": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -1504,9 +1533,9 @@ __metadata: resolution: "root-workspace-0b6124@workspace:." dependencies: "@calcit/procs": "npm:0.15.3" - "@google/genai": "npm:^2.20.0" + "@google/genai": "npm:2.23.0" "@tiye/main-fonts": "npm:0.0.1" - axios: "npm:^1.15.0" + axios: "npm:1.20.0" bottom-tip: "npm:^0.1.5" cirru-color: "npm:^0.2.4" copy-text-to-clipboard: "npm:^3.2.2" From d20ac6a01e5bcdeb764eeebf3313bc4166737ead Mon Sep 17 00:00:00 2001 From: tiye Date: Thu, 17 Sep 2026 21:10:01 +0800 Subject: [PATCH 2/3] migrate legacy stored messages --- calcit.cirru | 103 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 9 deletions(-) diff --git a/calcit.cirru b/calcit.cirru index d401922..690be06 100644 --- a/calcit.cirru +++ b/calcit.cirru @@ -499,8 +499,7 @@ let app-store $ option:fold (get reel :store) fn () store - fn (raw-store) - if (struct? raw-store) (unsafe-coerce raw-store 'app.schema/Store) (decode-map-as raw-store 'app.schema/Store) + fn (raw-store) (app.schema/normalize-store raw-store) sessions $ :sessions app-store archived-count $ :archived-count app-store current-session-id $ :current-session-id app-store @@ -1381,9 +1380,12 @@ , :done? case-default done-value true (true true) (false false) , :messages - unsafe-coerce - option:unwrap-or (get data :messages) ([]) - :: 'List 'app.schema/ChatMessage + let + raw-message-value $ option:unwrap-or (get data :messages) ([]) + raw-messages $ if (list? raw-message-value) + assert-type raw-message-value $ :: 'List 'Dynamic + [] + map raw-messages $ fn (message) (app.schema/normalize-chat-message message) , :model if (tag? model-value) model-value :gemini , :thinking $ stream-text $ option:unwrap-or (get data :thinking) | @@ -2225,6 +2227,26 @@ :archived-count 'Number :examples $ [] :schema $ :: 'StructDef + 'normalize-chat-message $ %{} 'CodeEntry (:doc |) + :code $ quote $ defn normalize-chat-message (raw) + hint-fn $ {} + :args $ [] 'T + :return 'app.schema/ChatMessage + :features $ #{} :js-ffi + :generics $ [] 'T + if (struct? raw) (assert-type raw 'app.schema/ChatMessage) + if (map? raw) + let + data $ assert-type raw $ :: 'Map 'Tag 'Dynamic + thinking-value $ option:unwrap-or (get data :thinking) | + normalized-thinking $ if (string? thinking-value) (assert-type thinking-value 'String) | + decode-map-as (assoc data :thinking normalized-thinking) 'app.schema/ChatMessage + raise "|Expected chat message map" + :examples $ [] + :schema $ :: 'Fn $ {} (:return 'app.schema/ChatMessage) + :args $ [] 'T + :features $ #{} :js-ffi + :generics $ [] 'T 'normalize-chat-session $ %{} 'CodeEntry (:doc |) :code $ quote $ defn normalize-chat-session (raw) hint-fn $ {} @@ -2232,7 +2254,20 @@ :return 'app.schema/ChatSession :features $ #{} :js-ffi :generics $ [] 'T - if (struct? raw) (assert-type raw 'app.schema/ChatSession) (decode-map-as raw 'app.schema/ChatSession) + if (struct? raw) (assert-type raw 'app.schema/ChatSession) + if (map? raw) + let + data $ assert-type raw $ :: 'Map 'Tag 'Dynamic + raw-message-value $ option:unwrap-or (get data :messages) ([]) + raw-messages $ if (list? raw-message-value) + assert-type raw-message-value $ :: 'List 'Dynamic + [] + messages $ map raw-messages $ fn (message) (normalize-chat-message message) + base $ decode-map-as + assoc data :messages $ [] + , 'app.schema/ChatSession + ChatSession :id (:id base) :created-at (:created-at base) :messages messages :model (:model base) :preview (:preview base) :is-history? $ :is-history? base + raise "|Expected chat session map" :examples $ [] :schema $ :: 'Fn $ {} (:return 'app.schema/ChatSession) :args $ [] 'T @@ -2251,6 +2286,58 @@ is $ = |decoded $ :id decoded is $ = :anthropic $ :model decoded :tags $ #{} :regression :unit + 'normalize-store $ %{} 'CodeEntry (:doc |) + :code $ quote $ defn normalize-store (raw) + hint-fn $ {} + :args $ [] 'T + :return 'app.schema/Store + :features $ #{} :js-ffi + :generics $ [] 'T + if (struct? raw) (assert-type raw 'app.schema/Store) + if (map? raw) + let + data $ assert-type raw $ :: 'Map 'Tag 'Dynamic + raw-session-value $ option:unwrap-or (get data :sessions) ([]) + raw-sessions $ if (list? raw-session-value) + assert-type raw-session-value $ :: 'List 'Dynamic + [] + sessions $ map raw-sessions $ fn (session) (normalize-chat-session session) + patched $ dissoc data :current-chapter-id + base $ decode-map-as + assoc patched :sessions $ [] + , 'app.schema/Store + Store :states (:states base) :sessions sessions :current-session-id (:current-session-id base) :model (:model base) :archived-count $ :archived-count base + raise "|Expected store map" + :examples $ [] + :schema $ :: 'Fn $ {} (:return 'app.schema/Store) + :args $ [] 'T + :features $ #{} :js-ffi + :generics $ [] 'T + :tests $ [] $ %{} 'TestEntry (:name |migrates-legacy-message-thinking) + :code $ quote $ let + legacy $ {} + :states $ {} $ :cursor ([]) + :sessions $ [] $ {} (:id |legacy) (:created-at 1) + :messages $ [] $ {} (:role :user) (:content |hello) + :model :gemini + :preview |hello + :is-history? true + :current-session-id nil + :model nil + :archived-count 0 + normalized $ assert-type (normalize-store legacy) 'app.schema/Store + sessions $ assert-type (:sessions normalized) (:: 'List 'app.schema/ChatSession) + fallback-session $ ChatSession :id |fallback :created-at 0 :messages ([]) :model :gemini :preview | :is-history? false + session $ option:unwrap-or + assert-type (first sessions) (:: 'Option 'app.schema/ChatSession) + , fallback-session + messages $ assert-type (:messages session) (:: 'List 'app.schema/ChatMessage) + fallback-message $ ChatMessage :role :user :content | :thinking |fallback + message $ option:unwrap-or + assert-type (first messages) (:: 'Option 'app.schema/ChatMessage) + , fallback-message + is $ = | $ :thinking message + :tags $ #{} :regression :unit 'store $ %{} 'CodeEntry (:doc |) :code $ quote $ def store Store :states @@ -2289,9 +2376,7 @@ assert-type changes $ :: 'Map 'Tag 'Dynamic do (eprintln |unknown-state-to-merge state) state assoc store :states updated-states - (:hydrate-storage data) - if (struct? data) (assert-type data 'app.schema/Store) - decode-map-as (dissoc data :current-chapter-id) 'app.schema/Store + (:hydrate-storage data) (app.schema/normalize-store data) (:change-model) if = (:model store) :anthropic From d03fdc8025cf3c8138af45d1278a1c7ed008050f Mon Sep 17 00:00:00 2001 From: tiye Date: Thu, 17 Sep 2026 21:54:32 +0800 Subject: [PATCH 3/3] upgrade markdown rendering dependencies --- deps.cirru | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deps.cirru b/deps.cirru index a607865..7043d2d 100644 --- a/deps.cirru +++ b/deps.cirru @@ -1,9 +1,9 @@ {} (:calcit-version |0.15.3) :version |0.0.7 - :dependencies $ {} (|Respo/alerts.calcit |0.10.39) + :dependencies $ {} (|Respo/alerts.calcit |0.10.40) |Respo/reel.calcit |0.6.27 - |Respo/respo-markdown.calcit |0.4.39 + |Respo/respo-markdown.calcit |0.4.40 |Respo/respo-ui.calcit |0.7.25 |Respo/respo.calcit |0.16.104 |calcit-lang/js-ffi |0.1.19