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
94 changes: 94 additions & 0 deletions samples/AgentStudioMemoryStores.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import com.alibaba.dashscope.agentstudio.AgentStudioClient;
import com.alibaba.dashscope.agentstudio.model.AgentStudioDeletionStatus;
import com.alibaba.dashscope.agentstudio.model.Memory;
import com.alibaba.dashscope.agentstudio.model.MemoryStore;
import com.alibaba.dashscope.agentstudio.model.MemoryVersion;
import com.alibaba.dashscope.agentstudio.param.MemoryCreateParam;
import com.alibaba.dashscope.agentstudio.param.MemoryListParam;
import com.alibaba.dashscope.agentstudio.param.MemoryStoreCreateParam;
import com.alibaba.dashscope.agentstudio.param.MemoryStoreListParam;
import com.alibaba.dashscope.agentstudio.param.MemoryUpdateParam;
import com.alibaba.dashscope.agentstudio.param.MemoryVersionListParam;

/**
* Memory store example: seed a store, read it back, audit versions, cleanup.
*
* <p>Set DASHSCOPE_API_KEY and DASHSCOPE_WORKSPACE before running.
*/
public class AgentStudioMemoryStores {

public static void main(String[] args) {
try (AgentStudioClient client = new AgentStudioClient()) {
// 1. Create a store; description is read by the agent - write it for
// the model, not for humans.
MemoryStore store =
client
.memoryStores()
.create(
MemoryStoreCreateParam.builder()
.name("demo-preferences")
.description("Per-user preferences and project context.")
.build());
System.out.printf("store: %s%n", store.getId());

// 2. Seed reference material before any session runs.
Memory memory =
client
.memoryStores()
.memories()
.create(
store.getId(),
MemoryCreateParam.builder()
.path("/formatting_standards.md")
.content("All reports use GAAP formatting.")
.build());
System.out.printf(
"memory: %s %s (%d bytes)%n",
memory.getId(), memory.getPath(), memory.getContentSizeBytes());

// 3. Read back with content (view=full; the default basic is metadata
// only). Print prefixes before iterating: the loop auto-paginates
// and prefixes are per page.
com.alibaba.dashscope.agentstudio.pagination.CursorPage<Memory> page =
client
.memoryStores()
.memories()
.list(store.getId(), MemoryListParam.builder().view("full").build());
System.out.printf("prefixes: %s%n", page.getPrefixes());
for (Memory item : page) {
System.out.printf("%s -> %s%n", item.getPath(), item.getContent());
}

// 4. Update with the optimistic lock (contentSha256 from step 2).
Memory updated =
client
.memoryStores()
.memories()
.update(
store.getId(),
memory.getId(),
MemoryUpdateParam.builder()
.content("All reports use GAAP formatting. ISO-8601 dates.")
.contentSha256(memory.getContentSha256())
.build());
System.out.printf("updated sha: %s%n", updated.getContentSha256());

// 5. Audit history: every mutation produced a memver_ snapshot.
for (MemoryVersion version :
client
.memoryStores()
.memoryVersions()
.list(store.getId(), MemoryVersionListParam.builder().build())) {
System.out.printf("version: %s %s%n", version.getId(), version.getOperation());
}

// 6. List stores and clean up.
for (MemoryStore item :
client.memoryStores().list(MemoryStoreListParam.builder().limit(20).build())) {
System.out.printf("store: %s %s%n", item.getId(), item.getName());
}
AgentStudioDeletionStatus deleted = client.memoryStores().delete(store.getId());
System.out.printf("deleted: %s%n", deleted.getType());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.alibaba.dashscope.agentstudio.resource.Deployments;
import com.alibaba.dashscope.agentstudio.resource.Environments;
import com.alibaba.dashscope.agentstudio.resource.Files;
import com.alibaba.dashscope.agentstudio.resource.MemoryStores;
import com.alibaba.dashscope.agentstudio.resource.Security;
import com.alibaba.dashscope.agentstudio.resource.Sessions;
import com.alibaba.dashscope.agentstudio.resource.Skills;
Expand All @@ -24,6 +25,7 @@ public class AgentStudioClient implements Closeable {
private final Environments environments;
private final Skills skills;
private final Vaults vaults;
private final MemoryStores memoryStores;
private final Files files;
private final WebhookEndpoints webhookEndpoints;
private final Security security;
Expand Down Expand Up @@ -56,6 +58,7 @@ public AgentStudioClient(
this.files = new Files(this.baseUrl, connectionOptions, apiKey);
this.skills = new Skills(this.baseUrl, connectionOptions, apiKey, this.files);
this.vaults = new Vaults(this.baseUrl, connectionOptions, apiKey);
this.memoryStores = new MemoryStores(this.baseUrl, connectionOptions, apiKey);
this.webhookEndpoints = new WebhookEndpoints(this.baseUrl, connectionOptions, apiKey);
this.security = new Security(this.baseUrl, connectionOptions, apiKey);
}
Expand Down Expand Up @@ -129,6 +132,10 @@ public Vaults vaults() {
return vaults;
}

public MemoryStores memoryStores() {
return memoryStores;
}

public Files files() {
return files;
}
Expand Down
49 changes: 49 additions & 0 deletions src/main/java/com/alibaba/dashscope/agentstudio/model/Memory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) Alibaba, Inc. and its affiliates.
package com.alibaba.dashscope.agentstudio.model;

import com.alibaba.dashscope.common.FlattenResultBase;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
* One text document inside a memory store, addressed by {@code path}.
*
* <p>{@code content} appears only in retrieve responses and in list responses with {@code
* view="full"}; create and update never return it. {@code contentSha256} identifies the content
* revision — pass it back to {@code memories().update()} for optimistic concurrency (a mismatch
* returns 409 {@code memory_precondition_failed_error}).
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class Memory extends FlattenResultBase {
@SerializedName("id")
private String id;

@SerializedName("type")
private String type;

@SerializedName("memory_store_id")
private String memoryStoreId;

@SerializedName("path")
private String path;

@SerializedName("content")
private String content;

@SerializedName("content_sha256")
private String contentSha256;

@SerializedName("content_size_bytes")
private Long contentSizeBytes;

@SerializedName("memory_version_id")
private String memoryVersionId;

@SerializedName("created_at")
private String createdAt;

@SerializedName("updated_at")
private String updatedAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) Alibaba, Inc. and its affiliates.
package com.alibaba.dashscope.agentstudio.model;

import com.alibaba.dashscope.common.FlattenResultBase;
import com.google.gson.annotations.SerializedName;
import java.util.Map;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
* A workspace-scoped memory store: a collection of small text documents that persists across
* sessions.
*
* <p>Stores are attached to sessions via the session {@code resources[]} array and mounted into the
* session container at {@code /mnt/memory/<name>/}. {@code archivedAt} is set once the store is
* archived: read-only afterwards, existing session attachments keep working, but new sessions
* cannot reference it.
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class MemoryStore extends FlattenResultBase {
@SerializedName("id")
private String id;

@SerializedName("type")
private String type;

@SerializedName("name")
private String name;

@SerializedName("description")
private String description;

@SerializedName("metadata")
private Map<String, Object> metadata;

@SerializedName("archived_at")
private String archivedAt;

@SerializedName("created_at")
private String createdAt;

@SerializedName("updated_at")
private String updatedAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) Alibaba, Inc. and its affiliates.
package com.alibaba.dashscope.agentstudio.model;

import com.alibaba.dashscope.common.FlattenResultBase;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
* Immutable snapshot produced by every memory mutation; versions are returned newest-first.
*
* <p>{@code operation} is {@code created}, {@code modified} or {@code deleted}. After {@code
* redact()}, {@code path}, {@code content}, {@code contentSha256} and {@code contentSizeBytes} are
* cleared; the audit trail is preserved.
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class MemoryVersion extends FlattenResultBase {
@SerializedName("id")
private String id;

@SerializedName("type")
private String type;

@SerializedName("memory_store_id")
private String memoryStoreId;

@SerializedName("memory_id")
private String memoryId;

@SerializedName("operation")
private String operation;

@SerializedName("path")
private String path;

@SerializedName("content")
private String content;

@SerializedName("content_sha256")
private String contentSha256;

@SerializedName("content_size_bytes")
private Long contentSizeBytes;

@SerializedName("created_at")
private String createdAt;

@SerializedName("redacted_at")
private String redactedAt;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ public class CursorPage<T> extends FlattenResultBase implements Iterable<T> {
@SerializedName("next_page")
private String nextPage;

/** Directory prefixes of a tree-style listing (memory listings only, null elsewhere). */
@SerializedName("prefixes")
private List<String> prefixes;

@EqualsAndHashCode.Exclude
private transient Function<String, CompletableFuture<CursorPage<T>>> fetchNext;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Alibaba, Inc. and its affiliates.
package com.alibaba.dashscope.agentstudio.param;

import com.alibaba.dashscope.base.FlattenHalfDuplexParamBase;
import com.google.gson.JsonObject;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
import lombok.experimental.SuperBuilder;

/**
* Request body for {@code POST /memory_stores/{store_id}/memories}.
*
* <p>{@code path} rules (enforced server-side, case-sensitive): POSIX style with a leading {@code
* /} and no trailing {@code /}; 2..1024 UTF-8 bytes; NFC-normalized; every segment non-empty and
* not {@code .} or {@code ..}; no control / format / line- or paragraph-separator code points.
* {@code content} is UTF-8 text, at most 102400 bytes. A memory already existing at {@code path}
* returns 409 {@code memory_path_conflict_error}.
*/
@Data
@SuperBuilder
@EqualsAndHashCode(callSuper = true)
public class MemoryCreateParam extends FlattenHalfDuplexParamBase {
@NonNull private String path;
@NonNull private String content;

@Override
public JsonObject getHttpBody() {
JsonObject body = new JsonObject();
body.addProperty("path", path);
body.addProperty("content", content);
addExtraBody(body);
return body;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) Alibaba, Inc. and its affiliates.
package com.alibaba.dashscope.agentstudio.param;

import com.alibaba.dashscope.agentstudio.AgentStudioConstants;
import com.alibaba.dashscope.base.FlattenHalfDuplexParamBase;
import com.google.gson.JsonObject;
import lombok.Builder.Default;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.SuperBuilder;

/**
* Query params for {@code GET /memory_stores/{store_id}/memories}.
*
* <p>{@code pathPrefix} scopes the listing (server-validated: must start and end with {@code /} —
* {@code "/notes/"} matches {@code /notes/a.md} but not {@code /notes_backup/old.md}; a bare {@code
* "/"} lists the whole store). {@code view} is {@code basic} (metadata only, the default; {@code
* limit} up to 100) or {@code full} (include {@code content}; {@code limit} is capped at 20 and
* higher values are rejected with 400 — CMA silently clamps instead). {@code depth} is 0/absent
* (flat) or 1 (single-level tree) on the wire; larger values are derived client-side from a flat
* listing (no {@code depth} is sent). With {@code view=full}, the wire still transfers the content
* of files the derivation cuts — prefer {@code basic} for deep walks.
*/
@Data
@SuperBuilder
@EqualsAndHashCode(callSuper = true)
public class MemoryListParam extends FlattenHalfDuplexParamBase {
@Default private String pathPrefix = null;
@Default private Integer depth = null;
@Default private String view = null;
@Default private Integer limit = null;
@Default private String page = null;

@Override
public JsonObject getHttpBody() {
return new JsonObject();
}

public String toQueryString() {
StringBuilder sb = new StringBuilder();
AgentStudioConstants.appendParam(sb, "path_prefix", pathPrefix);
AgentStudioConstants.appendParam(sb, "depth", depth);
AgentStudioConstants.appendParam(sb, "view", view);
AgentStudioConstants.appendParam(sb, "limit", limit);
AgentStudioConstants.appendParam(sb, "page", page);
return sb.toString();
}
}
Loading
Loading