Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -265,15 +265,15 @@ public AgentWithUpgrades addToolsItem(Map<String, Object> 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<Map<String, Object>> getTools() {
return tools;
}


@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<Map<String, Object>> tools) {
this.tools = tools;
}
Expand All @@ -298,15 +298,15 @@ public AgentWithUpgrades addMcpServersItem(Map<String, Object> 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<Map<String, Object>> getMcpServers() {
return mcpServers;
}


@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<Map<String, Object>> mcpServers) {
this.mcpServers = mcpServers;
}
Expand All @@ -331,15 +331,15 @@ public AgentWithUpgrades addSkillsItem(Map<String, Object> 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<Map<String, Object>> getSkills() {
return skills;
}


@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<Map<String, Object>> skills) {
this.skills = skills;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,15 @@ 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<String> getVaultIds() {
return vaultIds;
}


@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<String> vaultIds) {
this.vaultIds = vaultIds;
}
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/volcengine/ark/runtime/service/ArkApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -382,6 +383,9 @@ Single<ListSessionsResponse> listSessions(@Query("agent_id") String agentId,
@POST("/api/v3/sessions/{sessionId}")
Single<Session> updateSession(@Path("sessionId") String sessionId, @Body UpdateSessionRequest request, @HeaderMap Map<String, String> customHeaders);

@POST("/api/v3/sessions/{sessionId}/upgrades")
Single<Session> upgradeSession(@Path("sessionId") String sessionId, @Body CreateSessionUpgradeRequest request, @HeaderMap Map<String, String> customHeaders);

@DELETE("/api/v3/sessions/{sessionId}")
Single<DeleteSessionResponse> deleteSession(@Path("sessionId") String sessionId, @HeaderMap Map<String, String> customHeaders);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<>()));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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 extends Annotation> T findAnnotation(Annotation[] annotations, Class<T> 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());
}
}
}
Loading