Skip to content
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7b1deb0
[US-001] Add usage_events table to runtime schema
tim-inkeep Mar 19, 2026
46ae1a5
[US-002] Create pricing service with gateway and models.dev fallback
tim-inkeep Mar 19, 2026
a004ff5
[US-003] Create usage events data access layer
tim-inkeep Mar 19, 2026
a63b7c3
[US-004] Create usage tracker wrapper and OTel enrichment
tim-inkeep Mar 19, 2026
2a41bb3
[US-005] Resolve usage/totalUsage in resolveGenerationResponse
tim-inkeep Mar 19, 2026
255404f
[US-006] Instrument main generation path with usage tracking
tim-inkeep Mar 19, 2026
4597b1a
[US-007] Instrument status update and artifact metadata generations
tim-inkeep Mar 19, 2026
a31d94b
Move token-estimator from agents-api to agents-core
tim-inkeep Mar 19, 2026
d4c0414
Refactor usage tracking to trackedGenerate wrapper
tim-inkeep Mar 19, 2026
e85c836
[US-009/US-010] Add usage summary and events API endpoints
tim-inkeep Mar 19, 2026
fe7c0bf
[US-011/US-012] Add usage dashboard to Manage UI
tim-inkeep Mar 19, 2026
613dd0a
Add shared UsageDashboard component and project-level usage page
tim-inkeep Mar 19, 2026
2d321c0
Fix usage API auth + initialize pricing service on startup
tim-inkeep Mar 19, 2026
ac46527
Fix cost estimation: use parsed model name for pricing lookup
tim-inkeep Mar 19, 2026
a27c78f
Add step-level usage, trace/span IDs, cost in traces, compression tra…
tim-inkeep Mar 20, 2026
f73bd84
Migrate usage tracking from Postgres to SigNoz OTel spans
tim-inkeep Mar 20, 2026
b77c288
added new token and cost tracking
tim-inkeep Mar 23, 2026
fbc060d
updated all to use real token counts
tim-inkeep Mar 23, 2026
725d4cc
update pricing server
tim-inkeep Mar 23, 2026
7267edd
updated changset
tim-inkeep Mar 23, 2026
daea46d
Merge branch 'main' into implement/usage-tracker
tim-inkeep Mar 23, 2026
b675151
style: auto-format with biome
github-actions[bot] Mar 23, 2026
ba09180
updated with comments
tim-inkeep Mar 23, 2026
7ab059e
updated with comments
tim-inkeep Mar 23, 2026
e626b64
merged ui from main
tim-inkeep Mar 23, 2026
62bfdad
updated again
tim-inkeep Mar 23, 2026
62647f1
updated
tim-inkeep Mar 23, 2026
0b87184
fixed for all llm calls
tim-inkeep Mar 24, 2026
adb2750
fixed tests
tim-inkeep Mar 24, 2026
d61caec
knipped
tim-inkeep Mar 24, 2026
6ad46e2
merged main
tim-inkeep Mar 24, 2026
2140a36
updated pricing server refresh strategy
tim-inkeep Mar 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/golden-crimson-emu.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@inkeep/agents-core": patch
"@inkeep/agents-api": patch
---

Use actual AI SDK token usage for compression decisions and fix pricing service model ID lookup
51 changes: 24 additions & 27 deletions agents-api/src/__tests__/run/agents/ModelFactory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('Anthropic');
expect(model).toHaveProperty('modelId');
});

test('should create OpenAI model with explicit config', () => {
Expand All @@ -130,7 +130,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('OpenAI');
expect(model).toHaveProperty('modelId');
});

test('should create Anthropic model with proper provider prefix', () => {
Expand All @@ -141,7 +141,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('Anthropic');
expect(model).toHaveProperty('modelId');
});

test('should create Anthropic model with custom provider options', () => {
Expand All @@ -159,7 +159,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('Anthropic');
expect(model).toHaveProperty('modelId');
});

test('should create OpenAI model with custom provider options', () => {
Expand All @@ -176,7 +176,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('OpenAI');
expect(model).toHaveProperty('modelId');
});

// Google/Gemini specific tests
Expand All @@ -188,8 +188,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('Google');
expect(model).toHaveProperty('modelId', 'gemini-2.5-flash');
expect(model).toHaveProperty('modelId');
});

test('should create Google Gemini Pro model', () => {
Expand All @@ -200,7 +199,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('Google');
expect(model).toHaveProperty('modelId');
});

test('should create Google Gemini Flash Lite model', () => {
Expand All @@ -211,7 +210,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('Google');
expect(model).toHaveProperty('modelId');
});

test('should create Google model with custom provider options', () => {
Expand All @@ -227,9 +226,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('Google');
// Note: We can't reliably test the mock calls due to interference in the full suite
// The functionality itself works correctly
expect(model).toHaveProperty('modelId');
});

test('should handle Google model with gateway configuration', () => {
Expand All @@ -247,7 +244,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('Google');
expect(model).toHaveProperty('modelId');
// Note: We can't reliably test the mock calls due to interference in the full suite
// The functionality itself works correctly
});
Expand Down Expand Up @@ -277,7 +274,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('Anthropic');
expect(model).toHaveProperty('modelId');
});

test('should throw error for unknown provider', () => {
Expand All @@ -300,7 +297,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('Anthropic');
expect(model).toHaveProperty('modelId');
});
});

