@leanandmean/coding-agent 0.74.1-scramjet.34 → 0.74.1-scramjet.39

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.
Files changed (62) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +1 -1
  3. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  4. package/dist/core/agent-session-runtime.js +1 -0
  5. package/dist/core/agent-session-runtime.js.map +1 -1
  6. package/dist/core/agent-session-services.d.ts +1 -0
  7. package/dist/core/agent-session-services.d.ts.map +1 -1
  8. package/dist/core/agent-session-services.js +2 -0
  9. package/dist/core/agent-session-services.js.map +1 -1
  10. package/dist/core/agent-session.d.ts +15 -0
  11. package/dist/core/agent-session.d.ts.map +1 -1
  12. package/dist/core/agent-session.js +90 -0
  13. package/dist/core/agent-session.js.map +1 -1
  14. package/dist/core/extensions/index.d.ts +1 -1
  15. package/dist/core/extensions/index.d.ts.map +1 -1
  16. package/dist/core/extensions/index.js.map +1 -1
  17. package/dist/core/extensions/runner.d.ts +6 -5
  18. package/dist/core/extensions/runner.d.ts.map +1 -1
  19. package/dist/core/extensions/runner.js +48 -1
  20. package/dist/core/extensions/runner.js.map +1 -1
  21. package/dist/core/extensions/types.d.ts +16 -1
  22. package/dist/core/extensions/types.d.ts.map +1 -1
  23. package/dist/core/extensions/types.js.map +1 -1
  24. package/dist/core/output-throughput-history.d.ts +25 -0
  25. package/dist/core/output-throughput-history.d.ts.map +1 -0
  26. package/dist/core/output-throughput-history.js +240 -0
  27. package/dist/core/output-throughput-history.js.map +1 -0
  28. package/dist/core/output-throughput.d.ts +43 -0
  29. package/dist/core/output-throughput.d.ts.map +1 -0
  30. package/dist/core/output-throughput.js +161 -0
  31. package/dist/core/output-throughput.js.map +1 -0
  32. package/dist/core/sdk.d.ts +2 -0
  33. package/dist/core/sdk.d.ts.map +1 -1
  34. package/dist/core/sdk.js +11 -2
  35. package/dist/core/sdk.js.map +1 -1
  36. package/dist/core/skills.d.ts.map +1 -1
  37. package/dist/core/skills.js +6 -2
  38. package/dist/core/skills.js.map +1 -1
  39. package/dist/index.d.ts +1 -1
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js.map +1 -1
  42. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  43. package/dist/modes/interactive/components/footer.js +6 -2
  44. package/dist/modes/interactive/components/footer.js.map +1 -1
  45. package/dist/modes/interactive/components/model-selector.d.ts +3 -1
  46. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  47. package/dist/modes/interactive/components/model-selector.js +9 -3
  48. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  49. package/dist/modes/interactive/components/scoped-models-selector.d.ts +3 -1
  50. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  51. package/dist/modes/interactive/components/scoped-models-selector.js +8 -2
  52. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  53. package/dist/modes/interactive/interactive-mode.d.ts +3 -0
  54. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  55. package/dist/modes/interactive/interactive-mode.js +45 -7
  56. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  57. package/docs/extensions.md +24 -4
  58. package/docs/models.md +2 -0
  59. package/docs/session-format.md +2 -1
  60. package/docs/skills.md +2 -2
  61. package/docs/usage.md +3 -1
  62. package/package.json +8 -4
@@ -29,6 +29,8 @@ import { exportSessionToHtml } from "./export-html/index.js";
29
29
  import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
30
30
  import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
31
31
  import { emitSessionShutdownEvent, spliceContributedSections } from "./extensions/runner.js";
32
+ import { OutputThroughputTracker } from "./output-throughput.js";
33
+ import { OutputThroughputHistoryStore } from "./output-throughput-history.js";
32
34
  import { expandPromptTemplate } from "./prompt-templates.js";
33
35
  import { indexScramjetCommandStarts, restoreScramjetCommandInvocation } from "./scramjet-command-parser.js";
34
36
  import { CURRENT_SESSION_VERSION, getLatestCompactionEntry } from "./session-manager.js";
