@hydraharness/harness-client-runtime 0.0.0-stage → 0.1.1-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +96 -2
- package/lib/client.js +10964 -0
- package/lib/index.js +6 -0
- package/lib/invariant.js +36 -0
- package/lib/types/client/agents/scope.d.ts +35 -0
- package/lib/types/client/contract/conversation.d.ts +242 -0
- package/lib/types/client/contract/session.d.ts +97 -0
- package/lib/types/client/contract/sessions-port.d.ts +55 -0
- package/lib/types/client/contract/sessions.d.ts +164 -0
- package/lib/types/client/contract/settings-scope.d.ts +79 -0
- package/lib/types/client/contract/store.d.ts +90 -0
- package/lib/types/client/contract/workspaces.d.ts +102 -0
- package/lib/types/client/conversation/definition-registry.d.ts +30 -0
- package/lib/types/client/conversation/event-registry.d.ts +27 -0
- package/lib/types/client/conversation/view-registry.d.ts +15 -0
- package/lib/types/client/index.d.ts +128 -0
- package/lib/types/client/ordered-baseline.d.ts +12 -0
- package/lib/types/client/sessions/assistant-timing.d.ts +34 -0
- package/lib/types/client/sessions/context-provenance.d.ts +58 -0
- package/lib/types/client/sessions/conversation-assembler.d.ts +107 -0
- package/lib/types/client/sessions/conversation-context.d.ts +22 -0
- package/lib/types/client/sessions/conversation-location-index.d.ts +70 -0
- package/lib/types/client/sessions/conversation-versions.d.ts +25 -0
- package/lib/types/client/sessions/conversation.d.ts +422 -0
- package/lib/types/client/sessions/failure-display.d.ts +7 -0
- package/lib/types/client/sessions/lineage.d.ts +47 -0
- package/lib/types/client/sessions/manager.d.ts +300 -0
- package/lib/types/client/sessions/notifier.d.ts +35 -0
- package/lib/types/client/sessions/partial.d.ts +40 -0
- package/lib/types/client/sessions/pending.d.ts +55 -0
- package/lib/types/client/sessions/projection-store.d.ts +111 -0
- package/lib/types/client/sessions/provide.d.ts +79 -0
- package/lib/types/client/sessions/queue-mirror.d.ts +33 -0
- package/lib/types/client/sessions/remotes.d.ts +10 -0
- package/lib/types/client/sessions/request-inspection.d.ts +74 -0
- package/lib/types/client/sessions/service.d.ts +415 -0
- package/lib/types/client/sessions/session.d.ts +287 -0
- package/lib/types/client/sessions/steering-history.d.ts +23 -0
- package/lib/types/client/sessions/subagent-lineage.d.ts +24 -0
- package/lib/types/client/sessions/tool-call-tree.d.ts +45 -0
- package/lib/types/client/slots.d.ts +191 -0
- package/lib/types/client/time-zone.d.ts +8 -0
- package/lib/types/client/workspaces/manager.d.ts +182 -0
- package/lib/types/client/workspaces/path.d.ts +17 -0
- package/lib/types/client/workspaces/service.d.ts +179 -0
- package/lib/types/client/workspaces/workspace.d.ts +65 -0
- package/lib/types/index.d.ts +4 -0
- package/lib/types/invariant.d.ts +16 -0
- package/package.json +94 -3
package/lib/index.js
ADDED
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region lib/types/invariant.js
|
|
2
|
+
/**
|
|
3
|
+
* Package-owned invariant companion for `@hydraharness/harness-client-runtime`.
|
|
4
|
+
* @module @hydraharness/harness-client-runtime/invariant
|
|
5
|
+
*/
|
|
6
|
+
const PACKAGE_NAME = "@hydraharness/harness-client-runtime";
|
|
7
|
+
/** Cordis companion plugin name. */
|
|
8
|
+
const name = "client-runtime-invariant";
|
|
9
|
+
/** Service required before the companion can register. */
|
|
10
|
+
const inject = ["invariants"];
|
|
11
|
+
/**
|
|
12
|
+
* Owned relation: every 'slots/changed'(key) emission must observe the
|
|
13
|
+
* mutation already applied — SlotCore bumps the key's version synchronously
|
|
14
|
+
* before the service re-emits, so a zero version at dispatch time means the
|
|
15
|
+
* event fired without (or ahead of) its mutation.
|
|
16
|
+
*/
|
|
17
|
+
const install = (ctx, fail) => {
|
|
18
|
+
ctx.on("internal/dispatch", (_mode, eventName, args) => {
|
|
19
|
+
if (eventName !== "slots/changed") return;
|
|
20
|
+
const key = args[0];
|
|
21
|
+
if (typeof key !== "string" || key === "") {
|
|
22
|
+
fail("'slots/changed' dispatched without a slot key argument");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const slots = ctx.get("slots");
|
|
26
|
+
if (slots !== void 0 && slots.getVersion(key) === 0) fail(`'slots/changed' fired for "${key}" before any mutation bumped its version — emission must follow the applied mutation`);
|
|
27
|
+
}, { global: true });
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Register this package's invariant companion.
|
|
31
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
32
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
33
|
+
*/
|
|
34
|
+
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
35
|
+
//#endregion
|
|
36
|
+
export { apply, inject, name };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Context, Fiber } from '@hydraharness/cordis';
|
|
2
|
+
import type { SessionId } from '@hydraharness/harness-api-remotes/client';
|
|
3
|
+
import type { TypertClientRemote, TypertRemoteScopeApi } from '@hydraharness/harness-typert-protocol';
|
|
4
|
+
/** Client Cordis Context carrying one Agent identity and its scoped Remote namespaces. */
|
|
5
|
+
export type AgentContext = Omit<Context, 'remote'> & {
|
|
6
|
+
readonly remote: TypertClientRemote & TypertRemoteScopeApi<'agent'>;
|
|
7
|
+
};
|
|
8
|
+
/** A minted Agent scope and its disposal boundary. */
|
|
9
|
+
export interface AgentScopeHandle {
|
|
10
|
+
/**
|
|
11
|
+
* Tagged context: scope-owned registrations and scoped dispatch both go
|
|
12
|
+
* through it (passing it as the dispatch subject routes to this agent's
|
|
13
|
+
* tagged listeners plus every untagged one).
|
|
14
|
+
*/
|
|
15
|
+
ctx: AgentContext;
|
|
16
|
+
/** Backing fiber (dispose tears down every scope-owned registration). */
|
|
17
|
+
fiber: Fiber;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Mint an Agent scope under `ctx`: a no-op plugin fiber whose context
|
|
21
|
+
* carries the agent tag and the dispatch filter — untagged listeners are
|
|
22
|
+
* admitted globally, tagged listeners only for a matching agent.
|
|
23
|
+
* Registrations through the returned ctx dispose with the fiber.
|
|
24
|
+
* @param ctx - client root context the scope fiber mounts under.
|
|
25
|
+
* @param key - owning agent identity (the routing tag; agent id === session id).
|
|
26
|
+
* @returns the tagged context and its backing fiber.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createScope(ctx: Context, key: SessionId): AgentScopeHandle;
|
|
29
|
+
/**
|
|
30
|
+
* Read the nearest agent tag inherited by a context.
|
|
31
|
+
* @param ctx - any client context.
|
|
32
|
+
* @returns its agent identity (the session id), or undefined for root contexts.
|
|
33
|
+
*/
|
|
34
|
+
export declare function scopeOf(ctx: Context): SessionId | undefined;
|
|
35
|
+
//# sourceMappingURL=scope.d.ts.map
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import type { SessionEvent } from '@hydraharness/harness-session/types';
|
|
2
|
+
import type { ToolEventView } from '@hydraharness/harness-api-remotes/client';
|
|
3
|
+
/** One raw log event plus its optional envelope-level presentation view. */
|
|
4
|
+
export interface ConversationEventInput {
|
|
5
|
+
readonly event: SessionEvent;
|
|
6
|
+
readonly view: ToolEventView | undefined;
|
|
7
|
+
}
|
|
8
|
+
/** Definition-local identity and lifecycle role extracted from one event. */
|
|
9
|
+
export interface ConversationMatchResult {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly role: 'start' | 'update';
|
|
12
|
+
}
|
|
13
|
+
/** Merge-extensible business values published against one Turn. */
|
|
14
|
+
export interface ConversationTurnDataMap {
|
|
15
|
+
}
|
|
16
|
+
/** Merge-extensible business values published against one Step. */
|
|
17
|
+
export interface ConversationStepDataMap {
|
|
18
|
+
}
|
|
19
|
+
/** Stable keyed reader for independently owned Location business values. */
|
|
20
|
+
export interface ConversationLocationDataStore<DataMap extends object> {
|
|
21
|
+
/**
|
|
22
|
+
* Read one business value without exposing another owner's mutable State.
|
|
23
|
+
* @param key - declaration-merged business key.
|
|
24
|
+
* @returns latest immutable value, when its owning Context has published one.
|
|
25
|
+
*/
|
|
26
|
+
get<Key extends keyof DataMap & string>(key: Key): Readonly<DataMap[Key]> | undefined;
|
|
27
|
+
}
|
|
28
|
+
interface ConversationLocationDataValue {
|
|
29
|
+
readonly kind: 'turn' | 'step';
|
|
30
|
+
readonly turn: number;
|
|
31
|
+
readonly step?: number;
|
|
32
|
+
readonly key: string;
|
|
33
|
+
readonly value: unknown;
|
|
34
|
+
}
|
|
35
|
+
type RegisteredTurnData = {
|
|
36
|
+
[Key in keyof ConversationTurnDataMap & string]: {
|
|
37
|
+
readonly kind: 'turn';
|
|
38
|
+
readonly turn: number;
|
|
39
|
+
readonly key: Key;
|
|
40
|
+
readonly value: ConversationTurnDataMap[Key];
|
|
41
|
+
};
|
|
42
|
+
}[keyof ConversationTurnDataMap & string];
|
|
43
|
+
type RegisteredStepData = {
|
|
44
|
+
[Key in keyof ConversationStepDataMap & string]: {
|
|
45
|
+
readonly kind: 'step';
|
|
46
|
+
readonly turn: number;
|
|
47
|
+
readonly step: number;
|
|
48
|
+
readonly key: Key;
|
|
49
|
+
readonly value: ConversationStepDataMap[Key];
|
|
50
|
+
};
|
|
51
|
+
}[keyof ConversationStepDataMap & string];
|
|
52
|
+
/** One Definition-owned value attached to an Engine-owned Turn or Step. */
|
|
53
|
+
export type ConversationLocationData = [
|
|
54
|
+
keyof ConversationTurnDataMap | keyof ConversationStepDataMap
|
|
55
|
+
] extends [never] ? ConversationLocationDataValue : RegisteredTurnData | RegisteredStepData;
|
|
56
|
+
/** Immutable resolved boundary for one Agent step. */
|
|
57
|
+
export interface StepLocation {
|
|
58
|
+
readonly turn: number;
|
|
59
|
+
readonly step: number;
|
|
60
|
+
readonly start: SessionEvent<'step/start'> | undefined;
|
|
61
|
+
readonly end: SessionEvent<'step/end'> | undefined;
|
|
62
|
+
readonly status: 'open' | 'closed' | 'unknown';
|
|
63
|
+
/** Stable reader for Step-scoped business values. */
|
|
64
|
+
readonly data: ConversationLocationDataStore<ConversationStepDataMap>;
|
|
65
|
+
}
|
|
66
|
+
/** Immutable resolved boundary for one Agent turn. */
|
|
67
|
+
export interface TurnLocation {
|
|
68
|
+
readonly turn: number;
|
|
69
|
+
readonly start: SessionEvent<'turn/start'> | undefined;
|
|
70
|
+
readonly end: SessionEvent<'turn/end'> | undefined;
|
|
71
|
+
readonly status: 'open' | 'closed' | 'unknown';
|
|
72
|
+
readonly steps: readonly StepLocation[];
|
|
73
|
+
/** Stable reader for Turn-scoped business values. */
|
|
74
|
+
readonly data: ConversationLocationDataStore<ConversationTurnDataMap>;
|
|
75
|
+
}
|
|
76
|
+
/** Engine-owned placement of one matched event in the Session hierarchy. */
|
|
77
|
+
export type ConversationLocation = {
|
|
78
|
+
readonly kind: 'session';
|
|
79
|
+
} | {
|
|
80
|
+
readonly kind: 'turn';
|
|
81
|
+
readonly turn: TurnLocation;
|
|
82
|
+
} | {
|
|
83
|
+
readonly kind: 'step';
|
|
84
|
+
readonly turn: TurnLocation;
|
|
85
|
+
readonly step: StepLocation;
|
|
86
|
+
} | {
|
|
87
|
+
readonly kind: 'unresolved';
|
|
88
|
+
};
|
|
89
|
+
/** One event accepted by a Definition, with its current resolved Location. */
|
|
90
|
+
export interface ConversationMatch extends ConversationEventInput {
|
|
91
|
+
readonly role: 'start' | 'update';
|
|
92
|
+
readonly location: ConversationLocation;
|
|
93
|
+
}
|
|
94
|
+
/** Target-neutral identity returned by a business Definition. */
|
|
95
|
+
export interface ConversationViewNode {
|
|
96
|
+
readonly key: string;
|
|
97
|
+
readonly kind: string;
|
|
98
|
+
readonly id: string;
|
|
99
|
+
readonly target: string;
|
|
100
|
+
readonly data: unknown;
|
|
101
|
+
}
|
|
102
|
+
/** Merge-extensible immutable snapshots published by registered view targets. */
|
|
103
|
+
export interface ConversationViewSnapshotMap {
|
|
104
|
+
}
|
|
105
|
+
/** Stable reader over the latest snapshot of every registered view target. */
|
|
106
|
+
export interface ConversationViewSnapshotStore {
|
|
107
|
+
/** @param target - registered view target. @returns its current snapshot. */
|
|
108
|
+
get<Target extends Extract<keyof ConversationViewSnapshotMap, string>>(target: Target): ConversationViewSnapshotMap[Target] | undefined;
|
|
109
|
+
}
|
|
110
|
+
/** Final Chat render unit produced directly by a business Definition. */
|
|
111
|
+
export interface ChatConversationViewNode extends ConversationViewNode {
|
|
112
|
+
readonly target: 'chat';
|
|
113
|
+
readonly anchorSeq: number;
|
|
114
|
+
readonly location: ConversationLocation;
|
|
115
|
+
readonly visibility: 'visible' | 'hidden';
|
|
116
|
+
}
|
|
117
|
+
/** Immutable public view of an assembled business Context. */
|
|
118
|
+
export interface ConversationNodeContext<State = unknown> {
|
|
119
|
+
readonly key: string;
|
|
120
|
+
readonly kind: string;
|
|
121
|
+
readonly id: string;
|
|
122
|
+
readonly matches: readonly ConversationMatch[];
|
|
123
|
+
readonly start: ConversationMatch | undefined;
|
|
124
|
+
readonly state: State | undefined;
|
|
125
|
+
readonly current: ReadonlyMap<string, ConversationViewNode | null>;
|
|
126
|
+
}
|
|
127
|
+
/** Read-only predecessor returned to a Definition's start function. */
|
|
128
|
+
export interface ConversationPreviousContext<State = unknown> {
|
|
129
|
+
readonly key: string;
|
|
130
|
+
readonly kind: string;
|
|
131
|
+
readonly id: string;
|
|
132
|
+
readonly startSeq: number;
|
|
133
|
+
readonly state: Readonly<State>;
|
|
134
|
+
readonly matches: readonly ConversationMatch[];
|
|
135
|
+
}
|
|
136
|
+
/** Strictly-backward Context lookup available while a start is evaluated. */
|
|
137
|
+
export interface ConversationContextReader {
|
|
138
|
+
/**
|
|
139
|
+
* Find the active Context of `kind` with the greatest start seq below the
|
|
140
|
+
* current start event.
|
|
141
|
+
* @param kind - Definition kind to query.
|
|
142
|
+
* @returns the nearest predecessor, or undefined when absent in the current window.
|
|
143
|
+
*/
|
|
144
|
+
previous<State>(kind: string): ConversationPreviousContext<State> | undefined;
|
|
145
|
+
}
|
|
146
|
+
/** Requested cadence for materializing updated business State into view Nodes. */
|
|
147
|
+
export type ConversationPublication = 'none' | 'animation-frame' | 'immediate';
|
|
148
|
+
/** Engine-owned Location data publication phase. */
|
|
149
|
+
export type ConversationLocationDataScope = 'step' | 'turn';
|
|
150
|
+
/** One independently registered business Event-to-Node state machine. */
|
|
151
|
+
export interface ConversationNodeDefinition<State = unknown> {
|
|
152
|
+
readonly kind: string;
|
|
153
|
+
/** Sole view target owned by this Definition; omitted for state-only Contexts. */
|
|
154
|
+
readonly target?: string;
|
|
155
|
+
/**
|
|
156
|
+
* Extract this Definition's stable business identity from one event.
|
|
157
|
+
* @param event - raw Session event; no Context or history access is available.
|
|
158
|
+
* @returns identity and lifecycle role, or null when unrelated.
|
|
159
|
+
*/
|
|
160
|
+
match(event: SessionEvent): ConversationMatchResult | null;
|
|
161
|
+
/**
|
|
162
|
+
* Create State from the unique start Match.
|
|
163
|
+
* @param context - complete evidence currently collected for the Context.
|
|
164
|
+
* @param match - the start Match.
|
|
165
|
+
* @param reader - strictly-backward read-only Context lookup.
|
|
166
|
+
* @returns the State adopted by the engine.
|
|
167
|
+
*/
|
|
168
|
+
start(context: ConversationNodeContext<State>, match: ConversationMatch, reader: ConversationContextReader): State;
|
|
169
|
+
/**
|
|
170
|
+
* Apply one post-start update Match.
|
|
171
|
+
* @param context - Context with its current State.
|
|
172
|
+
* @param match - update Match in ascending log order.
|
|
173
|
+
* @returns the State adopted by the engine.
|
|
174
|
+
*/
|
|
175
|
+
update(context: ConversationNodeContext<State> & {
|
|
176
|
+
readonly state: State;
|
|
177
|
+
}, match: ConversationMatch): State;
|
|
178
|
+
/**
|
|
179
|
+
* Select publication cadence for one accepted Match.
|
|
180
|
+
* @param match - accepted Match.
|
|
181
|
+
* @returns requested cadence; omission defaults to immediate.
|
|
182
|
+
*/
|
|
183
|
+
publication?(match: ConversationMatch): ConversationPublication;
|
|
184
|
+
/**
|
|
185
|
+
* Publish this Definition's read-only business value for one Location phase.
|
|
186
|
+
* The Engine evaluates every Definition first for Step and then for Turn,
|
|
187
|
+
* owns replacement/removal, and rejects another Context trying to publish
|
|
188
|
+
* the same Location key.
|
|
189
|
+
* @param context - latest complete Context.
|
|
190
|
+
* @param scope - Location hierarchy level currently being materialized.
|
|
191
|
+
* @returns current Location value, or null while unavailable.
|
|
192
|
+
*/
|
|
193
|
+
buildLocationData?(context: ConversationNodeContext<State>, scope: ConversationLocationDataScope): ConversationLocationData | null;
|
|
194
|
+
/**
|
|
195
|
+
* Materialize one final Node for this Definition's declared view target.
|
|
196
|
+
* @param context - latest complete Context.
|
|
197
|
+
* @returns final Node, or null when this Context is not currently visible.
|
|
198
|
+
*/
|
|
199
|
+
buildViewNode?(context: ConversationNodeContext<State>): ConversationViewNode | null;
|
|
200
|
+
}
|
|
201
|
+
/** Reference-stable Turn/Step facts published beside view Nodes. */
|
|
202
|
+
export interface ConversationTimelineSnapshot {
|
|
203
|
+
readonly turnOrder: readonly number[];
|
|
204
|
+
readonly turns: ReadonlyMap<number, TurnLocation>;
|
|
205
|
+
}
|
|
206
|
+
/** Per-Session incremental builder for one view target. */
|
|
207
|
+
export interface ConversationViewBuilder<Node extends ConversationViewNode = ConversationViewNode, Snapshot = unknown> {
|
|
208
|
+
readonly empty: Snapshot;
|
|
209
|
+
/**
|
|
210
|
+
* Replace the low-frequency complete materialized Node set.
|
|
211
|
+
* @param input - complete Nodes and current timeline.
|
|
212
|
+
* @returns next view snapshot.
|
|
213
|
+
*/
|
|
214
|
+
replace(input: {
|
|
215
|
+
readonly nodes: readonly Node[];
|
|
216
|
+
readonly timeline: ConversationTimelineSnapshot;
|
|
217
|
+
}): Snapshot;
|
|
218
|
+
/**
|
|
219
|
+
* Apply only Nodes whose materialized values changed in this transaction.
|
|
220
|
+
* @param input - changed Nodes and current timeline.
|
|
221
|
+
* @returns next view snapshot.
|
|
222
|
+
*/
|
|
223
|
+
apply(input: {
|
|
224
|
+
readonly upserts: readonly Node[];
|
|
225
|
+
readonly timeline: ConversationTimelineSnapshot;
|
|
226
|
+
}): Snapshot;
|
|
227
|
+
}
|
|
228
|
+
/** Registry contribution that creates one isolated view builder per Session. */
|
|
229
|
+
export interface ConversationViewDefinition<Node extends ConversationViewNode = ConversationViewNode, Snapshot = unknown> {
|
|
230
|
+
readonly target: string;
|
|
231
|
+
/** @returns a new Session-owned incremental builder. */
|
|
232
|
+
create(): ConversationViewBuilder<Node, Snapshot>;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Build a stable collision-free key for one Definition-local business identity.
|
|
236
|
+
* @param kind - Definition kind.
|
|
237
|
+
* @param id - Definition-local business identity.
|
|
238
|
+
* @returns engine-owned Context key.
|
|
239
|
+
*/
|
|
240
|
+
export declare function conversationContextKey(kind: string, id: string): string;
|
|
241
|
+
export {};
|
|
242
|
+
//# sourceMappingURL=conversation.d.ts.map
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The outward session face. Feature packages never see the concrete Session
|
|
3
|
+
* class: components read conversation state through `useSession` (the
|
|
4
|
+
* ObservableSnapshot half), and orchestration code calls the behavior verbs
|
|
5
|
+
* below — nothing else. Widening this interface is the explicit act of
|
|
6
|
+
* widening what features may do to a session (and what every test fixture
|
|
7
|
+
* must stub); runtime-internal entry points (history staging, wire-frame
|
|
8
|
+
* dispatch) stay on the class, invisible out here.
|
|
9
|
+
*/
|
|
10
|
+
import type { AttachmentIdType, ImageAttachmentRef, VideoAttachmentRef } from '@hydraharness/harness-attachment';
|
|
11
|
+
import type { MessageId, PromptContentPart, QueueAction, RpcResult, SessionId } from '@hydraharness/harness-api-remotes/client';
|
|
12
|
+
import type { RemoteResult } from '@hydraharness/harness-typert-protocol';
|
|
13
|
+
import type { ConversationSnapshot } from '../sessions/conversation.ts';
|
|
14
|
+
import type { ObservableSnapshot } from './store.ts';
|
|
15
|
+
/** Key-addressed projection read face (the useProjection resolution path; see ProjectionValueStore). */
|
|
16
|
+
export interface ProjectionsFace {
|
|
17
|
+
/**
|
|
18
|
+
* The identity-stable bare observable for one projection key (absence is
|
|
19
|
+
* an `undefined` snapshot, never a missing face).
|
|
20
|
+
* @param key - projection key.
|
|
21
|
+
* @returns the key's value face.
|
|
22
|
+
*/
|
|
23
|
+
faceOf(key: string): ObservableSnapshot<unknown>;
|
|
24
|
+
}
|
|
25
|
+
/** Identity plus the behavior verbs features may invoke on a session. */
|
|
26
|
+
export interface ISession {
|
|
27
|
+
/** The session's host identity (agent id — same axis). */
|
|
28
|
+
readonly sessionId: SessionId;
|
|
29
|
+
/** Host-computed projection values by key (the useProjection seat). */
|
|
30
|
+
readonly projections: ProjectionsFace;
|
|
31
|
+
/**
|
|
32
|
+
* Send a prompt into the session.
|
|
33
|
+
* @param content - text plus browser-owned temporary image uploads.
|
|
34
|
+
* @param mode - 'queue' appends a turn; 'steer' interrupts the running one.
|
|
35
|
+
* @returns acceptance, or the business error (also mirrored into snapshot.promptError).
|
|
36
|
+
*/
|
|
37
|
+
prompt(content: PromptContentPart[], mode: 'queue' | 'steer', signal?: AbortSignal): Promise<RpcResult<{
|
|
38
|
+
accepted: true;
|
|
39
|
+
}>>;
|
|
40
|
+
/**
|
|
41
|
+
* Resolve durable image or video bytes referenced by this session.
|
|
42
|
+
* @param attachmentId - opaque id found in the folded session log.
|
|
43
|
+
* @returns the authenticated reference and decoded bytes.
|
|
44
|
+
*/
|
|
45
|
+
readAttachment(attachmentId: AttachmentIdType): Promise<RpcResult<{
|
|
46
|
+
attachment: ImageAttachmentRef | VideoAttachmentRef;
|
|
47
|
+
data: Uint8Array;
|
|
48
|
+
}>>;
|
|
49
|
+
/**
|
|
50
|
+
* Apply one edit, remove, or strict steer action to a still-pending queue occurrence.
|
|
51
|
+
* @param itemId - agent-owned inbox occurrence identity.
|
|
52
|
+
* @param action - requested queue operation.
|
|
53
|
+
* @returns acceptance, or a business/transport error.
|
|
54
|
+
*/
|
|
55
|
+
updateQueue(itemId: MessageId, action: QueueAction): Promise<RpcResult<{
|
|
56
|
+
accepted: true;
|
|
57
|
+
}>>;
|
|
58
|
+
/**
|
|
59
|
+
* Cancel the running turn. Pending queued work remains and resumes in FIFO
|
|
60
|
+
* order after the Host reaches cancellation quiescence.
|
|
61
|
+
* @returns acceptance, or the business error.
|
|
62
|
+
*/
|
|
63
|
+
cancel(): Promise<RpcResult<{
|
|
64
|
+
accepted: true;
|
|
65
|
+
}>>;
|
|
66
|
+
/**
|
|
67
|
+
* Rename this session (explicit user title; pins it against automatic
|
|
68
|
+
* regeneration).
|
|
69
|
+
* @param title - raw title text (the host normalizes acceptance).
|
|
70
|
+
* @returns the normalized accepted title and its event seq, or the business error.
|
|
71
|
+
*/
|
|
72
|
+
rename(title: string): Promise<RpcResult<{
|
|
73
|
+
title: string;
|
|
74
|
+
seq: number;
|
|
75
|
+
}>>;
|
|
76
|
+
/**
|
|
77
|
+
* Extend the history window backwards (older messages pagination).
|
|
78
|
+
* @returns completion; failures land in snapshot.openState/loadingOlder.
|
|
79
|
+
*/
|
|
80
|
+
loadOlder(): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* Execute one slash-command line against this session's agent — pure
|
|
83
|
+
* admission semantics (the host executor durably logs the lifecycle).
|
|
84
|
+
* @param line - the full command line, leading slash included.
|
|
85
|
+
* @returns the admission result, or the Remote face's error branch.
|
|
86
|
+
*/
|
|
87
|
+
command(line: string): Promise<RemoteResult<{
|
|
88
|
+
matched: boolean;
|
|
89
|
+
}>>;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The full outward face: behavior verbs plus the conversation read side
|
|
93
|
+
* (the `useSession` hook source). This is the type carried by
|
|
94
|
+
* `SessionBinding.session` and the provide channel.
|
|
95
|
+
*/
|
|
96
|
+
export type SessionFace = ISession & ObservableSnapshot<ConversationSnapshot>;
|
|
97
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-domain sessions face: the contract surface sibling domains (today:
|
|
3
|
+
* workspaces) consume instead of the sessions implementation. The sessions
|
|
4
|
+
* domain satisfies it structurally — SessionRuntime is assignable, checked
|
|
5
|
+
* wherever the assembly layer or a test injects the real service — so
|
|
6
|
+
* widening this face is the explicit act of widening the inter-domain
|
|
7
|
+
* dependency.
|
|
8
|
+
*/
|
|
9
|
+
import type { SessionId, WorkspaceId } from '@hydraharness/harness-api-remotes/client';
|
|
10
|
+
import type { ObservableSnapshot } from './store.ts';
|
|
11
|
+
/** Session-list row facts sibling domains read: recency, blank-reuse eligibility, and its cwd canon. */
|
|
12
|
+
export interface SessionsPortSummary {
|
|
13
|
+
id: SessionId;
|
|
14
|
+
/** Empty-log bit (blank sessions are reused by New Session instead of minting another). */
|
|
15
|
+
blank: boolean;
|
|
16
|
+
cwd?: string;
|
|
17
|
+
updatedAt: number;
|
|
18
|
+
}
|
|
19
|
+
/** Session-list facts sibling domains read: readiness, selection, and the row map. */
|
|
20
|
+
export interface SessionsPortList {
|
|
21
|
+
ids: SessionId[];
|
|
22
|
+
byId: Record<SessionId, SessionsPortSummary>;
|
|
23
|
+
current: SessionId | undefined;
|
|
24
|
+
phase: 'pending' | 'ready';
|
|
25
|
+
}
|
|
26
|
+
/** The sessions-service face injected into sibling domains. */
|
|
27
|
+
export interface SessionsPort {
|
|
28
|
+
/** Observable list snapshot (read face only; writes stay inside the sessions domain). */
|
|
29
|
+
readonly list: ObservableSnapshot<SessionsPortList>;
|
|
30
|
+
/**
|
|
31
|
+
* Create or explicitly adopt a session on the host.
|
|
32
|
+
* @param opts - target workspace and optional confirmed blank-reuse id.
|
|
33
|
+
* @returns the created or adopted session id.
|
|
34
|
+
*/
|
|
35
|
+
create(opts: {
|
|
36
|
+
workspaceId: WorkspaceId;
|
|
37
|
+
sessionId?: SessionId;
|
|
38
|
+
reuseWorkspaceBlank?: true;
|
|
39
|
+
/**
|
|
40
|
+
* Local list-row cwd fill for the create echo. The Host derives cwd from
|
|
41
|
+
* the Workspace and this value is not sent on the wire; New Session
|
|
42
|
+
* supplies the Workspace path so the hero composer can resolve ownership
|
|
43
|
+
* before `host/session-added` arrives.
|
|
44
|
+
*/
|
|
45
|
+
cwd?: string;
|
|
46
|
+
}): Promise<SessionId>;
|
|
47
|
+
/**
|
|
48
|
+
* Select a session as current.
|
|
49
|
+
* @param id - session id (must exist in the list store).
|
|
50
|
+
*/
|
|
51
|
+
open(id: SessionId): void;
|
|
52
|
+
/** Clear the current selection into the no-session view state. */
|
|
53
|
+
clear(): void;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=sessions-port.d.ts.map
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The outward sessions-service face — what `ctx.sessions` exposes to feature
|
|
3
|
+
* packages and the renderer host, and therefore exactly what the test
|
|
4
|
+
* runtime's sessions double must implement. Wire-pump entry points
|
|
5
|
+
* (handleMuxEnvelope/handleConnected) and runtime internals stay on the
|
|
6
|
+
* concrete class; cross-domain consumers keep the narrower
|
|
7
|
+
* [SessionsPort](./sessions-port.ts). Widening this interface is the
|
|
8
|
+
* explicit act of widening what features may do to the sessions domain.
|
|
9
|
+
*/
|
|
10
|
+
import type { Context } from '@hydraharness/cordis';
|
|
11
|
+
import type { RpcResult, SessionId, SubagentAddress } from '@hydraharness/harness-api-remotes/client';
|
|
12
|
+
import type { PromptRevisionRequest } from '@hydraharness/harness-host-apiproxy/api';
|
|
13
|
+
import type { HostObservable, SessionMaybeProvideInfo, SessionProvideInfo } from '@hydraharness/harness-client-ui-slots';
|
|
14
|
+
import type { AgentContext } from '../agents/scope.ts';
|
|
15
|
+
import type { SessionSearchResultItem } from '../sessions/manager.ts';
|
|
16
|
+
import type { SessionBinding, SessionListState, SessionProvideDescriptor } from '../sessions/service.ts';
|
|
17
|
+
import type { SessionFace } from './session.ts';
|
|
18
|
+
import type { ObservableSnapshot } from './store.ts';
|
|
19
|
+
export type { AgentContext } from '../agents/scope.ts';
|
|
20
|
+
/** The sessions-service face injected as `ctx.sessions`. */
|
|
21
|
+
export interface ISessions {
|
|
22
|
+
/** The useSessions standard feed (list rows + current selection; read face — writes stay inside the domain). */
|
|
23
|
+
readonly list: ObservableSnapshot<SessionListState>;
|
|
24
|
+
/** Atomic current-session provide projection (the renderer host's `sessions.provideInfo` feed). */
|
|
25
|
+
readonly currentProvideInfo: HostObservable<SessionMaybeProvideInfo>;
|
|
26
|
+
/** Resolve one session's render bundle without selecting it as current. */
|
|
27
|
+
provideInfo(id: string): SessionProvideInfo | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* The `session.search` result bound the wire schema fixes, exposed to
|
|
30
|
+
* presentation as injected data. Not per-connection state: every transport
|
|
31
|
+
* (fixture included) reports the same number.
|
|
32
|
+
*/
|
|
33
|
+
readonly searchResultLimit: number;
|
|
34
|
+
/** Create or adopt a session without selecting it as current. */
|
|
35
|
+
create(opts?: {
|
|
36
|
+
workspaceId?: import('@hydraharness/harness-api-remotes/client').WorkspaceId;
|
|
37
|
+
cwd?: string;
|
|
38
|
+
sessionId?: SessionId;
|
|
39
|
+
reuseWorkspaceBlank?: true;
|
|
40
|
+
}): Promise<SessionId>;
|
|
41
|
+
/** Permanently delete a session after the UI confirmation step. */
|
|
42
|
+
delete(sessionId: SessionId): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Select a session as current.
|
|
45
|
+
* @param id - session id (must exist in the list; unknown ids fail loud).
|
|
46
|
+
*/
|
|
47
|
+
open(id: SessionId): void;
|
|
48
|
+
/**
|
|
49
|
+
* Open a healthy catalog child through its exact direct-parent address.
|
|
50
|
+
* @param address - catalog-derived parent and child ids.
|
|
51
|
+
*/
|
|
52
|
+
openSubagent(address: SubagentAddress): void;
|
|
53
|
+
/**
|
|
54
|
+
* Resolve an already discovered direct-parent address without opening it.
|
|
55
|
+
* @param id - possible addressed child id.
|
|
56
|
+
* @returns the retained address, when present.
|
|
57
|
+
*/
|
|
58
|
+
subagentAddress(id: SessionId): SubagentAddress | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* Mark whether a catalog menu is consuming live membership updates.
|
|
61
|
+
* @param parentSessionId - catalog owner.
|
|
62
|
+
* @param open - current menu state.
|
|
63
|
+
*/
|
|
64
|
+
setSubagentCatalogOpen(parentSessionId: SessionId, open: boolean): void;
|
|
65
|
+
/**
|
|
66
|
+
* Refresh one direct-child catalog.
|
|
67
|
+
* @param parentSessionId - catalog owner.
|
|
68
|
+
* @returns completion of the current or newly started refresh.
|
|
69
|
+
*/
|
|
70
|
+
refreshSubagents(parentSessionId: SessionId): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Refresh the session-list baseline, reusing an in-flight pull. A page that
|
|
73
|
+
* aggregates cold list rows (Settings Usage) calls this on mount so those
|
|
74
|
+
* rows carry the Host's latest projection cut instead of the last baseline's.
|
|
75
|
+
* @returns completion of the current or newly started baseline pull.
|
|
76
|
+
*/
|
|
77
|
+
refresh(): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Record the composition one session now runs. The agent-preset seat calls
|
|
80
|
+
* this after a successful blank-session switch, so the header label moves
|
|
81
|
+
* with the composition instead of waiting for the next full list refresh.
|
|
82
|
+
* @param sessionId - the switched session.
|
|
83
|
+
* @param agentPreset - the preset id the host confirmed.
|
|
84
|
+
*/
|
|
85
|
+
noteAgentPreset(sessionId: SessionId, agentPreset: string): void;
|
|
86
|
+
/** Clear the current selection into the no-session view state. */
|
|
87
|
+
clear(): void;
|
|
88
|
+
/**
|
|
89
|
+
* Search the Host's visible message-content index. Results stay
|
|
90
|
+
* request-local; the list snapshot remains the metadata authority.
|
|
91
|
+
* @param query - non-blank literal phrase.
|
|
92
|
+
* @param signal - cancellation for a superseded search.
|
|
93
|
+
* @returns bounded results, or a business/transport error.
|
|
94
|
+
*/
|
|
95
|
+
search(query: string, signal: AbortSignal): Promise<RpcResult<{
|
|
96
|
+
items: SessionSearchResultItem[];
|
|
97
|
+
hasMore: boolean;
|
|
98
|
+
}>>;
|
|
99
|
+
/**
|
|
100
|
+
* Fork a session from a completed-turn prefix of the source; on resolution
|
|
101
|
+
* the child is in the list store and `open()` can target it.
|
|
102
|
+
* @param opts - source session id, the optional event seq anchoring the
|
|
103
|
+
* cut (the boundary is the first turn/end at or after it; an in-log
|
|
104
|
+
* anchor in an open turn is unavailable rather than clipped backward),
|
|
105
|
+
* and whether to increment an inherited durable title before resolving.
|
|
106
|
+
* `beforeSeq` excludes the selected turn-opening user message's entire turn
|
|
107
|
+
* and cannot accompany `atSeq`; the first and active turns are supported.
|
|
108
|
+
* @returns the child session id.
|
|
109
|
+
* @throws when the fork fails, or when a requested child-title rename fails after creation.
|
|
110
|
+
*/
|
|
111
|
+
fork(opts: {
|
|
112
|
+
sessionId: SessionId;
|
|
113
|
+
atSeq?: number;
|
|
114
|
+
beforeSeq?: number;
|
|
115
|
+
increaseTitle?: boolean;
|
|
116
|
+
}): Promise<SessionId>;
|
|
117
|
+
/**
|
|
118
|
+
* Admit a prompt revision or retry and make its attempt synchronously addressable.
|
|
119
|
+
* @param input - Host-validated source, workspace, edit, and stable retry key.
|
|
120
|
+
* @returns the new attempt session id; rejection leaves selection unchanged.
|
|
121
|
+
*/
|
|
122
|
+
revise(input: PromptRevisionRequest): Promise<SessionId>;
|
|
123
|
+
/**
|
|
124
|
+
* View or reference a stored path in the same session.
|
|
125
|
+
* @param sessionId - Owning session.
|
|
126
|
+
* @param versionId - Stored path.
|
|
127
|
+
* @param mode - View selection or logged reference injection.
|
|
128
|
+
* @returns Host acknowledgement and refreshed session metadata.
|
|
129
|
+
*/
|
|
130
|
+
selectVersion(sessionId: SessionId, versionId: import('@hydraharness/harness-session/types').SessionVersionId, mode?: 'view' | 'reference'): Promise<void>;
|
|
131
|
+
/**
|
|
132
|
+
* Register a per-session standard-props provider (hooks become `use<Name>`
|
|
133
|
+
* selector hooks on the render side; props spread verbatim).
|
|
134
|
+
* @param descriptor - static member roster plus per-session resolver.
|
|
135
|
+
* @returns disposer removing the provider.
|
|
136
|
+
*/
|
|
137
|
+
provide(descriptor: SessionProvideDescriptor): () => void;
|
|
138
|
+
/**
|
|
139
|
+
* Resolve an Agent-scoped context view (use-and-discard).
|
|
140
|
+
* @param id - session id.
|
|
141
|
+
* @returns scoped ctx, or undefined for a session neither listed nor already scoped.
|
|
142
|
+
*/
|
|
143
|
+
scope(id: SessionId): AgentContext | undefined;
|
|
144
|
+
/**
|
|
145
|
+
* Read the Agent scope tag off a context (service-method boundary: fetch
|
|
146
|
+
* bundles must reach scope resolution through ctx.sessions).
|
|
147
|
+
* @param ctx - any client context.
|
|
148
|
+
* @returns the session id, or undefined on root contexts.
|
|
149
|
+
*/
|
|
150
|
+
scopeOf(ctx: Context): SessionId | undefined;
|
|
151
|
+
/**
|
|
152
|
+
* Resolve the session face behind an Agent-scoped context.
|
|
153
|
+
* @param ctx - an Agent-scoped context.
|
|
154
|
+
* @returns the session face, or undefined when the ctx is untagged or its scope was pruned.
|
|
155
|
+
*/
|
|
156
|
+
sessionOf(ctx: Context): SessionFace | undefined;
|
|
157
|
+
/**
|
|
158
|
+
* Resolve the stable session binding (scope-addressed assembly feed).
|
|
159
|
+
* @param id - session id.
|
|
160
|
+
* @returns binding, or undefined for a session neither listed nor already scoped.
|
|
161
|
+
*/
|
|
162
|
+
binding(id: SessionId): SessionBinding | undefined;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=sessions.d.ts.map
|