mirror of
https://github.com/hanzoai/agent.git
synced 2026-09-11 21:08:51 +00:00
Runnable examples for the two SDKs that had none
Thirty-five examples in this repo and every one of them is Python. Go and TypeScript shipped clients with nothing showing how to call them, which is why an outside adopter with working SDKs in front of them wrote their own. Go's are Example functions rather than a main.go, so `go test` compiles them on every run and `go doc` attaches them to Client.Complete. An example nobody builds is prose that rots; this kind cannot drift from the API without turning the build red. TypeScript's two are in tsconfig's include for the same reason — outside it they would typecheck never. tsup takes only src/index.ts and the package ships only dist, so nothing here reaches the tarball. Both set the endpoint explicitly, and that is the point rather than boilerplate. Go's Config defaults BaseURL to api.openai.com and TypeScript's provider union names ten third parties without naming Hanzo, so an example that set only the provider would send our key to somebody else's endpoint. Worth fixing in the clients; meanwhile the examples do not teach it. Small things the examples make explicit because the first one a person copies is the one they keep: a deadline on a network call, Choices checked rather than indexed at zero, and an error printed as its message rather than as an object that can carry a key into a log. Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
package ai_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/hanzoai/agents/sdk/go/ai"
|
||||
)
|
||||
|
||||
// The shortest thing this client does: one prompt, one answer.
|
||||
//
|
||||
// BaseURL is set rather than left to the default. The zero value points at
|
||||
// api.openai.com, which is not where this estate's models are — api.hanzo.ai
|
||||
// is the one endpoint, and an example that quietly talked to somebody else's
|
||||
// would teach the wrong address.
|
||||
func ExampleClient_Complete() {
|
||||
client, err := ai.NewClient(&ai.Config{
|
||||
APIKey: os.Getenv("HANZO_API_KEY"),
|
||||
BaseURL: "https://api.hanzo.ai/v1",
|
||||
Model: "zen-3",
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("config:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// A deadline, because a model call is a network call and an example without
|
||||
// one teaches a program that can hang.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
|
||||
answer, err := client.Complete(ctx, "Name the four colours of a standard deck of cards.")
|
||||
if err != nil {
|
||||
fmt.Println("complete:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Choices is a slice and a refusal can leave it empty, so it is checked
|
||||
// rather than indexed — Choices[0] on an empty answer panics, which is a
|
||||
// worse failure than the one that produced it.
|
||||
if len(answer.Choices) == 0 {
|
||||
fmt.Println("the model returned no choices")
|
||||
return
|
||||
}
|
||||
fmt.Println(answer.Choices[0].Message.Content)
|
||||
}
|
||||
|
||||
// The same call with a system instruction and a ceiling on the reply.
|
||||
//
|
||||
// Options are variadic and each is independent, which is what lets a caller
|
||||
// add one without restating the rest.
|
||||
func ExampleClient_Complete_options() {
|
||||
client, err := ai.NewClient(&ai.Config{
|
||||
APIKey: os.Getenv("HANZO_API_KEY"),
|
||||
BaseURL: "https://api.hanzo.ai/v1",
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("config:", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
|
||||
answer, err := client.Complete(ctx, "Explain a hash map.",
|
||||
ai.WithSystem("You answer in exactly one sentence."),
|
||||
ai.WithModel("zen-3"),
|
||||
ai.WithTemperature(0),
|
||||
ai.WithMaxTokens(120),
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println("complete:", err)
|
||||
return
|
||||
}
|
||||
if len(answer.Choices) > 0 {
|
||||
fmt.Println(answer.Choices[0].Message.Content)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* The shortest thing this SDK does: one prompt, one answer.
|
||||
*
|
||||
* Run it with a key in the environment:
|
||||
*
|
||||
* HANZO_API_KEY=… npx tsx examples/complete.ts
|
||||
*
|
||||
* `baseUrl` is set rather than left to the provider default. `provider` is the
|
||||
* wire dialect — our gateway speaks the OpenAI one — and `baseUrl` is the
|
||||
* address. An example that set only the provider would talk to somebody else's
|
||||
* endpoint with our key, which is the one mistake worth designing out of a
|
||||
* first example.
|
||||
*/
|
||||
import { AIClient } from '../src/ai/AIClient.js';
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const client = new AIClient({
|
||||
provider: 'openai',
|
||||
baseUrl: 'https://api.hanzo.ai/v1',
|
||||
apiKey: process.env.HANZO_API_KEY,
|
||||
model: 'zen-3',
|
||||
temperature: 0,
|
||||
});
|
||||
|
||||
const answer = await client.generate('Name the four suits of a standard deck of cards.');
|
||||
console.log(answer);
|
||||
}
|
||||
|
||||
main().catch((error: unknown) => {
|
||||
// The message, not the object: an unhandled rejection prints a stack over a
|
||||
// string nobody reads, and a key can end up in a dumped request object.
|
||||
console.error(error instanceof Error ? error.message : String(error));
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* The same call, returning a typed object rather than prose.
|
||||
*
|
||||
* `generate` is overloaded: hand it a schema and it resolves to that shape
|
||||
* instead of a string, so the result needs no parsing and no cast.
|
||||
*
|
||||
* HANZO_API_KEY=… npx tsx examples/structured.ts
|
||||
*/
|
||||
import * as z from 'zod';
|
||||
import { AIClient } from '../src/ai/AIClient.js';
|
||||
|
||||
const Card = z.object({
|
||||
suit: z.enum(['hearts', 'diamonds', 'clubs', 'spades']),
|
||||
rank: z.string(),
|
||||
});
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const client = new AIClient({
|
||||
provider: 'openai',
|
||||
baseUrl: 'https://api.hanzo.ai/v1',
|
||||
apiKey: process.env.HANZO_API_KEY,
|
||||
model: 'zen-3',
|
||||
});
|
||||
|
||||
// The schema is the second argument's `schema` field, and the return type
|
||||
// follows from it — `card.suit` is the enum, checked at compile time.
|
||||
const card = await client.generate('Pick one playing card.', { schema: Card });
|
||||
console.log(`${card.rank} of ${card.suit}`);
|
||||
}
|
||||
|
||||
main().catch((error: unknown) => {
|
||||
console.error(error instanceof Error ? error.message : String(error));
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -15,6 +15,6 @@
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"include": ["src/**/*", "examples/**/*"],
|
||||
"exclude": ["node_modules", "dist", "tests"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user