@promptbook/cli 0.112.0-133 → 0.112.0-135

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.
Files changed (56) hide show
  1. package/apps/agents-server/src/app/admin/chat-feedback/page.tsx +2 -4
  2. package/apps/agents-server/src/app/admin/chat-history/page.tsx +2 -4
  3. package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +2 -0
  4. package/apps/agents-server/src/app/api/agents/[agentName]/route.ts +33 -9
  5. package/apps/agents-server/src/app/api/chat/route.ts +29 -7
  6. package/apps/agents-server/src/app/api/chat-feedback/export/route.ts +2 -2
  7. package/apps/agents-server/src/app/api/chat-feedback/route.ts +3 -3
  8. package/apps/agents-server/src/app/api/chat-history/[id]/route.ts +2 -2
  9. package/apps/agents-server/src/app/api/chat-history/export/route.ts +2 -2
  10. package/apps/agents-server/src/app/api/chat-history/route.ts +3 -3
  11. package/apps/agents-server/src/app/api/chat-streaming/route.ts +29 -0
  12. package/apps/agents-server/src/app/api/elevenlabs/tts/route.ts +60 -2
  13. package/apps/agents-server/src/app/api/images/[filename]/route.ts +102 -0
  14. package/apps/agents-server/src/app/api/openai/v1/audio/transcriptions/route.ts +111 -2
  15. package/apps/agents-server/src/app/api/page-preview/check/route.ts +18 -0
  16. package/apps/agents-server/src/app/api/page-preview/screenshot/route.ts +15 -8
  17. package/apps/agents-server/src/app/api/team-agent-profile/route.ts +20 -0
  18. package/apps/agents-server/src/app/api/v1/agents/[agentId]/route.ts +4 -0
  19. package/apps/agents-server/src/app/api/v1/agents/route.ts +2 -0
  20. package/apps/agents-server/src/app/recycle-bin/actions.ts +3 -0
  21. package/apps/agents-server/src/components/AgentContextMenu/useAgentContextMenuItems.ts +27 -19
  22. package/apps/agents-server/src/constants/defaultAgentAvatarVisual.ts +1 -1
  23. package/apps/agents-server/src/database/migrations/2026-06-2600-agent-directory-performance-indexes.sql +14 -0
  24. package/apps/agents-server/src/database/migrations/2026-06-2700-default-agent-avatar-visual-octopus3d4.sql +16 -0
  25. package/apps/agents-server/src/database/sqlite/$provideLocalSqliteSupabase.ts +92 -1
  26. package/apps/agents-server/src/utils/agentOwnership.ts +54 -5
  27. package/apps/agents-server/src/utils/findAgentForCallerWriteAccess.ts +36 -0
  28. package/apps/agents-server/src/utils/paidApiRequestGuard.ts +241 -0
  29. package/apps/agents-server/src/utils/userChat/createRunUserChatJobExecutionContext.ts +36 -8
  30. package/apps/agents-server/src/utils/userChat/listUserChats.ts +5 -1
  31. package/apps/agents-server/src/utils/userChat/persistUserChatJobProgressCard.ts +11 -2
  32. package/apps/agents-server/src/utils/userChat/resolveUserChatProgressToolHighlights.ts +100 -0
  33. package/apps/agents-server/src/utils/userChat/runUserChatJob.ts +4 -3
  34. package/apps/agents-server/src/utils/userChat/userChatProgressCard.ts +272 -27
  35. package/apps/agents-server/src/utils/validateApiKey.ts +7 -3
  36. package/esm/index.es.js +795 -39
  37. package/esm/index.es.js.map +1 -1
  38. package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
  39. package/esm/src/avatars/visuals/octopus3d4AvatarVisual.d.ts +7 -0
  40. package/esm/src/utils/validators/url/isValidAgentUrl.d.ts +5 -0
  41. package/esm/src/version.d.ts +1 -1
  42. package/package.json +1 -1
  43. package/src/avatars/types/AvatarVisualDefinition.ts +1 -0
  44. package/src/avatars/visuals/avatarVisualRegistry.ts +2 -0
  45. package/src/avatars/visuals/octopus3d4AvatarVisual.ts +1295 -0
  46. package/src/other/templates/getTemplatesPipelineCollection.ts +759 -679
  47. package/src/utils/agents/resolveAgentAvatarImageUrl.ts +1 -1
  48. package/src/utils/validators/url/isValidAgentUrl.ts +5 -7
  49. package/src/version.ts +2 -2
  50. package/src/versions.txt +1 -0
  51. package/umd/index.umd.js +795 -39
  52. package/umd/index.umd.js.map +1 -1
  53. package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
  54. package/umd/src/avatars/visuals/octopus3d4AvatarVisual.d.ts +7 -0
  55. package/umd/src/utils/validators/url/isValidAgentUrl.d.ts +5 -0
  56. package/umd/src/version.d.ts +1 -1
