openvibers/openvibe.network Commits
Frame Runs: a Vibe chat's title is its own name (#877)
Changes
@@@ -78,7 +78,7 @@ function createFrameRuns({ svcUrl = (name, fallback) => fallback, personOf = asyconst persona = c.persona && typeof c.persona === 'object' ? c.persona : null;const at = iso(c.last_message_at || c.updated_at || c.created_at) || new Date(now()).toISOString();const run = {-- id: String(c.slug), ref: `chat:${c.slug}`, kind: 'chat', title: clip((persona && persona.name) || c.name || 'Vibe', 200) || 'Vibe',++ id: String(c.slug), ref: `chat:${c.slug}`, kind: 'chat', title: clip(c.name || (persona && persona.name) || 'Vibe', 200) || 'Vibe', // the chat's own name: Chat sets it to the persona's unless the person renamed itowner, agent: { id: 'vibe', name: clip((persona && persona.name) || 'Vibe', 160) || 'Vibe', product: 'chat', harness: 'openvibe' },status: 'waiting', waiting: { for: 'message' },url: httpsUrl(c.url) || `https://openvibe.chat/vibe/${encodeURIComponent(c.slug)}`,@@@ -26,7 +26,7 @@ const sendJson = (res, status, body) => { res.statusCode = status; res.setHeaderconst chat = await listen(async (req, res) => {seen.push({ svc: 'chat', method: req.method, url: req.url, auth: req.headers.authorization });const u = new URL(req.url, 'http://x');-- if (u.pathname === '/api/vibe/conversations') return sendJson(res, 200, { conversations: [{ slug: 'c_keys', name: 'Keyboard Scout', last_line: 'Three picks under $90.', last_message_at: '2026-11-12 10:00:20', site: 'https://openvibe.deals', persona: { name: 'Keyboard Scout', glyph: 'search', hue: 212 } }], count: 1 });++ if (u.pathname === '/api/vibe/conversations') return sendJson(res, 200, { conversations: [{ slug: 'c_keys', name: 'My keyboard hunt', last_line: 'Three picks under $90.', last_message_at: '2026-11-12 10:00:20', site: 'https://openvibe.deals', persona: { name: 'Keyboard Scout', glyph: 'search', hue: 212 } }], count: 1 });if (u.pathname === '/api/vibe/chat') {if (u.searchParams.get('slug') !== 'c_keys') return sendJson(res, 200, { chat: null, messages: [] });const after = Number(u.searchParams.get('after')) || 0;@@@ -94,6 +94,7 @@ const sendJson = (res, status, body) => { res.statusCode = status; res.setHeaderassert.strictEqual(vibeRun.status, 'waiting');assert.deepStrictEqual(vibeRun.waiting, { for: 'message' }, 'a conversation is a run waiting for a message');assert.deepStrictEqual(vibeRun.agent, { id: 'vibe', name: 'Keyboard Scout', product: 'chat', harness: 'openvibe', glyph: 'search', hue: 212 }, 'the persona is the agent\'s face');++ assert.strictEqual(vibeRun.title, 'My keyboard hunt', 'the chat\'s own name is its title (a person\'s rename stays theirs); the persona names the agent');assert.strictEqual(vibeRun.updated_at, '2026-11-12T10:00:20.000Z', 'a time without a zone is UTC');assert.deepStrictEqual(vibeRun.context, { site: 'openvibe.deals' });assert.deepStrictEqual(vibeRun.owner, { type: 'user', id: 'usr_01K9R2V6M8Q4T0B7C3D5E9F2GH' });
@@ -78,7 +78,7 @@ function createFrameRuns({ svcUrl = (name, fallback) => fallback, personOf = asy
@@ -78,7 +78,7 @@ function createFrameRuns({ svcUrl = (name, fallback) => fallback, personOf = asy
const persona = c.persona && typeof c.persona === 'object' ? c.persona : null;
const persona = c.persona && typeof c.persona === 'object' ? c.persona : null;
const at = iso(c.last_message_at || c.updated_at || c.created_at) || new Date(now()).toISOString();
const at = iso(c.last_message_at || c.updated_at || c.created_at) || new Date(now()).toISOString();
const run = {
const run = {
- id: String(c.slug), ref: `chat:${c.slug}`, kind: 'chat', title: clip((persona && persona.name) || c.name || 'Vibe', 200) || 'Vibe',
+ id: String(c.slug), ref: `chat:${c.slug}`, kind: 'chat', title: clip(c.name || (persona && persona.name) || 'Vibe', 200) || 'Vibe', // the chat's own name: Chat sets it to the persona's unless the person renamed it
owner, agent: { id: 'vibe', name: clip((persona && persona.name) || 'Vibe', 160) || 'Vibe', product: 'chat', harness: 'openvibe' },
owner, agent: { id: 'vibe', name: clip((persona && persona.name) || 'Vibe', 160) || 'Vibe', product: 'chat', harness: 'openvibe' },
status: 'waiting', waiting: { for: 'message' },
status: 'waiting', waiting: { for: 'message' },
url: httpsUrl(c.url) || `https://openvibe.chat/vibe/${encodeURIComponent(c.slug)}`,
url: httpsUrl(c.url) || `https://openvibe.chat/vibe/${encodeURIComponent(c.slug)}`,
@@ -26,7 +26,7 @@ const sendJson = (res, status, body) => { res.statusCode = status; res.setHeader
@@ -26,7 +26,7 @@ const sendJson = (res, status, body) => { res.statusCode = status; res.setHeader
const chat = await listen(async (req, res) => {
const chat = await listen(async (req, res) => {
seen.push({ svc: 'chat', method: req.method, url: req.url, auth: req.headers.authorization });
seen.push({ svc: 'chat', method: req.method, url: req.url, auth: req.headers.authorization });
const u = new URL(req.url, 'http://x');
const u = new URL(req.url, 'http://x');
- if (u.pathname === '/api/vibe/conversations') return sendJson(res, 200, { conversations: [{ slug: 'c_keys', name: 'Keyboard Scout', last_line: 'Three picks under $90.', last_message_at: '2026-11-12 10:00:20', site: 'https://openvibe.deals', persona: { name: 'Keyboard Scout', glyph: 'search', hue: 212 } }], count: 1 });
+ if (u.pathname === '/api/vibe/conversations') return sendJson(res, 200, { conversations: [{ slug: 'c_keys', name: 'My keyboard hunt', last_line: 'Three picks under $90.', last_message_at: '2026-11-12 10:00:20', site: 'https://openvibe.deals', persona: { name: 'Keyboard Scout', glyph: 'search', hue: 212 } }], count: 1 });
if (u.pathname === '/api/vibe/chat') {
if (u.pathname === '/api/vibe/chat') {
if (u.searchParams.get('slug') !== 'c_keys') return sendJson(res, 200, { chat: null, messages: [] });
if (u.searchParams.get('slug') !== 'c_keys') return sendJson(res, 200, { chat: null, messages: [] });
const after = Number(u.searchParams.get('after')) || 0;
const after = Number(u.searchParams.get('after')) || 0;
@@ -94,6 +94,7 @@ const sendJson = (res, status, body) => { res.statusCode = status; res.setHeader
@@ -94,6 +94,7 @@ const sendJson = (res, status, body) => { res.statusCode = status; res.setHeader
assert.strictEqual(vibeRun.status, 'waiting');
assert.strictEqual(vibeRun.status, 'waiting');
assert.deepStrictEqual(vibeRun.waiting, { for: 'message' }, 'a conversation is a run waiting for a message');
assert.deepStrictEqual(vibeRun.waiting, { for: 'message' }, 'a conversation is a run waiting for a message');
assert.deepStrictEqual(vibeRun.agent, { id: 'vibe', name: 'Keyboard Scout', product: 'chat', harness: 'openvibe', glyph: 'search', hue: 212 }, 'the persona is the agent\'s face');
assert.deepStrictEqual(vibeRun.agent, { id: 'vibe', name: 'Keyboard Scout', product: 'chat', harness: 'openvibe', glyph: 'search', hue: 212 }, 'the persona is the agent\'s face');
+ assert.strictEqual(vibeRun.title, 'My keyboard hunt', 'the chat\'s own name is its title (a person\'s rename stays theirs); the persona names the agent');
assert.strictEqual(vibeRun.updated_at, '2026-11-12T10:00:20.000Z', 'a time without a zone is UTC');
assert.strictEqual(vibeRun.updated_at, '2026-11-12T10:00:20.000Z', 'a time without a zone is UTC');
assert.deepStrictEqual(vibeRun.context, { site: 'openvibe.deals' });
assert.deepStrictEqual(vibeRun.context, { site: 'openvibe.deals' });
assert.deepStrictEqual(vibeRun.owner, { type: 'user', id: 'usr_01K9R2V6M8Q4T0B7C3D5E9F2GH' });
assert.deepStrictEqual(vibeRun.owner, { type: 'user', id: 'usr_01K9R2V6M8Q4T0B7C3D5E9F2GH' });