Skip to content

Implemented the core infrastructure for the Code Execution Engine#45

Merged
orpiske merged 1 commit intowanaku-ai:mainfrom
orpiske:cce-v1
Jan 20, 2026
Merged

Implemented the core infrastructure for the Code Execution Engine#45
orpiske merged 1 commit intowanaku-ai:mainfrom
orpiske:cce-v1

Conversation

@orpiske
Copy link
Copy Markdown
Contributor

@orpiske orpiske commented Jan 19, 2026

  • Implemented the exchange data types for the Code Execution Engine
  • Adjusted the ServiceTarget for the Code Execution Engine
  • Implemented data types for the Code Execution Engine
  • Added a Code Execution Engine service type
  • Added a more fields to the ServiceTarget

This solves issue #42

Summary by Sourcery

Introduce core data model for the Code Execution Engine and extend service discovery metadata to support code execution services.

New Features:

  • Add request, response, status, event, and error DTOs for the Code Execution Engine API, including SSE event streaming support.
  • Introduce a new CODE_EXECUTION_ENGINE service type for capabilities providers.

Enhancements:

  • Extend ServiceTarget with string-based service type plus subtype and language metadata, and propagate the new serviceName accessor across discovery and logging.
  • Update file header selection to work with string service type identifiers, treating code-execution-engine as multi-capability, and adjust Java tool archetype and tests to the new API.

- Implemented the exchange data types for the Code Execution Engine
- Adjusted the ServiceTarget for the Code Execution Engine
- Implemented data types for the Code Execution Engine
- Added a Code Execution Engine service type
- Added a more fields to the ServiceTarget

This solves issue wanaku-ai#42
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Jan 19, 2026

Reviewer's Guide

Introduces core data and exchange types plus service metadata changes to support a new sandboxed Code Execution Engine and string-based service type identifiers across discovery and persistence components.

Sequence diagram for Code Execution Engine request and SSE streaming

sequenceDiagram
    actor Client
    participant Api as CodeExecutionAPI
    participant Engine as ExecutionEngine
    participant Store as TaskStore
    participant Stream as SSEStream

    Client->>Api: POST /code-execution request(CodeExecutionRequest)
    Api->>+Engine: submit(CodeExecutionRequest)
    Engine->>Engine: create CodeExecutionTask
    Engine->>Store: save(CodeExecutionTask)
    Engine-->>Api: CodeExecutionResponse(taskId, streamUrl, PENDING)
    Api-->>Client: 202 Accepted with CodeExecutionResponse

    Client->>Stream: GET streamUrl (SSE)
    Stream->>Store: load(taskId)
    Store-->>Stream: CodeExecutionTask

    Engine->>Engine: start execution
    Engine->>Stream: send CodeExecutionEvent.started(taskId)
    loop while running
        Engine->>Stream: send CodeExecutionEvent.output(taskId, chunk)
        alt error output
            Engine->>Stream: send CodeExecutionEvent.error(taskId, stderrChunk)
        end
    end
    alt success
        Engine->>Stream: send CodeExecutionEvent.completed(taskId, exitCode)
    else failure
        Engine->>Stream: send CodeExecutionEvent.failed(taskId, exitCode, message)
    else timeout
        Engine->>Stream: send CodeExecutionEvent.timeout(taskId)
    else cancelled
        Engine->>Stream: send CodeExecutionEvent.cancelled(taskId)
    end

    Stream-->>Client: SSE event stream closes
Loading

Class diagram for updated ServiceTarget and ServiceType

