veryfront 0.1.231 → 0.1.233

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 (55) hide show
  1. package/esm/deno.d.ts +2 -0
  2. package/esm/deno.js +3 -1
  3. package/esm/src/agent/conversation-bootstrap.d.ts +61 -0
  4. package/esm/src/agent/conversation-bootstrap.d.ts.map +1 -0
  5. package/esm/src/agent/conversation-bootstrap.js +131 -0
  6. package/esm/src/agent/durable.d.ts +118 -0
  7. package/esm/src/agent/durable.d.ts.map +1 -0
  8. package/esm/src/agent/durable.js +191 -0
  9. package/esm/src/agent/index.d.ts +2 -0
  10. package/esm/src/agent/index.d.ts.map +1 -1
  11. package/esm/src/agent/index.js +2 -0
  12. package/esm/src/channels/control-plane.d.ts +6 -0
  13. package/esm/src/channels/control-plane.d.ts.map +1 -1
  14. package/esm/src/channels/control-plane.js +6 -0
  15. package/esm/src/proxy/handler.d.ts.map +1 -1
  16. package/esm/src/proxy/handler.js +1 -0
  17. package/esm/src/server/handlers/request/agent-run-cancel.handler.d.ts.map +1 -1
  18. package/esm/src/server/handlers/request/agent-run-cancel.handler.js +6 -2
  19. package/esm/src/server/handlers/request/agent-run-resume.handler.d.ts.map +1 -1
  20. package/esm/src/server/handlers/request/agent-run-resume.handler.js +6 -2
  21. package/esm/src/server/handlers/request/agent-stream.handler.d.ts.map +1 -1
  22. package/esm/src/server/handlers/request/agent-stream.handler.js +5 -1
  23. package/esm/src/server/handlers/request/internal-agents-list.handler.d.ts.map +1 -1
  24. package/esm/src/server/handlers/request/internal-agents-list.handler.js +5 -2
  25. package/esm/src/server/runtime-handler/environment-resolution.d.ts.map +1 -1
  26. package/esm/src/server/runtime-handler/environment-resolution.js +2 -1
  27. package/esm/src/server/runtime-handler/request-utils.d.ts.map +1 -1
  28. package/esm/src/server/runtime-handler/request-utils.js +2 -1
  29. package/esm/src/utils/index.d.ts +2 -2
  30. package/esm/src/utils/index.d.ts.map +1 -1
  31. package/esm/src/utils/index.js +1 -1
  32. package/esm/src/utils/logger/logger.d.ts +6 -0
  33. package/esm/src/utils/logger/logger.d.ts.map +1 -1
  34. package/esm/src/utils/logger/logger.js +10 -0
  35. package/esm/src/utils/logger/request-context.d.ts +2 -0
  36. package/esm/src/utils/logger/request-context.d.ts.map +1 -1
  37. package/esm/src/utils/version-constant.d.ts +1 -1
  38. package/esm/src/utils/version-constant.js +1 -1
  39. package/package.json +9 -1
  40. package/src/deno.js +3 -1
  41. package/src/src/agent/conversation-bootstrap.ts +195 -0
  42. package/src/src/agent/durable.ts +259 -0
  43. package/src/src/agent/index.ts +23 -0
  44. package/src/src/channels/control-plane.ts +7 -0
  45. package/src/src/proxy/handler.ts +1 -0
  46. package/src/src/server/handlers/request/agent-run-cancel.handler.ts +9 -2
  47. package/src/src/server/handlers/request/agent-run-resume.handler.ts +10 -2
  48. package/src/src/server/handlers/request/agent-stream.handler.ts +9 -2
  49. package/src/src/server/handlers/request/internal-agents-list.handler.ts +6 -1
  50. package/src/src/server/runtime-handler/environment-resolution.ts +2 -1
  51. package/src/src/server/runtime-handler/request-utils.ts +2 -1
  52. package/src/src/utils/index.ts +4 -1
  53. package/src/src/utils/logger/logger.ts +16 -0
  54. package/src/src/utils/logger/request-context.ts +2 -0
  55. package/src/src/utils/version-constant.ts +1 -1
