Skip to content

feat(examples): add a self-modifying harness - #2207

Open
mattzcarey wants to merge 7 commits into
cloudflare:mainfrom
mattzcarey:feat/self-modifying-harness
Open

feat(examples): add a self-modifying harness#2207
mattzcarey wants to merge 7 commits into
cloudflare:mainfrom
mattzcarey:feat/self-modifying-harness

Conversation

@mattzcarey

@mattzcarey mattzcarey commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds an example-only SelfModifyingHarness under examples/next/harnesses/self-modifying. No package export, no changeset.

The example composes a plain DurableObject with Lifecycle, Tasks, Streams, WebSockets, a durable Shell Workspace, Worker Bundler, and Worker Loader. The editable TypeScript harness is versioned in the Workspace and loaded into a fresh Dynamic Worker for every chat turn.

How it works

  • SelfModifyingHarness accepts an AI SDK LanguageModelV4; the example passes the workers-ai-provider@4 model directly.
  • System tools are fixed trusted capabilities for source access, activation, restore, and journaling. They execute in the Durable Object over a turn-scoped RPC target.
  • Custom tools are editable CustomTool exports under /harness/src/tools/ and execute inside the Dynamic Worker. Activation discovers them; a Custom tool cannot shadow a System tool.
  • Activation snapshots the Workspace source, bundles it, checks it in an isolated Worker, and atomically advances the active revision.
  • Turns run as one Tasks step, pin their revision, journal model and tool effects by stable key, and publish events through Streams.
  • The UI is served over the WebSockets capability. The client connects with useAgent from agents/react; a useHarnessSession hook replays-then-tails each turn's Streams log. The Kumo chat shows tool calls per turn, and an inspector shows the active revision's code, the revision history with a restore action, and the journal.

Review

Start with the README, then src/self-modifying-harness.ts, src/harness-runtime.ts, and src/transport.ts.

Worker Loader access is required to run or deploy this example. The example's Workers-runtime tests drive a deterministic LanguageModelV4 through the real Durable Object over RPC.

@changeset-bot

changeset-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 8930378

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@agent-think

agent-think Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

⚪ agents import sizes

Measured 287 runtime imports as minified bundles. The primary size is gzip; raw minified size is included for diagnosis. An existing import growing by more than 10% is marked red. This report is informational.

Red Yellow Green Unchanged New Removed
0 0 0 287 0 0

Compared 6da4c44b with 27004a09. Open workflow run.

No import sizes changed.

