Merge remote-tracking branch 'origin/master' into worktree/web-multimodal-image-input
# Conflicts: # apps/cli/README.i18n.yaml # docs/core-data-structures/core.i18n.yaml # docs/core-data-structures/llm-streaming.i18n.yaml # examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl # packages/client/connection/src/client/fixture.ts # packages/client/connection/src/client/index.ts # packages/client/runtime/README.i18n.yaml # packages/client/runtime/README.md # packages/client/runtime/README.zh.md # packages/client/ui-conversation/README.i18n.yaml # packages/client/ui-conversation/src/client/input/hub.ts # packages/client/ui-conversation/src/client/service.ts # packages/client/ui-conversation/src/client/skeleton/InputBar.tsx # packages/compact/compact-basic/src/summarizer.ts # packages/compact/compact-basic/tests/compact-basic.spec.ts # packages/host/apiproxy/src/api-proxy.ts # packages/host/apiproxy/src/api/rpc.schema.ts # packages/host/apiproxy/src/api/rpc.ts # packages/host/apiproxy/src/api/sessions.ts # packages/host/apiproxy/tests/rpc-schemas.spec.ts # packages/llm/llm-deepseek/tests/serialize.spec.ts # packages/llm/llm-pi-ai/tests/adapter.spec.ts # packages/llm/llm-pi-ai/tests/convert.spec.ts # packages/llm/llm-pi-ai/tests/provider-apis.e2e.ts # packages/llm/token-meter/tests/token-meter.spec.ts # packages/ui/tui/README.i18n.yaml
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
*/
|
||||
|
||||
import { LlmError } from '@deepseek-ai/dsh-llm'
|
||||
import type { Message } from '@deepseek-ai/dsh-llm'
|
||||
import type { Message, ModelMessageSource } from '@deepseek-ai/dsh-llm'
|
||||
import type { Api, AssistantMessage, Usage as PiUsage } from '@earendil-works/pi-ai'
|
||||
|
||||
type PiAiReplayBlock =
|
||||
@@ -123,6 +123,7 @@ function readReplayState(value: unknown): PiAiReplayState {
|
||||
|
||||
/** Convert provider-neutral blocks without trusting them as same-model replay. */
|
||||
function foreignAssistant(message: Message): AssistantMessage {
|
||||
const source = message.source.kind === 'model' ? message.source : undefined
|
||||
const content: AssistantMessage['content'] = []
|
||||
for (const block of message.content) {
|
||||
switch (block.type) {
|
||||
@@ -145,10 +146,10 @@ function foreignAssistant(message: Message): AssistantMessage {
|
||||
role: 'assistant',
|
||||
content,
|
||||
// Deliberately never equals a catalog API: absent replay state is foreign
|
||||
// even if provenance names the same provider/model as this request.
|
||||
// even if source names the same provider/model as this request.
|
||||
api: 'dsh-foreign',
|
||||
provider: message.provenance?.provider ?? 'dsh-foreign',
|
||||
model: message.provenance?.model ?? 'dsh-foreign',
|
||||
provider: source?.provider ?? 'dsh-foreign',
|
||||
model: source?.model ?? 'dsh-foreign',
|
||||
usage: emptyPiUsage(),
|
||||
stopReason: content.some(piece => piece.type === 'toolCall') ? 'toolUse' : 'stop',
|
||||
timestamp: 0,
|
||||
@@ -156,11 +157,10 @@ function foreignAssistant(message: Message): AssistantMessage {
|
||||
}
|
||||
|
||||
/** Recombine durable Harness content with validated pi-ai replay metadata. */
|
||||
function replayedAssistant(message: Message, rawState: unknown): AssistantMessage {
|
||||
function replayedAssistant(message: Message, source: ModelMessageSource, rawState: unknown): AssistantMessage {
|
||||
const state = readReplayState(rawState)
|
||||
const provenance = message.provenance
|
||||
if (state.provider !== provenance?.provider) return invalidReplay('provider does not match assistant provenance')
|
||||
if (state.model !== provenance.model) return invalidReplay('model does not match assistant provenance')
|
||||
if (state.provider !== source.provider) return invalidReplay('provider does not match assistant source')
|
||||
if (state.model !== source.model) return invalidReplay('model does not match assistant source')
|
||||
if (state.blocks.length !== message.content.length) return invalidReplay('block count does not match assistant content')
|
||||
const content: AssistantMessage['content'] = message.content.map((block, index) => {
|
||||
const replay = state.blocks[index]
|
||||
@@ -204,10 +204,12 @@ function replayedAssistant(message: Message, rawState: unknown): AssistantMessag
|
||||
|
||||
/**
|
||||
* Convert one durable Harness assistant message into pi-ai history.
|
||||
* @param message - assistant content with optional adapter-owned replay metadata.
|
||||
* @param message - assistant content with required source and optional adapter-owned replay metadata.
|
||||
* @returns a native pi-ai assistant message reconstructed from durable content.
|
||||
*/
|
||||
export function toPiAssistant(message: Message): AssistantMessage {
|
||||
const replayState = message.provenance?.replayState
|
||||
return replayState === undefined ? foreignAssistant(message) : replayedAssistant(message, replayState)
|
||||
const source = message.source
|
||||
return source.kind !== 'model' || source.replayState === undefined
|
||||
? foreignAssistant(message)
|
||||
: replayedAssistant(message, source, source.replayState)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user