diff --git a/artifacts/sdk-docs/go-sdk/types.mdx b/artifacts/sdk-docs/go-sdk/types.mdx index 66804fdeb..f536a74a9 100644 --- a/artifacts/sdk-docs/go-sdk/types.mdx +++ b/artifacts/sdk-docs/go-sdk/types.mdx @@ -201,8 +201,13 @@ ExecuteResponse represents a command execution response ```go type ExecuteResponse struct { - ExitCode int - Result string + ExitCode int + // Result is the combined stdout and stderr in arrival order (interleaved) + Result string + // Stdout is the standard output only; nil when the sandbox daemon predates split streams + Stdout *string + // Stderr is the standard error only; nil when the sandbox daemon predates split streams + Stderr *string Artifacts *ExecutionArtifacts // nil when no artifacts available } ``` diff --git a/artifacts/sdk-docs/python-sdk/async/async-process.mdx b/artifacts/sdk-docs/python-sdk/async/async-process.mdx index 22e084cb8..e7c2dda6c 100644 --- a/artifacts/sdk-docs/python-sdk/async/async-process.mdx +++ b/artifacts/sdk-docs/python-sdk/async/async-process.mdx @@ -50,7 +50,9 @@ Execute a shell command in the Sandbox. - `ExecuteResponse` - Command execution results containing: - exit_code: The command's exit status - - result: Standard output from the command + - result: Combined stdout and stderr from the command (interleaved) + - stdout: Standard output only; None when the sandbox daemon predates split streams + - stderr: Standard error only; None when the sandbox daemon predates split streams - artifacts: ExecutionArtifacts object containing `stdout` (same as result) and `charts` (matplotlib charts metadata) @@ -62,6 +64,11 @@ Execute a shell command in the Sandbox. response = await sandbox.process.exec("echo 'Hello'") print(response.artifacts.stdout) # Prints: Hello +# Split streams +response = await sandbox.process.exec("echo out; echo err >&2") +print(response.stdout) # Prints: out +print(response.stderr) # Prints: err + # Command with working directory result = await sandbox.process.exec("ls", cwd="workspace/src") @@ -866,7 +873,9 @@ Response from the command execution. **Attributes**: - `exit_code` _int_ - The exit code from the command execution -- `result` _str_ - The output from the command execution +- `result` _str_ - Combined stdout and stderr from the command execution (interleaved) +- `stdout` _str | None_ - Standard output only; None when the sandbox daemon predates split streams +- `stderr` _str | None_ - Standard error only; None when the sandbox daemon predates split streams - `artifacts` _ExecutionArtifacts | None_ - Artifacts from the command execution ## SessionExecuteResponse diff --git a/artifacts/sdk-docs/python-sdk/sync/process.mdx b/artifacts/sdk-docs/python-sdk/sync/process.mdx index 0c47f0500..93d66e408 100644 --- a/artifacts/sdk-docs/python-sdk/sync/process.mdx +++ b/artifacts/sdk-docs/python-sdk/sync/process.mdx @@ -51,7 +51,9 @@ Execute a shell command in the Sandbox. - `ExecuteResponse` - Command execution results containing: - exit_code: The command's exit status - - result: Standard output from the command + - result: Combined stdout and stderr from the command (interleaved) + - stdout: Standard output only; None when the sandbox daemon predates split streams + - stderr: Standard error only; None when the sandbox daemon predates split streams - artifacts: ExecutionArtifacts object containing `stdout` (same as result) and `charts` (matplotlib charts metadata) @@ -63,6 +65,11 @@ Execute a shell command in the Sandbox. response = sandbox.process.exec("echo 'Hello'") print(response.artifacts.stdout) # Prints: Hello +# Split streams +response = sandbox.process.exec("echo out; echo err >&2") +print(response.stdout) # Prints: out +print(response.stderr) # Prints: err + # Command with working directory result = sandbox.process.exec("ls", cwd="workspace/src") @@ -857,7 +864,9 @@ Response from the command execution. **Attributes**: - `exit_code` _int_ - The exit code from the command execution -- `result` _str_ - The output from the command execution +- `result` _str_ - Combined stdout and stderr from the command execution (interleaved) +- `stdout` _str | None_ - Standard output only; None when the sandbox daemon predates split streams +- `stderr` _str | None_ - Standard error only; None when the sandbox daemon predates split streams - `artifacts` _ExecutionArtifacts | None_ - Artifacts from the command execution ## SessionExecuteResponse diff --git a/artifacts/sdk-docs/ruby-sdk/process.mdx b/artifacts/sdk-docs/ruby-sdk/process.mdx index 8dde0c72f..278fd7873 100644 --- a/artifacts/sdk-docs/ruby-sdk/process.mdx +++ b/artifacts/sdk-docs/ruby-sdk/process.mdx @@ -94,7 +94,8 @@ Execute a shell command in the Sandbox **Returns**: -- `ExecuteResponse` - Command execution results containing exit_code, result, and artifacts +- `ExecuteResponse` - Command execution results containing exit_code, combined stdout and stderr (interleaved) as result, +split stdout/stderr (nil when the sandbox daemon predates split streams), and artifacts **Examples:** diff --git a/artifacts/sdk-docs/typescript-sdk/execute-response.mdx b/artifacts/sdk-docs/typescript-sdk/execute-response.mdx index 31c9402ba..f654081ff 100644 --- a/artifacts/sdk-docs/typescript-sdk/execute-response.mdx +++ b/artifacts/sdk-docs/typescript-sdk/execute-response.mdx @@ -12,7 +12,9 @@ Response from the command execution. - `artifacts?` _ExecutionArtifacts_ - Artifacts from the command execution - `exitCode` _number_ - The exit code from the command execution -- `result` _string_ - The output from the command execution +- `result` _string_ - Combined stdout and stderr from the command execution (interleaved) +- `stderr?` _string_ - Standard error only; undefined when the sandbox daemon predates split streams +- `stdout?` _string_ - Standard output only; undefined when the sandbox daemon predates split streams ## ExecutionArtifacts Artifacts from the command execution. diff --git a/artifacts/sdk-docs/typescript-sdk/process.mdx b/artifacts/sdk-docs/typescript-sdk/process.mdx index 49081cf38..23c3f1d89 100644 --- a/artifacts/sdk-docs/typescript-sdk/process.mdx +++ b/artifacts/sdk-docs/typescript-sdk/process.mdx @@ -322,7 +322,9 @@ Executes a shell command in the Sandbox. - `Promise` - Command execution results containing: - exitCode: The command's exit status - - result: Standard output from the command + - result: Combined stdout and stderr from the command (interleaved) + - stdout: Standard output only; undefined when the sandbox daemon predates split streams + - stderr: Standard error only; undefined when the sandbox daemon predates split streams - artifacts: ExecutionArtifacts object containing `stdout` (same as result) and `charts` (matplotlib charts metadata) **Examples:** @@ -333,6 +335,13 @@ const response = await process.executeCommand('echo "Hello"'); console.log(response.artifacts.stdout); // Prints: Hello ``` +```ts +// Split streams +const response = await process.executeCommand('echo out; echo err >&2'); +console.log(response.stdout); // Prints: out +console.log(response.stderr); // Prints: err +``` + ```ts // Command with working directory const result = await process.executeCommand('ls', 'workspace/src'); diff --git a/openapi-specs/toolbox.json b/openapi-specs/toolbox.json index 40ab1caa8..ed951a5c6 100644 --- a/openapi-specs/toolbox.json +++ b/openapi-specs/toolbox.json @@ -4427,6 +4427,15 @@ "type": "integer" }, "result": { + "description": "Combined stdout and stderr in arrival order (interleaved)", + "type": "string" + }, + "stderr": { + "description": "Standard error only; omitted by daemons that predate split streams", + "type": "string" + }, + "stdout": { + "description": "Standard output only; omitted by daemons that predate split streams", "type": "string" } } diff --git a/sdk-go/pkg/daytona/process.go b/sdk-go/pkg/daytona/process.go index 9e587d2e9..68178b1af 100644 --- a/sdk-go/pkg/daytona/process.go +++ b/sdk-go/pkg/daytona/process.go @@ -176,6 +176,8 @@ func (p *ProcessService) ExecuteCommand(ctx context.Context, command string, opt return &types.ExecuteResponse{ ExitCode: exitCode, Result: resp.Result, + Stdout: resp.Stdout, + Stderr: resp.Stderr, Artifacts: &types.ExecutionArtifacts{ Stdout: resp.Result, }, diff --git a/sdk-go/pkg/types/types.go b/sdk-go/pkg/types/types.go index 32e8612e3..7f0b4c5f4 100644 --- a/sdk-go/pkg/types/types.go +++ b/sdk-go/pkg/types/types.go @@ -377,8 +377,13 @@ type CodeRunParams struct { // ExecuteResponse represents a command execution response type ExecuteResponse struct { - ExitCode int - Result string + ExitCode int + // Result is the combined stdout and stderr in arrival order (interleaved) + Result string + // Stdout is the standard output only; nil when the sandbox daemon predates split streams + Stdout *string + // Stderr is the standard error only; nil when the sandbox daemon predates split streams + Stderr *string Artifacts *ExecutionArtifacts // nil when no artifacts available } diff --git a/sdk-java/src/main/java/io/daytona/sdk/model/ExecuteResponse.java b/sdk-java/src/main/java/io/daytona/sdk/model/ExecuteResponse.java index 16b308cce..a69edd842 100644 --- a/sdk-java/src/main/java/io/daytona/sdk/model/ExecuteResponse.java +++ b/sdk-java/src/main/java/io/daytona/sdk/model/ExecuteResponse.java @@ -16,6 +16,8 @@ public ExecuteResponse(io.daytona.toolbox.client.model.ExecuteResponse source) { if (source != null) { setExitCode(source.getExitCode()); setResult(source.getResult()); + setStdout(source.getStdout()); + setStderr(source.getStderr()); } } @@ -35,4 +37,34 @@ public CodeRunArtifacts getArtifacts() { public void setArtifacts(CodeRunArtifacts artifacts) { this.artifacts = artifacts; } + + /** + * Gets the combined stdout and stderr (interleaved). + * + * @return combined stdout and stderr (interleaved) + */ + @Override + public String getResult() { + return super.getResult(); + } + + /** + * Gets the split stdout stream; null when the sandbox daemon predates split streams. + * + * @return split stdout stream, or {@code null} + */ + @Override + public String getStdout() { + return super.getStdout(); + } + + /** + * Gets the split stderr stream; null when the sandbox daemon predates split streams. + * + * @return split stderr stream, or {@code null} + */ + @Override + public String getStderr() { + return super.getStderr(); + } } diff --git a/sdk-java/src/test/java/io/daytona/sdk/ProcessTest.java b/sdk-java/src/test/java/io/daytona/sdk/ProcessTest.java index 0b05bedd3..1323e6b3b 100644 --- a/sdk-java/src/test/java/io/daytona/sdk/ProcessTest.java +++ b/sdk-java/src/test/java/io/daytona/sdk/ProcessTest.java @@ -72,18 +72,36 @@ void executeCommandUsesMinimalRequest() { io.daytona.toolbox.client.model.ExecuteResponse response = new io.daytona.toolbox.client.model.ExecuteResponse(); response.setExitCode(0); response.setResult("ok"); + response.setStdout("out"); + response.setStderr("err"); when(processApi.executeCommand(any())).thenReturn(response); ExecuteResponse result = process.executeCommand("echo hello"); assertThat(result.getExitCode()).isEqualTo(0); assertThat(result.getResult()).isEqualTo("ok"); + assertThat(result.getStdout()).isEqualTo("out"); + assertThat(result.getStderr()).isEqualTo("err"); ArgumentCaptor captor = ArgumentCaptor.forClass(ExecuteRequest.class); verify(processApi).executeCommand(captor.capture()); assertThat(captor.getValue().getCommand()).isEqualTo("echo hello"); assertThat(captor.getValue().getCwd()).isNull(); } + @Test + void executeCommandKeepsSplitStreamsNullForOlderDaemons() { + io.daytona.toolbox.client.model.ExecuteResponse response = new io.daytona.toolbox.client.model.ExecuteResponse(); + response.setExitCode(0); + response.setResult("combined"); + when(processApi.executeCommand(any())).thenReturn(response); + + ExecuteResponse result = process.executeCommand("echo hello"); + + assertThat(result.getResult()).isEqualTo("combined"); + assertThat(result.getStdout()).isNull(); + assertThat(result.getStderr()).isNull(); + } + @Test void executeCommandPassesCwdEnvAndTimeout() { Map env = new HashMap(); diff --git a/sdk-python/src/daytona/_async/process.py b/sdk-python/src/daytona/_async/process.py index 2047d6e8c..d24e31147 100644 --- a/sdk-python/src/daytona/_async/process.py +++ b/sdk-python/src/daytona/_async/process.py @@ -105,7 +105,9 @@ async def exec( Returns: ExecuteResponse: Command execution results containing: - exit_code: The command's exit status - - result: Standard output from the command + - result: Combined stdout and stderr from the command (interleaved) + - stdout: Standard output only; None when the sandbox daemon predates split streams + - stderr: Standard error only; None when the sandbox daemon predates split streams - artifacts: ExecutionArtifacts object containing `stdout` (same as result) and `charts` (matplotlib charts metadata) @@ -115,6 +117,11 @@ async def exec( response = await sandbox.process.exec("echo 'Hello'") print(response.artifacts.stdout) # Prints: Hello + # Split streams + response = await sandbox.process.exec("echo out; echo err >&2") + print(response.stdout) # Prints: out + print(response.stderr) # Prints: err + # Command with working directory result = await sandbox.process.exec("ls", cwd="workspace/src") @@ -138,6 +145,8 @@ async def exec( response.exit_code if response.exit_code is not None else response.additional_properties.get("code") ), result=result, + stdout=response.stdout, + stderr=response.stderr, artifacts=artifacts, additional_properties=response.additional_properties, ) diff --git a/sdk-python/src/daytona/_sync/process.py b/sdk-python/src/daytona/_sync/process.py index 0930bbb5a..ae1b959ba 100644 --- a/sdk-python/src/daytona/_sync/process.py +++ b/sdk-python/src/daytona/_sync/process.py @@ -101,7 +101,9 @@ def exec( Returns: ExecuteResponse: Command execution results containing: - exit_code: The command's exit status - - result: Standard output from the command + - result: Combined stdout and stderr from the command (interleaved) + - stdout: Standard output only; None when the sandbox daemon predates split streams + - stderr: Standard error only; None when the sandbox daemon predates split streams - artifacts: ExecutionArtifacts object containing `stdout` (same as result) and `charts` (matplotlib charts metadata) @@ -111,6 +113,11 @@ def exec( response = sandbox.process.exec("echo 'Hello'") print(response.artifacts.stdout) # Prints: Hello + # Split streams + response = sandbox.process.exec("echo out; echo err >&2") + print(response.stdout) # Prints: out + print(response.stderr) # Prints: err + # Command with working directory result = sandbox.process.exec("ls", cwd="workspace/src") @@ -133,6 +140,8 @@ def exec( response.exit_code if response.exit_code is not None else response.additional_properties.get("code") ), result=result, + stdout=response.stdout, + stderr=response.stderr, artifacts=artifacts, additional_properties=response.additional_properties, ) diff --git a/sdk-python/src/daytona/common/process.py b/sdk-python/src/daytona/common/process.py index d035bffd7..01cabd7d5 100644 --- a/sdk-python/src/daytona/common/process.py +++ b/sdk-python/src/daytona/common/process.py @@ -80,12 +80,16 @@ class ExecuteResponse(BaseModel): Attributes: exit_code (int): The exit code from the command execution - result (str): The output from the command execution + result (str): Combined stdout and stderr from the command execution (interleaved) + stdout (str | None): Standard output only; None when the sandbox daemon predates split streams + stderr (str | None): Standard error only; None when the sandbox daemon predates split streams artifacts (ExecutionArtifacts | None): Artifacts from the command execution """ exit_code: int result: str + stdout: str | None = None + stderr: str | None = None artifacts: ExecutionArtifacts | None = None additional_properties: dict[str, object] = Field(default_factory=dict) diff --git a/sdk-python/tests/test_process.py b/sdk-python/tests/test_process.py index 16179e989..06dbf17b4 100644 --- a/sdk-python/tests/test_process.py +++ b/sdk-python/tests/test_process.py @@ -40,6 +40,26 @@ def test_exec_falls_back_to_additional_properties_code(self): result = proc.exec("false") assert result.exit_code == 42 + def test_exec_returns_split_streams(self): + proc, api = self._make_process() + api.execute_command.return_value = MagicMock( + result="out\nerr\n", exit_code=0, stdout="out\n", stderr="err\n", additional_properties={} + ) + result = proc.exec("echo out; echo err >&2") + assert result.result == "out\nerr\n" + assert result.stdout == "out\n" + assert result.stderr == "err\n" + + def test_exec_split_streams_none_on_old_daemon(self): + proc, api = self._make_process() + api.execute_command.return_value = MagicMock( + result="combined", exit_code=0, stdout=None, stderr=None, additional_properties={} + ) + result = proc.exec("echo combined") + assert result.result == "combined" + assert result.stdout is None + assert result.stderr is None + def test_code_run_uses_language_and_params(self): proc, api = self._make_process() api.code_run.return_value = MagicMock( diff --git a/sdk-ruby/lib/daytona/common/process.rb b/sdk-ruby/lib/daytona/common/process.rb index 7d4d28480..a8bae5aeb 100644 --- a/sdk-ruby/lib/daytona/common/process.rb +++ b/sdk-ruby/lib/daytona/common/process.rb @@ -8,9 +8,15 @@ class ExecuteResponse # @return [Integer] The exit code from the command execution attr_reader :exit_code - # @return [String] The output from the command execution + # @return [String] Combined stdout and stderr (interleaved) attr_reader :result + # @return [String, nil] Split stdout; nil when the sandbox daemon predates split streams + attr_reader :stdout + + # @return [String, nil] Split stderr; nil when the sandbox daemon predates split streams + attr_reader :stderr + # @return [ExecutionArtifacts, nil] Artifacts from the command execution attr_reader :artifacts @@ -20,12 +26,16 @@ class ExecuteResponse # Initialize a new ExecuteResponse # # @param exit_code [Integer] The exit code from the command execution - # @param result [String] The output from the command execution + # @param result [String] Combined stdout and stderr (interleaved) + # @param stdout [String, nil] Split stdout; nil when the sandbox daemon predates split streams + # @param stderr [String, nil] Split stderr; nil when the sandbox daemon predates split streams # @param artifacts [ExecutionArtifacts, nil] Artifacts from the command execution # @param additional_properties [Hash] Additional properties from the response - def initialize(exit_code:, result:, artifacts: nil, additional_properties: {}) + def initialize(exit_code:, result:, stdout: nil, stderr: nil, artifacts: nil, additional_properties: {}) @exit_code = exit_code @result = result + @stdout = stdout + @stderr = stderr @artifacts = artifacts @additional_properties = additional_properties end diff --git a/sdk-ruby/lib/daytona/process.rb b/sdk-ruby/lib/daytona/process.rb index 114e3a7ae..80a079380 100644 --- a/sdk-ruby/lib/daytona/process.rb +++ b/sdk-ruby/lib/daytona/process.rb @@ -44,7 +44,8 @@ def initialize(sandbox_id:, toolbox_api:, get_preview_link:, language: 'python', # @param cwd [String, nil] Working directory for command execution. If not specified, uses the sandbox working directory # @param env [Hash, nil] Environment variables to set for the command # @param timeout [Integer, nil] Maximum time in seconds to wait for the command to complete. - # @return [ExecuteResponse] Command execution results containing exit_code, result, and artifacts + # @return [ExecuteResponse] Command execution results containing exit_code, combined stdout and stderr (interleaved) as result, + # split stdout/stderr (nil when the sandbox daemon predates split streams), and artifacts # # @example # # Simple command @@ -66,6 +67,8 @@ def exec(command:, cwd: nil, env: nil, timeout: nil) ExecuteResponse.new( exit_code: response.exit_code, result:, + stdout: response.respond_to?(:stdout) ? response.stdout : nil, + stderr: response.respond_to?(:stderr) ? response.stderr : nil, artifacts: ExecutionArtifacts.new(result, []) ) rescue *Sdk::API_ERROR_CLASSES => e diff --git a/sdk-ruby/spec/daytona/process_spec.rb b/sdk-ruby/spec/daytona/process_spec.rb index f2f0f208b..b9701fa39 100644 --- a/sdk-ruby/spec/daytona/process_spec.rb +++ b/sdk-ruby/spec/daytona/process_spec.rb @@ -92,7 +92,7 @@ def open? end describe '#exec' do - let(:exec_response) { double('ExecResponse', exit_code: 0, result: "Hello\n") } + let(:exec_response) { double('ExecResponse', exit_code: 0, result: "Hello\n", stdout: "Hello\n", stderr: nil) } it 'executes a command and returns ExecuteResponse' do allow(toolbox_api).to receive(:execute_command).and_return(exec_response) @@ -102,9 +102,23 @@ def open? expect(response).to be_a(Daytona::ExecuteResponse) expect(response.exit_code).to eq(0) expect(response.result).to eq("Hello\n") + expect(response.stdout).to eq("Hello\n") + expect(response.stderr).to be_nil expect(response.artifacts.stdout).to eq("Hello\n") end + it 'leaves split streams nil when the daemon omits them' do + allow(toolbox_api).to receive(:execute_command).and_return( + double('ExecResponse', exit_code: 0, result: "Hello\n") + ) + + response = process.exec(command: 'echo Hello') + + expect(response.stdout).to be_nil + expect(response.stderr).to be_nil + expect(response.result).to eq("Hello\n") + end + it 'passes cwd, timeout, and env variables through as envs' do allow(toolbox_api).to receive(:execute_command).and_return(exec_response) diff --git a/sdk-typescript/src/Process.ts b/sdk-typescript/src/Process.ts index c2f4cfe4d..5660139ff 100644 --- a/sdk-typescript/src/Process.ts +++ b/sdk-typescript/src/Process.ts @@ -98,7 +98,9 @@ export class Process { * the client-wide `requestTimeoutMs`; `0` disables the server-side limit. * @returns {Promise} Command execution results containing: * - exitCode: The command's exit status - * - result: Standard output from the command + * - result: Combined stdout and stderr from the command (interleaved) + * - stdout: Standard output only; undefined when the sandbox daemon predates split streams + * - stderr: Standard error only; undefined when the sandbox daemon predates split streams * - artifacts: ExecutionArtifacts object containing `stdout` (same as result) and `charts` (matplotlib charts metadata) * * @example @@ -107,6 +109,12 @@ export class Process { * console.log(response.artifacts.stdout); // Prints: Hello * * @example + * // Split streams + * const response = await process.executeCommand('echo out; echo err >&2'); + * console.log(response.stdout); // Prints: out + * console.log(response.stderr); // Prints: err + * + * @example * // Command with working directory * const result = await process.executeCommand('ls', 'workspace/src'); * @@ -135,6 +143,8 @@ export class Process { return { exitCode: response.data.exitCode ?? (response.data as any).code, result, + stdout: response.data.stdout, + stderr: response.data.stderr, artifacts: { stdout: result, }, diff --git a/sdk-typescript/src/__tests__/Process.test.ts b/sdk-typescript/src/__tests__/Process.test.ts index 814bed2f4..a2edf2ecb 100644 --- a/sdk-typescript/src/__tests__/Process.test.ts +++ b/sdk-typescript/src/__tests__/Process.test.ts @@ -92,6 +92,26 @@ describe('Process', () => { ) }) + it('executeCommand returns split stdout and stderr when the daemon provides them', async () => { + const { process, apiClient } = await makeProcess() + + apiClient.executeCommand.mockResolvedValue( + createApiResponse({ exitCode: 0, result: 'out\nerr\n', stdout: 'out\n', stderr: 'err\n' }), + ) + const result = await process.executeCommand('echo out; echo err >&2') + expect(result).toMatchObject({ exitCode: 0, result: 'out\nerr\n', stdout: 'out\n', stderr: 'err\n' }) + }) + + it('executeCommand leaves split streams undefined for daemons that predate them', async () => { + const { process, apiClient } = await makeProcess() + + apiClient.executeCommand.mockResolvedValue(createApiResponse({ exitCode: 0, result: 'combined' })) + const result = await process.executeCommand('echo combined') + expect(result.result).toBe('combined') + expect(result.stdout).toBeUndefined() + expect(result.stderr).toBeUndefined() + }) + it('executeCommand with exec timeout does not override the HTTP deadline when requestTimeoutMs is not configured', async () => { const { process, apiClient } = await makeProcess() diff --git a/sdk-typescript/src/types/ExecuteResponse.ts b/sdk-typescript/src/types/ExecuteResponse.ts index f3a0852d5..f5eefe4d4 100644 --- a/sdk-typescript/src/types/ExecuteResponse.ts +++ b/sdk-typescript/src/types/ExecuteResponse.ts @@ -22,11 +22,15 @@ export interface ExecutionArtifacts { * * @interface * @property exitCode - The exit code from the command execution - * @property result - The output from the command execution + * @property result - Combined stdout and stderr from the command execution (interleaved) + * @property stdout - Standard output only; undefined when the sandbox daemon predates split streams + * @property stderr - Standard error only; undefined when the sandbox daemon predates split streams * @property artifacts - Artifacts from the command execution */ export interface ExecuteResponse { exitCode: number result: string + stdout?: string + stderr?: string artifacts?: ExecutionArtifacts } diff --git a/toolbox-api-client-go/api/openapi.yaml b/toolbox-api-client-go/api/openapi.yaml index 1f887a12b..9455dd360 100644 --- a/toolbox-api-client-go/api/openapi.yaml +++ b/toolbox-api-client-go/api/openapi.yaml @@ -4276,11 +4276,22 @@ components: ExecuteResponse: example: result: result + stdout: stdout exitCode: 0 + stderr: stderr properties: exitCode: type: integer result: + description: Combined stdout and stderr in arrival order (interleaved) + type: string + stderr: + description: Standard error only; omitted by daemons that predate split + streams + type: string + stdout: + description: Standard output only; omitted by daemons that predate split + streams type: string required: - result diff --git a/toolbox-api-client-go/model_execute_response.go b/toolbox-api-client-go/model_execute_response.go index be21dd63e..b7d6341fd 100644 --- a/toolbox-api-client-go/model_execute_response.go +++ b/toolbox-api-client-go/model_execute_response.go @@ -21,7 +21,12 @@ var _ MappedNullable = &ExecuteResponse{} // ExecuteResponse struct for ExecuteResponse type ExecuteResponse struct { ExitCode *int32 `json:"exitCode,omitempty"` + // Combined stdout and stderr in arrival order (interleaved) Result string `json:"result"` + // Standard error only; omitted by daemons that predate split streams + Stderr *string `json:"stderr,omitempty"` + // Standard output only; omitted by daemons that predate split streams + Stdout *string `json:"stdout,omitempty"` AdditionalProperties map[string]interface{} } @@ -101,6 +106,70 @@ func (o *ExecuteResponse) SetResult(v string) { o.Result = v } +// GetStderr returns the Stderr field value if set, zero value otherwise. +func (o *ExecuteResponse) GetStderr() string { + if o == nil || IsNil(o.Stderr) { + var ret string + return ret + } + return *o.Stderr +} + +// GetStderrOk returns a tuple with the Stderr field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ExecuteResponse) GetStderrOk() (*string, bool) { + if o == nil || IsNil(o.Stderr) { + return nil, false + } + return o.Stderr, true +} + +// HasStderr returns a boolean if a field has been set. +func (o *ExecuteResponse) HasStderr() bool { + if o != nil && !IsNil(o.Stderr) { + return true + } + + return false +} + +// SetStderr gets a reference to the given string and assigns it to the Stderr field. +func (o *ExecuteResponse) SetStderr(v string) { + o.Stderr = &v +} + +// GetStdout returns the Stdout field value if set, zero value otherwise. +func (o *ExecuteResponse) GetStdout() string { + if o == nil || IsNil(o.Stdout) { + var ret string + return ret + } + return *o.Stdout +} + +// GetStdoutOk returns a tuple with the Stdout field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ExecuteResponse) GetStdoutOk() (*string, bool) { + if o == nil || IsNil(o.Stdout) { + return nil, false + } + return o.Stdout, true +} + +// HasStdout returns a boolean if a field has been set. +func (o *ExecuteResponse) HasStdout() bool { + if o != nil && !IsNil(o.Stdout) { + return true + } + + return false +} + +// SetStdout gets a reference to the given string and assigns it to the Stdout field. +func (o *ExecuteResponse) SetStdout(v string) { + o.Stdout = &v +} + func (o ExecuteResponse) MarshalJSON() ([]byte, error) { toSerialize,err := o.ToMap() if err != nil { @@ -115,6 +184,12 @@ func (o ExecuteResponse) ToMap() (map[string]interface{}, error) { toSerialize["exitCode"] = o.ExitCode } toSerialize["result"] = o.Result + if !IsNil(o.Stderr) { + toSerialize["stderr"] = o.Stderr + } + if !IsNil(o.Stdout) { + toSerialize["stdout"] = o.Stdout + } for key, value := range o.AdditionalProperties { toSerialize[key] = value @@ -160,6 +235,8 @@ func (o *ExecuteResponse) UnmarshalJSON(data []byte) (err error) { if err = json.Unmarshal(data, &additionalProperties); err == nil { delete(additionalProperties, "exitCode") delete(additionalProperties, "result") + delete(additionalProperties, "stderr") + delete(additionalProperties, "stdout") o.AdditionalProperties = additionalProperties } diff --git a/toolbox-api-client-java/src/main/java/io/daytona/toolbox/client/model/ExecuteResponse.java b/toolbox-api-client-java/src/main/java/io/daytona/toolbox/client/model/ExecuteResponse.java index 8d26f468c..6546f1eb2 100644 --- a/toolbox-api-client-java/src/main/java/io/daytona/toolbox/client/model/ExecuteResponse.java +++ b/toolbox-api-client-java/src/main/java/io/daytona/toolbox/client/model/ExecuteResponse.java @@ -60,6 +60,16 @@ public class ExecuteResponse { @javax.annotation.Nonnull private String result; + public static final String SERIALIZED_NAME_STDERR = "stderr"; + @SerializedName(SERIALIZED_NAME_STDERR) + @javax.annotation.Nullable + private String stderr; + + public static final String SERIALIZED_NAME_STDOUT = "stdout"; + @SerializedName(SERIALIZED_NAME_STDOUT) + @javax.annotation.Nullable + private String stdout; + public ExecuteResponse() { } @@ -88,7 +98,7 @@ public ExecuteResponse result(@javax.annotation.Nonnull String result) { } /** - * Get result + * Combined stdout and stderr in arrival order (interleaved) * @return result */ @javax.annotation.Nonnull @@ -100,6 +110,44 @@ public void setResult(@javax.annotation.Nonnull String result) { this.result = result; } + + public ExecuteResponse stderr(@javax.annotation.Nullable String stderr) { + this.stderr = stderr; + return this; + } + + /** + * Standard error only; omitted by daemons that predate split streams + * @return stderr + */ + @javax.annotation.Nullable + public String getStderr() { + return stderr; + } + + public void setStderr(@javax.annotation.Nullable String stderr) { + this.stderr = stderr; + } + + + public ExecuteResponse stdout(@javax.annotation.Nullable String stdout) { + this.stdout = stdout; + return this; + } + + /** + * Standard output only; omitted by daemons that predate split streams + * @return stdout + */ + @javax.annotation.Nullable + public String getStdout() { + return stdout; + } + + public void setStdout(@javax.annotation.Nullable String stdout) { + this.stdout = stdout; + } + /** * A container for additional, undeclared properties. * This is a holder for any undeclared properties as specified with @@ -156,13 +204,15 @@ public boolean equals(Object o) { } ExecuteResponse executeResponse = (ExecuteResponse) o; return Objects.equals(this.exitCode, executeResponse.exitCode) && - Objects.equals(this.result, executeResponse.result)&& + Objects.equals(this.result, executeResponse.result) && + Objects.equals(this.stderr, executeResponse.stderr) && + Objects.equals(this.stdout, executeResponse.stdout)&& Objects.equals(this.additionalProperties, executeResponse.additionalProperties); } @Override public int hashCode() { - return Objects.hash(exitCode, result, additionalProperties); + return Objects.hash(exitCode, result, stderr, stdout, additionalProperties); } @Override @@ -171,6 +221,8 @@ public String toString() { sb.append("class ExecuteResponse {\n"); sb.append(" exitCode: ").append(toIndentedString(exitCode)).append("\n"); sb.append(" result: ").append(toIndentedString(result)).append("\n"); + sb.append(" stderr: ").append(toIndentedString(stderr)).append("\n"); + sb.append(" stdout: ").append(toIndentedString(stdout)).append("\n"); sb.append(" additionalProperties: ").append(toIndentedString(additionalProperties)).append("\n"); sb.append("}"); return sb.toString(); @@ -190,7 +242,7 @@ private String toIndentedString(Object o) { static { // a set of all properties/fields (JSON key names) - openapiFields = new HashSet(Arrays.asList("exitCode", "result")); + openapiFields = new HashSet(Arrays.asList("exitCode", "result", "stderr", "stdout")); // a set of required properties/fields (JSON key names) openapiRequiredFields = new HashSet(Arrays.asList("result")); @@ -219,6 +271,12 @@ public static void validateJsonElement(JsonElement jsonElement) throws IOExcepti if (!jsonObj.get("result").isJsonPrimitive()) { throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "Expected the field `result` to be a primitive type in the JSON string but got `%s`", jsonObj.get("result").toString())); } + if ((jsonObj.get("stderr") != null && !jsonObj.get("stderr").isJsonNull()) && !jsonObj.get("stderr").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "Expected the field `stderr` to be a primitive type in the JSON string but got `%s`", jsonObj.get("stderr").toString())); + } + if ((jsonObj.get("stdout") != null && !jsonObj.get("stdout").isJsonNull()) && !jsonObj.get("stdout").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "Expected the field `stdout` to be a primitive type in the JSON string but got `%s`", jsonObj.get("stdout").toString())); + } } public static class CustomTypeAdapterFactory implements TypeAdapterFactory { diff --git a/toolbox-api-client-java/src/test/java/io/daytona/toolbox/client/model/ExecuteResponseTest.java b/toolbox-api-client-java/src/test/java/io/daytona/toolbox/client/model/ExecuteResponseTest.java index 7a603cba7..33d8fa993 100644 --- a/toolbox-api-client-java/src/test/java/io/daytona/toolbox/client/model/ExecuteResponseTest.java +++ b/toolbox-api-client-java/src/test/java/io/daytona/toolbox/client/model/ExecuteResponseTest.java @@ -53,4 +53,20 @@ public void resultTest() { // TODO: test result } + /** + * Test the property 'stderr' + */ + @Test + public void stderrTest() { + // TODO: test stderr + } + + /** + * Test the property 'stdout' + */ + @Test + public void stdoutTest() { + // TODO: test stdout + } + } diff --git a/toolbox-api-client-python-async/daytona_toolbox_api_client_async/models/execute_response.py b/toolbox-api-client-python-async/daytona_toolbox_api_client_async/models/execute_response.py index deb4aaaf6..470f8ec59 100644 --- a/toolbox-api-client-python-async/daytona_toolbox_api_client_async/models/execute_response.py +++ b/toolbox-api-client-python-async/daytona_toolbox_api_client_async/models/execute_response.py @@ -30,9 +30,11 @@ class ExecuteResponse(BaseModel): ExecuteResponse """ # noqa: E501 exit_code: Optional[StrictInt] = Field(default=None, serialization_alias="exitCode") - result: StrictStr + result: StrictStr = Field(description="Combined stdout and stderr in arrival order (interleaved)") + stderr: Optional[StrictStr] = Field(default=None, description="Standard error only; omitted by daemons that predate split streams") + stdout: Optional[StrictStr] = Field(default=None, description="Standard output only; omitted by daemons that predate split streams") additional_properties: Dict[str, Any] = {} - __properties: ClassVar[List[str]] = ["exitCode", "result"] + __properties: ClassVar[List[str]] = ["exitCode", "result", "stderr", "stdout"] model_config = ConfigDict( populate_by_name=True, @@ -92,7 +94,9 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "exit_code": obj.get("exitCode"), - "result": obj.get("result") + "result": obj.get("result"), + "stderr": obj.get("stderr"), + "stdout": obj.get("stdout") }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/toolbox-api-client-python/daytona_toolbox_api_client/models/execute_response.py b/toolbox-api-client-python/daytona_toolbox_api_client/models/execute_response.py index deb4aaaf6..470f8ec59 100644 --- a/toolbox-api-client-python/daytona_toolbox_api_client/models/execute_response.py +++ b/toolbox-api-client-python/daytona_toolbox_api_client/models/execute_response.py @@ -30,9 +30,11 @@ class ExecuteResponse(BaseModel): ExecuteResponse """ # noqa: E501 exit_code: Optional[StrictInt] = Field(default=None, serialization_alias="exitCode") - result: StrictStr + result: StrictStr = Field(description="Combined stdout and stderr in arrival order (interleaved)") + stderr: Optional[StrictStr] = Field(default=None, description="Standard error only; omitted by daemons that predate split streams") + stdout: Optional[StrictStr] = Field(default=None, description="Standard output only; omitted by daemons that predate split streams") additional_properties: Dict[str, Any] = {} - __properties: ClassVar[List[str]] = ["exitCode", "result"] + __properties: ClassVar[List[str]] = ["exitCode", "result", "stderr", "stdout"] model_config = ConfigDict( populate_by_name=True, @@ -92,7 +94,9 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: _obj = cls.model_validate({ "exit_code": obj.get("exitCode"), - "result": obj.get("result") + "result": obj.get("result"), + "stderr": obj.get("stderr"), + "stdout": obj.get("stdout") }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/toolbox-api-client-ruby/lib/daytona_toolbox_api_client/models/execute_response.rb b/toolbox-api-client-ruby/lib/daytona_toolbox_api_client/models/execute_response.rb index ab0c3c156..e08d52a3b 100644 --- a/toolbox-api-client-ruby/lib/daytona_toolbox_api_client/models/execute_response.rb +++ b/toolbox-api-client-ruby/lib/daytona_toolbox_api_client/models/execute_response.rb @@ -17,13 +17,22 @@ module DaytonaToolboxApiClient class ExecuteResponse < ApiModelBase attr_accessor :exit_code + # Combined stdout and stderr in arrival order (interleaved) attr_accessor :result + # Standard error only; omitted by daemons that predate split streams + attr_accessor :stderr + + # Standard output only; omitted by daemons that predate split streams + attr_accessor :stdout + # Attribute mapping from ruby-style variable name to JSON key. def self.attribute_map { :'exit_code' => :'exitCode', - :'result' => :'result' + :'result' => :'result', + :'stderr' => :'stderr', + :'stdout' => :'stdout' } end @@ -41,7 +50,9 @@ def self.acceptable_attributes def self.openapi_types { :'exit_code' => :'Integer', - :'result' => :'String' + :'result' => :'String', + :'stderr' => :'String', + :'stdout' => :'String' } end @@ -76,6 +87,14 @@ def initialize(attributes = {}) else self.result = nil end + + if attributes.key?(:'stderr') + self.stderr = attributes[:'stderr'] + end + + if attributes.key?(:'stdout') + self.stdout = attributes[:'stdout'] + end end # Show invalid properties with the reasons. Usually used together with valid? @@ -114,7 +133,9 @@ def ==(o) return true if self.equal?(o) self.class == o.class && exit_code == o.exit_code && - result == o.result + result == o.result && + stderr == o.stderr && + stdout == o.stdout end # @see the `==` method @@ -126,7 +147,7 @@ def eql?(o) # Calculates hash code according to all attributes. # @return [Integer] Hash code def hash - [exit_code, result].hash + [exit_code, result, stderr, stdout].hash end # Builds the object from hash diff --git a/toolbox-api-client/src/models/execute-response.ts b/toolbox-api-client/src/models/execute-response.ts index 721cb0cd5..2cdb007c5 100644 --- a/toolbox-api-client/src/models/execute-response.ts +++ b/toolbox-api-client/src/models/execute-response.ts @@ -16,6 +16,17 @@ export interface ExecuteResponse { 'exitCode'?: number; + /** + * Combined stdout and stderr in arrival order (interleaved) + */ 'result': string; + /** + * Standard error only; omitted by daemons that predate split streams + */ + 'stderr'?: string; + /** + * Standard output only; omitted by daemons that predate split streams + */ + 'stdout'?: string; }