@@ -1,4 +1,5 @@
1
1
  import type { ChatMessage } from '@promptbook-local/types';
2
+ import { spaceTrim } from '../../../../../src/_packages/utils.index';
2
3
 
3
4
  /**
4
5
  * User-facing phases shown while one durable chat answer is being prepared.
@@ -10,6 +11,70 @@ export type UserChatProgressPhase =
10
11
  | 'checking_capabilities'
11
12
  | 'starting_response';
12
13
 
14
+ /**
15
+ * Real runtime details surfaced into the user-facing progress card text.
16
+ *
17
+ * Only signals that are already known at the corresponding phase are filled in,
18
+ * so the produced markdown reflects what the worker is actually doing right now
19
+ * instead of a generic scripted summary.
20
+ */
21
+ export type UserChatProgressContext = {
22
+ /**
23
+ * Resolved human-readable agent name, when already loaded for this turn.
24
+ */
25
+ readonly agentName?: string;
26
+
27
+ /**
28
+ * Stable agent identifier shown when the human-readable name is not yet known.
29
+ */
30
+ readonly agentPermanentId?: string;
31
+
32
+ /**
33
+ * Resolved LLM provider title (e.g. `OpenAI`, `Anthropic`), when already known.
34
+ */
35
+ readonly provider?: string;
36
+
37
+ /**
38
+ * Number of attachments the user submitted with the current turn.
39
+ */
40
+ readonly attachmentCount?: number;
41
+
42
+ /**
43
+ * Number of agent-defined tools available to the model for this turn.
44
+ */
45
+ readonly toolCount?: number;
46
+
47
+ /**
48
+ * Concise user-facing tool labels (e.g. `web browser`, `calendar`) for the progress text.
49
+ */
50
+ readonly toolHighlights?: ReadonlyArray<string>;
51
+
52
+ /**
53
+ * Number of knowledge sources the agent will reference during the turn.
54
+ */
55
+ readonly knowledgeSourceCount?: number;
56
+
57
+ /**
58
+ * Whether the calendar integration is wired up for this turn.
59
+ */
60
+ readonly hasCalendarAccess?: boolean;
61
+
62
+ /**
63
+ * Whether the email-sending integration is wired up for this turn.
64
+ */
65
+ readonly hasEmailAccess?: boolean;
66
+
67
+ /**
68
+ * Whether one or more project repositories are linked to this turn.
69
+ */
70
+ readonly hasProjectAccess?: boolean;
71
+
72
+ /**
73
+ * Whether the AgentKit runtime for this agent came from the in-process cache.
74
+ */
75
+ readonly isAgentKitCached?: boolean;
76
+ };
77
+
13
78
  /**
14
79
  * Default title used by durable chat progress cards.
15
80
  */
@@ -26,39 +91,25 @@ const USER_CHAT_PROGRESS_ITEM_IDS = {
26
91
  } as const;
27
92
 
28
93
  /**
29
- * Static progress copy for one durable chat phase.
94
+ * Static checklist mapping for one durable chat phase.
30
95
  */
