@agenticros/core 0.5.0
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/LICENSE +192 -0
- package/README.md +88 -0
- package/dist/banner.d.ts +7 -0
- package/dist/banner.d.ts.map +1 -0
- package/dist/banner.js +25 -0
- package/dist/banner.js.map +1 -0
- package/dist/capabilities.d.ts +101 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +240 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/cmd-vel-twist.d.ts +9 -0
- package/dist/cmd-vel-twist.d.ts.map +1 -0
- package/dist/cmd-vel-twist.js +32 -0
- package/dist/cmd-vel-twist.js.map +1 -0
- package/dist/config.d.ts +1195 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +427 -0
- package/dist/config.js.map +1 -0
- package/dist/discovery.d.ts +113 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +141 -0
- package/dist/discovery.js.map +1 -0
- package/dist/find-robots-for.d.ts +85 -0
- package/dist/find-robots-for.d.ts.map +1 -0
- package/dist/find-robots-for.js +120 -0
- package/dist/find-robots-for.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/factory.d.ts +18 -0
- package/dist/memory/factory.d.ts.map +1 -0
- package/dist/memory/factory.js +51 -0
- package/dist/memory/factory.js.map +1 -0
- package/dist/memory/index.d.ts +3 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +2 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/local/provider.d.ts +29 -0
- package/dist/memory/local/provider.d.ts.map +1 -0
- package/dist/memory/local/provider.js +202 -0
- package/dist/memory/local/provider.js.map +1 -0
- package/dist/memory/mem0/provider.d.ts +66 -0
- package/dist/memory/mem0/provider.d.ts.map +1 -0
- package/dist/memory/mem0/provider.js +310 -0
- package/dist/memory/mem0/provider.js.map +1 -0
- package/dist/memory/types.d.ts +91 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +10 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/mission-registry.d.ts +94 -0
- package/dist/mission-registry.d.ts.map +1 -0
- package/dist/mission-registry.js +123 -0
- package/dist/mission-registry.js.map +1 -0
- package/dist/mission-transcript-sink.d.ts +33 -0
- package/dist/mission-transcript-sink.d.ts.map +1 -0
- package/dist/mission-transcript-sink.js +76 -0
- package/dist/mission-transcript-sink.js.map +1 -0
- package/dist/mission.d.ts +281 -0
- package/dist/mission.d.ts.map +1 -0
- package/dist/mission.js +331 -0
- package/dist/mission.js.map +1 -0
- package/dist/planner/index.d.ts +84 -0
- package/dist/planner/index.d.ts.map +1 -0
- package/dist/planner/index.js +486 -0
- package/dist/planner/index.js.map +1 -0
- package/dist/robots.d.ts +133 -0
- package/dist/robots.d.ts.map +1 -0
- package/dist/robots.js +220 -0
- package/dist/robots.js.map +1 -0
- package/dist/topic-utils.d.ts +47 -0
- package/dist/topic-utils.d.ts.map +1 -0
- package/dist/topic-utils.js +136 -0
- package/dist/topic-utils.js.map +1 -0
- package/dist/transport/factory.d.ts +10 -0
- package/dist/transport/factory.d.ts.map +1 -0
- package/dist/transport/factory.js +40 -0
- package/dist/transport/factory.js.map +1 -0
- package/dist/transport/local/conversion.d.ts +30 -0
- package/dist/transport/local/conversion.d.ts.map +1 -0
- package/dist/transport/local/conversion.js +340 -0
- package/dist/transport/local/conversion.js.map +1 -0
- package/dist/transport/local/entities.d.ts +34 -0
- package/dist/transport/local/entities.d.ts.map +1 -0
- package/dist/transport/local/entities.js +108 -0
- package/dist/transport/local/entities.js.map +1 -0
- package/dist/transport/local/transport.d.ts +53 -0
- package/dist/transport/local/transport.d.ts.map +1 -0
- package/dist/transport/local/transport.js +344 -0
- package/dist/transport/local/transport.js.map +1 -0
- package/dist/transport/rosbridge/actions.d.ts +30 -0
- package/dist/transport/rosbridge/actions.d.ts.map +1 -0
- package/dist/transport/rosbridge/actions.js +61 -0
- package/dist/transport/rosbridge/actions.js.map +1 -0
- package/dist/transport/rosbridge/adapter.d.ts +29 -0
- package/dist/transport/rosbridge/adapter.d.ts.map +1 -0
- package/dist/transport/rosbridge/adapter.js +108 -0
- package/dist/transport/rosbridge/adapter.js.map +1 -0
- package/dist/transport/rosbridge/client.d.ts +55 -0
- package/dist/transport/rosbridge/client.d.ts.map +1 -0
- package/dist/transport/rosbridge/client.js +375 -0
- package/dist/transport/rosbridge/client.js.map +1 -0
- package/dist/transport/rosbridge/services.d.ts +14 -0
- package/dist/transport/rosbridge/services.d.ts.map +1 -0
- package/dist/transport/rosbridge/services.js +25 -0
- package/dist/transport/rosbridge/services.js.map +1 -0
- package/dist/transport/rosbridge/topics.d.ts +28 -0
- package/dist/transport/rosbridge/topics.d.ts.map +1 -0
- package/dist/transport/rosbridge/topics.js +59 -0
- package/dist/transport/rosbridge/topics.js.map +1 -0
- package/dist/transport/rosbridge/types.d.ts +87 -0
- package/dist/transport/rosbridge/types.d.ts.map +1 -0
- package/dist/transport/rosbridge/types.js +6 -0
- package/dist/transport/rosbridge/types.js.map +1 -0
- package/dist/transport/transport.d.ts +39 -0
- package/dist/transport/transport.d.ts.map +1 -0
- package/dist/transport/transport.js +2 -0
- package/dist/transport/transport.js.map +1 -0
- package/dist/transport/types.d.ts +100 -0
- package/dist/transport/types.d.ts.map +1 -0
- package/dist/transport/types.js +5 -0
- package/dist/transport/types.js.map +1 -0
- package/dist/transport/webrtc/signaling-client.d.ts +38 -0
- package/dist/transport/webrtc/signaling-client.d.ts.map +1 -0
- package/dist/transport/webrtc/signaling-client.js +161 -0
- package/dist/transport/webrtc/signaling-client.js.map +1 -0
- package/dist/transport/webrtc/signaling-types.d.ts +112 -0
- package/dist/transport/webrtc/signaling-types.d.ts.map +1 -0
- package/dist/transport/webrtc/signaling-types.js +8 -0
- package/dist/transport/webrtc/signaling-types.js.map +1 -0
- package/dist/transport/webrtc/transport.d.ts +67 -0
- package/dist/transport/webrtc/transport.d.ts.map +1 -0
- package/dist/transport/webrtc/transport.js +406 -0
- package/dist/transport/webrtc/transport.js.map +1 -0
- package/dist/transport/zenoh/adapter.d.ts +47 -0
- package/dist/transport/zenoh/adapter.d.ts.map +1 -0
- package/dist/transport/zenoh/adapter.js +296 -0
- package/dist/transport/zenoh/adapter.js.map +1 -0
- package/dist/transport/zenoh/cdr.d.ts +17 -0
- package/dist/transport/zenoh/cdr.d.ts.map +1 -0
- package/dist/transport/zenoh/cdr.js +170 -0
- package/dist/transport/zenoh/cdr.js.map +1 -0
- package/dist/transport/zenoh/keys.d.ts +21 -0
- package/dist/transport/zenoh/keys.d.ts.map +1 -0
- package/dist/transport/zenoh/keys.js +44 -0
- package/dist/transport/zenoh/keys.js.map +1 -0
- package/dist/transport-pool.d.ts +74 -0
- package/dist/transport-pool.d.ts.map +1 -0
- package/dist/transport-pool.js +135 -0
- package/dist/transport-pool.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-adapter semantic memory primitives.
|
|
3
|
+
*
|
|
4
|
+
* Memory is an optional, off-by-default subsystem that gives every adapter
|
|
5
|
+
* (OpenClaw, Claude Code MCP, Gemini CLI) a shared way to remember facts
|
|
6
|
+
* across sessions. Records are namespaced (default: robot namespace), so
|
|
7
|
+
* the three adapters talking to the same robot share the same store.
|
|
8
|
+
*/
|
|
9
|
+
export interface MemoryRecord {
|
|
10
|
+
/** Provider-assigned id. Used for `forget({ id })`. */
|
|
11
|
+
id: string;
|
|
12
|
+
/** Raw text content the agent stored. */
|
|
13
|
+
content: string;
|
|
14
|
+
/** Namespace this record belongs to (defaults to robot namespace at call time). */
|
|
15
|
+
namespace: string;
|
|
16
|
+
/** Optional tags the agent supplied at write time. */
|
|
17
|
+
tags?: string[];
|
|
18
|
+
/** Optional hierarchical path hint (e.g. "profile.preferences.speed"). */
|
|
19
|
+
path?: string;
|
|
20
|
+
/** ms since epoch when the record was created. */
|
|
21
|
+
createdAt: number;
|
|
22
|
+
/** Similarity / relevance score, populated only by `recall`. Higher = more relevant. */
|
|
23
|
+
score?: number;
|
|
24
|
+
}
|
|
25
|
+
export interface MemoryStatus {
|
|
26
|
+
/** True when a non-null provider was created from config. */
|
|
27
|
+
enabled: boolean;
|
|
28
|
+
/** Active backend identifier. */
|
|
29
|
+
backend: "local" | "mem0";
|
|
30
|
+
/** Effective namespace the adapter is using. */
|
|
31
|
+
namespace: string;
|
|
32
|
+
/** Number of records stored under this namespace (may be approximate for mem0). */
|
|
33
|
+
recordCount: number;
|
|
34
|
+
/** ms since epoch of the most recent write under this namespace, or null. */
|
|
35
|
+
lastWriteAt: number | null;
|
|
36
|
+
/** Embedder description for the mem0 backend, when configured. */
|
|
37
|
+
embedder?: {
|
|
38
|
+
provider: string;
|
|
39
|
+
model?: string;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export interface RememberInput {
|
|
43
|
+
content: string;
|
|
44
|
+
namespace?: string;
|
|
45
|
+
tags?: string[];
|
|
46
|
+
path?: string;
|
|
47
|
+
}
|
|
48
|
+
export interface RecallInput {
|
|
49
|
+
query: string;
|
|
50
|
+
namespace?: string;
|
|
51
|
+
limit?: number;
|
|
52
|
+
}
|
|
53
|
+
export interface ForgetInput {
|
|
54
|
+
id?: string;
|
|
55
|
+
query?: string;
|
|
56
|
+
namespace?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Backend-agnostic memory provider.
|
|
60
|
+
*
|
|
61
|
+
* Implementations are obtained via `createMemory(config)`. The provider is
|
|
62
|
+
* null when `config.memory.enabled === false`, so adapters skip registering
|
|
63
|
+
* memory tools entirely.
|
|
64
|
+
*/
|
|
65
|
+
export interface MemoryProvider {
|
|
66
|
+
/** Backend identifier (matches `config.memory.backend`). */
|
|
67
|
+
readonly backend: "local" | "mem0";
|
|
68
|
+
/** Store a new memory. Returns the persisted record (with provider-assigned id). */
|
|
69
|
+
remember(input: RememberInput): Promise<MemoryRecord>;
|
|
70
|
+
/** Recall up to `limit` memories ranked by relevance to `query`. */
|
|
71
|
+
recall(input: RecallInput): Promise<MemoryRecord[]>;
|
|
72
|
+
/**
|
|
73
|
+
* Delete memories. Either:
|
|
74
|
+
* - `{ id }` — delete one record by id.
|
|
75
|
+
* - `{ query }` — delete all records in `namespace` matching the query.
|
|
76
|
+
* - `{ namespace }` only (no id, no query) — delete every record in the namespace.
|
|
77
|
+
*/
|
|
78
|
+
forget(input: ForgetInput): Promise<{
|
|
79
|
+
removed: number;
|
|
80
|
+
}>;
|
|
81
|
+
/** Health check: counts records, reports last-write time and embedder info if any. */
|
|
82
|
+
status(namespace: string): Promise<MemoryStatus>;
|
|
83
|
+
/**
|
|
84
|
+
* Return up to `limit` most recently written records in the namespace.
|
|
85
|
+
* Used by adapters that want to surface "recently remembered" snippets in
|
|
86
|
+
* the system prompt so the LLM doesn't need a tool call for common
|
|
87
|
+
* personal-context questions. Order: newest first.
|
|
88
|
+
*/
|
|
89
|
+
recent(namespace: string, limit?: number): Promise<MemoryRecord[]>;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/memory/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,SAAS,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,wFAAwF;IACxF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,6DAA6D;IAC7D,OAAO,EAAE,OAAO,CAAC;IACjB,iCAAiC;IACjC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC;IAC1B,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACjD;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC;IAEnC,oFAAoF;IACpF,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAEtD,oEAAoE;IACpE,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAEpD;;;;;OAKG;IACH,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAEzD,sFAAsF;IACtF,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAEjD;;;;;OAKG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;CACpE"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-adapter semantic memory primitives.
|
|
3
|
+
*
|
|
4
|
+
* Memory is an optional, off-by-default subsystem that gives every adapter
|
|
5
|
+
* (OpenClaw, Claude Code MCP, Gemini CLI) a shared way to remember facts
|
|
6
|
+
* across sessions. Records are namespaced (default: robot namespace), so
|
|
7
|
+
* the three adapters talking to the same robot share the same store.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/memory/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MissionRegistry — Phase 1.f in-process tracker for active missions.
|
|
3
|
+
*
|
|
4
|
+
* Each adapter (Claude Code MCP server, OpenClaw plugin, Gemini CLI)
|
|
5
|
+
* keeps a module-level registry. When `run_mission` starts, the adapter
|
|
6
|
+
* registers a fresh cancellation token under a unique `mission_id` and
|
|
7
|
+
* returns the id in the tool response. A sibling `mission_cancel` tool
|
|
8
|
+
* call then looks up the token by id and flips `cancelled = true` — the
|
|
9
|
+
* mission runner picks that up at the next step boundary and stops
|
|
10
|
+
* gracefully.
|
|
11
|
+
*
|
|
12
|
+
* Lifetime semantics:
|
|
13
|
+
* - `register()` returns the cancellation token AND a `dispose()`
|
|
14
|
+
* callback the caller is expected to invoke in a `finally` block
|
|
15
|
+
* once the mission ends (regardless of outcome). Disposal removes
|
|
16
|
+
* the entry so a subsequent cancel doesn't silently target a
|
|
17
|
+
* completed mission and the in-memory map stays small.
|
|
18
|
+
* - `cancel()` is idempotent — calling it on a missing id returns
|
|
19
|
+
* `{ found: false }`; calling it twice on the same id is a no-op
|
|
20
|
+
* after the first.
|
|
21
|
+
*
|
|
22
|
+
* Why in-process (not cross-process)? Cancellation is fundamentally
|
|
23
|
+
* "stop the dispatcher I'm running"; that dispatcher is local to the
|
|
24
|
+
* adapter process. Cross-agent coordination is Phase 4. The transcript
|
|
25
|
+
* subsystem (memory) handles the "different agent reads what I did"
|
|
26
|
+
* story orthogonally.
|
|
27
|
+
*/
|
|
28
|
+
import type { MissionCancellationToken } from "./mission.js";
|
|
29
|
+
/** One registered mission. */
|
|
30
|
+
export interface MissionRegistryEntry {
|
|
31
|
+
mission_id: string;
|
|
32
|
+
/** Adapter-supplied label for diagnostics (e.g. mission.name). */
|
|
33
|
+
name?: string;
|
|
34
|
+
/** ms since epoch when the mission was registered. */
|
|
35
|
+
started_at: number;
|
|
36
|
+
/** The token the mission runner reads each step. */
|
|
37
|
+
cancellation: MissionCancellationToken;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Generate a stable, URL-safe mission identifier.
|
|
41
|
+
*
|
|
42
|
+
* Uses `crypto.randomUUID()` when available (Node 14.17+, Bun, modern
|
|
43
|
+
* browsers); falls back to a Math.random hex string with a `mns_` prefix.
|
|
44
|
+
* Either way the id is opaque to downstream consumers — they just echo
|
|
45
|
+
* it back to `mission_cancel` / `memory_recall`.
|
|
46
|
+
*/
|
|
47
|
+
export declare function generateMissionId(): string;
|
|
48
|
+
/**
|
|
49
|
+
* Compute the canonical memory namespace for a mission's transcripts.
|
|
50
|
+
*
|
|
51
|
+
* The convention is `mission:<id>` so a downstream agent can recall
|
|
52
|
+
* every step the first agent ran via
|
|
53
|
+
* `memory_recall({ namespace: "mission:<id>", query: "" })`. This lives
|
|
54
|
+
* here (not in the memory module) because the adapter's transcript
|
|
55
|
+
* sink uses it and we want exactly one source of truth.
|
|
56
|
+
*/
|
|
57
|
+
export declare function missionTranscriptNamespace(missionId: string): string;
|
|
58
|
+
export declare class MissionRegistry {
|
|
59
|
+
private readonly entries;
|
|
60
|
+
/**
|
|
61
|
+
* Register a fresh mission, returning the entry (with the
|
|
62
|
+
* cancellation token to hand to `runMission`) and a `dispose` hook
|
|
63
|
+
* to invoke when the mission ends. The id is caller-supplied so
|
|
64
|
+
* adapters can echo it in the tool response before this point.
|
|
65
|
+
*/
|
|
66
|
+
register(missionId: string, opts?: {
|
|
67
|
+
name?: string;
|
|
68
|
+
}): {
|
|
69
|
+
entry: MissionRegistryEntry;
|
|
70
|
+
dispose: () => void;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Flip the cancellation token for the named mission.
|
|
74
|
+
*
|
|
75
|
+
* Returns `{ found: true }` when the mission existed (whether it was
|
|
76
|
+
* already cancelled or not), `{ found: false }` when the id is
|
|
77
|
+
* unknown (e.g. mission already finished + disposed).
|
|
78
|
+
*/
|
|
79
|
+
cancel(missionId: string, reason?: string): {
|
|
80
|
+
found: boolean;
|
|
81
|
+
alreadyCancelled: boolean;
|
|
82
|
+
};
|
|
83
|
+
/** True when the named mission is currently registered. */
|
|
84
|
+
has(missionId: string): boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Snapshot of the active mission set (for diagnostics / mission_list
|
|
87
|
+
* tools down the road). Returns a shallow copy so callers can't
|
|
88
|
+
* mutate internal state.
|
|
89
|
+
*/
|
|
90
|
+
list(): MissionRegistryEntry[];
|
|
91
|
+
/** Test-only: drop every registered mission. */
|
|
92
|
+
_clear(): void;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=mission-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mission-registry.d.ts","sourceRoot":"","sources":["../src/mission-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAE7D,8BAA8B;AAC9B,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,UAAU,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,YAAY,EAAE,wBAAwB,CAAC;CACxC;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAO1C;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2C;IAEnE;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG;QACrD,KAAK,EAAE,oBAAoB,CAAC;QAC5B,OAAO,EAAE,MAAM,IAAI,CAAC;KACrB;IAmBD;;;;;;OAMG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,gBAAgB,EAAE,OAAO,CAAA;KAAE;IASzF,2DAA2D;IAC3D,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAI/B;;;;OAIG;IACH,IAAI,IAAI,oBAAoB,EAAE;IAS9B,gDAAgD;IAChD,MAAM,IAAI,IAAI;CAGf"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MissionRegistry — Phase 1.f in-process tracker for active missions.
|
|
3
|
+
*
|
|
4
|
+
* Each adapter (Claude Code MCP server, OpenClaw plugin, Gemini CLI)
|
|
5
|
+
* keeps a module-level registry. When `run_mission` starts, the adapter
|
|
6
|
+
* registers a fresh cancellation token under a unique `mission_id` and
|
|
7
|
+
* returns the id in the tool response. A sibling `mission_cancel` tool
|
|
8
|
+
* call then looks up the token by id and flips `cancelled = true` — the
|
|
9
|
+
* mission runner picks that up at the next step boundary and stops
|
|
10
|
+
* gracefully.
|
|
11
|
+
*
|
|
12
|
+
* Lifetime semantics:
|
|
13
|
+
* - `register()` returns the cancellation token AND a `dispose()`
|
|
14
|
+
* callback the caller is expected to invoke in a `finally` block
|
|
15
|
+
* once the mission ends (regardless of outcome). Disposal removes
|
|
16
|
+
* the entry so a subsequent cancel doesn't silently target a
|
|
17
|
+
* completed mission and the in-memory map stays small.
|
|
18
|
+
* - `cancel()` is idempotent — calling it on a missing id returns
|
|
19
|
+
* `{ found: false }`; calling it twice on the same id is a no-op
|
|
20
|
+
* after the first.
|
|
21
|
+
*
|
|
22
|
+
* Why in-process (not cross-process)? Cancellation is fundamentally
|
|
23
|
+
* "stop the dispatcher I'm running"; that dispatcher is local to the
|
|
24
|
+
* adapter process. Cross-agent coordination is Phase 4. The transcript
|
|
25
|
+
* subsystem (memory) handles the "different agent reads what I did"
|
|
26
|
+
* story orthogonally.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Generate a stable, URL-safe mission identifier.
|
|
30
|
+
*
|
|
31
|
+
* Uses `crypto.randomUUID()` when available (Node 14.17+, Bun, modern
|
|
32
|
+
* browsers); falls back to a Math.random hex string with a `mns_` prefix.
|
|
33
|
+
* Either way the id is opaque to downstream consumers — they just echo
|
|
34
|
+
* it back to `mission_cancel` / `memory_recall`.
|
|
35
|
+
*/
|
|
36
|
+
export function generateMissionId() {
|
|
37
|
+
const g = globalThis;
|
|
38
|
+
if (g.crypto?.randomUUID)
|
|
39
|
+
return `mn_${g.crypto.randomUUID()}`;
|
|
40
|
+
const a = Math.floor(Math.random() * 0xffffffff).toString(16).padStart(8, "0");
|
|
41
|
+
const b = Math.floor(Math.random() * 0xffffffff).toString(16).padStart(8, "0");
|
|
42
|
+
const c = Date.now().toString(16);
|
|
43
|
+
return `mn_${a}${b}${c}`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Compute the canonical memory namespace for a mission's transcripts.
|
|
47
|
+
*
|
|
48
|
+
* The convention is `mission:<id>` so a downstream agent can recall
|
|
49
|
+
* every step the first agent ran via
|
|
50
|
+
* `memory_recall({ namespace: "mission:<id>", query: "" })`. This lives
|
|
51
|
+
* here (not in the memory module) because the adapter's transcript
|
|
52
|
+
* sink uses it and we want exactly one source of truth.
|
|
53
|
+
*/
|
|
54
|
+
export function missionTranscriptNamespace(missionId) {
|
|
55
|
+
return `mission:${missionId}`;
|
|
56
|
+
}
|
|
57
|
+
export class MissionRegistry {
|
|
58
|
+
entries = new Map();
|
|
59
|
+
/**
|
|
60
|
+
* Register a fresh mission, returning the entry (with the
|
|
61
|
+
* cancellation token to hand to `runMission`) and a `dispose` hook
|
|
62
|
+
* to invoke when the mission ends. The id is caller-supplied so
|
|
63
|
+
* adapters can echo it in the tool response before this point.
|
|
64
|
+
*/
|
|
65
|
+
register(missionId, opts) {
|
|
66
|
+
const entry = {
|
|
67
|
+
mission_id: missionId,
|
|
68
|
+
name: opts?.name,
|
|
69
|
+
started_at: Date.now(),
|
|
70
|
+
cancellation: { cancelled: false },
|
|
71
|
+
};
|
|
72
|
+
this.entries.set(missionId, entry);
|
|
73
|
+
return {
|
|
74
|
+
entry,
|
|
75
|
+
dispose: () => {
|
|
76
|
+
// Only remove if we're disposing the same entry — guards against
|
|
77
|
+
// a race where the same id is re-registered between dispose calls
|
|
78
|
+
// (unlikely but cheap to defend against).
|
|
79
|
+
if (this.entries.get(missionId) === entry)
|
|
80
|
+
this.entries.delete(missionId);
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Flip the cancellation token for the named mission.
|
|
86
|
+
*
|
|
87
|
+
* Returns `{ found: true }` when the mission existed (whether it was
|
|
88
|
+
* already cancelled or not), `{ found: false }` when the id is
|
|
89
|
+
* unknown (e.g. mission already finished + disposed).
|
|
90
|
+
*/
|
|
91
|
+
cancel(missionId, reason) {
|
|
92
|
+
const entry = this.entries.get(missionId);
|
|
93
|
+
if (!entry)
|
|
94
|
+
return { found: false, alreadyCancelled: false };
|
|
95
|
+
const alreadyCancelled = entry.cancellation.cancelled === true;
|
|
96
|
+
entry.cancellation.cancelled = true;
|
|
97
|
+
if (reason !== undefined)
|
|
98
|
+
entry.cancellation.reason = reason;
|
|
99
|
+
return { found: true, alreadyCancelled };
|
|
100
|
+
}
|
|
101
|
+
/** True when the named mission is currently registered. */
|
|
102
|
+
has(missionId) {
|
|
103
|
+
return this.entries.has(missionId);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Snapshot of the active mission set (for diagnostics / mission_list
|
|
107
|
+
* tools down the road). Returns a shallow copy so callers can't
|
|
108
|
+
* mutate internal state.
|
|
109
|
+
*/
|
|
110
|
+
list() {
|
|
111
|
+
return [...this.entries.values()].map((e) => ({
|
|
112
|
+
mission_id: e.mission_id,
|
|
113
|
+
name: e.name,
|
|
114
|
+
started_at: e.started_at,
|
|
115
|
+
cancellation: { ...e.cancellation },
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
/** Test-only: drop every registered mission. */
|
|
119
|
+
_clear() {
|
|
120
|
+
this.entries.clear();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=mission-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mission-registry.js","sourceRoot":"","sources":["../src/mission-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory-backed mission transcript sink — Phase 1.f wiring.
|
|
3
|
+
*
|
|
4
|
+
* `createMemoryTranscriptSink(memory, missionId)` returns a
|
|
5
|
+
* `MissionTranscriptSink` the adapter hands to `runMission`. Each
|
|
6
|
+
* step's `MissionTranscriptEntry` is serialised to JSON and persisted
|
|
7
|
+
* via the shared `MemoryProvider` under the canonical
|
|
8
|
+
* `mission:<id>` namespace.
|
|
9
|
+
*
|
|
10
|
+
* Why JSON content (and not the structured `MemoryRecord` fields):
|
|
11
|
+
* `MemoryProvider.remember` only takes `content: string` (plus
|
|
12
|
+
* optional tags/path). We pack the full step snapshot into `content`
|
|
13
|
+
* so a downstream agent can `JSON.parse(record.content)` after
|
|
14
|
+
* `memory_recall(namespace="mission:<id>")`. Tags are used as
|
|
15
|
+
* coarse-grained filters (e.g. "step:ok" vs "step:error") for
|
|
16
|
+
* future status queries.
|
|
17
|
+
*
|
|
18
|
+
* The returned sink is best-effort by contract — `runMission` already
|
|
19
|
+
* swallows thrown errors, but we also defensively catch the await so a
|
|
20
|
+
* mem0 outage never propagates back into the run loop.
|
|
21
|
+
*/
|
|
22
|
+
import type { MemoryProvider } from "./memory/index.js";
|
|
23
|
+
import type { MissionTranscriptSink } from "./mission.js";
|
|
24
|
+
/**
|
|
25
|
+
* Build a transcript sink that writes each step's entry to memory.
|
|
26
|
+
*
|
|
27
|
+
* @param memory Active memory provider (caller has already
|
|
28
|
+
* confirmed `config.memory.enabled === true`).
|
|
29
|
+
* @param missionId Mission identifier. Surfaced as the namespace
|
|
30
|
+
* and also embedded in the content for grep-ability.
|
|
31
|
+
*/
|
|
32
|
+
export declare function createMemoryTranscriptSink(memory: MemoryProvider, missionId: string): MissionTranscriptSink;
|
|
33
|
+
//# sourceMappingURL=mission-transcript-sink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mission-transcript-sink.d.ts","sourceRoot":"","sources":["../src/mission-transcript-sink.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,qBAAqB,EAA0B,MAAM,cAAc,CAAC;AAGlF;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,GAChB,qBAAqB,CA2CvB"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory-backed mission transcript sink — Phase 1.f wiring.
|
|
3
|
+
*
|
|
4
|
+
* `createMemoryTranscriptSink(memory, missionId)` returns a
|
|
5
|
+
* `MissionTranscriptSink` the adapter hands to `runMission`. Each
|
|
6
|
+
* step's `MissionTranscriptEntry` is serialised to JSON and persisted
|
|
7
|
+
* via the shared `MemoryProvider` under the canonical
|
|
8
|
+
* `mission:<id>` namespace.
|
|
9
|
+
*
|
|
10
|
+
* Why JSON content (and not the structured `MemoryRecord` fields):
|
|
11
|
+
* `MemoryProvider.remember` only takes `content: string` (plus
|
|
12
|
+
* optional tags/path). We pack the full step snapshot into `content`
|
|
13
|
+
* so a downstream agent can `JSON.parse(record.content)` after
|
|
14
|
+
* `memory_recall(namespace="mission:<id>")`. Tags are used as
|
|
15
|
+
* coarse-grained filters (e.g. "step:ok" vs "step:error") for
|
|
16
|
+
* future status queries.
|
|
17
|
+
*
|
|
18
|
+
* The returned sink is best-effort by contract — `runMission` already
|
|
19
|
+
* swallows thrown errors, but we also defensively catch the await so a
|
|
20
|
+
* mem0 outage never propagates back into the run loop.
|
|
21
|
+
*/
|
|
22
|
+
import { missionTranscriptNamespace } from "./mission-registry.js";
|
|
23
|
+
/**
|
|
24
|
+
* Build a transcript sink that writes each step's entry to memory.
|
|
25
|
+
*
|
|
26
|
+
* @param memory Active memory provider (caller has already
|
|
27
|
+
* confirmed `config.memory.enabled === true`).
|
|
28
|
+
* @param missionId Mission identifier. Surfaced as the namespace
|
|
29
|
+
* and also embedded in the content for grep-ability.
|
|
30
|
+
*/
|
|
31
|
+
export function createMemoryTranscriptSink(memory, missionId) {
|
|
32
|
+
const namespace = missionTranscriptNamespace(missionId);
|
|
33
|
+
return async (entry) => {
|
|
34
|
+
try {
|
|
35
|
+
const content = JSON.stringify({
|
|
36
|
+
// Echo mission_id in the payload too — recall() returns the
|
|
37
|
+
// content blob; mission_id in the namespace might be lost if
|
|
38
|
+
// the caller scopes their recall differently.
|
|
39
|
+
mission_id: entry.mission_id || missionId,
|
|
40
|
+
mission_name: entry.mission_name,
|
|
41
|
+
adapter: entry.adapter,
|
|
42
|
+
robot_id: entry.robot_id,
|
|
43
|
+
started_at: entry.started_at,
|
|
44
|
+
step_index: entry.step_index,
|
|
45
|
+
step_total: entry.step_total,
|
|
46
|
+
step: {
|
|
47
|
+
id: entry.result.id,
|
|
48
|
+
capability: entry.result.capability,
|
|
49
|
+
status: entry.result.status,
|
|
50
|
+
inputs: entry.result.inputs,
|
|
51
|
+
outputs: entry.result.outputs,
|
|
52
|
+
message: entry.result.message,
|
|
53
|
+
error: entry.result.error,
|
|
54
|
+
duration_ms: entry.result.duration_ms,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
// Tags are deliberately stable + greppable so a future
|
|
58
|
+
// `memory_recall(tags=…)` can filter to "every cancelled step"
|
|
59
|
+
// or "every step that touched capability=drive_base".
|
|
60
|
+
await memory.remember({
|
|
61
|
+
namespace,
|
|
62
|
+
content,
|
|
63
|
+
tags: [
|
|
64
|
+
"mission_transcript",
|
|
65
|
+
`step:${entry.result.status}`,
|
|
66
|
+
`capability:${entry.result.capability}`,
|
|
67
|
+
],
|
|
68
|
+
path: `${missionId}/${String(entry.step_index).padStart(3, "0")}-${entry.result.id}`,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// Best-effort: transcript loss must NEVER abort the mission.
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=mission-transcript-sink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mission-transcript-sink.js","sourceRoot":"","sources":["../src/mission-transcript-sink.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AAEnE;;;;;;;GAOG;AACH,MAAM,UAAU,0BAA0B,CACxC,MAAsB,EACtB,SAAiB;IAEjB,MAAM,SAAS,GAAG,0BAA0B,CAAC,SAAS,CAAC,CAAC;IACxD,OAAO,KAAK,EAAE,KAA6B,EAAiB,EAAE;QAC5D,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;gBAC7B,4DAA4D;gBAC5D,6DAA6D;gBAC7D,8CAA8C;gBAC9C,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,SAAS;gBACzC,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,IAAI,EAAE;oBACJ,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE;oBACnB,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU;oBACnC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM;oBAC3B,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM;oBAC3B,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO;oBAC7B,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO;oBAC7B,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;oBACzB,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,WAAW;iBACtC;aACF,CAAC,CAAC;YACH,uDAAuD;YACvD,+DAA+D;YAC/D,sDAAsD;YACtD,MAAM,MAAM,CAAC,QAAQ,CAAC;gBACpB,SAAS;gBACT,OAAO;gBACP,IAAI,EAAE;oBACJ,oBAAoB;oBACpB,QAAQ,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE;oBAC7B,cAAc,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE;iBACxC;gBACD,IAAI,EAAE,GAAG,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE;aACrF,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,6DAA6D;QAC/D,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|