classDiagram
    class ServiceTarget {
        +String id
        +String serviceName
        +String host
        +int port
        +String serviceType
        +String serviceSubType
        +String languageName
        +String languageType
        +String languageSubType
        +ServiceTarget()
        +ServiceTarget(String id, String serviceName, String host, int port, String serviceType, String serviceSubType, String languageName, String languageType, String languageSubType)
        +String getServiceName()
        +void setServiceName(String serviceName)
        +String getHost()
        +int getPort()
        +String getServiceType()
        +void setServiceType(String serviceType)
        +String getServiceSubType()
        +void setServiceSubType(String serviceSubType)
        +String getLanguageName()
        +void setLanguageName(String languageName)
        +String getLanguageType()
        +void setLanguageType(String languageType)
        +String getLanguageSubType()
        +void setLanguageSubType(String languageSubType)
        +String getAddress()
        +boolean equals(Object o)
        +int hashCode()
        +String toString()
        +static ServiceTarget newEmptyTarget(String serviceName, String address, int port, String serviceType, String serviceSubType, String languageName, String languageType, String languageSubType)
        +static ServiceTarget newEmptyTarget(String serviceName, String address, int port, String serviceType)
    }

    class ServiceType {
        <<enum>>
        RESOURCE_PROVIDER
        TOOL_INVOKER
        MULTI_CAPABILITY
        CODE_EXECUTION_ENGINE
        +String asValue()
        +int asIntValue()
        +static ServiceType fromValue(String value)
        +static ServiceType fromIntValue(int value)
    }

    class InstanceDataManager {
        +InstanceDataManager(String dataDir, String serviceName)
        +void writeEntry(ServiceTarget serviceTarget)
        -static FileHeader newFileHeader(ServiceTarget serviceTarget)
    }

    class FileHeader {
        <<enum>>
        TOOL_INVOKER
        RESOURCE_PROVIDER
        MULTI_CAPABILITY
    }

    ServiceTarget ..> ServiceType : legacy enum reference
    InstanceDataManager ..> ServiceTarget : uses
    InstanceDataManager ..> FileHeader : maps serviceType string
Loading

Class diagram for core Code Execution Engine data types

classDiagram
    class CodeExecutionRequest {
        +static long DEFAULT_TIMEOUT_MS
        +static int MAX_CODE_SIZE_BYTES
        +static long MAX_TIMEOUT_MS
        +static long MIN_TIMEOUT_MS
        -String code
        -Long timeout
        -Map~String, String~ environment
        -List~String~ arguments
        -Map~String, Object~ metadata
        +CodeExecutionRequest()
        +CodeExecutionRequest(String code)
        +String getCode()
        +void setCode(String code)
        +Long getTimeout()
        +void setTimeout(Long timeout)
        +Map~String, String~ getEnvironment()
        +void setEnvironment(Map~String, String~ environment)
        +List~String~ getArguments()
        +void setArguments(List~String~ arguments)
        +Map~String, Object~ getMetadata()
        +void setMetadata(Map~String, Object~ metadata)
        +void validate()
        +boolean equals(Object o)
        +int hashCode()
        +String toString()
    }

    class CodeExecutionStatus {
        <<enum>>
        PENDING
        RUNNING
        COMPLETED
        FAILED
        CANCELLED
        TIMEOUT
        +boolean isTerminal()
        +boolean isSuccess()
        +boolean isError()
    }

    class CodeExecutionEventType {
        <<enum>>
        STARTED
        OUTPUT
        ERROR
        COMPLETED
        FAILED
        CANCELLED
        TIMEOUT
        +boolean isTerminal()
        +boolean isOutput()
    }

    class CodeExecutionEvent {
        -CodeExecutionEventType eventType
        -String taskId
        -Instant timestamp
        -CodeExecutionStatus status
        -String output
        -String error
        -Integer exitCode
        -String message
        -Map~String, Object~ metadata
        +CodeExecutionEvent()
        +CodeExecutionEvent(CodeExecutionEventType eventType, String taskId, CodeExecutionStatus status)
        +CodeExecutionEventType getEventType()
        +void setEventType(CodeExecutionEventType eventType)
        +String getTaskId()
        +void setTaskId(String taskId)
        +Instant getTimestamp()
        +void setTimestamp(Instant timestamp)
        +CodeExecutionStatus getStatus()
        +void setStatus(CodeExecutionStatus status)
        +String getOutput()
        +void setOutput(String output)
        +String getError()
        +void setError(String error)
        +Integer getExitCode()
        +void setExitCode(Integer exitCode)
        +String getMessage()
        +void setMessage(String message)
        +Map~String, Object~ getMetadata()
        +void setMetadata(Map~String, Object~ metadata)
        +static CodeExecutionEvent started(String taskId)
        +static CodeExecutionEvent output(String taskId, String output)
        +static CodeExecutionEvent error(String taskId, String error)
        +static CodeExecutionEvent completed(String taskId, int exitCode)
        +static CodeExecutionEvent failed(String taskId, int exitCode, String errorMessage)
        +static CodeExecutionEvent timeout(String taskId)
        +static CodeExecutionEvent cancelled(String taskId)
        +boolean equals(Object o)
        +int hashCode()
        +String toString()
    }

    class CodeExecutionTask {
        -String taskId
        -CodeExecutionRequest request
        -String engineType
        -String language
        -CodeExecutionStatus status
        -Instant submittedAt
        -Instant startedAt
        -Instant completedAt
        -Integer exitCode
        +CodeExecutionTask()
        +CodeExecutionTask(String taskId, CodeExecutionRequest request, String engineType, String language)
        +String getTaskId()
        +void setTaskId(String taskId)
        +CodeExecutionRequest getRequest()
        +void setRequest(CodeExecutionRequest request)
        +String getEngineType()
        +void setEngineType(String engineType)
        +String getLanguage()
        +void setLanguage(String language)
        +CodeExecutionStatus getStatus()
        +void setStatus(CodeExecutionStatus status)
        +Instant getSubmittedAt()
        +void setSubmittedAt(Instant submittedAt)
        +Instant getStartedAt()
        +void setStartedAt(Instant startedAt)
        +Instant getCompletedAt()
        +void setCompletedAt(Instant completedAt)
        +Integer getExitCode()
        +void setExitCode(Integer exitCode)
        +void markStarted()
        +void markCompleted(int exitCode)
        +void markFailed(int exitCode)
        +void markTimeout()
        +void markCancelled()
        +Long getExecutionDurationMs()
        +boolean isTerminal()
        +boolean equals(Object o)
        +int hashCode()
        +String toString()
    }

    class CodeExecutionResponse {
        <<record>>
        +String taskId
        +String streamUrl
        +CodeExecutionStatus status
        +Instant submittedAt
        +static CodeExecutionResponse create(String taskId, String streamUrl, CodeExecutionStatus status)
        +static CodeExecutionResponse createPending(String taskId, String streamUrl)
    }

    class CodeExecutionError {
        +String error
        +String message
        +String taskId
        +Long timestamp
        +Map~String, String~ details
        +CodeExecutionError()
        +CodeExecutionError(String error, String message)
        +CodeExecutionError(String error, String message, String taskId)
        +String getError()
        +void setError(String error)
        +String getMessage()
        +void setMessage(String message)
        +String getTaskId()
        +void setTaskId(String taskId)
        +Long getTimestamp()
        +void setTimestamp(Long timestamp)
        +Map~String, String~ getDetails()
        +void setDetails(Map~String, String~ details)
        +String toString()
    }

    CodeExecutionTask --> CodeExecutionRequest : contains
    CodeExecutionTask --> CodeExecutionStatus : uses
    CodeExecutionEvent --> CodeExecutionEventType : uses
    CodeExecutionEvent --> CodeExecutionStatus : uses
    CodeExecutionResponse --> CodeExecutionStatus : uses