Expand Down Expand Up @@ -509,7 +506,7 @@ describe('ModelFactory', () => {

expect(config).toHaveProperty('model');
expect(config.model).toBeDefined();
expect(config.model.constructor.name).toContain('Anthropic');
expect(config.model).toHaveProperty('modelId');
expect(config).toHaveProperty('temperature', 0.8);
expect(config).toHaveProperty('maxTokens', 2048);
expect(config).not.toHaveProperty('apiKey'); // Should be filtered out
Expand All @@ -534,7 +531,7 @@ describe('ModelFactory', () => {
const config = ModelFactory.prepareGenerationConfig(modelSettings);

expect(config).toHaveProperty('model');
expect(config.model.constructor.name).toContain('OpenAI');
expect(config.model).toHaveProperty('modelId');
expect(config).toHaveProperty('temperature', 0.3);
expect(config).toHaveProperty('frequencyPenalty', 0.1);
expect(config).not.toHaveProperty('baseURL'); // Should be filtered out
Expand All @@ -548,7 +545,7 @@ describe('ModelFactory', () => {
const config = ModelFactory.prepareGenerationConfig(modelSettings);

expect(config).toHaveProperty('model');
expect(config.model.constructor.name).toContain('Anthropic');
expect(config.model).toHaveProperty('modelId');
// Should only have the model property, no generation params
expect(Object.keys(config)).toEqual(['model']);
});
Expand Down Expand Up @@ -592,7 +589,7 @@ describe('ModelFactory', () => {
const config = ModelFactory.prepareGenerationConfig(modelSettings);

expect(config).toHaveProperty('model');
expect(config.model.constructor.name).toContain('Google');
expect(config.model).toHaveProperty('modelId');
expect(config).toHaveProperty('temperature', 0.5);
expect(config).toHaveProperty('maxTokens', 1024);
expect(config).toHaveProperty('topP', 0.9);
Expand All @@ -618,7 +615,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('Anthropic');
expect(model).toHaveProperty('modelId');
});

test('should handle model names with multiple slashes', () => {
Expand All @@ -629,7 +626,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('OpenAI');
expect(model).toHaveProperty('modelId');
});

test('should require provider prefix in model string', () => {
Expand Down Expand Up @@ -657,7 +654,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('Anthropic');
expect(model).toHaveProperty('modelId');
});

test('should handle OpenAI provider configuration', () => {
Expand All @@ -673,7 +670,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('OpenAI');
expect(model).toHaveProperty('modelId');
});

test('should handle both baseUrl and baseURL variants', () => {
Expand All @@ -689,7 +686,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('Anthropic');
expect(model).toHaveProperty('modelId');
});

test('should handle provider configuration with only generation params', () => {
Expand All @@ -705,7 +702,7 @@ describe('ModelFactory', () => {
const model = ModelFactory.createModel(config);

expect(model).toBeDefined();
expect(model.constructor.name).toContain('Anthropic');
expect(model).toHaveProperty('modelId');
});
});

Expand Down Expand Up @@ -874,7 +871,7 @@ describe('ModelFactory', () => {
const config: ModelSettings = { model: modelString };
const model = ModelFactory.createModel(config);
expect(model).toBeDefined();
expect(model.constructor.name).toBe('OpenRouterChatLanguageModel');
expect(model).toHaveProperty('modelId');
}
});

Expand Down Expand Up @@ -984,7 +981,7 @@ describe('ModelFactory', () => {
const gatewayModel = ModelFactory.createModel(gatewayConfig);

expect(openrouterModel).toBeDefined();
expect(openrouterModel.constructor.name).toBe('OpenRouterChatLanguageModel');
expect(openrouterModel).toHaveProperty('modelId');
expect(gatewayModel).toBeDefined();
expect(gatewayModel).toHaveProperty('modelId', baseModel);
}
Expand Down
6 changes: 4 additions & 2 deletions agents-api/src/domains/evals/services/EvaluationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,10 +346,12 @@ export class EvaluationService {
'Generating next user message with simulation agent'
);

const simulationResponse = await generateText({
const simulationConfig = {
...simulationModelConfig,
prompt: simulationPrompt,
});
};

const simulationResponse = await generateText(simulationConfig);

const nextUserMessage = simulationResponse.text.trim();

Expand Down
2 changes: 1 addition & 1 deletion agents-api/src/domains/run/agents/SystemPromptBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { AssembleResult } from '@inkeep/agents-core';
import { getLogger } from '../../../logger';
import type { AssembleResult } from '../utils/token-estimator';
import type { VersionConfig } from './types';

const logger = getLogger('SystemPromptBuilder');
Expand Down
25 changes: 24 additions & 1 deletion agents-api/src/domains/run/agents/agent-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,23 @@ export interface ResolvedGenerationResponse {
output?: any;
object?: any;
formattedContent?: MessageContent | null;
usage?: {
promptTokens?: number;
completionTokens?: number;
inputTokens?: number;
outputTokens?: number;
totalTokens?: number;
};
totalUsage?: {
promptTokens?: number;
completionTokens?: number;
inputTokens?: number;
outputTokens?: number;
totalTokens?: number;
};
response?: {
modelId?: string;
};
}

/**
Expand All @@ -101,13 +118,16 @@ export async function resolveGenerationResponse(
}

try {
const [steps, text, finishReason, output] = await Promise.all([
const [steps, text, finishReason, output, usage, totalUsage, responseObj] = await Promise.all([
Promise.resolve(
stepsValue as PromiseLike<Array<StepResult<ToolSet>>> | Array<StepResult<ToolSet>>
),
Promise.resolve(response.text as PromiseLike<string> | string),
Promise.resolve(response.finishReason as PromiseLike<FinishReason> | FinishReason),
Promise.resolve(response.output),
Promise.resolve(response.usage),
Promise.resolve(response.totalUsage),
Promise.resolve(response.response),
]);

return {
Expand All @@ -116,6 +136,9 @@ export async function resolveGenerationResponse(
text,
finishReason,
output,
usage,
totalUsage,
response: responseObj,
} as ResolvedGenerationResponse;
} catch (error) {
throw new Error(
Expand Down
Loading
Loading