Where did you hear about us?
1 of 6
저장소

저장소 - 만들고, 보고, 지우기.

저장소는 저장·회수의 단위인 user_id - 최종 사용자·에이전트·주제마다 격리된 기억 공간 하나입니다. 저장소는 명시적이라 저장·회수 전에 먼저 만들어야 하고, 아니면 404가 돌아옵니다. 모든 계정엔 default 저장소가 기본으로 있어 만들지 않고도 바로 시작할 수 있습니다.

격리 구조. 계정이 워크스페이스를 갖고, 워크스페이스마다 기억·API 키·사용량이 격리됩니다(결제는 계정 공유). 저장소는 워크스페이스 안에 있어, 같은 워크스페이스의 키는 저장소를 공유하고 다른 워크스페이스끼리는 서로의 기억을 못 봅니다. 계정 → 워크스페이스 → 저장소(user_id) → 기억.
mem.create_store("alice")        # create (idempotent)
mem.list_stores()              # [{"user_id","created_at","canonical_id"?}, ...]
mem.delete_store("alice")        # delete the store + all its memories
await mem.createStore("alice");
await mem.listStores();          // [{ user_id, created_at }, ...]
await mem.deleteStore("alice");     // store + all its memories
mem.create_store("alice").await?;
let stores = mem.list_stores().await?;
mem.delete_store("alice").await?;
# create
curl -X POST https://api.wontopos.com/api/v1/memory/collection \
  -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" -d '{"user_id":"alice"}'
# list
curl https://api.wontopos.com/api/v1/memory/collections -H "X-API-Key: $WOS_API_KEY"
# delete (store + all its memories)
curl -X DELETE https://api.wontopos.com/api/v1/memory/collection \
  -H "X-API-Key: $WOS_API_KEY" -H "Content-Type: application/json" -d '{"user_id":"alice"}'
실제 응답 - create
{ "user_id": "alice", "status": "created" }   // "exists" if it already did
// "canonical_id" and "note" appear when the id is stored in a normalized form
실제 응답 - list
{ "collections": [
  { "user_id": "default", "created_at": "2026-06-26T02:23:14Z" },
  { "user_id": "alice",   "created_at": "2026-06-26T02:24:01Z" }
], "count": 2 }
없는 저장소 회수 시
{ "error": { "type": "not_found_error",
  "message": "Store 'ghost' does not exist in this API key's workspace. …",
  "store": "ghost" } }
사람별로 기억을 나누려면 최종 사용자마다 저장소 하나("alice", "user_42"), 개인 비서라면 default 하나면 됩니다. 코드 없이 콘솔에서도 저장소를 만들고 둘러볼 수 있습니다(Memory ids → Issue). 저장소 삭제는 영구적 - 그 안의 모든 기억이 사라집니다. 저장소 id는 저장 전에 접힙니다. 소문자로 낮추고 [a-z0-9_] 밖의 문자는 _가 되므로 Alice.Smith와 alice-smith는 같은 저장소입니다. 기존 id와 같은 형태로 접히는 두 번째 id는 조용히 공유되지 않고 409로 거절됩니다. id 자체도 [A-Za-z0-9][A-Za-z0-9._-]{0,63}를 만족해야 하므로 이메일 주소나 비라틴 이름은 저장소 id가 될 수 없습니다. 내부 식별자를 사용하십시오.

저장소 준비

Scroll 2는 기억을 그 사람의 하루 위에 놓습니다. "오늘 아침", "어젯밤"처럼 꺼내고, 잠은 하루 단위로 읽습니다. 그러려면 저장소가 그 사람이 사는 시계를 알아야 합니다. 또 대화의 줄마다 누가 말했는지 남기므로, 대화의 두 쪽이 누구인지도 알아야 합니다.

그래서 Scroll 2 저장소는 첫 저장 전에 세 가지를 합니다.

  1. 대화하는 두 사람의 이름을 등록합니다. 사람 쪽과 어시스턴트 쪽입니다.
  2. 저장소의 시간대와, 두 쪽의 기본 이름을 정합니다.
  3. 그다음 저장합니다.

이 준비가 없으면 저장은 거절되고 아무것도 남지 않습니다. 오류에는 무엇이 빠졌는지가 적혀 옵니다(시간대가 없음, 이름이 없음, 등록하지 않은 이름).

from wontopos import Client

mem = Client(api_key="wos-live-...", model="scroll-2")

people = [                                      # store, the person, time zone
    ("jimin", "Jimin", "Asia/Seoul"),           # Korea
    ("emma",  "Emma",  "America/New_York"),     # US East
    ("noah",  "Noah",  "America/Los_Angeles"),  # US West
    ("wei",   "Wei",   "Asia/Shanghai"),        # China
    ("olga",  "Olga",  "Europe/Moscow"),        # Russia
]
for store, name, tz in people:
    mem.create_store(store)
    mem.add_speaker(name, store)                # the person
    mem.add_speaker("Kai", store)               # the assistant
    mem.set_settings(store, time_zone=tz,
                     default_speakers={"user": name, "assistant": "Kai"})
