@dsh-agentic-roleplay/state

memorytested: passnpmGPL-3.0-only

Persistent SQLite session state, story memory and recall, repositories, and model-facing record tools for DSH roleplay plugins.

下载量 / Downloads
4,524
依赖体积 / node_modules
469.08 MB
测试时间 / Tested
2026-11-06
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add @dsh-agentic-roleplay/state

Sandbox test results

StageResult
1 install✓
2 list✓
3 mount✓
4 boot—

Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).

README

@dsh-agentic-roleplay/state

The persistent session-state and memory service for DSH Agentic Roleplay, maintained by Firefox2100.

Most users should install @dsh-agentic-roleplay/all. Install this package separately when another DSH plugin needs the roleplay database, repositories, recall engine, or model-facing record tools without the complete roleplay interface.

A DeepSeek Harness plugin that keeps the state of roleplay sessions: one SQLite

database per session, reached through repositories over canonical models. It

does no orchestration and has no UI, so it can be installed on its own to get a

roleplay database and state management without the rest of the roleplay bundle.

Other plugins use it through the roleplayState service. Model-facing tools

are included and can be enabled through its configuration.

Requires DSH 0.2 and Node 22.19 or later (it uses the built-in node:sqlite).

dsh plugin --profile <name> add @dsh-agentic-roleplay/state

Using it from another plugin

import type {} from '@dsh-agentic-roleplay/state'            // types `ctx.roleplayState`
import type { Context } from '@deepseek-ai/cordis'

export const inject = ['roleplayState']

export function apply(ctx: Context) {
  // Creates sessions/<uuid>/session.sqlite and opens it.
  const session = ctx.roleplayState.createSession('/path/to/sessions', {
    name: 'First night',
    world: { id: 'blackwater-observatory', name: 'The Blackwater Observatory' },
  })

  session.transaction(() => {
    const mayor = session.characters.add({ name: 'Eleanor Graves', /* … */ control: 'agent' })
    session.characterStates.create(mayor.id, { publicState: '…', innerState: '…', activity: '…' })
    session.intents.add(mayor.id, { type: 'agenda', name: '…', /* … */ })
  })

  session.characters.findByName('the mayor')       // by name or alias, ignoring case
  session.characterStates.update(1, { activity: 'looking for the key' }, { expectedVersion: 3 })
}

The service creates and opens sessions under a sessions folder you give it,

shares one connection per session, and closes them all when the plugin unloads:

Method · Does

createSession(sessionsDir, init) · Creates the session folder and database and returns its repositories. The id is generated (UUID v4) unless given. Nothing is left behind if it fails.

openSession(sessionsDir, id) · Returns the repositories of an existing session.

listSessions(sessionsDir) · The metadata of every session under the folder (name, world, creation time, last played time, turns). A session that cannot be read is reported in problems, not thrown.

closeSession(sessionsDir, id) · Releases the connection; opening again reconnects.

deleteSession(sessionsDir, id) · Closes the session and removes its folder.

Session ids become folder names, so only a UUID v4 is accepted. The package also

exports the same operations as plain functions (createSession, openSession,

createSessionStore, …) for code that does not run inside DSH, such as tests.

The records API and the model-facing tools

The package owns how a story is remembered, not only where it is stored:

  • session.edit(edit) changes the story's records (character states, events with who took each in, beliefs, threads) together or not at all. It checks the whole edit first and throws InvalidEditError naming every problem, so a model's mistakes can be reported back to it. parseRecordsEdit(json) reads the wire format models write (snake_case) and recordsEditSchema({ characters, changes }) is its JSON schema, for a model's structured output or a tool's parameters.
  • session.records(scope) reads the records back in the same wire format.
  • session.recall({ characterId, situation, turn, policy }) is what a character is reminded of: events it took in and things it believes, by who the situation mentions, shared words and tags, importance and story-time recency; with policy.flaky the older and less important are told as faded or vague, or are gone. Age is elapsed story time from session.clock, never turn count; an unimportant event has a six-story-day half-life. It counts what it brings back as recalled, which makes it last longer.
  • session.recallStored(query, { queryVector? }) adds the session's search index to the cues: texts that match the situation by words and, with the vector of the situation, by meaning. session.searchEvents({ text, vector?, fromTurn, toTurn, minImportance, limit }) finds what happened by the same two searches, merged by reciprocal rank.
  • session.recallRanked(query, signal, { queryVector? }) is the call for anything that reminds a character of something: recall, ranked by meaning when a plugin has registered a ranker with roleplayState.rankMemories(ranker) (an embedding model, a reranker; see docs/capabilities.md). session.recallCandidates(query) gives what could be recalled, with the text to match, for a ranker. With explain: true in the query each recalled thing carries why: the cues of the moment (people named, words shared, place), what each search scored it, how much it matters, how long ago it was, how much of it is left in mind and what it was ranked by.
  • session.knowledge is the closed-world awareness graph for locations, items and directed exits (learn, knows, get, list, forget). Directional relationships are the corresponding character-to-character edges. Awareness grants identity only, not current state or whereabouts. session.planKnownMove plans through only a character's known places and exits; planMove remains the authoritative world planner.
  • session.factions, factionStates, factionMemberships, factionRelationships and factionIntents store persistent organisations separately from characters that act in scenes. Membership is many-to-many; relationships involving factions are directional and double as closed-world awareness e

…(truncated)

Rendered from the README published on npm. Formatted only, not edited.

Versions

Published on npm::28,最后更新 2026-11-05

Links

GitHub · Homepage · npm

Same category