feat: inject tenant skills into agent system prompt
Load active skills from the tenant's schema `skills` table and append them to the system prompt before passing to the Claude Agent SDK. This closes the gap where skills existed in the DB but were never surfaced to the agent during task execution. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
3ed20cdf08
commit
3278696f4c
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { AgentEnginePort, EngineTaskParams, EngineStreamEvent } from '../../../domain/ports/outbound/agent-engine.port';
|
||||
import { AgentEngineType } from '../../../domain/value-objects/agent-engine-type.vo';
|
||||
import { CommandRiskLevel } from '../../../domain/value-objects/command-risk-level.vo';
|
||||
|
|
@ -52,6 +53,7 @@ export class ClaudeAgentSdkEngine implements AgentEnginePort {
|
|||
private readonly configService: ConfigService,
|
||||
private readonly tenantConfigService: TenantAgentConfigService,
|
||||
private readonly allowedToolsResolver: AllowedToolsResolverService,
|
||||
private readonly dataSource: DataSource,
|
||||
) {}
|
||||
|
||||
async *executeTask(params: EngineTaskParams): AsyncGenerator<EngineStreamEvent> {
|
||||
|
|
@ -105,9 +107,13 @@ export class ClaudeAgentSdkEngine implements AgentEnginePort {
|
|||
// Set tenant-isolated HOME directory so SDK session files are separated per tenant
|
||||
this.ensureTenantHome(tenantId, env);
|
||||
|
||||
// Load tenant skills and build enriched system prompt
|
||||
const skills = await this.loadTenantSkills(tenantId);
|
||||
const enrichedSystemPrompt = this.buildSystemPromptWithSkills(params.systemPrompt, skills);
|
||||
|
||||
// Build SDK query options
|
||||
const sdkOptions: Record<string, any> = {
|
||||
systemPrompt: params.systemPrompt || undefined,
|
||||
systemPrompt: enrichedSystemPrompt,
|
||||
allowedTools: params.allowedTools?.length ? params.allowedTools : undefined,
|
||||
maxTurns: params.maxTurns,
|
||||
maxBudgetUsd: params.maxBudgetUsd,
|
||||
|
|
@ -361,6 +367,43 @@ export class ClaudeAgentSdkEngine implements AgentEnginePort {
|
|||
return this.activeSessions.get(sessionId)?.sdkSessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load active skills from the tenant's schema `skills` table.
|
||||
* Skills are injected into the system prompt so the agent knows what it can do.
|
||||
*/
|
||||
private async loadTenantSkills(tenantId: string): Promise<Array<{ name: string; content: string }>> {
|
||||
const safeId = tenantId.replace(/[^a-zA-Z0-9_]/g, '');
|
||||
const schemaName = `it0_t_${safeId}`;
|
||||
try {
|
||||
const skills: Array<{ name: string; content: string }> = await this.dataSource.query(
|
||||
`SELECT name, content FROM "${schemaName}".skills WHERE is_active = true ORDER BY name`,
|
||||
);
|
||||
this.logger.log(`Loaded ${skills.length} skills for tenant ${tenantId}`);
|
||||
return skills;
|
||||
} catch (err: any) {
|
||||
this.logger.warn(`Failed to load skills for tenant ${tenantId}: ${err.message}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build enriched system prompt by appending tenant skills.
|
||||
*/
|
||||
private buildSystemPromptWithSkills(
|
||||
basePrompt: string | undefined,
|
||||
skills: Array<{ name: string; content: string }>,
|
||||
): string | undefined {
|
||||
if (skills.length === 0) return basePrompt || undefined;
|
||||
|
||||
const skillsSection = skills
|
||||
.map((s) => `### ${s.name}\n${s.content}`)
|
||||
.join('\n\n');
|
||||
|
||||
const enrichment = `\n\n## Available Skills\n\nThe following skills are configured for this tenant. Use them as reference knowledge when executing tasks.\n\n${skillsSection}`;
|
||||
|
||||
return basePrompt ? `${basePrompt}${enrichment}` : enrichment.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a tenant-isolated HOME directory so SDK session files
|
||||
* are stored separately per tenant. Creates the directory structure
|
||||
|
|
|
|||
Loading…
Reference in New Issue