@hasna/mementos 0.16.0 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -14
- package/dist/cli/commands/agent.d.ts.map +1 -1
- package/dist/cli/commands/consolidation.d.ts.map +1 -1
- package/dist/cli/commands/decisions.d.ts +5 -0
- package/dist/cli/commands/decisions.d.ts.map +1 -0
- package/dist/cli/commands/io-export.d.ts.map +1 -1
- package/dist/cli/commands/io-restore.d.ts.map +1 -1
- package/dist/cli/commands/memory-cmd-crud.d.ts.map +1 -1
- package/dist/cli/commands/memory-cmd-list.d.ts +1 -1
- package/dist/cli/commands/memory-cmd-list.d.ts.map +1 -1
- package/dist/cli/commands/memory-cmd-recall.d.ts.map +1 -1
- package/dist/cli/commands/memory-cmd-remove.d.ts.map +1 -1
- package/dist/cli/commands/memory-cmd-search.d.ts.map +1 -1
- package/dist/cli/commands/memory-cmd-view.d.ts.map +1 -1
- package/dist/cli/commands/memory-cmd-when-to-use.d.ts.map +1 -1
- package/dist/cli/commands/project.d.ts.map +1 -1
- package/dist/cli/commands/system-status.d.ts.map +1 -1
- package/dist/cli/helpers.d.ts +3 -1
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/index.js +990 -113
- package/dist/cli/register-all.d.ts.map +1 -1
- package/dist/cli/structured-json.d.ts +54 -0
- package/dist/cli/structured-json.d.ts.map +1 -0
- package/dist/decisions/index.d.ts +17 -0
- package/dist/decisions/index.d.ts.map +1 -0
- package/dist/decisions/openrouter.d.ts +12 -0
- package/dist/decisions/openrouter.d.ts.map +1 -0
- package/dist/decisions/settings.d.ts +11 -0
- package/dist/decisions/settings.d.ts.map +1 -0
- package/dist/decisions/types.d.ts +70 -0
- package/dist/decisions/types.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +305 -13
- package/dist/lib/conversations-transport.d.ts +21 -0
- package/dist/lib/conversations-transport.d.ts.map +1 -0
- package/dist/lib/export-v1.d.ts +2 -0
- package/dist/lib/export-v1.d.ts.map +1 -1
- package/dist/mcp/index.js +275 -70
- package/dist/mcp/memory-broadcast.d.ts +6 -8
- package/dist/mcp/memory-broadcast.d.ts.map +1 -1
- package/dist/mcp/tools/bounded-output.d.ts +27 -0
- package/dist/mcp/tools/bounded-output.d.ts.map +1 -0
- package/dist/mcp/tools/lock-tools.d.ts.map +1 -1
- package/dist/mcp/tools/memory-inject.d.ts.map +1 -1
- package/dist/mcp/tools/memory-io.d.ts.map +1 -1
- package/dist/mcp/tools/utility-tools.d.ts.map +1 -1
- package/dist/sdk/index.d.ts +2 -1
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +348 -6
- package/package.json +1 -1
package/dist/mcp/index.js
CHANGED
|
@@ -12917,38 +12917,102 @@ var init_zod = __esm(() => {
|
|
|
12917
12917
|
init_external();
|
|
12918
12918
|
});
|
|
12919
12919
|
|
|
12920
|
+
// src/lib/conversations-transport.ts
|
|
12921
|
+
import {
|
|
12922
|
+
clientTransportEnvKeys as clientTransportEnvKeys3,
|
|
12923
|
+
resolveClientTransport as resolveClientTransport2,
|
|
12924
|
+
resolveCredential as resolveCredential2,
|
|
12925
|
+
toV1BaseUrl as toV1BaseUrl2
|
|
12926
|
+
} from "@hasna/contracts/client";
|
|
12927
|
+
function explicitApiUrl(env2) {
|
|
12928
|
+
const keys = clientTransportEnvKeys3("conversations").apiUrlKeys;
|
|
12929
|
+
for (const key of keys) {
|
|
12930
|
+
const value = env2[key]?.trim();
|
|
12931
|
+
if (value)
|
|
12932
|
+
return value;
|
|
12933
|
+
}
|
|
12934
|
+
return;
|
|
12935
|
+
}
|
|
12936
|
+
function isLoopbackUrl(value) {
|
|
12937
|
+
try {
|
|
12938
|
+
const host = new URL(value).hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
12939
|
+
return host === "localhost" || host === "::1" || /^127\./.test(host);
|
|
12940
|
+
} catch {
|
|
12941
|
+
return false;
|
|
12942
|
+
}
|
|
12943
|
+
}
|
|
12944
|
+
function resolveConversationsTransport(options = {}) {
|
|
12945
|
+
const env2 = options.env ?? process.env;
|
|
12946
|
+
const explicitUrl = explicitApiUrl(env2);
|
|
12947
|
+
if (explicitUrl && isLoopbackUrl(explicitUrl)) {
|
|
12948
|
+
return {
|
|
12949
|
+
baseUrl: toV1BaseUrl2(explicitUrl),
|
|
12950
|
+
apiKey: null,
|
|
12951
|
+
localExplicit: true,
|
|
12952
|
+
fetch: options.fetch ?? globalThis.fetch.bind(globalThis)
|
|
12953
|
+
};
|
|
12954
|
+
}
|
|
12955
|
+
const credential = resolveCredential2("conversations", env2, options.credentials ?? {});
|
|
12956
|
+
if (!credential) {
|
|
12957
|
+
throw new Error("Conversations notifications require a hosted credential from the Keychain, ~/.hasna/conversations/config/credentials, or HASNA_CONVERSATIONS_API_KEY; refusing localhost fallback");
|
|
12958
|
+
}
|
|
12959
|
+
const resolution = resolveClientTransport2("conversations", env2, {
|
|
12960
|
+
credentials: { ...options.credentials ?? {}, apiKey: credential.apiKey }
|
|
12961
|
+
});
|
|
12962
|
+
return {
|
|
12963
|
+
baseUrl: toV1BaseUrl2(resolution.baseUrl),
|
|
12964
|
+
apiKey: credential.apiKey,
|
|
12965
|
+
localExplicit: false,
|
|
12966
|
+
fetch: options.fetch ?? globalThis.fetch.bind(globalThis)
|
|
12967
|
+
};
|
|
12968
|
+
}
|
|
12969
|
+
async function conversationsRequest(path, init = {}, options = {}) {
|
|
12970
|
+
const transport = resolveConversationsTransport(options);
|
|
12971
|
+
const headers = new Headers(init.headers ?? {});
|
|
12972
|
+
if (transport.apiKey) {
|
|
12973
|
+
headers.set("x-api-key", transport.apiKey);
|
|
12974
|
+
headers.set("Authorization", `Bearer ${transport.apiKey}`);
|
|
12975
|
+
}
|
|
12976
|
+
const route = path.startsWith("/") ? path : `/${path}`;
|
|
12977
|
+
return transport.fetch(`${transport.baseUrl}${route}`, { ...init, headers });
|
|
12978
|
+
}
|
|
12979
|
+
var init_conversations_transport = () => {};
|
|
12980
|
+
|
|
12920
12981
|
// src/mcp/memory-broadcast.ts
|
|
12921
12982
|
var exports_memory_broadcast = {};
|
|
12922
12983
|
__export(exports_memory_broadcast, {
|
|
12923
12984
|
broadcastSharedMemory: () => broadcastSharedMemory
|
|
12924
12985
|
});
|
|
12925
|
-
async function broadcastSharedMemory(memory, savingAgentId) {
|
|
12986
|
+
async function broadcastSharedMemory(memory, savingAgentId, transport = {}) {
|
|
12926
12987
|
if (!memory.project_id)
|
|
12927
12988
|
return;
|
|
12928
12989
|
try {
|
|
12929
|
-
const
|
|
12930
|
-
|
|
12990
|
+
const query = new URLSearchParams({
|
|
12991
|
+
online_only: "true",
|
|
12992
|
+
project_id: memory.project_id
|
|
12931
12993
|
});
|
|
12994
|
+
const listRes = await conversationsRequest(`/agents?${query}`, {
|
|
12995
|
+
signal: AbortSignal.timeout(3000)
|
|
12996
|
+
}, transport);
|
|
12932
12997
|
if (!listRes.ok)
|
|
12933
12998
|
return;
|
|
12934
12999
|
const { agents } = await listRes.json();
|
|
12935
|
-
|
|
12936
|
-
|
|
12937
|
-
const otherAgents = agents.filter((a) => a.id !== savingAgentId);
|
|
12938
|
-
if (!otherAgents.length)
|
|
13000
|
+
const otherAgents = (agents ?? []).filter((agent) => agent.id !== savingAgentId);
|
|
13001
|
+
if (otherAgents.length === 0)
|
|
12939
13002
|
return;
|
|
12940
13003
|
const notification = `[Memory Update] Agent ${savingAgentId} saved shared memory: "${memory.key}" \u2014 ${memory.summary || memory.value.slice(0, 100)}. Consider recalling this memory if relevant to your current task.`;
|
|
12941
|
-
await Promise.all(otherAgents.map((agent) =>
|
|
13004
|
+
await Promise.all(otherAgents.map((agent) => conversationsRequest("/messages", {
|
|
12942
13005
|
method: "POST",
|
|
12943
13006
|
headers: { "Content-Type": "application/json" },
|
|
12944
13007
|
body: JSON.stringify({ from: savingAgentId, to: agent.id, content: notification }),
|
|
12945
13008
|
signal: AbortSignal.timeout(3000)
|
|
12946
|
-
}).catch(() => {
|
|
13009
|
+
}, transport).catch(() => {
|
|
13010
|
+
return;
|
|
13011
|
+
})));
|
|
12947
13012
|
} catch {}
|
|
12948
13013
|
}
|
|
12949
|
-
var CONVERSATIONS_API;
|
|
12950
13014
|
var init_memory_broadcast = __esm(() => {
|
|
12951
|
-
|
|
13015
|
+
init_conversations_transport();
|
|
12952
13016
|
});
|
|
12953
13017
|
|
|
12954
13018
|
// src/audit-contract.ts
|
|
@@ -13612,18 +13676,21 @@ var exports_export_v1 = {};
|
|
|
13612
13676
|
__export(exports_export_v1, {
|
|
13613
13677
|
toJsonl: () => toJsonl,
|
|
13614
13678
|
fromJsonl: () => fromJsonl,
|
|
13679
|
+
exportV1Entries: () => exportV1Entries,
|
|
13615
13680
|
exportV1: () => exportV1
|
|
13616
13681
|
});
|
|
13617
13682
|
function exportV1(filter, db) {
|
|
13618
|
-
const
|
|
13619
|
-
|
|
13683
|
+
const memories = listMemoriesBounded(filter ?? {}, undefined, db).rows;
|
|
13684
|
+
return exportV1Entries(memories, db);
|
|
13685
|
+
}
|
|
13686
|
+
function exportV1Entries(memories, db) {
|
|
13620
13687
|
const exportedAt = new Date().toISOString();
|
|
13621
13688
|
return memories.map((memory) => {
|
|
13622
13689
|
let entityLinks = [];
|
|
13623
13690
|
try {
|
|
13624
|
-
const links = getEntityMemoryLinks(undefined, memory.id,
|
|
13691
|
+
const links = getEntityMemoryLinks(undefined, memory.id, db);
|
|
13625
13692
|
entityLinks = links.map((link) => {
|
|
13626
|
-
const entity = getEntity(link.entity_id,
|
|
13693
|
+
const entity = getEntity(link.entity_id, db);
|
|
13627
13694
|
return {
|
|
13628
13695
|
entity_name: entity?.name ?? "unknown",
|
|
13629
13696
|
entity_type: entity?.type ?? "unknown",
|
|
@@ -13651,7 +13718,6 @@ var init_export_v1 = __esm(() => {
|
|
|
13651
13718
|
init_memories();
|
|
13652
13719
|
init_entity_memories();
|
|
13653
13720
|
init_entities();
|
|
13654
|
-
init_database();
|
|
13655
13721
|
});
|
|
13656
13722
|
|
|
13657
13723
|
// src/lib/injection-project.ts
|
|
@@ -65352,22 +65418,115 @@ function registerMemoryAuditTools(server) {
|
|
|
65352
65418
|
// src/mcp/tools/memory-io.ts
|
|
65353
65419
|
init_zod();
|
|
65354
65420
|
init_memories();
|
|
65421
|
+
init_redact();
|
|
65422
|
+
|
|
65423
|
+
// src/mcp/tools/bounded-output.ts
|
|
65424
|
+
var MCP_COMPACT_MAX_BYTES = 32 * 1024;
|
|
65425
|
+
var MCP_FULL_MAX_BYTES = 64 * 1024;
|
|
65426
|
+
var MCP_EXPLICIT_MAX_BYTES = 1024 * 1024;
|
|
65427
|
+
function mcpMaxBytes(value, detail) {
|
|
65428
|
+
if (value === undefined)
|
|
65429
|
+
return detail === "full" ? MCP_FULL_MAX_BYTES : MCP_COMPACT_MAX_BYTES;
|
|
65430
|
+
const parsed = typeof value === "number" ? value : Number(value);
|
|
65431
|
+
if (!Number.isInteger(parsed) || parsed < 1024 || parsed > MCP_EXPLICIT_MAX_BYTES) {
|
|
65432
|
+
throw new Error(`max_bytes must be an integer from 1024 to ${MCP_EXPLICIT_MAX_BYTES}`);
|
|
65433
|
+
}
|
|
65434
|
+
return parsed;
|
|
65435
|
+
}
|
|
65436
|
+
function boundedMcpOutput(args) {
|
|
65437
|
+
const makeEnvelope = (items, byteTruncated, omitted) => {
|
|
65438
|
+
const hasMore = byteTruncated || args.sourceHasMore;
|
|
65439
|
+
const nextOffset = hasMore ? args.offset + items.length : null;
|
|
65440
|
+
const envelope = {
|
|
65441
|
+
[args.collection]: items,
|
|
65442
|
+
_meta: {
|
|
65443
|
+
receipt: args.receipt,
|
|
65444
|
+
count: items.length,
|
|
65445
|
+
limit: args.limit,
|
|
65446
|
+
offset: args.offset,
|
|
65447
|
+
next_offset: nextOffset,
|
|
65448
|
+
has_more: hasMore,
|
|
65449
|
+
complete: args.offset === 0 && !hasMore,
|
|
65450
|
+
detail: args.detail,
|
|
65451
|
+
max_bytes: args.maxBytes,
|
|
65452
|
+
response_bytes: 0,
|
|
65453
|
+
truncated: hasMore,
|
|
65454
|
+
truncation_reason: byteTruncated ? "max_bytes" : args.sourceHasMore ? "limit" : null,
|
|
65455
|
+
omitted_from_page: omitted,
|
|
65456
|
+
next_arguments: nextOffset === null ? null : {
|
|
65457
|
+
offset: nextOffset,
|
|
65458
|
+
limit: args.limit,
|
|
65459
|
+
...args.includeDetailInNextArguments !== false && args.detail === "full" ? { detail: "full" } : {},
|
|
65460
|
+
max_bytes: args.maxBytes,
|
|
65461
|
+
...args.nextArguments
|
|
65462
|
+
},
|
|
65463
|
+
continuation_scope: "unchanged_snapshot",
|
|
65464
|
+
...args.metadata
|
|
65465
|
+
}
|
|
65466
|
+
};
|
|
65467
|
+
for (let attempt = 0;attempt < 8; attempt += 1) {
|
|
65468
|
+
const bytes = Buffer.byteLength(JSON.stringify(envelope));
|
|
65469
|
+
const meta = envelope["_meta"];
|
|
65470
|
+
if (meta["response_bytes"] === bytes)
|
|
65471
|
+
break;
|
|
65472
|
+
meta["response_bytes"] = bytes;
|
|
65473
|
+
}
|
|
65474
|
+
return envelope;
|
|
65475
|
+
};
|
|
65476
|
+
for (let count = args.items.length;count >= 0; count -= 1) {
|
|
65477
|
+
const byteTruncated = count < args.items.length;
|
|
65478
|
+
const envelope = makeEnvelope(args.items.slice(0, count), byteTruncated, args.items.length - count);
|
|
65479
|
+
const text = JSON.stringify(envelope);
|
|
65480
|
+
if (Buffer.byteLength(text) > args.maxBytes)
|
|
65481
|
+
continue;
|
|
65482
|
+
if (count === 0 && args.items.length > 0) {
|
|
65483
|
+
throw new Error(`One ${args.detail} result exceeds max_bytes=${args.maxBytes}; request compact detail or a larger max_bytes value`);
|
|
65484
|
+
}
|
|
65485
|
+
const meta = envelope["_meta"];
|
|
65486
|
+
return {
|
|
65487
|
+
text,
|
|
65488
|
+
selectedCount: count,
|
|
65489
|
+
hasMore: meta["has_more"] === true,
|
|
65490
|
+
nextOffset: typeof meta["next_offset"] === "number" ? meta["next_offset"] : null
|
|
65491
|
+
};
|
|
65492
|
+
}
|
|
65493
|
+
throw new Error(`Response metadata exceeds max_bytes=${args.maxBytes}`);
|
|
65494
|
+
}
|
|
65495
|
+
|
|
65496
|
+
// src/mcp/tools/memory-io.ts
|
|
65355
65497
|
function registerMemoryIoTools(server) {
|
|
65356
|
-
server.tool("memory_export", "Export
|
|
65498
|
+
server.tool("memory_export", "Export one truthful byte-bounded page. format='json' returns full memory objects; format='v1' returns portable entries with entity links. Continue with next_offset.", {
|
|
65357
65499
|
scope: exports_external.enum(["global", "shared", "private", "working"]).optional(),
|
|
65358
65500
|
category: exports_external.enum(["preference", "fact", "knowledge", "history", "procedural", "resource"]).optional(),
|
|
65359
65501
|
agent_id: exports_external.string().optional(),
|
|
65360
65502
|
project_id: exports_external.string().optional(),
|
|
65361
|
-
format: exports_external.enum(["json", "v1"]).optional().describe("Export format: json (default) or v1
|
|
65503
|
+
format: exports_external.enum(["json", "v1"]).optional().describe("Export page format: json (default) or portable v1 entries"),
|
|
65504
|
+
limit: exports_external.coerce.number().int().min(1).max(1000).optional().describe("Page size (default: 20, maximum: 1000)"),
|
|
65505
|
+
offset: exports_external.coerce.number().int().min(0).optional().describe("Continuation offset"),
|
|
65506
|
+
max_bytes: exports_external.coerce.number().int().min(1024).max(1024 * 1024).optional().describe("Response ceiling (default: 65536, maximum: 1048576)")
|
|
65362
65507
|
}, async (args) => {
|
|
65363
65508
|
try {
|
|
65364
|
-
|
|
65365
|
-
|
|
65366
|
-
|
|
65367
|
-
|
|
65368
|
-
|
|
65369
|
-
const
|
|
65370
|
-
|
|
65509
|
+
const { format, limit: requestedLimit, offset: requestedOffset, max_bytes, ...filter } = args;
|
|
65510
|
+
const limit = requestedLimit ?? 20;
|
|
65511
|
+
const offset = requestedOffset ?? 0;
|
|
65512
|
+
const page = listMemoriesBounded({ ...filter, offset }, limit);
|
|
65513
|
+
const memories = page.rows.map(redactMemoryForOutput);
|
|
65514
|
+
const portable = format === "v1";
|
|
65515
|
+
const items = portable ? (await Promise.resolve().then(() => (init_export_v1(), exports_export_v1))).exportV1Entries(memories) : memories;
|
|
65516
|
+
const output = boundedMcpOutput({
|
|
65517
|
+
collection: portable ? "entries" : "memories",
|
|
65518
|
+
receipt: portable ? "mementos.export.v1.page.v1" : "mementos.export.page.v1",
|
|
65519
|
+
items,
|
|
65520
|
+
offset,
|
|
65521
|
+
limit,
|
|
65522
|
+
sourceHasMore: page.has_more,
|
|
65523
|
+
detail: "full",
|
|
65524
|
+
maxBytes: mcpMaxBytes(max_bytes, "full"),
|
|
65525
|
+
metadata: { format: portable ? "v1" : "json" },
|
|
65526
|
+
nextArguments: { format: portable ? "v1" : "json", ...filter },
|
|
65527
|
+
includeDetailInNextArguments: false
|
|
65528
|
+
});
|
|
65529
|
+
return { content: [{ type: "text", text: output.text }] };
|
|
65371
65530
|
} catch (e) {
|
|
65372
65531
|
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
65373
65532
|
}
|
|
@@ -65473,7 +65632,7 @@ function getSubscriptionNotifications(agentId, db) {
|
|
|
65473
65632
|
init_hooks();
|
|
65474
65633
|
init_machine_visibility();
|
|
65475
65634
|
function registerMemoryInjectTools(server) {
|
|
65476
|
-
server.tool("memory_inject", "Get memory context for system prompt injection.
|
|
65635
|
+
server.tool("memory_inject", "Get memory context for system prompt injection. Defaults to lightweight hints; set mode='full' explicitly for complete content.", {
|
|
65477
65636
|
agent_id: exports_external.string().optional(),
|
|
65478
65637
|
project_id: exports_external.string().optional(),
|
|
65479
65638
|
session_id: exports_external.string().optional(),
|
|
@@ -65485,11 +65644,12 @@ function registerMemoryInjectTools(server) {
|
|
|
65485
65644
|
strategy: exports_external.enum(["default", "smart"]).optional().describe("Injection strategy: 'default' uses importance+recency, 'smart' uses embedding similarity+importance+recency"),
|
|
65486
65645
|
query: exports_external.string().optional().describe("Query for smart injection relevance scoring. Required when strategy='smart'."),
|
|
65487
65646
|
task_context: exports_external.string().optional().describe("What the agent is about to do. When provided, activates intent-based retrieval \u2014 matches against when_to_use fields for situationally relevant memories."),
|
|
65488
|
-
mode: exports_external.enum(["full", "hints"]).optional().default("
|
|
65647
|
+
mode: exports_external.enum(["full", "hints"]).optional().default("hints").describe("'hints' = lightweight topic summary (default); 'full' = explicit complete content compatibility."),
|
|
65489
65648
|
machine_id: exports_external.string().optional().describe("Current machine ID for machine-local memory visibility. Defaults to the current machine.")
|
|
65490
65649
|
}, async (args) => {
|
|
65491
65650
|
try {
|
|
65492
|
-
|
|
65651
|
+
const mode = args.mode ?? "hints";
|
|
65652
|
+
if (args.strategy === "smart" && args.task_context && mode !== "hints") {
|
|
65493
65653
|
const { smartInject: smartInject2 } = await Promise.resolve().then(() => (init_injector(), exports_injector));
|
|
65494
65654
|
const result = await smartInject2({
|
|
65495
65655
|
task_context: args.task_context,
|
|
@@ -65620,7 +65780,7 @@ function registerMemoryInjectTools(server) {
|
|
|
65620
65780
|
return new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime();
|
|
65621
65781
|
});
|
|
65622
65782
|
}
|
|
65623
|
-
if (
|
|
65783
|
+
if (mode === "hints") {
|
|
65624
65784
|
let extractTopics = function(memories, maxTopics = 8) {
|
|
65625
65785
|
const wordCounts = new Map;
|
|
65626
65786
|
for (const m of memories) {
|
|
@@ -66956,6 +67116,7 @@ function checkMemoryWriteLock(key, scope, projectId, db) {
|
|
|
66956
67116
|
|
|
66957
67117
|
// src/mcp/tools/lock-tools.ts
|
|
66958
67118
|
init_api_mode();
|
|
67119
|
+
init_conversations_transport();
|
|
66959
67120
|
function formatLockLine(lock, index) {
|
|
66960
67121
|
return `${index + 1}. ${lock.id.slice(0, 8)} ${lock.lock_type} ${lock.resource_type}:${compactText(lock.resource_id, 48)} agent=${lock.agent_id} expires=${lock.expires_at}`;
|
|
66961
67122
|
}
|
|
@@ -67111,15 +67272,16 @@ ${visible.map(formatLockLine).join(`
|
|
|
67111
67272
|
const expired = cleanExpiredLocksWithInfo();
|
|
67112
67273
|
const count = expired.length;
|
|
67113
67274
|
if (count > 0) {
|
|
67114
|
-
const conversationsUrl = process.env.CONVERSATIONS_API_URL || "http://localhost:7020";
|
|
67115
67275
|
for (const lock of expired) {
|
|
67116
67276
|
const msg = `Your ${lock.lock_type} lock on ${lock.resource_type}/${lock.resource_id} has expired. Another agent may now acquire it.`;
|
|
67117
|
-
|
|
67277
|
+
conversationsRequest("/messages", {
|
|
67118
67278
|
method: "POST",
|
|
67119
67279
|
headers: { "Content-Type": "application/json" },
|
|
67120
67280
|
body: JSON.stringify({ from: "system", to: lock.agent_id, content: msg }),
|
|
67121
67281
|
signal: AbortSignal.timeout(2000)
|
|
67122
|
-
}).catch(() => {
|
|
67282
|
+
}).catch(() => {
|
|
67283
|
+
return;
|
|
67284
|
+
});
|
|
67123
67285
|
}
|
|
67124
67286
|
}
|
|
67125
67287
|
return { content: [{ type: "text", text: `Cleaned ${count} expired lock(s)${count > 0 ? ` and notified ${count} agent(s)` : ""}.` }] };
|
|
@@ -69506,7 +69668,10 @@ var UTILITY_TOOL_SCHEMAS = {
|
|
|
69506
69668
|
agent_id: { type: "string", description: "Agent UUID filter" },
|
|
69507
69669
|
project_id: { type: "string", description: "Project UUID filter" },
|
|
69508
69670
|
scope: { type: "string", description: "Scope filter", enum: ["global", "shared", "private", "working"] },
|
|
69509
|
-
limit: { type: "number", description: "Max results (default:
|
|
69671
|
+
limit: { type: "number", description: "Max results (default: 10, maximum: 50)" },
|
|
69672
|
+
offset: { type: "number", description: "Continuation offset in the ranked result set" },
|
|
69673
|
+
detail: { type: "string", description: "compact previews (default) or explicit full memory objects", enum: ["compact", "full"] },
|
|
69674
|
+
max_bytes: { type: "number", description: "Response byte ceiling (compact default: 32768; full default: 65536)" },
|
|
69510
69675
|
decay_halflife_days: { type: "number", description: "Importance half-life in days (default: 90). Lower = more weight on recent memories." },
|
|
69511
69676
|
no_decay: { type: "boolean", description: "Set true to disable decay and sort purely by importance." },
|
|
69512
69677
|
task_context: { type: "string", description: "What the agent is about to do. When provided, activates intent-based retrieval \u2014 matches against when_to_use fields." },
|
|
@@ -69630,15 +69795,18 @@ Summary: ${newMems.length} new, ${updatedMems.length} updated, ${expiredMems.len
|
|
|
69630
69795
|
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
69631
69796
|
}
|
|
69632
69797
|
});
|
|
69633
|
-
server.tool("memory_context", "Get
|
|
69798
|
+
server.tool("memory_context", "Get a ranked, byte-bounded memory-context page. Compact detail is the default; set detail='full' explicitly for complete memory fields.", {
|
|
69634
69799
|
agent_id: exports_external.string().optional(),
|
|
69635
69800
|
project_id: exports_external.string().optional(),
|
|
69636
69801
|
scope: exports_external.enum(["global", "shared", "private", "working"]).optional(),
|
|
69637
|
-
limit: exports_external.coerce.number().optional(),
|
|
69802
|
+
limit: exports_external.coerce.number().optional().describe("Max results (default: 10, maximum: 50)"),
|
|
69803
|
+
offset: exports_external.coerce.number().int().min(0).optional().describe("Continuation offset in the ranked result set"),
|
|
69804
|
+
detail: exports_external.enum(["compact", "full"]).optional().default("compact").describe("compact returns ~240-character previews; full returns complete memory objects"),
|
|
69805
|
+
max_bytes: exports_external.coerce.number().int().min(1024).max(1024 * 1024).optional().describe("Response ceiling (compact default: 32768; full default: 65536)"),
|
|
69638
69806
|
decay_halflife_days: exports_external.coerce.number().optional().describe("Importance half-life in days (default: 90). Lower = more weight on recent memories."),
|
|
69639
69807
|
no_decay: exports_external.coerce.boolean().optional().describe("Set true to disable decay and sort purely by importance."),
|
|
69640
|
-
task_context: exports_external.string().optional().describe("What the agent is about to do. When provided, activates intent-based retrieval \u2014 matches against when_to_use fields
|
|
69641
|
-
strategy: exports_external.enum(["default", "smart"]).optional().default("default").describe("
|
|
69808
|
+
task_context: exports_external.string().optional().describe("What the agent is about to do. When provided, activates intent-based retrieval \u2014 matches against when_to_use fields."),
|
|
69809
|
+
strategy: exports_external.enum(["default", "smart"]).optional().default("default").describe("'default' = ranked bounded page, 'smart' = activation-matched pipeline when task_context is provided"),
|
|
69642
69810
|
machine_id: exports_external.string().optional().describe("Current machine ID for machine-local memory visibility. Defaults to the current machine.")
|
|
69643
69811
|
}, async (args) => {
|
|
69644
69812
|
try {
|
|
@@ -69653,16 +69821,18 @@ Summary: ${newMems.length} new, ${updatedMems.length} updated, ${expiredMems.len
|
|
|
69653
69821
|
});
|
|
69654
69822
|
return { content: [{ type: "text", text: result.output }] };
|
|
69655
69823
|
}
|
|
69824
|
+
const limit = positiveLimit(args.limit, 10);
|
|
69825
|
+
const offset = args.offset ?? 0;
|
|
69826
|
+
const detail = args.detail ?? "compact";
|
|
69656
69827
|
const visibleMachineId = resolveVisibleMachineId(args.machine_id);
|
|
69657
69828
|
const filter = {
|
|
69658
69829
|
scope: args.scope,
|
|
69659
69830
|
agent_id: args.agent_id,
|
|
69660
69831
|
project_id: args.project_id,
|
|
69661
69832
|
status: "active",
|
|
69662
|
-
visible_to_machine_id: visibleMachineId
|
|
69663
|
-
limit: (args.limit || 30) * 2
|
|
69833
|
+
visible_to_machine_id: visibleMachineId
|
|
69664
69834
|
};
|
|
69665
|
-
const memories =
|
|
69835
|
+
const memories = listMemoriesBounded(filter, undefined).rows;
|
|
69666
69836
|
const activationBoostedIds = new Set;
|
|
69667
69837
|
if (args.task_context) {
|
|
69668
69838
|
try {
|
|
@@ -69674,45 +69844,80 @@ Summary: ${newMems.length} new, ${updatedMems.length} updated, ${expiredMems.len
|
|
|
69674
69844
|
agent_id: args.agent_id,
|
|
69675
69845
|
project_id: args.project_id
|
|
69676
69846
|
});
|
|
69677
|
-
const seenIds = new Set(memories.map((
|
|
69678
|
-
for (const
|
|
69679
|
-
if (!isMemoryVisibleToMachine(
|
|
69847
|
+
const seenIds = new Set(memories.map((memory) => memory.id));
|
|
69848
|
+
for (const result of activationResults) {
|
|
69849
|
+
if (!isMemoryVisibleToMachine(result.memory, visibleMachineId))
|
|
69680
69850
|
continue;
|
|
69681
|
-
activationBoostedIds.add(
|
|
69682
|
-
if (!seenIds.has(
|
|
69683
|
-
seenIds.add(
|
|
69684
|
-
memories.push(
|
|
69851
|
+
activationBoostedIds.add(result.memory.id);
|
|
69852
|
+
if (!seenIds.has(result.memory.id)) {
|
|
69853
|
+
seenIds.add(result.memory.id);
|
|
69854
|
+
memories.push(result.memory);
|
|
69685
69855
|
}
|
|
69686
69856
|
}
|
|
69687
69857
|
} catch {}
|
|
69688
69858
|
}
|
|
69689
|
-
if (memories.length === 0) {
|
|
69690
|
-
return { content: [{ type: "text", text: "No memories in current context." }] };
|
|
69691
|
-
}
|
|
69692
69859
|
const halflifeDays = args.decay_halflife_days ?? 90;
|
|
69693
69860
|
const now3 = Date.now();
|
|
69694
|
-
const scored = memories.map((
|
|
69695
|
-
const activationBoost = activationBoostedIds.has(
|
|
69696
|
-
let effectiveScore =
|
|
69697
|
-
if (!args.no_decay && !
|
|
69698
|
-
const
|
|
69699
|
-
|
|
69700
|
-
|
|
69701
|
-
|
|
69702
|
-
}
|
|
69703
|
-
if (m.flag)
|
|
69861
|
+
const scored = memories.map((memory) => {
|
|
69862
|
+
const activationBoost = activationBoostedIds.has(memory.id) ? 3 : 0;
|
|
69863
|
+
let effectiveScore = memory.importance + activationBoost;
|
|
69864
|
+
if (!args.no_decay && !memory.pinned) {
|
|
69865
|
+
const ageDays = (now3 - new Date(memory.updated_at).getTime()) / 86400000;
|
|
69866
|
+
effectiveScore *= Math.pow(0.5, ageDays / halflifeDays);
|
|
69867
|
+
}
|
|
69868
|
+
if (memory.flag)
|
|
69704
69869
|
effectiveScore = Math.max(effectiveScore, 11);
|
|
69705
|
-
return {
|
|
69870
|
+
return {
|
|
69871
|
+
...memory,
|
|
69872
|
+
effective_score: Math.round(effectiveScore * 100) / 100,
|
|
69873
|
+
activation_matched: activationBoostedIds.has(memory.id)
|
|
69874
|
+
};
|
|
69706
69875
|
});
|
|
69707
|
-
|
|
69708
|
-
scored.
|
|
69709
|
-
const
|
|
69710
|
-
|
|
69711
|
-
|
|
69712
|
-
|
|
69713
|
-
|
|
69714
|
-
|
|
69715
|
-
|
|
69876
|
+
scored.sort((a, b) => b.effective_score - a.effective_score || b.importance - a.importance || new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime() || b.id.localeCompare(a.id));
|
|
69877
|
+
const page = scored.slice(offset, offset + limit + 1);
|
|
69878
|
+
const hasMore = page.length > limit;
|
|
69879
|
+
const visible = hasMore ? page.slice(0, limit) : page;
|
|
69880
|
+
const items = detail === "full" ? visible : visible.map((memory) => ({
|
|
69881
|
+
id: memory.id,
|
|
69882
|
+
key: memory.key,
|
|
69883
|
+
preview: compactText(memory.summary || memory.value, 240),
|
|
69884
|
+
scope: memory.scope,
|
|
69885
|
+
category: memory.category,
|
|
69886
|
+
importance: memory.importance,
|
|
69887
|
+
effective_score: memory.effective_score,
|
|
69888
|
+
pinned: memory.pinned,
|
|
69889
|
+
...memory.flag ? { flag: memory.flag } : {},
|
|
69890
|
+
...memory.activation_matched ? { activation_matched: true } : {},
|
|
69891
|
+
updated_at: memory.updated_at
|
|
69892
|
+
}));
|
|
69893
|
+
const output = boundedMcpOutput({
|
|
69894
|
+
collection: "memories",
|
|
69895
|
+
receipt: "mementos.context.page.v1",
|
|
69896
|
+
items,
|
|
69897
|
+
offset,
|
|
69898
|
+
limit,
|
|
69899
|
+
sourceHasMore: hasMore,
|
|
69900
|
+
detail,
|
|
69901
|
+
maxBytes: mcpMaxBytes(args.max_bytes, detail),
|
|
69902
|
+
metadata: {
|
|
69903
|
+
total_ranked: scored.length,
|
|
69904
|
+
ranking: {
|
|
69905
|
+
order: "effective_score_desc,importance_desc,updated_at_desc,id_desc",
|
|
69906
|
+
decay_halflife_days: halflifeDays,
|
|
69907
|
+
decay_enabled: !args.no_decay,
|
|
69908
|
+
activation_boost: 3,
|
|
69909
|
+
flagged_score_floor: 11
|
|
69910
|
+
}
|
|
69911
|
+
},
|
|
69912
|
+
nextArguments: {
|
|
69913
|
+
...args.scope ? { scope: args.scope } : {},
|
|
69914
|
+
...args.agent_id ? { agent_id: args.agent_id } : {},
|
|
69915
|
+
...args.project_id ? { project_id: args.project_id } : {}
|
|
69916
|
+
}
|
|
69917
|
+
});
|
|
69918
|
+
for (const memory of visible.slice(0, output.selectedCount))
|
|
69919
|
+
touchMemory(memory.id);
|
|
69920
|
+
return { content: [{ type: "text", text: output.text }] };
|
|
69716
69921
|
} catch (e) {
|
|
69717
69922
|
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
69718
69923
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Memory broadcast utility — notifies active agents when shared memories are saved.
|
|
3
|
-
*
|
|
4
|
-
* Non-blocking: failures
|
|
3
|
+
* Conversations authority and credentials resolve through @hasna/contracts.
|
|
4
|
+
* Non-blocking: notification failures never fail the memory write.
|
|
5
5
|
*/
|
|
6
|
-
import type { Memory } from
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
*/
|
|
11
|
-
export declare function broadcastSharedMemory(memory: Memory, savingAgentId: string): Promise<void>;
|
|
6
|
+
import type { Memory } from "../types/index.js";
|
|
7
|
+
import { type ConversationsTransportOptions } from "../lib/conversations-transport.js";
|
|
8
|
+
/** Broadcast a newly saved shared memory to the other active project agents. */
|
|
9
|
+
export declare function broadcastSharedMemory(memory: Memory, savingAgentId: string, transport?: ConversationsTransportOptions): Promise<void>;
|
|
12
10
|
//# sourceMappingURL=memory-broadcast.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-broadcast.d.ts","sourceRoot":"","sources":["../../src/mcp/memory-broadcast.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"memory-broadcast.d.ts","sourceRoot":"","sources":["../../src/mcp/memory-broadcast.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAEL,KAAK,6BAA6B,EACnC,MAAM,mCAAmC,CAAC;AAE3C,gFAAgF;AAChF,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,SAAS,GAAE,6BAAkC,GAC5C,OAAO,CAAC,IAAI,CAAC,CA8Bf"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare const MCP_COMPACT_MAX_BYTES: number;
|
|
2
|
+
export declare const MCP_FULL_MAX_BYTES: number;
|
|
3
|
+
export declare const MCP_EXPLICIT_MAX_BYTES: number;
|
|
4
|
+
export type McpOutputDetail = "compact" | "full";
|
|
5
|
+
export declare function mcpMaxBytes(value: unknown, detail: McpOutputDetail): number;
|
|
6
|
+
interface BoundedMcpOutputArgs<T> {
|
|
7
|
+
collection: string;
|
|
8
|
+
receipt: string;
|
|
9
|
+
items: T[];
|
|
10
|
+
offset: number;
|
|
11
|
+
limit: number;
|
|
12
|
+
sourceHasMore: boolean;
|
|
13
|
+
detail: McpOutputDetail;
|
|
14
|
+
maxBytes: number;
|
|
15
|
+
metadata?: Record<string, unknown>;
|
|
16
|
+
nextArguments?: Record<string, unknown>;
|
|
17
|
+
includeDetailInNextArguments?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface BoundedMcpOutput {
|
|
20
|
+
text: string;
|
|
21
|
+
selectedCount: number;
|
|
22
|
+
hasMore: boolean;
|
|
23
|
+
nextOffset: number | null;
|
|
24
|
+
}
|
|
25
|
+
export declare function boundedMcpOutput<T>(args: BoundedMcpOutputArgs<T>): BoundedMcpOutput;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=bounded-output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bounded-output.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/bounded-output.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,QAAY,CAAC;AAC/C,eAAO,MAAM,kBAAkB,QAAY,CAAC;AAC5C,eAAO,MAAM,sBAAsB,QAAc,CAAC;AAElD,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,MAAM,CAAC;AAEjD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,eAAe,GAAG,MAAM,CAO3E;AAED,UAAU,oBAAoB,CAAC,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,4BAA4B,CAAC,EAAE,OAAO,CAAC;CACxC;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,IAAI,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CA2DnF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lock-tools.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/lock-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"lock-tools.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/lock-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA8BpE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA0NzD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-inject.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/memory-inject.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAcpE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"memory-inject.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/memory-inject.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAcpE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+UjE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-io.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/memory-io.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"memory-io.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/memory-io.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQpE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8E7D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utility-tools.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/utility-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"utility-tools.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/utility-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAkBpE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAuFlD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,CAyWpF"}
|
package/dist/sdk/index.d.ts
CHANGED
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
* client silently talking to an empty local store while the operator believes
|
|
45
45
|
* it is on the fleet is the false green this whole ruling exists to end.
|
|
46
46
|
*/
|
|
47
|
+
export * from "../decisions/index.js";
|
|
47
48
|
import { AUDIT_EXPORT_CONTRACT, AUDIT_STATS_CONTRACT, AUDIT_TRAIL_CONTRACT, type AuditEntry, type AuditOperation, type AuditPage, type AuditStats } from "../audit-contract.js";
|
|
48
49
|
export { AUDIT_EXPORT_CONTRACT as MEMENTOS_AUDIT_EXPORT_CONTRACT, AUDIT_STATS_CONTRACT as MEMENTOS_AUDIT_STATS_CONTRACT, AUDIT_TRAIL_CONTRACT as MEMENTOS_AUDIT_TRAIL_CONTRACT, };
|
|
49
50
|
export type MementosAuditEntry = AuditEntry;
|
|
@@ -694,7 +695,7 @@ export interface SessionJobsPage {
|
|
|
694
695
|
has_more: boolean;
|
|
695
696
|
next_offset: number | null;
|
|
696
697
|
}
|
|
697
|
-
/**
|
|
698
|
+
/** Explicit endpoint for the deliberate single-operator local opt-in. Never an SDK default. */
|
|
698
699
|
export declare const MEMENTOS_DEFAULT_BASE_URL = "http://localhost:19428";
|
|
699
700
|
/**
|
|
700
701
|
* Split a configured base URL into the authority-plus-path root and the
|