@promptbook/cli 0.112.0-112 → 0.112.0-114

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 (94) hide show
  1. package/README.md +7 -7
  2. package/apps/agents-server/README.md +1 -1
  3. package/apps/agents-server/next.config.ts +20 -1
  4. package/apps/agents-server/src/app/agents/[agentName]/api/user-chats/[chatId]/stream/route.ts +85 -56
  5. package/apps/agents-server/src/app/agents/[agentName]/chat/useAgentChatHistorySyncEffects.ts +7 -13
  6. package/apps/agents-server/src/app/api/admin/code-runners/route.ts +1 -1
  7. package/apps/agents-server/src/app/api/internal/user-chat-jobs/run/route.ts +1 -1
  8. package/apps/agents-server/src/database/migrations/2026-06-1300-user-chat-active-read-indexes.sql +7 -0
  9. package/apps/agents-server/src/instrumentation-client.ts +28 -0
  10. package/apps/agents-server/src/instrumentation.ts +16 -0
  11. package/apps/agents-server/src/sentry.edge.config.ts +18 -0
  12. package/apps/agents-server/src/sentry.server.config.ts +19 -0
  13. package/apps/agents-server/src/utils/agentRouting/resolveAgentRouteTarget.ts +38 -0
  14. package/apps/agents-server/src/utils/codeRunnerConfiguration.ts +1 -1
  15. package/apps/agents-server/src/utils/errorReporting/agentsServerSentryContext.ts +203 -0
  16. package/apps/agents-server/src/utils/errorReporting/registerServerErrorSentryLogging.ts +59 -9
  17. package/apps/agents-server/src/utils/errorReporting/sendApplicationErrorReportToSentry.ts +39 -3
  18. package/apps/agents-server/src/utils/errorReporting/sentrySdkConfig.ts +237 -0
  19. package/apps/agents-server/src/utils/errorReporting/sentryStore.ts +10 -0
  20. package/apps/agents-server/src/utils/externalChatRunner/createExternalAgentRepositoryFiles.ts +2 -2
  21. package/apps/agents-server/src/utils/userChat/createImmediateUserChatAnswerModelRequirements.ts +15 -12
  22. package/apps/agents-server/src/utils/userChat/createUserChatDetailPayload.ts +33 -18
  23. package/apps/agents-server/src/utils/userChat/hasPotentiallyPendingAssistantMessages.ts +26 -0
  24. package/apps/agents-server/src/utils/userChat/runImmediateUserChatAnswer.ts +1 -1
  25. package/apps/agents-server/src/utils/userChat/triggerUserChatJobWorker.ts +54 -19
  26. package/apps/agents-server/src/utils/vpsConfiguration.ts +1 -1
  27. package/esm/index.es.js +9285 -8807
  28. package/esm/index.es.js.map +1 -1
  29. package/esm/scripts/run-agent-chat/executeAgentChatTurn.d.ts +28 -0
  30. package/esm/scripts/run-agent-chat/runAgentChat.d.ts +5 -0
  31. package/esm/scripts/run-agent-chat/runAgentExec.d.ts +11 -0
  32. package/esm/scripts/run-agent-messages/messages/createAgentRunnerSystemMessage.d.ts +10 -0
  33. package/esm/scripts/run-codex-prompts/common/resolveInlineOrFileText.d.ts +14 -0
  34. package/esm/scripts/run-codex-prompts/common/runGoScript/printLiveScriptChunk.d.ts +4 -0
  35. package/esm/src/_packages/node.index.d.ts +20 -0
  36. package/esm/src/_packages/types.index.d.ts +16 -0
  37. package/esm/src/book-3.0/BookNodeAgentSource.d.ts +38 -0
  38. package/esm/src/book-3.0/CliAgent.d.ts +68 -0
  39. package/esm/src/book-3.0/LiteAgent.d.ts +68 -0
  40. package/esm/src/book-components/BookEditor/BookEditorAboutPromptbookInformation.d.ts +12 -0
  41. package/esm/src/cli/cli-commands/agent/agentCliOptions.d.ts +38 -0
  42. package/esm/src/cli/cli-commands/agent/chat.d.ts +10 -0
  43. package/esm/src/cli/cli-commands/agent/exec.d.ts +10 -0
  44. package/esm/src/cli/cli-commands/agent/run.test.d.ts +1 -0
  45. package/esm/src/cli/cli-commands/agent.d.ts +14 -0
  46. package/esm/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +3 -4
  47. package/esm/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +9 -9
  48. package/esm/src/version.d.ts +1 -1
  49. package/package.json +2 -1
  50. package/src/_packages/node.index.ts +20 -0
  51. package/src/_packages/types.index.ts +16 -0
  52. package/src/book-3.0/BookNodeAgentSource.ts +135 -0
  53. package/src/book-3.0/CliAgent.ts +236 -0
  54. package/src/book-3.0/LiteAgent.ts +468 -0
  55. package/src/book-components/BookEditor/BookEditor.module.css +61 -0
  56. package/src/book-components/BookEditor/BookEditorAboutPromptbookInformation.tsx +74 -0
  57. package/src/book-components/BookEditor/BookEditorActionbar.tsx +3 -3
  58. package/src/cli/cli-commands/agent/agentCliOptions.ts +92 -0
  59. package/src/cli/cli-commands/agent/chat.ts +54 -0
  60. package/src/cli/cli-commands/agent/exec.ts +60 -0
  61. package/src/cli/cli-commands/agent.ts +44 -0
  62. package/src/cli/cli-commands/agents-server/startAgentsServer.ts +3 -19
  63. package/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts +1 -1
  64. package/src/cli/cli-commands/common/promptRunnerCliOptions.ts +27 -23
  65. package/src/cli/promptbookCli.ts +2 -0
  66. package/src/other/templates/getTemplatesPipelineCollection.ts +747 -771
  67. package/src/version.ts +2 -2
  68. package/src/versions.txt +2 -0
  69. package/umd/index.umd.js +9285 -8807
  70. package/umd/index.umd.js.map +1 -1
  71. package/umd/scripts/run-agent-chat/executeAgentChatTurn.d.ts +28 -0
  72. package/umd/scripts/run-agent-chat/runAgentChat.d.ts +5 -0
  73. package/umd/scripts/run-agent-chat/runAgentExec.d.ts +11 -0
  74. package/umd/scripts/run-agent-messages/messages/createAgentRunnerSystemMessage.d.ts +10 -0
  75. package/umd/scripts/run-codex-prompts/common/resolveInlineOrFileText.d.ts +14 -0
  76. package/umd/scripts/run-codex-prompts/common/runGoScript/printLiveScriptChunk.d.ts +4 -0
  77. package/umd/src/_packages/node.index.d.ts +20 -0
  78. package/umd/src/_packages/types.index.d.ts +16 -0
  79. package/umd/src/book-3.0/BookNodeAgentSource.d.ts +38 -0
  80. package/umd/src/book-3.0/CliAgent.d.ts +68 -0
  81. package/umd/src/book-3.0/CliAgent.test.d.ts +1 -0
  82. package/umd/src/book-3.0/LiteAgent.d.ts +68 -0
  83. package/umd/src/book-3.0/LiteAgent.test.d.ts +1 -0
  84. package/umd/src/book-components/BookEditor/BookEditorAboutPromptbookInformation.d.ts +12 -0
  85. package/umd/src/cli/cli-commands/agent/agentCliOptions.d.ts +38 -0
  86. package/umd/src/cli/cli-commands/agent/chat.d.ts +10 -0
  87. package/umd/src/cli/cli-commands/agent/exec.d.ts +10 -0
  88. package/umd/src/cli/cli-commands/agent/run.test.d.ts +1 -0
  89. package/umd/src/cli/cli-commands/agent.d.ts +14 -0
  90. package/umd/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +3 -4
  91. package/umd/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +9 -9
  92. package/umd/src/version.d.ts +1 -1
  93. /package/esm/src/{cli/cli-commands/agents-server/startAgentsServer.test.d.ts → book-3.0/CliAgent.test.d.ts} +0 -0
  94. /package/{umd/src/cli/cli-commands/agents-server/startAgentsServer.test.d.ts → esm/src/book-3.0/LiteAgent.test.d.ts} +0 -0
