@yeaft/webchat-agent 1.0.573 → 1.0.574
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/index.js +1 -1
- package/local-runtime/server/handlers/client-conversation.js +13 -0
- package/local-runtime/version.json +1 -1
- package/local-runtime/web/app.bundle.js +143 -107
- package/local-runtime/web/app.bundle.js.gz +0 -0
- package/local-runtime/web/index.html +2 -2
- package/local-runtime/web/style.bundle.css +1 -1
- package/local-runtime/web/style.bundle.css.gz +0 -0
- package/package.json +1 -1
- package/yeaft/conversation/persist.js +42 -2
- package/yeaft/sessions/session-crud.js +7 -1
- package/yeaft/web-bridge.js +3 -0
|
Binary file
|
package/package.json
CHANGED
|
@@ -1962,9 +1962,12 @@ export class ConversationStore {
|
|
|
1962
1962
|
* copied persisted message are remapped; external/client/tool identities are
|
|
1963
1963
|
* intentionally preserved.
|
|
1964
1964
|
*
|
|
1965
|
+
* @param {string} sourceSessionId
|
|
1966
|
+
* @param {string} targetSessionId
|
|
1967
|
+
* @param {{throughTurnId?: string}} [options]
|
|
1965
1968
|
* @returns {{ copiedCount: number, idMap: Map<string, string> }}
|
|
1966
1969
|
*/
|
|
1967
|
-
copySession(sourceSessionId, targetSessionId) {
|
|
1970
|
+
copySession(sourceSessionId, targetSessionId, options = {}) {
|
|
1968
1971
|
if (!sourceSessionId || !targetSessionId || sourceSessionId === targetSessionId) {
|
|
1969
1972
|
return { copiedCount: 0, idMap: new Map() };
|
|
1970
1973
|
}
|
|
@@ -1986,7 +1989,44 @@ export class ConversationStore {
|
|
|
1986
1989
|
if (row?.sessionId !== sourceSessionId || typeof row.id !== 'string' || !row.id) continue;
|
|
1987
1990
|
rowsById.set(row.id, row);
|
|
1988
1991
|
}
|
|
1989
|
-
|
|
1992
|
+
let rows = [...rowsById.values()].sort(compareMessagesBySeq);
|
|
1993
|
+
if (Object.prototype.hasOwnProperty.call(options, 'throughTurnId')) {
|
|
1994
|
+
const throughTurnId = typeof options.throughTurnId === 'string'
|
|
1995
|
+
? options.throughTurnId.trim()
|
|
1996
|
+
: '';
|
|
1997
|
+
if (!throughTurnId) {
|
|
1998
|
+
const error = new Error('throughTurnId must be a nonempty string');
|
|
1999
|
+
error.code = 'invalid_fork_boundary';
|
|
2000
|
+
throw error;
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
const matchingAssistantRows = rows.filter(row => row?.role === 'assistant' && row.turnId === throughTurnId);
|
|
2004
|
+
if (matchingAssistantRows.length === 0) {
|
|
2005
|
+
const error = new Error(`Assistant turn not found: ${throughTurnId}`);
|
|
2006
|
+
error.code = 'fork_boundary_not_found';
|
|
2007
|
+
throw error;
|
|
2008
|
+
}
|
|
2009
|
+
const speakers = new Set(matchingAssistantRows.map(row => row.speakerVpId || row.vpId || '').filter(Boolean));
|
|
2010
|
+
if (speakers.size > 1) {
|
|
2011
|
+
const error = new Error(`Assistant turn boundary is ambiguous: ${throughTurnId}`);
|
|
2012
|
+
error.code = 'ambiguous_fork_boundary';
|
|
2013
|
+
throw error;
|
|
2014
|
+
}
|
|
2015
|
+
const endpoint = rows.reduce((last, row, index) => row?.turnId === throughTurnId ? index : last, -1);
|
|
2016
|
+
const prefix = rows.slice(0, endpoint + 1);
|
|
2017
|
+
const sanitized = pairSanitize(prefix);
|
|
2018
|
+
const pairShape = row => ({
|
|
2019
|
+
id: row?.id,
|
|
2020
|
+
toolCalls: Array.isArray(row?.toolCalls) ? row.toolCalls.map(call => call?.id) : undefined,
|
|
2021
|
+
});
|
|
2022
|
+
if (sanitized.length !== prefix.length
|
|
2023
|
+
|| sanitized.some((row, index) => JSON.stringify(pairShape(row)) !== JSON.stringify(pairShape(prefix[index])))) {
|
|
2024
|
+
const error = new Error(`Assistant turn boundary would split provider tool history: ${throughTurnId}`);
|
|
2025
|
+
error.code = 'incomplete_fork_boundary';
|
|
2026
|
+
throw error;
|
|
2027
|
+
}
|
|
2028
|
+
rows = prefix;
|
|
2029
|
+
}
|
|
1990
2030
|
if (rows.length === 0) return { copiedCount: 0, idMap: new Map() };
|
|
1991
2031
|
|
|
1992
2032
|
const firstSeq = this.#reserveSeqRange(rows.length);
|
|
@@ -641,11 +641,17 @@ export function copySession(yeaftDir, sourceSessionId, options = {}) {
|
|
|
641
641
|
}
|
|
642
642
|
|
|
643
643
|
const transcript = new ConversationStore(sourceYeaftDir);
|
|
644
|
-
const
|
|
644
|
+
const transcriptOptions = Object.prototype.hasOwnProperty.call(options, 'throughTurnId')
|
|
645
|
+
? { throughTurnId: options.throughTurnId }
|
|
646
|
+
: {};
|
|
647
|
+
const { copiedCount } = transcript.copySession(sourceSessionId, copied.id, transcriptOptions);
|
|
645
648
|
return { ...requireSessionMeta(sourceYeaftDir, copied.id), copiedMessageCount: copiedCount };
|
|
646
649
|
} catch (error) {
|
|
647
650
|
// A partial clone must never appear as a successful copy.
|
|
648
651
|
deleteSession(sourceYeaftDir, copied.id, options);
|
|
652
|
+
if (['invalid_fork_boundary', 'fork_boundary_not_found', 'ambiguous_fork_boundary', 'incomplete_fork_boundary'].includes(error?.code)) {
|
|
653
|
+
throw new SessionCrudError(error.code, sourceSessionId, error.message);
|
|
654
|
+
}
|
|
649
655
|
throw error;
|
|
650
656
|
}
|
|
651
657
|
}
|
package/yeaft/web-bridge.js
CHANGED
|
@@ -3663,6 +3663,9 @@ export function handleYeaftCopySession(msg) {
|
|
|
3663
3663
|
const session = copySession(yeaftDir, sessionId, {
|
|
3664
3664
|
...configuredVpPaths(),
|
|
3665
3665
|
name: msg && msg.name,
|
|
3666
|
+
...(msg && Object.prototype.hasOwnProperty.call(msg, 'throughTurnId')
|
|
3667
|
+
? { throughTurnId: msg.throughTurnId }
|
|
3668
|
+
: {}),
|
|
3666
3669
|
});
|
|
3667
3670
|
recordAgentSessionCreated();
|
|
3668
3671
|
session.config = loadSessionConfig(yeaftDir, session.id);
|