feat: improve AI chat - system prompt, tool output, context window display (#17769)

⚠️ **AI-generated PR — not ready for review** ⚠️

cc @FelixMalfait

---

## Changes

### System prompt improvements
- Explicit skill-before-tools workflow to prevent the model from calling
tools without loading the matching skill first
- Data efficiency guidance (default small limits, use filters)
- Pluralized `load_skill` → `load_skills` for consistency with
`load_tools`

### Token usage reduction
- Output serialization layer: strips null/undefined/empty values from
tool results
- Lowered default `find_*` limit from 100 → 10, max from 1000 → 100

### System object tool generation
- System objects (calendar events, messages, etc.) now generate AI tools
- Only workflow-related and favorite-related objects are excluded

### Context window display fix
- **Bug**: UI compared cumulative tokens (sum of all turns) against
single-request context window → showed 100% after a few turns
- **Fix**: Track `conversationSize` (last step's `inputTokens`) which
represents the actual conversation history size sent to the model
- New `conversationSize` column on thread entity with migration

### Workspace AI instructions
- Support for custom workspace-level AI instructions

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
This commit is contained in:
Félix Malfait
2026-02-09 14:26:02 +01:00
committed by GitHub
parent 6c7c389785
commit 3216b634a3
105 changed files with 3245 additions and 1714 deletions
+19 -2
View File
@@ -21,6 +21,19 @@ export type Scalars = {
Upload: any;
};
export type AiSystemPromptPreview = {
__typename?: 'AISystemPromptPreview';
estimatedTokenCount: Scalars['Int'];
sections: Array<AiSystemPromptSection>;
};
export type AiSystemPromptSection = {
__typename?: 'AISystemPromptSection';
content: Scalars['String'];
estimatedTokenCount: Scalars['Int'];
title: Scalars['String'];
};
export type ActivateWorkspaceInput = {
displayName?: InputMaybe<Scalars['String']>;
};
@@ -76,12 +89,13 @@ export type Agent = {
export type AgentChatThread = {
__typename?: 'AgentChatThread';
contextWindowTokens?: Maybe<Scalars['Int']>;
conversationSize: Scalars['Int'];
createdAt: Scalars['DateTime'];
id: Scalars['UUID'];
title?: Maybe<Scalars['String']>;
totalInputCredits: Scalars['Int'];
totalInputCredits: Scalars['Float'];
totalInputTokens: Scalars['Int'];
totalOutputCredits: Scalars['Int'];
totalOutputCredits: Scalars['Float'];
totalOutputTokens: Scalars['Int'];
updatedAt: Scalars['DateTime'];
};
@@ -2039,6 +2053,7 @@ export enum MessageChannelVisibility {
export enum ModelProvider {
ANTHROPIC = 'ANTHROPIC',
GROQ = 'GROQ',
NONE = 'NONE',
OPENAI = 'OPENAI',
OPENAI_COMPATIBLE = 'OPENAI_COMPATIBLE',
@@ -4759,6 +4774,7 @@ export type UpdateWorkflowVersionStepInput = {
};
export type UpdateWorkspaceInput = {
aiAdditionalInstructions?: InputMaybe<Scalars['String']>;
allowImpersonation?: InputMaybe<Scalars['Boolean']>;
customDomain?: InputMaybe<Scalars['String']>;
defaultRoleId?: InputMaybe<Scalars['UUID']>;
@@ -5146,6 +5162,7 @@ export type WorkflowVersionStepChanges = {
export type Workspace = {
__typename?: 'Workspace';
activationStatus: WorkspaceActivationStatus;
aiAdditionalInstructions?: Maybe<Scalars['String']>;
allowImpersonation: Scalars['Boolean'];
billingEntitlements: Array<BillingEntitlement>;
billingSubscriptions: Array<BillingSubscription>;