@@ -0,0 +1,203 @@
1
+ import { BOOK_LANGUAGE_VERSION, PROMPTBOOK_ENGINE_VERSION } from '../../../../../src/version';
2
+ import {
3
+ createSentrySdkTags,
4
+ resolveSentrySdkCommitHash,
5
+ resolveSentrySdkEnvironment,
6
+ resolveSentrySdkRelease,
7
+ resolveSentrySdkRepositoryBranch,
8
+ } from './sentrySdkConfig';
9
+ import type { SentryStorePayload } from './sentryStore';
10
+
11
+ /**
12
+ * Shared deployment and runtime context added to every Agents Server Sentry event.
13
+ */
14
+ type AgentsServerSentryContext = {
15
+ /**
16
+ * Sentry release identifier.
17
+ */
18
+ readonly release: string;
19
+
20
+ /**
21
+ * Sentry environment identifier.
22
+ */
23
+ readonly environment: string;
24
+
25
+ /**
26
+ * Filterable Sentry tags.
27
+ */
28
+ readonly tags: Record<string, string>;
29
+
30
+ /**
31
+ * Full non-secret diagnostic context.
32
+ */
33
+ readonly extra: Record<string, unknown>;
34
+ };
35
+
36
+ /**
37
+ * Adds shared Agents Server release, environment, version, deployment, git, and runtime details.
38
+ *
39
+ * @param payload - Event-specific Sentry payload.
40
+ * @returns Payload enriched with common Agents Server diagnostics.
41
+ *
42
+ * @private internal helper for Agents Server Sentry reporting
43
+ */
44
+ export function enrichSentryStorePayloadWithAgentsServerContext(payload: SentryStorePayload): SentryStorePayload {
45
+ const context = createAgentsServerSentryContext();
46
+
47
+ return {
48
+ ...payload,
49
+ release: context.release,
50
+ environment: context.environment,
51
+ tags: {
52
+ ...context.tags,
53
+ ...payload.tags,
54
+ },
55
+ extra: {
56
+ ...context.extra,
57
+ ...payload.extra,
58
+ },
59
+ };
60
+ }
61
+
62
+ /**
63
+ * Creates a current Agents Server diagnostic context matching the admin About page metadata.
64
+ *
65
+ * @returns Common Sentry context for one event.
66
+ *
67
+ * @private internal helper for Agents Server Sentry reporting
68
+ */
69
+ export function createAgentsServerSentryContext(): AgentsServerSentryContext {
70
+ const deploymentEnvironment = resolveSentrySdkEnvironment();
71
+ const appPackageVersion = normalizeOptionalString(process.env.npm_package_version) ?? PROMPTBOOK_ENGINE_VERSION;
72
+ const commitHash = resolveSentrySdkCommitHash();
73
+ const repositoryBranch = resolveSentrySdkRepositoryBranch();
74
+ const memoryUsage = process.memoryUsage();
75
+
76
+ return {
77
+ release: resolveSentrySdkRelease(),
78
+ environment: deploymentEnvironment,
79
+ tags: createSentrySdkTags(),
80
+ extra: {
81
+ agentsServer: {
82
+ versions: {
83
+ promptbookEngineVersion: PROMPTBOOK_ENGINE_VERSION,
84
+ bookLanguageVersion: BOOK_LANGUAGE_VERSION,
85
+ appPackageVersion,
86
+ appPackageName: normalizeOptionalString(process.env.npm_package_name),
87
+ nextBuildId: normalizeOptionalString(process.env.NEXT_BUILD_ID),
88
+ nextDistDirectory: normalizeOptionalString(process.env.NEXT_DIST_DIR),
89
+ npmLifecycleEvent: normalizeOptionalString(process.env.npm_lifecycle_event),
90
+ npmUserAgent: normalizeOptionalString(process.env.npm_config_user_agent),
91
+ },
92
+ deployment: {
93
+ environment: deploymentEnvironment,
94
+ vercelEnvironment: getFirstNonEmptyString(process.env.NEXT_PUBLIC_VERCEL_ENV, process.env.VERCEL_ENV),
95
+ targetEnvironment: getFirstNonEmptyString(
96
+ process.env.NEXT_PUBLIC_VERCEL_TARGET_ENV,
97
+ process.env.VERCEL_TARGET_ENV,
98
+ ),
99
+ siteUrl: normalizeOptionalString(process.env.NEXT_PUBLIC_SITE_URL),
100
+ vercelUrl: getFirstNonEmptyString(process.env.NEXT_PUBLIC_VERCEL_URL, process.env.VERCEL_URL),
101
+ vercelBranchUrl: normalizeOptionalString(process.env.NEXT_PUBLIC_VERCEL_BRANCH_URL),
102
+ vercelProductionUrl: normalizeOptionalString(process.env.NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL),
103
+ vercelRegion: normalizeOptionalString(process.env.VERCEL_REGION),
104
+ repositoryRef: normalizeOptionalString(process.env.PROMPTBOOK_REPOSITORY_REF),
105
+ supabaseTablePrefix: normalizeOptionalString(process.env.SUPABASE_TABLE_PREFIX),
106
+ currentWorkingDirectory: process.cwd(),
107
+ },
108
+ git: {
109
+ provider: getFirstNonEmptyString(
110
+ process.env.NEXT_PUBLIC_VERCEL_GIT_PROVIDER,
111
+ process.env.VERCEL_GIT_PROVIDER,
112
+ ),
113
+ repositoryOwner: getFirstNonEmptyString(
114
+ process.env.NEXT_PUBLIC_VERCEL_GIT_REPO_OWNER,
115
+ process.env.VERCEL_GIT_REPO_OWNER,
116
+ ),
117
+ repositorySlug: getFirstNonEmptyString(
118
+ process.env.NEXT_PUBLIC_VERCEL_GIT_REPO_SLUG,
119
+ process.env.VERCEL_GIT_REPO_SLUG,
120
+ ),
121
+ repositoryId: getFirstNonEmptyString(
122
+ process.env.NEXT_PUBLIC_VERCEL_GIT_REPO_ID,
123
+ process.env.VERCEL_GIT_REPO_ID,
124
+ ),
125
+ commitHash,
126
+ previousCommitHash: getFirstNonEmptyString(
127
+ process.env.NEXT_PUBLIC_VERCEL_GIT_PREVIOUS_SHA,
128
+ process.env.VERCEL_GIT_PREVIOUS_SHA,
129
+ ),
130
+ branch: repositoryBranch,
131
+ commitMessage: getFirstNonEmptyString(
132
+ process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_MESSAGE,
133
+ process.env.VERCEL_GIT_COMMIT_MESSAGE,
134
+ ),
135
+ authorName: getFirstNonEmptyString(
136
+ process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_AUTHOR_NAME,
137
+ process.env.VERCEL_GIT_COMMIT_AUTHOR_NAME,
138
+ ),
139
+ authorLogin: getFirstNonEmptyString(
140
+ process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_AUTHOR_LOGIN,
141
+ process.env.VERCEL_GIT_COMMIT_AUTHOR_LOGIN,
142
+ ),
143
+ pullRequestId: getFirstNonEmptyString(
144
+ process.env.NEXT_PUBLIC_VERCEL_GIT_PULL_REQUEST_ID,
145
+ process.env.VERCEL_GIT_PULL_REQUEST_ID,
146
+ ),
147
+ },
148
+ runtime: {
149
+ nodeVersion: process.version,
150
+ nodeEnvironment: normalizeOptionalString(process.env.NODE_ENV),
151
+ nextRuntime: normalizeOptionalString(process.env.NEXT_RUNTIME),
152
+ processId: process.pid,
153
+ processUptimeSeconds: process.uptime(),
154
+ hostname: getFirstNonEmptyString(process.env.HOSTNAME, process.env.COMPUTERNAME),
155
+ platform: process.platform,
156
+ architecture: process.arch,
157
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC',
158
+ },
159
+ memory: {
160
+ rssBytes: memoryUsage.rss,
161
+ heapUsedBytes: memoryUsage.heapUsed,
162
+ heapTotalBytes: memoryUsage.heapTotal,
163
+ externalBytes: memoryUsage.external,
164
+ arrayBuffersBytes: memoryUsage.arrayBuffers ?? 0,
165
+ },
166
+ },
167
+ },
168
+ };
169
+ }
170
+
171
+ /**
172
+ * Returns the first non-empty string from a list.
173
+ *
174
+ * @param values - Candidate values in priority order.
175
+ * @returns First trimmed string or null.
176
+ */
177
+ function getFirstNonEmptyString(...values: Array<string | null | undefined>): string | null {
178
+ for (const value of values) {
179
+ const normalizedValue = normalizeOptionalString(value);
180
+
181
+ if (normalizedValue) {
182
+ return normalizedValue;
183
+ }
184
+ }
185
+
186
+ return null;
187
+ }
188
+
189
+ /**
190
+ * Trims one optional environment value.
191
+ *
192
+ * @param value - Raw optional value.
193
+ * @returns Trimmed string or null.
194
+ */
195
+ function normalizeOptionalString(value: string | null | undefined): string | null {
196
+ if (typeof value !== 'string') {
197
+ return null;
198
+ }
199
+
200
+ const normalizedValue = value.trim();
201
+
202
+ return normalizedValue || null;
203
+ }
@@ -1,5 +1,8 @@
1
1
  import { inspect } from 'node:util';