@@ -0,0 +1,259 @@
1
+ import "../../_dnt.polyfills.js";
2
+ import * as dntShim from "../../_dnt.shims.js";
3
+ import { z } from "zod";
4
+
5
+ const AGENT_RUN_API_TIMEOUT_MS = 15_000;
6
+
7
+ export const ConversationRunTargetsSchema = z.object({
8
+ sourceTargetKind: z.enum(["project", "preview_branch"]).nullable(),
9
+ runtimeTargetKind: z.enum(["production", "preview_branch"]).nullable(),
10
+ targetBranchId: z.string().uuid().nullable(),
11
+ });
12
+
13
+ export type ConversationRunTargets = z.infer<typeof ConversationRunTargetsSchema>;
14
+
15
+ export function resolveConversationRunTargets(input: {
16
+ projectId?: string | null;
17
+ branchId?: string | null;
18
+ }): ConversationRunTargets {
19
+ return ConversationRunTargetsSchema.parse(
20
+ !input.projectId
21
+ ? {
22
+ sourceTargetKind: null,
23
+ runtimeTargetKind: null,
24
+ targetBranchId: null,
25
+ }
26
+ : input.branchId
27
+ ? {
28
+ sourceTargetKind: "preview_branch",
29
+ runtimeTargetKind: "preview_branch",
30
+ targetBranchId: input.branchId,
31
+ }
32
+ : {
33
+ sourceTargetKind: "project",
34
+ runtimeTargetKind: "production",
35
+ targetBranchId: null,
36
+ },
37
+ );
38
+ }
39
+
40
+ export const ConversationRunProjectionSchema = z
41
+ .object({
42
+ runId: z.string().min(1).optional(),
43
+ run_id: z.string().min(1).optional(),
44
+ conversationId: z.string().uuid().optional(),
45
+ conversation_id: z.string().uuid().optional(),
46
+ messageId: z.string().uuid().optional(),
47
+ message_id: z.string().uuid().optional(),
48
+ latestEventId: z.number().int().nonnegative().optional(),
49
+ latest_event_id: z.number().int().nonnegative().optional(),
50
+ latestExternalEventSequence: z.number().int().nonnegative().optional(),
51
+ latest_external_event_sequence: z.number().int().nonnegative().optional(),
52
+ status: z.enum(["pending", "running", "waiting_for_tool", "completed", "failed", "cancelled"]),
53
+ })
54
+ .passthrough()
55
+ .transform((data) => {
56
+ const runId = data.runId ?? data.run_id;
57
+ const conversationId = data.conversationId ?? data.conversation_id;
58
+ const messageId = data.messageId ?? data.message_id;
59
+ const latestEventId = data.latestEventId ?? data.latest_event_id ?? 0;
60
+ const latestExternalEventSequence = data.latestExternalEventSequence ??
61
+ data.latest_external_event_sequence;
62
+
63
+ if (!runId || !conversationId || !messageId) {
64
+ throw new Error("Missing run identifiers in durable run response");
65
+ }
66
+
67
+ if (latestExternalEventSequence === undefined) {
68
+ throw new Error("Missing latestExternalEventSequence in durable run response");
69
+ }
70
+
71
+ return {
72
+ runId,
73
+ conversationId,
74
+ messageId,
75
+ latestEventId,
76
+ latestExternalEventSequence,
77
+ status: data.status,
78
+ };
79
+ });
80
+
81
+ export type ConversationRunProjection = z.infer<typeof ConversationRunProjectionSchema>;
82
+
83
+ export const CreateConversationRunAcceptedSchema = z
84
+ .object({
85
+ run: z
86
+ .object({
87
+ runId: z.string().min(1).optional(),
88
+ run_id: z.string().min(1).optional(),
89
+ })
90
+ .passthrough(),
91
+ })
92
+ .passthrough()
93
+ .transform((data) => {
94
+ const runId = data.run.runId ?? data.run.run_id;
95
+ if (!runId) {
96
+ throw new Error("Missing run id in canonical create run response");
97
+ }
98
+
99
+ return { runId };
100
+ });
101
+
102
+ export const CompleteConversationRunResponseSchema = z
103
+ .object({
104
+ completed: z.boolean(),
105
+ run: z
106
+ .object({
107
+ runId: z.string().min(1).optional(),
108
+ run_id: z.string().min(1).optional(),
109
+ status: z.enum(["pending", "running", "waiting", "completed", "failed", "cancelled"]),
110
+ })
111
+ .passthrough(),
112
+ })
113
+ .passthrough();
114
+
115
+ export interface ConversationAgentRunUsage {
116
+ inputTokens: number;
117
+ outputTokens: number;
118
+ totalTokens: number;
119
+ }
120
+
121
+ export interface CreateConversationAgentRunInput {
122
+ authToken: string;
123
+ apiUrl: string;
124
+ conversationId: string;
125
+ runId?: string;
126
+ agentId: string;
127
+ projectId?: string | null;
128
+ branchId?: string | null;
129
+ }
130
+
131
+ export interface FinalizeConversationAgentRunInput {
132
+ authToken: string;
133
+ apiUrl: string;
134
+ conversationId: string;
135
+ runId: string;
136
+ status: "completed" | "failed" | "cancelled";
137
+ model: string;
138
+ provider: string;
139
+ usage?: ConversationAgentRunUsage;
140
+ terminalErrorCode?: string | null;
141
+ terminalErrorMessage?: string | null;
142
+ }
143
+
144
+ async function controlPlaneJson<T>(input: {
145
+ authToken: string;
146
+ url: string;
147
+ method?: "GET" | "POST";
148
+ body?: unknown;
149
+ responseSchema: z.ZodSchema<T>;
150
+ operation: string;
151
+ }): Promise<T> {
152
+ const controller = new AbortController();
153
+ const timeout = dntShim.setTimeout(() => {
154
+ controller.abort();
155
+ }, AGENT_RUN_API_TIMEOUT_MS);
156
+
157
+ let response: Response;
158
+ try {
159
+ response = await fetch(input.url, {
160
+ method: input.method ?? "GET",
161
+ headers: {
162
+ Authorization: `Bearer ${input.authToken}`,
163
+ "Content-Type": "application/json",
164
+ },
165
+ ...(input.body !== undefined ? { body: JSON.stringify(input.body) } : {}),
166
+ signal: controller.signal,
167
+ });
168
+ } catch (error) {
169
+ if (error instanceof DOMException && error.name === "AbortError") {
170
+ throw new Error(`${input.operation} timed out after ${AGENT_RUN_API_TIMEOUT_MS}ms`);
171
+ }
172
+ throw error;
173
+ } finally {
174
+ clearTimeout(timeout);
175
+ }
176
+
177
+ if (!response.ok) {
178
+ const body = await response.text().catch(() => "");
179
+ throw new Error(
180
+ `${input.operation} failed (${response.status}): ${body || response.statusText}`,
181
+ );
182
+ }
183
+
184
+ return input.responseSchema.parse(await response.json());
185
+ }
186
+
187
+ export async function createConversationAgentRun(
188
+ input: CreateConversationAgentRunInput,
189
+ ): Promise<ConversationRunProjection> {
190
+ const targets = resolveConversationRunTargets({
191
+ projectId: input.projectId ?? null,
192
+ branchId: input.branchId ?? null,
193
+ });
194
+ const runId = input.runId ?? `run_${dntShim.crypto.randomUUID()}`;
195
+
196
+ await controlPlaneJson({
197
+ authToken: input.authToken,
198
+ url: `${input.apiUrl}/runs`,
199
+ method: "POST",
200
+ body: {
201
+ kind: "agent",
202
+ owner: {
203
+ kind: "conversation",
204
+ id: input.conversationId,
205
+ },
206
+ public_id: runId,
207
+ request: {
208
+ mode: "default_chat",
209
+ agent_id: input.agentId,
210
+ initial_status: "running",
211
+ ...(targets.sourceTargetKind ? { source_target_kind: targets.sourceTargetKind } : {}),
212
+ ...(targets.runtimeTargetKind ? { runtime_target_kind: targets.runtimeTargetKind } : {}),
213
+ ...(targets.targetBranchId
214
+ ? {
215
+ source_target_branch_id: targets.targetBranchId,
216
+ runtime_target_branch_id: targets.targetBranchId,
217
+ }
218
+ : {}),
219
+ },
220
+ },
221
+ responseSchema: CreateConversationRunAcceptedSchema,
222
+ operation: "Create canonical durable run",
223
+ });
224
+
225
+ return controlPlaneJson({
226
+ authToken: input.authToken,
227
+ url: `${input.apiUrl}/conversations/${input.conversationId}/runs/${runId}`,
228
+ responseSchema: ConversationRunProjectionSchema,
229
+ operation: "Read conversation durable run projection",
230
+ });
231
+ }
232
+
233
+ export async function finalizeConversationAgentRun(
234
+ input: FinalizeConversationAgentRunInput,
235
+ ): Promise<void> {
236
+ const metadata = input.status === "completed"
237
+ ? {
238
+ provider: input.provider,
239
+ model: input.model,
240
+ inputTokens: input.usage?.inputTokens ?? 0,
241
+ outputTokens: input.usage?.outputTokens ?? 0,
242
+ finishReason: "stop",
243
+ }
244
+ : null;
245
+
246
+ await controlPlaneJson({
247
+ authToken: input.authToken,
248
+ url: `${input.apiUrl}/runs/${input.runId}/complete`,
249
+ method: "POST",
250
+ body: {
251
+ status: input.status,
252
+ metadata,
253
+ terminal_error_code: input.terminalErrorCode ?? null,
254
+ terminal_error_message: input.terminalErrorMessage ?? null,
255
+ },
256
+ responseSchema: CompleteConversationRunResponseSchema,
257
+ operation: "Complete canonical durable run",
258
+ });
259
+ }
@@ -180,6 +180,29 @@ export {
180
180
  createAgUiBrowserResponseStream,
181
181
  type CreateAgUiBrowserResponseStreamInput,
182
182
  } from "./ag-ui-browser-response-stream.js";
