@promptbook/cli 0.112.0 → 0.113.0-1
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/README.md +45 -29
- package/agents/default/developer.book +2 -1
- package/apps/agents-server/next.config.ts +21 -0
- package/apps/agents-server/src/app/admin/limits/LimitsClient.tsx +1 -1
- package/apps/agents-server/src/app/admin/task-manager/TaskManagerTaskRow.tsx +7 -2
- package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +52 -33
- package/apps/agents-server/src/app/api/agent-folders/[folderId]/visibility/route.ts +19 -7
- package/apps/agents-server/src/app/api/agents/[agentName]/route.ts +8 -18
- package/apps/agents-server/src/app/api/internal/agent-runner-limits/route.ts +1 -1
- package/apps/agents-server/src/app/api/page-preview/check/route.ts +5 -20
- package/apps/agents-server/src/app/api/page-preview/interact/route.ts +179 -0
- package/apps/agents-server/src/app/api/page-preview/live/route.ts +67 -0
- package/apps/agents-server/src/app/api/page-preview/screenshot/route.ts +13 -21
- package/apps/agents-server/src/app/api/v1/agents/[agentId]/route.ts +13 -8
- package/apps/agents-server/src/components/AgentProfile/AgentCapabilityChips.tsx +39 -5
- package/apps/agents-server/src/components/Homepage/AgentCard.tsx +7 -1
- package/apps/agents-server/src/components/Homepage/AgentsList.tsx +3 -0
- package/apps/agents-server/src/components/Homepage/AgentsListHeader.tsx +41 -0
- package/apps/agents-server/src/components/Homepage/hiddenFolders.ts +104 -0
- package/apps/agents-server/src/components/Homepage/useAgentsListQueryState.ts +35 -0
- package/apps/agents-server/src/components/Homepage/useAgentsListState.ts +24 -4
- package/apps/agents-server/src/constants/chatVisualMode.ts +1 -1
- package/apps/agents-server/src/constants/serverLimits.ts +19 -0
- package/apps/agents-server/src/constants/themeMode.ts +1 -1
- package/apps/agents-server/src/database/migrations/2026-05-2600-default-theme.sql +2 -2
- package/apps/agents-server/src/database/seedCoreAgents.ts +0 -2
- package/apps/agents-server/src/database/seedDefaultAgents.ts +0 -2
- package/apps/agents-server/src/tools/agent_progress.ts +4 -10
- package/apps/agents-server/src/utils/agentVisibility.ts +25 -62
- package/apps/agents-server/src/utils/chatTasksAdmin.ts +3 -1
- package/apps/agents-server/src/utils/createAgentWithDefaultVisibility.ts +3 -1
- package/apps/agents-server/src/utils/externalChatRunner/processExternalUserChatJob.ts +9 -17
- package/apps/agents-server/src/utils/getAdminChatTasksResponse/mapVpsSelfUpdateJobToAdminChatTask.ts +84 -0
- package/apps/agents-server/src/utils/getAdminChatTasksResponse.ts +195 -5
- package/apps/agents-server/src/utils/localChatRunner/LocalUserChatJobMetadata.ts +15 -5
- package/apps/agents-server/src/utils/localChatRunner/processLocalUserChatJob.ts +17 -26
- package/apps/agents-server/src/utils/pagePreview/livePagePreviewSessions.ts +365 -0
- package/apps/agents-server/src/utils/pagePreview/resolvePagePreviewRequestUrl.ts +74 -0
- package/apps/agents-server/src/utils/serverLimits.ts +2 -0
- package/apps/agents-server/src/utils/serverManagement/createManagedServer/seedServerCoreAgents.ts +2 -2
- package/apps/agents-server/src/utils/serverManagement/createManagedServer/seedServerDefaultAgents.ts +1 -1
- package/apps/agents-server/src/utils/userChat/createUserChatHarnessProgressCard.ts +0 -6
- package/apps/agents-server/src/utils/userChat/createUserChatRunnerProgressCard.ts +0 -6
- package/apps/agents-server/src/utils/userChat/userChatMessageLifecycle.ts +69 -0
- package/apps/agents-server/src/utils/userChat/userChatProgressCard.ts +0 -6
- package/apps/agents-server/src/utils/vpsSelfUpdate.ts +150 -24
- package/esm/apps/agents-server/src/constants/serverLimits.d.ts +17 -0
- package/esm/index.es.js +581 -93
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-agent-messages/main/runMultipleAgentMessages.d.ts +1 -0
- package/esm/scripts/run-agent-messages/main/tickAgentMessages.d.ts +1 -0
- package/esm/src/_packages/core.index.d.ts +22 -0
- package/esm/src/_packages/types.index.d.ts +2 -0
- package/esm/src/book-2.0/agent-source/AgentBasicInformation.d.ts +2 -0
- package/esm/src/book-2.0/agent-source/agentSourceVisibility.d.ts +97 -0
- package/esm/src/book-2.0/agent-source/agentSourceVisibility.test.d.ts +1 -0
- package/esm/src/book-components/BookEditor/BookEditorMonacoTokenization.d.ts +1 -0
- package/esm/src/book-components/Chat/Chat/CitationIframePreview.d.ts +2 -2
- package/esm/src/book-components/Chat/utils/livePagePreviewConstants.d.ts +12 -0
- package/esm/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +6 -0
- package/esm/src/collection/agent-collection/CreateAgentInput.d.ts +2 -1
- package/esm/src/collection/agent-collection/constructors/agent-collection-in-supabase/prepareAgentSourceForPersistence.d.ts +21 -1
- package/esm/src/commitments/META_VISIBILITY/META_VISIBILITY.d.ts +27 -0
- package/esm/src/commitments/index.d.ts +2 -1
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/_packages/core.index.ts +22 -0
- package/src/_packages/types.index.ts +2 -0
- package/src/book-2.0/agent-source/AgentBasicInformation.ts +2 -0
- package/src/book-2.0/agent-source/agentSourceVisibility.ts +214 -0
- package/src/book-2.0/agent-source/parseAgentSource/applyMetaCommitment.ts +17 -0
- package/src/book-2.0/book-language-documentation/createStandaloneBookLanguageMarkdown.ts +1 -0
- package/src/book-components/BookEditor/BookEditorMonacoTokenization.ts +11 -0
- package/src/book-components/BookEditor/useBookEditorMonacoLanguage.ts +7 -3
- package/src/book-components/Chat/Chat/Chat.module.css +14 -5
- package/src/book-components/Chat/Chat/CitationIframePreview.tsx +197 -22
- package/src/book-components/Chat/utils/livePagePreviewConstants.ts +17 -0
- package/src/cli/cli-commands/agents-server/buildAgentsServer.ts +144 -16
- package/src/cli/cli-commands/agents-server/startAgentsServer.ts +22 -2
- package/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts +1 -1
- package/src/cli/cli-commands/coder/run.ts +30 -0
- package/src/collection/agent-collection/CreateAgentInput.ts +10 -5
- package/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.ts +7 -3
- package/src/collection/agent-collection/constructors/agent-collection-in-supabase/createAgentPersistenceRecords.ts +7 -4
- package/src/collection/agent-collection/constructors/agent-collection-in-supabase/prepareAgentSourceForPersistence.ts +44 -8
- package/src/commitments/META_VISIBILITY/META_VISIBILITY.ts +78 -0
- package/src/commitments/index.ts +2 -0
- package/src/other/templates/getTemplatesPipelineCollection.ts +826 -650
- package/src/version.ts +2 -2
- package/src/versions.txt +2 -0
- package/umd/apps/agents-server/src/constants/serverLimits.d.ts +17 -0
- package/umd/index.umd.js +581 -93
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-agent-messages/main/runMultipleAgentMessages.d.ts +1 -0
- package/umd/scripts/run-agent-messages/main/tickAgentMessages.d.ts +1 -0
- package/umd/src/_packages/core.index.d.ts +22 -0
- package/umd/src/_packages/types.index.d.ts +2 -0
- package/umd/src/book-2.0/agent-source/AgentBasicInformation.d.ts +2 -0
- package/umd/src/book-2.0/agent-source/agentSourceVisibility.d.ts +97 -0
- package/umd/src/book-2.0/agent-source/agentSourceVisibility.test.d.ts +1 -0
- package/umd/src/book-components/BookEditor/BookEditorMonacoTokenization.d.ts +1 -0
- package/umd/src/book-components/Chat/Chat/CitationIframePreview.d.ts +2 -2
- package/umd/src/book-components/Chat/utils/livePagePreviewConstants.d.ts +12 -0
- package/umd/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +6 -0
- package/umd/src/collection/agent-collection/CreateAgentInput.d.ts +2 -1
- package/umd/src/collection/agent-collection/constructors/agent-collection-in-supabase/prepareAgentSourceForPersistence.d.ts +21 -1
- package/umd/src/commitments/META_VISIBILITY/META_VISIBILITY.d.ts +27 -0
- package/umd/src/commitments/index.d.ts +2 -1
- package/umd/src/version.d.ts +1 -1
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { ensureUserChatTimeoutWorkerBootstrapped } from '@/src/utils/userChatTimeout/ensureUserChatTimeoutWorkerBootstrapped';
|
|
2
|
-
import type { AdminChatTaskListResponse } from './chatTasksAdmin';
|
|
2
|
+
import type { AdminChatTaskCounters, AdminChatTaskListResponse, AdminChatTaskRecord } from './chatTasksAdmin';
|
|
3
3
|
import { getAdminChatTasks } from './getAdminChatTasksResponse/getAdminChatTasks';
|
|
4
|
-
import {
|
|
4
|
+
import { mapVpsSelfUpdateJobToAdminChatTask } from './getAdminChatTasksResponse/mapVpsSelfUpdateJobToAdminChatTask';
|
|
5
|
+
import { parseAdminChatTaskQuery, type ParsedAdminChatTaskQuery } from './getAdminChatTasksResponse/parseAdminChatTaskQuery';
|
|
5
6
|
import { throttledAdminRecovery } from './getAdminChatTasksResponse/throttledAdminRecovery';
|
|
7
|
+
import { readVpsSelfUpdateJobSnapshot } from './vpsSelfUpdate';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Milliseconds in one hour.
|
|
11
|
+
*
|
|
12
|
+
* @private internal constant of `getAdminChatTasksResponse`
|
|
13
|
+
*/
|
|
14
|
+
const HOUR_IN_MILLISECONDS = 60 * 60 * 1000;
|
|
6
15
|
|
|
7
16
|
/**
|
|
8
17
|
* Successful task-manager response envelope.
|
|
@@ -53,13 +62,23 @@ export async function getAdminChatTasksResponse(
|
|
|
53
62
|
await throttledAdminRecovery();
|
|
54
63
|
|
|
55
64
|
const adminChatTasks = await getAdminChatTasks(parsedQuery);
|
|
65
|
+
const vpsSelfUpdateTask = await loadVpsSelfUpdateAdminChatTask();
|
|
66
|
+
const injectedTasks = collectAdminChatTasksToInject(vpsSelfUpdateTask, parsedQuery);
|
|
67
|
+
const { items, total } = mergeInjectedAdminChatTasks({
|
|
68
|
+
databaseItems: adminChatTasks.items,
|
|
69
|
+
databaseTotal: adminChatTasks.total,
|
|
70
|
+
injectedTasks,
|
|
71
|
+
page: parsedQuery.page,
|
|
72
|
+
pageSize: parsedQuery.pageSize,
|
|
73
|
+
});
|
|
74
|
+
const counters = mergeInjectedAdminChatTaskCounters(adminChatTasks.counters, vpsSelfUpdateTask);
|
|
56
75
|
|
|
57
76
|
return {
|
|
58
77
|
status: 200,
|
|
59
78
|
response: {
|
|
60
|
-
items
|
|
61
|
-
counters
|
|
62
|
-
total
|
|
79
|
+
items,
|
|
80
|
+
counters,
|
|
81
|
+
total,
|
|
63
82
|
page: parsedQuery.page,
|
|
64
83
|
pageSize: parsedQuery.pageSize,
|
|
65
84
|
view: parsedQuery.view,
|
|
@@ -69,3 +88,174 @@ export async function getAdminChatTasksResponse(
|
|
|
69
88
|
},
|
|
70
89
|
};
|
|
71
90
|
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Loads the currently persisted standalone VPS self-update task, if any.
|
|
94
|
+
*
|
|
95
|
+
* The read is defensive so a corrupt status file cannot block the admin task manager from rendering.
|
|
96
|
+
*
|
|
97
|
+
* @returns Injectable task record or `null` when no self-update has ever been triggered on this server.
|
|
98
|
+
*/
|
|
99
|
+
async function loadVpsSelfUpdateAdminChatTask(): Promise<AdminChatTaskRecord | null> {
|
|
100
|
+
try {
|
|
101
|
+
const jobSnapshot = await readVpsSelfUpdateJobSnapshot();
|
|
102
|
+
return mapVpsSelfUpdateJobToAdminChatTask(jobSnapshot);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error('[admin-chat-task] failed to load VPS self-update task snapshot', error);
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Filters out injected tasks that do not belong to the requested admin task-manager view or search.
|
|
111
|
+
*
|
|
112
|
+
* @param vpsSelfUpdateTask - Currently persisted self-update task or `null`.
|
|
113
|
+
* @param query - Parsed admin task-manager query.
|
|
114
|
+
* @returns Tasks to inject on top of the database-backed items.
|
|
115
|
+
*/
|
|
116
|
+
function collectAdminChatTasksToInject(
|
|
117
|
+
vpsSelfUpdateTask: AdminChatTaskRecord | null,
|
|
118
|
+
query: ParsedAdminChatTaskQuery,
|
|
119
|
+
): ReadonlyArray<AdminChatTaskRecord> {
|
|
120
|
+
if (!vpsSelfUpdateTask) {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!matchesAdminChatTaskView(vpsSelfUpdateTask, query, Date.now())) {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (!matchesAdminChatTaskSearch(vpsSelfUpdateTask, query.search)) {
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return [vpsSelfUpdateTask];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Prepends the injected task rows to the paginated database items so the self-update stays visible on page 1.
|
|
137
|
+
*
|
|
138
|
+
* @param options - Merge inputs.
|
|
139
|
+
* @returns Merged items for the current page and the updated total row count.
|
|
140
|
+
*/
|
|
141
|
+
function mergeInjectedAdminChatTasks(options: {
|
|
142
|
+
readonly databaseItems: ReadonlyArray<AdminChatTaskRecord>;
|
|
143
|
+
readonly databaseTotal: number;
|
|
144
|
+
readonly injectedTasks: ReadonlyArray<AdminChatTaskRecord>;
|
|
145
|
+
readonly page: number;
|
|
146
|
+
readonly pageSize: number;
|
|
147
|
+
}): { items: Array<AdminChatTaskRecord>; total: number } {
|
|
148
|
+
const total = options.databaseTotal + options.injectedTasks.length;
|
|
149
|
+
|
|
150
|
+
if (options.injectedTasks.length === 0) {
|
|
151
|
+
return { items: [...options.databaseItems], total };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (options.page !== 1) {
|
|
155
|
+
return { items: [...options.databaseItems], total };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const items = [...options.injectedTasks, ...options.databaseItems].slice(0, options.pageSize);
|
|
159
|
+
return { items, total };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Adds the injected self-update task to the summary counters so the header metrics stay accurate.
|
|
164
|
+
*
|
|
165
|
+
* @param databaseCounters - Counters computed from durable database rows.
|
|
166
|
+
* @param vpsSelfUpdateTask - Currently persisted self-update task or `null`.
|
|
167
|
+
* @returns Merged counters including the injected task.
|
|
168
|
+
*/
|
|
169
|
+
function mergeInjectedAdminChatTaskCounters(
|
|
170
|
+
databaseCounters: AdminChatTaskCounters,
|
|
171
|
+
vpsSelfUpdateTask: AdminChatTaskRecord | null,
|
|
172
|
+
): AdminChatTaskCounters {
|
|
173
|
+
if (!vpsSelfUpdateTask) {
|
|
174
|
+
return databaseCounters;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const nowTimestamp = Date.now();
|
|
178
|
+
const isRunning = vpsSelfUpdateTask.status === 'RUNNING';
|
|
179
|
+
const isFailedInWindow =
|
|
180
|
+
vpsSelfUpdateTask.status === 'FAILED' &&
|
|
181
|
+
isIsoTimestampAtOrAfter(vpsSelfUpdateTask.finishedAt, nowTimestamp - 24 * HOUR_IN_MILLISECONDS);
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
runningCount: databaseCounters.runningCount + (isRunning ? 1 : 0),
|
|
185
|
+
queuedCount: databaseCounters.queuedCount,
|
|
186
|
+
failedLast24hCount: databaseCounters.failedLast24hCount + (isFailedInWindow ? 1 : 0),
|
|
187
|
+
oldestQueuedAgeMs: databaseCounters.oldestQueuedAgeMs,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Returns whether the injected task belongs in the requested admin task-manager view.
|
|
193
|
+
*
|
|
194
|
+
* @param task - Injected task.
|
|
195
|
+
* @param query - Parsed admin task-manager query.
|
|
196
|
+
* @param nowTimestamp - Current epoch used for time-window filtering.
|
|
197
|
+
* @returns `true` when the task should be included.
|
|
198
|
+
*/
|
|
199
|
+
function matchesAdminChatTaskView(
|
|
200
|
+
task: AdminChatTaskRecord,
|
|
201
|
+
query: ParsedAdminChatTaskQuery,
|
|
202
|
+
nowTimestamp: number,
|
|
203
|
+
): boolean {
|
|
204
|
+
switch (query.view) {
|
|
205
|
+
case 'running':
|
|
206
|
+
return task.status === 'RUNNING';
|
|
207
|
+
case 'queued':
|
|
208
|
+
return task.status === 'QUEUED';
|
|
209
|
+
case 'failed':
|
|
210
|
+
return (
|
|
211
|
+
task.status === 'FAILED' &&
|
|
212
|
+
isIsoTimestampAtOrAfter(task.finishedAt, nowTimestamp - 24 * HOUR_IN_MILLISECONDS)
|
|
213
|
+
);
|
|
214
|
+
case 'all':
|
|
215
|
+
return isIsoTimestampAtOrAfter(task.updatedAt, nowTimestamp - query.timeWindowHours * HOUR_IN_MILLISECONDS);
|
|
216
|
+
case 'active':
|
|
217
|
+
default:
|
|
218
|
+
return task.status === 'QUEUED' || task.status === 'RUNNING';
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Returns whether the injected task matches the free-text admin search input.
|
|
224
|
+
*
|
|
225
|
+
* @param task - Injected task.
|
|
226
|
+
* @param search - Trimmed search text from the parsed query.
|
|
227
|
+
* @returns `true` when the task should be included.
|
|
228
|
+
*/
|
|
229
|
+
function matchesAdminChatTaskSearch(task: AdminChatTaskRecord, search: string): boolean {
|
|
230
|
+
if (!search) {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const normalizedSearch = search.toLowerCase();
|
|
235
|
+
if (task.id.toLowerCase().includes(normalizedSearch)) {
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
if (task.agentPermanentId.toLowerCase().includes(normalizedSearch)) {
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
if ((task.agentName || '').toLowerCase().includes(normalizedSearch)) {
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
return task.chatId.toLowerCase().includes(normalizedSearch);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Returns whether one ISO timestamp is at or after the given cutoff.
|
|
249
|
+
*
|
|
250
|
+
* @param timestampIso - Optional ISO timestamp.
|
|
251
|
+
* @param cutoffTimestamp - Epoch cutoff in milliseconds.
|
|
252
|
+
* @returns `true` when the timestamp is at or after the cutoff.
|
|
253
|
+
*/
|
|
254
|
+
function isIsoTimestampAtOrAfter(timestampIso: string | null, cutoffTimestamp: number): boolean {
|
|
255
|
+
if (!timestampIso) {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const timestamp = Date.parse(timestampIso);
|
|
260
|
+
return Number.isFinite(timestamp) && timestamp >= cutoffTimestamp;
|
|
261
|
+
}
|
|
@@ -23,10 +23,11 @@ export function createLocalUserChatJobMetadata(options: {
|
|
|
23
23
|
agentDirectoryName: string;
|
|
24
24
|
threadId: string;
|
|
25
25
|
threadCreatedAt: string;
|
|
26
|
+
jobId: string;
|
|
26
27
|
queuedAt: string;
|
|
27
28
|
expectedMessagesBeforeAnswer: number;
|
|
28
29
|
}): LocalUserChatJobMetadata {
|
|
29
|
-
const fileName = createLocalChatMessageFileName(options.threadId, options.threadCreatedAt);
|
|
30
|
+
const fileName = createLocalChatMessageFileName(options.threadId, options.threadCreatedAt, options.jobId);
|
|
30
31
|
|
|
31
32
|
return {
|
|
32
33
|
version: 1,
|
|
@@ -102,15 +103,24 @@ export function withoutLocalUserChatJobMetadata(parameters: UserChatJobParameter
|
|
|
102
103
|
/**
|
|
103
104
|
* Creates the filename used by one local message-thread book.
|
|
104
105
|
*/
|
|
105
|
-
export function createLocalChatMessageFileName(threadId: string, threadCreatedAt: string): string {
|
|
106
|
+
export function createLocalChatMessageFileName(threadId: string, threadCreatedAt: string, jobId?: string): string {
|
|
106
107
|
const createdOnDate = resolveLocalChatThreadCreatedOnDate(threadCreatedAt);
|
|
107
|
-
const normalizedThreadId = threadId
|
|
108
|
+
const normalizedThreadId = threadId
|
|
109
|
+
.trim()
|
|
110
|
+
.replace(/[^a-zA-Z0-9._-]+/g, '-')
|
|
111
|
+
.replace(/^-+|-+$/g, '');
|
|
112
|
+
const normalizedJobId = jobId
|
|
113
|
+
?.trim()
|
|
114
|
+
.replace(/[^a-zA-Z0-9._-]+/g, '-')
|
|
115
|
+
.replace(/^-+|-+$/g, '');
|
|
108
116
|
|
|
109
117
|
if (normalizedThreadId.length > 0) {
|
|
110
|
-
return `${createdOnDate}-${normalizedThreadId}.book`;
|
|
118
|
+
return `${createdOnDate}-${normalizedThreadId}${normalizedJobId ? `-${normalizedJobId}` : ''}.book`;
|
|
111
119
|
}
|
|
112
120
|
|
|
113
|
-
return `${createdOnDate}-${Buffer.from(threadId, 'utf8').toString('hex') || 'thread'}
|
|
121
|
+
return `${createdOnDate}-${Buffer.from(threadId, 'utf8').toString('hex') || 'thread'}${
|
|
122
|
+
normalizedJobId ? `-${normalizedJobId}` : ''
|
|
123
|
+
}.book`;
|
|
114
124
|
}
|
|
115
125
|
|
|
116
126
|
/**
|
|
@@ -13,7 +13,7 @@ import { createUserChatRunnerProgressCard } from '../userChat/createUserChatRunn
|
|
|
13
13
|
import { updateUserChatAssistantMessage } from '../userChat/updateUserChatAssistantMessage';
|
|
14
14
|
import type { UserChatJobRecord } from '../userChat/UserChatJobRecord';
|
|
15
15
|
import type { UserChatJobRow } from '../userChat/UserChatJobRow';
|
|
16
|
-
import {
|
|
16
|
+
import { createUserChatRunnerThreadMessages } from '../userChat/userChatMessageLifecycle';
|
|
17
17
|
import {
|
|
18
18
|
createLocalUserChatJobMetadata,
|
|
19
19
|
getLocalUserChatJobMetadata,
|
|
@@ -85,9 +85,11 @@ export async function processLocalUserChatJob(job: UserChatJobRecord): Promise<P
|
|
|
85
85
|
/**
|
|
86
86
|
* Processes the next local user chat job waiting for worker attention.
|
|
87
87
|
*/
|
|
88
|
-
export async function processNextLocalUserChatJob(
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
export async function processNextLocalUserChatJob(
|
|
89
|
+
options: {
|
|
90
|
+
preferredJobId?: string;
|
|
91
|
+
} = {},
|
|
92
|
+
): Promise<ProcessLocalUserChatJobResult | null> {
|
|
91
93
|
if (options.preferredJobId) {
|
|
92
94
|
const claimedPreferredJob = await claimNextQueuedUserChatJob({ preferredJobId: options.preferredJobId });
|
|
93
95
|
if (claimedPreferredJob) {
|
|
@@ -142,27 +144,11 @@ async function enqueueLocalUserChatJob(job: UserChatJobRecord): Promise<ProcessL
|
|
|
142
144
|
throw new Error(`User message "${job.userMessageId}" was not found in chat "${job.chatId}".`);
|
|
143
145
|
}
|
|
144
146
|
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const agentInitialMessage = previousThreadMessages.length === 0
|
|
151
|
-
? parseAgentSource(agentSourceSnapshot.agentSource).initialMessage
|
|
152
|
-
: null;
|
|
153
|
-
const initialAgentThreadMessages = agentInitialMessage
|
|
154
|
-
? [{ sender: 'AGENT' as const, content: agentInitialMessage }]
|
|
155
|
-
: [];
|
|
156
|
-
|
|
157
|
-
const threadMessages = [
|
|
158
|
-
...initialAgentThreadMessages,
|
|
159
|
-
...[...previousThreadMessages, userMessage]
|
|
160
|
-
.filter((message) => message.isComplete !== false)
|
|
161
|
-
.filter((message) => message.sender === 'USER' || message.sender === 'AGENT'),
|
|
162
|
-
].map((message) => ({
|
|
163
|
-
sender: String(message.sender),
|
|
164
|
-
content: message.content,
|
|
165
|
-
}));
|
|
147
|
+
const threadMessages = createUserChatRunnerThreadMessages({
|
|
148
|
+
messages: chat.messages,
|
|
149
|
+
userMessageId: job.userMessageId,
|
|
150
|
+
resolveInitialAgentMessage: () => parseAgentSource(agentSourceSnapshot.agentSource).initialMessage,
|
|
151
|
+
});
|
|
166
152
|
|
|
167
153
|
const agentFolder = await ensureLocalAgentFolder(agentSourceSnapshot);
|
|
168
154
|
const queuedAt = new Date().toISOString();
|
|
@@ -170,6 +156,7 @@ async function enqueueLocalUserChatJob(job: UserChatJobRecord): Promise<ProcessL
|
|
|
170
156
|
agentDirectoryName: agentFolder.directoryName,
|
|
171
157
|
threadId: chat.id,
|
|
172
158
|
threadCreatedAt: chat.createdAt,
|
|
159
|
+
jobId: job.id,
|
|
173
160
|
queuedAt,
|
|
174
161
|
expectedMessagesBeforeAnswer: threadMessages.length,
|
|
175
162
|
});
|
|
@@ -326,7 +313,11 @@ async function handleLocalUserChatJobProcessingError(
|
|
|
326
313
|
const metadata = getLocalUserChatJobMetadata(job);
|
|
327
314
|
const failureReason = error instanceof Error ? error.message : 'Local agent runner synchronization failed.';
|
|
328
315
|
|
|
329
|
-
if (
|
|
316
|
+
if (
|
|
317
|
+
job.status === 'QUEUED' ||
|
|
318
|
+
(job.status === 'RUNNING' && !metadata) ||
|
|
319
|
+
(metadata && isLocalUserChatJobTimedOut(metadata))
|
|
320
|
+
) {
|
|
330
321
|
await persistUserChatJobTerminalState({
|
|
331
322
|
job,
|
|
332
323
|
status: 'FAILED',
|