From effect-ts
This skill should be used when the user asks about "Effect AI", "@effect/ai", "LLM integration", "AI tool use", "AI execution planning", "building AI agents", "AI providers", "structured AI output", "AI completions", "Effect OpenAI", "Effect Anthropic", or needs to understand how Effect integrates with AI/LLM services.
npx claudepluginhub andrueandersoncs/claude-skill-effect-ts --plugin effect-tsThis skill uses the workspace's default tool permissions.
Effect AI (`@effect/ai`) provides type-safe integration with AI/LLM services:
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Effect AI (@effect/ai) provides type-safe integration with AI/LLM services:
npm install @effect/ai @effect/ai-openai
# or
npm install @effect/ai @effect/ai-anthropic
import { AiChat } from "@effect/ai";
import { OpenAiChat } from "@effect/ai-openai";
import { Effect, Layer } from "effect";
const OpenAiLive = OpenAiChat.layer({
apiKey: Config.redacted("OPENAI_API_KEY"),
model: "gpt-4",
});
import { AnthropicChat } from "@effect/ai-anthropic";
const AnthropicLive = AnthropicChat.layer({
apiKey: Config.redacted("ANTHROPIC_API_KEY"),
model: "claude-3-opus-20240229",
});
const program = Effect.gen(function* () {
const ai = yield* AiChat.AiChat;
const response = yield* ai.generateText({
prompt: "Explain functional programming in one sentence.",
});
return response.text;
});
const result = yield * program.pipe(Effect.provide(OpenAiLive));
const chat = Effect.gen(function* () {
const ai = yield* AiChat.AiChat;
const response = yield* ai.generateText({
messages: [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: "What is Effect-TS?" },
],
});
return response.text;
});
Define tools that AI can call:
import { AiTool } from "@effect/ai";
import { Schema } from "effect";
const WeatherInput = Schema.Struct({
city: Schema.String,
unit: Schema.optional(Schema.Literal("celsius", "fahrenheit")),
});
const getWeather = AiTool.make({
name: "get_weather",
description: "Get current weather for a city",
input: WeatherInput,
handler: (input) =>
Effect.succeed({
city: input.city,
temperature: 22,
unit: input.unit ?? "celsius",
conditions: "sunny",
}),
});
const programWithTools = Effect.gen(function* () {
const ai = yield* AiChat.AiChat;
const response = yield* ai.generateText({
prompt: "What's the weather in Tokyo?",
tools: [getWeather],
});
return response.text;
});
const searchTool = AiTool.make({
name: "search",
description: "Search the web",
input: Schema.Struct({ query: Schema.String }),
handler: ({ query }) => performSearch(query),
});
const calculatorTool = AiTool.make({
name: "calculator",
description: "Perform calculations",
input: Schema.Struct({
expression: Schema.String,
}),
handler: ({ expression }) => evaluate(expression),
});
const response =
yield *
ai.generateText({
prompt: "Search for Effect-TS and calculate 2+2",
tools: [searchTool, calculatorTool],
});
Get typed, validated responses:
const ProductReview = Schema.Struct({
sentiment: Schema.Literal("positive", "negative", "neutral"),
score: Schema.Number.pipe(Schema.between(1, 5)),
summary: Schema.String,
keywords: Schema.Array(Schema.String),
});
const analyzeReview = Effect.gen(function* () {
const ai = yield* AiChat.AiChat;
const review = yield* ai.generateObject({
prompt: "Analyze this product review: 'Great product, highly recommend!'",
schema: ProductReview,
});
return review;
});
For complex multi-step AI workflows:
import { AiPlan } from "@effect/ai";
const researchPlan = AiPlan.make({
name: "research",
description: "Research a topic and summarize findings",
steps: [
{
name: "search",
description: "Search for relevant information",
tool: searchTool,
},
{
name: "analyze",
description: "Analyze search results",
handler: (context) =>
Effect.gen(function* () {
const ai = yield* AiChat.AiChat;
return yield* ai.generateText({
prompt: `Analyze these results: ${context.previousResults}`,
});
}),
},
{
name: "summarize",
description: "Create final summary",
handler: (context) =>
Effect.gen(function* () {
const ai = yield* AiChat.AiChat;
return yield* ai.generateObject({
prompt: `Summarize: ${context.analysis}`,
schema: ResearchSummary,
});
}),
},
],
});
const result =
yield *
AiPlan.execute(researchPlan, {
topic: "Effect-TS benefits",
});
import { Stream } from "effect";
const streamProgram = Effect.gen(function* () {
const ai = yield* AiChat.AiChat;
const stream = yield* ai.streamText({
prompt: "Write a short story about a robot.",
});
yield* Stream.runForEach(stream, (chunk) => Effect.sync(() => process.stdout.write(chunk)));
});
const OpenAiLive = OpenAiChat.layer({
apiKey: Config.redacted("OPENAI_API_KEY"),
model: "gpt-4-turbo",
temperature: 0.7,
maxTokens: 1000,
organizationId: Config.string("OPENAI_ORG_ID").pipe(Config.option),
});
const AnthropicLive = AnthropicChat.layer({
apiKey: Config.redacted("ANTHROPIC_API_KEY"),
model: "claude-3-opus-20240229",
maxTokens: 4096,
});
import { AiError } from "@effect/ai";
const safeChat = program.pipe(
Effect.catchTag("AiRateLimitError", (error) =>
Effect.gen(function* () {
yield* Effect.sleep(error.retryAfter);
return yield* program;
}),
),
Effect.catchTag("AiAuthenticationError", () => Effect.fail(new ConfigurationError())),
Effect.catchTag("AiError", (error) =>
Effect.gen(function* () {
yield* Effect.logError("AI error", error);
return "Sorry, I couldn't process that request.";
}),
),
);
const MockAiLive = Layer.succeed(AiChat.AiChat, {
generateText: () => Effect.succeed({ text: "Mock response" }),
generateObject: (options) => Effect.succeed(mockData),
streamText: () => Effect.succeed(Stream.make("Mock", " ", "stream")),
});
const testProgram = program.pipe(Effect.provide(MockAiLive));
For comprehensive Effect AI documentation, consult ${CLAUDE_PLUGIN_ROOT}/references/llms-full.txt.
Search for these sections: