@lumifai/harness 0.0.1
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.
- package/README.md +368 -0
- package/dist/create-lumif-harness.d.ts +3 -0
- package/dist/create-lumif-harness.js +45 -0
- package/dist/create-lumif-harness.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +18 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
# @lumifai/harness
|
|
2
|
+
|
|
3
|
+
Lumif's thin harness factory around Mastra's `AgentController` runtime. The controller is shared;
|
|
4
|
+
each conversation is owned by a Mastra `Session`. Server integrations add scoped identity,
|
|
5
|
+
durable lifecycle, reconnect, and transport behavior.
|
|
6
|
+
|
|
7
|
+
## Layered install
|
|
8
|
+
|
|
9
|
+
1. **Core** — `@lumifai/harness`, `@lumifai/harness-protocol`
|
|
10
|
+
2. **Presets** — `@lumifai/harness-presets`
|
|
11
|
+
3. **Tool packs** — individual `@lumifai/harness-tool-pack-*` packages
|
|
12
|
+
4. **Server** — `@lumifai/harness-server`, `@lumifai/harness-server-fastify`, `@lumifai/harness-server-nest`
|
|
13
|
+
5. **Client / React** — `@lumifai/harness-client`, `@lumifai/harness-react`, `@lumifai/harness-react-mantine`
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { LibSQLStore } from '@mastra/libsql';
|
|
19
|
+
import { createLumifHarness } from '@lumifai/harness';
|
|
20
|
+
import { createPresetHarnessConfig, createPresetWorkspace } from '@lumifai/harness-presets';
|
|
21
|
+
|
|
22
|
+
const presets = createPresetHarnessConfig({
|
|
23
|
+
includeRequestAccess: true,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const controller = createLumifHarness({
|
|
27
|
+
id: 'my-service-agent',
|
|
28
|
+
storage: new LibSQLStore({ url: 'file:./data.db' }),
|
|
29
|
+
workspace: createPresetWorkspace({
|
|
30
|
+
workspaceMode: 'local',
|
|
31
|
+
sandboxEnabled: true,
|
|
32
|
+
}),
|
|
33
|
+
modes: presets.modes,
|
|
34
|
+
subagents: presets.subagents,
|
|
35
|
+
tools: presets.tools,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
await controller.init();
|
|
39
|
+
const session = await controller.createSession({
|
|
40
|
+
id: 'session-1',
|
|
41
|
+
ownerId: 'user-1',
|
|
42
|
+
resourceId: 'resource-1',
|
|
43
|
+
});
|
|
44
|
+
await session.sendMessage({ content: 'Hello!' });
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`workspace` is required. Everything else is forwarded to Mastra's harness and can be overridden as needed.
|
|
48
|
+
|
|
49
|
+
## Production defaults
|
|
50
|
+
|
|
51
|
+
The server wrapper in `@lumifai/harness-server` makes persistence and tenancy explicit:
|
|
52
|
+
|
|
53
|
+
- `storage` defaults to a local LibSQL file store under the workspace path
|
|
54
|
+
- `memory` defaults to `new Memory({ storage })`, but you can pass any Mastra memory or a factory
|
|
55
|
+
- `threadLock` can be supplied for multi-pod / multi-process coordination
|
|
56
|
+
- `contextResolver` lets adapters inject `tenantId`, `userId`, `resourceId`, `sessionId`, `threadId`, and arbitrary request context
|
|
57
|
+
- `authorize` lets adapters enforce route-level access control before state changes or reads
|
|
58
|
+
- `allowClientResourceId` is `false` by default so resource scope comes from server context, not the browser
|
|
59
|
+
- `/healthz` and `/readyz` are exposed by the Fastify server
|
|
60
|
+
|
|
61
|
+
## Workspace modes
|
|
62
|
+
|
|
63
|
+
`createPresetWorkspace()` and `createHarnessServerWorkspace()` make the workspace shape explicit:
|
|
64
|
+
|
|
65
|
+
- `workspaceMode: 'local'` - `LocalFilesystem` plus optional `LocalSandbox`
|
|
66
|
+
- `workspaceMode: 'filesystem'` - a single filesystem provider, no sandbox
|
|
67
|
+
- `workspaceMode: 'mounts'` - mount-backed workspace for sandbox-visible cloud storage
|
|
68
|
+
|
|
69
|
+
`filesystem` and `mounts` are mutually exclusive. Use `mounts` when the sandbox must see cloud storage paths directly.
|
|
70
|
+
|
|
71
|
+
Sandbox is off by default. In local mode, set `sandboxEnabled: true` to attach a `LocalSandbox` whose `workingDirectory` matches the `LocalFilesystem` `basePath`. You can also pass a custom `sandbox` or tune local sandbox settings via `localSandboxOptions`.
|
|
72
|
+
|
|
73
|
+
Mount-backed example for cloud storage visible inside the sandbox:
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { LocalSandbox } from '@mastra/core/workspace';
|
|
77
|
+
|
|
78
|
+
createPresetWorkspace({
|
|
79
|
+
workspaceMode: 'mounts',
|
|
80
|
+
mounts: { '/data': myCloudFilesystem },
|
|
81
|
+
sandbox: new LocalSandbox({ workingDirectory: './workspace' }),
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Persistence and resume
|
|
86
|
+
|
|
87
|
+
The server integration uses two Mastra storage layers:
|
|
88
|
+
|
|
89
|
+
- Mastra's `harness` domain stores one scoped session record containing tenant/owner/resource
|
|
90
|
+
identity, the active thread, mode/model, configuration, lifecycle status, and all pending native
|
|
91
|
+
suspensions.
|
|
92
|
+
- Mastra memory/thread storage remains the source of truth for messages, threads, and AgentController
|
|
93
|
+
state. The session record is a registry and lifecycle index, not a second message store.
|
|
94
|
+
|
|
95
|
+
The external `sessionId` is a client handle. The durable record ID is a versioned SHA-256 scope key
|
|
96
|
+
over tenant, owner, resource, and external session ID, so identical browser IDs cannot collide
|
|
97
|
+
across users or tenants. Explicit destroy deletes owned threads and soft-deletes the record with
|
|
98
|
+
`deletedAt`; storage retention/pruning handles physical cleanup.
|
|
99
|
+
|
|
100
|
+
Tool _approvals_ are intentionally **not** persisted: the approval gate is an in-memory parked promise that does not survive a restart, so a pending approval is resolvable only within the live process. Interactive tool _suspensions_ (`ask_user`, `submit_plan`, `request_access`) are the durable, resumable primitive.
|
|
101
|
+
|
|
102
|
+
Resume flow:
|
|
103
|
+
|
|
104
|
+
1. A request comes in with `sessionId`
|
|
105
|
+
2. `HarnessSessionManager` derives the trusted scope and looks up the harness record directly
|
|
106
|
+
3. A fresh `HarnessSession` is created on the current pod
|
|
107
|
+
4. The harness is reattached to the persisted `threadId` and `resourceId`
|
|
108
|
+
5. Every persisted native suspension is re-registered from the record
|
|
109
|
+
6. SSE/event subscriptions attach to the new in-memory session instance
|
|
110
|
+
|
|
111
|
+
This is what makes the harness resumable across pods. Pod-local memory is not the source of truth.
|
|
112
|
+
|
|
113
|
+
Display state and SSE events include `currentRunId` plus an array of pending suspensions. Each item
|
|
114
|
+
has its own `toolCallId` and optional `runId`, so parallel human-input prompts can be rendered and
|
|
115
|
+
resumed independently.
|
|
116
|
+
|
|
117
|
+
Mastra approvals are deliberately process-local. If a process dies while an approval is parked,
|
|
118
|
+
the next runtime reports the session as `interrupted`; an old approval response cannot be replayed.
|
|
119
|
+
Native tool suspensions are the durable human-input primitive.
|
|
120
|
+
|
|
121
|
+
While a session is running, `sendMessage` starts a normal run, `followUp` queues input behind the
|
|
122
|
+
current run, and `steer` aborts the current run and redirects it. A session waiting on native input
|
|
123
|
+
does not keep a model process alive: it can be evicted from the in-memory LRU and reconstructed
|
|
124
|
+
when the user returns minutes or days later.
|
|
125
|
+
|
|
126
|
+
## Human-in-the-loop tools
|
|
127
|
+
|
|
128
|
+
Lumif presets replace Mastra's built-in `ask_user` and `submit_plan` with host-owned versions
|
|
129
|
+
(same tool ids) and disable those builtins via `disableBuiltinTools`:
|
|
130
|
+
|
|
131
|
+
- `ask_user` — free-text or choice questions, including `selectionMode`. Coerces free-form mistakes
|
|
132
|
+
(`selectionMode` without options) into a real free-text suspend instead of Mastra's soft failure
|
|
133
|
+
- `submit_plan` — plan review and approval in plan mode
|
|
134
|
+
- `request_access` — sandbox directory access prompts (only when `includeRequestAccess: true` and the workspace exposes a `LocalFilesystem`)
|
|
135
|
+
|
|
136
|
+
All interactive flows suspend via Mastra's tool suspension API instead of ad-hoc harness events.
|
|
137
|
+
Presets keep `autoResumeSuspendedTools` off so the host (Studio / API
|
|
138
|
+
`respondToToolSuspension`) owns resumes — Mastra's auto-resume path otherwise coaches the model
|
|
139
|
+
to stuff `resumeData` into tool-call arguments. Lumif keeps the public
|
|
140
|
+
`{ answer: string | string[] }` response shape for `ask_user` and converts it to Mastra's native
|
|
141
|
+
resume value at the server boundary.
|
|
142
|
+
|
|
143
|
+
The server disables Mastra builtins for each same-id preset tool that is registered. Turn a tool
|
|
144
|
+
off entirely with `toolToggles.ask_user = false` (also disables the Mastra builtin).
|
|
145
|
+
|
|
146
|
+
Studio treats empty options and single “Use free text” proxy choices as a textarea so free-form
|
|
147
|
+
questions still render correctly when the model mis-shapes the payload.
|
|
148
|
+
|
|
149
|
+
## Server integration
|
|
150
|
+
|
|
151
|
+
Use `@lumifai/harness-server` with Fastify or NestJS adapters. Boot config owns workspace shape, tool packs, and permission rules:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { createHarnessSessionManager } from '@lumifai/harness-server';
|
|
155
|
+
// Fastify: harnessFastifyPlugin from '@lumifai/harness-server-fastify'
|
|
156
|
+
// NestJS: HarnessModule from '@lumifai/harness-server-nest'
|
|
157
|
+
|
|
158
|
+
createHarnessSessionManager({
|
|
159
|
+
bootConfig: {
|
|
160
|
+
workspaceBasePath: './workspace',
|
|
161
|
+
workspaceMode: 'local',
|
|
162
|
+
sandboxEnabled: true,
|
|
163
|
+
storage: new LibSQLStore({ url: 'file:/absolute/path/to/harness.db' }),
|
|
164
|
+
threadLock: {
|
|
165
|
+
acquire: async ({ threadId }) => {
|
|
166
|
+
/* distributed lock */
|
|
167
|
+
},
|
|
168
|
+
release: async ({ threadId }) => {
|
|
169
|
+
/* distributed unlock */
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
toolPacks: [
|
|
173
|
+
/* ... */
|
|
174
|
+
],
|
|
175
|
+
permissionRules: { categories: { execute: 'ask' } },
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Built-in workspace boot options (ignored when `workspace` is provided):
|
|
181
|
+
|
|
182
|
+
- `workspaceMode` — `'local' | 'filesystem' | 'mounts'`
|
|
183
|
+
- `workspaceFilesystem` — custom filesystem provider
|
|
184
|
+
- `workspaceMounts` — mount map for `mounts` mode
|
|
185
|
+
- `sandboxEnabled`, `sandbox`, `localSandboxOptions`
|
|
186
|
+
- `onMount` — hook before mounting cloud filesystems into a sandbox
|
|
187
|
+
|
|
188
|
+
Adapter hooks available on the HTTP layer:
|
|
189
|
+
|
|
190
|
+
- `contextResolver(request)` — derive tenancy and ownership from auth/session headers
|
|
191
|
+
- `authorize({ action, request, context })` — gate create/read/write/resume operations
|
|
192
|
+
- `allowClientResourceId` — only enable for local development or trusted callers
|
|
193
|
+
|
|
194
|
+
NestJS standalone server:
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
import { createStandaloneHarnessNestServer } from '@lumifai/harness-server-nest';
|
|
198
|
+
|
|
199
|
+
await createStandaloneHarnessNestServer({
|
|
200
|
+
port: 4310,
|
|
201
|
+
bootConfig: { workspaceMode: 'local', sandboxEnabled: true },
|
|
202
|
+
});
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Tool permissions
|
|
206
|
+
|
|
207
|
+
The server applies preset permission defaults automatically via `buildHarnessOptions()`:
|
|
208
|
+
|
|
209
|
+
- **Read** tools (workspace reads, schema inspection) → auto-approved
|
|
210
|
+
- **Edit / execute / other** categories → prompt for approval (`ask`)
|
|
211
|
+
- **Tool pack defaults** → per-tool overrides from each pack's `toolConfig`
|
|
212
|
+
- `request_access` is only enabled when the workspace exposes a local filesystem, because that path is persisted via local filesystem state.
|
|
213
|
+
|
|
214
|
+
Override from server boot (recommended):
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
import { createHarnessSessionManager } from '@lumifai/harness-server';
|
|
218
|
+
import { createPostgresToolPack } from '@lumifai/harness-tool-pack-postgres';
|
|
219
|
+
|
|
220
|
+
createHarnessSessionManager({
|
|
221
|
+
bootConfig: {
|
|
222
|
+
toolPacks: [createPostgresToolPack({ connectionString: process.env.DATABASE_URL! })],
|
|
223
|
+
permissionRules: {
|
|
224
|
+
tools: { my_custom_tool: 'ask' },
|
|
225
|
+
categories: { execute: 'deny' },
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Direct harness construction:
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
import { createPresetPermissionConfig } from '@lumifai/harness-presets';
|
|
235
|
+
|
|
236
|
+
createLumifHarness({
|
|
237
|
+
...createPresetPermissionConfig({
|
|
238
|
+
packs: [
|
|
239
|
+
/* tool packs */
|
|
240
|
+
],
|
|
241
|
+
overrides: { tools: { my_custom_tool: 'ask' } },
|
|
242
|
+
}),
|
|
243
|
+
// workspace, modes, tools, ...
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Custom tools:
|
|
248
|
+
|
|
249
|
+
- Add via `bootConfig.extraTools` (Fastify/Nest) or `createPresetTools({ extra: { my_tool: createTool({...}) } })`
|
|
250
|
+
- Set deployment policy in `bootConfig.permissionRules.tools.my_tool`
|
|
251
|
+
- Use `requireApproval` on `createTool` only when approval is intrinsic to the tool design
|
|
252
|
+
- Optional: wrap reusable custom tools in a local `ToolPack` with `toolConfig` / `permissionPolicies`
|
|
253
|
+
- For durable HITL, give the tool `suspendSchema` / `resumeSchema` and call `suspend()`; pair with a
|
|
254
|
+
client `defineSuspensionRenderer` (see Browser UI)
|
|
255
|
+
|
|
256
|
+
Permissions are server-owned and are not exposed on the session `HarnessConfigPatch` API.
|
|
257
|
+
|
|
258
|
+
## Browser UI
|
|
259
|
+
|
|
260
|
+
- `@lumifai/harness-client` — framework-agnostic browser client and shared reducer/state helpers
|
|
261
|
+
- `@lumifai/harness-react` — headless provider, hooks, browser client, session store, suspension renderer registry
|
|
262
|
+
- `@lumifai/harness-react-mantine` — Mantine `HarnessStudio` components
|
|
263
|
+
|
|
264
|
+
The browser client refreshes its authoritative session snapshot after an SSE failure,
|
|
265
|
+
and the serialized display state retains the latest run error as `lastError`. The
|
|
266
|
+
Mantine studio renders concurrent pending suspensions and supports free-text,
|
|
267
|
+
single-select, and multi-select `ask_user` responses.
|
|
268
|
+
|
|
269
|
+
Custom suspension UIs: pass `suspensionRenderers` to `HarnessProvider` and/or `HarnessStudio`.
|
|
270
|
+
Studio merges builtins (`ask_user`, `submit_plan`, `request_access`) then provider then studio
|
|
271
|
+
props (later wins by `toolName`). Headless apps can call `useResolvedSuspensionRenderer(suspension)`
|
|
272
|
+
and `resumeToolSuspension(data, toolCallId)`.
|
|
273
|
+
|
|
274
|
+
## Presets
|
|
275
|
+
|
|
276
|
+
Import configurable presets from `@lumifai/harness-presets`:
|
|
277
|
+
|
|
278
|
+
- `createPresetModes()` — `plan` and `build` modes
|
|
279
|
+
- `createPresetCustomModes()` — returns the built-in modes plus your custom list when you need the final array yourself
|
|
280
|
+
- `createPresetSubagents()` — `explore` subagent; opt-in `websearch` subagent via `includeWebSearch: true`
|
|
281
|
+
- `createPresetTools()` — Lumif baseline with `ask_user` and `submit_plan` (displaces Mastra builtins). Pass `packs`, `toolPackToggles`, `toolToggles`, `includeRequestAccess`, and/or `extra`
|
|
282
|
+
- `createPresetSkills()` — default `.agents/skills` resolver paths
|
|
283
|
+
- `createPresetHarnessConfig()` — combines the above and merges enabled pack skill paths
|
|
284
|
+
- `createPresetPermissionConfig()` — default category resolver and merged `permissionRules` for harness init
|
|
285
|
+
|
|
286
|
+
## Tool packs
|
|
287
|
+
|
|
288
|
+
Import opt-in capability bundles from `@lumifai/harness-tool-pack-*` packages. Shared types and merge helpers live in `@lumifai/harness-tool-packs`:
|
|
289
|
+
|
|
290
|
+
- `ToolPack` — named bundle of related tools (and optional skills) that flattens into `tools` at harness init
|
|
291
|
+
- `createPostgresToolPack()` — read-only PostgreSQL schema inspection and query tools (`@lumifai/harness-tool-pack-postgres`)
|
|
292
|
+
- `createWorkspaceDataToolPack()` — workspace JSON, CSV, and jq query tools (`@lumifai/harness-tool-pack-workspace-data`)
|
|
293
|
+
- `createServerlessWorkflowToolPack()` — serverless runtime tool pack (`@lumifai/harness-tool-pack-serverless-workflow`)
|
|
294
|
+
- `createWebSearchToolPack()` — provider-native web search with structured output (`@lumifai/harness-tool-pack-web-search`)
|
|
295
|
+
- `createFileProcessingToolPack()` — PDF text extraction to `/processed/` (`@lumifai/harness-tool-pack-file-processing`)
|
|
296
|
+
|
|
297
|
+
Override any preset or pack via the options objects on each factory.
|
|
298
|
+
|
|
299
|
+
Example:
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
import { createPresetHarnessConfig } from '@lumifai/harness-presets';
|
|
303
|
+
import { createPostgresToolPack } from '@lumifai/harness-tool-pack-postgres';
|
|
304
|
+
import { createServerlessWorkflowToolPack } from '@lumifai/harness-tool-pack-serverless-workflow';
|
|
305
|
+
import { createWebSearchToolPack } from '@lumifai/harness-tool-pack-web-search';
|
|
306
|
+
import { createFileProcessingToolPack } from '@lumifai/harness-tool-pack-file-processing';
|
|
307
|
+
import { createWorkspaceDataToolPack } from '@lumifai/harness-tool-pack-workspace-data';
|
|
308
|
+
import { Agent } from '@mastra/core/agent';
|
|
309
|
+
|
|
310
|
+
const presets = createPresetHarnessConfig({
|
|
311
|
+
subagents: {
|
|
312
|
+
includeWebSearch: true,
|
|
313
|
+
webSearchProvider: 'openai',
|
|
314
|
+
},
|
|
315
|
+
customModes: [
|
|
316
|
+
{
|
|
317
|
+
id: 'review',
|
|
318
|
+
name: 'Review',
|
|
319
|
+
defaultModelId: 'openai/gpt-5.4-mini',
|
|
320
|
+
color: '#059669',
|
|
321
|
+
agent: new Agent({
|
|
322
|
+
id: 'lumif-review-agent',
|
|
323
|
+
name: 'Review Agent',
|
|
324
|
+
instructions: 'Review the user changes and report issues.',
|
|
325
|
+
model: 'openai/gpt-5.4-mini',
|
|
326
|
+
}),
|
|
327
|
+
},
|
|
328
|
+
],
|
|
329
|
+
skills: {
|
|
330
|
+
paths: ['.agents/skills'],
|
|
331
|
+
},
|
|
332
|
+
tools: {
|
|
333
|
+
packs: [
|
|
334
|
+
createWorkspaceDataToolPack(),
|
|
335
|
+
createPostgresToolPack({
|
|
336
|
+
connectionString: process.env.DATABASE_URL,
|
|
337
|
+
allowAllRoleVisible: true,
|
|
338
|
+
// or resolveAccessPolicy / resolveConnectionString for production tenants
|
|
339
|
+
}),
|
|
340
|
+
createServerlessWorkflowToolPack({
|
|
341
|
+
runtimeHost: process.env.RUNTIME_HOST!,
|
|
342
|
+
workflowNamespace: 'lumif',
|
|
343
|
+
resolveAuthContext: (ctx) => ({
|
|
344
|
+
accessToken: ctx.requestContext?.auth?.accessToken ?? '',
|
|
345
|
+
}),
|
|
346
|
+
}),
|
|
347
|
+
createWebSearchToolPack({
|
|
348
|
+
defaultProvider: 'openai',
|
|
349
|
+
}),
|
|
350
|
+
createFileProcessingToolPack(),
|
|
351
|
+
],
|
|
352
|
+
toolPackToggles: {
|
|
353
|
+
postgres: true,
|
|
354
|
+
},
|
|
355
|
+
toolToggles: {
|
|
356
|
+
postgres_query: true,
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
});
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Tool pack toggles
|
|
363
|
+
|
|
364
|
+
- `toolPackToggles` — enable or disable an entire pack (tools and bundled skills)
|
|
365
|
+
- `toolToggles` — enable or disable individual tools by id within enabled packs
|
|
366
|
+
- `toolConfig.enabledByDefault` on a pack — default per-tool state before `toolToggles` overrides
|
|
367
|
+
|
|
368
|
+
Tool packs are published as separate `@lumifai/harness-tool-pack-*` packages. Their bundled skills are merged into `workspace.skills` automatically when the pack is enabled.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createLumifHarness = createLumifHarness;
|
|
4
|
+
const agent_controller_1 = require("@mastra/core/agent-controller");
|
|
5
|
+
const workspace_1 = require("@mastra/core/workspace");
|
|
6
|
+
function assertWorkspace(workspace) {
|
|
7
|
+
if (workspace === undefined || workspace === null) {
|
|
8
|
+
throw new Error('LumifHarness requires a workspace. Pass a Workspace instance, WorkspaceConfig, or a factory function.');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function createLumifHarness(options) {
|
|
12
|
+
assertWorkspace(options.workspace);
|
|
13
|
+
const workspace = normalizeWorkspace(options.workspace);
|
|
14
|
+
const { heartbeatHandlers, intervalHandlers, ...config } = options;
|
|
15
|
+
if (heartbeatHandlers && intervalHandlers) {
|
|
16
|
+
throw new Error('Pass either heartbeatHandlers or intervalHandlers, not both.');
|
|
17
|
+
}
|
|
18
|
+
return new agent_controller_1.AgentController({
|
|
19
|
+
...config,
|
|
20
|
+
workspace,
|
|
21
|
+
intervalHandlers: intervalHandlers ?? heartbeatHandlers,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function isPromiseLike(value) {
|
|
25
|
+
return value != null && typeof value.then === 'function';
|
|
26
|
+
}
|
|
27
|
+
function normalizeWorkspace(workspace) {
|
|
28
|
+
if (typeof workspace === 'function') {
|
|
29
|
+
const factory = workspace;
|
|
30
|
+
return (input) => {
|
|
31
|
+
const resolved = factory(input);
|
|
32
|
+
if (isPromiseLike(resolved)) {
|
|
33
|
+
return Promise.resolve(resolved).then((value) => value ? normalizeWorkspaceValue(value) : undefined);
|
|
34
|
+
}
|
|
35
|
+
return resolved ? normalizeWorkspaceValue(resolved) : undefined;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return normalizeWorkspaceValue(workspace);
|
|
39
|
+
}
|
|
40
|
+
function normalizeWorkspaceValue(workspace) {
|
|
41
|
+
return workspace instanceof workspace_1.Workspace
|
|
42
|
+
? workspace
|
|
43
|
+
: new workspace_1.Workspace(workspace);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=create-lumif-harness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-lumif-harness.js","sourceRoot":"","sources":["../src/create-lumif-harness.ts"],"names":[],"mappings":";;AAoBA,gDAiBC;AArCD,oEAA4F;AAE5F,sDAAyE;AAQzE,SAAS,eAAe,CACtB,SAA2C;IAE3C,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CACb,uGAAuG,CACxG,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAgB,kBAAkB,CAChC,OAAoC;IAEpC,eAAe,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEnC,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,MAAM,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;IAEnE,IAAI,iBAAiB,IAAI,gBAAgB,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;IAED,OAAO,IAAI,kCAAe,CAAC;QACzB,GAAG,MAAM;QACT,SAAS;QACT,gBAAgB,EAAE,gBAAgB,IAAI,iBAAiB;KACvB,CAAC,CAAC;AACtC,CAAC;AAED,SAAS,aAAa,CAAI,KAAyB;IACjD,OAAO,KAAK,IAAI,IAAI,IAAI,OAAQ,KAAwB,CAAC,IAAI,KAAK,UAAU,CAAC;AAC/E,CAAC;AAED,SAAS,kBAAkB,CACzB,SAA+D;IAE/D,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,SAAS,CAAC;QAC1B,OAAO,CAAC,KAAK,EAAE,EAAE;YACf,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;YAChC,IAAI,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC5B,OAAO,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAC9C,KAAK,CAAC,CAAC,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CACnD,CAAC;YACJ,CAAC;YACD,OAAO,QAAQ,CAAC,CAAC,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAClE,CAAC,CAAC;IACJ,CAAC;IAED,OAAO,uBAAuB,CAAC,SAAS,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,uBAAuB,CAC9B,SAAuF;IAEvF,OAAO,SAAS,YAAY,qBAAS;QACnC,CAAC,CAAE,SAAuB;QAC1B,CAAC,CAAC,IAAI,qBAAS,CAAC,SAA4B,CAAC,CAAC;AAClD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { createLumifHarness } from './create-lumif-harness';
|
|
2
|
+
export type { LumifHarnessOptions, LumifWorkspace, LumifWorkspaceFactory } from './types';
|
|
3
|
+
export { AgentController, Session } from '@mastra/core/agent-controller';
|
|
4
|
+
/** Lumif's stable Harness export, backed by Mastra's AgentController runtime. */
|
|
5
|
+
export { AgentController as Harness } from '@mastra/core/agent-controller';
|
|
6
|
+
export type { AgentControllerConfig, AgentControllerDisplayState, AgentControllerEvent, AgentControllerMode, AgentControllerSubagent, AgentControllerThread, AgentControllerConfig as HarnessConfig, AgentControllerDisplayState as HarnessDisplayState, AgentControllerEvent as HarnessEvent, AgentControllerMode as HarnessMode, AgentControllerSubagent as HarnessSubagent, AgentControllerThread as HarnessThread, } from '@mastra/core/agent-controller';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Harness = exports.Session = exports.AgentController = exports.createLumifHarness = void 0;
|
|
4
|
+
var create_lumif_harness_1 = require("./create-lumif-harness");
|
|
5
|
+
Object.defineProperty(exports, "createLumifHarness", { enumerable: true, get: function () { return create_lumif_harness_1.createLumifHarness; } });
|
|
6
|
+
var agent_controller_1 = require("@mastra/core/agent-controller");
|
|
7
|
+
Object.defineProperty(exports, "AgentController", { enumerable: true, get: function () { return agent_controller_1.AgentController; } });
|
|
8
|
+
Object.defineProperty(exports, "Session", { enumerable: true, get: function () { return agent_controller_1.Session; } });
|
|
9
|
+
/** Lumif's stable Harness export, backed by Mastra's AgentController runtime. */
|
|
10
|
+
var agent_controller_2 = require("@mastra/core/agent-controller");
|
|
11
|
+
Object.defineProperty(exports, "Harness", { enumerable: true, get: function () { return agent_controller_2.AgentController; } });
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,+DAA4D;AAAnD,0HAAA,kBAAkB,OAAA;AAG3B,kEAAyE;AAAhE,mHAAA,eAAe,OAAA;AAAE,2GAAA,OAAO,OAAA;AACjC,iFAAiF;AACjF,kEAA2E;AAAlE,2GAAA,eAAe,OAAW"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AgentControllerConfig } from '@mastra/core/agent-controller';
|
|
2
|
+
import type { RequestContext } from '@mastra/core/request-context';
|
|
3
|
+
import type { Mastra } from '@mastra/core';
|
|
4
|
+
import type { Workspace, WorkspaceConfig, WorkspaceFilesystem, WorkspaceSandbox } from '@mastra/core/workspace';
|
|
5
|
+
type MountCapableWorkspaceConfig = WorkspaceConfig<WorkspaceFilesystem | undefined, WorkspaceSandbox | undefined, Record<string, WorkspaceFilesystem> | undefined>;
|
|
6
|
+
type MountCapableWorkspace = Workspace<WorkspaceFilesystem | undefined, WorkspaceSandbox | undefined, Record<string, WorkspaceFilesystem> | undefined>;
|
|
7
|
+
export type LumifWorkspaceFactory = (input: {
|
|
8
|
+
requestContext: RequestContext;
|
|
9
|
+
mastra?: Mastra;
|
|
10
|
+
}) => Workspace | MountCapableWorkspace | MountCapableWorkspaceConfig | undefined | Promise<Workspace | MountCapableWorkspace | MountCapableWorkspaceConfig | undefined>;
|
|
11
|
+
export type LumifWorkspace<_TState = {}> = Workspace | MountCapableWorkspace | MountCapableWorkspaceConfig | LumifWorkspaceFactory;
|
|
12
|
+
export type LumifHarnessOptions<TState = {}> = Omit<AgentControllerConfig<TState>, 'workspace' | 'intervalHandlers'> & {
|
|
13
|
+
workspace: LumifWorkspace<TState>;
|
|
14
|
+
/** @deprecated Renamed to `intervalHandlers` by Mastra. */
|
|
15
|
+
heartbeatHandlers?: AgentControllerConfig<TState>['intervalHandlers'];
|
|
16
|
+
intervalHandlers?: AgentControllerConfig<TState>['intervalHandlers'];
|
|
17
|
+
};
|
|
18
|
+
export {};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lumifai/harness",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"license": "UNLICENSED",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=22.13.0"
|
|
7
|
+
},
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.js",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
17
|
+
"main": "dist/index.js",
|
|
18
|
+
"types": "dist/index.d.ts",
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"!dist/**/*.test.*",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@mastra/core": "1.50.1"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public",
|
|
29
|
+
"registry": "https://registry.npmjs.org/"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsc -p tsconfig.json"
|
|
33
|
+
}
|
|
34
|
+
}
|