@steamory-agent-kit/gum
v0.2.0
Published
Node.js SDK for the Gum service.
Readme
Contents
Features
- Fully typed TypeScript API.
- ESM and CommonJS builds.
- Works on Node.js 18+ with the built-in Fetch API.
- Optional custom
fetchimplementation for tests, proxies, and custom runtimes. - Automatic
Dateserialization and undefined-value cleanup for request bodies. - Request timeout support with typed API errors, connection errors, and timeout errors.
Getting Started
Installation
# Install the SDK from npm.
npm install @steamory-agent-kit/gumQuick Start
import { GumClient } from "@steamory-agent-kit/gum";
// Create a Gum client with your server-side API key.
const gum = new GumClient({
apiKey: process.env.GUM_API_KEY!,
});
// Initialize a memory session for one user conversation.
const session = await gum.sessions.init({
user_id: "user_id_xxxxx",
session_id: "session_id_xxxxx",
});
// Add the conversation turns that Gum should use as memory.
await session.addMessages([
{
role: "user",
content:
"I'm setting up regular check-ins for our Europe team. Let's use Berlin as the city for that group.",
},
{
role: "assistant",
content:
"Got it. I will use Berlin when you mention the Europe team.",
},
{
role: "user",
content:
"For the Americas team, Toronto is usually the city I want to use.",
},
]);
// Retrieve relevant memory before the next assistant response.
const memory = await session.getMemory({
query: "which city should be used for Europe or Americas team scheduling",
});
console.log(memory.data);Show Demo: Team Scheduling Assistant
This example shows a realistic turn lifecycle for an AI scheduling assistant: retrieve memory before calling your model, then write the new conversation back after the reply. The user does not need to repeat that Europe team scheduling usually uses Berlin, while Americas team scheduling usually uses Toronto.
import { GumClient } from "@steamory-agent-kit/gum";
const gum = new GumClient({
apiKey: process.env.GUM_API_KEY!,
});
// Initialize this once for a new conversation, then store session.id.
const session = await gum.sessions.init({
user_id: "user_id_xxxxxx",
session_id: "session_id_xxxxxx",
title: "Team scheduling session",
});
async function schedulingAssistantTurn(userContent: string) {
// 1. SEARCH: retrieve relevant memory before calling your model.
const memory = await session.getMemory({
query: userContent,
details: true,
});
// 2. PROMPT: inject the recalled memory into your model context.
const systemPrompt = `
You are a team scheduling assistant.
Known user preferences:
${JSON.stringify(memory.data ?? {}, null, 2)}
Use these preferences naturally when answering.
`;
// 3. LLM: replace this with OpenAI, Anthropic, Gemini, or your own model call.
const assistantReply = await callYourLLM(systemPrompt, userContent);
// 4. ADD: write the new turn back to Gum without blocking the response.
void session.addMessages([
{ role: "user", content: userContent },
{ role: "assistant", content: assistantReply },
]).catch((error) => {
console.error("Gum memory write failed", error);
});
return assistantReply;
}Example flow:
await schedulingAssistantTurn(
"For recurring team check-ins, use Berlin when I mention Europe and Toronto when I mention the Americas.",
);
await schedulingAssistantTurn(
"Can you schedule the next sync for the region we discussed?",
);Configuration
import { GumClient } from "@steamory-agent-kit/gum";
// Configure the client host and default timeout.
const gum = new GumClient({
apiKey: process.env.GUM_API_KEY!,
host: "gum.asix.inc",
timeoutMs: 30_000,
});| Option | Type | Default | Description |
| --- | --- | --- | --- |
| apiKey | string | Required | Gum API key. The SDK sends it as Authorization: Api-Key <apiKey>. Passing a value that already starts with Api-Key is also supported. |
| host | string | gum.asix.inc | Gum service host override. Plain host values are normalized to HTTPS, so gum.asix.inc becomes https://gum.asix.inc. Explicit http:// or https:// URLs are preserved. |
| timeoutMs | number | 30000 | Default request timeout in milliseconds. Set to 0 to disable the SDK timeout. |
| fetch | FetchLike | globalThis.fetch | Custom Fetch-compatible implementation for tests, proxies, or custom runtimes. |
API Reference
Client
new GumClient(options)
Creates a client instance. The client exposes resource groups under
gum.sessions and gum.userActions.
// Create a Gum client with the required API key.
const gum = new GumClient({
apiKey: "gum_api_key",
});gum.health(options?)
Checks the Gum service health endpoint.
// Check the Gum service health endpoint.
const health = await gum.health();Sessions
gum.sessions.init(input, options?)
Initializes a Session and returns a Session object. Pass a creation request
to create a new Session through the Gum API, or pass an existing Session id to
rebuild the local object-style API without a network request. The object exposes
the Session id and convenience methods that automatically use that id.
input.user_id and input.session_id are required when creating a new Session.
// Create a new Session and inspect the returned helper.
const session = await gum.sessions.init({
user_id: "user_123",
session_id: "session_123",
title: "Team scheduling session",
metadata: {
source: "assistant-api",
channel: "web-chat",
},
});
console.log(session.id);
console.log(session.rawResponse);If Gum returns a successful response without data.session_id, the SDK throws
Error: Gum API did not return data.session_id.
// Rebuild a Session helper from an existing Session id.
const session = await gum.sessions.init("session_123");
await session.addMessage({
role: "user",
content: "Continue where we left off. If I mention a region, use the city we picked for that team.",
});
const memory = await session.getMemory({
query: "which city should be used for the user's team scheduling request",
});session.addMessage(message, options?)
Adds one message to the created Session.
// Append one message to the Session.
await session.addMessage({
role: "user",
content:
"For the Americas team, I usually coordinate from Toronto.",
});session.addMessages(input, options?)
Adds messages to the created Session. input can be either a direct message
array or an object with a messages property.
// Append messages with the array shorthand.
await session.addMessages([
{
role: "user",
content:
"For the Europe team check-in, keep Berlin as the city we are working from.",
},
{
role: "assistant",
content:
"Understood. I will use Berlin for Europe team scheduling and Toronto for the Americas team.",
},
]);
// Append messages with the object form.
await session.addMessages({
messages: [
{
role: "user",
content:
"That works for me: Berlin when I mention Europe, and Toronto when I mention the Americas.",
metadata: {
channel: "chat",
},
},
],
});session.getMemory(params?, options?)
Retrieves memory for the created Session. Pass query to focus the retrieval
and details to include detailed memory data when the API supports it.
const memory = await session.getMemory({
query: "which city should be used for Europe or Americas team scheduling",
details: true,
});Pass recall_config to override memory recall behavior. When
recall_config is present, the SDK uses the POST context endpoint so the
configuration can be sent as a JSON body.
const memory = await session.getMemory({
query: "which city should be used for the user's team scheduling request",
details: true,
recall_config: {
message_recent_limit: 20,
message_semantic_top_k: 8,
query_router: "single_hop_parallel",
enable_long_term_recall: false,
},
});gum.sessions.addMessages(sessionId, input, options?)
Lower-level API for adding messages when you already have a Session id.
input can be either a direct message array or an object with a messages
property.
// Append messages by Session id with the array shorthand.
await gum.sessions.addMessages("session_123", [
{
role: "user",
content:
"Use the Europe city we discussed and draft the agenda for the next team check-in.",
},
{
role: "assistant",
content:
"I will use Berlin for that check-in and keep the agenda focused on project updates.",
},
]);
// Append messages by Session id with the object form.
await gum.sessions.addMessages("session_123", {
messages: [
{
role: "user",
content:
"That works for me: Berlin when I mention Europe, and Toronto when I mention the Americas.",
metadata: {
channel: "chat",
},
},
],
});gum.sessions.getMemory(sessionId, params?, options?)
Lower-level API for retrieving memory when you already have a Session id. Pass
query to focus the retrieval and details to include detailed memory data
when the API supports it.
const memory = await gum.sessions.getMemory("session_123", {
query: "which city should be used for Europe or Americas team scheduling",
details: true,
});As with session.getMemory, this lower-level method automatically uses the
POST context endpoint when recall_config is present.
User Actions
gum.userActions.create(input, options?)
Creates one user action log.
// Write a user action event with optional anchors and metadata.
await gum.userActions.create({
user_id: "user_123",
timestamp: new Date(),
content: "User opened the Europe team scheduling page",
session_id: "session_123",
event_type: "page_view",
page: "team_scheduling",
anchors: {
region: "Europe",
city: "Berlin",
},
metadata: {
source: "assistant-api",
},
});Runtime Contracts
Request Options
Every SDK method accepts optional request options as its last argument.
// Override timeout, abort signal, and headers for one request.
const controller = new AbortController();
await gum.sessions.getMemory(
"session_123",
{ query: "which city should be used for the user's team scheduling request" },
{
timeoutMs: 5_000,
signal: controller.signal,
headers: {
"X-Request-Id": "request_123",
},
},
);| Option | Type | Description |
| --- | --- | --- |
| timeoutMs | number | Overrides the client timeout for one request. |
| signal | AbortSignal | External abort signal. |
| headers | HeadersInit | Additional request headers. |
Response Shape
Resource methods return the Gum response envelope:
// Resource methods return this generic Gum response envelope.
type GumEnvelope<T = unknown> = {
data?: T;
success?: boolean;
message?: string;
error?: unknown;
[key: string]: unknown;
};For example, gum.sessions.init() returns Promise<Session>. The Session id
is available as session.id, and session.rawResponse preserves the original
create response envelope for new Sessions. When initialized from an existing id,
rawResponse is synthetic and shaped as { data: { session_id: sessionId } }.
This is a breaking change from earlier 0.x versions where gum.sessions.create()
and gum.sessions.fromId() were separate public methods.
Error Handling
import {
GumApiError,
GumConnectionError,
GumTimeoutError,
} from "@steamory-agent-kit/gum";
// Handle SDK error types explicitly.
try {
await gum.sessions.init({
user_id: "user_123",
session_id: "session_123",
title: "Team scheduling session",
});
} catch (error) {
if (error instanceof GumApiError) {
console.error(error.status, error.detail, error.body);
} else if (error instanceof GumTimeoutError) {
console.error(`Request timed out after ${error.timeoutMs}ms`);
} else if (error instanceof GumConnectionError) {
console.error("Network or fetch failure", error.cause);
} else {
throw error;
}
}| Error | When it is thrown |
| --- | --- |
| GumApiError | Gum returns a non-2xx response. Includes status, statusText, headers, body, and detail. |
| GumConnectionError | The underlying fetch request fails before a response is received. |
| GumTimeoutError | A request is aborted by timeout or an AbortSignal. Extends GumConnectionError. |
TypeScript
The package ships generated type declarations. Public types are exported from the package root:
// Import public SDK TypeScript types from the package root.
import type {
ActionLogInput,
GumClientOptions,
Message,
RecallConfig,
Session,
SessionMemory,
} from "@steamory-agent-kit/gum";Session public types use the same naming as the gum.sessions resource group.
Project
Development
# Install dependencies, verify types, run tests, and build the package.
npm install
npm run typecheck
npm test
npm run test:coverage
npm run buildPublishing
The repository includes a .gitlab-ci.yml pipeline for verifying, building, and
publishing this SDK to npm.
GitLab requirements:
- Add a masked and protected CI/CD variable named
NPM_TOKEN. NPM_TOKENmust contain an npm granular access token with publish permission for@steamory-agent-kit/gum.- If the npm account or package requires 2FA for publishing, create the token
with bypass 2FA enabled. Otherwise the publish job will fail with
EOTP. - For a one-off manual publish with a non-bypass token, run the
publishjob manually and add a temporaryNPM_OTPvariable containing the current authenticator code.
Pipeline flow:
# Verify and publish the package from CI.
npm ci
npm run typecheck
npm test
npm run build
npm pack --dry-run
npm publish --access public --tag latestThe publish job runs automatically for Git tags and can be run manually from the
default branch. Automatic tag publishing requires an NPM_TOKEN that can publish
without an interactive OTP prompt. Before publishing, update the version in
package.json. npm does not allow publishing the same package version twice.
Contributing
Issues and pull requests are welcome. For code changes, please run the local checks before opening a pull request:
# Run the core local checks before opening a pull request.
npm run typecheck
npm test
npm run buildLicense
MIT
