mattermost-mobile/app/products/agents/client/rest.ts
Felipe Martin 714c3dc769
feat: AI rewrite (#9280)
* feat: ai rewrite

* feat: allow crating content apart from editing it

* feat: feature parity with webapp

* feat: feature parity with webapp

* chore: fixed padding

* map ux to webapp

* refactored ai rewrite logic to separate package

* chore: tests and lint

* Update app/products/ai/rewrite/screens/options/options.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* rewrite post editor animation

* i18n

* ui feedback, centered icon and less top padding

* chore: lint

* Consolidate @ai product into @agents

Move all rewrite functionality from app/products/ai/ into
app/products/agents/ to unify under a single namespace.

- Add rewrite types, store, hooks, components, and screens to agents
- Merge AI client methods into agents client
- Update screen constants (AI_* -> AGENTS_*)
- Update all consumer imports
- Remove AI state from EphemeralStore
- Remove @ai path alias from config
- Delete app/products/ai/ directory

* refactor: load screens from product package

* refactor: move detection logic to the agents pacakge

* refactor: remove "backwards compatibility"

* refactor: move hooks to proper package

* refactor: styles

* refactor: remove unneedd position attribute

* refactor: remove unneeded cancel animation calls

* refactor: "backwards compat"

* refactor: optimize renderContent with useCallback for performance

* refactor: rename variable to avoid confusion

* refactor: update handleRewrite to use async/await for better error handling

* refactor: simplify handleRewrite by always dismissing keyboard

* refactor: use hook, always all keyboard.dismiss

* chore: enhance AgentSelector component with FlatList support

* feat: add rewriteMessage function for AI message rewriting and integrate it into useRewrite hook

* refactor: simplify message length calculation in useHandleSendMessage hook

* refactor: consolidate agent screen constants and integrate with existing screens

* fix: update dependency array in useMemo for isUnrevealedPost to include post expiration metadata

* refactor: remove unused variable to clean up Typing component

* refactor: simplify logic for atDisabled and slashDisabled flags in QuickActions component

* feat: add AIRewriteAction component for AI message rewriting functionality

* revert: thread.ts changes manually

* refactor: integrate useSafeAreaInsets

* refactor: cleanup unused methods

* chore: add comment to clarify casting

* refactor: use_agents

* chore: lint and test

* fix: trim

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-16 16:48:57 +01:00

126 lines
4.1 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {Agent, AgentsResponse, AgentsStatusResponse, ChannelAnalysisOptions, ChannelAnalysisResponse, RewriteRequest, RewriteResponse} from '@agents/types/api';
export type {Agent};
export interface ClientAgentsMix {
getAgentsRoute: () => string;
getAgents: () => Promise<Agent[]>;
stopGeneration: (postId: string) => Promise<void>;
regenerateResponse: (postId: string) => Promise<void>;
doChannelAnalysis: (
channelId: string,
analysisType: string,
botUsername: string,
options?: ChannelAnalysisOptions,
) => Promise<ChannelAnalysisResponse>;
submitToolApproval: (postId: string, acceptedToolIds: string[]) => Promise<void>;
// Rewrite methods
getRewrittenMessage: (message: string, action?: string, customPrompt?: string, agentId?: string) => Promise<string>;
getAgentsStatus: () => Promise<AgentsStatusResponse>;
}
const ClientAgents = (superclass: any) => class extends superclass {
getAgentsRoute = () => {
return '/plugins/mattermost-ai';
};
getAgents = async (): Promise<Agent[]> => {
const response = await this.doFetch(
`${this.urlVersion}/agents`,
{method: 'get'},
);
// Handle both array response and wrapped response
if (Array.isArray(response)) {
return response;
}
return (response as AgentsResponse).agents || [];
};
stopGeneration = async (postId: string) => {
return this.doFetch(
`${this.getAgentsRoute()}/post/${postId}/stop`,
{method: 'post'},
);
};
regenerateResponse = async (postId: string) => {
return this.doFetch(
`${this.getAgentsRoute()}/post/${postId}/regenerate`,
{method: 'post'},
);
};
doChannelAnalysis = async (
channelId: string,
analysisType: string,
botUsername: string,
options?: ChannelAnalysisOptions,
): Promise<ChannelAnalysisResponse> => {
const {since, until, days, prompt, unreads_only} = options || {};
return this.doFetch(
`${this.getAgentsRoute()}/channel/${channelId}/analyze?botUsername=${encodeURIComponent(botUsername)}`,
{
method: 'post',
body: {
analysis_type: analysisType,
since,
until,
days,
prompt,
unreads_only,
},
},
);
};
submitToolApproval = async (postId: string, acceptedToolIds: string[]) => {
return this.doFetch(
`${this.getAgentsRoute()}/post/${postId}/tool_call`,
{
method: 'post',
body: {accepted_tool_ids: acceptedToolIds},
},
);
};
// =========================================================================
// Rewrite Methods
// =========================================================================
getRewrittenMessage = async (message: string, action?: string, customPrompt?: string, agentId?: string): Promise<string> => {
const body: RewriteRequest = {
agent_id: agentId,
message,
action,
custom_prompt: customPrompt,
};
const response = await this.doFetch(
`${this.urlVersion}/posts/rewrite`,
{method: 'post', body},
true,
) as RewriteResponse;
// Handle cases where the AI returns plain text instead of the expected JSON format.
// If rewritten_text is undefined, treat the entire response as the rewritten message.
if (response.rewritten_text === undefined) {
return response as unknown as string;
}
return response.rewritten_text;
};
getAgentsStatus = async (): Promise<AgentsStatusResponse> => {
return this.doFetch(
`${this.urlVersion}/agents/status`,
{method: 'get'},
);
};
};
export default ClientAgents;