@autifyhq/muon
Version:
Muon - AI-Powered Playwright Test Coding Agent with Advanced Test Fixing Capabilities
155 lines (154 loc) • 5.27 kB
JavaScript
import { MuonAuth } from './auth.js';
import { StreamingMuonAgent, } from './streaming-agent.js';
class MuonQueryImpl {
constructor(agent, generator) {
this.agent = agent;
this.generator = generator;
}
async next() {
return this.generator.next();
}
async return(value) {
return this.generator.return(value);
}
async throw(e) {
return this.generator.throw(e);
}
[Symbol.asyncIterator]() {
return this.generator;
}
abort() {
this.agent.abort();
}
async interrupt() {
this.agent.abort();
}
}
export function muonQuery(prompt, options = {}) {
const apiKey = options.apiKey || process.env.MUON_API_KEY;
const serverUrl = options.serverUrl || process.env.MUON_SERVER_URL || 'http://127.0.0.1:3001';
let accessToken = options.accessToken;
let auth;
// If no API key and no access token provided, try to load from device flow auth
if (!apiKey && !accessToken) {
try {
auth = new MuonAuth(serverUrl);
const tokens = auth.getTokens();
if (tokens) {
accessToken = tokens.accessToken;
}
}
catch (_error) {
// Ignore auth loading errors, we'll handle auth requirement below
}
}
// Require either API key or access token
if (!apiKey && !accessToken) {
throw new Error('Authentication is required to use Muon Agent.\n' +
'Option 1: Run "muon login" to authenticate via OAuth\n' +
'Option 2: Set MUON_API_KEY environment variable or pass apiKey in options.\n' +
`Get your API key from: ${serverUrl}/keys`);
}
const agent = new StreamingMuonAgent({
serverUrl,
apiKey,
accessToken,
auth,
projectPath: options.projectPath || '.',
agentType: options.agentType,
nlstepMode: options.nlstepMode,
...options,
});
const generator = agent.query(prompt);
return new MuonQueryImpl(agent, generator);
}
// Direct nlstep execution function
export async function muonNLStep(request, options = {}) {
const apiKey = options.apiKey || process.env.MUON_API_KEY;
const serverUrl = options.serverUrl || process.env.MUON_SERVER_URL || 'http://127.0.0.1:3001';
let accessToken = options.accessToken;
let auth;
// If no API key and no access token provided, try to load from device flow auth
if (!apiKey && !accessToken) {
try {
auth = new MuonAuth(serverUrl);
const tokens = auth.getTokens();
if (tokens) {
accessToken = tokens.accessToken;
}
}
catch (_error) {
// Ignore auth loading errors, we'll handle auth requirement below
}
}
// Require either API key or access token
if (!apiKey && !accessToken) {
throw new Error('Authentication is required to use Muon NLStep.\n' +
'Option 1: Run "muon login" to authenticate via OAuth\n' +
'Option 2: Set MUON_API_KEY environment variable or pass apiKey in options.\n' +
`Get your API key from: ${serverUrl}/keys`);
}
const agent = new StreamingMuonAgent({
serverUrl,
apiKey,
accessToken,
auth,
projectPath: options.projectPath,
agentType: options.agentType,
});
return agent.executeNLStep(request);
}
// Convenience function for simple usage
export async function muonTask(prompt, options = {}) {
const query = muonQuery(prompt, options);
let lastResult = '';
const iterator = query[Symbol.asyncIterator]();
while (true) {
const result = await iterator.next();
if (result.done) {
// Generator completed - return the last assistant message content
return lastResult;
}
else {
// Process yielded message
const message = result.value;
if (message.type === 'assistant' && message.content) {
lastResult = message.content;
}
}
}
}
// Stream processing utilities
export async function muonStream(prompt, onMessage, options = {}) {
const query = muonQuery(prompt, options);
try {
// Manually iterate to capture the return value
const iterator = query[Symbol.asyncIterator]();
while (true) {
const result = await iterator.next();
if (result.done) {
// Generator completed - result.value contains the MuonResultMessage
return result.value;
}
else {
// Yield message - process it
onMessage(result.value);
}
}
}
catch (error) {
// Handle any errors during iteration
if (error && typeof error === 'object' && 'type' in error && error.type === 'result') {
return error;
}
// Return error result for unexpected errors
return {
type: 'result',
subtype: 'error',
duration_ms: 0,
session_id: '',
error: error instanceof Error ? error.message : String(error),
};
}
}
export { StreamingMuonAgent };