Skip to content

Commit 580b169

Browse files
committed
fix(agentos): remove eager usage-ledger imports from lightweight API paths
Deferred UsageLedger imports in agent.ts, generateText.ts, and streamText.ts to avoid pulling heavy dependency chains when only the lightweight generation API is used.
1 parent 7f056e2 commit 580b169

File tree

26 files changed

+552
-243
lines changed

26 files changed

+552
-243
lines changed

README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,44 @@ console.log(followUp.text);
179179
const config = tutor.exportJSON();
180180
```
181181

182+
The lightweight API also supports per-call model routing and lifecycle middleware without booting the full `AgentOS` runtime:
183+
184+
```typescript
185+
import type { IModelRouter } from '@framers/agentos';
186+
187+
const router: IModelRouter = {
188+
routerId: 'fast-vs-quality',
189+
async initialize() {},
190+
async selectModel(params) {
191+
if (params.optimizationPreference === 'speed') {
192+
return null; // fall back to the caller's provider/model
193+
}
194+
return null;
195+
},
196+
};
197+
198+
const reviewer = agent({
199+
instructions: 'Review drafts for policy and tone.',
200+
router,
201+
skills: [{
202+
skill: {
203+
name: 'policy-review',
204+
description: 'Review output before it is shown to users.',
205+
content: 'Flag unsafe content and keep the tone concise.',
206+
},
207+
frontmatter: {} as any,
208+
}],
209+
onBeforeGeneration: async (ctx) => ({
210+
...ctx,
211+
messages: [{ role: 'system', content: 'User is on the free plan.' }, ...ctx.messages],
212+
}),
213+
onAfterGeneration: async (result) => ({
214+
...result,
215+
text: result.text.trim(),
216+
}),
217+
});
218+
```
219+
182220
### 5. Multimodal (Image, Video, Audio, OCR, Embeddings)
183221

184222
```typescript

