@genesislcap/ai-assistant 15.19.0 → 15.19.1
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/package.json +17 -18
- package/api-extractor.json +0 -11
- package/dist/dts/components/chat-driver/chat-driver.compact.test.d.ts +0 -2
- package/dist/dts/components/chat-driver/chat-driver.compact.test.d.ts.map +0 -1
- package/dist/dts/components/chat-driver/chat-driver.invocation-scope.test.d.ts +0 -2
- package/dist/dts/components/chat-driver/chat-driver.invocation-scope.test.d.ts.map +0 -1
- package/dist/dts/components/chat-driver/chat-driver.test.d.ts +0 -2
- package/dist/dts/components/chat-driver/chat-driver.test.d.ts.map +0 -1
- package/dist/dts/components/chat-driver/chat-driver.thinking-policy.test.d.ts +0 -2
- package/dist/dts/components/chat-driver/chat-driver.thinking-policy.test.d.ts.map +0 -1
- package/dist/dts/components/chat-driver/chat-driver.trace-capture.test.d.ts +0 -2
- package/dist/dts/components/chat-driver/chat-driver.trace-capture.test.d.ts.map +0 -1
- package/dist/dts/components/chat-driver/chat-driver.turn-usage.test.d.ts +0 -2
- package/dist/dts/components/chat-driver/chat-driver.turn-usage.test.d.ts.map +0 -1
- package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.test.d.ts +0 -2
- package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.test.d.ts.map +0 -1
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.budget.test.d.ts +0 -2
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.budget.test.d.ts.map +0 -1
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.cost.test.d.ts +0 -2
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.cost.test.d.ts.map +0 -1
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.pin.test.d.ts +0 -2
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.pin.test.d.ts.map +0 -1
- package/dist/dts/components/settings-modal/settings-modal.styles.test.d.ts +0 -2
- package/dist/dts/components/settings-modal/settings-modal.styles.test.d.ts.map +0 -1
- package/dist/dts/components/settings-modal/settings-modal.template.test.d.ts +0 -2
- package/dist/dts/components/settings-modal/settings-modal.template.test.d.ts.map +0 -1
- package/dist/dts/config/define-stateful-agent.test.d.ts +0 -2
- package/dist/dts/config/define-stateful-agent.test.d.ts.map +0 -1
- package/dist/dts/config/validate-providers.test.d.ts +0 -2
- package/dist/dts/config/validate-providers.test.d.ts.map +0 -1
- package/dist/dts/main/blocked-state.test.d.ts +0 -2
- package/dist/dts/main/blocked-state.test.d.ts.map +0 -1
- package/dist/dts/main/budget-meter.test.d.ts +0 -2
- package/dist/dts/main/budget-meter.test.d.ts.map +0 -1
- package/dist/dts/main/cost-session-banking.test.d.ts +0 -2
- package/dist/dts/main/cost-session-banking.test.d.ts.map +0 -1
- package/dist/dts/main/file-attachments.test.d.ts +0 -2
- package/dist/dts/main/file-attachments.test.d.ts.map +0 -1
- package/dist/dts/main/interaction-cost.test.d.ts +0 -2
- package/dist/dts/main/interaction-cost.test.d.ts.map +0 -1
- package/dist/dts/main/main.styles.test.d.ts +0 -2
- package/dist/dts/main/main.styles.test.d.ts.map +0 -1
- package/dist/dts/main/persistence-broken-sources.test.d.ts +0 -2
- package/dist/dts/main/persistence-broken-sources.test.d.ts.map +0 -1
- package/dist/dts/main/popout-interaction-gate.test.d.ts +0 -2
- package/dist/dts/main/popout-interaction-gate.test.d.ts.map +0 -1
- package/dist/dts/state/ai-assistant-slice.test.d.ts +0 -2
- package/dist/dts/state/ai-assistant-slice.test.d.ts.map +0 -1
- package/dist/dts/state/debug-event-log.test.d.ts +0 -2
- package/dist/dts/state/debug-event-log.test.d.ts.map +0 -1
- package/dist/dts/state/driver-registry.test.d.ts +0 -2
- package/dist/dts/state/driver-registry.test.d.ts.map +0 -1
- package/dist/dts/state/interaction-context.test.d.ts +0 -2
- package/dist/dts/state/interaction-context.test.d.ts.map +0 -1
- package/dist/dts/state/persistence/diagnostics-cursors.test.d.ts +0 -2
- package/dist/dts/state/persistence/diagnostics-cursors.test.d.ts.map +0 -1
- package/dist/dts/state/persistence/diagnostics.test.d.ts +0 -2
- package/dist/dts/state/persistence/diagnostics.test.d.ts.map +0 -1
- package/dist/dts/state/persistence/session-persistence-provider.test.d.ts +0 -2
- package/dist/dts/state/persistence/session-persistence-provider.test.d.ts.map +0 -1
- package/dist/dts/state/persistence/session-persistence.integration.test.d.ts +0 -2
- package/dist/dts/state/persistence/session-persistence.integration.test.d.ts.map +0 -1
- package/dist/dts/state/persistence/session-persister.test.d.ts +0 -2
- package/dist/dts/state/persistence/session-persister.test.d.ts.map +0 -1
- package/dist/dts/state/persistence/session-snapshot.test.d.ts +0 -2
- package/dist/dts/state/persistence/session-snapshot.test.d.ts.map +0 -1
- package/dist/dts/state/persistence/stateful-restore.e2e.test.d.ts +0 -2
- package/dist/dts/state/persistence/stateful-restore.e2e.test.d.ts.map +0 -1
- package/dist/dts/utils/animation-exclusivity.test.d.ts +0 -2
- package/dist/dts/utils/animation-exclusivity.test.d.ts.map +0 -1
- package/dist/dts/utils/collect-session-models.test.d.ts +0 -2
- package/dist/dts/utils/collect-session-models.test.d.ts.map +0 -1
- package/dist/dts/utils/condense-history.test.d.ts +0 -2
- package/dist/dts/utils/condense-history.test.d.ts.map +0 -1
- package/dist/dts/utils/cost-session-history.test.d.ts +0 -2
- package/dist/dts/utils/cost-session-history.test.d.ts.map +0 -1
- package/dist/dts/utils/derive-cost-session-title.test.d.ts +0 -2
- package/dist/dts/utils/derive-cost-session-title.test.d.ts.map +0 -1
- package/dist/dts/utils/flatten-sub-agent-messages.test.d.ts +0 -2
- package/dist/dts/utils/flatten-sub-agent-messages.test.d.ts.map +0 -1
- package/dist/dts/utils/history-transform.test.d.ts +0 -2
- package/dist/dts/utils/history-transform.test.d.ts.map +0 -1
- package/dist/dts/utils/message-partition.test.d.ts +0 -2
- package/dist/dts/utils/message-partition.test.d.ts.map +0 -1
- package/dist/dts/utils/resolve-cost-history-config.test.d.ts +0 -2
- package/dist/dts/utils/resolve-cost-history-config.test.d.ts.map +0 -1
- package/dist/dts/utils/resolve-preference-baseline.test.d.ts +0 -2
- package/dist/dts/utils/resolve-preference-baseline.test.d.ts.map +0 -1
- package/dist/dts/utils/strip-agent-handlers.test.d.ts +0 -2
- package/dist/dts/utils/strip-agent-handlers.test.d.ts.map +0 -1
- package/dist/dts/utils/sum-costs.test.d.ts +0 -2
- package/dist/dts/utils/sum-costs.test.d.ts.map +0 -1
- package/dist/dts/utils/sum-tokens.test.d.ts +0 -2
- package/dist/dts/utils/sum-tokens.test.d.ts.map +0 -1
- package/dist/dts/utils/sum-usage.test.d.ts +0 -2
- package/dist/dts/utils/sum-usage.test.d.ts.map +0 -1
- package/dist/dts/utils/usage-rows.test.d.ts +0 -2
- package/dist/dts/utils/usage-rows.test.d.ts.map +0 -1
- package/dist/esm/components/chat-driver/chat-driver.compact.test.js +0 -93
- package/dist/esm/components/chat-driver/chat-driver.invocation-scope.test.js +0 -238
- package/dist/esm/components/chat-driver/chat-driver.test.js +0 -2770
- package/dist/esm/components/chat-driver/chat-driver.thinking-policy.test.js +0 -137
- package/dist/esm/components/chat-driver/chat-driver.trace-capture.test.js +0 -200
- package/dist/esm/components/chat-driver/chat-driver.turn-usage.test.js +0 -268
- package/dist/esm/components/chat-interaction-wrapper/chat-interaction-wrapper.test.js +0 -104
- package/dist/esm/components/orchestrating-driver/orchestrating-driver.budget.test.js +0 -312
- package/dist/esm/components/orchestrating-driver/orchestrating-driver.cost.test.js +0 -76
- package/dist/esm/components/orchestrating-driver/orchestrating-driver.pin.test.js +0 -61
- package/dist/esm/components/settings-modal/settings-modal.styles.test.js +0 -80
- package/dist/esm/components/settings-modal/settings-modal.template.test.js +0 -91
- package/dist/esm/config/define-stateful-agent.test.js +0 -53
- package/dist/esm/config/validate-providers.test.js +0 -100
- package/dist/esm/main/blocked-state.test.js +0 -1065
- package/dist/esm/main/budget-meter.test.js +0 -359
- package/dist/esm/main/cost-session-banking.test.js +0 -538
- package/dist/esm/main/file-attachments.test.js +0 -164
- package/dist/esm/main/interaction-cost.test.js +0 -107
- package/dist/esm/main/main.styles.test.js +0 -161
- package/dist/esm/main/persistence-broken-sources.test.js +0 -180
- package/dist/esm/main/popout-interaction-gate.test.js +0 -54
- package/dist/esm/state/ai-assistant-slice.test.js +0 -229
- package/dist/esm/state/debug-event-log.test.js +0 -117
- package/dist/esm/state/driver-registry.test.js +0 -55
- package/dist/esm/state/interaction-context.test.js +0 -78
- package/dist/esm/state/persistence/diagnostics-cursors.test.js +0 -30
- package/dist/esm/state/persistence/diagnostics.test.js +0 -280
- package/dist/esm/state/persistence/session-persistence-provider.test.js +0 -110
- package/dist/esm/state/persistence/session-persistence.integration.test.js +0 -113
- package/dist/esm/state/persistence/session-persister.test.js +0 -613
- package/dist/esm/state/persistence/session-snapshot.test.js +0 -256
- package/dist/esm/state/persistence/stateful-restore.e2e.test.js +0 -158
- package/dist/esm/utils/animation-exclusivity.test.js +0 -52
- package/dist/esm/utils/collect-session-models.test.js +0 -53
- package/dist/esm/utils/condense-history.test.js +0 -547
- package/dist/esm/utils/cost-session-history.test.js +0 -174
- package/dist/esm/utils/derive-cost-session-title.test.js +0 -37
- package/dist/esm/utils/flatten-sub-agent-messages.test.js +0 -139
- package/dist/esm/utils/history-transform.test.js +0 -158
- package/dist/esm/utils/message-partition.test.js +0 -90
- package/dist/esm/utils/resolve-cost-history-config.test.js +0 -32
- package/dist/esm/utils/resolve-preference-baseline.test.js +0 -69
- package/dist/esm/utils/strip-agent-handlers.test.js +0 -81
- package/dist/esm/utils/sum-costs.test.js +0 -114
- package/dist/esm/utils/sum-tokens.test.js +0 -51
- package/dist/esm/utils/sum-usage.test.js +0 -164
- package/dist/esm/utils/usage-rows.test.js +0 -189
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/license.txt +0 -46
- package/sandbox/tsconfig.json +0 -8
- package/src/channel/ai-activity-bus.ts +0 -209
- package/src/channel/ai-activity-channel.ts +0 -146
- package/src/chat-driver-node.ts +0 -159
- package/src/components/activity-halo/activity-halo.ts +0 -106
- package/src/components/agent-picker/agent-picker.constants.ts +0 -2
- package/src/components/agent-picker/agent-picker.styles.ts +0 -24
- package/src/components/agent-picker/agent-picker.template.ts +0 -54
- package/src/components/agent-picker/agent-picker.ts +0 -99
- package/src/components/agent-picker/index.ts +0 -1
- package/src/components/ai-driver/ai-driver.ts +0 -166
- package/src/components/ai-driver/index.ts +0 -1
- package/src/components/chat-bubble/chat-bubble.styles.ts +0 -194
- package/src/components/chat-bubble/chat-bubble.template.ts +0 -67
- package/src/components/chat-bubble/chat-bubble.ts +0 -436
- package/src/components/chat-bubble/index.ts +0 -1
- package/src/components/chat-driver/align-event-globals.ts +0 -23
- package/src/components/chat-driver/chat-driver.compact.test.ts +0 -131
- package/src/components/chat-driver/chat-driver.invocation-scope.test.ts +0 -285
- package/src/components/chat-driver/chat-driver.test.ts +0 -3679
- package/src/components/chat-driver/chat-driver.thinking-policy.test.ts +0 -185
- package/src/components/chat-driver/chat-driver.trace-capture.test.ts +0 -251
- package/src/components/chat-driver/chat-driver.ts +0 -3925
- package/src/components/chat-driver/chat-driver.turn-usage.test.ts +0 -362
- package/src/components/chat-driver/index.ts +0 -1
- package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.styles.ts +0 -7
- package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.template.ts +0 -6
- package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.test.ts +0 -144
- package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.ts +0 -243
- package/src/components/chat-interaction-wrapper/index.ts +0 -3
- package/src/components/chat-markdown/chat-markdown.ts +0 -89
- package/src/components/chat-markdown/index.ts +0 -1
- package/src/components/flowing-waves-indicator.ts +0 -286
- package/src/components/halo-overlay.ts +0 -184
- package/src/components/orchestrating-driver/index.ts +0 -1
- package/src/components/orchestrating-driver/orchestrating-driver.budget.test.ts +0 -438
- package/src/components/orchestrating-driver/orchestrating-driver.cost.test.ts +0 -107
- package/src/components/orchestrating-driver/orchestrating-driver.pin.test.ts +0 -96
- package/src/components/orchestrating-driver/orchestrating-driver.ts +0 -813
- package/src/components/plasma-orb-indicator.ts +0 -281
- package/src/components/popout-manager/index.ts +0 -1
- package/src/components/popout-manager/popout-manager.ts +0 -212
- package/src/components/settings-modal/index.ts +0 -2
- package/src/components/settings-modal/settings-modal.styles.test.ts +0 -94
- package/src/components/settings-modal/settings-modal.styles.ts +0 -853
- package/src/components/settings-modal/settings-modal.template.test.ts +0 -124
- package/src/components/settings-modal/settings-modal.template.ts +0 -943
- package/src/components/waves-indicator.ts +0 -241
- package/src/config/config.ts +0 -608
- package/src/config/define-stateful-agent.test.ts +0 -64
- package/src/config/define-stateful-agent.ts +0 -642
- package/src/config/fallback-agents.ts +0 -29
- package/src/config/index.ts +0 -2
- package/src/config/validate-providers.test.ts +0 -148
- package/src/config/validate-providers.ts +0 -58
- package/src/index.ts +0 -29
- package/src/main/blocked-state.test.ts +0 -1444
- package/src/main/budget-meter.test.ts +0 -477
- package/src/main/cost-session-banking.test.ts +0 -679
- package/src/main/file-attachments.test.ts +0 -215
- package/src/main/index.ts +0 -3
- package/src/main/interaction-cost.test.ts +0 -140
- package/src/main/main.styles.test.ts +0 -216
- package/src/main/main.styles.ts +0 -995
- package/src/main/main.template.ts +0 -1119
- package/src/main/main.ts +0 -5432
- package/src/main/main.types.ts +0 -225
- package/src/main/persistence-broken-sources.test.ts +0 -219
- package/src/main/popout-interaction-gate.test.ts +0 -87
- package/src/provider/ai-provider-switcher.ts +0 -40
- package/src/provider/assistant-app-settings.ts +0 -84
- package/src/state/ai-assistant-slice.test.ts +0 -336
- package/src/state/ai-assistant-slice.ts +0 -604
- package/src/state/debug-event-log.test.ts +0 -154
- package/src/state/debug-event-log.ts +0 -358
- package/src/state/driver-registry.test.ts +0 -70
- package/src/state/driver-registry.ts +0 -79
- package/src/state/interaction-context.test.ts +0 -90
- package/src/state/interaction-context.ts +0 -101
- package/src/state/persistence/build-timeline-entries.ts +0 -66
- package/src/state/persistence/diagnostics-cursors.test.ts +0 -53
- package/src/state/persistence/diagnostics-cursors.ts +0 -80
- package/src/state/persistence/diagnostics.test.ts +0 -346
- package/src/state/persistence/diagnostics.ts +0 -220
- package/src/state/persistence/index.ts +0 -10
- package/src/state/persistence/persister-registry.ts +0 -55
- package/src/state/persistence/session-persistence-provider.test.ts +0 -136
- package/src/state/persistence/session-persistence-provider.ts +0 -226
- package/src/state/persistence/session-persistence.integration.test.ts +0 -141
- package/src/state/persistence/session-persister.test.ts +0 -787
- package/src/state/persistence/session-persister.ts +0 -917
- package/src/state/persistence/session-snapshot.test.ts +0 -352
- package/src/state/persistence/session-snapshot.ts +0 -344
- package/src/state/persistence/stateful-restore.e2e.test.ts +0 -229
- package/src/state/session-store.ts +0 -56
- package/src/styles/ai-colours.ts +0 -30
- package/src/styles/menu.ts +0 -187
- package/src/styles/settings-section.ts +0 -40
- package/src/suggestions/chat-suggestions.ts +0 -186
- package/src/tags/index.ts +0 -1
- package/src/types/ai-chat-widget.ts +0 -67
- package/src/types/interaction-context.ts +0 -82
- package/src/utils/animated-panel-toggle.ts +0 -62
- package/src/utils/animation-exclusivity.test.ts +0 -72
- package/src/utils/animation-exclusivity.ts +0 -40
- package/src/utils/banked-usage-baselines.ts +0 -90
- package/src/utils/collect-session-models.test.ts +0 -82
- package/src/utils/collect-session-models.ts +0 -65
- package/src/utils/condense-history.test.ts +0 -746
- package/src/utils/condense-history.ts +0 -448
- package/src/utils/cost-session-history.test.ts +0 -226
- package/src/utils/cost-session-history.ts +0 -218
- package/src/utils/derive-cost-session-title.test.ts +0 -63
- package/src/utils/derive-cost-session-title.ts +0 -76
- package/src/utils/flatten-sub-agent-messages.test.ts +0 -163
- package/src/utils/flatten-sub-agent-messages.ts +0 -88
- package/src/utils/format-usd.ts +0 -26
- package/src/utils/history-transform.test.ts +0 -228
- package/src/utils/history-transform.ts +0 -163
- package/src/utils/index.ts +0 -3
- package/src/utils/logger.ts +0 -3
- package/src/utils/message-partition.test.ts +0 -129
- package/src/utils/message-partition.ts +0 -115
- package/src/utils/resolve-cost-history-config.test.ts +0 -38
- package/src/utils/resolve-cost-history-config.ts +0 -38
- package/src/utils/resolve-preference-baseline.test.ts +0 -84
- package/src/utils/resolve-preference-baseline.ts +0 -80
- package/src/utils/strip-agent-handlers.test.ts +0 -99
- package/src/utils/strip-agent-handlers.ts +0 -53
- package/src/utils/sum-costs.test.ts +0 -136
- package/src/utils/sum-costs.ts +0 -18
- package/src/utils/sum-tokens.test.ts +0 -93
- package/src/utils/sum-tokens.ts +0 -68
- package/src/utils/sum-usage.test.ts +0 -191
- package/src/utils/sum-usage.ts +0 -208
- package/src/utils/tool-fold.ts +0 -181
- package/src/utils/usage-rows.test.ts +0 -237
- package/src/utils/usage-rows.ts +0 -187
- package/src/utils/with-timeout.ts +0 -24
- package/tsconfig.json +0 -9
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AIProvider,
|
|
3
|
-
AIProviderRegistry,
|
|
4
|
-
ChatMessage,
|
|
5
|
-
ChatRequestOptions,
|
|
6
|
-
ChatThinkingPolicy,
|
|
7
|
-
} from '@genesislcap/foundation-ai';
|
|
8
|
-
import { assert, createLogicSuite } from '@genesislcap/foundation-testing';
|
|
9
|
-
import type { AgentConfig } from '../../config/config';
|
|
10
|
-
// Side-effect import — MUST come before `./chat-driver` so the driver subclasses
|
|
11
|
-
// jsdom's EventTarget rather than Node's native one. Mirrors chat-driver.test.ts.
|
|
12
|
-
import './align-event-globals';
|
|
13
|
-
import { ChatDriver } from './chat-driver';
|
|
14
|
-
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
// Per-turn `thinkingPolicy` resolution.
|
|
17
|
-
//
|
|
18
|
-
// The cost case for this option is the SHAPE of a tool loop, not a single call: the
|
|
19
|
-
// opening turn is a real decision and worth reasoning over, while the iterations that
|
|
20
|
-
// follow mostly pick the next tool from a narrow set — and on a thinking model each of
|
|
21
|
-
// those bills reasoning at the full output rate. That saving only exists if the
|
|
22
|
-
// resolver runs per iteration, so these tests assert the sequence across a loop, not
|
|
23
|
-
// just that one value arrives.
|
|
24
|
-
//
|
|
25
|
-
// The other half is the undefined case. Every agent written before this option leaves
|
|
26
|
-
// it unset, and a resolver may answer `undefined` on any given turn; both must reach
|
|
27
|
-
// the transport as `undefined` so the model keeps its own default. `undefined` reaching
|
|
28
|
-
// the wire as `'off'` would be a silent capability regression, and as `'auto'` a silent
|
|
29
|
-
// bill increase — so it is asserted explicitly rather than assumed.
|
|
30
|
-
// ---------------------------------------------------------------------------
|
|
31
|
-
|
|
32
|
-
/** Captures the policy seen on each model call; calls one tool, then finishes. */
|
|
33
|
-
const capturingProvider = (): AIProvider & { seen: Array<ChatThinkingPolicy | undefined> } => {
|
|
34
|
-
const seen: Array<ChatThinkingPolicy | undefined> = [];
|
|
35
|
-
let turns = 0;
|
|
36
|
-
return {
|
|
37
|
-
seen,
|
|
38
|
-
chat: async (
|
|
39
|
-
_history: ChatMessage[],
|
|
40
|
-
_userMessage: string,
|
|
41
|
-
options?: ChatRequestOptions,
|
|
42
|
-
): Promise<ChatMessage> => {
|
|
43
|
-
seen.push(options?.thinkingPolicy);
|
|
44
|
-
turns += 1;
|
|
45
|
-
// Two tool calls, so the loop runs three model calls in total — enough for a
|
|
46
|
-
// per-turn resolver to say something different on the later ones.
|
|
47
|
-
if (turns <= 2) {
|
|
48
|
-
return {
|
|
49
|
-
role: 'assistant',
|
|
50
|
-
content: '',
|
|
51
|
-
toolCalls: [{ id: `t${turns}`, name: 'step', args: {} }],
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
return { role: 'assistant', content: 'done' };
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const makeRegistry = (provider: AIProvider): AIProviderRegistry => ({
|
|
60
|
-
get: () => provider,
|
|
61
|
-
default: () => provider,
|
|
62
|
-
defaultName: () => 'test',
|
|
63
|
-
names: () => ['test'],
|
|
64
|
-
getStatus: async () => null,
|
|
65
|
-
listStatuses: async () => [],
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
const agent = (overrides: Partial<AgentConfig>): AgentConfig =>
|
|
69
|
-
({
|
|
70
|
-
name: 'worker',
|
|
71
|
-
description: 'test agent',
|
|
72
|
-
toolDefinitions: [
|
|
73
|
-
{ name: 'step', description: 'step', parameters: { type: 'object', properties: {} } },
|
|
74
|
-
],
|
|
75
|
-
toolHandlers: { step: async () => 'stepped' },
|
|
76
|
-
...overrides,
|
|
77
|
-
}) as AgentConfig;
|
|
78
|
-
|
|
79
|
-
/** Run one user turn through a driver carrying `config`, and return the policies seen. */
|
|
80
|
-
const policiesFor = async (
|
|
81
|
-
config: Partial<AgentConfig>,
|
|
82
|
-
): Promise<Array<ChatThinkingPolicy | undefined>> => {
|
|
83
|
-
const provider = capturingProvider();
|
|
84
|
-
const driver = new ChatDriver(makeRegistry(provider), {
|
|
85
|
-
maxToolIterations: 10,
|
|
86
|
-
maxFoldOperations: 5,
|
|
87
|
-
sessionKey: '',
|
|
88
|
-
});
|
|
89
|
-
driver.applyAgent(agent(config));
|
|
90
|
-
await driver.sendMessage('go');
|
|
91
|
-
return provider.seen;
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const suite = createLogicSuite('ChatDriver thinkingPolicy');
|
|
95
|
-
|
|
96
|
-
suite('leaves the policy undefined when the agent does not set one', async () => {
|
|
97
|
-
// The compatibility case: every existing agent. Undefined must reach the transport
|
|
98
|
-
// as undefined so each model keeps its own default posture — not silently coerced
|
|
99
|
-
// to 'off' (a capability regression) or 'auto' (a bill increase).
|
|
100
|
-
const seen = await policiesFor({});
|
|
101
|
-
assert.ok(seen.length >= 3, `expected a multi-call loop, got ${seen.length}`);
|
|
102
|
-
assert.equal(
|
|
103
|
-
seen.filter((p) => p !== undefined),
|
|
104
|
-
[],
|
|
105
|
-
'no turn invents a policy',
|
|
106
|
-
);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
suite('applies a static policy to every turn of the loop', async () => {
|
|
110
|
-
const seen = await policiesFor({ thinkingPolicy: 'off' });
|
|
111
|
-
assert.ok(seen.length >= 3);
|
|
112
|
-
assert.equal([...new Set(seen)], ['off'], 'a static value is not just a first-turn setting');
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
suite('pins the resolved policy for the whole tool loop', async () => {
|
|
116
|
-
// A tool-use loop is ONE assistant turn and Anthropic requires a single thinking mode
|
|
117
|
-
// for its duration. Toggling part-way does not error — the API silently disables
|
|
118
|
-
// thinking for that request and strips blocks that would leave the turn structure
|
|
119
|
-
// invalid, so an 'auto' -> 'off' switch loses the continuity the opening call
|
|
120
|
-
// established and 'off' -> 'auto' never delivers the reasoning asked for. It also
|
|
121
|
-
// invalidates the prompt cache, costing more than the reasoning it meant to save.
|
|
122
|
-
//
|
|
123
|
-
// So a resolver that changes its mind mid-loop must NOT be honoured mid-loop. This
|
|
124
|
-
// asserts the opposite of what it looks like it should: the later values are ignored.
|
|
125
|
-
let call = 0;
|
|
126
|
-
const seen = await policiesFor({
|
|
127
|
-
thinkingPolicy: () => {
|
|
128
|
-
call += 1;
|
|
129
|
-
return call === 1 ? 'auto' : 'off';
|
|
130
|
-
},
|
|
131
|
-
});
|
|
132
|
-
assert.ok(seen.length >= 3, `expected a multi-call loop, got ${seen.length}`);
|
|
133
|
-
assert.equal(
|
|
134
|
-
[...new Set(seen)],
|
|
135
|
-
['auto'],
|
|
136
|
-
'the first call decides; later resolutions do not take effect until the next user turn',
|
|
137
|
-
);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
suite('re-resolves on the next user turn', async () => {
|
|
141
|
-
// The flip side: pinning is per turn, not for the driver's lifetime, so a state change
|
|
142
|
-
// between turns still lands.
|
|
143
|
-
const provider = capturingProvider();
|
|
144
|
-
const driver = new ChatDriver(makeRegistry(provider), {
|
|
145
|
-
maxToolIterations: 10,
|
|
146
|
-
maxFoldOperations: 5,
|
|
147
|
-
sessionKey: '',
|
|
148
|
-
});
|
|
149
|
-
let turn = 0;
|
|
150
|
-
driver.applyAgent(
|
|
151
|
-
agent({
|
|
152
|
-
thinkingPolicy: () => (turn === 0 ? 'auto' : 'off'),
|
|
153
|
-
}),
|
|
154
|
-
);
|
|
155
|
-
await driver.sendMessage('go');
|
|
156
|
-
const firstTurn = [...provider.seen];
|
|
157
|
-
turn = 1;
|
|
158
|
-
await driver.sendMessage('again');
|
|
159
|
-
const secondTurn = provider.seen.slice(firstTurn.length);
|
|
160
|
-
|
|
161
|
-
assert.equal([...new Set(firstTurn)], ['auto'], 'turn one holds its posture');
|
|
162
|
-
assert.equal([...new Set(secondTurn)], ['off'], 'turn two picks up the new one');
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
suite('passes undefined through when the resolver declines to choose', async () => {
|
|
166
|
-
// A resolver may answer on some turns and not others. `undefined` is its third answer —
|
|
167
|
-
// "leave this model alone" — and must not be normalised into a value. Asserted across
|
|
168
|
-
// the whole loop because the first call's answer is the one that gets pinned.
|
|
169
|
-
const seen = await policiesFor({ thinkingPolicy: () => undefined });
|
|
170
|
-
assert.ok(seen.length >= 3);
|
|
171
|
-
assert.equal(
|
|
172
|
-
seen.filter((p) => p !== undefined),
|
|
173
|
-
[],
|
|
174
|
-
'declining is not the same as choosing',
|
|
175
|
-
);
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
suite('awaits an async resolver', async () => {
|
|
179
|
-
const seen = await policiesFor({
|
|
180
|
-
thinkingPolicy: async () => 'off' as ChatThinkingPolicy,
|
|
181
|
-
});
|
|
182
|
-
assert.equal([...new Set(seen)], ['off'], 'a promise is resolved, not passed through');
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
suite.run();
|
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AIProvider,
|
|
3
|
-
AIProviderRegistry,
|
|
4
|
-
ChatMessage,
|
|
5
|
-
ChatRequestOptions,
|
|
6
|
-
} from '@genesislcap/foundation-ai';
|
|
7
|
-
import { assert, createLogicSuite } from '@genesislcap/foundation-testing';
|
|
8
|
-
import type { AgentConfig } from '../../config/config';
|
|
9
|
-
import { sumUsage } from '../../utils/sum-usage';
|
|
10
|
-
import { usageRows } from '../../utils/usage-rows';
|
|
11
|
-
// Side-effect import — MUST come before `./chat-driver` so the driver subclasses
|
|
12
|
-
// jsdom's EventTarget rather than Node's native one. Mirrors chat-driver.test.ts.
|
|
13
|
-
import './align-event-globals';
|
|
14
|
-
import { ChatDriver } from './chat-driver';
|
|
15
|
-
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
// Sub-agent trace capture when ONE tool call invokes SEVERAL sub-agents.
|
|
18
|
-
//
|
|
19
|
-
// The capture slot used to be a single `{ trace?: ChatMessage[] }` per tool call,
|
|
20
|
-
// assigned by each `requestSubAgent`. That covers N tool calls × 1 sub-agent — the
|
|
21
|
-
// case its docblock named — but not 1 tool call × N sub-agents, which is what a
|
|
22
|
-
// code-driven scheduler or a retry produces. All but the last trace was dropped, so
|
|
23
|
-
// those children ran, were billed, and then had no record in history.
|
|
24
|
-
//
|
|
25
|
-
// The failure was invisible to every existing check: `sumUsage` and `usageRows` both
|
|
26
|
-
// recurse into `subAgentTrace`, so they summed a truncated input and still reconciled
|
|
27
|
-
// with each other perfectly. Measured at 1 of 7 traces kept on a seven-way fan-out,
|
|
28
|
-
// ~2.3x under the true cost.
|
|
29
|
-
//
|
|
30
|
-
// These tests assert the traces SURVIVE, which is upstream of any cost assertion.
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
|
|
33
|
-
/** Answers by rule: concurrent children under one turn make a FIFO queue nondeterministic. */
|
|
34
|
-
const ruleProvider = (): AIProvider => {
|
|
35
|
-
let parentTurns = 0;
|
|
36
|
-
return {
|
|
37
|
-
chat: async (
|
|
38
|
-
_history: ChatMessage[],
|
|
39
|
-
_userMessage: string,
|
|
40
|
-
options?: ChatRequestOptions,
|
|
41
|
-
): Promise<ChatMessage> => {
|
|
42
|
-
const tools = (options?.tools ?? []).map((t) => t.name);
|
|
43
|
-
// Child turn: finishes via its completion tool, and reports usage so the
|
|
44
|
-
// reconciliation assertions have something to add up.
|
|
45
|
-
if (tools.includes('work')) {
|
|
46
|
-
return {
|
|
47
|
-
role: 'assistant',
|
|
48
|
-
content: '',
|
|
49
|
-
model: 'claude-sonnet-5',
|
|
50
|
-
cost: 0.01,
|
|
51
|
-
inputTokens: 100,
|
|
52
|
-
outputTokens: 20,
|
|
53
|
-
toolCalls: [{ id: 'w1', name: 'work', args: {} }],
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
if (tools.includes('delegate') && parentTurns === 0) {
|
|
57
|
-
parentTurns += 1;
|
|
58
|
-
return {
|
|
59
|
-
role: 'assistant',
|
|
60
|
-
content: '',
|
|
61
|
-
model: 'claude-sonnet-5',
|
|
62
|
-
cost: 0.02,
|
|
63
|
-
inputTokens: 200,
|
|
64
|
-
outputTokens: 30,
|
|
65
|
-
toolCalls: [{ id: 'd0', name: 'delegate', args: {} }],
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
return { role: 'assistant', content: 'done', model: 'claude-sonnet-5' };
|
|
69
|
-
},
|
|
70
|
-
};
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const makeRegistry = (provider: AIProvider): AIProviderRegistry => ({
|
|
74
|
-
get: () => provider,
|
|
75
|
-
default: () => provider,
|
|
76
|
-
defaultName: () => 'test',
|
|
77
|
-
names: () => ['test'],
|
|
78
|
-
getStatus: async () => null,
|
|
79
|
-
listStatuses: async () => [],
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
const agent = (overrides: Partial<AgentConfig> & { name: string }): AgentConfig =>
|
|
83
|
-
({ description: 'test agent', ...overrides }) as AgentConfig;
|
|
84
|
-
|
|
85
|
-
/** A child that reports one unit of usage and completes. */
|
|
86
|
-
const worker = (name: string): AgentConfig =>
|
|
87
|
-
agent({
|
|
88
|
-
name,
|
|
89
|
-
toolDefinitions: [
|
|
90
|
-
{ name: 'work', description: 'work', parameters: { type: 'object', properties: {} } },
|
|
91
|
-
],
|
|
92
|
-
toolHandlers: {
|
|
93
|
-
work: async (_args, ctx) => {
|
|
94
|
-
ctx.completeSubAgent?.({ ok: true });
|
|
95
|
-
return 'worked';
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* A parent whose single `delegate` tool call invokes `names` in turn — the shape a
|
|
102
|
-
* code-driven scheduler produces, and the one the old single slot truncated.
|
|
103
|
-
*/
|
|
104
|
-
const boss = (children: AgentConfig[], invoke: string[]): AgentConfig =>
|
|
105
|
-
agent({
|
|
106
|
-
name: 'boss',
|
|
107
|
-
subAgents: children,
|
|
108
|
-
toolDefinitions: [
|
|
109
|
-
{ name: 'delegate', description: 'delegate', parameters: { type: 'object', properties: {} } },
|
|
110
|
-
],
|
|
111
|
-
toolHandlers: {
|
|
112
|
-
delegate: async (_args, ctx) => {
|
|
113
|
-
await Promise.all(invoke.map((n) => ctx.requestSubAgent!(n, { task: 'go' })));
|
|
114
|
-
return 'delegated';
|
|
115
|
-
},
|
|
116
|
-
},
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
const run = async (config: AgentConfig): Promise<readonly ChatMessage[]> => {
|
|
120
|
-
const driver = new ChatDriver(makeRegistry(ruleProvider()), {
|
|
121
|
-
maxToolIterations: 20,
|
|
122
|
-
maxFoldOperations: 5,
|
|
123
|
-
sessionKey: '',
|
|
124
|
-
});
|
|
125
|
-
driver.applyAgent(config);
|
|
126
|
-
await driver.sendMessage('go');
|
|
127
|
-
return driver.getHistory();
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
const tracesIn = (history: readonly ChatMessage[]): readonly ChatMessage[][] =>
|
|
131
|
-
history.flatMap((m) =>
|
|
132
|
-
(m.toolCalls ?? []).flatMap((tc) => (tc.subAgentTrace ? [tc.subAgentTrace] : [])),
|
|
133
|
-
);
|
|
134
|
-
|
|
135
|
-
const suite = createLogicSuite('ChatDriver sub-agent trace capture');
|
|
136
|
-
|
|
137
|
-
// ---------------------------------------------------------------------------
|
|
138
|
-
|
|
139
|
-
suite('keeps every trace when one tool call invokes three sub-agents', async () => {
|
|
140
|
-
const names = ['gen_a', 'gen_b', 'gen_c'];
|
|
141
|
-
const history = await run(boss(names.map(worker), names));
|
|
142
|
-
|
|
143
|
-
const traces = tracesIn(history);
|
|
144
|
-
assert.is(traces.length, 1, 'one tool call, so one concatenated trace');
|
|
145
|
-
|
|
146
|
-
// Each child contributes at least its own assistant turn. Before the fix this was
|
|
147
|
-
// one child's worth regardless of how many ran.
|
|
148
|
-
const seen = new Set(traces[0].map((m) => m.agentName).filter(Boolean));
|
|
149
|
-
assert.equal(
|
|
150
|
-
[...seen].sort(),
|
|
151
|
-
names,
|
|
152
|
-
`every invoked child must appear — got ${JSON.stringify([...seen])}`,
|
|
153
|
-
);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
suite('prices every child — usageRows emits a row per child and reconciles', async () => {
|
|
157
|
-
// The reconciliation test extended to a fan-out. The single-child version passed
|
|
158
|
-
// before the fix AND after it, which is exactly why it did not catch this.
|
|
159
|
-
const names = ['gen_a', 'gen_b', 'gen_c'];
|
|
160
|
-
const history = await run(boss(names.map(worker), names));
|
|
161
|
-
|
|
162
|
-
const rows = usageRows(history);
|
|
163
|
-
const childRows = rows.filter((r) => r.subAgentDepth === 1);
|
|
164
|
-
assert.is(childRows.length, names.length, 'one row per child that ran');
|
|
165
|
-
|
|
166
|
-
const rowTotal = rows.reduce((n, r) => n + (r.costUsd ?? 0) + (r.externalCostUsd ?? 0), 0);
|
|
167
|
-
assert.ok(
|
|
168
|
-
Math.abs(rowTotal - sumUsage(history).costUsd) < 1e-12,
|
|
169
|
-
`rows ${rowTotal} vs sumUsage ${sumUsage(history).costUsd}`,
|
|
170
|
-
);
|
|
171
|
-
// Parent turn ($0.02) + three children ($0.01 each). Asserted as a number so a
|
|
172
|
-
// regression that silently drops a child fails here rather than only in the
|
|
173
|
-
// reconciliation above, which would still agree with a truncated input.
|
|
174
|
-
assert.ok(Math.abs(rowTotal - 0.05) < 1e-12, `expected 0.05, got ${rowTotal}`);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
suite('keeps both traces when the same sub-agent is invoked twice (a retry)', async () => {
|
|
178
|
-
// The retry shape: one handler, one child name, two invocations. Under the old slot
|
|
179
|
-
// the first attempt's trace was overwritten by the second.
|
|
180
|
-
const history = await run(boss([worker('gen_a')], ['gen_a', 'gen_a']));
|
|
181
|
-
|
|
182
|
-
const traces = tracesIn(history);
|
|
183
|
-
assert.is(traces.length, 1);
|
|
184
|
-
const childTurns = traces[0].filter((m) => m.agentName === 'gen_a' && m.cost != null);
|
|
185
|
-
assert.is(childTurns.length, 2, 'both attempts survive, not just the last');
|
|
186
|
-
|
|
187
|
-
const rows = usageRows(history).filter((r) => r.subAgentDepth === 1);
|
|
188
|
-
assert.is(rows.length, 2, 'and both are priced');
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
suite('keeps child traces when the parent handler throws after they ran', async () => {
|
|
192
|
-
// Children that completed were billed by the provider. If the error path drops
|
|
193
|
-
// their traces, the run under-reports exactly as the single-slot bug did — and
|
|
194
|
-
// just as silently, since `sumUsage` and `usageRows` would still agree with each
|
|
195
|
-
// other over the truncated input. PR review.
|
|
196
|
-
const names = ['gen_a', 'gen_b'];
|
|
197
|
-
const parent = agent({
|
|
198
|
-
name: 'boss',
|
|
199
|
-
subAgents: names.map(worker),
|
|
200
|
-
toolDefinitions: [
|
|
201
|
-
{ name: 'delegate', description: 'delegate', parameters: { type: 'object', properties: {} } },
|
|
202
|
-
],
|
|
203
|
-
toolHandlers: {
|
|
204
|
-
delegate: async (_args, ctx) => {
|
|
205
|
-
await Promise.all(names.map((n) => ctx.requestSubAgent!(n, { task: 'go' })));
|
|
206
|
-
throw new Error('post-processing the children failed');
|
|
207
|
-
},
|
|
208
|
-
},
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
const history = await run(parent);
|
|
212
|
-
const traces = tracesIn(history);
|
|
213
|
-
assert.is(traces.length, 1, 'the failed tool call still carries its trace');
|
|
214
|
-
const seen = [...new Set(traces[0].map((m) => m.agentName).filter(Boolean))].sort();
|
|
215
|
-
assert.equal(seen, names, 'both children survive the throw');
|
|
216
|
-
|
|
217
|
-
const childRows = usageRows(history).filter((r) => r.subAgentDepth === 1);
|
|
218
|
-
assert.is(childRows.length, 2, 'and both are still priced');
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
suite('leaves subAgentTrace undefined when no sub-agent ran', async () => {
|
|
222
|
-
// Presence is the signal readers key off (`usage-rows.ts`, the UI's `when(...)`),
|
|
223
|
-
// so an empty array would be a different and wrong claim.
|
|
224
|
-
const history = await run(
|
|
225
|
-
agent({
|
|
226
|
-
name: 'boss',
|
|
227
|
-
subAgents: [worker('gen_a')],
|
|
228
|
-
toolDefinitions: [
|
|
229
|
-
{
|
|
230
|
-
name: 'delegate',
|
|
231
|
-
description: 'delegate',
|
|
232
|
-
parameters: { type: 'object', properties: {} },
|
|
233
|
-
},
|
|
234
|
-
],
|
|
235
|
-
toolHandlers: { delegate: async () => 'did it myself' },
|
|
236
|
-
}),
|
|
237
|
-
);
|
|
238
|
-
|
|
239
|
-
for (const m of history) {
|
|
240
|
-
for (const tc of m.toolCalls ?? []) {
|
|
241
|
-
assert.is(tc.subAgentTrace, undefined, 'not an empty array');
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
assert.equal(
|
|
245
|
-
usageRows(history).filter((r) => r.subAgentDepth === 1),
|
|
246
|
-
[],
|
|
247
|
-
'no child rows',
|
|
248
|
-
);
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
suite.run();
|