@recombine-ai/platform 0.9.1-test.1 → 0.9.1-test.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/build/bosun-app/frontend/client/_app/immutable/chunks/{D7a3sSg2.js → 4FZq9ouk.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/4FZq9ouk.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/4FZq9ouk.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{BP8LHuYi.js → CyqpLl7J.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CyqpLl7J.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CyqpLl7J.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{DdbOX2wg.js → DS8Gs9Et.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/DS8Gs9Et.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/DS8Gs9Et.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{CeiDiTKi.js → RQoHgnUz.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/RQoHgnUz.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{CeiDiTKi.js.gz → RQoHgnUz.js.gz} +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{Bgf7U1Tc.js → pgn8lPGH.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/pgn8lPGH.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/pgn8lPGH.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/{app.D20SOteC.js → app.BnxfWXrI.js} +2 -2
- package/build/bosun-app/frontend/client/_app/immutable/entry/app.BnxfWXrI.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/app.BnxfWXrI.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/start.-9o7BwoJ.js +1 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/start.-9o7BwoJ.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/start.-9o7BwoJ.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{0.T9WgLrTj.js → 0.gzTYpBz_.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/0.gzTYpBz_.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/0.gzTYpBz_.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{1.3cRzg0A0.js → 1.BN8lpuUS.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/1.BN8lpuUS.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/1.BN8lpuUS.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{10.28fogxMw.js → 10.Dcq7nqT7.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/10.Dcq7nqT7.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/10.Dcq7nqT7.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{17.CZ8fUbCu.js → 17.Czyb-2Fi.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/17.Czyb-2Fi.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/17.Czyb-2Fi.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{18.CLTXnmXM.js → 18.DR0DZOgU.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/18.DR0DZOgU.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/18.DR0DZOgU.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{2.BVj8fduB.js → 2.BIIegE95.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/2.BIIegE95.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{2.BVj8fduB.js.gz → 2.BIIegE95.js.gz} +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{3.D1hXqvoR.js → 3.7xwGWKCq.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/3.7xwGWKCq.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/3.7xwGWKCq.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{4.Q-efp8BE.js → 4.Bfcf410Z.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/4.Bfcf410Z.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/4.Bfcf410Z.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{5.BlBkWeY0.js → 5.DSGKP42a.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/5.DSGKP42a.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/5.DSGKP42a.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{6.CQPXvkij.js → 6.BEXpYqQW.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/6.BEXpYqQW.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/6.BEXpYqQW.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{8.Bcw_NHql.js → 8.b23ZAcd2.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/8.b23ZAcd2.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/8.b23ZAcd2.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{9.iQdTFqAn.js → 9.XMXj24Oz.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/9.XMXj24Oz.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/9.XMXj24Oz.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/version.json +1 -1
- package/build/bosun-app/frontend/client/_app/version.json.br +0 -0
- package/build/bosun-app/frontend/client/_app/version.json.gz +0 -0
- package/build/bosun-app/frontend/handler.js +4 -4
- package/build/bosun-app/frontend/index.js +4 -4
- package/build/bosun-app/frontend/server/chunks/chunks/{internal.js-BzxoI2ap.js → internal.js-3uEm1Cu_.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/chunks/{internal.js-BzxoI2ap.js.map → internal.js-3uEm1Cu_.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/{handler-DxgO6iGt.js → handler-R2AAMK_d.js} +3 -3
- package/build/bosun-app/frontend/server/chunks/{handler-DxgO6iGt.js.map → handler-R2AAMK_d.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/{index.js-DBoPzuHL.js → index.js-B6PA6y5X.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/{index.js-DBoPzuHL.js.map → index.js-B6PA6y5X.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/{manifest.js-BZqGcn9f.js → manifest.js-Cj-2oIll.js} +14 -14
- package/build/bosun-app/frontend/server/chunks/{manifest.js-BZqGcn9f.js.map → manifest.js-Cj-2oIll.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{0.js-CPauJheb.js → 0.js-CbAwoV50.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{0.js-CPauJheb.js.map → 0.js-CbAwoV50.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{1.js-BdQRe_JA.js → 1.js-DZOnORaH.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{1.js-BdQRe_JA.js.map → 1.js-DZOnORaH.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{10.js-BQ80fBM8.js → 10.js-Bp0YUwTV.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{10.js-BQ80fBM8.js.map → 10.js-Bp0YUwTV.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{17.js-C1ScVFoO.js → 17.js-DWWiIFyE.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{17.js-C1ScVFoO.js.map → 17.js-DWWiIFyE.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{18.js-BErYMv7b.js → 18.js-CZhmYe9G.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{18.js-BErYMv7b.js.map → 18.js-CZhmYe9G.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{2.js-yX-cUBDA.js → 2.js-De6gUBiZ.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{2.js-yX-cUBDA.js.map → 2.js-De6gUBiZ.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{3.js-2Vh4A63Y.js → 3.js-B7tTR5rm.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{3.js-2Vh4A63Y.js.map → 3.js-B7tTR5rm.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{4.js-D_hzQEmf.js → 4.js-DYuQ_t39.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{4.js-D_hzQEmf.js.map → 4.js-DYuQ_t39.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{5.js-Bksbf9B2.js → 5.js-BuTKb27s.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{5.js-Bksbf9B2.js.map → 5.js-BuTKb27s.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{6.js-CBJdIQil.js → 6.js-D1pHkiGV.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{6.js-CBJdIQil.js.map → 6.js-D1pHkiGV.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{8.js-BESSf_tJ.js → 8.js-DX7CP-FP.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{8.js-BESSf_tJ.js.map → 8.js-DX7CP-FP.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{9.js-CAwt5c8Z.js → 9.js-D-08G8Ub.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{9.js-CAwt5c8Z.js.map → 9.js-D-08G8Ub.js.map} +1 -1
- package/build/engine/index.d.ts +3 -2
- package/build/engine/index.d.ts.map +1 -1
- package/build/engine/index.js +1 -1
- package/build/engine/interfaces/stream.d.ts +31 -1
- package/build/engine/interfaces/stream.d.ts.map +1 -1
- package/build/engine/stream/index.d.ts +3 -1
- package/build/engine/stream/index.d.ts.map +1 -1
- package/build/engine/stream/index.js +1 -0
- package/build/engine/stream/jev-prediction-chooser.d.ts +11 -0
- package/build/engine/stream/jev-prediction-chooser.d.ts.map +1 -0
- package/build/engine/stream/jev-prediction-chooser.js +135 -0
- package/build/engine/stream/predictive-prompts.d.ts +1 -1
- package/build/engine/stream/predictive-prompts.d.ts.map +1 -1
- package/build/engine/stream/predictive-prompts.js +7 -28
- package/build/engine/stream/predictive-workflow.d.ts.map +1 -1
- package/build/engine/stream/predictive-workflow.js +199 -45
- package/package.json +2 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/BP8LHuYi.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/BP8LHuYi.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/Bgf7U1Tc.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/Bgf7U1Tc.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CeiDiTKi.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/D7a3sSg2.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/D7a3sSg2.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/DdbOX2wg.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/DdbOX2wg.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/app.D20SOteC.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/app.D20SOteC.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/start.BqFNrTS7.js +0 -1
- package/build/bosun-app/frontend/client/_app/immutable/entry/start.BqFNrTS7.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/start.BqFNrTS7.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/0.T9WgLrTj.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/0.T9WgLrTj.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/1.3cRzg0A0.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/1.3cRzg0A0.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/10.28fogxMw.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/10.28fogxMw.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/17.CZ8fUbCu.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/17.CZ8fUbCu.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/18.CLTXnmXM.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/18.CLTXnmXM.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/2.BVj8fduB.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/3.D1hXqvoR.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/3.D1hXqvoR.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/4.Q-efp8BE.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/4.Q-efp8BE.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/5.BlBkWeY0.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/5.BlBkWeY0.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/6.CQPXvkij.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/6.CQPXvkij.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/8.Bcw_NHql.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/8.Bcw_NHql.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/9.iQdTFqAn.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/9.iQdTFqAn.js.gz +0 -0
|
@@ -9,7 +9,7 @@ export function createPredictiveWorkflow(config, engineConfig, nunjucksEnv) {
|
|
|
9
9
|
if (!predictiveModels) {
|
|
10
10
|
throw new Error('Predictive models are not configured.');
|
|
11
11
|
}
|
|
12
|
-
const { predictorModel,
|
|
12
|
+
const { predictorModel, chooser } = predictiveModels;
|
|
13
13
|
if (!Number.isInteger(config.predictionCount) || config.predictionCount < 1) {
|
|
14
14
|
throw new Error('predictionCount must be a positive integer.');
|
|
15
15
|
}
|
|
@@ -48,8 +48,10 @@ export function createPredictiveWorkflow(config, engineConfig, nunjucksEnv) {
|
|
|
48
48
|
state.stopCurrent?.();
|
|
49
49
|
state.requestGeneration += 1;
|
|
50
50
|
const generation = state.requestGeneration;
|
|
51
|
-
const
|
|
52
|
-
const
|
|
51
|
+
const lastMessage = messages.at(-1);
|
|
52
|
+
const isUserTurn = lastMessage?.sender === 'user';
|
|
53
|
+
const isSubstantiveUserTurn = isUserTurn && lastMessage.text.trim().length > 0;
|
|
54
|
+
const predictionSets = isSubstantiveUserTurn
|
|
53
55
|
? [state.preparedPrewarm, state.preparedNormal].filter(isPreparedSet)
|
|
54
56
|
: [];
|
|
55
57
|
const predictions = predictionSets.flatMap((set) => set.pairs);
|
|
@@ -57,6 +59,7 @@ export function createPredictiveWorkflow(config, engineConfig, nunjucksEnv) {
|
|
|
57
59
|
const renderedPrompt = nunjucksEnv.renderString(template, ctx || {});
|
|
58
60
|
const stringifiedConversation = stringifyMessages(messages);
|
|
59
61
|
const runId = crypto.randomUUID();
|
|
62
|
+
const responseStartedAt = Date.now();
|
|
60
63
|
const mainTrace = {
|
|
61
64
|
workflowId: config.name,
|
|
62
65
|
workflowRunId: runId,
|
|
@@ -69,6 +72,18 @@ export function createPredictiveWorkflow(config, engineConfig, nunjucksEnv) {
|
|
|
69
72
|
renderedPrompt,
|
|
70
73
|
stringifiedConversation,
|
|
71
74
|
};
|
|
75
|
+
logger.info('Predictive response started', {
|
|
76
|
+
callId,
|
|
77
|
+
runId,
|
|
78
|
+
generation,
|
|
79
|
+
messageCount: messages.length,
|
|
80
|
+
lastMessageSender: lastMessage?.sender,
|
|
81
|
+
lastMessageLength: lastMessage?.text.length ?? 0,
|
|
82
|
+
isSubstantiveUserTurn,
|
|
83
|
+
prewarmPredictionCount: state.preparedPrewarm?.pairs.length ?? 0,
|
|
84
|
+
normalPredictionCount: state.preparedNormal?.pairs.length ?? 0,
|
|
85
|
+
chooserCandidateCount: predictions.length,
|
|
86
|
+
});
|
|
72
87
|
let active = true;
|
|
73
88
|
let output = '';
|
|
74
89
|
let outputStarted = false;
|
|
@@ -81,28 +96,55 @@ export function createPredictiveWorkflow(config, engineConfig, nunjucksEnv) {
|
|
|
81
96
|
throw createOperationError(error, config.model, mainTrace);
|
|
82
97
|
});
|
|
83
98
|
const firstProvisionalChunk = readFirstNonEmptyChunk(provisionalStream, mainTrace, config.model);
|
|
84
|
-
const
|
|
99
|
+
const chooserResult = predictions.length
|
|
100
|
+
? choosePrediction(predictions, messages, ctx, runId, isCurrent)
|
|
101
|
+
: new Promise(() => undefined);
|
|
85
102
|
function isCurrent() {
|
|
86
103
|
return active && !state.closed && state.requestGeneration === generation;
|
|
87
104
|
}
|
|
88
105
|
function consumePredictions() {
|
|
106
|
+
const consumesPrewarm = isSubstantiveUserTurn && !state.prewarmConsumed;
|
|
107
|
+
const consumedPrewarmCount = consumesPrewarm
|
|
108
|
+
? (state.preparedPrewarm?.pairs.length ?? 0)
|
|
109
|
+
: 0;
|
|
110
|
+
let consumedNormalCount = 0;
|
|
89
111
|
for (const set of predictionSets) {
|
|
90
|
-
if (state.preparedPrewarm?.id === set.id) {
|
|
91
|
-
state.preparedPrewarm = undefined;
|
|
92
|
-
state.prewarmConsumed = true;
|
|
93
|
-
}
|
|
94
112
|
if (state.preparedNormal?.id === set.id) {
|
|
113
|
+
consumedNormalCount = set.pairs.length;
|
|
95
114
|
state.preparedNormal = undefined;
|
|
96
115
|
}
|
|
97
116
|
}
|
|
117
|
+
if (consumesPrewarm) {
|
|
118
|
+
state.preparedPrewarm = undefined;
|
|
119
|
+
state.prewarmConsumed = true;
|
|
120
|
+
}
|
|
121
|
+
if (isSubstantiveUserTurn || consumedNormalCount > 0) {
|
|
122
|
+
logger.info('Prepared predictions consumed', {
|
|
123
|
+
callId,
|
|
124
|
+
runId,
|
|
125
|
+
generation,
|
|
126
|
+
prewarmPredictionCount: consumedPrewarmCount,
|
|
127
|
+
normalPredictionCount: consumedNormalCount,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
98
130
|
}
|
|
99
|
-
function publish(controller, delta) {
|
|
131
|
+
function publish(controller, delta, source, match) {
|
|
100
132
|
if (!isCurrent() || !delta)
|
|
101
133
|
return false;
|
|
102
134
|
if (!outputStarted) {
|
|
103
135
|
outputStarted = true;
|
|
104
136
|
consumePredictions();
|
|
105
137
|
logger.debug(`[MARK] Predictive workflow TTFT: ${config.name}`);
|
|
138
|
+
logger.info('Predictive response winner selected', {
|
|
139
|
+
callId,
|
|
140
|
+
runId,
|
|
141
|
+
generation,
|
|
142
|
+
source,
|
|
143
|
+
ttftMs: Date.now() - responseStartedAt,
|
|
144
|
+
chooserCandidateCount: predictions.length,
|
|
145
|
+
selectedIndex: match?.index,
|
|
146
|
+
selectedScore: match?.score,
|
|
147
|
+
});
|
|
106
148
|
}
|
|
107
149
|
output += delta;
|
|
108
150
|
controller.enqueue({ role: 'agent', delta });
|
|
@@ -116,6 +158,13 @@ export function createPredictiveWorkflow(config, engineConfig, nunjucksEnv) {
|
|
|
116
158
|
state.stopCurrent = undefined;
|
|
117
159
|
mainTrace.response = output;
|
|
118
160
|
void addAndFlushTrace(stepTracer, mainTrace, logger);
|
|
161
|
+
logger.info('Predictive response completed', {
|
|
162
|
+
callId,
|
|
163
|
+
runId,
|
|
164
|
+
generation,
|
|
165
|
+
durationMs: Date.now() - responseStartedAt,
|
|
166
|
+
outputLength: output.length,
|
|
167
|
+
});
|
|
119
168
|
if (!state.closed) {
|
|
120
169
|
startNormalPrediction(messages, output, renderedPrompt, ctx, state, generation);
|
|
121
170
|
}
|
|
@@ -124,6 +173,13 @@ export function createPredictiveWorkflow(config, engineConfig, nunjucksEnv) {
|
|
|
124
173
|
if (!active)
|
|
125
174
|
return;
|
|
126
175
|
active = false;
|
|
176
|
+
logger.info('Predictive response stopped', {
|
|
177
|
+
callId,
|
|
178
|
+
runId,
|
|
179
|
+
generation,
|
|
180
|
+
outputStarted,
|
|
181
|
+
durationMs: Date.now() - responseStartedAt,
|
|
182
|
+
});
|
|
127
183
|
void provisionalReader?.cancel();
|
|
128
184
|
try {
|
|
129
185
|
publicController?.close();
|
|
@@ -163,27 +219,27 @@ export function createPredictiveWorkflow(config, engineConfig, nunjucksEnv) {
|
|
|
163
219
|
}
|
|
164
220
|
async function orchestrate(controller) {
|
|
165
221
|
try {
|
|
166
|
-
const winner = await Promise.race([firstProvisionalChunk,
|
|
222
|
+
const winner = await Promise.race([firstProvisionalChunk, chooserResult]);
|
|
167
223
|
if (!isCurrent())
|
|
168
224
|
return;
|
|
169
225
|
if (winner.kind === 'prediction') {
|
|
170
226
|
void firstProvisionalChunk
|
|
171
227
|
.then(({ reader }) => reader.cancel())
|
|
172
228
|
.catch(() => undefined);
|
|
173
|
-
publish(controller, winner.pair.agentResponse);
|
|
229
|
+
publish(controller, winner.pair.agentResponse, winner.kind, winner);
|
|
174
230
|
controller.close();
|
|
175
231
|
finishSuccessfulResponse();
|
|
176
232
|
return;
|
|
177
233
|
}
|
|
178
234
|
provisionalReader = winner.reader;
|
|
179
|
-
if (!publish(controller, winner.chunk))
|
|
235
|
+
if (!publish(controller, winner.chunk, winner.kind))
|
|
180
236
|
return;
|
|
181
237
|
while (isCurrent()) {
|
|
182
238
|
try {
|
|
183
239
|
const next = await winner.reader.read();
|
|
184
240
|
if (next.done)
|
|
185
241
|
break;
|
|
186
|
-
if (!publish(controller, next.value))
|
|
242
|
+
if (!publish(controller, next.value, winner.kind))
|
|
187
243
|
return;
|
|
188
244
|
}
|
|
189
245
|
catch (error) {
|
|
@@ -210,14 +266,42 @@ export function createPredictiveWorkflow(config, engineConfig, nunjucksEnv) {
|
|
|
210
266
|
});
|
|
211
267
|
}
|
|
212
268
|
function prewarmForUsersHello(ctx) {
|
|
213
|
-
if (config.prewarmPredictions.length === 0)
|
|
214
|
-
return;
|
|
215
269
|
const callId = getCallId(ctx);
|
|
216
270
|
const state = getOrCreateState(callId);
|
|
217
|
-
if (state.prewarmStarted || state.prewarmConsumed)
|
|
271
|
+
if (state.prewarmStarted || state.prewarmConsumed) {
|
|
272
|
+
logger.debug('Opening prediction prewarm skipped', {
|
|
273
|
+
callId,
|
|
274
|
+
prewarmStarted: state.prewarmStarted,
|
|
275
|
+
prewarmConsumed: state.prewarmConsumed,
|
|
276
|
+
});
|
|
218
277
|
return;
|
|
278
|
+
}
|
|
219
279
|
state.prewarmStarted = true;
|
|
280
|
+
logger.info('Opening prediction prewarm started', {
|
|
281
|
+
callId,
|
|
282
|
+
predictionCount: config.prewarmPredictions.length,
|
|
283
|
+
chooserPrewarmEnabled: chooser.prewarm !== undefined,
|
|
284
|
+
});
|
|
285
|
+
const chooserPrewarmStartedAt = Date.now();
|
|
286
|
+
void chooser
|
|
287
|
+
.prewarm?.()
|
|
288
|
+
.then(() => {
|
|
289
|
+
logger.info('Prediction chooser prewarm completed', {
|
|
290
|
+
callId,
|
|
291
|
+
durationMs: Date.now() - chooserPrewarmStartedAt,
|
|
292
|
+
});
|
|
293
|
+
})
|
|
294
|
+
.catch((error) => {
|
|
295
|
+
logger.warn('Prediction chooser prewarm failed', {
|
|
296
|
+
callId,
|
|
297
|
+
durationMs: Date.now() - chooserPrewarmStartedAt,
|
|
298
|
+
error,
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
if (config.prewarmPredictions.length === 0)
|
|
302
|
+
return;
|
|
220
303
|
const generation = state.requestGeneration;
|
|
304
|
+
const predictionStartedAt = Date.now();
|
|
221
305
|
const task = (async () => {
|
|
222
306
|
const template = typeof config.prompt === 'string' ? config.prompt : await config.prompt.content();
|
|
223
307
|
const renderedPrompt = nunjucksEnv.renderString(template, ctx || {});
|
|
@@ -229,18 +313,32 @@ export function createPredictiveWorkflow(config, engineConfig, nunjucksEnv) {
|
|
|
229
313
|
supplementalPredictions: config.prewarmPredictions,
|
|
230
314
|
traceName: 'predictor[prewarm]',
|
|
231
315
|
});
|
|
232
|
-
|
|
316
|
+
const stored = !state.closed && !state.prewarmConsumed;
|
|
317
|
+
if (stored) {
|
|
233
318
|
state.preparedPrewarm = { id: crypto.randomUUID(), pairs: prediction.pairs };
|
|
319
|
+
}
|
|
320
|
+
logger.info('Opening prediction prewarm completed', {
|
|
321
|
+
callId,
|
|
322
|
+
durationMs: Date.now() - predictionStartedAt,
|
|
323
|
+
predictionCount: prediction.pairs.length,
|
|
324
|
+
stored,
|
|
325
|
+
discardReason: state.closed
|
|
326
|
+
? 'call-closed'
|
|
327
|
+
: state.prewarmConsumed
|
|
328
|
+
? 'opening-turn-consumed'
|
|
329
|
+
: undefined,
|
|
330
|
+
});
|
|
331
|
+
if (!state.closed) {
|
|
234
332
|
await addAndFlushTrace(stepTracer, prediction.trace, logger);
|
|
235
333
|
}
|
|
236
334
|
})();
|
|
237
|
-
trackPrediction(task, state, ctx, generation);
|
|
335
|
+
trackPrediction(task, state, ctx, generation, () => !state.prewarmConsumed);
|
|
238
336
|
}
|
|
239
337
|
async function waitForPendingPrediction(callId) {
|
|
240
338
|
const state = states.get(callId);
|
|
241
339
|
if (!state)
|
|
242
340
|
return;
|
|
243
|
-
await Promise.all([...
|
|
341
|
+
await Promise.all([...state.pendingPredictions.values()].flatMap((predictions) => [...predictions]));
|
|
244
342
|
}
|
|
245
343
|
function clear(callId) {
|
|
246
344
|
const state = states.get(callId);
|
|
@@ -267,6 +365,12 @@ export function createPredictiveWorkflow(config, engineConfig, nunjucksEnv) {
|
|
|
267
365
|
return state;
|
|
268
366
|
}
|
|
269
367
|
function startNormalPrediction(messages, agentResponse, renderedMainPrompt, ctx, state, generation) {
|
|
368
|
+
const callId = getCallId(ctx);
|
|
369
|
+
const predictionStartedAt = Date.now();
|
|
370
|
+
logger.debug('Normal prediction generation started', {
|
|
371
|
+
callId,
|
|
372
|
+
generation,
|
|
373
|
+
});
|
|
270
374
|
const conversationWithResponse = [
|
|
271
375
|
stringifyMessages(messages).trim(),
|
|
272
376
|
`Agent: ${agentResponse.trim()}`,
|
|
@@ -281,16 +385,31 @@ export function createPredictiveWorkflow(config, engineConfig, nunjucksEnv) {
|
|
|
281
385
|
supplementalPredictions: config.normalFlowPredictions,
|
|
282
386
|
traceName: 'predictor[normal]',
|
|
283
387
|
}).then(async (prediction) => {
|
|
284
|
-
|
|
388
|
+
const stored = !state.closed && state.requestGeneration === generation;
|
|
389
|
+
if (stored) {
|
|
285
390
|
state.preparedNormal = { id: crypto.randomUUID(), pairs: prediction.pairs };
|
|
391
|
+
}
|
|
392
|
+
logger.info('Normal prediction generation completed', {
|
|
393
|
+
callId,
|
|
394
|
+
generation,
|
|
395
|
+
durationMs: Date.now() - predictionStartedAt,
|
|
396
|
+
predictionCount: prediction.pairs.length,
|
|
397
|
+
stored,
|
|
398
|
+
discardReason: state.closed
|
|
399
|
+
? 'call-closed'
|
|
400
|
+
: state.requestGeneration !== generation
|
|
401
|
+
? 'conversation-changed'
|
|
402
|
+
: undefined,
|
|
403
|
+
});
|
|
404
|
+
if (!state.closed) {
|
|
286
405
|
await addAndFlushTrace(stepTracer, prediction.trace, logger);
|
|
287
406
|
}
|
|
288
407
|
});
|
|
289
408
|
trackPrediction(task, state, ctx, generation);
|
|
290
409
|
}
|
|
291
|
-
function trackPrediction(task, state, ctx, generation) {
|
|
410
|
+
function trackPrediction(task, state, ctx, generation, isRelevant = () => state.requestGeneration === generation) {
|
|
292
411
|
const handled = task.catch(async (error) => {
|
|
293
|
-
if (state.closed ||
|
|
412
|
+
if (state.closed || !isRelevant())
|
|
294
413
|
return;
|
|
295
414
|
const operation = isOperationError(error) ? error : undefined;
|
|
296
415
|
const cause = operation?.cause ?? error;
|
|
@@ -364,46 +483,81 @@ export function createPredictiveWorkflow(config, engineConfig, nunjucksEnv) {
|
|
|
364
483
|
});
|
|
365
484
|
return { pairs, trace };
|
|
366
485
|
}
|
|
367
|
-
async function choosePrediction(
|
|
486
|
+
async function choosePrediction(pairs, messages, ctx, parentRunId, isActive) {
|
|
487
|
+
const callId = getCallId(ctx);
|
|
488
|
+
const chooserStartedAt = Date.now();
|
|
368
489
|
const actualUserResponse = messages.at(-1)?.text ?? '';
|
|
369
|
-
const history =
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
reference: pair.userResponse,
|
|
373
|
-
alternative: actualUserResponse,
|
|
374
|
-
});
|
|
490
|
+
const history = messages.slice(0, -1);
|
|
491
|
+
const stringifiedHistory = stringifyMessages(history);
|
|
492
|
+
const input = { history, actualUserResponse, candidates: pairs };
|
|
375
493
|
const trace = {
|
|
376
494
|
workflowId: config.name,
|
|
377
495
|
workflowRunId: parentRunId,
|
|
378
496
|
name: 'chooser',
|
|
379
|
-
model: JSON.stringify(
|
|
497
|
+
model: JSON.stringify(chooser.getOptions()),
|
|
380
498
|
createdAt: Date.now(),
|
|
381
499
|
response: '',
|
|
382
500
|
receivedContext: ctx,
|
|
383
501
|
receivedPrompt: chooserPrompt,
|
|
384
|
-
renderedPrompt:
|
|
385
|
-
stringifiedConversation:
|
|
502
|
+
renderedPrompt: JSON.stringify(input),
|
|
503
|
+
stringifiedConversation: stringifiedHistory,
|
|
386
504
|
};
|
|
387
|
-
let
|
|
505
|
+
let result;
|
|
388
506
|
try {
|
|
389
|
-
|
|
507
|
+
result = await chooser.choose(input);
|
|
390
508
|
}
|
|
391
509
|
catch (error) {
|
|
392
|
-
throw createOperationError(error,
|
|
510
|
+
throw createOperationError(error, chooser, trace);
|
|
393
511
|
}
|
|
394
|
-
if (!isActive())
|
|
512
|
+
if (!isActive()) {
|
|
513
|
+
logger.debug('Prediction chooser result ignored', {
|
|
514
|
+
callId,
|
|
515
|
+
parentRunId,
|
|
516
|
+
durationMs: Date.now() - chooserStartedAt,
|
|
517
|
+
reason: 'response-replaced',
|
|
518
|
+
});
|
|
395
519
|
return new Promise(() => undefined);
|
|
396
|
-
const label = raw.trim();
|
|
397
|
-
trace.response = label;
|
|
398
|
-
if (label !== 'N' && label !== 'U') {
|
|
399
|
-
if (label === 'E') {
|
|
400
|
-
void addAndFlushTrace(stepTracer, trace, logger);
|
|
401
|
-
return { kind: 'prediction', pair };
|
|
402
|
-
}
|
|
403
|
-
throw createOperationError(new Error(`Chooser returned an invalid label: ${label}`), chooserModel, trace);
|
|
404
520
|
}
|
|
521
|
+
trace.response = JSON.stringify(result);
|
|
522
|
+
if (result.scores.length !== pairs.length) {
|
|
523
|
+
throw createOperationError(new Error('Chooser returned the wrong number of candidate scores.'), chooser, trace);
|
|
524
|
+
}
|
|
525
|
+
if (result.selectedIndex === undefined) {
|
|
526
|
+
logger.info('Prediction chooser completed', {
|
|
527
|
+
callId,
|
|
528
|
+
parentRunId,
|
|
529
|
+
durationMs: Date.now() - chooserStartedAt,
|
|
530
|
+
candidateCount: pairs.length,
|
|
531
|
+
scores: result.scores,
|
|
532
|
+
usage: result.usage,
|
|
533
|
+
diagnostics: result.diagnostics,
|
|
534
|
+
});
|
|
535
|
+
void addAndFlushTrace(stepTracer, trace, logger);
|
|
536
|
+
return new Promise(() => undefined);
|
|
537
|
+
}
|
|
538
|
+
if (!Number.isInteger(result.selectedIndex) ||
|
|
539
|
+
result.selectedIndex < 0 ||
|
|
540
|
+
result.selectedIndex >= pairs.length) {
|
|
541
|
+
throw createOperationError(new Error('Chooser returned an invalid candidate index.'), chooser, trace);
|
|
542
|
+
}
|
|
543
|
+
logger.info('Prediction chooser completed', {
|
|
544
|
+
callId,
|
|
545
|
+
parentRunId,
|
|
546
|
+
durationMs: Date.now() - chooserStartedAt,
|
|
547
|
+
candidateCount: pairs.length,
|
|
548
|
+
selectedIndex: result.selectedIndex,
|
|
549
|
+
selectedScore: result.scores[result.selectedIndex],
|
|
550
|
+
scores: result.scores,
|
|
551
|
+
usage: result.usage,
|
|
552
|
+
diagnostics: result.diagnostics,
|
|
553
|
+
});
|
|
405
554
|
void addAndFlushTrace(stepTracer, trace, logger);
|
|
406
|
-
return
|
|
555
|
+
return {
|
|
556
|
+
kind: 'prediction',
|
|
557
|
+
pair: pairs[result.selectedIndex],
|
|
558
|
+
index: result.selectedIndex,
|
|
559
|
+
score: result.scores[result.selectedIndex],
|
|
560
|
+
};
|
|
407
561
|
}
|
|
408
562
|
return { run, prewarmForUsersHello, waitForPendingPrediction, clear };
|
|
409
563
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@recombine-ai/platform",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.9.1-test.
|
|
4
|
+
"version": "0.9.1-test.3",
|
|
5
5
|
"description": "The Recombine platform: engine, telescope, dockyard, call control, the voice agent API, and the Bosun bindings in one package",
|
|
6
6
|
"license": "EULA",
|
|
7
7
|
"author": "recombine.ai",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"registry": "https://registry.npmjs.org"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
+
"@typesafe-ai/sdk": "0.6.0",
|
|
45
46
|
"dotenv": "17.4.2",
|
|
46
47
|
"esbuild": "0.27.3",
|
|
47
48
|
"fast-xml-parser": "5.7.3",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as r}from"../chunks/BP8LHuYi.js";import{y as t}from"../chunks/D7a3sSg2.js";export{t as load_css,r as start};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|