package.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,26 @@
1212
"default": "./dist/index.js",
1313
"types": "./dist/index.d.ts"
1414
},
15+
"./api": {
16+
"import": "./dist/api/index.js",
17+
"default": "./dist/api/index.js",
18+
"types": "./dist/api/index.d.ts"
19+
},
20+
"./api/agent": {
21+
"import": "./dist/api/agent.js",
22+
"default": "./dist/api/agent.js",
23+
"types": "./dist/api/agent.d.ts"
24+
},
25+
"./api/generateText": {
26+
"import": "./dist/api/generateText.js",
27+
"default": "./dist/api/generateText.js",
28+
"types": "./dist/api/generateText.d.ts"
29+
},
30+
"./api/streamText": {
31+
"import": "./dist/api/streamText.js",
32+
"default": "./dist/api/streamText.js",
33+
"types": "./dist/api/streamText.d.ts"
34+
},
1535
"./config/extension-secrets.json": "./dist/config/extension-secrets.json",
1636
"./skills": {
1737
"import": "./dist/skills.js",

src/api/agent.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,12 @@ import {
2121
import { streamText, type StreamTextResult } from './streamText.js';
2222
import type { IModelRouter } from '../core/llm/routing/IModelRouter.js';
2323
import type { SkillEntry } from '../skills/types.js';
24-
import {
25-
getRecordedAgentOSUsage,
26-
type AgentOSUsageAggregate,
27-
type AgentOSUsageLedgerOptions,
24+
import type {
25+
AgentOSUsageAggregate,
26+
AgentOSUsageLedgerOptions,
2827
} from './runtime/usageLedger.js';
2928
import type { BaseAgentConfig } from './types.js';
30-
import { exportAgentConfig, exportAgentConfigJSON, type AgentExportConfig } from './agentExport.js';
29+
import { exportAgentConfig, exportAgentConfigJSON, type AgentExportConfig } from './agentExportCore.js';
3130

3231
/**
3332
* Configuration options for the {@link agent} factory function.
@@ -173,6 +172,13 @@ function mergeUsageLedgerOptions(
173172
return Object.keys(merged).length > 0 ? merged : undefined;
174173
}
175174

175+
async function loadRecordedAgentOSUsage(
176+
options?: Pick<AgentOSUsageLedgerOptions, 'enabled' | 'path' | 'sessionId' | 'personaId'>
177+
): Promise<AgentOSUsageAggregate> {
178+
const { getRecordedAgentOSUsage } = await import('./runtime/usageLedger.js');
179+
return getRecordedAgentOSUsage(options);
180+
}
181+
176182
/** Timeout for memory operations to prevent blocking generation. */
177183
const MEMORY_TIMEOUT_MS = 5000;
178184

@@ -423,7 +429,7 @@ export function agent(opts: AgentOptions): Agent {
423429
},
424430

425431
async usage(): Promise<AgentOSUsageAggregate> {
426-
return getRecordedAgentOSUsage({
432+
return loadRecordedAgentOSUsage({
427433
enabled: baseOpts.usageLedger?.enabled,
428434
path: baseOpts.usageLedger?.path,
429435
sessionId,
@@ -437,7 +443,7 @@ export function agent(opts: AgentOptions): Agent {
437443
},
438444

439445
async usage(sessionId?: string): Promise<AgentOSUsageAggregate> {
440-
return getRecordedAgentOSUsage({
446+
return loadRecordedAgentOSUsage({
441447
enabled: baseOpts.usageLedger?.enabled,
442448
path: baseOpts.usageLedger?.path,
443449
sessionId,

src/api/agentExport.ts

Lines changed: 4 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -34,186 +34,10 @@ import YAML from 'yaml';
3434
import { agent as createAgent } from './agent.js';
3535
import { agency as createAgency } from './agency.js';
3636
import type { BaseAgentConfig, AgencyOptions, AgencyStrategy, Agent } from './types.js';
37-
38-
// ============================================================================
39-
// EXPORT CONFIG TYPE
40-
// ============================================================================
41-
42-
/**
43-
* Portable agent configuration envelope.
44-
*
45-
* Wraps a `BaseAgentConfig` with version metadata, export timestamp,
46-
* and type discriminator so import logic can reconstruct the correct agent
47-
* variant (single agent vs. multi-agent agency).
48-
*/
49-
export interface AgentExportConfig {
50-
/** Schema version for forward-compatible deserialization. */
51-
version: '1.0.0';
52-
53-
/** ISO 8601 timestamp of when the export was created. */
54-
exportedAt: string;
55-
56-
/**
57-
* Discriminator: `'agent'` for a single-agent export, `'agency'` for
58-
* a multi-agent export that includes a sub-agent roster.
59-
*/
60-
type: 'agent' | 'agency';
61-
62-
/** The full agent configuration. */
63-
config: BaseAgentConfig;
64-
65-
// -- Agency-specific fields (present when `type === 'agency'`) --
66-
67-
/** Sub-agent roster keyed by agent name. Present for agency exports. */
68-
agents?: Record<string, BaseAgentConfig>;
69-
70-
/** Orchestration strategy. Present for agency exports. */
71-
strategy?: AgencyStrategy;
72-
73-
/** Whether runtime strategy adaptation is enabled. */
74-
adaptive?: boolean;
75-
76-
/** Maximum orchestration rounds for iterative strategies. */
77-
maxRounds?: number;
78-
79-
// -- Optional metadata --
80-
81-
/** Human-readable metadata about the export (name, author, tags, etc.). */
82-
metadata?: {
83-
/** Display name for the exported agent. */
84-
name?: string;
85-
/** Free-text description of what this agent does. */
86-
description?: string;
87-
/** Author identifier (person or system). */
88-
author?: string;
89-
/** Searchable tags for categorization. */
90-
tags?: string[];
91-
};
92-
}
93-
94-
// ============================================================================
95-
// EXPORT FUNCTIONS
96-
// ============================================================================
97-
98-
/**
99-
* Extracts the stored configuration from an Agent instance.
100-
*
101-
* The agent's config is captured at creation time by the `agent()` and
102-
* `agency()` factories and attached as a non-enumerable `__config` property.
103-
* If the property is absent (e.g. the agent was created by external code),
104-
* we return an empty config.
105-
*
106-
* @param agentInstance - The agent to extract config from.
107-
* @returns The stored BaseAgentConfig or an empty object.
108-
*/
109-
function extractConfig(agentInstance: Agent): BaseAgentConfig {
110-
// The __config property is set by our patched agent/agency factories
111-
const config = (agentInstance as unknown as Record<string, unknown>).__config;
112-
if (config && typeof config === 'object') {
113-
return config as BaseAgentConfig;
114-
}
115-
// Fallback: no stored config — return empty
116-
return {};
117-
}
118-
119-
/**
120-
* Extracts agency-specific fields from an Agent instance that was created
121-
* by the `agency()` factory.
122-
*
123-
* @param agentInstance - The agent/agency to extract from.
124-
* @returns Agency fields if present, or undefined for plain agents.
125-
*/
126-
function extractAgencyFields(agentInstance: Agent):
127-
| {
128-
agents?: Record<string, BaseAgentConfig>;
129-
strategy?: AgencyStrategy;
130-
adaptive?: boolean;
131-
maxRounds?: number;
132-
}
133-
| undefined {
134-
const raw = (agentInstance as unknown as Record<string, unknown>).__agencyConfig;
135-
if (raw && typeof raw === 'object') {
136-
return raw as {
137-
agents?: Record<string, BaseAgentConfig>;
138-
strategy?: AgencyStrategy;
139-
adaptive?: boolean;
140-
maxRounds?: number;
141-
};
142-
}
143-
return undefined;
144-
}
145-
146-
/**
147-
* Exports an agent's configuration as a portable {@link AgentExportConfig} object.
148-
*
149-
* Captures the full `BaseAgentConfig` including model, instructions,
150-
* personality, tools, guardrails, memory, RAG, voice, channels, and all
151-
* other configuration surfaces. For agency instances, the sub-agent roster,
152-
* strategy, and round limits are also included.
153-
*
154-
* @param agentInstance - The agent (or agency) instance to export.
155-
* @param metadata - Optional human-readable metadata to attach to the export.
156-
* @returns A portable config object that can be serialized to JSON or YAML.
157-
*
158-
* @example
159-
* ```ts
160-
* const config = exportAgentConfig(myAgent, {
161-
* name: 'Research Assistant',
162-
* author: 'team-alpha',
163-
* tags: ['research', 'summarization'],
164-
* });
165-
* ```
166-
*/
167-
export function exportAgentConfig(
168-
agentInstance: Agent,
169-
metadata?: AgentExportConfig['metadata']
170-
): AgentExportConfig {
171-
const config = extractConfig(agentInstance);
172-
const agencyFields = extractAgencyFields(agentInstance);
173-
174-
const isAgency = !!agencyFields?.agents;
175-
176-
const exportConfig: AgentExportConfig = {
177-
version: '1.0.0',
178-
exportedAt: new Date().toISOString(),
179-
type: isAgency ? 'agency' : 'agent',
180-
config,
181-
};
182-
183-
// Attach agency-specific fields when present
184-
if (isAgency && agencyFields) {
185-
exportConfig.agents = agencyFields.agents;
186-
exportConfig.strategy = agencyFields.strategy;
187-
exportConfig.adaptive = agencyFields.adaptive;
188-
exportConfig.maxRounds = agencyFields.maxRounds;
189-
}
190-
191-
if (metadata) {
192-
exportConfig.metadata = metadata;
193-
}
194-
195-
return exportConfig;
196-
}
197-
198-
/**
199-
* Exports an agent's configuration as a pretty-printed JSON string.
200-
*
201-
* @param agentInstance - The agent (or agency) instance to export.
202-
* @param metadata - Optional human-readable metadata to attach.
203-
* @returns JSON string with 2-space indentation.
204-
*
205-
* @example
206-
* ```ts
207-
* const json = exportAgentConfigJSON(myAgent);
208-
* fs.writeFileSync('agent.json', json);
209-
* ```
210-
*/
211-
export function exportAgentConfigJSON(
212-
agentInstance: Agent,
213-
metadata?: AgentExportConfig['metadata']
214-
): string {
215-
return JSON.stringify(exportAgentConfig(agentInstance, metadata), null, 2);
216-
}
37+
import { exportAgentConfig, exportAgentConfigJSON } from './agentExportCore.js';
38+
export { exportAgentConfig, exportAgentConfigJSON };
39+
export type { AgentExportConfig } from './agentExportCore.js';
40+
import type { AgentExportConfig } from './agentExportCore.js';
21741

21842
/**
21943
* Exports an agent's configuration as a YAML string.

0 commit comments

Comments
 (0)