History

Add spans over execution stack assembly

Name the shared executor, plugin, engine, and MCP server assembly steps so the post-auth execution gap is visible in traces.

Rhys Sullivan committed 4 months ago

Commit 2c1687a1 parent c926a3f5 files · +35 −16Browse files

Unified · Split

5 files
  1. apps/cloud/src/mcp/session-durable-object.ts +3 −1
  2. packages/core/api/src/server/execution-stack-middleware.ts +5 −2
  3. packages/core/api/src/server/execution-stack.ts +14 −8
  4. packages/core/api/src/server/mcp-build.ts +2 −0
  5. packages/core/api/src/server/scoped-executor.ts +11 −5
apps/cloud/src/mcp/session-durable-object.ts+3−1
@@ -271,7 +271,9 @@ export class McpSessionDOSqlite extends McpAgentSessionDOBase<Env, CloudSessionD · 270 unmodified lines
271 // Build the description here so `executor.connections.list()` stays under271 // Build the description here so `executor.connections.list()` stays under
272 // the DO startup span and the MCP SDK receives a concrete string instead272 // the DO startup span and the MCP SDK receives a concrete string instead
273 // of invoking `engine.getDescription` across its async boundary.273 // of invoking `engine.getDescription` across its async boundary.
274 const description = yield* buildExecuteDescription(executor);274 const description = yield* buildExecuteDescription(executor).pipe(
275 Effect.withSpan("mcp.execute.description.build"),
276 );
275 const sessionElicitationMode = sessionMeta.elicitationMode ?? "model";277 const sessionElicitationMode = sessionMeta.elicitationMode ?? "model";
276 const mcpServer = yield* createExecutorMcpServer({278 const mcpServer = yield* createExecutorMcpServer({
277 engine,279 engine,
packages/core/api/src/server/execution-stack-middleware.ts+5−2
@@ -188,8 +188,11 @@ export const makeExecutionStackMiddleware = < · 187 unmodified lines
188 // provider carried one. Absent slug -> the service stays unprovided and188 // provider carried one. Absent slug -> the service stays unprovided and
189 // the URL falls back to its bare, client-canonicalized form.189 // the URL falls back to its bare, client-canonicalized form.
190 const { executor, engine } = yield* resolved.organizationSlug !== undefined190 const { executor, engine } = yield* resolved.organizationSlug !== undefined
191 ? stack.pipe(Effect.provideService(RequestOrgSlug, { slug: resolved.organizationSlug }))191 ? stack.pipe(
192 : stack;192 Effect.provideService(RequestOrgSlug, { slug: resolved.organizationSlug }),
193 Effect.withSpan("executor.stack.http.resolve"),
194 )
195 : stack.pipe(Effect.withSpan("executor.stack.http.resolve"));
193 return yield* httpEffect.pipe(196 return yield* httpEffect.pipe(
194 Effect.provideService(AuthContext, auth),197 Effect.provideService(AuthContext, auth),
195 Effect.provideService(ExecutorService, executor),198 Effect.provideService(ExecutorService, executor),
packages/core/api/src/server/execution-stack.ts+14−8
@@ -108,13 +108,19 @@ export const makeExecutionStack = < · 107 unmodified lines
108 organizationId,108 organizationId,
109 organizationName,109 organizationName,
110 { plugins: { mcpResource: options?.mcpResource } },110 { plugins: { mcpResource: options?.mcpResource } },
111 ).pipe(Effect.withSpan("executor.stack.scoped_executor"));
112 const codeExecutor = yield* CodeExecutorProvider.asEffect().pipe(
113 Effect.withSpan("executor.stack.code_executor"),
111 );114 );
112 const codeExecutor = yield* CodeExecutorProvider;115 const { decorate } = yield* EngineDecorator.asEffect().pipe(
113 const { decorate } = yield* EngineDecorator;116 Effect.withSpan("executor.stack.decorator"),
114 const engine = decorate(createExecutionEngine({ executor, codeExecutor }), {117 );
115 accountId,118 const engine = yield* Effect.sync(() =>
116 organizationId,119 decorate(createExecutionEngine({ executor, codeExecutor }), {
117 organizationName,120 accountId,
118 });121 organizationId,
122 organizationName,
123 }),
124 ).pipe(Effect.withSpan("executor.stack.engine.init"));
119 return { executor, engine };125 return { executor, engine };
120 });126 }).pipe(Effect.withSpan("executor.stack.build"));
packages/core/api/src/server/mcp-build.ts+2−0
@@ -42,6 +42,7 @@ export const makeMcpBuildServer = · 41 unmodified lines
42 makeExecutionStack(principal.accountId, principal.organizationId, principal.organizationName, {42 makeExecutionStack(principal.accountId, principal.organizationId, principal.organizationName, {
43 mcpResource: options?.resource,43 mcpResource: options?.resource,
44 }).pipe(44 }).pipe(
45 Effect.withSpan("mcp.execution_stack.build"),
45 Effect.map(({ engine }) => engine),46 Effect.map(({ engine }) => engine),
46 // Pin browser-handoff URLs to the principal's org slug when present;47 // Pin browser-handoff URLs to the principal's org slug when present;
47 // absent slug leaves the service unprovided and the URL stays bare.48 // absent slug leaves the service unprovided and the URL stays bare.
@@ -52,6 +53,7 @@ export const makeMcpBuildServer = · 4 unmodified lines
52 Effect.mapError((cause) => new McpEngineBuildError({ cause })),53 Effect.mapError((cause) => new McpEngineBuildError({ cause })),
53 Effect.flatMap((engine) =>54 Effect.flatMap((engine) =>
54 createExecutorMcpServer({ engine, ...(options ?? {}) }).pipe(55 createExecutorMcpServer({ engine, ...(options ?? {}) }).pipe(
56 Effect.withSpan("mcp.server.create"),
55 Effect.map((mcpServer) => ({ mcpServer, engine })),57 Effect.map((mcpServer) => ({ mcpServer, engine })),
56 ),58 ),
57 ),59 ),
packages/core/api/src/server/scoped-executor.ts+11−5
@@ -210,9 +210,13 @@ export const makeScopedExecutor = < · 209 unmodified lines
210 options?: { readonly plugins?: PluginsProviderContext },210 options?: { readonly plugins?: PluginsProviderContext },
211): Effect.Effect<Executor<TPlugins>, StorageFailure, DbProvider | PluginsProvider | HostConfig> =>211): Effect.Effect<Executor<TPlugins>, StorageFailure, DbProvider | PluginsProvider | HostConfig> =>
212 Effect.gen(function* () {212 Effect.gen(function* () {
213 const { db, blobs } = yield* DbProvider;213 const { db, blobs } = yield* DbProvider.asEffect().pipe(
214 const { plugins: pluginsFactory } = yield* PluginsProvider;214 Effect.withSpan("executor.stack.db_provider"),
215 const config = yield* HostConfig;215 );
216 const { plugins: pluginsFactory } = yield* PluginsProvider.asEffect().pipe(
217 Effect.withSpan("executor.stack.plugins_provider"),
218 );
219 const config = yield* HostConfig.asEffect().pipe(Effect.withSpan("executor.stack.host_config"));
216 // Explicit config wins; otherwise fall back to the request origin if a host220 // Explicit config wins; otherwise fall back to the request origin if a host
217 // provided one (HTTP middleware / MCP session DO). Stays `undefined` for221 // provided one (HTTP middleware / MCP session DO). Stays `undefined` for
218 // non-request callers — `coreTools.webBaseUrl` is optional and only the222 // non-request callers — `coreTools.webBaseUrl` is optional and only the
@@ -248,7 +252,9 @@ export const makeScopedExecutor = < · 29 unmodified lines
248 oauthCallbackPath: config.oauthCallbackPath,252 oauthCallbackPath: config.oauthCallbackPath,
249 });253 });
250 254
251 const plugins = pluginsFactory(options?.plugins);255 const plugins = yield* Effect.sync(() => pluginsFactory(options?.plugins)).pipe(
256 Effect.withSpan("executor.plugins.init"),
257 );
252 const hostedHttpOptions = {258 const hostedHttpOptions = {
253 allowLocalNetwork: config.allowLocalNetwork,259 allowLocalNetwork: config.allowLocalNetwork,
254 };260 };
@@ -274,7 +280,7 @@ export const makeScopedExecutor = < · 19 unmodified lines
274 orgSlug,280 orgSlug,
275 includeProviders: config.exposeCredentialProviders ?? true,281 includeProviders: config.exposeCredentialProviders ?? true,
276 },282 },
277 });283 }).pipe(Effect.withSpan("executor.stack.create_executor"));
278 // The seam erases the plugin tuple type; the caller re-narrows via the284 // The seam erases the plugin tuple type; the caller re-narrows via the
279 // `TPlugins` phantom. Runtime shape is identical to a typed285 // `TPlugins` phantom. Runtime shape is identical to a typed
280 // `createExecutor({ plugins })` call.286 // `createExecutor({ plugins })` call.