@tpsdev-ai/agent 0.2.0 → 0.4.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.
Files changed (99) hide show
  1. package/README.md +54 -0
  2. package/dist/bin.d.ts +3 -0
  3. package/dist/bin.d.ts.map +1 -0
  4. package/dist/bin.js +32 -0
  5. package/dist/bin.js.map +1 -0
  6. package/dist/config.d.ts +23 -0
  7. package/dist/config.d.ts.map +1 -0
  8. package/dist/config.js +39 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/governance/boundary.d.ts +30 -0
  11. package/dist/governance/boundary.d.ts.map +1 -0
  12. package/dist/governance/boundary.js +120 -0
  13. package/dist/governance/boundary.js.map +1 -0
  14. package/dist/governance/review-gate.d.ts +9 -0
  15. package/dist/governance/review-gate.d.ts.map +1 -0
  16. package/dist/governance/review-gate.js +28 -0
  17. package/dist/governance/review-gate.js.map +1 -0
  18. package/dist/index.d.ts +16 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +19 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/io/context.d.ts +18 -0
  23. package/dist/io/context.d.ts.map +1 -0
  24. package/dist/io/context.js +76 -0
  25. package/dist/io/context.js.map +1 -0
  26. package/dist/io/mail.d.ts +22 -0
  27. package/dist/io/mail.d.ts.map +1 -0
  28. package/dist/io/mail.js +45 -0
  29. package/dist/io/mail.js.map +1 -0
  30. package/dist/io/memory.d.ts +24 -0
  31. package/dist/io/memory.d.ts.map +1 -0
  32. package/dist/io/memory.js +91 -0
  33. package/dist/io/memory.js.map +1 -0
  34. package/dist/llm/provider.d.ts +26 -0
  35. package/dist/llm/provider.d.ts.map +1 -0
  36. package/dist/llm/provider.js +254 -0
  37. package/dist/llm/provider.js.map +1 -0
  38. package/dist/runtime/agent.d.ts +14 -0
  39. package/dist/runtime/agent.d.ts.map +1 -0
  40. package/dist/runtime/agent.js +46 -0
  41. package/dist/runtime/agent.js.map +1 -0
  42. package/dist/runtime/event-loop.d.ts +32 -0
  43. package/dist/runtime/event-loop.d.ts.map +1 -0
  44. package/dist/runtime/event-loop.js +178 -0
  45. package/dist/runtime/event-loop.js.map +1 -0
  46. package/dist/runtime/types.d.ts +66 -0
  47. package/dist/runtime/types.d.ts.map +1 -0
  48. package/dist/runtime/types.js +2 -0
  49. package/dist/runtime/types.js.map +1 -0
  50. package/dist/tools/edit.d.ts +4 -0
  51. package/dist/tools/edit.d.ts.map +1 -0
  52. package/dist/tools/edit.js +46 -0
  53. package/dist/tools/edit.js.map +1 -0
  54. package/dist/tools/exec.d.ts +4 -0
  55. package/dist/tools/exec.d.ts.map +1 -0
  56. package/dist/tools/exec.js +74 -0
  57. package/dist/tools/exec.js.map +1 -0
  58. package/dist/tools/index.d.ts +17 -0
  59. package/dist/tools/index.d.ts.map +1 -0
  60. package/dist/tools/index.js +23 -0
  61. package/dist/tools/index.js.map +1 -0
  62. package/dist/tools/mail.d.ts +4 -0
  63. package/dist/tools/mail.d.ts.map +1 -0
  64. package/dist/tools/mail.js +19 -0
  65. package/dist/tools/mail.js.map +1 -0
  66. package/dist/tools/read.d.ts +4 -0
  67. package/dist/tools/read.d.ts.map +1 -0
  68. package/dist/tools/read.js +31 -0
  69. package/dist/tools/read.js.map +1 -0
  70. package/dist/tools/registry.d.ts +24 -0
  71. package/dist/tools/registry.d.ts.map +1 -0
  72. package/dist/tools/registry.js +23 -0
  73. package/dist/tools/registry.js.map +1 -0
  74. package/dist/tools/write.d.ts +4 -0
  75. package/dist/tools/write.d.ts.map +1 -0
  76. package/dist/tools/write.js +32 -0
  77. package/dist/tools/write.js.map +1 -0
  78. package/package.json +19 -4
  79. package/src/bin.ts +40 -0
  80. package/src/config.ts +64 -0
  81. package/src/governance/boundary.ts +112 -18
  82. package/src/index.ts +15 -2
  83. package/src/io/context.ts +59 -15
  84. package/src/io/memory.ts +53 -9
  85. package/src/llm/provider.ts +203 -42
  86. package/src/runtime/agent.ts +30 -3
  87. package/src/runtime/event-loop.ts +168 -26
  88. package/src/runtime/types.ts +54 -6
  89. package/src/tools/edit.ts +59 -0
  90. package/src/tools/exec.ts +92 -0
  91. package/src/tools/index.ts +30 -0
  92. package/src/tools/mail.ts +28 -0
  93. package/src/tools/read.ts +38 -0
  94. package/src/tools/registry.ts +16 -7
  95. package/src/tools/write.ts +40 -0
  96. package/src/types/js-tiktoken.d.ts +7 -0
  97. package/test/governance.test.ts +61 -32
  98. package/test/io.test.ts +15 -7
  99. package/test/runtime.test.ts +26 -5
