@turingfocus/chat-runtime 0.1.0
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/dist/chat-client.d.ts +34 -0
- package/dist/chat-client.d.ts.map +1 -0
- package/dist/chat-client.js +502 -0
- package/dist/chat-client.js.map +1 -0
- package/dist/gateway-notification-queue.d.ts +17 -0
- package/dist/gateway-notification-queue.d.ts.map +1 -0
- package/dist/gateway-notification-queue.js +31 -0
- package/dist/gateway-notification-queue.js.map +1 -0
- package/dist/immutable.d.ts +4 -0
- package/dist/immutable.d.ts.map +1 -0
- package/dist/immutable.js +53 -0
- package/dist/immutable.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/snapshot-state.d.ts +20 -0
- package/dist/snapshot-state.d.ts.map +1 -0
- package/dist/snapshot-state.js +238 -0
- package/dist/snapshot-state.js.map +1 -0
- package/dist/snapshot-store.d.ts +22 -0
- package/dist/snapshot-store.d.ts.map +1 -0
- package/dist/snapshot-store.js +99 -0
- package/dist/snapshot-store.js.map +1 -0
- package/dist/timeline.d.ts +22 -0
- package/dist/timeline.d.ts.map +1 -0
- package/dist/timeline.js +130 -0
- package/dist/timeline.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway-notification-queue.js","sourceRoot":"","sources":["../src/gateway-notification-queue.ts"],"names":[],"mappings":"AAgBA,qFAAqF;AACrF,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAC5C,QAAuC,EACb,EAAE;IAC5B,MAAM,OAAO,GAA0B,EAAE,CAAC;IAC1C,IAAI,UAA8B,CAAC;IACnC,IAAI,KAAK,GAAwC,WAAW,CAAC;IAE7D,MAAM,cAAc,GAAG,CAAC,YAAiC,EAAQ,EAAE;QACjE,IAAI,UAAU,KAAK,SAAS;YAAE,QAAQ,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IACnE,CAAC,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,CAAC,YAAY,EAAE,EAAE;YACxB,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;gBACvB,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAC3B,OAAO;YACT,CAAC;YACD,cAAc,CAAC,YAAY,CAAC,CAAC;QAC/B,CAAC;QACD,QAAQ,EAAE,CAAC,gBAAgB,EAAE,EAAE;YAC7B,IAAI,KAAK,KAAK,WAAW;gBAAE,OAAO;YAClC,UAAU,GAAG,gBAAgB,CAAC;YAC9B,KAAK,GAAG,UAAU,CAAC;YACnB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;gBACvD,cAAc,CAAC,OAAO,CAAC,KAAK,CAAE,CAAC,CAAC;YAClC,CAAC;YACD,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;YACnB,KAAK,GAAG,QAAQ,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"immutable.d.ts","sourceRoot":"","sources":["../src/immutable.ts"],"names":[],"mappings":"AA0BA,gFAAgF;AAChF,eAAO,MAAM,cAAc,GAAI,CAAC,EAAE,OAAO,CAAC,KAAG,CACM,CAAC;AAEpD,eAAO,MAAM,SAAS,GAAI,MAAM,OAAO,EAAE,OAAO,OAAO,KAAG,OA4BzD,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const cloneValue = (value, seen) => {
|
|
2
|
+
if (value === null || typeof value !== "object")
|
|
3
|
+
return value;
|
|
4
|
+
const existing = seen.get(value);
|
|
5
|
+
if (existing !== undefined)
|
|
6
|
+
return existing;
|
|
7
|
+
if (Array.isArray(value)) {
|
|
8
|
+
const clone = [];
|
|
9
|
+
seen.set(value, clone);
|
|
10
|
+
for (const entry of value)
|
|
11
|
+
clone.push(cloneValue(entry, seen));
|
|
12
|
+
return Object.freeze(clone);
|
|
13
|
+
}
|
|
14
|
+
const clone = {};
|
|
15
|
+
seen.set(value, clone);
|
|
16
|
+
for (const key of Object.keys(value)) {
|
|
17
|
+
Object.defineProperty(clone, key, {
|
|
18
|
+
configurable: true,
|
|
19
|
+
enumerable: true,
|
|
20
|
+
value: cloneValue(value[key], seen),
|
|
21
|
+
writable: true,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return Object.freeze(clone);
|
|
25
|
+
};
|
|
26
|
+
/** Clone normalized Protocol data and freeze every exposed object and array. */
|
|
27
|
+
export const cloneImmutable = (value) => cloneValue(value, new WeakMap());
|
|
28
|
+
export const deepEqual = (left, right) => {
|
|
29
|
+
if (Object.is(left, right))
|
|
30
|
+
return true;
|
|
31
|
+
if (left === null ||
|
|
32
|
+
right === null ||
|
|
33
|
+
typeof left !== "object" ||
|
|
34
|
+
typeof right !== "object") {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
38
|
+
if (!Array.isArray(left) || !Array.isArray(right))
|
|
39
|
+
return false;
|
|
40
|
+
if (left.length !== right.length)
|
|
41
|
+
return false;
|
|
42
|
+
return left.every((entry, index) => deepEqual(entry, right[index]));
|
|
43
|
+
}
|
|
44
|
+
const leftRecord = left;
|
|
45
|
+
const rightRecord = right;
|
|
46
|
+
const leftKeys = Object.keys(leftRecord);
|
|
47
|
+
const rightKeys = Object.keys(rightRecord);
|
|
48
|
+
if (leftKeys.length !== rightKeys.length)
|
|
49
|
+
return false;
|
|
50
|
+
return leftKeys.every((key) => Object.prototype.hasOwnProperty.call(rightRecord, key) &&
|
|
51
|
+
deepEqual(leftRecord[key], rightRecord[key]));
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=immutable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"immutable.js","sourceRoot":"","sources":["../src/immutable.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,GAAG,CAAI,KAAQ,EAAE,IAA8B,EAAK,EAAE;IACpE,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAE9D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACjC,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,QAAa,CAAC;IAEjD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,KAAK,GAAc,EAAE,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACvB,KAAK,MAAM,KAAK,IAAI,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;QAC/D,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAM,CAAC;IACnC,CAAC;IAED,MAAM,KAAK,GAA4B,EAAE,CAAC;IAC1C,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACvB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE;YAChC,YAAY,EAAE,IAAI;YAClB,UAAU,EAAE,IAAI;YAChB,KAAK,EAAE,UAAU,CAAE,KAAiC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;YAChE,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAM,CAAC;AACnC,CAAC,CAAC;AAEF,gFAAgF;AAChF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAI,KAAQ,EAAK,EAAE,CAC/C,UAAU,CAAC,KAAK,EAAE,IAAI,OAAO,EAAmB,CAAC,CAAC;AAEpD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAa,EAAE,KAAc,EAAW,EAAE;IAClE,IAAI,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,IACE,IAAI,KAAK,IAAI;QACb,KAAK,KAAK,IAAI;QACd,OAAO,IAAI,KAAK,QAAQ;QACxB,OAAO,KAAK,KAAK,QAAQ,EACzB,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAChD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAChE,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,UAAU,GAAG,IAA+B,CAAC;IACnD,MAAM,WAAW,GAAG,KAAgC,CAAC;IACrD,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAEvD,OAAO,QAAQ,CAAC,KAAK,CACnB,CAAC,GAAG,EAAE,EAAE,CACN,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC;QACtD,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAC/C,CAAC;AACJ,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,8BAA8B,GACpC,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,gBAAgB,GAMjB,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type ChatError, type ChatSnapshot, type ChatUpdate } from "@turingfocus/chat-protocol";
|
|
2
|
+
import { type TimelineState } from "./timeline.js";
|
|
3
|
+
export interface SnapshotState {
|
|
4
|
+
readonly snapshot: ChatSnapshot;
|
|
5
|
+
readonly timeline: TimelineState;
|
|
6
|
+
}
|
|
7
|
+
export declare const createSnapshotState: (snapshot: ChatSnapshot) => SnapshotState;
|
|
8
|
+
export declare const updateSnapshotState: (state: SnapshotState, changes: Partial<Omit<ChatSnapshot, "timeline">> & {
|
|
9
|
+
readonly timeline?: TimelineState | undefined;
|
|
10
|
+
}) => SnapshotState;
|
|
11
|
+
/**
|
|
12
|
+
* Three-way merge a full reload with state published after that reload began.
|
|
13
|
+
* This keeps reload publication atomic without discarding newer subscription or
|
|
14
|
+
* history changes.
|
|
15
|
+
*/
|
|
16
|
+
export declare const rebaseSnapshotState: (baseline: SnapshotState, loaded: SnapshotState, current: SnapshotState) => SnapshotState;
|
|
17
|
+
export declare const updateConversationId: (update: ChatUpdate) => string | undefined;
|
|
18
|
+
export declare const applySnapshotUpdate: (state: SnapshotState, update: ChatUpdate) => SnapshotState;
|
|
19
|
+
export declare const applySnapshotError: (state: SnapshotState, error: ChatError) => SnapshotState;
|
|
20
|
+
//# sourceMappingURL=snapshot-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-state.d.ts","sourceRoot":"","sources":["../src/snapshot-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,UAAU,EAChB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAIL,KAAK,aAAa,EAEnB,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;CAClC;AAKD,eAAO,MAAM,mBAAmB,GAAI,UAAU,YAAY,KAAG,aAkB5D,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,OAAO,aAAa,EACpB,SAAS,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,GAAG;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;CAC/C,KACA,aAQF,CAAC;AA6BF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC9B,UAAU,aAAa,EACvB,QAAQ,aAAa,EACrB,SAAS,aAAa,KACrB,aA+DF,CAAC;AA6GF,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,UAAU,KACjB,MAAM,GAAG,SASX,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,OAAO,aAAa,EACpB,QAAQ,UAAU,KACjB,aA4EF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,OAAO,aAAa,EACpB,OAAO,SAAS,KACf,aAKF,CAAC"}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { compareAgentEventTransitions, hasCompatibleAgentEventMetadata, } from "@turingfocus/chat-protocol";
|
|
2
|
+
import { cloneImmutable, deepEqual } from "./immutable.js";
|
|
3
|
+
import { createTimelineState, findEventTimelineItem, rebaseTimelineState, upsertTimelineItem, } from "./timeline.js";
|
|
4
|
+
const freezeSnapshot = (snapshot) => Object.freeze(snapshot);
|
|
5
|
+
export const createSnapshotState = (snapshot) => {
|
|
6
|
+
const timeline = createTimelineState(snapshot.timeline);
|
|
7
|
+
return {
|
|
8
|
+
timeline,
|
|
9
|
+
snapshot: freezeSnapshot({
|
|
10
|
+
conversation: cloneImmutable(snapshot.conversation),
|
|
11
|
+
timeline: timeline.items,
|
|
12
|
+
run: cloneImmutable(snapshot.run),
|
|
13
|
+
capabilities: cloneImmutable(snapshot.capabilities),
|
|
14
|
+
pageInfo: cloneImmutable(snapshot.pageInfo),
|
|
15
|
+
...(snapshot.pendingInteraction === undefined
|
|
16
|
+
? {}
|
|
17
|
+
: { pendingInteraction: cloneImmutable(snapshot.pendingInteraction) }),
|
|
18
|
+
...(snapshot.error === undefined
|
|
19
|
+
? {}
|
|
20
|
+
: { error: cloneImmutable(snapshot.error) }),
|
|
21
|
+
}),
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export const updateSnapshotState = (state, changes) => {
|
|
25
|
+
const timeline = changes.timeline ?? state.timeline;
|
|
26
|
+
const snapshot = freezeSnapshot({
|
|
27
|
+
...state.snapshot,
|
|
28
|
+
...changes,
|
|
29
|
+
timeline: timeline.items,
|
|
30
|
+
});
|
|
31
|
+
return { timeline, snapshot };
|
|
32
|
+
};
|
|
33
|
+
const rebaseValue = (baseline, loaded, current) => deepEqual(current, baseline) ? loaded : current;
|
|
34
|
+
const interactionMetadataError = (conversationId) => cloneImmutable({
|
|
35
|
+
code: "validation",
|
|
36
|
+
message: "Conflicting metadata was received for an interaction revision",
|
|
37
|
+
retryable: false,
|
|
38
|
+
conversationId,
|
|
39
|
+
});
|
|
40
|
+
const hasSameInteractionIdentity = (left, right) => left !== undefined &&
|
|
41
|
+
right !== undefined &&
|
|
42
|
+
left.requestId === right.requestId &&
|
|
43
|
+
left.revision === right.revision;
|
|
44
|
+
const hasConflictingInteractionMetadata = (existing, incoming) => hasSameInteractionIdentity(existing, incoming) &&
|
|
45
|
+
!deepEqual(existing, incoming);
|
|
46
|
+
/**
|
|
47
|
+
* Three-way merge a full reload with state published after that reload began.
|
|
48
|
+
* This keeps reload publication atomic without discarding newer subscription or
|
|
49
|
+
* history changes.
|
|
50
|
+
*/
|
|
51
|
+
export const rebaseSnapshotState = (baseline, loaded, current) => {
|
|
52
|
+
const timeline = rebaseTimelineState(baseline.timeline, loaded.timeline, current.timeline);
|
|
53
|
+
const rebasedError = rebaseValue(baseline.snapshot.error, loaded.snapshot.error, current.snapshot.error);
|
|
54
|
+
const pendingWasUnchanged = deepEqual(current.snapshot.pendingInteraction, baseline.snapshot.pendingInteraction);
|
|
55
|
+
const hasLoadedInteractionConflict = pendingWasUnchanged &&
|
|
56
|
+
hasConflictingInteractionMetadata(current.snapshot.pendingInteraction, loaded.snapshot.pendingInteraction);
|
|
57
|
+
const pendingInteraction = hasLoadedInteractionConflict
|
|
58
|
+
? current.snapshot.pendingInteraction
|
|
59
|
+
: rebaseValue(baseline.snapshot.pendingInteraction, loaded.snapshot.pendingInteraction, current.snapshot.pendingInteraction);
|
|
60
|
+
const error = hasLoadedInteractionConflict
|
|
61
|
+
? interactionMetadataError(current.snapshot.conversation.id)
|
|
62
|
+
: rebasedError;
|
|
63
|
+
const rebased = {
|
|
64
|
+
timeline,
|
|
65
|
+
snapshot: freezeSnapshot({
|
|
66
|
+
conversation: rebaseValue(baseline.snapshot.conversation, loaded.snapshot.conversation, current.snapshot.conversation),
|
|
67
|
+
timeline: timeline.items,
|
|
68
|
+
run: rebaseValue(baseline.snapshot.run, loaded.snapshot.run, current.snapshot.run),
|
|
69
|
+
capabilities: rebaseValue(baseline.snapshot.capabilities, loaded.snapshot.capabilities, current.snapshot.capabilities),
|
|
70
|
+
pageInfo: rebaseValue(baseline.snapshot.pageInfo, loaded.snapshot.pageInfo, current.snapshot.pageInfo),
|
|
71
|
+
...(pendingInteraction === undefined ? {} : { pendingInteraction }),
|
|
72
|
+
...(error === undefined ? {} : { error }),
|
|
73
|
+
}),
|
|
74
|
+
};
|
|
75
|
+
if (deepEqual(rebased.snapshot, current.snapshot))
|
|
76
|
+
return current;
|
|
77
|
+
if (deepEqual(rebased.snapshot, loaded.snapshot))
|
|
78
|
+
return loaded;
|
|
79
|
+
return rebased;
|
|
80
|
+
};
|
|
81
|
+
const eventMetadataError = (conversationId) => cloneImmutable({
|
|
82
|
+
code: "validation",
|
|
83
|
+
message: "Conflicting metadata was received for an existing agent event",
|
|
84
|
+
retryable: false,
|
|
85
|
+
conversationId,
|
|
86
|
+
});
|
|
87
|
+
const retainedEventFields = (existing) => existing?.raw === undefined ? {} : { raw: existing.raw };
|
|
88
|
+
const buildAgentEvent = (update, existing) => {
|
|
89
|
+
if (update.event.eventCategory === "tool") {
|
|
90
|
+
const byId = new Map(existing?.eventCategory === "tool"
|
|
91
|
+
? existing.transitions.map((transition) => [transition.id, transition])
|
|
92
|
+
: []);
|
|
93
|
+
const transition = cloneImmutable(update.event.transition);
|
|
94
|
+
byId.set(transition.id, transition);
|
|
95
|
+
const transitions = Object.freeze([...byId.values()].sort(compareAgentEventTransitions));
|
|
96
|
+
const latest = transitions.at(-1);
|
|
97
|
+
return cloneImmutable({
|
|
98
|
+
kind: "agent-event",
|
|
99
|
+
eventCategory: "tool",
|
|
100
|
+
id: update.event.id,
|
|
101
|
+
conversationId: update.conversationId,
|
|
102
|
+
eventType: update.event.eventType,
|
|
103
|
+
status: latest.status,
|
|
104
|
+
createdAt: update.event.createdAt,
|
|
105
|
+
updatedAt: latest.occurredAt,
|
|
106
|
+
...(update.event.sequence === undefined
|
|
107
|
+
? {}
|
|
108
|
+
: { sequence: update.event.sequence }),
|
|
109
|
+
...(latest.summary === undefined
|
|
110
|
+
? existing?.summary === undefined
|
|
111
|
+
? {}
|
|
112
|
+
: { summary: existing.summary }
|
|
113
|
+
: { summary: latest.summary }),
|
|
114
|
+
...retainedEventFields(existing),
|
|
115
|
+
transitions,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
const byId = new Map(existing?.eventCategory === "generic"
|
|
119
|
+
? existing.transitions.map((transition) => [transition.id, transition])
|
|
120
|
+
: []);
|
|
121
|
+
const transition = cloneImmutable(update.event.transition);
|
|
122
|
+
byId.set(transition.id, transition);
|
|
123
|
+
const transitions = Object.freeze([...byId.values()].sort(compareAgentEventTransitions));
|
|
124
|
+
const latest = transitions.at(-1);
|
|
125
|
+
return cloneImmutable({
|
|
126
|
+
kind: "agent-event",
|
|
127
|
+
eventCategory: "generic",
|
|
128
|
+
id: update.event.id,
|
|
129
|
+
conversationId: update.conversationId,
|
|
130
|
+
eventType: update.event.eventType,
|
|
131
|
+
status: latest.status,
|
|
132
|
+
createdAt: update.event.createdAt,
|
|
133
|
+
updatedAt: latest.occurredAt,
|
|
134
|
+
...(update.event.sequence === undefined
|
|
135
|
+
? {}
|
|
136
|
+
: { sequence: update.event.sequence }),
|
|
137
|
+
...(latest.summary === undefined
|
|
138
|
+
? existing?.summary === undefined
|
|
139
|
+
? {}
|
|
140
|
+
: { summary: existing.summary }
|
|
141
|
+
: { summary: latest.summary }),
|
|
142
|
+
...retainedEventFields(existing),
|
|
143
|
+
transitions,
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
const applyTransition = (state, update) => {
|
|
147
|
+
const existing = findEventTimelineItem(state.timeline, update.event.id);
|
|
148
|
+
if (existing !== undefined &&
|
|
149
|
+
(existing.kind !== "agent-event" ||
|
|
150
|
+
!hasCompatibleAgentEventMetadata(existing, update))) {
|
|
151
|
+
const error = eventMetadataError(update.conversationId);
|
|
152
|
+
return deepEqual(state.snapshot.error, error)
|
|
153
|
+
? state
|
|
154
|
+
: updateSnapshotState(state, { error });
|
|
155
|
+
}
|
|
156
|
+
const event = buildAgentEvent(update, existing);
|
|
157
|
+
const timeline = upsertTimelineItem(state.timeline, event);
|
|
158
|
+
return timeline === state.timeline
|
|
159
|
+
? state
|
|
160
|
+
: updateSnapshotState(state, { timeline });
|
|
161
|
+
};
|
|
162
|
+
export const updateConversationId = (update) => {
|
|
163
|
+
if (update.kind === "snapshot.replace") {
|
|
164
|
+
return update.snapshot.conversation.id;
|
|
165
|
+
}
|
|
166
|
+
if (update.kind === "conversation.upsert")
|
|
167
|
+
return update.conversation.id;
|
|
168
|
+
if (update.kind === "error.reported") {
|
|
169
|
+
return update.conversationId ?? update.error.conversationId;
|
|
170
|
+
}
|
|
171
|
+
return update.conversationId;
|
|
172
|
+
};
|
|
173
|
+
export const applySnapshotUpdate = (state, update) => {
|
|
174
|
+
const activeConversationId = state.snapshot.conversation.id;
|
|
175
|
+
const targetConversationId = updateConversationId(update);
|
|
176
|
+
if (targetConversationId !== undefined &&
|
|
177
|
+
targetConversationId !== activeConversationId) {
|
|
178
|
+
return state;
|
|
179
|
+
}
|
|
180
|
+
switch (update.kind) {
|
|
181
|
+
case "snapshot.replace": {
|
|
182
|
+
const replacement = createSnapshotState(update.snapshot);
|
|
183
|
+
if (hasConflictingInteractionMetadata(state.snapshot.pendingInteraction, replacement.snapshot.pendingInteraction)) {
|
|
184
|
+
return updateSnapshotState(replacement, {
|
|
185
|
+
pendingInteraction: state.snapshot.pendingInteraction,
|
|
186
|
+
error: interactionMetadataError(activeConversationId),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
return deepEqual(replacement.snapshot, state.snapshot)
|
|
190
|
+
? state
|
|
191
|
+
: replacement;
|
|
192
|
+
}
|
|
193
|
+
case "conversation.upsert": {
|
|
194
|
+
const conversation = cloneImmutable(update.conversation);
|
|
195
|
+
return deepEqual(conversation, state.snapshot.conversation)
|
|
196
|
+
? state
|
|
197
|
+
: updateSnapshotState(state, { conversation });
|
|
198
|
+
}
|
|
199
|
+
case "timeline.upsert": {
|
|
200
|
+
const timeline = upsertTimelineItem(state.timeline, update.item);
|
|
201
|
+
return timeline === state.timeline
|
|
202
|
+
? state
|
|
203
|
+
: updateSnapshotState(state, { timeline });
|
|
204
|
+
}
|
|
205
|
+
case "event.transition.upsert":
|
|
206
|
+
return applyTransition(state, update);
|
|
207
|
+
case "run.replace": {
|
|
208
|
+
const run = cloneImmutable(update.run);
|
|
209
|
+
return deepEqual(run, state.snapshot.run)
|
|
210
|
+
? state
|
|
211
|
+
: updateSnapshotState(state, { run });
|
|
212
|
+
}
|
|
213
|
+
case "capabilities.replace": {
|
|
214
|
+
const capabilities = cloneImmutable(update.capabilities);
|
|
215
|
+
return deepEqual(capabilities, state.snapshot.capabilities)
|
|
216
|
+
? state
|
|
217
|
+
: updateSnapshotState(state, { capabilities });
|
|
218
|
+
}
|
|
219
|
+
case "interaction.replace": {
|
|
220
|
+
const pendingInteraction = cloneImmutable(update.interaction ?? undefined);
|
|
221
|
+
if (hasConflictingInteractionMetadata(state.snapshot.pendingInteraction, pendingInteraction)) {
|
|
222
|
+
return applySnapshotError(state, interactionMetadataError(activeConversationId));
|
|
223
|
+
}
|
|
224
|
+
return deepEqual(pendingInteraction, state.snapshot.pendingInteraction)
|
|
225
|
+
? state
|
|
226
|
+
: updateSnapshotState(state, { pendingInteraction });
|
|
227
|
+
}
|
|
228
|
+
case "error.reported":
|
|
229
|
+
return applySnapshotError(state, update.error);
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
export const applySnapshotError = (state, error) => {
|
|
233
|
+
const immutableError = cloneImmutable(error);
|
|
234
|
+
return deepEqual(immutableError, state.snapshot.error)
|
|
235
|
+
? state
|
|
236
|
+
: updateSnapshotState(state, { error: immutableError });
|
|
237
|
+
};
|
|
238
|
+
//# sourceMappingURL=snapshot-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-state.js","sourceRoot":"","sources":["../src/snapshot-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ChatSnapshot } from "@turingfocus/chat-protocol";
|
|
2
|
+
import type { SnapshotState } from "./snapshot-state.js";
|
|
3
|
+
export type SnapshotListener = (snapshot: ChatSnapshot) => void;
|
|
4
|
+
export interface SnapshotSubscription {
|
|
5
|
+
readonly closed: boolean;
|
|
6
|
+
dispose(): void;
|
|
7
|
+
}
|
|
8
|
+
export interface SnapshotStoreOptions {
|
|
9
|
+
readonly onListenerError?: ((error: unknown) => void) | undefined;
|
|
10
|
+
}
|
|
11
|
+
/** Owns immutable snapshot publication and shields listeners from reentrant writes. */
|
|
12
|
+
export declare class SnapshotStore {
|
|
13
|
+
#private;
|
|
14
|
+
constructor(options?: SnapshotStoreOptions);
|
|
15
|
+
get state(): SnapshotState | null;
|
|
16
|
+
getSnapshot(): ChatSnapshot | null;
|
|
17
|
+
subscribe(listener: SnapshotListener): SnapshotSubscription;
|
|
18
|
+
latestState(): SnapshotState | null;
|
|
19
|
+
commit(next: SnapshotState): void;
|
|
20
|
+
close(): void;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=snapshot-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-store.d.ts","sourceRoot":"","sources":["../src/snapshot-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;AAEhE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CACnE;AAQD,uFAAuF;AACvF,qBAAa,aAAa;;gBAQZ,OAAO,GAAE,oBAAyB;IAI9C,IAAI,KAAK,IAAI,aAAa,GAAG,IAAI,CAEhC;IAED,WAAW,IAAI,YAAY,GAAG,IAAI;IAIlC,SAAS,CAAC,QAAQ,EAAE,gBAAgB,GAAG,oBAAoB;IA2B3D,WAAW,IAAI,aAAa,GAAG,IAAI;IAInC,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAqBjC,KAAK,IAAI,IAAI;CA0Bd"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/** Owns immutable snapshot publication and shields listeners from reentrant writes. */
|
|
2
|
+
export class SnapshotStore {
|
|
3
|
+
#listeners = new Set();
|
|
4
|
+
#onListenerError;
|
|
5
|
+
#pendingCommits = [];
|
|
6
|
+
#closed = false;
|
|
7
|
+
#notifying = false;
|
|
8
|
+
#state = null;
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
this.#onListenerError = options.onListenerError;
|
|
11
|
+
}
|
|
12
|
+
get state() {
|
|
13
|
+
return this.#state;
|
|
14
|
+
}
|
|
15
|
+
getSnapshot() {
|
|
16
|
+
return this.#state?.snapshot ?? null;
|
|
17
|
+
}
|
|
18
|
+
subscribe(listener) {
|
|
19
|
+
const registration = {
|
|
20
|
+
active: true,
|
|
21
|
+
lastSnapshot: null,
|
|
22
|
+
listener,
|
|
23
|
+
};
|
|
24
|
+
if (!this.#closed) {
|
|
25
|
+
this.#listeners.add(registration);
|
|
26
|
+
if (this.#state !== null) {
|
|
27
|
+
this.#callListener(registration, this.#state.snapshot);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
registration.active = false;
|
|
32
|
+
}
|
|
33
|
+
return Object.freeze({
|
|
34
|
+
get closed() {
|
|
35
|
+
return !registration.active;
|
|
36
|
+
},
|
|
37
|
+
dispose: () => {
|
|
38
|
+
if (!registration.active)
|
|
39
|
+
return;
|
|
40
|
+
registration.active = false;
|
|
41
|
+
this.#listeners.delete(registration);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
latestState() {
|
|
46
|
+
return this.#pendingCommits.at(-1) ?? this.#state;
|
|
47
|
+
}
|
|
48
|
+
commit(next) {
|
|
49
|
+
const latest = this.latestState();
|
|
50
|
+
if (this.#closed || next === latest)
|
|
51
|
+
return;
|
|
52
|
+
this.#pendingCommits.push(next);
|
|
53
|
+
if (this.#notifying)
|
|
54
|
+
return;
|
|
55
|
+
this.#notifying = true;
|
|
56
|
+
try {
|
|
57
|
+
while (!this.#closed && this.#pendingCommits.length > 0) {
|
|
58
|
+
const state = this.#pendingCommits.shift();
|
|
59
|
+
this.#state = state;
|
|
60
|
+
for (const registration of [...this.#listeners]) {
|
|
61
|
+
this.#callListener(registration, state.snapshot);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
this.#notifying = false;
|
|
67
|
+
if (this.#closed)
|
|
68
|
+
this.#pendingCommits.length = 0;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
close() {
|
|
72
|
+
if (this.#closed)
|
|
73
|
+
return;
|
|
74
|
+
this.#closed = true;
|
|
75
|
+
this.#pendingCommits.length = 0;
|
|
76
|
+
for (const registration of this.#listeners)
|
|
77
|
+
registration.active = false;
|
|
78
|
+
this.#listeners.clear();
|
|
79
|
+
this.#state = null;
|
|
80
|
+
}
|
|
81
|
+
#callListener(registration, snapshot) {
|
|
82
|
+
if (!registration.active || registration.lastSnapshot === snapshot)
|
|
83
|
+
return;
|
|
84
|
+
registration.lastSnapshot = snapshot;
|
|
85
|
+
try {
|
|
86
|
+
registration.listener(snapshot);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
// One host listener must not prevent other subscribers from updating.
|
|
90
|
+
try {
|
|
91
|
+
this.#onListenerError?.(error);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// A diagnostic hook must not break publication to healthy listeners.
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=snapshot-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-store.js","sourceRoot":"","sources":["../src/snapshot-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type TimelineItem } from "@turingfocus/chat-protocol";
|
|
2
|
+
export interface TimelineState {
|
|
3
|
+
readonly index: TimelineItemIndex;
|
|
4
|
+
readonly items: readonly TimelineItem[];
|
|
5
|
+
}
|
|
6
|
+
interface TimelineItemIndex {
|
|
7
|
+
readonly base: ReadonlyMap<string, TimelineItem>;
|
|
8
|
+
readonly overlay: ReadonlyMap<string, TimelineItem>;
|
|
9
|
+
}
|
|
10
|
+
export declare const createTimelineState: (items: readonly TimelineItem[]) => TimelineState;
|
|
11
|
+
export declare const findEventTimelineItem: (state: TimelineState, eventId: string) => TimelineItem | undefined;
|
|
12
|
+
export declare const upsertTimelineItem: (state: TimelineState, candidate: TimelineItem) => TimelineState;
|
|
13
|
+
/** Merge an older history page while preserving newer in-memory items. */
|
|
14
|
+
export declare const mergeHistoryTimeline: (current: TimelineState, history: readonly TimelineItem[]) => TimelineState;
|
|
15
|
+
/**
|
|
16
|
+
* Rebase a freshly loaded timeline onto changes published since the load began.
|
|
17
|
+
* Current changes win per stable item key; otherwise the loaded value (including
|
|
18
|
+
* a deletion) is adopted.
|
|
19
|
+
*/
|
|
20
|
+
export declare const rebaseTimelineState: (baseline: TimelineState, loaded: TimelineState, current: TimelineState) => TimelineState;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=timeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../src/timeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,4BAA4B,CAAC;AAIpC,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;CACzC;AAED,UAAU,iBAAiB;IACzB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACjD,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACrD;AAuCD,eAAO,MAAM,mBAAmB,GAC9B,OAAO,SAAS,YAAY,EAAE,KAC7B,aACkE,CAAC;AAEtE,eAAO,MAAM,qBAAqB,GAChC,OAAO,aAAa,EACpB,SAAS,MAAM,KACd,YAAY,GAAG,SAEjB,CAAC;AA6BF,eAAO,MAAM,kBAAkB,GAC7B,OAAO,aAAa,EACpB,WAAW,YAAY,KACtB,aAsCF,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,oBAAoB,GAC/B,SAAS,aAAa,EACtB,SAAS,SAAS,YAAY,EAAE,KAC/B,aAYF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC9B,UAAU,aAAa,EACvB,QAAQ,aAAa,EACrB,SAAS,aAAa,KACrB,aA+BF,CAAC"}
|