import { Client } from "wontopos";

const mem = new Client({ apiKey: process.env.WOS_API_KEY!, model: "scroll-2" });

const people = [                                // store, the person, time zone
  ["jimin", "Jimin", "Asia/Seoul"],             // Korea
  ["emma",  "Emma",  "America/New_York"],       // US East
  ["noah",  "Noah",  "America/Los_Angeles"],    // US West
  ["wei",   "Wei",   "Asia/Shanghai"],          // China
  ["olga",  "Olga",  "Europe/Moscow"],          // Russia
];
for (const [store, name, timeZone] of people) {
  await mem.createStore(store);
  await mem.addSpeaker(name, store);            // the person
  await mem.addSpeaker("Kai", store);           // the assistant
  await mem.setSettings(store, { timeZone, defaultSpeakers: { user: name, assistant: "Kai" } });
}
use wontopos::{Client, DefaultSpeakers, SettingsOpts};

let mem = Client::new(&std::env::var("WOS_API_KEY")?).with_model("scroll-2");

let people = [                                  // store, the person, time zone
    ("jimin", "Jimin", "Asia/Seoul"),           // Korea
    ("emma",  "Emma",  "America/New_York"),     // US East
    ("noah",  "Noah",  "America/Los_Angeles"),  // US West
    ("wei",   "Wei",   "Asia/Shanghai"),        // China
    ("olga",  "Olga",  "Europe/Moscow"),        // Russia
];
for (store, name, tz) in people {
    mem.create_store(store).await?;
    mem.add_speaker(name, store).await?;        // the person
    mem.add_speaker("Kai", store).await?;       // the assistant
    mem.set_settings(store, &SettingsOpts {
        time_zone: Some(tz.into()),
        default_speakers: Some(DefaultSpeakers {
            user: Some(Some(name.into())),
            assistant: Some(Some("Kai".into())),
        }),
        ..Default::default()
    }).await?;
}
# one store, Seoul: register both names, then the time zone and the defaults
H='-H "X-API-Key: $WOS_API_KEY" -H "X-WOS-Model: scroll-2" -H "Content-Type: application/json"'
curl -X POST https://api.wontopos.com/api/v1/memory/collection $H -d '{"user_id":"jimin"}'
curl -X POST https://api.wontopos.com/api/v1/memory/speakers   $H -d '{"user_id":"jimin","speaker":"Jimin"}'
curl -X POST https://api.wontopos.com/api/v1/memory/speakers   $H -d '{"user_id":"jimin","speaker":"Kai"}'
curl -X POST https://api.wontopos.com/api/v1/memory/settings   $H \
  -d '{"user_id":"jimin","time_zone":"Asia/Seoul","default_speakers":{"user":"Jimin","assistant":"Kai"}}'
응답 - set_settings
{ "changed": ["time_zone", "default_speakers.user", "default_speakers.assistant"],
  "default_speakers": {"assistant": "Kai", "user": "Jimin"},
  "history": [
    { "at": "2026-11-04T00:49:42.327539801Z", "confirmed_by_user": false,
      "field": "speakers", "from": null, "to": "Jimin" },
    { "at": "2026-11-04T00:49:42.764610715Z", "confirmed_by_user": false,
      "field": "speakers", "from": null, "to": "Kai" },
    { "at": "2026-11-04T00:49:43.622615786Z", "confirmed_by_user": false,
      "field": "time_zone", "from": null, "to": "Asia/Seoul" },
    { "at": "2026-11-04T00:49:43.622615786Z", "confirmed_by_user": false,
      "field": "default_speakers.user", "from": null, "to": "Jimin" },
    { "at": "2026-11-04T00:49:43.622615786Z", "confirmed_by_user": false,
      "field": "default_speakers.assistant", "from": null, "to": "Kai" }
  ],
  "required": true,
  "reserved": ["unknown"],
  "speakers": ["Jimin", "Kai"],
  "status": "ok",
  "time_zone": "Asia/Seoul",
  "user_id": "jimin",
  "utc_offset_minutes": 540 }
응답 - 준비 전에 저장했을 때
{ "type": "error",
  "error": { "type": "invalid_request_error",
             "message": "this store has no time zone. Scroll 2 keeps the real time of every memory and shows its age in the user's zone, so a store needs one before anything is stored. Set it once, as the user's IANA zone name: POST /api/v1/memory/settings {\"time_zone\":\"Asia/Seoul\"} with this store's user_id. Nothing was stored.",
             "request_id": "45e3e593-b25e-4827-9ed7-85b662d7c1e4",
             "code": "time_zone_required" } }
