@pensar/apex 2.6.1 → 2.7.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/build/agent-4f87bydg.js +13 -0
- package/build/{agent-ayreaj6z.js → agent-6h49fhz1.js} +5 -5
- package/build/{agent-yby11zaq.js → agent-a5vq5fsm.js} +6 -6
- package/build/{agent-runs-g37vkrjr.js → agent-runs-9nncftzk.js} +16 -16
- package/build/agent-sa0ty54v.js +13 -0
- package/build/{apps-xn6km9yn.js → apps-rh90z2nb.js} +13 -13
- package/build/{auth-d105wc64.js → auth-hshx11mc.js} +13 -13
- package/build/{blackboxAgent-s56sgx9b.js → blackboxAgent-t6zq0ekj.js} +6 -6
- package/build/{blackboxPentest-ps78v3w7.js → blackboxPentest-eskvsmez.js} +11 -11
- package/build/{cli-d37a42dc.js → cli-29179gt8.js} +8 -8
- package/build/{cli-gx71jcke.js → cli-2etfgtj3.js} +1 -1
- package/build/{cli-ngq9dr8n.js → cli-6r1ntbmf.js} +3 -3
- package/build/{cli-709rvekb.js → cli-9eyk8rhx.js} +1 -1
- package/build/{cli-ae8jqxqr.js → cli-c4x5b3q4.js} +2 -2
- package/build/{cli-az3xq70v.js → cli-c9nnxr52.js} +1 -1
- package/build/{cli-1ve18npr.js → cli-dawkcveq.js} +1 -1
- package/build/{cli-3sp6nd8d.js → cli-dqrqgfrp.js} +2 -2
- package/build/{cli-7eea4e2y.js → cli-e0v6hd3d.js} +6 -6
- package/build/{cli-k2nwxta0.js → cli-ewav0q78.js} +2 -2
- package/build/{cli-kb21qhvm.js → cli-fk5e62a6.js} +2 -2
- package/build/{cli-65g6rcat.js → cli-gzgyjs36.js} +1 -1
- package/build/{cli-c05y640n.js → cli-mrk3hg6f.js} +1 -1
- package/build/{cli-dpsw2fe6.js → cli-prw2dfje.js} +353 -185
- package/build/{cli-qgz1q9g5.js → cli-pwhx13h3.js} +105 -36
- package/build/{cli-n2en7j5b.js → cli-q0wmet0t.js} +1 -1
- package/build/{cli-xtc2t6me.js → cli-tf2kp8s4.js} +3 -3
- package/build/{cli-fy6vh2a7.js → cli-vdbnh2ha.js} +1 -1
- package/build/cli.js +37 -37
- package/build/{config-zpqkd5cz.js → config-srw06gyv.js} +1 -1
- package/build/{fastStrike-mcjdvwez.js → fastStrike-gaphkhrs.js} +5 -5
- package/build/{fixes-kytx5dmj.js → fixes-j99tce5t.js} +13 -13
- package/build/{index-wqetp6gq.js → index-3rsrzfje.js} +5 -5
- package/build/{index-fv64eb32.js → index-652yqmn2.js} +2 -2
- package/build/{index-n65z6v7b.js → index-6fxag2h2.js} +6 -6
- package/build/{index-r9yjkfrv.js → index-a9yy0fe3.js} +4 -4
- package/build/{index-dr3tg1w3.js → index-c1tgca1w.js} +1 -1
- package/build/{index-qv4cc65p.js → index-fsv57ssp.js} +13 -13
- package/build/{index-ns4m4s01.js → index-y9h10rfq.js} +4 -4
- package/build/{index-4vqdgb42.js → index-yj0ye642.js} +1236 -1195
- package/build/{index-je6hcsqr.js → index-ynsam8mg.js} +1 -1
- package/build/{issues-eb3q9d3a.js → issues-267ytycy.js} +13 -13
- package/build/{knowledge-fqsvtx0f.js → knowledge-44acmwfw.js} +13 -13
- package/build/lib/{chunk-yrnrbjes.js → chunk-2015fqpw.js} +1 -1
- package/build/lib/{chunk-acgbyf5h.js → chunk-3jr0sp3v.js} +1 -1
- package/build/lib/{chunk-7pwa92rn.js → chunk-45ne0t6e.js} +1 -1
- package/build/lib/{chunk-nhfax4gb.js → chunk-5ma2ns65.js} +1 -1
- package/build/lib/{chunk-z96pbjhd.js → chunk-8zfn4feq.js} +1 -1
- package/build/lib/{chunk-1jvwqnem.js → chunk-93b8vp9x.js} +3 -3
- package/build/lib/{chunk-r4j8ybn9.js → chunk-9kmc9yp6.js} +37 -20
- package/build/lib/{chunk-9yksqgzr.js → chunk-bb2sekn4.js} +11 -11
- package/build/lib/{chunk-e8yy2k73.js → chunk-c3e9aen5.js} +1 -1
- package/build/lib/{chunk-v3dk9j7k.js → chunk-db0bmkrv.js} +11 -11
- package/build/lib/{chunk-1yct6cra.js → chunk-dm8yvkdy.js} +1 -1
- package/build/lib/{chunk-xhdpgpkm.js → chunk-dvn6bg2m.js} +2 -2
- package/build/lib/{chunk-9tt2021m.js → chunk-fwe0fdb5.js} +9 -9
- package/build/lib/{chunk-3c00n0cy.js → chunk-gfzspfyd.js} +3 -3
- package/build/lib/{chunk-ba41jh41.js → chunk-hw0vcs3m.js} +297 -127
- package/build/lib/{chunk-r2dkp4tb.js → chunk-m8w0npxg.js} +1 -1
- package/build/lib/{chunk-z137x08b.js → chunk-mbm9w4ac.js} +5 -5
- package/build/lib/{chunk-4hwzqthr.js → chunk-mjey3y7s.js} +1 -1
- package/build/lib/{chunk-mg03jdmt.js → chunk-mw108bmx.js} +1 -1
- package/build/lib/{chunk-1azdancq.js → chunk-njn4tjsr.js} +1 -1
- package/build/lib/{chunk-bb0ekhkw.js → chunk-p8jd9s8k.js} +8 -8
- package/build/lib/{chunk-2qsq76xq.js → chunk-t6yh604c.js} +62 -10
- package/build/lib/{chunk-1fy8azee.js → chunk-yqengqce.js} +1 -1
- package/build/lib/{chunk-w66ce82a.js → chunk-ysmhn1p6.js} +1 -1
- package/build/lib/core/agents/offSecAgent/index.js +7 -7
- package/build/lib/core/agents/offSecAgent/subagentSpawner.js +5 -5
- package/build/lib/core/agents/offSecAgent/tools/index.js +4 -4
- package/build/lib/core/agents/offSecAgent/tools/listMemories.d.ts +11 -1
- package/build/lib/core/agents/specialized/attackSurface/blackboxAgent.js +9 -9
- package/build/lib/core/agents/specialized/attackSurface/schemas.js +9 -9
- package/build/lib/core/agents/specialized/authenticationAgent/index.js +10 -10
- package/build/lib/core/agents/specialized/codeAgent/agent.js +9 -9
- package/build/lib/core/agents/specialized/findingJudge/agent.js +8 -8
- package/build/lib/core/agents/specialized/findingJudge/index.js +3 -3
- package/build/lib/core/agents/specialized/patching/index.js +10 -10
- package/build/lib/core/agents/specialized/pentest/agent.js +9 -9
- package/build/lib/core/agents/specialized/whiteboxAttackSurface/index.js +9 -9
- package/build/lib/core/ai/ai.d.ts +23 -6
- package/build/lib/core/ai/ai.js +2 -2
- package/build/lib/core/ai/index.js +2 -2
- package/build/lib/core/ai/models/claude-capabilities.d.ts +3 -2
- package/build/lib/core/ai/models/index.d.ts +1 -1
- package/build/lib/core/ai/utils.d.ts +2 -0
- package/build/lib/core/ai/utils.js +4 -2
- package/build/lib/core/api/index.js +19 -19
- package/build/lib/core/api/targetedPentest.js +10 -10
- package/build/lib/core/config/index.js +1 -1
- package/build/lib/core/findings/registry.js +3 -3
- package/build/lib/core/session/index.js +2 -2
- package/build/lib/core/session/persistence.js +3 -3
- package/build/lib/core/workflows/pentest.js +15 -15
- package/build/lib/core/workflows/seams.js +4 -4
- package/build/lib/core/workflows/whiteboxAttackSurface.js +11 -11
- package/build/lib/index.js +22 -22
- package/build/{logs-x62b7hk1.js → logs-wx69vy65.js} +13 -13
- package/build/{native-rollout-evidence-c9yhfqcs.js → native-rollout-evidence-2akrepvz.js} +3 -3
- package/build/{offesecAgent-5whnpeta.js → offesecAgent-zewvmk98.js} +4 -4
- package/build/pentest-n2mjksg2.js +22 -0
- package/build/{pentests-e0f32aqx.js → pentests-xvj8g8h4.js} +13 -13
- package/build/recordedRunClient-a0ye97sw.js +11 -0
- package/build/{targetedPentest-rcbs4nvp.js → targetedPentest-p3cdq712.js} +6 -6
- package/build/{targets-xj9g3q0z.js → targets-1wajqhm7.js} +13 -13
- package/build/threatModel-g9pbtnt1.js +21 -0
- package/build/{uninstall-7s784q4a.js → uninstall-jpm5ppfb.js} +1 -1
- package/build/{upload-4gvhwmvr.js → upload-csny5mns.js} +4 -4
- package/build/{utils-cjrz64pc.js → utils-tzbr4bxg.js} +3 -3
- package/package.json +1 -1
- package/src/core/agents/offSecAgent/offensiveSecurityAgent.test.ts +92 -5
- package/src/core/agents/offSecAgent/offensiveSecurityAgent.ts +49 -28
- package/src/core/agents/offSecAgent/tools/listMemories.test.ts +230 -0
- package/src/core/agents/offSecAgent/tools/listMemories.ts +73 -6
- package/src/core/ai/ai.operator-context.bench.test.ts +1408 -0
- package/src/core/ai/ai.recorded-context.test.ts +74 -0
- package/src/core/ai/ai.test.ts +54 -0
- package/src/core/ai/ai.ts +299 -80
- package/src/core/ai/compactionTelemetry.test.ts +2 -2
- package/src/core/ai/models/anthropic.ts +6 -0
- package/src/core/ai/models/bedrock.ts +18 -0
- package/src/core/ai/models/claude-capabilities.ts +29 -8
- package/src/core/ai/models/index.ts +4 -1
- package/src/core/ai/models/models.test.ts +23 -0
- package/src/core/ai/models/openrouter.ts +6 -0
- package/src/core/ai/providers/anthropic-models.test.ts +60 -1
- package/src/core/ai/providers/bedrock-models.test.ts +81 -0
- package/src/core/ai/providers/gateway-models.test.ts +16 -6
- package/src/core/ai/utils.native-rollout-evidence.test.ts +1 -0
- package/src/core/ai/utils.ts +189 -143
- package/src/core/observability/telemetry.test.ts +2 -3
- package/src/tui/components/chat/loading-indicator.tsx +20 -4
- package/src/tui/components/chat/message-list.tsx +1 -0
- package/src/tui/components/operator-dashboard/run-events.test.ts +3 -1
- package/src/tui/components/shared/__tests__/tool-renderer-lifecycle.tsx +18 -0
- package/src/tui/components/shared/action-label.test.ts +9 -0
- package/src/tui/components/shared/compacting-icon.tsx +18 -0
- package/src/tui/components/shared/index.ts +1 -0
- package/src/tui/components/shared/tool-registry.ts +1 -0
- package/src/tui/components/shared/tool-renderer.tsx +21 -7
- package/build/agent-6w7egcf1.js +0 -13
- package/build/agent-9zx75feh.js +0 -13
- package/build/pentest-e61hc38s.js +0 -22
- package/build/recordedRunClient-dp032c32.js +0 -11
- package/build/threatModel-jkxfa40s.js +0 -21
package/src/core/ai/ai.ts
CHANGED
|
@@ -51,6 +51,9 @@ import {
|
|
|
51
51
|
} from "./compactionTelemetry";
|
|
52
52
|
import {
|
|
53
53
|
estimateMessageTokens,
|
|
54
|
+
estimateTokens,
|
|
55
|
+
estimateToolsOverheadTokens,
|
|
56
|
+
type FitContextResult,
|
|
54
57
|
fitMessagesToContext,
|
|
55
58
|
truncateWithMarker,
|
|
56
59
|
} from "./contextManagement";
|
|
@@ -60,6 +63,7 @@ import {
|
|
|
60
63
|
runWithInferenceRecorder,
|
|
61
64
|
} from "./inference-attempt";
|
|
62
65
|
import {
|
|
66
|
+
type ClaudeThinkingEffort,
|
|
63
67
|
getClaudeCapabilities,
|
|
64
68
|
getMaxOutputTokens,
|
|
65
69
|
getModelInfo,
|
|
@@ -74,6 +78,7 @@ import { OPENAI_PRO_TIMEOUT_MS } from "./providers/openai-pro-fetch";
|
|
|
74
78
|
import { STREAM_DEBUG } from "./streamTelemetry";
|
|
75
79
|
import {
|
|
76
80
|
type AIAuthConfig,
|
|
81
|
+
CompactionRejectedError,
|
|
77
82
|
checkIfContextLengthError,
|
|
78
83
|
createSummarizationStream,
|
|
79
84
|
getProviderModel,
|
|
@@ -136,11 +141,11 @@ export const DEFAULT_OPENAI_REASONING_EFFORT: OpenAIReasoningEffort = "medium";
|
|
|
136
141
|
|
|
137
142
|
/**
|
|
138
143
|
* Anthropic adaptive-thinking effort hint. Soft guidance for how much the model
|
|
139
|
-
* reasons (see AWS "adaptive thinking"): `low` minimizes thinking
|
|
140
|
-
*
|
|
141
|
-
* support adaptive thinking
|
|
144
|
+
* reasons (see AWS "adaptive thinking"): `low` minimizes thinking while
|
|
145
|
+
* `xhigh` and `max` allow progressively deeper work. Only meaningful for
|
|
146
|
+
* models that support adaptive thinking; ignored elsewhere.
|
|
142
147
|
*/
|
|
143
|
-
export type ThinkingEffort =
|
|
148
|
+
export type ThinkingEffort = ClaudeThinkingEffort;
|
|
144
149
|
|
|
145
150
|
const OPENAI_REASONING_MODEL_IDS = new Set([
|
|
146
151
|
"gpt-6.1-sol",
|
|
@@ -676,6 +681,43 @@ function createToolExecutionGate(): {
|
|
|
676
681
|
};
|
|
677
682
|
}
|
|
678
683
|
|
|
684
|
+
class InStreamCompactionRequired extends Error {
|
|
685
|
+
constructor(readonly fitted: FitContextResult) {
|
|
686
|
+
super("In-stream compaction required before provider dispatch");
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// Retry once after new tool output, then let fitting handle this turn.
|
|
691
|
+
const MAX_PROACTIVE_SUMMARY_FAILURES = 2;
|
|
692
|
+
|
|
693
|
+
function shouldSummarizeBeforeFitting(
|
|
694
|
+
messages: ModelMessage[],
|
|
695
|
+
contextWindow: number,
|
|
696
|
+
maxOutputTokens: number,
|
|
697
|
+
overheadTokens: number,
|
|
698
|
+
safetyMarginTokens: number,
|
|
699
|
+
system?: string,
|
|
700
|
+
toolChoice?: ToolChoice<ToolSet>,
|
|
701
|
+
): boolean {
|
|
702
|
+
const historyBudget =
|
|
703
|
+
contextWindow -
|
|
704
|
+
maxOutputTokens -
|
|
705
|
+
overheadTokens -
|
|
706
|
+
safetyMarginTokens -
|
|
707
|
+
(system ? estimateTokens(system) : 0);
|
|
708
|
+
const estimatedHistoryTokens = estimateMessageTokens(messages);
|
|
709
|
+
// Forced-tool replays missed the summary cache; keep their fitted history path.
|
|
710
|
+
return (
|
|
711
|
+
historyBudget > 0 &&
|
|
712
|
+
messages.length > 2 &&
|
|
713
|
+
toolChoice !== "required" &&
|
|
714
|
+
typeof toolChoice !== "object" &&
|
|
715
|
+
estimatedHistoryTokens >=
|
|
716
|
+
Math.max(100_000, Math.floor(historyBudget * 0.8)) &&
|
|
717
|
+
estimatedHistoryTokens <= historyBudget
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
|
|
679
721
|
// Helper function to wrap a stream with error handling for async errors
|
|
680
722
|
function wrapStreamWithErrorHandler(
|
|
681
723
|
originalStream: StreamTextResult<ToolSet, never>,
|
|
@@ -786,7 +828,10 @@ function wrapStreamWithErrorHandler(
|
|
|
786
828
|
|
|
787
829
|
// Check context length FIRST — these should never be retried
|
|
788
830
|
// as-is; the prompt must be reduced via summarization.
|
|
789
|
-
const isCtxError =
|
|
831
|
+
const isCtxError =
|
|
832
|
+
error instanceof InStreamCompactionRequired ||
|
|
833
|
+
error instanceof CompactionRejectedError ||
|
|
834
|
+
checkIfContextLengthError(error);
|
|
790
835
|
|
|
791
836
|
// A latched persistence failure is terminal: retrying would
|
|
792
837
|
// dispatch a turn whose context was never durably committed.
|
|
@@ -893,42 +938,50 @@ function wrapStreamWithErrorHandler(
|
|
|
893
938
|
}
|
|
894
939
|
|
|
895
940
|
if (isCtxError) {
|
|
896
|
-
let currentMessages: ModelMessage[] =
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
941
|
+
let currentMessages: ModelMessage[] =
|
|
942
|
+
error instanceof InStreamCompactionRequired
|
|
943
|
+
? error.fitted.messages
|
|
944
|
+
: messagesContainer.current;
|
|
945
|
+
if (!(error instanceof InStreamCompactionRequired)) {
|
|
946
|
+
try {
|
|
947
|
+
const response = await originalStream.response;
|
|
948
|
+
if (response.messages && response.messages.length > 0) {
|
|
949
|
+
currentMessages = response.messages as ModelMessage[];
|
|
950
|
+
}
|
|
951
|
+
} catch {
|
|
952
|
+
// Fall back to container messages.
|
|
901
953
|
}
|
|
902
|
-
} catch {
|
|
903
|
-
// Fall back to container messages.
|
|
904
954
|
}
|
|
905
955
|
|
|
906
|
-
const fitted =
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
956
|
+
const fitted =
|
|
957
|
+
error instanceof InStreamCompactionRequired
|
|
958
|
+
? error.fitted
|
|
959
|
+
: fitMessagesToContext(currentMessages, {
|
|
960
|
+
contextWindow: getContextWindow(
|
|
961
|
+
opts.model,
|
|
962
|
+
opts.authConfig?.customProviders,
|
|
963
|
+
opts.authConfig?.hoonifyModels,
|
|
964
|
+
),
|
|
965
|
+
maxOutputTokens: getMaxOutputTokens(
|
|
966
|
+
opts.model,
|
|
967
|
+
opts.authConfig?.customProviders,
|
|
968
|
+
opts.authConfig?.hoonifyModels,
|
|
969
|
+
),
|
|
970
|
+
system: applySequentialToolCallPolicy(
|
|
971
|
+
opts.system,
|
|
972
|
+
opts.tools,
|
|
973
|
+
opts.model,
|
|
974
|
+
),
|
|
975
|
+
tools: opts.tools,
|
|
976
|
+
sessionPath: opts.sessionPath,
|
|
977
|
+
telemetry: {
|
|
978
|
+
trigger: "context_overflow",
|
|
979
|
+
model: opts.model,
|
|
980
|
+
sessionId: opts.sessionId,
|
|
981
|
+
restartDepth: opts._restartDepth,
|
|
982
|
+
previous: opts._compaction?.last,
|
|
983
|
+
},
|
|
984
|
+
});
|
|
932
985
|
|
|
933
986
|
if (fitted.compaction && opts._compaction)
|
|
934
987
|
opts._compaction.last = fitted.compaction;
|
|
@@ -944,7 +997,11 @@ function wrapStreamWithErrorHandler(
|
|
|
944
997
|
// `MAX_RESTART_DEPTH` finally trips.
|
|
945
998
|
let postReactiveDepth = opts._restartDepth ?? 0;
|
|
946
999
|
|
|
947
|
-
if (
|
|
1000
|
+
if (
|
|
1001
|
+
!(error instanceof CompactionRejectedError) &&
|
|
1002
|
+
fitted.fitsBudget &&
|
|
1003
|
+
fitted.modified
|
|
1004
|
+
) {
|
|
948
1005
|
if (!silent) {
|
|
949
1006
|
log.warn(
|
|
950
1007
|
`Context length error — Layer 1+2 reduced to ~${fitted.estimatedInputTokens} tokens, retrying`,
|
|
@@ -1017,12 +1074,19 @@ function wrapStreamWithErrorHandler(
|
|
|
1017
1074
|
}
|
|
1018
1075
|
|
|
1019
1076
|
try {
|
|
1077
|
+
if (error instanceof CompactionRejectedError) throw error;
|
|
1020
1078
|
const summarizationStream = createSummarizationStream(
|
|
1021
1079
|
messagesForSummary,
|
|
1022
1080
|
{
|
|
1023
1081
|
...opts,
|
|
1024
1082
|
_restartDepth: postReactiveDepth,
|
|
1025
|
-
_compactionTrigger:
|
|
1083
|
+
_compactionTrigger:
|
|
1084
|
+
error instanceof InStreamCompactionRequired
|
|
1085
|
+
? "proactive"
|
|
1086
|
+
: "context_overflow",
|
|
1087
|
+
_proactiveSummaryMayFit:
|
|
1088
|
+
error instanceof InStreamCompactionRequired &&
|
|
1089
|
+
error.fitted.fitsBudget,
|
|
1026
1090
|
},
|
|
1027
1091
|
model,
|
|
1028
1092
|
);
|
|
@@ -1030,7 +1094,7 @@ function wrapStreamWithErrorHandler(
|
|
|
1030
1094
|
yield chunk;
|
|
1031
1095
|
}
|
|
1032
1096
|
} catch (summarizeError) {
|
|
1033
|
-
//
|
|
1097
|
+
// Fall through to minimal restart for context or rejected-summary
|
|
1034
1098
|
// errors. For everything else — auth failures, network
|
|
1035
1099
|
// errors, abort signals, the typed terminal
|
|
1036
1100
|
// `ContextLengthExhaustedError`, or non-`Error` throws —
|
|
@@ -1043,7 +1107,10 @@ function wrapStreamWithErrorHandler(
|
|
|
1043
1107
|
(summarizeError instanceof Error &&
|
|
1044
1108
|
summarizeError.name === "AbortError") ||
|
|
1045
1109
|
opts.abortSignal?.aborted ||
|
|
1046
|
-
!
|
|
1110
|
+
!(
|
|
1111
|
+
checkIfContextLengthError(summarizeError) ||
|
|
1112
|
+
summarizeError instanceof CompactionRejectedError
|
|
1113
|
+
)
|
|
1047
1114
|
) {
|
|
1048
1115
|
throw summarizeError;
|
|
1049
1116
|
}
|
|
@@ -1279,12 +1346,19 @@ export type ReasoningProviderOptions = {
|
|
|
1279
1346
|
effort?: ThinkingEffort;
|
|
1280
1347
|
};
|
|
1281
1348
|
bedrock?: {
|
|
1282
|
-
reasoningConfig:
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1349
|
+
reasoningConfig:
|
|
1350
|
+
| {
|
|
1351
|
+
type: "adaptive";
|
|
1352
|
+
display: "summarized";
|
|
1353
|
+
// Bedrock's channel for the adaptive effort hint (maps to Claude's
|
|
1354
|
+
// output_config.effort).
|
|
1355
|
+
maxReasoningEffort?: ThinkingEffort;
|
|
1356
|
+
}
|
|
1357
|
+
| { type: "disabled" };
|
|
1358
|
+
/** Explicitly forwarded for Anthropic because the Bedrock SDK currently
|
|
1359
|
+
* drops reasoningConfig.type="disabled" instead of sending it. */
|
|
1360
|
+
additionalModelRequestFields?: {
|
|
1361
|
+
thinking: { type: "disabled" };
|
|
1288
1362
|
};
|
|
1289
1363
|
};
|
|
1290
1364
|
openai?: OpenAIResponsesProviderOptions;
|
|
@@ -1360,8 +1434,8 @@ export function buildReasoningProviderOptions(
|
|
|
1360
1434
|
enableThinking?: boolean;
|
|
1361
1435
|
/**
|
|
1362
1436
|
* Adaptive-thinking effort hint for Anthropic models that support it
|
|
1363
|
-
*
|
|
1364
|
-
*
|
|
1437
|
+
* Ignored on models without adaptive support. When omitted, models in the
|
|
1438
|
+
* Claude capability registry use their documented provider default.
|
|
1365
1439
|
*/
|
|
1366
1440
|
thinkingEffort?: ThinkingEffort | null;
|
|
1367
1441
|
openAIReasoningEffort?: OpenAIReasoningEffort | null;
|
|
@@ -1371,11 +1445,12 @@ export function buildReasoningProviderOptions(
|
|
|
1371
1445
|
if (claude) {
|
|
1372
1446
|
const provider = getModelInfo(model).provider;
|
|
1373
1447
|
const thinking = !!opts.enableThinking || claude.alwaysOnThinking;
|
|
1448
|
+
const effort = opts.thinkingEffort ?? claude.defaultEffort;
|
|
1374
1449
|
if (provider === "openrouter") {
|
|
1375
1450
|
return {
|
|
1376
1451
|
openrouter: {
|
|
1377
1452
|
reasoning: {
|
|
1378
|
-
effort: thinking ?
|
|
1453
|
+
effort: thinking ? effort : "none",
|
|
1379
1454
|
enabled: thinking,
|
|
1380
1455
|
},
|
|
1381
1456
|
},
|
|
@@ -1385,19 +1460,38 @@ export function buildReasoningProviderOptions(
|
|
|
1385
1460
|
return {
|
|
1386
1461
|
openai: {
|
|
1387
1462
|
forceReasoning: true,
|
|
1388
|
-
reasoningEffort: thinking ?
|
|
1463
|
+
reasoningEffort: thinking ? effort : "none",
|
|
1389
1464
|
reasoningSummary: "auto",
|
|
1390
1465
|
},
|
|
1391
1466
|
};
|
|
1392
1467
|
}
|
|
1393
1468
|
return {
|
|
1394
1469
|
anthropic: {
|
|
1395
|
-
thinking:
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
...(opts.thinkingEffort ? { effort: opts.thinkingEffort } : {}),
|
|
1470
|
+
thinking: thinking
|
|
1471
|
+
? { type: "adaptive", display: "summarized" }
|
|
1472
|
+
: { type: "disabled" },
|
|
1473
|
+
...(thinking ? { effort } : {}),
|
|
1400
1474
|
},
|
|
1475
|
+
...(provider === "bedrock"
|
|
1476
|
+
? {
|
|
1477
|
+
bedrock: {
|
|
1478
|
+
reasoningConfig: thinking
|
|
1479
|
+
? {
|
|
1480
|
+
type: "adaptive" as const,
|
|
1481
|
+
display: "summarized" as const,
|
|
1482
|
+
maxReasoningEffort: effort,
|
|
1483
|
+
}
|
|
1484
|
+
: { type: "disabled" as const },
|
|
1485
|
+
...(!thinking
|
|
1486
|
+
? {
|
|
1487
|
+
additionalModelRequestFields: {
|
|
1488
|
+
thinking: { type: "disabled" as const },
|
|
1489
|
+
},
|
|
1490
|
+
}
|
|
1491
|
+
: {}),
|
|
1492
|
+
},
|
|
1493
|
+
}
|
|
1494
|
+
: {}),
|
|
1401
1495
|
};
|
|
1402
1496
|
}
|
|
1403
1497
|
const useThinking =
|
|
@@ -1474,6 +1568,11 @@ export interface StreamResponseOpts {
|
|
|
1474
1568
|
* new messages (not the full pre-summarization history).
|
|
1475
1569
|
*/
|
|
1476
1570
|
onSummarized?: (summary: string) => void;
|
|
1571
|
+
/** The fitted context and prior generated-message count for transcript writers. */
|
|
1572
|
+
onContextPrepared?: (context: {
|
|
1573
|
+
messages: ModelMessage[];
|
|
1574
|
+
responseMessageOffset: number;
|
|
1575
|
+
}) => void;
|
|
1477
1576
|
/**
|
|
1478
1577
|
* Deprecated host shim: fires only when a cache counter is `> 0`.
|
|
1479
1578
|
* Apex internals read cache from {@link normalizeStepUsage} on the step.
|
|
@@ -1506,6 +1605,8 @@ export interface StreamResponseOpts {
|
|
|
1506
1605
|
/** Shared only by continuations of this stream, never across agents. */
|
|
1507
1606
|
_compaction?: { last?: CompactionLink };
|
|
1508
1607
|
_compactionTrigger?: CompactionTrigger;
|
|
1608
|
+
_proactiveSummaryMayFit?: boolean;
|
|
1609
|
+
_proactiveSummaryFailures?: number;
|
|
1509
1610
|
}
|
|
1510
1611
|
|
|
1511
1612
|
const NATIVE_STREAM_RECOVERY = Symbol("native-stream-recovery");
|
|
@@ -1581,13 +1682,19 @@ function streamResponseWithinOperation(
|
|
|
1581
1682
|
thinkingEffort,
|
|
1582
1683
|
openAIReasoningEffort,
|
|
1583
1684
|
sessionId,
|
|
1685
|
+
sessionPath,
|
|
1584
1686
|
contextRecorder,
|
|
1687
|
+
onContextPrepared,
|
|
1585
1688
|
} = opts;
|
|
1586
1689
|
|
|
1587
|
-
//
|
|
1588
|
-
//
|
|
1589
|
-
//
|
|
1690
|
+
// response.messages accumulates generated steps after prepareStep rewrites
|
|
1691
|
+
// provider context. The offset prevents transcript writers from appending
|
|
1692
|
+
// older, pre-fit messages again.
|
|
1590
1693
|
let recorderBase: ModelMessage[] | undefined;
|
|
1694
|
+
let responseMessageLength = 0;
|
|
1695
|
+
const estimatedOverheadTokens = estimateToolsOverheadTokens(tools) + 1_000;
|
|
1696
|
+
let preparedInputEstimateTokens = 0;
|
|
1697
|
+
let inputSafetyMarginTokens = 10_000;
|
|
1591
1698
|
|
|
1592
1699
|
// Wrap onStepFinish to fire cache metrics and the usage callback for every
|
|
1593
1700
|
// step. Must be async so that callers returning a Promise (persistence,
|
|
@@ -1596,6 +1703,18 @@ function streamResponseWithinOperation(
|
|
|
1596
1703
|
// provider metadata is never parsed twice.
|
|
1597
1704
|
const onStepFinish: typeof userOnStepFinish = async (step) => {
|
|
1598
1705
|
const stepUsage = normalizeStepUsage(step);
|
|
1706
|
+
if (
|
|
1707
|
+
preparedInputEstimateTokens > 0 &&
|
|
1708
|
+
stepUsage.inputTokens > 0 &&
|
|
1709
|
+
step.response?.id !== "summarization" &&
|
|
1710
|
+
step.response?.id !== "tool-repair"
|
|
1711
|
+
) {
|
|
1712
|
+
// Fixed system and tool overhead is already reserved by the fitter; calibrate only the remaining tokenization gap.
|
|
1713
|
+
inputSafetyMarginTokens = Math.max(
|
|
1714
|
+
inputSafetyMarginTokens,
|
|
1715
|
+
stepUsage.inputTokens - preparedInputEstimateTokens + 10_000,
|
|
1716
|
+
);
|
|
1717
|
+
}
|
|
1599
1718
|
// Canonical commit precedes every downstream use; the recorder latches
|
|
1600
1719
|
// rejections (SDK notify() swallows them) until the next turn gate or
|
|
1601
1720
|
// agent-side flush turns the latch into a stream failure.
|
|
@@ -1611,10 +1730,20 @@ function streamResponseWithinOperation(
|
|
|
1611
1730
|
throw new Error("context recorder active without a committed base");
|
|
1612
1731
|
}
|
|
1613
1732
|
await contextRecorder.checkpoint({
|
|
1614
|
-
messages: [
|
|
1733
|
+
messages: [
|
|
1734
|
+
...recorderBase,
|
|
1735
|
+
...step.response.messages.slice(responseMessageLength),
|
|
1736
|
+
],
|
|
1615
1737
|
system: effectiveSystem ?? null,
|
|
1616
1738
|
});
|
|
1617
1739
|
}
|
|
1740
|
+
if (
|
|
1741
|
+
step.response?.id !== "summarization" &&
|
|
1742
|
+
step.response?.id !== "tool-repair" &&
|
|
1743
|
+
step.response?.messages
|
|
1744
|
+
) {
|
|
1745
|
+
responseMessageLength = step.response.messages.length;
|
|
1746
|
+
}
|
|
1618
1747
|
if (
|
|
1619
1748
|
onCacheMetrics &&
|
|
1620
1749
|
(stepUsage.cacheReadTokens > 0 || stepUsage.cacheWriteTokens > 0)
|
|
@@ -1661,22 +1790,54 @@ function streamResponseWithinOperation(
|
|
|
1661
1790
|
model,
|
|
1662
1791
|
);
|
|
1663
1792
|
|
|
1793
|
+
const contextWindow = getContextWindow(
|
|
1794
|
+
model,
|
|
1795
|
+
authConfig?.customProviders,
|
|
1796
|
+
authConfig?.hoonifyModels,
|
|
1797
|
+
);
|
|
1798
|
+
const maxOutputTokens = getMaxOutputTokens(
|
|
1799
|
+
model,
|
|
1800
|
+
authConfig?.customProviders,
|
|
1801
|
+
authConfig?.hoonifyModels,
|
|
1802
|
+
);
|
|
1803
|
+
if (
|
|
1804
|
+
messages &&
|
|
1805
|
+
!opts._proactiveSummaryFailures &&
|
|
1806
|
+
shouldSummarizeBeforeFitting(
|
|
1807
|
+
messages,
|
|
1808
|
+
contextWindow,
|
|
1809
|
+
maxOutputTokens,
|
|
1810
|
+
estimatedOverheadTokens,
|
|
1811
|
+
inputSafetyMarginTokens,
|
|
1812
|
+
systemWithToolPolicy,
|
|
1813
|
+
toolChoice,
|
|
1814
|
+
)
|
|
1815
|
+
) {
|
|
1816
|
+
return wrapStreamWithErrorHandler(
|
|
1817
|
+
createSummarizationStream(
|
|
1818
|
+
messages,
|
|
1819
|
+
{
|
|
1820
|
+
...opts,
|
|
1821
|
+
_compactionTrigger: "proactive",
|
|
1822
|
+
_proactiveSummaryMayFit: true,
|
|
1823
|
+
},
|
|
1824
|
+
providerModel,
|
|
1825
|
+
),
|
|
1826
|
+
{ current: messages },
|
|
1827
|
+
opts,
|
|
1828
|
+
providerModel,
|
|
1829
|
+
silent,
|
|
1830
|
+
);
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1664
1833
|
// Proactive context fit: compact before the call. Reactive recovery
|
|
1665
1834
|
// below is a safety net for tokenizer drift the estimate doesn't catch.
|
|
1666
1835
|
let fittedMessages = messages;
|
|
1667
1836
|
let proactiveFitFailed = false;
|
|
1668
1837
|
if (messages && messages.length > 0) {
|
|
1669
1838
|
const fitted = fitMessagesToContext(messages, {
|
|
1670
|
-
contextWindow
|
|
1671
|
-
|
|
1672
|
-
authConfig?.customProviders,
|
|
1673
|
-
authConfig?.hoonifyModels,
|
|
1674
|
-
),
|
|
1675
|
-
maxOutputTokens: getMaxOutputTokens(
|
|
1676
|
-
model,
|
|
1677
|
-
authConfig?.customProviders,
|
|
1678
|
-
authConfig?.hoonifyModels,
|
|
1679
|
-
),
|
|
1839
|
+
contextWindow,
|
|
1840
|
+
maxOutputTokens,
|
|
1680
1841
|
system: systemWithToolPolicy,
|
|
1681
1842
|
tools,
|
|
1682
1843
|
sessionPath: opts.sessionPath,
|
|
@@ -1723,7 +1884,11 @@ function streamResponseWithinOperation(
|
|
|
1723
1884
|
return wrapStreamWithErrorHandler(
|
|
1724
1885
|
createSummarizationStream(
|
|
1725
1886
|
fittedMessages,
|
|
1726
|
-
{
|
|
1887
|
+
{
|
|
1888
|
+
...opts,
|
|
1889
|
+
_compactionTrigger: "proactive",
|
|
1890
|
+
_proactiveSummaryMayFit: false,
|
|
1891
|
+
},
|
|
1727
1892
|
providerModel,
|
|
1728
1893
|
),
|
|
1729
1894
|
messagesContainer,
|
|
@@ -1818,28 +1983,82 @@ function streamResponseWithinOperation(
|
|
|
1818
1983
|
// Awaiting inside prepareStep keeps streamResponse synchronous; the
|
|
1819
1984
|
// SDK awaits it before provider dispatch, so every turn and every
|
|
1820
1985
|
// recovery re-entry commits before use.
|
|
1821
|
-
prepareStep: async (
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1986
|
+
prepareStep: async (step) => {
|
|
1987
|
+
let stepMessages = step.messages;
|
|
1988
|
+
if (step.stepNumber > 0) {
|
|
1989
|
+
if (
|
|
1990
|
+
(opts._proactiveSummaryFailures ?? 0) <
|
|
1991
|
+
MAX_PROACTIVE_SUMMARY_FAILURES &&
|
|
1992
|
+
shouldSummarizeBeforeFitting(
|
|
1993
|
+
stepMessages,
|
|
1994
|
+
contextWindow,
|
|
1995
|
+
maxOutputTokens,
|
|
1996
|
+
estimatedOverheadTokens,
|
|
1997
|
+
inputSafetyMarginTokens,
|
|
1998
|
+
effectiveSystem,
|
|
1999
|
+
toolChoice,
|
|
2000
|
+
)
|
|
2001
|
+
) {
|
|
2002
|
+
messagesContainer.current = stepMessages;
|
|
2003
|
+
throw new InStreamCompactionRequired({
|
|
2004
|
+
messages: stepMessages,
|
|
2005
|
+
estimatedInputTokens: estimateMessageTokens(stepMessages),
|
|
2006
|
+
modified: false,
|
|
2007
|
+
fitsBudget: true,
|
|
2008
|
+
});
|
|
1825
2009
|
}
|
|
2010
|
+
const fitted = fitMessagesToContext(stepMessages, {
|
|
2011
|
+
contextWindow,
|
|
2012
|
+
maxOutputTokens,
|
|
2013
|
+
system: effectiveSystem,
|
|
2014
|
+
tools,
|
|
2015
|
+
overheadTokens: estimatedOverheadTokens,
|
|
2016
|
+
sessionPath,
|
|
2017
|
+
safetyMarginTokens: inputSafetyMarginTokens,
|
|
2018
|
+
telemetry: {
|
|
2019
|
+
trigger: "proactive",
|
|
2020
|
+
model,
|
|
2021
|
+
sessionId,
|
|
2022
|
+
restartDepth,
|
|
2023
|
+
previous: compactionState.last,
|
|
2024
|
+
},
|
|
2025
|
+
});
|
|
2026
|
+
if (fitted.compaction) compactionState.last = fitted.compaction;
|
|
2027
|
+
stepMessages = fitted.messages;
|
|
2028
|
+
if (!fitted.fitsBudget) {
|
|
2029
|
+
messagesContainer.current = stepMessages;
|
|
2030
|
+
throw new InStreamCompactionRequired(fitted);
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
if (contextRecorder) {
|
|
2034
|
+
recorderBase = structuredClone(stepMessages);
|
|
1826
2035
|
// Full logical context each turn — accepted step outputs must
|
|
1827
2036
|
// survive into every later commit, and system is explicit (when
|
|
1828
2037
|
// cached into messages, effectiveSystem is undefined → null).
|
|
1829
2038
|
await contextRecorder.checkpoint({
|
|
1830
|
-
messages:
|
|
2039
|
+
messages: stepMessages,
|
|
1831
2040
|
system: effectiveSystem ?? null,
|
|
1832
2041
|
});
|
|
1833
2042
|
}
|
|
1834
2043
|
// Update the container with the latest messages
|
|
1835
|
-
messagesContainer.current =
|
|
2044
|
+
messagesContainer.current = stepMessages;
|
|
2045
|
+
preparedInputEstimateTokens =
|
|
2046
|
+
estimateMessageTokens(stepMessages) +
|
|
2047
|
+
estimatedOverheadTokens +
|
|
2048
|
+
(effectiveSystem ? estimateTokens(effectiveSystem) : 0);
|
|
2049
|
+
onContextPrepared?.({
|
|
2050
|
+
messages: stepMessages,
|
|
2051
|
+
responseMessageOffset: responseMessageLength,
|
|
2052
|
+
});
|
|
1836
2053
|
// Mark the last message so the growing conversation caches incrementally
|
|
1837
2054
|
if (cacheBreakpoint) {
|
|
1838
2055
|
return {
|
|
1839
|
-
messages: withCachedLastMessage(
|
|
2056
|
+
messages: withCachedLastMessage(stepMessages, cacheBreakpoint),
|
|
1840
2057
|
};
|
|
1841
2058
|
}
|
|
1842
|
-
return
|
|
2059
|
+
return stepMessages === step.messages
|
|
2060
|
+
? undefined
|
|
2061
|
+
: { messages: stepMessages };
|
|
1843
2062
|
},
|
|
1844
2063
|
onError: async ({ error }: { error: unknown }) => {
|
|
1845
2064
|
// Never throw here: the SDK calls this inside its stream pipeline,
|
|
@@ -387,7 +387,7 @@ describe("compaction observability", () => {
|
|
|
387
387
|
).toBe(true);
|
|
388
388
|
});
|
|
389
389
|
|
|
390
|
-
it("
|
|
390
|
+
it("passes tool evidence to the summarizer and links its actual request and response", async () => {
|
|
391
391
|
const summaryModel = model();
|
|
392
392
|
state.model = summaryModel;
|
|
393
393
|
const messages: ModelMessage[] = [
|
|
@@ -422,7 +422,7 @@ describe("compaction observability", () => {
|
|
|
422
422
|
expect(summary.attributes["ai.prompt.messages"]).toContain(
|
|
423
423
|
"continue researching",
|
|
424
424
|
);
|
|
425
|
-
expect(summary.attributes["ai.prompt.messages"]).
|
|
425
|
+
expect(summary.attributes["ai.prompt.messages"]).toContain(
|
|
426
426
|
"evidence evidence",
|
|
427
427
|
);
|
|
428
428
|
expect(summary.attributes["ai.response.text"]).toBe("A compact summary");
|
|
@@ -112,6 +112,12 @@ export const ANTHROPIC_MODELS: ModelInfo[] = [
|
|
|
112
112
|
provider: "anthropic",
|
|
113
113
|
contextLength: 1000000,
|
|
114
114
|
},
|
|
115
|
+
{
|
|
116
|
+
id: "claude-haiku-5-5",
|
|
117
|
+
name: "Claude Haiku 5.5",
|
|
118
|
+
provider: "anthropic",
|
|
119
|
+
contextLength: 1000000,
|
|
120
|
+
},
|
|
115
121
|
{
|
|
116
122
|
id: "claude-sonnet-5-5",
|
|
117
123
|
name: "Claude Sonnet 5.5",
|
|
@@ -465,6 +465,18 @@ export const BEDROCK_MODELS: ModelInfo[] = [
|
|
|
465
465
|
provider: "bedrock",
|
|
466
466
|
contextLength: 262000,
|
|
467
467
|
},
|
|
468
|
+
{
|
|
469
|
+
id: "anthropic.claude-haiku-5-5",
|
|
470
|
+
name: "Claude Haiku 5.5 (Bedrock)",
|
|
471
|
+
provider: "bedrock",
|
|
472
|
+
contextLength: 1000000,
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
id: "us.anthropic.claude-haiku-5-5",
|
|
476
|
+
name: "Claude Haiku 5.5 (US)",
|
|
477
|
+
provider: "bedrock",
|
|
478
|
+
contextLength: 1000000,
|
|
479
|
+
},
|
|
468
480
|
{
|
|
469
481
|
id: "anthropic.claude-opus-4-8",
|
|
470
482
|
name: "Claude Opus 4.8 (Bedrock)",
|
|
@@ -597,4 +609,10 @@ export const BEDROCK_MODELS: ModelInfo[] = [
|
|
|
597
609
|
provider: "bedrock",
|
|
598
610
|
contextLength: 1000000,
|
|
599
611
|
},
|
|
612
|
+
{
|
|
613
|
+
id: "global.anthropic.claude-haiku-5-5",
|
|
614
|
+
name: "Claude Haiku 5.5 (Global)",
|
|
615
|
+
provider: "bedrock",
|
|
616
|
+
contextLength: 1000000,
|
|
617
|
+
},
|
|
600
618
|
];
|