lewnpc
v0.1.0
Published
Persistent memory and stable personality for game NPCs. One API. Lewis underneath.
Maintainers
Readme
lewnpc
NPCs that remember. Dialogue that levels up.
Drop-in persistent memory and stable personality for game characters. One NPM package. One API call. Your NPC remembers every player, evolves every session, and never breaks character.
→ lewnpc.com · Get API Key · Docs
Install
npm install lewnpcQuick start
import { LewNPC } from 'lewnpc';
const client = new LewNPC({
apiKey: process.env.LEWNPC_API_KEY,
});
// Create an NPC with Big Five personality traits
const edric = await client.createNPC({
id: "edric_blacksmith",
role: "Village blacksmith and veteran of the Northern War",
backstory: "Lost his partner Maren to an avalanche on the northern pass. Quiet but warm once trust is earned.",
traits: {
openness: 0.3, // Traditional, practical
conscientiousness: 0.8, // Meticulous craftsman
extraversion: 0.5, // Opens up over time
agreeableness: 0.7, // Kind but not a pushover
neuroticism: 0.2, // Steady, rarely rattled
},
});
// Send a player message
const response = await client.message({
npc_id: "edric_blacksmith",
player_id: "player_7f2a",
message: "I need a sword for the northern pass.",
});
console.log(response.text);
// "The northern pass? That route's been closed since the avalanche took
// Maren's caravan. I can forge you a short blade — but you'll want a
// cloak more than a sword up there."
console.log(response.emotion); // "concerned"
console.log(response.memory_delta); // ["Player intends to travel the northern pass", ...]
console.log(response.memory_count); // 2
console.log(response.latency_ms); // 174The NPC remembers
// Next session — same npc_id + player_id, different day
const laterResponse = await client.message({
npc_id: "edric_blacksmith",
player_id: "player_7f2a",
message: "I made it back from the pass.",
});
console.log(laterResponse.text);
// "Ha! Told you about the cloak, didn't I? Maren would've said the same —
// she knew those mountains better than anyone. Come, let me see that blade."
console.log(laterResponse.emotion); // "warm"No special setup. No session management. The NPC remembers because the API stores what it learned.
API
new LewNPC(config)
const client = new LewNPC({
apiKey: string, // required — get one at lewnpc.com
baseUrl?: string, // default: https://api.lewnpc.com/v1
timeout?: number, // default: 30000ms
});client.createNPC(params)
Create a character. Trait scores shape every response the character ever gives.
await client.createNPC({
id: string, // unique ID — you choose it
role: string, // character role/title
backstory?: string, // optional backstory
traits: {
openness: number, // 0.0–1.0
conscientiousness: number,
extraversion: number,
agreeableness: number,
neuroticism: number,
},
initial_memories?: string[], // optional seed memories
metadata?: object, // arbitrary data, not used by model
});client.message(params) → MessageResponse
Send a player message and get a response. This is the main method.
await client.message({
npc_id: string, // which NPC
player_id: string, // which player — memory is per (npc, player) pair
message: string, // the player's message
context?: string, // optional per-turn context ("Player just defeated the boss")
temperature?: number, // default: 0.7
max_tokens?: number, // default: 512
});Response:
{
text: string, // the NPC's dialogue
emotion: string, // current emotional state ("warm", "concerned", "nostalgic", ...)
memory_delta: string[], // what the NPC learned this turn
memory_count: number, // total memories held for this player
latency_ms: number, // actual inference time
model: string, // "lewis-2.0"
}client.listMemories(params) → ListMemoriesResponse
Inspect everything an NPC remembers about a player.
const { memories, total } = await client.listMemories({
npc_id: "edric_blacksmith",
player_id: "player_7f2a",
limit: 50, // optional, default 50
offset: 0, // optional, for pagination
});
memories.forEach(m => console.log(`[Turn ${m.turn}] ${m.content}`));
// [Turn 1] Player intends to travel the northern pass
// [Turn 1] Player may not know about the avalanche
// [Turn 3] Player survived the northern pass
// [Turn 3] Relationship: strengthening — shared experienceclient.resetMemory(params)
Reset a player's memory with an NPC. The NPC will treat their next message as a first meeting.
await client.resetMemory({
npc_id: "edric_blacksmith",
player_id: "player_7f2a",
});client.getNPC(id) / client.listNPCs() / client.deleteNPC(id)
Standard CRUD.
Error handling
import { LewNPC, LewNPCError, LewNPCRateLimitError, LewNPCAuthError } from 'lewnpc';
try {
const response = await client.message({ ... });
} catch (err) {
if (err instanceof LewNPCAuthError) {
console.error("Invalid API key — get one at lewnpc.com");
} else if (err instanceof LewNPCRateLimitError) {
console.error(`Rate limited. Retry after ${err.retryAfter}s`);
} else if (err instanceof LewNPCError) {
console.error(`LewNPC error ${err.status}: ${err.message} (${err.code})`);
} else {
throw err;
}
}The Big Five
LewNPC uses the Big Five (OCEAN) model for personality. All scores are floats between 0.0 and 1.0.
| Trait | Low (0.0) | High (1.0) | |---|---|---| | Openness | Practical, conventional, prefers routine | Curious, creative, open to new ideas | | Conscientiousness | Flexible, spontaneous, disorganized | Organized, reliable, goal-directed | | Extraversion | Reserved, solitary, quiet | Outgoing, energetic, talkative | | Agreeableness | Competitive, critical, blunt | Cooperative, warm, empathetic | | Neuroticism | Calm, stable, resilient | Anxious, moody, easily stressed |
Traits are stable across the lifetime of a character. They don't drift. A blacksmith with neuroticism: 0.2 stays steady whether it's their first interaction or their thousandth.
Powered by Lewis
LewNPC runs on Lewis — an 8B parameter language model fine-tuned on 1M+ behavioral interactions from Swarmgram's 20,000-agent social simulation. Not a prompt wrapper on GPT-4. A purpose-built behavioral model.
Pricing
- Free: 3 NPCs, 1,000 messages/month
- Pro: $29/month — unlimited NPCs, 50K messages/month
License
MIT — see LICENSE