// "speaker_required": no name, and no default for that side
// "unknown_speaker":  a name that was never registered

저장할 때 이름은 이렇게 정해집니다

  • 대화 한 번(사람의 말과 어시스턴트의 답)을 저장하면, 두 쪽에 기본 이름이 붙습니다. 그 대화만 다른 이름으로 저장할 수도 있습니다.
  • 한 줄을 저장할 때 이름을 주면 그 사람의 말이 됩니다. "me"라고 주면 어시스턴트의 말, 이름을 안 주면 사람 쪽 기본 이름의 말이 됩니다.
  • 지난 대화를 여러 조각으로 가져오면 조각마다 준 이름이 붙고, 없으면 역할에 맞는 기본 이름이 붙습니다.

시간대는 사람에게 묻고 바꿉니다

이미 정한 시간대를 바꾸려면 "사람이 확인했다"는 표시가 있어야 합니다. 이사나 여행처럼 그 사람의 삶이 바뀐 일이라서, 앱이 혼자 바꾸지 않고 먼저 묻게 하려는 것입니다. 바꾼 기록은 저장소에 남습니다.

시계는 두 가지입니다

  • 저장소의 시간대. "Asia/Seoul" 같은 이름으로 저장소에 남고, 서머타임도 따라갑니다.
  • 호출의 시계. "지금 이 요청은 UTC+1에서 왔다"처럼 호출하는 쪽이 정하는 시간 차입니다. 여행 중인 사람에게 씁니다. 호출에 시계가 없으면 저장소의 시간대를 씁니다.
mem.add_turn("What time is the meeting tomorrow?", "10 a.m.", "jimin")   # Jimin, then Kai
mem.add("Jimin's sister arrives on Friday", "jimin")                    # no name: Jimin
mem.add("I'll remind Jimin on Thursday", "jimin", speaker="me")         # "me": Kai

# Emma moved from New York to Los Angeles and said so: change it with her word
mem.set_settings("emma", time_zone="America/Los_Angeles", confirmed_by_user=True)

# Olga is in Seoul this week: the turns from her trip carry UTC+9
mem.with_tz(9).add_turn("Where should I eat tonight?", "Try the market in Gwangjang.", "olga")
await mem.addTurn("What time is the meeting tomorrow?", "10 a.m.", "jimin");   // Jimin, then Kai
await mem.add("Jimin's sister arrives on Friday", "jimin");                   // no name: Jimin
await mem.add("I'll remind Jimin on Thursday", "jimin", { speaker: "me" });   // "me": Kai

// Emma moved from New York to Los Angeles and said so: change it with her word
await mem.setSettings("emma", { timeZone: "America/Los_Angeles", confirmedByUser: true });

// Olga is in Seoul this week: the turns from her trip carry UTC+9
await mem.withTz(9).addTurn("Where should I eat tonight?", "Try the market in Gwangjang.", "olga");
mem.add_turn("What time is the meeting tomorrow?", "10 a.m.", "jimin").await?;    // Jimin, then Kai
mem.add("Jimin's sister arrives on Friday", "jimin", json!({})).await?;          // no name: Jimin
mem.add("I'll remind Jimin on Thursday", "jimin", json!({"speaker": "me"})).await?; // "me": Kai

// Emma moved from New York to Los Angeles and said so: change it with her word
mem.set_settings("emma", &SettingsOpts {
    time_zone: Some("America/Los_Angeles".into()),
    confirmed_by_user: Some(true),
    ..Default::default()
}).await?;

// Olga is in Seoul this week: the turns from her trip carry UTC+9
mem.with_tz(9.0)?.add_turn("Where should I eat tonight?", "Try the market in Gwangjang.", "olga").await?;
curl -X POST https://api.wontopos.com/api/v1/memory/store-turn $H \
  -d '{"user_id":"jimin","user_msg":"What time is the meeting tomorrow?","assistant_msg":"10 a.m."}'
curl -X POST https://api.wontopos.com/api/v1/memory/settings $H \
  -d '{"user_id":"emma","time_zone":"America/Los_Angeles","confirmed_by_user":true}'
curl -X POST https://api.wontopos.com/api/v1/memory/store-turn $H \
  -d '{"user_id":"olga","user_msg":"Where should I eat tonight?","assistant_msg":"Try the market in Gwangjang.","tz_offset_minutes":540}'

저장소 목록과 삭제

mem.list_stores()                # [{"user_id","created_at","canonical_id"?}, …]
mem.delete_store("alice")      # the store and every memory in it
await mem.listStores();
await mem.deleteStore("alice");
let stores = mem.list_stores().await?;
mem.delete_store("alice").await?;
curl           .../api/v1/memory/collections
curl -X DELETE .../api/v1/memory/collection  -d '{"user_id":"alice"}'