Loading

State diagram for CodeExecutionStatus lifecycle

stateDiagram-v2
    [*] --> PENDING

    PENDING --> RUNNING: start execution
    PENDING --> CANCELLED: cancel before start

    RUNNING --> COMPLETED: execution finished
    RUNNING --> FAILED: execution error
    RUNNING --> TIMEOUT: exceeded timeout
    RUNNING --> CANCELLED: user cancelled

    COMPLETED --> [*]
    FAILED --> [*]
    TIMEOUT --> [*]
    CANCELLED --> [*]
Loading

File-Level Changes

Change Details Files
Extend ServiceTarget to use string-based service types and add service/language classification metadata.
  • Rename service field to serviceName and propagate new getter/setter usage.
  • Replace ServiceType enum field with string serviceType and add serviceSubType, languageName, languageType, and languageSubType fields with accessors.
  • Update equals, hashCode, toString, and factory methods to include new fields and string-based service type.
  • Add overloaded newEmptyTarget factory methods matching the new signature.
capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/providers/ServiceTarget.java
Adapt discovery, registration archetype, and instance data header mapping to string service types and support the new code-execution-engine type.
  • Map string serviceType values to FileHeader enums, treating code-execution-engine as multi-capability and validating non-null serviceType.
  • Adjust InstanceDataManager test to construct ServiceTarget with string service type.
  • Update ZeroDepRegistrationManager and DiscoveryLogCallback to use getServiceName() and string serviceType in logging and InstanceDataManager initialization.
  • Change Java tool archetype to construct ServiceTarget with literal "tool-invoker" instead of ServiceType enum.
