Merge branch 'stack/agent-profiles-1-seam' into stack/agent-profiles-3-wire
master extracted this layer's inline cold-resume resolver into @deepseek-ai/dsh-api-remotes, whose `setup` was a fixed AgentSetup. A resumed session composes the preset ITS header recorded, so the option becomes a function of that header; the resolver builds the setup before the published re-checks so those stay adjacent to `resume`. Conflicts: docs/cordis-catalog/services.md docs/module-graph.md packages/host/apiproxy/package.json packages/host/apiproxy/src/api-proxy.ts pnpm-lock.yaml
This commit is contained in:
@@ -15,12 +15,17 @@
|
||||
"types": "./lib/types/invariant.d.ts",
|
||||
"default": "./lib/invariant.js"
|
||||
},
|
||||
"./types": {
|
||||
"types": "./lib/types/types.d.ts",
|
||||
"default": "./lib/types/types.js"
|
||||
},
|
||||
"./src/*": "./src/*",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
"lib/invariant.js",
|
||||
"lib/types/**/*.js",
|
||||
"lib/types/**/*.d.ts"
|
||||
],
|
||||
"license": "BSD-3-Clause",
|
||||
@@ -30,6 +35,7 @@
|
||||
"@deepseek-ai/dsh-scope": "^0.0.1",
|
||||
"@deepseek-ai/dsh-session": "^0.0.1",
|
||||
"@deepseek-ai/dsh-system-prompt": "^0.0.1",
|
||||
"@deepseek-ai/dsh-type-meta": "^0.0.1",
|
||||
"cordis": "^4.0.0-rc.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -38,6 +44,8 @@
|
||||
"@deepseek-ai/dsh-scope": "workspace:^",
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-system-prompt": "workspace:^",
|
||||
"@deepseek-ai/dsh-type-meta": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-registry": "workspace:^",
|
||||
"cordis": "^4.0.0-rc.7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { isPromise } from 'node:util/types'
|
||||
import { scopeTarget } from '@deepseek-ai/dsh-scope'
|
||||
import type { Scoped } from '@deepseek-ai/dsh-scope'
|
||||
import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session'
|
||||
import type { TypeRTContext, TypeRTLookup } from '@deepseek-ai/dsh-type-meta'
|
||||
import type { Agent, AgentOptions } from './types.ts'
|
||||
|
||||
export * from './types.ts'
|
||||
@@ -20,6 +21,16 @@ export * from './llm-target.ts'
|
||||
export { agentCarrier, agentEvents, assembleContextFor, emitAgentEvent } from './dispatch.ts'
|
||||
export type { AgentEventDispatch, AgentSubjectEvent } from './dispatch.ts'
|
||||
|
||||
declare module '@deepseek-ai/dsh-type-meta' {
|
||||
interface TypeRTLookupMap {
|
||||
agent: TypeRTLookup<Agent, SessionId>
|
||||
}
|
||||
|
||||
interface TypeRTContextMap {
|
||||
agent: TypeRTContext<SessionId>
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'cordis' {
|
||||
interface Context {
|
||||
agents: AgentRegistry
|
||||
@@ -252,6 +263,20 @@ export class AgentRegistry extends Service {
|
||||
|
||||
constructor(ctx: Context) {
|
||||
super(ctx, 'agents')
|
||||
ctx.inject(['typert'], (typeCtx) => {
|
||||
typeCtx.typert.lookups.register('agent', {
|
||||
parameter: 'agent',
|
||||
wire: 'agentId',
|
||||
hostTypeSymbol: '@deepseek-ai/dsh-agent#Agent',
|
||||
wireTypeSymbol: '@deepseek-ai/dsh-session/types#SessionId',
|
||||
resolve: sessionId => this.get(sessionId),
|
||||
})
|
||||
typeCtx.typert.contexts.registerHost('agent', {
|
||||
wire: 'agentId',
|
||||
wireTypeSymbol: '@deepseek-ai/dsh-session/types#SessionId',
|
||||
resolve: sessionId => this.get(sessionId)?.ctx,
|
||||
})
|
||||
})
|
||||
// The `ctx.agent` DX accessor: default `undefined` on every context, so a
|
||||
// plain plugin context reads cleanly instead of hitting the Cordis
|
||||
// unknown-property throw. Each Agent.ctx shadows it with an own property
|
||||
|
||||
@@ -6,6 +6,7 @@ import AgentRegistry, {
|
||||
agentEvents,
|
||||
Inbox,
|
||||
} from '@deepseek-ai/dsh-agent'
|
||||
import TypertRegistry from '@deepseek-ai/dsh-typert-registry'
|
||||
|
||||
import type {
|
||||
Agent,
|
||||
@@ -142,6 +143,31 @@ describe('Inbox', () => {
|
||||
})
|
||||
|
||||
describe('AgentRegistry', () => {
|
||||
it('contributes Agent lookup and scoped Context providers while TypeRT is live', async () => {
|
||||
const ctx = new Context()
|
||||
const agentFiber = ctx.plugin(AgentRegistry)
|
||||
await agentFiber
|
||||
await ctx.plugin(TypertRegistry)
|
||||
const agent = stubAgent('remote-agent')
|
||||
const disposeAgent = ctx.agents.register(agent)
|
||||
|
||||
const lookup = ctx.typert.lookups.get('agent')
|
||||
expect(lookup).toMatchObject({
|
||||
parameter: 'agent',
|
||||
wire: 'agentId',
|
||||
hostTypeSymbol: '@deepseek-ai/dsh-agent#Agent',
|
||||
wireTypeSymbol: '@deepseek-ai/dsh-session/types#SessionId',
|
||||
})
|
||||
expect(lookup?.resolve(agent.id)).toBe(agent)
|
||||
expect(ctx.typert.contexts.getHost('agent')?.resolve(agent.id)).toBe(agent.ctx)
|
||||
|
||||
disposeAgent()
|
||||
expect(lookup?.resolve(agent.id)).toBeUndefined()
|
||||
await agentFiber.dispose()
|
||||
expect(ctx.typert.lookups.get('agent')).toBeUndefined()
|
||||
expect(ctx.typert.contexts.getHost('agent')).toBeUndefined()
|
||||
})
|
||||
|
||||
it('registers exact entries, emits lifecycle events, and unregisters on owner disposal', async () => {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(AgentRegistry)
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
},
|
||||
{
|
||||
"path": "../../support/invariants"
|
||||
},
|
||||
{
|
||||
"path": "../../typert/type-meta"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"@deepseek-ai/dsh-invariants": "^0.0.1",
|
||||
"@deepseek-ai/dsh-llm": "^0.0.1",
|
||||
"@deepseek-ai/dsh-scope": "^0.0.1",
|
||||
"@deepseek-ai/dsh-type-meta": "^0.0.1",
|
||||
"cordis": "^4.0.0-rc.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -45,6 +46,8 @@
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm": "workspace:^",
|
||||
"@deepseek-ai/dsh-scope": "workspace:^",
|
||||
"@deepseek-ai/dsh-type-meta": "workspace:^",
|
||||
"@deepseek-ai/dsh-typert-registry": "workspace:^",
|
||||
"cordis": "^4.0.0-rc.7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import { scopeOf, scopeTarget } from '@deepseek-ai/dsh-scope'
|
||||
import type { Scoped } from '@deepseek-ai/dsh-scope'
|
||||
import type { Message } from '@deepseek-ai/dsh-llm'
|
||||
import { SESSION_FORMAT_VERSION, SessionId } from './types.ts'
|
||||
import type { TypeRTLookup } from '@deepseek-ai/dsh-type-meta'
|
||||
import type { CreateSessionOptions, EpochHeader, PrepareSessionOptions, RequestContext, SessionEvent, SessionEventMap, SessionEventType, SessionHeader, SurfaceIntent, SurfaceEventType } from './types.ts'
|
||||
import { snapshotJsonValue } from './json.ts'
|
||||
import { deriveEventMessage, SurfaceManager } from './surface.ts'
|
||||
@@ -105,6 +106,12 @@ declare module 'cordis' {
|
||||
}
|
||||
}
|
||||
|
||||
declare module '@deepseek-ai/dsh-type-meta' {
|
||||
interface TypeRTLookupMap {
|
||||
session: TypeRTLookup<Session, SessionId>
|
||||
}
|
||||
}
|
||||
|
||||
/** Validate and freeze one detached creation header in place. */
|
||||
function validateSessionHeader(id: SessionId, input: unknown): SessionHeader {
|
||||
if (input === null || typeof input !== 'object' || Array.isArray(input)) {
|
||||
@@ -806,6 +813,15 @@ export class SessionStore extends Service {
|
||||
|
||||
constructor(ctx: Context) {
|
||||
super(ctx, 'sessions')
|
||||
ctx.inject(['typert'], (typeCtx) => {
|
||||
typeCtx.typert.lookups.register('session', {
|
||||
parameter: 'session',
|
||||
wire: 'sessionId',
|
||||
hostTypeSymbol: '@deepseek-ai/dsh-session#Session',
|
||||
wireTypeSymbol: '@deepseek-ai/dsh-session/types#SessionId',
|
||||
resolve: sessionId => this.get(sessionId),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
26
packages/core/session/tests/typert.spec.ts
Normal file
26
packages/core/session/tests/typert.spec.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { Context } from 'cordis'
|
||||
import SessionStore, { SessionId } from '@deepseek-ai/dsh-session'
|
||||
import TypertRegistry from '@deepseek-ai/dsh-typert-registry'
|
||||
|
||||
describe('Session TypeRT provider', () => {
|
||||
it('contributes live Session lookup in either service load order', async () => {
|
||||
const ctx = new Context()
|
||||
const sessionFiber = ctx.plugin(SessionStore)
|
||||
await sessionFiber
|
||||
await ctx.plugin(TypertRegistry)
|
||||
const session = ctx.sessions.create(SessionId('remote-session'))
|
||||
|
||||
const lookup = ctx.typert.lookups.get('session')
|
||||
expect(lookup).toMatchObject({
|
||||
parameter: 'session',
|
||||
wire: 'sessionId',
|
||||
hostTypeSymbol: '@deepseek-ai/dsh-session#Session',
|
||||
wireTypeSymbol: '@deepseek-ai/dsh-session/types#SessionId',
|
||||
})
|
||||
expect(lookup?.resolve(session.id)).toBe(session)
|
||||
|
||||
await sessionFiber.dispose()
|
||||
expect(ctx.typert.lookups.get('session')).toBeUndefined()
|
||||
})
|
||||
})
|
||||
@@ -25,6 +25,9 @@
|
||||
},
|
||||
{
|
||||
"path": "../../support/invariants"
|
||||
},
|
||||
{
|
||||
"path": "../../typert/type-meta"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user