This commit is contained in:
192
.agents/skills/ax-signature/SKILL.md
Normal file
192
.agents/skills/ax-signature/SKILL.md
Normal file
@@ -0,0 +1,192 @@
|
||||
---
|
||||
name: ax-signature
|
||||
description: This skill helps an LLM generate correct DSPy signature code using @ax-llm/ax. Use when the user asks about signatures, s(), f(), field types, string syntax, fluent builder API, validation constraints, or type-safe inputs/outputs.
|
||||
version: "19.0.33"
|
||||
---
|
||||
|
||||
# Ax Signature Reference
|
||||
|
||||
## Signature Syntax
|
||||
|
||||
```
|
||||
[description] input1:type, input2:type -> output1:type, output2:type
|
||||
```
|
||||
|
||||
## Field Types
|
||||
|
||||
| Type | Syntax | TypeScript | Example |
|
||||
|------|--------|-----------|---------|
|
||||
| String | `:string` | `string` | `userName:string` |
|
||||
| Number | `:number` | `number` | `score:number` |
|
||||
| Boolean | `:boolean` | `boolean` | `isValid:boolean` |
|
||||
| JSON | `:json` | `any` | `metadata:json` |
|
||||
| Date | `:date` | `Date` | `birthDate:date` |
|
||||
| DateTime | `:datetime` | `Date` | `timestamp:datetime` |
|
||||
| Image | `:image` | `{mimeType, data}` | `photo:image` (input only) |
|
||||
| Audio | `:audio` | `{format?, data}` | `recording:audio` (input only) |
|
||||
| File | `:file` | `{mimeType, data}` | `document:file` (input only) |
|
||||
| URL | `:url` | `string` | `website:url` |
|
||||
| Code | `:code` | `string` | `pythonScript:code` |
|
||||
| Class | `:class "a, b, c"` | `"a" \| "b" \| "c"` | `mood:class "happy, sad"` |
|
||||
|
||||
## Arrays, Optional, and Internal Fields
|
||||
|
||||
```typescript
|
||||
'tags:string[] -> processedTags:string[]' // arrays
|
||||
'query:string, context?:string -> response:string' // optional with ?
|
||||
'problem:string -> reasoning!:string, solution:string' // internal with !
|
||||
```
|
||||
|
||||
## Three Ways to Create Signatures
|
||||
|
||||
### 1. String-Based (Recommended for simple cases)
|
||||
|
||||
```typescript
|
||||
import { ax, s } from '@ax-llm/ax';
|
||||
const gen = ax('input:string -> output:string');
|
||||
const sig = s('query:string -> response:string');
|
||||
```
|
||||
|
||||
### 2. Pure Fluent Builder API
|
||||
|
||||
```typescript
|
||||
import { f } from '@ax-llm/ax';
|
||||
const sig = f()
|
||||
.input('userMessage', f.string('User input'))
|
||||
.input('contextData', f.string('Additional context').optional())
|
||||
.input('tags', f.string('Keywords').array())
|
||||
.output('responseText', f.string('AI response'))
|
||||
.output('confidenceScore', f.number('Confidence 0-1'))
|
||||
.output('debugInfo', f.string('Debug info').internal())
|
||||
.build();
|
||||
```
|
||||
|
||||
### 3. Hybrid
|
||||
|
||||
```typescript
|
||||
import { s, f } from '@ax-llm/ax';
|
||||
const sig = s('base:string -> result:string')
|
||||
.appendInputField('extra', f.json('Metadata').optional())
|
||||
.appendOutputField('score', f.number('Quality score'));
|
||||
```
|
||||
|
||||
## Fluent API Reference
|
||||
|
||||
Type creators:
|
||||
- `f.string(desc)`, `f.number(desc)`, `f.boolean(desc)`, `f.json(desc)`
|
||||
- `f.image(desc)`, `f.audio(desc)`, `f.file(desc)`, `f.url(desc)`
|
||||
- `f.email(desc)`, `f.date(desc)`, `f.datetime(desc)`
|
||||
- `f.class(['a','b','c'], desc)`, `f.code(desc)`
|
||||
- `f.object({ field: f.string() }, desc)`
|
||||
|
||||
Chainable modifiers (method chaining only, no nesting):
|
||||
- `.optional()` - make field optional
|
||||
- `.array()` / `.array('list description')` - make field an array
|
||||
- `.internal()` - output only, hidden from final output
|
||||
- `.cache()` - input only, mark for prompt caching
|
||||
|
||||
```typescript
|
||||
// Correct: pure fluent chaining
|
||||
f.string('description').optional().array()
|
||||
f.string('context').cache().optional()
|
||||
f.object({ field: f.string() }, 'item desc').array('list desc')
|
||||
|
||||
// Wrong: nested function calls (removed)
|
||||
f.array(f.string('description')) // REMOVED
|
||||
f.optional(f.string('description')) // REMOVED
|
||||
f.internal(f.string('description')) // REMOVED
|
||||
```
|
||||
|
||||
## Validation Constraints
|
||||
|
||||
### String Constraints
|
||||
|
||||
```typescript
|
||||
f.string('username').min(3).max(20)
|
||||
f.string('email').email()
|
||||
f.string('website').url()
|
||||
f.string('birthDate').date()
|
||||
f.string('timestamp').datetime()
|
||||
f.string('pattern').regex('^[A-Z0-9]')
|
||||
```
|
||||
|
||||
### Number Constraints
|
||||
|
||||
```typescript
|
||||
f.number('age').min(18).max(120)
|
||||
f.number('score').min(0).max(100)
|
||||
```
|
||||
|
||||
### Complete Validation Example
|
||||
|
||||
```typescript
|
||||
const sig = f()
|
||||
.input('formData', f.string('Raw form data'))
|
||||
.output('user', f.object({
|
||||
username: f.string('Username').min(3).max(20),
|
||||
email: f.string('Email').email(),
|
||||
age: f.number('Age').min(18).max(120),
|
||||
bio: f.string('Bio').max(500).optional(),
|
||||
website: f.string('Website').url().optional(),
|
||||
tags: f.string('Tag').min(2).max(30).array()
|
||||
}, 'User profile'))
|
||||
.build();
|
||||
```
|
||||
|
||||
## Cached Input Fields
|
||||
|
||||
```typescript
|
||||
const sig = f()
|
||||
.input('staticContext', f.string('Context').cache())
|
||||
.input('userQuery', f.string('Dynamic query'))
|
||||
.output('answer', f.string('Response'))
|
||||
.build();
|
||||
```
|
||||
|
||||
## Field Naming Rules
|
||||
|
||||
Good: `userQuestion`, `customerEmail`, `analysisResult`, `confidenceScore`
|
||||
Bad: `text`, `data`, `input`, `output`, `a`, `x`, `val` (too generic), `1field` (starts with number)
|
||||
|
||||
## Media Type Restrictions
|
||||
|
||||
- Media types (image, audio, file) are **top-level input fields only**
|
||||
- Cannot be nested in objects
|
||||
- Cannot be output fields
|
||||
|
||||
## Common Patterns
|
||||
|
||||
```typescript
|
||||
// Chain of Thought
|
||||
'problem:string -> reasoning!:string, solution:string'
|
||||
|
||||
// Classification
|
||||
'email:string -> priority:class "urgent, normal, low"'
|
||||
|
||||
// Multi-modal
|
||||
'imageData:image, question?:string -> description:string, objects:string[]'
|
||||
|
||||
// Data Extraction
|
||||
'invoiceText:string -> invoiceNumber:string, totalAmount:number, lineItems:json[]'
|
||||
|
||||
// With description
|
||||
'"Answer TypeScript questions" question:string -> answer:string, confidence:number'
|
||||
```
|
||||
|
||||
## Critical Rules
|
||||
|
||||
- Use `f()` fluent builder, NOT nested `f.array(f.string())` -- those are removed.
|
||||
- Field names must be descriptive (not generic like `text`, `data`, `input`).
|
||||
- Media types are input-only, top-level only.
|
||||
- `.internal()` is output-only (for chain-of-thought reasoning).
|
||||
- `.cache()` is input-only (for prompt caching).
|
||||
- Validation errors trigger auto-retry with correction feedback.
|
||||
- `f.email()`, `f.url()`, `f.date()`, `f.datetime()` are shorthand for `f.string().email()` etc.
|
||||
|
||||
## Examples
|
||||
|
||||
Fetch these for full working code:
|
||||
|
||||
- [Fluent Signature](https://raw.githubusercontent.com/ax-llm/ax/refs/heads/main/src/examples/fluent-signature-example.ts) — fluent f() API
|
||||
- [Structured Output](https://raw.githubusercontent.com/ax-llm/ax/refs/heads/main/src/examples/structured_output.ts) — structured output with validation
|
||||
- [Debug Schema](https://raw.githubusercontent.com/ax-llm/ax/refs/heads/main/src/examples/debug_schema.ts) — JSON schema validation
|
||||
Reference in New Issue
Block a user