Skip to content

Conversation

@grypez
Copy link
Contributor

@grypez grypez commented Jan 14, 2026

Refactors kernel-utils and kernel-errors to enable makeJsonAgent to be bundled into vats using @endo/bundle-source.

Changes:

  • kernel-utils: Added subpath exports (counter, merge-disjoint-records, schema)
  • kernel-errors: Added bundleable subpath with simplified error classes
  • kernel-errors: Extracted ErrorCode to error-codes.ts (no @metamask/utils dep)
  • ocap-kernel: Moved isRetryableNetworkError from kernel-errors to utils
  • kernel-agents: Updated to use subpath imports

The bundler was failing due to transitive dependencies on @noble/hashes (through @metamask/utils) which has ESM/CJS compatibility issues. By using subpath exports and moving libp2p-specific code to ocap-kernel, we avoid pulling in unbundleable dependencies.


Note

Makes agent and supporting packages bundleable for vats and reduces unbundleable deps.

  • kernel-errors: Add bundleable/ subpath with lightweight SampleGenerationError; extract ErrorCode/ErrorSentinel to error-codes.ts; drop isRetryableNetworkError export; update BaseError and tests accordingly; update exports in package.json.
  • kernel-utils: Add subpath exports for counter, merge-disjoint-records, and schema; move makeCounter to counter.ts (re-exported from misc.ts); update package exports.
  • ocap-kernel: Move isRetryableNetworkError into utils/ with tests; update ConnectionFactory and network to import it locally.
  • kernel-agents: Switch imports to new subpaths (merge-disjoint-records, schema, discoverable); use bundleable SampleGenerationError.
  • Cleanup deps: remove libp2p dependency from kernel-errors and adjust yarn.lock.

Written by Cursor Bugbot for commit 6c9d512. This will update automatically on new commits. Configure here.

@grypez grypez changed the base branch from main to grypez/add-skill-create-package January 14, 2026 18:50
@grypez grypez force-pushed the grypez/refactor-kernel-errors-libp2p branch from d349ac7 to 1cd0e2b Compare January 15, 2026 17:09
@grypez grypez force-pushed the grypez/add-skill-create-package branch from b817127 to d269097 Compare January 15, 2026 17:18
@grypez grypez changed the base branch from grypez/add-skill-create-package to main January 15, 2026 17:23
@grypez grypez force-pushed the grypez/refactor-kernel-errors-libp2p branch from 1cd0e2b to 6de5dee Compare January 15, 2026 17:24
@grypez grypez changed the title refactor: Make kernel-errors bundleable with @endo/bundle-source refactor: Make makeJsonAgent bundleable with @endo/bundle-source Jan 15, 2026
@grypez grypez marked this pull request as ready for review January 15, 2026 17:59
@grypez grypez requested a review from a team as a code owner January 15, 2026 17:59
This refactors kernel-utils and kernel-errors to enable makeJsonAgent
to be bundled into vats using @endo/bundle-source.

Changes:
- kernel-utils: Added subpath exports (counter, merge-disjoint-records, schema)
- kernel-errors: Added bundleable subpath with simplified error classes
- kernel-errors: Extracted ErrorCode to error-codes.ts (no @metamask/utils dep)
- ocap-kernel: Moved isRetryableNetworkError from kernel-errors to utils
- kernel-agents: Updated to use subpath imports

The bundler was failing due to transitive dependencies on @noble/hashes
which has ESM/CJS compatibility issues. By using subpath exports and
moving libp2p-specific code to ocap-kernel, we avoid pulling in
unbundleable dependencies.
@grypez grypez force-pushed the grypez/refactor-kernel-errors-libp2p branch from 6de5dee to 6c9d512 Compare January 15, 2026 18:02
@grypez grypez enabled auto-merge January 15, 2026 18:02
@@ -1,4 +1,4 @@
import { SampleGenerationError } from '@metamask/kernel-errors';
import { SampleGenerationError } from '@metamask/kernel-errors/bundleable';
Copy link

Choose a reason for hiding this comment

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

Class identity mismatch breaks retry logic across packages

High Severity

The import of SampleGenerationError changed from @metamask/kernel-errors to @metamask/kernel-errors/bundleable. Since these export different class objects, the instanceof check in withRetries on line 47 will fail for errors thrown by packages that still import from the main export (like kernel-agents-repl). This breaks retry functionality for invalid LLM responses when using makeReplAgent, as errors won't be recognized as retryable and will be thrown immediately instead.

Fix in Cursor Fix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@claude recommend a fix that works for this PR

Copy link

@claude claude bot Jan 15, 2026

Choose a reason for hiding this comment

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

Claude finished @grypez's task in 1m 6s —— View job


Recommended fix for class identity mismatch

I've analyzed the issue and here's my recommendation:

Problem Summary

The PR creates two separate SampleGenerationError classes:

  • Main export (@metamask/kernel-errors): Full-featured version with marshaling logic, extends BaseError, depends on @metamask/utils
  • Bundleable export (@metamask/kernel-errors/bundleable): Lightweight version without marshaling, extends Error directly, no @metamask/utils dependency

The issue occurs because:

  1. kernel-agents (used in vats) imports from /bundleable (line 1 of attempt.ts:47)
  2. kernel-agents-repl imports from the main export (line 1 of sample-collector.ts:39)
  3. When errors cross package boundaries, instanceof checks fail because they're different class objects

Recommended Solution: Use Error Code Checking Instead of instanceof

Since you've already extracted ErrorCode to error-codes.ts (which is already bundleable), the cleanest solution is to replace instanceof checks with error code checks:

In packages/kernel-agents/src/attempt.ts:

import { ErrorCode } from '@metamask/kernel-errors/error-codes';

// Change line 47 from:
(error) => error instanceof SampleGenerationError,

// To:
(error) => error instanceof Error && 
           'code' in error && 
           error.code === ErrorCode.SampleGenerationError,

Why this works:

  1. ✅ Both versions of SampleGenerationError have a .code property with the same value
  2. ErrorCode can be imported separately without pulling in unbundleable dependencies
  3. ✅ No class identity issues - checking a property value, not class reference
  4. ✅ Works across package boundaries and different module exports
  5. ✅ Maintains type safety with proper runtime checks
  6. ✅ Consistent with the ocap pattern of using structural typing

Alternative (if you need stricter typing):

Create a type guard function in error-codes.ts:

// In packages/kernel-errors/src/error-codes.ts
export const isSampleGenerationError = (error: unknown): error is {
  code: typeof ErrorCode.SampleGenerationError;
  data: { sample: string };
  message: string;
  cause?: Error;
} => {
  return (
    error instanceof Error &&
    'code' in error &&
    error.code === ErrorCode.SampleGenerationError &&
    'data' in error &&
    typeof error.data === 'object' &&
    error.data !== null &&
    'sample' in error.data
  );
};

Then use it in attempt.ts:

import { isSampleGenerationError } from '@metamask/kernel-errors/error-codes';

// Line 47:
(error) => isSampleGenerationError(error),

This approach gives you proper type narrowing and works with both versions of the class.


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.

2 participants