@linxiraos/pi-agent-core 1.1.14 → 1.1.16
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/CHANGELOG.md +169 -26
- package/THIRD-PARTY-NOTICES.txt +54 -25
- package/dist/types/agent.d.ts +17 -4
- package/dist/types/append-only-context.d.ts +0 -4
- package/dist/types/compaction/anthropic.d.ts +108 -0
- package/dist/types/compaction/compaction-v2-streaming.d.ts +2 -2
- package/dist/types/compaction/compaction.d.ts +33 -18
- package/dist/types/compaction/entries.d.ts +2 -0
- package/dist/types/compaction/index.d.ts +1 -0
- package/dist/types/compaction/openai.d.ts +9 -8
- package/dist/types/index.d.ts +1 -0
- package/dist/types/speculative-execution.d.ts +63 -0
- package/dist/types/thinking.d.ts +1 -1
- package/dist/types/types.d.ts +212 -3
- package/package.json +10 -10
- package/src/agent-loop.ts +582 -86
- package/src/agent.ts +183 -38
- package/src/append-only-context.ts +122 -1
- package/src/compaction/anthropic.ts +310 -0
- package/src/compaction/compaction-v2-streaming.ts +4 -3
- package/src/compaction/compaction.ts +299 -131
- package/src/compaction/entries.ts +2 -0
- package/src/compaction/index.ts +1 -0
- package/src/compaction/openai.ts +17 -10
- package/src/compaction/prompts/anthropic-compaction-instructions.md +17 -0
- package/src/index.ts +2 -0
- package/src/proxy.ts +49 -8
- package/src/speculative-execution.ts +953 -0
- package/src/telemetry.ts +1 -0
- package/src/thinking.ts +1 -1
- package/src/tokenizer.ts +11 -2
- package/src/types.ts +232 -4
package/src/telemetry.ts
CHANGED
|
@@ -1756,6 +1756,7 @@ export async function instrumentedCompleteSimple<TApi extends Api>(
|
|
|
1756
1756
|
const message = span.retry
|
|
1757
1757
|
? await retryTransientCompletion(runOnce, {
|
|
1758
1758
|
...span.retry,
|
|
1759
|
+
provider: model.provider,
|
|
1759
1760
|
// Framework-owned: the caller must not be able to detach the
|
|
1760
1761
|
// abort signal or the header source by passing them itself.
|
|
1761
1762
|
signal: options.signal,
|
package/src/thinking.ts
CHANGED
package/src/tokenizer.ts
CHANGED
|
@@ -219,14 +219,22 @@ export class Tokenizer {
|
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
switch (message.role) {
|
|
222
|
-
case "user":
|
|
223
|
-
|
|
222
|
+
case "user":
|
|
223
|
+
case "developer": {
|
|
224
|
+
// Both roles carry `string | (TextContent | ImageContent)[]` and both are
|
|
225
|
+
// sent to the provider -- convertMessageToLlm handles developer alongside
|
|
226
|
+
// user -- so they are counted alike. Without the developer case the switch
|
|
227
|
+
// fell through to `default: return 0`, and the old annotation narrowed the
|
|
228
|
+
// blocks to text-only, hiding the image charge the toolResult arm applies.
|
|
229
|
+
const content = message.content;
|
|
224
230
|
if (typeof content === "string") {
|
|
225
231
|
fragments.push(content);
|
|
226
232
|
} else if (Array.isArray(content)) {
|
|
227
233
|
for (const block of content) {
|
|
228
234
|
if (block.type === "text" && block.text) {
|
|
229
235
|
fragments.push(block.text);
|
|
236
|
+
} else if (block.type === "image") {
|
|
237
|
+
extra += IMAGE_TOKEN_ESTIMATE;
|
|
230
238
|
}
|
|
231
239
|
}
|
|
232
240
|
}
|
|
@@ -266,6 +274,7 @@ export class Tokenizer {
|
|
|
266
274
|
}
|
|
267
275
|
break;
|
|
268
276
|
}
|
|
277
|
+
case "custom":
|
|
269
278
|
case "hookMessage":
|
|
270
279
|
case "toolResult": {
|
|
271
280
|
if (typeof message.content === "string") {
|
package/src/types.ts
CHANGED
|
@@ -31,8 +31,22 @@ export type StreamFn = (
|
|
|
31
31
|
...args: Parameters<typeof streamSimple>
|
|
32
32
|
) => AssistantMessageEventStream | Promise<AssistantMessageEventStream>;
|
|
33
33
|
|
|
34
|
+
/** Staged queue preparation; commit synchronously only while the batch is still owned. */
|
|
35
|
+
export interface QueuedMessagePreparation {
|
|
36
|
+
/** Append context after the originals; undefined stops this attempt, retaining originals unless explicitly removed. */
|
|
37
|
+
commit(): readonly AgentMessage[] | undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Prepare an exclusively claimed batch. Undefined delivers unchanged; the signal also aborts when the claim is cancelled. */
|
|
41
|
+
export type PrepareQueuedMessages = (
|
|
42
|
+
messages: readonly AgentMessage[],
|
|
43
|
+
signal: AbortSignal,
|
|
44
|
+
) => QueuedMessagePreparation | undefined | Promise<QueuedMessagePreparation | undefined>;
|
|
45
|
+
|
|
34
46
|
/** Called once an aside has been inserted into the agent's live context. */
|
|
35
47
|
export const ASIDE_MESSAGE_COMMIT = Symbol("aside-message-commit");
|
|
48
|
+
/** Symbol-keyed handoff for one finalized, tool-owned stream speculation session. */
|
|
49
|
+
export const SPECULATIVE_STREAM_SESSION = Symbol("speculative-stream-session");
|
|
36
50
|
/** Called when an aside was drained but the agent loop ended before inserting it. */
|
|
37
51
|
export const ASIDE_MESSAGE_DISCARD = Symbol("aside-message-discard");
|
|
38
52
|
|
|
@@ -338,13 +352,33 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
|
|
|
338
352
|
* Use for deobfuscating secrets or rewriting arguments.
|
|
339
353
|
*/
|
|
340
354
|
transformToolCallArguments?: (args: Record<string, unknown>, toolName: string) => Record<string, unknown>;
|
|
355
|
+
/**
|
|
356
|
+
* Opt-in speculative execution for finalized, discard-safe tool calls.
|
|
357
|
+
*
|
|
358
|
+
* Candidates remain invisible until ordinary dispatch commits their result.
|
|
359
|
+
*/
|
|
360
|
+
speculativeToolExecution?: SpeculativeToolExecutionConfig;
|
|
341
361
|
/**
|
|
342
362
|
* Resolve a tool call whose name matched no advertised tool (including
|
|
343
363
|
* `customWireName` aliases). Lets hosts route calls to tools they expose
|
|
344
364
|
* through side transports (e.g. `xd://` device mounts) instead of failing
|
|
345
365
|
* with "Tool not found". Returning `undefined` keeps the failure.
|
|
366
|
+
*
|
|
367
|
+
* `advertised` is the very snapshot exact-name dispatch just searched — the
|
|
368
|
+
* set offered to THIS request. A host must resolve against it rather than
|
|
369
|
+
* its own live tool state: an MCP `tools/list_changed` mid-stream reassigns
|
|
370
|
+
* the agent's tools, so live state can hold a roster the model never saw,
|
|
371
|
+
* and a name-recovering host would dispatch a tool this request never
|
|
372
|
+
* advertised while exact dispatch still answered from the snapshot.
|
|
373
|
+
*/
|
|
374
|
+
resolveFallbackTool?: (name: string, advertised: readonly AgentTool<any>[]) => AgentTool<any> | undefined;
|
|
375
|
+
/**
|
|
376
|
+
* Names reachable through {@link resolveFallbackTool} but absent from the
|
|
377
|
+
* advertised set (e.g. `xd://` device mounts). Consulted only to name a
|
|
378
|
+
* plausible target when a call misses, so a mis-transcribed device call is
|
|
379
|
+
* recoverable; never a dispatch source.
|
|
346
380
|
*/
|
|
347
|
-
|
|
381
|
+
suggestFallbackToolNames?: () => Iterable<string>;
|
|
348
382
|
|
|
349
383
|
/**
|
|
350
384
|
* Enable intent tracing for tool calls.
|
|
@@ -565,6 +599,192 @@ export interface ToolCallContext {
|
|
|
565
599
|
/** A single tool-call content block emitted by an assistant message. */
|
|
566
600
|
export type AgentToolCall = Extract<AssistantMessage["content"][number], { type: "toolCall" }>;
|
|
567
601
|
|
|
602
|
+
export interface SpeculativeResourceAccess {
|
|
603
|
+
scheme: "file";
|
|
604
|
+
path: string;
|
|
605
|
+
access: "read";
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/** Declares an operation whose early execution can be discarded without rollback. */
|
|
609
|
+
export type ToolSpeculationEffect =
|
|
610
|
+
| { kind: "pure" }
|
|
611
|
+
| { kind: "local_read"; resources: readonly SpeculativeResourceAccess[] };
|
|
612
|
+
|
|
613
|
+
export type ToolSpeculationAssessment =
|
|
614
|
+
| { eligible: false; reason: string }
|
|
615
|
+
| { eligible: true; effect: ToolSpeculationEffect };
|
|
616
|
+
|
|
617
|
+
/** Immutable finalized call data provided to a tool-owned policy. */
|
|
618
|
+
export interface ToolSpeculationAssessmentContext {
|
|
619
|
+
toolCall: AgentToolCall;
|
|
620
|
+
args: Readonly<Record<string, unknown>>;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
export interface ToolSpeculationExecutionContext extends ToolSpeculationAssessmentContext {
|
|
624
|
+
effect: ToolSpeculationEffect;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
export interface ToolSpeculationCommitContext extends ToolSpeculationExecutionContext {
|
|
628
|
+
physicalOutcome: SpeculativePhysicalOutcome;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
export interface ToolSpeculationDiscardContext extends ToolSpeculationExecutionContext {
|
|
632
|
+
reason: string;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
export interface SpeculativePhysicalOutcome {
|
|
636
|
+
kind: "result";
|
|
637
|
+
result: AgentToolResult<unknown>;
|
|
638
|
+
isError: boolean;
|
|
639
|
+
/** Opaque evidence binding the result to the local bytes actually consumed. */
|
|
640
|
+
evidence?: unknown;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
export interface SpeculativeToolReference {
|
|
644
|
+
name: string;
|
|
645
|
+
approval?: ToolApproval;
|
|
646
|
+
formatApprovalDetails?: (args: unknown) => string | string[] | undefined;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
export interface SpeculativeOperationContext extends ToolSpeculationExecutionContext {
|
|
650
|
+
tool: SpeculativeToolReference;
|
|
651
|
+
candidateId: string;
|
|
652
|
+
source: "direct" | "eval_shadow";
|
|
653
|
+
dependencies: readonly string[];
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
export interface SpeculativeCommitContext extends SpeculativeOperationContext {
|
|
657
|
+
physicalOutcome: SpeculativePhysicalOutcome;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
export interface SpeculativeDiscardContext extends SpeculativeOperationContext {
|
|
661
|
+
reason: string;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
export type SpeculativeAuthorization =
|
|
665
|
+
| { allowed: false; reason: string }
|
|
666
|
+
| { allowed: true; deferBeforeToolCall?: boolean };
|
|
667
|
+
|
|
668
|
+
export type SpeculativeCommitDecision =
|
|
669
|
+
| { kind: "committed"; result: AgentToolResult<unknown> }
|
|
670
|
+
| { kind: "fallback"; reason: string }
|
|
671
|
+
| { kind: "failed"; error: unknown };
|
|
672
|
+
|
|
673
|
+
export interface SpeculativeExecutionHost {
|
|
674
|
+
authorize(context: SpeculativeOperationContext): SpeculativeAuthorization | Promise<SpeculativeAuthorization>;
|
|
675
|
+
/**
|
|
676
|
+
* Capture content evidence after admission gates pass but before the
|
|
677
|
+
* candidate executes. The coordinator invokes this immediately before
|
|
678
|
+
* starting speculative execution — which for hook-deferred candidates is
|
|
679
|
+
* after `beforeToolCall` runs — so content inspection never precedes a
|
|
680
|
+
* hook that may block the call. Return false (or throw) to veto the
|
|
681
|
+
* candidate without executing it. Hosts without this hook keep the legacy
|
|
682
|
+
* behavior of capturing during `authorize`.
|
|
683
|
+
*/
|
|
684
|
+
captureEvidence?(context: SpeculativeOperationContext): boolean | Promise<boolean>;
|
|
685
|
+
validate?(context: SpeculativeCommitContext): boolean | Promise<boolean>;
|
|
686
|
+
commit?(
|
|
687
|
+
context: SpeculativeCommitContext,
|
|
688
|
+
commitDefault: () => Promise<AgentToolResult<unknown>>,
|
|
689
|
+
): Promise<SpeculativeCommitDecision>;
|
|
690
|
+
discard?(context: SpeculativeDiscardContext): void | Promise<void>;
|
|
691
|
+
close?(reason: string): void | Promise<void>;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
export interface ToolSpeculationStreamContext {
|
|
695
|
+
readonly coordinator: SpeculativeOperationSink;
|
|
696
|
+
readonly parentToolCallId: string;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/** One dependency-aware child operation projected by a streamed outer tool. */
|
|
700
|
+
export interface SpeculativeChildDefinition {
|
|
701
|
+
candidateId: string;
|
|
702
|
+
parentToolCallId: string;
|
|
703
|
+
dependencies: readonly string[];
|
|
704
|
+
toolCall: AgentToolCall;
|
|
705
|
+
tool: AgentTool;
|
|
706
|
+
source: "eval_shadow";
|
|
707
|
+
virtualDurationMs?: number;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/** Opaque ownership handle returned after agent-core validates and authorizes a child. */
|
|
711
|
+
export interface SpeculativeChildHandle {
|
|
712
|
+
readonly candidateId: string;
|
|
713
|
+
readonly fingerprint: string;
|
|
714
|
+
readonly effect: ToolSpeculationEffect;
|
|
715
|
+
readonly outcome: Promise<SpeculativePhysicalOutcome>;
|
|
716
|
+
commit(actualArgs: Readonly<Record<string, unknown>>): Promise<AgentToolResult<unknown> | undefined>;
|
|
717
|
+
discard(reason: string): Promise<void>;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
export interface ToolSpeculationStreamSession {
|
|
721
|
+
/** True when the tool owns claim routing and does not need an AgentToolContext attachment. */
|
|
722
|
+
readonly contextIndependent?: boolean;
|
|
723
|
+
update(toolCall: AgentToolCall, partialJson?: string): void | Promise<void>;
|
|
724
|
+
finalize(context: ToolSpeculationAssessmentContext): void | Promise<void>;
|
|
725
|
+
commit(): void | Promise<void>;
|
|
726
|
+
discard(reason: string): void | Promise<void>;
|
|
727
|
+
/**
|
|
728
|
+
* Whether the session's streamed plan still authorizes these final
|
|
729
|
+
* arguments. The coordinator discards the session when the finalized call
|
|
730
|
+
* kept its ID but a hook or argument transform replaced its arguments:
|
|
731
|
+
* deferred work planned from the original code must never release.
|
|
732
|
+
* Sessions without this predicate are always retained.
|
|
733
|
+
*/
|
|
734
|
+
matchesFinalArgs?(args: Readonly<Record<string, unknown>>): boolean;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
export interface SpeculativeOperationSink {
|
|
738
|
+
readonly maxInFlight: number;
|
|
739
|
+
admit(definition: SpeculativeChildDefinition): Promise<SpeculativeChildHandle | undefined>;
|
|
740
|
+
discardChildren?(parentToolCallId: string, reason: string): void | Promise<void>;
|
|
741
|
+
close(reason: string): void | Promise<void>;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
export interface ToolSpeculationPolicy {
|
|
745
|
+
finalized?: {
|
|
746
|
+
assess(context: ToolSpeculationAssessmentContext): ToolSpeculationAssessment | Promise<ToolSpeculationAssessment>;
|
|
747
|
+
execute(context: ToolSpeculationExecutionContext, signal: AbortSignal): Promise<SpeculativePhysicalOutcome>;
|
|
748
|
+
commit?(
|
|
749
|
+
context: ToolSpeculationCommitContext,
|
|
750
|
+
outcome: SpeculativePhysicalOutcome,
|
|
751
|
+
): Promise<AgentToolResult<unknown>>;
|
|
752
|
+
discard?(context: ToolSpeculationDiscardContext): void | Promise<void>;
|
|
753
|
+
};
|
|
754
|
+
stream?: {
|
|
755
|
+
open(
|
|
756
|
+
context: ToolSpeculationStreamContext,
|
|
757
|
+
): ToolSpeculationStreamSession | Promise<ToolSpeculationStreamSession | undefined>;
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/** Diagnostic information for one speculative operation. */
|
|
762
|
+
export interface SpeculativeToolTelemetry {
|
|
763
|
+
source: "direct" | "eval_shadow";
|
|
764
|
+
candidateId: string;
|
|
765
|
+
parentToolCallId?: string;
|
|
766
|
+
toolName: string;
|
|
767
|
+
effectKind?: ToolSpeculationEffect["kind"];
|
|
768
|
+
candidateStartedAt?: number;
|
|
769
|
+
candidateFinishedAt?: number;
|
|
770
|
+
dispatchReachedAt?: number;
|
|
771
|
+
dependencyCount: number;
|
|
772
|
+
queueMs?: number;
|
|
773
|
+
executionDurationMs?: number;
|
|
774
|
+
overlapMs?: number;
|
|
775
|
+
outcome: "committed" | "discarded" | "ineligible" | "fingerprint_mismatch" | "aborted" | "commit_conflict";
|
|
776
|
+
reason?: string;
|
|
777
|
+
resourceCount: number;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/** Opt-in configuration for discard-safe speculative tool execution. */
|
|
781
|
+
export interface SpeculativeToolExecutionConfig {
|
|
782
|
+
enabled: boolean;
|
|
783
|
+
maxInFlight?: number;
|
|
784
|
+
host?: SpeculativeExecutionHost;
|
|
785
|
+
onTelemetry?: (event: SpeculativeToolTelemetry) => void;
|
|
786
|
+
}
|
|
787
|
+
|
|
568
788
|
/**
|
|
569
789
|
* Result returned from `beforeToolCall`.
|
|
570
790
|
*
|
|
@@ -609,7 +829,7 @@ export interface BeforeToolCallContext {
|
|
|
609
829
|
/** The raw tool call block from `assistantMessage.content`. */
|
|
610
830
|
toolCall: AgentToolCall;
|
|
611
831
|
/** The resolved tool the call dispatches to. */
|
|
612
|
-
tool: AgentTool
|
|
832
|
+
tool: AgentTool;
|
|
613
833
|
/**
|
|
614
834
|
* Validated tool arguments. The same reference is forwarded to `tool.execute`
|
|
615
835
|
* (after any `transformToolCallArguments` pass), so in-place mutations stick;
|
|
@@ -748,7 +968,8 @@ export type ToolApproval = ToolApprovalDecision | ((args: unknown) => ToolApprov
|
|
|
748
968
|
* Apps can extend via declaration merging.
|
|
749
969
|
*/
|
|
750
970
|
export interface AgentToolContext {
|
|
751
|
-
|
|
971
|
+
/** Present only while the matching outer tool owns its finalized stream session. */
|
|
972
|
+
[SPECULATIVE_STREAM_SESSION]?: ToolSpeculationStreamSession;
|
|
752
973
|
}
|
|
753
974
|
|
|
754
975
|
export type AgentToolExecFn<TParameters extends TSchema = TSchema, TDetails = any, TTheme = unknown> = (
|
|
@@ -791,8 +1012,9 @@ export interface AgentTool<
|
|
|
791
1012
|
* Called at `toolcall_start`, before any argument delta. Return `undefined` to opt out.
|
|
792
1013
|
*/
|
|
793
1014
|
openArgStream?: (init: AgentToolArgStreamInit) => AgentToolArgStream | undefined;
|
|
794
|
-
/** If true, tool is excluded unless explicitly listed in --tools or agent's tools field */
|
|
795
1015
|
hidden?: boolean;
|
|
1016
|
+
/** If true, the tool can read `skill://<name>` instruction content; prompt builders gate skill guidance on it. */
|
|
1017
|
+
readsSkillUris?: boolean;
|
|
796
1018
|
/** If true, tool can stage a pending action that requires explicit resolution via the resolve tool. */
|
|
797
1019
|
deferrable?: boolean;
|
|
798
1020
|
/** How an enabled tool is presented. See {@link ToolLoadMode}. Omitted is treated as `"essential"` for built-ins; custom-tool adapters normalize omission to `"discoverable"`. */
|
|
@@ -806,6 +1028,12 @@ export interface AgentTool<
|
|
|
806
1028
|
* - function: resolved per call from the (raw, pre-validation) arguments
|
|
807
1029
|
*/
|
|
808
1030
|
concurrency?: "shared" | "exclusive" | ((args: Partial<Static<TParameters>>) => "shared" | "exclusive");
|
|
1031
|
+
|
|
1032
|
+
/**
|
|
1033
|
+
* Declares the bounded, validated effect of a finalized call that may execute
|
|
1034
|
+
* before ordinary dispatch commits its result.
|
|
1035
|
+
*/
|
|
1036
|
+
speculation?: ToolSpeculationPolicy;
|
|
809
1037
|
/** If true, argument validation errors are non-fatal: raw args are passed to execute() instead of returning an error to the LLM. */
|
|
810
1038
|
lenientArgValidation?: boolean;
|
|
811
1039
|
/**
|