@rine-kit/agent-core 0.1.1 → 0.1.3
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/dist/index.d.ts +1 -1
- package/dist/turn.d.ts +21 -6
- package/dist/turn.js +58 -2
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { createChatModel, isRetryable, LlmError, toLlmError } from './llm.js';
|
|
2
2
|
export type { ChatModel, LlmErrorKind, OpenAiCompatibleOptions } from './llm.js';
|
|
3
3
|
export { AgentTurnService, MAX_TOOL_ROUNDS, memoryBlock } from './turn.js';
|
|
4
|
-
export type { AgentTurns, AgentTurnServiceOptions, PromptMessage, TurnInput } from './turn.js';
|
|
4
|
+
export type { AgentTurns, AgentTurnServiceOptions, PromptMessage, ToolRecord, TurnInput, TurnReply, } from './turn.js';
|
|
5
5
|
export { toToolSet } from './tool-set.js';
|
|
6
6
|
export type { LanguageModel } from 'ai';
|
package/dist/turn.d.ts
CHANGED
|
@@ -20,6 +20,19 @@ export interface TurnInput<Ctx> {
|
|
|
20
20
|
* that has no clear question (or does not want memory) just leaves it out.
|
|
21
21
|
*/
|
|
22
22
|
query?: string;
|
|
23
|
+
/** Answer from what is already in the prompt: no tool is offered (a rewrite pass after a tool result). */
|
|
24
|
+
noTools?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** One tool call of a turn, with what it returned: for a host that checks the answer against the results. */
|
|
27
|
+
export interface ToolRecord {
|
|
28
|
+
name: string;
|
|
29
|
+
input: unknown;
|
|
30
|
+
output: unknown;
|
|
31
|
+
}
|
|
32
|
+
/** An answer and the tool calls made on the way to it. */
|
|
33
|
+
export interface TurnReply {
|
|
34
|
+
text: string;
|
|
35
|
+
calls: ToolRecord[];
|
|
23
36
|
}
|
|
24
37
|
/** The lines a plugin recalled, as a block of the system prompt that cannot pass for instructions. */
|
|
25
38
|
export declare function memoryBlock(lines: string[]): string;
|
|
@@ -32,9 +45,12 @@ export interface AgentTurns<Ctx> {
|
|
|
32
45
|
/** Prompt fragments of the loaded plugins; the host puts them into its system prompt. */
|
|
33
46
|
readonly instructions: string[];
|
|
34
47
|
/** The finished answer of the last round (tool rounds before it are not part of the text). */
|
|
35
|
-
reply(input: TurnInput<Ctx>): Promise<
|
|
36
|
-
|
|
37
|
-
|
|
48
|
+
reply(input: TurnInput<Ctx>): Promise<TurnReply>;
|
|
49
|
+
/**
|
|
50
|
+
* The same answer, handed over while it is written: `onText` gets the whole text of the round being written so
|
|
51
|
+
* far (it starts over when a new round begins after a tool call). Resolves with the finished answer.
|
|
52
|
+
*/
|
|
53
|
+
replyStream(input: TurnInput<Ctx>, onText: (soFar: string) => void): Promise<TurnReply>;
|
|
38
54
|
/** The words of every round as they arrive; tool calls run between the rounds. */
|
|
39
55
|
speech(input: TurnInput<Ctx>): AsyncGenerator<string, void, void>;
|
|
40
56
|
}
|
|
@@ -59,9 +75,8 @@ export declare class AgentTurnService<Ctx> implements AgentTurns<Ctx> {
|
|
|
59
75
|
/** What the plugins remember that bears on the question, as a prompt block (empty when nothing). */
|
|
60
76
|
private recalled;
|
|
61
77
|
private agent;
|
|
62
|
-
reply(input: TurnInput<Ctx>): Promise<
|
|
63
|
-
|
|
64
|
-
}>;
|
|
78
|
+
reply(input: TurnInput<Ctx>): Promise<TurnReply>;
|
|
79
|
+
replyStream(input: TurnInput<Ctx>, onText: (soFar: string) => void): Promise<TurnReply>;
|
|
65
80
|
/**
|
|
66
81
|
* Tells the plugins' observe hooks about a finished turn. Fire and forget: learning must never delay
|
|
67
82
|
* the answer, and a cancelled turn teaches nothing.
|
package/dist/turn.js
CHANGED
|
@@ -57,7 +57,7 @@ export class AgentTurnService {
|
|
|
57
57
|
]
|
|
58
58
|
.filter(Boolean)
|
|
59
59
|
.join('\n\n');
|
|
60
|
-
const tools = this.plugins?.toolCount ? toToolSet(this.plugins, input.ctx) : undefined;
|
|
60
|
+
const tools = this.plugins?.toolCount && !input.noTools ? toToolSet(this.plugins, input.ctx) : undefined;
|
|
61
61
|
const agent = new ToolLoopAgent({
|
|
62
62
|
model: this.options.model,
|
|
63
63
|
instructions: system || undefined,
|
|
@@ -85,12 +85,54 @@ export class AgentTurnService {
|
|
|
85
85
|
throw new LlmError('empty', `the model returned nothing (${result.finishReason})`);
|
|
86
86
|
}
|
|
87
87
|
this.observe(input, text);
|
|
88
|
-
return { text };
|
|
88
|
+
return { text, calls: toolRecords(result.steps) };
|
|
89
89
|
}
|
|
90
90
|
catch (err) {
|
|
91
91
|
throw toLlmError(err, input.signal);
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
+
async replyStream(input, onText) {
|
|
95
|
+
const { agent, messages } = await this.agent(input);
|
|
96
|
+
let produced = false;
|
|
97
|
+
let round = '';
|
|
98
|
+
try {
|
|
99
|
+
const result = await agent.stream({ messages, abortSignal: input.signal });
|
|
100
|
+
for await (const part of result.fullStream) {
|
|
101
|
+
if (part.type === 'start-step') {
|
|
102
|
+
round = '';
|
|
103
|
+
}
|
|
104
|
+
else if (part.type === 'text-delta') {
|
|
105
|
+
if (!part.text)
|
|
106
|
+
continue;
|
|
107
|
+
produced = true;
|
|
108
|
+
round += part.text;
|
|
109
|
+
onText(round);
|
|
110
|
+
}
|
|
111
|
+
else if (part.type === 'tool-call') {
|
|
112
|
+
produced = true;
|
|
113
|
+
}
|
|
114
|
+
else if (part.type === 'error') {
|
|
115
|
+
throw part.error;
|
|
116
|
+
}
|
|
117
|
+
else if (part.type === 'abort') {
|
|
118
|
+
throw new LlmError('aborted', 'request was cancelled');
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const text = (await result.text).trim();
|
|
122
|
+
if (!text)
|
|
123
|
+
throw new LlmError('empty', 'the model returned nothing');
|
|
124
|
+
this.observe(input, text);
|
|
125
|
+
return { text, calls: toolRecords(await result.steps) };
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
// A provider that just closes the stream after some words has said what it had.
|
|
129
|
+
if (InvalidResponseDataError.isInstance(err) && produced && !input.signal.aborted && round.trim()) {
|
|
130
|
+
this.observe(input, round.trim());
|
|
131
|
+
return { text: round.trim(), calls: [] };
|
|
132
|
+
}
|
|
133
|
+
throw toLlmError(err, input.signal);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
94
136
|
/**
|
|
95
137
|
* Tells the plugins' observe hooks about a finished turn. Fire and forget: learning must never delay
|
|
96
138
|
* the answer, and a cancelled turn teaches nothing.
|
|
@@ -143,3 +185,17 @@ export class AgentTurnService {
|
|
|
143
185
|
this.observe(input, said.trim());
|
|
144
186
|
}
|
|
145
187
|
}
|
|
188
|
+
function toolRecords(steps) {
|
|
189
|
+
return steps.flatMap((step) => step.toolResults.map((r) => ({ name: r.toolName, input: r.input, output: parsed(r.output) })));
|
|
190
|
+
}
|
|
191
|
+
/** Tool results reach the model as JSON text (tool-set.ts); a host checking them wants the value. */
|
|
192
|
+
function parsed(output) {
|
|
193
|
+
if (typeof output !== 'string')
|
|
194
|
+
return output;
|
|
195
|
+
try {
|
|
196
|
+
return JSON.parse(output);
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
return output;
|
|
200
|
+
}
|
|
201
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rine-kit/agent-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The reasoning loop of an AI participant: chat model over an OpenAI-compatible endpoint, plugin tools, one turn service for text and voice. No dependency on RINE's API, LiveKit or desktop.",
|
|
6
6
|
"exports": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@ai-sdk/openai-compatible": "3.0.67",
|
|
15
15
|
"ai": "7.0.137",
|
|
16
|
-
"@rine-kit/plugin-sdk": "0.1.
|
|
16
|
+
"@rine-kit/plugin-sdk": "0.1.3"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@types/node": "^26.6.5",
|