@@ -61,11 +63,16 @@ export class AgentSession {
61
63
  agent;
62
64
  sessionManager;
63
65
  settingsManager;
66
+ outputThroughputHistoryPath;
64
67
  _scopedModels;
65
68
  // Event subscription state
66
69
  _unsubscribeAgent;
67
70
  _eventListeners = [];
68
71
  _agentEventQueue = Promise.resolve();
72
+ _outputThroughputTracker = new OutputThroughputTracker();
73
+ _outputThroughputHistory;
74
+ _outputThroughputGeneration;
75
+ _latestOutputThroughputSample;
69
76
  // SCRAMJET-DIVERGENCE: harness-tool persisted-settlement state (#341). `_disposed` gates post-
70
77
  // teardown invocations; the map keys each in-flight invocation's tool-call id to its persistence
71
78
  // acknowledgement so `_processAgentEvent` can settle it after the matching tool-result is persisted.
@@ -126,6 +133,15 @@ export class AgentSession {
126
133
  this.agent = config.agent;
127
134
  this.sessionManager = config.sessionManager;
128
135
  this.settingsManager = config.settingsManager;
136
+ this.outputThroughputHistoryPath = config.outputThroughputHistoryPath;
137
+ this._outputThroughputHistory = new OutputThroughputHistoryStore(this.outputThroughputHistoryPath, (diagnostic) => {
138
+ this._extensionRunner.emitError({
139
+ extensionPath: "output-throughput-history",
140
+ event: diagnostic.operation,
141
+ error: `${diagnostic.message} (${diagnostic.path})`,
142
+ stack: diagnostic.cause instanceof Error ? diagnostic.cause.stack : undefined,
143
+ });
144
+ });
129
145
  this._scopedModels = config.scopedModels ?? [];
130
146
  this._resourceLoader = config.resourceLoader;
131
147
  this._customTools = config.customTools ?? [];
@@ -253,6 +269,7 @@ export class AgentSession {
253
269
  _lastAssistantMessage = undefined;
254
270
  /** Internal handler for agent events - shared by subscribe and reconnect */
255
271
  _handleAgentEvent = (event) => {
272
+ this._captureOutputThroughput(event);
256
273
  // Create retry promise synchronously before queueing async processing.
257
274
  // Agent.emit() calls this handler synchronously, and prompt() calls waitForRetry()
258
275
  // as soon as agent.prompt() resolves. If _retryPromise is created only inside
@@ -263,6 +280,34 @@ export class AgentSession {
263
280
  // Keep queue alive if an event handler fails
264
281
  this._agentEventQueue.catch(() => { });
265
282
  };
283
+ // SCRAMJET-DIVERGENCE: Capture provider events synchronously and reset stale throughput lifecycles (#476).
284
+ _captureOutputThroughput(event) {
285
+ if (event.type === "message_start" && event.message.role === "assistant" && event.message.origin === "provider") {
286
+ this._outputThroughputGeneration = this._outputThroughputTracker.start({
287
+ provider: event.message.provider,
288
+ model: event.message.model,
289
+ });
290
+ return;
291
+ }
292
+ const generation = this._outputThroughputGeneration;
293
+ if (generation === undefined)
294
+ return;
295
+ if (event.type === "message_update" && event.message.role === "assistant") {
296
+ this._outputThroughputTracker.observe(generation, event.assistantMessageEvent);
297
+ }
298
+ else if (event.type === "message_end" && event.message.role === "assistant") {
299
+ const sample = this._outputThroughputTracker.finalize(generation, event.message);
300
+ this._outputThroughputGeneration = undefined;
301
+ if (sample) {
302
+ this._latestOutputThroughputSample = sample;
303
+ this._outputThroughputHistory.submit(sample);
304
+ }
305
+ }
306
+ }
307
+ _resetOutputThroughput() {
308
+ this._outputThroughputTracker.reset();
309
+ this._outputThroughputGeneration = undefined;
310
+ }
266
311
  _createRetryPromiseForAgentEnd(event) {
267
312
  if (event.type !== "agent_end" || this._retryPromise) {
268
313
  return;
@@ -618,6 +663,7 @@ export class AgentSession {
618
663
  if (this._disposed)
619
664
  return;
620
665
  this._disposed = true;
666
+ this._resetOutputThroughput();
621
667
  this._extensionRunner.invalidate("This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().");
622
668
  // Reject pending persistence acknowledgements before revoking Agent-side invocations, so a caller
623
669
  // awaiting invokeHarnessTool sees rejection rather than a promise that never settles. Already-
@@ -656,6 +702,48 @@ export class AgentSession {
656
702
  get systemPrompt() {
657
703
  return flattenSystemPrompt(this.agent.state.systemPrompt);
658
704
  }
705
+ get liveOutputRate() {
706
+ const model = this.state.model;
707
+ const identity = this._outputThroughputTracker.activeIdentity;
708
+ if (!model || identity?.provider !== model.provider || identity.model !== model.id)
709
+ return undefined;
710
+ return this._outputThroughputTracker.liveRate();
711
+ }
712
+ get outputThroughputActive() {
713
+ return this._outputThroughputTracker.outputActive;
714
+ }
715
+ get outputThroughputGeneration() {
716
+ return this._outputThroughputTracker.generation;
717
+ }
718
+ get medianOutputRate() {
719
+ const model = this.state.model;
720
+ if (!model)
721
+ return undefined;
722
+ const history = this._outputThroughputHistory.snapshot();
723
+ const local = this._latestOutputThroughputSample;
724
+ if (local?.provider === model.provider &&
725
+ local.model === model.id &&
726
+ !history
727
+ .samples(model.provider, model.id)
728
+ .some((sample) => sample.provider === local.provider &&
729
+ sample.model === local.model &&
730
+ sample.responseModel === local.responseModel &&
731
+ sample.outputTokens === local.outputTokens &&
732
+ sample.durationMs === local.durationMs &&
733
+ sample.observedAt === local.observedAt)) {
734
+ history.add(local);
735
+ }
736
+ return history.median(model.provider, model.id);
737
+ }
738
+ get outputThroughputHistory() {
739
+ return this._outputThroughputHistory.snapshot();
740
+ }
741
+ refreshOutputThroughputHistory() {
742
+ return this._outputThroughputHistory.refresh();
743
+ }
744
+ flushOutputThroughputHistory() {
745
+ return this._outputThroughputHistory.flush();
746
+ }
659
747
  /** Current retry attempt (0 if not retrying) */
660
748
  get retryAttempt() {
661
749
  return this._retryAttempt;
@@ -1322,6 +1410,7 @@ export class AgentSession {
1322
1410
  */
1323
1411
  async abort() {
1324
1412
  this.abortRetry();
1413
+ this._resetOutputThroughput();
1325
1414
  this.agent.abort();
1326
1415
  await this.agent.waitForIdle();
1327
1416
  }
@@ -1509,6 +1598,7 @@ export class AgentSession {
1509
1598
  * @param customInstructions Optional instructions for the compaction summary
1510
1599
  */
1511
1600
  async compact(customInstructions) {
1601
+ this._resetOutputThroughput();
1512
1602
  this._disconnectFromAgent();
1513
1603
  await this.abort();
1514
1604
  this._compactionAbortController = new AbortController();