agentfootprint 2.0.1 → 2.2.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/AGENTS.md +61 -0
- package/CLAUDE.md +61 -0
- package/README.md +3 -2
- package/ai-instructions/claude-code/SKILL.md +61 -0
- package/ai-instructions/clinerules +41 -0
- package/ai-instructions/copilot-instructions.md +41 -0
- package/ai-instructions/cursor/agentfootprint.md +41 -0
- package/ai-instructions/kiro/agentfootprint.md +41 -0
- package/ai-instructions/windsurfrules +41 -0
- package/dist/core/Agent.js +31 -0
- package/dist/core/Agent.js.map +1 -1
- package/dist/esm/core/Agent.js +31 -0
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/index.js +9 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/mcp/index.js +8 -0
- package/dist/esm/lib/mcp/index.js.map +1 -0
- package/dist/esm/lib/mcp/mcpClient.js +171 -0
- package/dist/esm/lib/mcp/mcpClient.js.map +1 -0
- package/dist/esm/lib/mcp/types.js +24 -0
- package/dist/esm/lib/mcp/types.js.map +1 -0
- package/dist/esm/lib/rag/defineRAG.js +118 -0
- package/dist/esm/lib/rag/defineRAG.js.map +1 -0
- package/dist/esm/lib/rag/index.js +8 -0
- package/dist/esm/lib/rag/index.js.map +1 -0
- package/dist/esm/lib/rag/indexDocuments.js +73 -0
- package/dist/esm/lib/rag/indexDocuments.js.map +1 -0
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/mcp/index.js +12 -0
- package/dist/lib/mcp/index.js.map +1 -0
- package/dist/lib/mcp/mcpClient.js +175 -0
- package/dist/lib/mcp/mcpClient.js.map +1 -0
- package/dist/lib/mcp/types.js +25 -0
- package/dist/lib/mcp/types.js.map +1 -0
- package/dist/lib/rag/defineRAG.js +122 -0
- package/dist/lib/rag/defineRAG.js.map +1 -0
- package/dist/lib/rag/index.js +13 -0
- package/dist/lib/rag/index.js.map +1 -0
- package/dist/lib/rag/indexDocuments.js +77 -0
- package/dist/lib/rag/indexDocuments.js.map +1 -0
- package/dist/types/core/Agent.d.ts +25 -0
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/mcp/index.d.ts +9 -0
- package/dist/types/lib/mcp/index.d.ts.map +1 -0
- package/dist/types/lib/mcp/mcpClient.d.ts +64 -0
- package/dist/types/lib/mcp/mcpClient.d.ts.map +1 -0
- package/dist/types/lib/mcp/types.d.ts +132 -0
- package/dist/types/lib/mcp/types.d.ts.map +1 -0
- package/dist/types/lib/rag/defineRAG.d.ts +141 -0
- package/dist/types/lib/rag/defineRAG.d.ts.map +1 -0
- package/dist/types/lib/rag/index.d.ts +8 -0
- package/dist/types/lib/rag/index.d.ts.map +1 -0
- package/dist/types/lib/rag/indexDocuments.d.ts +77 -0
- package/dist/types/lib/rag/indexDocuments.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcpClient — connect to an MCP server, expose its tools to your Agent.
|
|
3
|
+
*
|
|
4
|
+
* const slack = await mcpClient({
|
|
5
|
+
* name: 'slack',
|
|
6
|
+
* transport: { transport: 'stdio', command: 'npx', args: ['@example/slack-mcp'] },
|
|
7
|
+
* });
|
|
8
|
+
*
|
|
9
|
+
* const tools = await slack.tools(); // → readonly Tool[]
|
|
10
|
+
* const agent = Agent.create({ ... }).tools(tools).build();
|
|
11
|
+
*
|
|
12
|
+
* // ...
|
|
13
|
+
*
|
|
14
|
+
* await slack.close();
|
|
15
|
+
*
|
|
16
|
+
* Pattern: Adapter (GoF) — translates MCP `listTools()` / `callTool()`
|
|
17
|
+
* into agentfootprint's `Tool` interface (schema + execute).
|
|
18
|
+
* Each MCP tool becomes ONE agentfootprint Tool. The agent's
|
|
19
|
+
* existing tool-call handler invokes `client.callTool()`
|
|
20
|
+
* inside the wrapped `execute`.
|
|
21
|
+
*
|
|
22
|
+
* Role: Layer-3 integration. Sits next to `defineTool` — same
|
|
23
|
+
* shape, different source. Once tools land on the agent,
|
|
24
|
+
* the rest of the library doesn't know they came from MCP.
|
|
25
|
+
*
|
|
26
|
+
* Emits: N/A — wrapped tools emit the standard
|
|
27
|
+
* `agentfootprint.stream.tool_start` / `tool_end` events
|
|
28
|
+
* when the agent calls them. Add `name: '<mcp-server>'` to
|
|
29
|
+
* `McpClientOptions` so observability surfaces can group
|
|
30
|
+
* tool calls by server.
|
|
31
|
+
*
|
|
32
|
+
* 7-panel review (2026-04-29):
|
|
33
|
+
* - LLM Systems ✅ inputSchema preserved verbatim — the LLM sees
|
|
34
|
+
* the same tool schema MCP advertised
|
|
35
|
+
* - Architect ✅ pure adapter; no engine code. New tool sources
|
|
36
|
+
* slot in via the same `Tool` interface
|
|
37
|
+
* - API Designer ✅ three methods (.tools / .refresh / .close)
|
|
38
|
+
* mirror the MCP SDK lifecycle
|
|
39
|
+
* - Performance ✅ tool list cached after first fetch; .refresh
|
|
40
|
+
* is opt-in. callTool round-trip is one network
|
|
41
|
+
* hop per tool call (same as direct LLM-tool flow)
|
|
42
|
+
* - Privacy ✅ no implicit logging; consumer controls auth
|
|
43
|
+
* via transport headers
|
|
44
|
+
* - SoftEng ✅ lazy-required SDK + friendly install error;
|
|
45
|
+
* mock injection point for tests
|
|
46
|
+
* - TS Engineer ✅ structural McpSdkClient shim — works against
|
|
47
|
+
* any future SDK version with the same shape
|
|
48
|
+
*
|
|
49
|
+
* Lazy-require pattern: the `@modelcontextprotocol/sdk` peer-dep
|
|
50
|
+
* loads only when a consumer actually constructs a client. Tests
|
|
51
|
+
* inject `_client` and skip the import path entirely.
|
|
52
|
+
*/
|
|
53
|
+
import type { McpClient, McpClientOptions } from './types.js';
|
|
54
|
+
/**
|
|
55
|
+
* Connect to an MCP server. Returns an `McpClient` that exposes the
|
|
56
|
+
* server's tools as agentfootprint `Tool[]` and a `close()` to tear
|
|
57
|
+
* down the transport.
|
|
58
|
+
*
|
|
59
|
+
* @throws when `@modelcontextprotocol/sdk` is not installed (see
|
|
60
|
+
* error message for `npm install` hint), or when the transport
|
|
61
|
+
* fails to connect.
|
|
62
|
+
*/
|
|
63
|
+
export declare function mcpClient(opts: McpClientOptions): Promise<McpClient>;
|
|
64
|
+
//# sourceMappingURL=mcpClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpClient.d.ts","sourceRoot":"","sources":["../../../../src/lib/mcp/mcpClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAA8B,MAAM,YAAY,CAAC;AAO1F;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,CAAC,CA4B1E"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP — Model Context Protocol client integration.
|
|
3
|
+
*
|
|
4
|
+
* MCP (https://modelcontextprotocol.io) is an open standard for
|
|
5
|
+
* connecting LLMs to external tools and data sources. agentfootprint's
|
|
6
|
+
* MCP adapter is **client-only** — it consumes MCP servers and exposes
|
|
7
|
+
* their tools as agentfootprint `Tool[]` so consumers can plug them
|
|
8
|
+
* straight into `agent.tool(...)`.
|
|
9
|
+
*
|
|
10
|
+
* Pattern: Adapter (GoF) — translates MCP wire format ↔ agentfootprint
|
|
11
|
+
* `Tool` interface. The MCP SDK does the protocol work; we
|
|
12
|
+
* just bridge.
|
|
13
|
+
* Role: Layer-3 tool integration. Pairs with `defineTool` (the
|
|
14
|
+
* inline alternative for non-MCP tools).
|
|
15
|
+
* Emits: N/A directly — wrapped tools emit the standard
|
|
16
|
+
* `agentfootprint.stream.tool_start` / `tool_end` events
|
|
17
|
+
* when the agent calls them.
|
|
18
|
+
*
|
|
19
|
+
* Server-side support (exposing an agent or LLMCall as an MCP tool)
|
|
20
|
+
* is a separate concern not yet shipped. This module covers the
|
|
21
|
+
* 80% case: pulling an existing MCP server's tools INTO an agent.
|
|
22
|
+
*/
|
|
23
|
+
import type { Tool } from '../../core/tools.js';
|
|
24
|
+
/**
|
|
25
|
+
* `stdio` transport — spawns a local subprocess and speaks MCP over
|
|
26
|
+
* its stdin/stdout. Best for development, single-user scenarios, and
|
|
27
|
+
* testing against locally-installed MCP servers.
|
|
28
|
+
*/
|
|
29
|
+
export interface McpStdioTransport {
|
|
30
|
+
readonly transport: 'stdio';
|
|
31
|
+
/** Executable to spawn (e.g., `'npx'`, `'node'`, `'python'`). */
|
|
32
|
+
readonly command: string;
|
|
33
|
+
/** CLI args passed to the executable. */
|
|
34
|
+
readonly args?: readonly string[];
|
|
35
|
+
/** Optional env vars set on the subprocess. */
|
|
36
|
+
readonly env?: Readonly<Record<string, string>>;
|
|
37
|
+
/** Working directory for the subprocess. */
|
|
38
|
+
readonly cwd?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* `http` transport — speaks MCP over Streamable HTTP. Best for remote
|
|
42
|
+
* servers, web environments, and multi-user scenarios.
|
|
43
|
+
*/
|
|
44
|
+
export interface McpHttpTransport {
|
|
45
|
+
readonly transport: 'http';
|
|
46
|
+
/** MCP server endpoint URL. */
|
|
47
|
+
readonly url: string;
|
|
48
|
+
/** Optional auth headers (e.g., `Authorization: Bearer ...`). */
|
|
49
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
50
|
+
}
|
|
51
|
+
export type McpTransport = McpStdioTransport | McpHttpTransport;
|
|
52
|
+
export interface McpClientOptions {
|
|
53
|
+
/**
|
|
54
|
+
* Logical name for observability + tool-call routing. Surfaces in
|
|
55
|
+
* Lens chips and event payloads. Defaults to `'mcp'`. Recommend
|
|
56
|
+
* setting per-server (`'slack-mcp'`, `'github-mcp'`) when you
|
|
57
|
+
* connect to multiple servers.
|
|
58
|
+
*/
|
|
59
|
+
readonly name?: string;
|
|
60
|
+
/** Transport configuration — stdio or http. */
|
|
61
|
+
readonly transport: McpTransport;
|
|
62
|
+
/**
|
|
63
|
+
* Optional client identity sent on connect. Default:
|
|
64
|
+
* `{ name: 'agentfootprint', version: <package version> }`.
|
|
65
|
+
*/
|
|
66
|
+
readonly clientInfo?: {
|
|
67
|
+
readonly name: string;
|
|
68
|
+
readonly version: string;
|
|
69
|
+
};
|
|
70
|
+
/** Abort the connection / list / call paths. Honored by the SDK. */
|
|
71
|
+
readonly signal?: AbortSignal;
|
|
72
|
+
/**
|
|
73
|
+
* @internal Pre-built SDK client for tests. Skips SDK import +
|
|
74
|
+
* transport construction. Same convention as `AnthropicProvider._client`.
|
|
75
|
+
*/
|
|
76
|
+
readonly _client?: McpSdkClient;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* What `mcpClient(opts)` returns. Connect once; call `.tools()` to
|
|
80
|
+
* snapshot the tool list, `.refresh()` to re-list after the server's
|
|
81
|
+
* tools change, `.close()` when done.
|
|
82
|
+
*/
|
|
83
|
+
export interface McpClient {
|
|
84
|
+
/** Logical name from options (or default `'mcp'`). */
|
|
85
|
+
readonly name: string;
|
|
86
|
+
/**
|
|
87
|
+
* List the server's tools as agentfootprint `Tool[]`. First call
|
|
88
|
+
* after `mcpClient(...)` is the snapshot used to register on the
|
|
89
|
+
* agent; subsequent calls re-fetch (cheap, in-memory cached by the
|
|
90
|
+
* SDK between fetches).
|
|
91
|
+
*/
|
|
92
|
+
tools(): Promise<readonly Tool[]>;
|
|
93
|
+
/**
|
|
94
|
+
* Force a refresh from the server. Use when you suspect the server
|
|
95
|
+
* has dynamically added/removed tools mid-session (e.g., after the
|
|
96
|
+
* server processes a config update).
|
|
97
|
+
*/
|
|
98
|
+
refresh(): Promise<readonly Tool[]>;
|
|
99
|
+
/** Close the underlying transport. After `close()` the client is unusable. */
|
|
100
|
+
close(): Promise<void>;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Minimal structural type capturing the parts of the MCP SDK client
|
|
104
|
+
* we touch. Defined locally so we can:
|
|
105
|
+
* 1. Inject a mock for tests (`McpClientOptions._client`)
|
|
106
|
+
* 2. Avoid a hard import on `@modelcontextprotocol/sdk` (which is
|
|
107
|
+
* a lazy peer-dep)
|
|
108
|
+
*
|
|
109
|
+
* The real SDK exports a richer surface; we narrow to what's needed.
|
|
110
|
+
*/
|
|
111
|
+
export interface McpSdkClient {
|
|
112
|
+
connect(transport: unknown): Promise<void>;
|
|
113
|
+
listTools(): Promise<{
|
|
114
|
+
readonly tools: ReadonlyArray<{
|
|
115
|
+
readonly name: string;
|
|
116
|
+
readonly description?: string;
|
|
117
|
+
readonly inputSchema: Readonly<Record<string, unknown>>;
|
|
118
|
+
}>;
|
|
119
|
+
}>;
|
|
120
|
+
callTool(args: {
|
|
121
|
+
readonly name: string;
|
|
122
|
+
readonly arguments?: Readonly<Record<string, unknown>>;
|
|
123
|
+
}): Promise<{
|
|
124
|
+
readonly content: ReadonlyArray<{
|
|
125
|
+
readonly type: string;
|
|
126
|
+
readonly text?: string;
|
|
127
|
+
}>;
|
|
128
|
+
readonly isError?: boolean;
|
|
129
|
+
}>;
|
|
130
|
+
close(): Promise<void>;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/lib/mcp/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAIhD;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,iEAAiE;IACjE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,+CAA+C;IAC/C,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAChD,4CAA4C;IAC5C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,+BAA+B;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACrD;AAED,MAAM,MAAM,YAAY,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAIhE,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEvB,+CAA+C;IAC/C,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IAEjC;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAE1E,oEAAoE;IACpE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAE9B;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC;CACjC;AAID;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,sDAAsD;IACtD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;;;OAKG;IACH,KAAK,IAAI,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IAElC;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IAEpC,8EAA8E;IAC9E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAID;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,SAAS,IAAI,OAAO,CAAC;QACnB,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;YAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;YACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;YAC9B,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;SACzD,CAAC,CAAC;KACJ,CAAC,CAAC;IACH,QAAQ,CAAC,IAAI,EAAE;QACb,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;KACxD,GAAG,OAAO,CAAC;QACV,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;YAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;YACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;SACxB,CAAC,CAAC;QACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;KAC5B,CAAC,CAAC;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* defineRAG — sugar factory for retrieval-augmented generation.
|
|
3
|
+
*
|
|
4
|
+
* RAG is a context-engineering flavor: embed the user's question,
|
|
5
|
+
* retrieve top-K semantically similar chunks from a vector store,
|
|
6
|
+
* inject those chunks into the messages slot of the next LLM call.
|
|
7
|
+
* It's the same plumbing as `defineMemory({ type: SEMANTIC,
|
|
8
|
+
* strategy: TOP_K })` — the rename is for intent + ergonomics.
|
|
9
|
+
*
|
|
10
|
+
* defineMemory ─┬─► EPISODIC (raw conversation)
|
|
11
|
+
* ├─► SEMANTIC (extracted facts / RAG chunks)
|
|
12
|
+
* ├─► NARRATIVE (beats / summaries)
|
|
13
|
+
* └─► CAUSAL (footprintjs decision snapshots)
|
|
14
|
+
*
|
|
15
|
+
* defineRAG ─► SEMANTIC + TOP_K with RAG-specific defaults
|
|
16
|
+
* (asRole='user', threshold=0.7, no LLM-extract)
|
|
17
|
+
*
|
|
18
|
+
* Pattern: Composition over duplication — defineRAG returns a
|
|
19
|
+
* MemoryDefinition produced by defineMemory. No new engine
|
|
20
|
+
* code, no new slot subflow, no new event type.
|
|
21
|
+
*
|
|
22
|
+
* Role: Layer-3 context-engineering primitive. Lives next to
|
|
23
|
+
* defineSkill / defineSteering / defineInstruction / defineFact
|
|
24
|
+
* but resolves to a memory subflow rather than an Injection
|
|
25
|
+
* (RAG content is computed at runtime via async retrieval —
|
|
26
|
+
* can't fit the synchronous Injection.inject shape).
|
|
27
|
+
*
|
|
28
|
+
* Emits: Indirectly — the underlying memory pipeline emits
|
|
29
|
+
* `agentfootprint.context.injected` when retrieved chunks
|
|
30
|
+
* land in the messages slot.
|
|
31
|
+
*
|
|
32
|
+
* 7-panel review (2026-04-29):
|
|
33
|
+
* - LLM Systems ✅ injects as 'user' role by default — RAG chunks
|
|
34
|
+
* land where the LLM treats them as authoritative
|
|
35
|
+
* retrieved context, not behavior rules
|
|
36
|
+
* - Architect ✅ composition over defineMemory; zero new engine
|
|
37
|
+
* code; multi-RAG layering works via per-id keys
|
|
38
|
+
* - API Designer ✅ one factory, mirrors defineMemory shape; consumer
|
|
39
|
+
* ergonomics: `agent.rag(defineRAG({...}))`
|
|
40
|
+
* - Performance ✅ embedding cost is one call per turn (TURN_START
|
|
41
|
+
* timing, default); strict threshold prevents
|
|
42
|
+
* injecting low-confidence noise
|
|
43
|
+
* - Privacy ✅ multi-tenant via MemoryIdentity tuple; doc
|
|
44
|
+
* content never crosses tenant boundaries
|
|
45
|
+
* - ML / IR ✅ embedder version pinned via `embedderId`; cosine
|
|
46
|
+
* score semantics inherited from MemoryStore
|
|
47
|
+
* - SoftEng ✅ thin file (this one); existing memory tests
|
|
48
|
+
* cover the underlying pipeline
|
|
49
|
+
*
|
|
50
|
+
* @see ./indexDocuments.ts for the seeding helper
|
|
51
|
+
* @see ../../memory/define.ts for the underlying factory
|
|
52
|
+
*
|
|
53
|
+
* @example Basic usage
|
|
54
|
+
* ```ts
|
|
55
|
+
* import {
|
|
56
|
+
* Agent, defineRAG, indexDocuments, InMemoryStore, mockEmbedder,
|
|
57
|
+
* } from 'agentfootprint';
|
|
58
|
+
*
|
|
59
|
+
* const embedder = mockEmbedder();
|
|
60
|
+
* const store = new InMemoryStore();
|
|
61
|
+
*
|
|
62
|
+
* // Seed the store once at startup
|
|
63
|
+
* await indexDocuments(store, embedder, [
|
|
64
|
+
* { id: 'doc1', content: 'Refunds are processed within 3 business days.' },
|
|
65
|
+
* { id: 'doc2', content: 'Pro plan costs $20/month.' },
|
|
66
|
+
* ]);
|
|
67
|
+
*
|
|
68
|
+
* const docs = defineRAG({
|
|
69
|
+
* id: 'product-docs',
|
|
70
|
+
* description: 'Retrieve product documentation chunks',
|
|
71
|
+
* store,
|
|
72
|
+
* embedder,
|
|
73
|
+
* topK: 3,
|
|
74
|
+
* threshold: 0.6,
|
|
75
|
+
* });
|
|
76
|
+
*
|
|
77
|
+
* const agent = Agent.create({ provider }).rag(docs).build();
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
import type { ContextRole } from '../../events/types.js';
|
|
81
|
+
import type { Embedder } from '../../memory/embedding/index.js';
|
|
82
|
+
import type { MemoryStore } from '../../memory/store/index.js';
|
|
83
|
+
import type { MemoryDefinition } from '../../memory/define.types.js';
|
|
84
|
+
export interface DefineRAGOptions {
|
|
85
|
+
/** Stable id. Becomes the scope-key suffix and the Lens label. */
|
|
86
|
+
readonly id: string;
|
|
87
|
+
/**
|
|
88
|
+
* Human-readable description. Surfaces in narrative + Lens hover.
|
|
89
|
+
* Recommend describing the *corpus* (e.g., "Product documentation
|
|
90
|
+
* chunks indexed weekly from docs.example.com").
|
|
91
|
+
*/
|
|
92
|
+
readonly description?: string;
|
|
93
|
+
/**
|
|
94
|
+
* Vector-capable store containing the indexed corpus. Must implement
|
|
95
|
+
* `search()`. Use `indexDocuments(store, embedder, docs)` at startup
|
|
96
|
+
* to populate it. Ships with `InMemoryStore` for dev/tests; swap to
|
|
97
|
+
* `pgvector` / Pinecone / Qdrant adapters in production.
|
|
98
|
+
*/
|
|
99
|
+
readonly store: MemoryStore;
|
|
100
|
+
/**
|
|
101
|
+
* Embedder used for the read-side query. Pass the SAME embedder
|
|
102
|
+
* instance (or one with the same `name`) that was used for indexing
|
|
103
|
+
* — cross-model similarity scores are not comparable.
|
|
104
|
+
*/
|
|
105
|
+
readonly embedder: Embedder;
|
|
106
|
+
/**
|
|
107
|
+
* Stable id of the embedder. Stored on entries during indexing
|
|
108
|
+
* (via `indexDocuments`) and filtered at search time so a later
|
|
109
|
+
* embedder swap doesn't pollute results.
|
|
110
|
+
*/
|
|
111
|
+
readonly embedderId?: string;
|
|
112
|
+
/**
|
|
113
|
+
* Top-K chunks to retrieve per turn. Default 3 (balanced —
|
|
114
|
+
* defends against lost-in-the-middle while giving multiple
|
|
115
|
+
* perspectives). Increase for richer context, decrease for cost.
|
|
116
|
+
*/
|
|
117
|
+
readonly topK?: number;
|
|
118
|
+
/**
|
|
119
|
+
* Minimum cosine similarity to inject. **Strict** — when no chunk
|
|
120
|
+
* meets the threshold, NO injection happens (no fallback that would
|
|
121
|
+
* pollute the prompt with weak matches). Default 0.7.
|
|
122
|
+
*/
|
|
123
|
+
readonly threshold?: number;
|
|
124
|
+
/**
|
|
125
|
+
* Role to use when injecting retrieved chunks into the messages
|
|
126
|
+
* slot. Default `'user'` — RAG chunks are most often treated as
|
|
127
|
+
* "context the user provided" by LLMs. Use `'system'` for
|
|
128
|
+
* authoritative reference docs that should outweigh user instruction.
|
|
129
|
+
*/
|
|
130
|
+
readonly asRole?: ContextRole;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Build a RAG context-engineering definition. The returned
|
|
134
|
+
* `MemoryDefinition` is registered on the Agent via `.rag(definition)`
|
|
135
|
+
* (or, equivalently, `.memory(definition)` — same plumbing).
|
|
136
|
+
*
|
|
137
|
+
* @throws when `store` does not implement `search()`. RAG requires a
|
|
138
|
+
* vector-capable adapter.
|
|
139
|
+
*/
|
|
140
|
+
export declare function defineRAG(opts: DefineRAGOptions): MemoryDefinition;
|
|
141
|
+
//# sourceMappingURL=defineRAG.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defineRAG.d.ts","sourceRoot":"","sources":["../../../../src/lib/rag/defineRAG.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8EG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAIrE,MAAM,WAAW,gBAAgB;IAC/B,kEAAkE;IAClE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAE5B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAE5B;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAE7B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEvB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAE5B;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,gBAAgB,CA8BlE"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RAG — retrieval-augmented generation as a context-engineering
|
|
3
|
+
* flavor. ONE factory + ONE seeding helper. Composes over the memory
|
|
4
|
+
* subsystem (semantic + top-K + strict threshold).
|
|
5
|
+
*/
|
|
6
|
+
export { defineRAG, type DefineRAGOptions } from './defineRAG.js';
|
|
7
|
+
export { indexDocuments, type IndexDocumentsOptions, type RagDocument } from './indexDocuments.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/rag/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* indexDocuments — seed a vector-capable MemoryStore with documents.
|
|
3
|
+
*
|
|
4
|
+
* Embeds each document, builds a `MemoryEntry<{content, metadata?}>`,
|
|
5
|
+
* batches into `store.putMany()`. Used at application startup to
|
|
6
|
+
* populate a RAG store before the first agent run.
|
|
7
|
+
*
|
|
8
|
+
* Pattern: Bulk-write helper. Not a flowchart stage — it runs once
|
|
9
|
+
* at boot, not per-iteration.
|
|
10
|
+
* Role: Layer-3 RAG pipeline starter. Pairs with `defineRAG()`
|
|
11
|
+
* which only does the read side.
|
|
12
|
+
* Emits: N/A — startup-time batch write, not part of the agent run.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { InMemoryStore, mockEmbedder, indexDocuments, defineRAG } from 'agentfootprint';
|
|
17
|
+
*
|
|
18
|
+
* const store = new InMemoryStore();
|
|
19
|
+
* const embedder = mockEmbedder();
|
|
20
|
+
*
|
|
21
|
+
* await indexDocuments(store, embedder, [
|
|
22
|
+
* { id: 'doc1', content: 'Refunds processed within 3 business days.' },
|
|
23
|
+
* { id: 'doc2', content: 'Pro plan: $20/mo, includes priority support.', metadata: { tier: 'pro' } },
|
|
24
|
+
* { id: 'doc3', content: 'Free plan: limited to 100 calls/month.' },
|
|
25
|
+
* ]);
|
|
26
|
+
*
|
|
27
|
+
* const docs = defineRAG({ id: 'product-docs', store, embedder });
|
|
28
|
+
* agent.rag(docs);
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
import type { Embedder } from '../../memory/embedding/index.js';
|
|
32
|
+
import type { MemoryStore } from '../../memory/store/index.js';
|
|
33
|
+
import type { MemoryIdentity } from '../../memory/identity/index.js';
|
|
34
|
+
/** A document to index. `id` must be unique within the store + identity. */
|
|
35
|
+
export interface RagDocument {
|
|
36
|
+
readonly id: string;
|
|
37
|
+
readonly content: string;
|
|
38
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
39
|
+
}
|
|
40
|
+
export interface IndexDocumentsOptions {
|
|
41
|
+
/**
|
|
42
|
+
* Identity scope to write under. Default: a single shared
|
|
43
|
+
* `{ conversationId: '_global' }` namespace, suitable for app-wide
|
|
44
|
+
* corpora. Override for per-tenant document partitions.
|
|
45
|
+
*/
|
|
46
|
+
readonly identity?: MemoryIdentity;
|
|
47
|
+
/**
|
|
48
|
+
* Stable id of the embedder. Stored on each entry so a future
|
|
49
|
+
* embedder swap doesn't silently mix similarity scores. Default:
|
|
50
|
+
* `'default-embedder'` — pass an explicit id when you may rotate
|
|
51
|
+
* embedders.
|
|
52
|
+
*/
|
|
53
|
+
readonly embedderId?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Optional tier tag to attach to indexed entries (`'hot'` /
|
|
56
|
+
* `'warm'` / `'cold'`). Useful when read-side `defineRAG` should
|
|
57
|
+
* filter to a subset of the corpus.
|
|
58
|
+
*/
|
|
59
|
+
readonly tier?: 'hot' | 'warm' | 'cold';
|
|
60
|
+
/**
|
|
61
|
+
* Optional TTL in milliseconds from indexing time. Useful for
|
|
62
|
+
* compliance retention windows (e.g., re-index quarterly).
|
|
63
|
+
*/
|
|
64
|
+
readonly ttlMs?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Optional abort signal — embedders making network calls thread
|
|
67
|
+
* this through to abort batch indexing on shutdown / timeout.
|
|
68
|
+
*/
|
|
69
|
+
readonly signal?: AbortSignal;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Embed + persist documents. Returns the count actually indexed
|
|
73
|
+
* (skips duplicates if the store rejects them). Throws on embedder
|
|
74
|
+
* failure or store error — fail loud at startup is desirable.
|
|
75
|
+
*/
|
|
76
|
+
export declare function indexDocuments(store: MemoryStore, embedder: Embedder, documents: readonly RagDocument[], options?: IndexDocumentsOptions): Promise<number>;
|
|
77
|
+
//# sourceMappingURL=indexDocuments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexDocuments.d.ts","sourceRoot":"","sources":["../../../../src/lib/rag/indexDocuments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAEhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAErE,4EAA4E;AAC5E,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAEnC;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAE7B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IAExC;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAID;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,SAAS,WAAW,EAAE,EACjC,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,MAAM,CAAC,CAwCjB"}
|
package/package.json
CHANGED