@modelprofile.com/flexharness 10.12.0 → 10.14.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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.codesandbox.d.ts +39 -0
- package/dist_ts/classes.codesandbox.js +539 -0
- package/dist_ts/classes.flexharness.d.ts +17 -0
- package/dist_ts/classes.flexharness.js +222 -8
- package/dist_ts/classes.toolcatalog.d.ts +90 -0
- package/dist_ts/classes.toolcatalog.js +1398 -0
- package/dist_ts/index.d.ts +1 -0
- package/dist_ts/index.js +2 -1
- package/dist_ts/interfaces.d.ts +237 -3
- package/dist_ts/interfaces.js +50 -1
- package/dist_ts/plugins.d.ts +66 -1
- package/dist_ts/plugins.js +19 -1
- package/dist_ts/utils.harnessoptions.d.ts +7 -1
- package/dist_ts/utils.harnessoptions.js +48 -2
- package/dist_ts/utils.json.js +3 -1
- package/dist_ts/utils.schemadeclarations.d.ts +53 -0
- package/dist_ts/utils.schemadeclarations.js +315 -0
- package/dist_ts/utils.tooloutput.d.ts +2 -0
- package/dist_ts/utils.tooloutput.js +11 -1
- package/dist_ts_compaction/plugins.d.ts +3 -3
- package/dist_ts_compaction/plugins.js +3 -3
- package/dist_ts_compaction/smartagent.compaction.d.ts +10 -1
- package/dist_ts_compaction/smartagent.compaction.js +79 -38
- package/package.json +17 -4
- package/readme.md +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.codesandbox.ts +565 -0
- package/ts/classes.flexharness.ts +242 -7
- package/ts/classes.toolcatalog.ts +1512 -0
- package/ts/index.ts +1 -0
- package/ts/interfaces.ts +285 -3
- package/ts/plugins.ts +86 -0
- package/ts/readme.md +1 -1
- package/ts/utils.harnessoptions.ts +55 -0
- package/ts/utils.json.ts +2 -0
- package/ts/utils.schemadeclarations.ts +322 -0
- package/ts/utils.tooloutput.ts +9 -0
- package/ts_compaction/plugins.ts +3 -3
- package/ts_compaction/smartagent.compaction.ts +90 -34
package/ts/index.ts
CHANGED
package/ts/interfaces.ts
CHANGED
|
@@ -31,6 +31,8 @@ export type TFlexRetryReason = plugins.TAgentRetryReason;
|
|
|
31
31
|
* Every call carries `provider` and `requestedModelId`; key usage caps on those two.
|
|
32
32
|
*/
|
|
33
33
|
export type TFlexModelCallUsage = plugins.TAgentModelCallUsage;
|
|
34
|
+
/** A model call's usage as harness events carry it: a reported call also states its cache hit ratio. */
|
|
35
|
+
export type TFlexObservedModelCallUsage = plugins.TAgentObservedModelCallUsage;
|
|
34
36
|
|
|
35
37
|
export interface IFlexTextPromptPart {
|
|
36
38
|
type: 'text';
|
|
@@ -135,6 +137,8 @@ export interface IFlexToolMessagePart {
|
|
|
135
137
|
output?: TJsonValue;
|
|
136
138
|
error?: string;
|
|
137
139
|
childSessionId?: string;
|
|
140
|
+
/** For a catalog call a `run_code` program made: the `run_code` call's ID. */
|
|
141
|
+
parentToolCallId?: string;
|
|
138
142
|
model?: IFlexModelIdentity;
|
|
139
143
|
/** ISO time the tool call began. Absent on parts recorded before part times existed. */
|
|
140
144
|
startedAt?: string;
|
|
@@ -648,17 +652,294 @@ export interface IFlexToolProviderContext<TScope> extends IFlexSessionGeneration
|
|
|
648
652
|
requestPermission(request: IFlexPermissionRequestInput): Promise<void>;
|
|
649
653
|
}
|
|
650
654
|
|
|
651
|
-
export interface IFlexToolHandle {
|
|
655
|
+
export interface IFlexToolHandle<TScope = unknown> {
|
|
652
656
|
tools: TFlexAgentToolSet;
|
|
657
|
+
/**
|
|
658
|
+
* Methods the model finds with `search_tools`, reads with `describe_tools` and calls with
|
|
659
|
+
* `execute`, instead of seeing each one as a tool on every step. Return the same object on
|
|
660
|
+
* every run: FlexHarness prepares a catalog once per object and treats it as immutable.
|
|
661
|
+
*/
|
|
662
|
+
catalog?: IFlexToolCatalog<TScope>;
|
|
653
663
|
close?(): Promise<void> | void;
|
|
654
664
|
}
|
|
655
665
|
|
|
656
666
|
export interface IFlexToolProvider<TScope> {
|
|
657
667
|
provideTools(
|
|
658
668
|
context: IFlexToolProviderContext<TScope>,
|
|
659
|
-
): Promise<IFlexToolHandle | undefined> | IFlexToolHandle | undefined;
|
|
669
|
+
): Promise<IFlexToolHandle<TScope> | undefined> | IFlexToolHandle<TScope> | undefined;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/** The names of the built-in catalog tools, reserved while a run has a catalog. */
|
|
673
|
+
export const FLEX_TOOL_CATALOG_TOOL_NAMES = Object.freeze({
|
|
674
|
+
search: 'search_tools',
|
|
675
|
+
describe: 'describe_tools',
|
|
676
|
+
execute: 'execute',
|
|
677
|
+
} as const);
|
|
678
|
+
|
|
679
|
+
export const FLEX_TOOL_CATALOG_LIMITS = Object.freeze({
|
|
680
|
+
maxMethods: 4096,
|
|
681
|
+
maxTypes: 4096,
|
|
682
|
+
maxMethodPathCharacters: 160,
|
|
683
|
+
maxMethodPathSegments: 8,
|
|
684
|
+
maxIdentifierCharacters: 128,
|
|
685
|
+
maxSummaryCharacters: 120,
|
|
686
|
+
maxDescriptionBytes: 16 * 1024,
|
|
687
|
+
maxDeclarationBytes: 16 * 1024,
|
|
688
|
+
maxTags: 16,
|
|
689
|
+
maxTagCharacters: 48,
|
|
690
|
+
maxExamples: 4,
|
|
691
|
+
maxExampleBytes: 1024,
|
|
692
|
+
maxSchemaBytes: 64 * 1024,
|
|
693
|
+
defaultSearchResults: 10,
|
|
694
|
+
maxSearchResults: 50,
|
|
695
|
+
maxQueryCharacters: 512,
|
|
696
|
+
maxDescribeMethods: 16,
|
|
697
|
+
maxDescribeTypes: 32,
|
|
698
|
+
maxDescribeBytes: 64 * 1024,
|
|
699
|
+
maxParamIssues: 10,
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
export interface IFlexCatalogSearchInput {
|
|
703
|
+
/** Words to rank methods by. */
|
|
704
|
+
query?: string;
|
|
705
|
+
/** A dotted namespace to search in or, without `query`, to list. */
|
|
706
|
+
namespace?: string;
|
|
707
|
+
limit?: number;
|
|
708
|
+
offset?: number;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
export interface IFlexCatalogDescribeInput {
|
|
712
|
+
/** Dotted method paths. */
|
|
713
|
+
methods?: readonly string[];
|
|
714
|
+
/** Named types to declare again or for the first time. */
|
|
715
|
+
types?: readonly string[];
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
export interface IFlexCatalogDescribeResult {
|
|
719
|
+
/** TypeScript text, or a JSON object in `json-schema` mode. */
|
|
720
|
+
output: TJsonValue;
|
|
721
|
+
/** The named types the output declares. */
|
|
722
|
+
declaredTypes: string[];
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/** One way `execute`'s params miss the method's schema. */
|
|
726
|
+
export interface IFlexCatalogParamIssue {
|
|
727
|
+
/** Where, such as `params.lines[0].amount`. */
|
|
728
|
+
path: string;
|
|
729
|
+
expected: string;
|
|
730
|
+
/** The given value as compact JSON, or `missing`. */
|
|
731
|
+
got: string;
|
|
660
732
|
}
|
|
661
733
|
|
|
734
|
+
/** What `execute` reports to the model, as JSON, when it cannot call a method. */
|
|
735
|
+
export type TFlexCatalogCallError =
|
|
736
|
+
| {
|
|
737
|
+
error: 'unknown_method';
|
|
738
|
+
method: string;
|
|
739
|
+
didYouMean: string[];
|
|
740
|
+
hint: string;
|
|
741
|
+
}
|
|
742
|
+
| {
|
|
743
|
+
error: 'invalid_params';
|
|
744
|
+
method: string;
|
|
745
|
+
issues: IFlexCatalogParamIssue[];
|
|
746
|
+
/** How many more issues were found than listed. */
|
|
747
|
+
more?: number;
|
|
748
|
+
/** The lookup that returns the method's declaration. */
|
|
749
|
+
see: string;
|
|
750
|
+
}
|
|
751
|
+
| {
|
|
752
|
+
error: 'denied';
|
|
753
|
+
method: string;
|
|
754
|
+
reason: string;
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
export interface IFlexCatalogToolDefinition {
|
|
758
|
+
description: string;
|
|
759
|
+
/** The tool's input as JSON Schema. */
|
|
760
|
+
inputSchema: plugins.JSONSchema7;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/**
|
|
764
|
+
* A parameter or result schema: a plain JSON Schema object, or a zod, Standard Schema or AI SDK
|
|
765
|
+
* schema. `$ref`s to `#/$defs/<Name>` or `#/definitions/<Name>` that the schema does not define name
|
|
766
|
+
* a catalog type.
|
|
767
|
+
*/
|
|
768
|
+
export type TFlexCatalogSchema = { readonly [keyword: string]: unknown } | plugins.FlexibleSchema<unknown>;
|
|
769
|
+
|
|
770
|
+
export interface IFlexCatalogRunContext<TScope = unknown> {
|
|
771
|
+
/** The dotted path the model called. */
|
|
772
|
+
readonly method: string;
|
|
773
|
+
/**
|
|
774
|
+
* The call's ID, which its tool part and permission requests carry: the `execute` call's, or for
|
|
775
|
+
* a call inside `run_code` the inner call's, `<run_code call ID>.<n>`.
|
|
776
|
+
*/
|
|
777
|
+
readonly toolCallId: string;
|
|
778
|
+
readonly abortSignal: AbortSignal;
|
|
779
|
+
/** The run's tool-provider context: scope, session, run and `requestPermission`. */
|
|
780
|
+
readonly provider: Readonly<IFlexToolProviderContext<TScope>>;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
export interface IFlexCatalogMethod<TScope = unknown, TParams = any, TResult = unknown> {
|
|
784
|
+
/**
|
|
785
|
+
* The dotted path the model calls, such as `banking.listMovements`: up to 8 segments, each a
|
|
786
|
+
* JavaScript identifier of letters, digits and `_`.
|
|
787
|
+
*/
|
|
788
|
+
method: string;
|
|
789
|
+
/** One line of at most 120 characters, shown in search results. */
|
|
790
|
+
summary: string;
|
|
791
|
+
/** The full description, shown with the declaration. */
|
|
792
|
+
description?: string;
|
|
793
|
+
/** More words `search_tools` matches. */
|
|
794
|
+
tags?: readonly string[];
|
|
795
|
+
/** Code shown as `@example` in the declaration. */
|
|
796
|
+
examples?: readonly string[];
|
|
797
|
+
/** The parameter object's schema; `execute` validates every call against it. */
|
|
798
|
+
inputSchema: TFlexCatalogSchema;
|
|
799
|
+
/** The result's schema, declared as the method's return type. */
|
|
800
|
+
outputSchema?: TFlexCatalogSchema;
|
|
801
|
+
/**
|
|
802
|
+
* Declaration text that replaces the generated one, such as a declaration built from TypeScript
|
|
803
|
+
* sources with their JSDoc: `function listMovements(params: …): Promise<…>;`, optionally after
|
|
804
|
+
* its JSDoc, with the last path segment as the function name.
|
|
805
|
+
*/
|
|
806
|
+
declaration?: string;
|
|
807
|
+
/** Runs the method with validated parameters. */
|
|
808
|
+
run(
|
|
809
|
+
params: TParams,
|
|
810
|
+
context: IFlexCatalogRunContext<TScope>,
|
|
811
|
+
): TResult | PromiseLike<TResult> | AsyncIterable<TResult>;
|
|
812
|
+
/**
|
|
813
|
+
* Decides each validated call before it runs: `run` (the default without this hook), `propose`
|
|
814
|
+
* to hand it to the catalog's `onProposals` instead of running it, or `{ deny }` to refuse it.
|
|
815
|
+
*/
|
|
816
|
+
onCall?(
|
|
817
|
+
params: TParams,
|
|
818
|
+
context: IFlexCatalogRunContext<TScope>,
|
|
819
|
+
): TFlexCatalogCallDecision | PromiseLike<TFlexCatalogCallDecision>;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
export type TFlexCatalogCallDecision = 'run' | 'propose' | { deny: string };
|
|
823
|
+
|
|
824
|
+
/** A call a method's `onCall` decided to propose instead of running. */
|
|
825
|
+
export interface IFlexCatalogProposal {
|
|
826
|
+
/** The call's ID: the `execute` call's, or the inner call's inside `run_code`. */
|
|
827
|
+
id: string;
|
|
828
|
+
method: string;
|
|
829
|
+
params: unknown;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
export interface IFlexCatalogProposalContext<TScope = unknown> {
|
|
833
|
+
/** The `execute` or `run_code` call that made the proposals. */
|
|
834
|
+
readonly toolCallId: string;
|
|
835
|
+
readonly abortSignal: AbortSignal;
|
|
836
|
+
readonly provider: Readonly<IFlexToolProviderContext<TScope>>;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/** A named type that method declarations refer to; it needs a `declaration`, a `schema`, or both. */
|
|
840
|
+
export interface IFlexCatalogType {
|
|
841
|
+
/** A JavaScript identifier such as `IMoney`. */
|
|
842
|
+
name: string;
|
|
843
|
+
description?: string;
|
|
844
|
+
/** Validates parameters that refer to this type, and generates its declaration. */
|
|
845
|
+
schema?: TFlexCatalogSchema;
|
|
846
|
+
/** Declaration text that replaces the generated one, such as `interface IMoney { … }`. */
|
|
847
|
+
declaration?: string;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
export interface IFlexToolCatalog<TScope = unknown> {
|
|
851
|
+
methods: readonly IFlexCatalogMethod<TScope>[];
|
|
852
|
+
types?: readonly IFlexCatalogType[];
|
|
853
|
+
/**
|
|
854
|
+
* Receives the calls `onCall` proposed, as one batch: the proposed call of an `execute`, or every
|
|
855
|
+
* call a `run_code` program proposed, once the program finished. A failed program proposes
|
|
856
|
+
* nothing. What it returns is what the model sees for them.
|
|
857
|
+
*/
|
|
858
|
+
onProposals?(
|
|
859
|
+
proposals: readonly IFlexCatalogProposal[],
|
|
860
|
+
context: IFlexCatalogProposalContext<TScope>,
|
|
861
|
+
): unknown;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
export interface IFlexToolCatalogOptions {
|
|
865
|
+
/**
|
|
866
|
+
* What `describe_tools` returns: `typescript` (default) declarations with named types shared
|
|
867
|
+
* across the session, or `json-schema` with each method's self-contained JSON Schema.
|
|
868
|
+
*/
|
|
869
|
+
declarations?: 'typescript' | 'json-schema';
|
|
870
|
+
/**
|
|
871
|
+
* Adds `run_code`, which runs a short TypeScript or JavaScript program against the catalog in a
|
|
872
|
+
* QuickJS sandbox. Needs the optional peers `quickjs-emscripten-core`,
|
|
873
|
+
* `@jitl/quickjs-ng-wasmfile-release-sync` and `amaro`.
|
|
874
|
+
*/
|
|
875
|
+
codeMode?: boolean | IFlexCodeModeOptions;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
export interface IFlexCodeModeOptions {
|
|
879
|
+
limits?: Partial<IFlexCodeModeLimits>;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/** The bounds of one `run_code` program. */
|
|
883
|
+
export interface IFlexCodeModeLimits {
|
|
884
|
+
/** UTF-8 bytes of the program. */
|
|
885
|
+
maxSourceBytes: number;
|
|
886
|
+
/** Milliseconds the program may compute; time waiting for calls does not count. */
|
|
887
|
+
cpuMs: number;
|
|
888
|
+
/** Milliseconds the program may take in all, not counting waits for a permission decision. */
|
|
889
|
+
wallMs: number;
|
|
890
|
+
/** Bytes of the sandbox's heap. */
|
|
891
|
+
memoryBytes: number;
|
|
892
|
+
/**
|
|
893
|
+
* Bytes of the sandbox's stack. QuickJS runs on the host's stack as well, so a larger value lets
|
|
894
|
+
* deep recursion reach the host's limit first; the program then fails at its `stack` limit all
|
|
895
|
+
* the same.
|
|
896
|
+
*/
|
|
897
|
+
stackBytes: number;
|
|
898
|
+
/** Catalog calls per program. */
|
|
899
|
+
maxCalls: number;
|
|
900
|
+
/** Catalog calls running at once; further calls wait for a slot. */
|
|
901
|
+
maxConcurrentCalls: number;
|
|
902
|
+
/** UTF-8 bytes of console output kept; more is cut off. */
|
|
903
|
+
maxLogBytes: number;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
export const FLEX_CODE_MODE_TOOL_NAME = 'run_code';
|
|
907
|
+
|
|
908
|
+
export const FLEX_CODE_MODE_DEFAULT_LIMITS: Readonly<IFlexCodeModeLimits> = Object.freeze({
|
|
909
|
+
maxSourceBytes: 32 * 1024,
|
|
910
|
+
cpuMs: 5_000,
|
|
911
|
+
wallMs: 60_000,
|
|
912
|
+
memoryBytes: 64 * 1024 * 1024,
|
|
913
|
+
stackBytes: 64 * 1024,
|
|
914
|
+
maxCalls: 200,
|
|
915
|
+
maxConcurrentCalls: 8,
|
|
916
|
+
maxLogBytes: 16 * 1024,
|
|
917
|
+
});
|
|
918
|
+
|
|
919
|
+
export const FLEX_CODE_MODE_MAXIMUM_LIMITS: Readonly<IFlexCodeModeLimits> = Object.freeze({
|
|
920
|
+
maxSourceBytes: 256 * 1024,
|
|
921
|
+
cpuMs: 60_000,
|
|
922
|
+
wallMs: 30 * 60_000,
|
|
923
|
+
memoryBytes: 512 * 1024 * 1024,
|
|
924
|
+
stackBytes: 256 * 1024,
|
|
925
|
+
maxCalls: 10_000,
|
|
926
|
+
maxConcurrentCalls: 64,
|
|
927
|
+
maxLogBytes: 256 * 1024,
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
/** What `run_code` reports to the model, as JSON, when a program does not finish. */
|
|
931
|
+
export interface IFlexCodeRunFailure {
|
|
932
|
+
error: 'syntax_error' | 'program_error' | 'limit_exceeded' | 'aborted';
|
|
933
|
+
/** The limit that stopped the program, for `limit_exceeded`. */
|
|
934
|
+
limit?: 'source' | 'cpu' | 'wall' | 'memory' | 'stack' | 'calls';
|
|
935
|
+
name?: string;
|
|
936
|
+
message: string;
|
|
937
|
+
/** The program's line, when known. */
|
|
938
|
+
line?: number;
|
|
939
|
+
/** Catalog calls the program made. */
|
|
940
|
+
calls: number;
|
|
941
|
+
logs?: string;
|
|
942
|
+
}
|
|
662
943
|
export interface IFlexResourceToolProviderResolverContext<TScope> extends IFlexSessionGeneration {
|
|
663
944
|
scopeId: string;
|
|
664
945
|
scope: TScope;
|
|
@@ -1419,6 +1700,7 @@ export interface IFlexHarnessOptions<TScope> {
|
|
|
1419
1700
|
externalErrorProjector?: TFlexExternalErrorProjector;
|
|
1420
1701
|
subagents?: IFlexSubagentDefinition[];
|
|
1421
1702
|
builtInTools?: IFlexBuiltInToolsOptions;
|
|
1703
|
+
toolCatalog?: IFlexToolCatalogOptions;
|
|
1422
1704
|
slashCommands?: readonly TFlexSlashCommandRegistration<TScope>[];
|
|
1423
1705
|
/** Maximum child depth (root is 0). Defaults to 6; configurable from 1 through 8. */
|
|
1424
1706
|
maxSubagentDepth?: number;
|
|
@@ -1597,7 +1879,7 @@ export type TFlexModelUsageEvent = IFlexEventBase & {
|
|
|
1597
1879
|
readonly type: 'model.usage';
|
|
1598
1880
|
readonly runId?: string;
|
|
1599
1881
|
readonly source: 'generation' | 'compaction';
|
|
1600
|
-
} & Readonly<
|
|
1882
|
+
} & Readonly<TFlexObservedModelCallUsage>;
|
|
1601
1883
|
|
|
1602
1884
|
export interface IFlexPromptQueueEvent extends IFlexEventBase {
|
|
1603
1885
|
readonly type: 'prompt.queued' | 'prompt.started' | 'prompt.running' | 'prompt.finished';
|
package/ts/plugins.ts
CHANGED
|
@@ -6,6 +6,91 @@ import * as path from 'node:path';
|
|
|
6
6
|
|
|
7
7
|
export { AsyncLocalStorage, crypto, fs, path };
|
|
8
8
|
|
|
9
|
+
// third party scope
|
|
10
|
+
import { asSchema, jsonSchema } from 'ai';
|
|
11
|
+
import { Validator as JsonSchemaValidator } from '@cfworker/json-schema';
|
|
12
|
+
|
|
13
|
+
export { asSchema, jsonSchema, JsonSchemaValidator };
|
|
14
|
+
export type { FlexibleSchema, JSONSchema7, ModelMessage, Schema } from 'ai';
|
|
15
|
+
|
|
16
|
+
// optional code mode peers: QuickJS-ng compiled to WebAssembly, and amaro to strip TypeScript types
|
|
17
|
+
|
|
18
|
+
/** A value inside a QuickJS context; the host disposes every handle it owns. */
|
|
19
|
+
export interface IQuickJsHandle {
|
|
20
|
+
readonly alive: boolean;
|
|
21
|
+
dispose(): void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type TQuickJsResult =
|
|
25
|
+
| { value: IQuickJsHandle; error?: undefined }
|
|
26
|
+
| { error: IQuickJsHandle; value?: undefined };
|
|
27
|
+
|
|
28
|
+
export interface IQuickJsDeferredPromise {
|
|
29
|
+
readonly handle: IQuickJsHandle;
|
|
30
|
+
readonly alive: boolean;
|
|
31
|
+
resolve(value?: IQuickJsHandle): void;
|
|
32
|
+
reject(value?: IQuickJsHandle): void;
|
|
33
|
+
dispose(): void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface IQuickJsContext {
|
|
37
|
+
readonly global: IQuickJsHandle;
|
|
38
|
+
newString(value: string): IQuickJsHandle;
|
|
39
|
+
getString(handle: IQuickJsHandle): string;
|
|
40
|
+
newFunction(name: string, implementation: (...args: IQuickJsHandle[]) => IQuickJsHandle | void): IQuickJsHandle;
|
|
41
|
+
setProp(target: IQuickJsHandle, key: string, value: IQuickJsHandle): void;
|
|
42
|
+
newPromise(): IQuickJsDeferredPromise;
|
|
43
|
+
newError(message: string): IQuickJsHandle;
|
|
44
|
+
evalCode(code: string, filename?: string): TQuickJsResult;
|
|
45
|
+
resolvePromise(handle: IQuickJsHandle): Promise<TQuickJsResult>;
|
|
46
|
+
dump(handle: IQuickJsHandle): unknown;
|
|
47
|
+
dispose(): void;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface IQuickJsRuntime {
|
|
51
|
+
readonly alive: boolean;
|
|
52
|
+
setMemoryLimit(bytes: number): void;
|
|
53
|
+
setMaxStackSize(bytes: number): void;
|
|
54
|
+
setInterruptHandler(handler: () => boolean): void;
|
|
55
|
+
newContext(): IQuickJsContext;
|
|
56
|
+
/** Runs the queued promise jobs; `error` is an exception none of them caught. */
|
|
57
|
+
executePendingJobs(): { error?: IQuickJsHandle };
|
|
58
|
+
dispose(): void;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface IQuickJsModule {
|
|
62
|
+
newRuntime(): IQuickJsRuntime;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** A failed strip, as amaro reports it. */
|
|
66
|
+
export interface IAmaroError {
|
|
67
|
+
code?: string;
|
|
68
|
+
message?: string;
|
|
69
|
+
startLine?: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface ICodeSandboxEngine {
|
|
73
|
+
/** A new WebAssembly instance of QuickJS-ng, with a memory of its own. */
|
|
74
|
+
newModule(): Promise<IQuickJsModule>;
|
|
75
|
+
/** Removes TypeScript type syntax, keeping every line where it was. */
|
|
76
|
+
stripTypes(source: string): string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Loads QuickJS and amaro, the optional peers code mode needs. */
|
|
80
|
+
export const importCodeSandboxEngine = async (): Promise<ICodeSandboxEngine> => {
|
|
81
|
+
const [core, variant, amaro] = await Promise.all([
|
|
82
|
+
import('quickjs-emscripten-core'),
|
|
83
|
+
import('@jitl/quickjs-ng-wasmfile-release-sync'),
|
|
84
|
+
import('amaro'),
|
|
85
|
+
]);
|
|
86
|
+
// The variant's typings resolve as CommonJS; at run time the default export is the variant.
|
|
87
|
+
const quickjsVariant = (variant as { default: unknown }).default as Parameters<typeof core.newQuickJSWASMModuleFromVariant>[0];
|
|
88
|
+
return {
|
|
89
|
+
newModule: async () => await core.newQuickJSWASMModuleFromVariant(quickjsVariant) as unknown as IQuickJsModule,
|
|
90
|
+
stripTypes: (source) => amaro.transformSync(source, { mode: 'strip-only' }).code,
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
|
|
9
94
|
// @push.rocks scope
|
|
10
95
|
import {
|
|
11
96
|
AgentEventStoreConflictError,
|
|
@@ -73,6 +158,7 @@ export type {
|
|
|
73
158
|
TAgentGenerationOutcome,
|
|
74
159
|
TAgentModelCallUsage,
|
|
75
160
|
TAgentModelCallUsageEvent,
|
|
161
|
+
TAgentObservedModelCallUsage,
|
|
76
162
|
TAgentRetryReason,
|
|
77
163
|
TAgentToolCallFinishEvent,
|
|
78
164
|
TAgentToolExecutionReconciliationOptions,
|
package/ts/readme.md
CHANGED
|
@@ -1026,7 +1026,7 @@ A `contextCompactor` states which model to compact with from the model the compa
|
|
|
1026
1026
|
|
|
1027
1027
|
A compactor uses `resolvedModel.model` directly, and resolves `modelHint` the way its model resolver resolves a prompt's `modelHint`. Only when neither member is present, because nothing dispatched states a model, does the host choose the compaction model itself.
|
|
1028
1028
|
|
|
1029
|
-
A `context-overflow` or `context-budget` compaction also carries `system` and `providerOptions`: the instructions and the provider options (cache options applied, so `store: false` on OpenAI) the run's turns are sent with. `compactMessages()` sends its summary call with them as one streamed call, the shape of every turn, so a compactor that passes its options through
|
|
1029
|
+
A `context-overflow` or `context-budget` compaction also carries `system` and `providerOptions`: the instructions and the provider options (cache options applied, so `store: false` on OpenAI) the run's turns are sent with. A `context-budget` compaction on a provider that caches the prefix also carries the turns' `tools`. `compactMessages()` sends its summary call with them as one streamed call, the shape of every turn, with the tools' definitions but none of their code, so a compactor that passes its options through repeats the run's prefix and reads it from the provider's prompt cache; definitions that outweigh the history nine times are left out. Without `system` it sends its own instructions.
|
|
1030
1030
|
|
|
1031
1031
|
```typescript
|
|
1032
1032
|
agentSessionPolicy: {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { FlexHarnessValidationError } from './errors.js';
|
|
2
2
|
import {
|
|
3
|
+
FLEX_CODE_MODE_DEFAULT_LIMITS,
|
|
4
|
+
FLEX_CODE_MODE_MAXIMUM_LIMITS,
|
|
3
5
|
FLEX_REVERSION_DEFAULT_LIMITS,
|
|
4
6
|
FLEX_REVERSION_MAXIMUM_LIMITS,
|
|
5
7
|
} from './interfaces.js';
|
|
@@ -12,7 +14,9 @@ import type {
|
|
|
12
14
|
IFlexReversionLimits,
|
|
13
15
|
IFlexSlashCommandHandlerRegistration,
|
|
14
16
|
IFlexSlashCommandTemplateRegistration,
|
|
17
|
+
IFlexCodeModeLimits,
|
|
15
18
|
IFlexSubagentDefinition,
|
|
19
|
+
IFlexToolCatalogOptions,
|
|
16
20
|
TFlexSlashCommandRegistration,
|
|
17
21
|
} from './interfaces.js';
|
|
18
22
|
import {
|
|
@@ -156,6 +160,57 @@ export function normalizeSubagents(
|
|
|
156
160
|
return Object.freeze(normalized);
|
|
157
161
|
}
|
|
158
162
|
|
|
163
|
+
export interface INormalizedToolCatalogOptions {
|
|
164
|
+
readonly declarations: 'typescript' | 'json-schema';
|
|
165
|
+
/** The limits of `run_code`; absent while code mode is off. */
|
|
166
|
+
readonly codeMode?: Readonly<IFlexCodeModeLimits>;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const isPlainOptions = (value: unknown): value is Record<string, unknown> =>
|
|
170
|
+
!!value
|
|
171
|
+
&& typeof value === 'object'
|
|
172
|
+
&& !Array.isArray(value)
|
|
173
|
+
&& [Object.prototype, null].includes(Object.getPrototypeOf(value));
|
|
174
|
+
|
|
175
|
+
export function normalizeToolCatalogOptions(
|
|
176
|
+
options: IFlexToolCatalogOptions | undefined,
|
|
177
|
+
): INormalizedToolCatalogOptions {
|
|
178
|
+
if (options === undefined) return Object.freeze({ declarations: 'typescript' });
|
|
179
|
+
if (!isPlainOptions(options)) throw new FlexHarnessValidationError('toolCatalog must be a plain object.');
|
|
180
|
+
const unsupported = Object.keys(options).find((key) => key !== 'declarations' && key !== 'codeMode');
|
|
181
|
+
if (unsupported) throw new FlexHarnessValidationError(`toolCatalog does not support "${unsupported}".`);
|
|
182
|
+
const declarations = options.declarations ?? 'typescript';
|
|
183
|
+
if (declarations !== 'typescript' && declarations !== 'json-schema') {
|
|
184
|
+
throw new FlexHarnessValidationError('toolCatalog.declarations must be "typescript" or "json-schema".');
|
|
185
|
+
}
|
|
186
|
+
const codeMode = normalizeCodeModeLimits(options.codeMode);
|
|
187
|
+
return Object.freeze({ declarations, ...(codeMode ? { codeMode } : {}) });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function normalizeCodeModeLimits(codeMode: unknown): Readonly<IFlexCodeModeLimits> | undefined {
|
|
191
|
+
if (codeMode === undefined || codeMode === false) return undefined;
|
|
192
|
+
if (codeMode === true) return FLEX_CODE_MODE_DEFAULT_LIMITS;
|
|
193
|
+
if (!isPlainOptions(codeMode)) {
|
|
194
|
+
throw new FlexHarnessValidationError('toolCatalog.codeMode must be a boolean or a plain object.');
|
|
195
|
+
}
|
|
196
|
+
const unsupported = Object.keys(codeMode).find((key) => key !== 'limits');
|
|
197
|
+
if (unsupported) throw new FlexHarnessValidationError(`toolCatalog.codeMode does not support "${unsupported}".`);
|
|
198
|
+
const limits = codeMode.limits ?? {};
|
|
199
|
+
if (!isPlainOptions(limits)) throw new FlexHarnessValidationError('toolCatalog.codeMode.limits must be a plain object.');
|
|
200
|
+
const resolved: Record<string, number> = { ...FLEX_CODE_MODE_DEFAULT_LIMITS };
|
|
201
|
+
for (const [key, value] of Object.entries(limits)) {
|
|
202
|
+
if (!Object.prototype.hasOwnProperty.call(FLEX_CODE_MODE_MAXIMUM_LIMITS, key)) {
|
|
203
|
+
throw new FlexHarnessValidationError(`toolCatalog.codeMode.limits does not support "${key}".`);
|
|
204
|
+
}
|
|
205
|
+
const maximum = FLEX_CODE_MODE_MAXIMUM_LIMITS[key as keyof IFlexCodeModeLimits];
|
|
206
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 1 || value > maximum) {
|
|
207
|
+
throw new FlexHarnessValidationError(`toolCatalog.codeMode.limits.${key} must be an integer from 1 through ${maximum}.`);
|
|
208
|
+
}
|
|
209
|
+
resolved[key] = value;
|
|
210
|
+
}
|
|
211
|
+
return Object.freeze(resolved as unknown as IFlexCodeModeLimits);
|
|
212
|
+
}
|
|
213
|
+
|
|
159
214
|
export function normalizeBuiltInTools(
|
|
160
215
|
options: IFlexHarnessOptions<unknown>['builtInTools'],
|
|
161
216
|
): INormalizedBuiltInTools {
|
package/ts/utils.json.ts
CHANGED
|
@@ -785,6 +785,7 @@ function validateMessage(value: unknown, path: string): IValidatedMessageIdentit
|
|
|
785
785
|
'output',
|
|
786
786
|
'error',
|
|
787
787
|
'childSessionId',
|
|
788
|
+
'parentToolCallId',
|
|
788
789
|
'model',
|
|
789
790
|
'startedAt',
|
|
790
791
|
'completedAt',
|
|
@@ -801,6 +802,7 @@ function validateMessage(value: unknown, path: string): IValidatedMessageIdentit
|
|
|
801
802
|
}
|
|
802
803
|
requireOptionalString(part.error, `${partPath}.error`);
|
|
803
804
|
requireOptionalString(part.childSessionId, `${partPath}.childSessionId`);
|
|
805
|
+
requireOptionalString(part.parentToolCallId, `${partPath}.parentToolCallId`);
|
|
804
806
|
if (part.model !== undefined) validateModel(part.model, `${partPath}.model`);
|
|
805
807
|
requireOptionalString(part.startedAt, `${partPath}.startedAt`);
|
|
806
808
|
requireOptionalString(part.completedAt, `${partPath}.completedAt`);
|