claudient 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +42 -0
- package/CONTEXT.md +58 -0
- package/README.md +165 -0
- package/agents/build-resolvers/de/python-resolver.md +64 -0
- package/agents/build-resolvers/de/typescript-resolver.md +65 -0
- package/agents/build-resolvers/es/python-resolver.md +64 -0
- package/agents/build-resolvers/es/typescript-resolver.md +65 -0
- package/agents/build-resolvers/fr/python-resolver.md +64 -0
- package/agents/build-resolvers/fr/typescript-resolver.md +65 -0
- package/agents/build-resolvers/nl/python-resolver.md +64 -0
- package/agents/build-resolvers/nl/typescript-resolver.md +65 -0
- package/agents/build-resolvers/python-resolver.md +62 -0
- package/agents/build-resolvers/typescript-resolver.md +63 -0
- package/agents/core/architect.md +64 -0
- package/agents/core/code-reviewer.md +78 -0
- package/agents/core/de/architect.md +66 -0
- package/agents/core/de/code-reviewer.md +80 -0
- package/agents/core/de/planner.md +63 -0
- package/agents/core/de/security-reviewer.md +93 -0
- package/agents/core/es/architect.md +66 -0
- package/agents/core/es/code-reviewer.md +80 -0
- package/agents/core/es/planner.md +63 -0
- package/agents/core/es/security-reviewer.md +93 -0
- package/agents/core/fr/architect.md +66 -0
- package/agents/core/fr/code-reviewer.md +80 -0
- package/agents/core/fr/planner.md +63 -0
- package/agents/core/fr/security-reviewer.md +93 -0
- package/agents/core/nl/architect.md +66 -0
- package/agents/core/nl/code-reviewer.md +80 -0
- package/agents/core/nl/planner.md +63 -0
- package/agents/core/nl/security-reviewer.md +93 -0
- package/agents/core/planner.md +61 -0
- package/agents/core/security-reviewer.md +91 -0
- package/guides/agent-orchestration.md +231 -0
- package/guides/de/agent-orchestration.md +174 -0
- package/guides/de/getting-started.md +164 -0
- package/guides/de/hooks-cookbook.md +160 -0
- package/guides/de/memory-management.md +153 -0
- package/guides/de/security.md +180 -0
- package/guides/de/skill-authoring.md +214 -0
- package/guides/de/token-optimization.md +156 -0
- package/guides/es/agent-orchestration.md +174 -0
- package/guides/es/getting-started.md +164 -0
- package/guides/es/hooks-cookbook.md +160 -0
- package/guides/es/memory-management.md +153 -0
- package/guides/es/security.md +180 -0
- package/guides/es/skill-authoring.md +214 -0
- package/guides/es/token-optimization.md +156 -0
- package/guides/fr/agent-orchestration.md +174 -0
- package/guides/fr/getting-started.md +164 -0
- package/guides/fr/hooks-cookbook.md +227 -0
- package/guides/fr/memory-management.md +169 -0
- package/guides/fr/security.md +180 -0
- package/guides/fr/skill-authoring.md +214 -0
- package/guides/fr/token-optimization.md +158 -0
- package/guides/getting-started.md +164 -0
- package/guides/hooks-cookbook.md +423 -0
- package/guides/memory-management.md +192 -0
- package/guides/nl/agent-orchestration.md +174 -0
- package/guides/nl/getting-started.md +164 -0
- package/guides/nl/hooks-cookbook.md +160 -0
- package/guides/nl/memory-management.md +153 -0
- package/guides/nl/security.md +180 -0
- package/guides/nl/skill-authoring.md +214 -0
- package/guides/nl/token-optimization.md +156 -0
- package/guides/security.md +229 -0
- package/guides/skill-authoring.md +226 -0
- package/guides/token-optimization.md +169 -0
- package/hooks/lifecycle/cost-tracker.md +49 -0
- package/hooks/lifecycle/cost-tracker.sh +59 -0
- package/hooks/lifecycle/pre-compact-save.md +56 -0
- package/hooks/lifecycle/pre-compact-save.sh +37 -0
- package/hooks/lifecycle/session-start.md +50 -0
- package/hooks/lifecycle/session-start.sh +47 -0
- package/hooks/post-tool-use/audit-log.md +53 -0
- package/hooks/post-tool-use/audit-log.sh +53 -0
- package/hooks/post-tool-use/prettier.md +53 -0
- package/hooks/post-tool-use/prettier.sh +49 -0
- package/hooks/pre-tool-use/block-dangerous.md +48 -0
- package/hooks/pre-tool-use/block-dangerous.sh +76 -0
- package/hooks/pre-tool-use/git-push-confirm.md +46 -0
- package/hooks/pre-tool-use/git-push-confirm.sh +36 -0
- package/mcp/configs/github.json +11 -0
- package/mcp/configs/postgres.json +11 -0
- package/mcp/de/recommended-servers.md +170 -0
- package/mcp/es/recommended-servers.md +170 -0
- package/mcp/fr/recommended-servers.md +170 -0
- package/mcp/nl/recommended-servers.md +170 -0
- package/mcp/recommended-servers.md +168 -0
- package/package.json +45 -0
- package/prompts/project-starters/de/fastapi-project.md +62 -0
- package/prompts/project-starters/de/nextjs-project.md +82 -0
- package/prompts/project-starters/es/fastapi-project.md +62 -0
- package/prompts/project-starters/es/nextjs-project.md +82 -0
- package/prompts/project-starters/fastapi-project.md +60 -0
- package/prompts/project-starters/fr/fastapi-project.md +62 -0
- package/prompts/project-starters/fr/nextjs-project.md +82 -0
- package/prompts/project-starters/nextjs-project.md +80 -0
- package/prompts/project-starters/nl/fastapi-project.md +62 -0
- package/prompts/project-starters/nl/nextjs-project.md +82 -0
- package/prompts/system-prompts/ai-product.md +80 -0
- package/prompts/system-prompts/data-pipeline.md +76 -0
- package/prompts/system-prompts/de/ai-product.md +82 -0
- package/prompts/system-prompts/de/data-pipeline.md +78 -0
- package/prompts/system-prompts/de/saas-backend.md +71 -0
- package/prompts/system-prompts/es/ai-product.md +82 -0
- package/prompts/system-prompts/es/data-pipeline.md +78 -0
- package/prompts/system-prompts/es/saas-backend.md +71 -0
- package/prompts/system-prompts/fr/ai-product.md +82 -0
- package/prompts/system-prompts/fr/data-pipeline.md +78 -0
- package/prompts/system-prompts/fr/saas-backend.md +71 -0
- package/prompts/system-prompts/nl/ai-product.md +82 -0
- package/prompts/system-prompts/nl/data-pipeline.md +78 -0
- package/prompts/system-prompts/nl/saas-backend.md +71 -0
- package/prompts/system-prompts/saas-backend.md +69 -0
- package/prompts/task-specific/changelog.md +81 -0
- package/prompts/task-specific/de/changelog.md +83 -0
- package/prompts/task-specific/de/debugging.md +78 -0
- package/prompts/task-specific/de/pr-description.md +69 -0
- package/prompts/task-specific/debugging.md +76 -0
- package/prompts/task-specific/es/changelog.md +83 -0
- package/prompts/task-specific/es/debugging.md +78 -0
- package/prompts/task-specific/es/pr-description.md +69 -0
- package/prompts/task-specific/fr/changelog.md +83 -0
- package/prompts/task-specific/fr/debugging.md +78 -0
- package/prompts/task-specific/fr/pr-description.md +69 -0
- package/prompts/task-specific/nl/changelog.md +83 -0
- package/prompts/task-specific/nl/debugging.md +78 -0
- package/prompts/task-specific/nl/pr-description.md +69 -0
- package/prompts/task-specific/pr-description.md +67 -0
- package/rules/common/coding-style.md +45 -0
- package/rules/common/de/coding-style.md +47 -0
- package/rules/common/de/git.md +48 -0
- package/rules/common/de/performance.md +40 -0
- package/rules/common/de/security.md +45 -0
- package/rules/common/de/testing.md +45 -0
- package/rules/common/es/coding-style.md +47 -0
- package/rules/common/es/git.md +48 -0
- package/rules/common/es/performance.md +40 -0
- package/rules/common/es/security.md +45 -0
- package/rules/common/es/testing.md +45 -0
- package/rules/common/fr/coding-style.md +47 -0
- package/rules/common/fr/git.md +48 -0
- package/rules/common/fr/performance.md +40 -0
- package/rules/common/fr/security.md +45 -0
- package/rules/common/fr/testing.md +45 -0
- package/rules/common/git.md +46 -0
- package/rules/common/nl/coding-style.md +47 -0
- package/rules/common/nl/git.md +48 -0
- package/rules/common/nl/performance.md +40 -0
- package/rules/common/nl/security.md +45 -0
- package/rules/common/nl/testing.md +45 -0
- package/rules/common/performance.md +38 -0
- package/rules/common/security.md +43 -0
- package/rules/common/testing.md +43 -0
- package/rules/language-specific/de/go.md +48 -0
- package/rules/language-specific/de/python.md +38 -0
- package/rules/language-specific/de/typescript.md +51 -0
- package/rules/language-specific/es/go.md +48 -0
- package/rules/language-specific/es/python.md +38 -0
- package/rules/language-specific/es/typescript.md +51 -0
- package/rules/language-specific/fr/go.md +48 -0
- package/rules/language-specific/fr/python.md +38 -0
- package/rules/language-specific/fr/typescript.md +51 -0
- package/rules/language-specific/go.md +46 -0
- package/rules/language-specific/nl/go.md +48 -0
- package/rules/language-specific/nl/python.md +38 -0
- package/rules/language-specific/nl/typescript.md +51 -0
- package/rules/language-specific/python.md +36 -0
- package/rules/language-specific/typescript.md +49 -0
- package/scripts/cli.js +161 -0
- package/scripts/link-skills.sh +35 -0
- package/scripts/list-skills.sh +34 -0
- package/skills/ai-engineering/agent-construction.md +285 -0
- package/skills/ai-engineering/claude-api.md +248 -0
- package/skills/ai-engineering/de/agent-construction.md +287 -0
- package/skills/ai-engineering/de/claude-api.md +250 -0
- package/skills/ai-engineering/es/agent-construction.md +287 -0
- package/skills/ai-engineering/es/claude-api.md +250 -0
- package/skills/ai-engineering/fr/agent-construction.md +287 -0
- package/skills/ai-engineering/fr/claude-api.md +250 -0
- package/skills/ai-engineering/nl/agent-construction.md +287 -0
- package/skills/ai-engineering/nl/claude-api.md +250 -0
- package/skills/backend/dotnet/csharp.md +304 -0
- package/skills/backend/dotnet/de/csharp.md +306 -0
- package/skills/backend/dotnet/es/csharp.md +306 -0
- package/skills/backend/dotnet/fr/csharp.md +306 -0
- package/skills/backend/dotnet/nl/csharp.md +306 -0
- package/skills/backend/go/de/go.md +307 -0
- package/skills/backend/go/es/go.md +307 -0
- package/skills/backend/go/fr/go.md +307 -0
- package/skills/backend/go/go.md +305 -0
- package/skills/backend/go/nl/go.md +307 -0
- package/skills/backend/nodejs/de/nestjs.md +274 -0
- package/skills/backend/nodejs/de/nextjs.md +222 -0
- package/skills/backend/nodejs/es/nestjs.md +274 -0
- package/skills/backend/nodejs/es/nextjs.md +222 -0
- package/skills/backend/nodejs/fr/nestjs.md +274 -0
- package/skills/backend/nodejs/fr/nextjs.md +222 -0
- package/skills/backend/nodejs/nestjs.md +272 -0
- package/skills/backend/nodejs/nextjs.md +220 -0
- package/skills/backend/nodejs/nl/nestjs.md +274 -0
- package/skills/backend/nodejs/nl/nextjs.md +222 -0
- package/skills/backend/python/de/django.md +285 -0
- package/skills/backend/python/de/fastapi.md +244 -0
- package/skills/backend/python/django.md +283 -0
- package/skills/backend/python/es/django.md +285 -0
- package/skills/backend/python/es/fastapi.md +244 -0
- package/skills/backend/python/fastapi.md +242 -0
- package/skills/backend/python/fr/django.md +285 -0
- package/skills/backend/python/fr/fastapi.md +244 -0
- package/skills/backend/python/nl/django.md +285 -0
- package/skills/backend/python/nl/fastapi.md +244 -0
- package/skills/data-ml/dbt-data-pipelines.md +155 -0
- package/skills/data-ml/de/dbt-data-pipelines.md +157 -0
- package/skills/data-ml/de/pandas-polars.md +147 -0
- package/skills/data-ml/de/pytorch-tensorflow.md +171 -0
- package/skills/data-ml/es/dbt-data-pipelines.md +157 -0
- package/skills/data-ml/es/pandas-polars.md +147 -0
- package/skills/data-ml/es/pytorch-tensorflow.md +171 -0
- package/skills/data-ml/fr/dbt-data-pipelines.md +157 -0
- package/skills/data-ml/fr/pandas-polars.md +147 -0
- package/skills/data-ml/fr/pytorch-tensorflow.md +171 -0
- package/skills/data-ml/nl/dbt-data-pipelines.md +157 -0
- package/skills/data-ml/nl/pandas-polars.md +147 -0
- package/skills/data-ml/nl/pytorch-tensorflow.md +171 -0
- package/skills/data-ml/pandas-polars.md +145 -0
- package/skills/data-ml/pytorch-tensorflow.md +169 -0
- package/skills/database/de/graphql.md +181 -0
- package/skills/database/es/graphql.md +181 -0
- package/skills/database/fr/graphql.md +181 -0
- package/skills/database/graphql.md +179 -0
- package/skills/database/nl/graphql.md +181 -0
- package/skills/devops-infra/de/docker.md +133 -0
- package/skills/devops-infra/de/github-actions.md +179 -0
- package/skills/devops-infra/de/kubernetes.md +129 -0
- package/skills/devops-infra/de/terraform.md +130 -0
- package/skills/devops-infra/docker.md +131 -0
- package/skills/devops-infra/es/docker.md +133 -0
- package/skills/devops-infra/es/github-actions.md +179 -0
- package/skills/devops-infra/es/kubernetes.md +129 -0
- package/skills/devops-infra/es/terraform.md +130 -0
- package/skills/devops-infra/fr/docker.md +133 -0
- package/skills/devops-infra/fr/github-actions.md +179 -0
- package/skills/devops-infra/fr/kubernetes.md +129 -0
- package/skills/devops-infra/fr/terraform.md +130 -0
- package/skills/devops-infra/github-actions.md +177 -0
- package/skills/devops-infra/kubernetes.md +127 -0
- package/skills/devops-infra/nl/docker.md +133 -0
- package/skills/devops-infra/nl/github-actions.md +179 -0
- package/skills/devops-infra/nl/kubernetes.md +129 -0
- package/skills/devops-infra/nl/terraform.md +130 -0
- package/skills/devops-infra/terraform.md +128 -0
- package/skills/finance-payments/de/stripe.md +187 -0
- package/skills/finance-payments/es/stripe.md +187 -0
- package/skills/finance-payments/fr/stripe.md +187 -0
- package/skills/finance-payments/nl/stripe.md +187 -0
- package/skills/finance-payments/stripe.md +185 -0
- package/workflows/code-review.md +151 -0
- package/workflows/de/code-review.md +153 -0
- package/workflows/de/debugging-session.md +146 -0
- package/workflows/de/feature-development.md +155 -0
- package/workflows/de/new-project-bootstrap.md +175 -0
- package/workflows/de/refactor-safely.md +150 -0
- package/workflows/debugging-session.md +144 -0
- package/workflows/es/code-review.md +153 -0
- package/workflows/es/debugging-session.md +146 -0
- package/workflows/es/feature-development.md +155 -0
- package/workflows/es/new-project-bootstrap.md +175 -0
- package/workflows/es/refactor-safely.md +150 -0
- package/workflows/feature-development.md +153 -0
- package/workflows/fr/code-review.md +153 -0
- package/workflows/fr/debugging-session.md +146 -0
- package/workflows/fr/feature-development.md +155 -0
- package/workflows/fr/new-project-bootstrap.md +175 -0
- package/workflows/fr/refactor-safely.md +150 -0
- package/workflows/new-project-bootstrap.md +173 -0
- package/workflows/nl/code-review.md +153 -0
- package/workflows/nl/debugging-session.md +146 -0
- package/workflows/nl/feature-development.md +155 -0
- package/workflows/nl/new-project-bootstrap.md +175 -0
- package/workflows/nl/refactor-safely.md +150 -0
- package/workflows/refactor-safely.md +148 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
> 🇳🇱 Dit is de Nederlandse vertaling. [Engelse versie](../claude-api.md).
|
|
2
|
+
|
|
3
|
+
# Claude API Skill
|
|
4
|
+
|
|
5
|
+
## Wanneer te activeren
|
|
6
|
+
- Code schrijven die de Anthropic Claude API aanroept (Python of TypeScript SDK)
|
|
7
|
+
- Prompt-caching, streaming of batchverwerking implementeren
|
|
8
|
+
- Beheer van gesprekken met meerdere beurten ontwerpen
|
|
9
|
+
- Het juiste Claude-model (Haiku, Sonnet, Opus) kiezen voor een taak
|
|
10
|
+
- Toolgebruik / function calling toevoegen aan een Claude-integratie
|
|
11
|
+
- Optimaliseren voor kosten of latentie in een productie-Claude-app
|
|
12
|
+
|
|
13
|
+
## Wanneer NIET te gebruiken
|
|
14
|
+
- OpenAI of andere provider-API's — andere SDK, andere patronen
|
|
15
|
+
- Algemeen LLM-advies dat niet gerelateerd is aan de Anthropic API
|
|
16
|
+
- Projecten die al LangChain of LlamaIndex-abstracties gebruiken — adresseer de abstractielaag in plaats daarvan
|
|
17
|
+
|
|
18
|
+
## Instructies
|
|
19
|
+
|
|
20
|
+
### Modelselectiegids
|
|
21
|
+
| Model | Gebruik wanneer | Vermijd wanneer |
|
|
22
|
+
|-------|----------|------------|
|
|
23
|
+
| `claude-haiku-4-5-20251001` | Classificatie, extractie, routing, eenvoudige Q&A, hoog-volume goedkoop | Complexe redenering, meerstaps codegeneratie |
|
|
24
|
+
| `claude-sonnet-4-6` | Algemeen gebruik: code, analyse, schrijven, agentische workflows | Token-beperkte budgetten op massale schaal |
|
|
25
|
+
| `claude-opus-4-7` | Expertniveau-redenering, genuanceerd oordeel, complexe lange tekst | De meeste taken — Sonnet is meestal voldoende |
|
|
26
|
+
|
|
27
|
+
### Basis berichtaanroep (Python)
|
|
28
|
+
```python
|
|
29
|
+
import anthropic
|
|
30
|
+
|
|
31
|
+
client = anthropic.Anthropic() # leest ANTHROPIC_API_KEY uit omgeving
|
|
32
|
+
|
|
33
|
+
message = client.messages.create(
|
|
34
|
+
model="claude-sonnet-4-6",
|
|
35
|
+
max_tokens=1024,
|
|
36
|
+
system="You are a helpful assistant specialized in Python.",
|
|
37
|
+
messages=[
|
|
38
|
+
{"role": "user", "content": "Explain Python's GIL in 3 sentences."}
|
|
39
|
+
]
|
|
40
|
+
)
|
|
41
|
+
print(message.content[0].text)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Prompt-caching (kritisch voor kosten)
|
|
45
|
+
Prompt-caching kan kosten met maximaal 90% verlagen voor herhaalde context. Cache stabiele inhoud (systeemprompts, grote documenten, few-shot-voorbeelden).
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
message = client.messages.create(
|
|
49
|
+
model="claude-sonnet-4-6",
|
|
50
|
+
max_tokens=1024,
|
|
51
|
+
system=[
|
|
52
|
+
{
|
|
53
|
+
"type": "text",
|
|
54
|
+
"text": "You are a code review assistant. Here are our coding standards: ...",
|
|
55
|
+
"cache_control": {"type": "ephemeral"} # Cache dit blok
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
messages=[
|
|
59
|
+
{
|
|
60
|
+
"role": "user",
|
|
61
|
+
"content": [
|
|
62
|
+
{
|
|
63
|
+
"type": "text",
|
|
64
|
+
"text": large_document,
|
|
65
|
+
"cache_control": {"type": "ephemeral"} # Cache ook het document
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"type": "text",
|
|
69
|
+
"text": "Summarize the key points."
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
)
|
|
75
|
+
# Controleer cachegebruik in respons
|
|
76
|
+
print(message.usage.cache_read_input_tokens) # tokens gelezen uit cache
|
|
77
|
+
print(message.usage.cache_creation_input_tokens) # tokens geschreven naar cache
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Cacheregels:
|
|
81
|
+
- Minimaal cacheerbaar blok: 1024 tokens (Sonnet/Opus), 2048 tokens (Haiku)
|
|
82
|
+
- Cache-TTL: 5 minuten
|
|
83
|
+
- Alleen het laatste `cache_control`-blok in een berichtarray telt — cachepunten zijn cumulatief
|
|
84
|
+
|
|
85
|
+
### Streaming
|
|
86
|
+
```python
|
|
87
|
+
with client.messages.stream(
|
|
88
|
+
model="claude-sonnet-4-6",
|
|
89
|
+
max_tokens=1024,
|
|
90
|
+
messages=[{"role": "user", "content": prompt}]
|
|
91
|
+
) as stream:
|
|
92
|
+
for text in stream.text_stream:
|
|
93
|
+
print(text, end="", flush=True)
|
|
94
|
+
|
|
95
|
+
# Of met events:
|
|
96
|
+
with client.messages.stream(...) as stream:
|
|
97
|
+
for event in stream:
|
|
98
|
+
if event.type == "content_block_delta":
|
|
99
|
+
print(event.delta.text, end="")
|
|
100
|
+
elif event.type == "message_stop":
|
|
101
|
+
print() # nieuwe regel wanneer klaar
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Toolgebruik
|
|
105
|
+
```python
|
|
106
|
+
tools = [
|
|
107
|
+
{
|
|
108
|
+
"name": "get_weather",
|
|
109
|
+
"description": "Get current weather for a city",
|
|
110
|
+
"input_schema": {
|
|
111
|
+
"type": "object",
|
|
112
|
+
"properties": {
|
|
113
|
+
"city": {"type": "string", "description": "City name"},
|
|
114
|
+
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
|
|
115
|
+
},
|
|
116
|
+
"required": ["city"]
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
response = client.messages.create(
|
|
122
|
+
model="claude-sonnet-4-6",
|
|
123
|
+
max_tokens=1024,
|
|
124
|
+
tools=tools,
|
|
125
|
+
messages=[{"role": "user", "content": "What's the weather in Paris?"}]
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# Controleer of Claude een tool wil gebruiken
|
|
129
|
+
if response.stop_reason == "tool_use":
|
|
130
|
+
tool_use = next(b for b in response.content if b.type == "tool_use")
|
|
131
|
+
tool_result = call_tool(tool_use.name, tool_use.input)
|
|
132
|
+
|
|
133
|
+
# Ga door met gesprek met toolresultaat
|
|
134
|
+
follow_up = client.messages.create(
|
|
135
|
+
model="claude-sonnet-4-6",
|
|
136
|
+
max_tokens=1024,
|
|
137
|
+
tools=tools,
|
|
138
|
+
messages=[
|
|
139
|
+
{"role": "user", "content": "What's the weather in Paris?"},
|
|
140
|
+
{"role": "assistant", "content": response.content},
|
|
141
|
+
{
|
|
142
|
+
"role": "user",
|
|
143
|
+
"content": [{
|
|
144
|
+
"type": "tool_result",
|
|
145
|
+
"tool_use_id": tool_use.id,
|
|
146
|
+
"content": json.dumps(tool_result)
|
|
147
|
+
}]
|
|
148
|
+
}
|
|
149
|
+
]
|
|
150
|
+
)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Gesprek met meerdere beurten
|
|
154
|
+
```python
|
|
155
|
+
class Conversation:
|
|
156
|
+
def __init__(self, system: str, model: str = "claude-sonnet-4-6"):
|
|
157
|
+
self.client = anthropic.Anthropic()
|
|
158
|
+
self.model = model
|
|
159
|
+
self.system = system
|
|
160
|
+
self.messages: list[dict] = []
|
|
161
|
+
|
|
162
|
+
def chat(self, user_message: str, max_tokens: int = 1024) -> str:
|
|
163
|
+
self.messages.append({"role": "user", "content": user_message})
|
|
164
|
+
response = self.client.messages.create(
|
|
165
|
+
model=self.model,
|
|
166
|
+
max_tokens=max_tokens,
|
|
167
|
+
system=self.system,
|
|
168
|
+
messages=self.messages,
|
|
169
|
+
)
|
|
170
|
+
assistant_message = response.content[0].text
|
|
171
|
+
self.messages.append({"role": "assistant", "content": assistant_message})
|
|
172
|
+
return assistant_message
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Batchverwerking
|
|
176
|
+
```python
|
|
177
|
+
from anthropic.types.message_create_params import MessageCreateParamsNonStreaming
|
|
178
|
+
from anthropic.types.messages.batch_create_params import Request
|
|
179
|
+
|
|
180
|
+
requests = [
|
|
181
|
+
Request(
|
|
182
|
+
custom_id=f"review-{i}",
|
|
183
|
+
params=MessageCreateParamsNonStreaming(
|
|
184
|
+
model="claude-haiku-4-5-20251001",
|
|
185
|
+
max_tokens=256,
|
|
186
|
+
messages=[{"role": "user", "content": f"Classify: {review}"}],
|
|
187
|
+
)
|
|
188
|
+
)
|
|
189
|
+
for i, review in enumerate(reviews)
|
|
190
|
+
]
|
|
191
|
+
|
|
192
|
+
batch = client.messages.batches.create(requests=requests)
|
|
193
|
+
print(f"Batch ID: {batch.id}")
|
|
194
|
+
|
|
195
|
+
# Poll voor resultaten (of gebruik webhooks)
|
|
196
|
+
import time
|
|
197
|
+
while True:
|
|
198
|
+
batch = client.messages.batches.retrieve(batch.id)
|
|
199
|
+
if batch.processing_status == "ended":
|
|
200
|
+
break
|
|
201
|
+
time.sleep(60)
|
|
202
|
+
|
|
203
|
+
for result in client.messages.batches.results(batch.id):
|
|
204
|
+
print(result.custom_id, result.result.message.content[0].text)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Foutafhandeling en herhaalpogingen
|
|
208
|
+
```python
|
|
209
|
+
from anthropic import APIStatusError, APITimeoutError, RateLimitError
|
|
210
|
+
|
|
211
|
+
def call_with_retry(client, **kwargs, max_retries=3):
|
|
212
|
+
for attempt in range(max_retries):
|
|
213
|
+
try:
|
|
214
|
+
return client.messages.create(**kwargs)
|
|
215
|
+
except RateLimitError:
|
|
216
|
+
wait = 2 ** attempt
|
|
217
|
+
time.sleep(wait)
|
|
218
|
+
except APITimeoutError:
|
|
219
|
+
if attempt == max_retries - 1:
|
|
220
|
+
raise
|
|
221
|
+
time.sleep(1)
|
|
222
|
+
except APIStatusError as e:
|
|
223
|
+
if e.status_code >= 500 and attempt < max_retries - 1:
|
|
224
|
+
time.sleep(2 ** attempt)
|
|
225
|
+
else:
|
|
226
|
+
raise
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Kostenoptimalisatie-checklist
|
|
230
|
+
- Gebruik Haiku voor classificatie, routing en eenvoudige extractietaken
|
|
231
|
+
- Schakel prompt-caching in voor elke systeemprompt > 1024 tokens
|
|
232
|
+
- Gebruik de batch API voor offline/async-workloads — 50% kostenvermindering
|
|
233
|
+
- Stel `max_tokens` in op het minimum dat nodig is — je betaalt voor gegenereerde output-tokens
|
|
234
|
+
- Cache grote documenten in het gebruikersbericht, niet alleen de systeemprompt
|
|
235
|
+
- Monitor de verhouding `cache_read_input_tokens` vs `input_tokens` — streef naar >80% voor stabiele contexten
|
|
236
|
+
|
|
237
|
+
## Voorbeeld
|
|
238
|
+
|
|
239
|
+
**Gebruiker:** Bouw een Python-klasse die klantenservicetickets indeelt in categorieën met Claude, met prompt-caching voor de categorielijst en streaming voor de uitleg.
|
|
240
|
+
|
|
241
|
+
**Verwachte output:**
|
|
242
|
+
- `TicketClassifier`-klasse met `ANTHROPIC_API_KEY` uit omgeving
|
|
243
|
+
- Systeemprompt met alle categorieën gecacht via `cache_control: ephemeral`
|
|
244
|
+
- `classify(ticket_text)` → retourneert `{category: str, confidence: str}` geparseerd uit gestructureerde output
|
|
245
|
+
- `classify_and_explain(ticket_text)` → streamt de uitleg naar stdout
|
|
246
|
+
- Gebruikt `claude-haiku-4-5-20251001` voor classificatie (kostenefficiënt), `claude-sonnet-4-6` voor uitleg
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
> **Werk met ons:** Claudient wordt ondersteund door [Uitbreiden](https://uitbreiden.com/) — we bouwen AI-producten en B2B-oplossingen met ontwikkelaarsgemeenschappen. [uitbreiden.com](https://uitbreiden.com/)
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# C#/.NET Skill
|
|
2
|
+
|
|
3
|
+
## When to activate
|
|
4
|
+
- Building a .NET Web API (minimal API or controller-based)
|
|
5
|
+
- Setting up Entity Framework Core with migrations
|
|
6
|
+
- Configuring the .NET dependency injection container
|
|
7
|
+
- Writing background services with `IHostedService` or `BackgroundService`
|
|
8
|
+
- Implementing middleware pipeline components
|
|
9
|
+
- Writing LINQ queries and understanding deferred execution
|
|
10
|
+
- Setting up async/await correctly in ASP.NET Core
|
|
11
|
+
|
|
12
|
+
## When NOT to use
|
|
13
|
+
- Node.js or Python services
|
|
14
|
+
- .NET Framework (pre-.NET 5) legacy codebases — patterns differ
|
|
15
|
+
- Blazor or MAUI frontend — different concerns
|
|
16
|
+
- Unity game development — different runtime
|
|
17
|
+
|
|
18
|
+
## Instructions
|
|
19
|
+
|
|
20
|
+
### Project structure
|
|
21
|
+
```
|
|
22
|
+
MyApi/
|
|
23
|
+
├── MyApi.sln
|
|
24
|
+
├── src/
|
|
25
|
+
│ └── MyApi/
|
|
26
|
+
│ ├── Program.cs # Entry point + DI container
|
|
27
|
+
│ ├── appsettings.json
|
|
28
|
+
│ ├── appsettings.Development.json
|
|
29
|
+
│ ├── Controllers/ # Controller-based API
|
|
30
|
+
│ ├── Endpoints/ # Minimal API extensions
|
|
31
|
+
│ ├── Models/ # EF Core entities
|
|
32
|
+
│ ├── DTOs/ # Request/response shapes
|
|
33
|
+
│ ├── Services/ # Business logic interfaces + implementations
|
|
34
|
+
│ ├── Data/
|
|
35
|
+
│ │ └── AppDbContext.cs
|
|
36
|
+
│ └── Middleware/
|
|
37
|
+
└── tests/
|
|
38
|
+
└── MyApi.Tests/
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Program.cs — minimal API setup
|
|
42
|
+
```csharp
|
|
43
|
+
// Program.cs — .NET 6+ top-level statements + minimal API
|
|
44
|
+
var builder = WebApplication.CreateBuilder(args);
|
|
45
|
+
|
|
46
|
+
// Register services
|
|
47
|
+
builder.Services.AddDbContext<AppDbContext>(options =>
|
|
48
|
+
options.UseNpgsql(builder.Configuration.GetConnectionString("Default")));
|
|
49
|
+
|
|
50
|
+
builder.Services.AddScoped<IUserService, UserService>();
|
|
51
|
+
builder.Services.AddControllers();
|
|
52
|
+
builder.Services.AddEndpointsApiExplorer();
|
|
53
|
+
builder.Services.AddSwaggerGen();
|
|
54
|
+
|
|
55
|
+
var app = builder.Build();
|
|
56
|
+
|
|
57
|
+
if (app.Environment.IsDevelopment())
|
|
58
|
+
{
|
|
59
|
+
app.UseSwagger();
|
|
60
|
+
app.UseSwaggerUI();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
app.UseHttpsRedirection();
|
|
64
|
+
app.UseAuthentication();
|
|
65
|
+
app.UseAuthorization();
|
|
66
|
+
app.MapControllers();
|
|
67
|
+
|
|
68
|
+
// Minimal API endpoints
|
|
69
|
+
app.MapGroup("/api/v1").MapUserEndpoints();
|
|
70
|
+
|
|
71
|
+
app.Run();
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### EF Core entity + DbContext
|
|
75
|
+
```csharp
|
|
76
|
+
// Models/User.cs
|
|
77
|
+
public class User
|
|
78
|
+
{
|
|
79
|
+
public Guid Id { get; set; } = Guid.NewGuid();
|
|
80
|
+
public required string Email { get; set; }
|
|
81
|
+
public required string PasswordHash { get; set; }
|
|
82
|
+
public bool IsActive { get; set; } = true;
|
|
83
|
+
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
|
84
|
+
|
|
85
|
+
public ICollection<Post> Posts { get; set; } = [];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Data/AppDbContext.cs
|
|
89
|
+
public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
|
|
90
|
+
{
|
|
91
|
+
public DbSet<User> Users => Set<User>();
|
|
92
|
+
public DbSet<Post> Posts => Set<Post>();
|
|
93
|
+
|
|
94
|
+
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
95
|
+
{
|
|
96
|
+
modelBuilder.Entity<User>(e =>
|
|
97
|
+
{
|
|
98
|
+
e.HasIndex(u => u.Email).IsUnique();
|
|
99
|
+
e.Property(u => u.Email).HasMaxLength(320);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Dependency injection — services
|
|
106
|
+
```csharp
|
|
107
|
+
// Services/IUserService.cs
|
|
108
|
+
public interface IUserService
|
|
109
|
+
{
|
|
110
|
+
Task<UserDto> GetByIdAsync(Guid id, CancellationToken ct = default);
|
|
111
|
+
Task<UserDto> CreateAsync(CreateUserRequest request, CancellationToken ct = default);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Services/UserService.cs
|
|
115
|
+
public class UserService(AppDbContext db) : IUserService
|
|
116
|
+
{
|
|
117
|
+
public async Task<UserDto> GetByIdAsync(Guid id, CancellationToken ct = default)
|
|
118
|
+
{
|
|
119
|
+
var user = await db.Users
|
|
120
|
+
.AsNoTracking()
|
|
121
|
+
.FirstOrDefaultAsync(u => u.Id == id, ct)
|
|
122
|
+
?? throw new NotFoundException($"User {id} not found");
|
|
123
|
+
|
|
124
|
+
return new UserDto(user.Id, user.Email, user.CreatedAt);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
public async Task<UserDto> CreateAsync(CreateUserRequest request, CancellationToken ct = default)
|
|
128
|
+
{
|
|
129
|
+
if (await db.Users.AnyAsync(u => u.Email == request.Email, ct))
|
|
130
|
+
throw new ConflictException("Email already in use");
|
|
131
|
+
|
|
132
|
+
var user = new User
|
|
133
|
+
{
|
|
134
|
+
Email = request.Email,
|
|
135
|
+
PasswordHash = BCrypt.Net.BCrypt.HashPassword(request.Password)
|
|
136
|
+
};
|
|
137
|
+
db.Users.Add(user);
|
|
138
|
+
await db.SaveChangesAsync(ct);
|
|
139
|
+
return new UserDto(user.Id, user.Email, user.CreatedAt);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Controller-based API
|
|
145
|
+
```csharp
|
|
146
|
+
[ApiController]
|
|
147
|
+
[Route("api/v1/[controller]")]
|
|
148
|
+
public class UsersController(IUserService userService) : ControllerBase
|
|
149
|
+
{
|
|
150
|
+
[HttpGet("{id:guid}")]
|
|
151
|
+
[ProducesResponseType<UserDto>(StatusCodes.Status200OK)]
|
|
152
|
+
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
153
|
+
public async Task<IActionResult> GetUser(Guid id, CancellationToken ct)
|
|
154
|
+
{
|
|
155
|
+
var user = await userService.GetByIdAsync(id, ct);
|
|
156
|
+
return Ok(user);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
[HttpPost]
|
|
160
|
+
[ProducesResponseType<UserDto>(StatusCodes.Status201Created)]
|
|
161
|
+
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
|
162
|
+
[ProducesResponseType(StatusCodes.Status409Conflict)]
|
|
163
|
+
public async Task<IActionResult> CreateUser(
|
|
164
|
+
[FromBody] CreateUserRequest request,
|
|
165
|
+
CancellationToken ct)
|
|
166
|
+
{
|
|
167
|
+
var user = await userService.CreateAsync(request, ct);
|
|
168
|
+
return CreatedAtAction(nameof(GetUser), new { id = user.Id }, user);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Minimal API endpoints (extension method pattern)
|
|
174
|
+
```csharp
|
|
175
|
+
// Endpoints/UserEndpoints.cs
|
|
176
|
+
public static class UserEndpoints
|
|
177
|
+
{
|
|
178
|
+
public static RouteGroupBuilder MapUserEndpoints(this RouteGroupBuilder group)
|
|
179
|
+
{
|
|
180
|
+
var users = group.MapGroup("/users").WithTags("Users");
|
|
181
|
+
|
|
182
|
+
users.MapGet("/{id:guid}", async (Guid id, IUserService svc, CancellationToken ct) =>
|
|
183
|
+
{
|
|
184
|
+
var user = await svc.GetByIdAsync(id, ct);
|
|
185
|
+
return Results.Ok(user);
|
|
186
|
+
})
|
|
187
|
+
.WithName("GetUser")
|
|
188
|
+
.Produces<UserDto>();
|
|
189
|
+
|
|
190
|
+
return group;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Middleware
|
|
196
|
+
```csharp
|
|
197
|
+
// Middleware/RequestLoggingMiddleware.cs
|
|
198
|
+
public class RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
|
|
199
|
+
{
|
|
200
|
+
public async Task InvokeAsync(HttpContext context)
|
|
201
|
+
{
|
|
202
|
+
var sw = Stopwatch.StartNew();
|
|
203
|
+
try
|
|
204
|
+
{
|
|
205
|
+
await next(context);
|
|
206
|
+
}
|
|
207
|
+
finally
|
|
208
|
+
{
|
|
209
|
+
sw.Stop();
|
|
210
|
+
logger.LogInformation(
|
|
211
|
+
"{Method} {Path} {StatusCode} in {Elapsed}ms",
|
|
212
|
+
context.Request.Method,
|
|
213
|
+
context.Request.Path,
|
|
214
|
+
context.Response.StatusCode,
|
|
215
|
+
sw.ElapsedMilliseconds);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Register in Program.cs before other middleware:
|
|
221
|
+
app.UseMiddleware<RequestLoggingMiddleware>();
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Background services
|
|
225
|
+
```csharp
|
|
226
|
+
// Services/CleanupService.cs
|
|
227
|
+
public class CleanupService(IServiceProvider services, ILogger<CleanupService> logger)
|
|
228
|
+
: BackgroundService
|
|
229
|
+
{
|
|
230
|
+
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
231
|
+
{
|
|
232
|
+
while (!stoppingToken.IsCancellationRequested)
|
|
233
|
+
{
|
|
234
|
+
await DoCleanupAsync(stoppingToken);
|
|
235
|
+
await Task.Delay(TimeSpan.FromHours(1), stoppingToken);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
private async Task DoCleanupAsync(CancellationToken ct)
|
|
240
|
+
{
|
|
241
|
+
// Use a new scope for each iteration — BackgroundService is singleton
|
|
242
|
+
using var scope = services.CreateScope();
|
|
243
|
+
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
|
244
|
+
var cutoff = DateTimeOffset.UtcNow.AddDays(-30);
|
|
245
|
+
await db.Sessions.Where(s => s.ExpiresAt < cutoff).ExecuteDeleteAsync(ct);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Register: builder.Services.AddHostedService<CleanupService>();
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### LINQ best practices
|
|
253
|
+
```csharp
|
|
254
|
+
// Always use AsNoTracking() for read-only queries
|
|
255
|
+
var users = await db.Users.AsNoTracking().Where(u => u.IsActive).ToListAsync(ct);
|
|
256
|
+
|
|
257
|
+
// Select only needed columns — avoid loading full entities for projections
|
|
258
|
+
var emails = await db.Users
|
|
259
|
+
.Where(u => u.IsActive)
|
|
260
|
+
.Select(u => u.Email)
|
|
261
|
+
.ToListAsync(ct);
|
|
262
|
+
|
|
263
|
+
// Use ExecuteUpdateAsync/ExecuteDeleteAsync for bulk ops — skips loading entities
|
|
264
|
+
await db.Users
|
|
265
|
+
.Where(u => !u.IsActive && u.CreatedAt < cutoff)
|
|
266
|
+
.ExecuteDeleteAsync(ct);
|
|
267
|
+
|
|
268
|
+
// Avoid N+1: use Include() for related data
|
|
269
|
+
var posts = await db.Posts
|
|
270
|
+
.Include(p => p.Author)
|
|
271
|
+
.Include(p => p.Tags)
|
|
272
|
+
.Where(p => p.Published)
|
|
273
|
+
.AsNoTracking()
|
|
274
|
+
.ToListAsync(ct);
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### DTOs and records
|
|
278
|
+
```csharp
|
|
279
|
+
// Use records for immutable DTOs
|
|
280
|
+
public record UserDto(Guid Id, string Email, DateTimeOffset CreatedAt);
|
|
281
|
+
public record CreateUserRequest(
|
|
282
|
+
[property: Required, EmailAddress] string Email,
|
|
283
|
+
[property: Required, MinLength(8)] string Password
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
// Response types with problem details (built-in .NET)
|
|
287
|
+
// Return Results.Problem() or throw exceptions caught by middleware
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Example
|
|
291
|
+
|
|
292
|
+
**User:** Add a `BlogPost` resource to a .NET Web API: CRUD endpoints, EF Core entity, migrations, and a background job that publishes scheduled posts.
|
|
293
|
+
|
|
294
|
+
**Expected output:**
|
|
295
|
+
- `Models/BlogPost.cs` — entity with `Id`, `Title`, `Body`, `AuthorId` (FK to User), `PublishedAt` (nullable), `ScheduledFor` (nullable)
|
|
296
|
+
- `DTOs/BlogPostDtos.cs` — `BlogPostDto` record, `CreateBlogPostRequest` record with `[Required]` validation
|
|
297
|
+
- `Services/IBlogPostService.cs` + `BlogPostService.cs` — CRUD methods, `GetPendingScheduledAsync` for background job
|
|
298
|
+
- `Controllers/BlogPostsController.cs` — all CRUD with proper status codes
|
|
299
|
+
- `Services/PostPublisherService.cs` — `BackgroundService` that checks every minute and publishes due posts
|
|
300
|
+
- EF Core migration: `dotnet ef migrations add AddBlogPosts`
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
> **Work with us:** Claudient is backed by [Uitbreiden](https://uitbreiden.com/) — we build AI products and B2B solutions with developer communities. [uitbreiden.com](https://uitbreiden.com/)
|