| @@ -436,6 +436,82 @@ export abstract class McpAgentSessionDOBase< · 435 unmodified lines |
| 436 | }); | 436 | }); |
| 437 | } | 437 | } |
| 438 | | 438 | |
| | 439 | private logExecutionOwnerDirectoryFailure(input: { |
| | 440 | readonly operation: "put" | "get" | "delete"; |
| | 441 | readonly executionId: string; |
| | 442 | readonly cause: Cause.Cause<unknown>; |
| | 443 | }): Effect.Effect<void> { |
| | 444 | const self = this; |
| | 445 | return Effect.gen(function* () { |
| | 446 | const first = Cause.prettyErrors(input.cause)[0]; |
| | 447 | console.error( |
| | 448 | JSON.stringify({ |
| | 449 | event: "mcp_execution_owner_directory_error", |
| | 450 | operation: input.operation, |
| | 451 | executionId: input.executionId, |
| | 452 | sessionId: self.sessionId, |
| | 453 | exceptionType: first?.name ?? "Error", |
| | 454 | exceptionMessage: first?.message ?? "unknown", |
| | 455 | cause: Cause.pretty(input.cause), |
| | 456 | }), |
| | 457 | ); |
| | 458 | yield* Effect.annotateCurrentSpan({ |
| | 459 | "mcp.execution_owner.directory.operation": input.operation, |
| | 460 | }); |
| | 461 | yield* self.recordCauseOnSpan(input.cause); |
| | 462 | }); |
| | 463 | } |
| | 464 | |
| | 465 | private logModelResumeForwardFailure(input: { |
| | 466 | readonly executionId: string; |
| | 467 | readonly owner: McpExecutionOwnerRoute; |
| | 468 | readonly cause: Cause.Cause<unknown>; |
| | 469 | }): Effect.Effect<void> { |
| | 470 | const self = this; |
| | 471 | return Effect.gen(function* () { |
| | 472 | const first = Cause.prettyErrors(input.cause)[0]; |
| | 473 | console.error( |
| | 474 | JSON.stringify({ |
| | 475 | event: "mcp_model_resume_forward_error", |
| | 476 | executionId: input.executionId, |
| | 477 | sessionId: self.sessionId, |
| | 478 | ownerSessionId: input.owner.sessionId, |
| | 479 | exceptionType: first?.name ?? "Error", |
| | 480 | exceptionMessage: first?.message ?? "unknown", |
| | 481 | cause: Cause.pretty(input.cause), |
| | 482 | }), |
| | 483 | ); |
| | 484 | yield* Effect.annotateCurrentSpan({ |
| | 485 | "mcp.execution_owner.forward.owner_session_id": input.owner.sessionId, |
| | 486 | }); |
| | 487 | yield* self.recordCauseOnSpan(input.cause); |
| | 488 | }); |
| | 489 | } |
| | 490 | |
| | 491 | private logModelResumeForwardTimeout(input: { |
| | 492 | readonly executionId: string; |
| | 493 | readonly owner: McpExecutionOwnerRoute; |
| | 494 | readonly timeoutMs: number; |
| | 495 | }): Effect.Effect<void> { |
| | 496 | const self = this; |
| | 497 | return Effect.gen(function* () { |
| | 498 | console.error( |
| | 499 | JSON.stringify({ |
| | 500 | event: "mcp_model_resume_forward_error", |
| | 501 | reason: "timeout", |
| | 502 | executionId: input.executionId, |
| | 503 | sessionId: self.sessionId, |
| | 504 | ownerSessionId: input.owner.sessionId, |
| | 505 | timeoutMs: input.timeoutMs, |
| | 506 | }), |
| | 507 | ); |
| | 508 | yield* Effect.annotateCurrentSpan({ |
| | 509 | "mcp.execution_owner.forward.owner_session_id": input.owner.sessionId, |
| | 510 | "mcp.execution_owner.forward.error": "timeout", |
| | 511 | }); |
| | 512 | }); |
| | 513 | } |
| | 514 | |
| 439 | private withSpanFlush<A, E>(effect: Effect.Effect<A, E>): Effect.Effect<A, E> { | 515 | private withSpanFlush<A, E>(effect: Effect.Effect<A, E>): Effect.Effect<A, E> { |
| 440 | const self = this; | 516 | const self = this; |
| 441 | return effect.pipe(Effect.ensuring(Effect.promise(() => self.flushTelemetry()))); | 517 | return effect.pipe(Effect.ensuring(Effect.promise(() => self.flushTelemetry()))); |
| @@ -813,6 +889,9 @@ export abstract class McpAgentSessionDOBase< · 371 unmodified lines |
| 813 | Effect.map((record) => | 889 | Effect.map((record) => |
| 814 | record ? { expiresAt: record.expiresAt, ttlMs: record.ttlMs } : undefined, | 890 | record ? { expiresAt: record.expiresAt, ttlMs: record.ttlMs } : undefined, |
| 815 | ), | 891 | ), |
| | 892 | Effect.tapCause((cause) => |
| | 893 | this.logExecutionOwnerDirectoryFailure({ operation: "get", executionId, cause }), |
| | 894 | ), |
| 816 | Effect.catchCause(() => noDeadline), | 895 | Effect.catchCause(() => noDeadline), |
| 817 | ); | 896 | ); |
| 818 | } | 897 | } |
| @@ -835,13 +914,26 @@ export abstract class McpAgentSessionDOBase< · 16 unmodified lines |
| 835 | expiresAt: deadline.expiresAt, | 914 | expiresAt: deadline.expiresAt, |
| 836 | ttlMs: deadline.ttlMs, | 915 | ttlMs: deadline.ttlMs, |
| 837 | }; | 916 | }; |
| 838 | yield* directory.put(record); | 917 | yield* directory |
| | 918 | .put(record) |
| | 919 | .pipe( |
| | 920 | Effect.tapCause((cause) => |
| | 921 | self.logExecutionOwnerDirectoryFailure({ operation: "put", executionId, cause }), |
| | 922 | ), |
| | 923 | ); |
| 839 | }).pipe(Effect.ignore); | 924 | }).pipe(Effect.ignore); |
| 840 | } | 925 | } |
| 841 | | 926 | |
| 842 | private deleteExecutionOwnerEntry(executionId: string): Effect.Effect<void> { | 927 | private deleteExecutionOwnerEntry(executionId: string): Effect.Effect<void> { |
| 843 | const directory = this.executionOwnerDirectory(); | 928 | const directory = this.executionOwnerDirectory(); |
| 844 | return directory?.delete(executionId).pipe(Effect.ignore) ?? Effect.void; | 929 | return ( |
| | 930 | directory?.delete(executionId).pipe( |
| | 931 | Effect.tapCause((cause) => |
| | 932 | this.logExecutionOwnerDirectoryFailure({ operation: "delete", executionId, cause }), |
| | 933 | ), |
| | 934 | Effect.ignore, |
| | 935 | ) ?? Effect.void |
| | 936 | ); |
| 845 | } | 937 | } |
| 846 | | 938 | |
| 847 | private resumeEngineWithLifecycle( | 939 | private resumeEngineWithLifecycle( |
| @@ -864,9 +956,12 @@ export abstract class McpAgentSessionDOBase< · 16 unmodified lines |
| 864 | if (!directory) return Effect.succeed(null); | 956 | if (!directory) return Effect.succeed(null); |
| 865 | const self = this; | 957 | const self = this; |
| 866 | return Effect.gen(function* () { | 958 | return Effect.gen(function* () { |
| 867 | const record = yield* directory | 959 | const record = yield* directory.get(executionId).pipe( |
| 868 | .get(executionId) | 960 | Effect.tapCause((cause) => |
| 869 | .pipe(Effect.catchCause(() => Effect.succeed(null))); | 961 | self.logExecutionOwnerDirectoryFailure({ operation: "get", executionId, cause }), |
| | 962 | ), |
| | 963 | Effect.catchCause(() => Effect.succeed(null)), |
| | 964 | ); |
| 870 | if (!record) return null; | 965 | if (!record) return null; |
| 871 | | 966 | |
| 872 | const sessionMeta = yield* self.loadSessionMeta(); | 967 | const sessionMeta = yield* self.loadSessionMeta(); |
| @@ -893,10 +988,24 @@ export abstract class McpAgentSessionDOBase< · 20 unmodified lines |
| 893 | Effect.timeoutOrElse({ | 988 | Effect.timeoutOrElse({ |
| 894 | duration: `${MODEL_RESUME_FORWARD_TIMEOUT_MS} millis`, | 989 | duration: `${MODEL_RESUME_FORWARD_TIMEOUT_MS} millis`, |
| 895 | orElse: () => | 990 | orElse: () => |
| 896 | Effect.succeed({ status: "execution_expired" as const, ttlMs: record.ttlMs }), | 991 | Effect.gen(function* () { |
| | 992 | yield* self.logModelResumeForwardTimeout({ |
| | 993 | executionId, |
| | 994 | owner: record.owner, |
| | 995 | timeoutMs: MODEL_RESUME_FORWARD_TIMEOUT_MS, |
| | 996 | }); |
| | 997 | return { status: "execution_expired" as const, ttlMs: record.ttlMs }; |
| | 998 | }), |
| 897 | }), | 999 | }), |
| 898 | Effect.catchCause(() => | 1000 | Effect.catchCause((cause) => |
| 899 | Effect.succeed({ status: "execution_expired" as const, ttlMs: record.ttlMs }), | 1001 | Effect.gen(function* () { |
| | 1002 | yield* self.logModelResumeForwardFailure({ |
| | 1003 | executionId, |
| | 1004 | owner: record.owner, |
| | 1005 | cause, |
| | 1006 | }); |
| | 1007 | return { status: "execution_expired" as const, ttlMs: record.ttlMs }; |
| | 1008 | }), |
| 900 | ), | 1009 | ), |
| 901 | ); | 1010 | ); |
| 902 | if ( | 1011 | if ( |
| @@ -994,10 +1103,7 @@ export abstract class McpAgentSessionDOBase< · 91 unmodified lines |
| 994 | const self = this; | 1103 | const self = this; |
| 995 | return Effect.gen(function* () { | 1104 | return Effect.gen(function* () { |
| 996 | const lease = self.pendingApprovalLeases.get(executionId); | 1105 | const lease = self.pendingApprovalLeases.get(executionId); |
| 997 | if (!lease) { | 1106 | if (!lease) return; |
| 998 | yield* self.deleteExecutionOwnerEntry(executionId); | | |
| 999 | return; | | |
| 1000 | } | | |
| 1001 | if (lease.timeout) clearTimeout(lease.timeout); | 1107 | if (lease.timeout) clearTimeout(lease.timeout); |
| 1002 | self.pendingApprovalLeases.delete(executionId); | 1108 | self.pendingApprovalLeases.delete(executionId); |
| 1003 | lease.disposeKeepAlive(); | 1109 | lease.disposeKeepAlive(); |