chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
import { db } from '@sim/db'
|
||||
import { skill } from '@sim/db/schema'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { and, eq, inArray } from 'drizzle-orm'
|
||||
import { getBuiltinSkillById, getBuiltinSkillByName } from '@/lib/workflows/skills/builtin-skills'
|
||||
import type { SkillInput } from '@/executor/handlers/agent/types'
|
||||
|
||||
const logger = createLogger('SkillsResolver')
|
||||
|
||||
function escapeXml(str: string): string {
|
||||
return str
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
}
|
||||
|
||||
interface SkillMetadata {
|
||||
name: string
|
||||
description: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch skill metadata (name + description) for system prompt injection.
|
||||
* Only returns lightweight data so the LLM knows what skills are available.
|
||||
*/
|
||||
export async function resolveSkillMetadata(
|
||||
skillInputs: SkillInput[],
|
||||
workspaceId: string
|
||||
): Promise<SkillMetadata[]> {
|
||||
if (!skillInputs.length || !workspaceId) return []
|
||||
|
||||
const metadata: SkillMetadata[] = []
|
||||
const dbSkillIds: string[] = []
|
||||
for (const input of skillInputs) {
|
||||
const builtin = getBuiltinSkillById(input.skillId)
|
||||
if (builtin) {
|
||||
metadata.push({ name: builtin.name, description: builtin.description })
|
||||
} else {
|
||||
dbSkillIds.push(input.skillId)
|
||||
}
|
||||
}
|
||||
|
||||
if (dbSkillIds.length === 0) return metadata
|
||||
|
||||
try {
|
||||
const rows = await db
|
||||
.select({ name: skill.name, description: skill.description })
|
||||
.from(skill)
|
||||
.where(and(eq(skill.workspaceId, workspaceId), inArray(skill.id, dbSkillIds)))
|
||||
|
||||
return [...metadata, ...rows]
|
||||
} catch (error) {
|
||||
logger.error('Failed to resolve skill metadata', { error, dbSkillIds, workspaceId })
|
||||
return metadata
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch full skill content for a load_skill tool response.
|
||||
* Called when the LLM decides a skill is relevant and invokes load_skill.
|
||||
*/
|
||||
export async function resolveSkillContent(
|
||||
skillName: string,
|
||||
workspaceId: string
|
||||
): Promise<string | null> {
|
||||
if (!skillName || !workspaceId) return null
|
||||
|
||||
const builtin = getBuiltinSkillByName(skillName)
|
||||
if (builtin) return builtin.content
|
||||
|
||||
try {
|
||||
const rows = await db
|
||||
.select({ content: skill.content, name: skill.name })
|
||||
.from(skill)
|
||||
.where(and(eq(skill.workspaceId, workspaceId), eq(skill.name, skillName)))
|
||||
.limit(1)
|
||||
|
||||
if (rows.length === 0) {
|
||||
logger.warn('Skill not found', { skillName, workspaceId })
|
||||
return null
|
||||
}
|
||||
|
||||
return rows[0].content
|
||||
} catch (error) {
|
||||
logger.error('Failed to resolve skill content', { error, skillName, workspaceId })
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export async function resolveSkillContentById(
|
||||
skillId: string,
|
||||
workspaceId: string
|
||||
): Promise<{ name: string; content: string } | null> {
|
||||
if (!skillId || !workspaceId) return null
|
||||
|
||||
const builtin = getBuiltinSkillById(skillId)
|
||||
if (builtin) return { name: builtin.name, content: builtin.content }
|
||||
|
||||
try {
|
||||
const rows = await db
|
||||
.select({ content: skill.content, name: skill.name })
|
||||
.from(skill)
|
||||
.where(and(eq(skill.workspaceId, workspaceId), eq(skill.id, skillId)))
|
||||
.limit(1)
|
||||
|
||||
if (rows.length === 0) {
|
||||
logger.warn('Skill not found', { skillId, workspaceId })
|
||||
return null
|
||||
}
|
||||
|
||||
return rows[0]
|
||||
} catch (error) {
|
||||
logger.error('Failed to resolve skill content', { error, skillId, workspaceId })
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the system prompt section that lists available skills.
|
||||
* Uses XML format per the agentskills.io integration guide.
|
||||
*/
|
||||
export function buildSkillsSystemPromptSection(skills: SkillMetadata[]): string {
|
||||
if (!skills.length) return ''
|
||||
|
||||
const skillEntries = skills
|
||||
.map(
|
||||
(s) =>
|
||||
` <skill name="${escapeXml(s.name)}">\n <description>${escapeXml(s.description)}</description>\n </skill>`
|
||||
)
|
||||
.join('\n')
|
||||
|
||||
return [
|
||||
'',
|
||||
'You have access to the following skills. Use the load_skill tool to activate a skill when relevant.',
|
||||
'',
|
||||
'<available_skills>',
|
||||
skillEntries,
|
||||
'</available_skills>',
|
||||
].join('\n')
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the load_skill tool definition for injection into the tools array.
|
||||
* Returns a ProviderToolConfig-compatible object so all providers can process it.
|
||||
*/
|
||||
export function buildLoadSkillTool(skillNames: string[]) {
|
||||
return {
|
||||
id: 'load_skill',
|
||||
name: 'load_skill',
|
||||
description: `Load a skill to get specialized instructions. Available skills: ${skillNames.join(', ')}`,
|
||||
params: {},
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
skill_name: {
|
||||
type: 'string',
|
||||
description: 'Name of the skill to load',
|
||||
enum: skillNames,
|
||||
},
|
||||
},
|
||||
required: ['skill_name'],
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user