capabilities-data-files/src/main/java/ai/wanaku/capabilities/sdk/data/files/InstanceDataManager.java
capabilities-data-files/src/test/java/ai/wanaku/capabilities/sdk/data/files/InstanceDataManagerTest.java
capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/ZeroDepRegistrationManager.java
capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/DiscoveryLogCallback.java
capabilities-archetypes/capabilities-archetypes-java-tool/src/main/resources/archetype-resources/src/main/java/App.java
Introduce Code Execution Engine API types for requests, responses, statuses, events, and errors, including SSE streaming semantics.
  • Add CodeExecutionRequest with code, timeout, environment, args, metadata, size/timeout limits, and validation logic.
  • Add CodeExecutionResponse record encapsulating taskId, streamUrl, status, submittedAt with factory helpers and null/empty validation.
  • Add CodeExecutionStatus enum with lifecycle states and helpers for terminal/success/error checks.
  • Add CodeExecutionEventType enum to classify SSE event types with helpers for terminal and output events.
  • Add CodeExecutionEvent DTO with status, output/error fields, metadata, convenience factory methods for common events, and standard equals/hashCode/toString.
  • Add CodeExecutionTask internal model for tracking execution lifecycle, timestamps, exit code, and duration with state transition helpers.
  • Add CodeExecutionError DTO for API error payloads with basic structure and toString.
  • Add package-info documenting the execution types package.
capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/execution/CodeExecutionRequest.java
capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/execution/CodeExecutionResponse.java
capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/execution/CodeExecutionStatus.java
capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/execution/CodeExecutionEventType.java
capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/execution/CodeExecutionEvent.java
capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/execution/CodeExecutionTask.java
capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/execution/CodeExecutionError.java
capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/execution/package-info.java
Add a new CODE_EXECUTION_ENGINE service type to the ServiceType enum for backward compatibility where enums are still used.
  • Extend ServiceType enum with CODE_EXECUTION_ENGINE constant and associated int value.
  • Update fromIntValue to return CODE_EXECUTION_ENGINE for value 4.
capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/providers/ServiceType.java
Introduce protobuf definition for Code Execution Engine exchange API (file contents not shown in diff snippet).
  • Add codeexecution.proto in capabilities-exchange module to define wire-level request, response, event, and status messages for the Code Execution Engine.
capabilities-exchange/src/main/proto/codeexecution.proto

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@orpiske orpiske marked this pull request as ready for review January 20, 2026 10:55
@orpiske orpiske merged commit b1b5319 into wanaku-ai:main Jan 20, 2026
4 checks passed
Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • In CodeExecutionTask.equals, language == that.language compares String references rather than values; this should use Objects.equals(language, that.language) to behave correctly.
  • The switch in InstanceDataManager.newFileHeader uses hard-coded serviceType strings (e.g. "tool-invoker", "code-execution-engine"); consider centralizing these identifiers (e.g. via ServiceType or constants) to avoid drift between callers and the mapping logic.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In CodeExecutionTask.equals, `language == that.language` compares String references rather than values; this should use `Objects.equals(language, that.language)` to behave correctly.
- The switch in InstanceDataManager.newFileHeader uses hard-coded serviceType strings (e.g. "tool-invoker", "code-execution-engine"); consider centralizing these identifiers (e.g. via ServiceType or constants) to avoid drift between callers and the mapping logic.

## Individual Comments

### Comment 1
<location> `capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/execution/CodeExecutionTask.java:292-295` </location>
<code_context>
+            return false;
+        }
+        CodeExecutionTask that = (CodeExecutionTask) o;
+        return Objects.equals(taskId, that.taskId)
+                && Objects.equals(request, that.request)
+                && Objects.equals(engineType, that.engineType)
+                && language == that.language
+                && status == that.status
+                && Objects.equals(submittedAt, that.submittedAt)
</code_context>

<issue_to_address>
**issue (bug_risk):** Use `Objects.equals` for comparing `language` instead of `==` to avoid incorrect equality behavior.

