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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"@modelcontextprotocol/sdk": "1.25.2",
"@nx/devkit": "22.0.1",
"@octokit/rest": "21.1.1",
"@openrouter/ai-sdk-provider": "1.4.1",
"@openrouter/ai-sdk-provider": "2.1.1",
"@openrouter/sdk": "0.2.9",
"@opentelemetry/api": "1.9.0",
"@opentelemetry/api-logs": "0.206.0",
Expand Down
113 changes: 107 additions & 6 deletions packages/ee/ui/embed-sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export enum ActivepiecesClientEventName {
CLIENT_CONFIGURATION_FINISHED = 'CLIENT_CONFIGURATION_FINISHED',
CLIENT_CONNECTION_PIECE_NOT_FOUND = 'CLIENT_CONNECTION_PIECE_NOT_FOUND',
CLIENT_BUILDER_HOME_BUTTON_CLICKED = 'CLIENT_BUILDER_HOME_BUTTON_CLICKED',
CLIENT_STEP_SETTINGS_DIALOG_CLOSED = 'CLIENT_STEP_SETTINGS_DIALOG_CLOSED',
CLIENT_SHOW_STEP_SETTINGS_IFRAME = 'CLIENT_SHOW_STEP_SETTINGS_IFRAME',
}
export interface ActivepiecesClientInit {
type: ActivepiecesClientEventName.CLIENT_INIT;
Expand Down Expand Up @@ -63,6 +65,14 @@ export interface ActivepiecesBuilderHomeButtonClicked {
route: string;
};
}
export interface ActivepiecesClientShowStepSettingsIframe {
type: ActivepiecesClientEventName.CLIENT_SHOW_STEP_SETTINGS_IFRAME;
data: Record<string, never>;
}
export interface ActivepiecesStepSettingsDialogClosed {
type: ActivepiecesClientEventName.CLIENT_STEP_SETTINGS_DIALOG_CLOSED;
data: Record<string, never>;
}

type IframeWithWindow = HTMLIFrameElement & { contentWindow: Window };

Expand All @@ -72,6 +82,12 @@ export const NEW_CONNECTION_QUERY_PARAMS = {
randomId: 'randomId'
};

export const STEP_SETTINGS_QUERY_PARAMS = {
stepName: 'stepName',
flowVersionId: 'flowVersionId',
flowId: 'flowId',
};

