@looprun-ai/mastra 0.2.0 → 0.4.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.
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,kBAAkB,CAAC;AAE5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,UAAU;IACzB,cAAc,CAAC,GAAG,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,GAAG;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC/G,aAAa,CAAC,GAAG,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACnH;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,GAAG,UAAU,CAmCvF;AAED;;;;;GAKG;AAEH,wBAAgB,oBAAoB,CAAC,EAAE,KAAK,EAAE,EAAE,GAAG,GAAG,OAAO,CAU5D;AAED,gGAAgG;AAChG,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,SAAS,EACf,UAAU,EAAE,eAAe,GAE1B,GAAG,EAAE,GAAG,SAAS,CAcnB"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,kBAAkB,CAAC;AAE5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,UAAU;IACzB,cAAc,CAAC,GAAG,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,GAAG;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC/G,aAAa,CAAC,GAAG,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACnH;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,GAAG,UAAU,CAyCvF;AAED;;;;;GAKG;AAEH,wBAAgB,oBAAoB,CAAC,EAAE,KAAK,EAAE,EAAE,GAAG,GAAG,OAAO,CAU5D;AAED,gGAAgG;AAChG,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,SAAS,EACf,UAAU,EAAE,eAAe,GAE1B,GAAG,EAAE,GAAG,SAAS,CAcnB"}
package/dist/hooks.js CHANGED
@@ -6,12 +6,17 @@
6
6
  * fed by `hooks.afterToolCall`. Mastra applies hooks to ALL tool sources (assigned, toolsets,
7
7
  * client, MCP), so guards also govern native/MCP tools with zero extra wiring.
8
8
  */
