Skip to content
Draft
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
450 changes: 450 additions & 0 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions projects/plugins/jetpack/changelog/try-add-agenttic
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: other

try to add agenttic chat client
8 changes: 8 additions & 0 deletions projects/plugins/jetpack/class.jetpack-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,14 @@
'allowedMimeTypes' => wp_get_mime_types(),
'siteLocale' => str_replace( '_', '-', get_locale() ),
'ai-assistant' => $ai_assistant_state,
'agenttic' => array(

Check warning on line 805 in projects/plugins/jetpack/class.jetpack-gutenberg.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Array double arrow not aligned correctly; expected 5 space(s) between "'agenttic'" and double arrow, but found 9. (WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned)

Check failure on line 805 in projects/plugins/jetpack/class.jetpack-gutenberg.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Array item not aligned correctly; expected 12 spaces but found 16 (WordPress.Arrays.ArrayIndentation.ItemNotAligned)
'agent_id' => apply_filters( 'jetpack_agenttic_agent_id', 'big-sky' ),

Check failure on line 806 in projects/plugins/jetpack/class.jetpack-gutenberg.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Multi-line array item not aligned correctly; expected 16 spaces, but found 20 (WordPress.Arrays.ArrayIndentation.MultiLineArrayItemNotAligned)
'agent_key' => apply_filters( 'jetpack_agenttic_agent_key', 'big-sky' ),
'agent_url' => apply_filters(
'jetpack_agenttic_agent_url',
'https://public-api.wordpress.com/wpcom/v2/ai/agent'
),
),
'screenBase' => $screen_base,
/**
* Add your own feature flags to the block editor.
Expand Down
1 change: 1 addition & 0 deletions projects/plugins/jetpack/extensions/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"ai-assistant",
"ai-chat",
"ai-assistant-plugin",
"agenttic",
"blogging-prompt",
"business-hours",
"button",
Expand Down
42 changes: 42 additions & 0 deletions projects/plugins/jetpack/extensions/plugins/agenttic/agenttic.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
/**
* Block Editor - Agenttic plugin integration.
*
* @package automattic/jetpack
*/

namespace Automattic\Jetpack\Extensions\Agenttic;

use Automattic\Jetpack\Connection\Manager as Connection_Manager;
use Automattic\Jetpack\Status;
use Automattic\Jetpack\Status\Host;

// Feature name.
const FEATURE_NAME = 'agenttic';

/**
* Register the Agenttic sidebar plugin when Jetpack AI features are available.
*/
function register_plugin() {
if (
(
new Host() )->is_wpcom_simple()
|| ( ( new Connection_Manager( 'jetpack' ) )->has_connected_owner() && ! ( new Status() )->is_offline_mode()
)
&& apply_filters( 'jetpack_ai_enabled', true )
) {
\Jetpack_Gutenberg::set_extension_available( FEATURE_NAME );
}
}
add_action( 'jetpack_register_gutenberg_extensions', __NAMESPACE__ . '\\register_plugin' );

