@almadar/llm 2.56.0 → 2.58.0

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/src/contracts.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  * @packageDocumentation
9
9
  */
10
10
 
11
- import type { ServiceContract, ServiceParams, ServiceParamsValue } from "@almadar/core";
11
+ import type { ServiceContract, ServiceParams, ServiceParamsValue, TraceActivity } from "@almadar/core";
12
12
 
13
13
  /**
14
14
  * JSON Schema definition for structured extraction.
@@ -37,6 +37,30 @@ interface JsonSchemaDefinition extends ServiceParams {
37
37
  type ExtractedValue = string | number | boolean | null | ExtractedValue[] | { [key: string]: ExtractedValue };
38
38
  type ExtractedData = Record<string, ExtractedValue>;
39
39
 
40
+ /** One turn of the conversation `call-tools` continues. */
41
+ export interface AgentChatMessage extends ServiceParams {
42
+ role: "user" | "assistant";
43
+ content: string;
44
+ }
45
+
46
+ /**
47
+ * What the model may use in `call-tools`. Exactly one of:
48
+ * `event` — a declared external input, addressed like a `listens` source
49
+ * (`EVENT`, `Trait.EVENT`, `Orbital.Trait.EVENT`), fired as the caller;
50
+ * `read` — an entity whose rows the caller may read.
51
+ */
52
+ export interface AgentTool extends ServiceParams {
53
+ event?: string;
54
+ read?: string;
55
+ }
56
+
57
+ /**
58
+ * One thing a `call-tools` run did, in order: each model call (`llm_response`),
59
+ * each tool the model used (`tool_call`) and what the app answered
60
+ * (`tool_result`). The `@almadar/core` trace shape the activity feed renders.
61
+ */
62
+ export type AgentActivity = Extract<TraceActivity, { type: "llm_response" | "tool_call" | "tool_result" }>;
63
+
40
64
  /**
41
65
  * All call-service actions exposed by the LLM service.
42
66
  */
@@ -121,6 +145,38 @@ export type LLMServiceActions = {
121
145
  };
122
146
  };
123
147
 
148
+ /**
149
+ * Answer a request by operating the running app as the caller: the model may
150
+ * fire the declared inputs and read the entities named in `tools`, through the
151
+ * host's ordinary dispatch (guards, policies and listens all apply), until it
152
+ * replies. Hitting `maxSteps` is a failure.
153
+ * @synonyms agent, assistant, tool use, act
154
+ */
155
+ "call-tools": {
156
+ params: {
157
+ /** The conversation so far, oldest first; the last turn is the request. */
158
+ messages: AgentChatMessage[];
159
+ /** The inputs and entities the model may use. */
160
+ tools: AgentTool[];
161
+ /** Standing instructions for the model. */
162
+ instructions?: string;
163
+ /** Model round-trips allowed before the call fails (default 8). */
164
+ maxSteps?: number;
165
+ /** Model id override. */
166
+ model?: string;
167
+ };
168
+ result: {
169
+ reply: string;
170
+ steps: AgentActivity[];
171
+ usage: {
172
+ promptTokens: number;
173
+ completionTokens: number;
174
+ totalTokens: number;
175
+ modelCalls: number;
176
+ };
177
+ };
178
+ };
179
+
124
180
  /** Generate embeddings for an array of texts. */
125
181
  embed: {
126
182
  params: {
package/src/index.ts CHANGED
@@ -143,8 +143,20 @@ export {
143
143
  export {
144
144
  type LLMServiceActions,
145
145
  type LLMServiceContract,
146
+ type MLServiceActions,
147
+ type MLServiceContract,
148
+ type AgentChatMessage,
149
+ type AgentTool,
150
+ type AgentActivity,
146
151
  } from './contracts.js';
147
152
 
153
+ export {
154
+ createScriptedToolClient,
155
+ type ToolCallingClient,
156
+ type ScriptedTurn,
157
+ type ScriptedToolClient,
158
+ } from './scripted-tool-client.js';
159
+
148
160
  export {
149
161
  MasarProvider,
150
162
  MasarError,
@@ -0,0 +1,49 @@
1
+ /**
2
+ * The tool-calling seam a tool loop needs, and a scripted model for it.
3
+ *
4
+ * `ToolCallingClient` is the one `LLMClient` capability a tool loop uses: one
5
+ * `callWithTools` round-trip. `createScriptedToolClient` replays scripted
6
+ * assistant turns in order, so a loop runs deterministically with no network
7
+ * (unit tests, the verifiers' agent checks). It records every request it gets.
8
+ *
9
+ * @packageDocumentation
10
+ */
11
+
12
+ import type { LLMClient, LLMUsage } from './client.js';
13
+ import type { ChatCompletionMessage, ChatCompletionToolDef } from './tool-call-types.js';
14
+
15
+ export type ToolCallingClient = Pick<LLMClient, 'callWithTools'>;
16
+
17
+ export interface ScriptedTurn {
18
+ message: ChatCompletionMessage;
19
+ usage?: LLMUsage;
20
+ }
21
+
22
+ export interface ScriptedToolClient extends ToolCallingClient {
23
+ readonly requests: ReadonlyArray<{
24
+ messages: ReadonlyArray<ChatCompletionMessage>;
25
+ tools: ReadonlyArray<ChatCompletionToolDef>;
26
+ }>;
27
+ }
28
+
29
+ export function createScriptedToolClient(turns: readonly ScriptedTurn[]): ScriptedToolClient {
30
+ const requests: Array<{
31
+ messages: ReadonlyArray<ChatCompletionMessage>;
32
+ tools: ReadonlyArray<ChatCompletionToolDef>;
33
+ }> = [];
34
+ return {
35
+ requests,
36
+ async callWithTools(options) {
37
+ const turn = turns[requests.length];
38
+ requests.push({ messages: [...options.messages], tools: [...options.tools] });
39
+ if (turn === undefined) {
40
+ throw new Error(`scripted tool client: no scripted turn ${requests.length} (script has ${turns.length})`);
41
+ }
42
+ return {
43
+ message: turn.message,
44
+ finishReason: turn.message.tool_calls && turn.message.tool_calls.length > 0 ? 'tool_calls' : 'stop',
45
+ usage: turn.usage ?? null,
46
+ };
47
+ },
48
+ };
49
+ }