Merge branch 'stack/agent-profiles-5-web-ui' into stack/agent-profiles-8-authoring

# Conflicts:
#	apps/cli/tests/web-agent-presets.e2e.ts
#	packages/client/connection/README.i18n.yaml
#	packages/client/connection/README.md
#	packages/client/connection/README.zh.md
#	packages/client/ui-conversation/src/client/contract/slots.ts
#	packages/client/ui-primitives/tests/icons.spec.tsx
#	packages/client/ui-settings/src/client/contract/slots.ts
#	packages/host/apiproxy/tests/api-proxy-agent-preset.spec.ts
This commit is contained in:
Yichen Jiang
2026-08-09 23:02:37 +08:00
825 changed files with 2990 additions and 2066 deletions

View File

@@ -3,7 +3,7 @@
// Types and runtime protocol helpers/bounds come from the apiproxy api/ layer
// (zero Node deps, browser-safe); AbstractApiClient is the client boundary.
// NEVER import the package root: it drags bootHost/cordis into the browser bundle.
// The ./api and ./client subpath exports are the browser-safe channels added for this.
// The ./api and ./client subpath exports are the browser-safe channels.
export type {
ApiProxy, SessionsApi, SessionSearchItem, SessionSummary, HostApi, EventsApi, MuxFrame, HostFrame,
@@ -23,9 +23,9 @@ export type {
RpcRequest, RpcResponse, RpcResult, RpcError, RpcErrorCode,
ClientRequest, ServerResponse, ServerRequest, ClientResponse, RpcMessage, RpcReceipt,
} from '@deepseek-ai/dsh-host-apiproxy/api'
// transportError moved down to the apiproxy api layer (it belongs beside
// RpcResult, its subject); re-exported here so connection consumers keep one
// contract entry point.
// transportError lives in the apiproxy api layer (beside RpcResult, its
// subject); re-exported here so connection consumers keep one contract
// entry point.
export {
RpcId,
SESSION_SEARCH_RESULT_LIMIT,

View File

@@ -1,7 +1,7 @@
import type { IApiClient, HostFrame, MuxFrame, RpcRequest } from './api.ts'
/** Reconnect/backoff tunables (deployment-varying — no hardcoded tunables; web-cordis §B.1 lists
* these as the future `ctx.connection` plugin Config). All fields optional; defaults below. */
/** Reconnect/backoff tunables (deployment-varying — no hardcoded tunables; these become the
* future `ctx.connection` plugin's Config). All fields optional; defaults below. */
export interface ConnectionConfig {
/** First-retry backoff cap in ms (jittered: actual delay is cap/2..cap). */
backoffBaseMs?: number
@@ -10,9 +10,9 @@ export interface ConnectionConfig {
/** Upper bound for the backoff cap in ms. */
backoffMaxMs?: number
/** Cap on waiting for both streams' onOpen before onConnected, in ms. The strict handshake
* (audit C2) waits for mux+host stream establishment plus describe; a carrier that never
* waits for mux+host stream establishment plus describe; a carrier that never
* fires onOpen (misbehaving proxy) must not wedge the connection forever — on timeout the
* generation proceeds as connected and the live-gap repair path (audit S3) covers stragglers. */
* generation proceeds as connected and the live-gap repair path covers stragglers. */
streamOpenTimeoutMs?: number
}
@@ -35,7 +35,7 @@ function sleep(ms: number, signal: AbortSignal): Promise<void> {
})
}
/** Coarse connection state for the UI (audit C1): 'connected' after each generation's handshake,
/** Coarse connection state for the UI: 'connected' after each generation's handshake,
* 'reconnecting' the moment the generation fails (covers the whole backoff+retry span). */
export type ConnectionState = 'connected' | 'reconnecting'
@@ -125,7 +125,7 @@ export class ConnectionController {
})
try {
// Strict readiness handshake (audit C2): describe proves unary reachability, onOpen
// Strict readiness handshake: describe proves unary reachability, onOpen
// proves each physical stream is established before any frame —
// only then may onConnected fire, so the resync it triggers cannot outrun the
// subscribed baseline. The timeout guards against a carrier that never fires onOpen

View File

@@ -1284,7 +1284,7 @@ export interface FixtureOptions {
/** Inbox pump shared by both stream generators (FrameQueue pattern: ONE abort listener hung
* outside the loop — a per-iteration {once:true} listener never fires for non-final rounds and
* piles up for the stream's lifetime, audit C5). breakNow force-ends the stream without the
* piles up for the stream's lifetime). breakNow force-ends the stream without the
* client's signal (timing hook: simulated connection loss). */
class FxInbox<F> implements StreamConn<F> {
private readonly inbox: RpcRequest<F>[] = []
@@ -1669,7 +1669,7 @@ function createFixtureWorld(options: FixtureOptions): FixtureWorld {
/** history transit delay (timing hooks below); the page snapshot is taken at request time, like a real host. */
let historyDelayMs = 0
/** One-shot history failure (timing hook: the doomed in-flight request of the S4 reconnect scenario). */
/** One-shot history failure (timing hook: a pre-disconnect history request already doomed when reconnect lands). */
let failNextHistory = false
/** Force-enders for currently open stream generators (timing hook: simulated connection loss). */
const streamBreakers = new Set<() => void>()
@@ -1678,8 +1678,8 @@ function createFixtureWorld(options: FixtureOptions): FixtureWorld {
/** The single opt-in browser stress producer; normal fixture journeys never start it. */
let activeReasoningChunkStorm: ReasoningChunkStormState | null = null
// Timing-acceptance hooks (browser test backdoor): the in-memory fixture is ideally timed, which
// is exactly what masked the open-window and reconnect-gap bugs (audit S1/S3). These let
// Timing-acceptance hooks (browser test backdoor): the in-memory fixture is
// ideally timed. These let
// browser acceptance runs create slow-history, lost-frame, and reconnect
// windows a real host produces naturally.
const timingHooks = {
@@ -2784,8 +2784,8 @@ function createFixtureWorld(options: FixtureOptions): FixtureWorld {
* Fixture platform subclass: there is no HTTP at all, so instead of a doFetch transport it
* overrides the protocol-level virtuals (callUnary/openMux/openHost/respond) to dispatch
* straight into the in-memory ApiProxy — while still minting rpcIds, fabricating the four
* named full forms, and feeding the same tap as a real carrier. Delete when the fixture moves
* to the isomorphic pipeline (InProcessApiClient over toFetchHandler(fixtureImpl)).
* named full forms, and feeding the same tap as a real carrier. TODO: delete when the fixture
* moves to the isomorphic pipeline (InProcessApiClient over toFetchHandler(fixtureImpl)).
*/
export class FixtureApiClient extends AbstractApiClient {
private readonly api: ApiProxy