@orkestrel/agent 0.0.7 → 0.0.9
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 +1 -1
- package/dist/src/core/index.cjs +293 -92
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +241 -50
- package/dist/src/core/index.d.ts +241 -50
- package/dist/src/core/index.js +286 -93
- package/dist/src/core/index.js.map +1 -1
- package/package.json +24 -21
package/dist/src/core/index.cjs
CHANGED
|
@@ -74,6 +74,24 @@ var THINK_CLOSE = "</think>";
|
|
|
74
74
|
*/
|
|
75
75
|
var WORKSPACE_SECTION_HEADER = "## Workspace";
|
|
76
76
|
/**
|
|
77
|
+
* The estimated per-message role/framing overhead {@link import('./helpers.js').estimateMessages}
|
|
78
|
+
* adds on top of a message's content estimate — accounts for the fixed wire framing every
|
|
79
|
+
* conversation turn carries (its role tag, delimiters) that {@link import('./helpers.js').estimateTokens}'s
|
|
80
|
+
* content-only heuristic does not otherwise capture.
|
|
81
|
+
*/
|
|
82
|
+
var MESSAGE_TOKEN_OVERHEAD = 4;
|
|
83
|
+
/**
|
|
84
|
+
* The coarse, deliberately-approximate per-image token cost {@link import('./helpers.js').estimateMessages}
|
|
85
|
+
* charges for each attached image.
|
|
86
|
+
*
|
|
87
|
+
* @remarks
|
|
88
|
+
* A base64 image payload's LENGTH is NOT a reliable token proxy (a vision model's actual image
|
|
89
|
+
* token cost depends on resolution / tiling, not byte size), so this is a fixed, coarse
|
|
90
|
+
* per-image estimate rather than a derivation from `image.length` — a planning heuristic, not an
|
|
91
|
+
* exact count.
|
|
92
|
+
*/
|
|
93
|
+
var IMAGE_TOKEN_ESTIMATE = 512;
|
|
94
|
+
/**
|
|
77
95
|
* The extension→language table {@link import('./helpers.js').inferLanguage} reads to
|
|
78
96
|
* map a file path's extension to a fenced-code language tag. Covers the common source /
|
|
79
97
|
* markup / data extensions; an unlisted extension falls back to `'text'`.
|
|
@@ -202,18 +220,21 @@ function isAgentJobError(value) {
|
|
|
202
220
|
}
|
|
203
221
|
/**
|
|
204
222
|
* Thrown by a {@link ConversationInterface}'s `compact()` when the conversation has no
|
|
205
|
-
* {@link ConversationSummarizer} to fold its messages with
|
|
206
|
-
* `code`.
|
|
223
|
+
* {@link ConversationSummarizer} to fold its messages with, or when its `sections` cap is
|
|
224
|
+
* structurally invalid — carries a machine-readable `code`.
|
|
207
225
|
*
|
|
208
226
|
* @remarks
|
|
209
227
|
* Compaction REQUIRES a summarizer (it digests the folded slice into a section summary and
|
|
210
228
|
* regenerates the rollup); a conversation created without one can still store + `view()` its
|
|
211
|
-
* live tail, but a `compact()` is a programmer error (§12) and throws this
|
|
212
|
-
* `
|
|
229
|
+
* live tail, but a `compact()` is a programmer error (§12) and throws this with `'SUMMARIZER'`.
|
|
230
|
+
* A `sections` cap (§F2, on {@link import('./types.js').ConversationOptions} /
|
|
231
|
+
* {@link import('./types.js').ConversationManagerOptions} /
|
|
232
|
+
* {@link import('./types.js').CompactOptions}) must be `>= 1` — a sub-1 cap is a programmer
|
|
233
|
+
* error and throws this with `'SECTIONS'`. Narrow a caught value with
|
|
213
234
|
* {@link isConversationError} and branch on `error.code`.
|
|
214
235
|
*/
|
|
215
236
|
var ConversationError = class extends Error {
|
|
216
|
-
/** The machine-readable condition — `'SUMMARIZER'`: a `compact()` with no summarizer. */
|
|
237
|
+
/** The machine-readable condition — `'SUMMARIZER'`: a `compact()` with no summarizer; `'SECTIONS'`: a sub-1 `sections` cap. */
|
|
217
238
|
code;
|
|
218
239
|
constructor(code, message) {
|
|
219
240
|
super(message);
|
|
@@ -257,7 +278,7 @@ var WorkspaceError = class extends Error {
|
|
|
257
278
|
super(message);
|
|
258
279
|
this.name = "WorkspaceError";
|
|
259
280
|
this.code = code;
|
|
260
|
-
this.context = context;
|
|
281
|
+
if (context !== void 0) this.context = context;
|
|
261
282
|
}
|
|
262
283
|
};
|
|
263
284
|
/**
|
|
@@ -278,6 +299,45 @@ var WorkspaceError = class extends Error {
|
|
|
278
299
|
function isWorkspaceError(value) {
|
|
279
300
|
return value instanceof WorkspaceError;
|
|
280
301
|
}
|
|
302
|
+
/**
|
|
303
|
+
* Thrown synchronously by an {@link AgentInterface}'s `stream()` when a concurrent run would
|
|
304
|
+
* corrupt SHARED per-agent accounting — carries a machine-readable `code`.
|
|
305
|
+
*
|
|
306
|
+
* @remarks
|
|
307
|
+
* A run already in flight on the same agent, PLUS a construction-level `window` (a shared
|
|
308
|
+
* context budget) or a construction-level `budget` with no per-run override (a shared cost
|
|
309
|
+
* budget), means a second concurrent `stream()` would race its charges against the same
|
|
310
|
+
* shared instance — corrupting the accounting. `code` is `'CONCURRENCY'` (the only condition
|
|
311
|
+
* so far). Use separate agents, or per-run `budget` overrides with no `window`, for genuinely
|
|
312
|
+
* concurrent runs. Narrow a caught value with {@link isAgentError} and branch on `error.code`.
|
|
313
|
+
*/
|
|
314
|
+
var AgentError = class extends Error {
|
|
315
|
+
/** The machine-readable condition — `'CONCURRENCY'`: a concurrent run on a shared accounting agent. */
|
|
316
|
+
code;
|
|
317
|
+
constructor(code, message) {
|
|
318
|
+
super(message);
|
|
319
|
+
this.name = "AgentError";
|
|
320
|
+
this.code = code;
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
/**
|
|
324
|
+
* Narrow an unknown caught value to an {@link AgentError}.
|
|
325
|
+
*
|
|
326
|
+
* @param value - The value to test (typically a `catch` binding)
|
|
327
|
+
* @returns `true` when `value` is an {@link AgentError}
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* ```ts
|
|
331
|
+
* try {
|
|
332
|
+
* agent.stream()
|
|
333
|
+
* } catch (error) {
|
|
334
|
+
* if (isAgentError(error) && error.code === 'CONCURRENCY') useSeparateAgents()
|
|
335
|
+
* }
|
|
336
|
+
* ```
|
|
337
|
+
*/
|
|
338
|
+
function isAgentError(value) {
|
|
339
|
+
return value instanceof AgentError;
|
|
340
|
+
}
|
|
281
341
|
//#endregion
|
|
282
342
|
//#region src/core/conversations/Conversation.ts
|
|
283
343
|
/**
|
|
@@ -331,17 +391,20 @@ var Conversation = class {
|
|
|
331
391
|
#emitter;
|
|
332
392
|
#summarize;
|
|
333
393
|
#keep;
|
|
394
|
+
#cap;
|
|
334
395
|
#sections = [];
|
|
335
396
|
#summary;
|
|
336
397
|
#messages = /* @__PURE__ */ new Map();
|
|
337
398
|
constructor(options, seed) {
|
|
338
399
|
this.#id = seed?.id ?? options?.id ?? crypto.randomUUID();
|
|
339
400
|
this.#emitter = new _orkestrel_emitter.Emitter({
|
|
340
|
-
on: options
|
|
341
|
-
error: options
|
|
401
|
+
...options?.on === void 0 ? {} : { on: options.on },
|
|
402
|
+
...options?.error === void 0 ? {} : { error: options.error }
|
|
342
403
|
});
|
|
343
404
|
this.#summarize = options?.summarize;
|
|
344
405
|
this.#keep = options?.keep ?? 0;
|
|
406
|
+
if (options?.sections !== void 0 && options.sections < 1) throw new ConversationError("SECTIONS", "a sections cap must be >= 1");
|
|
407
|
+
this.#cap = options?.sections;
|
|
345
408
|
if (seed) {
|
|
346
409
|
this.#summary = seed.summary;
|
|
347
410
|
for (const section of seed.sections) this.#sections.push(section);
|
|
@@ -393,6 +456,8 @@ var Conversation = class {
|
|
|
393
456
|
async compact(options) {
|
|
394
457
|
const summarize = this.#summarize;
|
|
395
458
|
if (summarize === void 0) throw new ConversationError("SUMMARIZER", "cannot compact a conversation without a summarizer");
|
|
459
|
+
const cap = options?.sections ?? this.#cap;
|
|
460
|
+
if (cap !== void 0 && cap < 1) throw new ConversationError("SECTIONS", "a sections cap must be >= 1");
|
|
396
461
|
const keep = options?.keep ?? this.#keep;
|
|
397
462
|
const live = [...this.#messages.values()];
|
|
398
463
|
const fold = keep <= 0 ? live.length : live.length - keep;
|
|
@@ -406,6 +471,23 @@ var Conversation = class {
|
|
|
406
471
|
};
|
|
407
472
|
for (const message of slice) this.#messages.delete(message.id);
|
|
408
473
|
this.#sections.push(section);
|
|
474
|
+
if (cap !== void 0 && this.#sections.length > cap) {
|
|
475
|
+
const overflow = this.#sections.length - cap + 1;
|
|
476
|
+
const folded = this.#sections.slice(0, overflow);
|
|
477
|
+
try {
|
|
478
|
+
const merged = {
|
|
479
|
+
id: crypto.randomUUID(),
|
|
480
|
+
summary: await summarize(folded.map((one) => this.#summaryMessage(one))),
|
|
481
|
+
messages: folded.flatMap((one) => one.messages)
|
|
482
|
+
};
|
|
483
|
+
this.#sections.splice(0, overflow, merged);
|
|
484
|
+
this.#emitter.emit("collapse", merged);
|
|
485
|
+
} catch (error) {
|
|
486
|
+
this.#summary = await summarize(this.#sections.map((one) => this.#summaryMessage(one)));
|
|
487
|
+
this.#emitter.emit("summary", this.#summary);
|
|
488
|
+
throw error;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
409
491
|
this.#summary = await summarize(this.#sections.map((one) => this.#summaryMessage(one)));
|
|
410
492
|
this.#emitter.emit("summary", this.#summary);
|
|
411
493
|
this.#emitter.emit("compact", section);
|
|
@@ -505,10 +587,12 @@ var ConversationManager = class {
|
|
|
505
587
|
#active;
|
|
506
588
|
#summarize;
|
|
507
589
|
#keep;
|
|
590
|
+
#sections;
|
|
508
591
|
#store;
|
|
509
592
|
constructor(options) {
|
|
510
593
|
this.#summarize = options?.summarize;
|
|
511
594
|
this.#keep = options?.keep ?? 0;
|
|
595
|
+
this.#sections = options?.sections;
|
|
512
596
|
this.#store = options?.store;
|
|
513
597
|
}
|
|
514
598
|
get count() {
|
|
@@ -524,11 +608,14 @@ var ConversationManager = class {
|
|
|
524
608
|
return [...this.#conversations.values()];
|
|
525
609
|
}
|
|
526
610
|
add(input) {
|
|
611
|
+
const sections = input?.sections ?? this.#sections;
|
|
612
|
+
const summarize = input?.summarize ?? this.#summarize;
|
|
527
613
|
const conversation = new Conversation({
|
|
528
614
|
...input?.id === void 0 ? {} : { id: input.id },
|
|
529
615
|
...input?.on === void 0 ? {} : { on: input.on },
|
|
530
|
-
summarize:
|
|
531
|
-
keep: input?.keep ?? this.#keep
|
|
616
|
+
...summarize === void 0 ? {} : { summarize },
|
|
617
|
+
keep: input?.keep ?? this.#keep,
|
|
618
|
+
...sections === void 0 ? {} : { sections }
|
|
532
619
|
}, input?.snapshot);
|
|
533
620
|
this.#conversations.set(conversation.id, conversation);
|
|
534
621
|
if (this.#active === void 0) this.#active = conversation.id;
|
|
@@ -669,23 +756,40 @@ function estimateTokens(text) {
|
|
|
669
756
|
* (the {@link import('./types.js').AgentOptions} `window`).
|
|
670
757
|
*
|
|
671
758
|
* @remarks
|
|
672
|
-
* Sums {@link estimateTokens} over
|
|
673
|
-
* heuristic)
|
|
674
|
-
*
|
|
675
|
-
*
|
|
676
|
-
*
|
|
759
|
+
* Sums, per message, {@link estimateTokens} over its `content` (the `ceil(length / 4)` char
|
|
760
|
+
* heuristic) PLUS {@link import('./constants.js').MESSAGE_TOKEN_OVERHEAD} (a fixed per-message
|
|
761
|
+
* role/framing overhead) PLUS, when present, {@link estimateTokens} over its JSON-stringified
|
|
762
|
+
* `calls` PLUS `images.length * `{@link import('./constants.js').IMAGE_TOKEN_ESTIMATE} (a coarse,
|
|
763
|
+
* deliberately-approximate per-image cost — a base64 length is NOT a token proxy). Deterministic
|
|
764
|
+
* and provider-free — the same messages always yield the same estimate, with an empty batch `0`.
|
|
765
|
+
* It is the fully-swappable default an agent's auto-compaction context budget charges each
|
|
766
|
+
* turn's new messages through; a caller wanting a sharper count supplies its own `consume` to
|
|
767
|
+
* `createBudget` instead. Total — never throws: a `calls` `JSON.stringify` that throws (a
|
|
768
|
+
* circular `ToolCall.arguments`) is caught and replaced with a conservative fixed contribution of
|
|
769
|
+
* {@link import('./constants.js').MESSAGE_TOKEN_OVERHEAD} (the same per-message overhead scale)
|
|
770
|
+
* instead of estimating the (unreachable) serialized length.
|
|
677
771
|
*
|
|
678
772
|
* @param messages - The messages to estimate (a turn's appended assistant + tool messages)
|
|
679
|
-
* @returns The summed estimated token count (
|
|
773
|
+
* @returns The summed estimated token count (`0` when empty)
|
|
680
774
|
*
|
|
681
775
|
* @example
|
|
682
776
|
* ```ts
|
|
683
777
|
* estimateMessages([]) // 0
|
|
684
|
-
* estimateMessages([{ id: '1', role: 'user', content: 'hello' }]) // 2
|
|
778
|
+
* estimateMessages([{ id: '1', role: 'user', content: 'hello' }]) // 6 (2 content + 4 overhead)
|
|
685
779
|
* ```
|
|
686
780
|
*/
|
|
687
781
|
function estimateMessages(messages) {
|
|
688
|
-
return messages.reduce((sum, message) =>
|
|
782
|
+
return messages.reduce((sum, message) => {
|
|
783
|
+
const content = estimateTokens(message.content) + 4;
|
|
784
|
+
let calls = 0;
|
|
785
|
+
if (message.calls?.length) try {
|
|
786
|
+
calls = estimateTokens(JSON.stringify(message.calls));
|
|
787
|
+
} catch {
|
|
788
|
+
calls = 4;
|
|
789
|
+
}
|
|
790
|
+
const images = (message.images?.length ?? 0) * 512;
|
|
791
|
+
return sum + content + calls + images;
|
|
792
|
+
}, 0);
|
|
689
793
|
}
|
|
690
794
|
/**
|
|
691
795
|
* Run one rehydrated agent and apply the partial-as-configurable-failure policy — the
|
|
@@ -715,6 +819,38 @@ async function settleAgentJob(agent, allowPartial) {
|
|
|
715
819
|
return result;
|
|
716
820
|
}
|
|
717
821
|
/**
|
|
822
|
+
* Handle one queued agent job by rehydrating it through a registry with the queue
|
|
823
|
+
* attempt's signal, then applying the shared partial-result policy.
|
|
824
|
+
*
|
|
825
|
+
* @param registry - The registry that rehydrates the serializable job
|
|
826
|
+
* @param allowPartial - Whether a partial result resolves instead of throwing
|
|
827
|
+
* @param input - The serializable agent job
|
|
828
|
+
* @param execution - The queue attempt whose signal bounds the agent
|
|
829
|
+
* @returns The settled agent result
|
|
830
|
+
*/
|
|
831
|
+
function handleAgentQueueJob(registry, allowPartial, input, execution) {
|
|
832
|
+
return settleAgentJob(registry.build(input, execution.signal), allowPartial);
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Handle one runner agent job by fanning out its declared children, rehydrating the
|
|
836
|
+
* parent through a registry with the controller signal, and applying the shared
|
|
837
|
+
* partial-result policy.
|
|
838
|
+
*
|
|
839
|
+
* @remarks
|
|
840
|
+
* Children are fired and tracked through the runner controller without awaiting them
|
|
841
|
+
* inline, preserving bounded-runner progress.
|
|
842
|
+
*
|
|
843
|
+
* @param registry - The registry that rehydrates serializable jobs
|
|
844
|
+
* @param allowPartial - Whether a partial result resolves instead of throwing
|
|
845
|
+
* @param controller - The runner controller for this parent job
|
|
846
|
+
* @returns The settled parent agent result
|
|
847
|
+
*/
|
|
848
|
+
function handleAgentRunnerJob(registry, allowPartial, controller) {
|
|
849
|
+
const children = controller.input.children;
|
|
850
|
+
if (children !== void 0) for (const child of children) controller.spawn(child);
|
|
851
|
+
return settleAgentJob(registry.build(controller.input, controller.signal), allowPartial);
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
718
854
|
* Whether a {@link FileContent} is the TEXT arm — the narrowing guard for the text-vs-binary
|
|
719
855
|
* union (AGENTS §14: narrow an untyped arm via a guard, never an `as`).
|
|
720
856
|
*
|
|
@@ -1311,6 +1447,40 @@ function fencedFile(path, language, content) {
|
|
|
1311
1447
|
function escapeRegExp(value) {
|
|
1312
1448
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1313
1449
|
}
|
|
1450
|
+
/**
|
|
1451
|
+
* Sanitize one reported token count into a safe non-negative integer.
|
|
1452
|
+
*
|
|
1453
|
+
* @param value - The token count to sanitize
|
|
1454
|
+
* @returns The floored count, or `0` when the value is non-finite or non-positive
|
|
1455
|
+
*/
|
|
1456
|
+
function sanitizeToken(value) {
|
|
1457
|
+
return Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
|
|
1458
|
+
}
|
|
1459
|
+
/**
|
|
1460
|
+
* Sanitize a {@link TokenUsage} into safe, non-negative integers — the guard an agent's
|
|
1461
|
+
* abort-usage path applies to a provider's partial usage before it is charged against a
|
|
1462
|
+
* budget or folded into the run total.
|
|
1463
|
+
*
|
|
1464
|
+
* @remarks
|
|
1465
|
+
* Per field (`prompt` / `completion` / `total`): a non-finite value (`NaN`, `+Infinity`,
|
|
1466
|
+
* `-Infinity`) or a negative value floors to `0`; a fractional value floors to its
|
|
1467
|
+
* non-negative integer part. No upper cap is applied. Total — never throws.
|
|
1468
|
+
*
|
|
1469
|
+
* @param usage - The token usage to sanitize (e.g. a provider's abort-partial usage)
|
|
1470
|
+
* @returns A new {@link TokenUsage} with every field a safe non-negative integer
|
|
1471
|
+
*
|
|
1472
|
+
* @example
|
|
1473
|
+
* ```ts
|
|
1474
|
+
* sanitizeUsage({ prompt: -5, completion: NaN, total: 12.7 }) // { prompt: 0, completion: 0, total: 12 }
|
|
1475
|
+
* ```
|
|
1476
|
+
*/
|
|
1477
|
+
function sanitizeUsage(usage) {
|
|
1478
|
+
return {
|
|
1479
|
+
prompt: sanitizeToken(usage.prompt),
|
|
1480
|
+
completion: sanitizeToken(usage.completion),
|
|
1481
|
+
total: sanitizeToken(usage.total)
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1314
1484
|
//#endregion
|
|
1315
1485
|
//#region src/core/instructions/Instruction.ts
|
|
1316
1486
|
/**
|
|
@@ -1392,8 +1562,8 @@ var InstructionManager = class {
|
|
|
1392
1562
|
#format;
|
|
1393
1563
|
constructor(options) {
|
|
1394
1564
|
this.#emitter = new _orkestrel_emitter.Emitter({
|
|
1395
|
-
on: options
|
|
1396
|
-
error: options
|
|
1565
|
+
...options?.on === void 0 ? {} : { on: options.on },
|
|
1566
|
+
...options?.error === void 0 ? {} : { error: options.error }
|
|
1397
1567
|
});
|
|
1398
1568
|
this.#format = options?.format;
|
|
1399
1569
|
}
|
|
@@ -1595,8 +1765,8 @@ var Workspace = class {
|
|
|
1595
1765
|
constructor(options, seed) {
|
|
1596
1766
|
this.#id = options?.id ?? crypto.randomUUID();
|
|
1597
1767
|
this.#emitter = new _orkestrel_emitter.Emitter({
|
|
1598
|
-
on: options
|
|
1599
|
-
error: options
|
|
1768
|
+
...options?.on === void 0 ? {} : { on: options.on },
|
|
1769
|
+
...options?.error === void 0 ? {} : { error: options.error }
|
|
1600
1770
|
});
|
|
1601
1771
|
if (seed) for (const [path, file] of seed) this.#files.set(path, file);
|
|
1602
1772
|
}
|
|
@@ -1889,10 +2059,12 @@ var WorkspaceManager = class {
|
|
|
1889
2059
|
return [...this.#workspaces.values()];
|
|
1890
2060
|
}
|
|
1891
2061
|
add(input) {
|
|
2062
|
+
const on = input?.on ?? this.#on;
|
|
2063
|
+
const error = input?.error ?? this.#error;
|
|
1892
2064
|
const workspace = new Workspace({
|
|
1893
2065
|
...input?.id === void 0 ? {} : { id: input.id },
|
|
1894
|
-
on:
|
|
1895
|
-
error:
|
|
2066
|
+
...on === void 0 ? {} : { on },
|
|
2067
|
+
...error === void 0 ? {} : { error }
|
|
1896
2068
|
}, input?.seed);
|
|
1897
2069
|
this.#workspaces.set(workspace.id, workspace);
|
|
1898
2070
|
if (this.#active === void 0) this.#active = workspace.id;
|
|
@@ -2236,6 +2408,7 @@ var Agent = class {
|
|
|
2236
2408
|
#signal;
|
|
2237
2409
|
#authority;
|
|
2238
2410
|
#window;
|
|
2411
|
+
#strict;
|
|
2239
2412
|
#emitter;
|
|
2240
2413
|
id = crypto.randomUUID();
|
|
2241
2414
|
#status = "idle";
|
|
@@ -2243,9 +2416,12 @@ var Agent = class {
|
|
|
2243
2416
|
constructor(provider, options) {
|
|
2244
2417
|
this.#provider = provider;
|
|
2245
2418
|
this.#context = new AgentContext({
|
|
2246
|
-
system: options
|
|
2247
|
-
tools: options
|
|
2248
|
-
|
|
2419
|
+
...options?.system === void 0 ? {} : { system: options.system },
|
|
2420
|
+
...options?.tools === void 0 ? {} : { tools: options.tools },
|
|
2421
|
+
...options?.instructions === void 0 ? {} : { instructions: options.instructions },
|
|
2422
|
+
...options?.workspaces === void 0 ? {} : { workspaces: options.workspaces },
|
|
2423
|
+
...options?.scope === void 0 ? {} : { scope: options.scope },
|
|
2424
|
+
...options?.conversations === void 0 ? {} : { conversations: options.conversations }
|
|
2249
2425
|
});
|
|
2250
2426
|
this.#limit = options?.limit ?? 10;
|
|
2251
2427
|
this.#timeoutMs = options?.timeout;
|
|
@@ -2254,9 +2430,10 @@ var Agent = class {
|
|
|
2254
2430
|
this.#signal = options?.signal;
|
|
2255
2431
|
this.#authority = options?.authority;
|
|
2256
2432
|
this.#window = options?.window;
|
|
2433
|
+
this.#strict = options?.strict ?? false;
|
|
2257
2434
|
this.#emitter = new _orkestrel_emitter.Emitter({
|
|
2258
|
-
on: options
|
|
2259
|
-
error: options
|
|
2435
|
+
...options?.on === void 0 ? {} : { on: options.on },
|
|
2436
|
+
...options?.error === void 0 ? {} : { error: options.error }
|
|
2260
2437
|
});
|
|
2261
2438
|
}
|
|
2262
2439
|
get emitter() {
|
|
@@ -2272,48 +2449,49 @@ var Agent = class {
|
|
|
2272
2449
|
return this.stream(options).result;
|
|
2273
2450
|
}
|
|
2274
2451
|
stream(options) {
|
|
2452
|
+
if (this.#runs.size > 0 && (this.#window !== void 0 || this.#budget !== void 0 && options?.budget === void 0)) throw new AgentError("CONCURRENCY", "concurrent runs on one agent with a shared construction window/budget corrupt accounting; use separate agents or per-run budgets");
|
|
2275
2453
|
const timeoutMs = options?.timeout ?? this.#timeoutMs;
|
|
2276
2454
|
const timeout = timeoutMs === void 0 ? void 0 : (0, _orkestrel_timeout.createTimeout)({ ms: timeoutMs });
|
|
2277
2455
|
timeout?.start();
|
|
2278
2456
|
const budget = options?.budget ?? this.#budget;
|
|
2279
2457
|
budget?.start();
|
|
2280
2458
|
const limit = options?.limit ?? this.#limit;
|
|
2281
|
-
const
|
|
2459
|
+
const signal = this.#parents(timeout, budget, options?.signal);
|
|
2460
|
+
const abort = (0, _orkestrel_abort.createAbort)(signal === void 0 ? {} : { signal });
|
|
2282
2461
|
this.#runs.add(abort);
|
|
2283
2462
|
this.#status = "running";
|
|
2284
2463
|
this.#emitter.emit("start", this.id);
|
|
2285
|
-
const
|
|
2464
|
+
const state = { outcome: {
|
|
2286
2465
|
content: "",
|
|
2287
2466
|
thinking: void 0,
|
|
2288
2467
|
usage: void 0,
|
|
2289
2468
|
partial: false,
|
|
2290
2469
|
exhausted: false
|
|
2291
|
-
};
|
|
2470
|
+
} };
|
|
2292
2471
|
const channel = new Channel();
|
|
2293
2472
|
const settled = (0, _orkestrel_workflow.createDeferred)();
|
|
2294
|
-
this.#pump(abort,
|
|
2473
|
+
this.#pump(abort, state, timeout, channel, settled, options?.think, options?.schema, limit, budget);
|
|
2295
2474
|
settled.promise.catch(() => {});
|
|
2296
2475
|
return {
|
|
2297
2476
|
events: this.#events(channel, abort),
|
|
2298
2477
|
result: settled.promise,
|
|
2299
|
-
abort: (
|
|
2300
|
-
abort.abort(reason);
|
|
2301
|
-
}
|
|
2478
|
+
abort: abort.abort.bind(abort)
|
|
2302
2479
|
};
|
|
2303
2480
|
}
|
|
2304
2481
|
abort(reason) {
|
|
2305
2482
|
for (const abort of [...this.#runs]) abort.abort(reason);
|
|
2306
2483
|
}
|
|
2307
|
-
async #pump(abort,
|
|
2484
|
+
async #pump(abort, state, timeout, channel, settled, think, schema, limit, budget) {
|
|
2308
2485
|
let failure;
|
|
2309
2486
|
try {
|
|
2310
|
-
for await (const chunk of this.#run(abort,
|
|
2487
|
+
for await (const chunk of this.#run(abort, state, think, schema, limit, budget)) channel.push(chunk);
|
|
2311
2488
|
} catch (error) {
|
|
2312
2489
|
failure = { error };
|
|
2313
2490
|
} finally {
|
|
2314
2491
|
timeout?.clear();
|
|
2315
2492
|
this.#runs.delete(abort);
|
|
2316
2493
|
if (failure === void 0) {
|
|
2494
|
+
const outcome = state.outcome;
|
|
2317
2495
|
this.#status = "done";
|
|
2318
2496
|
channel.close();
|
|
2319
2497
|
const result = this.#result(outcome);
|
|
@@ -2336,7 +2514,7 @@ var Agent = class {
|
|
|
2336
2514
|
abort.abort();
|
|
2337
2515
|
}
|
|
2338
2516
|
}
|
|
2339
|
-
async *#run(abort,
|
|
2517
|
+
async *#run(abort, state, think, schema, limit, budget) {
|
|
2340
2518
|
const messages = [...this.#context.build(this.#provider.format)];
|
|
2341
2519
|
const tools = this.#context.tools;
|
|
2342
2520
|
let content = "";
|
|
@@ -2344,7 +2522,7 @@ var Agent = class {
|
|
|
2344
2522
|
let usage;
|
|
2345
2523
|
let pending = false;
|
|
2346
2524
|
let broke = false;
|
|
2347
|
-
const compaction = { futile: false };
|
|
2525
|
+
const compaction = { state: { futile: false } };
|
|
2348
2526
|
const compacting = this.#window !== void 0 && this.#context.conversations.active?.summarizable === true;
|
|
2349
2527
|
if (compacting) {
|
|
2350
2528
|
this.#window?.clear();
|
|
@@ -2356,14 +2534,20 @@ var Agent = class {
|
|
|
2356
2534
|
await this.#scheduler?.yield({ signal: abort.signal });
|
|
2357
2535
|
} catch (error) {
|
|
2358
2536
|
if (abort.signal.aborted) {
|
|
2359
|
-
outcome
|
|
2537
|
+
state.outcome = {
|
|
2538
|
+
...state.outcome,
|
|
2539
|
+
partial: true
|
|
2540
|
+
};
|
|
2360
2541
|
broke = true;
|
|
2361
2542
|
break;
|
|
2362
2543
|
}
|
|
2363
2544
|
throw error;
|
|
2364
2545
|
}
|
|
2365
2546
|
if (abort.signal.aborted) {
|
|
2366
|
-
outcome
|
|
2547
|
+
state.outcome = {
|
|
2548
|
+
...state.outcome,
|
|
2549
|
+
partial: true
|
|
2550
|
+
};
|
|
2367
2551
|
broke = true;
|
|
2368
2552
|
break;
|
|
2369
2553
|
}
|
|
@@ -2391,7 +2575,7 @@ var Agent = class {
|
|
|
2391
2575
|
if (isProviderAbortError(error)) {
|
|
2392
2576
|
if (error.partial.thinking !== void 0) thinking = this.#thought(thinking, error.partial.thinking);
|
|
2393
2577
|
if (error.partial.usage !== void 0) {
|
|
2394
|
-
const abortUsage = error.partial.usage;
|
|
2578
|
+
const abortUsage = sanitizeUsage(error.partial.usage);
|
|
2395
2579
|
budget?.consume({
|
|
2396
2580
|
prompt: abortUsage.prompt,
|
|
2397
2581
|
completion: Math.max(0, abortUsage.completion - charged),
|
|
@@ -2400,7 +2584,10 @@ var Agent = class {
|
|
|
2400
2584
|
usage = this.#sum(usage, abortUsage);
|
|
2401
2585
|
}
|
|
2402
2586
|
}
|
|
2403
|
-
outcome
|
|
2587
|
+
state.outcome = {
|
|
2588
|
+
...state.outcome,
|
|
2589
|
+
partial: true
|
|
2590
|
+
};
|
|
2404
2591
|
broke = true;
|
|
2405
2592
|
break;
|
|
2406
2593
|
}
|
|
@@ -2408,16 +2595,17 @@ var Agent = class {
|
|
|
2408
2595
|
}
|
|
2409
2596
|
if (result.thinking !== void 0 && result.thinking.length > 0) thinking = this.#thought(thinking, result.thinking);
|
|
2410
2597
|
if (result.usage !== void 0) {
|
|
2598
|
+
const resultUsage = sanitizeUsage(result.usage);
|
|
2411
2599
|
budget?.consume({
|
|
2412
|
-
prompt:
|
|
2413
|
-
completion: Math.max(0,
|
|
2414
|
-
total: Math.max(0,
|
|
2600
|
+
prompt: resultUsage.prompt,
|
|
2601
|
+
completion: Math.max(0, resultUsage.completion - charged),
|
|
2602
|
+
total: Math.max(0, resultUsage.total - charged)
|
|
2415
2603
|
});
|
|
2416
|
-
usage = this.#sum(usage,
|
|
2417
|
-
this.#emitter.emit("usage",
|
|
2604
|
+
usage = this.#sum(usage, resultUsage);
|
|
2605
|
+
this.#emitter.emit("usage", resultUsage);
|
|
2418
2606
|
yield {
|
|
2419
2607
|
type: "usage",
|
|
2420
|
-
usage:
|
|
2608
|
+
usage: resultUsage
|
|
2421
2609
|
};
|
|
2422
2610
|
}
|
|
2423
2611
|
if (result.tools !== void 0 && result.tools.length > 0) {
|
|
@@ -2457,17 +2645,21 @@ var Agent = class {
|
|
|
2457
2645
|
broke = true;
|
|
2458
2646
|
break;
|
|
2459
2647
|
}
|
|
2460
|
-
if (!broke && pending) {
|
|
2461
|
-
outcome
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
outcome
|
|
2466
|
-
|
|
2648
|
+
if (!broke && pending) state.outcome = {
|
|
2649
|
+
...state.outcome,
|
|
2650
|
+
partial: true,
|
|
2651
|
+
exhausted: !abort.signal.aborted
|
|
2652
|
+
};
|
|
2653
|
+
state.outcome = {
|
|
2654
|
+
...state.outcome,
|
|
2655
|
+
content,
|
|
2656
|
+
thinking,
|
|
2657
|
+
usage
|
|
2658
|
+
};
|
|
2467
2659
|
}
|
|
2468
2660
|
async #trim(messages, compaction, latchFutile) {
|
|
2469
2661
|
const conversation = this.#context.conversations.active;
|
|
2470
|
-
if (this.#window === void 0 || conversation?.summarizable !== true || compaction.futile) return;
|
|
2662
|
+
if (this.#window === void 0 || conversation?.summarizable !== true || compaction.state.futile) return;
|
|
2471
2663
|
this.#window.clear();
|
|
2472
2664
|
this.#window.consume(messages);
|
|
2473
2665
|
if (!this.#window.exhausted) return;
|
|
@@ -2476,10 +2668,11 @@ var Agent = class {
|
|
|
2476
2668
|
section = await conversation.compact();
|
|
2477
2669
|
} catch (error) {
|
|
2478
2670
|
this.#emitter.emit("compactError", error);
|
|
2671
|
+
if (this.#strict) throw error;
|
|
2479
2672
|
return;
|
|
2480
2673
|
}
|
|
2481
2674
|
if (section === void 0) {
|
|
2482
|
-
if (latchFutile) compaction.
|
|
2675
|
+
if (latchFutile) compaction.state = { futile: true };
|
|
2483
2676
|
return;
|
|
2484
2677
|
}
|
|
2485
2678
|
messages.splice(0, messages.length, ...this.#context.build(this.#provider.format));
|
|
@@ -2641,16 +2834,17 @@ var AgentRegistry = class {
|
|
|
2641
2834
|
return agent;
|
|
2642
2835
|
}
|
|
2643
2836
|
#options(input, signal) {
|
|
2837
|
+
const budget = this.#budget(input.budget);
|
|
2644
2838
|
return {
|
|
2645
|
-
system: input.system,
|
|
2646
2839
|
tools: this.#manager(input.tools),
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2840
|
+
...input.system === void 0 ? {} : { system: input.system },
|
|
2841
|
+
...input.limit === void 0 ? {} : { limit: input.limit },
|
|
2842
|
+
...input.timeout === void 0 ? {} : { timeout: input.timeout },
|
|
2843
|
+
...budget === void 0 ? {} : { budget },
|
|
2844
|
+
...input.authority === void 0 ? {} : { authority: this.authority(input.authority) },
|
|
2845
|
+
...input.scheduler === void 0 ? {} : { scheduler: this.scheduler(input.scheduler) },
|
|
2846
|
+
...this.#store === void 0 ? {} : { conversations: new ConversationManager({ store: this.#store }) },
|
|
2847
|
+
...signal === void 0 ? {} : { signal }
|
|
2654
2848
|
};
|
|
2655
2849
|
}
|
|
2656
2850
|
#manager(names) {
|
|
@@ -2716,7 +2910,7 @@ var Authority = class {
|
|
|
2716
2910
|
for (const rule of this.#rules) if (rule.match(context)) return {
|
|
2717
2911
|
zone: rule.zone,
|
|
2718
2912
|
allowed: rule.allowed ?? true,
|
|
2719
|
-
reason: rule.reason
|
|
2913
|
+
...rule.reason === void 0 ? {} : { reason: rule.reason }
|
|
2720
2914
|
};
|
|
2721
2915
|
return this.#fallback;
|
|
2722
2916
|
}
|
|
@@ -2895,16 +3089,19 @@ var Scope = class Scope {
|
|
|
2895
3089
|
files;
|
|
2896
3090
|
constructor(input) {
|
|
2897
3091
|
this.name = input.name;
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
3092
|
+
if (input.instructions !== void 0) this.instructions = [...input.instructions];
|
|
3093
|
+
if (input.tools !== void 0) this.tools = [...input.tools];
|
|
3094
|
+
if (input.files !== void 0) this.files = [...input.files];
|
|
2901
3095
|
}
|
|
2902
3096
|
narrow(config) {
|
|
3097
|
+
const instructions = Scope.#intersect(this.instructions, config.instructions);
|
|
3098
|
+
const tools = Scope.#intersect(this.tools, config.tools);
|
|
3099
|
+
const files = Scope.#intersect(this.files, config.files);
|
|
2903
3100
|
return new Scope({
|
|
2904
3101
|
name: this.name,
|
|
2905
|
-
instructions:
|
|
2906
|
-
tools:
|
|
2907
|
-
files:
|
|
3102
|
+
...instructions === void 0 ? {} : { instructions },
|
|
3103
|
+
...tools === void 0 ? {} : { tools },
|
|
3104
|
+
...files === void 0 ? {} : { files }
|
|
2908
3105
|
});
|
|
2909
3106
|
}
|
|
2910
3107
|
static #intersect(parent, child) {
|
|
@@ -2948,8 +3145,8 @@ var ScopeManager = class {
|
|
|
2948
3145
|
#emitter;
|
|
2949
3146
|
constructor(on, error) {
|
|
2950
3147
|
this.#emitter = new _orkestrel_emitter.Emitter({
|
|
2951
|
-
on,
|
|
2952
|
-
error
|
|
3148
|
+
...on === void 0 ? {} : { on },
|
|
3149
|
+
...error === void 0 ? {} : { error }
|
|
2953
3150
|
});
|
|
2954
3151
|
}
|
|
2955
3152
|
get emitter() {
|
|
@@ -3139,9 +3336,9 @@ var Tool = class {
|
|
|
3139
3336
|
#execute;
|
|
3140
3337
|
constructor(options) {
|
|
3141
3338
|
this.name = options.name;
|
|
3142
|
-
this.description = options.description;
|
|
3143
|
-
this.summary = options.summary;
|
|
3144
|
-
this.parameters = options.parameters;
|
|
3339
|
+
if (options.description !== void 0) this.description = options.description;
|
|
3340
|
+
if (options.summary !== void 0) this.summary = options.summary;
|
|
3341
|
+
if (options.parameters !== void 0) this.parameters = options.parameters;
|
|
3145
3342
|
this.#execute = options.execute;
|
|
3146
3343
|
}
|
|
3147
3344
|
execute(args) {
|
|
@@ -3799,11 +3996,11 @@ function createAgentRegistry(options) {
|
|
|
3799
3996
|
function createAgentQueue(options) {
|
|
3800
3997
|
const { registry, allowPartial = false, concurrency, retries, timeout, store } = options;
|
|
3801
3998
|
return (0, _orkestrel_queue.createQueue)({
|
|
3802
|
-
concurrency,
|
|
3803
|
-
retries,
|
|
3804
|
-
timeout,
|
|
3805
|
-
store,
|
|
3806
|
-
handler: (
|
|
3999
|
+
...concurrency === void 0 ? {} : { concurrency },
|
|
4000
|
+
...retries === void 0 ? {} : { retries },
|
|
4001
|
+
...timeout === void 0 ? {} : { timeout },
|
|
4002
|
+
...store === void 0 ? {} : { store },
|
|
4003
|
+
handler: handleAgentQueueJob.bind(void 0, registry, allowPartial)
|
|
3807
4004
|
});
|
|
3808
4005
|
}
|
|
3809
4006
|
/**
|
|
@@ -3845,14 +4042,10 @@ function createAgentQueue(options) {
|
|
|
3845
4042
|
function createAgentRunner(options) {
|
|
3846
4043
|
const { registry, allowPartial = false, concurrency, retries, timeout } = options;
|
|
3847
4044
|
return (0, _orkestrel_workflow.createRunner)({
|
|
3848
|
-
concurrency,
|
|
3849
|
-
retries,
|
|
3850
|
-
timeout,
|
|
3851
|
-
handler: (
|
|
3852
|
-
const children = controller.input.children;
|
|
3853
|
-
if (children !== void 0) for (const child of children) controller.spawn(child);
|
|
3854
|
-
return settleAgentJob(registry.build(controller.input, controller.signal), allowPartial);
|
|
3855
|
-
}
|
|
4045
|
+
...concurrency === void 0 ? {} : { concurrency },
|
|
4046
|
+
...retries === void 0 ? {} : { retries },
|
|
4047
|
+
...timeout === void 0 ? {} : { timeout },
|
|
4048
|
+
handler: handleAgentRunnerJob.bind(void 0, registry, allowPartial)
|
|
3856
4049
|
});
|
|
3857
4050
|
}
|
|
3858
4051
|
/**
|
|
@@ -4064,6 +4257,7 @@ function createWorkspaceManager(options) {
|
|
|
4064
4257
|
//#endregion
|
|
4065
4258
|
exports.Agent = Agent;
|
|
4066
4259
|
exports.AgentContext = AgentContext;
|
|
4260
|
+
exports.AgentError = AgentError;
|
|
4067
4261
|
exports.AgentJobError = AgentJobError;
|
|
4068
4262
|
exports.AgentRegistry = AgentRegistry;
|
|
4069
4263
|
exports.Authority = Authority;
|
|
@@ -4078,8 +4272,10 @@ exports.DEFAULT_CONVERSATION_KEEP = DEFAULT_CONVERSATION_KEEP;
|
|
|
4078
4272
|
exports.DatabaseConversationStore = DatabaseConversationStore;
|
|
4079
4273
|
exports.DatabaseWorkspaceStore = DatabaseWorkspaceStore;
|
|
4080
4274
|
exports.EXTENSION_TO_LANGUAGE = EXTENSION_TO_LANGUAGE;
|
|
4275
|
+
exports.IMAGE_TOKEN_ESTIMATE = IMAGE_TOKEN_ESTIMATE;
|
|
4081
4276
|
exports.Instruction = Instruction;
|
|
4082
4277
|
exports.InstructionManager = InstructionManager;
|
|
4278
|
+
exports.MESSAGE_TOKEN_OVERHEAD = MESSAGE_TOKEN_OVERHEAD;
|
|
4083
4279
|
exports.MemoryConversationStore = MemoryConversationStore;
|
|
4084
4280
|
exports.MemoryWorkspaceStore = MemoryWorkspaceStore;
|
|
4085
4281
|
exports.ProviderAbortError = ProviderAbortError;
|
|
@@ -4129,7 +4325,10 @@ exports.estimateMessages = estimateMessages;
|
|
|
4129
4325
|
exports.estimateTokens = estimateTokens;
|
|
4130
4326
|
exports.fencedFile = fencedFile;
|
|
4131
4327
|
exports.filterAllowList = filterAllowList;
|
|
4328
|
+
exports.handleAgentQueueJob = handleAgentQueueJob;
|
|
4329
|
+
exports.handleAgentRunnerJob = handleAgentRunnerJob;
|
|
4132
4330
|
exports.inferLanguage = inferLanguage;
|
|
4331
|
+
exports.isAgentError = isAgentError;
|
|
4133
4332
|
exports.isAgentJobError = isAgentJobError;
|
|
4134
4333
|
exports.isBinary = isBinary;
|
|
4135
4334
|
exports.isConversationError = isConversationError;
|
|
@@ -4146,6 +4345,8 @@ exports.isWorkspaceError = isWorkspaceError;
|
|
|
4146
4345
|
exports.isWorkspaceSnapshot = isWorkspaceSnapshot;
|
|
4147
4346
|
exports.offsetAt = offsetAt;
|
|
4148
4347
|
exports.rangeOf = rangeOf;
|
|
4348
|
+
exports.sanitizeToken = sanitizeToken;
|
|
4349
|
+
exports.sanitizeUsage = sanitizeUsage;
|
|
4149
4350
|
exports.settleAgentJob = settleAgentJob;
|
|
4150
4351
|
exports.sliceRange = sliceRange;
|
|
4151
4352
|
exports.spliceRange = spliceRange;
|