2
+ import * as Sentry from '@sentry/nextjs';
2
3
  import { DEFAULT_APPLICATION_ERROR_SERVER_NAME } from './applicationErrorHandling';
4
+ import { createAgentsServerSentryContext } from './agentsServerSentryContext';
5
+ import { enrichSentryStorePayloadWithAgentsServerContext } from './agentsServerSentryContext';
3
6
  import {
4
7
  createSentryTimestamp,
5
8
  resolveOptionalSentryDsn,
@@ -81,13 +84,17 @@ export function registerServerErrorSentryLogging(): void {
81
84
  console.error = (...consoleArguments: unknown[]): void => {
82
85
  loggingState.originalConsoleError?.(...consoleArguments);
83
86
 
87
+ const sentryPayload = createServerErrorSentryStorePayload(consoleArguments);
88
+
89
+ if (captureServerErrorWithSentrySdk(sentryPayload)) {
90
+ return;
91
+ }
92
+
84
93
  const sentryDsn = resolveOptionalSentryDsn();
85
94
  if (!sentryDsn) {
86
95
  return;
87
96
  }
88
97
 
89
- const sentryPayload = createServerErrorSentryStorePayload(consoleArguments);
90
-
91
98
  // Never log reporting failures through `console.error`, otherwise a broken Sentry configuration would recurse.
92
99
  void sendSentryStorePayload(sentryPayload, sentryDsn).catch(() => undefined);
93
100
  };
@@ -144,7 +151,7 @@ function getServerErrorSentryLoggingState(): ServerErrorSentryLoggingState {
144
151
  function createServerErrorSentryStorePayload(consoleArguments: readonly unknown[]): SentryStorePayload {
145
152
  const loggedError = findLoggedErrorInfo(consoleArguments);
146
153
 
147
- return {
154
+ return enrichSentryStorePayloadWithAgentsServerContext({
148
155
  platform: 'javascript',
149
156
  level: 'error',
150
157
  logger: SENTRY_SERVER_ERROR_LOGGER,
@@ -153,8 +160,6 @@ function createServerErrorSentryStorePayload(consoleArguments: readonly unknown[
153
160
  server_name: process.env.NEXT_PUBLIC_SERVER_NAME ?? DEFAULT_APPLICATION_ERROR_SERVER_NAME,
154
161
  tags: {
155
162
  source: 'agents-server.console-error',
156
- nextRuntime: process.env.NEXT_RUNTIME ?? 'nodejs',
157
- nodeEnv: process.env.NODE_ENV ?? 'unknown',
158
163
  },
159
164
  exception: loggedError
160
165
  ? {
@@ -169,11 +174,56 @@ function createServerErrorSentryStorePayload(consoleArguments: readonly unknown[
169
174
  extra: {
170
175
  consoleArguments: consoleArguments.map(serializeConsoleArgument),
171
176
  errorStack: loggedError?.stack ?? null,
172
- vercelEnv: process.env.VERCEL_ENV ?? null,
173
- vercelRegion: process.env.VERCEL_REGION ?? null,
174
- vercelUrl: process.env.VERCEL_URL ?? null,
175
177
  },
176
- };
178
+ });
179
+ }
180
+
181
+ /**
182
+ * Captures a server-side console error through the official Sentry SDK when it is initialized.
183
+ *
184
+ * @param sentryPayload - Structured event payload created from the original `console.error` call.
185
+ * @returns True when the SDK accepted the event.
186
+ */
187
+ function captureServerErrorWithSentrySdk(sentryPayload: SentryStorePayload): boolean {
188
+ if (!Sentry.getClient()) {
189
+ return false;
190
+ }
191
+
192
+ const agentsServerContext = createAgentsServerSentryContext();
193
+
194
+ Sentry.captureException(createServerErrorSdkException(sentryPayload), {
195
+ level: sentryPayload.level,
196
+ tags: {
197
+ ...agentsServerContext.tags,
198
+ ...sentryPayload.tags,
199
+ },
200
+ extra: {
201
+ ...agentsServerContext.extra,
202
+ ...sentryPayload.extra,
203
+ },
204
+ });
205
+
206
+ return true;
207
+ }
208
+
209
+ /**
210
+ * Rebuilds an `Error` object from the structured Sentry payload so the SDK can parse stack frames.
211
+ *
212
+ * @param sentryPayload - Structured event payload created from the original `console.error` call.
213
+ * @returns Error object with the original stack when one was logged.
214
+ */
215
+ function createServerErrorSdkException(sentryPayload: SentryStorePayload): Error {
216
+ const error = new Error(sentryPayload.message);
217
+ const exceptionValue = sentryPayload.exception?.values.at(0);
218
+ const errorStack = sentryPayload.extra?.errorStack;
219
+
220
+ error.name = exceptionValue?.type ?? 'Error';
221
+
222
+ if (typeof errorStack === 'string' && errorStack.trim()) {
223
+ error.stack = errorStack;
224
+ }
225
+
226
+ return error;
177
227
  }
178
228
 
179
229
  /**
@@ -1,4 +1,6 @@
1
+ import * as Sentry from '@sentry/nextjs';
1
2
  import type { ApplicationErrorReportPayload } from './applicationErrorHandling';
3
+ import { enrichSentryStorePayloadWithAgentsServerContext } from './agentsServerSentryContext';
2
4
  import {
3
5
  createSentryTimestamp,
4
6
  resolveRequiredSentryDsn,
@@ -18,7 +20,7 @@ const SENTRY_APPLICATION_ERROR_LOGGER = 'agents-server.application-error';
18
20
  * @returns Sentry store payload.
19
21
  */
20
22
  function createSentryStorePayload(report: ApplicationErrorReportPayload): SentryStorePayload {
21
- return {
23
+ return enrichSentryStorePayloadWithAgentsServerContext({
22
24
  platform: 'javascript',
23
25
  level: 'error',
24
26
  logger: SENTRY_APPLICATION_ERROR_LOGGER,
@@ -44,7 +46,7 @@ function createSentryStorePayload(report: ApplicationErrorReportPayload): Sentry
44
46
  pageUrl: report.pageUrl ?? null,
45
47
  reportedAt: report.reportedAt,
46
48
  },
47
- };
49
+ });
48
50
  }
49
51
 
50
52
  /**
@@ -53,5 +55,39 @@ function createSentryStorePayload(report: ApplicationErrorReportPayload): Sentry
53
55
  * @param report - Structured browser report payload.
54
56
  */
55
57
  export async function sendApplicationErrorReportToSentry(report: ApplicationErrorReportPayload): Promise<void> {
56
- await sendSentryStorePayload(createSentryStorePayload(report), resolveRequiredSentryDsn());
58
+ const sentryPayload = createSentryStorePayload(report);
59
+
60
+ if (Sentry.getClient()) {
61
+ Sentry.captureException(createApplicationErrorSdkException(report, sentryPayload), {
62
+ level: sentryPayload.level,
63
+ tags: sentryPayload.tags,
64
+ extra: sentryPayload.extra,
65
+ });
66
+ await Sentry.flush(2000);
67
+ return;
68
+ }
69
+
70
+ await sendSentryStorePayload(sentryPayload, resolveRequiredSentryDsn());
71
+ }
72
+
73
+ /**
74
+ * Rebuilds an `Error` object from a browser application report so the SDK can parse stack frames.
75
+ *
76
+ * @param report - Browser-generated application error report.
77
+ * @param sentryPayload - Structured Sentry payload created from the report.
78
+ * @returns Error object with the original browser stack when available.
79
+ */
80
+ function createApplicationErrorSdkException(
81
+ report: ApplicationErrorReportPayload,
82
+ sentryPayload: SentryStorePayload,
83
+ ): Error {
84
+ const error = new Error(sentryPayload.message);
85
+
86
+ error.name = report.errorName || 'Error';
87
+
88
+ if (report.errorStack?.trim()) {
89
+ error.stack = report.errorStack;
90
+ }
91
+
92
+ return error;
57
93
  }
@@ -0,0 +1,237 @@
1
+ import { BOOK_LANGUAGE_VERSION, PROMPTBOOK_ENGINE_VERSION } from '../../../../../src/version';
2
+
3
+ /**
4
+ * Default Sentry project DSN for Promptbook Agents Server telemetry.
5
+ *
6
+ * @private internal Sentry SDK configuration for Agents Server
7
+ */
8
+ export const DEFAULT_SENTRY_DSN =
9
+ 'https://986f734e9cddaeeec33e2a360f7d0b62@o4508778158030848.ingest.de.sentry.io/4511534509785168';
10
+
11
+ /**
12
+ * Sentry organization slug used by build-time SDK tooling.
13
+ *
14
+ * @private internal Sentry SDK configuration for Agents Server
15
+ */
16
+ export const SENTRY_ORGANIZATION = 'promptbook';
17
+
18
+ /**
19
+ * Sentry project slug used by build-time SDK tooling.
20
+ *
21
+ * @private internal Sentry SDK configuration for Agents Server
22
+ */
23
+ export const SENTRY_PROJECT = 's22';
24
+
25
+ /**
26
+ * Performance tracing sample rate requested for the Agents Server.
27
+ *
28
+ * @private internal Sentry SDK configuration for Agents Server
29
+ */
30
+ export const SENTRY_TRACES_SAMPLE_RATE = 1.0;
31
+
32
+ /**
33
+ * Browser-side targets that should receive distributed tracing headers.
34
+ *
35
+ * @private internal Sentry SDK configuration for Agents Server
36
+ */
37
+ export const SENTRY_TRACE_PROPAGATION_TARGETS: Array<string | RegExp> = [
38
+ 'localhost',
39
+ /^\/api\//,
40
+ /^https:\/\/.*\.ptbk\.io\/api\//,
41
+ /^https:\/\/.*\.vercel\.app\/api\//,
42
+ ];
43
+
44
+ /**
45
+ * Release name used for Agents Server Sentry events.
46
+ */
47
+ const AGENTS_SERVER_SENTRY_RELEASE_NAME = 'promptbook-agents-server';
48
+
49
+ /**
50
+ * Fallback text used in Sentry tags when a value is not configured.
51
+ */
52
+ const UNKNOWN_SENTRY_CONTEXT_VALUE = 'unknown';
53
+
54
+ /**
55
+ * Maximum length kept for Sentry tag values.
56
+ */
57
+ const MAX_SENTRY_TAG_VALUE_LENGTH = 200;
58
+
59
+ /**
60
+ * Resolves the browser-safe Sentry DSN.
61
+ *
62
+ * @returns Browser-safe Sentry DSN.
63
+ *
64
+ * @private internal Sentry SDK configuration for Agents Server
65
+ */
66
+ export function resolveBrowserSentryDsn(): string {
67
+ return process.env.NEXT_PUBLIC_SENTRY_DSN ?? DEFAULT_SENTRY_DSN;
68
+ }
69
+
70
+ /**
71
+ * Resolves the server-side Sentry DSN.
72
+ *
73
+ * @returns Server-side Sentry DSN.
74
+ *
75
+ * @private internal Sentry SDK configuration for Agents Server
76
+ */
77
+ export function resolveServerSentryDsn(): string {
78
+ return process.env.SENTRY_DSN ?? resolveBrowserSentryDsn();
79
+ }
80
+
81
+ /**
82
+ * Resolves the most specific deployment environment name available.
83
+ *
84
+ * @returns Environment name suitable for Sentry.
85
+ *
86
+ * @private internal Sentry SDK configuration for Agents Server
87
+ */
88
+ export function resolveSentrySdkEnvironment(): string {
89
+ return (
90
+ getFirstNonEmptyString(
91
+ process.env.SENTRY_ENVIRONMENT,
92
+ process.env.NEXT_PUBLIC_VERCEL_TARGET_ENV,
93
+ process.env.VERCEL_TARGET_ENV,
94
+ process.env.NEXT_PUBLIC_VERCEL_ENV,
95
+ process.env.VERCEL_ENV,
96
+ process.env.PROMPTBOOK_REPOSITORY_REF,
97
+ process.env.NODE_ENV,
98
+ ) ?? UNKNOWN_SENTRY_CONTEXT_VALUE
99
+ );
100
+ }
101
+
102
+ /**
103
+ * Resolves the current deployment commit hash from common hosting environment variables.
104
+ *
105
+ * @returns Commit hash or null when unavailable.
106
+ *
107
+ * @private internal Sentry SDK configuration for Agents Server
108
+ */
109
+ export function resolveSentrySdkCommitHash(): string | null {
110
+ return getFirstNonEmptyString(
111
+ process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA,
112
+ process.env.VERCEL_GIT_COMMIT_SHA,
113
+ process.env.PROMPTBOOK_COMMIT_SHA,
114
+ process.env.GIT_COMMIT_SHA,
115
+ process.env.COMMIT_SHA,
116
+ process.env.SOURCE_VERSION,
117
+ );
118
+ }
119
+
120
+ /**
121
+ * Resolves the current repository branch or deployment ref.
122
+ *
123
+ * @returns Repository branch/ref or null when unavailable.
124
+ *
125
+ * @private internal Sentry SDK configuration for Agents Server
126
+ */
127
+ export function resolveSentrySdkRepositoryBranch(): string | null {
128
+ return getFirstNonEmptyString(
129
+ process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_REF,
130
+ process.env.VERCEL_GIT_COMMIT_REF,
131
+ process.env.PROMPTBOOK_REPOSITORY_REF,
132
+ process.env.GIT_BRANCH,
133
+ process.env.BRANCH_NAME,
134
+ );
135
+ }
136
+
137
+ /**
138
+ * Resolves the Sentry release name for the current Agents Server build.
139
+ *
140
+ * @returns Release identifier suitable for Sentry.
141
+ *
142
+ * @private internal Sentry SDK configuration for Agents Server
143
+ */
144
+ export function resolveSentrySdkRelease(): string {
145
+ const appPackageVersion = normalizeOptionalString(process.env.npm_package_version) ?? PROMPTBOOK_ENGINE_VERSION;
146
+ const commitHash = resolveSentrySdkCommitHash();
147
+
148
+ if (!commitHash) {
149
+ return `${AGENTS_SERVER_SENTRY_RELEASE_NAME}@${appPackageVersion}`;
150
+ }
151
+
152
+ return `${AGENTS_SERVER_SENTRY_RELEASE_NAME}@${appPackageVersion}+${commitHash}`;
153
+ }
154
+
155
+ /**
156
+ * Creates shared filterable Sentry tags for Agents Server events.
157
+ *
158
+ * @returns Sanitized Sentry tags.
159
+ *
160
+ * @private internal Sentry SDK configuration for Agents Server
161
+ */
162
+ export function createSentrySdkTags(): Record<string, string> {
163
+ return createSentryTags({
164
+ promptbookEngineVersion: PROMPTBOOK_ENGINE_VERSION,
165
+ bookLanguageVersion: BOOK_LANGUAGE_VERSION,
166
+ appPackageVersion: normalizeOptionalString(process.env.npm_package_version) ?? PROMPTBOOK_ENGINE_VERSION,
167
+ commitHash: resolveSentrySdkCommitHash(),
168
+ repositoryBranch: resolveSentrySdkRepositoryBranch(),
169
+ deploymentEnvironment: resolveSentrySdkEnvironment(),
170
+ vercelEnvironment: getFirstNonEmptyString(process.env.NEXT_PUBLIC_VERCEL_ENV, process.env.VERCEL_ENV),
171
+ targetEnvironment: getFirstNonEmptyString(
172
+ process.env.NEXT_PUBLIC_VERCEL_TARGET_ENV,
173
+ process.env.VERCEL_TARGET_ENV,
174
+ ),
175
+ nextRuntime: process.env.NEXT_RUNTIME,
176
+ nodeEnvironment: process.env.NODE_ENV,
177
+ vercelRegion: process.env.VERCEL_REGION,
178
+ });
179
+ }
180
+
181
+ /**
182
+ * Creates Sentry tag values, preserving missing values as explicit `unknown` markers.
183
+ *
184
+ * @param values - Raw tag values.
185
+ * @returns Sanitized Sentry tags.
186
+ */
187
+ function createSentryTags(values: Record<string, string | null | undefined>): Record<string, string> {
188
+ return Object.fromEntries(
189
+ Object.entries(values).map(([key, value]) => [key, sanitizeSentryTagValue(value)]),
190
+ ) as Record<string, string>;
191
+ }
192
+
193
+ /**
194
+ * Normalizes one value for use as a Sentry tag.
195
+ *
196
+ * @param value - Optional tag value.
197
+ * @returns Non-empty bounded tag value.
198
+ */
199
+ function sanitizeSentryTagValue(value: string | null | undefined): string {
200
+ const normalizedValue = normalizeOptionalString(value) ?? UNKNOWN_SENTRY_CONTEXT_VALUE;
201
+
202
+ return normalizedValue.replace(/\s+/gu, ' ').slice(0, MAX_SENTRY_TAG_VALUE_LENGTH);
203
+ }
204
+
205
+ /**
206
+ * Returns the first non-empty string from a list.
207
+ *
208
+ * @param values - Candidate values in priority order.
209
+ * @returns First trimmed string or null.
210
+ */
211
+ function getFirstNonEmptyString(...values: Array<string | null | undefined>): string | null {
212
+ for (const value of values) {
213
+ const normalizedValue = normalizeOptionalString(value);
214
+
215
+ if (normalizedValue) {
216
+ return normalizedValue;
217
+ }
218
+ }
219
+
220
+ return null;
221
+ }
222
+
223
+ /**
224
+ * Trims one optional environment value.
225
+ *
226
+ * @param value - Raw optional value.
227
+ * @returns Trimmed string or null.
228
+ */
229
+ function normalizeOptionalString(value: string | null | undefined): string | null {
230
+ if (typeof value !== 'string') {
231
+ return null;
232
+ }
233
+
234
+ const normalizedValue = value.trim();
235
+
236
+ return normalizedValue || null;
237
+ }
@@ -52,6 +52,16 @@ export type SentryStorePayload = {
52
52
  */
53
53
  message: string;
54
54
 
55
+ /**
56
+ * Sentry release identifier.
57
+ */
58
+ release?: string;
59
+
60
+ /**
61
+ * Deployment environment such as production, preview, or staging.
62
+ */
63
+ environment?: string;
64
+
55
65
  /**
56
66
  * Server/deployment name.
57
67
  */
@@ -53,9 +53,9 @@ function createExternalAgentRepositoryPackageJson(): string {
53
53
  scripts: {
54
54
  start: 'npm run agent:run',
55
55
  'agent:run':
56
- 'npx ptbk agent-folder run-agent --agent github-copilot --model gpt-5.4 --thinking-level high --auto-pull --auto-push',
56
+ 'npx ptbk agent-folder run-agent --harness github-copilot --model gpt-5.4 --thinking-level high --auto-pull --auto-push',
57
57
  'agent-local:run':
58
- 'ts-node ../../promptbook/src/cli/test/ptbk.ts agent-folder run-agent --agent github-copilot --model gpt-5.4 --auto-pull --auto-push',
58
+ 'ts-node ../../promptbook/src/cli/test/ptbk.ts agent-folder run-agent --harness github-copilot --model gpt-5.4 --auto-pull --auto-push',
59
59
  },
60
60
  },
61
61
  null,