diff --git a/src/main/java/com/volcengine/ark/runtime/models/session/AgentWithUpgrades.java b/src/main/java/com/volcengine/ark/runtime/models/session/AgentWithUpgrades.java index c9dff13..91eba10 100644 --- a/src/main/java/com/volcengine/ark/runtime/models/session/AgentWithUpgrades.java +++ b/src/main/java/com/volcengine/ark/runtime/models/session/AgentWithUpgrades.java @@ -265,7 +265,7 @@ public AgentWithUpgrades addToolsItem(Map toolsItem) { */ @javax.annotation.Nullable @JsonProperty(value = JSON_PROPERTY_TOOLS, required = false) - @JsonInclude(value = JsonInclude.Include.NON_EMPTY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) public List> getTools() { return tools; @@ -273,7 +273,7 @@ public List> getTools() { @JsonProperty(value = JSON_PROPERTY_TOOLS, required = false) - @JsonInclude(value = JsonInclude.Include.NON_EMPTY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) public void setTools(@javax.annotation.Nullable List> tools) { this.tools = tools; } @@ -298,7 +298,7 @@ public AgentWithUpgrades addMcpServersItem(Map mcpServersItem) { */ @javax.annotation.Nullable @JsonProperty(value = JSON_PROPERTY_MCP_SERVERS, required = false) - @JsonInclude(value = JsonInclude.Include.NON_EMPTY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) public List> getMcpServers() { return mcpServers; @@ -306,7 +306,7 @@ public List> getMcpServers() { @JsonProperty(value = JSON_PROPERTY_MCP_SERVERS, required = false) - @JsonInclude(value = JsonInclude.Include.NON_EMPTY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) public void setMcpServers(@javax.annotation.Nullable List> mcpServers) { this.mcpServers = mcpServers; } @@ -331,7 +331,7 @@ public AgentWithUpgrades addSkillsItem(Map skillsItem) { */ @javax.annotation.Nullable @JsonProperty(value = JSON_PROPERTY_SKILLS, required = false) - @JsonInclude(value = JsonInclude.Include.NON_EMPTY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) public List> getSkills() { return skills; @@ -339,7 +339,7 @@ public List> getSkills() { @JsonProperty(value = JSON_PROPERTY_SKILLS, required = false) - @JsonInclude(value = JsonInclude.Include.NON_EMPTY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) public void setSkills(@javax.annotation.Nullable List> skills) { this.skills = skills; } diff --git a/src/main/java/com/volcengine/ark/runtime/models/session/CreateSessionUpgradeRequest.java b/src/main/java/com/volcengine/ark/runtime/models/session/CreateSessionUpgradeRequest.java index 6fafa1f..22594b1 100644 --- a/src/main/java/com/volcengine/ark/runtime/models/session/CreateSessionUpgradeRequest.java +++ b/src/main/java/com/volcengine/ark/runtime/models/session/CreateSessionUpgradeRequest.java @@ -123,7 +123,7 @@ public CreateSessionUpgradeRequest addVaultIdsItem(String vaultIdsItem) { */ @javax.annotation.Nullable @JsonProperty(value = JSON_PROPERTY_VAULT_IDS, required = false) - @JsonInclude(value = JsonInclude.Include.NON_EMPTY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) public List getVaultIds() { return vaultIds; @@ -131,7 +131,7 @@ public List getVaultIds() { @JsonProperty(value = JSON_PROPERTY_VAULT_IDS, required = false) - @JsonInclude(value = JsonInclude.Include.NON_EMPTY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) public void setVaultIds(@javax.annotation.Nullable List vaultIds) { this.vaultIds = vaultIds; } diff --git a/src/main/java/com/volcengine/ark/runtime/service/ArkApi.java b/src/main/java/com/volcengine/ark/runtime/service/ArkApi.java index a2984f8..874913a 100644 --- a/src/main/java/com/volcengine/ark/runtime/service/ArkApi.java +++ b/src/main/java/com/volcengine/ark/runtime/service/ArkApi.java @@ -49,6 +49,7 @@ import com.volcengine.ark.runtime.models.responses.ResponsesRequest; import com.volcengine.ark.runtime.models.session.CreateSessionRequest; import com.volcengine.ark.runtime.models.session.CreateSessionResourceRequest; +import com.volcengine.ark.runtime.models.session.CreateSessionUpgradeRequest; import com.volcengine.ark.runtime.models.session.DeleteSessionResponse; import com.volcengine.ark.runtime.models.session.ListSessionEventsResponse; import com.volcengine.ark.runtime.models.session.ListSessionResourcesResponse; @@ -382,6 +383,9 @@ Single listSessions(@Query("agent_id") String agentId, @POST("/api/v3/sessions/{sessionId}") Single updateSession(@Path("sessionId") String sessionId, @Body UpdateSessionRequest request, @HeaderMap Map customHeaders); + @POST("/api/v3/sessions/{sessionId}/upgrades") + Single upgradeSession(@Path("sessionId") String sessionId, @Body CreateSessionUpgradeRequest request, @HeaderMap Map customHeaders); + @DELETE("/api/v3/sessions/{sessionId}") Single deleteSession(@Path("sessionId") String sessionId, @HeaderMap Map customHeaders); diff --git a/src/main/java/com/volcengine/ark/runtime/service/ArkService.java b/src/main/java/com/volcengine/ark/runtime/service/ArkService.java index a85ed88..0ea2fc3 100644 --- a/src/main/java/com/volcengine/ark/runtime/service/ArkService.java +++ b/src/main/java/com/volcengine/ark/runtime/service/ArkService.java @@ -68,6 +68,7 @@ import com.volcengine.ark.runtime.models.responses.ResponsesRequest; import com.volcengine.ark.runtime.models.session.CreateSessionRequest; import com.volcengine.ark.runtime.models.session.CreateSessionResourceRequest; +import com.volcengine.ark.runtime.models.session.CreateSessionUpgradeRequest; import com.volcengine.ark.runtime.models.session.DeleteSessionResponse; import com.volcengine.ark.runtime.models.session.ListSessionEventsResponse; import com.volcengine.ark.runtime.models.session.ListSessionResourcesResponse; @@ -830,6 +831,10 @@ public Session updateSession(String sessionId, UpdateSessionRequest request) { return execute(api.updateSession(sessionId, request, new HashMap<>())); } + public Session upgradeSession(String sessionId, CreateSessionUpgradeRequest request) { + return execute(api.upgradeSession(sessionId, request, new HashMap<>())); + } + public DeleteSessionResponse deleteSession(String sessionId) { return execute(api.deleteSession(sessionId, new HashMap<>())); } diff --git a/src/test/java/com/volcengine/ark/runtime/service/ArkServiceSessionUpgradeTest.java b/src/test/java/com/volcengine/ark/runtime/service/ArkServiceSessionUpgradeTest.java new file mode 100644 index 0000000..ee94aa8 --- /dev/null +++ b/src/test/java/com/volcengine/ark/runtime/service/ArkServiceSessionUpgradeTest.java @@ -0,0 +1,119 @@ +// Copyright (c) 2026 ByteDance Ltd. and/or its affiliates. +// SPDX-License-Identifier: Apache-2.0 + +package com.volcengine.ark.runtime.service; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import com.volcengine.ark.runtime.models.session.AgentWithUpgrades; +import com.volcengine.ark.runtime.models.session.CreateSessionUpgradeRequest; +import com.volcengine.ark.runtime.models.session.Session; +import io.reactivex.Single; +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Collections; +import java.util.Map; +import org.junit.Test; +import retrofit2.http.POST; +import retrofit2.http.Path; + +public class ArkServiceSessionUpgradeTest { + @Test + public void upgradeSessionPassesRequestAndReturnsSession() { + CapturingArkApi handler = new CapturingArkApi(); + ArkService service = new ArkService(api(handler)); + CreateSessionUpgradeRequest request = request(); + + Session out = service.upgradeSession("sess-1", request); + + assertEquals("sess-1", out.getId()); + assertEquals("sess-1", handler.args[0]); + assertSame(request, handler.args[1]); + assertTrue(((Map) handler.args[2]).isEmpty()); + } + + @Test + public void upgradeSessionApiKeepsPostContract() throws Exception { + Method method = ArkApi.class.getMethod( + "upgradeSession", + String.class, + CreateSessionUpgradeRequest.class, + Map.class + ); + + assertEquals("/api/v3/sessions/{sessionId}/upgrades", method.getAnnotation(POST.class).value()); + assertEquals("sessionId", findAnnotation(method.getParameterAnnotations()[0], Path.class).value()); + } + + @Test + public void upgradeSessionPreservesExplicitEmptyArrays() throws Exception { + String json = ArkService.defaultObjectMapper().writeValueAsString(request()); + + assertTrue(json.contains("\"tools\":[]")); + assertTrue(json.contains("\"vault_ids\":[]")); + assertFalse(json.contains("initial_events")); + } + + private static CreateSessionUpgradeRequest request() { + AgentWithUpgrades agent = AgentWithUpgrades.builder() + .type(AgentWithUpgrades.TypeEnum.AGENT_WITH_UPGRADES) + .id("agent-1") + .tools(Collections.emptyList()) + .build(); + return CreateSessionUpgradeRequest.builder() + .agent(agent) + .vaultIds(Collections.emptyList()) + .build(); + } + + private static ArkApi api(CapturingArkApi handler) { + return (ArkApi) Proxy.newProxyInstance( + ArkApi.class.getClassLoader(), + new Class[] {ArkApi.class}, + handler + ); + } + + private static T findAnnotation(Annotation[] annotations, Class type) { + for (Annotation annotation : annotations) { + if (type.isInstance(annotation)) { + return type.cast(annotation); + } + } + throw new AssertionError("missing annotation " + type.getSimpleName()); + } + + private static final class CapturingArkApi implements InvocationHandler { + private Object[] args; + + @Override + public Object invoke(Object proxy, Method method, Object[] args) { + if (method.getDeclaringClass() == Object.class) { + return objectMethod(proxy, method, args); + } + if (!"upgradeSession".equals(method.getName())) { + throw new AssertionError("unexpected API call: " + method.getName()); + } + this.args = args; + return Single.just(new Session().id("sess-1")); + } + + private Object objectMethod(Object proxy, Method method, Object[] args) { + if ("toString".equals(method.getName())) { + return "capturing ArkApi proxy"; + } + if ("hashCode".equals(method.getName())) { + return System.identityHashCode(proxy); + } + if ("equals".equals(method.getName())) { + return proxy == args[0]; + } + throw new AssertionError("unexpected Object method: " + method.getName()); + } + } +}