Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@
/CLAUDE.md
.takumi/todos
/tmp
/plugins/*/node_modules
/plugins/*/dist
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@
"@openai/agents-extensions": "^0.0.16",
"@openrouter/ai-sdk-provider": "^0.7.5",
"@sinclair/typebox": "^0.34.38",
"@stagewise/agent-interface": "^0.2.3",
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"@types/bun": "^1.2.21",
"@types/debug": "^4.1.12",
Expand Down
21 changes: 21 additions & 0 deletions plugins/plugin-stagewise/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "@neovate/plugin-stagewise",
"version": "0.0.1",
"description": "Stagewise plugin for neovate",
"type": "module",
"main": "dist/index.mjs",
"types": "dist/index.d.ts",
"source": "src/index.ts",
"scripts": {
"build": "bun build src/index.ts --minify --external @neovate/code --outfile dist/index.mjs --target=node",
"dev": "bun build src/index.ts --watch --external @neovate/code --outfile dist/index.mjs --target=node"
},
"devDependencies": {
"@stagewise/agent-interface": "^0.2.3",
"@neovate/code": "workspace:*"
},
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "[email protected]"
}
75 changes: 44 additions & 31 deletions src/plugins/stagewise.ts → plugins/plugin-stagewise/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
// @ts-nocheck
import { type Context, type Plugin, _Project as Project } from '@neovate/code';
import {
type AgentServer,
AgentStateType,
createAgentServer,
} from '@stagewise/agent-interface/agent';
import createDebug from 'debug';
import { Context } from '../context';
import { type Plugin } from '../plugin';
import { Service } from '../service';
import { relativeToHome } from '../utils/path';
import os from 'os';

const debug = createDebug('neovate:plugins:stagewise');

type CreateStagewisePluginOpts = {};

export const createStagewisePlugin = (opts: CreateStagewisePluginOpts) => {
export const createStagewisePlugin = () => {
let sw: StagewiseAgent | null = null;

return {
name: 'stagewise',
async cliStart() {

async initialized(this: Context) {
try {
sw = new StagewiseAgent({
context: this,
Expand All @@ -29,10 +26,12 @@ export const createStagewisePlugin = (opts: CreateStagewisePluginOpts) => {
debug('Failed to start Stagewise agent:', error);
}
},

async destroy() {
await sw?.stop();
},
async status() {

async status(this: Context) {
const port = sw?.port;
const status = port ? `Connected, port: ${port}` : 'Disconnected';
return {
Expand All @@ -50,21 +49,15 @@ export interface StagewiseAgentOpts {

export class StagewiseAgent {
private context: Context;
private service?: Service;
private server: AgentServer | null = null;
private activeProjects: Map<string, Project> = new Map();
public port: number = 0;

constructor(opts: StagewiseAgentOpts) {
this.context = opts.context;
}

async start() {
// Create a separate service for Stagewise with independent chat history
this.service = await Service.create({
agentType: 'code',
context: this.context,
});

this.server = await createAgentServer();

this.server.setAgentName(`${this.context.productName} AI Agent`);
Expand All @@ -88,6 +81,17 @@ export class StagewiseAgent {
await this.server.wss.close();
await this.server.server.close();
}
this.activeProjects.clear();
}

private getOrCreateProject(connectionId: string): Project {
if (!this.activeProjects.has(connectionId)) {
const project = new Project({
context: this.context,
});
this.activeProjects.set(connectionId, project);
}
return this.activeProjects.get(connectionId)!;
}

private async processUserMessage(message: any) {
Expand Down Expand Up @@ -116,13 +120,12 @@ export class StagewiseAgent {
debug('Processing user message:', userText);

const { metadata } = message;
const connectionId = message.connectionId || 'default';

// Build enhanced content with selected elements context
let enhancedContent = userText;

enhancedContent += `\n\nIMPORTANT: don't need to run test or build to check if the code is working, speed is more important.`;

// Add current page context
if (metadata.currentUrl) {
enhancedContent += `\n\nCurrent page context:`;
enhancedContent += `\n- URL: ${metadata.currentUrl}`;
Expand All @@ -131,7 +134,6 @@ export class StagewiseAgent {
}
}

// Add selected elements context
if (metadata.selectedElements && metadata.selectedElements.length > 0) {
enhancedContent += `\n\nSelected elements context (${metadata.selectedElements.length} element(s)):`;

Expand All @@ -154,7 +156,6 @@ export class StagewiseAgent {
if (val && val.value && val.value._debugSource) {
enhancedContent += `\n- ${property} value debug source: ${val.value._debugSource}`;
}
// Add other useful properties
if (val && typeof val === 'string' && val.length < 100) {
enhancedContent += `\n- ${property}: ${val}`;
}
Expand All @@ -168,18 +169,26 @@ export class StagewiseAgent {
'Generating response...',
);

const { query } = await import('../query');
const { isReasoningModel } = await import('../provider');

const result = await query({
input: [{ role: 'user', content: enhancedContent }],
service: this.service!,
thinking: isReasoningModel(this.service!.context.config.model),
const project = this.getOrCreateProject(connectionId);

const result = await project.send(enhancedContent, {
onToolApprove: () => Promise.resolve(true),
onTextDelta: async (text: string) => {
this.server!.interface.messaging.set([
{
type: 'text',
text,
},
]);
},
});

let response =
result.finalText ||
"I processed your request but didn't generate a text response.";
let response: string;
if (result.success) {
response = result.data.text || 'I processed your request successfully.';
} else {
response = `I encountered an error: ${result.error.message}`;
}

this.server!.interface.messaging.set([
{
Expand Down Expand Up @@ -210,3 +219,7 @@ export class StagewiseAgent {
}
}
}

export function relativeToHome(p: string) {
return p.replace(os.homedir(), '~');
}
12 changes: 9 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ packages:
- browser
- vscode-extension
- examples/*
- plugins/*

patchedDependencies:
'@openai/agents-core': patches/@openai__agents-core.patch
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export { createTool } from './tool';
export { z as _zod } from 'zod';
export { ConfigManager as _ConfigManager } from './config';
export { query as _query } from './query';
export { Project as _Project } from './project';

export type { Plugin, Context };

Expand Down
Loading