dsh-plugin-soulbridge 0.0.120 → 0.0.121
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 +41 -9
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -1677,15 +1677,30 @@ async function runExtraction(text, turnId, turnNo, origin = 'live', unit = null)
|
|
|
1677
1677
|
});
|
|
1678
1678
|
const result = soul.commitDrafts(draft, { turnId, turnIds });
|
|
1679
1679
|
// Attribution is written even when nothing was extracted: a turn that says
|
|
1680
|
-
// "无" (nothing worth remembering) can still be part of a thread.
|
|
1681
|
-
|
|
1680
|
+
// "无" (nothing worth remembering) can still be part of a thread. The unit is
|
|
1681
|
+
// fanned over per turn (0028 ③): every turn of the segment gets attached, a
|
|
1682
|
+
// turn no span covers chains to the previous one, and the continue/new/
|
|
1683
|
+
// fallback chain inside applyThread is untouched (ADR 0034).
|
|
1684
|
+
const spanTurns = (turns ?? [{ turnNo: 1, id: turnId, userText: text }]).map((entry) => ({
|
|
1685
|
+
promptNo: entry.turnNo,
|
|
1686
|
+
turnNo: entry.hostTurnNo ?? turnNo,
|
|
1687
|
+
turnId: entry.id,
|
|
1688
|
+
at: entry.startedAt ?? Date.now(),
|
|
1689
|
+
fallbackTopic: firstSentence(entry.userText ?? text),
|
|
1690
|
+
}));
|
|
1691
|
+
const applied = soul.applyThreadSpans(draft.spans, {
|
|
1682
1692
|
sessionId: turnRow?.sessionId ?? 'unknown',
|
|
1683
|
-
|
|
1684
|
-
turnId,
|
|
1685
|
-
at: Date.now(),
|
|
1686
|
-
fallbackTopic: firstSentence(text),
|
|
1693
|
+
turns: spanTurns,
|
|
1687
1694
|
previousThreadId: context.previousThreadId,
|
|
1688
1695
|
});
|
|
1696
|
+
const attribution = applied[0];
|
|
1697
|
+
// One thread keeps the old line's thread part byte for byte (`thread=th_xxx(new)`);
|
|
1698
|
+
// a split segment lists every thread it produced, and `join=` is the unit's
|
|
1699
|
+
// per-turn reasons joined with `+` (one value only when they agree) — the head
|
|
1700
|
+
// alone no longer describes what the rest of the segment did.
|
|
1701
|
+
const threadIds = [...new Set(applied.map((entry) => entry.threadId))];
|
|
1702
|
+
const createdNew = applied.filter((entry) => entry.created).length;
|
|
1703
|
+
const joins = [...new Set(applied.map((entry) => entry.joinReason))].join('+');
|
|
1689
1704
|
const ms = Date.now() - started;
|
|
1690
1705
|
// Provenance is observable (ADR 0035): the fact count alone cannot tell whether
|
|
1691
1706
|
// anything came from my side of the exchange.
|
|
@@ -1699,9 +1714,10 @@ async function runExtraction(text, turnId, turnNo, origin = 'live', unit = null)
|
|
|
1699
1714
|
` inferred=${inferred}` +
|
|
1700
1715
|
` unit=${turns ? `${turns.length}turns` : '1turn'}` +
|
|
1701
1716
|
` ms=${ms} turn=${turnNo} origin=${origin}` +
|
|
1702
|
-
` thread=${
|
|
1703
|
-
|
|
1704
|
-
|
|
1717
|
+
` thread=${threadIds.join(',')}` +
|
|
1718
|
+
`${createdNew > 0 ? (threadIds.length === 1 ? '(new)' : `(${createdNew} new)`) : ''}` +
|
|
1719
|
+
` join=${joins} threadLine=${draft.threadLine ?? 'rules'}` +
|
|
1720
|
+
`${applied.some((entry) => entry.topicUpdated) ? ' topic=updated' : ''}`,
|
|
1705
1721
|
);
|
|
1706
1722
|
for (const skipped of result.skipped.slice(0, 3)) {
|
|
1707
1723
|
log(` extract skipped: ${skipped.what} (${skipped.reason})`);
|
|
@@ -1732,6 +1748,18 @@ async function runExtraction(text, turnId, turnNo, origin = 'live', unit = null)
|
|
|
1732
1748
|
threadTopic: attribution.topic,
|
|
1733
1749
|
threadLine: draft.threadLine ?? null,
|
|
1734
1750
|
topicUpdated: attribution.topicUpdated,
|
|
1751
|
+
// Only when the segment actually split: one thread is the old shape, and the
|
|
1752
|
+
// per-turn runs are what makes a wrong split diagnosable later (0028 ③).
|
|
1753
|
+
...(applied.length > 1
|
|
1754
|
+
? {
|
|
1755
|
+
threadSpans: applied.map((entry, index) => ({
|
|
1756
|
+
span: spanTurns[index].promptNo,
|
|
1757
|
+
thread: entry.threadId,
|
|
1758
|
+
join: entry.joinReason,
|
|
1759
|
+
created: entry.created,
|
|
1760
|
+
})),
|
|
1761
|
+
}
|
|
1762
|
+
: {}),
|
|
1735
1763
|
origin,
|
|
1736
1764
|
joinReason: attribution.joinReason,
|
|
1737
1765
|
ms,
|
|
@@ -1851,7 +1879,11 @@ export async function drainExtractionQueue(options = {}) {
|
|
|
1851
1879
|
// turn, so a fact's 轮次 lands on source_turn_id.
|
|
1852
1880
|
const turns = taken.map((entry, index) => ({
|
|
1853
1881
|
id: entry.item.turnId,
|
|
1882
|
+
// Prompt numbering (1..n, what the model's spans match) and the host's real
|
|
1883
|
+
// turn number (threads count turns that jump by 10–30) are different numbers;
|
|
1884
|
+
// both ride along so attribution never has to guess which is which.
|
|
1854
1885
|
turnNo: index + 1,
|
|
1886
|
+
hostTurnNo: entry.row.turn,
|
|
1855
1887
|
userText: entry.row.userText,
|
|
1856
1888
|
assistantText: entry.row.assistantText,
|
|
1857
1889
|
startedAt: entry.row.at,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-soulbridge",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.121",
|
|
4
4
|
"description": "Inject soulbridge context into DSH sessions and feed user turns back as observations.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -42,6 +42,6 @@
|
|
|
42
42
|
"setup": "node scripts/install-hooks.mjs"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"soulbridge": ">=0.0.
|
|
45
|
+
"soulbridge": ">=0.0.117 <0.1.0"
|
|
46
46
|
}
|
|
47
47
|
}
|