- Add tunnel.sh for SSH tunneling to vLLM server (port 8000 is firewalled, tunnel required for local dev) - Add dev:tunnel script to package.json for running dev with tunnel - Add SYNAP_SPACE env var support to synap.ts, sends X-Memory-Space-Id header when set - Fix SSR hydration mismatch in person-switcher by deferring personId render until client mount Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
164 lines
3.7 KiB
TypeScript
164 lines
3.7 KiB
TypeScript
const SYNAP_URL =
|
|
process.env.SYNAP_URL ?? "https://api.synap.orchard9.ai";
|
|
const SYNAP_API_KEY = process.env.SYNAP_API_KEY ?? "";
|
|
const SYNAP_SPACE = process.env.SYNAP_SPACE ?? "";
|
|
|
|
// --- Response types ---
|
|
|
|
export interface SynapConfidence {
|
|
value: number;
|
|
category: string;
|
|
}
|
|
|
|
export interface SynapMessageResponse {
|
|
message_id: string;
|
|
stored_at: string;
|
|
activated_memories?: SynapActivatedMemory[];
|
|
}
|
|
|
|
export interface SynapActivatedMemory {
|
|
id: string;
|
|
content: string;
|
|
confidence: SynapConfidence;
|
|
}
|
|
|
|
export interface SynapMessage {
|
|
id: string;
|
|
user_id: string;
|
|
content: string;
|
|
timestamp: string;
|
|
}
|
|
|
|
export interface SynapMessagesResponse {
|
|
messages: SynapMessage[];
|
|
activated_memories?: SynapActivatedMemory[];
|
|
pagination: { offset: number; limit: number; returned: number };
|
|
}
|
|
|
|
export interface SynapRecallMemory {
|
|
id: string;
|
|
content: string;
|
|
confidence: SynapConfidence;
|
|
activation_level: number;
|
|
}
|
|
|
|
export interface SynapRecallResponse {
|
|
memories: {
|
|
vivid: SynapRecallMemory[];
|
|
associated: SynapRecallMemory[];
|
|
reconstructed: SynapRecallMemory[];
|
|
};
|
|
recall_confidence: SynapConfidence;
|
|
}
|
|
|
|
export interface SynapRememberResponse {
|
|
memory_id: string;
|
|
observed_at: string;
|
|
stored_at: string;
|
|
storage_confidence: SynapConfidence;
|
|
}
|
|
|
|
// --- Client ---
|
|
|
|
async function request<T>(
|
|
path: string,
|
|
init?: RequestInit
|
|
): Promise<T> {
|
|
const res = await fetch(`${SYNAP_URL}${path}`, {
|
|
...init,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Authorization: `Bearer ${SYNAP_API_KEY}`,
|
|
...(SYNAP_SPACE ? { "X-Memory-Space-Id": SYNAP_SPACE } : {}),
|
|
...init?.headers,
|
|
},
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const body = await res.text().catch(() => "");
|
|
throw new Error(`Synap ${res.status}: ${body}`);
|
|
}
|
|
|
|
return res.json();
|
|
}
|
|
|
|
/** Store a message in a conversation. */
|
|
export function sendMessage(
|
|
userId: string,
|
|
message: string,
|
|
conversationId: string
|
|
): Promise<SynapMessageResponse> {
|
|
return request("/api/v1/messages", {
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
user_id: userId,
|
|
message,
|
|
conversation_id: conversationId,
|
|
}),
|
|
});
|
|
}
|
|
|
|
/** Retrieve messages for a conversation. */
|
|
export function getMessages(
|
|
conversationId: string,
|
|
limit = 50,
|
|
offset = 0
|
|
): Promise<SynapMessagesResponse> {
|
|
const params = new URLSearchParams({
|
|
conversation_id: conversationId,
|
|
limit: String(limit),
|
|
offset: String(offset),
|
|
});
|
|
return request(`/api/v1/messages?${params}`);
|
|
}
|
|
|
|
/** Recall relevant memories by natural language query. */
|
|
export function recall(
|
|
query: string,
|
|
maxResults = 5,
|
|
threshold = 0.5
|
|
): Promise<SynapRecallResponse> {
|
|
const params = new URLSearchParams({
|
|
query,
|
|
max_results: String(maxResults),
|
|
threshold: String(threshold),
|
|
});
|
|
return request(`/api/v1/memories/recall?${params}`);
|
|
}
|
|
|
|
/** Recall memories filtered by tags. */
|
|
export function recallByTag(
|
|
query: string,
|
|
tags: string[],
|
|
maxResults = 10,
|
|
threshold = 0.3
|
|
): Promise<SynapRecallResponse> {
|
|
const params = new URLSearchParams({
|
|
query,
|
|
max_results: String(maxResults),
|
|
threshold: String(threshold),
|
|
tags: tags.join(","),
|
|
});
|
|
return request(`/api/v1/memories/recall?${params}`);
|
|
}
|
|
|
|
/** Store a new memory. */
|
|
export function remember(
|
|
content: string,
|
|
opts: {
|
|
confidence?: number;
|
|
memoryType?: "semantic" | "episodic" | "procedural";
|
|
tags?: string[];
|
|
} = {}
|
|
): Promise<SynapRememberResponse> {
|
|
return request("/api/v1/memories/remember", {
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
content,
|
|
confidence: opts.confidence ?? 0.7,
|
|
memory_type: opts.memoryType ?? "semantic",
|
|
tags: opts.tags,
|
|
}),
|
|
});
|
|
}
|