Skip to content

Conversation

@jeff-hykin
Copy link
Member

@jeff-hykin jeff-hykin commented Jan 28, 2026

I'll fix the test in just a bit

@greptile-apps
Copy link

greptile-apps bot commented Jan 28, 2026

Greptile Overview

Greptile Summary

This PR implements a major refactoring of the RPC system with support for Spec-based module references. The core changes enable modules to declare dependencies on other modules via Protocol-based specifications rather than concrete types.

Major Changes:

  • Renamed ModuleBlueprintSetBlueprint and ModuleBlueprint_BlueprintAtom for clearer semantics
  • Renamed ModuleConnectionStreamRef to better reflect its purpose
  • Added ModuleRef dataclass to track module-to-module references via Specs
  • Introduced Spec protocol system in dimos/spec/utils.py with structural and annotation compliance checking
  • Updated Blueprint to support remapping module references to specific implementations
  • Added _connect_module_refs() method to resolve Spec-based dependencies at build time
  • Enhanced Module class with set_module_ref(), set_rpc_method(), and get_rpc_method_names() for dynamic RPC binding
  • Added new dependency: annotation-protocol package

Critical Issue:

  • Line 314 in dimos/core/blueprints.py has incorrect inspect.isclass() usage with two arguments instead of one, which will cause a runtime error

Confidence Score: 2/5

  • This PR has a critical syntax error that will cause runtime failures
  • The incorrect inspect.isclass(spec, type) call on line 314 will raise a TypeError when executed. This is in the module reference connection logic, which is a core part of the new RPC spec system. The error will prevent any module using Spec-based references from being deployed.
  • dimos/core/blueprints.py requires immediate attention - line 314 must be fixed before merge

Important Files Changed

Filename Overview
dimos/core/blueprints.py Major refactor: renamed classes (ModuleBlueprint->_BlueprintAtom, ModuleBlueprintSet->Blueprint), added ModuleRef support for RPC specs. Critical bug: inspect.isclass() called with wrong number of arguments on line 314
dimos/spec/utils.py New file implementing Spec protocol system with structural and annotation compliance checking for module specifications
examples/rpc_protocol_ref.py New example demonstrating the RPC protocol pattern using Spec to define module interfaces
dimos/core/module.py Added get_rpc_method_names(), set_rpc_method(), and set_module_ref() methods to support dynamic RPC method binding

Sequence Diagram

sequenceDiagram
    participant Client as Client Module
    participant BP as Blueprint
    participant MC as ModuleCoordinator
    participant Calc as Calculator Module
    participant RPC as LCMRPC

    Note over Client,Calc: Module Definition Phase
    Client->>Client: Define calc: ComputeSpec
    Calc->>Calc: Implement @rpc methods

    Note over BP,MC: Blueprint Build Phase
    BP->>BP: Create _BlueprintAtom for each module
    BP->>BP: Extract StreamRefs (In/Out)
    BP->>BP: Extract ModuleRefs (Spec/Module)
    BP->>MC: build() - deploy modules
    MC->>Calc: Instantiate Calculator
    MC->>Client: Instantiate Client
    
    Note over BP,MC: Connection Phase
    BP->>BP: _connect_module_refs()
    BP->>BP: Find module matching ComputeSpec
    BP->>BP: Check spec_structural_compliance(Calculator, ComputeSpec)
    BP->>BP: Check spec_annotation_compliance(Calculator, ComputeSpec)
    BP->>Client: setattr(calc, calculator_instance)
    BP->>Client: set_module_ref("calc", calculator_instance)
    
    BP->>BP: _connect_rpc_methods()
    BP->>RPC: Register Calculator.compute1
    BP->>RPC: Register Calculator.compute2
    BP->>Client: set_rpc_method("Calculator.compute1", callable)
    BP->>Client: set_rpc_method("Calculator.compute2", callable)

    Note over Client,RPC: Runtime RPC Call
    Client->>Client: start()
    Client->>Calc: self.calc.compute1(2, 3)
    Calc->>RPC: call_sync("Calculator/compute1", args)
    RPC->>Calc: Execute compute1(2, 3)
    Calc-->>RPC: Return result: 5
    RPC-->>Client: Return result: 5
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

@jeff-hykin jeff-hykin changed the title RPC Rework: Part 6: add _connect_module_refs RPC Rework: With Var Renames Jan 29, 2026
@jeff-hykin jeff-hykin closed this Jan 29, 2026
@jeff-hykin jeff-hykin reopened this Jan 29, 2026
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

4 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

)

# if the spec is actually module, use that (basically a user override)
if inspect.isclass(spec, type) and issubclass(spec, Module):
Copy link

Choose a reason for hiding this comment

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

inspect.isclass() only takes one argument, not two

Suggested change
if inspect.isclass(spec, type) and issubclass(spec, Module):
if inspect.isclass(spec) and issubclass(spec, Module):

@@ -0,0 +1,56 @@
# Copyright 2026 Dimensional Inc.
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this example be in the docs? I don't think anyone will look at it here.

Copy link
Member Author

Choose a reason for hiding this comment

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

I should have updated blueprints.md for the docs and the had this as a standalone example for people who jump into the code. (I believe this dir is linked to somewhere in the docs)

Comment on lines 268 to 294
def _connect_transports(self, module_coordinator: ModuleCoordinator) -> None:
# Gather all the In/Out connections with remapping applied.
# dict when given (final/remapped) connection name+type, provides a list of modules + original (non-remapped) connection names
connections = defaultdict(list)
# Track original name -> remapped name for each module
module_conn_mapping = defaultdict(dict) # type: ignore[var-annotated]

for blueprint in self.blueprints:
for conn in blueprint.connections:
# Check if this connection should be remapped
remapped_name = self.remapping_map.get((blueprint.module, conn.name), conn.name)
# Store the mapping for later use
module_conn_mapping[blueprint.module][conn.name] = remapped_name
# Group by remapped name and type
connections[remapped_name, conn.type].append((blueprint.module, conn.name))
if isinstance(remapped_name, str):
# Group by remapped name and type
connections[remapped_name, conn.type].append((blueprint.module, conn.name))

# Connect all In/Out connections by remapped name and type.
for remapped_name, type in connections.keys():
transport = self._get_transport_for(remapped_name, type)
for module, original_name in connections[(remapped_name, type)]:
instance = module_coordinator.get_instance(module)
for remapped_name, stream_type in connections.keys():
transport = self._get_transport_for(remapped_name, stream_type)
for module, original_name in connections[(remapped_name, stream_type)]:
instance = module_coordinator.get_instance(module) # type: ignore[assignment]
instance.set_transport(original_name, transport) # type: ignore[union-attr]
logger.info(
"Transport",
name=remapped_name,
original_name=original_name,
topic=str(getattr(transport, "topic", None)),
type=f"{type.__module__}.{type.__qualname__}",
type=f"{stream_type.__module__}.{stream_type.__qualname__}",
module=module.__name__,
transport=transport.__class__.__name__,
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe this should be called _connect_streams() and connection renamed to stream everywhere in this func to match the rest of the renames.

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.

3 participants