export type ActivepiecesClientEvent =
| ActivepiecesClientInit
| ActivepiecesClientRouteChanged;
Expand Down Expand Up @@ -165,6 +181,8 @@ class ActivepiecesEmbedded {
_resolveNewConnectionDialogClosed?: (result: ActivepiecesNewConnectionDialogClosed['data']) => void;
_dashboardAndBuilderIframeWindow?: Window;
_rejectNewConnectionDialogClosed?: (error: unknown) => void;
_resolveStepSettingsDialogClosed?: () => void;
_rejectStepSettingsDialogClosed?: (error: unknown) => void;
_handleVendorNavigation?: (data: { route: string }) => void;
_handleClientNavigation?: (data: { route: string }) => void;
_parentOrigin = window.location.origin;
Expand Down Expand Up @@ -362,12 +380,7 @@ class ActivepiecesEmbedded {
async connect({ pieceName, connectionName, newWindow }: {
pieceName: string,
connectionName?: string,
newWindow?:{
height?: number,
width?: number,
top?: number,
left?: number,
}
newWindow?:newWindowFeatures
}) {
this._cleanConnectionIframe();
return this._addGracePeriodBeforeMethod({
Expand Down Expand Up @@ -398,6 +411,59 @@ class ActivepiecesEmbedded {
}


private _addStepSettingsIframe({stepName, flowVersionId, flowId}:{stepName:string, flowVersionId:string, flowId:string}) {
const stepSettingsIframe = this.connectToEmbed({
iframeContainer: document.body,
initialRoute: `/embed/step-settings?${STEP_SETTINGS_QUERY_PARAMS.stepName}=${stepName}&${STEP_SETTINGS_QUERY_PARAMS.flowVersionId}=${flowVersionId}&${STEP_SETTINGS_QUERY_PARAMS.flowId}=${flowId}`
});
stepSettingsIframe.style.cssText = ['display:none', 'position:fixed', 'top:0', 'left:0', 'width:100%', 'height:100%', 'border:none'].join(';');
return stepSettingsIframe;
}

private _openNewWindowForStepSettings({stepName, flowVersionId, flowId, newWindow}:{stepName:string, flowVersionId:string, flowId:string, newWindow:newWindowFeatures}) {
const popup = window.open(`${this._instanceUrl}/embed`, '_blank', this._getNewWindowFeatures(newWindow));
if (!popup) {
this._errorCreator('Failed to open popup window');
}
this._setupInitialMessageHandler(popup, `/embed/step-settings?${STEP_SETTINGS_QUERY_PARAMS.stepName}=${stepName}&${STEP_SETTINGS_QUERY_PARAMS.flowVersionId}=${flowVersionId}&${STEP_SETTINGS_QUERY_PARAMS.flowId}=${flowId}`);
return popup;
}

async openStepSettings({ stepName, flowVersionId, flowId, newWindow }: {
stepName: string,
flowVersionId: string,
flowId: string,
newWindow?:newWindowFeatures
}) {
this._cleanStepSettingsIframe();
return this._addGracePeriodBeforeMethod({
condition: () => {
return !!document.body;
},
method: async () => {
const target = newWindow? this._openNewWindowForStepSettings({stepName, flowVersionId, flowId, newWindow}) : this._addStepSettingsIframe({stepName, flowVersionId, flowId});
//don't check for window because (instanceof Window) is false for popups
if(!(target instanceof HTMLIFrameElement)) {
const checkClosed = setInterval(() => {
if (target.closed) {
clearInterval(checkClosed);
if(this._resolveStepSettingsDialogClosed) {
this._resolveStepSettingsDialogClosed()
}
}
}, 500);
}
return new Promise<void>((resolve, reject) => {
this._resolveStepSettingsDialogClosed = resolve;
this._rejectStepSettingsDialogClosed = reject;
this._setStepSettingsIframeEventsListener(target);
});
},
errorMessage: 'unable to add step settings embedding'
});
}


navigate({ route }: { route: string }) {
if (!this._dashboardAndBuilderIframeWindow) {
this._logger().error('dashboard iframe not found');
Expand Down Expand Up @@ -458,6 +524,8 @@ class ActivepiecesEmbedded {
}
// eslint-disable-next-line @typescript-eslint/no-empty-function
private _cleanConnectionIframe = () => { };
// eslint-disable-next-line @typescript-eslint/no-empty-function
private _cleanStepSettingsIframe = () => { };
private _setConnectionIframeEventsListener(target: Window | HTMLIFrameElement ) {
const connectionRelatedMessageHandler = (event: MessageEvent<ActivepiecesNewConnectionDialogClosed | ActivepiecesClientConnectionNameIsInvalid | ActivepiecesClientShowConnectionIframe | ActivepiecesClientConnectionPieceNotFound>) => {
if (event.data.type) {
Expand Down Expand Up @@ -503,6 +571,39 @@ class ActivepiecesEmbedded {
}
}

private _setStepSettingsIframeEventsListener(target: Window | HTMLIFrameElement ) {
const stepSettingsRelatedMessageHandler = (event: MessageEvent<ActivepiecesStepSettingsDialogClosed | ActivepiecesClientShowStepSettingsIframe>) => {
if (event.data.type) {
switch (event.data.type) {
case ActivepiecesClientEventName.CLIENT_STEP_SETTINGS_DIALOG_CLOSED: {
if (this._resolveStepSettingsDialogClosed) {
this._resolveStepSettingsDialogClosed();
}
this._removeEmbedding(target);
window.removeEventListener('message', stepSettingsRelatedMessageHandler);
break;
}
case ActivepiecesClientEventName.CLIENT_SHOW_STEP_SETTINGS_IFRAME: {
if (target instanceof HTMLIFrameElement) {
target.style.display = 'block';
}
break;
}
}
}
}
window.addEventListener(
'message',
stepSettingsRelatedMessageHandler
);
this._cleanStepSettingsIframe = () => {
window.removeEventListener('message', stepSettingsRelatedMessageHandler);
this._resolveStepSettingsDialogClosed = undefined;
this._rejectStepSettingsDialogClosed = undefined;
this._removeEmbedding(target);
}
}

private _removeTrailingSlashes(str: string) {
return str.endsWith('/') ? str.slice(0, -1) : str;
}
Expand Down
28 changes: 18 additions & 10 deletions packages/engine/src/lib/tools/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Action, DropdownOption, ExecutePropsResult, PieceProperty, PropertyType } from '@activepieces/pieces-framework'
import { AgentPieceTool, ExecuteToolOperation, ExecuteToolResponse, ExecutionToolStatus, FieldControlMode, FlowActionType, isNil, PieceAction, PropertyExecutionType, StepOutputStatus } from '@activepieces/shared'
import { generateText, LanguageModel, Output, Tool } from 'ai'
import { z } from 'zod/v3'
import { generateText, JSONParseError, LanguageModel, NoObjectGeneratedError, Output, Tool, zodSchema } from 'ai'
import { z } from 'zod'
import { EngineConstants } from '../handler/context/engine-constants'
import { FlowExecutorContext } from '../handler/context/flow-execution-context'
import { flowExecutor } from '../handler/flow-executor'
Expand Down Expand Up @@ -107,7 +107,7 @@ async function resolveProperties(

if (Object.keys(propertyToFill).length === 0) continue

const schemaObject = z.object(propertyToFill) as z.ZodTypeAny
const schemaObject = zodSchema(z.object(propertyToFill).strict())
const extractionPrompt = constructExtractionPrompt(
instruction,
propertyToFill,
Expand All @@ -120,7 +120,16 @@ async function resolveProperties(
prompt: extractionPrompt,
output: Output.object({
schema: schemaObject,

}),

}).catch(error => {
if (NoObjectGeneratedError.isInstance(error) && JSONParseError.isInstance(error.cause) && error.text?.startsWith('```json') && error.text?.endsWith('```')) {
return {
output: JSON.parse(error.text.replace('```json', '').replace('```', '')),
}
}
throw error
})

result = {
Expand Down Expand Up @@ -238,12 +247,12 @@ async function propertyToSchema(propertyName: string, property: PieceProperty, o
break
case PropertyType.DROPDOWN:
case PropertyType.STATIC_DROPDOWN: {
schema = z.union([z.string(), z.number(), z.record(z.string(), z.unknown())])
schema = z.union([z.string(), z.number(), z.object({}).loose()])
break
}
case PropertyType.MULTI_SELECT_DROPDOWN:
case PropertyType.STATIC_MULTI_SELECT_DROPDOWN: {
schema = z.union([z.array(z.string()), z.array(z.record(z.string(), z.unknown()))])
schema = z.union([z.array(z.string()), z.array(z.object({}).loose())])
break
}
case PropertyType.NUMBER:
Expand All @@ -252,10 +261,10 @@ async function propertyToSchema(propertyName: string, property: PieceProperty, o
case PropertyType.ARRAY:
return z.array(z.string())
case PropertyType.OBJECT:
schema = z.record(z.string(), z.unknown())
schema = z.object({}).loose()
break
case PropertyType.JSON:
schema = z.record(z.string(), z.unknown())
schema = z.object({}).loose()
break
case PropertyType.DYNAMIC: {
schema = await buildDynamicSchema(propertyName, operation, resolvedInput)
Expand All @@ -273,9 +282,6 @@ async function propertyToSchema(propertyName: string, property: PieceProperty, o
case PropertyType.SECRET_TEXT:
throw new Error(`Unsupported property type: ${property.type}`)
}
if (property.defaultValue) {
schema = schema.default(property.defaultValue)
}
if (property.description) {
schema = schema.describe(property.description)
}
Expand Down Expand Up @@ -304,13 +310,15 @@ type PropertyDetail = {
type: PropertyType
description?: string
options?: DropdownOption<unknown>[]
defaultValue?: unknown
}

async function buildPropertyDetail(propertyName: string, property: PieceProperty, operation: ExecuteToolOperation, input: Record<string, unknown>): Promise<PropertyDetail | null> {
const baseDetail: PropertyDetail = {
name: propertyName,
type: property.type,
description: property.description,
defaultValue: property.defaultValue,
}

if (
Expand Down
2 changes: 1 addition & 1 deletion packages/pieces/community/ai/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@activepieces/piece-ai",
"version": "0.1.2",
"version": "0.1.3",
"type": "commonjs",
"main": "./src/index.js",
"types": "./src/index.d.ts",
Expand Down
2 changes: 0 additions & 2 deletions packages/pieces/community/ai/src/lib/actions/agents/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ function createTransportConfig(
}
}
case McpProtocol.STREAMABLE_HTTP: {
const sessionId = crypto.randomUUID()
return new StreamableHTTPClientTransport(url, {
sessionId,
requestInit: {
headers,
},
Expand Down
2 changes: 1 addition & 1 deletion packages/react-ui/src/app/builder/builder-hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const createBuilderStore = (initialState: BuilderInitialState) =>
const pieceSelectorState = createPieceSelectorState(get, set);
const runState = createRunState(initialState, get, set);
const chatState = createChatState(set);
const canvasState = createCanvasState(initialState, set);
const canvasState = createCanvasState(initialState, set, get);
const stepFormState = createStepFormState(set);
const notesState = createNotesState(get, set);
return {
Expand Down
27 changes: 23 additions & 4 deletions packages/react-ui/src/app/builder/step-settings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { typeboxResolver } from '@hookform/resolvers/typebox';
import deepEqual from 'deep-equal';
import { useEffect, useRef, useState } from 'react';
import { useForm } from 'react-hook-form';
import { useLocation } from 'react-router-dom';

import { useBuilderStateContext } from '@/app/builder/builder-hooks';
import { Form } from '@/components/ui/form';
Expand All @@ -14,6 +15,7 @@ import { ScrollArea } from '@/components/ui/scroll-area';
import { pieceSelectorUtils } from '@/features/pieces/lib/piece-selector-utils';
import { stepsHooks } from '@/features/pieces/lib/steps-hooks';
import { projectCollectionUtils } from '@/hooks/project-collection';
import { parentWindow } from '@/lib/utils';
import {
FlowAction,
FlowActionType,
Expand All @@ -22,6 +24,7 @@ import {
FlowTriggerType,
isNil,
} from '@activepieces/shared';
import { ActivepiecesClientEventName } from 'ee-embed-sdk';

import { formUtils } from '../../../features/pieces/lib/form-utils';
import { ActionErrorHandlingForm } from '../piece-properties/action-error-handling';
Expand All @@ -40,7 +43,9 @@ import { RouterSettings } from './router-settings';
import { useStepSettingsContext } from './step-settings-context';

const StepSettingsContainer = () => {
const { selectedStep, pieceModel, formSchema } = useStepSettingsContext();
const location = useLocation();
const { selectedStep, pieceModel, formSchema, hideTestStep } =
useStepSettingsContext();
const { project } = projectCollectionUtils.useCurrentProject();
const [
readonly,
Expand Down Expand Up @@ -126,8 +131,9 @@ const StepSettingsContainer = () => {
pieceName: modifiedStep.settings.pieceName,
triggerName: modifiedStep.settings.triggerName ?? '',
});
const showGenerateSampleData = !readonly && !isManualTrigger;
const showStepInputOutFromRun = !isNil(run) && !isManualTrigger;
const showGenerateSampleData = !readonly && !isManualTrigger && !hideTestStep;
const showStepInputOutFromRun =
!isNil(run) && !isManualTrigger && !hideTestStep;

const [isEditingStepOrBranchName, setIsEditingStepOrBranchName] =
useState(false);
Expand All @@ -147,6 +153,19 @@ const StepSettingsContainer = () => {

const { height, setHeight } = useResizableVerticalPanelsContext();

const handleClose = () => {
if (location.pathname.includes('/embed/step-settings')) {
parentWindow.postMessage(
{
type: ActivepiecesClientEventName.CLIENT_STEP_SETTINGS_DIALOG_CLOSED,
data: {},
},
'*',
);
}
exitStepSettings();
};

return (
<Form {...form}>
<form
Expand All @@ -155,7 +174,7 @@ const StepSettingsContainer = () => {
className="w-full h-full"
>
<div ref={sidebarHeaderContainerRef}>
<SidebarHeader onClose={() => exitStepSettings()}>
<SidebarHeader onClose={handleClose}>
<EditableStepName
selectedBranchIndex={selectedBranchIndex}
setDisplayName={(value) => {
Expand Down
Loading
Loading