feat(session): add cross-session references
This commit is contained in:
@@ -58,7 +58,7 @@ Automatic callers state why policy is running; implementations may treat confirm
|
||||
type CompactionTrigger = 'pressure' | 'context-overflow'
|
||||
```
|
||||
|
||||
`CompactService` exposes `compactIfNeeded(agent, trigger, signal)` for automatic `pressure` or `context-overflow` policy, returning `null` when no safe work exists, and `compactRegion(...)` for an explicit inclusive surface range. Implementations must forward the supplied signal to summarization. The seam owns no pricing API: the singleton [`ctx.tokenMeter`](token-meter.md) directly owns estimation and replay, while `dsh-compact-basic` owns retention, event sequencing, routed summarization calls, and their configuration.
|
||||
`CompactService` exposes `compactIfNeeded(agent, trigger, signal)` for automatic `pressure` or `context-overflow` policy, returning `null` when no safe work exists, and `compactRegion(...)` for an explicit inclusive surface range. Every backend marks its replacement `user/message` with the package-exported `COMPACT_CHECKPOINT_SOURCE`; consumers call `isCompactCheckpointSource()` instead of coupling checkpoint recognition to one backend. Implementations must forward the supplied signal to summarization. The seam owns no pricing API: the singleton [`ctx.tokenMeter`](token-meter.md) directly owns estimation and replay, while `dsh-compact-basic` owns retention, event sequencing, routed summarization calls, and their configuration.
|
||||
|
||||
Pressure compaction runs at serial `agent/post-step`, after successful assistant output, tool results, buffered context, and steering are durable but before `step/end`. Once pressure or canonical overflow qualifies, compact-basic invokes optional [`ctx.toolResultPrune`](../../packages/compact/compact-tool-result-prune/README.md) before range selection, remeasures through `ctx.tokenMeter`, and can advance the surface without a summary. Failed-request recovery runs through `agent/request-error` after the failed step closes and authorizes a fresh numbered-step retry only when the surface replacement generation advances, even if later summary work throws after pruning; cancellation still wins. Region boundaries preserve tool-call/result pairing but not whole turns, allowing early closed steps of one oversized turn to compact. `dsh-compact-basic` owns thresholds, retained-tail policy, overflow caps, and failure handling.
|
||||
|
||||
|
||||
@@ -340,6 +340,22 @@ The fourteen event variants (`turn/start`, `turn/end`, `step/start`, `step/end`,
|
||||
|
||||
Source: [`packages/core/agent/src/types.ts`](../../packages/core/agent/src/types.ts)
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
* Message options. An omitted source attests direct human input as `{ kind: 'user' }`
|
||||
* and may authorize policy consumers, so non-human producers must label their content.
|
||||
*/
|
||||
interface SendOptions {
|
||||
source?: MessageSource
|
||||
/**
|
||||
* Model-facing contexts captured with this inbox item. A queued prompt exposes
|
||||
* them through the default `agent/prompt-submit` allow decision, while steering
|
||||
* records them directly at its next checkpoint.
|
||||
*/
|
||||
contexts?: HookContext[]
|
||||
}
|
||||
```
|
||||
|
||||
`InjectOptions` extends ordinary message attribution with durable model-hidden JSON metadata:
|
||||
|
||||
```ts type-equiv
|
||||
@@ -365,7 +381,8 @@ interface Agent {
|
||||
* Queue one detached, frozen lossless-JSON item. If claimed, it is the sole
|
||||
* ordinary message in its FIFO-ordered turn; the next claimed item waits for
|
||||
* that turn's checkpoint.
|
||||
* Invalid input throws synchronously before notification or enqueue.
|
||||
* Attached contexts share the same snapshot and ownership boundary. Invalid
|
||||
* input throws synchronously before notification or enqueue.
|
||||
*/
|
||||
send(content: ContentBlock[], options?: SendOptions): void
|
||||
|
||||
@@ -418,7 +435,7 @@ Each `agent/*` interception waterfall returns a small, seam-specific typed union
|
||||
Source: [`packages/core/agent/src/types.ts`](../../packages/core/agent/src/types.ts)
|
||||
|
||||
```ts type-equiv
|
||||
/** Model-facing context injected by a listener; `source` prevents plugin text from being labeled as user input. */
|
||||
/** Model-facing context injected by a listener or atomically attached to one inbox message. */
|
||||
interface HookContext {
|
||||
content: ContentBlock[]
|
||||
source: MessageSource
|
||||
@@ -434,7 +451,9 @@ interface HookContext {
|
||||
* Prompt interception result. `allow.content` replaces the prompt and each
|
||||
* `additionalContexts` entry becomes a separate context message. `block`
|
||||
* records a durable `prompt/blocked` and ends the claimed prompt's zero-step
|
||||
* turn as rejected.
|
||||
* turn as rejected. An `allow` returned by a listener is authoritative: a
|
||||
* listener wrapping `next()` preserves downstream `content` and
|
||||
* `additionalContexts` unless it intentionally replaces them.
|
||||
*/
|
||||
type PromptDecision =
|
||||
| { kind: 'allow'; content?: ContentBlock[]; additionalContexts?: HookContext[] }
|
||||
|
||||
@@ -25,6 +25,20 @@ interface SessionRecord {
|
||||
}
|
||||
```
|
||||
|
||||
`SessionSurfaceSnapshot` is one exact-read observation rather than a retained subscription. Its raw-log boundary and folded events come from the same live-preferred load.
|
||||
|
||||
```ts type-equiv
|
||||
/** One atomic live-preferred observation of a session's current model surface. */
|
||||
interface SessionSurfaceSnapshot {
|
||||
/** Cloned session header selected from the same corpus observation as `events`. */
|
||||
session: SessionHeader
|
||||
/** Highest raw-log seq included in the observation, or `null` for an empty log. */
|
||||
capturedThroughSeq: number | null
|
||||
/** Cloned current surface events in model-history order. */
|
||||
events: SurfaceEvent[]
|
||||
}
|
||||
```
|
||||
|
||||
```ts type-equiv
|
||||
/** Lightweight metadata for one event within a logical session. */
|
||||
interface SessionEventRecord {
|
||||
|
||||
65
docs/core-data-structures/session-reference.md
Normal file
65
docs/core-data-structures/session-reference.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# Session References
|
||||
|
||||
Structured cross-session reference requests and prepared message contexts. The [package contract](../../packages/context/session-reference) owns canonical URIs, current-surface projection, tag-safe JSON and byte retention, stable errors, and the untrusted model prompt. Host adapters use these types instead of passing their UI mention syntax into the agent core.
|
||||
|
||||
Source: [`packages/context/session-reference/src/types.ts`](../../packages/context/session-reference/src/types.ts)
|
||||
|
||||
## Inputs and candidates
|
||||
|
||||
`SessionReferenceInput` is the host-independent selection. The id is authoritative; the label is display metadata carried into the snapshot.
|
||||
|
||||
```ts type-equiv
|
||||
/** One source session selected by a host. */
|
||||
interface SessionReferenceInput {
|
||||
/** Opaque source session identity. */
|
||||
sessionId: SessionId
|
||||
/** Optional user-facing mention label. */
|
||||
label?: string
|
||||
}
|
||||
```
|
||||
|
||||
`SessionReferenceCandidate` is metadata-only discovery output. Candidate search does not expose transcript text.
|
||||
|
||||
```ts type-equiv
|
||||
/** One host-facing candidate from exact session metadata. */
|
||||
interface SessionReferenceCandidate {
|
||||
/** Opaque source session identity. */
|
||||
sessionId: SessionId
|
||||
/** Default display label. */
|
||||
label: string
|
||||
/** Source session working directory, when recorded. */
|
||||
cwd?: string
|
||||
/** Source session creation time in Unix epoch milliseconds. */
|
||||
createdAt: number
|
||||
}
|
||||
```
|
||||
|
||||
## Prepared messages
|
||||
|
||||
Preparation preserves readable current-message content and returns at most one aggregated context. The host binds `contexts` to that exact `send()` or `steer()` call.
|
||||
|
||||
```ts type-equiv
|
||||
/** Message payload and the zero-or-one durable snapshot contexts bound to it. */
|
||||
interface PreparedReferencedMessage {
|
||||
/** Readable message content after host mention tokens are removed. */
|
||||
content: ContentBlock[]
|
||||
/** Empty without references; otherwise one aggregated untrusted context. */
|
||||
contexts: HookContext[]
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
`SessionReferenceError.code` separates invalid configuration or input, self-reference, count limits, source-read failure, budget failure, and cancellation. Host protocols map these codes to their own error envelopes without inspecting prompt bytes.
|
||||
|
||||
```ts type-equiv
|
||||
/** Stable failure codes exposed to host adapters. */
|
||||
type SessionReferenceErrorCode =
|
||||
| 'SESSION_REFERENCE_INVALID_CONFIG'
|
||||
| 'SESSION_REFERENCE_INVALID_REFERENCE'
|
||||
| 'SESSION_REFERENCE_SELF_REFERENCE'
|
||||
| 'SESSION_REFERENCE_TOO_MANY'
|
||||
| 'SESSION_REFERENCE_READ_FAILED'
|
||||
| 'SESSION_REFERENCE_BUDGET_EXCEEDED'
|
||||
| 'SESSION_REFERENCE_CANCELLED'
|
||||
```
|
||||
Reference in New Issue
Block a user