@looprun-ai/core 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 (46) hide show
  1. package/LICENSE +202 -0
  2. package/dist/guards.d.ts +76 -0
  3. package/dist/guards.d.ts.map +1 -0
  4. package/dist/guards.js +407 -0
  5. package/dist/guards.js.map +1 -0
  6. package/dist/index.d.ts +23 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +17 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/model-params.d.ts +16 -0
  11. package/dist/model-params.d.ts.map +1 -0
  12. package/dist/model-params.js +27 -0
  13. package/dist/model-params.js.map +1 -0
  14. package/dist/rules.d.ts +76 -0
  15. package/dist/rules.d.ts.map +1 -0
  16. package/dist/rules.js +11 -0
  17. package/dist/rules.js.map +1 -0
  18. package/dist/runtime/ledger.d.ts +28 -0
  19. package/dist/runtime/ledger.d.ts.map +1 -0
  20. package/dist/runtime/ledger.js +50 -0
  21. package/dist/runtime/ledger.js.map +1 -0
  22. package/dist/runtime/terminal.d.ts +18 -0
  23. package/dist/runtime/terminal.d.ts.map +1 -0
  24. package/dist/runtime/terminal.js +50 -0
  25. package/dist/runtime/terminal.js.map +1 -0
  26. package/dist/runtime/turn.d.ts +38 -0
  27. package/dist/runtime/turn.d.ts.map +1 -0
  28. package/dist/runtime/turn.js +127 -0
  29. package/dist/runtime/turn.js.map +1 -0
  30. package/dist/runtime/types.d.ts +55 -0
  31. package/dist/runtime/types.d.ts.map +1 -0
  32. package/dist/runtime/types.js +5 -0
  33. package/dist/runtime/types.js.map +1 -0
  34. package/dist/spec.d.ts +147 -0
  35. package/dist/spec.d.ts.map +1 -0
  36. package/dist/spec.js +168 -0
  37. package/dist/spec.js.map +1 -0
  38. package/dist/trunk.d.ts +35 -0
  39. package/dist/trunk.d.ts.map +1 -0
  40. package/dist/trunk.js +98 -0
  41. package/dist/trunk.js.map +1 -0
  42. package/dist/validate.d.ts +15 -0
  43. package/dist/validate.d.ts.map +1 -0
  44. package/dist/validate.js +36 -0
  45. package/dist/validate.js.map +1 -0
  46. package/package.json +49 -0
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @looprun-ai/core runtime — the per-conversation observation LEDGER (framework-free).
3
+ *
4
+ * The ledger is what guards read (`ctx.observed`, `producedThisTurn`, …): the model's own verified
5
+ * tool activity — never the user text (magnet firewall). `observed` accumulates for the whole
6
+ * conversation; the other fields reset per turn via `beginTurn`.
7
+ */
8
+ import type { ObservedCall } from '../rules.js';
9
+ export interface TurnLedger {
10
+ observed: ObservedCall[];
11
+ turnIndex: number;
12
+ producedThisTurn: string[];
13
+ turnCorrections: string[];
14
+ attachments: string[];
15
+ terminalReply: string;
16
+ }
17
+ export declare function createLedger(): TurnLedger;
18
+ /** Reset the per-turn fields (the conversation-scoped `observed` is kept). */
19
+ export declare function beginTurn(ledger: TurnLedger, turnIndex: number): void;
20
+ /** Structural success check on a tool result ({success:false} / {error} / {PREREQ_NOT_MET} ⇒ failed). */
21
+ export declare function resultOk(r: unknown): boolean;
22
+ /** Record a guard VETO of a tool call (the call did not run). */
23
+ export declare function recordVeto(ledger: TurnLedger, name: string, args: Record<string, unknown>, correction: string): void;
24
+ /** Record an EXECUTED tool call's outcome (afterToolCall): ok flag, confirmation flag, produced label. */
25
+ export declare function recordToolResult(ledger: TurnLedger, name: string, args: Record<string, unknown>, output: unknown): void;
26
+ /** Record a TERMINAL tool call (replyToUser/askUser): capture the user-facing text. */
27
+ export declare function recordTerminal(ledger: TurnLedger, name: string, args: Record<string, unknown>): void;
28
+ //# sourceMappingURL=ledger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/runtime/ledger.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,YAAY,IAAI,UAAU,CAEzC;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAMrE;AAED,yGAAyG;AACzG,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAM5C;AAED,iEAAiE;AACjE,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAGpH;AAED,0GAA0G;AAC1G,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAcvH;AAED,uFAAuF;AACvF,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAIpG"}
@@ -0,0 +1,50 @@
1
+ export function createLedger() {
2
+ return { observed: [], turnIndex: 0, producedThisTurn: [], turnCorrections: [], attachments: [], terminalReply: '' };
3
+ }
4
+ /** Reset the per-turn fields (the conversation-scoped `observed` is kept). */
5
+ export function beginTurn(ledger, turnIndex) {
6
+ ledger.turnIndex = turnIndex;
7
+ ledger.producedThisTurn = [];
8
+ ledger.turnCorrections = [];
9
+ ledger.attachments = [];
10
+ ledger.terminalReply = '';
11
+ }
12
+ /** Structural success check on a tool result ({success:false} / {error} / {PREREQ_NOT_MET} ⇒ failed). */
13
+ export function resultOk(r) {
14
+ if (r && typeof r === 'object') {
15
+ const o = r;
16
+ if (o.success === false || o.PREREQ_NOT_MET === true || typeof o.error === 'string')
17
+ return false;
18
+ }
19
+ return true;
20
+ }
21
+ /** Record a guard VETO of a tool call (the call did not run). */
22
+ export function recordVeto(ledger, name, args, correction) {
23
+ ledger.observed.push({ name, args, ok: false, turnIndex: ledger.turnIndex });
24
+ ledger.turnCorrections.push(correction);
25
+ }
26
+ /** Record an EXECUTED tool call's outcome (afterToolCall): ok flag, confirmation flag, produced label. */
27
+ export function recordToolResult(ledger, name, args, output) {
28
+ const ok = output !== undefined && resultOk(output);
29
+ const requiresConfirmation = output?.requiresConfirmation === true;
30
+ ledger.observed.push({
31
+ name,
32
+ args,
33
+ ok,
34
+ turnIndex: ledger.turnIndex,
35
+ ...(requiresConfirmation ? { resultFlags: { requiresConfirmation: true } } : {}),
36
+ });
37
+ if (ok) {
38
+ const lbl = output?.label;
39
+ if (typeof lbl === 'string')
40
+ ledger.producedThisTurn.push(lbl);
41
+ }
42
+ }
43
+ /** Record a TERMINAL tool call (replyToUser/askUser): capture the user-facing text. */
44
+ export function recordTerminal(ledger, name, args) {
45
+ const text = typeof args.text === 'string' ? args.text : '';
46
+ if (text.trim())
47
+ ledger.terminalReply = text;
48
+ ledger.observed.push({ name, args, ok: true, turnIndex: ledger.turnIndex });
49
+ }
50
+ //# sourceMappingURL=ledger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../src/runtime/ledger.ts"],"names":[],"mappings":"AAkBA,MAAM,UAAU,YAAY;IAC1B,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,gBAAgB,EAAE,EAAE,EAAE,eAAe,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;AACvH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,SAAS,CAAC,MAAkB,EAAE,SAAiB;IAC7D,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,MAAM,CAAC,gBAAgB,GAAG,EAAE,CAAC;IAC7B,MAAM,CAAC,eAAe,GAAG,EAAE,CAAC;IAC5B,MAAM,CAAC,WAAW,GAAG,EAAE,CAAC;IACxB,MAAM,CAAC,aAAa,GAAG,EAAE,CAAC;AAC5B,CAAC;AAED,yGAAyG;AACzG,MAAM,UAAU,QAAQ,CAAC,CAAU;IACjC,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAG,CAA4B,CAAC;QACvC,IAAI,CAAC,CAAC,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC,cAAc,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;IACpG,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,UAAU,CAAC,MAAkB,EAAE,IAAY,EAAE,IAA6B,EAAE,UAAkB;IAC5G,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IAC7E,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAC1C,CAAC;AAED,0GAA0G;AAC1G,MAAM,UAAU,gBAAgB,CAAC,MAAkB,EAAE,IAAY,EAAE,IAA6B,EAAE,MAAe;IAC/G,MAAM,EAAE,GAAG,MAAM,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpD,MAAM,oBAAoB,GAAI,MAAgE,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC9H,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QACnB,IAAI;QACJ,IAAI;QACJ,EAAE;QACF,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,oBAAoB,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACjF,CAAC,CAAC;IACH,IAAI,EAAE,EAAE,CAAC;QACP,MAAM,GAAG,GAAI,MAAiD,EAAE,KAAK,CAAC;QACtE,IAAI,OAAO,GAAG,KAAK,QAAQ;YAAE,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjE,CAAC;AACH,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,cAAc,CAAC,MAAkB,EAAE,IAAY,EAAE,IAA6B;IAC5F,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5D,IAAI,IAAI,CAAC,IAAI,EAAE;QAAE,MAAM,CAAC,aAAa,GAAG,IAAI,CAAC;IAC7C,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;AAC9E,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @looprun-ai/core runtime — the TERMINAL protocol (framework-free).
3
+ *
4
+ * The certified turn shape: the model speaks to the user ONLY through the runtime-owned terminal
5
+ * tools (`replyToUser` / `askUser`) — combined with `toolChoice:'required'` this forces action
6
+ * before speech and makes the user-facing text a verifiable tool argument instead of free text.
7
+ */
8
+ import type { ToolDef } from './types.js';
9
+ export declare const TERMINAL_TOOLS: readonly ["replyToUser", "askUser"];
10
+ export declare function isTerminal(name: string): boolean;
11
+ export declare const TERMINAL_PROTOCOL: string;
12
+ export declare const TERMINAL_PROTOCOL_REPLY_ONLY: string;
13
+ export declare function terminalProtocol(replyOnly: boolean): string;
14
+ /** The forced-terminal fallback prompt (pushes a weak model past the action wall). */
15
+ export declare function forcedTerminalPrompt(replyOnly: boolean): string;
16
+ /** Default JSON-schema defs for the terminal tools (used when the host's toolDefs omit them). */
17
+ export declare function terminalToolDefs(): ToolDef[];
18
+ //# sourceMappingURL=terminal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/runtime/terminal.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,eAAO,MAAM,cAAc,qCAAsC,CAAC;AAGlE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED,eAAO,MAAM,iBAAiB,QAMqD,CAAC;AAEpF,eAAO,MAAM,4BAA4B,QAMgB,CAAC;AAE1D,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAE3D;AAED,sFAAsF;AACtF,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAI/D;AAED,iGAAiG;AACjG,wBAAgB,gBAAgB,IAAI,OAAO,EAAE,CAqB5C"}
@@ -0,0 +1,50 @@
1
+ export const TERMINAL_TOOLS = ['replyToUser', 'askUser'];
2
+ const TERMINAL_SET = new Set(TERMINAL_TOOLS);
3
+ export function isTerminal(name) {
4
+ return TERMINAL_SET.has(name);
5
+ }
6
+ export const TERMINAL_PROTOCOL = '\n\n## Turn protocol (ABSOLUTE)\n' +
7
+ '- You speak to the user ONLY by calling **replyToUser** (to answer or summarize what you did) or **askUser** ' +
8
+ '(to ask ONE clarifying question). NEVER write a free-text reply — text outside these tools is not delivered.\n' +
9
+ '- Every turn MUST call at least one tool, and MUST END by calling exactly one replyToUser or askUser whose ' +
10
+ '`text` carries the COMPLETE user-facing message in the user\'s language.\n' +
11
+ '- Do the domain tools first; then close the turn with the single terminal call.';
12
+ export const TERMINAL_PROTOCOL_REPLY_ONLY = '\n\n## Turn protocol (ABSOLUTE)\n' +
13
+ '- You speak to the user ONLY by calling **replyToUser**. NEVER write a free-text reply and NEVER ask the ' +
14
+ 'user a question — there is no ask tool.\n' +
15
+ '- If something is ambiguous, make the MOST REASONABLE assumption and PROCEED — never stop to ask.\n' +
16
+ '- Every turn MUST first DO the requested action with the domain tools, then END by calling replyToUser whose ' +
17
+ '`text` reports what you did, in the user\'s language.';
18
+ export function terminalProtocol(replyOnly) {
19
+ return replyOnly ? TERMINAL_PROTOCOL_REPLY_ONLY : TERMINAL_PROTOCOL;
20
+ }
21
+ /** The forced-terminal fallback prompt (pushes a weak model past the action wall). */
22
+ export function forcedTerminalPrompt(replyOnly) {
23
+ return replyOnly
24
+ ? 'Close the turn now by calling replyToUser. Do NOT ask a question — state what you did in `text`.'
25
+ : 'Close the turn now: call replyToUser to answer / summarize what you did, or askUser to ask ONE clarifying question. Put the COMPLETE user-facing message in `text`.';
26
+ }
27
+ /** Default JSON-schema defs for the terminal tools (used when the host's toolDefs omit them). */
28
+ export function terminalToolDefs() {
29
+ return [
30
+ {
31
+ name: 'replyToUser',
32
+ description: 'Deliver the COMPLETE user-facing reply for this turn. Call exactly once, at the end of the turn.',
33
+ inputSchema: {
34
+ type: 'object',
35
+ properties: { text: { type: 'string', description: "The complete user-facing message, in the user's language." } },
36
+ required: ['text'],
37
+ },
38
+ },
39
+ {
40
+ name: 'askUser',
41
+ description: 'Ask the user ONE clarifying question and end the turn. Use only when you cannot proceed.',
42
+ inputSchema: {
43
+ type: 'object',
44
+ properties: { text: { type: 'string', description: "The single clarifying question, in the user's language." } },
45
+ required: ['text'],
46
+ },
47
+ },
48
+ ];
49
+ }
50
+ //# sourceMappingURL=terminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../src/runtime/terminal.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,aAAa,EAAE,SAAS,CAAU,CAAC;AAClE,MAAM,YAAY,GAAwB,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC;AAElE,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAC5B,mCAAmC;IACnC,+GAA+G;IAC/G,gHAAgH;IAChH,6GAA6G;IAC7G,4EAA4E;IAC5E,iFAAiF,CAAC;AAEpF,MAAM,CAAC,MAAM,4BAA4B,GACvC,mCAAmC;IACnC,2GAA2G;IAC3G,2CAA2C;IAC3C,qGAAqG;IACrG,+GAA+G;IAC/G,uDAAuD,CAAC;AAE1D,MAAM,UAAU,gBAAgB,CAAC,SAAkB;IACjD,OAAO,SAAS,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,iBAAiB,CAAC;AACtE,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,oBAAoB,CAAC,SAAkB;IACrD,OAAO,SAAS;QACd,CAAC,CAAC,kGAAkG;QACpG,CAAC,CAAC,qKAAqK,CAAC;AAC5K,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,gBAAgB;IAC9B,OAAO;QACL;YACE,IAAI,EAAE,aAAa;YACnB,WAAW,EAAE,kGAAkG;YAC/G,WAAW,EAAE;gBACX,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,2DAA2D,EAAE,EAAE;gBAClH,QAAQ,EAAE,CAAC,MAAM,CAAC;aACnB;SACF;QACD;YACE,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,0FAA0F;YACvG,WAAW,EAAE;gBACX,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yDAAyD,EAAE,EAAE;gBAChH,QAAQ,EAAE,CAAC,MAAM,CAAC;aACnB;SACF;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { AgentSpec } from '../spec.js';
2
+ import type { TrunkTheme } from '../trunk.js';
3
+ import type { AgentWorld, Guard } from '../rules.js';
4
+ import { type TurnLedger } from './ledger.js';
5
+ export interface ReplyViolation {
6
+ guard: Guard;
7
+ reason: string;
8
+ }
9
+ export type PreToolVerdict = {
10
+ verdict: 'allow';
11
+ } | {
12
+ verdict: 'deny';
13
+ reason: string;
14
+ guard: Guard;
15
+ };
16
+ /** Run the preTool guards for one candidate call. On deny, the veto is recorded in the ledger. */
17
+ export declare function evaluatePreTool(spec: AgentSpec, ledger: TurnLedger, world: AgentWorld, tool: string, args: Record<string, unknown>): Promise<PreToolVerdict>;
18
+ /** Run the onInput guards (before any LLM call). Returns the refusal reason, or null to proceed. */
19
+ export declare function evaluateOnInput(spec: AgentSpec, ledger: TurnLedger, world: AgentWorld): Promise<string | null>;
20
+ /** Apply the deterministic egress mutators (e.g. jargonScrub) to the reply text. */
21
+ export declare function applyMutators(spec: AgentSpec, ledger: TurnLedger, world: AgentWorld, text: string): string;
22
+ /** Run the onReply guard checks against a candidate reply. */
23
+ export declare function checkReply(spec: AgentSpec, ledger: TurnLedger, world: AgentWorld, text: string): Promise<ReplyViolation[]>;
24
+ /** The redrive user message a backend sends for a bounded NO-TOOLS re-generation. */
25
+ export declare function redriveMessage(violations: ReplyViolation[]): string;
26
+ /** The built-in honest-abstain closure: a pure function of verified observations. */
27
+ export declare function defaultExhaustionReply(theme: TrunkTheme | undefined, world: AgentWorld, okTools: string[], produced: string[], violations: string[]): string;
28
+ export interface FinalizedReply {
29
+ text: string;
30
+ exhausted: boolean;
31
+ violations: string[];
32
+ }
33
+ /**
34
+ * The whole reply pipeline: mutators → onReply checks → up to `maxRedrives` NO-TOOLS re-generations
35
+ * (via the backend-supplied `redrive` callback) → deterministic exhaustion closure if still violating.
36
+ */
37
+ export declare function finalizeReply(spec: AgentSpec, theme: TrunkTheme | undefined, world: AgentWorld, ledger: TurnLedger, initialText: string, redrive: (message: string) => Promise<string>, maxRedrives: number): Promise<FinalizedReply>;
38
+ //# sourceMappingURL=turn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turn.d.ts","sourceRoot":"","sources":["../../src/runtime/turn.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAY,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,GACpB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAEtD,kGAAkG;AAClG,wBAAsB,eAAe,CACnC,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,cAAc,CAAC,CAkBzB;AAED,oGAAoG;AACpG,wBAAsB,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAWpH;AAED,oFAAoF;AACpF,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAkB1G;AAED,8DAA8D;AAC9D,wBAAsB,UAAU,CAC9B,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,cAAc,EAAE,CAAC,CAiB3B;AAED,qFAAqF;AACrF,wBAAgB,cAAc,CAAC,UAAU,EAAE,cAAc,EAAE,GAAG,MAAM,CAGnE;AAED,qFAAqF;AACrF,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,UAAU,GAAG,SAAS,EAC7B,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,MAAM,EAAE,EACjB,QAAQ,EAAE,MAAM,EAAE,EAClB,UAAU,EAAE,MAAM,EAAE,GACnB,MAAM,CAKR;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,UAAU,GAAG,SAAS,EAC7B,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,UAAU,EAClB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,EAC7C,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC,CAsBzB"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * @looprun-ai/core runtime — the governed-TURN state machine (framework-free).
3
+ *
4
+ * Everything deterministic about one turn lives here; a backend (e.g. @looprun-ai/mastra) supplies only
5
+ * the framework glue: how tools are wired, how the LLM is called, and ONE async `redrive` callback
6
+ * that re-generates text with tools disabled.
7
+ *
8
+ * The reply pipeline (finalizeReply): mutators → onReply checks → bounded NO-TOOLS redrive →
9
+ * deterministic honest-abstain closure. The redrive is a plain text re-generation with the
10
+ * correction appended — NEVER a framework retry that re-runs the whole generation (that re-executes
11
+ * side-effecting tools; measured ~100× slower).
12
+ */
13
+ import { resolveGuards, resolveMutators } from '../spec.js';
14
+ import { recordVeto } from './ledger.js';
15
+ /** Run the preTool guards for one candidate call. On deny, the veto is recorded in the ledger. */
16
+ export async function evaluatePreTool(spec, ledger, world, tool, args) {
17
+ const guards = resolveGuards(spec.guards.preTool, tool);
18
+ const gctx = {
19
+ args,
20
+ tool,
21
+ world,
22
+ observed: ledger.observed,
23
+ turnIndex: ledger.turnIndex,
24
+ attachmentsThisTurn: ledger.attachments,
25
+ };
26
+ for (const g of guards) {
27
+ const reason = await g.check(gctx);
28
+ if (reason) {
29
+ recordVeto(ledger, tool, args, `${g.dim}:${g.kind}:${tool}`);
30
+ return { verdict: 'deny', reason, guard: g };
31
+ }
32
+ }
33
+ return { verdict: 'allow' };
34
+ }
35
+ /** Run the onInput guards (before any LLM call). Returns the refusal reason, or null to proceed. */
36
+ export async function evaluateOnInput(spec, ledger, world) {
37
+ const guards = resolveGuards(spec.guards.onInput);
38
+ const gctx = { args: {}, world, observed: ledger.observed, turnIndex: ledger.turnIndex };
39
+ for (const g of guards) {
40
+ const reason = await g.check(gctx);
41
+ if (reason) {
42
+ ledger.turnCorrections.push(`onInput:${g.kind}`);
43
+ return reason;
44
+ }
45
+ }
46
+ return null;
47
+ }
48
+ /** Apply the deterministic egress mutators (e.g. jargonScrub) to the reply text. */
49
+ export function applyMutators(spec, ledger, world, text) {
50
+ let out = text;
51
+ for (const m of resolveMutators(spec.guards.onReplyMutate)) {
52
+ const mctx = {
53
+ args: {},
54
+ world,
55
+ observed: ledger.observed,
56
+ turnIndex: ledger.turnIndex,
57
+ reply: out,
58
+ producedThisTurn: ledger.producedThisTurn,
59
+ };
60
+ const next = m.apply(out, mctx);
61
+ if (next !== out) {
62
+ ledger.turnCorrections.push(`mutate:${m.kind}`);
63
+ out = next;
64
+ }
65
+ }
66
+ return out;
67
+ }
68
+ /** Run the onReply guard checks against a candidate reply. */
69
+ export async function checkReply(spec, ledger, world, text) {
70
+ const rctx = {
71
+ args: {},
72
+ world,
73
+ observed: ledger.observed,
74
+ turnIndex: ledger.turnIndex,
75
+ reply: text,
76
+ producedThisTurn: ledger.producedThisTurn,
77
+ attachmentsThisTurn: ledger.attachments,
78
+ notes: ledger.turnCorrections,
79
+ };
80
+ const out = [];
81
+ for (const g of resolveGuards(spec.guards.onReply)) {
82
+ const r = await g.check(rctx);
83
+ if (r)
84
+ out.push({ guard: g, reason: r });
85
+ }
86
+ return out;
87
+ }
88
+ /** The redrive user message a backend sends for a bounded NO-TOOLS re-generation. */
89
+ export function redriveMessage(violations) {
90
+ const correction = violations.map((v) => `- ${v.reason}`).join('\n');
91
+ return `Revise your last reply to the user:\n${correction}\nReply now in the user's language. Do NOT call a tool.`;
92
+ }
93
+ /** The built-in honest-abstain closure: a pure function of verified observations. */
94
+ export function defaultExhaustionReply(theme, world, okTools, produced, violations) {
95
+ if (theme?.exhaustionReply)
96
+ return theme.exhaustionReply(world, okTools, produced, violations);
97
+ return okTools.length
98
+ ? `Done this step: ${[...new Set(okTools)].join(', ')}${produced.length ? ` (${produced.join(', ')})` : ''}. I could not safely finish the rest — how would you like to proceed?`
99
+ : 'I could not complete this safely — nothing was changed. Could you rephrase or add detail?';
100
+ }
101
+ /**
102
+ * The whole reply pipeline: mutators → onReply checks → up to `maxRedrives` NO-TOOLS re-generations
103
+ * (via the backend-supplied `redrive` callback) → deterministic exhaustion closure if still violating.
104
+ */
105
+ export async function finalizeReply(spec, theme, world, ledger, initialText, redrive, maxRedrives) {
106
+ let text = applyMutators(spec, ledger, world, initialText);
107
+ let violations = await checkReply(spec, ledger, world, text);
108
+ for (let r = 0; r < maxRedrives && violations.length; r++) {
109
+ const next = await redrive(redriveMessage(violations));
110
+ for (const v of violations)
111
+ ledger.turnCorrections.push(`redrive:${v.guard.kind}`);
112
+ if (next)
113
+ text = next;
114
+ violations = await checkReply(spec, ledger, world, text);
115
+ }
116
+ const finalViolations = violations.map((v) => v.guard.kind);
117
+ if (finalViolations.length) {
118
+ const okTools = ledger.observed.filter((o) => o.turnIndex === ledger.turnIndex && o.ok).map((o) => o.name);
119
+ const closure = spec.controls.exhaustionReply
120
+ ? spec.controls.exhaustionReply(world, okTools, ledger.producedThisTurn, finalViolations)
121
+ : defaultExhaustionReply(theme, world, okTools, ledger.producedThisTurn, finalViolations);
122
+ ledger.turnCorrections.push('exhaustion-terminal');
123
+ return { text: closure, exhausted: true, violations: finalViolations };
124
+ }
125
+ return { text, exhausted: false, violations: [] };
126
+ }
127
+ //# sourceMappingURL=turn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turn.js","sourceRoot":"","sources":["../../src/runtime/turn.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @looprun-ai/core runtime — shared types of the governed-turn machine (framework-free).
3
+ */
4
+ /** A tool definition (name / description / JSON schema) executed through the world seam. */
5
+ export interface ToolDef {
6
+ name: string;
7
+ description: string;
8
+ inputSchema: Record<string, unknown>;
9
+ }
10
+ export interface TokenUsage {
11
+ input: number | null;
12
+ output: number | null;
13
+ reasoning: number | null;
14
+ cacheRead: number | null;
15
+ cacheWrite: number | null;
16
+ total: number | null;
17
+ }
18
+ /** One conversation turn's input (channel-agnostic). */
19
+ export interface TurnInput {
20
+ userText: string;
21
+ attachments?: string[];
22
+ }
23
+ /** A per-turn record emitted by a backend's conversation runner. */
24
+ export interface TurnRecord {
25
+ userText: string;
26
+ assistantFinalText: string;
27
+ finalMode: string;
28
+ assistantMsgCount: number;
29
+ iters: number;
30
+ llmCalls: number;
31
+ toolCalls: Array<{
32
+ name: string;
33
+ args: unknown;
34
+ resultSummary: string;
35
+ tookEffect?: boolean;
36
+ latencyMs: number;
37
+ }>;
38
+ thoughts: string | null;
39
+ tokens: TokenUsage;
40
+ llmCallLatenciesMs: number[];
41
+ durationMs: number;
42
+ maxIterHit: boolean;
43
+ recoveryEvents: string[];
44
+ sseActions?: unknown[];
45
+ attachments?: string[];
46
+ }
47
+ export interface RunResult {
48
+ turnRecords: TurnRecord[];
49
+ messages: any[];
50
+ errorMsg?: string;
51
+ }
52
+ /** Continuity aliases (the pre-extraction runtime names). */
53
+ export type RuntimeTurnInput = TurnInput;
54
+ export type RuntimeTurnRecord = TurnRecord;
55
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,4FAA4F;AAC5F,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wDAAwD;AACxD,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,oEAAoE;AACpE,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,UAAU,CAAC;IACnB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,UAAU,EAAE,CAAC;IAE1B,QAAQ,EAAE,GAAG,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,6DAA6D;AAC7D,MAAM,MAAM,gBAAgB,GAAG,SAAS,CAAC;AACzC,MAAM,MAAM,iBAAiB,GAAG,UAAU,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @looprun-ai/core runtime — shared types of the governed-turn machine (framework-free).
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
package/dist/spec.d.ts ADDED
@@ -0,0 +1,147 @@
1
+ import type { AgentWorld, Guard, ReplyMutator, SpatialEdge } from './rules.js';
2
+ import type { TrunkTheme } from './trunk.js';
3
+ export type Hook = 'onInput' | 'preTool' | 'postTool' | 'onReply';
4
+ export type ToolTarget = 'any' | string[];
5
+ export type Layer = 'minimal' | 'base' | 'full' | 'agent';
6
+ /** true ⇒ force reply()-only this turn (drop askUser). State-driven, per turn. */
7
+ export type TerminalPolicy = (world: AgentWorld) => boolean;
8
+ /** State-keyed positive guidance rendered statically as "IF <cond> → <directive>" (cache-stable). */
9
+ export interface StateDirective {
10
+ id: string;
11
+ cond: string;
12
+ directive: string;
13
+ when?: (world: AgentWorld) => boolean;
14
+ }
15
+ export interface AgentModelRef {
16
+ provider?: string;
17
+ model?: string;
18
+ id?: string;
19
+ }
20
+ export interface MutatorBinding {
21
+ id: string;
22
+ mutator: ReplyMutator;
23
+ layer: Layer;
24
+ disabled: boolean;
25
+ }
26
+ export interface GuardBinding {
27
+ id: string;
28
+ target: ToolTarget;
29
+ guard: Guard;
30
+ layer: Layer;
31
+ disabled: boolean;
32
+ }
33
+ export interface AgentControls {
34
+ maxSteps?: number;
35
+ redrives?: number;
36
+ terminal?: TerminalPolicy;
37
+ directives?: StateDirective[];
38
+ escalate?: {
39
+ model: AgentModelRef;
40
+ maxAttempts?: number;
41
+ };
42
+ /** Committed when the reply still violates its checks after all redrives — MUST be a pure function
43
+ * of verified observations (structurally unable to fabricate). Omitted ⇒ the theme/default closure. */
44
+ exhaustionReply?: (world: AgentWorld, okTools: string[], produced: string[], violations: string[]) => string;
45
+ }
46
+ export interface AgentSpec {
47
+ id: string;
48
+ mode: string;
49
+ /** THIS agent's persona/role line (persona-on-spec law: per-agent, owned by the spec — never a
50
+ * shared/global persona; the domain-common VOICE lives on the theme). Rendered as the FIRST
51
+ * `## Behavior` bullet — per-agent divergence as late as possible so the domain's agents share a
52
+ * maximal static trunk prefix (trunk-static law). MUST be case-invariant (state-in-tail law). */
53
+ persona: string;
54
+ surface: {
55
+ tools: string[];
56
+ systemPrompt?: (world: AgentWorld, recentUploads?: readonly string[]) => string;
57
+ };
58
+ flow: SpatialEdge[];
59
+ guards: {
60
+ onInput?: GuardBinding[];
61
+ preTool: GuardBinding[];
62
+ postTool?: GuardBinding[];
63
+ onReply: GuardBinding[];
64
+ onReplyMutate?: MutatorBinding[];
65
+ };
66
+ controls: AgentControls;
67
+ behavior: string[];
68
+ /** Optional reference to the DOMAIN theme this spec belongs to. Themes stay domain-level objects
69
+ * (1 theme : N agents, byte-identical shared trunk head — trunk-static law); this field lets a
70
+ * generated bundle point every spec at the SAME theme object so a host can construct an agent
71
+ * from the spec alone. A host-provided theme always overrides it. */
72
+ theme?: TrunkTheme;
73
+ }
74
+ export declare function resolveBindings(bindings: GuardBinding[] | undefined, tool?: string): GuardBinding[];
75
+ export declare function resolveGuards(bindings: GuardBinding[] | undefined, tool?: string): Guard[];
76
+ export declare function resolveMutators(bindings: MutatorBinding[] | undefined): ReplyMutator[];
77
+ export interface ToolSchemaLike {
78
+ required?: string[];
79
+ properties?: Record<string, {
80
+ pattern?: string;
81
+ type?: string;
82
+ }>;
83
+ }
84
+ export interface AgentSpecConfig {
85
+ id: string;
86
+ mode: string;
87
+ /** Required per-agent persona/role line (persona-on-spec law) — case-invariant; rendered as the
88
+ * first Behavior bullet. */
89
+ persona: string;
90
+ tools: string[];
91
+ systemPrompt?: (world: AgentWorld, recentUploads?: readonly string[]) => string;
92
+ flow?: SpatialEdge[];
93
+ behavior?: string[];
94
+ terminal?: TerminalPolicy;
95
+ directives?: StateDirective[];
96
+ maxSteps?: number;
97
+ redrives?: number;
98
+ escalate?: {
99
+ model: AgentModelRef;
100
+ maxAttempts?: number;
101
+ };
102
+ exhaustionReply?: (world: AgentWorld, okTools: string[], produced: string[], violations: string[]) => string;
103
+ destructiveTools?: string[];
104
+ toolSchemas?: Record<string, ToolSchemaLike>;
105
+ /** Optional domain-theme reference (see {@link AgentSpec.theme}). */
106
+ theme?: TrunkTheme;
107
+ }
108
+ export declare class AgentSpecMinimal implements AgentSpec {
109
+ readonly id: string;
110
+ readonly mode: string;
111
+ readonly persona: string;
112
+ readonly surface: AgentSpec['surface'];
113
+ readonly flow: SpatialEdge[];
114
+ readonly guards: Required<AgentSpec['guards']>;
115
+ readonly controls: AgentControls;
116
+ readonly behavior: string[];
117
+ readonly theme?: TrunkTheme;
118
+ protected readonly destructiveTools: string[];
119
+ protected readonly toolSchemas: Record<string, ToolSchemaLike>;
120
+ private seq;
121
+ constructor(cfg: AgentSpecConfig);
122
+ protected installMinimal(): void;
123
+ addGuard(hook: Hook, target: ToolTarget, guard: Guard, opts?: {
124
+ id?: string;
125
+ layer?: Layer;
126
+ }): string;
127
+ addReplyCheck(guard: Guard, opts?: {
128
+ id?: string;
129
+ layer?: Layer;
130
+ }): string;
131
+ addMutator(mutator: ReplyMutator, opts?: {
132
+ id?: string;
133
+ layer?: Layer;
134
+ }): string;
135
+ get isPureGuardSet(): boolean;
136
+ addBehavior(line: string): this;
137
+ addFlow(edge: SpatialEdge): this;
138
+ }
139
+ export declare class AgentSpecBase extends AgentSpecMinimal {
140
+ constructor(cfg: AgentSpecConfig);
141
+ protected installBase(): void;
142
+ }
143
+ export declare class AgentSpecFull extends AgentSpecBase {
144
+ constructor(cfg: AgentSpecConfig);
145
+ protected installFull(): void;
146
+ }
147
+ //# sourceMappingURL=spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../src/spec.ts"],"names":[],"mappings":"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"}