Expose saved decisions, timelines and source evidence through read-only Story Graph tools across Model, Harness and local/remote OpenCode and Continue. Supervisor enablement and runtime assignments govern discovery and calls; reads do not invoke models or modify stored evidence. Remote use requires matching Desktop and Agent changes. Make Continue discussion show the complete editable message with a separated destination and shared action layout. Sending uses the visible draft without reattaching removed context. Validation: existing focused MCP, runtime, controlled Linux Host, discussion component and Electron layout checks plus typechecks; staged diff check passed. Cross-scope fact reuse, historical reconstruction and full package acceptance remain deferred. Release note: Agents can consult saved supervisor decisions and their sources when continuing work. Continue discussion now lets you review and edit the complete message before sending.
199 lines
6.3 KiB
TypeScript
199 lines
6.3 KiB
TypeScript
import type {
|
|
AcpBindingCursors,
|
|
AcpCompletePromptRequest,
|
|
AcpCompletePromptResult,
|
|
AcpEscalateCancellationRequest,
|
|
AcpReconcilePromptRequest,
|
|
AcpReconcilePromptResult
|
|
} from '../../shared/agent-protocol'
|
|
import type {
|
|
RemoteOwnedPromptStartRequest,
|
|
RemoteOwnedPromptStartResult,
|
|
RemotePromptOperationAcceptance,
|
|
RemotePromptOperationPreparation,
|
|
remoteOwnedPromptAttachRequestSchema,
|
|
remoteSemanticTranscriptAckRequestSchema,
|
|
remoteSemanticTranscriptAckResultSchema,
|
|
remoteSemanticTranscriptPageRequestSchema,
|
|
remoteSemanticTranscriptPageResultSchema,
|
|
} from '../../shared/remote-agent-contracts'
|
|
import type { z } from 'zod'
|
|
import type { ImageToolBinding } from './image-tool-binding'
|
|
import type { RemoteQuestionResponse } from '../../shared/remote-question-contracts'
|
|
import type {
|
|
ModelBridgePolicy
|
|
} from '../../shared/model-bridge-contracts'
|
|
|
|
export type RemoteRuntimeChannelCapabilities = {
|
|
cancellationEscalation: boolean
|
|
promptOperationReconciliation: boolean
|
|
ownedPrompt?: boolean
|
|
modelBridge?: boolean
|
|
}
|
|
|
|
export type RemoteOwnedPromptAttachRequest = z.infer<
|
|
typeof remoteOwnedPromptAttachRequestSchema
|
|
>
|
|
export type RemoteSemanticTranscriptPageRequest = z.infer<
|
|
typeof remoteSemanticTranscriptPageRequestSchema
|
|
>
|
|
export type RemoteSemanticTranscriptPageResult = z.infer<
|
|
typeof remoteSemanticTranscriptPageResultSchema
|
|
>
|
|
export type RemoteSemanticTranscriptAckRequest = z.infer<
|
|
typeof remoteSemanticTranscriptAckRequestSchema
|
|
>
|
|
export type RemoteSemanticTranscriptAckResult = z.infer<
|
|
typeof remoteSemanticTranscriptAckResultSchema
|
|
>
|
|
|
|
export type RuntimeSessionBindingCursors = AcpBindingCursors
|
|
|
|
export type RemoteCancellationEscalation = Omit<
|
|
AcpEscalateCancellationRequest,
|
|
'reason'
|
|
> & {
|
|
reason: unknown
|
|
}
|
|
|
|
export type RemotePromptOperationReconciliation =
|
|
AcpReconcilePromptRequest
|
|
|
|
export type RemotePromptOperationReconciliationResult =
|
|
AcpReconcilePromptResult
|
|
export type RemotePromptOperationCompletion = AcpCompletePromptRequest
|
|
export type RemotePromptOperationCompletionResult =
|
|
AcpCompletePromptResult
|
|
|
|
export type RemoteModelBridgeOpenRequest = {
|
|
bindingId: string
|
|
promptOperationId: string
|
|
requestId: string
|
|
policy: ModelBridgePolicy
|
|
}
|
|
|
|
export type RemoteModelBridgeCloseResult = {
|
|
clean: boolean
|
|
poisoned: boolean
|
|
}
|
|
|
|
export interface RemoteModelBridgeSession {
|
|
readonly version: 'goodbuddy-model-bridge-v1'
|
|
readonly channelId: string
|
|
readonly channelEpoch: string
|
|
readonly policy: ModelBridgePolicy
|
|
readonly closed: Promise<RemoteModelBridgeCloseResult>
|
|
close(reason?: string): Promise<RemoteModelBridgeCloseResult>
|
|
}
|
|
|
|
/**
|
|
* A process-neutral, already authenticated ACP virtual channel.
|
|
*
|
|
* Implementations own framing, journaling and transport generation checks.
|
|
* The runtime intentionally receives no SSH client, socket or command API.
|
|
*/
|
|
export interface RemoteRuntimeChannel {
|
|
respondToQuestion?(request: RemoteQuestionResponse): Promise<void>
|
|
readonly input: ReadableStream<Uint8Array>
|
|
readonly output: WritableStream<Uint8Array>
|
|
readonly generation: number
|
|
readonly channelEpoch: string
|
|
/**
|
|
* Signed Runtime capability identity advertised by the Agent before the
|
|
* untrusted Runtime process starts.
|
|
*/
|
|
readonly advertisedAcpCapabilitiesDigest: string
|
|
readonly capabilities: RemoteRuntimeChannelCapabilities
|
|
readonly closed: Promise<void>
|
|
|
|
isCurrentGeneration(): boolean
|
|
getBindingCursors(
|
|
bindingId: string
|
|
): Promise<RuntimeSessionBindingCursors>
|
|
/** Accepts the prompt and starts its Ask or Execute Runtime process. */
|
|
preparePrompt(
|
|
preparation: RemotePromptOperationPreparation,
|
|
imageToolBinding?: ImageToolBinding,
|
|
waitSignal?: AbortSignal,
|
|
storyGraphBinding?: import('./knowledge-mcp-gateway').StoryGraphRemoteBinding
|
|
): Promise<RemotePromptOperationAcceptance>
|
|
/** Starts an Agent-owned ACP prompt exactly once for its stable operation. */
|
|
startOwnedPrompt?(
|
|
request: RemoteOwnedPromptStartRequest
|
|
): Promise<RemoteOwnedPromptStartResult>
|
|
/** Reattaches to an already accepted Agent-owned prompt without replaying it. */
|
|
attachOwnedPrompt?(
|
|
request: RemoteOwnedPromptAttachRequest
|
|
): Promise<RemoteOwnedPromptStartResult>
|
|
pageOwnedPromptTranscript?(
|
|
request: RemoteSemanticTranscriptPageRequest
|
|
): Promise<RemoteSemanticTranscriptPageResult>
|
|
ackOwnedPromptTranscript?(
|
|
request: RemoteSemanticTranscriptAckRequest
|
|
): Promise<RemoteSemanticTranscriptAckResult>
|
|
/**
|
|
* Bounds same-daemon stream recovery to the signed prompt lifetime and
|
|
* caller cancellation. Implementations that cannot recover may omit it.
|
|
*/
|
|
setRecoveryBoundary?(
|
|
deadlineAt: string,
|
|
signal: AbortSignal
|
|
): void
|
|
clearRecoveryBoundary?(): void
|
|
/**
|
|
* Allocates and registers a fresh Main-owned model channel for one prompt.
|
|
* Legacy channels may omit this when the runtime is configured without a
|
|
* model bridge.
|
|
*/
|
|
openModelBridge?(
|
|
request: RemoteModelBridgeOpenRequest
|
|
): Promise<RemoteModelBridgeSession>
|
|
completePromptOperation(
|
|
operation: RemotePromptOperationCompletion
|
|
): Promise<RemotePromptOperationCompletionResult>
|
|
/**
|
|
* Stops or resumes inbound ACP delivery. Pausing must take effect before
|
|
* the returned promise resolves and must not advance the Main ACK cursor.
|
|
*/
|
|
setInboundPaused(paused: boolean): Promise<void>
|
|
escalateCancellation(
|
|
escalation: RemoteCancellationEscalation
|
|
): Promise<void>
|
|
reconcilePromptOperation(
|
|
operation: RemotePromptOperationReconciliation
|
|
): Promise<RemotePromptOperationReconciliationResult>
|
|
close(): Promise<void>
|
|
}
|
|
|
|
export class StaleRemoteRuntimeGenerationError extends Error {
|
|
constructor() {
|
|
super('远端 Runtime 连接代际已失效')
|
|
this.name = 'StaleRemoteRuntimeGenerationError'
|
|
}
|
|
}
|
|
|
|
export function isDefinitiveRemoteRuntimeRequestRejection(
|
|
error: unknown,
|
|
method: string
|
|
): boolean {
|
|
if (
|
|
error === null ||
|
|
typeof error !== 'object' ||
|
|
!('remoteRequestOutcome' in error) ||
|
|
error.remoteRequestOutcome !== 'rejected' ||
|
|
!('remoteMethod' in error) ||
|
|
error.remoteMethod !== method
|
|
) {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
export function assertCurrentRemoteRuntimeGeneration(
|
|
channel: RemoteRuntimeChannel
|
|
): void {
|
|
if (!channel.isCurrentGeneration()) {
|
|
throw new StaleRemoteRuntimeGenerationError()
|
|
}
|
|
}
|