@qilin-agent/client-ui-conversation 0.0.0-stage → 3.1.3
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.i18n.yaml +37 -0
- package/README.md +149 -2
- package/README.zh.md +150 -0
- package/lib/client.js +19198 -0
- package/lib/index.js +46 -0
- package/lib/types/client/apply.d.ts +25 -0
- package/lib/types/client/context-occupancy.d.ts +14 -0
- package/lib/types/client/contract/composer-blocks.d.ts +28 -0
- package/lib/types/client/contract/composer-submission.d.ts +8 -0
- package/lib/types/client/contract/context-producer.d.ts +29 -0
- package/lib/types/client/contract/conversation.d.ts +279 -0
- package/lib/types/client/contract/draft-editor.d.ts +102 -0
- package/lib/types/client/contract/groups.d.ts +116 -0
- package/lib/types/client/contract/input.d.ts +361 -0
- package/lib/types/client/contract/records.d.ts +301 -0
- package/lib/types/client/contract/request-inspection.d.ts +131 -0
- package/lib/types/client/contract/slots.d.ts +541 -0
- package/lib/types/client/contract/snapshot.d.ts +20 -0
- package/lib/types/client/contract/system-prompt.d.ts +35 -0
- package/lib/types/client/contract/views.d.ts +36 -0
- package/lib/types/client/conversation/assembler.d.ts +151 -0
- package/lib/types/client/conversation/assembly.d.ts +128 -0
- package/lib/types/client/conversation/definition-registry.d.ts +33 -0
- package/lib/types/client/conversation/event-registry.d.ts +40 -0
- package/lib/types/client/conversation/group-registry.d.ts +30 -0
- package/lib/types/client/conversation/group-store.d.ts +29 -0
- package/lib/types/client/conversation/historical-images.d.ts +49 -0
- package/lib/types/client/conversation/location-index.d.ts +91 -0
- package/lib/types/client/conversation/view-registry.d.ts +12 -0
- package/lib/types/client/image-labels.d.ts +23 -0
- package/lib/types/client/index.d.ts +39 -0
- package/lib/types/client/input/blocks.d.ts +27 -0
- package/lib/types/client/input/decorations.d.ts +32 -0
- package/lib/types/client/input/editor/ComposerContentEditable.d.ts +16 -0
- package/lib/types/client/input/editor/DecoratorPortals.d.ts +14 -0
- package/lib/types/client/input/editor/DraftEditor.d.ts +27 -0
- package/lib/types/client/input/editor/ReferenceChip.d.ts +17 -0
- package/lib/types/client/input/editor/chip-node.d.ts +110 -0
- package/lib/types/client/input/editor/claim-decor.d.ts +23 -0
- package/lib/types/client/input/editor/keymap.d.ts +43 -0
- package/lib/types/client/input/editor/projection.d.ts +93 -0
- package/lib/types/client/input/editor/reference-activation.d.ts +10 -0
- package/lib/types/client/input/editor/runtime.d.ts +123 -0
- package/lib/types/client/input/editor/span-map.d.ts +38 -0
- package/lib/types/client/input/editor/text-ref.d.ts +49 -0
- package/lib/types/client/input/editor/view-binding.d.ts +60 -0
- package/lib/types/client/input/facade.d.ts +303 -0
- package/lib/types/client/input/hub.d.ts +100 -0
- package/lib/types/client/input/machine.d.ts +46 -0
- package/lib/types/client/input/submission-policy.d.ts +52 -0
- package/lib/types/client/layout-policy.d.ts +42 -0
- package/lib/types/client/locales.d.ts +770 -0
- package/lib/types/client/queue/QueueDock.d.ts +27 -0
- package/lib/types/client/service.d.ts +186 -0
- package/lib/types/client/settings/ContentWidthRow.d.ts +26 -0
- package/lib/types/client/settings/EnterBehaviorRow.d.ts +21 -0
- package/lib/types/client/skeleton/ContextMeter.d.ts +14 -0
- package/lib/types/client/skeleton/ConversationContent.d.ts +8 -0
- package/lib/types/client/skeleton/ConversationHeader.d.ts +8 -0
- package/lib/types/client/skeleton/ConversationMainPanel.d.ts +3 -0
- package/lib/types/client/skeleton/ConversationPanel.d.ts +9 -0
- package/lib/types/client/skeleton/ConversationRoot.d.ts +5 -0
- package/lib/types/client/skeleton/ConversationSession.d.ts +21 -0
- package/lib/types/client/skeleton/ConversationWidthControls.d.ts +14 -0
- package/lib/types/client/skeleton/DefaultConversationViews.d.ts +9 -0
- package/lib/types/client/skeleton/EmptyHero.d.ts +49 -0
- package/lib/types/client/skeleton/InputBar.d.ts +18 -0
- package/lib/types/client/skeleton/TodoPanel.d.ts +21 -0
- package/lib/types/client/skeleton/control-row-layout.d.ts +10 -0
- package/lib/types/client/skeleton/safari.d.ts +18 -0
- package/lib/types/client/stop-sequence.d.ts +32 -0
- package/lib/types/client/stop-shortcut.d.ts +17 -0
- package/lib/types/client/stores.d.ts +24 -0
- package/lib/types/client/view-selection.d.ts +11 -0
- package/lib/types/conversation-settings.d.ts +38 -0
- package/lib/types/index.d.ts +9 -0
- package/package.json +106 -3
package/lib/index.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import z from "@qilin-agent/schemastery";
|
|
2
|
+
//#region lib/types/conversation-settings.js
|
|
3
|
+
/** Conversation preferences stored in the Host user-settings document. */
|
|
4
|
+
/** Settings namespace owned by the conversation plugin. */
|
|
5
|
+
const CONVERSATION_SETTINGS_NAMESPACE = "ui-conversation";
|
|
6
|
+
/** Field carrying the delivery mode for plain Enter while an agent is busy. */
|
|
7
|
+
const BUSY_ENTER_FIELD = "busyEnter";
|
|
8
|
+
/** Field carrying the transcript content width. */
|
|
9
|
+
const CONTENT_WIDTH_FIELD = "contentWidth";
|
|
10
|
+
/** Busy-Enter behaviors accepted at settings and input boundaries. */
|
|
11
|
+
const BUSY_ENTER_BEHAVIORS = ["queue", "steer"];
|
|
12
|
+
/** Default preserves Enter-as-Queue for running conversations. */
|
|
13
|
+
const DEFAULT_BUSY_ENTER_BEHAVIOR = "queue";
|
|
14
|
+
/**
|
|
15
|
+
* Content width that leaves the transcript to the layout's adaptive clamp
|
|
16
|
+
* (`clamp(680px, 64% of the column, 920px)`); any other value is an explicit
|
|
17
|
+
* width in px.
|
|
18
|
+
*/
|
|
19
|
+
const CONTENT_WIDTH_ADAPTIVE = 0;
|
|
20
|
+
/** Narrowest explicit content width (px); the layout center-column floor. */
|
|
21
|
+
const CONTENT_WIDTH_MIN = 640;
|
|
22
|
+
/** Widest persistable content width (px), bounding a hand-edited settings document. */
|
|
23
|
+
const CONTENT_WIDTH_MAX = 2400;
|
|
24
|
+
/** Increment one stepper click moves the content width (px). */
|
|
25
|
+
const CONTENT_WIDTH_STEP = 20;
|
|
26
|
+
/** Content width before the user picks one. */
|
|
27
|
+
const DEFAULT_CONTENT_WIDTH = 0;
|
|
28
|
+
/** Durable conversation schema; also the wire envelope the browser scope validates against. */
|
|
29
|
+
const ConversationSettingsSchema = z.object({
|
|
30
|
+
[BUSY_ENTER_FIELD]: z.union([...BUSY_ENTER_BEHAVIORS]).default(DEFAULT_BUSY_ENTER_BEHAVIOR),
|
|
31
|
+
[CONTENT_WIDTH_FIELD]: z.natural().max(CONTENT_WIDTH_MAX).default(0)
|
|
32
|
+
});
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region lib/types/index.js
|
|
35
|
+
/** Host registration for browser conversation preferences. */
|
|
36
|
+
/**
|
|
37
|
+
* Register the durable conversation section when a settings provider exists.
|
|
38
|
+
* @param ctx - Host context whose optional settings service owns the section.
|
|
39
|
+
*/
|
|
40
|
+
function apply(ctx) {
|
|
41
|
+
ctx.inject(["settings"], (settingsCtx) => {
|
|
42
|
+
settingsCtx.settings.register(CONVERSATION_SETTINGS_NAMESPACE, ConversationSettingsSchema);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { BUSY_ENTER_BEHAVIORS, BUSY_ENTER_FIELD, CONTENT_WIDTH_ADAPTIVE, CONTENT_WIDTH_FIELD, CONTENT_WIDTH_MAX, CONTENT_WIDTH_MIN, CONTENT_WIDTH_STEP, CONVERSATION_SETTINGS_NAMESPACE, DEFAULT_BUSY_ENTER_BEHAVIOR, DEFAULT_CONTENT_WIDTH, apply };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Registers the target-neutral Conversation assembly, shell, input, and docks. */
|
|
2
|
+
import type { Context } from '@qilin-agent/kylin';
|
|
3
|
+
import z from '@qilin-agent/schemastery';
|
|
4
|
+
import { type ConversationKey } from './locales.ts';
|
|
5
|
+
declare module '@qilin-agent/client-ui-slots' {
|
|
6
|
+
interface LocaleNamespaceMap {
|
|
7
|
+
/** Conversation shell, composer, queue, and dock copy. */
|
|
8
|
+
conversation: ConversationKey;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/** Services required by the Conversation plugin. */
|
|
12
|
+
export declare const inject: string[];
|
|
13
|
+
/** Conversation runtime configuration. */
|
|
14
|
+
export interface Config {
|
|
15
|
+
/** Maximum generic-file uploads allowed to run concurrently in browser Workers. */
|
|
16
|
+
maxConcurrentFileUploads?: number;
|
|
17
|
+
}
|
|
18
|
+
/** Validated Conversation runtime configuration. */
|
|
19
|
+
export declare const Config: z<Config>;
|
|
20
|
+
/**
|
|
21
|
+
* Mount the Conversation core and target-neutral presentation.
|
|
22
|
+
* @param ctx - Client root context.
|
|
23
|
+
*/
|
|
24
|
+
export declare function apply(ctx: Context, config?: Config): void;
|
|
25
|
+
//# sourceMappingURL=apply.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ContextPressureProjection } from '@qilin-agent/token-meter/client';
|
|
2
|
+
/** Context usage rendered by conversation and Chat status surfaces. */
|
|
3
|
+
export interface ContextOccupancy {
|
|
4
|
+
percent: number;
|
|
5
|
+
usedTokens: number;
|
|
6
|
+
contextWindow: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Resolve bounded display occupancy from independently updated pressure fields.
|
|
10
|
+
* @param pressure - latest token-meter projection.
|
|
11
|
+
* @returns occupancy, or null until numerator and capacity are known.
|
|
12
|
+
*/
|
|
13
|
+
export declare function contextOccupancy(pressure: ContextPressureProjection | undefined): ContextOccupancy | null;
|
|
14
|
+
//# sourceMappingURL=context-occupancy.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { SnapshotStore } from '@qilin-agent/client-store';
|
|
2
|
+
import type { SessionId } from '@qilin-agent/session/types';
|
|
3
|
+
/** Why one session's composer is inert. */
|
|
4
|
+
export interface ComposerBlock {
|
|
5
|
+
/** Localized placeholder owned by the plugin that raised the block. */
|
|
6
|
+
readonly reason: string;
|
|
7
|
+
}
|
|
8
|
+
/** The registry face other plugins reach through `ctx.conversation.blocks`. */
|
|
9
|
+
export interface ComposerBlocks {
|
|
10
|
+
/**
|
|
11
|
+
* Raise or clear this session's block.
|
|
12
|
+
* @param sessionId - Session whose composer is affected.
|
|
13
|
+
* @param block - Block to raise, or undefined to clear it.
|
|
14
|
+
*/
|
|
15
|
+
set(sessionId: SessionId, block: ComposerBlock | undefined): void;
|
|
16
|
+
/**
|
|
17
|
+
* Resolve the observable block state for one Session.
|
|
18
|
+
* @param sessionId - Session to observe.
|
|
19
|
+
* @returns Identity-stable block store.
|
|
20
|
+
*/
|
|
21
|
+
storeFor(sessionId: SessionId): SnapshotStore<ComposerBlock | undefined>;
|
|
22
|
+
/**
|
|
23
|
+
* Drop one Session's store.
|
|
24
|
+
* @param sessionId - Session being released.
|
|
25
|
+
*/
|
|
26
|
+
forget(sessionId: SessionId): void;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=composer-blocks.d.ts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Composer submission vocabulary shared by the input and settings domains. */
|
|
2
|
+
import type { BusyEnterBehavior } from '../../conversation-settings.ts';
|
|
3
|
+
export type { BusyEnterBehavior } from '../../conversation-settings.ts';
|
|
4
|
+
/** Delivery mode requested for one ordinary composer message. */
|
|
5
|
+
export type InputSubmitMode = BusyEnterBehavior;
|
|
6
|
+
/** Keyboard gesture whose delivery mode the submission policy resolves. */
|
|
7
|
+
export type ComposerSubmitGesture = 'enter' | 'accelerated';
|
|
8
|
+
//# sourceMappingURL=composer-submission.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Shared types for target-owned context-source projections. */
|
|
2
|
+
/**
|
|
3
|
+
* Which model-facing role a logged non-user message plays.
|
|
4
|
+
*
|
|
5
|
+
* `recall` marks material lifted out of another session's log; `inject` marks
|
|
6
|
+
* every other producer-supplied context. Mid-turn steering is the third role
|
|
7
|
+
* the transcript distinguishes, but it has its own event and node kind
|
|
8
|
+
* (`steering/message` / `SteeringMessageNode`) and never reaches here.
|
|
9
|
+
*/
|
|
10
|
+
export type ContextRole = 'inject' | 'recall';
|
|
11
|
+
/** Role and producer name presented for one logged non-user message. */
|
|
12
|
+
export interface ContextProducerView {
|
|
13
|
+
/** The role this context plays in the model-facing conversation. */
|
|
14
|
+
role: ContextRole;
|
|
15
|
+
/**
|
|
16
|
+
* Producer name for the row header, taken from the durable source: the
|
|
17
|
+
* instruction paths, the referenced session titles, the plugin id, or the
|
|
18
|
+
* bare source kind for a producer this UI version does not know. Null only
|
|
19
|
+
* when the source carries no readable kind at all.
|
|
20
|
+
*/
|
|
21
|
+
label: string | null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* One durable context form this UI version knows how to present. Target
|
|
25
|
+
* projections map absent or unknown forms to their opaque presentation so
|
|
26
|
+
* logs written by older, newer, or foreign producers remain visible.
|
|
27
|
+
*/
|
|
28
|
+
export type KnownContextForm = 'instructions' | 'catalog' | 'snapshot' | 'notice' | 'relay' | 'recall';
|
|
29
|
+
//# sourceMappingURL=context-producer.d.ts.map
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import type { SessionEventLike } from '@qilin-agent/api-session-controller/client';
|
|
2
|
+
import type { SessionEvent } from '@qilin-agent/session/types';
|
|
3
|
+
import type { ConversationGroupData, ConversationGroupedView, ConversationGroupInput } from './groups.ts';
|
|
4
|
+
/** Definition-local identity; start permits initialization when no earlier start is present. */
|
|
5
|
+
export interface ConversationMatchResult {
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly role: 'start' | 'update';
|
|
8
|
+
}
|
|
9
|
+
/** Merge-extensible business values published against one Turn. */
|
|
10
|
+
export interface ConversationTurnDataMap {
|
|
11
|
+
}
|
|
12
|
+
/** Merge-extensible business values published against one Step. */
|
|
13
|
+
export interface ConversationStepDataMap {
|
|
14
|
+
}
|
|
15
|
+
/** Observable value for one independently owned Location-data key. */
|
|
16
|
+
export interface ConversationLocationDataSource<Value> {
|
|
17
|
+
/** @returns the current value. */
|
|
18
|
+
readonly getSnapshot: () => Value;
|
|
19
|
+
/** @param listener - callback for value changes. @returns the unsubscribe function. */
|
|
20
|
+
readonly subscribe: (listener: () => void) => () => void;
|
|
21
|
+
}
|
|
22
|
+
/** Stable keyed reader for independently owned Location business values. */
|
|
23
|
+
export interface ConversationLocationDataStore<DataMap extends object> {
|
|
24
|
+
/**
|
|
25
|
+
* Read one business value without exposing another owner's mutable State.
|
|
26
|
+
* @param key - declaration-merged business key.
|
|
27
|
+
* @returns latest immutable value, when its owning Context has published one.
|
|
28
|
+
*/
|
|
29
|
+
get<Key extends keyof DataMap & string>(key: Key): Readonly<DataMap[Key]> | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Observe one business value without subscribing to unrelated Location keys.
|
|
32
|
+
* @param key - declaration-merged business key.
|
|
33
|
+
* @returns identity-stable source for the current value.
|
|
34
|
+
*/
|
|
35
|
+
source<Key extends keyof DataMap & string>(key: Key): ConversationLocationDataSource<Readonly<DataMap[Key]> | undefined>;
|
|
36
|
+
}
|
|
37
|
+
interface ConversationLocationDataValue {
|
|
38
|
+
readonly kind: 'turn' | 'step';
|
|
39
|
+
readonly turn: number;
|
|
40
|
+
readonly step?: number;
|
|
41
|
+
readonly key: string;
|
|
42
|
+
readonly value: unknown;
|
|
43
|
+
}
|
|
44
|
+
type RegisteredTurnData<DataMap extends object> = {
|
|
45
|
+
[Key in Extract<keyof DataMap, string>]: {
|
|
46
|
+
readonly kind: 'turn';
|
|
47
|
+
readonly turn: number;
|
|
48
|
+
readonly key: Key;
|
|
49
|
+
readonly value: DataMap[Key];
|
|
50
|
+
};
|
|
51
|
+
}[Extract<keyof DataMap, string>];
|
|
52
|
+
type RegisteredStepData<DataMap extends object> = {
|
|
53
|
+
[Key in Extract<keyof DataMap, string>]: {
|
|
54
|
+
readonly kind: 'step';
|
|
55
|
+
readonly turn: number;
|
|
56
|
+
readonly step: number;
|
|
57
|
+
readonly key: Key;
|
|
58
|
+
readonly value: DataMap[Key];
|
|
59
|
+
};
|
|
60
|
+
}[Extract<keyof DataMap, string>];
|
|
61
|
+
type ConversationLocationDataOf<TurnData extends object, StepData extends object> = [
|
|
62
|
+
keyof TurnData | keyof StepData
|
|
63
|
+
] extends [never] ? ConversationLocationDataValue : RegisteredTurnData<TurnData> | RegisteredStepData<StepData>;
|
|
64
|
+
/** One Definition-owned value attached to an Engine-owned Turn or Step. */
|
|
65
|
+
export type ConversationLocationData = ConversationLocationDataOf<ConversationTurnDataMap, ConversationStepDataMap>;
|
|
66
|
+
/** Immutable resolved boundary for one Agent step. */
|
|
67
|
+
export interface StepLocation {
|
|
68
|
+
readonly turn: number;
|
|
69
|
+
readonly step: number;
|
|
70
|
+
readonly start: SessionEvent<'step/start'> | undefined;
|
|
71
|
+
readonly end: SessionEvent<'step/end'> | undefined;
|
|
72
|
+
readonly status: 'open' | 'closed' | 'unknown';
|
|
73
|
+
/** Stable reader for Step-scoped business values. */
|
|
74
|
+
readonly data: ConversationLocationDataStore<ConversationStepDataMap>;
|
|
75
|
+
}
|
|
76
|
+
/** Immutable resolved boundary for one Agent turn. */
|
|
77
|
+
export interface TurnLocation {
|
|
78
|
+
readonly turn: number;
|
|
79
|
+
readonly start: SessionEvent<'turn/start'> | undefined;
|
|
80
|
+
readonly end: SessionEvent<'turn/end'> | undefined;
|
|
81
|
+
readonly status: 'open' | 'closed' | 'unknown';
|
|
82
|
+
readonly steps: readonly StepLocation[];
|
|
83
|
+
/** Stable reader for Turn-scoped business values. */
|
|
84
|
+
readonly data: ConversationLocationDataStore<ConversationTurnDataMap>;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Extract a stable business identity using only the current event.
|
|
88
|
+
* @param event - durable or transient Client event.
|
|
89
|
+
* @returns identity and lifecycle role, or null when unrelated.
|
|
90
|
+
*/
|
|
91
|
+
export type ConversationMatchHandler = (event: SessionEventLike) => ConversationMatchResult | null;
|
|
92
|
+
/** Registration accepts a function or an immutable table of own event-type handlers. */
|
|
93
|
+
export type ConversationNodeDefinitionInput<State = unknown> = Omit<ConversationNodeDefinition<State>, 'match'> & {
|
|
94
|
+
readonly match: ConversationMatchHandler | Readonly<Record<string, ConversationMatchHandler>>;
|
|
95
|
+
};
|
|
96
|
+
/** Engine-owned placement of one matched event in the Session hierarchy. */
|
|
97
|
+
export type ConversationLocation = {
|
|
98
|
+
readonly kind: 'session';
|
|
99
|
+
} | {
|
|
100
|
+
readonly kind: 'turn';
|
|
101
|
+
readonly turn: TurnLocation;
|
|
102
|
+
} | {
|
|
103
|
+
readonly kind: 'step';
|
|
104
|
+
readonly turn: TurnLocation;
|
|
105
|
+
readonly step: StepLocation;
|
|
106
|
+
} | {
|
|
107
|
+
readonly kind: 'unresolved';
|
|
108
|
+
};
|
|
109
|
+
interface ConversationMatchOf<Event extends SessionEventLike, Role extends ConversationMatchResult['role']> {
|
|
110
|
+
readonly event: Event;
|
|
111
|
+
readonly role: Role;
|
|
112
|
+
readonly location: ConversationLocation;
|
|
113
|
+
}
|
|
114
|
+
/** A durable or transient event that can initialize its Context. */
|
|
115
|
+
export type ConversationStartMatch = ConversationMatchOf<SessionEventLike, 'start'>;
|
|
116
|
+
/** One event accepted by a Definition, with its lifecycle role and resolved Location. */
|
|
117
|
+
export type ConversationMatch = ConversationStartMatch | ConversationMatchOf<SessionEventLike, 'update'>;
|
|
118
|
+
/** Target-neutral identity returned by a business Definition. */
|
|
119
|
+
export interface ConversationViewNode {
|
|
120
|
+
readonly key: string;
|
|
121
|
+
readonly kind: string;
|
|
122
|
+
readonly id: string;
|
|
123
|
+
readonly target: string;
|
|
124
|
+
readonly data: unknown;
|
|
125
|
+
}
|
|
126
|
+
/** Merge-extensible immutable snapshots published by registered view targets. */
|
|
127
|
+
export interface ConversationViewSnapshotMap {
|
|
128
|
+
}
|
|
129
|
+
/** Stable reader over the latest snapshot of every registered view target. */
|
|
130
|
+
export interface ConversationViewSnapshotStore {
|
|
131
|
+
/** @param target - registered view target. @returns its current snapshot. */
|
|
132
|
+
get<Target extends Extract<keyof ConversationViewSnapshotMap, string>>(target: Target): ConversationViewSnapshotMap[Target] | undefined;
|
|
133
|
+
/**
|
|
134
|
+
* Read grouping for an activated target without activating another target.
|
|
135
|
+
* @param target - registered View target.
|
|
136
|
+
* @returns its grouped reader, when a Group Definition is active.
|
|
137
|
+
*/
|
|
138
|
+
grouped<Target extends string>(target: Target): ConversationGroupedView<ConversationGroupData<Target>> | undefined;
|
|
139
|
+
}
|
|
140
|
+
/** Immutable public view of an assembled business Context. */
|
|
141
|
+
export interface ConversationNodeContext<State = unknown> {
|
|
142
|
+
readonly key: string;
|
|
143
|
+
readonly kind: string;
|
|
144
|
+
readonly id: string;
|
|
145
|
+
readonly matches: readonly ConversationMatch[];
|
|
146
|
+
readonly start: ConversationStartMatch | undefined;
|
|
147
|
+
readonly state: State | undefined;
|
|
148
|
+
readonly current: ReadonlyMap<string, ConversationViewNode | null>;
|
|
149
|
+
}
|
|
150
|
+
/** Read-only predecessor returned to a Definition's start function. */
|
|
151
|
+
export interface ConversationPreviousContext<State = unknown> {
|
|
152
|
+
readonly key: string;
|
|
153
|
+
readonly kind: string;
|
|
154
|
+
readonly id: string;
|
|
155
|
+
readonly startSeq: number;
|
|
156
|
+
readonly state: Readonly<State>;
|
|
157
|
+
readonly matches: readonly ConversationMatch[];
|
|
158
|
+
}
|
|
159
|
+
/** Strictly-backward Context lookup available while a start is evaluated. */
|
|
160
|
+
export interface ConversationContextReader {
|
|
161
|
+
/**
|
|
162
|
+
* Find the active Context of `kind` with the greatest start seq below the
|
|
163
|
+
* current start event.
|
|
164
|
+
* @param kind - Definition kind to query.
|
|
165
|
+
* @returns the nearest predecessor, or undefined when absent in the current window.
|
|
166
|
+
*/
|
|
167
|
+
previous<State>(kind: string): ConversationPreviousContext<State> | undefined;
|
|
168
|
+
}
|
|
169
|
+
/** Requested cadence; `animation-frame` materializes after three browser animation frames. */
|
|
170
|
+
export type ConversationPublication = 'none' | 'animation-frame' | 'immediate';
|
|
171
|
+
/** Engine-owned Location data publication phase. */
|
|
172
|
+
export type ConversationLocationDataScope = 'step' | 'turn';
|
|
173
|
+
/** One independently registered business Event-to-Node state machine. */
|
|
174
|
+
export interface ConversationNodeDefinition<State = unknown> {
|
|
175
|
+
readonly kind: string;
|
|
176
|
+
/** Sole view target owned by this Definition; omitted for state-only Contexts. */
|
|
177
|
+
readonly target?: string;
|
|
178
|
+
/**
|
|
179
|
+
* Extract this Definition's stable business identity from one event.
|
|
180
|
+
* @param event - standard or compact Client history event; no Context or history access is available.
|
|
181
|
+
* @returns identity and lifecycle role, or null when unrelated.
|
|
182
|
+
*/
|
|
183
|
+
match(event: SessionEventLike): ConversationMatchResult | null;
|
|
184
|
+
/**
|
|
185
|
+
* Create State from the earliest currently loaded start Match.
|
|
186
|
+
* @param context - complete evidence currently collected for the Context.
|
|
187
|
+
* @param match - the start Match.
|
|
188
|
+
* @param reader - strictly-backward read-only Context lookup.
|
|
189
|
+
* @returns the State adopted by the engine.
|
|
190
|
+
*/
|
|
191
|
+
start(context: ConversationNodeContext<State>, match: ConversationStartMatch, reader: ConversationContextReader): State;
|
|
192
|
+
/**
|
|
193
|
+
* Apply a later Match, including another event marked start.
|
|
194
|
+
* @param context - Context with its current State.
|
|
195
|
+
* @param match - subsequent Match in ascending event order.
|
|
196
|
+
* @returns the State adopted by the engine.
|
|
197
|
+
*/
|
|
198
|
+
update(context: ConversationNodeContext<State> & {
|
|
199
|
+
readonly state: State;
|
|
200
|
+
}, match: ConversationMatch): State;
|
|
201
|
+
/**
|
|
202
|
+
* Select publication cadence for one accepted Match.
|
|
203
|
+
* @param match - accepted Match.
|
|
204
|
+
* @returns requested cadence; omission defaults to immediate.
|
|
205
|
+
*/
|
|
206
|
+
publication?(match: ConversationMatch): ConversationPublication;
|
|
207
|
+
/**
|
|
208
|
+
* Publish this Definition's read-only business value for one Location phase.
|
|
209
|
+
* The Engine evaluates every Definition first for Step and then for Turn,
|
|
210
|
+
* owns replacement/removal, and rejects another Context trying to publish
|
|
211
|
+
* the same Location key.
|
|
212
|
+
* @param context - latest complete Context.
|
|
213
|
+
* @param scope - Location hierarchy level currently being materialized.
|
|
214
|
+
* @param previous - value from the preceding materialization; return it when unchanged.
|
|
215
|
+
* @returns current Location value, preserving value identity while unchanged,
|
|
216
|
+
* or null while unavailable.
|
|
217
|
+
*/
|
|
218
|
+
buildLocationData?(context: ConversationNodeContext<State>, scope: ConversationLocationDataScope, previous: ConversationLocationData | null): ConversationLocationData | null;
|
|
219
|
+
/**
|
|
220
|
+
* Materialize one final Node for this Definition's declared view target.
|
|
221
|
+
* @param context - latest complete Context.
|
|
222
|
+
* @returns final Node, or null when this Context is not currently visible.
|
|
223
|
+
*/
|
|
224
|
+
buildViewNode?(context: ConversationNodeContext<State>): ConversationViewNode | null;
|
|
225
|
+
}
|
|
226
|
+
/** Reference-stable Turn/Step facts published beside view Nodes. */
|
|
227
|
+
export interface ConversationTimelineSnapshot {
|
|
228
|
+
readonly turnOrder: readonly number[];
|
|
229
|
+
readonly turns: ReadonlyMap<number, TurnLocation>;
|
|
230
|
+
}
|
|
231
|
+
/** Per-Session incremental builder for one view target. */
|
|
232
|
+
export interface ConversationViewBuilder<Node extends ConversationViewNode = ConversationViewNode, Snapshot = unknown> {
|
|
233
|
+
readonly empty: Snapshot;
|
|
234
|
+
/**
|
|
235
|
+
* Replace the low-frequency complete materialized Node set.
|
|
236
|
+
* @param input - complete Nodes and current timeline.
|
|
237
|
+
* @returns next view snapshot.
|
|
238
|
+
*/
|
|
239
|
+
replace(input: {
|
|
240
|
+
readonly nodes: readonly Node[];
|
|
241
|
+
readonly timeline: ConversationTimelineSnapshot;
|
|
242
|
+
readonly changedTurns?: readonly number[];
|
|
243
|
+
}): Snapshot;
|
|
244
|
+
/**
|
|
245
|
+
* Apply only Nodes whose materialized values changed in this transaction.
|
|
246
|
+
* @param input - changed Nodes and current timeline.
|
|
247
|
+
* @returns next view snapshot.
|
|
248
|
+
*/
|
|
249
|
+
apply(input: {
|
|
250
|
+
readonly upserts: readonly Node[];
|
|
251
|
+
readonly timeline: ConversationTimelineSnapshot;
|
|
252
|
+
readonly changedTurns?: readonly number[];
|
|
253
|
+
}): Snapshot;
|
|
254
|
+
/** @returns the latest target-processed Node inputs; required only for a grouped target. */
|
|
255
|
+
groupInput?(): ConversationGroupInput<Node>;
|
|
256
|
+
/** Publish local sources after all target snapshots and grouping results have been installed. */
|
|
257
|
+
publish?(): void;
|
|
258
|
+
}
|
|
259
|
+
/** Registry contribution that creates an isolated builder when a Session first uses this target. */
|
|
260
|
+
export interface ConversationViewDefinition<Node extends ConversationViewNode = ConversationViewNode, Snapshot = unknown> {
|
|
261
|
+
readonly target: string;
|
|
262
|
+
/** @returns a new Session-owned incremental builder. */
|
|
263
|
+
create(): ConversationViewBuilder<Node, Snapshot>;
|
|
264
|
+
/**
|
|
265
|
+
* Decide whether this target contributes visible Conversation activity.
|
|
266
|
+
* @param snapshot - latest target-owned snapshot.
|
|
267
|
+
* @returns whether the shell should treat this target as active.
|
|
268
|
+
*/
|
|
269
|
+
isActive?(snapshot: Snapshot): boolean;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Build a stable collision-free key for one Definition-local business identity.
|
|
273
|
+
* @param kind - Definition kind.
|
|
274
|
+
* @param id - Definition-local business identity.
|
|
275
|
+
* @returns engine-owned Context key.
|
|
276
|
+
*/
|
|
277
|
+
export declare function conversationContextKey(kind: string, id: string): string;
|
|
278
|
+
export {};
|
|
279
|
+
//# sourceMappingURL=conversation.d.ts.map
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/** Editor-facing ranges, reference projections, and the composer keyboard interface. */
|
|
2
|
+
import type { LexicalEditor } from 'lexical';
|
|
3
|
+
import type { InputState } from './input.ts';
|
|
4
|
+
import type { InputSubmitMode } from './composer-submission.ts';
|
|
5
|
+
/** Pick-time draft span guarded by the input revision. */
|
|
6
|
+
export interface TokenSpan {
|
|
7
|
+
readonly start: number;
|
|
8
|
+
readonly end: number;
|
|
9
|
+
readonly draftRev: number;
|
|
10
|
+
}
|
|
11
|
+
/** Structured reference inserted by an input-trigger source. */
|
|
12
|
+
export interface ReferenceInsert {
|
|
13
|
+
readonly source: string;
|
|
14
|
+
readonly ref: string;
|
|
15
|
+
readonly label: string;
|
|
16
|
+
readonly appearance?: 'session' | 'file' | 'folder';
|
|
17
|
+
readonly clipboardText: string;
|
|
18
|
+
}
|
|
19
|
+
/** Keyboard keys intercepted by an open trigger menu. */
|
|
20
|
+
export type ArbitrateKey = 'up' | 'down' | 'enter' | 'escape' | 'tab' | 'tabBack';
|
|
21
|
+
/** Trigger-menu keyboard routing result. */
|
|
22
|
+
export type ArbitrateOutcome = 'consumed' | 'pick-highlighted' | 'pass';
|
|
23
|
+
/**
|
|
24
|
+
* The InputBar-exclusive keyboard/DOM command face: synchronous
|
|
25
|
+
* returns and event-handler semantics that must not enter the public provide
|
|
26
|
+
* channel. Handed to the composer-bar entry through its own inject —
|
|
27
|
+
* package-internal, never across a plugin boundary. The session shell
|
|
28
|
+
* satisfies it structurally. Text editing itself rides the shell's Lexical
|
|
29
|
+
* editor (exposed here for the contenteditable binding); the members below
|
|
30
|
+
* are the submit-plane and trigger-pipeline verbs the editor does not own.
|
|
31
|
+
*/
|
|
32
|
+
export interface ComposerKeyboard {
|
|
33
|
+
/** Live machine state for event-handler reads (render reads go through useInput). */
|
|
34
|
+
readonly snapshot: InputState;
|
|
35
|
+
/** The shell-owned Lexical editor the composer binds its contenteditable to. */
|
|
36
|
+
readonly editor: LexicalEditor;
|
|
37
|
+
/** Submit with an explicit delivery mode resolved by the submission policy (Enter gestures and the primary Send button). */
|
|
38
|
+
submit(mode: InputSubmitMode): void;
|
|
39
|
+
/**
|
|
40
|
+
* Steer every still-pending queued message into the running turn (the
|
|
41
|
+
* empty-draft accelerated-Enter gesture; the queue dock's per-row steer
|
|
42
|
+
* button is the same operation applied to the whole queue).
|
|
43
|
+
*/
|
|
44
|
+
steerQueue(): void;
|
|
45
|
+
/** Insert pasted plain text over the current editor selection (reference-placeholder-sanitized). */
|
|
46
|
+
paste(text: string): void;
|
|
47
|
+
/**
|
|
48
|
+
* The live selection as a detect-coordinate span (menu-launcher synthetic
|
|
49
|
+
* hits replace it on pick); an absent selection answers a collapsed span at
|
|
50
|
+
* the document end.
|
|
51
|
+
*/
|
|
52
|
+
caretSpan(): EditSelection;
|
|
53
|
+
/** Keyboard arbitration while the menu is open ('pass' when no pipeline). */
|
|
54
|
+
arbitrate(key: ArbitrateKey, composing: boolean): ArbitrateOutcome;
|
|
55
|
+
/** Space adjudication; true = the input applied a claim — caller preventDefaults. */
|
|
56
|
+
space(): boolean;
|
|
57
|
+
/** Dismiss the popupSelect shell (any interaction outside the box). */
|
|
58
|
+
dismissPopup(): void;
|
|
59
|
+
/**
|
|
60
|
+
* Bind the mounted composer's file action and live intake availability.
|
|
61
|
+
* @param picker - availability query and native file-dialog opener.
|
|
62
|
+
* @returns the unbind disposer.
|
|
63
|
+
*/
|
|
64
|
+
bindFilePicker(picker: {
|
|
65
|
+
available(): boolean;
|
|
66
|
+
open(): void;
|
|
67
|
+
}): () => void;
|
|
68
|
+
}
|
|
69
|
+
/** Half-open [start, end) range/selection in detect-projection coordinates. */
|
|
70
|
+
export interface EditSelection {
|
|
71
|
+
readonly start: number;
|
|
72
|
+
readonly end: number;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* One reference occurrence projected from the editor's chip nodes, in
|
|
76
|
+
* clipboard-text coordinates. Identity is occurrenceId — a stable per-shell
|
|
77
|
+
* assignment per chip NodeKey, so same-named references stay independently
|
|
78
|
+
* addressable and survive undo. label/appearance/clipboardText are the
|
|
79
|
+
* owner's insert-time projections cached on the node (invalid flips instead
|
|
80
|
+
* of dropping the occurrence).
|
|
81
|
+
*/
|
|
82
|
+
export interface Occurrence {
|
|
83
|
+
/** Shell-assigned stable identity (monotonic per shell, keyed by NodeKey). */
|
|
84
|
+
readonly occurrenceId: number;
|
|
85
|
+
/** Owning source name (serializer routing key). */
|
|
86
|
+
readonly source: string;
|
|
87
|
+
/** Owner-scoped reference id. */
|
|
88
|
+
readonly ref: string;
|
|
89
|
+
/** Offset in the clipboard-text projection. */
|
|
90
|
+
readonly offset: number;
|
|
91
|
+
/** Length in the clipboard-text projection; the occurrence occupies exactly [offset, offset+length). */
|
|
92
|
+
readonly length: number;
|
|
93
|
+
/** Inline display label (insert-time cache). */
|
|
94
|
+
readonly label: string;
|
|
95
|
+
/** Optional domain glyph (insert-time cache). */
|
|
96
|
+
readonly appearance?: ReferenceInsert['appearance'];
|
|
97
|
+
/** Clipboard / persistence projection, e.g. `/name` (insert-time cache, never the model form). */
|
|
98
|
+
readonly clipboardText: string;
|
|
99
|
+
/** Owner-resolution failure flag: the chip renders the failure treatment. */
|
|
100
|
+
readonly invalid?: boolean;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=draft-editor.d.ts.map
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/** Definition-owned grouping over a target's already materialized Nodes. */
|
|
2
|
+
import type { Branded } from '@qilin-agent/brand';
|
|
3
|
+
import type { ObservableSnapshot } from '@qilin-agent/client-store';
|
|
4
|
+
import type { ConversationTimelineSnapshot, ConversationViewNode } from './conversation.ts';
|
|
5
|
+
/** Existing Node identity, without allocating another execution Node. */
|
|
6
|
+
export type NodeKey = Branded<'ConversationNodeKey'>;
|
|
7
|
+
/** Definition-local group identity within one Session and target. */
|
|
8
|
+
export type GroupKey = Branded<'ConversationGroupKey'>;
|
|
9
|
+
/** One whole Node or a renderer-owned part of that Node. */
|
|
10
|
+
export interface NodeReference {
|
|
11
|
+
readonly kind: 'node';
|
|
12
|
+
readonly key: NodeKey;
|
|
13
|
+
readonly groupPart?: string;
|
|
14
|
+
}
|
|
15
|
+
/** Root-list reference to a separately observed group. */
|
|
16
|
+
export interface GroupReference {
|
|
17
|
+
readonly kind: 'group';
|
|
18
|
+
readonly key: GroupKey;
|
|
19
|
+
}
|
|
20
|
+
/** The two supported root rendering positions. */
|
|
21
|
+
export type RenderEntry = NodeReference | GroupReference;
|
|
22
|
+
/** Immutable group data and its ordered, non-nested Node references. */
|
|
23
|
+
export interface GroupSnapshot<Data> {
|
|
24
|
+
readonly key: GroupKey;
|
|
25
|
+
readonly data: Data;
|
|
26
|
+
readonly members: readonly NodeReference[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* One atomic grouping update. Replacement input requires entries and a complete
|
|
30
|
+
* group replacement; apply input may omit entries to preserve the root list.
|
|
31
|
+
* Group removal never deletes source Nodes.
|
|
32
|
+
*/
|
|
33
|
+
export interface GroupUpdate<Data> {
|
|
34
|
+
/** Complete root sequence; only its Node references and referenced group members render. */
|
|
35
|
+
readonly entries?: readonly RenderEntry[];
|
|
36
|
+
readonly groups: {
|
|
37
|
+
readonly kind: 'replace';
|
|
38
|
+
readonly snapshots: readonly GroupSnapshot<Data>[];
|
|
39
|
+
} | {
|
|
40
|
+
readonly kind: 'apply';
|
|
41
|
+
readonly upserts: readonly GroupSnapshot<Data>[];
|
|
42
|
+
readonly removes: readonly GroupKey[];
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** Target-processed Node values before and after one update. */
|
|
46
|
+
export interface NodeChange<Node> {
|
|
47
|
+
readonly previous: Node | undefined;
|
|
48
|
+
readonly current: Node;
|
|
49
|
+
}
|
|
50
|
+
/** Owning Turn and immediate neighbours in the target's visible Node order. */
|
|
51
|
+
export interface GroupNodePosition {
|
|
52
|
+
readonly turn: number | undefined;
|
|
53
|
+
readonly previous: NodeKey | undefined;
|
|
54
|
+
readonly next: NodeKey | undefined;
|
|
55
|
+
}
|
|
56
|
+
interface GroupInputNodes<Node> {
|
|
57
|
+
readonly order: readonly NodeKey[];
|
|
58
|
+
/** @param key - target Node identity. @returns its current value during this synchronous update. */
|
|
59
|
+
readonly readNode: (key: NodeKey) => Node | undefined;
|
|
60
|
+
/** @param turn - owning Turn. @returns its visible keys in target order; empty when absent. */
|
|
61
|
+
readonly readTurn: (turn: number) => readonly NodeKey[];
|
|
62
|
+
/** @param key - target Node identity. @returns its visible position, or absence outside the target order. */
|
|
63
|
+
readonly readPosition: (key: NodeKey) => GroupNodePosition | undefined;
|
|
64
|
+
readonly timeline: ConversationTimelineSnapshot;
|
|
65
|
+
}
|
|
66
|
+
/** Target-local inputs; apply includes lifecycle changes without Node upserts. */
|
|
67
|
+
export type ConversationGroupInput<Node> = GroupInputNodes<Node> & ({
|
|
68
|
+
readonly kind: 'replace';
|
|
69
|
+
} | {
|
|
70
|
+
readonly kind: 'apply';
|
|
71
|
+
readonly changes: readonly NodeChange<Node>[];
|
|
72
|
+
readonly changedTurns: readonly number[];
|
|
73
|
+
/** Turns whose visible keys or immediate neighbours changed, including removal and cross-Turn moves. */
|
|
74
|
+
readonly changedTurnOrders: readonly number[];
|
|
75
|
+
});
|
|
76
|
+
/** Framework-owned State for one Session's registered Group Definition. */
|
|
77
|
+
export interface ConversationGroupContext<State> {
|
|
78
|
+
readonly state: State;
|
|
79
|
+
}
|
|
80
|
+
/** Business grouping rules, driven after the target Builder has installed Nodes. */
|
|
81
|
+
export interface ConversationGroupDefinition<Node extends ConversationViewNode = ConversationViewNode, State = unknown, Data = unknown> {
|
|
82
|
+
readonly kind: string;
|
|
83
|
+
readonly target: string;
|
|
84
|
+
/** @returns initial Session-local grouping State. */
|
|
85
|
+
create(): State;
|
|
86
|
+
/**
|
|
87
|
+
* Consume target Node changes, not raw Session events or presentation modes.
|
|
88
|
+
* @param context - current Session-local State.
|
|
89
|
+
* @param input - current target inputs; its readers are valid only during this call.
|
|
90
|
+
* @returns State adopted by the framework.
|
|
91
|
+
*/
|
|
92
|
+
update(context: ConversationGroupContext<State>, input: ConversationGroupInput<Node>): State;
|
|
93
|
+
/**
|
|
94
|
+
* Materialize pending grouping changes without changing the business State.
|
|
95
|
+
* @param context - State adopted after update.
|
|
96
|
+
* @returns complete output for replace input; an update or null when unchanged for apply input.
|
|
97
|
+
*/
|
|
98
|
+
buildGroups(context: ConversationGroupContext<State>): GroupUpdate<Data> | null;
|
|
99
|
+
}
|
|
100
|
+
/** Merge-extensible group data associated with each registered target. */
|
|
101
|
+
export interface ConversationGroupDataMap {
|
|
102
|
+
}
|
|
103
|
+
/** Group data declared by a target; undeclared targets have no group payload. */
|
|
104
|
+
export type ConversationGroupData<Target extends string> = Target extends keyof ConversationGroupDataMap ? ConversationGroupDataMap[Target] : never;
|
|
105
|
+
/** Stable grouped reader; data-only updates preserve entries and member arrays. */
|
|
106
|
+
export interface ConversationGroupedView<Data> {
|
|
107
|
+
readonly entries: readonly RenderEntry[];
|
|
108
|
+
/**
|
|
109
|
+
* Observe a group without subscribing to the root sequence.
|
|
110
|
+
* @param key - group identity within this target.
|
|
111
|
+
* @returns an identity-stable source, whose value is absent after removal.
|
|
112
|
+
*/
|
|
113
|
+
groupSource(key: GroupKey): ObservableSnapshot<GroupSnapshot<Data> | undefined>;
|
|
114
|
+
}
|
|
115
|
+
export {};
|
|
116
|
+
//# sourceMappingURL=groups.d.ts.map
|