mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-09-11 04:00:38 +00:00
Merge remote-tracking branch 'origin/worktree/session-format-04-live-assistant-stream' into worktree/session-format-05-v1-v2-chunk-migration
# Conflicts: # .agents/notes/implemented/architecture/2026-08-31-live-assistant-stream-frames.i18n.yaml # .agents/notes/implemented/architecture/2026-08-31-live-assistant-stream-frames.md # .agents/notes/implemented/architecture/2026-08-31-live-assistant-stream-frames.zh.md # .agents/notes/implemented/simplification/2026-08-06-buffer-free-feedback-telemetry.i18n.yaml # .agents/notes/implemented/simplification/2026-08-06-buffer-free-feedback-telemetry.md # .agents/notes/implemented/simplification/2026-08-06-buffer-free-feedback-telemetry.zh.md # apps/web/tests/scaffold.ts # docs/config-catalog.i18n.yaml # docs/config-catalog.md # docs/config-catalog.zh.md # packages/api/session-controller/README.i18n.yaml # packages/api/session-controller/README.md # packages/api/session-controller/README.zh.md # packages/api/session-controller/src/client/sessions/assistant-stream.ts # packages/core/agent-loop/src/agent.ts # packages/core/agent-loop/src/assistant-stream.ts # packages/core/agent-loop/tests/loop.spec.ts # packages/core/agent/src/runtime-types.ts # packages/session/session-telemetry/tests/telemetry.spec.ts # packages/test-support/llm-replay/README.i18n.yaml # packages/test-support/llm-replay/README.md # packages/test-support/llm-replay/README.zh.md # packages/test-support/llm-replay/src/alpha-refusal-fixtures.ts # packages/test-support/llm-replay/src/index.ts # packages/test-support/llm-replay/tests/llm-replay.spec.ts # packages/test-support/session-snapshot/README.i18n.yaml # packages/test-support/session-snapshot/README.md # packages/test-support/session-snapshot/README.zh.md # packages/test-support/session-snapshot/src/suite.ts # packages/test-support/session-snapshot/tests/suite.spec.ts # snapshots/sdk/sdk.snapshot.ts # snapshots/session/headless.snapshot.ts
This commit is contained in:
@@ -101,6 +101,7 @@ export class ClientAssistantStream {
|
||||
this.durableCursor = Math.max(this.durableCursor, event.seq)
|
||||
this.transientInGap = 0
|
||||
if (this.attemptForSettlement(event) !== undefined) {
|
||||
if (this.pending.has(event.seq)) return { type: 'rebaseline' }
|
||||
this.pending.set(event.seq, entry)
|
||||
return undefined
|
||||
}
|
||||
@@ -115,6 +116,7 @@ export class ClientAssistantStream {
|
||||
acceptFrame(frame: SessionAssistantStreamFrame): ClientAssistantStreamResult {
|
||||
switch (frame.type) {
|
||||
case 'start':
|
||||
if (this.activeAttempt !== undefined || this.pending.size > 0) return { type: 'rebaseline' }
|
||||
this.pending.clear()
|
||||
this.activeAttempt = {
|
||||
attemptId: String(frame.attemptId),
|
||||
@@ -126,9 +128,11 @@ export class ClientAssistantStream {
|
||||
return undefined
|
||||
case 'chunk': {
|
||||
const attempt = this.activeAttempt
|
||||
if (attempt === undefined
|
||||
|| attempt.attemptId !== String(frame.attemptId)
|
||||
|| frame.index !== attempt.nextIndex) return { type: 'rebaseline' }
|
||||
// A controller mounted after the Host saw this attempt has no start
|
||||
// frame to reconstruct. Its durable settlement publishes directly;
|
||||
// ignore the transient suffix until the next known start.
|
||||
if (attempt === undefined || attempt.attemptId !== String(frame.attemptId)) return undefined
|
||||
if (frame.index !== attempt.nextIndex) return { type: 'rebaseline' }
|
||||
attempt.nextIndex += 1
|
||||
this.transientInGap += 1
|
||||
return {
|
||||
@@ -151,10 +155,10 @@ export class ClientAssistantStream {
|
||||
}
|
||||
case 'end': {
|
||||
const attempt = this.activeAttempt
|
||||
this.activeAttempt = undefined
|
||||
if (attempt === undefined || attempt.attemptId !== String(frame.attemptId)) {
|
||||
return { type: 'rebaseline' }
|
||||
return undefined
|
||||
}
|
||||
this.activeAttempt = undefined
|
||||
if (frame.index !== attempt.nextIndex) return { type: 'rebaseline' }
|
||||
if (frame.outcome.kind === 'abandoned') {
|
||||
return this.pending.size === 0 ? undefined : { type: 'rebaseline' }
|
||||
@@ -162,9 +166,7 @@ export class ClientAssistantStream {
|
||||
if (this.publishedSeqs.has(frame.outcome.seq)) return undefined
|
||||
const entry = this.pending.get(frame.outcome.seq)
|
||||
if (entry === undefined
|
||||
|| entry.event.type !== frame.outcome.eventType
|
||||
|| entry.event.data.turn !== attempt.turn
|
||||
|| entry.event.data.step !== attempt.step) {
|
||||
|| entry.event.type !== frame.outcome.eventType) {
|
||||
return { type: 'rebaseline' }
|
||||
}
|
||||
this.pending.delete(frame.outcome.seq)
|
||||
|
||||
@@ -369,7 +369,8 @@ export class SessionController extends TypertRemoteService {
|
||||
* Follow one Session log from its opening or resume cursor.
|
||||
* @param request - durable address and last committed sequence already held by the caller.
|
||||
* @param signal - cancellation owned by the Remote stream carrier.
|
||||
* @returns a complete opening snapshot followed by gap-free event frames.
|
||||
* @returns a complete opening snapshot followed by gap-free durable event
|
||||
* frames and optional cursorless assistant-stream frames.
|
||||
*/
|
||||
@Remote({ mode: 'stream' })
|
||||
follow(request: SessionFollowRequest, signal: AbortSignal): AsyncIterable<SessionFollowFrame> {
|
||||
|
||||
@@ -145,8 +145,6 @@ export class ApiSessionList {
|
||||
|
||||
private summarizeCold(header: SessionHeader): SessionSummary {
|
||||
const projections = this.projectionsFor(header, undefined)
|
||||
const raced = this.ctx.sessions.get(header.id)
|
||||
if (raced !== undefined) return this.summaryFor(raced)
|
||||
const metadata = projections?.values.sessionListMetadata
|
||||
return {
|
||||
sessionId: header.id,
|
||||
|
||||
Reference in New Issue
Block a user