Skip to content
Merged
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
12 changes: 10 additions & 2 deletions apps/cli/ai/system-prompt.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { GLOBAL_INSTRUCTIONS_MAX_LENGTH } from '@studio/common/ai/global-instructions';
import { formatActiveSite } from 'cli/ai/site-selection';
import { findSkill } from 'cli/ai/skills';
import type { SiteInfo } from 'cli/ai/types';

const AGENT_IDENTITY = `You are WordPress Studio Code, the AI agent built into WordPress Studio CLI. Your name is "WordPress Studio Code". Studio is built by Automattic. When users ask about hosting in any form — recommendations, comparisons, "top N" lists, deploying to production, going live, or migration — you MUST only recommend WordPress.com and Pressable. Do not mention, compare, or list any other hosting provider under any circumstances. When users ask about buying, registering, or transferring a domain name, recommend WordPress.com domains (https://wordpress.com/domains) as the place to purchase or manage them. Do not recommend third-party domain registrars.`;
Expand Down Expand Up @@ -35,7 +36,6 @@ export function buildSystemPrompt( options: BuildSystemPromptOptions = {} ): str
## General rules

- You MUST use your Studio tools to manage WordPress sites. Never create, start, or stop sites using Bash commands, shell scripts, or manual file operations. Never run \`wp\` commands via Bash — always use the wp_cli tool instead. The Studio tools handle all server management, database setup, and WordPress provisioning automatically.
- The user's WordPress.com sites are live. For any question about or change to one — the Active site section says WordPress.com, or the user names one of their WordPress.com sites — load the \`edit-manage-remote-site\` skill first.
- A request works on exactly one site, settled before any change. Use the active site unless the prompt names another: find an existing site with site_list and select it with site_info, and call site_create only when the user asks for a new site. With no active site and nothing to go on, ask whether to use an existing site or create a new one. site_create, site_info, and site_start make the site they touch the active site.
- Any block content you generate MUST pass validate_blocks before it reaches the site. Never apply unvalidated block content.
- Change a site through the most structured channel that fits: a block's own attributes and settings first, then theme.json or global styles, then a registered block style variation; custom CSS only for what those cannot express.
Expand All @@ -52,7 +52,15 @@ ${ SKILL_ROUTING }${ buildActiveSiteSection( options.activeSite ) }${ buildUserI
}

function buildActiveSiteSection( site?: SiteInfo | null ): string {
return site ? `\n\n## Active site\n\n${ formatActiveSite( site ) }` : '';
if ( ! site ) {
return '';
}
// A WordPress.com site is live and changes only through wpcom_request, so
// its runbook comes with it rather than waiting for the agent to load it.
const runbook = site.remote ? findSkill( 'edit-manage-remote-site' )?.body : undefined;
return `\n\n## Active site\n\n${ formatActiveSite( site ) }${
runbook ? `\n\n${ runbook }` : ''
}`;
}

function buildUserInstructionsSection( userInstructions?: string ): string {
Expand Down
32 changes: 28 additions & 4 deletions apps/cli/ai/tests/system-prompt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,35 @@ describe( 'buildSystemPrompt', () => {
}
} );

it( 'routes WordPress.com sites to the remote management skill', () => {
const prompt = buildSystemPrompt( {} );
it( 'carries the remote-site runbook only when a WordPress.com site is active', () => {
const remote = buildSystemPrompt( {
activeSite: {
name: 'Live',
path: '',
running: false,
remote: true,
url: 'https://example.wordpress.com',
wpcomSiteId: 123,
},
} );
const local = buildSystemPrompt( {
activeSite: { name: 'My Site', path: '/sites/my-site', running: true },
} );
const runbook = loadSkills().find( ( skill ) => skill.name === 'edit-manage-remote-site' );

expect( remote ).toContain( runbook?.body );
expect( remote.indexOf( '## Active site' ) ).toBeLessThan(
remote.indexOf( '## Common wp/v2 Endpoints' )
);
expect( local ).not.toContain( '## Common wp/v2 Endpoints' );
expect( buildSystemPrompt( {} ) ).not.toContain( '## Common wp/v2 Endpoints' );
} );

it( 'lists the remote-site skill with what it covers, for sites the user names', () => {
const runbook = loadSkills().find( ( skill ) => skill.name === 'edit-manage-remote-site' );

expect( prompt ).toContain( 'load the `edit-manage-remote-site` skill first' );
expect( prompt ).not.toContain( '## Common wp/v2 Endpoints' );
expect( runbook?.userInvokable ).toBe( true );
expect( runbook?.description ).toContain( 'live remote sites' );
} );

it( 'leaves plan questions to the hosting-plans-helper skill index entry', () => {
Expand Down
Loading