All 287 current runtime imports
Status Import Gzip Raw minified
agents#__DO_NOT_USE_WILL_BREAK__agentContext 258.6 KiB 1130.0 KiB
agents#__DO_NOT_USE_WILL_BREAK__withInvocationScope 258.6 KiB 1130.0 KiB
agents#Agent 258.6 KiB 1130.0 KiB
agents#AGENT_TOOL_MILESTONE_PART 258.6 KiB 1130.0 KiB
agents#AGENT_TOOL_PROGRESS_PART 258.6 KiB 1130.0 KiB
agents#buildAgentPath 259.1 KiB 1132.3 KiB
agents#buildAgentUrl 259.3 KiB 1132.7 KiB
agents#callable 258.6 KiB 1130.1 KiB
agents#camelCaseToKebabCase 258.6 KiB 1130.0 KiB
agents#createHeaderBasedEmailResolver 258.8 KiB 1130.4 KiB
agents#DEFAULT_AGENT_STATIC_OPTIONS 258.6 KiB 1130.0 KiB
agents#DurableObjectOAuthClientProvider 258.6 KiB 1130.0 KiB
agents#getAgentByName 258.6 KiB 1130.0 KiB
agents#getCurrentAgent 258.6 KiB 1130.0 KiB
agents#getSubAgentByName 258.9 KiB 1130.7 KiB
agents#isDurableObjectCodeUpdateReset 258.6 KiB 1130.0 KiB
agents#isDurableObjectMemoryLimitReset 258.6 KiB 1130.0 KiB
agents#isDurableObjectStorageReset 258.6 KiB 1130.1 KiB
agents#isPlatformTransientError 258.6 KiB 1130.0 KiB
agents#MCP_SERVER_ID_MAX_LENGTH 258.6 KiB 1130.0 KiB
agents#MessageType 258.8 KiB 1130.3 KiB
agents#normalizeServerId 258.6 KiB 1130.0 KiB
agents#parseSubAgentPath 258.6 KiB 1130.0 KiB
agents#routeAgentEmail 258.9 KiB 1130.7 KiB
agents#routeAgentRequest 259.2 KiB 1131.9 KiB
agents#routeSubAgentRequest 258.8 KiB 1130.6 KiB
agents#SqlError 258.6 KiB 1130.0 KiB
agents#StreamingResponse 258.6 KiB 1130.0 KiB
agents#SUB_PREFIX 258.6 KiB 1130.0 KiB
agents#unstable_callable 258.7 KiB 1130.2 KiB
agents/agent-tools#agentTool 112.5 KiB 538.2 KiB
agents/browser#BrowserConnector 50.5 KiB 176.6 KiB
agents/browser#browserContent 36.3 KiB 127.4 KiB
agents/browser#browserExtract 36.3 KiB 127.4 KiB
agents/browser#browserLinks 36.3 KiB 127.4 KiB
agents/browser#browserMarkdown 36.3 KiB 127.4 KiB
agents/browser#browserPdf 36.3 KiB 127.3 KiB
agents/browser#BrowserRenderingError 36.0 KiB 126.7 KiB
agents/browser#browserScrape 36.3 KiB 127.4 KiB
agents/browser#browserScreenshot 36.3 KiB 127.3 KiB
agents/browser#browserSnapshot 36.3 KiB 127.4 KiB
agents/browser#CdpSession 37.2 KiB 129.8 KiB
agents/browser#CodemodeRuntime 39.6 KiB 139.0 KiB
agents/browser#connectBrowser 37.8 KiB 131.4 KiB
agents/browser#connectBrowserSession 37.5 KiB 130.4 KiB
agents/browser#connectUrl 37.6 KiB 130.5 KiB
agents/browser#createBrowserSession 36.3 KiB 127.5 KiB
agents/browser#DEFAULT_EXEC_SWEEP_IDLE_MS 36.0 KiB 126.6 KiB
agents/browser#DEFAULT_SWEEP_IDLE_MS 36.0 KiB 126.6 KiB
agents/browser#deleteBrowserSession 36.1 KiB 126.9 KiB
agents/browser#DurableBrowserSessionStore 36.4 KiB 127.6 KiB
agents/browser#getBrowserRecording 36.2 KiB 127.1 KiB
agents/browser#listBrowserTargets 36.1 KiB 126.9 KiB
agents/browser#loadCdpSpec 36.6 KiB 128.3 KiB
agents/browser#runQuickAction 36.0 KiB 126.6 KiB
agents/browser/ai#createBrowserRuntime 146.0 KiB 630.3 KiB
agents/browser/ai#createBrowserTools 146.0 KiB 630.3 KiB
agents/browser/ai#createQuickActionTools 122.5 KiB 554.3 KiB
agents/browser/tanstack-ai#createBrowserTools 161.7 KiB 699.2 KiB
agents/chat#AbortRegistry 2.5 KiB 8.9 KiB
agents/chat#AGENT_TOOL_STREAM_PROGRESS_BUMP_THROTTLE_MS 2.3 KiB 8.2 KiB
agents/chat#AgentToolProgressEmitter 2.6 KiB 9.5 KiB
agents/chat#AgentToolStreamProgressThrottle 2.3 KiB 8.3 KiB
agents/chat#aiSdkRecoveryCodec 2.3 KiB 8.2 KiB
agents/chat#applyAgentToolEvent 3.2 KiB 10.9 KiB
agents/chat#applyChunkToParts 2.3 KiB 8.2 KiB
agents/chat#applyToolUpdate 2.4 KiB 8.4 KiB
agents/chat#AutoContinuationController 2.3 KiB 8.2 KiB
agents/chat#awaitWithDeadline 2.4 KiB 8.4 KiB
agents/chat#broadcastTransition 3.1 KiB 11.4 KiB
agents/chat#buildChatRecoveringFrame 2.4 KiB 8.3 KiB
agents/chat#buildInClauseStrings 2.4 KiB 8.4 KiB
agents/chat#bumpChatRecoveryProgress 2.3 KiB 8.3 KiB
agents/chat#byteLength 2.3 KiB 8.2 KiB
agents/chat#CHAT_LAST_TERMINAL_KEY 2.3 KiB 8.2 KiB
agents/chat#CHAT_MESSAGE_TYPES 2.3 KiB 8.2 KiB
agents/chat#CHAT_RECOVERING_FLAG_TTL_MS 2.3 KiB 8.2 KiB
agents/chat#CHAT_RECOVERING_KEY 2.3 KiB 8.2 KiB
agents/chat#CHAT_RECOVERY_ALARM_DEBOUNCE_MS 2.3 KiB 8.2 KiB
agents/chat#CHAT_RECOVERY_INCIDENT_KEY_PREFIX 2.3 KiB 8.2 KiB
agents/chat#CHAT_RECOVERY_INCIDENT_TTL_MS 2.3 KiB 8.2 KiB
agents/chat#CHAT_RECOVERY_PROGRESS_KEY 2.3 KiB 8.2 KiB
agents/chat#CHAT_RECOVERY_STABLE_RETRY_DELAY_SECONDS 2.3 KiB 8.2 KiB
agents/chat#CHAT_RECOVERY_TASK_NAME 2.3 KiB 8.2 KiB
agents/chat#CHAT_STREAM_PROGRESS_CREDIT_THROTTLE_MS 2.3 KiB 8.2 KiB
agents/chat#ChatRecoveryEngine 4.4 KiB 15.2 KiB
agents/chat#chatRecoveryTaskRunOptions 2.4 KiB 8.5 KiB
agents/chat#ChatStreamStalledError 2.3 KiB 8.3 KiB
agents/chat#classifyAgentToolChildRecovery 2.4 KiB 8.5 KiB
agents/chat#cleanupStreamBuffers 2.3 KiB 8.2 KiB
agents/chat#clearChatTerminal 2.3 KiB 8.2 KiB
agents/chat#clientResolvableToolNames 2.3 KiB 8.3 KiB
agents/chat#ContinuationState 2.6 KiB 9.8 KiB
agents/chat#createAgentToolEventState 2.3 KiB 8.2 KiB
agents/chat#createChatFiberSnapshot 2.4 KiB 8.6 KiB
agents/chat#createChatRecoveryTaskDefinition 2.6 KiB 9.0 KiB
agents/chat#createChatStreams 5.5 KiB 19.3 KiB
agents/chat#createChatTurnTaskDefinition 2.6 KiB 8.9 KiB
agents/chat#createToolsFromClientSchemas 114.3 KiB 545.4 KiB
agents/chat#crossMessageToolResultUpdate 2.4 KiB 8.6 KiB
agents/chat#DEFAULT_CHAT_RECOVERY_MAX_ATTEMPTS 2.3 KiB 8.2 KiB
agents/chat#DEFAULT_CHAT_RECOVERY_MAX_OOM_RETRIES 2.3 KiB 8.2 KiB
agents/chat#DEFAULT_CHAT_RECOVERY_MAX_WORK 2.3 KiB 8.2 KiB
agents/chat#DEFAULT_CHAT_RECOVERY_NO_PROGRESS_TIMEOUT_MS 2.3 KiB 8.2 KiB
agents/chat#DEFAULT_CHAT_RECOVERY_STABLE_TIMEOUT_MS 2.3 KiB 8.2 KiB
agents/chat#DEFAULT_CHAT_RECOVERY_TERMINAL_MESSAGE 2.3 KiB 8.3 KiB
agents/chat#dispatchChatRecoveryToHandoff 3.0 KiB 9.9 KiB
agents/chat#drainInteractionApplies 2.3 KiB 8.3 KiB
agents/chat#enforceRowSizeLimit 3.4 KiB 11.0 KiB
agents/chat#hasIncompleteToolBatch 2.4 KiB 8.6 KiB
agents/chat#interceptAgentToolBroadcast 2.5 KiB 8.6 KiB
agents/chat#isPlatformFailure 2.6 KiB 8.9 KiB
agents/chat#isReplayChunk 2.4 KiB 8.6 KiB
agents/chat#iterateWithStallWatchdog 2.6 KiB 8.8 KiB
agents/chat#KV_DELETE_MAX_KEYS 2.3 KiB 8.2 KiB
agents/chat#listActiveChatRecoveryIncidents 2.4 KiB 8.4 KiB
agents/chat#MAX_BOUND_PARAMS 2.3 KiB 8.2 KiB
agents/chat#MessageType 2.4 KiB 9.0 KiB
agents/chat#normalizeToolInput 2.3 KiB 8.2 KiB
agents/chat#parseProtocolMessage 2.5 KiB 9.0 KiB
agents/chat#partAwaitsClientInteraction 2.4 KiB 8.5 KiB
agents/chat#pausedExecutionUpdate 2.4 KiB 8.4 KiB
agents/chat#pendingChatTerminal 2.3 KiB 8.3 KiB
agents/chat#persistReconstructedOrphan 3.0 KiB 11.0 KiB
agents/chat#PreStreamTurns 2.6 KiB 9.2 KiB
agents/chat#readChatRecoveryProgress 2.3 KiB 8.3 KiB
agents/chat#reconcileMessages 2.8 KiB 9.5 KiB
agents/chat#reconcileOrphanPartial 2.4 KiB 8.4 KiB
agents/chat#recordChatTerminal 2.3 KiB 8.3 KiB
agents/chat#repairInterruptedToolParts 2.6 KiB 9.1 KiB
agents/chat#resolveChatRecoveryConfig 2.5 KiB 8.9 KiB
agents/chat#resolveToolMergeId 2.4 KiB 8.5 KiB
agents/chat#ResumableStream 4.6 KiB 15.3 KiB
agents/chat#ResumeHandshake 2.9 KiB 10.4 KiB
agents/chat#ROW_MAX_BYTES 2.3 KiB 8.2 KiB
agents/chat#runChatRecoveryExhaustion 2.5 KiB 8.9 KiB
agents/chat#sanitizeMessage 2.5 KiB 9.0 KiB
agents/chat#sendIfOpen 2.4 KiB 8.3 KiB
agents/chat#setChatRecovering 2.4 KiB 8.5 KiB
agents/chat#shouldCreditStreamProgress 2.3 KiB 8.3 KiB
agents/chat#STREAM_CLEANUP_DELAY_SECONDS 2.3 KiB 8.2 KiB
agents/chat#STREAM_RESUME_NONE_REASONS 2.3 KiB 8.2 KiB
agents/chat#StreamAccumulator 2.9 KiB 10.7 KiB
agents/chat#StreamProgressCreditThrottle 2.3 KiB 8.3 KiB
agents/chat#SubmitConcurrencyController 2.9 KiB 10.2 KiB
agents/chat#sweepStaleChatRecoveryIncidents 2.4 KiB 8.4 KiB
agents/chat#TextSegmentJoiner 2.7 KiB 9.2 KiB
agents/chat#TIMED_OUT 2.3 KiB 8.2 KiB
agents/chat#toolApprovalUpdate 2.4 KiB 8.5 KiB
agents/chat#toolPartHasSettledResult 2.3 KiB 8.3 KiB
agents/chat#toolResultUpdate 2.4 KiB 8.4 KiB
agents/chat#TurnQueue 2.6 KiB 9.2 KiB
agents/chat#unwrapChatFiberSnapshot 2.4 KiB 8.5 KiB
agents/chat#wrapChatFiberSnapshot 2.3 KiB 8.2 KiB
agents/chat-sdk#ChatSdkStateAdapter 261.0 KiB 1141.6 KiB
agents/chat-sdk#ChatSdkStateAgent 260.4 KiB 1139.1 KiB
agents/chat-sdk#createChatSdkState 261.0 KiB 1141.6 KiB
agents/chat-sdk#defaultKeyShard 258.8 KiB 1130.2 KiB
agents/chat-sdk#defaultThreadShard 258.7 KiB 1130.1 KiB
agents/chat/react#detectToolsRequiringConfirmation 3.3 KiB 8.3 KiB
agents/chat/react#extractClientToolSchemas 3.2 KiB 8.3 KiB
agents/chat/react#getAgentMessages 3.4 KiB 8.6 KiB
agents/chat/react#getToolApproval 3.1 KiB 8.0 KiB
agents/chat/react#getToolCallId 3.1 KiB 8.0 KiB
agents/chat/react#getToolInput 3.1 KiB 8.0 KiB
agents/chat/react#getToolOutput 3.1 KiB 8.0 KiB
agents/chat/react#getToolPartState 3.2 KiB 8.2 KiB
agents/chat/react#useAgentChat 132.9 KiB 609.7 KiB
agents/chat/react#WebSocketChatTransport 5.7 KiB 17.1 KiB
agents/chat/transport#WebSocketChatTransport 2.8 KiB 9.2 KiB
agents/client#AgentClient 5.7 KiB 16.6 KiB
agents/client#AgentConnectionError 582 B 993 B
agents/client#agentFetch 4.2 KiB 12.3 KiB
agents/client#createStubProxy 638 B 1.0 KiB
agents/client#DEFAULT_CALL_TIMEOUT_MS 473 B 770 B
agents/client#isTerminalCloseEvent 509 B 822 B
agents/email#createAddressBasedEmailResolver 193 B 227 B
agents/email#createCatchAllEmailResolver 110 B 97 B
agents/email#createHeaderBasedEmailResolver 334 B 492 B
agents/email#createSecureReplyEmailResolver 718 B 1.3 KiB
agents/email#DEFAULT_MAX_AGE_SECONDS 56 B 39 B
agents/email#isAutoReplyEmail 201 B 249 B
agents/email#signAgentHeaders 424 B 812 B
agents/experimental/memory/session#AgentContextProvider 425 B 810 B
agents/experimental/memory/session#AgentSearchProvider 821 B 2.0 KiB
agents/experimental/memory/session#AgentSessionProvider 2.5 KiB 8.8 KiB
agents/experimental/memory/session#isSearchProvider 128 B 134 B
agents/experimental/memory/session#isSkillProvider 127 B 130 B
agents/experimental/memory/session#isWritableProvider 126 B 128 B
agents/experimental/memory/session#PostgresContextProvider 422 B 671 B
agents/experimental/memory/session#PostgresSearchProvider 630 B 1.1 KiB
agents/experimental/memory/session#PostgresSessionProvider 1.7 KiB 5.3 KiB
agents/experimental/memory/session#R2SkillProvider 436 B 791 B
agents/experimental/memory/session#Session 93.4 KiB 454.0 KiB
agents/experimental/memory/session#SessionManager 94.5 KiB 460.1 KiB
agents/experimental/memory/utils#alignBoundaryBackward 291 B 584 B
agents/experimental/memory/utils#alignBoundaryForward 275 B 539 B
agents/experimental/memory/utils#buildSummaryPrompt 867 B 2.0 KiB
agents/experimental/memory/utils#CHARS_PER_TOKEN 51 B 31 B
agents/experimental/memory/utils#COMPACTION_PREFIX 63 B 43 B
agents/experimental/memory/utils#computeSummaryBudget 363 B 634 B
agents/experimental/memory/utils#createCompactFunction 1.8 KiB 4.2 KiB
agents/experimental/memory/utils#estimateMessageTokens 336 B 567 B
agents/experimental/memory/utils#estimateStringTokens 142 B 145 B
agents/experimental/memory/utils#findTailCutByTokens 597 B 1.3 KiB
agents/experimental/memory/utils#isCompactionMessage 98 B 83 B
agents/experimental/memory/utils#sanitizeToolPairs 537 B 1.1 KiB
agents/experimental/memory/utils#TOKENS_PER_MESSAGE 51 B 31 B
agents/experimental/memory/utils#truncateOlderMessages 1022 B 2.2 KiB
agents/experimental/memory/utils#WORDS_TOKEN_MULTIPLIER 53 B 33 B
agents/experimental/webmcp#registerWebMcp 85.2 KiB 295.8 KiB
agents/lifecycle#getCurrentAgent 376 B 798 B
agents/lifecycle#Lifecycle 8.3 KiB 25.8 KiB
agents/lifecycle#LifecycleCapability 484 B 975 B
agents/mcp#createLegacyMcpHandler 375.9 KiB 1572.2 KiB
agents/mcp#createMcpHandler 388.2 KiB 1617.4 KiB
agents/mcp#DurableObjectEventStore 342.5 KiB 1430.7 KiB
agents/mcp#ElicitRequestSchema 342.5 KiB 1430.7 KiB
agents/mcp#experimental_createMcpHandler 376.1 KiB 1572.5 KiB
agents/mcp#getMcpAuthContext 342.5 KiB 1430.8 KiB
agents/mcp#MCP_SERVER_ID_MAX_LENGTH 342.5 KiB 1430.7 KiB
agents/mcp#McpAgent 342.5 KiB 1430.7 KiB
agents/mcp#normalizeServerId 342.5 KiB 1430.7 KiB
agents/mcp#RPC_DO_PREFIX 342.5 KiB 1430.7 KiB
agents/mcp#RPCClientTransport 342.5 KiB 1430.7 KiB
agents/mcp#RPCServerTransport 342.5 KiB 1430.7 KiB
agents/mcp#SSEEdgeClientTransport 342.6 KiB 1431.0 KiB
agents/mcp#StreamableHTTPEdgeClientTransport 342.6 KiB 1431.0 KiB
agents/mcp#WorkerTransport 345.8 KiB 1447.6 KiB
agents/mcp/client#getNamespacedData 62.9 KiB 240.0 KiB
agents/mcp/client#MCP_SERVER_ID_MAX_LENGTH 62.9 KiB 239.9 KiB
agents/mcp/client#MCPClientManager 158.6 KiB 702.6 KiB
agents/mcp/client#normalizeServerId 63.0 KiB 240.2 KiB
agents/mcp/do-oauth-client-provider#DurableObjectOAuthClientProvider 2.1 KiB 6.6 KiB
agents/mcp/server#createMcpHandler 80.5 KiB 307.2 KiB
agents/mcp/server#getMcpAuthContext 64.0 KiB 245.5 KiB
agents/observability#channels 259 B 549 B
agents/observability#genericObservability 470 B 1.2 KiB
agents/observability#subscribe 324 B 668 B
agents/observability/ai#wrapAISDK 8.8 KiB 30.5 KiB
agents/react#_testUtils 3.8 KiB 9.5 KiB
agents/react#useAgent 10.8 KiB 31.1 KiB
agents/react#useAgentToolEvents 5.6 KiB 16.8 KiB
agents/routing#getAgentByName 795 B 1.7 KiB
agents/routing#routeAgentRequest 1.6 KiB 3.6 KiB
agents/routing#RoutedAgents 2.4 KiB 6.2 KiB
agents/schedule#getSchedulePrompt 85.8 KiB 424.7 KiB
agents/schedule#scheduleSchema 85.3 KiB 423.6 KiB
agents/schedule#unstable_getSchedulePrompt 85.9 KiB 424.9 KiB
agents/schedule#unstable_scheduleSchema 85.3 KiB 423.6 KiB
agents/schedules#Scheduler 6.8 KiB 22.0 KiB
agents/schedules/parser#getSchedulePrompt 85.8 KiB 424.7 KiB
agents/schedules/parser#scheduleSchema 85.3 KiB 423.6 KiB
agents/skills#fromManifest 309.8 KiB 1084.0 KiB
agents/skills#parseSkillFrontmatter 328.4 KiB 1146.2 KiB
agents/skills#parseSkillMarkdown 328.6 KiB 1146.5 KiB
agents/skills#r2 330.2 KiB 1150.4 KiB
agents/skills#runner 369.0 KiB 1297.8 KiB
agents/skills#SkillRegistry 397.5 KiB 1513.3 KiB
agents/skills/compile#compileSkillScript 15.4 KiB 43.4 KiB
agents/skills/compile#isCompilableSkillScript 15.4 KiB 43.3 KiB
agents/streams#DEFAULT_MAX_CHUNK_BYTES 83 B 81 B
agents/streams#sseResponse 843 B 1.6 KiB
agents/streams#StreamClosedError 161 B 197 B
agents/streams#StreamNotFoundError 201 B 261 B
agents/streams#Streams 3.4 KiB 11.1 KiB
agents/streams#StreamSerializationError 158 B 186 B
agents/tasks#DuplicateTaskStepError 328 B 463 B
agents/tasks#MAX_SERIALIZED_BYTES 190 B 232 B
agents/tasks#MissingTaskDefinitionError 358 B 536 B
agents/tasks#NonRetryableError 238 B 308 B
agents/tasks#TaskReplayDivergedError 341 B 483 B
agents/tasks#Tasks 8.9 KiB 31.8 KiB
agents/tasks#TaskSerializationError 258 B 339 B
agents/types#MessageType 211 B 365 B
agents/vite#default 353.8 KiB 1356.1 KiB
agents/websockets#CALLABLES_RPC_QUERY 12.4 KiB 43.3 KiB
agents/websockets#CALLABLES_RPC_VALUE 12.4 KiB 43.3 KiB
agents/websockets#callablesFromDecorated 12.7 KiB 44.3 KiB
agents/websockets#callablesRpcUrl 12.5 KiB 43.5 KiB
agents/websockets#isCallablesRpcUpgrade 12.4 KiB 43.4 KiB
agents/websockets#WebSockets 17.7 KiB 62.2 KiB
agents/workflows#AgentWorkflow 260.0 KiB 1134.8 KiB
agents/workflows#WorkflowRejectedError 258.7 KiB 1130.2 KiB
agents/x402#normalizeNetwork 14.7 KiB 61.1 KiB
agents/x402#withX402 23.0 KiB 89.2 KiB
agents/x402#withX402Client 104.1 KiB 346.5 KiB

