@msm-core/mini 0.1.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.
Files changed (94) hide show
  1. package/README.md +297 -0
  2. package/dist/adapters/index.d.ts +9 -0
  3. package/dist/adapters/index.d.ts.map +1 -0
  4. package/dist/adapters/index.js +7 -0
  5. package/dist/adapters/index.js.map +1 -0
  6. package/dist/adapters/redis-control.d.ts +25 -0
  7. package/dist/adapters/redis-control.d.ts.map +1 -0
  8. package/dist/adapters/redis-control.js +48 -0
  9. package/dist/adapters/redis-control.js.map +1 -0
  10. package/dist/adapters/redis-lock.d.ts +31 -0
  11. package/dist/adapters/redis-lock.d.ts.map +1 -0
  12. package/dist/adapters/redis-lock.js +73 -0
  13. package/dist/adapters/redis-lock.js.map +1 -0
  14. package/dist/adapters/redis-memory.d.ts +42 -0
  15. package/dist/adapters/redis-memory.d.ts.map +1 -0
  16. package/dist/adapters/redis-memory.js +87 -0
  17. package/dist/adapters/redis-memory.js.map +1 -0
  18. package/dist/adapters/redis-types.d.ts +17 -0
  19. package/dist/adapters/redis-types.d.ts.map +1 -0
  20. package/dist/adapters/redis-types.js +2 -0
  21. package/dist/adapters/redis-types.js.map +1 -0
  22. package/dist/brain/anthropic.d.ts +10 -0
  23. package/dist/brain/anthropic.d.ts.map +1 -0
  24. package/dist/brain/anthropic.js +73 -0
  25. package/dist/brain/anthropic.js.map +1 -0
  26. package/dist/brain/factory.d.ts +7 -0
  27. package/dist/brain/factory.d.ts.map +1 -0
  28. package/dist/brain/factory.js +24 -0
  29. package/dist/brain/factory.js.map +1 -0
  30. package/dist/brain/gemini.d.ts +10 -0
  31. package/dist/brain/gemini.d.ts.map +1 -0
  32. package/dist/brain/gemini.js +113 -0
  33. package/dist/brain/gemini.js.map +1 -0
  34. package/dist/brain/ollama.d.ts +10 -0
  35. package/dist/brain/ollama.d.ts.map +1 -0
  36. package/dist/brain/ollama.js +38 -0
  37. package/dist/brain/ollama.js.map +1 -0
  38. package/dist/brain/openai.d.ts +11 -0
  39. package/dist/brain/openai.d.ts.map +1 -0
  40. package/dist/brain/openai.js +96 -0
  41. package/dist/brain/openai.js.map +1 -0
  42. package/dist/brain/types.d.ts +6 -0
  43. package/dist/brain/types.d.ts.map +1 -0
  44. package/dist/brain/types.js +2 -0
  45. package/dist/brain/types.js.map +1 -0
  46. package/dist/core/context-builder.d.ts +25 -0
  47. package/dist/core/context-builder.d.ts.map +1 -0
  48. package/dist/core/context-builder.js +107 -0
  49. package/dist/core/context-builder.js.map +1 -0
  50. package/dist/core/gates.d.ts +16 -0
  51. package/dist/core/gates.d.ts.map +1 -0
  52. package/dist/core/gates.js +70 -0
  53. package/dist/core/gates.js.map +1 -0
  54. package/dist/core/guards.d.ts +22 -0
  55. package/dist/core/guards.d.ts.map +1 -0
  56. package/dist/core/guards.js +119 -0
  57. package/dist/core/guards.js.map +1 -0
  58. package/dist/core/hooks.d.ts +13 -0
  59. package/dist/core/hooks.d.ts.map +1 -0
  60. package/dist/core/hooks.js +61 -0
  61. package/dist/core/hooks.js.map +1 -0
  62. package/dist/core/loop.d.ts +16 -0
  63. package/dist/core/loop.d.ts.map +1 -0
  64. package/dist/core/loop.js +255 -0
  65. package/dist/core/loop.js.map +1 -0
  66. package/dist/core/types.d.ts +310 -0
  67. package/dist/core/types.d.ts.map +1 -0
  68. package/dist/core/types.js +8 -0
  69. package/dist/core/types.js.map +1 -0
  70. package/dist/definition/parser.d.ts +12 -0
  71. package/dist/definition/parser.d.ts.map +1 -0
  72. package/dist/definition/parser.js +117 -0
  73. package/dist/definition/parser.js.map +1 -0
  74. package/dist/index.d.ts +22 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +25 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/quality/scorer.d.ts +18 -0
  79. package/dist/quality/scorer.d.ts.map +1 -0
  80. package/dist/quality/scorer.js +22 -0
  81. package/dist/quality/scorer.js.map +1 -0
  82. package/dist/server.d.ts +27 -0
  83. package/dist/server.d.ts.map +1 -0
  84. package/dist/server.js +118 -0
  85. package/dist/server.js.map +1 -0
  86. package/dist/tools/dedup.d.ts +20 -0
  87. package/dist/tools/dedup.d.ts.map +1 -0
  88. package/dist/tools/dedup.js +47 -0
  89. package/dist/tools/dedup.js.map +1 -0
  90. package/dist/tools/executor.d.ts +32 -0
  91. package/dist/tools/executor.d.ts.map +1 -0
  92. package/dist/tools/executor.js +75 -0
  93. package/dist/tools/executor.js.map +1 -0
  94. package/package.json +67 -0
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Definition Parser — parse .md agent definition files.
3
+ *
4
+ * Supported sections: Persona, Brain, Capabilities, Limits, Sections
5
+ * Stripped: Equipment, Skills, Hours, Memory rules (owned by the app layer)
6
+ */
7
+ import { readFileSync } from "fs";
8
+ /**
9
+ * Parse an agent definition from a .md file path or raw markdown string.
10
+ */
11
+ export function parseDefinition(input) {
12
+ // If it looks like a file path, read it
13
+ const md = input.trimStart().startsWith("#")
14
+ ? input
15
+ : readFileSync(input, "utf-8");
16
+ return parseMd(md);
17
+ }
18
+ function parseMd(md) {
19
+ const lines = md.split("\n");
20
+ // Title — first H1
21
+ const titleLine = lines.find((l) => l.startsWith("# "));
22
+ const name = titleLine ? titleLine.replace(/^# /, "").trim() : "Agent";
23
+ // Top-level metadata (key: value lines before first ##)
24
+ const meta = parseTopMeta(lines);
25
+ // Sections
26
+ const persona = parseSection(lines, "Persona");
27
+ const brain = parseBrainSection(lines);
28
+ const capabilities = parseListSection(lines, "Capabilities");
29
+ const limits = parseLimitsSection(lines);
30
+ const sections = parseListSection(lines, "Sections");
31
+ const personaName = extractKey(persona, "name") ?? extractKey(persona, "Name");
32
+ const personaStyle = extractKey(persona, "style") ?? extractKey(persona, "Style");
33
+ const brainEndpoint = brain["endpoint"] ?? brain["Endpoint"];
34
+ const domain = meta["domain"] ?? meta["Domain"];
35
+ const language = meta["language"] ?? meta["Language"];
36
+ return {
37
+ name,
38
+ ...(domain !== undefined ? { domain } : {}),
39
+ ...(language !== undefined ? { language } : {}),
40
+ persona: {
41
+ ...(personaName !== undefined ? { name: personaName } : {}),
42
+ ...(personaStyle !== undefined ? { style: personaStyle } : {}),
43
+ },
44
+ brain: {
45
+ provider: (brain["provider"] ??
46
+ brain["Provider"] ??
47
+ "openai"),
48
+ model: brain["model"] ?? brain["Model"] ?? "gpt-4o-mini",
49
+ ...(brainEndpoint !== undefined ? { endpoint: brainEndpoint } : {}),
50
+ },
51
+ capabilities,
52
+ limits: {
53
+ maxIterations: Number(limits["maxIterations"] ?? limits["MaxIterations"] ?? 60),
54
+ costCapPerTask: Number(limits["costCapPerTask"] ?? limits["CostCapPerTask"] ?? 2.5),
55
+ timeoutMs: Number(limits["timeoutMs"] ?? limits["TimeoutMs"] ?? 900_000),
56
+ confidenceThreshold: Number(limits["confidenceThreshold"] ?? limits["ConfidenceThreshold"] ?? 0.75),
57
+ maxConsecutiveFailures: Number(limits["maxConsecutiveFailures"] ??
58
+ limits["MaxConsecutiveFailures"] ??
59
+ 3),
60
+ },
61
+ ...(sections.length > 0 ? { sections } : {}),
62
+ };
63
+ }
64
+ // ─── Helpers ─────────────────────────────────────────────────
65
+ function parseTopMeta(lines) {
66
+ const result = {};
67
+ for (const line of lines) {
68
+ if (line.startsWith("##"))
69
+ break;
70
+ const m = /^([A-Za-z]+)\s*:\s*(.+)$/.exec(line.trim());
71
+ if (m && m[1] && m[2])
72
+ result[m[1]] = m[2].trim();
73
+ }
74
+ return result;
75
+ }
76
+ function getSectionLines(lines, sectionName) {
77
+ const startIdx = lines.findIndex((l) => l.match(new RegExp(`^##\\s+${sectionName}\\s*$`, "i")));
78
+ if (startIdx === -1)
79
+ return [];
80
+ const result = [];
81
+ for (let i = startIdx + 1; i < lines.length; i++) {
82
+ const line = lines[i];
83
+ if (line === undefined)
84
+ break;
85
+ if (/^##\s/.test(line))
86
+ break;
87
+ result.push(line);
88
+ }
89
+ return result;
90
+ }
91
+ function parseSection(lines, sectionName) {
92
+ const sectionLines = getSectionLines(lines, sectionName);
93
+ const result = {};
94
+ for (const line of sectionLines) {
95
+ const m = /^([A-Za-z]+)\s*:\s*(.+)$/.exec(line.trim());
96
+ if (m && m[1] && m[2])
97
+ result[m[1]] = m[2].trim();
98
+ }
99
+ return result;
100
+ }
101
+ function parseBrainSection(lines) {
102
+ return parseSection(lines, "Brain");
103
+ }
104
+ function parseListSection(lines, sectionName) {
105
+ return getSectionLines(lines, sectionName)
106
+ .map((l) => l.trim())
107
+ .filter((l) => l.startsWith("-"))
108
+ .map((l) => l.replace(/^-\s*/, "").trim())
109
+ .filter(Boolean);
110
+ }
111
+ function parseLimitsSection(lines) {
112
+ return parseSection(lines, "Limits");
113
+ }
114
+ function extractKey(obj, key) {
115
+ return obj[key] ?? obj[key.toLowerCase()];
116
+ }
117
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/definition/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * msm-mini — Public API
3
+ *
4
+ * import { createAgent } from 'msm-mini'
5
+ * import { createGeminiBrain } from 'msm-mini' // or openai/anthropic/ollama
6
+ * import { scoreOutcome } from 'msm-mini/quality'
7
+ * import { RedisMemory, RedisControlBus } from 'msm-mini/adapters'
8
+ */
9
+ export { createAgent } from "./core/loop.js";
10
+ export { createGeminiBrain } from "./brain/gemini.js";
11
+ export { createOpenAIBrain } from "./brain/openai.js";
12
+ export { createAnthropicBrain } from "./brain/anthropic.js";
13
+ export { createOllamaBrain } from "./brain/ollama.js";
14
+ export { buildBrain } from "./brain/factory.js";
15
+ export { parseDefinition } from "./definition/parser.js";
16
+ export type { Agent, AgentConfig, AgentEvent, AgentContext, AgentDefinition, AgentHooks, Brain, BrainPayload, BrainRunInput, DocumentState, GateConfig, GuardConfig, GuardSignal, GuardSignalType, IterationInfo, LoopOutcome, MemoryEntry, Message, OutcomeType, RedisConfig, RunState, SectionInfo, Tool, ToolCallInfo, ToolDefinition, ToolMeta, ToolParameter, ToolResult, } from "./core/types.js";
17
+ export { resolveGuards, DEFAULT_GUARDS } from "./core/guards.js";
18
+ export { scoreOutcome } from "./quality/scorer.js";
19
+ export type { QualityScore, QualityFlag } from "./quality/scorer.js";
20
+ export { createAgentServer } from "./server.js";
21
+ export type { AgentServer, AgentServerOptions } from "./server.js";
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,YAAY,EACV,KAAK,EACL,WAAW,EACX,UAAU,EACV,YAAY,EACZ,eAAe,EACf,UAAU,EACV,KAAK,EACL,YAAY,EACZ,aAAa,EACb,aAAa,EACb,UAAU,EACV,WAAW,EACX,WAAW,EACX,eAAe,EACf,aAAa,EACb,WAAW,EACX,WAAW,EACX,OAAO,EACP,WAAW,EACX,WAAW,EACX,QAAQ,EACR,WAAW,EACX,IAAI,EACJ,YAAY,EACZ,cAAc,EACd,QAAQ,EACR,aAAa,EACb,UAAU,GACX,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGjE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * msm-mini — Public API
3
+ *
4
+ * import { createAgent } from 'msm-mini'
5
+ * import { createGeminiBrain } from 'msm-mini' // or openai/anthropic/ollama
6
+ * import { scoreOutcome } from 'msm-mini/quality'
7
+ * import { RedisMemory, RedisControlBus } from 'msm-mini/adapters'
8
+ */
9
+ // ── Main factory ────────────────────────────────────────────────────────────
10
+ export { createAgent } from "./core/loop.js";
11
+ // ── Brain factories ─────────────────────────────────────────────────────────
12
+ export { createGeminiBrain } from "./brain/gemini.js";
13
+ export { createOpenAIBrain } from "./brain/openai.js";
14
+ export { createAnthropicBrain } from "./brain/anthropic.js";
15
+ export { createOllamaBrain } from "./brain/ollama.js";
16
+ export { buildBrain } from "./brain/factory.js";
17
+ // ── Definition parser ───────────────────────────────────────────────────────
18
+ export { parseDefinition } from "./definition/parser.js";
19
+ // ── Guard utilities ─────────────────────────────────────────────────────────
20
+ export { resolveGuards, DEFAULT_GUARDS } from "./core/guards.js";
21
+ // ── Quality scorer ──────────────────────────────────────────────────────────
22
+ export { scoreOutcome } from "./quality/scorer.js";
23
+ // ── HTTP server wrapper ─────────────────────────────────────────────────────
24
+ export { createAgentServer } from "./server.js";
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,+EAA+E;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,+EAA+E;AAC/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,+EAA+E;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAkCzD,+EAA+E;AAC/E,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEjE,+EAA+E;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,+EAA+E;AAC/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Quality Scorer — pure function, zero side effects.
3
+ * Compute resolution/efficiency/errorRate from a LoopOutcome.
4
+ * Feeds the dashboard quality monitor. No evolving layer.
5
+ */
6
+ import type { LoopOutcome } from "../core/types.js";
7
+ export type QualityFlag = "failed_resolution" | "slow_response" | "high_error_rate";
8
+ export interface QualityScore {
9
+ /** 0–1: likelihood the user's request was resolved */
10
+ resolution: number;
11
+ /** 0–1: 1=direct (≤1 tool call), 0=verbose (>5) */
12
+ efficiency: number;
13
+ /** 0–1: 1=no tool failures, 0=all failed */
14
+ errorRate: number;
15
+ flags: QualityFlag[];
16
+ }
17
+ export declare function scoreOutcome(outcome: LoopOutcome): QualityScore;
18
+ //# sourceMappingURL=scorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scorer.d.ts","sourceRoot":"","sources":["../../src/quality/scorer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,MAAM,WAAW,GACnB,mBAAmB,GACnB,eAAe,GACf,iBAAiB,CAAC;AAEtB,MAAM,WAAW,YAAY;IAC3B,sDAAsD;IACtD,UAAU,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,YAAY,CAe/D"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Quality Scorer — pure function, zero side effects.
3
+ * Compute resolution/efficiency/errorRate from a LoopOutcome.
4
+ * Feeds the dashboard quality monitor. No evolving layer.
5
+ */
6
+ export function scoreOutcome(outcome) {
7
+ const toolCalls = outcome.toolCalls ?? [];
8
+ const totalTools = outcome.metrics.totalToolCalls;
9
+ const failedTools = toolCalls.filter((t) => t.status === "failed").length;
10
+ const resolution = outcome.type === "response" ? 1 : outcome.type === "error" ? 0 : 0.5;
11
+ const efficiency = totalTools === 0 ? 1 : Math.max(0, 1 - (totalTools - 1) / 5);
12
+ const errorRate = totalTools === 0 ? 1 : 1 - failedTools / totalTools;
13
+ const flags = [];
14
+ if (resolution < 0.5)
15
+ flags.push("failed_resolution");
16
+ if (efficiency < 0.5)
17
+ flags.push("slow_response");
18
+ if (errorRate < 0.7)
19
+ flags.push("high_error_rate");
20
+ return { resolution, efficiency, errorRate, flags };
21
+ }
22
+ //# sourceMappingURL=scorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scorer.js","sourceRoot":"","sources":["../../src/quality/scorer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAmBH,MAAM,UAAU,YAAY,CAAC,OAAoB;IAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC;IAC1C,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC;IAClD,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;IAE1E,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACxF,MAAM,UAAU,GAAG,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAChF,MAAM,SAAS,GAAG,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,GAAG,UAAU,CAAC;IAEtE,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,IAAI,UAAU,GAAG,GAAG;QAAE,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACtD,IAAI,UAAU,GAAG,GAAG;QAAE,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAClD,IAAI,SAAS,GAAG,GAAG;QAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAEnD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AACtD,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * createAgentServer — lightweight HTTP wrapper around an msm-mini Agent.
3
+ *
4
+ * Exposes:
5
+ * POST /v1/event → agent.handle({ sessionId, message, context? })
6
+ * GET /health → { ok: true, uptime }
7
+ *
8
+ * The UTS api/server.ts proxies /chat → /v1/event on this server.
9
+ * All other msm-agent HTTP surface (dashboard etc.) is NOT replicated — keep it slim.
10
+ *
11
+ * @example
12
+ * const agentServer = createAgentServer(agent, { port: PORT + 1 });
13
+ * await agentServer.start();
14
+ * // ...
15
+ * await agentServer.stop();
16
+ */
17
+ import type { Agent } from "./core/types.js";
18
+ export interface AgentServerOptions {
19
+ port: number;
20
+ host?: string;
21
+ }
22
+ export interface AgentServer {
23
+ start(): Promise<void>;
24
+ stop(): Promise<void>;
25
+ }
26
+ export declare function createAgentServer(agent: Agent, opts: AgentServerOptions): AgentServer;
27
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAOH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAE7C,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AA4BD,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,kBAAkB,GACvB,WAAW,CAoFb"}
package/dist/server.js ADDED
@@ -0,0 +1,118 @@
1
+ /**
2
+ * createAgentServer — lightweight HTTP wrapper around an msm-mini Agent.
3
+ *
4
+ * Exposes:
5
+ * POST /v1/event → agent.handle({ sessionId, message, context? })
6
+ * GET /health → { ok: true, uptime }
7
+ *
8
+ * The UTS api/server.ts proxies /chat → /v1/event on this server.
9
+ * All other msm-agent HTTP surface (dashboard etc.) is NOT replicated — keep it slim.
10
+ *
11
+ * @example
12
+ * const agentServer = createAgentServer(agent, { port: PORT + 1 });
13
+ * await agentServer.start();
14
+ * // ...
15
+ * await agentServer.stop();
16
+ */
17
+ import { createServer, } from "node:http";
18
+ function readBody(req) {
19
+ return new Promise((resolve, reject) => {
20
+ const chunks = [];
21
+ req.on("data", (c) => chunks.push(c));
22
+ req.on("end", () => {
23
+ try {
24
+ resolve(JSON.parse(Buffer.concat(chunks).toString("utf8")));
25
+ }
26
+ catch {
27
+ reject(new Error("Invalid JSON body"));
28
+ }
29
+ });
30
+ req.on("error", reject);
31
+ });
32
+ }
33
+ function json(res, status, body) {
34
+ const payload = JSON.stringify(body);
35
+ res.writeHead(status, {
36
+ "Content-Type": "application/json",
37
+ "Content-Length": Buffer.byteLength(payload),
38
+ });
39
+ res.end(payload);
40
+ }
41
+ const START_TIME = Date.now();
42
+ export function createAgentServer(agent, opts) {
43
+ const host = opts.host ?? "127.0.0.1";
44
+ const port = opts.port;
45
+ const server = createServer(async (req, res) => {
46
+ const path = (req.url ?? "/").split("?")[0];
47
+ // CORS preflight
48
+ if (req.method === "OPTIONS") {
49
+ res.writeHead(204, {
50
+ "Access-Control-Allow-Origin": "*",
51
+ "Access-Control-Allow-Methods": "POST, GET, OPTIONS",
52
+ "Access-Control-Allow-Headers": "Content-Type, Authorization",
53
+ });
54
+ res.end();
55
+ return;
56
+ }
57
+ try {
58
+ // ── Health ────────────────────────────────────────────────────────────
59
+ if (path === "/health" && req.method === "GET") {
60
+ json(res, 200, { ok: true, uptime: Date.now() - START_TIME });
61
+ return;
62
+ }
63
+ // ── Agent event ───────────────────────────────────────────────────────
64
+ if (path === "/v1/event" && req.method === "POST") {
65
+ let body;
66
+ try {
67
+ body = (await readBody(req));
68
+ }
69
+ catch {
70
+ json(res, 400, { error: "Invalid JSON body" });
71
+ return;
72
+ }
73
+ const sessionId = typeof body["sessionId"] === "string" ? body["sessionId"] : "";
74
+ const text = typeof body["text"] === "string" ? body["text"] : "";
75
+ if (!sessionId || !text) {
76
+ json(res, 400, {
77
+ error: "Missing required fields: sessionId, text",
78
+ });
79
+ return;
80
+ }
81
+ const outcome = await agent.handle({
82
+ sessionId,
83
+ message: text,
84
+ });
85
+ json(res, 200, outcome);
86
+ return;
87
+ }
88
+ json(res, 404, { error: "Not found" });
89
+ }
90
+ catch (err) {
91
+ if (!res.headersSent) {
92
+ json(res, 500, { error: String(err) });
93
+ }
94
+ console.error("[AgentServer]", err);
95
+ }
96
+ });
97
+ return {
98
+ start() {
99
+ return new Promise((resolve) => {
100
+ server.listen(port, host, () => {
101
+ console.log(`[AgentServer] listening on http://${host}:${port}`);
102
+ resolve();
103
+ });
104
+ });
105
+ },
106
+ stop() {
107
+ return new Promise((resolve, reject) => {
108
+ server.close((err) => {
109
+ if (err)
110
+ reject(err);
111
+ else
112
+ resolve();
113
+ });
114
+ });
115
+ },
116
+ };
117
+ }
118
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Tool Dedup — Hash-based idempotency for tool calls.
3
+ *
4
+ * Deduplication key: SHA-256(toolName + JSON.stringify(sortedArgs))
5
+ * Stored in Redis as: {prefix}:session:{id}:tools:dedup hash field
6
+ * TTL: 5 minutes (configurable)
7
+ */
8
+ import type { ToolResult } from "../core/types.js";
9
+ type RedisLike = {
10
+ hget(key: string, field: string): Promise<string | null>;
11
+ hset(key: string, field: string, value: string): Promise<unknown>;
12
+ expire(key: string, seconds: number): Promise<unknown>;
13
+ };
14
+ export declare function toolDedupKey(prefix: string, sessionId: string): string;
15
+ export declare function checkDedup(redis: RedisLike, dedupKey: string, hash: string): Promise<ToolResult | null>;
16
+ export declare function storeDedup(redis: RedisLike, dedupKey: string, hash: string, result: ToolResult, ttlSeconds: number): Promise<void>;
17
+ /** Deterministic hash of a tool call — pure function, no crypto dependency */
18
+ export declare function hashToolCall(toolName: string, args: Record<string, unknown>): string;
19
+ export {};
20
+ //# sourceMappingURL=dedup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedup.d.ts","sourceRoot":"","sources":["../../src/tools/dedup.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,KAAK,SAAS,GAAG;IACf,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClE,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACxD,CAAC;AAEF,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAsB,UAAU,CAC9B,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAQ5B;AAED,wBAAsB,UAAU,CAC9B,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAUpF"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Tool Dedup — Hash-based idempotency for tool calls.
3
+ *
4
+ * Deduplication key: SHA-256(toolName + JSON.stringify(sortedArgs))
5
+ * Stored in Redis as: {prefix}:session:{id}:tools:dedup hash field
6
+ * TTL: 5 minutes (configurable)
7
+ */
8
+ export function toolDedupKey(prefix, sessionId) {
9
+ return `${prefix}:session:${sessionId}:tools:dedup`;
10
+ }
11
+ export async function checkDedup(redis, dedupKey, hash) {
12
+ const cached = await redis.hget(dedupKey, hash);
13
+ if (!cached)
14
+ return null;
15
+ try {
16
+ return JSON.parse(cached);
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ }
22
+ export async function storeDedup(redis, dedupKey, hash, result, ttlSeconds) {
23
+ await redis.hset(dedupKey, hash, JSON.stringify(result));
24
+ await redis.expire(dedupKey, ttlSeconds);
25
+ }
26
+ /** Deterministic hash of a tool call — pure function, no crypto dependency */
27
+ export function hashToolCall(toolName, args) {
28
+ const sorted = sortKeys(args);
29
+ const str = toolName + "::" + JSON.stringify(sorted);
30
+ // FNV-1a 32-bit hash — fast, deterministic, no external dep
31
+ let h = 2166136261;
32
+ for (let i = 0; i < str.length; i++) {
33
+ h ^= str.charCodeAt(i);
34
+ h = (h * 16777619) >>> 0;
35
+ }
36
+ return h.toString(16).padStart(8, "0");
37
+ }
38
+ function sortKeys(obj) {
39
+ if (obj === null || typeof obj !== "object")
40
+ return obj;
41
+ if (Array.isArray(obj))
42
+ return obj.map(sortKeys);
43
+ return Object.fromEntries(Object.entries(obj)
44
+ .sort(([a], [b]) => a.localeCompare(b))
45
+ .map(([k, v]) => [k, sortKeys(v)]));
46
+ }
47
+ //# sourceMappingURL=dedup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedup.js","sourceRoot":"","sources":["../../src/tools/dedup.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,SAAiB;IAC5D,OAAO,GAAG,MAAM,YAAY,SAAS,cAAc,CAAC;AACtD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,KAAgB,EAChB,QAAgB,EAChB,IAAY;IAEZ,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAChD,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAe,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,KAAgB,EAChB,QAAgB,EAChB,IAAY,EACZ,MAAkB,EAClB,UAAkB;IAElB,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACzD,MAAM,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;AAC3C,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,IAA6B;IAC1E,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,GAAG,GAAG,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACrD,4DAA4D;IAC5D,IAAI,CAAC,GAAG,UAAU,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACvB,CAAC,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,QAAQ,CAAC,GAAY;IAC5B,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACjD,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,GAA8B,CAAC;SAC3C,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CACrC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Tool Executor — Validation, dedup, and execution pipeline.
3
+ *
4
+ * Pipeline per tool call:
5
+ * 1. Control bus — check if tool is disabled
6
+ * 2. Dedup — return cached result if same args seen in last 5 min
7
+ * 3. Validate — check required parameters are present and typed
8
+ * 4. Execute — call tool.execute()
9
+ * 5. Cache — store result in dedup hash
10
+ */
11
+ import type { Tool, ToolResult, ToolMeta } from "../core/types.js";
12
+ type RedisLike = {
13
+ hget(key: string, field: string): Promise<string | null>;
14
+ hset(key: string, field: string, value: string): Promise<unknown>;
15
+ expire(key: string, seconds: number): Promise<unknown>;
16
+ get(key: string): Promise<string | null>;
17
+ };
18
+ export interface ExecutorOptions {
19
+ redis: RedisLike;
20
+ redisPrefix: string;
21
+ dedupTtlSeconds: number;
22
+ }
23
+ export interface ExecutionResult {
24
+ result: ToolResult;
25
+ cached: boolean;
26
+ durationMs: number;
27
+ }
28
+ export declare function executeTool(tool: Tool, params: Record<string, unknown>, meta: ToolMeta, opts: ExecutorOptions): Promise<ExecutionResult>;
29
+ /** Build a ToolDefinition list from app-provided Tool objects (for brain prompt) */
30
+ export declare function toToolDefinitions(tools: Tool[]): import("../core/types.js").ToolDefinition[];
31
+ export {};
32
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/tools/executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGnE,KAAK,SAAS,GAAG;IACf,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClE,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC1C,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,WAAW,CAC/B,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,eAAe,CAAC,CAuC1B;AAqBD,oFAAoF;AACpF,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,IAAI,EAAE,GACZ,OAAO,kBAAkB,EAAE,cAAc,EAAE,CAS7C"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Tool Executor — Validation, dedup, and execution pipeline.
3
+ *
4
+ * Pipeline per tool call:
5
+ * 1. Control bus — check if tool is disabled
6
+ * 2. Dedup — return cached result if same args seen in last 5 min
7
+ * 3. Validate — check required parameters are present and typed
8
+ * 4. Execute — call tool.execute()
9
+ * 5. Cache — store result in dedup hash
10
+ */
11
+ import { hashToolCall, checkDedup, storeDedup, toolDedupKey } from "./dedup.js";
12
+ export async function executeTool(tool, params, meta, opts) {
13
+ const start = Date.now();
14
+ // Step 1: Validate required parameters
15
+ const validationError = validateParams(tool, params);
16
+ if (validationError) {
17
+ return {
18
+ result: { tool: tool.name, status: "failed", error: validationError },
19
+ cached: false,
20
+ durationMs: Date.now() - start,
21
+ };
22
+ }
23
+ // Step 2: Dedup check
24
+ const hash = hashToolCall(tool.name, params);
25
+ const dedupKey = toolDedupKey(opts.redisPrefix, meta.sessionId);
26
+ const cached = await checkDedup(opts.redis, dedupKey, hash);
27
+ if (cached) {
28
+ return { result: cached, cached: true, durationMs: Date.now() - start };
29
+ }
30
+ // Step 3: Execute
31
+ let result;
32
+ try {
33
+ result = await tool.execute(params, meta);
34
+ }
35
+ catch (err) {
36
+ result = {
37
+ tool: tool.name,
38
+ status: "failed",
39
+ error: err instanceof Error ? err.message : String(err),
40
+ };
41
+ }
42
+ // Step 4: Cache successful results only
43
+ if (result.status === "ok") {
44
+ await storeDedup(opts.redis, dedupKey, hash, result, opts.dedupTtlSeconds);
45
+ }
46
+ return { result, cached: false, durationMs: Date.now() - start };
47
+ }
48
+ /** Lightweight required-field validation (no Zod runtime dep in loop) */
49
+ function validateParams(tool, params) {
50
+ for (const [name, def] of Object.entries(tool.parameters)) {
51
+ if (!def.required)
52
+ continue;
53
+ if (params[name] === undefined || params[name] === null) {
54
+ return `Tool "${tool.name}": required parameter "${name}" is missing`;
55
+ }
56
+ const expected = def.type;
57
+ const actual = Array.isArray(params[name]) ? "array" : typeof params[name];
58
+ if (expected !== "object" && expected !== actual) {
59
+ return `Tool "${tool.name}": parameter "${name}" expected ${expected}, got ${actual}`;
60
+ }
61
+ }
62
+ return null;
63
+ }
64
+ /** Build a ToolDefinition list from app-provided Tool objects (for brain prompt) */
65
+ export function toToolDefinitions(tools) {
66
+ return tools.map((t) => ({
67
+ name: t.name,
68
+ description: t.description,
69
+ parameters: t.parameters,
70
+ ...(t.requiresApproval !== undefined
71
+ ? { requiresApproval: t.requiresApproval }
72
+ : {}),
73
+ }));
74
+ }
75
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/tools/executor.ts"],"names":[],"mappings":"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"}