@cubicecho/agent-core 4.19.0 → 4.20.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/README.md +9 -3
- package/dist/index.d.ts +1 -1
- package/dist/run/agent-loop.d.ts +23 -1
- package/dist/run/agent-loop.js +13 -12
- package/dist/run/run-calls.d.ts +13 -1
- package/dist/run/run-calls.js +41 -6
- package/dist/wire/tool-calls.d.ts +16 -1
- package/llms.txt +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -610,8 +610,10 @@ string. What still is not an object throws a `ToolArgumentsError` whose `kind` i
|
|
|
610
610
|
the turn stopped at the ceiling, with a message telling the model so, and `malformed` otherwise.
|
|
611
611
|
The repaired JSON is what the transcript keeps, and an unreadable call is replayed as `{}`, because
|
|
612
612
|
a server that parses replayed arguments refuses the originals on every later request. `dispatch`
|
|
613
|
-
is still handed the model's own text as `raw`,
|
|
614
|
-
|
|
613
|
+
is still handed the model's own text as `raw`, with `repaired` true where reading it took a repair
|
|
614
|
+
— whitespace and blank arguments do not count — and the dedupe compares repaired arguments, so
|
|
615
|
+
`{'a': 1}` and `{"a": 1}` are one call. A call recovered from text, below, is always `repaired`,
|
|
616
|
+
and its `raw` is the arguments recovery read out of the reply, as JSON.
|
|
615
617
|
|
|
616
618
|
A server whose tool-call parser was written for another template streams the model's call as
|
|
617
619
|
plain text, and the run ends on a reply that is nothing but a call nobody made. Unless
|
|
@@ -969,7 +971,11 @@ try {
|
|
|
969
971
|
|
|
970
972
|
`onMessage` hears the assistant message as it will be replayed — recovered calls folded in, and
|
|
971
973
|
arguments repaired, which the turn `onTurn` is handed does not show — together with that `Turn`,
|
|
972
|
-
and then each tool result, in transcript order.
|
|
974
|
+
and then each tool result, in transcript order. Beside an assistant message the model wrote comes a
|
|
975
|
+
fourth argument, `{ raw }`: the same message as the model produced it, its text whole with any call
|
|
976
|
+
written into it left there, and its calls' arguments exactly as streamed, under the same ids. Store
|
|
977
|
+
or show `raw` to keep what the model said; replay `message` to keep what an endpoint will take back.
|
|
978
|
+
The loop's own messages — a proxied run's preselected load — come without it. `onTurn` is not awaited and never sees a tool
|
|
973
979
|
result; this is the one to store from. What it returns is ignored, since `beforeStep` is the one way to rewrite
|
|
974
980
|
the transcript, and what it throws ends the run.
|
|
975
981
|
|
package/dist/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export { isGrammarError, relaxSchema, relaxTools, sanitizeSchema, sanitizeTools,
|
|
|
19
19
|
export { CACHE_PROMPT_FIELD, resetSlots, SESSION_HEADER, SLOT_FIELD, type SlotAllocator, slotAllocator, } from './endpoint/slots.ts';
|
|
20
20
|
export { HOOK_EVENTS, HookEvent, INJECT_EVENTS } from './hooks/hook-events.ts';
|
|
21
21
|
export { assembleContext, configureHooks, consult, type Gathered, gather, HOOK_CONTEXT_TOKENS, HOOK_PREFACE, type HookContext, type HookMessage, type HookNote, type HookOptions, type HookOutcome, type HookRunner, notify, resetHooks, turnIndex, turnMessages, UNTRUSTED_PREFACE, untrusted, withContext, } from './hooks/hooks.ts';
|
|
22
|
-
export { type AgentLoopHooks, type AgentLoopOptions, type AgentLoopRequest, type AgentLoopResult, PRESELECT_APPEND, PRESELECT_EXCLUSIVE, PRESELECTED_NOTICE, runAgentLoop, type StepWindow, } from './run/agent-loop.ts';
|
|
22
|
+
export { type AgentLoopHooks, type AgentLoopOptions, type AgentLoopRequest, type AgentLoopResult, PRESELECT_APPEND, PRESELECT_EXCLUSIVE, PRESELECTED_NOTICE, runAgentLoop, type StepWindow, type WrittenMessage, } from './run/agent-loop.ts';
|
|
23
23
|
export { configureEvents, type EventBusOptions, emit, endRun, fold, history, type LoadCounts, type RunEvent, type RunEventInput, RunEventKind, type RunMetrics, type RunMetricsOptions, RunOutcome, type RunUsage, resetEvents, runMetrics, type TurnReport, watch, } from './run/events.ts';
|
|
24
24
|
export { buildBody } from './run/request-body.ts';
|
|
25
25
|
export { preview, type ToolDispatch } from './run/run-calls.ts';
|
package/dist/run/agent-loop.d.ts
CHANGED
|
@@ -23,6 +23,24 @@ import { type ToolDispatch } from './run-calls.ts';
|
|
|
23
23
|
* and two never did. What is here is the part that does not know what the run is for; the
|
|
24
24
|
* prompts, the tools and what a run means stay with the caller.
|
|
25
25
|
*/
|
|
26
|
+
/**
|
|
27
|
+
* What `onMessage` is handed beside an assistant message the model wrote: that message as the model
|
|
28
|
+
* produced it.
|
|
29
|
+
*
|
|
30
|
+
* @remarks
|
|
31
|
+
* The message `onMessage` is handed is what later requests replay — arguments repaired, `{}` for
|
|
32
|
+
* none, recovered calls taken out of the text and made calls — which is right to send and quietly
|
|
33
|
+
* wrong to show as the model's. Absent for a message the loop wrote itself, such as a proxied
|
|
34
|
+
* run's preselected load.
|
|
35
|
+
*/
|
|
36
|
+
export interface WrittenMessage {
|
|
37
|
+
/**
|
|
38
|
+
* The reply as it streamed: its text whole, a call written into it as text left there, and the
|
|
39
|
+
* calls it sent as calls with their arguments as streamed. A call that never got a name is left
|
|
40
|
+
* off, since nothing answers it. Ids are the turn's, so the tool results pair with either.
|
|
41
|
+
*/
|
|
42
|
+
raw: OpenAI.ChatCompletionAssistantMessageParam;
|
|
43
|
+
}
|
|
26
44
|
/**
|
|
27
45
|
* One step's request as `onRequest` is handed it: what the model is about to read.
|
|
28
46
|
*
|
|
@@ -459,8 +477,12 @@ export interface AgentLoopOptions {
|
|
|
459
477
|
* a proxied run writes for its `preselected` shortlist, told as step zero's before any request.
|
|
460
478
|
* What it returns is ignored: `beforeStep` is the one way to rewrite the transcript. What it
|
|
461
479
|
* throws ends the run, and it is not called again for that run.
|
|
480
|
+
*
|
|
481
|
+
* Beside an assistant message the model wrote comes `written`, whose `raw` is the message as the
|
|
482
|
+
* model produced it, for a host that shows or stores what was said rather than what is replayed.
|
|
483
|
+
* See `WrittenMessage`.
|
|
462
484
|
*/
|
|
463
|
-
onMessage?: (message: OpenAI.ChatCompletionMessageParam, step: number, turn?: Turn) => void | Promise<void>;
|
|
485
|
+
onMessage?: (message: OpenAI.ChatCompletionMessageParam, step: number, turn?: Turn, written?: WrittenMessage) => void | Promise<void>;
|
|
464
486
|
/**
|
|
465
487
|
* How many times an answer cut off at `maxTokens` is continued, zero for never. Opt-in because
|
|
466
488
|
* it spends another request, and on a server that does not continue a trailing assistant
|
package/dist/run/agent-loop.js
CHANGED
|
@@ -22,7 +22,7 @@ import { recoverToolCalls, } from '../wire/tool-calls.js';
|
|
|
22
22
|
import { FinishReason, PartType, Role } from '../wire/wire.js';
|
|
23
23
|
import { RunEventKind, RunOutcome, runMetrics, stamp, } from './events.js';
|
|
24
24
|
import { buildBody } from './request-body.js';
|
|
25
|
-
import { assistantMessage, definedAs, loadShortlist, readCalls, runCalls, } from './run-calls.js';
|
|
25
|
+
import { assistantMessage, definedAs, loadShortlist, readCalls, runCalls, writtenMessage, } from './run-calls.js';
|
|
26
26
|
/** The `preselectRouting` that sends the first step the shortlist alone. */
|
|
27
27
|
export const PRESELECT_EXCLUSIVE = 'exclusive';
|
|
28
28
|
/** The `preselectRouting` that loads the shortlist after what was carried, and sends the first step like any other. */
|
|
@@ -502,8 +502,8 @@ function definitionsByName(tools) {
|
|
|
502
502
|
* Offers each message written into the transcript to the host.
|
|
503
503
|
*
|
|
504
504
|
* @param onMessage - The host's callback, awaited. Absent offers nothing.
|
|
505
|
-
* @returns The offer, taking a message, its step
|
|
506
|
-
* host has taken the message, and rejects with what the host threw — once.
|
|
505
|
+
* @returns The offer, taking a message, its step, the turn it came with and what the model wrote:
|
|
506
|
+
* it resolves once the host has taken the message, and rejects with what the host threw — once.
|
|
507
507
|
*
|
|
508
508
|
* @remarks
|
|
509
509
|
* Once `onMessage` has thrown the run is ending on that, and the results still to be written are
|
|
@@ -511,12 +511,12 @@ function definitionsByName(tools) {
|
|
|
511
511
|
*/
|
|
512
512
|
function announcer(onMessage) {
|
|
513
513
|
let heard = true;
|
|
514
|
-
return async (message, step, turn) => {
|
|
514
|
+
return async (message, step, turn, written) => {
|
|
515
515
|
if (!onMessage || !heard) {
|
|
516
516
|
return;
|
|
517
517
|
}
|
|
518
518
|
try {
|
|
519
|
-
await onMessage(message, step, turn);
|
|
519
|
+
await onMessage(message, step, turn, written);
|
|
520
520
|
}
|
|
521
521
|
catch (error) {
|
|
522
522
|
heard = false;
|
|
@@ -558,21 +558,21 @@ const usageEvent = (usage, turn, ledger, contextLength) => {
|
|
|
558
558
|
* nothing is looked for in a turn that made a named call of its own or has no text.
|
|
559
559
|
* @param notice - Told when calls were recovered, and how many.
|
|
560
560
|
* @returns `calls`, the turn's own less any with no name, and `content`, its text as it was — or,
|
|
561
|
-
* where calls were recovered, those calls and the text without them.
|
|
561
|
+
* where calls were recovered, those calls and the text without them, and `recovered` true.
|
|
562
562
|
*/
|
|
563
563
|
function turnCalls(turn, recoverable, notice) {
|
|
564
564
|
// A call with no name is a fragment the server never finished sending: nothing to run, and
|
|
565
565
|
// an assistant message naming it would be answered by nothing.
|
|
566
566
|
const calls = turn.toolCalls.filter((call) => call.function.name);
|
|
567
567
|
if (!recoverable || calls.length || !turn.content) {
|
|
568
|
-
return { calls, content: turn.content };
|
|
568
|
+
return { calls, content: turn.content, recovered: false };
|
|
569
569
|
}
|
|
570
570
|
const recovered = recoverToolCalls(turn.content, { names: recoverable });
|
|
571
571
|
if (!recovered.toolCalls.length) {
|
|
572
|
-
return { calls, content: turn.content };
|
|
572
|
+
return { calls, content: turn.content, recovered: false };
|
|
573
573
|
}
|
|
574
574
|
notice(`recovered ${counted(recovered.toolCalls.length, 'tool call')} the model wrote as text; the server's tool-call parser does not match this model's template`);
|
|
575
|
-
return { calls: recovered.toolCalls, content: recovered.content };
|
|
575
|
+
return { calls: recovered.toolCalls, content: recovered.content, recovered: true };
|
|
576
576
|
}
|
|
577
577
|
/**
|
|
578
578
|
* The steps of `runAgentLoop`, throwing what they caught as it was caught.
|
|
@@ -850,15 +850,16 @@ async function runSteps(options, standing, pin) {
|
|
|
850
850
|
notice(`the model stopped at maxTokens (${config.maxTokens}); this turn is cut short`);
|
|
851
851
|
}
|
|
852
852
|
const canRecover = recover && (tools.length > 0 || hostTools.length > 0 || onDemand);
|
|
853
|
-
const { calls, content } = turnCalls(turn, canRecover ? recoverable : undefined, notice);
|
|
853
|
+
const { calls, content, recovered } = turnCalls(turn, canRecover ? recoverable : undefined, notice);
|
|
854
854
|
const shown = { ...turn, content, toolCalls: calls };
|
|
855
855
|
onTurn?.(shown, step);
|
|
856
856
|
// Read before the assistant message is written, so what is replayed on every later request
|
|
857
857
|
// is the repaired JSON.
|
|
858
|
-
const parsed = readCalls(calls, turn.finishReason);
|
|
858
|
+
const parsed = readCalls(calls, turn.finishReason, recovered);
|
|
859
859
|
const assistant = assistantMessage(content, parsed);
|
|
860
860
|
messages.push(assistant);
|
|
861
|
-
|
|
861
|
+
// Recovered calls were never calls on the wire: what the model said is the text they came from.
|
|
862
|
+
await announce(assistant, step, shown, { raw: writtenMessage(turn.content, recovered ? [] : calls) });
|
|
862
863
|
const isAnswer = calls.length === 0;
|
|
863
864
|
const ended = isAnswer ? undefined : await runCalls(calling, parsed, messages, step);
|
|
864
865
|
if (ended) {
|
package/dist/run/run-calls.d.ts
CHANGED
|
@@ -31,12 +31,15 @@ export interface ReadCall {
|
|
|
31
31
|
error?: unknown;
|
|
32
32
|
/** The arguments as every later request replays them: the repaired JSON, or `{}` for none. */
|
|
33
33
|
normal: string;
|
|
34
|
+
/** Whether `args` took a repair to read, as `ToolCallRequest.repaired` says. */
|
|
35
|
+
repaired: boolean;
|
|
34
36
|
}
|
|
35
37
|
/**
|
|
36
38
|
* A turn's calls with their arguments read.
|
|
37
39
|
*
|
|
38
40
|
* @param calls - The turn's calls, in the order the model made them.
|
|
39
41
|
* @param finishReason - Why the turn ended, which tells a call cut off from one written wrongly.
|
|
42
|
+
* @param [recovered] - Whether the calls were recovered from the reply's text.
|
|
40
43
|
* @returns One entry per call, in the same order. Unreadable arguments do not throw: the entry
|
|
41
44
|
* carries the error in place of them.
|
|
42
45
|
*
|
|
@@ -44,7 +47,7 @@ export interface ReadCall {
|
|
|
44
47
|
* A server that parses replayed arguments refuses the almost-JSON a model wrote, so each is
|
|
45
48
|
* normalised here, and one that could not be read at all is replayed as no arguments.
|
|
46
49
|
*/
|
|
47
|
-
export declare const readCalls: (calls: ToolCall[], finishReason: Turn['finishReason']) => ReadCall[];
|
|
50
|
+
export declare const readCalls: (calls: ToolCall[], finishReason: Turn['finishReason'], recovered?: boolean) => ReadCall[];
|
|
48
51
|
/**
|
|
49
52
|
* The assistant message a turn is written into the transcript as, its calls' arguments repaired.
|
|
50
53
|
*
|
|
@@ -54,6 +57,15 @@ export declare const readCalls: (calls: ToolCall[], finishReason: Turn['finishRe
|
|
|
54
57
|
* @returns A new message, each call on it a copy with `normal` for its arguments.
|
|
55
58
|
*/
|
|
56
59
|
export declare const assistantMessage: (content: string, parsed: ReadCall[]) => OpenAI.ChatCompletionAssistantMessageParam;
|
|
60
|
+
/**
|
|
61
|
+
* The assistant message a turn is, as the model produced it: its text and calls as they streamed.
|
|
62
|
+
*
|
|
63
|
+
* @param content - The turn's text, recovered calls left in it. Empty is written as `null`.
|
|
64
|
+
* @param calls - The calls the model sent as calls, with their arguments as streamed. Not written
|
|
65
|
+
* to. None leaves `tool_calls` off the message rather than empty.
|
|
66
|
+
* @returns A new message, each call on it a copy.
|
|
67
|
+
*/
|
|
68
|
+
export declare const writtenMessage: (content: string, calls: ToolCall[]) => OpenAI.ChatCompletionAssistantMessageParam;
|
|
57
69
|
/**
|
|
58
70
|
* The definitions the host gave for these names, in the order the names are given.
|
|
59
71
|
*
|
package/dist/run/run-calls.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRecord } from '../core/guards.js';
|
|
1
2
|
import { CALL_TOOL, expandNames, inCatalog, LOAD_TOOLS, loadResult, proxiedCall, proxyLoadResult, requestedNames, shownCall, toolName, } from '../tools/tool-loading.js';
|
|
2
3
|
import { errorMessage } from '../wire/errors.js';
|
|
3
4
|
import { parseToolArguments, } from '../wire/tool-calls.js';
|
|
@@ -26,20 +27,40 @@ export const preview = (text, limit = 2000) => text.length > limit ? `${text.sli
|
|
|
26
27
|
const STOPPED_CALL = 'Stopped before this call finished.';
|
|
27
28
|
/** The same for a call of that step the loop never got to. */
|
|
28
29
|
const UNRUN_CALL = 'Not run: the run stopped first.';
|
|
30
|
+
/**
|
|
31
|
+
* Whether a call's arguments are, as written, the JSON of an object — or no arguments at all.
|
|
32
|
+
*
|
|
33
|
+
* @param raw - The arguments as the turn carried them: a string, or an object a server parsed.
|
|
34
|
+
* @returns False where reading them took `parseToolArguments`' repairs.
|
|
35
|
+
*/
|
|
36
|
+
function readsAsWritten(raw) {
|
|
37
|
+
if (typeof raw !== 'string' || !raw.trim()) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
return isRecord(JSON.parse(raw));
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
29
47
|
/**
|
|
30
48
|
* One call with its arguments read, or with why they could not be.
|
|
31
49
|
*
|
|
32
50
|
* @param call - The call as the turn carried it.
|
|
33
51
|
* @param finishReason - Why the turn ended, which tells a call cut off from one written wrongly.
|
|
52
|
+
* @param recovered - Whether the call was recovered from the reply's text, which makes it repaired
|
|
53
|
+
* whatever its arguments.
|
|
34
54
|
* @returns The call beside its arguments and their repaired JSON, or beside the error and `{}`.
|
|
35
55
|
*/
|
|
36
|
-
function readCall(call, finishReason) {
|
|
56
|
+
function readCall(call, finishReason, recovered) {
|
|
37
57
|
try {
|
|
38
58
|
const args = parseToolArguments(call.function.arguments, { finishReason });
|
|
39
|
-
|
|
59
|
+
const repaired = recovered || !readsAsWritten(call.function.arguments);
|
|
60
|
+
return { call, args, normal: JSON.stringify(args), repaired };
|
|
40
61
|
}
|
|
41
62
|
catch (error) {
|
|
42
|
-
return { call, error, normal: '{}' };
|
|
63
|
+
return { call, error, normal: '{}', repaired: false };
|
|
43
64
|
}
|
|
44
65
|
}
|
|
45
66
|
/**
|
|
@@ -47,6 +68,7 @@ function readCall(call, finishReason) {
|
|
|
47
68
|
*
|
|
48
69
|
* @param calls - The turn's calls, in the order the model made them.
|
|
49
70
|
* @param finishReason - Why the turn ended, which tells a call cut off from one written wrongly.
|
|
71
|
+
* @param [recovered] - Whether the calls were recovered from the reply's text.
|
|
50
72
|
* @returns One entry per call, in the same order. Unreadable arguments do not throw: the entry
|
|
51
73
|
* carries the error in place of them.
|
|
52
74
|
*
|
|
@@ -54,7 +76,7 @@ function readCall(call, finishReason) {
|
|
|
54
76
|
* A server that parses replayed arguments refuses the almost-JSON a model wrote, so each is
|
|
55
77
|
* normalised here, and one that could not be read at all is replayed as no arguments.
|
|
56
78
|
*/
|
|
57
|
-
export const readCalls = (calls, finishReason) => calls.map((call) => readCall(call, finishReason));
|
|
79
|
+
export const readCalls = (calls, finishReason, recovered = false) => calls.map((call) => readCall(call, finishReason, recovered));
|
|
58
80
|
/**
|
|
59
81
|
* The assistant message a turn is written into the transcript as, its calls' arguments repaired.
|
|
60
82
|
*
|
|
@@ -75,6 +97,19 @@ export const assistantMessage = (content, parsed) => ({
|
|
|
75
97
|
}
|
|
76
98
|
: {}),
|
|
77
99
|
});
|
|
100
|
+
/**
|
|
101
|
+
* The assistant message a turn is, as the model produced it: its text and calls as they streamed.
|
|
102
|
+
*
|
|
103
|
+
* @param content - The turn's text, recovered calls left in it. Empty is written as `null`.
|
|
104
|
+
* @param calls - The calls the model sent as calls, with their arguments as streamed. Not written
|
|
105
|
+
* to. None leaves `tool_calls` off the message rather than empty.
|
|
106
|
+
* @returns A new message, each call on it a copy.
|
|
107
|
+
*/
|
|
108
|
+
export const writtenMessage = (content, calls) => ({
|
|
109
|
+
role: Role.Assistant,
|
|
110
|
+
content: content || null,
|
|
111
|
+
...(calls.length ? { tool_calls: calls.map((call) => ({ ...call, function: { ...call.function } })) } : {}),
|
|
112
|
+
});
|
|
78
113
|
/**
|
|
79
114
|
* The definitions the host gave for these names, in the order the names are given.
|
|
80
115
|
*
|
|
@@ -284,7 +319,7 @@ function prepare(run, entry) {
|
|
|
284
319
|
}
|
|
285
320
|
// Built for every call rather than only the dispatched ones, so a host hears of the calls
|
|
286
321
|
// the loop answers itself in the same shape. Arguments that could not be read are none.
|
|
287
|
-
const request = { id: call.id, name, args: inner, raw };
|
|
322
|
+
const request = { id: call.id, name, args: inner, raw, repaired: entry.repaired };
|
|
288
323
|
// By the name the model called, not the one a `call_tool` wraps: `load_tools` is not in
|
|
289
324
|
// the catalogue, and one reached through `call_tool` is refused like any other.
|
|
290
325
|
const load = onDemand && call.function.name === LOAD_TOOLS;
|
|
@@ -540,7 +575,7 @@ export async function loadShortlist(run, shortlist, messages) {
|
|
|
540
575
|
// host that shortlisted more has already chosen.
|
|
541
576
|
const content = proxyLoadResult(expandNames(names, catalog, names.length), catalog, shortlist);
|
|
542
577
|
run.onEvent({ kind: RunEventKind.ToolCall, id, name: LOAD_TOOLS, text: preview(args) });
|
|
543
|
-
run.onToolCall?.({ id, name: LOAD_TOOLS, args: { names }, raw: args });
|
|
578
|
+
run.onToolCall?.({ id, name: LOAD_TOOLS, args: { names }, raw: args, repaired: false });
|
|
544
579
|
const loads = { toolsLoaded: names.length, redundantLoads: 0, unknownToolNames: 0 };
|
|
545
580
|
run.onEvent({ kind: RunEventKind.ToolResult, id, name: LOAD_TOOLS, ok: true, text: preview(content), loads });
|
|
546
581
|
run.onToolResult?.({ id, name: LOAD_TOOLS, ok: true, content });
|
|
@@ -114,9 +114,24 @@ export interface ToolCallRequest {
|
|
|
114
114
|
args: Record<string, unknown>;
|
|
115
115
|
/**
|
|
116
116
|
* The arguments as the model wrote them, before any repair. Through `call_tool`, the inner
|
|
117
|
-
* arguments as JSON text.
|
|
117
|
+
* arguments as JSON text. For a call recovered from the reply's text, the arguments recovery read
|
|
118
|
+
* out of it, as JSON text: the words the model wrote are the reply's content, which `onMessage`'s
|
|
119
|
+
* `raw` message carries.
|
|
118
120
|
*/
|
|
119
121
|
raw: string;
|
|
122
|
+
/**
|
|
123
|
+
* Whether `args` took a repair to read: true where `raw` does not parse, as written, to the JSON
|
|
124
|
+
* object `args` holds — near-JSON, or JSON inside a string — and for every call recovered from
|
|
125
|
+
* text, which the model never sent as a call. False for blank arguments, which every reader takes
|
|
126
|
+
* as none, and for arguments that could not be read at all. Through `call_tool`, whether the
|
|
127
|
+
* `call_tool`'s own arguments did.
|
|
128
|
+
*
|
|
129
|
+
* @remarks
|
|
130
|
+
* A host that shows or stores what the model said reads `raw` where this is true. Whitespace is
|
|
131
|
+
* not a repair, though the replayed arguments are re-serialised either way. `runAgentLoop` always
|
|
132
|
+
* sets it; optional so a request built before it existed still compiles.
|
|
133
|
+
*/
|
|
134
|
+
repaired?: boolean;
|
|
120
135
|
}
|
|
121
136
|
/** What one tool call did, in the order the model asked. */
|
|
122
137
|
export interface ToolCallOutcome {
|
package/llms.txt
CHANGED
|
@@ -176,6 +176,7 @@ The loop above a turn: send, run the tools the model asked for, send again, unti
|
|
|
176
176
|
- `PRESELECTED_NOTICE` — What opens the notice naming the loop's own picks, ahead of the names.
|
|
177
177
|
- `runAgentLoop` — Runs a question to its answer: one `runTurn` per step, the tools it asks for between them, until a turn asks for none or a call's answer ends the run.
|
|
178
178
|
- `StepWindow` (type) — How full the window is as a step is about to be sent, as `beforeStep` is told it.
|
|
179
|
+
- `WrittenMessage` (type) — What `onMessage` is handed beside an assistant message the model wrote: that message as the model produced it.
|
|
179
180
|
|
|
180
181
|
### events
|
|
181
182
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cubicecho/agent-core",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.20.0",
|
|
4
4
|
"description": "The endpoint-agnostic half of an OpenAI-compatible agent loop: tool-schema compatibility, on-demand tool loading, one-shot side tasks, run events, and a pooled client.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"openai",
|