@lumifai/harness 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -12,6 +12,13 @@ durable lifecycle, reconnect, and transport behavior.
12
12
  4. **Server** — `@lumifai/harness-server`, `@lumifai/harness-server-fastify`, `@lumifai/harness-server-nest`
13
13
  5. **Client / React** — `@lumifai/harness-client`, `@lumifai/harness-react`, `@lumifai/harness-react-mantine`
14
14
 
15
+ Mastra is a **peer dependency** (`@mastra/core` `^1.73`, plus `@mastra/memory` and `@mastra/libsql`
16
+ for the server package). Install it in your app so there is one copy of Mastra. Publish and upgrade
17
+ all `@lumifai/harness*` packages together.
18
+
19
+ For local development against a checkout, use `pnpm link` (or a local `pnpm.overrides` entry that
20
+ you do not commit); do not commit `link:` paths, they break Docker builds.
21
+
15
22
  ## Usage
16
23
 
17
24
  ```typescript
@@ -284,6 +291,7 @@ and `resumeToolSuspension(data, toolCallId)`.
284
291
 
285
292
  Import configurable presets from `@lumifai/harness-presets`:
286
293
 
294
+ - `createPresetProfiles()` — the preset modes as profiles (the model stays selectable); `createPresetHostOptions()` — profiles plus baseline tools, subagents and displaced built-ins, ready for `createAgentHostConfig`
287
295
  - `createPresetModes()` — `plan` and `build` modes
288
296
  - `createPresetCustomModes()` — returns the built-in modes plus your custom list when you need the final array yourself
289
297
  - `createPresetSubagents()` — `explore` subagent; opt-in `websearch` subagent via `includeWebSearch: true`
@@ -292,6 +300,158 @@ Import configurable presets from `@lumifai/harness-presets`:
292
300
  - `createPresetHarnessConfig()` — combines the above and merges enabled pack skill paths
293
301
  - `createPresetPermissionConfig()` — default category resolver and merged `permissionRules` for harness init
294
302
 
303
+ ## Profiles (your own modes)
304
+
305
+ Every Lumif app runs through one assembly, `createAgentHostConfig` in `@lumifai/harness`: a list
306
+ of **profiles** in, controller config out. A profile is a Mastra controller mode (instructions,
307
+ `availableTools`, `transitionsTo`, metadata) plus the agent-level settings that follow the mode:
308
+ model, processors, scorers and run options. The presets are just a ready-made set of profiles
309
+ (`createPresetProfiles()` in `@lumifai/harness-presets`); you can use them, extend them, or declare
310
+ your own.
311
+
312
+ On the server boot config, setting `profiles` replaces the presets (no plan/build modes, preset
313
+ subagents, `ask_user`, `submit_plan` or `request_access`):
314
+
315
+ ```typescript
316
+ createHarnessSessionManager({
317
+ bootConfig: {
318
+ systemContext: 'Shared context for every profile',
319
+ providerOptions: { openai: { reasoningEffort: 'high' } },
320
+ yolo: true, // tool calls run without approval; the default is to require it
321
+ profiles: [
322
+ {
323
+ id: 'concierge',
324
+ instructions: '...',
325
+ model: 'openai/gpt-6-luna',
326
+ availableTools: ['get_context', 'ask'], // final tool names, workspace tools included
327
+ },
328
+ {
329
+ id: 'matter',
330
+ instructions: '...',
331
+ model: 'openai/gpt-6-luna',
332
+ availableTools: ['get_context', 'propose_action'],
333
+ inputProcessors: [promptInjectionDetector],
334
+ outputProcessors: [],
335
+ scorers: {},
336
+ eagerToolExecution: false, // Mastra 1.71+ starts tools as soon as their call streams
337
+ },
338
+ ],
339
+ extraTools, // static tools, plus `toolPacks` as usual
340
+ // Per request: gate tools on the conversation or add per-user connectors.
341
+ toolsResolver: ({ requestContext }) => connectorsFor(requestContext.get('userId')),
342
+ hooks: { onRunStart, onToolCall, onApprovalRequired, onRunEnd }, // fired for every run
343
+ },
344
+ });
345
+ ```
346
+
347
+ All profiles run on one shared Mastra `Agent`. Its model, processors, scorers and options are
348
+ resolved from the active mode on every request, so there is no per-mode agent (deprecated in
349
+ Mastra).
350
+
351
+ - **Model.** Pinned to the profile's `model` by default, so deploying a new model reaches existing
352
+ threads. Set `modelSelectable: true` to let the session's model (`switchModel`, and what a thread
353
+ last used) win; the presets do this. A profile with no `model` uses the host's `defaultModel`.
354
+ - **Model fallback.** `model` and `defaultModel` take whatever a Mastra `Agent`'s `model` takes,
355
+ including an ordered `ModelWithRetries[]`: when an entry fails after its `maxRetries`, the next
356
+ one runs. The presets accept the same on `planModel` / `buildModel` (boot config and config
357
+ patches validate the JSON-serializable subset, at least one entry), e.g.
358
+ `[{ model: 'openai/gpt-6', maxRetries: 1 }, { model: 'anthropic/claude-sonnet-4-6' }]`. The list
359
+ reaches the Agent unchanged. An entry with `enabled: false` is skipped for display only: mode
360
+ summaries, the session model id, and the explore subagent use the first entry that is not
361
+ disabled. Explore gets that id and does not run the list. That mode's `modelSelectable` is
362
+ false (`listModeSummaries`, and `metadata.modelSelectable` on the controller mode) so a picker
363
+ can disable itself. `switchModel` rejects the mode with `HarnessClientError` (HTTP 400) and
364
+ leaves the list as configured. Session and request patches accept this same shape, including
365
+ `headers`, `providerOptions`, `modelSettings`, and `maxRetries`. Those values go out on
366
+ provider calls made with the server's credentials, and call headers override the provider's.
367
+ Authorize who can `updateConfig`; the harness does not narrow the patch.
368
+ - **Approval.** Tool calls require approval unless `yolo: true`. Permission rules and the tool
369
+ category resolver apply to profiles exactly as they do to the presets.
370
+ - **Built-in tools.** Mastra's built-ins (`ask_user`, `submit_plan`, `task_*`, `subagent`) are
371
+ removed unless you list others in `disableBuiltinTools`.
372
+ - **Preset-only options** (`customModes`, `subagents`, `includeRequestAccess: true`, `planModel`,
373
+ `buildModel`, `planInstructions`, `buildInstructions`, `modeOverrides`) are rejected when
374
+ `profiles` is set, rather than silently ignored. The same goes for session and request config
375
+ patches that set `planModel`, `buildModel`, `planInstructions`, `buildInstructions` or
376
+ `modeOverrides`. `includeRequestAccess: false` is accepted, since that is what profiles do.
377
+ A session stored before the switch may still have those keys: restoring it drops them and
378
+ logs a warning, so the session can load and be destroyed. A new patch that sets them is
379
+ still rejected.
380
+
381
+ Stored sessions keep their persisted mode id, so rename profiles with care.
382
+
383
+ ### Headless runs
384
+
385
+ ```typescript
386
+ const outcome = await manager.run(
387
+ sessionId,
388
+ {
389
+ modeId: 'matter',
390
+ message,
391
+ requestContext: { matterId },
392
+ signal, // optional AbortSignal
393
+ timeoutMs: 120_000,
394
+ },
395
+ context,
396
+ );
397
+ // { mastraRunId, finishReason, usage, toolCalls, error, aborted, timedOut, pendingApprovals? }
398
+ ```
399
+
400
+ `run` creates the session on first use and rejects with `HarnessRunBusyError` while a run is in
401
+ progress. Aborting ends the run but does not stop a tool already executing unless that tool honours
402
+ its abort signal, so do not treat run end as tool end.
403
+
404
+ Unless the host sets `yolo`, a tool call that needs approval parks the run. `run` then resolves
405
+ early with `finishReason: 'awaiting_approval'` and `pendingApprovals` (`toolCallId`, `toolName`,
406
+ `args`) instead of hanging. The run is still open: answer each call with
407
+ `manager.respondToToolApproval(sessionId, { toolCallId, approved }, context)` and the run continues
408
+ on its own, or abort it. `timeoutMs` and `signal` stop applying once `run` has returned, and
409
+ `run` rejects with `HarnessRunBusyError` until the approval is decided. A later approval in that
410
+ same run fires `hooks.onApprovalRequired` again (`toolCallId`, `toolName`, `args`), including
411
+ after `run` has returned. `onRunEnd` still reports how the run finished. Subscribing to session
412
+ events or polling `getSnapshot()` shows the same pending call.
413
+
414
+ ### Mid-run input (experimental)
415
+
416
+ ```typescript
417
+ await manager.signal(sessionId, { whenActive: 'deliver', content }, context);
418
+ ```
419
+
420
+ - `deliver`: inject into the active run without aborting it; the next model step sees it and the
421
+ run id is unchanged. A running tool is not interrupted. Returns `{ delivered: false, action:
422
+ 'idle' }` when no run is active. Uses Mastra's `sendSignal`, which Mastra marks experimental; if
423
+ it is missing, it falls back to a steer.
424
+ - `queue`: hold for the next run. On an idle session it starts a run immediately.
425
+ - `abort`: abort the active run; with `content` it is also sent as the next input (a steer).
426
+ Without `content` on an idle session it returns `{ delivered: false, action: 'idle' }`.
427
+
428
+ `signal` resolves once the input is accepted, not when the run it starts or steers finishes;
429
+ failures of that run are logged.
430
+
431
+ `agent-host.integration.test.ts` pins this behaviour against a real controller, so a Mastra upgrade
432
+ that changes it fails there.
433
+
434
+ ### Thread lock
435
+
436
+ ```typescript
437
+ import { Pool } from 'pg';
438
+ import { createPostgresThreadLock } from '@lumifai/harness-server';
439
+
440
+ // max must cover maxInMemorySessions (default 100) plus headroom for the app's own queries.
441
+ const pool = new Pool({ max: 120, connectionTimeoutMillis: 5_000 });
442
+ bootConfig.threadLock = createPostgresThreadLock({ pool });
443
+ ```
444
+
445
+ One session in any process holds a thread at a time; `acquire` throws `ThreadLockedError` rather
446
+ than waiting (set `waitTimeoutMs` to retry). Advisory locks belong to a connection, so each held
447
+ thread occupies one pooled connection for the session's life; size the pool for it, and set
448
+ `connectionTimeoutMillis`: `pg` otherwise waits on `pool.connect()` indefinitely once the pool is
449
+ exhausted, which stalls session creation instead of failing it. Session-level advisory locks need a
450
+ direct or session-mode connection; behind PgBouncer or Supabase transaction pooling they do not
451
+ hold. A crashed process frees its locks, and so does a dropped connection, even though the session
452
+ still believes it holds the thread. The harness holds a thread until the session is disposed, so a second
453
+ device is refused until then.
454
+
295
455
  ## Tool packs
296
456
 
297
457
  Import opt-in capability bundles from `@lumifai/harness-tool-pack-*` packages. Shared types and merge helpers live in `@lumifai/harness-tool-packs`:
@@ -0,0 +1,81 @@
1
+ import { type AgentExecutionOptions, type ModelWithRetries, type ToolsInput } from '@mastra/core/agent';
2
+ import type { AgentControllerConfig, AgentControllerMode, AgentControllerSubagent, BuiltinToolId, PermissionRules, ToolCategory } from '@mastra/core/agent-controller';
3
+ import type { MastraScorers } from '@mastra/core/evals';
4
+ import type { MastraModelConfig } from '@mastra/core/llm';
5
+ import type { ErrorProcessorOrWorkflow, InputProcessorOrWorkflow, OutputProcessorOrWorkflow } from '@mastra/core/processors';
6
+ import type { RequestContext } from '@mastra/core/request-context';
7
+ /**
8
+ * One mode of an agent host. It is a Mastra controller mode (instructions, tool
9
+ * allow-list, `transitionsTo`, metadata...) plus the agent-level settings that follow the
10
+ * mode: model, processors, scorers and run options.
11
+ *
12
+ * All profiles run on one shared Mastra `Agent` whose model, processors, scorers and
13
+ * options are resolved from the active mode on every request, so a mode switch changes
14
+ * them without a second agent (`AgentControllerMode.agent` is deprecated in Mastra).
15
+ */
16
+ export type AgentHostProfile = Omit<AgentControllerMode, 'agent' | 'default' | 'defaultModelId'> & {
17
+ /**
18
+ * Model for this profile. Falls back to the host's `defaultModel`. Pinned unless
19
+ * `modelSelectable` is set. Takes whatever a Mastra `Agent`'s `model` takes, including an
20
+ * ordered `ModelWithRetries[]` that falls back to the next entry when one fails its retries.
21
+ */
22
+ model?: MastraModelConfig | ModelWithRetries[];
23
+ /**
24
+ * Let the session's model (`switchModel`, and what a thread last used) win over `model`.
25
+ * Only applies to model ids (strings); a fallback list stays as configured. Off by default
26
+ * so deploying a new model reaches existing threads.
27
+ */
28
+ modelSelectable?: boolean;
29
+ /** Merged over the host-wide `providerOptions` for this profile's runs. */
30
+ providerOptions?: NonNullable<AgentExecutionOptions['providerOptions']>;
31
+ inputProcessors?: InputProcessorOrWorkflow[];
32
+ outputProcessors?: OutputProcessorOrWorkflow[];
33
+ errorProcessors?: ErrorProcessorOrWorkflow[];
34
+ scorers?: MastraScorers;
35
+ /**
36
+ * Start a tool as soon as its call has streamed. Left to Mastra's default (on since 1.71)
37
+ * unless set; turn it off if tool ordering or budget counting matters.
38
+ */
39
+ eagerToolExecution?: boolean;
40
+ /** The mode a session starts in. Defaults to the first profile flagged default, else the first. */
41
+ default?: boolean;
42
+ };
43
+ export type AgentHostToolsResolver = (input: {
44
+ requestContext: RequestContext;
45
+ }) => ToolsInput | undefined | Promise<ToolsInput | undefined>;
46
+ export type AgentHostOptions = {
47
+ profiles: AgentHostProfile[];
48
+ /** Model for profiles that declare none. */
49
+ defaultModel?: MastraModelConfig | ModelWithRetries[];
50
+ /** Host-wide context layered above every profile's instructions. */
51
+ systemContext?: string;
52
+ /** Tools registered once, before any request. */
53
+ tools?: ToolsInput;
54
+ /** Tools resolved per request (for example per-user connectors); merged over `tools`. */
55
+ toolsResolver?: AgentHostToolsResolver;
56
+ subagents?: AgentControllerSubagent[];
57
+ providerOptions?: AgentExecutionOptions['providerOptions'];
58
+ /** Mastra's built-in tools to remove. Defaults to all of them. */
59
+ disableBuiltinTools?: BuiltinToolId[];
60
+ permissionRules?: PermissionRules;
61
+ toolCategoryResolver?: (toolName: string) => ToolCategory | null;
62
+ /** Tool calls wait for approval unless this is false. Defaults to true. */
63
+ requireToolApproval?: boolean;
64
+ };
65
+ export type AgentHostConfig<TState = {}> = Pick<AgentControllerConfig<TState>, 'agent' | 'instructions' | 'defaultModeId' | 'modes' | 'tools' | 'subagents' | 'disableBuiltinTools' | 'initialState' | 'toolCategoryResolver'>;
66
+ export declare const ALL_BUILTIN_TOOLS: BuiltinToolId[];
67
+ export declare const AGENT_HOST_AGENT_ID = "lumif-harness-agent";
68
+ /**
69
+ * Model id used for display, mode summaries, and the explore subagent.
70
+ * A fallback list contributes its first entry that is not `enabled: false`.
71
+ * The list passed to the agent is unchanged, and explore does not receive the list.
72
+ */
73
+ export declare function firstModelId(model: string | ModelWithRetries[] | undefined): string | undefined;
74
+ /** The controller modes for a set of profiles. */
75
+ export declare function profilesToModes(profiles: AgentHostProfile[], defaultModel?: AgentHostProfile['model']): AgentControllerMode[];
76
+ /**
77
+ * Assemble the controller config for a set of profiles: one shared agent, one mode per
78
+ * profile, tools, permissions and approval defaults. This is the only place a Lumif app's
79
+ * modes become controller config; presets and hand-written profiles both go through it.
80
+ */
81
+ export declare function createAgentHostConfig<TState = {}>(options: AgentHostOptions): AgentHostConfig<TState>;
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AGENT_HOST_AGENT_ID = exports.ALL_BUILTIN_TOOLS = void 0;
4
+ exports.firstModelId = firstModelId;
5
+ exports.profilesToModes = profilesToModes;
6
+ exports.createAgentHostConfig = createAgentHostConfig;
7
+ const agent_1 = require("@mastra/core/agent");
8
+ exports.ALL_BUILTIN_TOOLS = [
9
+ 'ask_user',
10
+ 'submit_plan',
11
+ 'task_write',
12
+ 'task_update',
13
+ 'task_complete',
14
+ 'task_check',
15
+ 'subagent',
16
+ ];
17
+ exports.AGENT_HOST_AGENT_ID = 'lumif-harness-agent';
18
+ function isDefaultProfile(profile) {
19
+ return profile.default === true || profile.metadata?.default === true;
20
+ }
21
+ function pickDefaultProfile(profiles) {
22
+ return profiles.find(isDefaultProfile) ?? profiles[0];
23
+ }
24
+ /**
25
+ * Model id used for display, mode summaries, and the explore subagent.
26
+ * A fallback list contributes its first entry that is not `enabled: false`.
27
+ * The list passed to the agent is unchanged, and explore does not receive the list.
28
+ */
29
+ function firstModelId(model) {
30
+ if (typeof model === 'string')
31
+ return model;
32
+ if (!Array.isArray(model))
33
+ return undefined;
34
+ for (const entry of model) {
35
+ if (!entry || entry.enabled === false)
36
+ continue;
37
+ if (typeof entry.model === 'string')
38
+ return entry.model;
39
+ }
40
+ return undefined;
41
+ }
42
+ function assertValidProfiles(profiles, defaultModel) {
43
+ if (profiles.length === 0) {
44
+ throw new Error('An agent host needs at least one profile.');
45
+ }
46
+ const seen = new Set();
47
+ for (const profile of profiles) {
48
+ if (!profile.id)
49
+ throw new Error('Agent host profile ids must be non-empty.');
50
+ if (seen.has(profile.id)) {
51
+ throw new Error(`Duplicate agent host profile id "${profile.id}". Profile ids must be unique.`);
52
+ }
53
+ seen.add(profile.id);
54
+ if (profile.model === undefined && defaultModel === undefined) {
55
+ throw new Error(`Agent host profile "${profile.id}" has no model and the host has no defaultModel.`);
56
+ }
57
+ }
58
+ }
59
+ /** The active mode, as the controller exposes it on every request context. */
60
+ function controllerSession(requestContext) {
61
+ const controller = requestContext?.get('controller');
62
+ return controller?.session;
63
+ }
64
+ /** The controller modes for a set of profiles. */
65
+ function profilesToModes(profiles, defaultModel) {
66
+ const fallback = pickDefaultProfile(profiles);
67
+ return profiles.map((profile) => {
68
+ const { model, modelSelectable: _modelSelectable, providerOptions: _providerOptions, inputProcessors: _inputProcessors, outputProcessors: _outputProcessors, errorProcessors: _errorProcessors, scorers: _scorers, eagerToolExecution: _eagerToolExecution, default: _default, ...mode } = profile;
69
+ // The controller reads `defaultModelId` synchronously as the session's model id.
70
+ // A fallback list contributes its first enabled entry and is not selectable.
71
+ const effective = model ?? defaultModel;
72
+ const modelId = firstModelId(Array.isArray(effective) || typeof effective === 'string' ? effective : undefined);
73
+ const listBacked = Array.isArray(effective);
74
+ const metadata = {
75
+ ...mode.metadata,
76
+ ...(profile === fallback ? { default: true } : {}),
77
+ ...(listBacked ? { modelSelectable: false } : {}),
78
+ };
79
+ return {
80
+ ...mode,
81
+ ...(typeof modelId === 'string' ? { defaultModelId: modelId } : {}),
82
+ ...(Object.keys(metadata).length > 0 ? { metadata } : {}),
83
+ };
84
+ });
85
+ }
86
+ /**
87
+ * Assemble the controller config for a set of profiles: one shared agent, one mode per
88
+ * profile, tools, permissions and approval defaults. This is the only place a Lumif app's
89
+ * modes become controller config; presets and hand-written profiles both go through it.
90
+ */
91
+ function createAgentHostConfig(options) {
92
+ const { profiles, defaultModel } = options;
93
+ assertValidProfiles(profiles, defaultModel);
94
+ const byId = new Map(profiles.map((profile) => [profile.id, profile]));
95
+ const fallback = pickDefaultProfile(profiles);
96
+ const profileOf = (requestContext) => byId.get(controllerSession(requestContext)?.modeId ?? '') ?? fallback;
97
+ const agent = new agent_1.Agent({
98
+ id: exports.AGENT_HOST_AGENT_ID,
99
+ name: 'Lumif Harness Agent',
100
+ // Each mode's instructions are layered on by the controller.
101
+ instructions: '',
102
+ model: ({ requestContext }) => {
103
+ const profile = profileOf(requestContext);
104
+ const selected = controllerSession(requestContext)?.modelId;
105
+ if (profile.modelSelectable &&
106
+ selected &&
107
+ typeof (profile.model ?? defaultModel) === 'string') {
108
+ return selected;
109
+ }
110
+ return (profile.model ?? defaultModel);
111
+ },
112
+ inputProcessors: ({ requestContext }) => profileOf(requestContext).inputProcessors ?? [],
113
+ outputProcessors: ({ requestContext }) => profileOf(requestContext).outputProcessors ?? [],
114
+ errorProcessors: ({ requestContext }) => profileOf(requestContext).errorProcessors ?? [],
115
+ scorers: ({ requestContext }) => profileOf(requestContext).scorers ?? {},
116
+ defaultOptions: ({ requestContext }) => {
117
+ const profile = profileOf(requestContext);
118
+ const providerOptions = { ...options.providerOptions, ...profile.providerOptions };
119
+ return {
120
+ // The host owns suspension resumes; Mastra's auto-resume rewrites tool-call args.
121
+ autoResumeSuspendedTools: false,
122
+ ...(profile.eagerToolExecution === undefined
123
+ ? {}
124
+ : { eagerToolExecution: profile.eagerToolExecution }),
125
+ ...(Object.keys(providerOptions).length > 0 ? { providerOptions } : {}),
126
+ };
127
+ },
128
+ });
129
+ const staticTools = options.tools ?? {};
130
+ const { toolsResolver } = options;
131
+ return {
132
+ agent,
133
+ instructions: options.systemContext,
134
+ defaultModeId: fallback.id,
135
+ modes: profilesToModes(profiles, defaultModel),
136
+ tools: toolsResolver
137
+ ? async ({ requestContext }) => ({
138
+ ...staticTools,
139
+ ...(await toolsResolver({ requestContext })),
140
+ })
141
+ : staticTools,
142
+ subagents: options.subagents,
143
+ disableBuiltinTools: options.disableBuiltinTools ?? exports.ALL_BUILTIN_TOOLS,
144
+ toolCategoryResolver: options.toolCategoryResolver,
145
+ initialState: {
146
+ ...(options.permissionRules ? { permissionRules: options.permissionRules } : {}),
147
+ // Approval is the safe default; an app that vets its own tools opts out.
148
+ ...(options.requireToolApproval === false ? { yolo: true } : {}),
149
+ },
150
+ };
151
+ }
152
+ //# sourceMappingURL=agent-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-host.js","sourceRoot":"","sources":["../src/agent-host.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,10 +1,12 @@
1
+ export { Agent } from '@mastra/core/agent';
2
+ export type { ToolsInput } from '@mastra/core/agent';
1
3
  export { createLumifHarness } from './create-lumif-harness';
2
4
  export type { LumifHarnessOptions, LumifWorkspace, LumifWorkspaceFactory } from './types';
3
- export type { ToolsInput } from '@mastra/core/agent';
4
- export { Agent } from '@mastra/core/agent';
5
5
  export { createTool } from '@mastra/core/tools';
6
6
  export type { ToolExecutionContext } from '@mastra/core/tools';
7
7
  export { Session } from '@mastra/core/agent-controller';
8
8
  /** Lumif's stable Harness export, backed by Mastra's AgentController runtime. */
9
9
  export { AgentController as Harness } from '@mastra/core/agent-controller';
10
10
  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';
11
+ export { AGENT_HOST_AGENT_ID, ALL_BUILTIN_TOOLS, createAgentHostConfig, firstModelId, profilesToModes, } from './agent-host';
12
+ export type { AgentHostConfig, AgentHostOptions, AgentHostProfile, AgentHostToolsResolver, } from './agent-host';
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Harness = exports.Session = exports.createTool = exports.Agent = 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; } });
3
+ exports.profilesToModes = exports.firstModelId = exports.createAgentHostConfig = exports.ALL_BUILTIN_TOOLS = exports.AGENT_HOST_AGENT_ID = exports.Harness = exports.Session = exports.createTool = exports.createLumifHarness = exports.Agent = void 0;
6
4
  var agent_1 = require("@mastra/core/agent");
7
5
  Object.defineProperty(exports, "Agent", { enumerable: true, get: function () { return agent_1.Agent; } });
6
+ var create_lumif_harness_1 = require("./create-lumif-harness");
7
+ Object.defineProperty(exports, "createLumifHarness", { enumerable: true, get: function () { return create_lumif_harness_1.createLumifHarness; } });
8
8
  var tools_1 = require("@mastra/core/tools");
9
9
  Object.defineProperty(exports, "createTool", { enumerable: true, get: function () { return tools_1.createTool; } });
10
10
  var agent_controller_1 = require("@mastra/core/agent-controller");
@@ -12,4 +12,10 @@ Object.defineProperty(exports, "Session", { enumerable: true, get: function () {
12
12
  /** Lumif's stable Harness export, backed by Mastra's AgentController runtime. */
13
13
  var agent_controller_2 = require("@mastra/core/agent-controller");
14
14
  Object.defineProperty(exports, "Harness", { enumerable: true, get: function () { return agent_controller_2.AgentController; } });
15
+ var agent_host_1 = require("./agent-host");
16
+ Object.defineProperty(exports, "AGENT_HOST_AGENT_ID", { enumerable: true, get: function () { return agent_host_1.AGENT_HOST_AGENT_ID; } });
17
+ Object.defineProperty(exports, "ALL_BUILTIN_TOOLS", { enumerable: true, get: function () { return agent_host_1.ALL_BUILTIN_TOOLS; } });
18
+ Object.defineProperty(exports, "createAgentHostConfig", { enumerable: true, get: function () { return agent_host_1.createAgentHostConfig; } });
19
+ Object.defineProperty(exports, "firstModelId", { enumerable: true, get: function () { return agent_host_1.firstModelId; } });
20
+ Object.defineProperty(exports, "profilesToModes", { enumerable: true, get: function () { return agent_host_1.profilesToModes; } });
15
21
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,+DAA4D;AAAnD,0HAAA,kBAAkB,OAAA;AAG3B,4CAA2C;AAAlC,8FAAA,KAAK,OAAA;AAEd,4CAAgD;AAAvC,mGAAA,UAAU,OAAA;AAGnB,kEAAwD;AAA/C,2GAAA,OAAO,OAAA;AAChB,iFAAiF;AACjF,kEAA2E;AAAlE,2GAAA,eAAe,OAAW"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,4CAA2C;AAAlC,8FAAA,KAAK,OAAA;AAEd,+DAA4D;AAAnD,0HAAA,kBAAkB,OAAA;AAG3B,4CAAgD;AAAvC,mGAAA,UAAU,OAAA;AAGnB,kEAAwD;AAA/C,2GAAA,OAAO,OAAA;AAChB,iFAAiF;AACjF,kEAA2E;AAAlE,2GAAA,eAAe,OAAW;AAgBnC,2CAMsB;AALpB,iHAAA,mBAAmB,OAAA;AACnB,+GAAA,iBAAiB,OAAA;AACjB,mHAAA,qBAAqB,OAAA;AACrB,0GAAA,YAAY,OAAA;AACZ,6GAAA,eAAe,OAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumifai/harness",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "license": "UNLICENSED",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,13 +26,17 @@
26
26
  "!dist/**/*.test.*",
27
27
  "README.md"
28
28
  ],
29
- "dependencies": {
30
- "@mastra/core": "1.57.0"
31
- },
32
29
  "publishConfig": {
33
30
  "access": "public",
34
31
  "registry": "https://registry.npmjs.org/"
35
32
  },
33
+ "peerDependencies": {
34
+ "@mastra/core": "^1.73.0"
35
+ },
36
+ "devDependencies": {
37
+ "@mastra/core": "1.73.0",
38
+ "zod": "4.6.5"
39
+ },
36
40
  "scripts": {
37
41
  "build": "tsc -p tsconfig.json"
38
42
  }