@yeaft/webchat-agent 0.1.603 → 0.1.605

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeaft/webchat-agent",
3
- "version": "0.1.603",
3
+ "version": "0.1.605",
4
4
  "description": "Remote agent for Yeaft WebChat — connects worker machines to the central server",
5
5
  "main": "index.js",
6
6
  "type": "module",
package/unify/engine.js CHANGED
@@ -537,11 +537,13 @@ export class Engine {
537
537
  const budget = this.#config.messageTokenBudget || 8192;
538
538
  const compactCfg = (this.#config && this.#config.compact) || {};
539
539
 
540
- // Phase 8 PR-D: orchestrator opt-in. evaluateCompactTriggers (DESIGN
541
- // §4.1) and runCompact (DESIGN §4.2) are the new path. Existing
542
- // shouldConsolidate / consolidate stays as the default to preserve
543
- // production behaviour; flip via config.compact.useOrchestrator=true.
544
- if (compactCfg.useOrchestrator) {
540
+ // Phase 8 PR-H: orchestrator is now the default. The legacy
541
+ // shouldConsolidate / consolidate path remains reachable as an
542
+ // explicit fallback via `config.compact.useLegacy=true` for parity
543
+ // testing during migration. evaluateCompactTriggers (DESIGN §4.1)
544
+ // and runCompact (DESIGN §4.2) own the live path.
545
+ const useLegacy = compactCfg.useLegacy === true || compactCfg.useOrchestrator === false;
546
+ if (!useLegacy) {
545
547
  return this.#runOrchestratorCompact(budget, compactCfg);
546
548
  }
547
549
 
@@ -711,7 +713,7 @@ export class Engine {
711
713
  * SCENARIO_EFFORT. Unknown values fall through to 'high'.
712
714
  * @yields {EngineEvent}
713
715
  */
714
- async *query({ prompt, messages = [], signal, userEffort = null, scenario = 'chat', vpPersona, router, senderVpId, inboundEnvelope, taskId, taskMembers, groupId } = {}) {
716
+ async *query({ prompt, messages = [], signal, userEffort = null, scenario = 'chat', vpPersona, router, senderVpId, inboundEnvelope, taskId, taskMembers, groupId, vpPlan } = {}) {
715
717
  if (!prompt || typeof prompt !== 'string' || !prompt.trim()) {
716
718
  yield {
717
719
  type: 'error',
@@ -762,7 +764,7 @@ export class Engine {
762
764
  const runSignal = abortCtrl.signal;
763
765
 
764
766
  try {
765
- yield* this.#runQuery({ prompt: effectivePrompt, messages, signal: runSignal, userEffort: effectiveUserEffort, scenario, vpPersona, router, senderVpId, inboundEnvelope, taskId, taskMembers, groupId });
767
+ yield* this.#runQuery({ prompt: effectivePrompt, messages, signal: runSignal, userEffort: effectiveUserEffort, scenario, vpPersona, router, senderVpId, inboundEnvelope, taskId, taskMembers, groupId, vpPlan });
766
768
  } finally {
767
769
  if (signal) {
768
770
  try { signal.removeEventListener('abort', onExternalAbort); } catch { /* ignore */ }
@@ -780,7 +782,7 @@ export class Engine {
780
782
  * in a try/finally without indenting the whole loop.
781
783
  * @private
782
784
  */
783
- async *#runQuery({ prompt, messages, signal, userEffort = null, scenario = 'chat', vpPersona, router, senderVpId, inboundEnvelope, taskId, taskMembers, groupId }) {
785
+ async *#runQuery({ prompt, messages, signal, userEffort = null, scenario = 'chat', vpPersona, router, senderVpId, inboundEnvelope, taskId, taskMembers, groupId, vpPlan }) {
784
786
 
785
787
  // ─── Pre-query: Memory Injection (task-287) + Compact Summary ──
786
788
  // Two-layer recall:
@@ -900,10 +902,19 @@ export class Engine {
900
902
  if (vpPersona && vpPersona.vpId) {
901
903
  const priorPlan = extractPriorPlan(conversationMessages, vpPersona.vpId);
902
904
  const thinkingCfg = (this.#config && this.#config.thinking) || {};
905
+ // PR-I: live routerPlan.thinking — when the dispatcher passes
906
+ // `vpPlan` for this turn (per-VP plan from the V2 router) and its
907
+ // `vpId` matches the active persona, surface its `thinking` field
908
+ // to resolveThinking. Mismatched vpId means the plan addresses a
909
+ // different VP — ignore it for this VP's thinking decision.
910
+ const liveRouterThinking = (vpPlan && typeof vpPlan === 'object'
911
+ && typeof vpPlan.vpId === 'string' && vpPlan.vpId === vpPersona.vpId
912
+ && (vpPlan.thinking === 'high' || vpPlan.thinking === 'max'))
913
+ ? vpPlan.thinking
914
+ : null;
903
915
  const resolved = resolveThinking({
904
916
  uiOverride: (userEffort === 'max' || userEffort === 'high') ? userEffort : null,
905
- routerPlan: null, // PR-C scope: priorPlan continuity only;
906
- // live router-plan thinking is a follow-up.
917
+ routerPlan: liveRouterThinking,
907
918
  priorPlan: priorPlan && priorPlan.thinking ? priorPlan.thinking : null,
908
919
  vpDefault: typeof vpPersona.thinking === 'string' ? vpPersona.thinking : null,
909
920
  globalDefault: typeof thinkingCfg.default === 'string' ? thinkingCfg.default : null,
@@ -1104,12 +1115,29 @@ export class Engine {
1104
1115
  // assistant message that produced it. Stripped at the wire by
1105
1116
  // stripMetaForWire — pure bookkeeping for priorPlan continuity.
1106
1117
  if (vpPersona && vpPersona.vpId) {
1118
+ // PR-I: when the dispatcher hands us a per-VP plan whose vpId matches
1119
+ // the active persona, persist its `forwardQuery`, `preselect`, and
1120
+ // `thinking` on the assistant message so the next turn's
1121
+ // priorPlan continuity (DESIGN.md §9.15) sees the live router's
1122
+ // decision — not a synthetic stub.
1123
+ const planForThisVp = (vpPlan && typeof vpPlan === 'object'
1124
+ && typeof vpPlan.vpId === 'string' && vpPlan.vpId === vpPersona.vpId)
1125
+ ? vpPlan
1126
+ : null;
1107
1127
  attachRouterPlan(assistantMsg, {
1108
1128
  vpId: vpPersona.vpId,
1109
- forwardQuery: { userOriginal: prompt || '', intent: '' },
1110
- preselect: undefined,
1111
- thinking: null,
1112
- thinkingReason: '',
1129
+ forwardQuery: planForThisVp && planForThisVp.forwardQuery
1130
+ ? planForThisVp.forwardQuery
1131
+ : { userOriginal: prompt || '', intent: '' },
1132
+ preselect: planForThisVp && planForThisVp.preselect
1133
+ ? planForThisVp.preselect
1134
+ : undefined,
1135
+ thinking: planForThisVp && (planForThisVp.thinking === 'high' || planForThisVp.thinking === 'max')
1136
+ ? planForThisVp.thinking
1137
+ : null,
1138
+ thinkingReason: planForThisVp && typeof planForThisVp.thinkingReason === 'string'
1139
+ ? planForThisVp.thinkingReason
1140
+ : '',
1113
1141
  });
1114
1142
  }
1115
1143
  conversationMessages.push(assistantMsg);
@@ -97,7 +97,7 @@ export class EngineInstance {
97
97
  * @param {AbortSignal} [params.signal]
98
98
  * @yields {object} EngineEvent with { ...event, threadId }
99
99
  */
100
- async *query({ prompt, mode, signal, vpPersona, router, senderVpId, inboundEnvelope, taskId, taskMembers, groupId } = {}) {
100
+ async *query({ prompt, mode, signal, vpPersona, router, senderVpId, inboundEnvelope, taskId, taskMembers, groupId, vpPlan } = {}) {
101
101
  if (this.#terminated) {
102
102
  yield {
103
103
  type: 'error',
@@ -173,7 +173,7 @@ export class EngineInstance {
173
173
  curToolResults = [];
174
174
  }
175
175
 
176
- for await (const event of this.#engine.query({ prompt, mode, messages: snapshot, signal, vpPersona, router, senderVpId, inboundEnvelope, taskId, taskMembers, groupId })) {
176
+ for await (const event of this.#engine.query({ prompt, mode, messages: snapshot, signal, vpPersona, router, senderVpId, inboundEnvelope, taskId, taskMembers, groupId, vpPlan })) {
177
177
  // Re-tag every event with the bound threadId. Non-object events
178
178
  // (shouldn't happen — all engine events are objects) are passed
179
179
  // through untouched.