Copilot composio prompting (#198)

* added an example on using composio to copilot

* temp save

* simple example

* updated the prompt

* added "searching for tools..." banner

* Merge branch 'dev' of github.com:rowboatlabs/rowboat into copilot-composio-prompting

* changed tools default when added from "mockTool: true" to false (so they are enabled by default)

* added pipelines to copilot

* fixed bug that made copilot agents default to conversation type

* Merge branch 'dev' of github.com:rowboatlabs/rowboat into copilot-composio-prompting

* Refactor agent configuration in workflow editor to enforce controlType and outputVisibility rules. Added logic to fix existing agents with incorrect settings on mount. Updated task agent creation to ensure proper defaults for pipeline and conversational agents. Increased maxSteps for text streaming in copilot.

* Merge branch 'dev' of github.com:rowboatlabs/rowboat into copilot-composio-prompting

* added example

* Add automated meeting preparation pipeline example with multi-step workflow for researching participants, compiling summaries, and posting to Slack.

* Update example agents to use placeholders for user email and Slack channel in instructions and examples, enhancing privacy and flexibility in the meeting preparation pipeline.

* Refactor sections in copilot_multi_agent.ts for clarity and consistency, including renaming section headers and improving instructions. Update query handling in copilot.ts to streamline event processing.

* made the tool card block params genereic and linked to the searchRelevantTools so that it relies on that instead of examples

* revert unrequired changes

* Refactor agent configuration handling in workflow editor to streamline agent creation and ensure correct default values for controlType and outputVisibility. Removed redundant code for fixing existing agents and improved clarity in agent initialization logic.

---------

Co-authored-by: Ramnique Singh <30795890+ramnique@users.noreply.github.com>
This commit is contained in:
Tushar 2025-08-13 16:19:49 +05:30 committed by GitHub
parent fa396aa0a4
commit a8f0a132af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 1206 additions and 267 deletions

View file

@ -69,6 +69,8 @@ const App = forwardRef<{ handleCopyChat: () => void; handleUserMessage: (message
const {
streamingResponse,
loading: loadingResponse,
toolCalling,
toolQuery,
error: responseError,
clearError: clearResponseError,
billingError,
@ -213,6 +215,16 @@ const App = forwardRef<{ handleCopyChat: () => void; handleUserMessage: (message
onStatusBarChange={handleStatusBarChange}
/>
</div>
{toolCalling && (
<div className="shrink-0 px-4 py-2.5 bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 shadow-sm dark:shadow-gray-950/20 rounded-2xl mx-1 mb-2">
<div className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
<Spinner size="sm" className="ml-2" />
<span>
Searching for tools{toolQuery ? ` to ${toolQuery}` : '...'}
</span>
</div>
</div>
)}
<div className="shrink-0 px-1 pb-6">
{responseError && (
<div className="mb-4 p-2 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg flex gap-2 justify-between items-center text-sm">

View file

@ -175,7 +175,7 @@ export function Action({
'bg-gray-200 text-gray-600': stale || allApplied || action.error,
}
)}>
{action.config_type === 'agent' ? '🧑‍💼' : action.config_type === 'tool' ? '🛠️' : '💬'}
{action.config_type === 'agent' ? '🧑‍💼' : action.config_type === 'tool' ? '🛠️' : action.config_type === 'pipeline' ? '⚙️' : '💬'}
</span>
<span className="font-semibold text-sm text-zinc-800 dark:text-zinc-100 truncate flex-1">
{action.action === 'create_new' ? 'Add' : 'Edit'} {action.config_type}: {action.name}
@ -227,7 +227,7 @@ export function ActionHeader() {
const { msgIndex, actionIndex, action, workflow, appliedFields, stale } = useContext(ActionContext);
if (!action || !workflow) return null;
const targetType = action.config_type === 'tool' ? 'tool' : action.config_type === 'agent' ? 'agent' : 'prompt';
const targetType = action.config_type === 'tool' ? 'tool' : action.config_type === 'agent' ? 'agent' : action.config_type === 'pipeline' ? 'pipeline' : 'prompt';
const change = action.action === 'create_new' ? 'Create' : 'Edit';
return <div className="flex gap-2 items-center py-1 px-1">
@ -273,6 +273,12 @@ export function ActionField({
if (prompt) {
oldValue = (prompt as any)[field];
}
} else if (action.config_type === 'pipeline') {
// Find the pipeline in the workflow
const pipeline = workflow.pipelines?.find(p => p.name === action.name);
if (pipeline) {
oldValue = (pipeline as any)[field];
}
}
}
@ -336,7 +342,7 @@ export function StreamingAction({
}: {
action: {
action?: 'create_new' | 'edit';
config_type?: 'tool' | 'agent' | 'prompt';
config_type?: 'tool' | 'agent' | 'prompt' | 'pipeline';
name?: string;
};
loading: boolean;
@ -362,7 +368,7 @@ export function StreamingAction({
'bg-gray-200 text-gray-600': !action.action,
}
)}>
{action.config_type === 'agent' ? '🧑‍💼' : action.config_type === 'tool' ? '🛠️' : '💬'}
{action.config_type === 'agent' ? '🧑‍💼' : action.config_type === 'tool' ? '🛠️' : action.config_type === 'pipeline' ? '⚙️' : '💬'}
</span>
<span className="font-semibold text-sm text-zinc-800 dark:text-zinc-100 truncate flex-1">
{action.action === 'create_new' ? 'Add' : 'Edit'} {action.config_type}: {action.name}

View file

@ -71,7 +71,7 @@ function enrich(response: string): z.infer<typeof CopilotResponsePart> {
type: 'action',
action: {
action: metadata.action as 'create_new' | 'edit',
config_type: metadata.config_type as 'tool' | 'agent' | 'prompt',
config_type: metadata.config_type as 'tool' | 'agent' | 'prompt' | 'pipeline',
name: metadata.name,
change_description: jsonData.change_description || '',
config_changes: {},
@ -84,7 +84,7 @@ function enrich(response: string): z.infer<typeof CopilotResponsePart> {
type: 'action',
action: {
action: metadata.action as 'create_new' | 'edit',
config_type: metadata.config_type as 'tool' | 'agent' | 'prompt',
config_type: metadata.config_type as 'tool' | 'agent' | 'prompt' | 'pipeline',
name: metadata.name,
change_description: jsonData.change_description || '',
config_changes: result.changes
@ -100,7 +100,7 @@ function enrich(response: string): z.infer<typeof CopilotResponsePart> {
type: 'streaming_action',
action: {
action: (metadata.action as 'create_new' | 'edit') || undefined,
config_type: (metadata.config_type as 'tool' | 'agent' | 'prompt') || undefined,
config_type: (metadata.config_type as 'tool' | 'agent' | 'prompt' | 'pipeline') || undefined,
name: metadata.name
}
};
@ -260,6 +260,15 @@ function AssistantMessage({
}
});
break;
case 'pipeline':
dispatch({
type: 'add_pipeline',
pipeline: {
name: action.name,
...action.config_changes
}
});
break;
}
} else if (action.action === 'edit') {
switch (action.config_type) {
@ -284,6 +293,13 @@ function AssistantMessage({
prompt: action.config_changes
});
break;
case 'pipeline':
dispatch({
type: 'update_pipeline',
name: action.name,
pipeline: action.config_changes
});
break;
}
}
}, [dispatch, workflow.agents, workflow.tools]);

View file

@ -16,6 +16,8 @@ interface UseCopilotParams {
interface UseCopilotResult {
streamingResponse: string;
loading: boolean;
toolCalling: boolean;
toolQuery: string | null;
error: string | null;
clearError: () => void;
billingError: string | null;
@ -30,6 +32,8 @@ interface UseCopilotResult {
export function useCopilot({ projectId, workflow, context, dataSources }: UseCopilotParams): UseCopilotResult {
const [streamingResponse, setStreamingResponse] = useState('');
const [loading, setLoading] = useState(false);
const [toolCalling, setToolCalling] = useState(false);
const [toolQuery, setToolQuery] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const [billingError, setBillingError] = useState<string | null>(null);
const cancelRef = useRef<() => void>(() => { });
@ -52,6 +56,8 @@ export function useCopilot({ projectId, workflow, context, dataSources }: UseCop
setStreamingResponse('');
responseRef.current = '';
setError(null);
setToolCalling(false);
setToolQuery(null);
setLoading(true);
try {
@ -77,6 +83,21 @@ export function useCopilot({ projectId, workflow, context, dataSources }: UseCop
}
};
eventSource.addEventListener('tool-call', (event) => {
try {
const data = JSON.parse(event.data);
setToolCalling(true);
setToolQuery(data.query || null);
} catch (e) {
setToolCalling(true);
setToolQuery(null);
}
});
eventSource.addEventListener('tool-result', (event) => {
setToolCalling(false);
});
eventSource.addEventListener('done', () => {
eventSource.close();
setLoading(false);
@ -104,6 +125,8 @@ export function useCopilot({ projectId, workflow, context, dataSources }: UseCop
return {
streamingResponse,
loading,
toolCalling,
toolQuery,
error,
clearError,
billingError,