|
|
@@ -2,7 +2,9 @@
|
|
|
* sessions.rename delegation through the composed SessionTitleService. The
|
|
|
* agent factory is a structural stub whose createAgent forwards seed/meta into
|
|
|
* the real SessionStore, and whose resume never runs (every source here is
|
|
|
- * already attached).
|
|
|
+ * already attached). Cold-session resolution is the shared `agentFor` path —
|
|
|
+ * api-proxy-cold.spec.ts owns the resume evidence for every unary that rides
|
|
|
+ * it, rename included.
|
|
|
*/
|
|
|
|
|
|
import { describe, expect, it } from 'vitest'
|
|
|
@@ -82,20 +84,37 @@ describe('sessions.rename', () => {
|
|
|
expect(event?.data).toMatchObject({ title: 'new name', source: { kind: 'user' } })
|
|
|
})
|
|
|
|
|
|
- it('maps an empty-normalizing title to title-invalid', async () => {
|
|
|
+ it('maps only an empty-normalizing title to title-invalid, with a presentable message', async () => {
|
|
|
const ctx = await composed()
|
|
|
const source = liveAgent(ctx, 'session-rename-bad', 1)
|
|
|
|
|
|
- const response = await api(ctx).sessions.rename(request({ sessionId: source.id, title: ' ' }))
|
|
|
+ // U+200B passes a client-side trim gate but normalizes to empty host-side.
|
|
|
+ const response = await api(ctx).sessions.rename(request({ sessionId: source.id, title: ' ' }))
|
|
|
expect(response.result.ok).toBe(false)
|
|
|
if (!response.result.ok) {
|
|
|
expect(response.result.error).toMatchObject({
|
|
|
code: 'title-invalid',
|
|
|
details: { sessionId: source.id },
|
|
|
})
|
|
|
+ // The message renders verbatim in the rename dialog's alert.
|
|
|
+ expect(response.result.error.message).toBe('session title must contain visible characters')
|
|
|
}
|
|
|
})
|
|
|
|
|
|
+ it('maps a non-validation rename failure (stale session object) to internal, not title-invalid', async () => {
|
|
|
+ const ctx = await composed()
|
|
|
+ // The registered agent holds a session object from another store: the
|
|
|
+ // title service's liveness check throws a plain Error, which must not
|
|
|
+ // read as the user's fault.
|
|
|
+ const foreign = await composed(false)
|
|
|
+ const stale = liveAgent(foreign, 'session-rename-stale', 1)
|
|
|
+ ctx.agents.register({ id: stale.id, session: stale, status: 'idle', ctx } as Agent)
|
|
|
+
|
|
|
+ const response = await api(ctx).sessions.rename(request({ sessionId: stale.id, title: 'name' }))
|
|
|
+ expect(response.result.ok).toBe(false)
|
|
|
+ if (!response.result.ok) expect(response.result.error.code).toBe('internal')
|
|
|
+ })
|
|
|
+
|
|
|
it('answers internal when the composition mounts no session-title service', async () => {
|
|
|
const ctx = await composed(false)
|
|
|
const source = liveAgent(ctx, 'session-no-titles', 1)
|
|
|
@@ -104,7 +123,7 @@ describe('sessions.rename', () => {
|
|
|
expect(response.result.ok).toBe(false)
|
|
|
if (!response.result.ok) {
|
|
|
expect(response.result.error.code).toBe('internal')
|
|
|
- expect(response.result.error.message).toMatch(/session-title service is absent/)
|
|
|
+ expect(response.result.error.message).toMatch(/mounts no session-title service/)
|
|
|
}
|
|
|
})
|
|
|
})
|