31
- type UserChatProgressPhasePresentation = {
32
- readonly now: string;
33
- readonly next: string;
96
+ type UserChatProgressPhaseChecklist = {
34
97
  readonly completedItemIds: ReadonlySet<string>;
35
98
  };
36
99
 
37
100
  /**
38
- * User-facing progress copy for durable chat phases.
101
+ * Static checklist progression shared across all durable chat phases.
39
102
  */
40
- const USER_CHAT_PROGRESS_PHASE_PRESENTATIONS: Record<UserChatProgressPhase, UserChatProgressPhasePresentation> = {
41
- queued: {
42
- now: 'Your message is queued and the agent will pick it up shortly.',
43
- next: 'The agent will read the conversation and prepare the answer.',
44
- completedItemIds: new Set([]),
45
- },
46
- reading_context: {
47
- now: 'Reading your message and the relevant conversation context.',
48
- next: 'Prepare the agent instructions and working context.',
49
- completedItemIds: new Set([USER_CHAT_PROGRESS_ITEM_IDS.RECEIVE_MESSAGE]),
50
- },
103
+ const USER_CHAT_PROGRESS_PHASE_CHECKLISTS: Record<UserChatProgressPhase, UserChatProgressPhaseChecklist> = {
104
+ queued: { completedItemIds: new Set([]) },
105
+ reading_context: { completedItemIds: new Set([USER_CHAT_PROGRESS_ITEM_IDS.RECEIVE_MESSAGE]) },
51
106
  preparing_agent: {
52
- now: 'Preparing the agent instructions and context needed for this request.',
53
- next: 'Check which tools and inputs are available.',
54
107
  completedItemIds: new Set([
55
108
  USER_CHAT_PROGRESS_ITEM_IDS.RECEIVE_MESSAGE,
56
109
  USER_CHAT_PROGRESS_ITEM_IDS.PREPARE_AGENT,
57
110
  ]),
58
111
  },
59
112
  checking_capabilities: {
60
- now: 'Checking available tools, attachments, and context before answering.',
61
- next: 'Start working through the response.',
62
113
  completedItemIds: new Set([
63
114
  USER_CHAT_PROGRESS_ITEM_IDS.RECEIVE_MESSAGE,
64
115
  USER_CHAT_PROGRESS_ITEM_IDS.PREPARE_AGENT,
@@ -66,8 +117,6 @@ const USER_CHAT_PROGRESS_PHASE_PRESENTATIONS: Record<UserChatProgressPhase, User
66
117
  ]),
67
118
  },
68
119
  starting_response: {
69
- now: 'Working through the response. Progress updates will stay focused on visible actions and results.',
70
- next: 'Stream the final answer as soon as it is ready.',
71
120
  completedItemIds: new Set([
72
121
  USER_CHAT_PROGRESS_ITEM_IDS.RECEIVE_MESSAGE,
73
122
  USER_CHAT_PROGRESS_ITEM_IDS.PREPARE_AGENT,
@@ -103,19 +152,215 @@ const USER_CHAT_PROGRESS_ITEMS: ReadonlyArray<{
103
152
 
104
153
  /**
105
154
  * Creates one user-facing durable chat progress card for the current job phase.
155
+ *
156
+ * The optional `context` carries already-resolved runtime details (agent name, provider,
157
+ * tool count, attachment count, integrations) so the rendered `now`/`next` text reflects
158
+ * what the worker is actually doing on this turn instead of a generic scripted summary.
106
159
  */
107
- export function createUserChatProgressCard(phase: UserChatProgressPhase): NonNullable<ChatMessage['progressCard']> {
108
- const presentation = USER_CHAT_PROGRESS_PHASE_PRESENTATIONS[phase];
160
+ export function createUserChatProgressCard(
161
+ phase: UserChatProgressPhase,
162
+ context?: UserChatProgressContext,
163
+ ): NonNullable<ChatMessage['progressCard']> {
164
+ const checklist = USER_CHAT_PROGRESS_PHASE_CHECKLISTS[phase];
165
+ const { now, next } = composeUserChatProgressPhaseText(phase, context);
109
166
 
110
167
  return {
111
168
  title: USER_CHAT_PROGRESS_TITLE,
112
- now: presentation.now,
113
- next: presentation.next,
169
+ now,
170
+ next,
114
171
  items: USER_CHAT_PROGRESS_ITEMS.map((item) => ({
115
172
  ...item,
116
- status: presentation.completedItemIds.has(item.id) ? 'completed' : 'pending',
173
+ status: checklist.completedItemIds.has(item.id) ? 'completed' : 'pending',
117
174
  })),
118
175
  updatedAt: new Date().toISOString() as NonNullable<ChatMessage['progressCard']>['updatedAt'],
119
176
  isVisible: true,
120
177
  };
121
178
  }
179
+
180
+ /**
181
+ * Composes the dynamic `now`/`next` markdown shown for one durable chat phase.
182
+ *
183
+ * @private internal helper of `createUserChatProgressCard`
184
+ */
185
+ function composeUserChatProgressPhaseText(
186
+ phase: UserChatProgressPhase,
187
+ context: UserChatProgressContext | undefined,
188
+ ): { now: string; next: string } {
189
+ const agentLabel = describeAgent(context);
190
+
191
+ switch (phase) {
192
+ case 'queued':
193
+ return {
194
+ now: spaceTrim(`
195
+ Your message is waiting in the queue for the next available worker to pick it up.
196
+ `),
197
+ next: spaceTrim(`
198
+ Read the conversation and load ${agentLabel}.
199
+ `),
200
+ };
201
+ case 'reading_context': {
202
+ const attachmentHint = describeAttachmentHint(context);
203
+ return {
204
+ now: spaceTrim(`
205
+ Reading your latest message${attachmentHint} together with the earlier conversation thread.
206
+ `),
207
+ next: spaceTrim(`
208
+ Resolve ${agentLabel} and load its instructions, persona, and rules.
209
+ `),
210
+ };
211
+ }
212
+ case 'preparing_agent': {
213
+ const knowledgeHint = describeKnowledgeHint(context);
214
+ return {
215
+ now: spaceTrim(`
216
+ Loading the instructions and configured commitments for ${agentLabel}${knowledgeHint}.
217
+ `),
218
+ next: spaceTrim(`
219
+ Check which tools, integrations, and attachments are usable for this turn.
220
+ `),
221
+ };
222
+ }
223
+ case 'checking_capabilities': {
224
+ const capabilitiesText = describeCapabilities(context);
225
+ return {
226
+ now: spaceTrim(`
227
+ Verifying that ${agentLabel} can use ${capabilitiesText} for this answer.
228
+ `),
229
+ next: spaceTrim(`
230
+ Connect to the language model and start streaming the response.
231
+ `),
232
+ };
233
+ }
234
+ case 'starting_response': {
235
+ const providerHint = describeProviderHint(context);
236
+ const cacheHint = context?.isAgentKitCached === false
237
+ ? ' Fresh runtime is being prepared because no cached agent was available.'
238
+ : '';
239
+ return {
240
+ now: spaceTrim(`
241
+ Calling the language model${providerHint} and waiting for the first tokens.${cacheHint}
242
+ `),
243
+ next: spaceTrim(`
244
+ Stream the response and update this panel with each user-relevant decision, action, or result.
245
+ `),
246
+ };
247
+ }
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Returns the user-facing label for the active agent based on available context.
253
+ *
254
+ * @private internal helper of `composeUserChatProgressPhaseText`
255
+ */
256
+ function describeAgent(context: UserChatProgressContext | undefined): string {
257
+ if (context?.agentName) {
258
+ return `agent **${context.agentName}**`;
259
+ }
260
+
261
+ if (context?.agentPermanentId) {
262
+ return `agent \`${context.agentPermanentId}\``;
263
+ }
264
+
265
+ return 'the agent';
266
+ }
267
+
268
+ /**
269
+ * Returns a fragment describing attachment count when one or more attachments are present.
270
+ *
271
+ * @private internal helper of `composeUserChatProgressPhaseText`
272
+ */
273
+ function describeAttachmentHint(context: UserChatProgressContext | undefined): string {
274
+ const count = context?.attachmentCount ?? 0;
275
+ if (count <= 0) {
276
+ return '';
277
+ }
278
+
279
+ return count === 1 ? ' and 1 attachment' : ` and ${count} attachments`;
280
+ }
281
+
282
+ /**
283
+ * Returns a fragment describing knowledge sources when one or more are configured.
284
+ *
285
+ * @private internal helper of `composeUserChatProgressPhaseText`
286
+ */
287
+ function describeKnowledgeHint(context: UserChatProgressContext | undefined): string {
288
+ const count = context?.knowledgeSourceCount ?? 0;
289
+ if (count <= 0) {
290
+ return '';
291
+ }
292
+
293
+ return count === 1 ? ' (1 knowledge source)' : ` (${count} knowledge sources)`;
294
+ }
295
+
296
+ /**
297
+ * Returns a fragment describing the LLM provider when already known.
298
+ *
299
+ * @private internal helper of `composeUserChatProgressPhaseText`
300
+ */
301
+ function describeProviderHint(context: UserChatProgressContext | undefined): string {
302
+ if (!context?.provider) {
303
+ return '';
304
+ }
305
+
306
+ return ` via ${context.provider}`;
307
+ }
308
+
309
+ /**
310
+ * Builds the markdown fragment describing tools, knowledge, attachments, and integrations.
311
+ *
312
+ * @private internal helper of `composeUserChatProgressPhaseText`
313
+ */
314
+ function describeCapabilities(context: UserChatProgressContext | undefined): string {
315
+ if (!context) {
316
+ return 'its configured tools and inputs';
317
+ }
318
+
319
+ const fragments: Array<string> = [];
320
+
321
+ const toolCount = context.toolCount ?? 0;
322
+ if (toolCount > 0) {
323
+ const highlights = (context.toolHighlights ?? []).filter((entry) => entry.trim().length > 0);
324
+ if (highlights.length > 0) {
325
+ fragments.push(`${toolCount === 1 ? '1 tool' : `${toolCount} tools`} (${highlights.join(', ')})`);
326
+ } else {
327
+ fragments.push(toolCount === 1 ? '1 tool' : `${toolCount} tools`);
328
+ }
329
+ }
330
+
331
+ const knowledgeCount = context.knowledgeSourceCount ?? 0;
332
+ if (knowledgeCount > 0) {
333
+ fragments.push(knowledgeCount === 1 ? '1 knowledge source' : `${knowledgeCount} knowledge sources`);
334
+ }
335
+
336
+ const attachmentCount = context.attachmentCount ?? 0;
337
+ if (attachmentCount > 0) {
338
+ fragments.push(attachmentCount === 1 ? '1 attachment' : `${attachmentCount} attachments`);
339
+ }
340
+
341
+ const integrations: Array<string> = [];
342
+ if (context.hasCalendarAccess) {
343
+ integrations.push('calendar');
344
+ }
345
+ if (context.hasEmailAccess) {
346
+ integrations.push('email');
347
+ }
348
+ if (context.hasProjectAccess) {
349
+ integrations.push('project repository');
350
+ }
351
+ if (integrations.length > 0) {
352
+ fragments.push(`${integrations.join(' / ')} access`);
353
+ }
354
+
355
+ if (fragments.length === 0) {
356
+ return 'its configured instructions and inputs';
357
+ }
358
+
359
+ if (fragments.length === 1) {
360
+ return fragments[0]!;
361
+ }
362
+
363
+ const head = fragments.slice(0, -1).join(', ');
364
+ const tail = fragments[fragments.length - 1]!;
365
+ return `${head}, and ${tail}`;
366
+ }
@@ -1,6 +1,7 @@
1
1
  import { NextRequest } from 'next/server';
2
2
  import { $getTableName } from '../database/$getTableName';
3
3
  import { $provideSupabaseForServer } from '../database/$provideSupabaseForServer';
4
+ import { parseSessionToken, SESSION_COOKIE_NAME } from './session';
4
5
 
5
6
  /**
6
7
  * Result of Api key validation.
@@ -21,10 +22,13 @@ export type ApiKeyValidationResult = {
21
22
  export async function validateApiKey(request: NextRequest): Promise<ApiKeyValidationResult> {
22
23
  const authHeader = request.headers.get('authorization');
23
24
 
24
- // If no auth header, check if user has a session cookie (logged in via web)
25
+ // If no auth header, check if user has a valid signed session cookie (logged in via web).
26
+ // The cookie value must pass HMAC-signature verification — merely sending a `sessionToken`
27
+ // cookie with arbitrary content must NOT authenticate the request.
25
28
  if (!authHeader) {
26
- const hasSession = request.cookies.has('sessionToken');
27
- if (hasSession) {
29
+ const sessionToken = request.cookies.get(SESSION_COOKIE_NAME)?.value;
30
+ const session = parseSessionToken(sessionToken);
31
+ if (session !== null) {
28
32
  return { isValid: true };
29
33
  }
30
34
  return {