Reported by agent-think[bot].

@pkg-pr-new

pkg-pr-new Bot commented Sep 3, 2026

Copy link
Copy Markdown

Open in StackBlitz

agents

npm i https://pkg.pr.new/agents@2207

@cloudflare/ai-chat

npm i https://pkg.pr.new/@cloudflare/ai-chat@2207

@cloudflare/codemode

npm i https://pkg.pr.new/@cloudflare/codemode@2207

hono-agents

npm i https://pkg.pr.new/hono-agents@2207

@cloudflare/shell

npm i https://pkg.pr.new/@cloudflare/shell@2207

@cloudflare/think

npm i https://pkg.pr.new/@cloudflare/think@2207

@cloudflare/voice

npm i https://pkg.pr.new/@cloudflare/voice@2207

@cloudflare/worker-bundler

npm i https://pkg.pr.new/@cloudflare/worker-bundler@2207

commit: 27004a0

…lity

Replace the HTTP operator API with a WebSocket protocol on the WebSockets
capability: an object snapshot on connect, subscribe to replay-then-tail
a turn's Streams log, and submit, write_source, activate, and restore
commands. Turn and revision changes broadcast to every connection.

The client connects with useAgent from agents/react through a
useHarnessSession hook and uses the same Kumo chat layout as the other
harness examples, with tool cards per turn and an inspector for the
active revision's code, revision history with restore, and the journal.
The worker routes with routeAgentRequest.