package/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # @tpsdev-ai/agent
2
+
3
+ > Native TPS Agent Runtime — headless, mail-driven, sandbox-ready.
4
+
5
+ The runtime library for building AI agents that run inside [TPS](https://github.com/tpsdev-ai/cli) branch offices. Provides the core primitives: event loop, mail I/O, memory, LLM provider management, tool registry, and governance boundaries.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @tpsdev-ai/agent
11
+ ```
12
+
13
+ ## What's Inside
14
+
15
+ | Module | Description |
16
+ |--------|-------------|
17
+ | `AgentRuntime` | Main lifecycle manager — boot, run, shutdown |
18
+ | `EventLoop` | Mail-driven event processing with backpressure |
19
+ | `MailClient` | Async Maildir-based messaging (send/receive/queue) |
20
+ | `MemoryStore` | Append-only memory with tail-read and size caps |
21
+ | `ContextManager` | Workspace context injection and brief generation |
22
+ | `ProviderManager` | Multi-provider LLM access (Anthropic, OpenAI, Google, Ollama) |
23
+ | `ToolRegistry` | Capability registration with boundary enforcement |
24
+ | `BoundaryManager` | Sandbox permission checks — filesystem, network, exec |
25
+ | `ReviewGate` | Human-in-the-loop approval for sensitive operations |
26
+
27
+ ## Quick Example
28
+
29
+ ```typescript
30
+ import { AgentRuntime, MailClient, MemoryStore } from "@tpsdev-ai/agent";
31
+
32
+ const runtime = new AgentRuntime({
33
+ agentId: "researcher",
34
+ workspace: "/home/researcher/.tps",
35
+ provider: { model: "claude-sonnet-4-20250514", provider: "anthropic" },
36
+ });
37
+
38
+ await runtime.boot();
39
+ await runtime.run(); // starts the mail-driven event loop
40
+ ```
41
+
42
+ ## Design Principles
43
+
44
+ - **Mail-driven, not chat-driven.** Agents communicate through persistent async mail, not ephemeral conversations.
45
+ - **Sandbox-first.** Every operation checks boundaries before executing. Works with `nono` profiles and Docker isolation.
46
+ - **No shared memory.** Agents are isolated by default. Coordination happens through mail and git, not shared state.
47
+
48
+ ## Used By
49
+
50
+ - [`@tpsdev-ai/cli`](https://www.npmjs.com/package/@tpsdev-ai/cli) — the TPS command-line interface
51
+
52
+ ## License
53
+
54
+ Apache-2.0
package/dist/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ import { AgentRuntime } from "./runtime/agent.js";
3
+ import { loadAgentConfig } from "./config.js";
4
+ function usage() {
5
+ console.error("Usage: tps-agent run --config <agent.yaml> --message <text>");
6
+ process.exit(1);
7
+ }
8
+ async function main() {
9
+ const args = process.argv.slice(2);
10
+ const cmd = args[0];
11
+ if (cmd !== "run") {
12
+ usage();
13
+ }
14
+ const configIdx = args.indexOf("--config");
15
+ const msgIdx = args.indexOf("--message");
16
+ if (configIdx < 0 || msgIdx < 0) {
17
+ usage();
18
+ }
19
+ const configPath = args[configIdx + 1];
20
+ const message = args.slice(msgIdx + 1).join(" ");
21
+ if (!configPath || !message) {
22
+ usage();
23
+ }
24
+ const config = loadAgentConfig(configPath);
25
+ const runtime = new AgentRuntime(config);
26
+ await runtime.runOnce(message);
27
+ }
28
+ main().catch((err) => {
29
+ console.error(err?.message || err);
30
+ process.exit(1);
31
+ });
32
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,SAAS,KAAK;IACZ,OAAO,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;IAC7E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAEpB,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;QAClB,KAAK,EAAE,CAAC;IACV,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAEzC,IAAI,SAAS,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,KAAK,EAAE,CAAC;IACV,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEjD,IAAI,CAAC,UAAU,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,KAAK,EAAE,CAAC;IACV,CAAC;IAED,MAAM,MAAM,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,IAAI,GAAG,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { AgentConfig } from "./runtime/types.js";
2
+ export interface AgentRuntimeConfig {
3
+ agentId: string;
4
+ name: string;
5
+ mailDir: string;
6
+ memoryPath?: string;
7
+ workspace: string;
8
+ systemPrompt?: string;
9
+ llm: {
10
+ provider: "anthropic" | "google" | "openai" | "ollama";
11
+ model: string;
12
+ apiKey?: string;
13
+ baseUrl?: string;
14
+ };
15
+ contextWindowTokens?: number;
16
+ maxTokens?: number;
17
+ tools?: Array<"read" | "write" | "edit" | "exec" | "mail">;
18
+ execAllowlist?: string[];
19
+ }
20
+ export declare function loadAgentConfig(path: string): AgentConfig;
21
+ export declare function defaultMemoryPath(workspace: string): string;
22
+ export declare function normalizeConfigObject(value: unknown): AgentRuntimeConfig;
23
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE;QACH,QAAQ,EAAE,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;QACvD,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,CAAC;IAC3D,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CA2BzD;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,CAKxE"}
package/dist/config.js ADDED
@@ -0,0 +1,39 @@
1
+ import { readFileSync } from "node:fs";
2
+ import yaml from "js-yaml";
3
+ import { createHash } from "node:crypto";
4
+ export function loadAgentConfig(path) {
5
+ const raw = readFileSync(path, "utf-8");
6
+ const parsed = (yaml.load(raw) ?? {});
7
+ const workspace = String(parsed.workspace || parsed.repo || process.cwd());
8
+ const memoryPath = parsed.memoryPath || `${workspace}/.openclaw/agent.memory.jsonl`;
9
+ const agent = {
10
+ agentId: String(parsed.agentId || parsed.id || "agent"),
11
+ name: String(parsed.name || parsed.agentId || "agent"),
12
+ workspace,
13
+ mailDir: String(parsed.mailDir || `${workspace}/mail`),
14
+ memoryPath: String(memoryPath),
15
+ systemPrompt: parsed.systemPrompt ? String(parsed.systemPrompt) : undefined,
16
+ contextWindowTokens: parsed.contextWindowTokens ? Number(parsed.contextWindowTokens) : 8192,
17
+ maxTokens: parsed.maxTokens ? Number(parsed.maxTokens) : 1024,
18
+ tools: parsed.tools ?? ["read", "write", "edit", "exec", "mail"],
19
+ execAllowlist: parsed.execAllowlist,
20
+ llm: {
21
+ provider: parsed.llm?.provider || parsed.provider || "openai",
22
+ model: parsed.llm?.model || parsed.model || "gpt-4o-mini",
23
+ apiKey: parsed.llm?.apiKey || parsed.apiKey,
24
+ baseUrl: parsed.llm?.baseUrl || parsed.baseUrl,
25
+ },
26
+ };
27
+ return agent;
28
+ }
29
+ export function defaultMemoryPath(workspace) {
30
+ const digest = createHash("sha1").update(workspace).digest("hex").slice(0, 8);
31
+ return `${workspace}/.openclaw/memory-${digest}.jsonl`;
32
+ }
33
+ export function normalizeConfigObject(value) {
34
+ if (typeof value !== "object" || !value) {
35
+ throw new Error("Invalid agent config");
36
+ }
37
+ return value;
38
+ }
39
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAsBzC,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAwB,CAAC;IAE7D,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3E,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,GAAG,SAAS,+BAA+B,CAAC;IAEpF,MAAM,KAAK,GAAgB;QACzB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,EAAE,IAAI,OAAO,CAAC;QACvD,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC;QACtD,SAAS;QACT,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,IAAI,GAAG,SAAS,OAAO,CAAC;QACtD,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;QAC9B,YAAY,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS;QAC3E,mBAAmB,EAAE,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,IAAI;QAC3F,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI;QAC7D,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;QAChE,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,GAAG,EAAE;YACH,QAAQ,EAAE,MAAM,CAAC,GAAG,EAAE,QAAQ,IAAI,MAAM,CAAC,QAAQ,IAAI,QAAQ;YAC7D,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,KAAK,IAAI,MAAM,CAAC,KAAK,IAAI,aAAa;YACzD,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,IAAI,MAAM,CAAC,MAAM;YAC3C,OAAO,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,IAAI,MAAM,CAAC,OAAO;SAC/C;KACF,CAAC;IAEF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,SAAiB;IACjD,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9E,OAAO,GAAG,SAAS,qBAAqB,MAAM,QAAQ,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,KAA2B,CAAC;AACrC,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * BoundaryManager handles execution-time policy controls for security boundaries.
3
+ */
4
+ export declare class BoundaryManager {
5
+ private readonly workspace;
6
+ private allowedNetworkHosts;
7
+ constructor(workspace: string);
8
+ addNetworkHost(host: string): void;
9
+ isNetworkAllowed(host: string): boolean;
10
+ /**
11
+ * Resolve a user requested filesystem path against workspace and ensure
12
+ * it cannot escape the workspace root.
13
+ */
14
+ resolveWorkspacePath(relativeOrAbsolutePath: string): string;
15
+ private isWithinWorkspace;
16
+ /**
17
+ * Verify that a command is safe before exec.
18
+ */
19
+ validateCommand(command: string, args: string[]): void;
20
+ /**
21
+ * Child processes must not inherit runtime secrets from the parent process.
22
+ */
23
+ scrubEnvironment(extraKeys?: string[]): NodeJS.ProcessEnv;
24
+ /** Returns human-readable boundaries for system prompts and audit logs. */
25
+ describeCapabilities(): string;
26
+ static isFileReadable(path: string): boolean;
27
+ static isFileWritable(path: string): boolean;
28
+ static canFollowSymlink(path: string): boolean;
29
+ }
30
+ //# sourceMappingURL=boundary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boundary.d.ts","sourceRoot":"","sources":["../../src/governance/boundary.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,qBAAa,eAAe;IAGd,OAAO,CAAC,QAAQ,CAAC,SAAS;IAFtC,OAAO,CAAC,mBAAmB,CAAqB;gBAEnB,SAAS,EAAE,MAAM;IAE9C,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIlC,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIvC;;;OAGG;IACH,oBAAoB,CAAC,sBAAsB,EAAE,MAAM,GAAG,MAAM;IAsB5D,OAAO,CAAC,iBAAiB;IAOzB;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI;IAqBtD;;OAEG;IACH,gBAAgB,CAAC,SAAS,GAAE,MAAM,EAAO,GAAG,MAAM,CAAC,UAAU;IAmB7D,2EAA2E;IAC3E,oBAAoB,IAAI,MAAM;IAK9B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAS5C,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAS5C,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAQ/C"}
@@ -0,0 +1,120 @@
1
+ import { resolve, relative, isAbsolute, sep } from "node:path";
2
+ import { accessSync, constants, existsSync, lstatSync, realpathSync } from "node:fs";
3
+ /**
4
+ * BoundaryManager handles execution-time policy controls for security boundaries.
5
+ */
6
+ export class BoundaryManager {
7
+ workspace;
8
+ allowedNetworkHosts = new Set();
9
+ constructor(workspace) {
10
+ this.workspace = workspace;
11
+ }
12
+ addNetworkHost(host) {
13
+ this.allowedNetworkHosts.add(host);
14
+ }
15
+ isNetworkAllowed(host) {
16
+ return this.allowedNetworkHosts.has(host) || this.allowedNetworkHosts.has("*");
17
+ }
18
+ /**
19
+ * Resolve a user requested filesystem path against workspace and ensure
20
+ * it cannot escape the workspace root.
21
+ */
22
+ resolveWorkspacePath(relativeOrAbsolutePath) {
23
+ const target = resolve(this.workspace, relativeOrAbsolutePath);
24
+ const workspaceReal = realpathSync(this.workspace);
25
+ let normalized = target;
26
+ if (existsSync(target)) {
27
+ normalized = realpathSync(target);
28
+ }
29
+ else {
30
+ // If target does not exist, resolve relative to existing parent.
31
+ const parent = resolve(target, "..");
32
+ if (existsSync(parent)) {
33
+ normalized = resolve(realpathSync(parent), target.slice(parent.length + 1));
34
+ }
35
+ }
36
+ if (!this.isWithinWorkspace(normalized, workspaceReal)) {
37
+ throw new Error(`Path traversal blocked: ${relativeOrAbsolutePath}`);
38
+ }
39
+ return target;
40
+ }
41
+ isWithinWorkspace(candidate, workspaceReal) {
42
+ const rel = relative(workspaceReal, candidate);
43
+ if (rel === "")
44
+ return true;
45
+ if (rel === ".." || rel.startsWith(`..${sep}`))
46
+ return false;
47
+ return !isAbsolute(rel);
48
+ }
49
+ /**
50
+ * Verify that a command is safe before exec.
51
+ */
52
+ validateCommand(command, args) {
53
+ if (!command) {
54
+ throw new Error("Exec requires a command");
55
+ }
56
+ const blockedFlags = ["--exec-path", "-e", "--eval", "-p", "-c", "/dev/fd", "--noprofile", "--norc", "node_options", "command="];
57
+ const tokens = [command, ...args].map((token) => String(token).toLowerCase());
58
+ for (const token of tokens) {
59
+ if (blockedFlags.includes(token) || token.includes("core.pager")) {
60
+ throw new Error(`Disallowed exec argument: ${token}`);
61
+ }
62
+ }
63
+ // Disallow attempts to execute compound expressions.
64
+ const full = tokens.join(" ");
65
+ if (full.includes("||") || full.includes("&&") || full.includes(";") || full.includes("|") || full.includes("$") || full.includes("`")) {
66
+ throw new Error(`Disallowed exec argument: ${full}`);
67
+ }
68
+ }
69
+ /**
70
+ * Child processes must not inherit runtime secrets from the parent process.
71
+ */
72
+ scrubEnvironment(extraKeys = []) {
73
+ const env = { ...process.env };
74
+ const denyPattern = /(API_KEY|APISECRET|SECRET|TOKEN|PASS|CREDENTIAL|AUTH)/i;
75
+ for (const key of Object.keys(env)) {
76
+ if (denyPattern.test(key)) {
77
+ delete env[key];
78
+ }
79
+ }
80
+ for (const key of extraKeys) {
81
+ if (key in env) {
82
+ delete env[key];
83
+ }
84
+ }
85
+ return env;
86
+ }
87
+ /** Returns human-readable boundaries for system prompts and audit logs. */
88
+ describeCapabilities() {
89
+ const nets = [...this.allowedNetworkHosts].join(", ") || "none";
90
+ return `Network access: ${nets}\nFilesystem access: ${this.workspace}`;
91
+ }
92
+ static isFileReadable(path) {
93
+ try {
94
+ accessSync(path, constants.R_OK);
95
+ return true;
96
+ }
97
+ catch {
98
+ return false;
99
+ }
100
+ }
101
+ static isFileWritable(path) {
102
+ try {
103
+ accessSync(path, constants.W_OK);
104
+ return true;
105
+ }
106
+ catch {
107
+ return false;
108
+ }
109
+ }
110
+ static canFollowSymlink(path) {
111
+ try {
112
+ const stat = lstatSync(path);
113
+ return !stat.isSymbolicLink();
114
+ }
115
+ catch {
116
+ return false;
117
+ }
118
+ }
119
+ }
120
+ //# sourceMappingURL=boundary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boundary.js","sourceRoot":"","sources":["../../src/governance/boundary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { MailClient } from "../io/mail.js";
2
+ export declare class ReviewGate {
3
+ private readonly mail;
4
+ private readonly approverAddress;
5
+ constructor(mail: MailClient, approverAddress: string);
6
+ isHighRisk(toolName: string): boolean;
7
+ requestApproval(toolName: string, args: Record<string, unknown>): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=review-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-gate.d.ts","sourceRoot":"","sources":["../../src/governance/review-gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAUhD,qBAAa,UAAU;IAEnB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,eAAe;gBADf,IAAI,EAAE,UAAU,EAChB,eAAe,EAAE,MAAM;IAG1C,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAI/B,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAatF"}
@@ -0,0 +1,28 @@
1
+ /** Actions that must pause for human-in-the-loop approval. */
2
+ const HIGH_RISK_ACTIONS = new Set([
3
+ "git_push",
4
+ "package_install",
5
+ "file_delete",
6
+ "exec_privileged",
7
+ ]);
8
+ export class ReviewGate {
9
+ mail;
10
+ approverAddress;
11
+ constructor(mail, approverAddress) {
12
+ this.mail = mail;
13
+ this.approverAddress = approverAddress;
14
+ }
15
+ isHighRisk(toolName) {
16
+ return HIGH_RISK_ACTIONS.has(toolName);
17
+ }
18
+ async requestApproval(toolName, args) {
19
+ const body = JSON.stringify({
20
+ type: "approval_request",
21
+ tool: toolName,
22
+ args,
23
+ requestedAt: new Date().toISOString(),
24
+ }, null, 2);
25
+ await this.mail.sendMail(this.approverAddress, body);
26
+ }
27
+ }
28
+ //# sourceMappingURL=review-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-gate.js","sourceRoot":"","sources":["../../src/governance/review-gate.ts"],"names":[],"mappings":"AAEA,8DAA8D;AAC9D,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,UAAU;IACV,iBAAiB;IACjB,aAAa;IACb,iBAAiB;CAClB,CAAC,CAAC;AAEH,MAAM,OAAO,UAAU;IAEF;IACA;IAFnB,YACmB,IAAgB,EAChB,eAAuB;QADvB,SAAI,GAAJ,IAAI,CAAY;QAChB,oBAAe,GAAf,eAAe,CAAQ;IACvC,CAAC;IAEJ,UAAU,CAAC,QAAgB;QACzB,OAAO,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,QAAgB,EAAE,IAA6B;QACnE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CACzB;YACE,IAAI,EAAE,kBAAkB;YACxB,IAAI,EAAE,QAAQ;YACd,IAAI;YACJ,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACtC,EACD,IAAI,EACJ,CAAC,CACF,CAAC;QACF,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;IACvD,CAAC;CACF"}
@@ -0,0 +1,16 @@
1
+ export { AgentRuntime } from "./runtime/agent.js";
2
+ export { EventLoop } from "./runtime/event-loop.js";
3
+ export type { AgentConfig, LLMConfig, AgentState, CompletionRequest, CompletionResponse, ToolCall, ToolSpec, LLMMessage, ToolResult, } from "./runtime/types.js";
4
+ export { MailClient } from "./io/mail.js";
5
+ export type { MailMessage } from "./io/mail.js";
6
+ export { MemoryStore } from "./io/memory.js";
7
+ export type { MemoryEvent } from "./io/memory.js";
8
+ export { ContextManager } from "./io/context.js";
9
+ export { ProviderManager } from "./llm/provider.js";
10
+ export { ToolRegistry } from "./tools/registry.js";
11
+ export type { Tool } from "./tools/registry.js";
12
+ export { createDefaultToolset } from "./tools/index.js";
13
+ export { BoundaryManager } from "./governance/boundary.js";
14
+ export { ReviewGate } from "./governance/review-gate.js";
15
+ export { loadAgentConfig } from "./config.js";
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,YAAY,EACV,WAAW,EACX,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,UAAU,GACX,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAGxD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAGzD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ // Public API for @tpsdev-ai/agent
2
+ // Runtime
3
+ export { AgentRuntime } from "./runtime/agent.js";
4
+ export { EventLoop } from "./runtime/event-loop.js";
5
+ // I/O
6
+ export { MailClient } from "./io/mail.js";
7
+ export { MemoryStore } from "./io/memory.js";
8
+ export { ContextManager } from "./io/context.js";
9
+ // LLM
10
+ export { ProviderManager } from "./llm/provider.js";
11
+ // Tools
12
+ export { ToolRegistry } from "./tools/registry.js";
13
+ export { createDefaultToolset } from "./tools/index.js";
14
+ // Governance
15
+ export { BoundaryManager } from "./governance/boundary.js";
16
+ export { ReviewGate } from "./governance/review-gate.js";
17
+ // Config
18
+ export { loadAgentConfig } from "./config.js";
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAElC,UAAU;AACV,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAapD,MAAM;AACN,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM;AACN,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,QAAQ;AACR,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,aAAa;AACb,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEzD,SAAS;AACT,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { MemoryStore, MemoryEvent } from "./memory.js";
2
+ /**
3
+ * Sliding window context manager with token-based compaction.
4
+ */
5
+ export declare class ContextManager {
6
+ private readonly memory;
7
+ private readonly windowTokens;
8
+ private encoder?;
9
+ constructor(memory: MemoryStore, windowTokens: number);
10
+ private getEncoder;
11
+ private countTokens;
12
+ /** Return recent events that fit within token window. */
13
+ getWindow(): Promise<MemoryEvent[]>;
14
+ /** Returns true if compaction is needed (>80% of window used). */
15
+ needsCompaction(): Promise<boolean>;
16
+ estimateTokenCount(): Promise<number>;
17
+ }
18
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/io/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE5D;;GAEG;AACH,qBAAa,cAAc;IAIvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAJ/B,OAAO,CAAC,OAAO,CAAC,CAAiD;gBAG9C,MAAM,EAAE,WAAW,EACnB,YAAY,EAAE,MAAM;YAKzB,UAAU;YA4BV,WAAW;IAMzB,yDAAyD;IACnD,SAAS,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAmBzC,kEAAkE;IAC5D,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAKnC,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC;CAQ5C"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Sliding window context manager with token-based compaction.
3
+ */
4
+ export class ContextManager {
5
+ memory;
6
+ windowTokens;
7
+ encoder;
8
+ constructor(memory, windowTokens) {
9
+ this.memory = memory;
10
+ this.windowTokens = windowTokens;
11
+ this.encoder = undefined;
12
+ }
13
+ async getEncoder() {
14
+ if (this.encoder)
15
+ return this.encoder;
16
+ try {
17
+ const mod = await import("js-tiktoken");
18
+ const fn = mod.encodingForModel?.("gpt-4o") ||
19
+ mod.encoding_for_model?.("gpt-4o") ||
20
+ mod.getEncoding?.("cl100k_base");
21
+ if (fn) {
22
+ this.encoder = (text) => {
23
+ const tokens = fn.encode(text);
24
+ if (Array.isArray(tokens))
25
+ return tokens;
26
+ return [];
27
+ };
28
+ return this.encoder;
29
+ }
30
+ }
31
+ catch { }
32
+ // Fallback: approximate tokenization (4 chars ~= 1 token)
33
+ this.encoder = (text) => {
34
+ const count = Math.max(1, Math.ceil(text.length / 4));
35
+ return new Array(count);
36
+ };
37
+ return this.encoder;
38
+ }
39
+ async countTokens(text) {
40
+ const encode = await this.getEncoder();
41
+ const tokens = await encode(text);
42
+ return Array.isArray(tokens) ? tokens.length : 0;
43
+ }
44
+ /** Return recent events that fit within token window. */
45
+ async getWindow() {
46
+ const all = this.memory.readAll();
47
+ if (all.length === 0)
48
+ return [];
49
+ const budget = this.windowTokens;
50
+ let budgetRemaining = budget;
51
+ const window = [];
52
+ for (let i = all.length - 1; i >= 0; i--) {
53
+ const serialized = JSON.stringify(all[i]);
54
+ const tokenCount = await this.countTokens(serialized);
55
+ if (tokenCount > budgetRemaining)
56
+ break;
57
+ window.unshift(all[i]);
58
+ budgetRemaining -= tokenCount;
59
+ }
60
+ return window;
61
+ }
62
+ /** Returns true if compaction is needed (>80% of window used). */
63
+ async needsCompaction() {
64
+ const total = await this.estimateTokenCount();
65
+ return total > this.windowTokens * 0.8;
66
+ }
67
+ async estimateTokenCount() {
68
+ const events = this.memory.readAll();
69
+ let total = 0;
70
+ for (const event of events) {
71
+ total += await this.countTokens(JSON.stringify(event));
72
+ }
73
+ return total;
74
+ }
75
+ }
76
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/io/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export interface MailMessage {
2
+ filename: string;
3
+ body: string;
4
+ receivedAt: Date;
5
+ }
6
+ /**
7
+ * Maildir-compatible mail client.
8
+ * Reads from mailDir/inbox/new and moves processed messages to mailDir/inbox/cur.
9
+ * Writes outgoing mail to mailDir/outbox/new.
10
+ */
11
+ export declare class MailClient {
12
+ readonly mailDir: string;
13
+ private inboxNew;
14
+ private inboxCur;
15
+ private outboxNew;
16
+ constructor(mailDir: string);
17
+ /** Return all messages in inbox/new and move them to inbox/cur. */
18
+ checkNewMail(): Promise<MailMessage[]>;
19
+ /** Write a message to outbox/new for relay delivery. */
20
+ sendMail(to: string, body: string): Promise<void>;
21
+ }
22
+ //# sourceMappingURL=mail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail.d.ts","sourceRoot":"","sources":["../../src/io/mail.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,IAAI,CAAC;CAClB;AAED;;;;GAIG;AACH,qBAAa,UAAU;aAKO,OAAO,EAAE,MAAM;IAJ3C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;gBAEE,OAAO,EAAE,MAAM;IAU3C,mEAAmE;IAC7D,YAAY,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAiB5C,wDAAwD;IAClD,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CASxD"}
@@ -0,0 +1,45 @@
1
+ import { existsSync, mkdirSync, readdirSync, renameSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ /**
4
+ * Maildir-compatible mail client.
5
+ * Reads from mailDir/inbox/new and moves processed messages to mailDir/inbox/cur.
6
+ * Writes outgoing mail to mailDir/outbox/new.
7
+ */
8
+ export class MailClient {
9
+ mailDir;
10
+ inboxNew;
11
+ inboxCur;
12
+ outboxNew;
13
+ constructor(mailDir) {
14
+ this.mailDir = mailDir;
15
+ this.inboxNew = join(mailDir, "inbox", "new");
16
+ this.inboxCur = join(mailDir, "inbox", "cur");
17
+ this.outboxNew = join(mailDir, "outbox", "new");
18
+ // Ensure directories exist
19
+ for (const dir of [this.inboxNew, this.inboxCur, this.outboxNew]) {
20
+ mkdirSync(dir, { recursive: true });
21
+ }
22
+ }
23
+ /** Return all messages in inbox/new and move them to inbox/cur. */
24
+ async checkNewMail() {
25
+ if (!existsSync(this.inboxNew))
26
+ return [];
27
+ const files = readdirSync(this.inboxNew).filter((f) => !f.startsWith(".") && !f.includes("/") && !f.includes("\\"));
28
+ const messages = [];
29
+ for (const file of files) {
30
+ const srcPath = join(this.inboxNew, file);
31
+ const dstPath = join(this.inboxCur, file);
32
+ const body = readFileSync(srcPath, "utf-8");
33
+ renameSync(srcPath, dstPath);
34
+ messages.push({ filename: file, body, receivedAt: new Date() });
35
+ }
36
+ return messages;
37
+ }
38
+ /** Write a message to outbox/new for relay delivery. */
39
+ async sendMail(to, body) {
40
+ const { writeFileSync } = await import("node:fs");
41
+ const filename = `${Date.now()}-${Math.random().toString(36).slice(2)}.json`;
42
+ writeFileSync(join(this.outboxNew, filename), JSON.stringify({ to, body, sentAt: new Date().toISOString() }, null, 2), "utf-8");
43
+ }
44
+ }
45
+ //# sourceMappingURL=mail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail.js","sourceRoot":"","sources":["../../src/io/mail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC;;;;GAIG;AACH,MAAM,OAAO,UAAU;IAKO;IAJpB,QAAQ,CAAS;IACjB,QAAQ,CAAS;IACjB,SAAS,CAAS;IAE1B,YAA4B,OAAe;QAAf,YAAO,GAAP,OAAO,CAAQ;QACzC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QAC9C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QAC9C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAChD,2BAA2B;QAC3B,KAAK,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YACjE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED,mEAAmE;IACnE,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,OAAO,EAAE,CAAC;QAE1C,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QACpH,MAAM,QAAQ,GAAkB,EAAE,CAAC;QAEnC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC1C,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC5C,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;QAClE,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,wDAAwD;IACxD,KAAK,CAAC,QAAQ,CAAC,EAAU,EAAE,IAAY;QACrC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;QAC7E,aAAa,CACX,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,EAC9B,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EACvE,OAAO,CACR,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,24 @@
1
+ export interface MemoryEvent {
2
+ type: string;
3
+ ts: string;
4
+ data: unknown;
5
+ }
6
+ /**
7
+ * Append-only JSONL memory store. Each event is a line of JSON.
8
+ * Provides a full audit trail of agent actions and LLM interactions.
9
+ */
10
+ export declare class MemoryStore {
11
+ readonly memoryPath: string;
12
+ constructor(memoryPath: string);
13
+ append(event: MemoryEvent): void;
14
+ readAll(maxBytes?: number): MemoryEvent[];
15
+ /**
16
+ * Scrub sensitive payloads so API keys never get persisted in memory.
17
+ */
18
+ private sanitize;
19
+ private sensitiveValues;
20
+ private mask;
21
+ /** Approximate token count kept for compat; use ContextManager for precise counts. */
22
+ estimatedTokenCount(): number;
23
+ }
24
+ //# sourceMappingURL=memory.d.ts.map