refactor(agent): align delivery method names
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
## Public API
|
||||
|
||||
- `listCandidates(agent, query?, limit?)` lists sessions other than `agent.id`, filters case-insensitively by id or cwd, and ranks same-cwd, cwd-less, then other-cwd records while preserving `listSessions()` creation order within each group. Each selected candidate uses its latest log-backed title as the mention label and falls back to the session id; titles and message bodies are not searched.
|
||||
- `prepare(agent, content, references, signal?)` preserves first-mention order, deduplicates ids, rejects self-reference and more than the configured distinct-source limit, reads every source in parallel, and returns detached content plus zero or one aggregated `HookContext`. Any invalid reference, failed read, cancellation, or budget failure rejects before the host calls `send()` or `steer()`.
|
||||
- `prepare(agent, content, references, signal?)` preserves first-mention order, deduplicates ids, rejects self-reference and more than the configured distinct-source limit, reads every source in parallel, and returns detached content plus zero or one aggregated `HookContext`. Any invalid reference, failed read, cancellation, or budget failure rejects before the host calls `followup()` or `steer()`.
|
||||
- `encodeSessionReferenceUri()` and `decodeSessionReferenceUri()` implement `dsh-session:<base64url(JSON.stringify(sessionId))>` so every JavaScript string id round-trips exactly. `formatSessionReferenceMention()` emits `@[label](uri)`, and `parseSessionReferenceText()` replaces Markdown mentions or bare canonical URIs with readable `@label` text while returning structured references. Explicit Markdown mentions reject every malformed URI; bare text is considered a reference only when a non-empty base64url-shaped payload follows the scheme, and a matching noncanonical candidate still fails. Empty or punctuation-only scheme mentions remain ordinary discussion text.
|
||||
|
||||
## Snapshot semantics
|
||||
|
||||
@@ -42,7 +42,7 @@ function sessionAgent(session: Session, id = 'agent'): Agent {
|
||||
session,
|
||||
status: 'running',
|
||||
ctx: new Context(),
|
||||
send: () => AgentMessageId('stub'),
|
||||
followup: () => AgentMessageId('stub'),
|
||||
queue: () => AgentMessageId('stub'),
|
||||
steer: () => AgentMessageId('stub'),
|
||||
inject(content, options) {
|
||||
@@ -52,7 +52,7 @@ function sessionAgent(session: Session, id = 'agent'): Agent {
|
||||
}, { surfaceOp: 'append' })
|
||||
return AgentMessageId('stub')
|
||||
},
|
||||
acceptInput: () => AgentMessageId('stub'),
|
||||
send: () => AgentMessageId('stub'),
|
||||
cancel() {},
|
||||
whenIdle: () => Promise.resolve(),
|
||||
}
|
||||
@@ -374,7 +374,7 @@ describe('real agent-loop request history', () => {
|
||||
})
|
||||
const agent = ctx.agentLoop.create(SessionId(`late-${mode}`), { provider: 'mock', model: 'mock' })
|
||||
|
||||
agent.send([{ type: 'text', text: 'start' }])
|
||||
agent.followup([{ type: 'text', text: 'start' }])
|
||||
await agent.whenIdle()
|
||||
|
||||
expect(laterSawReading).toBe(true)
|
||||
@@ -400,7 +400,7 @@ describe('real agent-loop request history', () => {
|
||||
}))
|
||||
const agent = ctx.agentLoop.create(SessionId('loop'), { provider: 'mock', model: 'mock' })
|
||||
|
||||
agent.send([{ type: 'text', text: 'start' }])
|
||||
agent.followup([{ type: 'text', text: 'start' }])
|
||||
await agent.whenIdle()
|
||||
|
||||
expect(adapter.requests).toHaveLength(2)
|
||||
|
||||
@@ -78,7 +78,7 @@ describe.skipIf(!process.env.DEEPSEEK_API_KEY)('workspace context e2e: real mode
|
||||
it('obeys a probe instruction loaded from the workspace', async () => {
|
||||
const live = await harness()
|
||||
|
||||
live.agent.send([{ type: 'text', text: 'Workspace context handshake?' }])
|
||||
live.agent.followup([{ type: 'text', text: 'Workspace context handshake?' }])
|
||||
await waitForIdle(live.ctx, live.agent)
|
||||
|
||||
expect(finalText([...live.agent.session.events])).toContain(PROBE)
|
||||
@@ -90,7 +90,7 @@ describe.skipIf(!process.env.DEEPSEEK_API_KEY)('workspace context e2e: real mode
|
||||
await writeFile(join(workdir!, 'pkg/AGENTS.md'), `If the user asks for the nested instruction handshake, reply with exactly this string and nothing else: ${NESTED_PROBE}.\n`)
|
||||
await writeFile(join(workdir!, 'pkg/deep/file.txt'), 'This file exists only to trigger nested workspace instructions.\n')
|
||||
|
||||
live.agent.send([{ type: 'text', text: 'Use the read tool to inspect pkg/deep/file.txt. After reading it, answer: nested instruction handshake?' }])
|
||||
live.agent.followup([{ type: 'text', text: 'Use the read tool to inspect pkg/deep/file.txt. After reading it, answer: nested instruction handshake?' }])
|
||||
await waitForIdle(live.ctx, live.agent)
|
||||
|
||||
expect(finalText([...live.agent.session.events])).toContain(NESTED_PROBE)
|
||||
@@ -99,11 +99,11 @@ describe.skipIf(!process.env.DEEPSEEK_API_KEY)('workspace context e2e: real mode
|
||||
it('appends changed baseline instructions after a real file-tool touch without rewriting the frozen prefix', async () => {
|
||||
const live = await harness()
|
||||
await writeFile(join(workdir!, 'trigger.txt'), 'This file triggers workspace instruction reconciliation.\n')
|
||||
live.agent.send([{ type: 'text', text: 'Workspace context handshake?' }])
|
||||
live.agent.followup([{ type: 'text', text: 'Workspace context handshake?' }])
|
||||
await waitForIdle(live.ctx, live.agent)
|
||||
await writeFile(join(workdir!, 'AGENTS.md'), `The old workspace handshake no longer applies. If the user asks for the updated workspace context handshake, reply with exactly this string and nothing else: ${UPDATED_PROBE}.\n`)
|
||||
|
||||
live.agent.send([{ type: 'text', text: 'You must use the read tool to inspect trigger.txt. After reading it, answer: updated workspace context handshake?' }])
|
||||
live.agent.followup([{ type: 'text', text: 'You must use the read tool to inspect trigger.txt. After reading it, answer: updated workspace context handshake?' }])
|
||||
await waitForIdle(live.ctx, live.agent)
|
||||
|
||||
const events = [...live.agent.session.events]
|
||||
|
||||
@@ -177,7 +177,7 @@ function stubAgent(cwd?: string, seed: SessionEvent[] = []): Agent {
|
||||
options: {},
|
||||
session,
|
||||
status: 'idle',
|
||||
send: () => AgentMessageId('stub'),
|
||||
followup: () => AgentMessageId('stub'),
|
||||
queue: () => AgentMessageId('stub'),
|
||||
steer: () => AgentMessageId('stub'),
|
||||
inject(content, options) {
|
||||
@@ -188,7 +188,7 @@ function stubAgent(cwd?: string, seed: SessionEvent[] = []): Agent {
|
||||
}, { surfaceOp: 'append' })
|
||||
return AgentMessageId('stub')
|
||||
},
|
||||
acceptInput: () => AgentMessageId('stub'),
|
||||
send: () => AgentMessageId('stub'),
|
||||
cancel() {},
|
||||
whenIdle: () => Promise.resolve(),
|
||||
}
|
||||
@@ -1717,11 +1717,11 @@ describe('dynamic nested workspace context injection', () => {
|
||||
},
|
||||
}))
|
||||
|
||||
agent.send([{ type: 'text', text: 'read and abort' }])
|
||||
agent.followup([{ type: 'text', text: 'read and abort' }])
|
||||
await agent.whenIdle()
|
||||
expect(agent.session.events.filter(event => event.type === 'user/message' && event.data.source.kind !== 'user')).toHaveLength(1)
|
||||
|
||||
agent.send([{ type: 'text', text: 'retry the read' }])
|
||||
agent.followup([{ type: 'text', text: 'retry the read' }])
|
||||
await agent.whenIdle()
|
||||
|
||||
const contexts = agent.session.events.filter(event => event.type === 'user/message' && event.data.source.kind !== 'user')
|
||||
|
||||
Reference in New Issue
Block a user