@looprun-ai/mastra 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.
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @looprun-ai/mastra — per-conversation session state.
3
+ *
4
+ * One LoopRunAgent is registered ONCE (Mastra instance / Studio) while each conversation gets its
5
+ * own world + ledger + message history, keyed by sessionId. A per-session promise-chain mutex
6
+ * serializes concurrent turns of the same conversation.
7
+ */
8
+ import { createLedger } from '@looprun-ai/core';
9
+ export class SessionStore {
10
+ sessions = new Map();
11
+ factory;
12
+ singleton;
13
+ constructor(world) {
14
+ if (typeof world === 'function') {
15
+ this.factory = world;
16
+ this.singleton = null;
17
+ }
18
+ else {
19
+ this.factory = null;
20
+ this.singleton = world;
21
+ }
22
+ }
23
+ get(id) {
24
+ const existing = this.sessions.get(id);
25
+ if (existing)
26
+ return existing;
27
+ if (this.singleton && id !== 'default') {
28
+ throw new Error(`looprun: session "${id}" requested but the agent was built with a single world INSTANCE — ` +
29
+ 'pass a world FACTORY ((sessionId) => world) to support multiple conversations.');
30
+ }
31
+ const world = this.singleton ?? this.factory(id);
32
+ const session = {
33
+ id,
34
+ world,
35
+ ledger: createLedger(),
36
+ turnIndex: 0,
37
+ messages: [],
38
+ chain: Promise.resolve(),
39
+ };
40
+ this.sessions.set(id, session);
41
+ return session;
42
+ }
43
+ end(id) {
44
+ this.sessions.delete(id);
45
+ }
46
+ /** Serialize `fn` on the session's mutex chain. */
47
+ run(session, fn) {
48
+ const next = session.chain.then(fn, fn);
49
+ session.chain = next.catch(() => { });
50
+ return next;
51
+ }
52
+ }
53
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAiBhD,MAAM,OAAO,YAAY;IACN,QAAQ,GAAG,IAAI,GAAG,EAA6B,CAAC;IAChD,OAAO,CAAyB;IAChC,SAAS,CAAW;IAErC,YAAY,KAA0B;QACpC,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;YAChC,IAAI,CAAC,OAAO,GAAG,KAAwB,CAAC;YACxC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACxB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;QACzB,CAAC;IACH,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvC,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAC9B,IAAI,IAAI,CAAC,SAAS,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CACb,qBAAqB,EAAE,qEAAqE;gBAC1F,gFAAgF,CACnF,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,OAAQ,CAAC,EAAE,CAAC,CAAC;QAClD,MAAM,OAAO,GAAsB;YACjC,EAAE;YACF,KAAK;YACL,MAAM,EAAE,YAAY,EAAE;YACtB,SAAS,EAAE,CAAC;YACZ,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;SACzB,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC;IAED,mDAAmD;IACnD,GAAG,CAAI,OAA0B,EAAE,EAAoB;QACrD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACxC,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ import type { ToolDef } from '@looprun-ai/core';
2
+ import type { LoopRunSession } from './session.js';
3
+ export type SessionAccessor = () => LoopRunSession;
4
+ /** Build the Mastra tool map for a spec surface: domain tools (world.exec) + the terminal tools. */
5
+ export declare function buildWorldTools(toolDefs: ToolDef[], surface: ReadonlySet<string>, getSession: SessionAccessor): Record<string, any>;
6
+ /** Build ONLY the terminal tools (native-tools mode: domain tools execute themselves). */
7
+ export declare function buildTerminalTools(getSession: SessionAccessor): Record<string, any>;
8
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGnD,MAAM,MAAM,eAAe,GAAG,MAAM,cAAc,CAAC;AAEnD,oGAAoG;AACpG,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAC5B,UAAU,EAAE,eAAe,GAE1B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAiCrB;AAED,0FAA0F;AAE1F,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAiBnF"}
package/dist/tools.js ADDED
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @looprun-ai/mastra — tool wiring: JSON-schema ToolDefs → Mastra tools executed through the world seam.
3
+ *
4
+ * Terminal tools (replyToUser/askUser) are runtime-owned: their execute captures the user-facing
5
+ * text into the ACTIVE session's ledger. Domain tools route to `world.exec(name, args)`.
6
+ */
7
+ import { createTool } from '@mastra/core/tools';
8
+ import { isTerminal, recordTerminal, terminalToolDefs } from '@looprun-ai/core';
9
+ import { jsonSchemaToZodObject } from './json-schema-zod.js';
10
+ /** Build the Mastra tool map for a spec surface: domain tools (world.exec) + the terminal tools. */
11
+ export function buildWorldTools(toolDefs, surface, getSession) {
12
+ const byName = new Map(toolDefs.map((d) => [d.name, d]));
13
+ // Backfill terminal defs when the host's toolDefs omit them.
14
+ for (const def of terminalToolDefs())
15
+ if (!byName.has(def.name))
16
+ byName.set(def.name, def);
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ const tools = {};
19
+ for (const def of byName.values()) {
20
+ if (!surface.has(def.name) && !isTerminal(def.name))
21
+ continue;
22
+ if (isTerminal(def.name)) {
23
+ tools[def.name] = createTool({
24
+ id: def.name,
25
+ description: def.description,
26
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
+ inputSchema: jsonSchemaToZodObject(def.inputSchema),
28
+ execute: async (input) => {
29
+ const args = (input ?? {});
30
+ const session = getSession();
31
+ recordTerminal(session.ledger, def.name, args);
32
+ return session.world.exec(def.name, args);
33
+ },
34
+ });
35
+ continue;
36
+ }
37
+ tools[def.name] = createTool({
38
+ id: def.name,
39
+ description: def.description,
40
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
+ inputSchema: jsonSchemaToZodObject(def.inputSchema),
42
+ execute: async (input) => getSession().world.exec(def.name, (input ?? {})),
43
+ });
44
+ }
45
+ return tools;
46
+ }
47
+ /** Build ONLY the terminal tools (native-tools mode: domain tools execute themselves). */
48
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
+ export function buildTerminalTools(getSession) {
50
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
51
+ const tools = {};
52
+ for (const def of terminalToolDefs()) {
53
+ tools[def.name] = createTool({
54
+ id: def.name,
55
+ description: def.description,
56
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
+ inputSchema: jsonSchemaToZodObject(def.inputSchema),
58
+ execute: async (input) => {
59
+ const args = (input ?? {});
60
+ recordTerminal(getSession().ledger, def.name, args);
61
+ return { success: true };
62
+ },
63
+ });
64
+ }
65
+ return tools;
66
+ }
67
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @looprun-ai/mastra — world adapters for NATIVE-TOOLS mode (including MCP).
3
+ *
4
+ * In native-tools mode the tools execute themselves (Mastra assigned tools, toolsets, or
5
+ * `@mastra/mcp` MCPClient tools) and guards are enforced through the agent hooks; the world seam
6
+ * is needed only for STATE: stateful guards (`precondition`, custom world reads) and
7
+ * `theme.stateBlock`. A `StateView` supplies those reads; `refresh` (if given) runs at each
8
+ * turn boundary so remote state can be re-fetched.
9
+ *
10
+ * Ledger-based guards (requiresBefore, noDuplicateCall, confirmFirst, maxCallsPerTurn, …) need
11
+ * NO state view — they read the observed ledger the hooks feed.
12
+ */
13
+ import type { AgentWorld } from '@looprun-ai/core';
14
+ /** Domain state reads for guards + theme.stateBlock (backed by your API / MCP resources / cache). */
15
+ export interface StateView {
16
+ /** Called at each turn boundary (advanceTurn) — re-fetch remote state here if needed. */
17
+ refresh?(): void | Promise<void>;
18
+ [k: string]: any;
19
+ }
20
+ /** Synthesize an AgentWorld for native-tools mode: state from `stateView`, execution by the tools. */
21
+ export declare function worldFromTools(opts?: {
22
+ stateView?: StateView;
23
+ }): AgentWorld;
24
+ //# sourceMappingURL=world-adapters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"world-adapters.d.ts","sourceRoot":"","sources":["../src/world-adapters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,qGAAqG;AACrG,MAAM,WAAW,SAAS;IACxB,yFAAyF;IACzF,OAAO,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjC,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;CAClB;AAED,sGAAsG;AACtG,wBAAgB,cAAc,CAAC,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,SAAS,CAAA;CAAO,GAAG,UAAU,CAsB/E"}
@@ -0,0 +1,24 @@
1
+ /** Synthesize an AgentWorld for native-tools mode: state from `stateView`, execution by the tools. */
2
+ export function worldFromTools(opts = {}) {
3
+ const view = opts.stateView ?? {};
4
+ const world = {
5
+ exec: (name) => {
6
+ throw new Error(`looprun: world.exec("${name}") called in native-tools mode — domain tools execute themselves; ` +
7
+ 'only the runtime-owned terminal tools should reach the world.');
8
+ },
9
+ advanceTurn: () => {
10
+ void view.refresh?.();
11
+ },
12
+ ingestAttachment: (url) => url,
13
+ toolCalls: [],
14
+ sseActions: [],
15
+ };
16
+ for (const [k, v] of Object.entries(view)) {
17
+ if (k === 'refresh')
18
+ continue;
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ world[k] = typeof v === 'function' ? v.bind(view) : v;
21
+ }
22
+ return world;
23
+ }
24
+ //# sourceMappingURL=world-adapters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"world-adapters.js","sourceRoot":"","sources":["../src/world-adapters.ts"],"names":[],"mappings":"AAsBA,sGAAsG;AACtG,MAAM,UAAU,cAAc,CAAC,OAAkC,EAAE;IACjE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;IAClC,MAAM,KAAK,GAAe;QACxB,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE;YACrB,MAAM,IAAI,KAAK,CACb,wBAAwB,IAAI,oEAAoE;gBAC9F,+DAA+D,CACpE,CAAC;QACF,CAAC;QACD,WAAW,EAAE,GAAG,EAAE;YAChB,KAAK,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;QACxB,CAAC;QACD,gBAAgB,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG;QACtC,SAAS,EAAE,EAAE;QACb,UAAU,EAAE,EAAE;KACf,CAAC;IACF,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC,KAAK,SAAS;YAAE,SAAS;QAC9B,8DAA8D;QAC7D,KAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@looprun-ai/mastra",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "looprun on Mastra: LoopRunAgent — a genuine @mastra/core Agent compiled from an AgentSpec, with deterministic guard enforcement (beforeToolCall veto), the terminal protocol, bounded no-tools redrive and honest-abstain exhaustion. Studio-compatible.",
6
+ "keywords": [
7
+ "ai",
8
+ "agents",
9
+ "llm",
10
+ "governance",
11
+ "guardrails",
12
+ "agentspec",
13
+ "mastra",
14
+ "agent"
15
+ ],
16
+ "license": "Apache-2.0",
17
+ "author": "LoopRun Team",
18
+ "homepage": "https://looprun.ai",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/looprun-ai/looprun.git",
22
+ "directory": "packages/mastra"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/looprun-ai/looprun/issues"
26
+ },
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "default": "./dist/index.js"
31
+ }
32
+ },
33
+ "files": [
34
+ "dist"
35
+ ],
36
+ "engines": {
37
+ "node": ">=22"
38
+ },
39
+ "dependencies": {
40
+ "@looprun-ai/core": "^0.1.0"
41
+ },
42
+ "peerDependencies": {
43
+ "@mastra/core": "^1.42.0",
44
+ "ai": "^6.0.0",
45
+ "zod": "^3.24.0"
46
+ },
47
+ "devDependencies": {
48
+ "@mastra/core": "^1.42.0",
49
+ "@types/node": "^22.0.0",
50
+ "ai": "^6.0.184",
51
+ "typescript": "^5.7.0",
52
+ "vitest": "^2.0.0",
53
+ "zod": "^3.24.0"
54
+ },
55
+ "scripts": {
56
+ "build": "tsc -p tsconfig.build.json",
57
+ "typecheck": "tsc --noEmit",
58
+ "test": "vitest run"
59
+ }
60
+ }