9
- import { evaluatePreTool, evaluateOnInput, enforcePostTool, isTerminal, recordToolResult, resolveGuards } from '@looprun-ai/core';
9
+ import { evaluatePreTool, evaluateOnInput, enforcePostTool, isTerminal, recordTerminalCall, recordToolResult, resolveGuards } from '@looprun-ai/core';
10
10
  export function makeGuardHooks(spec, getSession) {
11
11
  return {
12
12
  async beforeToolCall({ toolName, input }) {
13
- if (isTerminal(toolName))
13
+ if (isTerminal(toolName)) {
14
+ // SYNCHRONOUS segment (no await above): record the terminal call at HOOK time so a same-step
15
+ // sibling call's preTool checks can see it — see recordTerminalCall's doc for the concurrency
16
+ // rationale. The terminal tool's execute captures the reply text and does NOT push again.
17
+ recordTerminalCall(getSession().ledger, toolName, (input ?? {}));
14
18
  return undefined;
19
+ }
15
20
  const session = getSession();
16
21
  const args = (input ?? {});
17
22
  const verdict = await evaluatePreTool(spec, session.ledger, session.world, toolName, args);
package/dist/hooks.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * A script-driven LanguageModelV3 mock: each LLM call pops the next scripted step.
3
+ *
4
+ * Wraps `MockLanguageModelV3` from `ai/test` (the `ai` package is already a peer dependency of this
5
+ * backend). A `ScriptStep` is one LLM response: a list of tool-calls and/or text parts.
6
+ * `scriptedModel(script)` returns a model whose Nth generate() emits the Nth step (the last step repeats
7
+ * once the script is exhausted), plus `calls()` and the raw `received` options for prompt inspection.
8
+ * `fakeLLM` is a friendly alias.
9
+ */
10
+ import { MockLanguageModelV3 } from 'ai/test';
11
+ export type ScriptPart = {
12
+ tool: string;
13
+ args: Record<string, unknown>;
14
+ } | {
15
+ text: string;
16
+ };
17
+ export type ScriptStep = ScriptPart[];
18
+ export interface ScriptedModel {
19
+ model: MockLanguageModelV3;
20
+ calls: () => number;
21
+ /** The raw call options seen by the model (prompt inspection). */
22
+ received: any[];
23
+ }
24
+ export declare function scriptedModel(script: ScriptStep[]): ScriptedModel;
25
+ /** Friendly alias for {@link scriptedModel}. */
26
+ export declare const fakeLLM: typeof scriptedModel;
27
+ //# sourceMappingURL=fake-llm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-llm.d.ts","sourceRoot":"","sources":["../../src/testing/fake-llm.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAC5F,MAAM,MAAM,UAAU,GAAG,UAAU,EAAE,CAAC;AAEtC,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,mBAAmB,CAAC;IAC3B,KAAK,EAAE,MAAM,MAAM,CAAC;IACpB,kEAAkE;IAElE,QAAQ,EAAE,GAAG,EAAE,CAAC;CACjB;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,aAAa,CAuDjE;AAED,gDAAgD;AAChD,eAAO,MAAM,OAAO,sBAAgB,CAAC"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * A script-driven LanguageModelV3 mock: each LLM call pops the next scripted step.
3
+ *
4
+ * Wraps `MockLanguageModelV3` from `ai/test` (the `ai` package is already a peer dependency of this
5
+ * backend). A `ScriptStep` is one LLM response: a list of tool-calls and/or text parts.
6
+ * `scriptedModel(script)` returns a model whose Nth generate() emits the Nth step (the last step repeats
7
+ * once the script is exhausted), plus `calls()` and the raw `received` options for prompt inspection.
8
+ * `fakeLLM` is a friendly alias.
9
+ */
10
+ import { MockLanguageModelV3 } from 'ai/test';
11
+ export function scriptedModel(script) {
12
+ let call = 0;
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
+ const received = [];
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ const next = (options) => {
17
+ received.push(options);
18
+ const step = script[Math.min(call, script.length - 1)] ?? [{ text: '' }];
19
+ call++;
20
+ let id = 0;
21
+ const content = step.map((p) => 'text' in p
22
+ ? { type: 'text', text: p.text }
23
+ : {
24
+ type: 'tool-call',
25
+ toolCallId: `c${call}-${id++}`,
26
+ toolName: p.tool,
27
+ input: JSON.stringify(p.args),
28
+ });
29
+ const finishReason = step.some((p) => 'tool' in p) ? 'tool-calls' : 'stop';
30
+ return { content, finishReason, usage: { inputTokens: 1, outputTokens: 1, totalTokens: 2 }, warnings: [] };
31
+ };
32
+ const model = new MockLanguageModelV3({
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
+ doGenerate: (async (options) => next(options)),
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
+ doStream: async (options) => {
37
+ const r = next(options);
38
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
+ const parts = [{ type: 'stream-start', warnings: [] }];
40
+ let t = 0;
41
+ for (const c of r.content) {
42
+ if (c.type === 'text') {
43
+ const tid = `t${++t}`;
44
+ parts.push({ type: 'text-start', id: tid }, { type: 'text-delta', id: tid, delta: c.text }, { type: 'text-end', id: tid });
45
+ }
46
+ else {
47
+ parts.push(c);
48
+ }
49
+ }
50
+ parts.push({ type: 'finish', finishReason: r.finishReason, usage: r.usage });
51
+ return {
52
+ stream: new ReadableStream({
53
+ start(controller) {
54
+ for (const p of parts)
55
+ controller.enqueue(p);
56
+ controller.close();
57
+ },
58
+ }),
59
+ };
60
+ },
61
+ });
62
+ return { model, calls: () => call, received };
63
+ }
64
+ /** Friendly alias for {@link scriptedModel}. */
65
+ export const fakeLLM = scriptedModel;
66
+ //# sourceMappingURL=fake-llm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-llm.js","sourceRoot":"","sources":["../../src/testing/fake-llm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @looprun-ai/mastra `/testing` — the backend half of the shippable, domain-NEUTRAL testing kit.
3
+ *
4
+ * The fake LLM (scripted model) + the full-loop (L3) proof runners that drive a real
5
+ * runSpecConversation. Pair with `@looprun-ai/core/testing` (the fixture world + proof format + L1
6
+ * runner + spec builders) for the complete guard-proof harness.
7
+ */
8
+ export * from './fake-llm.js';
9
+ export * from './proof-loop.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @looprun-ai/mastra `/testing` — the backend half of the shippable, domain-NEUTRAL testing kit.
3
+ *
4
+ * The fake LLM (scripted model) + the full-loop (L3) proof runners that drive a real
5
+ * runSpecConversation. Pair with `@looprun-ai/core/testing` (the fixture world + proof format + L1
6
+ * runner + spec builders) for the complete guard-proof harness.
7
+ */
8
+ export * from './fake-llm.js';
9
+ export * from './proof-loop.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { GuardProof, ProofLoopCase } from '@looprun-ai/core/testing';
2
+ import type { AgentSpec, RunResult, RuntimeTurnRecord } from '@looprun-ai/core';
3
+ /** L3 — drive the full runSpecConversation loop for a proof's loop case. The fixture theme rides on the
4
+ * spec (set by the core spec builders); `redrives` is overridable (default 1). The runtime's fixed
5
+ * veto-storm limit never trips these single-veto scripts. */
6
+ export declare function runProofLoop(spec: AgentSpec, l3: ProofLoopCase, redrives?: number): Promise<RunResult>;
7
+ /** The `recoveryEvents` tag we expect this proof's loop case to emit ('' for a clean pass). */
8
+ export declare function expectedSignal(proof: GuardProof, l3: ProofLoopCase): string;
9
+ /** Pick the turnRecord a loop case asserts on (l3.turn, default the last). */
10
+ export declare function pickRecord(res: RunResult, l3: ProofLoopCase): RuntimeTurnRecord | undefined;
11
+ /** Assert the expected signal is present in a turnRecord's recoveryEvents. Returns a verdict + detail. */
12
+ export declare function assertSignal(record: RuntimeTurnRecord | undefined, proof: GuardProof, l3: ProofLoopCase): {
13
+ ok: boolean;
14
+ detail: string;
15
+ };
16
+ //# sourceMappingURL=proof-loop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proof-loop.d.ts","sourceRoot":"","sources":["../../src/testing/proof-loop.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAIhF;;8DAE8D;AAC9D,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,aAAa,EAAE,QAAQ,SAAI,GAAG,OAAO,CAAC,SAAS,CAAC,CAQjG;AAED,+FAA+F;AAC/F,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,aAAa,GAAG,MAAM,CAkB3E;AAED,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,EAAE,aAAa,GAAG,iBAAiB,GAAG,SAAS,CAG3F;AAED,0GAA0G;AAC1G,wBAAgB,YAAY,CAC1B,MAAM,EAAE,iBAAiB,GAAG,SAAS,EACrC,KAAK,EAAE,UAAU,EACjB,EAAE,EAAE,aAAa,GAChB;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAUjC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * The full-loop (L3) proof runners for the testing kit — the half that needs a framework backend.
3
+ *
4
+ * Each runner drives a real {@link runSpecConversation} loop: the {@link fakeLLM} scripted model against a
5
+ * fresh {@link FixtureWorld}, on a spec built by the core kit ({@link buildIsolatedSpec} /
6
+ * {@link buildCollectiveSpec}, which set the fixture theme). It then asserts the expected `recoveryEvents`
7
+ * SIGNAL — the tag the runtime emits when a guard fires.
8
+ *
9
+ * recoveryEvents tag formats (from the @looprun-ai/core runtime): preTool veto `${dim}:${kind}:${tool}`,
10
+ * onInput refusal `onInput:${kind}`, postTool report `output:${kind}:${tool}`, onReply redrive
11
+ * `redrive:${kind}`, exhaustion `exhaustion-terminal`.
12
+ */
13
+ import { requireMake } from '@looprun-ai/core/testing';
14
+ import { FixtureWorld, FIXTURE_TOOL_DEFS } from '@looprun-ai/core/testing';
15
+ import { runSpecConversation } from '../run-conversation.js';
16
+ import { fakeLLM } from './fake-llm.js';
17
+ /** L3 — drive the full runSpecConversation loop for a proof's loop case. The fixture theme rides on the
18
+ * spec (set by the core spec builders); `redrives` is overridable (default 1). The runtime's fixed
19
+ * veto-storm limit never trips these single-veto scripts. */
20
+ export function runProofLoop(spec, l3, redrives = 1) {
21
+ return runSpecConversation(spec, l3.turns, {
22
+ model: fakeLLM(l3.script).model,
23
+ modelParams: {},
24
+ world: new FixtureWorld(l3.preset),
25
+ toolDefs: FIXTURE_TOOL_DEFS,
26
+ redrives,
27
+ });
28
+ }
29
+ /** The `recoveryEvents` tag we expect this proof's loop case to emit ('' for a clean pass). */
30
+ export function expectedSignal(proof, l3) {
31
+ const kind = proof.guard;
32
+ const tool = l3.tool ?? (Array.isArray(proof.target) ? proof.target[0] ?? '' : '');
33
+ switch (l3.expect) {
34
+ case 'veto': {
35
+ const dim = requireMake(proof)().dim;
36
+ return `${dim}:${kind}:${tool}`;
37
+ }
38
+ case 'redrive':
39
+ // A postTool result invariant reports via `output:${kind}:${tool}` (then joins the redrive set);
40
+ // an onReply guard redrives via `redrive:${kind}`.
41
+ return proof.hook === 'postTool' ? `output:${kind}:${tool}` : `redrive:${kind}`;
42
+ case 'refusal':
43
+ return `onInput:${kind}`;
44
+ case 'pass':
45
+ default:
46
+ return '';
47
+ }
48
+ }
49
+ /** Pick the turnRecord a loop case asserts on (l3.turn, default the last). */
50
+ export function pickRecord(res, l3) {
51
+ const idx = l3.turn ?? res.turnRecords.length - 1;
52
+ return res.turnRecords[idx];
53
+ }
54
+ /** Assert the expected signal is present in a turnRecord's recoveryEvents. Returns a verdict + detail. */
55
+ export function assertSignal(record, proof, l3) {
56
+ if (!record)
57
+ return { ok: false, detail: 'no turnRecord to assert on' };
58
+ const events = record.recoveryEvents ?? [];
59
+ if (l3.expect === 'pass') {
60
+ const ok = events.length === 0;
61
+ return { ok, detail: ok ? 'clean pass (no recovery events)' : `expected no recovery events, got: [${events.join(', ')}]` };
62
+ }
63
+ const sig = expectedSignal(proof, l3);
64
+ const ok = events.includes(sig);
65
+ return { ok, detail: ok ? `found '${sig}'` : `expected '${sig}' in recoveryEvents, got: [${events.join(', ')}]` };
66
+ }
67
+ //# sourceMappingURL=proof-loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proof-loop.js","sourceRoot":"","sources":["../../src/testing/proof-loop.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,7 @@
7
7
  * `theme.stateBlock`. A `StateView` supplies those reads; `refresh` (if given) runs at each
8
8
  * turn boundary so remote state can be re-fetched.
9
9
  *
10
- * Ledger-based guards (requiresBefore, noDuplicateCall, confirmFirst, maxCallsPerTurn, …) need
10
+ * Ledger-based guards (requiresBefore, noDuplicateCall, confirmFirst, maxCalls, …) need
11
11
  * NO state view — they read the observed ledger the hooks feed.
12
12
  */
13
13
  import type { AgentWorld } from '@looprun-ai/core';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@looprun-ai/mastra",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
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
6
  "keywords": [
@@ -28,6 +28,10 @@
28
28
  ".": {
29
29
  "types": "./dist/index.d.ts",
30
30
  "default": "./dist/index.js"
31
+ },
32
+ "./testing": {
33
+ "types": "./dist/testing/index.d.ts",
34
+ "default": "./dist/testing/index.js"
31
35
  }
32
36
  },
33
37
  "files": [
@@ -37,7 +41,7 @@
37
41
  "node": ">=22"
38
42
  },
39
43
  "dependencies": {
40
- "@looprun-ai/core": "^0.2.0"
44
+ "@looprun-ai/core": "^0.4.0"
41
45
  },
42
46
  "peerDependencies": {
43
47
  "@mastra/core": "^1.42.0",
@@ -50,11 +54,13 @@
50
54
  "ai": "^6.0.184",
51
55
  "typescript": "^5.7.0",
52
56
  "vitest": "^2.0.0",
53
- "zod": "^3.24.0"
57
+ "zod": "^3.24.0",
58
+ "@looprun-ai/models": "^0.4.0"
54
59
  },
55
60
  "scripts": {
56
61
  "build": "tsc -p tsconfig.build.json",
57
62
  "typecheck": "tsc --noEmit",
58
- "test": "vitest run"
63
+ "test": "vitest run",
64
+ "test:proofs": "vitest run test/proofs --passWithNoTests"
59
65
  }
60
66
  }