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
21 changes: 13 additions & 8 deletions packages/pieces/community/ai/src/lib/actions/agents/run-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import {
AgentTool,
TASK_COMPLETION_TOOL_NAME,
AIProviderName,
AgentProviderModel,
} from '@activepieces/shared';
import { hasToolCall, stepCountIs, streamText } from 'ai';
import { agentOutputBuilder } from './agent-output-builder';
import { createAIModel } from '../../common/ai-sdk';
import { aiProps } from '../../common/props';
import { inspect } from 'util';
import { agentUtils } from './utils';
import { constructAgentTools } from './tools';
Expand Down Expand Up @@ -68,8 +68,10 @@ export const runAgent = createAction({
description: 'Describe what you want the assistant to do.',
required: true,
}),
[AgentPieceProps.AI_PROVIDER]: aiProps({ modelType: 'text' }).provider,
[AgentPieceProps.AI_MODEL]: aiProps({ modelType: 'text' }).model,
[AgentPieceProps.AI_PROVIDER_MODEL]: Property.Object({
displayName: 'AI Model',
required: true,
}),
[AgentPieceProps.AGENT_TOOLS]: Property.Array({
displayName: 'Agent Tools',
required: false,
Expand Down Expand Up @@ -102,10 +104,12 @@ export const runAgent = createAction({
}),
},
async run(context) {
const { prompt, maxSteps, model: modelId, provider } = context.propsValue;
const { prompt, maxSteps, aiProviderModel } = context.propsValue;
const agentProviderModel = aiProviderModel as AgentProviderModel

const model = await createAIModel({
modelId,
provider: provider as AIProviderName,
modelId: agentProviderModel.model,
provider: agentProviderModel.provider as AIProviderName,
engineToken: context.server.token,
apiUrl: context.server.apiUrl,
projectId: context.project.id,
Expand Down Expand Up @@ -199,12 +203,13 @@ export const runAgent = createAction({
}
}

const { status } = outputBuilder.build();
if (errors.length > 0 || status === AgentTaskStatus.IN_PROGRESS) {
if (errors.length > 0) {
const errorSummary = errors.map(e => `${e.type}: ${e.message}`).join('\n');
outputBuilder.addMarkdown(`\n\n**Errors encountered:**\n${errorSummary}`);
outputBuilder.fail({ message: 'Agent completed with errors' });
await context.output.update({ data: outputBuilder.build() });
} else {
outputBuilder.setStatus(AgentTaskStatus.COMPLETED)
}

} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const agentUtils = {
**Core Objective**:
- Help the user achieve their goal as quickly, accurately, and thoroughly as possible.
- Always prioritize user satisfaction by providing clear, concise, and relevant responses.
- Always make sure when u are asked a direct simple question you replay to it in simple clear and consize text response.

**Reasoning and Thinking Guidelines**:
- Think step-by-step before taking any action. Use chain-of-thought reasoning: First, understand the user's query fully. Then, break it down into sub-tasks. Evaluate what information or actions are needed. Finally, decide on the next steps.
Expand Down
58 changes: 2 additions & 56 deletions packages/pieces/community/ai/src/lib/common/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,61 +7,13 @@ import {
AIProviderWithoutSensitiveData,
} from '@activepieces/shared';

type Provider =
| 'activepieces'
| 'openai'
| 'anthropic'
| 'google'
| 'openrouter'
| 'cloudflare-gateway'
| 'custom'
| 'azure';

type AIModelType = 'text' | 'image';

type AIPropsParams<T extends AIModelType> = {
modelType: T;
allowedProviders?: AIProviderName[];
};

const RESTRICTED_PROVIDER_MODELS: Partial<Record<Provider, string[]>> = {
openai: [
'gpt-5.2',
'gpt-5.1',
'gpt-5-mini',
],
anthropic: [
'claude-sonnet-4-5-20250929',
'claude-opus-4-5-20251101',
'claude-haiku-4-5-20251001',
],
google: [
'gemini-3-pro-preview',
'gemini-3-flash-preview',
'gemini-2.5-flash-preview-09-2025',
'gemini-2.5-flash-lite-preview-09-2025',
],
};

function getAllowedModelsForProvider(
provider: Provider,
allModels: AIProviderModel[],
modelType: AIModelType
): AIProviderModel[] {
const restrictedModels = RESTRICTED_PROVIDER_MODELS[provider];

return allModels
.filter(model => model.type === modelType)
.filter(model => {
if (isNil(restrictedModels)) {
return true;
}

return restrictedModels.includes(model.id);
})
.sort((a, b) => a.name.localeCompare(b.name));
}

export const aiProps = <T extends AIModelType>({
modelType,
allowedProviders,
Expand Down Expand Up @@ -104,7 +56,7 @@ export const aiProps = <T extends AIModelType>({
required: true,
refreshers: ['provider'],
options: async (propsValue, ctx) => {
const provider = propsValue['provider'] as Provider | undefined;
const provider = propsValue['provider'] as string

if (isNil(provider)) {
return {
Expand All @@ -123,16 +75,10 @@ export const aiProps = <T extends AIModelType>({
},
});

const models = getAllowedModelsForProvider(
provider,
allModels,
modelType
);

return {
placeholder: 'Select AI Model',
disabled: false,
options: models.map(model => ({
options: allModels.filter(model => model.type === modelType).map(model => ({
label: model.name,
value: model.id,
})),
Expand Down
2 changes: 1 addition & 1 deletion packages/pieces/community/http/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@activepieces/piece-http",
"version": "0.10.0",
"version": "0.11.0",
"dependencies": {
"https-proxy-agent": "7.0.4"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,7 @@ export const httpSendRequestAction = createAction({
{ label: 'Do not continue (stop the flow)', value: 'continue_none' },
],
},
}),
stopFlow: Property.Checkbox({
displayName: 'Stop the flow on Failure ?',
required: false,
}),
})
},
errorHandlingOptions: {
continueOnFailure: { hide: true, defaultValue: false },
Expand All @@ -277,7 +273,6 @@ export const httpSendRequestAction = createAction({
use_proxy,
authType,
authFields,
stopFlow,
} = context.propsValue;

assertNotNullOrUndefined(method, 'Method');
Expand Down Expand Up @@ -381,10 +376,6 @@ export const httpSendRequestAction = createAction({
} catch (error) {
attempts++;

if (stopFlow) {
throw error;
}

switch (failureMode) {
case 'retry_all': {
if (attempts < 3) continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { useFormContext } from 'react-hook-form';
import { AgentTools } from '@/app/builder/step-settings/agent-settings/agent-tools';
import { FormField } from '@/components/ui/form';
import { Skeleton } from '@/components/ui/skeleton';
import { AIModelSelector } from '@/features/agents/ai-model';
import { AgentStructuredOutput } from '@/features/agents/structured-output';
import {
AgentPieceProps,
AgentProviderModel,
isNil,
PieceAction,
PieceActionSettings,
Expand Down Expand Up @@ -108,6 +110,18 @@ const selectAgentFormComponentForProperty = (
/>
);
}
case AgentPieceProps.AI_PROVIDER_MODEL: {
const provider = (field.value as AgentProviderModel).provider;
const model = (field.value as AgentProviderModel).model;
return (
<AIModelSelector
defaultModel={model}
defaultProvider={provider}
onChange={field.onChange}
disabled={disabled}
/>
);
}
default: {
return selectGenericFormComponentForProperty(params);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { t } from 'i18next';
import { useEffect, useMemo } from 'react';
import { useForm } from 'react-hook-form';

import { ApMarkdown } from '@/components/custom/markdown';
import { Form, FormField } from '@/components/ui/form';
import { ScrollArea } from '@/components/ui/scroll-area';
import {
Expand All @@ -16,14 +17,15 @@ import {
import { ConnectionDropdown } from '@/features/agents/agent-tools/piece-tool-dialog/connection-select';
import { usePieceToolsDialogStore } from '@/features/agents/agent-tools/stores/pieces-tools';
import { piecesHooks } from '@/features/pieces/lib/pieces-hooks';
import { PieceProperty } from '@activepieces/pieces-framework';
import { PieceProperty, PropertyType } from '@activepieces/pieces-framework';
import {
FieldControlMode,
isNil,
PredefinedInputField,
} from '@activepieces/shared';

import { selectGenericFormComponentForProperty } from '../../piece-properties/properties-utils';

const createPredefinedInputsFormSchema = (requireAuth: boolean) =>
Type.Object(
requireAuth
Expand All @@ -36,9 +38,11 @@ const createPredefinedInputsFormSchema = (requireAuth: boolean) =>
...(requireAuth && { required: ['auth'] }),
},
);

type PredefinedInputsFormValues = Static<
ReturnType<typeof createPredefinedInputsFormSchema>
>;

export const PredefinedInputsForm = () => {
const {
predefinedInputs,
Expand All @@ -48,7 +52,7 @@ export const PredefinedInputsForm = () => {
} = usePieceToolsDialogStore();
const { pieces } = piecesHooks.usePieces({});
const selectedPiece = pieces?.find((p) => p.name === piece?.pieceName);
const requireAuth = selectedAction?.requireAuth ?? false;
const requireAuth = selectedAction?.requireAuth ?? true;
const formSchema = useMemo(
() => createPredefinedInputsFormSchema(requireAuth),
[requireAuth],
Expand Down Expand Up @@ -150,7 +154,7 @@ export const PredefinedInputsForm = () => {
form.setValue(propertyName, undefined, { shouldDirty: false });
}
};
const pieceHasAuth = requireAuth;
const pieceHasAuth = requireAuth && selectedPiece?.auth;
return (
<Form {...form}>
<ScrollArea className="h-full">
Expand Down Expand Up @@ -185,6 +189,19 @@ export const PredefinedInputsForm = () => {
{Object.keys(properties).length > 0 && (
<div className="space-y-5">
{Object.entries(properties).map(([propertyName, property]) => {
const isMarkdown = property.type === PropertyType.MARKDOWN;

if (isMarkdown) {
return (
<ApMarkdown
key={propertyName}
markdown={property.description}
variables={{}}
variant={property.variant}
/>
);
}

const mode = getModeForProperty(propertyName);
const showInput = mode === FieldControlMode.CHOOSE_YOURSELF;
return (
Expand Down
7 changes: 5 additions & 2 deletions packages/react-ui/src/app/routes/platform/setup/ai/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import { DashboardPageHeader } from '@/app/components/dashboard-page-header';
import { aiProviderApi } from '@/features/platform-admin/lib/ai-provider-api';
import { flagsHooks } from '@/hooks/flags-hooks';
import { userHooks } from '@/hooks/user-hooks';
import { PlatformRole, ApFlagId } from '@activepieces/shared';
import {
PlatformRole,
ApFlagId,
SUPPORTED_AI_PROVIDERS,
} from '@activepieces/shared';

import LockedFeatureGuard from '../../../../components/locked-feature-guard';

import { AIProviderCard } from './universal-pieces/ai-provider-card';
import { SUPPORTED_AI_PROVIDERS } from './universal-pieces/supported-ai-providers';

export default function AIProvidersPage() {
const { data: providers, refetch } = useQuery({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { Pencil, Trash } from 'lucide-react';

import { Button } from '@/components/ui/button';
import { Card } from '@/components/ui/card';
import { AIProviderWithoutSensitiveData } from '@activepieces/shared';
import {
AiProviderInfo,
AIProviderWithoutSensitiveData,
} from '@activepieces/shared';

import { AiProviderInfo } from './supported-ai-providers';
import { UpsertAIProviderDialog } from './upsert-provider-dialog';

type AIProviderCardProps = {
Expand Down
Loading
Loading