@animalabs/agent-framework 0.23.1 → 0.24.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/README.md +212 -42
- package/dist/src/agent.d.ts +60 -9
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +92 -12
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +14 -12
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/code-execution/engine.d.ts +177 -0
- package/dist/src/code-execution/engine.d.ts.map +1 -0
- package/dist/src/code-execution/engine.js +494 -0
- package/dist/src/code-execution/engine.js.map +1 -0
- package/dist/src/code-execution/index.d.ts +5 -10
- package/dist/src/code-execution/index.d.ts.map +1 -1
- package/dist/src/code-execution/index.js +5 -9
- package/dist/src/code-execution/index.js.map +1 -1
- package/dist/src/code-execution/isolate/calls.d.ts +114 -0
- package/dist/src/code-execution/isolate/calls.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/calls.js +145 -0
- package/dist/src/code-execution/isolate/calls.js.map +1 -0
- package/dist/src/code-execution/isolate/child-entry.d.ts +2 -0
- package/dist/src/code-execution/isolate/child-entry.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/child-entry.js +5 -0
- package/dist/src/code-execution/isolate/child-entry.js.map +1 -0
- package/dist/src/code-execution/isolate/child-main.d.ts +26 -0
- package/dist/src/code-execution/isolate/child-main.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/child-main.js +132 -0
- package/dist/src/code-execution/isolate/child-main.js.map +1 -0
- package/dist/src/code-execution/isolate/child.d.ts +44 -0
- package/dist/src/code-execution/isolate/child.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/child.js +315 -0
- package/dist/src/code-execution/isolate/child.js.map +1 -0
- package/dist/src/code-execution/isolate/frames.d.ts +80 -0
- package/dist/src/code-execution/isolate/frames.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/frames.js +210 -0
- package/dist/src/code-execution/isolate/frames.js.map +1 -0
- package/dist/src/code-execution/isolate/output.d.ts +68 -0
- package/dist/src/code-execution/isolate/output.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/output.js +143 -0
- package/dist/src/code-execution/isolate/output.js.map +1 -0
- package/dist/src/code-execution/isolate/prelude.d.ts +109 -0
- package/dist/src/code-execution/isolate/prelude.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/prelude.js +401 -0
- package/dist/src/code-execution/isolate/prelude.js.map +1 -0
- package/dist/src/code-execution/isolate/protocol.d.ts +151 -0
- package/dist/src/code-execution/isolate/protocol.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/protocol.js +150 -0
- package/dist/src/code-execution/isolate/protocol.js.map +1 -0
- package/dist/src/code-execution/isolate/render.d.ts +57 -0
- package/dist/src/code-execution/isolate/render.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/render.js +214 -0
- package/dist/src/code-execution/isolate/render.js.map +1 -0
- package/dist/src/code-execution/isolate/runner.d.ts +250 -0
- package/dist/src/code-execution/isolate/runner.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/runner.js +854 -0
- package/dist/src/code-execution/isolate/runner.js.map +1 -0
- package/dist/src/code-execution/isolate/scripts.d.ts +175 -0
- package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/scripts.js +357 -0
- package/dist/src/code-execution/isolate/scripts.js.map +1 -0
- package/dist/src/code-execution/quickjs.wasm +0 -0
- package/dist/src/code-execution/tool-definition.d.ts +93 -43
- package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
- package/dist/src/code-execution/tool-definition.js +176 -142
- package/dist/src/code-execution/tool-definition.js.map +1 -1
- package/dist/src/deadline-timer.d.ts +3 -0
- package/dist/src/deadline-timer.d.ts.map +1 -1
- package/dist/src/deadline-timer.js +1 -1
- package/dist/src/deadline-timer.js.map +1 -1
- package/dist/src/framework.d.ts +1036 -440
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +4131 -2228
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +28 -1
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +88 -10
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/held-writes.d.ts +16 -3
- package/dist/src/held-writes.d.ts.map +1 -1
- package/dist/src/held-writes.js +16 -3
- package/dist/src/held-writes.js.map +1 -1
- package/dist/src/index.d.ts +6 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +9 -8
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcpl/channel-registry.d.ts +471 -75
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +1673 -337
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/conversation-router.d.ts +12 -7
- package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
- package/dist/src/mcpl/conversation-router.js +12 -7
- package/dist/src/mcpl/conversation-router.js.map +1 -1
- package/dist/src/mcpl/convert-block.d.ts.map +1 -1
- package/dist/src/mcpl/convert-block.js +9 -5
- package/dist/src/mcpl/convert-block.js.map +1 -1
- package/dist/src/mcpl/inbound-source.d.ts +50 -0
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
- package/dist/src/mcpl/inbound-source.js +130 -0
- package/dist/src/mcpl/inbound-source.js.map +1 -1
- package/dist/src/mcpl/index.d.ts +2 -1
- package/dist/src/mcpl/index.d.ts.map +1 -1
- package/dist/src/mcpl/index.js +3 -2
- package/dist/src/mcpl/index.js.map +1 -1
- package/dist/src/mcpl/log-value.d.ts +6 -0
- package/dist/src/mcpl/log-value.d.ts.map +1 -1
- package/dist/src/mcpl/log-value.js +8 -0
- package/dist/src/mcpl/log-value.js.map +1 -1
- package/dist/src/mcpl/modern-connection.d.ts +15 -6
- package/dist/src/mcpl/modern-connection.d.ts.map +1 -1
- package/dist/src/mcpl/modern-connection.js +168 -53
- package/dist/src/mcpl/modern-connection.js.map +1 -1
- package/dist/src/mcpl/prose-grammar.d.ts +4 -5
- package/dist/src/mcpl/prose-grammar.d.ts.map +1 -1
- package/dist/src/mcpl/prose-grammar.js +4 -5
- package/dist/src/mcpl/prose-grammar.js.map +1 -1
- package/dist/src/mcpl/protocol-family.d.ts +97 -10
- package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
- package/dist/src/mcpl/protocol-family.js +173 -16
- package/dist/src/mcpl/protocol-family.js.map +1 -1
- package/dist/src/mcpl/push-coalescer.d.ts +132 -14
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +227 -50
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/push-handler.d.ts +6 -1
- package/dist/src/mcpl/push-handler.d.ts.map +1 -1
- package/dist/src/mcpl/push-handler.js +4 -1
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/reference-fetcher.d.ts +2 -2
- package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
- package/dist/src/mcpl/reference-fetcher.js +4 -4
- package/dist/src/mcpl/reference-fetcher.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +50 -21
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +158 -74
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/tags.d.ts +24 -0
- package/dist/src/mcpl/tags.d.ts.map +1 -1
- package/dist/src/mcpl/tags.js +33 -0
- package/dist/src/mcpl/tags.js.map +1 -1
- package/dist/src/mcpl/tool-result-normalize.d.ts +2 -1
- package/dist/src/mcpl/tool-result-normalize.d.ts.map +1 -1
- package/dist/src/mcpl/tool-result-normalize.js.map +1 -1
- package/dist/src/mcpl/transport.d.ts +55 -7
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +163 -34
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +22 -6
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/module-registry.d.ts +4 -2
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +100 -13
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/discord/index.d.ts.map +1 -1
- package/dist/src/modules/discord/index.js +8 -13
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/history/index.d.ts.map +1 -1
- package/dist/src/modules/history/index.js +27 -4
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/history/semantic.d.ts +15 -3
- package/dist/src/modules/history/semantic.d.ts.map +1 -1
- package/dist/src/modules/history/semantic.js +27 -5
- package/dist/src/modules/history/semantic.js.map +1 -1
- package/dist/src/modules/index.d.ts +1 -1
- package/dist/src/modules/index.d.ts.map +1 -1
- package/dist/src/modules/index.js.map +1 -1
- package/dist/src/modules/unknown-tool.d.ts +4 -1
- package/dist/src/modules/unknown-tool.d.ts.map +1 -1
- package/dist/src/modules/unknown-tool.js +4 -1
- package/dist/src/modules/unknown-tool.js.map +1 -1
- package/dist/src/modules/workspace/branch-intent.d.ts +3 -1
- package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
- package/dist/src/modules/workspace/branch-intent.js +3 -1
- package/dist/src/modules/workspace/branch-intent.js.map +1 -1
- package/dist/src/modules/workspace/edit-plan.d.ts +265 -0
- package/dist/src/modules/workspace/edit-plan.d.ts.map +1 -0
- package/dist/src/modules/workspace/edit-plan.js +794 -0
- package/dist/src/modules/workspace/edit-plan.js.map +1 -0
- package/dist/src/modules/workspace/edit-text.d.ts +117 -0
- package/dist/src/modules/workspace/edit-text.d.ts.map +1 -0
- package/dist/src/modules/workspace/edit-text.js +584 -0
- package/dist/src/modules/workspace/edit-text.js.map +1 -0
- package/dist/src/modules/workspace/effects.d.ts +5 -4
- package/dist/src/modules/workspace/effects.d.ts.map +1 -1
- package/dist/src/modules/workspace/effects.js +78 -25
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +484 -61
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +2173 -645
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts +213 -38
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +416 -36
- package/dist/src/modules/workspace/observe.js.map +1 -1
- package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
- package/dist/src/modules/workspace/reconcile.js +15 -8
- package/dist/src/modules/workspace/reconcile.js.map +1 -1
- package/dist/src/modules/workspace/text.d.ts +32 -0
- package/dist/src/modules/workspace/text.d.ts.map +1 -0
- package/dist/src/modules/workspace/text.js +67 -0
- package/dist/src/modules/workspace/text.js.map +1 -0
- package/dist/src/modules/workspace/types.d.ts +210 -6
- package/dist/src/modules/workspace/types.d.ts.map +1 -1
- package/dist/src/modules/workspace/types.js.map +1 -1
- package/dist/src/modules/workspace/watcher.d.ts +3 -2
- package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
- package/dist/src/modules/workspace/watcher.js.map +1 -1
- package/dist/src/operator-log.d.ts +52 -24
- package/dist/src/operator-log.d.ts.map +1 -1
- package/dist/src/operator-log.js.map +1 -1
- package/dist/src/recovery/discord-awareness-outbox.d.ts +496 -72
- package/dist/src/recovery/discord-awareness-outbox.d.ts.map +1 -1
- package/dist/src/recovery/discord-awareness-outbox.js +1196 -289
- package/dist/src/recovery/discord-awareness-outbox.js.map +1 -1
- package/dist/src/recovery/offline-branch.d.ts +26 -1
- package/dist/src/recovery/offline-branch.d.ts.map +1 -1
- package/dist/src/recovery/offline-branch.js +164 -39
- package/dist/src/recovery/offline-branch.js.map +1 -1
- package/dist/src/recovery/recover-cli.js +23 -4
- package/dist/src/recovery/recover-cli.js.map +1 -1
- package/dist/src/send-tools.d.ts +11 -0
- package/dist/src/send-tools.d.ts.map +1 -0
- package/dist/src/send-tools.js +11 -0
- package/dist/src/send-tools.js.map +1 -0
- package/dist/src/tool-result-guard.d.ts +4 -3
- package/dist/src/tool-result-guard.d.ts.map +1 -1
- package/dist/src/tool-result-guard.js +5 -4
- package/dist/src/tool-result-guard.js.map +1 -1
- package/dist/src/tool-result-history.d.ts +1 -1
- package/dist/src/tool-result-history.js +1 -1
- package/dist/src/tune-out/coordinator.d.ts +21 -0
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +139 -37
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/types/agent.d.ts +4 -0
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +62 -9
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +62 -58
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +40 -8
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +111 -10
- package/dist/src/types/trace.d.ts.map +1 -1
- package/dist/src/usage/types.d.ts +16 -0
- package/dist/src/usage/types.d.ts.map +1 -1
- package/dist/src/usage/usage-tracker.d.ts +14 -1
- package/dist/src/usage/usage-tracker.d.ts.map +1 -1
- package/dist/src/usage/usage-tracker.js +81 -41
- package/dist/src/usage/usage-tracker.js.map +1 -1
- package/package.json +6 -5
- package/src/agent.ts +93 -12
- package/src/api/server.ts +14 -12
- package/src/code-execution/engine.ts +595 -0
- package/src/code-execution/index.ts +5 -17
- package/src/code-execution/isolate/calls.ts +199 -0
- package/src/code-execution/isolate/child-entry.ts +5 -0
- package/src/code-execution/isolate/child-main.ts +132 -0
- package/src/code-execution/isolate/child.ts +327 -0
- package/src/code-execution/isolate/frames.ts +209 -0
- package/src/code-execution/isolate/output.ts +161 -0
- package/src/code-execution/isolate/prelude.ts +409 -0
- package/src/code-execution/isolate/protocol.ts +240 -0
- package/src/code-execution/isolate/render.ts +230 -0
- package/src/code-execution/isolate/runner.ts +911 -0
- package/src/code-execution/isolate/scripts.ts +479 -0
- package/src/code-execution/quickjs.wasm +0 -0
- package/src/code-execution/quickjs.wasm.LICENSES +149 -0
- package/src/code-execution/tool-definition.ts +236 -167
- package/src/deadline-timer.ts +1 -1
- package/src/framework.ts +4507 -2406
- package/src/gate/event-gate.ts +78 -11
- package/src/held-writes.ts +17 -3
- package/src/index.ts +30 -22
- package/src/mcpl/channel-registry.ts +1825 -368
- package/src/mcpl/conversation-router.ts +12 -7
- package/src/mcpl/convert-block.ts +9 -5
- package/src/mcpl/inbound-source.ts +131 -0
- package/src/mcpl/index.ts +4 -2
- package/src/mcpl/log-value.ts +9 -0
- package/src/mcpl/modern-connection.ts +162 -53
- package/src/mcpl/prose-grammar.ts +4 -5
- package/src/mcpl/protocol-family.ts +199 -21
- package/src/mcpl/push-coalescer.ts +306 -62
- package/src/mcpl/push-handler.ts +10 -2
- package/src/mcpl/reference-fetcher.ts +4 -4
- package/src/mcpl/server-connection.ts +180 -79
- package/src/mcpl/tags.ts +36 -0
- package/src/mcpl/tool-result-normalize.ts +2 -1
- package/src/mcpl/transport.ts +162 -33
- package/src/mcpl/types.ts +23 -6
- package/src/module-registry.ts +92 -13
- package/src/modules/discord/index.ts +8 -13
- package/src/modules/history/index.ts +25 -3
- package/src/modules/history/semantic.ts +29 -6
- package/src/modules/index.ts +1 -0
- package/src/modules/unknown-tool.ts +4 -1
- package/src/modules/workspace/branch-intent.ts +3 -1
- package/src/modules/workspace/edit-plan.ts +954 -0
- package/src/modules/workspace/edit-text.ts +618 -0
- package/src/modules/workspace/effects.ts +70 -19
- package/src/modules/workspace/index.ts +2247 -642
- package/src/modules/workspace/observe.ts +465 -56
- package/src/modules/workspace/reconcile.ts +14 -7
- package/src/modules/workspace/text.ts +68 -0
- package/src/modules/workspace/types.ts +211 -6
- package/src/modules/workspace/watcher.ts +3 -2
- package/src/operator-log.ts +47 -19
- package/src/recovery/discord-awareness-outbox.ts +1500 -356
- package/src/recovery/offline-branch.ts +189 -55
- package/src/recovery/recover-cli.ts +25 -4
- package/src/send-tools.ts +11 -0
- package/src/tool-result-guard.ts +6 -5
- package/src/tool-result-history.ts +1 -1
- package/src/tune-out/coordinator.ts +163 -42
- package/src/types/agent.ts +4 -0
- package/src/types/events.ts +62 -9
- package/src/types/framework.ts +62 -58
- package/src/types/module.ts +40 -8
- package/src/types/trace.ts +121 -15
- package/src/usage/types.ts +16 -0
- package/src/usage/usage-tracker.ts +86 -43
- package/dist/src/code-execution/py-runner.d.ts +0 -191
- package/dist/src/code-execution/py-runner.d.ts.map +0 -1
- package/dist/src/code-execution/py-runner.js +0 -655
- package/dist/src/code-execution/py-runner.js.map +0 -1
- package/dist/src/code-execution/runtime-py.d.ts +0 -50
- package/dist/src/code-execution/runtime-py.d.ts.map +0 -1
- package/dist/src/code-execution/runtime-py.js +0 -677
- package/dist/src/code-execution/runtime-py.js.map +0 -1
- package/dist/src/mcpl/prose-stream-router.d.ts +0 -88
- package/dist/src/mcpl/prose-stream-router.d.ts.map +0 -1
- package/dist/src/mcpl/prose-stream-router.js +0 -291
- package/dist/src/mcpl/prose-stream-router.js.map +0 -1
- package/src/code-execution/py-runner.ts +0 -791
- package/src/code-execution/runtime-py.ts +0 -677
- package/src/mcpl/prose-stream-router.ts +0 -268
package/src/types/module.ts
CHANGED
|
@@ -27,7 +27,8 @@ export interface MessageQuery {
|
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* A message as a module context's reads answer it: a stored row, or a row
|
|
30
|
-
* for a write the framework holds (`held`).
|
|
30
|
+
* for a write the framework holds (`held`). Either is marked
|
|
31
|
+
* `heldFromResidents` when a tune-out holds it from the residents.
|
|
31
32
|
*/
|
|
32
33
|
export type ModuleMessage = StoredMessage & {
|
|
33
34
|
/**
|
|
@@ -39,9 +40,31 @@ export type ModuleMessage = StoredMessage & {
|
|
|
39
40
|
* and `timestamp` are provisional: the sequence comes after every stored
|
|
40
41
|
* row's, the timestamp is when the framework held the write (for a write
|
|
41
42
|
* an older release held, when its queue was read back), and both change
|
|
42
|
-
* when it lands.
|
|
43
|
+
* when it lands. A held write whose earlier write may already be stored
|
|
44
|
+
* is looked up first, and answered as the stored row it is when the store
|
|
45
|
+
* holds it. Absent on a stored row.
|
|
43
46
|
*/
|
|
44
47
|
held?: true;
|
|
48
|
+
/**
|
|
49
|
+
* True on a message a tune-out holds from the residents: one that arrived
|
|
50
|
+
* in a tuned-out channel, stamped `metadata.tuneOut` as it came in. The
|
|
51
|
+
* store keeps it, but no resident is shown the row itself: no resident's
|
|
52
|
+
* compiled view includes it, during the tune-out or after it, and a tool
|
|
53
|
+
* boundary of a turn alive when it arrived stores it without injecting it
|
|
54
|
+
* into the live turn. The subconscious reads it. Its text can still reach
|
|
55
|
+
* a resident in rows of their own, which aren't marked, such as the
|
|
56
|
+
* cancel's `<tuned-out-backlog>` row, with the text of the tune-out's newest
|
|
57
|
+
* messages, up to `backlogCap` of them and as many as fit in one of the
|
|
58
|
+
* residents' messages, the stored ones first and then those still held;
|
|
59
|
+
* what the subconscious says of it, in its report or its note; and the
|
|
60
|
+
* result of a tool that reads history on request, such as a
|
|
61
|
+
* channel's `fetch_history` or the history module's `extract`. A module
|
|
62
|
+
* that builds on what the residents see, such as one choosing from the
|
|
63
|
+
* recent conversation, leaves a marked row out, and one that matches
|
|
64
|
+
* what's stored, such as a sync's dedupe, keeps it. A held write (`held`)
|
|
65
|
+
* is marked too when it carries the stamp. Absent on every other row.
|
|
66
|
+
*/
|
|
67
|
+
heldFromResidents?: true;
|
|
45
68
|
};
|
|
46
69
|
|
|
47
70
|
/**
|
|
@@ -290,13 +313,17 @@ export interface ModuleContext {
|
|
|
290
313
|
|
|
291
314
|
/**
|
|
292
315
|
* Edit a message, by its id or a held write's handle. A held write is
|
|
293
|
-
* stored with the new content.
|
|
316
|
+
* stored with the new content. One whose earlier write may already be
|
|
317
|
+
* stored, where the store can't be searched to tell, throws with nothing
|
|
318
|
+
* changed.
|
|
294
319
|
*/
|
|
295
320
|
editMessage(id: MessageId, content: ContentBlock[]): void;
|
|
296
321
|
|
|
297
322
|
/**
|
|
298
323
|
* Remove a message, by its id or a held write's handle. A held write is
|
|
299
|
-
* dropped, so the agent never reads it.
|
|
324
|
+
* dropped, so the agent never reads it. One whose earlier write may
|
|
325
|
+
* already be stored, where the store can't be searched to tell, throws
|
|
326
|
+
* with nothing changed.
|
|
300
327
|
*/
|
|
301
328
|
removeMessage(id: MessageId): void;
|
|
302
329
|
|
|
@@ -312,7 +339,9 @@ export interface ModuleContext {
|
|
|
312
339
|
findMessageByExternalId(source: string, externalId: string): MessageId | null;
|
|
313
340
|
|
|
314
341
|
/**
|
|
315
|
-
* Get a message by its id or a held write's handle
|
|
342
|
+
* Get a message by its id or a held write's handle, marked
|
|
343
|
+
* `heldFromResidents` when a tune-out holds it from the residents
|
|
344
|
+
* (ModuleMessage).
|
|
316
345
|
*/
|
|
317
346
|
getMessage(id: MessageId): ModuleMessage | null;
|
|
318
347
|
|
|
@@ -322,7 +351,9 @@ export interface ModuleContext {
|
|
|
322
351
|
* The rows of writes the framework holds come after the stored rows, as
|
|
323
352
|
* the newest, or before them in a reversed query, marked `held`
|
|
324
353
|
* (ModuleMessage). Those the last process held show once create() has
|
|
325
|
-
* restored them, after every module's start() (addMessage).
|
|
354
|
+
* restored them, after every module's start() (addMessage). A message a
|
|
355
|
+
* tune-out holds from the residents is among the rows, marked
|
|
356
|
+
* `heldFromResidents` (ModuleMessage).
|
|
326
357
|
*/
|
|
327
358
|
queryMessages(filter: MessageQuery): MessageQueryResult;
|
|
328
359
|
|
|
@@ -571,8 +602,9 @@ export interface SpeechContext {
|
|
|
571
602
|
|
|
572
603
|
/**
|
|
573
604
|
* The turn this speech ends: the same id as `ToolCall.callerTurnId` on the
|
|
574
|
-
* calls made in it (its model's calls and
|
|
575
|
-
*
|
|
605
|
+
* calls made in it (its model's calls, and a script's calls that reach the
|
|
606
|
+
* host while a code_execution call of the turn watches the script), kept across the
|
|
607
|
+
* turn's streams (a context-budget restart or a
|
|
576
608
|
* retry), and larger for the agent's next turn. Unique only within one run
|
|
577
609
|
* of the process.
|
|
578
610
|
*/
|
package/src/types/trace.ts
CHANGED
|
@@ -33,9 +33,23 @@ export type TraceEvent =
|
|
|
33
33
|
| (TraceEventBase & {
|
|
34
34
|
type: 'process:completed';
|
|
35
35
|
processEvent: ProcessEvent;
|
|
36
|
+
/** The modules' responses that applied: one refused for malformed
|
|
37
|
+
* content is left out, and named by process:response-refused. */
|
|
36
38
|
responses: ModuleProcessResponse[];
|
|
37
39
|
durationMs: number;
|
|
38
40
|
})
|
|
41
|
+
/** A module's process response held content context-manager won't store,
|
|
42
|
+
* in a message it adds or an edit it makes, and was refused whole before
|
|
43
|
+
* any response to the event applied. `where` names the first such message
|
|
44
|
+
* or edit in the response, such as `addMessages[1]`, and `places` is
|
|
45
|
+
* malformedContentPlaces' answer for it. */
|
|
46
|
+
| (TraceEventBase & {
|
|
47
|
+
type: 'process:response-refused';
|
|
48
|
+
moduleName: string;
|
|
49
|
+
eventType: string;
|
|
50
|
+
where: string;
|
|
51
|
+
places: string[];
|
|
52
|
+
})
|
|
39
53
|
|
|
40
54
|
// Inference lifecycle
|
|
41
55
|
| (TraceEventBase & {
|
|
@@ -124,9 +138,15 @@ export type TraceEvent =
|
|
|
124
138
|
blockType: 'text' | 'thinking' | 'tool_call' | 'tool_result';
|
|
125
139
|
/** 0-indexed block position in the current assistant turn. */
|
|
126
140
|
blockIndex: number;
|
|
127
|
-
/** The channel this stream shows typing in
|
|
128
|
-
*
|
|
129
|
-
*
|
|
141
|
+
/** The channel this stream shows typing in, the conversation the turn
|
|
142
|
+
* is attending. Locus and hybrid mode: the turn's locus, which an
|
|
143
|
+
* addressed re-pin or the agent's own `channel_open` can move between
|
|
144
|
+
* rounds, so it can change within one stream; the indicator and these
|
|
145
|
+
* traces follow it from the next round on, at the model's first
|
|
146
|
+
* content in it or its retry after a refusal, and a tool result the
|
|
147
|
+
* boundary reports carries the channel of the round it answers. In
|
|
148
|
+
* hybrid mode a `>>>` envelope can send the text itself elsewhere.
|
|
149
|
+
* Explicit mode: the channel the start's wake came from. */
|
|
130
150
|
channelId?: string;
|
|
131
151
|
})
|
|
132
152
|
| (TraceEventBase & {
|
|
@@ -141,9 +161,15 @@ export type TraceEvent =
|
|
|
141
161
|
phase: 'block_start' | 'block_complete';
|
|
142
162
|
blockType: 'text' | 'thinking' | 'tool_call' | 'tool_result';
|
|
143
163
|
blockIndex: number;
|
|
144
|
-
/** The channel this stream shows typing in
|
|
145
|
-
*
|
|
146
|
-
*
|
|
164
|
+
/** The channel this stream shows typing in, the conversation the turn
|
|
165
|
+
* is attending. Locus and hybrid mode: the turn's locus, which an
|
|
166
|
+
* addressed re-pin or the agent's own `channel_open` can move between
|
|
167
|
+
* rounds, so it can change within one stream; the indicator and these
|
|
168
|
+
* traces follow it from the next round on, at the model's first
|
|
169
|
+
* content in it or its retry after a refusal, and a tool result the
|
|
170
|
+
* boundary reports carries the channel of the round it answers. In
|
|
171
|
+
* hybrid mode a `>>>` envelope can send the text itself elsewhere.
|
|
172
|
+
* Explicit mode: the channel the start's wake came from. */
|
|
147
173
|
channelId?: string;
|
|
148
174
|
})
|
|
149
175
|
| (TraceEventBase & {
|
|
@@ -173,6 +199,66 @@ export type TraceEvent =
|
|
|
173
199
|
type: 'inference:turn_ended';
|
|
174
200
|
agentName: string;
|
|
175
201
|
})
|
|
202
|
+
| (TraceEventBase & {
|
|
203
|
+
/**
|
|
204
|
+
* Prose that delivery published, sent once the publish succeeds: the
|
|
205
|
+
* outgoing stream's chunk (MCPL Spec 14.3 `channels/outgoing/chunk`),
|
|
206
|
+
* emitted whether or not the channel's server takes the stream. It
|
|
207
|
+
* carries only what was published, so a consumer that speaks or shows
|
|
208
|
+
* it, such as a voice relay, never gets text that delivery withholds (a
|
|
209
|
+
* `skip_reply`, a silencing send, a private `think`, a hold, a bounce,
|
|
210
|
+
* a draft) or a publish the server didn't confirm (`delivered: true`):
|
|
211
|
+
* one refused before sending, one that threw, timed out or got an
|
|
212
|
+
* error answer, one the server reported undelivered
|
|
213
|
+
* (`delivered: false`), and one whose reply leaves `delivered` out.
|
|
214
|
+
* `inference:tokens` stays the model's text as it is written (held, as
|
|
215
|
+
* before, while a tool-result guard's batch is pending). A later
|
|
216
|
+
* publish to the same destination, a server and its channel, by the
|
|
217
|
+
* same stream opens with a paragraph break (`\n\n`), so a
|
|
218
|
+
* destination's chunks joined in `index` order are its text, its
|
|
219
|
+
* messages kept apart.
|
|
220
|
+
* `mcpl:speech-routed` also reports speech publishes, with no stream
|
|
221
|
+
* id, index or end, each once delivered: deliverSpeech's, the `sleep`
|
|
222
|
+
* tool's announcement among them, and a subconscious's
|
|
223
|
+
* `speak_in_channel`'s. A relay that voices the agent's prose takes
|
|
224
|
+
* this trace, with `inference:published_complete`, and not
|
|
225
|
+
* `mcpl:speech-routed` as well, and takes each message's id from its
|
|
226
|
+
* `messageId` to edit what it voiced.
|
|
227
|
+
*/
|
|
228
|
+
type: 'inference:published';
|
|
229
|
+
agentName: string;
|
|
230
|
+
/** The server the prose is published to, and its channel there: two
|
|
231
|
+
* servers' channels with the same id are two destinations. */
|
|
232
|
+
serverId: string;
|
|
233
|
+
channelId: string;
|
|
234
|
+
/** The stream's id, shared with its `channels/outgoing/*` notifications. */
|
|
235
|
+
inferenceId: string;
|
|
236
|
+
/** Increases by one per chunk of the stream, across its channels. */
|
|
237
|
+
index: number;
|
|
238
|
+
text: string;
|
|
239
|
+
/** The id the channel's server returned for this chunk's publish
|
|
240
|
+
* (`ChannelsPublishResult.messageId`); absent when it returned none.
|
|
241
|
+
* Each chunk is one publish, so each carries its own. */
|
|
242
|
+
messageId?: string;
|
|
243
|
+
})
|
|
244
|
+
| (TraceEventBase & {
|
|
245
|
+
/**
|
|
246
|
+
* A stream's end for one destination it published to, a server and
|
|
247
|
+
* its channel, emitted on every exit path once the stream has ended
|
|
248
|
+
* and its deliveries have run, or, when the host stops, before its
|
|
249
|
+
* connections close: `text` is everything its `inference:published`
|
|
250
|
+
* chunks carried there by then, and none follows it. Like those
|
|
251
|
+
* chunks, it's emitted whether or not that server takes the stream,
|
|
252
|
+
* or registers the channel still; the MCPL
|
|
253
|
+
* `channels/outgoing/complete` goes to the server only when it does.
|
|
254
|
+
*/
|
|
255
|
+
type: 'inference:published_complete';
|
|
256
|
+
agentName: string;
|
|
257
|
+
serverId: string;
|
|
258
|
+
channelId: string;
|
|
259
|
+
inferenceId: string;
|
|
260
|
+
text: string;
|
|
261
|
+
})
|
|
176
262
|
|
|
177
263
|
// Tool lifecycle
|
|
178
264
|
| (TraceEventBase & {
|
|
@@ -216,10 +302,11 @@ export type TraceEvent =
|
|
|
216
302
|
})
|
|
217
303
|
| (TraceEventBase & {
|
|
218
304
|
/**
|
|
219
|
-
*
|
|
220
|
-
* failed (size cap, storeBlob failure, …) — the over-cap tail was NOT
|
|
305
|
+
* The workspace had a writable mount without an include, where spills
|
|
306
|
+
* go, but the oversized-result spill write failed (size cap, storeBlob failure, …) — the over-cap tail was NOT
|
|
221
307
|
* retained. Distinct from the no-workspace fallback, which is silent
|
|
222
|
-
* by design (nothing unexpected happened)
|
|
308
|
+
* by design (nothing unexpected happened), whether the setup has no
|
|
309
|
+
* writable mount or every writable mount has an include, as configured.
|
|
223
310
|
*/
|
|
224
311
|
type: 'tool:spill_failed';
|
|
225
312
|
label: string;
|
|
@@ -302,6 +389,18 @@ export type TraceEvent =
|
|
|
302
389
|
field?: string;
|
|
303
390
|
detail?: string;
|
|
304
391
|
})
|
|
392
|
+
/** MCPL content that context-manager won't store, because it doesn't
|
|
393
|
+
* match ContentBlock, reached the store/wake site and was refused there:
|
|
394
|
+
* no row, no wake. `places` is malformedContentPlaces' answer for it. */
|
|
395
|
+
| (TraceEventBase & {
|
|
396
|
+
type: 'mcpl:malformed-content-refused';
|
|
397
|
+
lane: 'push' | 'channel';
|
|
398
|
+
serverId: string;
|
|
399
|
+
places: string[];
|
|
400
|
+
eventId?: string;
|
|
401
|
+
channelId?: string;
|
|
402
|
+
messageId?: string;
|
|
403
|
+
})
|
|
305
404
|
/** MCPL content with nothing model-visible reached the store/wake site
|
|
306
405
|
* (module-emitted or coalescer-delivered) and was dropped: no row, no wake. */
|
|
307
406
|
| (TraceEventBase & {
|
|
@@ -442,13 +541,16 @@ export type TraceEvent =
|
|
|
442
541
|
})
|
|
443
542
|
|
|
444
543
|
// Host-owned speech routing (ChannelRegistry.routeSpeech). One trace per
|
|
445
|
-
// delivered prose segment
|
|
544
|
+
// delivered prose segment, and one per publish the subconscious's
|
|
545
|
+
// speak_in_channel delivers (ChannelRegistry.publishForAgent): that one's
|
|
546
|
+
// conversationId is the speaking agent's name, and it carries no
|
|
547
|
+
// messageId. `text` is the segment verbatim — the same content
|
|
446
548
|
// already on the bus chunk-by-chunk via inference:tokens, and mcpl:* traces
|
|
447
549
|
// are 'ops'-scoped on the webui wire — and `messageId` is the surface's id
|
|
448
|
-
// for the posted message (when the MCPL server
|
|
449
|
-
// give external taps the (channelId,
|
|
450
|
-
// a just-posted message, e.g. a TTS
|
|
451
|
-
// words actually voiced.
|
|
550
|
+
// for the posted message (on routeSpeech's traces, when the MCPL server
|
|
551
|
+
// reports one). Together they give external taps the (channelId,
|
|
552
|
+
// messageId, text) tuple needed to edit a just-posted message, e.g. a TTS
|
|
553
|
+
// interruption truncating a reply to the words actually voiced.
|
|
452
554
|
| (TraceEventBase & {
|
|
453
555
|
type: 'mcpl:speech-routed';
|
|
454
556
|
/** Agent / conversation whose speech was routed. */
|
|
@@ -459,7 +561,8 @@ export type TraceEvent =
|
|
|
459
561
|
textLen: number;
|
|
460
562
|
/** The routed prose segment, verbatim. */
|
|
461
563
|
text: string;
|
|
462
|
-
/** Surface message id (e.g. Discord message id), when reported
|
|
564
|
+
/** Surface message id (e.g. Discord message id), when reported, on
|
|
565
|
+
* routeSpeech's traces. speak_in_channel's carry none. */
|
|
463
566
|
messageId?: string;
|
|
464
567
|
})
|
|
465
568
|
| (TraceEventBase & {
|
|
@@ -473,6 +576,9 @@ export type TraceEvent =
|
|
|
473
576
|
/** `failed`: nothing was posted; `unknown`: the request was dispatched
|
|
474
577
|
* and no valid receipt came back, so it may have been. */
|
|
475
578
|
outcome?: 'failed' | 'unknown';
|
|
579
|
+
/** The connector error's structured data, bounded (connectorText),
|
|
580
|
+
* when it sent some: it may say what a multi-part send posted. */
|
|
581
|
+
detail?: string;
|
|
476
582
|
})
|
|
477
583
|
|
|
478
584
|
// Admin puppet: an operator executed a tool AS an agent and stored the
|
package/src/usage/types.ts
CHANGED
|
@@ -3,13 +3,29 @@ export interface SessionUsage {
|
|
|
3
3
|
outputTokens: number;
|
|
4
4
|
cacheCreationTokens: number;
|
|
5
5
|
cacheReadTokens: number;
|
|
6
|
+
/** The summed estimated cost of the inferences counted here that membrane
|
|
7
|
+
* priced, in one currency. An inference it couldn't price adds nothing, so
|
|
8
|
+
* this is a lower bound when any were unpriced. Absent when none was
|
|
9
|
+
* priced, and from the moment costs in two currencies meet here, since the
|
|
10
|
+
* two can't be summed, which `mixedCurrencies` records. */
|
|
6
11
|
estimatedCost?: { total: number; currency: string };
|
|
12
|
+
/** Set once inferences priced in two currencies have been counted here:
|
|
13
|
+
* `estimatedCost` stays absent from then on, since the two can't be
|
|
14
|
+
* summed and a later cost alone isn't this tally's. Stored and restored
|
|
15
|
+
* with it, and carried into the shared ephemeral entry when stored
|
|
16
|
+
* entries fold into it. */
|
|
17
|
+
mixedCurrencies?: true;
|
|
7
18
|
}
|
|
8
19
|
|
|
9
20
|
export interface AgentUsage {
|
|
10
21
|
agentName: string;
|
|
11
22
|
usage: SessionUsage;
|
|
12
23
|
inferenceCount: number;
|
|
24
|
+
/** Set on the one entry that holds every ephemeral agent's usage together
|
|
25
|
+
* (agentName EPHEMERAL_USAGE_NAME), apart from any agent of that name. Each
|
|
26
|
+
* ephemeral agent runs under a new name, so an entry per name would grow
|
|
27
|
+
* the record by one for every run, for good. */
|
|
28
|
+
ephemeral?: true;
|
|
13
29
|
}
|
|
14
30
|
|
|
15
31
|
export interface SessionUsageSnapshot {
|
|
@@ -7,10 +7,13 @@ function snapshotUsage(usage: SessionUsage): SessionUsage {
|
|
|
7
7
|
};
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
/** Add one count into a tally. `mixedCurrencies`: what's added is itself a
|
|
11
|
+
* tally in which two currencies met, as a stored entry being folded can be. */
|
|
10
12
|
function accumulateUsage(
|
|
11
13
|
target: SessionUsage,
|
|
12
14
|
tokens: { inputTokens: number; outputTokens: number; cacheCreationTokens: number; cacheReadTokens: number },
|
|
13
|
-
estimatedCost?: { total: number; currency: string }
|
|
15
|
+
estimatedCost?: { total: number; currency: string },
|
|
16
|
+
mixedCurrencies = false,
|
|
14
17
|
): void {
|
|
15
18
|
// A provider's usage can lack a count (membrane 0.5.87's Bedrock stream
|
|
16
19
|
// takes a message_delta's output count as reported); adding it would make
|
|
@@ -20,14 +23,16 @@ function accumulateUsage(
|
|
|
20
23
|
target.outputTokens += count(tokens.outputTokens);
|
|
21
24
|
target.cacheCreationTokens += count(tokens.cacheCreationTokens);
|
|
22
25
|
target.cacheReadTokens += count(tokens.cacheReadTokens);
|
|
26
|
+
// Costs in two currencies can't be summed, and a cost counted after they
|
|
27
|
+
// met is only part of this tally's, so once they meet the cost stays absent.
|
|
28
|
+
if (target.mixedCurrencies) return;
|
|
29
|
+
if (mixedCurrencies || (estimatedCost && target.estimatedCost && target.estimatedCost.currency !== estimatedCost.currency)) {
|
|
30
|
+
target.estimatedCost = undefined;
|
|
31
|
+
target.mixedCurrencies = true;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
23
34
|
if (estimatedCost) {
|
|
24
|
-
|
|
25
|
-
target.estimatedCost = { total: 0, currency: estimatedCost.currency };
|
|
26
|
-
} else if (target.estimatedCost.currency !== estimatedCost.currency) {
|
|
27
|
-
// Mixed currencies — drop cost tracking rather than produce garbage
|
|
28
|
-
target.estimatedCost = undefined;
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
35
|
+
target.estimatedCost ??= { total: 0, currency: estimatedCost.currency };
|
|
31
36
|
target.estimatedCost.total += estimatedCost.total;
|
|
32
37
|
}
|
|
33
38
|
}
|
|
@@ -47,18 +52,35 @@ function parseUsage(raw: unknown): SessionUsage | null {
|
|
|
47
52
|
outputTokens,
|
|
48
53
|
cacheCreationTokens: typeof o.cacheCreationTokens === 'number' ? o.cacheCreationTokens : 0,
|
|
49
54
|
cacheReadTokens: typeof o.cacheReadTokens === 'number' ? o.cacheReadTokens : 0,
|
|
50
|
-
|
|
51
|
-
? {
|
|
52
|
-
:
|
|
55
|
+
...(o.mixedCurrencies === true
|
|
56
|
+
? { mixedCurrencies: true as const }
|
|
57
|
+
: {
|
|
58
|
+
estimatedCost: o.estimatedCost && typeof o.estimatedCost === 'object'
|
|
59
|
+
? { total: (o.estimatedCost as any).total, currency: (o.estimatedCost as any).currency }
|
|
60
|
+
: undefined,
|
|
61
|
+
}),
|
|
53
62
|
};
|
|
54
63
|
}
|
|
55
64
|
|
|
56
65
|
export interface PersistedUsageState {
|
|
57
66
|
totals: SessionUsage;
|
|
58
|
-
byAgent: Array<{ agentName: string; usage: SessionUsage; inferenceCount: number }>;
|
|
67
|
+
byAgent: Array<{ agentName: string; usage: SessionUsage; inferenceCount: number; ephemeral?: true }>;
|
|
59
68
|
inferenceCount: number;
|
|
60
69
|
}
|
|
61
70
|
|
|
71
|
+
/** The name the entry for every ephemeral agent's usage together goes by. */
|
|
72
|
+
export const EPHEMERAL_USAGE_NAME = 'ephemeral agents';
|
|
73
|
+
|
|
74
|
+
type Tally = { usage: SessionUsage; inferenceCount: number };
|
|
75
|
+
|
|
76
|
+
const emptyUsage = (): SessionUsage => ({ inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0 });
|
|
77
|
+
|
|
78
|
+
/** Add one tally's stored usage and inference count into another. */
|
|
79
|
+
function addTally(target: Tally, usage: SessionUsage, inferenceCount: number): void {
|
|
80
|
+
accumulateUsage(target.usage, usage, usage.estimatedCost, usage.mixedCurrencies === true);
|
|
81
|
+
target.inferenceCount += inferenceCount;
|
|
82
|
+
}
|
|
83
|
+
|
|
62
84
|
/** What keeps a stored usage record from restoring, or undefined when it
|
|
63
85
|
* restores: it must be an object whose totals are token counts and whose
|
|
64
86
|
* byAgent, if it has one, is a list. Its per-agent entries are checked one
|
|
@@ -72,22 +94,30 @@ export function persistedUsageProblem(value: unknown): 'not a record' | 'totals'
|
|
|
72
94
|
}
|
|
73
95
|
|
|
74
96
|
export class UsageTracker {
|
|
75
|
-
private totals: SessionUsage =
|
|
76
|
-
private byAgent: Map<string,
|
|
97
|
+
private totals: SessionUsage = emptyUsage();
|
|
98
|
+
private byAgent: Map<string, Tally> = new Map();
|
|
99
|
+
/** Every ephemeral agent's usage together, kept apart from byAgent so an
|
|
100
|
+
* agent named EPHEMERAL_USAGE_NAME has an entry of its own. */
|
|
101
|
+
private ephemeral: Tally | undefined;
|
|
77
102
|
private inferenceCount = 0;
|
|
78
103
|
private emitTrace: (event: UsageUpdatedEvent) => void;
|
|
79
104
|
|
|
105
|
+
/** `wasEphemeral` names the stored unmarked entries that belong in the
|
|
106
|
+
* shared entry, such as an ephemeral agent's own from before ephemeral
|
|
107
|
+
* agents shared one: each restores into the shared entry instead. A stored
|
|
108
|
+
* entry marked ephemeral restores into it whatever its name. */
|
|
80
109
|
constructor(opts: {
|
|
81
110
|
emitTrace: (event: UsageUpdatedEvent) => void;
|
|
82
111
|
restored?: PersistedUsageState;
|
|
112
|
+
wasEphemeral?: (agentName: string) => boolean;
|
|
83
113
|
}) {
|
|
84
114
|
this.emitTrace = opts.emitTrace;
|
|
85
115
|
if (opts.restored) {
|
|
86
|
-
this.restoreFrom(opts.restored);
|
|
116
|
+
this.restoreFrom(opts.restored, opts.wasEphemeral ?? (() => false));
|
|
87
117
|
}
|
|
88
118
|
}
|
|
89
119
|
|
|
90
|
-
private restoreFrom(state: PersistedUsageState): void {
|
|
120
|
+
private restoreFrom(state: PersistedUsageState, wasEphemeral: (agentName: string) => boolean): void {
|
|
91
121
|
const totals = parseUsage(state.totals);
|
|
92
122
|
if (!totals) return;
|
|
93
123
|
this.totals = totals;
|
|
@@ -95,36 +125,43 @@ export class UsageTracker {
|
|
|
95
125
|
if (Array.isArray(state.byAgent)) {
|
|
96
126
|
for (const item of state.byAgent as unknown[]) {
|
|
97
127
|
if (!item || typeof item !== 'object') continue;
|
|
98
|
-
const entry = item as { agentName?: unknown; usage?: unknown; inferenceCount?: unknown };
|
|
128
|
+
const entry = item as { agentName?: unknown; usage?: unknown; inferenceCount?: unknown; ephemeral?: unknown };
|
|
99
129
|
const usage = parseUsage(entry.usage);
|
|
100
130
|
if (usage && typeof entry.agentName === 'string') {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
131
|
+
const inferenceCount = typeof entry.inferenceCount === 'number' ? entry.inferenceCount : 0;
|
|
132
|
+
if (entry.ephemeral === true || wasEphemeral(entry.agentName)) {
|
|
133
|
+
this.ephemeral ??= { usage: emptyUsage(), inferenceCount: 0 };
|
|
134
|
+
addTally(this.ephemeral, usage, inferenceCount);
|
|
135
|
+
} else {
|
|
136
|
+
this.byAgent.set(entry.agentName, { usage, inferenceCount });
|
|
137
|
+
}
|
|
105
138
|
}
|
|
106
139
|
}
|
|
107
140
|
}
|
|
141
|
+
// The totals count every entry's inferences, so stored entries whose
|
|
142
|
+
// costs are in two currencies, or one where two met, mean two met in the
|
|
143
|
+
// totals too. A record written before mixedCurrencies shows it only so.
|
|
144
|
+
const tallies = [...this.byAgent.values(), ...(this.ephemeral ? [this.ephemeral] : [])].map((tally) => tally.usage);
|
|
145
|
+
const currencies = new Set(tallies.flatMap((usage) => (usage.estimatedCost ? [usage.estimatedCost.currency] : [])));
|
|
146
|
+
if (this.totals.estimatedCost) currencies.add(this.totals.estimatedCost.currency);
|
|
147
|
+
if (!this.totals.mixedCurrencies && (currencies.size > 1 || tallies.some((usage) => usage.mixedCurrencies))) {
|
|
148
|
+
this.totals.estimatedCost = undefined;
|
|
149
|
+
this.totals.mixedCurrencies = true;
|
|
150
|
+
}
|
|
108
151
|
}
|
|
109
152
|
|
|
110
153
|
toJSON(): PersistedUsageState {
|
|
111
|
-
return
|
|
112
|
-
totals: snapshotUsage(this.totals),
|
|
113
|
-
byAgent: [...this.byAgent.entries()].map(([name, data]) => ({
|
|
114
|
-
agentName: name,
|
|
115
|
-
usage: snapshotUsage(data.usage),
|
|
116
|
-
inferenceCount: data.inferenceCount,
|
|
117
|
-
})),
|
|
118
|
-
inferenceCount: this.inferenceCount,
|
|
119
|
-
};
|
|
154
|
+
return this.getSnapshot();
|
|
120
155
|
}
|
|
121
156
|
|
|
157
|
+
/** `ephemeral`: the agent is an ephemeral one, whose usage counts in the
|
|
158
|
+
* shared entry; the trace still names the agent. */
|
|
122
159
|
onInferenceCompleted(agentName: string, usage: {
|
|
123
160
|
inputTokens: number;
|
|
124
161
|
outputTokens: number;
|
|
125
162
|
cacheCreationTokens?: number;
|
|
126
163
|
cacheReadTokens?: number;
|
|
127
|
-
}, estimatedCost?: { total: number; currency: string }): void {
|
|
164
|
+
}, estimatedCost?: { total: number; currency: string }, ephemeral = false): void {
|
|
128
165
|
const tokens = {
|
|
129
166
|
inputTokens: usage.inputTokens,
|
|
130
167
|
outputTokens: usage.outputTokens,
|
|
@@ -135,10 +172,11 @@ export class UsageTracker {
|
|
|
135
172
|
accumulateUsage(this.totals, tokens, estimatedCost);
|
|
136
173
|
this.inferenceCount++;
|
|
137
174
|
|
|
138
|
-
let agent = this.byAgent.get(agentName);
|
|
175
|
+
let agent = ephemeral ? this.ephemeral : this.byAgent.get(agentName);
|
|
139
176
|
if (!agent) {
|
|
140
|
-
agent = { usage:
|
|
141
|
-
this.
|
|
177
|
+
agent = { usage: emptyUsage(), inferenceCount: 0 };
|
|
178
|
+
if (ephemeral) this.ephemeral = agent;
|
|
179
|
+
else this.byAgent.set(agentName, agent);
|
|
142
180
|
}
|
|
143
181
|
accumulateUsage(agent.usage, tokens, estimatedCost);
|
|
144
182
|
agent.inferenceCount++;
|
|
@@ -152,14 +190,19 @@ export class UsageTracker {
|
|
|
152
190
|
}
|
|
153
191
|
|
|
154
192
|
getSnapshot(): SessionUsageSnapshot {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
193
|
+
const byAgent: SessionUsageSnapshot['byAgent'] = [...this.byAgent.entries()].map(([name, data]) => ({
|
|
194
|
+
agentName: name,
|
|
195
|
+
usage: snapshotUsage(data.usage),
|
|
196
|
+
inferenceCount: data.inferenceCount,
|
|
197
|
+
}));
|
|
198
|
+
if (this.ephemeral) {
|
|
199
|
+
byAgent.push({
|
|
200
|
+
agentName: EPHEMERAL_USAGE_NAME,
|
|
201
|
+
usage: snapshotUsage(this.ephemeral.usage),
|
|
202
|
+
inferenceCount: this.ephemeral.inferenceCount,
|
|
203
|
+
ephemeral: true,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
return { totals: snapshotUsage(this.totals), byAgent, inferenceCount: this.inferenceCount };
|
|
164
207
|
}
|
|
165
208
|
}
|