初始化项目版本
This commit is contained in:
134
.agents/skills/claude-api/ruby/claude-api/README.md
Normal file
134
.agents/skills/claude-api/ruby/claude-api/README.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# Claude API — Ruby
|
||||
|
||||
> **Note:** The Ruby SDK supports the Claude API. A tool runner is available in beta via `client.beta.messages.tool_runner()`. Agent SDK is not yet available for Ruby.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
gem install anthropic
|
||||
```
|
||||
|
||||
## Client Initialization
|
||||
|
||||
```ruby
|
||||
require "anthropic"
|
||||
|
||||
# Default (uses ANTHROPIC_API_KEY env var)
|
||||
client = Anthropic::Client.new
|
||||
|
||||
# Explicit API key
|
||||
client = Anthropic::Client.new(api_key: "your-api-key")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Basic Message Request
|
||||
|
||||
```ruby
|
||||
message = client.messages.create(
|
||||
model: :"claude-opus-5",
|
||||
max_tokens: 16000,
|
||||
messages: [
|
||||
{ role: "user", content: "What is the capital of France?" }
|
||||
]
|
||||
)
|
||||
# content is an array of polymorphic block objects (TextBlock, ThinkingBlock,
|
||||
# ToolUseBlock, ...). .type is a Symbol — compare with :text, not "text".
|
||||
# .text raises NoMethodError on non-TextBlock entries.
|
||||
message.content.each do |block|
|
||||
puts block.text if block.type == :text
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Extended Thinking
|
||||
|
||||
> **Fable 5, Claude Opus 5, Opus 4.8, Opus 4.7, Opus 4.6, and Sonnet 4.6:** Use adaptive thinking. `budget_tokens` is removed on Fable 5, Claude Opus 5, Opus 4.8, and 4.7 (400 if sent); deprecated on Opus 4.6 and Sonnet 4.6.
|
||||
> **Claude Opus 5:** thinking is on by default — omitting `thinking:` runs adaptive (`{ type: "adaptive" }` is equivalent), unlike Opus 4.8/4.7 where omitting it meant no thinking. `{ type: "disabled" }` is accepted only at effort `high` or lower; pairing it with `xhigh`/`max` returns a 400.
|
||||
> **Older models:** Use `thinking: { type: "enabled", budget_tokens: N }` (must be < `max_tokens`, min 1024).
|
||||
|
||||
```ruby
|
||||
message = client.messages.create(
|
||||
model: :"claude-opus-5",
|
||||
max_tokens: 16000,
|
||||
thinking: { type: "adaptive" },
|
||||
messages: [{ role: "user", content: "Solve: 27 * 453" }]
|
||||
)
|
||||
|
||||
message.content.each do |block|
|
||||
case block.type
|
||||
when :thinking then puts "Thinking: #{block.thinking}"
|
||||
when :text then puts "Response: #{block.text}"
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Prompt Caching
|
||||
|
||||
`system_:` (trailing underscore — avoids shadowing `Kernel#system`) takes an array of text blocks; set `cache_control` on the last block. Plain hashes work via the `OrHash` type alias. For placement patterns and the silent-invalidator audit checklist, see `shared/prompt-caching.md`.
|
||||
|
||||
```ruby
|
||||
message = client.messages.create(
|
||||
model: :"claude-opus-5",
|
||||
max_tokens: 16000,
|
||||
system_: [
|
||||
{ type: "text", text: long_system_prompt, cache_control: { type: "ephemeral" } }
|
||||
],
|
||||
messages: [{ role: "user", content: "Summarize the key points" }]
|
||||
)
|
||||
```
|
||||
|
||||
For 1-hour TTL: `cache_control: { type: "ephemeral", ttl: "1h" }`. There's also a top-level `cache_control:` on `messages.create` that auto-places on the last cacheable block.
|
||||
|
||||
Verify hits via `message.usage.cache_creation_input_tokens` / `message.usage.cache_read_input_tokens`.
|
||||
|
||||
---
|
||||
|
||||
## Stop Details
|
||||
|
||||
When `stop_reason` is `:refusal`, the response includes structured `stop_details`:
|
||||
|
||||
```ruby
|
||||
if message.stop_reason == :refusal && message.stop_details
|
||||
puts "Category: #{message.stop_details.category}" # e.g. :cyber, :bio, :reasoning_extraction, :frontier_llm, or nil — see docs for the full set
|
||||
puts "Explanation: #{message.stop_details.explanation}"
|
||||
end
|
||||
```
|
||||
|
||||
**Refusal fallbacks (Claude Fable 5) — opt in by default.** Fallbacks are opt-in: without them a refused request simply stops. New `claude-fable-5` code should include the server-side `fallbacks` parameter (beta header `server-side-fallback-2026-06-01`, `fallbacks: [{model: "claude-opus-4-8"}]` on the beta messages call) by default. The exact Ruby binding (and the client-side middleware for providers without server-side support) is not documented here — WebFetch the Ruby SDK repo's `examples/` from `shared/live-sources.md`; full semantics in `shared/model-migration.md` → Migrating to Claude Fable 5 → `refusal` stop reason.
|
||||
|
||||
---
|
||||
|
||||
## Beta Features
|
||||
|
||||
`betas:` is only valid on `client.beta.messages.create`, not the non-beta path.
|
||||
|
||||
### Task budgets
|
||||
|
||||
```ruby
|
||||
response = client.beta.messages.create(
|
||||
model: :"claude-opus-5",
|
||||
max_tokens: 16000,
|
||||
output_config: { task_budget: { type: :tokens, total: 64_000 } },
|
||||
tools: [...],
|
||||
messages: [...],
|
||||
betas: ["task-budgets-2026-03-13"]
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Type
|
||||
|
||||
`APIStatusError` exposes a `.type` field for programmatic error classification:
|
||||
|
||||
```ruby
|
||||
begin
|
||||
client.messages.create(...)
|
||||
rescue Anthropic::Errors::APIStatusError => e
|
||||
puts e.type # :rate_limit_error, :overloaded_error, etc.
|
||||
end
|
||||
```
|
||||
16
.agents/skills/claude-api/ruby/claude-api/streaming.md
Normal file
16
.agents/skills/claude-api/ruby/claude-api/streaming.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# Streaming — Ruby
|
||||
|
||||
## Streaming
|
||||
|
||||
```ruby
|
||||
stream = client.messages.stream(
|
||||
model: :"claude-opus-5",
|
||||
max_tokens: 64000,
|
||||
messages: [{ role: "user", content: "Write a haiku" }]
|
||||
)
|
||||
|
||||
stream.text.each { |text| print(text) }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
41
.agents/skills/claude-api/ruby/claude-api/tool-use.md
Normal file
41
.agents/skills/claude-api/ruby/claude-api/tool-use.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Tool Use — Ruby
|
||||
|
||||
For conceptual overview (tool definitions, tool choice, tips), see [shared/tool-use-concepts.md](../../shared/tool-use-concepts.md).
|
||||
|
||||
## Tool Use
|
||||
|
||||
The Ruby SDK supports tool use via raw JSON schema definitions and also provides a beta tool runner for automatic tool execution.
|
||||
|
||||
### Tool Runner (Beta)
|
||||
|
||||
```ruby
|
||||
class GetWeatherInput < Anthropic::BaseModel
|
||||
required :location, String, doc: "City and state, e.g. San Francisco, CA"
|
||||
end
|
||||
|
||||
class GetWeather < Anthropic::BaseTool
|
||||
doc "Get the current weather for a location"
|
||||
|
||||
input_schema GetWeatherInput
|
||||
|
||||
def call(input)
|
||||
"The weather in #{input.location} is sunny and 72°F."
|
||||
end
|
||||
end
|
||||
|
||||
client.beta.messages.tool_runner(
|
||||
model: :"claude-opus-5",
|
||||
max_tokens: 16000,
|
||||
tools: [GetWeather.new],
|
||||
messages: [{ role: "user", content: "What's the weather in San Francisco?" }]
|
||||
).each_message do |message|
|
||||
puts message.content
|
||||
end
|
||||
```
|
||||
|
||||
### Manual Loop
|
||||
|
||||
See the [shared tool use concepts](../../shared/tool-use-concepts.md) for the tool definition format and agentic loop pattern.
|
||||
|
||||
---
|
||||
|
||||
394
.agents/skills/claude-api/ruby/managed-agents/README.md
Normal file
394
.agents/skills/claude-api/ruby/managed-agents/README.md
Normal file
@@ -0,0 +1,394 @@
|
||||
# Managed Agents — Ruby
|
||||
|
||||
> **Bindings not shown here:** This README covers the most common managed-agents flows for Ruby. If you need a class, method, namespace, field, or behavior that isn't shown, WebFetch the Ruby SDK repo **or the relevant docs page** from `shared/live-sources.md` rather than guess. Do not extrapolate from cURL shapes or another language's SDK.
|
||||
|
||||
> **Agents are persistent — create once, reference by ID.** Store the agent ID returned by `client.beta.agents.create` and pass it to every subsequent `client.beta.sessions.create`; do not call `agents.create` in the request path. **Recommended:** define agents and environments as version-controlled YAML applied with the `ant` CLI — see `shared/anthropic-cli.md` (its live-docs URL is in `shared/live-sources.md`). The CLI owns the control plane (create/update); your code owns the data plane (sessions with the stored ID). The examples below show in-code creation for when you must provision programmatically; in production the create call belongs in setup, not in the request path.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
gem install anthropic
|
||||
```
|
||||
|
||||
## Client Initialization
|
||||
|
||||
```ruby
|
||||
require "anthropic"
|
||||
|
||||
# Default (uses ANTHROPIC_API_KEY env var)
|
||||
client = Anthropic::Client.new
|
||||
|
||||
# Explicit API key
|
||||
client = Anthropic::Client.new(api_key: "your-api-key")
|
||||
```
|
||||
|
||||
> ⚠️ **Trailing underscores:** The Ruby SDK uses `system_:` and `send_(` (trailing underscore) to avoid shadowing `Kernel#system` and `Kernel#send`. Use these forms throughout managed-agents code.
|
||||
|
||||
---
|
||||
|
||||
## Create an Environment
|
||||
|
||||
```ruby
|
||||
environment = client.beta.environments.create(
|
||||
name: "my-dev-env",
|
||||
config: {
|
||||
type: "cloud",
|
||||
networking: {type: "unrestricted"}
|
||||
}
|
||||
)
|
||||
puts "Environment ID: #{environment.id}" # env_...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Create an Agent (required first step)
|
||||
|
||||
> ⚠️ **There is no inline agent config.** `model`/`system_`/`tools` live on the agent object, not the session. Always start with `client.beta.agents.create()` — the session takes either `agent: agent.id` or the typed hash form `agent: {type: "agent", id: agent.id, version: agent.version}`.
|
||||
|
||||
### Minimal
|
||||
|
||||
```ruby
|
||||
# 1. Create the agent (reusable, versioned)
|
||||
agent = client.beta.agents.create(
|
||||
name: "Coding Assistant",
|
||||
model: :"claude-opus-5",
|
||||
system_: "You are a helpful coding assistant.",
|
||||
tools: [{type: "agent_toolset_20260401"}]
|
||||
)
|
||||
|
||||
# 2. Start a session
|
||||
session = client.beta.sessions.create(
|
||||
agent: {type: "agent", id: agent.id, version: agent.version},
|
||||
environment_id: environment.id,
|
||||
title: "Quickstart session"
|
||||
)
|
||||
puts "Session ID: #{session.id}"
|
||||
puts "Trace: https://platform.claude.com/workspaces/default/sessions/#{session.id}" # swap 'default' for your workspace ID if the API key is not in the Default workspace
|
||||
```
|
||||
|
||||
### Updating an Agent
|
||||
|
||||
Updates create new versions; the agent object is immutable per version.
|
||||
|
||||
```ruby
|
||||
updated_agent = client.beta.agents.update(
|
||||
agent.id,
|
||||
version: agent.version,
|
||||
system_: "You are a helpful coding agent. Always write tests."
|
||||
)
|
||||
puts "New version: #{updated_agent.version}"
|
||||
|
||||
# List all versions
|
||||
client.beta.agents.versions.list(agent.id).auto_paging_each do |version|
|
||||
puts "Version #{version.version}: #{version.updated_at.iso8601}"
|
||||
end
|
||||
|
||||
# Archive the agent
|
||||
archived = client.beta.agents.archive(agent.id)
|
||||
puts "Archived at: #{archived.archived_at.iso8601}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Send a User Message
|
||||
|
||||
```ruby
|
||||
client.beta.sessions.events.send_(
|
||||
session.id,
|
||||
events: [{
|
||||
type: "user.message",
|
||||
content: [{type: "text", text: "Review the auth module"}]
|
||||
}]
|
||||
)
|
||||
```
|
||||
|
||||
> 💡 **Stream-first:** Open the stream *before* (or concurrently with) sending the message. The stream only delivers events that occur after it opens — stream-after-send means early events arrive buffered in one batch. See [Steering Patterns](../../shared/managed-agents-events.md#steering-patterns).
|
||||
|
||||
---
|
||||
|
||||
## Stream Events (SSE)
|
||||
|
||||
```ruby
|
||||
# Open the stream first, then send the user message
|
||||
stream = client.beta.sessions.events.stream_events(session.id)
|
||||
|
||||
client.beta.sessions.events.send_(
|
||||
session.id,
|
||||
events: [{
|
||||
type: "user.message",
|
||||
content: [{type: "text", text: "Summarize the repo README"}]
|
||||
}]
|
||||
)
|
||||
|
||||
stream.each do |event|
|
||||
case event.type
|
||||
in :"agent.message"
|
||||
event.content.each { |block| print block.text }
|
||||
in :"agent.tool_use"
|
||||
puts "\n[Using tool: #{event.name}]"
|
||||
in :"session.status_idle"
|
||||
break
|
||||
in :"session.error"
|
||||
puts "\n[Error: #{event.error&.message || "unknown"}]"
|
||||
break
|
||||
else
|
||||
# ignore other event types
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
> ℹ️ Event `.type` is a Symbol (compare with `:"agent.message"`, not `"agent.message"`).
|
||||
|
||||
### Reconnecting and Tailing
|
||||
|
||||
When reconnecting mid-session, list past events first to dedupe, then tail live events:
|
||||
|
||||
```ruby
|
||||
require "set"
|
||||
|
||||
stream = client.beta.sessions.events.stream_events(session.id)
|
||||
|
||||
# Stream is open and buffering. List history before tailing live.
|
||||
seen_event_ids = Set.new
|
||||
client.beta.sessions.events.list(session.id).auto_paging_each { |past| seen_event_ids << past.id }
|
||||
|
||||
# Tail live events, skipping anything already seen
|
||||
stream.each do |event|
|
||||
next if seen_event_ids.include?(event.id)
|
||||
seen_event_ids << event.id
|
||||
case event.type
|
||||
in :"agent.message"
|
||||
event.content.each { |block| print block.text }
|
||||
in :"session.status_idle"
|
||||
break
|
||||
else
|
||||
# ignore other event types
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Provide Custom Tool Result
|
||||
|
||||
> ℹ️ The Ruby managed-agents bindings for `user.custom_tool_result` are not yet documented in this skill or in the apps source examples. Refer to `shared/managed-agents-events.md` for the wire format and the `anthropic` Ruby gem repository for the corresponding params.
|
||||
|
||||
---
|
||||
|
||||
## Poll Events
|
||||
|
||||
```ruby
|
||||
client.beta.sessions.events.list(session.id).auto_paging_each do |event|
|
||||
puts "#{event.type}: #{event.id}"
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Upload a File
|
||||
|
||||
```ruby
|
||||
require "pathname"
|
||||
|
||||
file = client.beta.files.upload(file: Pathname("data.csv"))
|
||||
puts "File ID: #{file.id}"
|
||||
|
||||
# Mount in a session
|
||||
session = client.beta.sessions.create(
|
||||
agent: agent.id,
|
||||
environment_id: environment.id,
|
||||
resources: [
|
||||
{
|
||||
type: "file",
|
||||
file_id: file.id,
|
||||
mount_path: "/workspace/data.csv"
|
||||
}
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
### Add and Manage Resources on an Existing Session
|
||||
|
||||
```ruby
|
||||
# Attach an additional file to an open session
|
||||
resource = client.beta.sessions.resources.add(
|
||||
session.id,
|
||||
type: "file",
|
||||
file_id: file.id
|
||||
)
|
||||
puts resource.id # "sesrsc_01ABC..."
|
||||
|
||||
# List resources on the session
|
||||
listed = client.beta.sessions.resources.list(session.id)
|
||||
listed.data.each { |entry| puts "#{entry.id} #{entry.type}" }
|
||||
|
||||
# Detach a resource
|
||||
client.beta.sessions.resources.delete(resource.id, session_id: session.id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## List and Download Session Files
|
||||
|
||||
```ruby
|
||||
files = client.beta.files.list(scope_id: "sesn_abc123", betas: ["managed-agents-2026-04-01"])
|
||||
content = client.beta.files.download(files.data[0].id)
|
||||
File.binwrite("output.txt", content.read)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Session Management
|
||||
|
||||
```ruby
|
||||
# List environments
|
||||
environments = client.beta.environments.list
|
||||
|
||||
# Retrieve a specific environment
|
||||
env = client.beta.environments.retrieve(environment.id)
|
||||
|
||||
# Archive an environment (read-only, existing sessions continue)
|
||||
client.beta.environments.archive(environment.id)
|
||||
|
||||
# Delete an environment (only if no sessions reference it)
|
||||
client.beta.environments.delete(environment.id)
|
||||
|
||||
# Delete a session
|
||||
client.beta.sessions.delete(session.id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## MCP Server Integration
|
||||
|
||||
```ruby
|
||||
# Agent declares MCP server (no auth here — auth goes in a vault)
|
||||
agent = client.beta.agents.create(
|
||||
name: "GitHub Assistant",
|
||||
model: :"claude-opus-5",
|
||||
mcp_servers: [
|
||||
{
|
||||
type: "url",
|
||||
name: "github",
|
||||
url: "https://api.githubcopilot.com/mcp/"
|
||||
}
|
||||
],
|
||||
tools: [
|
||||
{type: "agent_toolset_20260401"},
|
||||
{type: "mcp_toolset", mcp_server_name: "github"}
|
||||
]
|
||||
)
|
||||
|
||||
# Session attaches vault(s) containing credentials for those MCP server URLs
|
||||
session = client.beta.sessions.create(
|
||||
agent: {type: "agent", id: agent.id, version: agent.version},
|
||||
environment_id: environment.id,
|
||||
vault_ids: [vault.id]
|
||||
)
|
||||
```
|
||||
|
||||
See `shared/managed-agents-tools.md` §Vaults for creating vaults and adding credentials.
|
||||
|
||||
---
|
||||
|
||||
## Vaults
|
||||
|
||||
```ruby
|
||||
# Create a vault
|
||||
vault = client.beta.vaults.create(
|
||||
display_name: "Alice",
|
||||
metadata: {external_user_id: "usr_abc123"}
|
||||
)
|
||||
puts vault.id # "vlt_01ABC..."
|
||||
|
||||
# Add an OAuth credential
|
||||
credential = client.beta.vaults.credentials.create(
|
||||
vault.id,
|
||||
display_name: "Alice's Slack",
|
||||
auth: {
|
||||
type: "mcp_oauth",
|
||||
mcp_server_url: "https://mcp.slack.com/mcp",
|
||||
access_token: "xoxp-...",
|
||||
expires_at: "2026-04-15T00:00:00Z",
|
||||
refresh: {
|
||||
token_endpoint: "https://slack.com/api/oauth.v2.access",
|
||||
client_id: "1234567890.0987654321",
|
||||
scope: "channels:read chat:write",
|
||||
refresh_token: "xoxe-1-...",
|
||||
token_endpoint_auth: {
|
||||
type: "client_secret_post",
|
||||
client_secret: "abc123..."
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# Rotate the credential (e.g., after a token refresh)
|
||||
client.beta.vaults.credentials.update(
|
||||
credential.id,
|
||||
vault_id: vault.id,
|
||||
auth: {
|
||||
type: "mcp_oauth",
|
||||
access_token: "xoxp-new-...",
|
||||
expires_at: "2026-05-15T00:00:00Z",
|
||||
refresh: {refresh_token: "xoxe-1-new-..."}
|
||||
}
|
||||
)
|
||||
|
||||
# Archive a vault
|
||||
client.beta.vaults.archive(vault.id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## GitHub Repository Integration
|
||||
|
||||
Mount a GitHub repository as a session resource (a vault holds the GitHub MCP credential):
|
||||
|
||||
```ruby
|
||||
session = client.beta.sessions.create(
|
||||
agent: agent.id,
|
||||
environment_id: environment.id,
|
||||
vault_ids: [vault.id],
|
||||
resources: [
|
||||
{
|
||||
type: "github_repository",
|
||||
url: "https://github.com/org/repo",
|
||||
mount_path: "/workspace/repo",
|
||||
authorization_token: "ghp_your_github_token"
|
||||
}
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
Multiple repositories on the same session:
|
||||
|
||||
```ruby
|
||||
resources = [
|
||||
{
|
||||
type: "github_repository",
|
||||
url: "https://github.com/org/frontend",
|
||||
mount_path: "/workspace/frontend",
|
||||
authorization_token: "ghp_your_github_token"
|
||||
},
|
||||
{
|
||||
type: "github_repository",
|
||||
url: "https://github.com/org/backend",
|
||||
mount_path: "/workspace/backend",
|
||||
authorization_token: "ghp_your_github_token"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Rotating a repository's authorization token:
|
||||
|
||||
```ruby
|
||||
listed = client.beta.sessions.resources.list(session.id)
|
||||
repo_resource_id = listed.data.first.id
|
||||
|
||||
client.beta.sessions.resources.update(
|
||||
repo_resource_id,
|
||||
session_id: session.id,
|
||||
authorization_token: "ghp_your_new_github_token"
|
||||
)
|
||||
```
|
||||
Reference in New Issue
Block a user