|
|
@@ -47,6 +47,7 @@ const timingStateSchema: z.ZodType<TimingState> = z.object({
|
|
|
declare module '@deepseek-ai/dsh-session-projection/types' {
|
|
|
interface SessionProjectionStateMap {
|
|
|
subagentTiming: TimingState
|
|
|
+ subagent: IdentityState
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -60,7 +61,6 @@ declare module '@deepseek-ai/dsh-session-projection/types' {
|
|
|
*/
|
|
|
export const subagentTimingProjectionDefinition = {
|
|
|
key: 'subagentTiming',
|
|
|
- stateVersion: 2,
|
|
|
stateSchema: timingStateSchema,
|
|
|
init: () => ({ descriptorSeen: false, settledMs: 0 }),
|
|
|
apply: (state, event) => {
|
|
|
@@ -102,8 +102,14 @@ export const subagentTimingProjectionDefinition = {
|
|
|
...(state.active === undefined ? {} : { active: state.active }),
|
|
|
}),
|
|
|
},
|
|
|
+ stateVersion: 2,
|
|
|
} satisfies ProjectionDefinition<'subagentTiming', TimingState>
|
|
|
|
|
|
+interface IdentityState {
|
|
|
+ /** Identity from the last valid descriptor; absent before one, and after an invalid one. */
|
|
|
+ identity?: SubagentIdentityProjection | undefined
|
|
|
+}
|
|
|
+
|
|
|
// The cast bridges only the optional-label arm: Zod's optional output
|
|
|
// includes explicit `undefined`, which exactOptionalPropertyTypes excludes
|
|
|
// from the public interface. The no-value state itself is the serializable
|
|
|
@@ -124,6 +130,10 @@ const identityValueSchema = z.discriminatedUnion('mode', [
|
|
|
|
|
|
const identitySchema = identityValueSchema.nullable()
|
|
|
|
|
|
+const identityStateSchema: z.ZodType<IdentityState> = z.object({
|
|
|
+ identity: identityValueSchema.optional(),
|
|
|
+}).strict()
|
|
|
+
|
|
|
/** Interpret one `subagent/descriptor` event's identity; no value when the payload cannot be trusted. */
|
|
|
function descriptorIdentity(event: SessionEvent): SubagentIdentityProjection | undefined {
|
|
|
let descriptor: SubagentDescriptorData | undefined
|
|
|
@@ -157,13 +167,15 @@ function descriptorIdentity(event: SessionEvent): SubagentIdentityProjection | u
|
|
|
*/
|
|
|
export const subagentIdentityProjectionDefinition = {
|
|
|
key: 'subagent',
|
|
|
- stateVersion: 3,
|
|
|
- stateSchema: identitySchema,
|
|
|
- init: () => null,
|
|
|
+ stateSchema: identityStateSchema,
|
|
|
+ init: () => ({}),
|
|
|
apply: (state, event) => {
|
|
|
if (event.type !== 'subagent/descriptor') return state
|
|
|
const identity = descriptorIdentity(event)
|
|
|
- return identity === undefined ? null : identity
|
|
|
+ return identity === undefined ? {} : { identity }
|
|
|
},
|
|
|
- wire: { viewSchema: identitySchema, view: state => state },
|
|
|
-} satisfies ProjectionDefinition<'subagent', SubagentIdentityProjection | null>
|
|
|
+ wire: { viewSchema: identitySchema, view: state => state.identity ?? null },
|
|
|
+ // Bumped when the identity gained its `seq` field: an older checkpoint row
|
|
|
+ // would replay into a value the schema rejects, so it must refold instead.
|
|
|
+ stateVersion: 2,
|
|
|
+} satisfies ProjectionDefinition<'subagent', IdentityState>
|