@yeaft/webchat-agent 1.0.347 → 1.0.349

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/yeaft/engine.js CHANGED
@@ -1519,7 +1519,7 @@ export class Engine {
1519
1519
  return Boolean(this.#conversationStore) && !this.#config._readOnly;
1520
1520
  }
1521
1521
 
1522
- #conversationRecord(message, { sessionId, turnId, model, incomplete = false, stopReason = null } = {}) {
1522
+ #conversationRecord(message, { sessionId, turnId, model, incomplete = false, stopReason = null, executionOrigin = null } = {}) {
1523
1523
  const record = {
1524
1524
  role: message.role,
1525
1525
  content: typeof message.content === 'string'
@@ -1545,6 +1545,9 @@ export class Engine {
1545
1545
  record.foldedMessageIds = [...message.foldedMessageIds];
1546
1546
  }
1547
1547
  if (turnId && (message.role === 'assistant' || message.role === 'tool')) record.turnId = turnId;
1548
+ if (executionOrigin === 'route_forward' && (message.role === 'assistant' || message.role === 'tool')) {
1549
+ record.executionOrigin = executionOrigin;
1550
+ }
1548
1551
  if (this.#vpId && (message.role === 'assistant' || message.role === 'tool')) record.speakerVpId = this.#vpId;
1549
1552
  if (incomplete) record.incomplete = true;
1550
1553
  if (stopReason) record.stopReason = stopReason;
@@ -2117,6 +2120,9 @@ export class Engine {
2117
2120
  const runtimeThreadId = (typeof threadId === 'string' && threadId.trim())
2118
2121
  ? threadId.trim()
2119
2122
  : MAIN_THREAD_ID;
2123
+ const executionOrigin = inboundEnvelope?.msg?.meta?.injectedBy === 'route_forward'
2124
+ ? 'route_forward'
2125
+ : null;
2120
2126
  const queryTurnId = randomUUID();
2121
2127
  const queryStartedAt = Date.now();
2122
2128
  const userQuestionPreview = String(prompt || '').slice(0, 200);
@@ -2615,6 +2621,7 @@ export class Engine {
2615
2621
  model: currentModel,
2616
2622
  incomplete: true,
2617
2623
  stopReason: reason,
2624
+ executionOrigin,
2618
2625
  });
2619
2626
  };
2620
2627
  const toolCalls = [];
@@ -3363,6 +3370,7 @@ export class Engine {
3363
3370
  sessionId: runtimeSessionId,
3364
3371
  turnId: vpTurnId || queryTurnId,
3365
3372
  model: currentModel,
3373
+ executionOrigin,
3366
3374
  });
3367
3375
  if (persistedAssistantMessage) {
3368
3376
  assistantMsg._persistedMessageId = persistedAssistantMessage.id;
@@ -3687,6 +3695,7 @@ export class Engine {
3687
3695
  count: pairs.length,
3688
3696
  originalUserMsg: prompt,
3689
3697
  originatingTurnId: queryTurnId,
3698
+ executionOrigin,
3690
3699
  ready: false,
3691
3700
  result: null,
3692
3701
  error: null,
@@ -3973,6 +3982,7 @@ export class Engine {
3973
3982
  sessionId: runtimeSessionId,
3974
3983
  turnId: vpTurnId || queryTurnId,
3975
3984
  model: currentModel,
3985
+ executionOrigin,
3976
3986
  });
3977
3987
  if (persistedToolMessage) {
3978
3988
  toolMessage._persistedMessageId = persistedToolMessage.id;
@@ -4110,7 +4120,7 @@ export class Engine {
4110
4120
  batchStart,
4111
4121
  batchEnd,
4112
4122
  reflectionMessage,
4113
- { sessionId: runtimeSessionId, model: currentModel },
4123
+ { sessionId: runtimeSessionId, model: currentModel, executionOrigin },
4114
4124
  );
4115
4125
  if (durableRowsInRange && !persistedReflection) {
4116
4126
  throw new Error('T1 reflection could not publish its durable range replacement');
@@ -4303,7 +4313,10 @@ export class Engine {
4303
4313
  startIdx,
4304
4314
  endIdx,
4305
4315
  reflectionMessage,
4306
- context,
4316
+ {
4317
+ ...context,
4318
+ executionOrigin: info.executionOrigin === 'route_forward' ? 'route_forward' : null,
4319
+ },
4307
4320
  );
4308
4321
  if (durableRowsInRange && !persistedReflection) continue;
4309
4322
  // Mutate in place so caller's reference stays valid.
@@ -86,7 +86,8 @@ export function extractPriorPlan(messages, vpId) {
86
86
 
87
87
  /**
88
88
  * Return a copy of the messages array with engine-private metadata stripped
89
- * from every message. The serialisers (anthropic/openai-responses) read this;
89
+ * from every message. This includes durable UI-only execution provenance.
90
+ * The serialisers (anthropic/openai-responses) read this;
90
91
  * these fields are NEVER part of the wire payload. Cheap because we only
91
92
  * shallow-clone the messages that actually have private fields.
92
93
  *
@@ -99,9 +100,17 @@ export function stripMetaForWire(messages) {
99
100
  const out = messages.map(m => {
100
101
  if (m && typeof m === 'object'
101
102
  && ('_meta' in m || '_runtimeTurnId' in m || '_partialTurn' in m
102
- || '_persistedMessageId' in m || 'userAuthored' in m)) {
103
+ || '_persistedMessageId' in m || 'userAuthored' in m || 'executionOrigin' in m)) {
103
104
  mutated = true;
104
- const { _meta, _runtimeTurnId, _partialTurn, _persistedMessageId, userAuthored, ...rest } = m;
105
+ const {
106
+ _meta,
107
+ _runtimeTurnId,
108
+ _partialTurn,
109
+ _persistedMessageId,
110
+ userAuthored,
111
+ executionOrigin,
112
+ ...rest
113
+ } = m;
105
114
  return rest;
106
115
  }
107
116
  return m;
package/yeaft/session.js CHANGED
@@ -250,23 +250,12 @@ export async function loadSession(options = {}) {
250
250
  }
251
251
 
252
252
  // ─── 3. Create trajectory trace ─────────────────────────
253
- // Always-on request trace for the Debug panel. It is file-backed, not
254
- // SQLite-backed: each request writes one bounded JSON file under
255
- // `<yeaftDir>/debug/` (session traces are nested under
256
- // `<yeaftDir>/sessions/<sessionId>/debug/requests/`). A request file stores one
257
- // base request snapshot plus per-loop deltas, so 100-200 loop requests do
258
- // not become hundreds of tiny files or repeated cumulative payloads.
253
+ // Debug traces can contain prompts, tool payloads, and provider envelopes.
254
+ // Keep collection opt-in and avoid scanning trace history during Session boot.
259
255
  const trace = createTrace({
260
- enabled: true,
256
+ enabled: config.debug === true,
261
257
  dirPath: yeaftDir,
262
258
  });
263
- // Hard cap debug history to the most recent 10 requests per Session. Trace
264
- // failures are best-effort and must never stop the agent loop. cleanup() is
265
- // now async (it hydrates the in-memory index, then prunes); run it
266
- // fire-and-forget so session load never blocks on the startup disk scan.
267
- Promise.resolve(trace.cleanup?.(10)).catch((err) => {
268
- console.warn('[Yeaft] trace.cleanup failed:', err?.message || err);
269
- });
270
259
 
271
260
  // ─── 4. Create LLM adapter ────────────────────────────
272
261
  const adapter = withUsageAccounting(
@@ -6440,7 +6440,13 @@ export async function handleYeaftFetchDebugHistory(msg = {}) {
6440
6440
  let dreamEvents = [];
6441
6441
  let hasMore = false;
6442
6442
  try {
6443
- if (session?.trace && typeof session.trace.fetchRecentDebugHistory === 'function') {
6443
+ if (session?.trace && detailTurnId && sessionId && typeof session.trace.fetchTurnDebug === 'function') {
6444
+ const out = await session.trace.fetchTurnDebug({ sessionId, turnId: detailTurnId, dreamLimit });
6445
+ loops = Array.isArray(out?.loops) ? out.loops : [];
6446
+ turns = Array.isArray(out?.turns) ? out.turns : [];
6447
+ dreamEvents = Array.isArray(out?.dreamEvents) ? out.dreamEvents : [];
6448
+ hasMore = false;
6449
+ } else if (session?.trace && typeof session.trace.fetchRecentDebugHistory === 'function') {
6444
6450
  const out = await session.trace.fetchRecentDebugHistory({ limit, dreamLimit, sessionId, threadId, indexOnly, detailTurnId, search });
6445
6451
  loops = Array.isArray(out?.loops) ? out.loops : [];
6446
6452
  turns = Array.isArray(out?.turns) ? out.turns : [];
@@ -121,6 +121,7 @@ async function createDefaultService() {
121
121
  policyProvider: async () => readWorkCenterSettings(yeaftDir),
122
122
  attachmentRoot: join(yeaftDir, 'work-center', 'attachments'),
123
123
  yeaftDir,
124
+ debug: ctx.CONFIG?.debug === true,
124
125
  actionWorktreeRoot: join(yeaftDir, 'work-center', 'worktrees'),
125
126
  registry: defaultRegistry,
126
127
  store: null,
@@ -797,7 +797,7 @@ export class WorkItemRunner {
797
797
  this.policyProvider = typeof options.policyProvider === 'function' ? options.policyProvider : null;
798
798
  this.attachmentRoot = options.attachmentRoot || null;
799
799
  this.trace = options.trace || createTrace({
800
- enabled: Boolean(options.yeaftDir),
800
+ enabled: options.debug === true && Boolean(options.yeaftDir),
801
801
  dirPath: options.yeaftDir || null,
802
802
  });
803
803
  this.actionWorktreeRoot = options.actionWorktreeRoot || null;