@falai/agent 0.3.10 → 0.3.12
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/README.md +192 -16
- package/dist/adapters/PrismaAdapter.d.ts +115 -0
- package/dist/adapters/PrismaAdapter.d.ts.map +1 -0
- package/dist/adapters/PrismaAdapter.js +331 -0
- package/dist/adapters/PrismaAdapter.js.map +1 -0
- package/dist/adapters/index.d.ts +6 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +5 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/cjs/adapters/PrismaAdapter.d.ts +115 -0
- package/dist/cjs/adapters/PrismaAdapter.d.ts.map +1 -0
- package/dist/cjs/adapters/PrismaAdapter.js +335 -0
- package/dist/cjs/adapters/PrismaAdapter.js.map +1 -0
- package/dist/cjs/adapters/index.d.ts +6 -0
- package/dist/cjs/adapters/index.d.ts.map +1 -0
- package/dist/cjs/adapters/index.js +9 -0
- package/dist/cjs/adapters/index.js.map +1 -0
- package/dist/cjs/core/Agent.d.ts +35 -0
- package/dist/cjs/core/Agent.d.ts.map +1 -1
- package/dist/cjs/core/Agent.js +153 -0
- package/dist/cjs/core/Agent.js.map +1 -1
- package/dist/cjs/core/PersistenceManager.d.ts +77 -0
- package/dist/cjs/core/PersistenceManager.d.ts.map +1 -0
- package/dist/cjs/core/PersistenceManager.js +153 -0
- package/dist/cjs/core/PersistenceManager.js.map +1 -0
- package/dist/cjs/index.d.ts +6 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +8 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/providers/AnthropicProvider.d.ts +43 -0
- package/dist/cjs/providers/AnthropicProvider.d.ts.map +1 -0
- package/dist/cjs/providers/AnthropicProvider.js +328 -0
- package/dist/cjs/providers/AnthropicProvider.js.map +1 -0
- package/dist/cjs/providers/GeminiProvider.d.ts +4 -1
- package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/cjs/providers/GeminiProvider.js +96 -0
- package/dist/cjs/providers/GeminiProvider.js.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.d.ts +4 -1
- package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.js +115 -0
- package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.d.ts +4 -1
- package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.js +115 -0
- package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
- package/dist/cjs/providers/index.d.ts +13 -0
- package/dist/cjs/providers/index.d.ts.map +1 -0
- package/dist/cjs/providers/index.js +16 -0
- package/dist/cjs/providers/index.js.map +1 -0
- package/dist/cjs/types/agent.d.ts +3 -0
- package/dist/cjs/types/agent.d.ts.map +1 -1
- package/dist/cjs/types/agent.js.map +1 -1
- package/dist/cjs/types/ai.d.ts +28 -0
- package/dist/cjs/types/ai.d.ts.map +1 -1
- package/dist/cjs/types/index.d.ts +1 -0
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/persistence.d.ts +194 -0
- package/dist/cjs/types/persistence.d.ts.map +1 -0
- package/dist/cjs/types/persistence.js +7 -0
- package/dist/cjs/types/persistence.js.map +1 -0
- package/dist/core/Agent.d.ts +35 -0
- package/dist/core/Agent.d.ts.map +1 -1
- package/dist/core/Agent.js +153 -0
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/PersistenceManager.d.ts +77 -0
- package/dist/core/PersistenceManager.d.ts.map +1 -0
- package/dist/core/PersistenceManager.js +149 -0
- package/dist/core/PersistenceManager.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/providers/AnthropicProvider.d.ts +43 -0
- package/dist/providers/AnthropicProvider.d.ts.map +1 -0
- package/dist/providers/AnthropicProvider.js +321 -0
- package/dist/providers/AnthropicProvider.js.map +1 -0
- package/dist/providers/GeminiProvider.d.ts +4 -1
- package/dist/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/providers/GeminiProvider.js +96 -0
- package/dist/providers/GeminiProvider.js.map +1 -1
- package/dist/providers/OpenAIProvider.d.ts +4 -1
- package/dist/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/providers/OpenAIProvider.js +115 -0
- package/dist/providers/OpenAIProvider.js.map +1 -1
- package/dist/providers/OpenRouterProvider.d.ts +4 -1
- package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/providers/OpenRouterProvider.js +115 -0
- package/dist/providers/OpenRouterProvider.js.map +1 -1
- package/dist/providers/index.d.ts +13 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +9 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/types/agent.d.ts +3 -0
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/agent.js.map +1 -1
- package/dist/types/ai.d.ts +28 -0
- package/dist/types/ai.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/persistence.d.ts +194 -0
- package/dist/types/persistence.d.ts.map +1 -0
- package/dist/types/persistence.js +6 -0
- package/dist/types/persistence.js.map +1 -0
- package/docs/API_REFERENCE.md +260 -2
- package/docs/PERSISTENCE.md +419 -0
- package/docs/PROVIDERS.md +139 -2
- package/examples/business-onboarding.ts +5 -4
- package/examples/declarative-agent.ts +1 -1
- package/examples/domain-scoping.ts +5 -4
- package/examples/healthcare-agent.ts +4 -4
- package/examples/openai-agent.ts +6 -4
- package/examples/prisma-persistence.ts +313 -0
- package/examples/prisma-schema.example.prisma +74 -0
- package/examples/rules-prohibitions.ts +4 -4
- package/examples/streaming-agent.ts +371 -0
- package/examples/travel-agent.ts +7 -4
- package/package.json +10 -1
- package/src/adapters/PrismaAdapter.ts +510 -0
- package/src/adapters/index.ts +10 -0
- package/src/core/Agent.ts +205 -0
- package/src/core/PersistenceManager.ts +222 -0
- package/src/index.ts +23 -0
- package/src/providers/AnthropicProvider.ts +467 -0
- package/src/providers/GeminiProvider.ts +135 -0
- package/src/providers/OpenAIProvider.ts +157 -0
- package/src/providers/OpenRouterProvider.ts +157 -0
- package/src/providers/index.ts +16 -0
- package/src/types/agent.ts +3 -0
- package/src/types/ai.ts +32 -0
- package/src/types/index.ts +14 -0
- package/src/types/persistence.ts +234 -0
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
AiProvider,
|
|
10
10
|
GenerateMessageInput,
|
|
11
11
|
GenerateMessageOutput,
|
|
12
|
+
GenerateMessageStreamChunk,
|
|
12
13
|
AgentStructuredResponse,
|
|
13
14
|
} from "../types/ai";
|
|
14
15
|
import { withTimeoutAndRetry } from "../utils/retry";
|
|
@@ -164,6 +165,12 @@ export class OpenAIProvider implements AiProvider {
|
|
|
164
165
|
return this.generateWithBackup(input);
|
|
165
166
|
}
|
|
166
167
|
|
|
168
|
+
async *generateMessageStream<TContext = unknown>(
|
|
169
|
+
input: GenerateMessageInput<TContext>
|
|
170
|
+
): AsyncGenerator<GenerateMessageStreamChunk> {
|
|
171
|
+
yield* this.generateStreamWithBackup(input);
|
|
172
|
+
}
|
|
173
|
+
|
|
167
174
|
private async generateWithBackup<TContext = unknown>(
|
|
168
175
|
input: GenerateMessageInput<TContext>
|
|
169
176
|
): Promise<GenerateMessageOutput> {
|
|
@@ -353,4 +360,154 @@ export class OpenAIProvider implements AiProvider {
|
|
|
353
360
|
`OpenAI ${model}`
|
|
354
361
|
);
|
|
355
362
|
}
|
|
363
|
+
|
|
364
|
+
private async *generateStreamWithBackup<TContext = unknown>(
|
|
365
|
+
input: GenerateMessageInput<TContext>
|
|
366
|
+
): AsyncGenerator<GenerateMessageStreamChunk> {
|
|
367
|
+
// Try primary model first
|
|
368
|
+
try {
|
|
369
|
+
yield* this.generateStreamWithModel(this.primaryModel, input);
|
|
370
|
+
} catch (primaryError: unknown) {
|
|
371
|
+
const primaryErrMsg = getErrorMessage(primaryError);
|
|
372
|
+
console.warn(
|
|
373
|
+
`[OPENAI] Primary model ${this.primaryModel} failed: ${primaryErrMsg}`
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
if (!shouldUseBackupModel(primaryError)) {
|
|
377
|
+
throw primaryError;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
console.log(`[OPENAI] Trying backup models for streaming`);
|
|
381
|
+
|
|
382
|
+
let lastBackupError: unknown = primaryError;
|
|
383
|
+
|
|
384
|
+
for (let i = 0; i < this.backupModels.length; i++) {
|
|
385
|
+
const backupModel = this.backupModels[i];
|
|
386
|
+
console.log(
|
|
387
|
+
`[OPENAI] Trying backup model ${i + 1}/${
|
|
388
|
+
this.backupModels.length
|
|
389
|
+
}: ${backupModel}`
|
|
390
|
+
);
|
|
391
|
+
|
|
392
|
+
try {
|
|
393
|
+
yield* this.generateStreamWithModel(backupModel, input);
|
|
394
|
+
console.log(`[OPENAI] Backup model ${backupModel} succeeded`);
|
|
395
|
+
return;
|
|
396
|
+
} catch (backupError: unknown) {
|
|
397
|
+
const backupErrMsg = getErrorMessage(backupError);
|
|
398
|
+
console.warn(
|
|
399
|
+
`[OPENAI] Backup model ${backupModel} failed: ${backupErrMsg}`
|
|
400
|
+
);
|
|
401
|
+
lastBackupError = backupError;
|
|
402
|
+
|
|
403
|
+
if (
|
|
404
|
+
!shouldUseBackupModel(backupError) &&
|
|
405
|
+
i < this.backupModels.length - 1
|
|
406
|
+
) {
|
|
407
|
+
console.log(
|
|
408
|
+
`[OPENAI] Backup model error doesn't qualify for further attempts`
|
|
409
|
+
);
|
|
410
|
+
break;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const lastBackupErrMsg = getErrorMessage(lastBackupError);
|
|
416
|
+
console.error(
|
|
417
|
+
`[OPENAI] All models failed. Primary: ${primaryErrMsg}, Last backup: ${lastBackupErrMsg}`
|
|
418
|
+
);
|
|
419
|
+
throw lastBackupError;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
private async *generateStreamWithModel<TContext = unknown>(
|
|
424
|
+
model: string,
|
|
425
|
+
input: GenerateMessageInput<TContext>
|
|
426
|
+
): AsyncGenerator<GenerateMessageStreamChunk> {
|
|
427
|
+
const params = {
|
|
428
|
+
...this.config,
|
|
429
|
+
model,
|
|
430
|
+
messages: [
|
|
431
|
+
{
|
|
432
|
+
role: "user" as const,
|
|
433
|
+
content: input.prompt,
|
|
434
|
+
},
|
|
435
|
+
],
|
|
436
|
+
stream: true as const,
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
// Override with input parameters if provided
|
|
440
|
+
if (input.parameters?.maxOutputTokens !== undefined) {
|
|
441
|
+
params.max_tokens = input.parameters.maxOutputTokens;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Use JSON mode if requested
|
|
445
|
+
// Note: OpenAI streaming doesn't support the responses.parse API,
|
|
446
|
+
// so we use response_format with JSON mode instead
|
|
447
|
+
if (input.parameters?.jsonMode) {
|
|
448
|
+
params.response_format = { type: "json_object" };
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
const stream = await this.client.chat.completions.create(params);
|
|
452
|
+
|
|
453
|
+
let accumulated = "";
|
|
454
|
+
let currentModel = model;
|
|
455
|
+
let finishReason: string | undefined;
|
|
456
|
+
let promptTokens: number | undefined;
|
|
457
|
+
let completionTokens: number | undefined;
|
|
458
|
+
let totalTokens: number | undefined;
|
|
459
|
+
|
|
460
|
+
for await (const chunk of stream) {
|
|
461
|
+
currentModel = chunk.model;
|
|
462
|
+
const delta = chunk.choices[0]?.delta?.content || "";
|
|
463
|
+
|
|
464
|
+
if (delta) {
|
|
465
|
+
accumulated += delta;
|
|
466
|
+
yield {
|
|
467
|
+
delta,
|
|
468
|
+
accumulated,
|
|
469
|
+
done: false,
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (chunk.choices[0]?.finish_reason) {
|
|
474
|
+
finishReason = chunk.choices[0].finish_reason;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// OpenAI includes usage in the final chunk for some models
|
|
478
|
+
if (chunk.usage) {
|
|
479
|
+
promptTokens = chunk.usage.prompt_tokens;
|
|
480
|
+
completionTokens = chunk.usage.completion_tokens;
|
|
481
|
+
totalTokens = chunk.usage.total_tokens;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Parse JSON response if JSON mode was enabled
|
|
486
|
+
let structured: AgentStructuredResponse | undefined;
|
|
487
|
+
if (input.parameters?.jsonMode && accumulated) {
|
|
488
|
+
try {
|
|
489
|
+
structured = JSON.parse(accumulated) as AgentStructuredResponse;
|
|
490
|
+
} catch (error) {
|
|
491
|
+
console.warn(
|
|
492
|
+
"[OPENAI] Failed to parse JSON response in stream:",
|
|
493
|
+
error
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Yield final chunk
|
|
499
|
+
yield {
|
|
500
|
+
delta: "",
|
|
501
|
+
accumulated,
|
|
502
|
+
done: true,
|
|
503
|
+
metadata: {
|
|
504
|
+
model: currentModel,
|
|
505
|
+
finishReason,
|
|
506
|
+
tokensUsed: totalTokens,
|
|
507
|
+
promptTokens,
|
|
508
|
+
completionTokens,
|
|
509
|
+
},
|
|
510
|
+
structured,
|
|
511
|
+
};
|
|
512
|
+
}
|
|
356
513
|
}
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
AgentStructuredResponse,
|
|
12
12
|
GenerateMessageInput,
|
|
13
13
|
GenerateMessageOutput,
|
|
14
|
+
GenerateMessageStreamChunk,
|
|
14
15
|
} from "../types/ai";
|
|
15
16
|
import { withTimeoutAndRetry } from "../utils/retry";
|
|
16
17
|
|
|
@@ -174,6 +175,12 @@ export class OpenRouterProvider implements AiProvider {
|
|
|
174
175
|
return this.generateWithBackup(input);
|
|
175
176
|
}
|
|
176
177
|
|
|
178
|
+
async *generateMessageStream<TContext = unknown>(
|
|
179
|
+
input: GenerateMessageInput<TContext>
|
|
180
|
+
): AsyncGenerator<GenerateMessageStreamChunk> {
|
|
181
|
+
yield* this.generateStreamWithBackup(input);
|
|
182
|
+
}
|
|
183
|
+
|
|
177
184
|
private async generateWithBackup<TContext = unknown>(
|
|
178
185
|
input: GenerateMessageInput<TContext>
|
|
179
186
|
): Promise<GenerateMessageOutput> {
|
|
@@ -363,4 +370,154 @@ export class OpenRouterProvider implements AiProvider {
|
|
|
363
370
|
`OpenRouter ${model}`
|
|
364
371
|
);
|
|
365
372
|
}
|
|
373
|
+
|
|
374
|
+
private async *generateStreamWithBackup<TContext = unknown>(
|
|
375
|
+
input: GenerateMessageInput<TContext>
|
|
376
|
+
): AsyncGenerator<GenerateMessageStreamChunk> {
|
|
377
|
+
// Try primary model first
|
|
378
|
+
try {
|
|
379
|
+
yield* this.generateStreamWithModel(this.primaryModel, input);
|
|
380
|
+
} catch (primaryError: unknown) {
|
|
381
|
+
const primaryErrMsg = getErrorMessage(primaryError);
|
|
382
|
+
console.warn(
|
|
383
|
+
`[OPENROUTER] Primary model ${this.primaryModel} failed: ${primaryErrMsg}`
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
if (!shouldUseBackupModel(primaryError)) {
|
|
387
|
+
throw primaryError;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
console.log(`[OPENROUTER] Trying backup models for streaming`);
|
|
391
|
+
|
|
392
|
+
let lastBackupError: unknown = primaryError;
|
|
393
|
+
|
|
394
|
+
for (let i = 0; i < this.backupModels.length; i++) {
|
|
395
|
+
const backupModel = this.backupModels[i];
|
|
396
|
+
console.log(
|
|
397
|
+
`[OPENROUTER] Trying backup model ${i + 1}/${
|
|
398
|
+
this.backupModels.length
|
|
399
|
+
}: ${backupModel}`
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
try {
|
|
403
|
+
yield* this.generateStreamWithModel(backupModel, input);
|
|
404
|
+
console.log(`[OPENROUTER] Backup model ${backupModel} succeeded`);
|
|
405
|
+
return;
|
|
406
|
+
} catch (backupError: unknown) {
|
|
407
|
+
const backupErrMsg = getErrorMessage(backupError);
|
|
408
|
+
console.warn(
|
|
409
|
+
`[OPENROUTER] Backup model ${backupModel} failed: ${backupErrMsg}`
|
|
410
|
+
);
|
|
411
|
+
lastBackupError = backupError;
|
|
412
|
+
|
|
413
|
+
if (
|
|
414
|
+
!shouldUseBackupModel(backupError) &&
|
|
415
|
+
i < this.backupModels.length - 1
|
|
416
|
+
) {
|
|
417
|
+
console.log(
|
|
418
|
+
`[OPENROUTER] Backup model error doesn't qualify for further attempts`
|
|
419
|
+
);
|
|
420
|
+
break;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const lastBackupErrMsg = getErrorMessage(lastBackupError);
|
|
426
|
+
console.error(
|
|
427
|
+
`[OPENROUTER] All models failed. Primary: ${primaryErrMsg}, Last backup: ${lastBackupErrMsg}`
|
|
428
|
+
);
|
|
429
|
+
throw lastBackupError;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
private async *generateStreamWithModel<TContext = unknown>(
|
|
434
|
+
model: string,
|
|
435
|
+
input: GenerateMessageInput<TContext>
|
|
436
|
+
): AsyncGenerator<GenerateMessageStreamChunk> {
|
|
437
|
+
const params = {
|
|
438
|
+
...this.config,
|
|
439
|
+
model,
|
|
440
|
+
messages: [
|
|
441
|
+
{
|
|
442
|
+
role: "user" as const,
|
|
443
|
+
content: input.prompt,
|
|
444
|
+
},
|
|
445
|
+
],
|
|
446
|
+
stream: true as const,
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
// Override with input parameters if provided
|
|
450
|
+
if (input.parameters?.maxOutputTokens !== undefined) {
|
|
451
|
+
params.max_tokens = input.parameters.maxOutputTokens;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Use JSON mode if requested
|
|
455
|
+
// Note: OpenRouter streaming doesn't support the responses.parse API,
|
|
456
|
+
// so we use response_format with JSON mode instead
|
|
457
|
+
if (input.parameters?.jsonMode) {
|
|
458
|
+
params.response_format = { type: "json_object" };
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const stream = await this.client.chat.completions.create(params);
|
|
462
|
+
|
|
463
|
+
let accumulated = "";
|
|
464
|
+
let currentModel = model;
|
|
465
|
+
let finishReason: string | undefined;
|
|
466
|
+
let promptTokens: number | undefined;
|
|
467
|
+
let completionTokens: number | undefined;
|
|
468
|
+
let totalTokens: number | undefined;
|
|
469
|
+
|
|
470
|
+
for await (const chunk of stream) {
|
|
471
|
+
currentModel = chunk.model;
|
|
472
|
+
const delta = chunk.choices[0]?.delta?.content || "";
|
|
473
|
+
|
|
474
|
+
if (delta) {
|
|
475
|
+
accumulated += delta;
|
|
476
|
+
yield {
|
|
477
|
+
delta,
|
|
478
|
+
accumulated,
|
|
479
|
+
done: false,
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (chunk.choices[0]?.finish_reason) {
|
|
484
|
+
finishReason = chunk.choices[0].finish_reason;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// OpenRouter may include usage in the final chunk
|
|
488
|
+
if (chunk.usage) {
|
|
489
|
+
promptTokens = chunk.usage.prompt_tokens;
|
|
490
|
+
completionTokens = chunk.usage.completion_tokens;
|
|
491
|
+
totalTokens = chunk.usage.total_tokens;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Parse JSON response if JSON mode was enabled
|
|
496
|
+
let structured: AgentStructuredResponse | undefined;
|
|
497
|
+
if (input.parameters?.jsonMode && accumulated) {
|
|
498
|
+
try {
|
|
499
|
+
structured = JSON.parse(accumulated) as AgentStructuredResponse;
|
|
500
|
+
} catch (error) {
|
|
501
|
+
console.warn(
|
|
502
|
+
"[OPENROUTER] Failed to parse JSON response in stream:",
|
|
503
|
+
error
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Yield final chunk
|
|
509
|
+
yield {
|
|
510
|
+
delta: "",
|
|
511
|
+
accumulated,
|
|
512
|
+
done: true,
|
|
513
|
+
metadata: {
|
|
514
|
+
model: currentModel,
|
|
515
|
+
finishReason,
|
|
516
|
+
tokensUsed: totalTokens,
|
|
517
|
+
promptTokens,
|
|
518
|
+
completionTokens,
|
|
519
|
+
},
|
|
520
|
+
structured,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
366
523
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Provider exports
|
|
3
|
+
* Centralized export point for all AI provider implementations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { AnthropicProvider } from "./AnthropicProvider";
|
|
7
|
+
export type { AnthropicProviderOptions } from "./AnthropicProvider";
|
|
8
|
+
|
|
9
|
+
export { GeminiProvider } from "./GeminiProvider";
|
|
10
|
+
export type { GeminiProviderOptions } from "./GeminiProvider";
|
|
11
|
+
|
|
12
|
+
export { OpenAIProvider } from "./OpenAIProvider";
|
|
13
|
+
export type { OpenAIProviderOptions } from "./OpenAIProvider";
|
|
14
|
+
|
|
15
|
+
export { OpenRouterProvider } from "./OpenRouterProvider";
|
|
16
|
+
export type { OpenRouterProviderOptions } from "./OpenRouterProvider";
|
package/src/types/agent.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import type { AiProvider } from "./ai";
|
|
6
6
|
import type { ToolRef } from "./tool";
|
|
7
7
|
import type { RouteOptions } from "./route";
|
|
8
|
+
import type { PersistenceConfig } from "./persistence";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Composition mode determines how the agent processes and structures responses
|
|
@@ -85,6 +86,8 @@ export interface AgentOptions<TContext = unknown> {
|
|
|
85
86
|
routes?: RouteOptions[];
|
|
86
87
|
/** Initial observations for disambiguation */
|
|
87
88
|
observations?: ObservationOptions[];
|
|
89
|
+
/** Optional persistence configuration for auto-saving sessions and messages */
|
|
90
|
+
persistence?: PersistenceConfig;
|
|
88
91
|
}
|
|
89
92
|
|
|
90
93
|
/**
|
package/src/types/ai.ts
CHANGED
|
@@ -94,6 +94,31 @@ export interface GenerateMessageOutput {
|
|
|
94
94
|
structured?: AgentStructuredResponse;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Stream chunk from AI message generation
|
|
99
|
+
*/
|
|
100
|
+
export interface GenerateMessageStreamChunk {
|
|
101
|
+
/** The delta/chunk of the message */
|
|
102
|
+
delta: string;
|
|
103
|
+
/** Accumulated message so far */
|
|
104
|
+
accumulated: string;
|
|
105
|
+
/** Whether this is the final chunk */
|
|
106
|
+
done: boolean;
|
|
107
|
+
/** Optional metadata about generation */
|
|
108
|
+
metadata?: {
|
|
109
|
+
/** Model used */
|
|
110
|
+
model?: string;
|
|
111
|
+
/** Tokens consumed */
|
|
112
|
+
tokensUsed?: number;
|
|
113
|
+
/** Finish reason */
|
|
114
|
+
finishReason?: string;
|
|
115
|
+
/** Additional provider-specific data */
|
|
116
|
+
[key: string]: unknown;
|
|
117
|
+
};
|
|
118
|
+
/** Structured response data (only available when done=true and JSON mode is enabled) */
|
|
119
|
+
structured?: AgentStructuredResponse;
|
|
120
|
+
}
|
|
121
|
+
|
|
97
122
|
/**
|
|
98
123
|
* AI provider interface (strategy pattern)
|
|
99
124
|
*/
|
|
@@ -107,4 +132,11 @@ export interface AiProvider {
|
|
|
107
132
|
generateMessage<TContext = unknown>(
|
|
108
133
|
input: GenerateMessageInput<TContext>
|
|
109
134
|
): Promise<GenerateMessageOutput>;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Generate a message as a stream based on prompt and context
|
|
138
|
+
*/
|
|
139
|
+
generateMessageStream<TContext = unknown>(
|
|
140
|
+
input: GenerateMessageInput<TContext>
|
|
141
|
+
): AsyncGenerator<GenerateMessageStreamChunk>;
|
|
110
142
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -54,3 +54,17 @@ export { SectionStatus } from "./prompt";
|
|
|
54
54
|
|
|
55
55
|
// Observation types
|
|
56
56
|
export type { Observation, ObservationOptions } from "./observation";
|
|
57
|
+
|
|
58
|
+
// Persistence types
|
|
59
|
+
export type {
|
|
60
|
+
SessionData,
|
|
61
|
+
MessageData,
|
|
62
|
+
SessionStatus,
|
|
63
|
+
MessageRole,
|
|
64
|
+
SessionRepository,
|
|
65
|
+
MessageRepository,
|
|
66
|
+
PersistenceAdapter,
|
|
67
|
+
PersistenceConfig,
|
|
68
|
+
CreateSessionOptions,
|
|
69
|
+
SaveMessageOptions,
|
|
70
|
+
} from "./persistence";
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistence-related type definitions
|
|
3
|
+
* Support for optional database persistence (Prisma, etc.)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Event } from "./history";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Session status enum
|
|
10
|
+
*/
|
|
11
|
+
export type SessionStatus = "active" | "completed" | "abandoned";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Message role enum
|
|
15
|
+
*/
|
|
16
|
+
export type MessageRole = "user" | "agent" | "system";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Base session data structure
|
|
20
|
+
*/
|
|
21
|
+
export interface SessionData {
|
|
22
|
+
id: string;
|
|
23
|
+
userId?: string;
|
|
24
|
+
agentName?: string;
|
|
25
|
+
status: SessionStatus;
|
|
26
|
+
currentRoute?: string;
|
|
27
|
+
currentState?: string;
|
|
28
|
+
collectedData?: Record<string, unknown>;
|
|
29
|
+
messageCount?: number;
|
|
30
|
+
lastMessageAt?: Date;
|
|
31
|
+
completedAt?: Date;
|
|
32
|
+
createdAt: Date;
|
|
33
|
+
updatedAt: Date;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Base message data structure
|
|
38
|
+
*/
|
|
39
|
+
export interface MessageData {
|
|
40
|
+
id: string;
|
|
41
|
+
sessionId: string;
|
|
42
|
+
userId?: string;
|
|
43
|
+
role: MessageRole;
|
|
44
|
+
content: string;
|
|
45
|
+
route?: string;
|
|
46
|
+
state?: string;
|
|
47
|
+
toolCalls?: Array<{ toolName: string; arguments: Record<string, unknown> }>;
|
|
48
|
+
event?: Event; // Optional: store full event data
|
|
49
|
+
createdAt: Date;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Repository interface for sessions
|
|
54
|
+
* Implement this interface with your database of choice
|
|
55
|
+
*/
|
|
56
|
+
export interface SessionRepository {
|
|
57
|
+
/**
|
|
58
|
+
* Create a new session
|
|
59
|
+
*/
|
|
60
|
+
create(
|
|
61
|
+
data: Omit<SessionData, "id" | "createdAt" | "updatedAt">
|
|
62
|
+
): Promise<SessionData>;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Find session by ID
|
|
66
|
+
*/
|
|
67
|
+
findById(id: string): Promise<SessionData | null>;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Find active session by user ID
|
|
71
|
+
*/
|
|
72
|
+
findActiveByUserId(userId: string): Promise<SessionData | null>;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Find all sessions for a user
|
|
76
|
+
*/
|
|
77
|
+
findByUserId(userId: string, limit?: number): Promise<SessionData[]>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Update session
|
|
81
|
+
*/
|
|
82
|
+
update(
|
|
83
|
+
id: string,
|
|
84
|
+
data: Partial<Omit<SessionData, "id" | "createdAt">>
|
|
85
|
+
): Promise<SessionData | null>;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Update session status
|
|
89
|
+
*/
|
|
90
|
+
updateStatus(
|
|
91
|
+
id: string,
|
|
92
|
+
status: SessionStatus,
|
|
93
|
+
completedAt?: Date
|
|
94
|
+
): Promise<SessionData | null>;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Update collected data
|
|
98
|
+
*/
|
|
99
|
+
updateCollectedData(
|
|
100
|
+
id: string,
|
|
101
|
+
collectedData: Record<string, unknown>
|
|
102
|
+
): Promise<SessionData | null>;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Update current route and state
|
|
106
|
+
*/
|
|
107
|
+
updateRouteState(
|
|
108
|
+
id: string,
|
|
109
|
+
route?: string,
|
|
110
|
+
state?: string
|
|
111
|
+
): Promise<SessionData | null>;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Increment message count
|
|
115
|
+
*/
|
|
116
|
+
incrementMessageCount(id: string): Promise<SessionData | null>;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Delete session
|
|
120
|
+
*/
|
|
121
|
+
delete(id: string): Promise<boolean>;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Repository interface for messages
|
|
126
|
+
* Implement this interface with your database of choice
|
|
127
|
+
*/
|
|
128
|
+
export interface MessageRepository {
|
|
129
|
+
/**
|
|
130
|
+
* Create a new message
|
|
131
|
+
*/
|
|
132
|
+
create(data: Omit<MessageData, "id" | "createdAt">): Promise<MessageData>;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Find message by ID
|
|
136
|
+
*/
|
|
137
|
+
findById(id: string): Promise<MessageData | null>;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Find all messages for a session
|
|
141
|
+
*/
|
|
142
|
+
findBySessionId(sessionId: string, limit?: number): Promise<MessageData[]>;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Find messages for a user
|
|
146
|
+
*/
|
|
147
|
+
findByUserId(userId: string, limit?: number): Promise<MessageData[]>;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Delete message by ID
|
|
151
|
+
*/
|
|
152
|
+
delete(id: string): Promise<boolean>;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Delete all messages for a session
|
|
156
|
+
*/
|
|
157
|
+
deleteBySessionId(sessionId: string): Promise<number>;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Delete all messages for a user
|
|
161
|
+
*/
|
|
162
|
+
deleteByUserId(userId: string): Promise<number>;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Persistence adapter interface
|
|
167
|
+
* Implement this to create adapters for different databases
|
|
168
|
+
*/
|
|
169
|
+
export interface PersistenceAdapter {
|
|
170
|
+
/**
|
|
171
|
+
* Session repository
|
|
172
|
+
*/
|
|
173
|
+
readonly sessionRepository: SessionRepository;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Message repository
|
|
177
|
+
*/
|
|
178
|
+
readonly messageRepository: MessageRepository;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Initialize the adapter (create tables, indexes, etc.)
|
|
182
|
+
* Called automatically when adapter is created
|
|
183
|
+
*/
|
|
184
|
+
initialize?(): Promise<void>;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Disconnect/cleanup resources
|
|
188
|
+
*/
|
|
189
|
+
disconnect?(): Promise<void>;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Configuration for persistence
|
|
194
|
+
*/
|
|
195
|
+
export interface PersistenceConfig {
|
|
196
|
+
/**
|
|
197
|
+
* Persistence adapter instance (e.g., PrismaAdapter)
|
|
198
|
+
*/
|
|
199
|
+
adapter: PersistenceAdapter;
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Whether to auto-save messages (default: true)
|
|
203
|
+
*/
|
|
204
|
+
autoSave?: boolean;
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* User ID to associate with sessions/messages
|
|
208
|
+
* Can also be provided per-call in methods
|
|
209
|
+
*/
|
|
210
|
+
userId?: string;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Options for creating a session
|
|
215
|
+
*/
|
|
216
|
+
export interface CreateSessionOptions {
|
|
217
|
+
userId?: string;
|
|
218
|
+
agentName?: string;
|
|
219
|
+
initialData?: Record<string, unknown>;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Options for saving a message
|
|
224
|
+
*/
|
|
225
|
+
export interface SaveMessageOptions {
|
|
226
|
+
sessionId: string;
|
|
227
|
+
userId?: string;
|
|
228
|
+
role: MessageRole;
|
|
229
|
+
content: string;
|
|
230
|
+
route?: string;
|
|
231
|
+
state?: string;
|
|
232
|
+
toolCalls?: Array<{ toolName: string; arguments: Record<string, unknown> }>;
|
|
233
|
+
event?: Event;
|
|
234
|
+
}
|