@moxxy/sdk 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 (211) hide show
  1. package/dist/agent.d.ts +39 -0
  2. package/dist/agent.d.ts.map +1 -0
  3. package/dist/agent.js +2 -0
  4. package/dist/agent.js.map +1 -0
  5. package/dist/cache-strategy.d.ts +35 -0
  6. package/dist/cache-strategy.d.ts.map +1 -0
  7. package/dist/cache-strategy.js +2 -0
  8. package/dist/cache-strategy.js.map +1 -0
  9. package/dist/channel.d.ts +146 -0
  10. package/dist/channel.d.ts.map +1 -0
  11. package/dist/channel.js +2 -0
  12. package/dist/channel.js.map +1 -0
  13. package/dist/client-session.d.ts +83 -0
  14. package/dist/client-session.d.ts.map +1 -0
  15. package/dist/client-session.js +2 -0
  16. package/dist/client-session.js.map +1 -0
  17. package/dist/command.d.ts +90 -0
  18. package/dist/command.d.ts.map +1 -0
  19. package/dist/command.js +15 -0
  20. package/dist/command.js.map +1 -0
  21. package/dist/compactor-helpers.d.ts +34 -0
  22. package/dist/compactor-helpers.d.ts.map +1 -0
  23. package/dist/compactor-helpers.js +156 -0
  24. package/dist/compactor-helpers.js.map +1 -0
  25. package/dist/compactor.d.ts +20 -0
  26. package/dist/compactor.d.ts.map +1 -0
  27. package/dist/compactor.js +2 -0
  28. package/dist/compactor.js.map +1 -0
  29. package/dist/define.d.ts +51 -0
  30. package/dist/define.d.ts.map +1 -0
  31. package/dist/define.js +71 -0
  32. package/dist/define.js.map +1 -0
  33. package/dist/elision-helpers.d.ts +27 -0
  34. package/dist/elision-helpers.d.ts.map +1 -0
  35. package/dist/elision-helpers.js +109 -0
  36. package/dist/elision-helpers.js.map +1 -0
  37. package/dist/elision-state.d.ts +49 -0
  38. package/dist/elision-state.d.ts.map +1 -0
  39. package/dist/elision-state.js +144 -0
  40. package/dist/elision-state.js.map +1 -0
  41. package/dist/embedding-cache.d.ts +32 -0
  42. package/dist/embedding-cache.d.ts.map +1 -0
  43. package/dist/embedding-cache.js +0 -0
  44. package/dist/embedding-cache.js.map +1 -0
  45. package/dist/embedding.d.ts +21 -0
  46. package/dist/embedding.d.ts.map +1 -0
  47. package/dist/embedding.js +2 -0
  48. package/dist/embedding.js.map +1 -0
  49. package/dist/errors.d.ts +81 -0
  50. package/dist/errors.d.ts.map +1 -0
  51. package/dist/errors.js +241 -0
  52. package/dist/errors.js.map +1 -0
  53. package/dist/events.d.ts +193 -0
  54. package/dist/events.d.ts.map +1 -0
  55. package/dist/events.js +2 -0
  56. package/dist/events.js.map +1 -0
  57. package/dist/hooks.d.ts +52 -0
  58. package/dist/hooks.d.ts.map +1 -0
  59. package/dist/hooks.js +2 -0
  60. package/dist/hooks.js.map +1 -0
  61. package/dist/ids.d.ts +18 -0
  62. package/dist/ids.d.ts.map +1 -0
  63. package/dist/ids.js +7 -0
  64. package/dist/ids.js.map +1 -0
  65. package/dist/index.d.ts +45 -0
  66. package/dist/index.d.ts.map +1 -0
  67. package/dist/index.js +18 -0
  68. package/dist/index.js.map +1 -0
  69. package/dist/install-hints.d.ts +26 -0
  70. package/dist/install-hints.d.ts.map +1 -0
  71. package/dist/install-hints.js +15 -0
  72. package/dist/install-hints.js.map +1 -0
  73. package/dist/isolation.d.ts +125 -0
  74. package/dist/isolation.d.ts.map +1 -0
  75. package/dist/isolation.js +11 -0
  76. package/dist/isolation.js.map +1 -0
  77. package/dist/log.d.ts +11 -0
  78. package/dist/log.d.ts.map +1 -0
  79. package/dist/log.js +2 -0
  80. package/dist/log.js.map +1 -0
  81. package/dist/mode-helpers.d.ts +99 -0
  82. package/dist/mode-helpers.d.ts.map +1 -0
  83. package/dist/mode-helpers.js +368 -0
  84. package/dist/mode-helpers.js.map +1 -0
  85. package/dist/mode.d.ts +133 -0
  86. package/dist/mode.d.ts.map +1 -0
  87. package/dist/mode.js +2 -0
  88. package/dist/mode.js.map +1 -0
  89. package/dist/permission.d.ts +35 -0
  90. package/dist/permission.d.ts.map +1 -0
  91. package/dist/permission.js +2 -0
  92. package/dist/permission.js.map +1 -0
  93. package/dist/plugin.d.ts +88 -0
  94. package/dist/plugin.d.ts.map +1 -0
  95. package/dist/plugin.js +2 -0
  96. package/dist/plugin.js.map +1 -0
  97. package/dist/provider-utils.d.ts +40 -0
  98. package/dist/provider-utils.d.ts.map +1 -0
  99. package/dist/provider-utils.js +163 -0
  100. package/dist/provider-utils.js.map +1 -0
  101. package/dist/provider.d.ts +219 -0
  102. package/dist/provider.d.ts.map +1 -0
  103. package/dist/provider.js +2 -0
  104. package/dist/provider.js.map +1 -0
  105. package/dist/requirements.d.ts +22 -0
  106. package/dist/requirements.d.ts.map +1 -0
  107. package/dist/requirements.js +2 -0
  108. package/dist/requirements.js.map +1 -0
  109. package/dist/schemas.d.ts +228 -0
  110. package/dist/schemas.d.ts.map +1 -0
  111. package/dist/schemas.js +88 -0
  112. package/dist/schemas.js.map +1 -0
  113. package/dist/session-like.d.ts +111 -0
  114. package/dist/session-like.d.ts.map +1 -0
  115. package/dist/session-like.js +2 -0
  116. package/dist/session-like.js.map +1 -0
  117. package/dist/skill.d.ts +30 -0
  118. package/dist/skill.d.ts.map +1 -0
  119. package/dist/skill.js +2 -0
  120. package/dist/skill.js.map +1 -0
  121. package/dist/subagent.d.ts +45 -0
  122. package/dist/subagent.d.ts.map +1 -0
  123. package/dist/subagent.js +11 -0
  124. package/dist/subagent.js.map +1 -0
  125. package/dist/token-accounting.d.ts +73 -0
  126. package/dist/token-accounting.d.ts.map +1 -0
  127. package/dist/token-accounting.js +129 -0
  128. package/dist/token-accounting.js.map +1 -0
  129. package/dist/tool-dispatch.d.ts +19 -0
  130. package/dist/tool-dispatch.d.ts.map +1 -0
  131. package/dist/tool-dispatch.js +118 -0
  132. package/dist/tool-dispatch.js.map +1 -0
  133. package/dist/tool-gating.d.ts +32 -0
  134. package/dist/tool-gating.d.ts.map +1 -0
  135. package/dist/tool-gating.js +83 -0
  136. package/dist/tool-gating.js.map +1 -0
  137. package/dist/tool.d.ts +166 -0
  138. package/dist/tool.d.ts.map +1 -0
  139. package/dist/tool.js +2 -0
  140. package/dist/tool.js.map +1 -0
  141. package/dist/transcriber.d.ts +64 -0
  142. package/dist/transcriber.d.ts.map +1 -0
  143. package/dist/transcriber.js +21 -0
  144. package/dist/transcriber.js.map +1 -0
  145. package/dist/tunnel.d.ts +25 -0
  146. package/dist/tunnel.d.ts.map +1 -0
  147. package/dist/tunnel.js +2 -0
  148. package/dist/tunnel.js.map +1 -0
  149. package/dist/type-contracts.d.ts +2 -0
  150. package/dist/type-contracts.d.ts.map +1 -0
  151. package/dist/type-contracts.js +4 -0
  152. package/dist/type-contracts.js.map +1 -0
  153. package/dist/types.test-d.d.ts +2 -0
  154. package/dist/types.test-d.d.ts.map +1 -0
  155. package/dist/types.test-d.js +22 -0
  156. package/dist/types.test-d.js.map +1 -0
  157. package/dist/view-renderer.d.ts +97 -0
  158. package/dist/view-renderer.d.ts.map +1 -0
  159. package/dist/view-renderer.js +72 -0
  160. package/dist/view-renderer.js.map +1 -0
  161. package/package.json +38 -0
  162. package/src/agent.ts +38 -0
  163. package/src/cache-strategy.ts +39 -0
  164. package/src/channel.ts +158 -0
  165. package/src/client-session.ts +88 -0
  166. package/src/command.ts +86 -0
  167. package/src/compactor-helpers.test.ts +206 -0
  168. package/src/compactor-helpers.ts +163 -0
  169. package/src/compactor.ts +20 -0
  170. package/src/define.test.ts +76 -0
  171. package/src/define.ts +113 -0
  172. package/src/elision-helpers.ts +143 -0
  173. package/src/elision-state.ts +170 -0
  174. package/src/embedding-cache.ts +0 -0
  175. package/src/embedding.ts +22 -0
  176. package/src/errors.test.ts +176 -0
  177. package/src/errors.ts +308 -0
  178. package/src/events.ts +250 -0
  179. package/src/hooks.ts +54 -0
  180. package/src/ids.ts +16 -0
  181. package/src/index.ts +304 -0
  182. package/src/install-hints.ts +43 -0
  183. package/src/isolation.ts +148 -0
  184. package/src/log.ts +11 -0
  185. package/src/loop-helpers.test.ts +78 -0
  186. package/src/mode-helpers.ts +483 -0
  187. package/src/mode.ts +139 -0
  188. package/src/package-root.test.ts +40 -0
  189. package/src/permission.ts +37 -0
  190. package/src/plugin.ts +92 -0
  191. package/src/provider-utils.test.ts +84 -0
  192. package/src/provider-utils.ts +171 -0
  193. package/src/provider.ts +195 -0
  194. package/src/requirements.ts +35 -0
  195. package/src/schemas.test.ts +106 -0
  196. package/src/schemas.ts +97 -0
  197. package/src/session-like.ts +118 -0
  198. package/src/skill.ts +34 -0
  199. package/src/subagent.ts +46 -0
  200. package/src/token-accounting.test.ts +93 -0
  201. package/src/token-accounting.ts +202 -0
  202. package/src/token-efficiency.test.ts +459 -0
  203. package/src/tool-dispatch.ts +137 -0
  204. package/src/tool-gating.ts +107 -0
  205. package/src/tool.ts +175 -0
  206. package/src/transcriber.ts +71 -0
  207. package/src/tunnel.ts +26 -0
  208. package/src/type-contracts.ts +4 -0
  209. package/src/types.test-d.ts +29 -0
  210. package/src/view-renderer.test.ts +90 -0
  211. package/src/view-renderer.ts +156 -0
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Token accounting derived from the event log. The single source of truth is
3
+ * the stream of `provider_response` events (each carries the provider-reported
4
+ * usage for one call); cumulative session totals are just a fold over them, so
5
+ * there is no separate mutable counter to keep in sync.
6
+ *
7
+ * Anthropic usage semantics (which this models): `inputTokens` is the
8
+ * NON-cached portion of the prompt; cache reads and cache writes are reported
9
+ * separately and are NOT included in `inputTokens`. So the full prompt size of
10
+ * a call is `input + cacheRead + cacheCreation`.
11
+ */
12
+ // Relative price multipliers vs. an uncached input token (Anthropic ephemeral
13
+ // cache pricing). Kept here so the savings math is explicit and tweakable.
14
+ const CACHE_READ_MULT = 0.1;
15
+ const CACHE_WRITE_MULT = 1.25;
16
+ /** Partial `provider_response` fields for a given usage; `{}` when usage is absent. */
17
+ export function usageEventFields(usage) {
18
+ if (!usage)
19
+ return {};
20
+ return {
21
+ inputTokens: usage.inputTokens,
22
+ outputTokens: usage.outputTokens,
23
+ ...(usage.cacheReadTokens !== undefined ? { cacheReadTokens: usage.cacheReadTokens } : {}),
24
+ ...(usage.cacheCreationTokens !== undefined
25
+ ? { cacheCreationTokens: usage.cacheCreationTokens }
26
+ : {}),
27
+ };
28
+ }
29
+ /** Fold `provider_response` events into cumulative per-session token totals. */
30
+ export function summarizeSessionTokens(log) {
31
+ return foldResponses(log.ofType('provider_response'));
32
+ }
33
+ /**
34
+ * Same as {@link summarizeSessionTokens} but over a raw event array — for
35
+ * channels (e.g. the TUI) that hold the materialized event stream rather than
36
+ * an `EventLogReader`.
37
+ */
38
+ export function summarizeSessionTokensFromEvents(events) {
39
+ return foldResponses(events.filter((e) => e.type === 'provider_response'));
40
+ }
41
+ const ZERO_TOTALS = {
42
+ calls: 0,
43
+ inputTokens: 0,
44
+ outputTokens: 0,
45
+ cacheReadTokens: 0,
46
+ cacheCreationTokens: 0,
47
+ };
48
+ /** Add two {@link ModelUsageTotals} field-wise (for merging session deltas into the aggregate). */
49
+ export function addModelTotals(a, b) {
50
+ return {
51
+ calls: a.calls + b.calls,
52
+ inputTokens: a.inputTokens + b.inputTokens,
53
+ outputTokens: a.outputTokens + b.outputTokens,
54
+ cacheReadTokens: a.cacheReadTokens + b.cacheReadTokens,
55
+ cacheCreationTokens: a.cacheCreationTokens + b.cacheCreationTokens,
56
+ };
57
+ }
58
+ /** A `provider_response` reported usage iff any token field is present. */
59
+ function hasUsage(e) {
60
+ return (e.inputTokens !== undefined ||
61
+ e.outputTokens !== undefined ||
62
+ e.cacheReadTokens !== undefined ||
63
+ e.cacheCreationTokens !== undefined);
64
+ }
65
+ /**
66
+ * Fold `provider_response` events into per-model token totals, keyed by
67
+ * `"<provider>/<model>"` (the same model id can be served by more than one
68
+ * provider, so both pin the key). Used by the usage-stats plugin to compute a
69
+ * session's contribution and by the `/usage` panel to render the lifetime
70
+ * breakdown.
71
+ */
72
+ export function summarizeTokensByModel(events) {
73
+ const byModel = {};
74
+ for (const e of events) {
75
+ if (e.type !== 'provider_response')
76
+ continue;
77
+ if (!hasUsage(e))
78
+ continue;
79
+ const key = `${e.provider}/${e.model}`;
80
+ byModel[key] = addModelTotals(byModel[key] ?? ZERO_TOTALS, {
81
+ calls: 1,
82
+ inputTokens: e.inputTokens ?? 0,
83
+ outputTokens: e.outputTokens ?? 0,
84
+ cacheReadTokens: e.cacheReadTokens ?? 0,
85
+ cacheCreationTokens: e.cacheCreationTokens ?? 0,
86
+ });
87
+ }
88
+ return byModel;
89
+ }
90
+ function foldResponses(responses) {
91
+ let calls = 0;
92
+ let totalInput = 0;
93
+ let totalCacheRead = 0;
94
+ let totalCacheCreation = 0;
95
+ let totalOutput = 0;
96
+ for (const e of responses) {
97
+ // Count a call only when it reported any token data.
98
+ if (e.inputTokens === undefined &&
99
+ e.outputTokens === undefined &&
100
+ e.cacheReadTokens === undefined &&
101
+ e.cacheCreationTokens === undefined) {
102
+ continue;
103
+ }
104
+ calls += 1;
105
+ totalInput += e.inputTokens ?? 0;
106
+ totalCacheRead += e.cacheReadTokens ?? 0;
107
+ totalCacheCreation += e.cacheCreationTokens ?? 0;
108
+ totalOutput += e.outputTokens ?? 0;
109
+ }
110
+ const totalPrompt = totalInput + totalCacheRead + totalCacheCreation;
111
+ const billedInputEq = totalInput + totalCacheRead * CACHE_READ_MULT + totalCacheCreation * CACHE_WRITE_MULT;
112
+ const uncachedInputEq = totalPrompt;
113
+ const cacheHitRate = totalPrompt > 0 ? totalCacheRead / totalPrompt : 0;
114
+ return {
115
+ calls,
116
+ totalInput,
117
+ totalCacheRead,
118
+ totalCacheCreation,
119
+ totalOutput,
120
+ totalPrompt,
121
+ cacheHitRate,
122
+ billedInputEq,
123
+ uncachedInputEq,
124
+ savedRatio: uncachedInputEq > 0 ? 1 - billedInputEq / uncachedInputEq : 0,
125
+ // Broken = writing cache but not reading it back, over enough calls.
126
+ cacheEffective: !(calls >= 5 && totalCacheCreation > 0 && cacheHitRate < 0.05),
127
+ };
128
+ }
129
+ //# sourceMappingURL=token-accounting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-accounting.js","sourceRoot":"","sources":["../src/token-accounting.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { MoxxyEvent } from './events.js';
2
+ import type { ModeContext } from './mode.js';
3
+ import type { CollectedToolUse } from './mode-helpers.js';
4
+ /**
5
+ * Execute a single tool-use end-to-end: dispatch `dispatchToolCall` hooks, run
6
+ * the permission check, invoke the tool, and emit the approved/denied/result
7
+ * events. An async generator so a loop strategy can `yield*` it; callers that
8
+ * don't need the events can drain it (`for await (const _ of …) {}`) — either
9
+ * way the events reach the log via `ctx.emit`.
10
+ *
11
+ * Shared by every loop strategy (tool-use, plan-execute, developer, bmad) so
12
+ * the defensive outer try/catch below lives in ONE place. Without it, a throw
13
+ * from a hook handler / permission resolver / the emit itself escapes the
14
+ * generator and leaves this (and any later) call as an orphan
15
+ * `tool_call_requested` with no matching `tool_result` — which the provider
16
+ * then rejects on the next turn.
17
+ */
18
+ export declare function dispatchToolCall(ctx: ModeContext, t: CollectedToolUse, iteration: number): AsyncGenerator<MoxxyEvent, void, unknown>;
19
+ //# sourceMappingURL=tool-dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-dispatch.d.ts","sourceRoot":"","sources":["../src/tool-dispatch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;;;;;;;;;GAaG;AACH,wBAAuB,gBAAgB,CACrC,GAAG,EAAE,WAAW,EAChB,CAAC,EAAE,gBAAgB,EACnB,SAAS,EAAE,MAAM,GAChB,cAAc,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAkF3C"}
@@ -0,0 +1,118 @@
1
+ import { asToolCallId } from './ids.js';
2
+ /**
3
+ * Execute a single tool-use end-to-end: dispatch `dispatchToolCall` hooks, run
4
+ * the permission check, invoke the tool, and emit the approved/denied/result
5
+ * events. An async generator so a loop strategy can `yield*` it; callers that
6
+ * don't need the events can drain it (`for await (const _ of …) {}`) — either
7
+ * way the events reach the log via `ctx.emit`.
8
+ *
9
+ * Shared by every loop strategy (tool-use, plan-execute, developer, bmad) so
10
+ * the defensive outer try/catch below lives in ONE place. Without it, a throw
11
+ * from a hook handler / permission resolver / the emit itself escapes the
12
+ * generator and leaves this (and any later) call as an orphan
13
+ * `tool_call_requested` with no matching `tool_result` — which the provider
14
+ * then rejects on the next turn.
15
+ */
16
+ export async function* dispatchToolCall(ctx, t, iteration) {
17
+ try {
18
+ const verdict = await ctx.hooks.dispatchToolCall({
19
+ sessionId: ctx.sessionId,
20
+ cwd: '',
21
+ log: ctx.log,
22
+ env: {},
23
+ turnId: ctx.turnId,
24
+ iteration,
25
+ call: { callId: asToolCallId(t.id), name: t.name, input: t.input },
26
+ });
27
+ const actualInput = verdict.action === 'rewrite' ? verdict.input : t.input;
28
+ const denyReason = hookDeny(verdict);
29
+ if (denyReason) {
30
+ yield* emitDenied(ctx, t, denyReason, 'hook');
31
+ return;
32
+ }
33
+ const decision = await ctx.permissions.check({ callId: asToolCallId(t.id), name: t.name, input: actualInput }, { sessionId: String(ctx.sessionId), toolDescription: ctx.tools.get(t.name)?.description });
34
+ if (decision.mode === 'deny') {
35
+ yield* emitDenied(ctx, t, decision.reason ?? 'denied by resolver', 'resolver');
36
+ return;
37
+ }
38
+ yield await ctx.emit({
39
+ type: 'tool_call_approved',
40
+ sessionId: ctx.sessionId,
41
+ turnId: ctx.turnId,
42
+ source: 'system',
43
+ callId: asToolCallId(t.id),
44
+ decidedBy: 'resolver',
45
+ mode: decision.mode,
46
+ });
47
+ try {
48
+ const output = await ctx.tools.execute(t.name, actualInput, ctx.signal, {
49
+ callId: t.id,
50
+ sessionId: String(ctx.sessionId),
51
+ turnId: String(ctx.turnId),
52
+ log: ctx.log,
53
+ ...(ctx.subagents ? { subagents: ctx.subagents } : {}),
54
+ });
55
+ yield await ctx.emit({
56
+ type: 'tool_result',
57
+ sessionId: ctx.sessionId,
58
+ turnId: ctx.turnId,
59
+ source: 'tool',
60
+ callId: asToolCallId(t.id),
61
+ ok: true,
62
+ output,
63
+ });
64
+ }
65
+ catch (err) {
66
+ const message = err instanceof Error ? err.message : String(err);
67
+ const kind = ctx.signal.aborted ? 'aborted' : 'threw';
68
+ yield await ctx.emit({
69
+ type: 'tool_result',
70
+ sessionId: ctx.sessionId,
71
+ turnId: ctx.turnId,
72
+ source: 'tool',
73
+ callId: asToolCallId(t.id),
74
+ ok: false,
75
+ error: { kind, message },
76
+ });
77
+ }
78
+ }
79
+ catch (err) {
80
+ // Defensive: a hook handler, permission resolver, or the emit itself threw
81
+ // before we could produce a tool_result. Synthesize a failed result so the
82
+ // event log stays well-formed (no orphan tool_call_requested).
83
+ const message = err instanceof Error ? err.message : String(err);
84
+ yield await ctx.emit({
85
+ type: 'tool_result',
86
+ sessionId: ctx.sessionId,
87
+ turnId: ctx.turnId,
88
+ source: 'tool',
89
+ callId: asToolCallId(t.id),
90
+ ok: false,
91
+ error: { kind: 'threw', message: `pre-execute failure: ${message}` },
92
+ });
93
+ }
94
+ }
95
+ function hookDeny(verdict) {
96
+ return verdict.action === 'deny' ? verdict.reason : null;
97
+ }
98
+ async function* emitDenied(ctx, t, reason, by) {
99
+ yield await ctx.emit({
100
+ type: 'tool_call_denied',
101
+ sessionId: ctx.sessionId,
102
+ turnId: ctx.turnId,
103
+ source: 'system',
104
+ callId: asToolCallId(t.id),
105
+ decidedBy: by,
106
+ reason,
107
+ });
108
+ yield await ctx.emit({
109
+ type: 'tool_result',
110
+ sessionId: ctx.sessionId,
111
+ turnId: ctx.turnId,
112
+ source: 'tool',
113
+ callId: asToolCallId(t.id),
114
+ ok: false,
115
+ error: { kind: 'denied', message: reason },
116
+ });
117
+ }
118
+ //# sourceMappingURL=tool-dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-dispatch.js","sourceRoot":"","sources":["../src/tool-dispatch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { EventLogReader } from './log.js';
2
+ import type { ProviderMessage } from './provider.js';
3
+ import type { ToolDef } from './tool.js';
4
+ /**
5
+ * Lazy tool loading (request-scoped tool selection). Mirrors the skill
6
+ * lazy-load idiom: instead of sending every tool schema on every call, send a
7
+ * small always-on core plus whatever the model has explicitly loaded, and put
8
+ * a compact one-line index of the rest in the system prompt. The model calls
9
+ * `load_tool({ name })` to pull a schema in before using it.
10
+ *
11
+ * "Loaded" state is derived from the log (the `load_tool` calls), not a
12
+ * separate mutable store — so projection stays a pure function of the log, the
13
+ * same property that makes elision and caching deterministic.
14
+ */
15
+ /** Core tools always sent in full — the agent's baseline capability + the
16
+ * loaders themselves. Everything else is lazy-loadable when gating is on. */
17
+ export declare const ALWAYS_ON_TOOLS: ReadonlySet<string>;
18
+ /** Tool names the model has loaded this session (from `load_tool` calls). */
19
+ export declare function loadedToolNames(log: EventLogReader): ReadonlySet<string>;
20
+ /** Compact index (name + 1-line description) of not-yet-loaded tools. */
21
+ export declare function buildToolIndex(hidden: ReadonlyArray<ToolDef>): string;
22
+ export interface GatedTools {
23
+ readonly messages: ReadonlyArray<ProviderMessage>;
24
+ readonly tools: ReadonlyArray<ToolDef>;
25
+ }
26
+ /**
27
+ * Apply lazy tool gating: keep always-on + loaded tools in the request, move
28
+ * the rest into a system-prompt index. No-op (returns inputs) when nothing is
29
+ * gated, so the system prompt stays byte-stable on turns that load nothing.
30
+ */
31
+ export declare function applyLazyTools(messages: ReadonlyArray<ProviderMessage>, tools: ReadonlyArray<ToolDef>, log: EventLogReader): GatedTools;
32
+ //# sourceMappingURL=tool-gating.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-gating.d.ts","sourceRoot":"","sources":["../src/tool-gating.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC;;;;;;;;;;GAUG;AAEH;6EAC6E;AAC7E,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAW9C,CAAC;AAEH,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,GAAG,EAAE,cAAc,GAAG,WAAW,CAAC,MAAM,CAAC,CAUxE;AAUD,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,MAAM,CAUrE;AAuBD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAClD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CACxC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,aAAa,CAAC,eAAe,CAAC,EACxC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAC7B,GAAG,EAAE,cAAc,GAClB,UAAU,CAMZ"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Lazy tool loading (request-scoped tool selection). Mirrors the skill
3
+ * lazy-load idiom: instead of sending every tool schema on every call, send a
4
+ * small always-on core plus whatever the model has explicitly loaded, and put
5
+ * a compact one-line index of the rest in the system prompt. The model calls
6
+ * `load_tool({ name })` to pull a schema in before using it.
7
+ *
8
+ * "Loaded" state is derived from the log (the `load_tool` calls), not a
9
+ * separate mutable store — so projection stays a pure function of the log, the
10
+ * same property that makes elision and caching deterministic.
11
+ */
12
+ /** Core tools always sent in full — the agent's baseline capability + the
13
+ * loaders themselves. Everything else is lazy-loadable when gating is on. */
14
+ export const ALWAYS_ON_TOOLS = new Set([
15
+ 'Read',
16
+ 'Write',
17
+ 'Edit',
18
+ 'Bash',
19
+ 'Grep',
20
+ 'Glob',
21
+ 'recall',
22
+ 'load_skill',
23
+ 'load_tool',
24
+ 'dispatch_agent',
25
+ ]);
26
+ /** Tool names the model has loaded this session (from `load_tool` calls). */
27
+ export function loadedToolNames(log) {
28
+ const names = new Set();
29
+ for (const e of log.ofType('tool_call_requested')) {
30
+ if (e.name !== 'load_tool')
31
+ continue;
32
+ const input = e.input;
33
+ if (input && typeof input === 'object' && typeof input.name === 'string') {
34
+ names.add(input.name);
35
+ }
36
+ }
37
+ return names;
38
+ }
39
+ function oneLine(s) {
40
+ return s.replace(/[\r\n\t]+/g, ' ').replace(/\s{2,}/g, ' ').trim();
41
+ }
42
+ function truncate(s, n) {
43
+ return s.length <= n ? s : `${s.slice(0, n - 1)}…`;
44
+ }
45
+ /** Compact index (name + 1-line description) of not-yet-loaded tools. */
46
+ export function buildToolIndex(hidden) {
47
+ const lines = hidden
48
+ .map((t) => `- **${t.name}** — ${truncate(oneLine(t.description ?? ''), 100)}`)
49
+ .join('\n');
50
+ return (`## Loadable tools\n\n` +
51
+ `These tools exist but their full schemas are not loaded right now. When a ` +
52
+ `task needs one, call \`load_tool({ name: "<tool-name>" })\` first, then call ` +
53
+ `the tool on the next turn.\n\n${lines}`);
54
+ }
55
+ function injectIntoSystem(messages, index) {
56
+ const out = messages.map((m) => m);
57
+ const sysIdx = out.findIndex((m) => m.role === 'system');
58
+ if (sysIdx >= 0) {
59
+ const sys = out[sysIdx];
60
+ const content = sys.content.map((b) => b.type === 'text' ? { ...b, text: `${b.text}\n\n${index}` } : b);
61
+ // If there was no text block, append one.
62
+ if (!sys.content.some((b) => b.type === 'text')) {
63
+ content.push({ type: 'text', text: index });
64
+ }
65
+ out[sysIdx] = { role: 'system', content };
66
+ return out;
67
+ }
68
+ return [{ role: 'system', content: [{ type: 'text', text: index }] }, ...out];
69
+ }
70
+ /**
71
+ * Apply lazy tool gating: keep always-on + loaded tools in the request, move
72
+ * the rest into a system-prompt index. No-op (returns inputs) when nothing is
73
+ * gated, so the system prompt stays byte-stable on turns that load nothing.
74
+ */
75
+ export function applyLazyTools(messages, tools, log) {
76
+ const loaded = loadedToolNames(log);
77
+ const hidden = tools.filter((t) => !ALWAYS_ON_TOOLS.has(t.name) && !loaded.has(t.name));
78
+ if (hidden.length === 0)
79
+ return { messages, tools };
80
+ const visible = tools.filter((t) => ALWAYS_ON_TOOLS.has(t.name) || loaded.has(t.name));
81
+ return { messages: injectIntoSystem(messages, buildToolIndex(hidden)), tools: visible };
82
+ }
83
+ //# sourceMappingURL=tool-gating.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-gating.js","sourceRoot":"","sources":["../src/tool-gating.ts"],"names":[],"mappings":"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"}
package/dist/tool.d.ts ADDED
@@ -0,0 +1,166 @@
1
+ import type { z } from 'zod';
2
+ import type { EventLogReader } from './log.js';
3
+ import type { PermissionRule } from './permission.js';
4
+ import type { SessionId, ToolCallId, TurnId } from './ids.js';
5
+ import type { SubagentSpawner } from './subagent.js';
6
+ import type { ToolIsolationSpec } from './isolation.js';
7
+ /**
8
+ * Capability-mediated filesystem operations injected by isolators that
9
+ * support brokering. Handlers can opt in by checking `ctx.fs` at runtime
10
+ * and using these instead of `node:fs`; the broker validates each call
11
+ * against the tool's declared `caps.fs` spec on the parent side before
12
+ * executing.
13
+ *
14
+ * When `ctx.fs` is undefined (the `none`/`inproc` paths today, or any
15
+ * isolator that hasn't implemented a broker yet), handlers fall back to
16
+ * unmediated direct fs access.
17
+ */
18
+ export interface BrokeredFs {
19
+ /** Read a UTF-8 file. Throws if the path is outside `caps.fs.read`. */
20
+ readFile(filePath: string, opts?: {
21
+ encoding?: BufferEncoding;
22
+ }): Promise<string>;
23
+ /** Write a UTF-8 file (creates parent dirs). Throws if outside `caps.fs.write`. */
24
+ writeFile(filePath: string, data: string): Promise<void>;
25
+ /** List entries in a directory. Throws if outside `caps.fs.read`. */
26
+ readdir(dirPath: string): Promise<ReadonlyArray<string>>;
27
+ /** Stat a path. Throws if outside `caps.fs.read`. */
28
+ stat(filePath: string): Promise<BrokeredStat>;
29
+ }
30
+ export interface BrokeredStat {
31
+ readonly size: number;
32
+ readonly mtimeMs: number;
33
+ readonly isFile: boolean;
34
+ readonly isDirectory: boolean;
35
+ }
36
+ /**
37
+ * Capability-mediated `fetch`. Same shape as the global, but validated
38
+ * against `caps.net` on the parent side before the socket is opened.
39
+ *
40
+ * Returns a plain JSON-serializable response shape rather than the
41
+ * standard `Response` object — that's the price of crossing a process
42
+ * boundary cleanly.
43
+ */
44
+ export interface BrokeredFetch {
45
+ (url: string, init?: BrokeredFetchInit): Promise<BrokeredFetchResponse>;
46
+ }
47
+ export interface BrokeredFetchInit {
48
+ readonly method?: 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
49
+ readonly headers?: Readonly<Record<string, string>>;
50
+ readonly body?: string;
51
+ }
52
+ export interface BrokeredFetchResponse {
53
+ readonly status: number;
54
+ readonly statusText: string;
55
+ readonly headers: Readonly<Record<string, string>>;
56
+ readonly body: string;
57
+ }
58
+ /**
59
+ * Capability-mediated subprocess `exec`. Validated against `caps.subprocess`
60
+ * (must be true) and optional `caps.commands` allowlist on the parent side.
61
+ * Collects stdout/stderr and the exit code; for streaming use cases the
62
+ * broker layer will grow a separate streaming variant later.
63
+ */
64
+ export interface BrokeredExec {
65
+ (command: string, args?: ReadonlyArray<string>, opts?: BrokeredExecOpts): Promise<BrokeredExecResult>;
66
+ }
67
+ export interface BrokeredExecOpts {
68
+ readonly cwd?: string;
69
+ readonly env?: Readonly<Record<string, string>>;
70
+ readonly timeoutMs?: number;
71
+ }
72
+ export interface BrokeredExecResult {
73
+ readonly stdout: string;
74
+ readonly stderr: string;
75
+ readonly exitCode: number | null;
76
+ }
77
+ export interface ToolContext {
78
+ readonly sessionId: SessionId;
79
+ readonly turnId: TurnId;
80
+ readonly callId: ToolCallId;
81
+ readonly cwd: string;
82
+ readonly signal: AbortSignal;
83
+ readonly log: EventLogReader;
84
+ readonly logger: {
85
+ debug(msg: string, meta?: Record<string, unknown>): void;
86
+ info(msg: string, meta?: Record<string, unknown>): void;
87
+ warn(msg: string, meta?: Record<string, unknown>): void;
88
+ error(msg: string, meta?: Record<string, unknown>): void;
89
+ };
90
+ /**
91
+ * Spawner for child agents — present when the tool was invoked inside
92
+ * a run-turn loop (the normal case). Tools that fan work out (e.g.
93
+ * `dispatch_agent`) call `subagents.spawn(...)` to start a focused
94
+ * child loop and stream its events back to the parent log.
95
+ */
96
+ readonly subagents?: SubagentSpawner;
97
+ /**
98
+ * Capability-mediated filesystem ops. Present only when the active
99
+ * isolator implements a broker (currently `@moxxy/isolator-worker`).
100
+ * Handlers that use this get their fs access checked against
101
+ * `caps.fs` at every call, regardless of whether the path appeared
102
+ * in the validated input. Absent → handler is on its own for fs
103
+ * access (today's behavior).
104
+ */
105
+ readonly fs?: BrokeredFs;
106
+ /**
107
+ * Capability-mediated network. Present only when the active
108
+ * isolator implements a broker. Validates every URL against
109
+ * `caps.net` on the parent side. Returns a serializable response
110
+ * shape so the same value crosses a process boundary intact.
111
+ */
112
+ readonly fetch?: BrokeredFetch;
113
+ /**
114
+ * Capability-mediated subprocess execution. Present only when the
115
+ * active isolator implements a broker. Validated against
116
+ * `caps.subprocess` + optional `caps.commands` allowlist.
117
+ */
118
+ readonly exec?: BrokeredExec;
119
+ }
120
+ /**
121
+ * Optional presentation hint for compact rendering in TUI/chat surfaces.
122
+ * When present, the channel may aggregate consecutive calls of this tool
123
+ * into one "live block" with a verb+count summary, rather than rendering
124
+ * each call separately. Opting in is per-tool: noisy small-output tools
125
+ * (Read, Grep, Glob, Edit) benefit; tools with rich output (Bash,
126
+ * dispatch_agent) generally don't.
127
+ *
128
+ * Channels MAY ignore this hint — it's purely presentational. The event
129
+ * log and provider serialization don't see it.
130
+ */
131
+ export interface ToolCompactPresentation {
132
+ /** Present-participle verb used in summary, e.g. "Reading", "Searching for". */
133
+ readonly verb: string;
134
+ /** Noun for the count, pluralized e.g. `{ one: 'file', other: 'files' }`. */
135
+ readonly noun: {
136
+ readonly one: string;
137
+ readonly other: string;
138
+ };
139
+ /** Input field whose value previews the latest call (the line under the summary).
140
+ * e.g. `"file_path"` for Read so the preview shows the file just read. */
141
+ readonly previewKey?: string;
142
+ }
143
+ export interface ToolDef {
144
+ readonly name: string;
145
+ readonly description: string;
146
+ readonly inputSchema: z.ZodTypeAny;
147
+ /**
148
+ * Optional native JSON Schema. When present, providers serializing tools to
149
+ * their API should use this instead of converting `inputSchema` via zod.
150
+ * Useful for tools originating from external systems (e.g., MCP) that already
151
+ * carry a JSON Schema and where zod conversion would be lossy.
152
+ */
153
+ readonly inputJsonSchema?: unknown;
154
+ readonly outputSchema?: z.ZodTypeAny;
155
+ readonly permission?: PermissionRule;
156
+ readonly handler: (input: unknown, ctx: ToolContext) => Promise<unknown> | unknown;
157
+ /** Opt-in presentation hint. See `ToolCompactPresentation`. */
158
+ readonly compact?: ToolCompactPresentation;
159
+ /**
160
+ * Optional capability declaration. Advisory unless the user enables
161
+ * `@moxxy/plugin-security`, at which point the active `Isolator`
162
+ * enforces these bounds at every call. See `ToolIsolationSpec`.
163
+ */
164
+ readonly isolation?: ToolIsolationSpec;
165
+ }
166
+ //# sourceMappingURL=tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"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"}
package/dist/tool.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.js","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":""}