@ycodium-ai/plugin-conversation 0.2.3016 → 0.2.3020
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/assets/ui.js +8 -8
- package/dist/index.js +139 -78
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -435,41 +435,6 @@ function applyLiveAnswer(thread, messages, segment, answer) {
|
|
|
435
435
|
return { ...thread, running: thread.running || live.streaming, turns };
|
|
436
436
|
}
|
|
437
437
|
|
|
438
|
-
// src/ui/sessionMap/toolStrip.ts
|
|
439
|
-
function record(value) {
|
|
440
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
|
|
441
|
-
return value;
|
|
442
|
-
}
|
|
443
|
-
function text(value) {
|
|
444
|
-
return typeof value === "string" ? value.trim() : "";
|
|
445
|
-
}
|
|
446
|
-
function toolTitleFromActivity(payload) {
|
|
447
|
-
const root = record(payload);
|
|
448
|
-
if (root === null) return "";
|
|
449
|
-
const data = record(root.data) ?? root;
|
|
450
|
-
const toolLabel = record(data.toolLabel) ?? record(root.toolLabel);
|
|
451
|
-
if (toolLabel !== null) {
|
|
452
|
-
if (toolLabel.descriptive === false) return "";
|
|
453
|
-
const detail = text(toolLabel.detail);
|
|
454
|
-
if (detail.length > 0) return detail;
|
|
455
|
-
return text(toolLabel.title);
|
|
456
|
-
}
|
|
457
|
-
return text(root.title);
|
|
458
|
-
}
|
|
459
|
-
function titlesByCallId(activities) {
|
|
460
|
-
const titles = /* @__PURE__ */ new Map();
|
|
461
|
-
for (const activity of activities) {
|
|
462
|
-
const root = record(activity.payload);
|
|
463
|
-
if (root === null) continue;
|
|
464
|
-
const data = record(root.data) ?? root;
|
|
465
|
-
const callId = text(data.toolCallId) || text(root.toolCallId);
|
|
466
|
-
if (callId.length === 0) continue;
|
|
467
|
-
const title = toolTitleFromActivity(activity.payload);
|
|
468
|
-
if (title.length > 0) titles.set(callId, title);
|
|
469
|
-
}
|
|
470
|
-
return titles;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
438
|
// src/sessionMap/refreshGate.ts
|
|
474
439
|
var CARD_REFRESH_MS = 800;
|
|
475
440
|
var CardRefreshGate = class {
|
|
@@ -649,6 +614,134 @@ async function executionOf(ctx, threadId) {
|
|
|
649
614
|
return executionRow(execution);
|
|
650
615
|
}
|
|
651
616
|
|
|
617
|
+
// src/sessionMap/threadReads.ts
|
|
618
|
+
import {
|
|
619
|
+
isThreadNotFound,
|
|
620
|
+
threadOrNull,
|
|
621
|
+
THREAD_ACTIVITIES_LIST_LIMIT,
|
|
622
|
+
THREAD_MESSAGES_LIST_LIMIT,
|
|
623
|
+
TOOL_LIFECYCLE_ACTIVITY_KINDS
|
|
624
|
+
} from "@ycodium-ai/plugin-api";
|
|
625
|
+
|
|
626
|
+
// src/ui/sessionMap/toolStrip.ts
|
|
627
|
+
function record(value) {
|
|
628
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
|
|
629
|
+
return value;
|
|
630
|
+
}
|
|
631
|
+
function text(value) {
|
|
632
|
+
return typeof value === "string" ? value.trim() : "";
|
|
633
|
+
}
|
|
634
|
+
function toolTitleFromActivity(payload) {
|
|
635
|
+
const root = record(payload);
|
|
636
|
+
if (root === null) return "";
|
|
637
|
+
const data = record(root.data) ?? root;
|
|
638
|
+
const toolLabel = record(data.toolLabel) ?? record(root.toolLabel);
|
|
639
|
+
if (toolLabel !== null) {
|
|
640
|
+
if (toolLabel.descriptive === false) return "";
|
|
641
|
+
const detail = text(toolLabel.detail);
|
|
642
|
+
if (detail.length > 0) return detail;
|
|
643
|
+
return text(toolLabel.title);
|
|
644
|
+
}
|
|
645
|
+
return text(root.title);
|
|
646
|
+
}
|
|
647
|
+
function titlesByCallId(activities) {
|
|
648
|
+
const titles = /* @__PURE__ */ new Map();
|
|
649
|
+
for (const activity of activities) {
|
|
650
|
+
const root = record(activity.payload);
|
|
651
|
+
if (root === null) continue;
|
|
652
|
+
const data = record(root.data) ?? root;
|
|
653
|
+
const callId = text(data.toolCallId) || text(root.toolCallId);
|
|
654
|
+
if (callId.length === 0) continue;
|
|
655
|
+
const title = toolTitleFromActivity(activity.payload);
|
|
656
|
+
if (title.length > 0) titles.set(callId, title);
|
|
657
|
+
}
|
|
658
|
+
return titles;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// src/sessionMap/threadReads.ts
|
|
662
|
+
var MESSAGES_PAGE = THREAD_MESSAGES_LIST_LIMIT;
|
|
663
|
+
var ACTIVITIES_PAGE = THREAD_ACTIVITIES_LIST_LIMIT;
|
|
664
|
+
var MAX_TITLE_ACTIVITIES = 500;
|
|
665
|
+
var TOOL_ACTIVITY_KINDS = [...TOOL_LIFECYCLE_ACTIVITY_KINDS];
|
|
666
|
+
var messageOf = (item) => ({
|
|
667
|
+
messageId: item.id,
|
|
668
|
+
role: item.role,
|
|
669
|
+
text: item.text
|
|
670
|
+
});
|
|
671
|
+
async function readTranscript(threads, threadId) {
|
|
672
|
+
const newestFirst = [];
|
|
673
|
+
let cursor = null;
|
|
674
|
+
try {
|
|
675
|
+
do {
|
|
676
|
+
const page = await threads.messages.list({
|
|
677
|
+
threadId,
|
|
678
|
+
limit: MESSAGES_PAGE,
|
|
679
|
+
cursor
|
|
680
|
+
});
|
|
681
|
+
newestFirst.push(...page.items.map(messageOf));
|
|
682
|
+
cursor = page.nextCursor;
|
|
683
|
+
} while (cursor !== null);
|
|
684
|
+
} catch (error) {
|
|
685
|
+
if (isThreadNotFound(error)) return null;
|
|
686
|
+
throw error;
|
|
687
|
+
}
|
|
688
|
+
return newestFirst.toReversed();
|
|
689
|
+
}
|
|
690
|
+
async function readToolTitles(threads, threadId) {
|
|
691
|
+
const titles = /* @__PURE__ */ new Map();
|
|
692
|
+
let cursor = null;
|
|
693
|
+
let remaining = MAX_TITLE_ACTIVITIES;
|
|
694
|
+
try {
|
|
695
|
+
do {
|
|
696
|
+
const page = await threads.activities.list({
|
|
697
|
+
threadId,
|
|
698
|
+
kinds: TOOL_ACTIVITY_KINDS,
|
|
699
|
+
limit: Math.min(ACTIVITIES_PAGE, remaining),
|
|
700
|
+
cursor
|
|
701
|
+
});
|
|
702
|
+
remaining -= page.items.length;
|
|
703
|
+
const oldestFirst = page.items.toReversed().map((item) => ({ payload: "payload" in item ? item.payload : void 0 }));
|
|
704
|
+
for (const [callId, title] of titlesByCallId(oldestFirst)) {
|
|
705
|
+
if (!titles.has(callId)) titles.set(callId, title);
|
|
706
|
+
}
|
|
707
|
+
cursor = page.items.length === 0 ? null : page.nextCursor;
|
|
708
|
+
} while (cursor !== null && remaining > 0);
|
|
709
|
+
} catch (error) {
|
|
710
|
+
if (isThreadNotFound(error)) return /* @__PURE__ */ new Map();
|
|
711
|
+
throw error;
|
|
712
|
+
}
|
|
713
|
+
return titles;
|
|
714
|
+
}
|
|
715
|
+
async function readDetail(threads, threadId) {
|
|
716
|
+
const thread = await threadOrNull(threads, threadId);
|
|
717
|
+
if (thread === null) return { found: false, messages: [] };
|
|
718
|
+
let latest;
|
|
719
|
+
try {
|
|
720
|
+
latest = await threads.messages.list({
|
|
721
|
+
threadId,
|
|
722
|
+
limit: MAX_DETAIL_MESSAGES,
|
|
723
|
+
includeTotal: true
|
|
724
|
+
});
|
|
725
|
+
} catch (error) {
|
|
726
|
+
if (isThreadNotFound(error)) return { found: false, messages: [] };
|
|
727
|
+
throw error;
|
|
728
|
+
}
|
|
729
|
+
return {
|
|
730
|
+
found: true,
|
|
731
|
+
title: thread.title,
|
|
732
|
+
omitted: Math.max(0, (latest.total ?? 0) - latest.items.length),
|
|
733
|
+
messages: latest.items.toReversed().map((message) => {
|
|
734
|
+
const clipped = clipText(message.text, MAX_DETAIL_TEXT);
|
|
735
|
+
return {
|
|
736
|
+
messageId: message.id,
|
|
737
|
+
role: message.role,
|
|
738
|
+
text: clipped.text,
|
|
739
|
+
truncated: clipped.truncated
|
|
740
|
+
};
|
|
741
|
+
})
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
|
|
652
745
|
// src/sessionMap/mapLive.ts
|
|
653
746
|
function createSessionMapHub(ctx, canvas, options = {}) {
|
|
654
747
|
return new SessionMapHub(ctx, canvas, options.timers !== false);
|
|
@@ -831,7 +924,7 @@ var SessionMapHub = class {
|
|
|
831
924
|
if (live !== void 0) {
|
|
832
925
|
const message = await this.ctx.projections.getThreadMessage(live.messageId);
|
|
833
926
|
if (message !== null) {
|
|
834
|
-
this.transcripts.upsert(threadId,
|
|
927
|
+
this.transcripts.upsert(threadId, messageOf2(message));
|
|
835
928
|
const clipped = clipText(message.text, MAX_CARD_TEXT);
|
|
836
929
|
answer = { text: clipped.text, truncated: clipped.truncated };
|
|
837
930
|
}
|
|
@@ -854,9 +947,8 @@ var SessionMapHub = class {
|
|
|
854
947
|
}
|
|
855
948
|
async seedTranscript(threadId) {
|
|
856
949
|
if (this.transcripts.has(threadId)) return;
|
|
857
|
-
|
|
858
|
-
this.
|
|
859
|
-
this.rememberTitles(threadId, titlesByCallId(thread?.activities ?? []));
|
|
950
|
+
this.transcripts.seed(threadId, await readTranscript(this.ctx.threads, threadId) ?? []);
|
|
951
|
+
this.rememberTitles(threadId, await readToolTitles(this.ctx.threads, threadId));
|
|
860
952
|
}
|
|
861
953
|
rememberTitles(threadId, titles) {
|
|
862
954
|
if (titles.size === 0) return;
|
|
@@ -877,15 +969,14 @@ var SessionMapHub = class {
|
|
|
877
969
|
if (pending !== void 0) {
|
|
878
970
|
for (const messageId of pending) {
|
|
879
971
|
const message = await this.ctx.projections.getThreadMessage(messageId);
|
|
880
|
-
if (message !== null) this.transcripts.upsert(threadId,
|
|
972
|
+
if (message !== null) this.transcripts.upsert(threadId, messageOf2(message));
|
|
881
973
|
}
|
|
882
974
|
}
|
|
883
975
|
return this.transcripts.get(threadId) ?? [];
|
|
884
976
|
}
|
|
885
977
|
async loadParent(threadId) {
|
|
886
978
|
if (!this.transcripts.has(threadId)) {
|
|
887
|
-
|
|
888
|
-
this.transcripts.seed(threadId, transcriptOf(thread));
|
|
979
|
+
this.transcripts.seed(threadId, await readTranscript(this.ctx.threads, threadId) ?? []);
|
|
889
980
|
}
|
|
890
981
|
return this.transcripts.get(threadId) ?? [];
|
|
891
982
|
}
|
|
@@ -954,11 +1045,7 @@ function messageIdOf(event) {
|
|
|
954
1045
|
const messageId = readString(event.payload.messageId);
|
|
955
1046
|
return messageId.length > 0 ? messageId : null;
|
|
956
1047
|
}
|
|
957
|
-
function
|
|
958
|
-
if (thread === null) return [];
|
|
959
|
-
return thread.messages.map(messageOf);
|
|
960
|
-
}
|
|
961
|
-
function messageOf(message) {
|
|
1048
|
+
function messageOf2(message) {
|
|
962
1049
|
return { messageId: message.messageId, role: message.role, text: message.text };
|
|
963
1050
|
}
|
|
964
1051
|
function jsonValue(value) {
|
|
@@ -1046,7 +1133,7 @@ function activateSessionMap(ctx) {
|
|
|
1046
1133
|
properties: { threadId: { type: "string" } },
|
|
1047
1134
|
required: ["threadId"]
|
|
1048
1135
|
},
|
|
1049
|
-
handle: async (payload) =>
|
|
1136
|
+
handle: async (payload) => readDetail(ctx.threads, readString(payload["threadId"]))
|
|
1050
1137
|
});
|
|
1051
1138
|
ctx.command({
|
|
1052
1139
|
name: "preferences",
|
|
@@ -1187,32 +1274,6 @@ function activateSessionMap(ctx) {
|
|
|
1187
1274
|
)
|
|
1188
1275
|
});
|
|
1189
1276
|
}
|
|
1190
|
-
function transcriptOf2(thread) {
|
|
1191
|
-
if (thread === null) return [];
|
|
1192
|
-
return thread.messages.map(messageOf2);
|
|
1193
|
-
}
|
|
1194
|
-
function messageOf2(message) {
|
|
1195
|
-
return { messageId: message.messageId, role: message.role, text: message.text };
|
|
1196
|
-
}
|
|
1197
|
-
async function detailOf(ctx, threadId) {
|
|
1198
|
-
const thread = await ctx.projections.getThread(threadId);
|
|
1199
|
-
if (thread === null) return { found: false, messages: [] };
|
|
1200
|
-
const tail = thread.messages.slice(-MAX_DETAIL_MESSAGES);
|
|
1201
|
-
return {
|
|
1202
|
-
found: true,
|
|
1203
|
-
title: thread.title,
|
|
1204
|
-
omitted: Math.max(0, thread.messages.length - tail.length),
|
|
1205
|
-
messages: tail.map((message) => {
|
|
1206
|
-
const clipped = clipText(message.text, MAX_DETAIL_TEXT);
|
|
1207
|
-
return {
|
|
1208
|
-
messageId: message.messageId,
|
|
1209
|
-
role: message.role,
|
|
1210
|
-
text: clipped.text,
|
|
1211
|
-
truncated: clipped.truncated
|
|
1212
|
-
};
|
|
1213
|
-
})
|
|
1214
|
-
};
|
|
1215
|
-
}
|
|
1216
1277
|
async function createSession(ctx, projectId, text2, refresh) {
|
|
1217
1278
|
const trimmed = text2.trim();
|
|
1218
1279
|
if (trimmed.length === 0) return { ok: false, code: "empty" };
|
|
@@ -1261,9 +1322,9 @@ async function sendFollowUp(ctx, threadId, text2, refresh) {
|
|
|
1261
1322
|
async function forkSession(ctx, threadId, messageId, text2, refresh) {
|
|
1262
1323
|
const trimmed = text2.trim();
|
|
1263
1324
|
if (trimmed.length === 0) return { ok: false, code: "empty" };
|
|
1264
|
-
const
|
|
1265
|
-
if (
|
|
1266
|
-
const anchor = resolveForkAnchor(
|
|
1325
|
+
const transcript = await readTranscript(ctx.threads, threadId);
|
|
1326
|
+
if (transcript === null) return { ok: false, code: "missing-thread" };
|
|
1327
|
+
const anchor = resolveForkAnchor(transcript, messageId);
|
|
1267
1328
|
if (anchor === null) return { ok: false, code: "no-user-message" };
|
|
1268
1329
|
const execution = await executionOf(ctx, threadId);
|
|
1269
1330
|
const childId = NodeCrypto.randomUUID();
|
|
@@ -1319,7 +1380,7 @@ function abort(signal) {
|
|
|
1319
1380
|
// src/index.ts
|
|
1320
1381
|
var index_default = definePlugin({
|
|
1321
1382
|
id: "conversation",
|
|
1322
|
-
apiVersion:
|
|
1383
|
+
apiVersion: 9,
|
|
1323
1384
|
activate(ctx) {
|
|
1324
1385
|
activateSessionMap(ctx);
|
|
1325
1386
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ycodium-ai/plugin-conversation",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3020",
|
|
4
4
|
"description": "The conversation surface: chat, trajectory, and session map, the input card, the queue, and turn navigation.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chat",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"tailwindcss": "^4.0.0",
|
|
42
42
|
"typescript": "~6.0.3",
|
|
43
43
|
"vite-plus": "0.2.2",
|
|
44
|
-
"@ycodium-ai/plugin-api": "0.2.
|
|
44
|
+
"@ycodium-ai/plugin-api": "0.2.3020",
|
|
45
45
|
"ycodium-composer-tokens": "0.0.0",
|
|
46
46
|
"ycodium-workspace-path": "0.0.0"
|
|
47
47
|
},
|