Merge origin/master into codex/status-bar-token-metrics
Resolve the agent-loop import conflict by retaining both durable request context and runtime policy context. Refresh the combined session fixtures and regenerate documentation catalogs. Mark PDF artifacts as binary so staged whitespace checks do not parse PDF bytes as text.
This commit is contained in:
249 files changed
+72476
-2957
No files matched your search
@@ -34,6 +34,7 @@ import {
|
||||
LlmError,
|
||||
assertNever,
|
||||
createAssistantMessage,
|
||||
createUserMessage,
|
||||
deepFreeze,
|
||||
errorChain,
|
||||
freezeMessage,
|
||||
@@ -45,7 +46,7 @@ import {
|
||||
import type { GenerateOptions, LlmCallConfig, LlmFailure, Message, PreparedLlmCall, ResolvedRetryPolicy } from '@deepseek-ai/dsh-llm'
|
||||
import { canonicalHeader, headerEquals } from '@deepseek-ai/dsh-session'
|
||||
import type { AssistantMessage, EpochHeader, RequestContext, Session, SessionId, TurnEndReason, TurnTrigger, UserMessage } from '@deepseek-ai/dsh-session'
|
||||
import { renderPrompt } from '@deepseek-ai/dsh-system-prompt'
|
||||
import { renderContextSnapshot, renderPrompt } from '@deepseek-ai/dsh-system-prompt'
|
||||
import type {} from '@deepseek-ai/dsh-tools'
|
||||
import { executeToolCalls } from './tool-calls.ts'
|
||||
|
||||
@@ -54,6 +55,47 @@ type StepOutcome =
|
||||
| { kind: 'completed'; continueTurn: boolean; concluded: boolean; maxTokens: boolean }
|
||||
| { kind: 'request-failed'; error: RequestError; failure: LlmFailure; retryPolicy: ResolvedRetryPolicy | undefined }
|
||||
|
||||
const RUNTIME_CONTEXT_SOURCE = '@deepseek-ai/dsh-system-prompt'
|
||||
/** Clearing marker kept distinct from every prefixed {@link renderContextSnapshot} result. */
|
||||
const CLEARED_RUNTIME_CONTEXT = 'Current runtime context: none. Earlier runtime-context snapshots no longer apply.'
|
||||
|
||||
/** Whether one user message is owned by runtime-context materialization. */
|
||||
function isRuntimeContextMessage(message: UserMessage): boolean {
|
||||
return message.source.kind === 'plugin' && message.source.plugin === RUNTIME_CONTEXT_SOURCE
|
||||
}
|
||||
|
||||
/** Latest retained runtime-context snapshot; `found` distinguishes malformed content from absence. */
|
||||
function retainedRuntimeContext(session: Session): { found: boolean; text: string | undefined } {
|
||||
const events = session.events
|
||||
const nodes = session.surface.nodes
|
||||
for (let index = nodes.length - 1; index >= 0; index -= 1) {
|
||||
const event = events[nodes[index] as number]
|
||||
if (event?.type !== 'user/message' || !isRuntimeContextMessage(event.data)) continue
|
||||
const [block] = event.data.content
|
||||
return {
|
||||
found: true,
|
||||
text: event.data.content.length === 1 && block?.type === 'text' ? block.text : undefined,
|
||||
}
|
||||
}
|
||||
return { found: false, text: undefined }
|
||||
}
|
||||
|
||||
/** Append a full current snapshot only when it changed or compaction removed it. */
|
||||
function materializeRuntimeContext(session: Session, current: string): void {
|
||||
const previous = retainedRuntimeContext(session)
|
||||
if (!previous.found && current.length === 0) {
|
||||
const compactedPriorSnapshot = session.surface.replaceGeneration > 0
|
||||
&& session.events.some(event => event.type === 'user/message' && isRuntimeContextMessage(event.data))
|
||||
if (!compactedPriorSnapshot) return
|
||||
}
|
||||
const snapshot = current.length === 0 ? CLEARED_RUNTIME_CONTEXT : current
|
||||
if (previous.text === snapshot) return
|
||||
session.append('user/message', createUserMessage({
|
||||
content: [{ type: 'text', text: snapshot }],
|
||||
source: { kind: 'plugin', plugin: RUNTIME_CONTEXT_SOURCE },
|
||||
}), { surfaceOp: 'append' })
|
||||
}
|
||||
|
||||
/** Remove adapter-derived values before plugins propose the next request config. */
|
||||
function requestProposal(header: EpochHeader): LlmCallConfig {
|
||||
if (header.adapterDefaults === undefined) return header.config
|
||||
@@ -520,10 +562,13 @@ export class ReactLoopAgent implements Agent {
|
||||
// this request together.
|
||||
this.drainOutbox(turn)
|
||||
|
||||
// Assemble the system prompt fresh each step (it may depend on log state).
|
||||
// Assemble request-owned prompt inputs fresh each step. Dynamic context is
|
||||
// committed at the tail before deriving history once, preserving the stable
|
||||
// system/history cache prefix while keeping every model-visible byte logged.
|
||||
const assembly = await this.loopCtx.systemPrompt.assemble(assembleContextFor(this, signal))
|
||||
signal.throwIfAborted()
|
||||
const system = renderPrompt(assembly)
|
||||
materializeRuntimeContext(session, renderContextSnapshot(assembly))
|
||||
|
||||
// Snapshot the exact log prefix: the reconstruction boundary. Appends
|
||||
// after this synchronous snapshot join the next request.
|
||||
|
||||
Reference in New Issue
Block a user