refactor: identify and freeze messages at creation
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { createUserMessage } from '@deepseek-ai/dsh-llm'
|
||||
/**
|
||||
* Keyless real-Loader-path smoke for the combined SQLite session-query service.
|
||||
*
|
||||
@@ -48,7 +49,9 @@ describe('dsh-session-query-sqlite real Loader path', () => {
|
||||
type: 'user/message',
|
||||
seq: 0,
|
||||
time: 10,
|
||||
data: { content: [{ type: 'text', text: 'real Loader needle' }], source: { kind: 'user' } },
|
||||
data: createUserMessage({
|
||||
content: [{ type: 'text', text: 'real Loader needle' }], source: { kind: 'user' },
|
||||
}),
|
||||
surfaceOp: 'append',
|
||||
}])
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { createUserMessage } from '@deepseek-ai/dsh-llm'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { Context, type Fiber } from 'cordis'
|
||||
import { DatabaseSync } from 'node:sqlite'
|
||||
@@ -44,7 +45,9 @@ function messageEvents(text: string, time = 1): SessionEvent[] {
|
||||
type: 'user/message',
|
||||
seq: 0,
|
||||
time,
|
||||
data: { content: [{ type: 'text', text }], source: { kind: 'user' } },
|
||||
data: createUserMessage({
|
||||
content: [{ type: 'text', text }], source: { kind: 'user' },
|
||||
}),
|
||||
surfaceOp: 'append',
|
||||
}]
|
||||
}
|
||||
@@ -207,7 +210,9 @@ describe('SQLite session search', () => {
|
||||
})
|
||||
session.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'An AI helper' }], source: { kind: 'user' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'An AI helper' }], source: { kind: 'user' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
|
||||
@@ -224,9 +229,13 @@ describe('SQLite session search', () => {
|
||||
const ctx = await liveContext({ path: ':memory:', defaultLimit: 10, maxLimit: 20 })
|
||||
const parent = SessionId('parent')
|
||||
const events: SessionEvent[] = [
|
||||
{ type: 'user/message', seq: 0, time: 10, data: { content: [{ type: 'text', text: 'needle original' }], source: { kind: 'user' } }, surfaceOp: 'append' },
|
||||
{ type: 'user/message', seq: 0, time: 10, data: createUserMessage({
|
||||
content: [{ type: 'text', text: 'needle original' }], source: { kind: 'user' },
|
||||
}), surfaceOp: 'append' },
|
||||
{ type: 'assistant/chunk', seq: 1, time: 11, data: { turn: 1, step: 1, chunk: { type: 'text-delta', index: 0, text: 'needle raw' } } },
|
||||
{ type: 'user/message', seq: 2, time: 12, data: { content: [{ type: 'text', text: 'needle summary' }], source: { kind: 'plugin', plugin: 'test' } }, surfaceOp: { op: 'replace', start: 0, end: 0 }, sourceEventSeqs: [0] },
|
||||
{ type: 'user/message', seq: 2, time: 12, data: createUserMessage({
|
||||
content: [{ type: 'text', text: 'needle summary' }], source: { kind: 'plugin', plugin: 'test' },
|
||||
}), surfaceOp: { op: 'replace', start: 0, end: 0 }, sourceEventSeqs: [0] },
|
||||
{ type: 'turn/end', seq: 3, time: 13, data: { turn: 1, reason: { kind: 'error', step: 1, message: 'needle failure' } } },
|
||||
]
|
||||
ctx.sessions.create(SessionId('a'), { seed: events, meta: { cwd: '/a', parentSession: parent, createdAt: 20 } })
|
||||
@@ -445,7 +454,9 @@ describe('SQLite session search', () => {
|
||||
cursor: eventPage.nextCursor,
|
||||
})).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_CURSOR'))
|
||||
|
||||
target.append('user/message', { content: [{ type: 'text', text: 'needle four' }], source: { kind: 'user' } }, { surfaceOp: 'append' })
|
||||
target.append('user/message', createUserMessage({
|
||||
content: [{ type: 'text', text: 'needle four' }], source: { kind: 'user' },
|
||||
}), { surfaceOp: 'append' })
|
||||
await expect(ctx.sessionQuery.searchEvents({
|
||||
sessionId: target.id,
|
||||
query: 'needle',
|
||||
@@ -620,7 +631,9 @@ describe('SQLite reconciliation and source lifecycle', () => {
|
||||
await expect(ctx.sessionQuery.searchSessions({ query: 'durable' }))
|
||||
.resolves.toMatchObject({ items: [{ header: durable, live: false, persisted: true }] })
|
||||
const live = ctx.sessions.prepare(shared.id, { meta: { createdAt: 10, cwd: '/work' } })
|
||||
live.append('user/message', { content: [{ type: 'text', text: 'live needle' }], source: { kind: 'user' } }, { surfaceOp: 'append' })
|
||||
live.append('user/message', createUserMessage({
|
||||
content: [{ type: 'text', text: 'live needle' }], source: { kind: 'user' },
|
||||
}), { surfaceOp: 'append' })
|
||||
const detach = ctx.sessions.enter(live)
|
||||
ctx.sessions.announce(live)
|
||||
|
||||
@@ -1053,7 +1066,9 @@ describe('SQLite reconciliation and source lifecycle', () => {
|
||||
await ctx.sessionQuery.searchEvents({ sessionId: live.id, query: 'base' })
|
||||
const db = (ctx.sessionQuery as unknown as { _db: DatabaseSync })._db
|
||||
db.exec('PRAGMA query_only = ON')
|
||||
live.append('user/message', { content: [{ type: 'text', text: 'retry needle' }], source: { kind: 'user' } }, { surfaceOp: 'append' })
|
||||
live.append('user/message', createUserMessage({
|
||||
content: [{ type: 'text', text: 'retry needle' }], source: { kind: 'user' },
|
||||
}), { surfaceOp: 'append' })
|
||||
await expect(ctx.sessionQuery.searchEvents({ sessionId: live.id, query: 'needle' }))
|
||||
.rejects.toThrow(expectCode('SESSION_QUERY_INDEX_FAILED'))
|
||||
db.exec('PRAGMA query_only = OFF')
|
||||
|
||||
@@ -13,14 +13,15 @@ import type { SessionEvent } from '@deepseek-ai/dsh-session'
|
||||
export function extractSessionEventText(event: SessionEvent): string {
|
||||
switch (event.type) {
|
||||
case 'user/message':
|
||||
return contentText(event.data.content)
|
||||
case 'assistant/message':
|
||||
case 'steering/message':
|
||||
return contentText(event.data.content)
|
||||
return contentText(event.data.message.content)
|
||||
case 'tool/call':
|
||||
return joinText([event.data.name, event.data.arguments])
|
||||
case 'tool/result':
|
||||
return joinText([
|
||||
contentText(event.data.content),
|
||||
contentText(event.data.message.content),
|
||||
event.data.error?.name ?? '',
|
||||
event.data.error?.code ?? '',
|
||||
])
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { Context } from 'cordis'
|
||||
import { CallId } from '@deepseek-ai/dsh-llm'
|
||||
import SessionStore, { SESSION_FORMAT_VERSION, SessionId } from '@deepseek-ai/dsh-session'
|
||||
import { createUserMessage, CallId , createMessage, createToolResultMessage } from '@deepseek-ai/dsh-llm'
|
||||
import SessionStore, {
|
||||
SESSION_FORMAT_VERSION,
|
||||
SessionId,
|
||||
} from '@deepseek-ai/dsh-session'
|
||||
import type { SessionEvent, SessionHeader } from '@deepseek-ai/dsh-session'
|
||||
import {
|
||||
buildSessionEventRecords,
|
||||
@@ -42,13 +45,58 @@ describe('session-query semantic extraction', () => {
|
||||
{ type: 'future-content', payload: 'hidden' } as never,
|
||||
]
|
||||
const events: SessionEvent[] = [
|
||||
{ type: 'user/message', seq: 0, time: 1, data: { content: messageContent, source: { kind: 'user' } }, surfaceOp: 'append' },
|
||||
{ type: 'assistant/message', seq: 1, time: 2, data: { turn: 1, step: 1, content: messageContent, provenance: { provider: 'mock', model: 'mock' } }, surfaceOp: 'append' },
|
||||
{ type: 'user/message', seq: 2, time: 3, data: { content: messageContent, source: { kind: 'plugin', plugin: 'test' } }, surfaceOp: 'append' },
|
||||
{ type: 'steering/message', seq: 3, time: 4, data: { turn: 1, content: messageContent, source: { kind: 'user' } }, surfaceOp: 'append' },
|
||||
{ type: 'user/message', seq: 0, time: 1, data: createUserMessage({
|
||||
content: messageContent, source: { kind: 'user' },
|
||||
}), surfaceOp: 'append' },
|
||||
{ type: 'assistant/message', seq: 1, time: 2, data: {
|
||||
turn: 1, step: 1,
|
||||
message: createMessage({
|
||||
role: 'assistant',
|
||||
content: messageContent,
|
||||
source: {
|
||||
kind: 'model',
|
||||
...{ provider: 'mock', model: 'mock' },
|
||||
},
|
||||
}),
|
||||
}, surfaceOp: 'append' },
|
||||
{ type: 'user/message', seq: 2, time: 3, data: createUserMessage({
|
||||
content: messageContent, source: { kind: 'plugin', plugin: 'test' },
|
||||
}), surfaceOp: 'append' },
|
||||
{ type: 'steering/message', seq: 3, time: 4, data: {
|
||||
turn: 1,
|
||||
message: createUserMessage({
|
||||
content: messageContent,
|
||||
source: { kind: 'user' },
|
||||
}),
|
||||
}, surfaceOp: 'append' },
|
||||
{ type: 'tool/call', seq: 4, time: 5, data: { turn: 1, step: 1, callId, name: 'bash', arguments: '{"cmd":"pwd"}' } },
|
||||
{ type: 'tool/result', seq: 5, time: 6, data: { turn: 1, step: 1, callId, content: [{ type: 'text', text: 'failed' }], isError: true, error: { name: 'Oops', code: 'E_OOPS' } }, surfaceOp: 'append' },
|
||||
{ type: 'tool/result', seq: 6, time: 7, data: { turn: 1, step: 1, callId, content: [], isError: false }, surfaceOp: 'append' },
|
||||
{
|
||||
type: 'tool/result',
|
||||
seq: 5,
|
||||
time: 6,
|
||||
data: {
|
||||
turn: 1,
|
||||
step: 1,
|
||||
message: createToolResultMessage({
|
||||
callId,
|
||||
content: [{ type: 'text', text: 'failed' }],
|
||||
isError: true,
|
||||
}),
|
||||
error: { name: 'Oops', code: 'E_OOPS' },
|
||||
},
|
||||
surfaceOp: 'append',
|
||||
},
|
||||
{
|
||||
type: 'tool/result',
|
||||
seq: 6,
|
||||
time: 7,
|
||||
data: {
|
||||
turn: 1,
|
||||
step: 1,
|
||||
message: createToolResultMessage({ callId, content: [], isError: false }),
|
||||
},
|
||||
surfaceOp: 'append',
|
||||
},
|
||||
{ type: 'todo/write', seq: 7, time: 8, data: { todos: [{ status: 'in_progress', content: 'ship search' }] } },
|
||||
]
|
||||
|
||||
@@ -90,9 +138,21 @@ describe('session-query semantic extraction', () => {
|
||||
|
||||
describe('session-query document and filter helpers', () => {
|
||||
const events: SessionEvent[] = [
|
||||
{ type: 'user/message', seq: 0, time: 10, data: { content: [{ type: 'text', text: 'Hello\n(AI)+' }], source: { kind: 'user' } }, surfaceOp: 'append' },
|
||||
{ type: 'user/message', seq: 0, time: 10, data: createUserMessage({
|
||||
content: [{ type: 'text', text: 'Hello\n(AI)+' }], source: { kind: 'user' },
|
||||
}), surfaceOp: 'append' },
|
||||
{ type: 'assistant/chunk', seq: 1, time: 11, data: { turn: 1, step: 1, chunk: { type: 'text-delta', index: 0, text: 'raw' } } },
|
||||
{ type: 'assistant/message', seq: 2, time: 12, data: { turn: 1, step: 1, content: [{ type: 'text', text: 'replacement' }], provenance: { provider: 'mock', model: 'mock' } }, surfaceOp: { op: 'replace', start: 0, end: 0 }, sourceEventSeqs: [0] },
|
||||
{ type: 'assistant/message', seq: 2, time: 12, data: {
|
||||
turn: 1, step: 1,
|
||||
message: createMessage({
|
||||
role: 'assistant',
|
||||
content: [{ type: 'text', text: 'replacement' }],
|
||||
source: {
|
||||
kind: 'model',
|
||||
...{ provider: 'mock', model: 'mock' },
|
||||
},
|
||||
}),
|
||||
}, surfaceOp: { op: 'replace', start: 0, end: 0 }, sourceEventSeqs: [0] },
|
||||
{ type: 'turn/end', seq: 3, time: 13, data: { turn: 1, reason: { kind: 'interrupted' } } },
|
||||
]
|
||||
|
||||
@@ -163,7 +223,17 @@ describe('session-query document and filter helpers', () => {
|
||||
type: 'assistant/message',
|
||||
seq: 0,
|
||||
time: 1,
|
||||
data: { turn: 1, step: 1, content: [{ type: 'text', text: 'bad' }], provenance: { provider: 'mock', model: 'mock' } },
|
||||
data: {
|
||||
turn: 1, step: 1,
|
||||
message: createMessage({
|
||||
role: 'assistant',
|
||||
content: [{ type: 'text', text: 'bad' }],
|
||||
source: {
|
||||
kind: 'model',
|
||||
...{ provider: 'mock', model: 'mock' },
|
||||
},
|
||||
}),
|
||||
},
|
||||
surfaceOp: { op: 'replace', start: 9, end: 9 },
|
||||
}]
|
||||
expect(() => buildSessionEventRecords(id, malformed)).toThrow(expectCode('SESSION_QUERY_INVALID_SURFACE'))
|
||||
@@ -199,8 +269,12 @@ describe('session-query document and filter helpers', () => {
|
||||
await ctx.plugin(SessionStore)
|
||||
await ctx.plugin(TestSessionQueryService)
|
||||
const session = ctx.sessions.create(id)
|
||||
session.append('user/message', { content: [{ type: 'text', text: 'Alpha\n beta' }], source: { kind: 'user' } }, { surfaceOp: 'append' })
|
||||
session.append('user/message', { content: [{ type: 'text', text: 'other' }], source: { kind: 'user' } }, { surfaceOp: 'append' })
|
||||
session.append('user/message', createUserMessage({
|
||||
content: [{ type: 'text', text: 'Alpha\n beta' }], source: { kind: 'user' },
|
||||
}), { surfaceOp: 'append' })
|
||||
session.append('user/message', createUserMessage({
|
||||
content: [{ type: 'text', text: 'other' }], source: { kind: 'user' },
|
||||
}), { surfaceOp: 'append' })
|
||||
await expect(ctx.sessionQuery.filterEvents(id, [{ kind: 'text', text: 'alpha beta' }]))
|
||||
.resolves.toMatchObject([{ seq: 0, text: 'Alpha\n beta' }])
|
||||
})
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { createUserMessage, createMessage } from '@deepseek-ai/dsh-llm'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { Context, type Fiber } from 'cordis'
|
||||
import SessionStore, { SESSION_FORMAT_VERSION, SessionId } from '@deepseek-ai/dsh-session'
|
||||
@@ -20,7 +21,9 @@ function eventLog(text = 'hello'): SessionEvent[] {
|
||||
type: 'user/message',
|
||||
seq: 0,
|
||||
time: 10,
|
||||
data: { content: [{ type: 'text', text }], source: { kind: 'user' } },
|
||||
data: createUserMessage({
|
||||
content: [{ type: 'text', text }], source: { kind: 'user' },
|
||||
}),
|
||||
surfaceOp: 'append',
|
||||
}]
|
||||
}
|
||||
@@ -855,7 +858,9 @@ describe('session-query exact reads', () => {
|
||||
const live = ctx.sessions.create(SessionId('live-filter'), { meta: { createdAt: 2 } })
|
||||
live.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'live' }], source: { kind: 'user' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'live' }], source: { kind: 'user' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
const persistence = await ctx.plugin(TestPersistence)
|
||||
@@ -887,7 +892,9 @@ describe('session-query exact reads', () => {
|
||||
session.append('step/start', { turn: 1, step: 1 })
|
||||
const first = session.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'first' }], source: { kind: 'user' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'first' }], source: { kind: 'user' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
session.append('assistant/chunk', {
|
||||
@@ -897,7 +904,17 @@ describe('session-query exact reads', () => {
|
||||
})
|
||||
session.append(
|
||||
'assistant/message',
|
||||
{ provenance: { provider: 'mock', model: 'mock' }, turn: 1, step: 1, content: [{ type: 'text', text: 'replacement' }] },
|
||||
{
|
||||
turn: 1, step: 1,
|
||||
message: createMessage({
|
||||
role: 'assistant',
|
||||
content: [{ type: 'text', text: 'replacement' }],
|
||||
source: {
|
||||
kind: 'model',
|
||||
...{ provider: 'mock', model: 'mock' },
|
||||
},
|
||||
}),
|
||||
},
|
||||
{ surfaceOp: { op: 'replace', start: first.seq, end: first.seq }, sourceEventSeqs: [first.seq] },
|
||||
)
|
||||
|
||||
@@ -910,7 +927,9 @@ describe('session-query exact reads', () => {
|
||||
const session = ctx.sessions.create(SessionId('surface-snapshot'), { meta: { cwd: '/work' } })
|
||||
const first = session.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'old' }], source: { kind: 'user' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'old' }], source: { kind: 'user' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
session.append('assistant/chunk', {
|
||||
@@ -920,22 +939,38 @@ describe('session-query exact reads', () => {
|
||||
})
|
||||
session.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'checkpoint' }], source: { kind: 'plugin', plugin: 'compact' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'checkpoint' }], source: { kind: 'plugin', plugin: 'compact' },
|
||||
}),
|
||||
{ surfaceOp: { op: 'replace', start: first.seq, end: first.seq }, sourceEventSeqs: [first.seq] },
|
||||
)
|
||||
const retained = session.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'retained tail' }], source: { kind: 'user' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'retained tail' }], source: { kind: 'user' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
session.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'latest checkpoint' }], source: { kind: 'plugin', plugin: 'compact' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'latest checkpoint' }], source: { kind: 'plugin', plugin: 'compact' },
|
||||
}),
|
||||
{ surfaceOp: { op: 'replace', start: 2, end: retained.seq }, sourceEventSeqs: [2, retained.seq] },
|
||||
)
|
||||
session.append(
|
||||
'assistant/message',
|
||||
{ provenance: { provider: 'mock', model: 'mock' }, turn: 2, step: 1, content: [{ type: 'text', text: 'latest answer' }] },
|
||||
{
|
||||
turn: 2, step: 1,
|
||||
message: createMessage({
|
||||
role: 'assistant',
|
||||
content: [{ type: 'text', text: 'latest answer' }],
|
||||
source: {
|
||||
kind: 'model',
|
||||
...{ provider: 'mock', model: 'mock' },
|
||||
},
|
||||
}),
|
||||
},
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
|
||||
@@ -947,7 +982,9 @@ describe('session-query exact reads', () => {
|
||||
[5, 'assistant/message'],
|
||||
])
|
||||
if (snapshot.events[0]?.type !== 'user/message') throw new Error('expected current user message')
|
||||
snapshot.events[0].data.content = []
|
||||
expect(() => {
|
||||
(snapshot.events[0]!.data as { content: unknown[] }).content = []
|
||||
}).toThrow()
|
||||
Object.assign(snapshot.session, { cwd: '/mutated' })
|
||||
|
||||
expect(session.events[4]?.type === 'user/message' && session.events[4].data.content).toHaveLength(1)
|
||||
@@ -970,7 +1007,9 @@ describe('session-query exact reads', () => {
|
||||
for (const text of ['one', 'two', 'three']) {
|
||||
session.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text }], source: { kind: 'user' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text }], source: { kind: 'user' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
}
|
||||
@@ -980,7 +1019,9 @@ describe('session-query exact reads', () => {
|
||||
expect(result.session).toEqual(session.header)
|
||||
Object.assign(result.session, { createdAt: -1 })
|
||||
if (result.events[0]?.type !== 'user/message') throw new Error('expected user message')
|
||||
result.events[0].data.content = []
|
||||
expect(() => {
|
||||
(result.events[0]!.data as { content: unknown[] }).content = []
|
||||
}).toThrow()
|
||||
expect(session.header.createdAt).not.toBe(-1)
|
||||
expect(session.events[1]?.type === 'user/message' && session.events[1].data.content).toHaveLength(1)
|
||||
|
||||
@@ -1007,7 +1048,9 @@ describe('session-query exact reads', () => {
|
||||
live.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
live.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'live' }], source: { kind: 'user' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'live' }], source: { kind: 'user' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
const persistence = await ctx.plugin(TestPersistence)
|
||||
@@ -1045,7 +1088,9 @@ describe('session-query exact reads', () => {
|
||||
live.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
live.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'available' }], source: { kind: 'user' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'available' }], source: { kind: 'user' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
await ctx.plugin(TestPersistence)
|
||||
@@ -1097,7 +1142,9 @@ describe('session-query exact reads', () => {
|
||||
type: 'user/message',
|
||||
seq: 0,
|
||||
time: 1,
|
||||
data: { content: [{ type: 'text', text: 'hidden' }], source: { kind: 'user' } },
|
||||
data: createUserMessage({
|
||||
content: [{ type: 'text', text: 'hidden' }], source: { kind: 'user' },
|
||||
}),
|
||||
}],
|
||||
}])
|
||||
const persistence = await ctx.plugin(TestPersistence)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { createUserMessage, createMessage } from '@deepseek-ai/dsh-llm'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { Context } from 'cordis'
|
||||
import SessionStore, { SESSION_FORMAT_VERSION, SessionId } from '@deepseek-ai/dsh-session'
|
||||
@@ -22,7 +23,9 @@ function appendEvent(seq: number, sources?: number[]): SessionEvent {
|
||||
type: 'user/message',
|
||||
seq,
|
||||
time: seq + 1,
|
||||
data: { content: [{ type: 'text', text: `event ${seq}` }], source: { kind: 'user' } },
|
||||
data: createUserMessage({
|
||||
content: [{ type: 'text', text: `event ${seq}` }], source: { kind: 'user' },
|
||||
}),
|
||||
surfaceOp: 'append',
|
||||
...sources === undefined ? {} : { sourceEventSeqs: sources },
|
||||
}
|
||||
@@ -107,24 +110,48 @@ function appendTraceEvents(session: Session): void {
|
||||
})
|
||||
session.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'original' }], source: { kind: 'user' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'original' }], source: { kind: 'user' },
|
||||
}),
|
||||
{ surfaceOp: 'append', sourceEventSeqs: [2] },
|
||||
)
|
||||
session.append(
|
||||
'assistant/message',
|
||||
{ provenance: { provider: 'mock', model: 'mock' }, turn: 1, step: 1, content: [{ type: 'text', text: 'summary one' }] },
|
||||
{
|
||||
turn: 1, step: 1,
|
||||
message: createMessage({
|
||||
role: 'assistant',
|
||||
content: [{ type: 'text', text: 'summary one' }],
|
||||
source: {
|
||||
kind: 'model',
|
||||
...{ provider: 'mock', model: 'mock' },
|
||||
},
|
||||
}),
|
||||
},
|
||||
{ surfaceOp: { op: 'replace', start: 3, end: 3 }, sourceEventSeqs: [3, 2] },
|
||||
)
|
||||
session.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'context' }], source: { kind: 'plugin', plugin: 'test' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'context' }], source: { kind: 'plugin', plugin: 'test' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
session.append('step/end', { turn: 1, step: 1 })
|
||||
session.append('step/start', { turn: 1, step: 2 })
|
||||
session.append(
|
||||
'assistant/message',
|
||||
{ provenance: { provider: 'mock', model: 'mock' }, turn: 1, step: 2, content: [{ type: 'text', text: 'summary two' }] },
|
||||
{
|
||||
turn: 1, step: 2,
|
||||
message: createMessage({
|
||||
role: 'assistant',
|
||||
content: [{ type: 'text', text: 'summary two' }],
|
||||
source: {
|
||||
kind: 'model',
|
||||
...{ provider: 'mock', model: 'mock' },
|
||||
},
|
||||
}),
|
||||
},
|
||||
{ surfaceOp: { op: 'replace', start: 4, end: 4 }, sourceEventSeqs: [2, 4] },
|
||||
)
|
||||
}
|
||||
@@ -319,7 +346,9 @@ describe('session event tracing', () => {
|
||||
live.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
live.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'live' }], source: { kind: 'plugin', plugin: 'test' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'live' }], source: { kind: 'plugin', plugin: 'test' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
TracePersistence.listFailure = new Error('list unavailable')
|
||||
@@ -352,7 +381,17 @@ describe('session event tracing', () => {
|
||||
type: 'assistant/message',
|
||||
seq: 1,
|
||||
time: 2,
|
||||
data: { turn: 1, step: 1, content: [], provenance: { provider: 'mock', model: 'mock' } },
|
||||
data: {
|
||||
turn: 1, step: 1,
|
||||
message: createMessage({
|
||||
role: 'assistant',
|
||||
content: [],
|
||||
source: {
|
||||
kind: 'model',
|
||||
...{ provider: 'mock', model: 'mock' },
|
||||
},
|
||||
}),
|
||||
},
|
||||
surfaceOp: { op: 'replace', start: 9, end: 9 },
|
||||
sourceEventSeqs: [],
|
||||
}]
|
||||
|
||||
@@ -4,7 +4,7 @@ import { mkdtemp, rm } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||
import { CallId } from '@deepseek-ai/dsh-llm'
|
||||
import { createUserMessage, CallId } from '@deepseek-ai/dsh-llm'
|
||||
import SessionStore, {
|
||||
SESSION_FORMAT_VERSION,
|
||||
SessionId,
|
||||
@@ -54,10 +54,10 @@ describe('tool-session-query with the real SQLite provider', () => {
|
||||
type: 'user/message',
|
||||
seq: 0,
|
||||
time: 2,
|
||||
data: {
|
||||
data: createUserMessage({
|
||||
content: [{ type: 'text', text: 'persisted integration needle' }],
|
||||
source: { kind: 'user' },
|
||||
},
|
||||
}),
|
||||
surfaceOp: 'append',
|
||||
}])
|
||||
|
||||
@@ -67,7 +67,9 @@ describe('tool-session-query with the real SQLite provider', () => {
|
||||
caller.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
caller.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'live integration needle' }], source: { kind: 'user' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'live integration needle' }], source: { kind: 'user' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
caller.append('step/start', { turn: 1, step: 1 })
|
||||
@@ -123,40 +125,40 @@ describe('tool-session-query with the real SQLite provider', () => {
|
||||
type: 'user/message',
|
||||
seq: 0,
|
||||
time: base + 123,
|
||||
data: {
|
||||
data: createUserMessage({
|
||||
content: [{ type: 'text', text: 'fractional integration needle' }],
|
||||
source: { kind: 'user' },
|
||||
},
|
||||
}),
|
||||
surfaceOp: 'append',
|
||||
},
|
||||
{
|
||||
type: 'user/message',
|
||||
seq: 1,
|
||||
time: base + 124,
|
||||
data: {
|
||||
data: createUserMessage({
|
||||
content: [{ type: 'text', text: 'fractional integration needle' }],
|
||||
source: { kind: 'user' },
|
||||
},
|
||||
}),
|
||||
surfaceOp: 'append',
|
||||
},
|
||||
{
|
||||
type: 'user/message',
|
||||
seq: 2,
|
||||
time: -124,
|
||||
data: {
|
||||
data: createUserMessage({
|
||||
content: [{ type: 'text', text: 'pre-epoch fractional needle' }],
|
||||
source: { kind: 'user' },
|
||||
},
|
||||
}),
|
||||
surfaceOp: 'append',
|
||||
},
|
||||
{
|
||||
type: 'user/message',
|
||||
seq: 3,
|
||||
time: -123,
|
||||
data: {
|
||||
data: createUserMessage({
|
||||
content: [{ type: 'text', text: 'pre-epoch fractional needle' }],
|
||||
source: { kind: 'user' },
|
||||
},
|
||||
}),
|
||||
surfaceOp: 'append',
|
||||
},
|
||||
])
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { Context, type Fiber } from 'cordis'
|
||||
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||
import { CallId, HarnessError } from '@deepseek-ai/dsh-llm'
|
||||
import { createUserMessage, CallId, HarnessError , createMessage } from '@deepseek-ai/dsh-llm'
|
||||
import { MAX_TIMER_DELAY_MS, TimeoutReason } from '@deepseek-ai/dsh-timeout'
|
||||
import * as TimeoutPolicy from '@deepseek-ai/dsh-timeout-policy'
|
||||
import SessionStore, {
|
||||
@@ -67,7 +67,9 @@ function openStep(session: Session, text = 'prior needle'): void {
|
||||
session.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
session.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text }], source: { kind: 'user' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text }], source: { kind: 'user' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
session.append('step/start', { turn: 1, step: 1 })
|
||||
@@ -871,7 +873,9 @@ describe('workspace authority and lineage redaction', () => {
|
||||
const target = createSession(mounted.ctx, `${toolName}-failure-target`, '/work')
|
||||
target.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'event' }], source: { kind: 'user' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'event' }], source: { kind: 'user' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
const secret = `event missing beside hidden-${toolName}-secret`
|
||||
@@ -900,7 +904,9 @@ describe('workspace authority and lineage redaction', () => {
|
||||
const target = createSession(mounted.ctx, `cancelled-${toolName}`, '/work')
|
||||
target.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'pending exact read' }], source: { kind: 'user' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'pending exact read' }], source: { kind: 'user' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
const controller = new AbortController()
|
||||
@@ -1130,7 +1136,9 @@ describe('workspace authority and lineage redaction', () => {
|
||||
const target = createSession(mounted.ctx, 'moving-target', '/work')
|
||||
target.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'authorized payload' }], source: { kind: 'user' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'authorized payload' }], source: { kind: 'user' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
const movedHeader = header(target.id, '/outside')
|
||||
@@ -1947,7 +1955,9 @@ describe('trace and exact read rendering', () => {
|
||||
const session = createSession(mounted.ctx, 'relationships', '/work')
|
||||
session.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'source' }], source: { kind: 'user' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'source' }], source: { kind: 'user' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
session.append(
|
||||
@@ -1955,8 +1965,14 @@ describe('trace and exact read rendering', () => {
|
||||
{
|
||||
turn: 1,
|
||||
step: 1,
|
||||
content: [{ type: 'text', text: 'replacement' }],
|
||||
provenance: { provider: 'test', model: 'test' },
|
||||
message: createMessage({
|
||||
role: 'assistant',
|
||||
content: [{ type: 'text', text: 'replacement' }],
|
||||
source: {
|
||||
kind: 'model',
|
||||
...{ provider: 'test', model: 'test' },
|
||||
},
|
||||
}),
|
||||
},
|
||||
{ surfaceOp: { op: 'replace', start: 0, end: 0 }, sourceEventSeqs: [0] },
|
||||
)
|
||||
@@ -1971,7 +1987,9 @@ describe('trace and exact read rendering', () => {
|
||||
const session = createSession(mounted.ctx, 'read', '/work')
|
||||
session.append(
|
||||
'user/message',
|
||||
{ content: [{ type: 'text', text: 'before semantic text' }], source: { kind: 'user' } },
|
||||
createUserMessage({
|
||||
content: [{ type: 'text', text: 'before semantic text' }], source: { kind: 'user' },
|
||||
}),
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
session.append(
|
||||
@@ -1979,8 +1997,14 @@ describe('trace and exact read rendering', () => {
|
||||
{
|
||||
turn: 1,
|
||||
step: 1,
|
||||
content: [{ type: 'text', text: 'target full text' }],
|
||||
provenance: { provider: 'test', model: 'test' },
|
||||
message: createMessage({
|
||||
role: 'assistant',
|
||||
content: [{ type: 'text', text: 'target full text' }],
|
||||
source: {
|
||||
kind: 'model',
|
||||
...{ provider: 'test', model: 'test' },
|
||||
},
|
||||
}),
|
||||
},
|
||||
{ surfaceOp: 'append' },
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user