@yeaft/webchat-agent 1.0.345 → 1.0.347
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/local-runtime/server/db/connection.js +12 -2
- package/local-runtime/server/db/session-ui-metadata-db.js +38 -21
- package/local-runtime/server/handlers/agent-conversation.js +23 -3
- package/local-runtime/server/handlers/agent-output.js +6 -1
- package/local-runtime/server/handlers/client-conversation.js +120 -28
- package/local-runtime/server/session-catalog.js +18 -11
- package/local-runtime/server/ws-utils.js +20 -5
- package/local-runtime/version.json +1 -1
- package/local-runtime/web/app.bundle.js +302 -193
- 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/session-message-quote.js +58 -7
- package/yeaft/work-center/bridge.js +3 -3
- package/yeaft/work-center/controller.js +6 -1
- package/yeaft/work-center/coordinator.js +12 -2
- package/yeaft/work-center/mainline-projection.js +210 -61
- package/yeaft/work-center/projection.js +23 -0
- package/yeaft/work-center/runner.js +17 -7
- package/yeaft/work-center/service.js +3 -0
- package/yeaft/work-center/store.js +14 -5
- package/yeaft/work-center/workflow.js +6 -1
|
@@ -12,6 +12,7 @@ import { runPreflow } from '../memory/preflow.js';
|
|
|
12
12
|
import { formatPickedForInjection } from '../sessions/pre-flow.js';
|
|
13
13
|
import { existsSync, lstatSync, realpathSync } from 'node:fs';
|
|
14
14
|
import path from 'node:path';
|
|
15
|
+
import { sessionMessageQuotePrompt } from '../session-message-quote.js';
|
|
15
16
|
import { buildWorkItemAttachmentContext } from './attachments.js';
|
|
16
17
|
import { withUsageAccounting } from '../llm/usage-accounting.js';
|
|
17
18
|
import {
|
|
@@ -62,6 +63,21 @@ const WORK_ITEM_TOOL_NAMES = Object.freeze([
|
|
|
62
63
|
]);
|
|
63
64
|
const WORK_ITEM_TOOL_ALLOWLIST = new Set(WORK_ITEM_TOOL_NAMES);
|
|
64
65
|
const DEFAULT_PROGRESS_INTERVAL_MS = 200;
|
|
66
|
+
const ACTION_INPUT_QUOTE_MAX_BYTES = 8 * 1024;
|
|
67
|
+
|
|
68
|
+
export function renderPendingActionInput(item, attachmentFileById = new Map()) {
|
|
69
|
+
const attachments = Array.isArray(item?.attachments) ? item.attachments : [];
|
|
70
|
+
const attachmentLines = attachments.map(attachment => {
|
|
71
|
+
const file = attachmentFileById.get(attachment.id);
|
|
72
|
+
return file ? `- ${attachment.name}: ${file.ref}` : `- ${attachment.name}`;
|
|
73
|
+
});
|
|
74
|
+
const quoteContext = sessionMessageQuotePrompt(item?.quote, {
|
|
75
|
+
maxBytes: ACTION_INPUT_QUOTE_MAX_BYTES,
|
|
76
|
+
});
|
|
77
|
+
return [item?.text || '', quoteContext, attachmentLines.length > 0
|
|
78
|
+
? `Additional WorkItem attachments:\n${attachmentLines.join('\n')}` : '']
|
|
79
|
+
.filter(Boolean).join('\n\n');
|
|
80
|
+
}
|
|
65
81
|
|
|
66
82
|
function structuredOutcome(value) {
|
|
67
83
|
return value && typeof value === 'object'
|
|
@@ -1197,13 +1213,7 @@ export class WorkItemRunner {
|
|
|
1197
1213
|
) || [];
|
|
1198
1214
|
const accepted = [];
|
|
1199
1215
|
for (const item of pending) {
|
|
1200
|
-
const
|
|
1201
|
-
const file = attachmentFileById.get(attachment.id);
|
|
1202
|
-
return file ? `- ${attachment.name}: ${file.ref}` : `- ${attachment.name}`;
|
|
1203
|
-
});
|
|
1204
|
-
const content = [item.text, attachmentLines.length > 0
|
|
1205
|
-
? `Additional WorkItem attachments:\n${attachmentLines.join('\n')}` : '']
|
|
1206
|
-
.filter(Boolean).join('\n\n');
|
|
1216
|
+
const content = renderPendingActionInput(item, attachmentFileById);
|
|
1207
1217
|
if (!content) continue;
|
|
1208
1218
|
pendingEntriesById.set(String(item.id), item);
|
|
1209
1219
|
accepted.push({
|
|
@@ -388,6 +388,7 @@ export class WorkCenterService {
|
|
|
388
388
|
ledgerRevision: payload.ledgerRevision,
|
|
389
389
|
coordinatorRevision: payload.coordinatorRevision,
|
|
390
390
|
clientMessageId: typeof payload.clientMessageId === 'string' ? payload.clientMessageId : null,
|
|
391
|
+
quote: payload.quote,
|
|
391
392
|
addedAttachments,
|
|
392
393
|
attachments: [...(workItem.attachments || []), ...addedAttachments],
|
|
393
394
|
}, {
|
|
@@ -450,6 +451,7 @@ export class WorkCenterService {
|
|
|
450
451
|
revision: payload.revision,
|
|
451
452
|
generation,
|
|
452
453
|
clientMessageId: typeof payload.clientMessageId === 'string' ? payload.clientMessageId : null,
|
|
454
|
+
quote: payload.quote,
|
|
453
455
|
addedAttachmentCount: addedAttachments.length,
|
|
454
456
|
addedAttachments,
|
|
455
457
|
attachments: [...(workItem.attachments || []), ...addedAttachments],
|
|
@@ -610,6 +612,7 @@ export class WorkCenterService {
|
|
|
610
612
|
recovery: Boolean(recoverable.recovery),
|
|
611
613
|
addedAttachments: Array.isArray(recoverable.addedAttachments)
|
|
612
614
|
? recoverable.addedAttachments : [],
|
|
615
|
+
quote: recoverable.quote || null,
|
|
613
616
|
onUpdate: (type, detail) => this.#emit({ type, workItem: detail }),
|
|
614
617
|
});
|
|
615
618
|
turn?.task?.catch?.(() => {});
|
|
@@ -385,6 +385,8 @@ function carryCurrentActionInputContext(db, action, extraInputs = [], explicitOn
|
|
|
385
385
|
return [{
|
|
386
386
|
...entry,
|
|
387
387
|
inputId,
|
|
388
|
+
summary: event?.data?.text || entry.summary || '',
|
|
389
|
+
quote: event?.data?.quote || entry.quote || null,
|
|
388
390
|
attachments: Array.isArray(entry.attachments) && entry.attachments.length > 0
|
|
389
391
|
? entry.attachments
|
|
390
392
|
: inputAttachments(event),
|
|
@@ -400,6 +402,7 @@ function carryCurrentActionInputContext(db, action, extraInputs = [], explicitOn
|
|
|
400
402
|
role: 'user',
|
|
401
403
|
inputId,
|
|
402
404
|
summary: event.data?.text || '',
|
|
405
|
+
quote: event.data?.quote || null,
|
|
403
406
|
attachments: inputAttachments(event),
|
|
404
407
|
evidence: [],
|
|
405
408
|
});
|
|
@@ -1755,7 +1758,7 @@ export class WorkItemStore {
|
|
|
1755
1758
|
return true;
|
|
1756
1759
|
}
|
|
1757
1760
|
|
|
1758
|
-
addActionInput(id, input, expected, attachments = null, addedAttachments = [], clientMessageId = null) {
|
|
1761
|
+
addActionInput(id, input, expected, attachments = null, addedAttachments = [], clientMessageId = null, quote = null) {
|
|
1759
1762
|
return withTransaction(this.db, () => {
|
|
1760
1763
|
const sourceKey = typeof clientMessageId === 'string' && clientMessageId
|
|
1761
1764
|
? `client:message:${id}:${clientMessageId}` : null;
|
|
@@ -1818,6 +1821,7 @@ export class WorkItemStore {
|
|
|
1818
1821
|
role: 'user',
|
|
1819
1822
|
inputId,
|
|
1820
1823
|
summary: input,
|
|
1824
|
+
quote,
|
|
1821
1825
|
attachments: projectedAttachments,
|
|
1822
1826
|
evidence: [],
|
|
1823
1827
|
});
|
|
@@ -1871,6 +1875,7 @@ export class WorkItemStore {
|
|
|
1871
1875
|
inputId,
|
|
1872
1876
|
clientMessageId,
|
|
1873
1877
|
text: input,
|
|
1878
|
+
quote,
|
|
1874
1879
|
attachments: projectedAttachments,
|
|
1875
1880
|
}, { actionId: action.id, runId: eventRunId, actionGeneration: eventGeneration });
|
|
1876
1881
|
if (action.status === 'running') {
|
|
@@ -1896,7 +1901,7 @@ export class WorkItemStore {
|
|
|
1896
1901
|
status: 'pending',
|
|
1897
1902
|
text: input,
|
|
1898
1903
|
attachments: projectedAttachments,
|
|
1899
|
-
payload: { eventId, inputId, actionGeneration: eventGeneration, actionSpecHash: eventSpecHash },
|
|
1904
|
+
payload: { eventId, inputId, quote, actionGeneration: eventGeneration, actionSpecHash: eventSpecHash },
|
|
1900
1905
|
createdAt: now,
|
|
1901
1906
|
}, sourceKey || `pending_action_inputs:event:${eventId}`);
|
|
1902
1907
|
} else if (sourceKey) {
|
|
@@ -1909,7 +1914,7 @@ export class WorkItemStore {
|
|
|
1909
1914
|
status: 'consumed',
|
|
1910
1915
|
text: input,
|
|
1911
1916
|
attachments: projectedAttachments,
|
|
1912
|
-
payload: { eventId, inputId, actionGeneration: eventGeneration, actionSpecHash: eventSpecHash },
|
|
1917
|
+
payload: { eventId, inputId, quote, actionGeneration: eventGeneration, actionSpecHash: eventSpecHash },
|
|
1913
1918
|
createdAt: now,
|
|
1914
1919
|
}, sourceKey);
|
|
1915
1920
|
}
|
|
@@ -1920,8 +1925,8 @@ export class WorkItemStore {
|
|
|
1920
1925
|
listPendingActionInputs(actionId, runId, ownerBootId, leaseEpoch) {
|
|
1921
1926
|
const active = this.#activeRunRow(runId, ownerBootId, leaseEpoch, true);
|
|
1922
1927
|
if (!active || active.action_id !== actionId) return [];
|
|
1923
|
-
return this.db.prepare(`SELECT p.*, ae.id AS action_entry_id, ae.sequence AS action_entry_sequence
|
|
1924
|
-
FROM pending_action_inputs p
|
|
1928
|
+
return this.db.prepare(`SELECT p.*, ae.id AS action_entry_id, ae.sequence AS action_entry_sequence,
|
|
1929
|
+
ae.payload AS action_entry_payload FROM pending_action_inputs p
|
|
1925
1930
|
LEFT JOIN action_entries ae ON CAST(json_extract(ae.payload, '$.eventId') AS INTEGER) = p.event_id
|
|
1926
1931
|
AND ae.action_id = p.action_id
|
|
1927
1932
|
WHERE p.action_id = ? AND p.run_id = ? AND p.action_generation = ? AND p.action_spec_hash = ?
|
|
@@ -1932,6 +1937,7 @@ export class WorkItemStore {
|
|
|
1932
1937
|
actionEntryId: row.action_entry_id || null,
|
|
1933
1938
|
sequence: row.action_entry_sequence == null ? null : Number(row.action_entry_sequence),
|
|
1934
1939
|
text: row.text || '',
|
|
1940
|
+
quote: parseJson(row.action_entry_payload, null)?.quote || null,
|
|
1935
1941
|
attachments: parseJson(row.attachments, []),
|
|
1936
1942
|
}));
|
|
1937
1943
|
}
|
|
@@ -3155,9 +3161,11 @@ export class WorkItemStore {
|
|
|
3155
3161
|
throw new Error('WorkItem Coordinator message or attachments are required');
|
|
3156
3162
|
}
|
|
3157
3163
|
const turnId = randomUUID();
|
|
3164
|
+
const quote = options.quote && typeof options.quote === 'object' ? options.quote : null;
|
|
3158
3165
|
const userMessage = automaticRecovery ? null : {
|
|
3159
3166
|
id: randomUUID(), turnId, role: 'user', text, attachments: projectedAttachments,
|
|
3160
3167
|
status: 'completed', createdAt: now,
|
|
3168
|
+
...(quote ? { quote } : {}),
|
|
3161
3169
|
};
|
|
3162
3170
|
const assistantMessage = {
|
|
3163
3171
|
id: randomUUID(), turnId, role: 'assistant', text: '', status: 'thinking',
|
|
@@ -3177,6 +3185,7 @@ export class WorkItemStore {
|
|
|
3177
3185
|
text,
|
|
3178
3186
|
recovery,
|
|
3179
3187
|
clientMessageId,
|
|
3188
|
+
...(quote ? { quote } : {}),
|
|
3180
3189
|
addedAttachments: projectedAttachments,
|
|
3181
3190
|
}, clientMessageId ? `client:message:${id}:${clientMessageId}` : `coordinator:turn:${turnId}`);
|
|
3182
3191
|
const messages = [...(workItem.messages || []), ...(userMessage ? [userMessage] : []), assistantMessage]
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sessionMessageQuotePrompt } from '../session-message-quote.js';
|
|
1
2
|
import { renderSessionContextSnapshot } from './session-context.js';
|
|
2
3
|
|
|
3
4
|
export const BUILT_IN_ACTION_TYPES = Object.freeze([
|
|
@@ -22,6 +23,7 @@ const MODEL_MODES = new Set(['inherit', 'primary', 'fast', 'specific']);
|
|
|
22
23
|
const MODEL_EFFORTS = new Set(['minimal', 'low', 'medium', 'high', 'xhigh', 'max']);
|
|
23
24
|
const WORKSPACE_MODES = new Set(['shared', 'read', 'isolated-write', 'integrate']);
|
|
24
25
|
const HIGH_EFFORT_ACTION_TYPES = new Set(['triage', 'research', 'design', 'diagnose', 'review']);
|
|
26
|
+
const ACTION_CONTEXT_QUOTE_MAX_BYTES = 8 * 1024;
|
|
25
27
|
|
|
26
28
|
const DEFAULT_STAGE_INSTRUCTIONS = Object.freeze({
|
|
27
29
|
triage: 'Turn the request into an executable contract. Inspect relevant repository facts before deciding the flow. Classify the WorkItem, identify constraints, risks, dependencies, and missing acceptance criteria, then plan only the Actions needed for this task. Do not implement. If the goal or acceptance criteria must change, submit a contractPatch and explain why.',
|
|
@@ -716,8 +718,11 @@ function renderContext(context = []) {
|
|
|
716
718
|
const decision = entry.reviewDecision ? `\nReview decision: ${entry.reviewDecision}` : '';
|
|
717
719
|
const waitingReason = entry.waitingReason ? `\nWaiting reason: ${entry.waitingReason}` : '';
|
|
718
720
|
const answer = entry.answer ? `\nUser answer: ${entry.answer}` : '';
|
|
721
|
+
const quote = entry.quote
|
|
722
|
+
? sessionMessageQuotePrompt(entry.quote, { maxBytes: ACTION_CONTEXT_QUOTE_MAX_BYTES })
|
|
723
|
+
: '';
|
|
719
724
|
const source = entry.sourceTitle ? ` from ${entry.sourceTitle}` : '';
|
|
720
|
-
return `### ${entry.type}${source} (${entry.vpId || entry.role || 'unknown VP'})\n${entry.summary || '(no summary)'}${decision}${waitingReason}${answer}${evidence}`;
|
|
725
|
+
return `### ${entry.type}${source} (${entry.vpId || entry.role || 'unknown VP'})\n${entry.summary || '(no summary)'}${decision}${waitingReason}${answer}${quote}${evidence}`;
|
|
721
726
|
});
|
|
722
727
|
return `\n\nReusable Work Center context and prior Action results:\n${blocks.join('\n\n')}`;
|
|
723
728
|
}
|