mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
* fix(omp): answer startup Kitty queries before renderer handoff Forward actual renderer capability through local and remote spawn. Preserve source ranges and following keyboard mode pushes, and retain independent ConPTY color authority. Refs #17081. Secondary review: #17082. Co-authored-by: stevelliu <stevelliu@tencent.com> * test(omp): cover fragmented keyboard modes and ConPTY handoff * fix: preserve keyboard startup intent without terminal colors * fix: negotiate keyboard support for host-authoritative agent launches * fix: keep terminal creation within line budget * fix(omp): negotiate keyboard support for paired web launches * test: remove obsolete message type import after main integration * fix: validate paired launch results and retry incomplete SSH test snapshots * fix(omp): negotiate keyboard support for background paired launches --------- Co-authored-by: stevelliu <stevelliu@tencent.com>
217 lines
6.9 KiB
TypeScript
217 lines
6.9 KiB
TypeScript
import {
|
|
hasUnsafeProviderSessionIdChars,
|
|
isResumableTuiAgent,
|
|
type AgentProviderSessionMetadata,
|
|
type ResumableTuiAgent
|
|
} from './agent-session-resume'
|
|
import type { RuntimeTerminalCreate, RuntimeTerminalPresentation } from './runtime-types'
|
|
import { isTerminalLeafId } from './stable-pane-id'
|
|
import { isValidTerminalTabId } from './terminal-tab-id'
|
|
import type { TuiAgent } from './tui-agent'
|
|
|
|
export { AGENT_SESSION_HOST_AUTHORITY_RUNTIME_CAPABILITY as AGENT_SESSION_HOST_AUTHORITY_CAPABILITY } from './protocol-version'
|
|
|
|
export const AGENT_SESSION_RPC_ERROR_CODES = [
|
|
'agent_session_identity_required',
|
|
'agent_session_conflict',
|
|
'agent_session_resume_not_authorized',
|
|
'agent_session_exited_during_start',
|
|
'agent_session_claim_unavailable',
|
|
'agent_session_ownership_unknown',
|
|
'agent_session_checkpoint_stale',
|
|
'agent_session_operation_invalid',
|
|
'agent_session_operation_conflict',
|
|
'agent_session_operation_expired',
|
|
'agent_session_operation_capacity',
|
|
'agent_session_operation_unknown',
|
|
'agent_session_legacy_required',
|
|
'execution_owner_reconciling',
|
|
'execution_owner_unavailable'
|
|
] as const
|
|
|
|
export const AGENT_SESSION_CLAIM_DIGEST_VERSION = 1 as const
|
|
|
|
export const AGENT_SESSION_EXECUTION_OWNER_PROTOCOL_VERSION = 2 as const
|
|
export const AGENT_SESSION_CREATE_OPERATION_PROTOCOL_VERSION = 1 as const
|
|
|
|
export const AGENT_SESSION_OPERATION_FUTURE_SKEW_MS = 5 * 60 * 1000
|
|
export const AGENT_SESSION_MAX_NEW_OPERATION_AGE_MS = 24 * 60 * 60 * 1000
|
|
/** Oldest an operation can be when admitted, plus the host tombstone lifetime after admission. */
|
|
export const AGENT_SESSION_MAX_OPERATION_REPLAY_AGE_MS =
|
|
AGENT_SESSION_MAX_NEW_OPERATION_AGE_MS * 2 + AGENT_SESSION_OPERATION_FUTURE_SKEW_MS
|
|
|
|
const AGENT_SESSION_OPERATION_ID_PATTERN = /^(\d{13})-[0-9a-f]{32}$/
|
|
|
|
export function parseAgentSessionOperationTimestamp(operationId: string): number | null {
|
|
const match = AGENT_SESSION_OPERATION_ID_PATTERN.exec(operationId)
|
|
if (!match) {
|
|
return null
|
|
}
|
|
const timestamp = Number(match[1])
|
|
return Number.isSafeInteger(timestamp) ? timestamp : null
|
|
}
|
|
|
|
const BASE64URL_RE = /^[A-Za-z0-9_-]+$/
|
|
const SHA256_BASE64URL_LENGTH = 43
|
|
|
|
function isBoundedWireString(value: unknown, maxLength: number): value is string {
|
|
return (
|
|
typeof value === 'string' &&
|
|
value.length > 0 &&
|
|
value.length <= maxLength &&
|
|
!hasUnsafeProviderSessionIdChars(value)
|
|
)
|
|
}
|
|
|
|
export type AgentSessionSurfaceBinding = {
|
|
worktreeId: string
|
|
tabId: string
|
|
leafId: string
|
|
terminalHandle: string
|
|
}
|
|
|
|
export type AgentSessionExecutionClaim = {
|
|
digestVersion: typeof AGENT_SESSION_CLAIM_DIGEST_VERSION
|
|
keyId: string
|
|
identityDigest: string
|
|
worktreeScopeDigest: string
|
|
agent: ResumableTuiAgent
|
|
}
|
|
|
|
export type AgentSessionOwnerBinding = {
|
|
claim: AgentSessionExecutionClaim
|
|
generation: string
|
|
phase: 'reserved' | 'live'
|
|
ptyId: string
|
|
surface: AgentSessionSurfaceBinding
|
|
}
|
|
|
|
export type AgentSessionClaimedSpawnResult = {
|
|
disposition: 'created' | 'adopted'
|
|
owner: AgentSessionOwnerBinding
|
|
}
|
|
|
|
export type AgentLaunchPreferences = {
|
|
model?: string
|
|
effort?: string
|
|
mode?: string
|
|
}
|
|
|
|
export type AgentPromptDelivery = 'auto-submit' | 'draft'
|
|
|
|
export type RuntimeEnsureAgentSessionRequest =
|
|
| {
|
|
kind: 'automatic'
|
|
sleepingCheckpointId: string
|
|
presentation?: RuntimeTerminalPresentation
|
|
}
|
|
| {
|
|
kind: 'explicit'
|
|
worktree: string
|
|
agent: ResumableTuiAgent
|
|
providerSession: AgentProviderSessionMetadata
|
|
ompResumeFilePath?: string
|
|
terminalKittyKeyboardProtocol?: boolean
|
|
/** Explicit client override. Omission keeps launch defaults host-owned. */
|
|
agentArgs?: string | null
|
|
launchPreferences?: AgentLaunchPreferences
|
|
presentation?: RuntimeTerminalPresentation
|
|
placement?: { tabId?: string; leafId?: string }
|
|
}
|
|
|
|
export type RuntimeEnsureAgentSessionResult = {
|
|
terminal: RuntimeTerminalCreate
|
|
disposition: 'created' | 'adopted'
|
|
}
|
|
|
|
export type RuntimeCreateAgentSessionRequest = {
|
|
clientOperationId: string
|
|
terminalKittyKeyboardProtocol?: boolean
|
|
worktree: string
|
|
agent: TuiAgent
|
|
prompt?: string
|
|
promptDelivery?: AgentPromptDelivery
|
|
/** Explicit client override. Omission keeps launch defaults host-owned. */
|
|
agentArgs?: string | null
|
|
launchPreferences?: AgentLaunchPreferences
|
|
startupCwd?: string
|
|
presentation?: RuntimeTerminalPresentation
|
|
placement?: { tabId?: string; leafId?: string }
|
|
viewMode?: 'terminal' | 'chat'
|
|
}
|
|
|
|
export type RuntimeCreateAgentSessionResult = {
|
|
terminal: RuntimeTerminalCreate
|
|
disposition: 'created' | 'replayed'
|
|
}
|
|
|
|
export type RuntimeAgentSessionRpcCaller = {
|
|
clientId?: string
|
|
clientKind?: 'mobile' | 'runtime'
|
|
signal?: AbortSignal
|
|
}
|
|
|
|
export function isAgentSessionExecutionClaim(value: unknown): value is AgentSessionExecutionClaim {
|
|
if (typeof value !== 'object' || value === null) {
|
|
return false
|
|
}
|
|
const claim = value as Partial<AgentSessionExecutionClaim>
|
|
return (
|
|
claim.digestVersion === AGENT_SESSION_CLAIM_DIGEST_VERSION &&
|
|
isBoundedWireString(claim.keyId, 128) &&
|
|
BASE64URL_RE.test(claim.keyId) &&
|
|
typeof claim.identityDigest === 'string' &&
|
|
claim.identityDigest.length === SHA256_BASE64URL_LENGTH &&
|
|
BASE64URL_RE.test(claim.identityDigest) &&
|
|
typeof claim.worktreeScopeDigest === 'string' &&
|
|
claim.worktreeScopeDigest.length === SHA256_BASE64URL_LENGTH &&
|
|
BASE64URL_RE.test(claim.worktreeScopeDigest) &&
|
|
isResumableTuiAgent(claim.agent)
|
|
)
|
|
}
|
|
|
|
export function isAgentSessionSurfaceBinding(value: unknown): value is AgentSessionSurfaceBinding {
|
|
if (typeof value !== 'object' || value === null) {
|
|
return false
|
|
}
|
|
const surface = value as Partial<AgentSessionSurfaceBinding>
|
|
return (
|
|
isBoundedWireString(surface.worktreeId, 4096) &&
|
|
isBoundedWireString(surface.tabId, 512) &&
|
|
isValidTerminalTabId(surface.tabId) &&
|
|
typeof surface.leafId === 'string' &&
|
|
isTerminalLeafId(surface.leafId) &&
|
|
isBoundedWireString(surface.terminalHandle, 128) &&
|
|
surface.terminalHandle.startsWith('term_') &&
|
|
BASE64URL_RE.test(surface.terminalHandle)
|
|
)
|
|
}
|
|
|
|
export function isAgentSessionOwnerBinding(value: unknown): value is AgentSessionOwnerBinding {
|
|
if (typeof value !== 'object' || value === null) {
|
|
return false
|
|
}
|
|
const owner = value as Partial<AgentSessionOwnerBinding>
|
|
return (
|
|
isAgentSessionExecutionClaim(owner.claim) &&
|
|
isBoundedWireString(owner.generation, 128) &&
|
|
(owner.phase === 'reserved' || owner.phase === 'live') &&
|
|
isBoundedWireString(owner.ptyId, 4096) &&
|
|
isAgentSessionSurfaceBinding(owner.surface)
|
|
)
|
|
}
|
|
|
|
export function isAgentSessionClaimedSpawnResult(
|
|
value: unknown
|
|
): value is AgentSessionClaimedSpawnResult {
|
|
if (typeof value !== 'object' || value === null) {
|
|
return false
|
|
}
|
|
const result = value as Partial<AgentSessionClaimedSpawnResult>
|
|
return (
|
|
(result.disposition === 'created' || result.disposition === 'adopted') &&
|
|
isAgentSessionOwnerBinding(result.owner) &&
|
|
result.owner.phase === 'live'
|
|
)
|
|
}
|