In this `equals` implementation, `language` is a `String` but is compared with `==`:
```java
&& language == that.language
```
This checks reference equality, not value equality, so two objects with the same language content may be considered unequal. This breaks the contract of `equals` and can cause subtle bugs when these objects are used in collections or comparisons.
</issue_to_address>

### Comment 2
<location> `capabilities-data-files/src/test/java/ai/wanaku/capabilities/sdk/data/files/InstanceDataManagerTest.java:52` </location>
<code_context>
         final String expectedID = UUID.randomUUID().toString();
         ServiceTarget serviceTarget = ServiceTarget
-                .newEmptyTarget("testService", "localhost", 9190, ServiceType.TOOL_INVOKER);
+                .newEmptyTarget("testService", "localhost", 9190, "tool-invoker");
         serviceTarget.setId(expectedID);

</code_context>

<issue_to_address>
**suggestion (testing):** Add tests for the new string-based serviceType mapping, including null and unknown values

The production code now maps string service types to `FileHeader` and throws `IllegalArgumentException` for `null` or unknown values (with a special case for `"code-execution-engine"`). The current test only covers the happy path for `"tool-invoker"`. Please extend `InstanceDataManagerTest` with:

- A test that `"resource-provider"`, `"tool-invoker"`, and `"multi-capability"` each produce the expected `FileHeader`.
- A test that `"code-execution-engine"` is treated as `FileHeader.MULTI_CAPABILITY`.
- A test that `serviceType == null` throws `IllegalArgumentException`.
- A test that an unknown string (e.g. `"unknown-service"`) throws `IllegalArgumentException`.

Suggested implementation:

```java
import ai.wanaku.capabilities.sdk.api.types.providers.ServiceTarget;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;

```

```java
        final String expectedID = UUID.randomUUID().toString();

        // Valid service types should be accepted
        assertDoesNotThrow(
                () -> ServiceTarget.newEmptyTarget("testService", "localhost", 9190, "resource-provider"));
        assertDoesNotThrow(
                () -> ServiceTarget.newEmptyTarget("testService", "localhost", 9190, "tool-invoker"));
        assertDoesNotThrow(
                () -> ServiceTarget.newEmptyTarget("testService", "localhost", 9190, "multi-capability"));
        // "code-execution-engine" should be treated as MULTI_CAPABILITY and therefore also be accepted
        assertDoesNotThrow(
                () -> ServiceTarget.newEmptyTarget("testService", "localhost", 9190, "code-execution-engine"));

        // Null and unknown service types should be rejected
        assertThrows(
                IllegalArgumentException.class,
                () -> ServiceTarget.newEmptyTarget("testService", "localhost", 9190, null));
        assertThrows(
                IllegalArgumentException.class,
                () -> ServiceTarget.newEmptyTarget("testService", "localhost", 9190, "unknown-service"));

        ServiceTarget serviceTarget = ServiceTarget
                .newEmptyTarget("testService", "localhost", 9190, "tool-invoker");

```

To fully align with the review comment and explicitly verify the `FileHeader` mapping (not just that the calls succeed/fail), you will also need to:

1. Expose or access the mapped `FileHeader` for a given `ServiceTarget` or service type (e.g., via a getter on `ServiceTarget`, a helper on `InstanceDataManager`, or by inspecting the generated instance data file).
2. Add separate `@Test` methods in `InstanceDataManagerTest` that:
   - Assert `"resource-provider"`, `"tool-invoker"`, and `"multi-capability"` each map to their expected `FileHeader` value.
   - Assert `"code-execution-engine"` maps to `FileHeader.MULTI_CAPABILITY`.

The exact assertions depend on how `FileHeader` is surfaced in your test (e.g., `assertEquals(FileHeader.RESOURCE_PROVIDER, target.getFileHeader())`). Insert these new test methods at the class level of `InstanceDataManagerTest`, respecting the existing test structure and naming conventions.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +292 to +295
return Objects.equals(taskId, that.taskId)
&& Objects.equals(request, that.request)
&& Objects.equals(engineType, that.engineType)
&& language == that.language
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): Use Objects.equals for comparing language instead of == to avoid incorrect equality behavior.

In this equals implementation, language is a String but is compared with ==:

&& language == that.language

This checks reference equality, not value equality, so two objects with the same language content may be considered unequal. This breaks the contract of equals and can cause subtle bugs when these objects are used in collections or comparisons.

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