neuron-explorer
Steering-first neuron explorer for Qwen3.5-4B: push every MLP neuron, keep every rollout, browse the results
Modern LLM integration framework for TypeScript
Translation pending
Developer toolsTypeScript · JavaScriptGitHub @svetzalOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Loading the full README. The saved excerpt is shown below.
A modern LLM integration framework for TypeScript with full feature parity across Python, Elixir, and Rust implementations. Perfect for building VS Code extensions, Obsidian plugins, and Node.js applications.Read the full README ↗A modern LLM integration framework for TypeScript with full feature parity across Python, Elixir, and Rust implementations. Perfect for building VS Code extensions, Obsidian plugins, and Node.js applications.
npm install mojentic
# or
yarn add mojentic
# or
pnpm add mojentic
To use Mojentic with local models, you need Ollama installed and running:
ollama pull qwen3:32bollama listimport { LlmBroker, OllamaGateway, Message } from 'mojentic';
import { isOk } from 'mojentic';
const gateway = new OllamaGateway();
const broker = new LlmBroker('qwen3:32b', gateway);
const messages = [Message.user('What is TypeScript?')];
const result = await broker.generate(messages);
if (isOk(result)) {
console.log(result.value);
} else {
console.error(result.error);
}
import { LlmBroker, OllamaGateway, Message } from 'mojentic';
import { isOk } from 'mojentic';
interface SentimentAnalysis {
sentiment: string;
confidence: number;
reasoning: string;
}
const gateway = new OllamaGateway();
const broker = new LlmBroker('qwen3:32b', gateway);
const schema = {
type: 'object',
properties: {
sentiment: { type: 'string', enum: ['positive', 'negative', 'neutral'] },
confidence: { type: 'number', minimum: 0, maximum: 1 },
reasoning: { type: 'string' },
},
required: ['sentiment', 'confidence', 'reasoning'],
};
const messages = [
Message.user('I love this new framework!'),
];
const result = await broker.generateObject<SentimentAnalysis>(messages, schema);
if (isOk(result)) {
console.log(`Sentiment: ${result.value.sentiment}`);
console.log(`Confidence: ${(result.value.confidence * 100).toFixed(1)}%`);
}
import { LlmBroker, OllamaGateway, Message, DateResolverTool } from 'mojentic';
import { isOk } from 'mojentic';
const gateway = new OllamaGateway();
const broker = new LlmBroker('qwen3:32b', gateway);
const tools = [new DateResolverTool()];
const messages = [
Message.system('You are a helpful assistant with access to tools.'),
Message.user('What day of the week is next Friday?'),
];
// The broker automatically handles tool calls
const result = await broker.generate(messages, tools);
if (isOk(result)) {
console.log(result.value);
}
import { LlmBroker, OllamaGateway, Message } from 'mojentic';
import { isOk } from 'mojentic';
const gateway = new OllamaGateway();
const broker = new LlmBroker('qwen3:32b', gateway);
const messages = [Message.user('Write a short poem about TypeScript')];
for await (const chunk of broker.generateStream(messages)) {
if (isOk(chunk)) {
process.stdout.write(chunk.value);
}
}
Monitor and debug your LLM applications:
import { LlmBroker, OllamaGateway, Message, TracerSystem } from 'mojentic';
import { DateResolverTool } from 'mojentic';
import { isOk } from 'mojentic';
// Create a tracer system
const tracer = new TracerSystem();
const gateway = new OllamaGateway();
const broker = new LlmBroker('qwen3:32b', gateway, tracer);
const tools = [new DateResolverTool()];
// Generate unique correlation ID for tracing related events
const correlationId = crypto.randomUUID();
const messages = [
Message.user('What day is next Friday?'),
];
const result = await broker.generate(messages, tools, {}, 10, correlationId);
// Query tracer events
const allEvents = tracer.getEvents();
console.log(`Recorded ${allEvents.length} events`);
// Filter by correlation ID
const relatedEvents = tracer.getEvents({
filterFunc: (e) => e.correlationId === correlationId
});
// Print event summaries
relatedEvents.forEach(event => {
console.log(event.printableSummary());
});
See Tracer Documentation for comprehensive usage guide.
Native tool-turn reasoning history is opt-in on Ollama and oMLX with
{ retainReasoning: true }. Assistant thinking stays separate from visible
content and tool results; selected profiles validate history capability. OpenAI
rejects enabled retention before dispatch. See the reasoning history migration
guide.
Mojentic is structured in three layers:
Implement the LlmTool interface:
import { BaseTool, ToolArgs, ToolDescriptor, ToolResult } from 'mojentic';
import { Ok, Result } from 'mojentic';
export class WeatherTool extends BaseTool {
async run(args: ToolArgs): Promise<Result<ToolResult, Error>> {
const location = args.location as string;
// Fetch weather data...
return Ok({
location,
temperature: 22,
condition: 'sunny',
});
}
descriptor(): ToolDescriptor {
return {
type: 'function',
function: {
name: 'get_weather',
description: 'Get current weather for a location',
parameters: {
type: 'object',
properties: {
location: {
type: 'string',
description: 'City name',
},
},
required: ['location'],
},
},
};
}
}
Mojentic uses a Result type pattern inspired by Rust:
import { Result, Ok, Err, isOk, isErr, unwrap, unwrapOr } from 'mojentic';
const result = await broker.generate(messages);
// Pattern 1: Check and narrow
if (isOk(result)) {
console.log(result.value); // Type: string
} else {
console.error(result.error); // Type: Error
}
// Pattern 2: Unwrap (throws on error)
const value = unwrap(result);
// Pattern 3: Unwrap with default
const value = unwrapOr(result, 'default value');
// Pattern 4: Map and transform
const mapped = mapResult(result, (text) => text.toUpperCase());
import {
MojenticError, // Base error
GatewayError, // API/network errors
ToolError, // Tool execution errors
ValidationError, // Input validation errors
ParseError, // JSON parsing errors
TimeoutError, // Timeout errors
} from 'mojentic';
Main interface for LLM interactions:
class LlmBroker {
constructor(model: string, gateway: LlmGateway);
// Generate text completion
generate(
messages: LlmMessage[],
tools?: LlmTool[],
config?: CompletionConfig,
maxToolIterations?: number
): Promise<Result<string, Error>>;
// Generate structured object
generateObject<T>(
messages: LlmMessage[],
schema: Record<string, unknown>,
config?: CompletionConfig
): Promise<Result<T, Error>>;
// Generate streaming completion
generateStream(
messages: LlmMessage[],
config?: CompletionConfig,
tools?: LlmTool[]
): AsyncGenerator<Result<string, Error>>;
// List available models
listModels(): Promise<Result<string[], Error>>;
// Get current model
getModel(): string;
}
class Message {
static system(content: string): LlmMessage;
static user(content: string): LlmMessage;
static assistant(content: string, toolCalls?: ToolCall[], thinking?: string): LlmMessage;
static tool(content: string, toolCallId: string, name: string): LlmMessage;
}
interface CompletionConfig {
retainReasoning?: boolean;
temperature?: number;
/** Optional output limit; omit to use provider/model limits. */
maxTokens?: number;
topP?: number;
frequencyPenalty?: number;
presencePenalty?: number;
stop?: string[];
stream?: boolean;
responseFormat?: {
type: 'json_object' | 'text';
schema?: Record<string, unknown>;
};
}
Omitted temperature and numCtx leave sampling and Ollama context settings to
the provider/model on all maintained completion routes, including structured
output, streaming and recovery. OpenAI and oMLX never send numCtx. To keep the
former OpenAI/oMLX sampling value, pass { temperature: 1 }; add numCtx: 32768
for an explicit Ollama context size. Explicit zero is preserved where the model
supports it; existing OpenAI model adaptation still applies to caller-set values.
ChatSession keeps its own configured temperature default of 1.
Run any of the 24 included examples:
# Install dependencies
npm install
# Core examples
npm run example:simple # Simple text generation
npm run example:structured # Structured output
npm run example:tool # Tool usage
npm run example:streaming # Streaming responses
# Advanced examples
npm run example:broker # Comprehensive broker features
npm run example:broker-as-tool # Agent delegation pattern
npm run example:tracer # Tracer system demo
npm run example:async-llm # Async agents
npm run example:iterative-solver # Multi-step problem solving
npm run example:recursive-agent # Recursive agent patterns
Mojentic is structured in three layers:
LlmBroker - Main interface for LLM interactionsLlmGateway interface - Abstract interface for LLM providersOllamaGateway / OpenAiGateway / OMLXGateway - Provider implementationsChatSession - Conversational session managementTokenizerGateway - Token counting with tiktokenEmbeddingsGateway - Vector embeddingsTracerSystem - Event recording for observabilityEventStore - Flexible event storage and queryingAsyncDispatcher - Async event processingRouter - Event-to-agent routingAsyncLlmAgent - LLM-powered agentsAsyncAggregatorAgent - Multi-event aggregationIterativeProblemSolver - Multi-step reasoningSimpleRecursiveAgent - Self-recursive processingSharedWorkingMemory - Agent context sharing# Install dependencies
npm install
# Build
npm run build
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Lint (zero warnings enforced)
npm run lint
# Format
npm run format
# Full quality check
npm run quality
Contributions are welcome! This is part of the Mojentic family of implementations:
MIT License - see LICENSE for details
Mojentic is a Mojility product by Stacey Vetzal.