@firstlovecenter/ai-chat 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ All notable changes to `@firstlovecenter/ai-chat` are documented here.
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.3] — 2026-05-08
9
+
10
+ ### Fixed
11
+
12
+ - **Empty placeholder boxes when the model produces a content-free `present()`** — when the agent loop forces a model through `SELF_VERIFY_REQUIRED` for a question with no data answer (advisory / strategic prompts), some models satisfy the schema with empty strings (`text: ''`, `key_facts: []`, etc.) instead of refusing. The result was a row of empty cyan callout boxes in the chat. Two fixes:
13
+ - **Agent loop** (`runAgent`) — after `present()` returns, if every block in the payload is functionally empty AND the transcript contains assistant text, replace the payload with a synthetic single-block `paragraph_brief` carrying the model's last text. The user gets the model's actual reasoning instead of empty boxes.
14
+ - **UI** (`AnswerBlocks`) — defensive filter: blocks where `isBlockEmpty()` returns true are hidden at render time. Catches the case where the agent-loop salvage didn't apply (e.g. a partial-empty payload mixed with real content).
15
+
16
+ ### Changed
17
+
18
+ - **Live "Thinking… (15s)" counter styling** — the elapsed-time chip now renders one tier smaller (`text-xs`) than the surrounding "Thinking…" copy and gets a wider gap (`ml-2`) so it reads as a secondary annotation rather than running into the main text.
19
+
8
20
  ## [0.2.2] — 2026-05-08
9
21
 
10
22
  ### Added
@@ -79,6 +91,7 @@ Initial public release on npm under `@firstlovecenter/ai-chat`.
79
91
  - Dual ESM + CJS output via `tsup` with full `.d.ts` (and `.d.cts`) generation.
80
92
  - UI bundle gets a post-build `'use client';` directive injection (tsup otherwise strips module-level directives during bundling, breaking RSC consumers that import the UI from a server file).
81
93
 
94
+ [0.2.3]: https://github.com/firstlovecenter/flc-ai-chat/compare/v0.2.2...v0.2.3
82
95
  [0.2.2]: https://github.com/firstlovecenter/flc-ai-chat/compare/v0.2.1...v0.2.2
83
96
  [0.2.1]: https://github.com/firstlovecenter/flc-ai-chat/compare/v0.2.0...v0.2.1
84
97
  [0.2.0]: https://github.com/firstlovecenter/flc-ai-chat/compare/v0.1.1...v0.2.0
@@ -130,8 +130,46 @@ async function runAgent(input) {
130
130
  transcript
131
131
  };
132
132
  }
133
+ if (allBlocksEmpty(presentPayload.blocks)) {
134
+ const lastAssistantText = [...transcript].reverse().find((e) => e.kind === "assistant_text");
135
+ const text = lastAssistantText?.text.trim();
136
+ if (text) {
137
+ const topic = input.question.length > 80 ? input.question.slice(0, 77) + "..." : input.question;
138
+ presentPayload = {
139
+ blocks: [
140
+ {
141
+ kind: "paragraph_brief",
142
+ topic,
143
+ key_facts: [text]
144
+ }
145
+ ],
146
+ raw_numbers: presentPayload.raw_numbers ?? {}
147
+ };
148
+ }
149
+ }
133
150
  return { ok: true, structured: presentPayload, toolCallCount, transcript };
134
151
  }
152
+ function allBlocksEmpty(blocks) {
153
+ if (blocks.length === 0) return true;
154
+ return blocks.every((b) => {
155
+ if (b.kind === "paragraph_brief") {
156
+ return b.key_facts.length === 0 || b.key_facts.every((f) => !f.trim());
157
+ }
158
+ if (b.kind === "list") {
159
+ return b.items.length === 0 || b.items.every((i) => !i.trim());
160
+ }
161
+ if (b.kind === "callout") {
162
+ return !b.text.trim();
163
+ }
164
+ if (b.kind === "chart") {
165
+ return b.data.length === 0;
166
+ }
167
+ if (b.kind === "table") {
168
+ return b.rows.length === 0;
169
+ }
170
+ return false;
171
+ });
172
+ }
135
173
  var ClaudeToolProvider = class {
136
174
  id = "claude";
137
175
  client;