+28
-13
@@ -12,13 +12,20 @@ npm install @earendil-works/pi-agent-core
|
||||
|
||||
```typescript
|
||||
import { Agent } from "@earendil-works/pi-agent-core";
|
||||
import { getModel } from "@earendil-works/pi-ai";
|
||||
import { createModels } from "@earendil-works/pi-ai";
|
||||
import { anthropicProvider } from "@earendil-works/pi-ai/providers/anthropic";
|
||||
|
||||
const models = createModels();
|
||||
models.setProvider(anthropicProvider());
|
||||
const model = models.getModel("anthropic", "claude-sonnet-4-6");
|
||||
if (!model) throw new Error("Model not found");
|
||||
|
||||
const agent = new Agent({
|
||||
initialState: {
|
||||
systemPrompt: "You are a helpful assistant.",
|
||||
model: getModel("anthropic", "claude-sonnet-4-20250514"),
|
||||
model,
|
||||
},
|
||||
streamFunction: models.streamSimple.bind(models),
|
||||
});
|
||||
|
||||
agent.subscribe((event) => {
|
||||
@@ -115,13 +122,19 @@ Tools can also return `terminate: true` to hint that the automatic follow-up LLM
|
||||
Low-level loop callers can set `shouldStopAfterTurn` to stop gracefully after the current turn completes:
|
||||
|
||||
```typescript
|
||||
const stream = agentLoop(prompts, context, {
|
||||
model,
|
||||
convertToLlm,
|
||||
shouldStopAfterTurn: async ({ message, toolResults, context, newMessages }) => {
|
||||
return shouldCompactBeforeNextTurn(context.messages);
|
||||
const stream = agentLoop(
|
||||
prompts,
|
||||
context,
|
||||
{
|
||||
model,
|
||||
convertToLlm,
|
||||
shouldStopAfterTurn: async ({ message, toolResults, context, newMessages }) => {
|
||||
return shouldCompactBeforeNextTurn(context.messages);
|
||||
},
|
||||
},
|
||||
});
|
||||
undefined,
|
||||
models.streamSimple.bind(models),
|
||||
);
|
||||
```
|
||||
|
||||
`shouldStopAfterTurn` runs after `turn_end` is emitted and after the assistant response and any tool executions have completed normally. If it returns `true`, the loop emits `agent_end` and exits before polling steering or follow-up queues, and before starting another LLM call. It does not abort the provider stream, does not cancel running tools, and does not alter the assistant message stop reason.
|
||||
@@ -181,8 +194,8 @@ const agent = new Agent({
|
||||
// Follow-up mode: "one-at-a-time" (default) or "all"
|
||||
followUpMode: "one-at-a-time",
|
||||
|
||||
// Custom stream function (for proxy backends)
|
||||
streamFn: streamProxy,
|
||||
// Required stream function
|
||||
streamFunction: models.streamSimple.bind(models),
|
||||
|
||||
// Session ID for provider caching
|
||||
sessionId: "session-123",
|
||||
@@ -369,6 +382,7 @@ Handle custom types in `convertToLlm`:
|
||||
|
||||
```typescript
|
||||
const agent = new Agent({
|
||||
streamFunction: models.streamSimple.bind(models),
|
||||
convertToLlm: (messages) => messages.flatMap(m => {
|
||||
if (m.role === "notification") return []; // Filter out
|
||||
return [m];
|
||||
@@ -439,7 +453,7 @@ For browser apps that proxy through a backend:
|
||||
import { Agent, streamProxy } from "@earendil-works/pi-agent-core";
|
||||
|
||||
const agent = new Agent({
|
||||
streamFn: (model, context, options) =>
|
||||
streamFunction: (model, context, options) =>
|
||||
streamProxy(model, context, {
|
||||
...options,
|
||||
authToken: "...",
|
||||
@@ -471,12 +485,13 @@ const config: AgentLoopConfig = {
|
||||
|
||||
const userMessage = { role: "user", content: "Hello", timestamp: Date.now() };
|
||||
|
||||
for await (const event of agentLoop([userMessage], context, config)) {
|
||||
const streamFunction = models.streamSimple.bind(models);
|
||||
for await (const event of agentLoop([userMessage], context, config, undefined, streamFunction)) {
|
||||
console.log(event.type);
|
||||
}
|
||||
|
||||
// Continue from existing context
|
||||
for await (const event of agentLoopContinue(context, config)) {
|
||||
for await (const event of agentLoopContinue(context, config, undefined, streamFunction)) {
|
||||
console.log(event.type);
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user