diff --git a/src/main/java/com/alibaba/dashscope/agentstudio/model/Configs.java b/src/main/java/com/alibaba/dashscope/agentstudio/model/Configs.java index b20c5d5..d24698d 100644 --- a/src/main/java/com/alibaba/dashscope/agentstudio/model/Configs.java +++ b/src/main/java/com/alibaba/dashscope/agentstudio/model/Configs.java @@ -3,6 +3,7 @@ import com.google.gson.annotations.SerializedName; import java.util.List; +import java.util.Map; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -82,6 +83,13 @@ public static class PerToolConfig { @SerializedName("permission_policy") private PermissionPolicy permissionPolicy; + + /** + * Per-tool parameters, e.g. {@code knowledge_application_id} for the {@code + * search_knowledgebases} knowledge-retrieval tool. Serialized only when set. + */ + @SerializedName("params") + private Map params; } } diff --git a/src/main/java/com/alibaba/dashscope/agentstudio/model/Mount.java b/src/main/java/com/alibaba/dashscope/agentstudio/model/Mount.java new file mode 100644 index 0000000..e380dbd --- /dev/null +++ b/src/main/java/com/alibaba/dashscope/agentstudio/model/Mount.java @@ -0,0 +1,127 @@ +package com.alibaba.dashscope.agentstudio.model; + +import java.util.LinkedHashMap; +import java.util.List; + +/** + * Typed session-resource mount descriptor (create-time input on POST /sessions). + * + *

Extends {@link LinkedHashMap} so it fits the existing {@code List>} + * resources parameter without conversion: + * + *

{@code
+ * List> resources = new ArrayList<>();
+ * resources.add(Mount.oss("cn-beijing", "my-bucket", "datasets/", "/data")
+ *     .readOnly());
+ * resources.add(Mount.bailianMemory("lib_xxx", "customer_001")
+ *     .projectIds(Arrays.asList("fact_rule_1"))
+ *     .profileSchema("schema_xxx"));
+ * }
+ */ +public class Mount extends LinkedHashMap { + + private static final long serialVersionUID = 1L; + + public static Mount file(String fileId, String mountPath) { + return new Mount().putType("file").fileId(fileId).mountPath(mountPath); + } + + public static Mount memoryStore(String memoryStoreId) { + return new Mount().putType("memory_store").memoryStoreId(memoryStoreId); + } + + public static Mount bailianMemory(String memoryStoreId, String entityId) { + return new Mount() + .putType("memory_store") + .provider("agentstudio_memory") + .memoryStoreId(memoryStoreId) + .entityId(entityId); + } + + public static Mount oss(String region, String bucket, String ossPath, String mountPath) { + return new Mount() + .putType("oss") + .region(region) + .bucket(bucket) + .ossPath(ossPath) + .mountPath(mountPath); + } + + public Mount putType(String type) { + put("type", type); + return this; + } + + public Mount fileId(String fileId) { + put("file_id", fileId); + return this; + } + + public Mount mountPath(String mountPath) { + put("mount_path", mountPath); + return this; + } + + public Mount memoryStoreId(String memoryStoreId) { + put("memory_store_id", memoryStoreId); + return this; + } + + public Mount provider(String provider) { + put("provider", provider); + return this; + } + + public Mount entityId(String entityId) { + put("entity_id", entityId); + return this; + } + + public Mount projectIds(List projectIds) { + put("project_ids", projectIds); + return this; + } + + public Mount profileSchema(String profileSchema) { + put("profile_schema", profileSchema); + return this; + } + + public Mount description(String description) { + put("description", description); + return this; + } + + public Mount access(String access) { + put("access", access); + return this; + } + + public Mount readOnly() { + return access("read_only"); + } + + public Mount readWrite() { + return access("read_write"); + } + + public Mount instructions(String instructions) { + put("instructions", instructions); + return this; + } + + public Mount region(String region) { + put("region", region); + return this; + } + + public Mount bucket(String bucket) { + put("bucket", bucket); + return this; + } + + public Mount ossPath(String ossPath) { + put("oss_path", ossPath); + return this; + } +} diff --git a/src/main/java/com/alibaba/dashscope/agentstudio/model/Session.java b/src/main/java/com/alibaba/dashscope/agentstudio/model/Session.java index a0fc5bf..0a09a34 100644 --- a/src/main/java/com/alibaba/dashscope/agentstudio/model/Session.java +++ b/src/main/java/com/alibaba/dashscope/agentstudio/model/Session.java @@ -114,6 +114,15 @@ public static class StopReason { private List pendingCallIds; } + /** + * A resource mounted into a session. Fields depend on {@code type}: {@code file} carries {@code + * fileId}/{@code mountPath}; {@code memory_store} carries {@code memoryStoreId}/{@code + * access}/{@code instructions}/{@code name}/{@code description} and — when {@code provider} is + * {@code agentstudio_memory} — {@code entityId}/{@code projectIds}/{@code profileSchema} (Bailian + * memory mounts carry no mount path); {@code oss} carries {@code region}/{@code bucket}/{@code + * ossPath}/{@code mountPath}/{@code access}. {@code provider} values are not validated so + * historical responses stay readable. Memory and OSS mounts are create-only. + */ @Data @EqualsAndHashCode(callSuper = true) public static class SessionResource extends FlattenResultBase { @@ -126,9 +135,45 @@ public static class SessionResource extends FlattenResultBase { @SerializedName("file_id") private String fileId; + @SerializedName("memory_store_id") + private String memoryStoreId; + + @SerializedName("provider") + private String provider; + + @SerializedName("entity_id") + private String entityId; + + @SerializedName("project_ids") + private List projectIds; + + @SerializedName("profile_schema") + private String profileSchema; + + @SerializedName("access") + private String access; + + @SerializedName("instructions") + private String instructions; + + @SerializedName("name") + private String name; + + @SerializedName("description") + private String description; + @SerializedName("mount_path") private String mountPath; + @SerializedName("region") + private String region; + + @SerializedName("bucket") + private String bucket; + + @SerializedName("oss_path") + private String ossPath; + @SerializedName("created_at") private String createdAt; diff --git a/src/test/java/com/alibaba/dashscope/TestAgentStudioProtocol.java b/src/test/java/com/alibaba/dashscope/TestAgentStudioProtocol.java index 2f9f60e..9b98ab8 100644 --- a/src/test/java/com/alibaba/dashscope/TestAgentStudioProtocol.java +++ b/src/test/java/com/alibaba/dashscope/TestAgentStudioProtocol.java @@ -11,6 +11,7 @@ import com.alibaba.dashscope.agentstudio.message.ContentBlock; import com.alibaba.dashscope.agentstudio.message.Message; import com.alibaba.dashscope.agentstudio.model.Configs; +import com.alibaba.dashscope.agentstudio.model.Mount; import com.alibaba.dashscope.agentstudio.model.Session; import com.alibaba.dashscope.agentstudio.param.AgentCreateParam; import com.alibaba.dashscope.agentstudio.param.SessionEventListParam; @@ -20,6 +21,7 @@ import com.google.gson.JsonObject; import java.io.IOException; import java.util.Arrays; +import java.util.HashSet; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.mockwebserver.MockResponse; @@ -212,4 +214,111 @@ void testPermissionPolicySerializedInToolConfig() { assertEquals( "always_ask", dcJson.getAsJsonObject("permission_policy").get("type").getAsString()); } + + @Test + void testMountUsesWireKeys() { + Mount bailian = + Mount.bailianMemory("0123", "customer_001") + .projectIds(Arrays.asList("fact_rule_1")) + .profileSchema("schema_demo") + .description("ctx") + .readOnly(); + assertEquals( + new HashSet<>( + Arrays.asList( + "type", + "provider", + "memory_store_id", + "entity_id", + "project_ids", + "profile_schema", + "description", + "access")), + bailian.keySet()); + assertEquals("agentstudio_memory", bailian.get("provider")); + assertEquals("read_only", bailian.get("access")); + + Mount oss = Mount.oss("cn-beijing", "bkt", "datasets/", "/data").readOnly(); + assertEquals( + new HashSet<>( + Arrays.asList("type", "region", "bucket", "oss_path", "mount_path", "access")), + oss.keySet()); + } + + @Test + void testToolConfigParamsSerialized() { + Configs.ToolConfig.PerToolConfig perTool = new Configs.ToolConfig.PerToolConfig(); + perTool.setName("search_knowledgebases"); + perTool.setEnabled(true); + java.util.HashMap params = new java.util.HashMap<>(); + params.put("knowledge_application_id", "aid_demo"); + perTool.setParams(params); + + Configs.ToolConfig tool = new Configs.ToolConfig(); + tool.setType("builtin_toolkit"); + tool.setConfigs(Arrays.asList(perTool)); + + JsonObject body = + AgentCreateParam.builder() + .name("rag") + .model("qwen-max") + .tools(Arrays.asList(tool)) + .build() + .getHttpBody(); + JsonObject perToolJson = + body.getAsJsonArray("tools") + .get(0) + .getAsJsonObject() + .getAsJsonArray("configs") + .get(0) + .getAsJsonObject(); + assertEquals( + "aid_demo", + perToolJson.getAsJsonObject("params").get("knowledge_application_id").getAsString()); + + // Read back: Agent.tools keeps params, so read-modify-write resubmits them. + Configs.ToolConfig parsed = + GSON.fromJson(body.getAsJsonArray("tools").get(0), Configs.ToolConfig.class); + assertEquals( + "aid_demo", parsed.getConfigs().get(0).getParams().get("knowledge_application_id")); + } + + @Test + void testSessionResourceParsesMountFields() { + Session.SessionResource memory = + GSON.fromJson( + "{\"id\":\"mount_1\",\"type\":\"memory_store\",\"memory_store_id\":\"0123\"," + + "\"provider\":\"agentstudio_memory\",\"entity_id\":\"customer_001\"," + + "\"project_ids\":[\"fact_rule_1\"],\"profile_schema\":\"schema_demo\"," + + "\"description\":\"ctx\",\"access\":\"read_only\"}", + Session.SessionResource.class); + assertEquals("agentstudio_memory", memory.getProvider()); + assertEquals("customer_001", memory.getEntityId()); + assertEquals(Arrays.asList("fact_rule_1"), memory.getProjectIds()); + assertEquals("schema_demo", memory.getProfileSchema()); + assertEquals("read_only", memory.getAccess()); + assertNull(memory.getMountPath()); + + Session.SessionResource oss = + GSON.fromJson( + "{\"id\":\"sesrsc_1\",\"type\":\"oss\",\"region\":\"cn-beijing\"," + + "\"bucket\":\"agentstudio-ma-oss-mnt\",\"oss_path\":\"datasets/\"," + + "\"mount_path\":\"/data\",\"access\":\"read_only\"}", + Session.SessionResource.class); + assertEquals("cn-beijing", oss.getRegion()); + assertEquals("agentstudio-ma-oss-mnt", oss.getBucket()); + assertEquals("datasets/", oss.getOssPath()); + assertEquals("/data", oss.getMountPath()); + + // Historical built-in mounts predate provider; those fields stay null. + Session.SessionResource legacy = + GSON.fromJson( + "{\"id\":\"mount_2\",\"type\":\"memory_store\",\"memory_store_id\":\"memstore_1\"," + + "\"mount_path\":\"/uploads/memory\"}", + Session.SessionResource.class); + assertNull(legacy.getProvider()); + assertNull(legacy.getEntityId()); + assertEquals("memstore_1", legacy.getMemoryStoreId()); + assertEquals("/uploads/memory", legacy.getMountPath()); + } }