mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-10-26 16:55:08 +00:00
Merge pull request #7003 from deepseek-harness/session-baseline-split-6998
feat(typert): extract Session baseline cleanup and default resource resolvers
This commit is contained in:
commit
83a0433bc7
42 files changed
+440
-349
No files matched your search
@@ -6,8 +6,8 @@
|
||||
en: 735eb4f22d5f6f71
|
||||
zh: 697eef269b133039
|
||||
/api-gateway/programming-model:
|
||||
en: 78eb70d6c2ce6608
|
||||
zh: 826f0ccc206b7299
|
||||
en: 008d81750e966b5d
|
||||
zh: c31ca07da77ffdcc
|
||||
/api-gateway/component-responsibilities:
|
||||
en: fe382a9bcc768cc2
|
||||
zh: 78e3d50d59780c3d
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ Business services use `@Remote` or `@RemoteScope` to select the methods exposed
|
||||
|
||||
`@RemoteScope(key)` first resolves an identity to a scoped Context through `ctx.typert.contexts`, then obtains the service from that Context and invokes the method. It applies when the method itself depends on scoped composition and does not need to receive objects such as `Agent` explicitly.
|
||||
|
||||
`@Remote` accepts an export name or `{ name?, mode?, resources? }`, and `@RemoteScope(key, option?)` accepts an export name, as in `@RemoteScope('agent', 'current')` below, or `{ name?, resources? }` as its second argument. `resources` holds per-kind readers that return the identities of the resources one call touches for access control; each reader receives the method's wire arguments as its own parameters, with types inferred from the decorated method. Most methods declare no readers, because the Gateway also reads identities from lookup parameters and scoped Contexts that declare a `resource`, and from the default fields in `typert.resources`; the [Typert subsystem](subsystems/typert.md) owns that order.
|
||||
`@Remote` accepts an export name or `{ name?, mode?, resources? }`, and `@RemoteScope(key, option?)` accepts an export name, as in `@RemoteScope('agent', 'current')` below, or `{ name?, resources? }` as its second argument. `resources` holds per-kind readers that return the identities of the resources one call touches for access control; each reader receives the method's wire arguments as its own parameters, with types inferred from the decorated method. Most methods declare no readers, because the Gateway also reads identities from lookup parameters and scoped Contexts that declare a `resource`, and from the default fields or resolvers in `typert.resources`; the [Typert subsystem](subsystems/typert.md) owns that order.
|
||||
|
||||
Services normally extend `TypertRemoteService` so the constructor explicitly binds the Cordis service key and default Remote namespace. A service that already has another base class can instead declare `readonly typertRemote = bindTypertRemote(this, serviceKey)`; both forms leave an inspectable public binding and do not depend on the compiler injecting a symbol into the constructor.
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
`@RemoteScope(key)` 表示先通过 `ctx.typert.contexts` 把 identity 解析为一个作用域 Context,再从该 Context 取得服务并调用方法。它适用于方法本身依赖作用域组合、而不需要显式接收 `Agent` 等对象的情形。
|
||||
|
||||
`@Remote` 接受导出名或 `{ name?, mode?, resources? }`;`@RemoteScope(key, option?)` 的第二个参数接受导出名(如下文的 `@RemoteScope('agent', 'current')`)或 `{ name?, resources? }`。`resources` 按资源种类给出读取函数,返回一次调用所访问资源的身份,供访问控制使用;每个读取函数以方法的 wire 参数作为自身参数,类型从被装饰方法推断。多数方法不声明读取函数,因为 Gateway 还会从声明了 `resource` 的 lookup 参数与作用域 Context 以及 `typert.resources` 中的默认字段读取身份;[Typert 子系统](subsystems/typert.zh.md)负责该顺序。
|
||||
`@Remote` 接受导出名或 `{ name?, mode?, resources? }`;`@RemoteScope(key, option?)` 的第二个参数接受导出名(如下文的 `@RemoteScope('agent', 'current')`)或 `{ name?, resources? }`。`resources` 按资源种类给出读取函数,返回一次调用所访问资源的身份,供访问控制使用;每个读取函数以方法的 wire 参数作为自身参数,类型从被装饰方法推断。多数方法不声明读取函数,因为 Gateway 还会从声明了 `resource` 的 lookup 参数与作用域 Context 以及 `typert.resources` 中的默认字段或 resolver 读取身份;[Typert 子系统](subsystems/typert.zh.md)负责该顺序。
|
||||
|
||||
服务通常继承 `TypertRemoteService`,让 Cordis 服务 key 与默认 Remote namespace 在构造器中显式绑定。已有其他基类的服务可以改为声明 `readonly typertRemote = bindTypertRemote(this, serviceKey)`;两种方式都会留下可检查的公开 binding,不依赖编译器向构造函数注入 symbol。
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ export interface Config {
|
||||
## `@deepseek-ai/dsh-api-session-controller`
|
||||
|
||||
- `inject`: `agentDefaultModel` · `agents` · `attachments` · `fileUploads` · `fs` · `llm` · `remoteAccess` · `sessions` · `sessionProjections` · `sessionQuery` · `typert` · `workspaceRegistry`
|
||||
- `source`: [`packages/api/session-controller/src/index.ts:93`](../packages/api/session-controller/src/index.ts)
|
||||
- `source`: [`packages/api/session-controller/src/index.ts:109`](../packages/api/session-controller/src/index.ts)
|
||||
|
||||
```ts config-catalog
|
||||
/** Session Controller deployment policy. */
|
||||
|
||||
@@ -245,7 +245,7 @@ export interface Config {
|
||||
## `@deepseek-ai/dsh-api-session-controller`
|
||||
|
||||
- `inject`: `agentDefaultModel` · `agents` · `attachments` · `fileUploads` · `fs` · `llm` · `remoteAccess` · `sessions` · `sessionProjections` · `sessionQuery` · `typert` · `workspaceRegistry`
|
||||
- `source`: [`packages/api/session-controller/src/index.ts:93`](../packages/api/session-controller/src/index.ts)
|
||||
- `source`: [`packages/api/session-controller/src/index.ts:109`](../packages/api/session-controller/src/index.ts)
|
||||
|
||||
```ts config-catalog
|
||||
/** Session Controller deployment policy. */
|
||||
|
||||
@@ -839,14 +839,6 @@ Host service backing the generated `ctx.remote.session` namespace.
|
||||
*/
|
||||
resolveAgent(sessionId: SessionId): Promise<ApiSessionAgentResult>
|
||||
|
||||
/**
|
||||
* Inspect one attached or persisted Session without activating its Agent.
|
||||
* @param sessionId - durable Session identity.
|
||||
* @param signal - optional caller cancellation for persistence reads.
|
||||
* @returns the current attached state or persisted header and event prefix.
|
||||
*/
|
||||
inspect( sessionId: SessionId, signal?: AbortSignal, ): Promise<SessionInspection>
|
||||
|
||||
/**
|
||||
* Read all visible Session rows without resuming an Agent.
|
||||
* @param _request - reserved empty list request.
|
||||
@@ -972,7 +964,7 @@ workspaceDesktop(): { name: string; available: boolean; fileManager: 'finder' |
|
||||
* @param signal - cancellation for persistence reads.
|
||||
* @returns one chronological page.
|
||||
*/
|
||||
@Remote({ name: 'page', resources: { session: addressedSession } }) page(request: SessionPageRequest, signal: AbortSignal): Promise<SessionPage>
|
||||
@Remote('page') page(request: SessionPageRequest, signal: AbortSignal): Promise<SessionPage>
|
||||
|
||||
/**
|
||||
* Follow one Session log from its opening or resume cursor.
|
||||
@@ -981,7 +973,7 @@ workspaceDesktop(): { name: string; available: boolean; fileManager: 'finder' |
|
||||
* @returns a complete opening snapshot followed by gap-free durable event
|
||||
* frames and optional cursorless assistant-stream frames.
|
||||
*/
|
||||
@Remote({ mode: 'stream', resources: { session: addressedSession } }) follow(request: SessionFollowRequest, signal: AbortSignal): AsyncIterable<SessionFollowFrame>
|
||||
@Remote({ mode: 'stream' }) follow(request: SessionFollowRequest, signal: AbortSignal): AsyncIterable<SessionFollowFrame>
|
||||
|
||||
/**
|
||||
* Read exact projections, returning cached hints only when migration is required.
|
||||
@@ -999,7 +991,7 @@ workspaceDesktop(): { name: string; available: boolean; fileManager: 'finder' |
|
||||
@Remote({ mode: 'stream' }) async *control(signal: AbortSignal): AsyncIterable<SessionControlFrame>
|
||||
```
|
||||
|
||||
Types: [SessionId](core.md) · [SessionInspection](persistence.md) · [SessionSearchRequest](session-query.md)
|
||||
Types: [SessionId](core.md) · [SessionSearchRequest](session-query.md)
|
||||
|
||||
Source: [`packages/api/session-controller/src/index.ts`](../../packages/api/session-controller/src/index.ts)
|
||||
|
||||
|
||||
@@ -843,14 +843,6 @@ Host service backing the generated `ctx.remote.session` namespace.
|
||||
*/
|
||||
resolveAgent(sessionId: SessionId): Promise<ApiSessionAgentResult>
|
||||
|
||||
/**
|
||||
* Inspect one attached or persisted Session without activating its Agent.
|
||||
* @param sessionId - durable Session identity.
|
||||
* @param signal - optional caller cancellation for persistence reads.
|
||||
* @returns the current attached state or persisted header and event prefix.
|
||||
*/
|
||||
inspect( sessionId: SessionId, signal?: AbortSignal, ): Promise<SessionInspection>
|
||||
|
||||
/**
|
||||
* Read all visible Session rows without resuming an Agent.
|
||||
* @param _request - reserved empty list request.
|
||||
@@ -976,7 +968,7 @@ workspaceDesktop(): { name: string; available: boolean; fileManager: 'finder' |
|
||||
* @param signal - cancellation for persistence reads.
|
||||
* @returns one chronological page.
|
||||
*/
|
||||
@Remote({ name: 'page', resources: { session: addressedSession } }) page(request: SessionPageRequest, signal: AbortSignal): Promise<SessionPage>
|
||||
@Remote('page') page(request: SessionPageRequest, signal: AbortSignal): Promise<SessionPage>
|
||||
|
||||
/**
|
||||
* Follow one Session log from its opening or resume cursor.
|
||||
@@ -985,7 +977,7 @@ workspaceDesktop(): { name: string; available: boolean; fileManager: 'finder' |
|
||||
* @returns a complete opening snapshot followed by gap-free durable event
|
||||
* frames and optional cursorless assistant-stream frames.
|
||||
*/
|
||||
@Remote({ mode: 'stream', resources: { session: addressedSession } }) follow(request: SessionFollowRequest, signal: AbortSignal): AsyncIterable<SessionFollowFrame>
|
||||
@Remote({ mode: 'stream' }) follow(request: SessionFollowRequest, signal: AbortSignal): AsyncIterable<SessionFollowFrame>
|
||||
|
||||
/**
|
||||
* Read exact projections, returning cached hints only when migration is required.
|
||||
@@ -1003,7 +995,7 @@ workspaceDesktop(): { name: string; available: boolean; fileManager: 'finder' |
|
||||
@Remote({ mode: 'stream' }) async *control(signal: AbortSignal): AsyncIterable<SessionControlFrame>
|
||||
```
|
||||
|
||||
Types: [SessionId](core.zh.md) · [SessionInspection](persistence.zh.md) · [SessionSearchRequest](session-query.zh.md)
|
||||
Types: [SessionId](core.zh.md) · [SessionSearchRequest](session-query.zh.md)
|
||||
|
||||
Source: [`packages/api/session-controller/src/index.ts`](../../packages/api/session-controller/src/index.ts)
|
||||
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
en: 21e88d68154c2c92
|
||||
zh: 8c9e05c65ef0f34d
|
||||
/typert-remote-calls/remote-access-resources:
|
||||
en: fa95f70437c07395
|
||||
zh: d4870b678b569a89
|
||||
en: 2e27d0745a4e3eac
|
||||
zh: eb4ad825852c595b
|
||||
/typert-remote-calls/typert-registry:
|
||||
en: 5827ef50011811c9
|
||||
zh: 21a9e7b368ba211a
|
||||
en: d891e9390cf890da
|
||||
zh: f45a31cc2ce2021e
|
||||
/typert-remote-calls/host-gateway:
|
||||
en: 58b923de12e48f18
|
||||
zh: d3c2372d8becf65e
|
||||
|
||||
@@ -286,7 +286,7 @@ interface RemoteInvocation {
|
||||
|
||||
## Remote access resources
|
||||
|
||||
Every Remote method is under the access control of [`dsh-api-remote-access`](../../packages/api/remote-access/README.md): a non-owner call is allowed only when the policy for its principal kind binds, on every resource the call touches, a role that lists the endpoint action. The package that owns an identity type merge-declares its resource kind in `TypertResourceMap`; `global`, the built-in identity-less resource, is never a kind there. The Gateway reads a kind's identities from the `resources` readers of `@Remote({ resources })` or `@RemoteScope(key, { resources })`, else from a lookup parameter or scoped Context that declares the kind as its `resource`, else from the default field registered in `typert.resources`; a call that names no resource touches `global`. The [Peer principals Agent Note](../../.agents/notes/implemented/architecture/2026-10-12-peer-principal-and-remote-access.md) owns the decision.
|
||||
Every Remote method is under the access control of [`dsh-api-remote-access`](../../packages/api/remote-access/README.md): a non-owner call is allowed only when the policy for its principal kind binds, on every resource the call touches, a role that lists the endpoint action. The package that owns an identity type merge-declares its resource kind in `TypertResourceMap`; `global`, the built-in identity-less resource, is never a kind there. The Gateway reads a kind's identities from the `resources` readers of `@Remote({ resources })` or `@RemoteScope(key, { resources })`, else from a lookup parameter or scoped Context that declares the kind as its `resource`, else from the default field or resolver registered in `typert.resources`; a call that names no resource touches `global`. The [Peer principals Agent Note](../../.agents/notes/implemented/architecture/2026-10-12-peer-principal-and-remote-access.md) owns the decision.
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
@@ -334,11 +334,14 @@ interface RemoteScopeOptions<WireArgs extends readonly unknown[] = never> {
|
||||
* throw, an empty list, or an identity other than a non-empty string
|
||||
* refuses the call. For a kind without a reader, the Gateway reads the
|
||||
* identity of a scoped Context whose Host adapter declares that `resource`
|
||||
* and of lookup parameters declaring it, else the field registered in
|
||||
* `typert.resources`: a top-level argument or, failing that, the first
|
||||
* object argument. A call that carries no identity touches `global`. The
|
||||
* readers and these defaults together must name every resource the method
|
||||
* accesses: access control never checks a resource they omit.
|
||||
* and of lookup parameters declaring it, else the registered default of
|
||||
* `typert.resources`: a `resolve` function receiving the validated named
|
||||
* wire values and their ordered parameters, or a `field` naming a top-level
|
||||
* argument or, failing that, a field of the first object argument. A
|
||||
* throwing resolver, an array result, or a field holding an array refuses
|
||||
* the call. A call that carries no identity touches `global`. The readers
|
||||
* and these defaults together must name every resource the method accesses:
|
||||
* access control never checks a resource they omit.
|
||||
*/
|
||||
readonly resources?: TypertResourceReaders<WireArgs>
|
||||
}
|
||||
@@ -358,7 +361,7 @@ interface RemoteMethodOptions<WireArgs extends readonly unknown[] = never> exten
|
||||
|
||||
## Typert registry
|
||||
|
||||
`ctx.typert` separates current-environment descriptors, explicitly selected Remote contributions, lookup providers, scoped Context providers, and the default fields of resource kinds. A lookup provider owns the stable wire declaration and default resolver; Host composition can configure an effect-scoped synchronous or asynchronous resolver for the same key, and unloading that configuration restores the default policy. Registrations are Cordis-owned effects and return awaitable disposers.
|
||||
`ctx.typert` separates current-environment descriptors, explicitly selected Remote contributions, lookup providers, scoped Context providers, and the default fields or resolvers of resource kinds. A lookup provider owns the stable wire declaration and default resolver; Host composition can configure an effect-scoped synchronous or asynchronous resolver for the same key, and unloading that configuration restores the default policy. Registrations are Cordis-owned effects and return awaitable disposers.
|
||||
|
||||
```ts type-equiv
|
||||
/** Minimal Typert runtime consumed through dependency inversion. */
|
||||
|
||||
@@ -286,7 +286,7 @@ interface RemoteInvocation {
|
||||
|
||||
## Remote 访问资源
|
||||
|
||||
每个 Remote 方法都受 [`dsh-api-remote-access`](../../packages/api/remote-access/README.zh.md) 的访问控制:只有当该 principal 种类的 policy 在调用访问的每个资源上都绑定了列出该端点 action 的 role 时,非 owner 调用才被放行。拥有某个身份类型的包把其资源种类声明合并进 `TypertResourceMap`;内置的无身份资源 `global` 从不是其中的种类。Gateway 从 `@Remote({ resources })` 或 `@RemoteScope(key, { resources })` 的 `resources` 读取函数读取某个种类的身份,其次是把该种类声明为 `resource` 的 lookup 参数或作用域 Context,再次是在 `typert.resources` 中登记的默认字段;不指向任何资源的调用访问 `global`。决策由 [Peer 身份属性 Agent Note](../../.agents/notes/implemented/architecture/2026-10-12-peer-principal-and-remote-access.zh.md) 负责。
|
||||
每个 Remote 方法都受 [`dsh-api-remote-access`](../../packages/api/remote-access/README.zh.md) 的访问控制:只有当该 principal 种类的 policy 在调用访问的每个资源上都绑定了列出该端点 action 的 role 时,非 owner 调用才被放行。拥有某个身份类型的包把其资源种类声明合并进 `TypertResourceMap`;内置的无身份资源 `global` 从不是其中的种类。Gateway 从 `@Remote({ resources })` 或 `@RemoteScope(key, { resources })` 的 `resources` 读取函数读取某个种类的身份,其次是把该种类声明为 `resource` 的 lookup 参数或作用域 Context,再次是在 `typert.resources` 中登记的默认字段或 resolver;不指向任何资源的调用访问 `global`。决策由 [Peer 身份属性 Agent Note](../../.agents/notes/implemented/architecture/2026-10-12-peer-principal-and-remote-access.zh.md) 负责。
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
@@ -334,11 +334,14 @@ interface RemoteScopeOptions<WireArgs extends readonly unknown[] = never> {
|
||||
* throw, an empty list, or an identity other than a non-empty string
|
||||
* refuses the call. For a kind without a reader, the Gateway reads the
|
||||
* identity of a scoped Context whose Host adapter declares that `resource`
|
||||
* and of lookup parameters declaring it, else the field registered in
|
||||
* `typert.resources`: a top-level argument or, failing that, the first
|
||||
* object argument. A call that carries no identity touches `global`. The
|
||||
* readers and these defaults together must name every resource the method
|
||||
* accesses: access control never checks a resource they omit.
|
||||
* and of lookup parameters declaring it, else the registered default of
|
||||
* `typert.resources`: a `resolve` function receiving the validated named
|
||||
* wire values and their ordered parameters, or a `field` naming a top-level
|
||||
* argument or, failing that, a field of the first object argument. A
|
||||
* throwing resolver, an array result, or a field holding an array refuses
|
||||
* the call. A call that carries no identity touches `global`. The readers
|
||||
* and these defaults together must name every resource the method accesses:
|
||||
* access control never checks a resource they omit.
|
||||
*/
|
||||
readonly resources?: TypertResourceReaders<WireArgs>
|
||||
}
|
||||
@@ -358,7 +361,7 @@ interface RemoteMethodOptions<WireArgs extends readonly unknown[] = never> exten
|
||||
|
||||
## Typert 注册表
|
||||
|
||||
`ctx.typert` 分开保存当前环境的 descriptor、显式选择的 Remote contribution、lookup 提供方、作用域上下文提供方与资源种类的默认字段。lookup 提供方拥有稳定 wire 声明和默认 resolver;Host 组合可以为同一个 key 配置 effect-scoped 同步或异步 resolver,配置卸载后恢复默认策略。各项注册都是由 Cordis 持有的 effect,并返回可等待的 disposer。
|
||||
`ctx.typert` 分开保存当前环境的 descriptor、显式选择的 Remote contribution、lookup 提供方、作用域上下文提供方与资源种类的默认字段或 resolver。lookup 提供方拥有稳定 wire 声明和默认 resolver;Host 组合可以为同一个 key 配置 effect-scoped 同步或异步 resolver,配置卸载后恢复默认策略。各项注册都是由 Cordis 持有的 effect,并返回可等待的 disposer。
|
||||
|
||||
```ts type-equiv
|
||||
/** Minimal Typert runtime consumed through dependency inversion. */
|
||||
|
||||
Reference in new issue
Block a user