Tests drive the test object over RPC instead of the removed HTTP adapter.
Drop the dev-time journal column migration and the duplicated file list
from the snapshot.

Claude-Session: https://claude.ai/code/session_01KEFnjoMnZBMewsuD9qxGrL
@mattzcarey
mattzcarey marked this pull request as ready for review September 3, 2026 13:22

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 7 potential issues.

3 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment thread examples/next/harnesses/self-modifying/src/use-harness-session.ts Outdated
Comment on lines +489 to +491
} catch (error) {
outcome = taskOutcome({ ok: false, error: errorMessage(error) });
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Task retries become terminal failures

When step.do schedules a retry, this catch converts its suspension into a completed failure outcome. The task settles immediately, so retries never run.

Prompt for agents
Allow Tasks control-flow exceptions from step.do to propagate so ReplayStep can park or retry the run. Only convert a genuinely terminal editable-harness outcome into TurnTaskOutcome. The current catch also swallows TaskSuspension, defeating the configured retry policy and settling the step with ok:false.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +11 to +12
const ENTRY_SOURCE = `import { WorkerEntrypoint } from "cloudflare:workers";
import harness from "./src/index";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Custom-tool validation can be bypassed

If edited src/index.ts omits the virtual registry, compileHarness never evaluates tool modules. Activation accepts invalid tools, while valid tools disappear.

Prompt for agents
Make the immutable generated entrypoint import the generated custom-tools registry unconditionally, then expose its definitions and dispatcher to editable code through a contract that does not depend on src/index.ts retaining a particular import. Activation must evaluate every src/tools/*.ts module even after the editable entrypoint is reorganized, so malformed, duplicate, and System-shadowing tools still reject the candidate.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +357 to +360
if (prompt.trim() === "") throw new Error("Turn prompt must not be empty");
const active = this.#store.activeBuild();
if (!active) throw new Error("Harness genesis has not been activated");
const existing = this.#store.turn(turnId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Concurrent turns corrupt conversation order

#admit accepts turns while earlier ones remain active. Their prompts and replies interleave, so later model history no longer represents a valid conversation.

Prompt for agents
Serialize turn admission at the server, not only in each browser's busy state. Before accepting a new turn, reject it or queue it behind every queued/running turn. Ensure history for a turn is assembled only after all preceding turns have terminal assistant output, including submissions racing from multiple WebSocket connections.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +144 to +145
case "write_source":
await this.#host.writeSource(message.path, message.content);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟥 Unauthenticated clients replace executable code

Any client can send write_source, activate, or restore without authorization. Attackers can replace the shared harness code executed by later turns.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +13 to +27
function absoluteHarnessPath(path: string): string {
const absolute = path.startsWith("/") ? path : `${HARNESS_ROOT}${path}`;
if (
!absolute.startsWith(HARNESS_ROOT) ||
absolute.includes("/../") ||
absolute.endsWith("/..")
) {
throw new HarnessPathError(
`Harness source path must remain under ${HARNESS_ROOT}: ${JSON.stringify(path)}`
);
}
if (absolute === HARNESS_ROOT) {
throw new HarnessPathError("Harness source path must name a file");
}
return absolute;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟥 Symlinks escape the harness directory

absoluteHarnessPath validates only the written path before Workspace follows symlinks. A harness symlink can read or overwrite files outside /harness.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +31 to +37
function isClientMessage(value: unknown): value is HarnessClientMessage {
return (
typeof value === "object" &&
value !== null &&
"type" in value &&
typeof value.type === "string"
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟨 WebSocket payloads bypass validation

isClientMessage accepts any object with a string type. Malformed or oversized fields reach source writes, builds, subscriptions, and model turns unchecked.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

…tor port

Deploy as self-modifying-harness-example, give the Vite dev server its own
inspector port so it can run beside the other harness examples, and note
CLOUDFLARE_ACCOUNT_ID for logins with several accounts.
agents/react resolved a second React copy from the agents package, which
broke every hook call in the browser.
…the client

A closed stream ends as soon as it is replayed, and every stream end
asked for a snapshot that resubscribed to every turn, so the page kept
re-rendering and scrolling to the bottom. Subscribe to each turn once per
connection, refresh only after a live tail ends, and scroll only when
content is added.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant