fix: use valid Zen summaries for notes
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import express from 'express';
|
||||
import { normalizeCustomOpenAIBaseURL } from './base-url.js';
|
||||
import { summarizeText, sanitizeForTTS, sanitizeForNote } from '../text/summarization.js';
|
||||
import { summarizeText, sanitizeForTTS, sanitizeForNote, sanitizeForNotification } from '../text/summarization.js';
|
||||
|
||||
export function registerTtsRoutes(app, { resolveZenModel, sayTTSCapability }) {
|
||||
let ttsModulePromise = null;
|
||||
@@ -124,7 +124,7 @@ export function registerTtsRoutes(app, { resolveZenModel, sayTTSCapability }) {
|
||||
}
|
||||
|
||||
const sumZenModel = await resolveZenModel(typeof req.body?.zenModel === 'string' ? req.body.zenModel : undefined);
|
||||
const result = await summarizeText({
|
||||
let result = await summarizeText({
|
||||
text,
|
||||
threshold,
|
||||
maxLength,
|
||||
@@ -132,6 +132,27 @@ export function registerTtsRoutes(app, { resolveZenModel, sayTTSCapability }) {
|
||||
mode: typeof mode === 'string' ? mode : 'tts',
|
||||
});
|
||||
|
||||
if (mode === 'note' && !result.summarized) {
|
||||
const notificationResult = await summarizeText({
|
||||
text,
|
||||
threshold,
|
||||
maxLength,
|
||||
zenModel: sumZenModel,
|
||||
mode: 'notification',
|
||||
});
|
||||
if (notificationResult.summarized && notificationResult.summary) {
|
||||
result = {
|
||||
...notificationResult,
|
||||
summary: sanitizeForNote(sanitizeForNotification(notificationResult.summary)),
|
||||
};
|
||||
} else {
|
||||
return res.status(502).json({
|
||||
error: 'Note summarization failed',
|
||||
reason: notificationResult.reason || result.reason || 'No distilled result from model',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return res.json(result);
|
||||
} catch (error) {
|
||||
console.error('[Summarize] Error:', error);
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import express from 'express';
|
||||
import request from 'supertest';
|
||||
|
||||
import { registerTtsRoutes } from './routes.js';
|
||||
|
||||
const createApp = () => {
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
registerTtsRoutes(app, {
|
||||
resolveZenModel: async () => 'gpt-5-nano',
|
||||
sayTTSCapability: null,
|
||||
});
|
||||
return app;
|
||||
};
|
||||
|
||||
describe('tts routes', () => {
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it('retries note summarization with notification mode before failing', async () => {
|
||||
vi.stubGlobal('fetch', vi.fn(async () => ({
|
||||
ok: false,
|
||||
status: 503,
|
||||
json: async () => ({ error: 'unavailable' }),
|
||||
})));
|
||||
|
||||
const response = await request(createApp())
|
||||
.post('/api/text/summarize')
|
||||
.send({
|
||||
text: 'First sentence. Second sentence with the useful insight.',
|
||||
threshold: 0,
|
||||
maxLength: 100,
|
||||
mode: 'note',
|
||||
});
|
||||
|
||||
expect(response.status).toBe(502);
|
||||
expect(fetch).toHaveBeenCalledTimes(2);
|
||||
expect(response.body).toEqual({
|
||||
error: 'Note summarization failed',
|
||||
reason: 'zen API returned 503',
|
||||
});
|
||||
});
|
||||
|
||||
it('uses notification summarizer result when note mode falls back', async () => {
|
||||
vi.stubGlobal('fetch', vi.fn()
|
||||
.mockResolvedValueOnce({
|
||||
ok: false,
|
||||
status: 503,
|
||||
json: async () => ({ error: 'unavailable' }),
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
output: [{
|
||||
type: 'message',
|
||||
content: [{ type: 'output_text', text: '**Keep provider state stable** during streaming.' }],
|
||||
}],
|
||||
}),
|
||||
}));
|
||||
|
||||
const response = await request(createApp())
|
||||
.post('/api/text/summarize')
|
||||
.send({
|
||||
text: 'First sentence. Preserve provider state references during streaming to avoid wide rerenders.',
|
||||
threshold: 0,
|
||||
maxLength: 100,
|
||||
mode: 'note',
|
||||
});
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toMatchObject({
|
||||
summary: 'Keep provider state stable during streaming.',
|
||||
summarized: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('keeps notification fallback behavior', async () => {
|
||||
vi.stubGlobal('fetch', vi.fn(async () => ({
|
||||
ok: false,
|
||||
status: 503,
|
||||
json: async () => ({ error: 'unavailable' }),
|
||||
})));
|
||||
|
||||
const response = await request(createApp())
|
||||
.post('/api/text/summarize')
|
||||
.send({
|
||||
text: 'Notification text that should fall back cleanly.',
|
||||
threshold: 0,
|
||||
maxLength: 100,
|
||||
mode: 'notification',
|
||||
});
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toMatchObject({
|
||||
summary: 'Notification text that should fall back cleanly.',
|
||||
summarized: false,
|
||||
reason: 'zen API returned 503',
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user