// Populate the available extensions with the Agenttic plugin.
add_filter(
'jetpack_set_available_extensions',
function ( $extensions ) {
return array_merge(
(array) $extensions,
array( FEATURE_NAME )
);
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
/**
* External dependencies
*/
import {
createJetpackAuthProvider,
type JetpackApiError,
type UIMessage,
useAgentChat,
} from '@automattic/agenttic-client';

Check failure on line 9 in projects/plugins/jetpack/extensions/plugins/agenttic/components/agenttic-sidebar.tsx

View workflow job for this annotation

GitHub Actions / Type checking

Cannot find module '@automattic/agenttic-client' or its corresponding type declarations.

Check failure on line 9 in projects/plugins/jetpack/extensions/plugins/agenttic/components/agenttic-sidebar.tsx

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

Unable to resolve path to module '@automattic/agenttic-client'
import { AgentUI } from '@automattic/agenttic-ui';

Check failure on line 10 in projects/plugins/jetpack/extensions/plugins/agenttic/components/agenttic-sidebar.tsx

View workflow job for this annotation

GitHub Actions / Type checking

Cannot find module '@automattic/agenttic-ui' or its corresponding type declarations.

Check failure on line 10 in projects/plugins/jetpack/extensions/plugins/agenttic/components/agenttic-sidebar.tsx

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

Unable to resolve path to module '@automattic/agenttic-ui'
import { store as blockEditorStore } from '@wordpress/block-editor';

Check failure on line 11 in projects/plugins/jetpack/extensions/plugins/agenttic/components/agenttic-sidebar.tsx

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

'blockEditorStore' is defined but never used
import { Notice } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import { store as editPostStore } from '@wordpress/edit-post';
import { PluginSidebar, store as editorStore } from '@wordpress/editor';

Check failure on line 15 in projects/plugins/jetpack/extensions/plugins/agenttic/components/agenttic-sidebar.tsx

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

'editorStore' is defined but never used
import { useEffect, useMemo, useRef } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import useApplyBlockEdits from '../hooks/use-apply-block-edits';
import { createToolProvider, createContextProvider } from '../utils/agent-helpers';
import './style.scss';

const SIDEBAR_IDENTIFIER = 'jetpack-agenttic/block-editor-assistant';
const SIDEBAR_DOM_ID = SIDEBAR_IDENTIFIER.replace( /\//g, '-' );
const SIDEBAR_WIDTH = '600px';
const DEFAULT_AGENT_ID = 'big-sky';
const DEFAULT_AGENT_URL = 'https://public-api.wordpress.com/wpcom/v2/ai/agent';

interface AgentticConfig {
agent_id?: string;
agent_key?: string;
agent_url?: string;
}

interface AgentticChatProps {
agentId: string;
agentUrl: string;
}

/**

Check warning on line 42 in projects/plugins/jetpack/extensions/plugins/agenttic/components/agenttic-sidebar.tsx

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

Missing JSDoc @return declaration
* Generate a UUID v4
*/
const generateUUID = (): string => {
// Using crypto.randomUUID if available (modern browsers)
if ( typeof crypto !== 'undefined' && crypto.randomUUID ) {
return crypto.randomUUID();
}

// Fallback to manual UUID v4 generation
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace( /[xy]/g, function ( c ) {
const r = ( Math.random() * 16 ) | 0;

Check failure on line 53 in projects/plugins/jetpack/extensions/plugins/agenttic/components/agenttic-sidebar.tsx

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

Unexpected use of '|'
const v = c === 'x' ? r : ( r & 0x3 ) | 0x8;

Check failure on line 54 in projects/plugins/jetpack/extensions/plugins/agenttic/components/agenttic-sidebar.tsx

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

Unexpected use of '&'

Check failure on line 54 in projects/plugins/jetpack/extensions/plugins/agenttic/components/agenttic-sidebar.tsx

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

Unexpected use of '|'
return v.toString( 16 );
} );
};

const buildWelcomeMessage = (): UIMessage => ( {
id: generateUUID(),
role: 'agent',
content: [
{
type: 'text',
text: __(
'Hi! I can help you edit blocks in your post, create images, or answer questions. How can I assist you today?',
'jetpack'
),
},
],
timestamp: Date.now(),
archived: false,
showIcon: true,
icon: 'assistant',
} );

const AgentticChat = ( { agentId, agentUrl }: AgentticChatProps ) => {
// Get block editing functionality
const { applyBlockEdits } = useApplyBlockEdits();

const authProvider = useMemo(
() =>
createJetpackAuthProvider( ( error: JetpackApiError ) => {
if ( error?.code === 'rest_forbidden' ) {
return __(
'You need the correct permissions to generate images for this site.',
'jetpack'
);
}

return __(
'We could not verify your Jetpack connection. Please refresh and try again.',
'jetpack'
);
} ),
[]
);

const sessionId = useMemo( () => generateUUID(), [] );

// Create tool and context providers using the helper functions
const toolProvider = useMemo( () => createToolProvider( applyBlockEdits ), [ applyBlockEdits ] );
const contextProvider = useMemo( () => createContextProvider(), [] );

const {
messages,
isProcessing,
error,
onSubmit,
suggestions,
clearSuggestions,
messageRenderer,
abortCurrentRequest,
addMessage,
} = useAgentChat( {
agentId,
agentUrl,
sessionId,
authProvider,
enableStreaming: true,
toolProvider,
contextProvider,
} );

const hasSeededGreeting = useRef( false );

useEffect( () => {
if ( hasSeededGreeting.current ) {
return;
}

if ( messages.length > 0 ) {
hasSeededGreeting.current = true;
return;
}

addMessage( buildWelcomeMessage() );
hasSeededGreeting.current = true;
}, [ addMessage, messages ] );

return (
<AgentUI
messages={ messages }
isProcessing={ isProcessing }
error={ error }
onSubmit={ onSubmit }
suggestions={ suggestions }
clearSuggestions={ clearSuggestions }
messageRenderer={ messageRenderer }
onStop={ abortCurrentRequest }
variant="embedded"
placeholder={ __( 'Type a message…', 'jetpack' ) }
/>
);
};

const AgentticSidebar = () => {
const isPostEditor = ( window as any )?.Jetpack_Editor_Initial_State?.screenBase === 'post';

Check failure on line 158 in projects/plugins/jetpack/extensions/plugins/agenttic/components/agenttic-sidebar.tsx

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

Unexpected any. Specify a different type

console.log( '[Agenttic] Sidebar mounting, isPostEditor:', isPostEditor );

Check failure on line 160 in projects/plugins/jetpack/extensions/plugins/agenttic/components/agenttic-sidebar.tsx

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

Unexpected console statement
console.log( '[Agenttic] Window state:', ( window as any )?.Jetpack_Editor_Initial_State );

Check failure on line 161 in projects/plugins/jetpack/extensions/plugins/agenttic/components/agenttic-sidebar.tsx

View workflow job for this annotation

GitHub Actions / ESLint (non-excluded files only)

Unexpected console statement

const { isSidebarActive } = useSelect( select => {
const editPost = select( 'core/edit-post' ) as {
getActiveGeneralSidebarName?: () => string | undefined;
};

return {
isSidebarActive: editPost?.getActiveGeneralSidebarName?.() === SIDEBAR_IDENTIFIER,
};
}, [] );

const { openGeneralSidebar } = useDispatch( editPostStore );

// Auto-open the sidebar when in post editor
useEffect( () => {
if ( ! isPostEditor || typeof openGeneralSidebar !== 'function' ) {
return;
}

// Open the sidebar if not already active
if ( ! isSidebarActive ) {
openGeneralSidebar( SIDEBAR_IDENTIFIER );
}
}, [ isPostEditor, openGeneralSidebar, isSidebarActive ] );

useEffect( () => {
if ( ! isSidebarActive || typeof document === 'undefined' ) {
return;
}

const panel = document.getElementById( SIDEBAR_DOM_ID );

if ( ! panel ) {
return;
}

const pluginFill = panel.closest( '.interface-complementary-area__fill' ) as HTMLElement | null;

if ( ! pluginFill ) {
return;
}

const storedFillStyles = {
width: pluginFill.style.width,
maxWidth: pluginFill.style.maxWidth,
flex: pluginFill.style.flex,
overflow: pluginFill.style.overflow,
};

pluginFill.style.width = SIDEBAR_WIDTH;
pluginFill.style.maxWidth = SIDEBAR_WIDTH;
pluginFill.style.flex = `0 0 ${ SIDEBAR_WIDTH }`;
pluginFill.style.overflow = 'hidden';

return () => {
pluginFill.style.width = storedFillStyles.width;
pluginFill.style.maxWidth = storedFillStyles.maxWidth;
pluginFill.style.flex = storedFillStyles.flex;
pluginFill.style.overflow = storedFillStyles.overflow;
};
}, [ isSidebarActive ] );

// For debugging - temporarily always render
const shouldRender = true; // was: isPostEditor;

console.log( '[Agenttic] Should render:', shouldRender );

if ( ! shouldRender ) {
console.log( '[Agenttic] Not rendering sidebar - shouldRender is false' );
return null;
}

console.log( '[Agenttic] Rendering sidebar...' );

const config = ( ( window as any )?.Jetpack_Editor_Initial_State?.agenttic ??
{} ) as AgentticConfig;
const agentId = config.agent_id ?? config.agent_key ?? DEFAULT_AGENT_ID;
const agentUrl = config.agent_url ?? DEFAULT_AGENT_URL;
const hasAgentConfig = Boolean( agentUrl );

return (
<PluginSidebar
name={ SIDEBAR_IDENTIFIER }
title={ __( 'Block Editor Assistant', 'jetpack' ) }
icon={
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" role="img">
<title>{ __( 'Jetpack AI Spark', 'jetpack' ) }</title>
<path
fill="#3858E9"
d="m19.223 11.55-3.095-1.068a4.21 4.21 0 0 1-2.61-2.61L12.45 4.777c-.145-.426-.755-.426-.9 0l-1.068 3.095a4.21 4.21 0 0 1-2.61 2.61L4.777 11.55c-.426.145-.426.755 0 .9l3.095 1.068a4.21 4.21 0 0 1 2.61 2.61l1.068 3.095c.145.426.755.426.9 0l1.068-3.095a4.21 4.21 0 0 1 2.61-2.61l3.095-1.068c.426-.145.426-.755 0-.9Zm-3.613.68-1.547.533a2.105 2.105 0 0 0-1.306 1.305l-.533 1.548a.24.24 0 0 1-.453 0l-.534-1.548a2.105 2.105 0 0 0-1.305-1.305l-1.548-.534a.24.24 0 0 1 0-.453l1.548-.534a2.105 2.105 0 0 0 1.305-1.305l.534-1.547a.24.24 0 0 1 .453 0l.534 1.547c.21.615.695 1.095 1.305 1.305l1.547.534a.24.24 0 0 1 0 .453Z"
/>
</svg>
}
className="jetpack-agenttic-sidebar"
>
<div className="jetpack-agenttic-sidebar__content">
{ ! hasAgentConfig && (
<Notice status="warning" isDismissible={ false }>
{ __(
'Block editing assistant is not available on this site right now. Check your Jetpack connection and try again.',
'jetpack'
) }
</Notice>
) }

{ hasAgentConfig && (
<div className="jetpack-agenttic-sidebar__chat">
<AgentticChat agentId={ agentId } agentUrl={ agentUrl } />
</div>
) }
</div>
</PluginSidebar>
);
};

export default AgentticSidebar;
Loading
Loading