183
+ export {
184
+ bootstrapConversationAgentRun,
185
+ type BootstrapConversationAgentRunResult,
186
+ type ConversationMessageRecord,
187
+ ConversationMessageRecordSchema,
188
+ type ConversationRecord,
189
+ ConversationRecordSchema,
190
+ createConversationMessage,
191
+ createConversationRecord,
192
+ ensureConversationProjectLink,
193
+ fetchConversationRecord,
194
+ } from "./conversation-bootstrap.js";
195
+ export {
196
+ CompleteConversationRunResponseSchema,
197
+ type ConversationAgentRunUsage,
198
+ type ConversationRunProjection,
199
+ ConversationRunProjectionSchema,
200
+ type ConversationRunTargets,
201
+ ConversationRunTargetsSchema,
202
+ createConversationAgentRun,
203
+ finalizeConversationAgentRun,
204
+ resolveConversationRunTargets,
205
+ } from "./durable.js";
183
206
  export {
184
207
  type HostedChildLifecycleAdapter,
185
208
  type HostedChildLifecycleRunnerOptions,
@@ -8,6 +8,13 @@ import { z } from "zod";
8
8
 
9
9
  const SIGNATURE_SKEW_SECONDS = 5;
10
10
 
11
+ export const CONTROL_PLANE_AGENTS_LIST_PATH = "/api/control-plane/agents/list";
12
+ export const CONTROL_PLANE_AGENT_STREAM_PATH = "/api/control-plane/agents/stream";
13
+ export const CONTROL_PLANE_AGENT_RUNS_PATH_PREFIX = "/api/control-plane/agents/runs/";
14
+ export const LEGACY_INTERNAL_AGENTS_LIST_PATH = "/internal/agents/list";
15
+ export const LEGACY_INTERNAL_AGENT_STREAM_PATH = "/internal/agents/stream";
16
+ export const LEGACY_INTERNAL_AGENT_RUNS_PATH_PREFIX = "/internal/agents/runs/";
17
+
11
18
  const compactJwsHeaderSchema = z.object({
12
19
  alg: z.literal("EdDSA"),
13
20
  typ: z.string().optional(),
@@ -70,6 +70,7 @@ const INTERNAL_CONTROL_PLANE_SIGNATURE_HEADERS = [
70
70
 
71
71
  function isInternalControlPlanePath(pathname: string): boolean {
72
72
  return pathname === "/channels/invoke" ||
73
+ pathname.startsWith("/api/control-plane/agents/") ||
73
74
  pathname.startsWith("/internal/agents/") ||
74
75
  pathname.startsWith("/internal/tasks/") ||
75
76
  pathname.startsWith("/internal/workflows/");
@@ -1,3 +1,7 @@
1
+ import {
2
+ CONTROL_PLANE_AGENT_RUNS_PATH_PREFIX,
3
+ LEGACY_INTERNAL_AGENT_RUNS_PATH_PREFIX,
4
+ } from "../../../channels/control-plane.js";
1
5
  import {
2
6
  ControlPlaneRequestError,
3
7
  verifyControlPlaneRequest,
@@ -15,7 +19,7 @@ import { BaseHandler } from "../response/base.js";
15
19
  import type { HandlerContext, HandlerMetadata, HandlerPriority, HandlerResult } from "../types.js";
16
20
  import { PRIORITY_MEDIUM_API } from "../../../utils/constants/index.js";
17
21
 
18
- const CANCEL_PATH_REGEX = /^\/internal\/agents\/runs\/([^/]+)$/;
22
+ const CANCEL_PATH_REGEX = /^\/(?:api\/control-plane\/agents|internal\/agents)\/runs\/([^/]+)$/;
19
23
 
20
24
  function getRunId(pathname: string): string | null {
21
25
  return CANCEL_PATH_REGEX.exec(pathname)?.[1] ?? null;
@@ -25,7 +29,10 @@ export class AgentRunCancelHandler extends BaseHandler {
25
29
  metadata: HandlerMetadata = {
26
30
  name: "AgentRunCancelHandler",
27
31
  priority: PRIORITY_MEDIUM_API as HandlerPriority,
28
- patterns: [{ pattern: "/internal/agents/runs/", prefix: true, method: "DELETE" }],
32
+ patterns: [
33
+ { pattern: CONTROL_PLANE_AGENT_RUNS_PATH_PREFIX, prefix: true, method: "DELETE" },
34
+ { pattern: LEGACY_INTERNAL_AGENT_RUNS_PATH_PREFIX, prefix: true, method: "DELETE" },
35
+ ],
29
36
  };
30
37
 
31
38
  constructor(private readonly sessionManager: AgentRunSessionManager = agentRunSessionManager) {
@@ -1,3 +1,7 @@
1
+ import {
2
+ CONTROL_PLANE_AGENT_RUNS_PATH_PREFIX,
3
+ LEGACY_INTERNAL_AGENT_RUNS_PATH_PREFIX,
4
+ } from "../../../channels/control-plane.js";
1
5
  import {
2
6
  ControlPlaneRequestError,
3
7
  verifyControlPlaneRequest,
@@ -19,7 +23,8 @@ import { BaseHandler } from "../response/base.js";
19
23
  import type { HandlerContext, HandlerMetadata, HandlerPriority, HandlerResult } from "../types.js";
20
24
  import { PRIORITY_MEDIUM_API } from "../../../utils/constants/index.js";
21
25
 
22
- const RESUME_PATH_REGEX = /^\/internal\/agents\/runs\/([^/]+)\/resume$/;
26
+ const RESUME_PATH_REGEX =
27
+ /^\/(?:api\/control-plane\/agents|internal\/agents)\/runs\/([^/]+)\/resume$/;
23
28
 
24
29
  function getRunId(pathname: string): string | null {
25
30
  return RESUME_PATH_REGEX.exec(pathname)?.[1] ?? null;
@@ -29,7 +34,10 @@ export class AgentRunResumeHandler extends BaseHandler {
29
34
  metadata: HandlerMetadata = {
30
35
  name: "AgentRunResumeHandler",
31
36
  priority: PRIORITY_MEDIUM_API as HandlerPriority,
32
- patterns: [{ pattern: "/internal/agents/runs/", prefix: true, method: "POST" }],
37
+ patterns: [
38
+ { pattern: CONTROL_PLANE_AGENT_RUNS_PATH_PREFIX, prefix: true, method: "POST" },
39
+ { pattern: LEGACY_INTERNAL_AGENT_RUNS_PATH_PREFIX, prefix: true, method: "POST" },
40
+ ],
33
41
  };
34
42
 
35
43
  constructor(private readonly sessionManager: AgentRunSessionManager = agentRunSessionManager) {
@@ -1,6 +1,10 @@
1
1
  import type { Agent } from "../../../agent/index.js";
2
2
  import { defaultChannelInvokeDeps } from "../../../channels/invoke.js";
3
- import { type RuntimeAgentDiscoveryDeps } from "../../../channels/control-plane.js";
3
+ import {
4
+ CONTROL_PLANE_AGENT_STREAM_PATH,
5
+ LEGACY_INTERNAL_AGENT_STREAM_PATH,
6
+ type RuntimeAgentDiscoveryDeps,
7
+ } from "../../../channels/control-plane.js";
4
8
  import {
5
9
  createRuntimeAgentStreamResponse,
6
10
  type RuntimeAgentStreamExecutionDeps,
@@ -116,7 +120,10 @@ export class AgentStreamHandler extends BaseHandler {
116
120
  metadata: HandlerMetadata = {
117
121
  name: "AgentStreamHandler",
118
122
  priority: PRIORITY_MEDIUM_API as HandlerPriority,
119
- patterns: [{ pattern: "/internal/agents/stream", exact: true, method: "POST" }],
123
+ patterns: [
124
+ { pattern: CONTROL_PLANE_AGENT_STREAM_PATH, exact: true, method: "POST" },
125
+ { pattern: LEGACY_INTERNAL_AGENT_STREAM_PATH, exact: true, method: "POST" },
126
+ ],
120
127
  };
121
128
 
122
129
  constructor(private readonly deps: AgentStreamHandlerDeps = defaultDeps) {
@@ -1,8 +1,10 @@
1
1
  import { BaseHandler } from "../response/base.js";
2
2
  import type { HandlerContext, HandlerMetadata, HandlerPriority, HandlerResult } from "../types.js";
3
3
  import {
4
+ CONTROL_PLANE_AGENTS_LIST_PATH,
4
5
  type ControlPlaneAgentsListRequest,
5
6
  ControlPlaneAgentsListRequestSchema,
7
+ LEGACY_INTERNAL_AGENTS_LIST_PATH,
6
8
  listRuntimeAgents,
7
9
  type RuntimeAgentDiscoveryDeps,
8
10
  } from "../../../channels/control-plane.js";
@@ -23,7 +25,10 @@ export class InternalAgentsListHandler extends BaseHandler {
23
25
  metadata: HandlerMetadata = {
24
26
  name: "InternalAgentsListHandler",
25
27
  priority: PRIORITY_MEDIUM_API as HandlerPriority,
26
- patterns: [{ pattern: "/internal/agents/list", exact: true, method: "POST" }],
28
+ patterns: [
29
+ { pattern: CONTROL_PLANE_AGENTS_LIST_PATH, exact: true, method: "POST" },
30
+ { pattern: LEGACY_INTERNAL_AGENTS_LIST_PATH, exact: true, method: "POST" },
31
+ ],
27
32
  };
28
33
 
29
34
  constructor(private readonly deps: RuntimeAgentDiscoveryDeps = defaultChannelInvokeDeps) {
@@ -64,7 +64,8 @@ export function resolveEnvironment(
64
64
 
65
65
  // Some internal framework surfaces are routed directly to a runtime owner pod and
66
66
  // rely on signed control-plane auth instead of a user-facing release address.
67
- const isInternalAgentControlPlanePath = opts.pathname.startsWith("/internal/agents/");
67
+ const isInternalAgentControlPlanePath = opts.pathname.startsWith("/internal/agents/") ||
68
+ opts.pathname.startsWith("/api/control-plane/agents/");
68
69
 
69
70
  // Skip releaseId validation for development assets and signed internal control-plane
70
71
  // requests because they do not require a user-facing release context.
@@ -84,5 +84,6 @@ export function isWebSocketPath(pathname: string): boolean {
84
84
  * render cache prefix/content-source derivation and the enriched render payload.
85
85
  */
86
86
  export function shouldSkipEnrichedContext(pathname: string): boolean {
87
- return pathname.startsWith("/api/") || pathname.startsWith("/internal/agents/");
87
+ return pathname.startsWith("/api/") || pathname.startsWith("/internal/agents/") ||
88
+ pathname.startsWith("/api/control-plane/agents/");
88
89
  }
@@ -24,15 +24,18 @@ export {
24
24
  } from "./runtime-guards.js";
25
25
 
26
26
  export {
27
+ __registerTraceContextGetter,
28
+ __registerTraceContextGetter as registerTraceContextGetter,
27
29
  agentLogger,
28
30
  bundlerLogger,
29
31
  createJobUserLogger,
30
32
  logger,
31
33
  refreshLoggerConfig,
32
34
  rendererLogger,
35
+ runWithRequestContextAsync,
33
36
  serverLogger,
34
37
  } from "./logger/index.js";
35
- export type { Logger } from "./logger/index.js";
38
+ export type { Logger, RequestContext } from "./logger/index.js";
36
39
 
37
40
  export {
38
41
  BREAKPOINT_LG,
@@ -66,6 +66,12 @@ export interface LogEntry {
66
66
  task?: string;
67
67
  event_kind?: string;
68
68
  user_visible?: string;
69
+ user_id?: string;
70
+ conversation_id?: string;
71
+ /** @deprecated Use `user_id` instead. Kept for Grafana dashboard transition. */
72
+ userId?: string;
73
+ /** @deprecated Use `conversation_id` instead. Kept for Grafana dashboard transition. */
74
+ conversationId?: string;
69
75
  // Duration for timed operations
70
76
  /** @deprecated Use `duration_ms` instead. Kept for Grafana dashboard transition. Planned removal after Grafana dashboard migration is complete. */
71
77
  durationMs?: number;
@@ -327,6 +333,12 @@ class ConsoleLogger implements Logger {
327
333
  extractToEntryField(entry, mergedContext, "event_kind", (v) => String(v));
328
334
  extractToEntryField(entry, mergedContext, "user_visible", (v) => String(v));
329
335
  extractToEntryField(entry, mergedContext, "duration_ms", (v) => Number(v));
336
+ extractToEntryField(entry, mergedContext, "user_id", (v) => String(v));
337
+ extractToEntryField(entry, mergedContext, "conversation_id", (v) => String(v));
338
+
339
+ // Also extract camelCase variants so callers can use either convention
340
+ extractToEntryField(entry, mergedContext, "userId", (v) => String(v));
341
+ extractToEntryField(entry, mergedContext, "conversationId", (v) => String(v));
330
342
 
331
343
  // Emit snake_case aliases for camelCase fields (transition period)
332
344
  if (entry.requestId && !entry.request_id) entry.request_id = entry.requestId;
@@ -334,6 +346,10 @@ class ConsoleLogger implements Logger {
334
346
  if (entry.spanId && !entry.span_id) entry.span_id = entry.spanId;
335
347
  if (entry.projectSlug && !entry.project_slug) entry.project_slug = entry.projectSlug;
336
348
  if (entry.durationMs != null && entry.duration_ms == null) entry.duration_ms = entry.durationMs;
349
+ if (entry.userId && !entry.user_id) entry.user_id = entry.userId;
350
+ if (entry.conversationId && !entry.conversation_id) {
351
+ entry.conversation_id = entry.conversationId;
352
+ }
337
353
 
338
354
  if (Object.keys(mergedContext).length > 0) entry.context = mergedContext;
339
355
  if (error) entry.error = error;
@@ -16,6 +16,8 @@ export interface RequestContext {
16
16
  projectSlug?: string;
17
17
  projectId?: string;
18
18
  domain?: string;
19
+ userId?: string;
20
+ conversationId?: string;
19
21
  }
20
22
 
21
23
  export const requestContextStore = new AsyncLocalStorage<RequestContext>();
@@ -1,3 +1,3 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.231";
3
+ export const VERSION = "0.1.233";