@windagency/valora 2.1.4 → 2.2.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.
Files changed (131) hide show
  1. package/README.md +2 -2
  2. package/data/commands/create-backlog.md +4 -0
  3. package/data/commands/create-prd.md +3 -0
  4. package/data/commands/generate-docs.md +4 -0
  5. package/data/commands/plan-architecture.md +1 -0
  6. package/data/commands/plan-implementation.md +2 -0
  7. package/data/commands/refine-specs.md +2 -0
  8. package/data/commands/refine-task.md +2 -0
  9. package/data/commands/review-code.md +1 -0
  10. package/data/commands/review-functional.md +1 -0
  11. package/data/commands/review-plan.md +5 -0
  12. package/dist/batch/batch-eligibility.d.ts +17 -0
  13. package/dist/batch/batch-eligibility.d.ts.map +1 -0
  14. package/dist/batch/batch-eligibility.js +22 -0
  15. package/dist/batch/batch-eligibility.js.map +1 -0
  16. package/dist/batch/batch-orchestrator.d.ts +35 -0
  17. package/dist/batch/batch-orchestrator.d.ts.map +1 -0
  18. package/dist/batch/batch-orchestrator.js +121 -0
  19. package/dist/batch/batch-orchestrator.js.map +1 -0
  20. package/dist/batch/batch-provider.interface.d.ts +14 -0
  21. package/dist/batch/batch-provider.interface.d.ts.map +1 -0
  22. package/dist/batch/batch-provider.interface.js +9 -0
  23. package/dist/batch/batch-provider.interface.js.map +1 -0
  24. package/dist/batch/batch-session.d.ts +29 -0
  25. package/dist/batch/batch-session.d.ts.map +1 -0
  26. package/dist/batch/batch-session.js +91 -0
  27. package/dist/batch/batch-session.js.map +1 -0
  28. package/dist/batch/batch.types.d.ts +48 -0
  29. package/dist/batch/batch.types.d.ts.map +1 -0
  30. package/dist/batch/batch.types.js +5 -0
  31. package/dist/batch/batch.types.js.map +1 -0
  32. package/dist/batch/providers/anthropic.batch-provider.d.ts +33 -0
  33. package/dist/batch/providers/anthropic.batch-provider.d.ts.map +1 -0
  34. package/dist/batch/providers/anthropic.batch-provider.js +106 -0
  35. package/dist/batch/providers/anthropic.batch-provider.js.map +1 -0
  36. package/dist/batch/providers/google.batch-provider.d.ts +32 -0
  37. package/dist/batch/providers/google.batch-provider.d.ts.map +1 -0
  38. package/dist/batch/providers/google.batch-provider.js +41 -0
  39. package/dist/batch/providers/google.batch-provider.js.map +1 -0
  40. package/dist/batch/providers/openai.batch-provider.d.ts +32 -0
  41. package/dist/batch/providers/openai.batch-provider.d.ts.map +1 -0
  42. package/dist/batch/providers/openai.batch-provider.js +151 -0
  43. package/dist/batch/providers/openai.batch-provider.js.map +1 -0
  44. package/dist/cli/command-executor.d.ts +5 -0
  45. package/dist/cli/command-executor.d.ts.map +1 -1
  46. package/dist/cli/command-executor.js +63 -11
  47. package/dist/cli/command-executor.js.map +1 -1
  48. package/dist/cli/commands/batch.command.d.ts +14 -0
  49. package/dist/cli/commands/batch.command.d.ts.map +1 -0
  50. package/dist/cli/commands/batch.command.js +174 -0
  51. package/dist/cli/commands/batch.command.js.map +1 -0
  52. package/dist/cli/commands/monitoring.d.ts.map +1 -1
  53. package/dist/cli/commands/monitoring.js +119 -0
  54. package/dist/cli/commands/monitoring.js.map +1 -1
  55. package/dist/cli/flags.d.ts +1 -0
  56. package/dist/cli/flags.d.ts.map +1 -1
  57. package/dist/cli/flags.js +1 -0
  58. package/dist/cli/flags.js.map +1 -1
  59. package/dist/cli/index.js +4 -0
  60. package/dist/cli/index.js.map +1 -1
  61. package/dist/cli/result-presenter.d.ts +6 -2
  62. package/dist/cli/result-presenter.d.ts.map +1 -1
  63. package/dist/cli/result-presenter.js +22 -12
  64. package/dist/cli/result-presenter.js.map +1 -1
  65. package/dist/cli/types/cli-options.types.d.ts +1 -0
  66. package/dist/cli/types/cli-options.types.d.ts.map +1 -1
  67. package/dist/config/schema.d.ts +87 -12
  68. package/dist/config/schema.d.ts.map +1 -1
  69. package/dist/config/schema.js +1 -0
  70. package/dist/config/schema.js.map +1 -1
  71. package/dist/executor/stage-executor.d.ts +11 -0
  72. package/dist/executor/stage-executor.d.ts.map +1 -1
  73. package/dist/executor/stage-executor.js +89 -0
  74. package/dist/executor/stage-executor.js.map +1 -1
  75. package/dist/executor/variable-resolution.service.d.ts.map +1 -1
  76. package/dist/executor/variable-resolution.service.js +1 -2
  77. package/dist/executor/variable-resolution.service.js.map +1 -1
  78. package/dist/executor/variables.d.ts +1 -5
  79. package/dist/executor/variables.d.ts.map +1 -1
  80. package/dist/executor/variables.js +0 -21
  81. package/dist/executor/variables.js.map +1 -1
  82. package/dist/llm/providers/anthropic.provider.d.ts +30 -1
  83. package/dist/llm/providers/anthropic.provider.d.ts.map +1 -1
  84. package/dist/llm/providers/anthropic.provider.js +163 -6
  85. package/dist/llm/providers/anthropic.provider.js.map +1 -1
  86. package/dist/llm/providers/google.provider.d.ts +9 -0
  87. package/dist/llm/providers/google.provider.d.ts.map +1 -1
  88. package/dist/llm/providers/google.provider.js +25 -10
  89. package/dist/llm/providers/google.provider.js.map +1 -1
  90. package/dist/llm/providers/openai.provider.d.ts +17 -1
  91. package/dist/llm/providers/openai.provider.d.ts.map +1 -1
  92. package/dist/llm/providers/openai.provider.js +93 -25
  93. package/dist/llm/providers/openai.provider.js.map +1 -1
  94. package/dist/output/processing-feedback.d.ts +14 -0
  95. package/dist/output/processing-feedback.d.ts.map +1 -1
  96. package/dist/output/processing-feedback.js +46 -7
  97. package/dist/output/processing-feedback.js.map +1 -1
  98. package/dist/package.json +3 -3
  99. package/dist/session/context.d.ts +2 -0
  100. package/dist/session/context.d.ts.map +1 -1
  101. package/dist/session/context.js +43 -13
  102. package/dist/session/context.js.map +1 -1
  103. package/dist/tsconfig.json +1 -0
  104. package/dist/types/command.types.d.ts +2 -0
  105. package/dist/types/command.types.d.ts.map +1 -1
  106. package/dist/types/llm.types.d.ts +4 -0
  107. package/dist/types/llm.types.d.ts.map +1 -1
  108. package/dist/ui/dashboard/detail-panels/spending-panel.d.ts +9 -0
  109. package/dist/ui/dashboard/detail-panels/spending-panel.d.ts.map +1 -0
  110. package/dist/ui/dashboard/detail-panels/spending-panel.js +28 -0
  111. package/dist/ui/dashboard/detail-panels/spending-panel.js.map +1 -0
  112. package/dist/ui/dashboard/hooks/use-navigation.js +1 -1
  113. package/dist/ui/dashboard/hooks/use-navigation.js.map +1 -1
  114. package/dist/ui/dashboard/index.d.ts +1 -0
  115. package/dist/ui/dashboard/index.d.ts.map +1 -1
  116. package/dist/ui/dashboard/index.js +1 -0
  117. package/dist/ui/dashboard/index.js.map +1 -1
  118. package/dist/ui/dashboard/types.d.ts +1 -1
  119. package/dist/ui/dashboard/types.d.ts.map +1 -1
  120. package/dist/ui/dashboard/views/session-details-view.d.ts.map +1 -1
  121. package/dist/ui/dashboard/views/session-details-view.js +5 -1
  122. package/dist/ui/dashboard/views/session-details-view.js.map +1 -1
  123. package/dist/utils/spending-tracker.d.ts +64 -0
  124. package/dist/utils/spending-tracker.d.ts.map +1 -0
  125. package/dist/utils/spending-tracker.js +107 -0
  126. package/dist/utils/spending-tracker.js.map +1 -0
  127. package/dist/utils/token-estimator.d.ts +31 -5
  128. package/dist/utils/token-estimator.d.ts.map +1 -1
  129. package/dist/utils/token-estimator.js +42 -20
  130. package/dist/utils/token-estimator.js.map +1 -1
  131. package/package.json +3 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.types.d.ts","sourceRoot":"","sources":["../../src/batch/batch.types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEjF,MAAM,WAAW,YAAY;IAC5B,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,OAAO,EAAE,oBAAoB,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IAC3B,yBAAyB;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,yBAAyB;IACzB,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,YAAY,GAAG,QAAQ,CAAC;AAE1G,MAAM,WAAW,eAAe;IAC/B,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,oBAAoB;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,gBAAgB,CAAC;IACzB,eAAe;IACf,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,eAAe,CAAC;CAC5B"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Batch processing type definitions
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=batch.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.types.js","sourceRoot":"","sources":["../../src/batch/batch.types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Anthropic Message Batches helper functions
3
+ *
4
+ * Used by AnthropicProvider to implement BatchableProvider.
5
+ * Handles request formatting, status mapping, and response parsing
6
+ * specific to the Anthropic batch API.
7
+ */
8
+ import type Anthropic from '@anthropic-ai/sdk';
9
+ import type { BatchResult, BatchStatusInfo, BatchStatusValue, BatchSubmission } from '../batch.types.js';
10
+ /**
11
+ * Maps Anthropic processing_status → BatchStatusValue
12
+ */
13
+ export declare function mapAnthropicStatus(status: string): BatchStatusValue;
14
+ /**
15
+ * Submit requests to the Anthropic Message Batches API
16
+ */
17
+ export declare function submitAnthropicBatch(client: Anthropic, requests: Array<{
18
+ customId: string;
19
+ params: Anthropic.MessageCreateParamsNonStreaming;
20
+ }>, providerName: string, localId: string): Promise<BatchSubmission>;
21
+ /**
22
+ * Retrieve batch status from Anthropic
23
+ */
24
+ export declare function getAnthropicBatchStatus(client: Anthropic, batchId: string): Promise<BatchStatusInfo>;
25
+ /**
26
+ * Retrieve completed batch results from Anthropic
27
+ */
28
+ export declare function getAnthropicBatchResults(client: Anthropic, batchId: string): Promise<BatchResult[]>;
29
+ /**
30
+ * Cancel a batch job
31
+ */
32
+ export declare function cancelAnthropicBatch(client: Anthropic, batchId: string): Promise<void>;
33
+ //# sourceMappingURL=anthropic.batch-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.batch-provider.d.ts","sourceRoot":"","sources":["../../../src/batch/providers/anthropic.batch-provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,SAAS,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIzG;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAWnE;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACzC,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,KAAK,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,SAAS,CAAC,+BAA+B,CAAC;CAClD,CAAC,EACF,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,eAAe,CAAC,CAgB1B;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAY1G;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CA0CzG;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5F"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Anthropic Message Batches helper functions
3
+ *
4
+ * Used by AnthropicProvider to implement BatchableProvider.
5
+ * Handles request formatting, status mapping, and response parsing
6
+ * specific to the Anthropic batch API.
7
+ */
8
+ /**
9
+ * Maps Anthropic processing_status → BatchStatusValue
10
+ */
11
+ export function mapAnthropicStatus(status) {
12
+ switch (status) {
13
+ case 'canceling':
14
+ return 'cancelled';
15
+ case 'ended':
16
+ return 'completed';
17
+ case 'in_progress':
18
+ return 'processing';
19
+ default:
20
+ return 'queued';
21
+ }
22
+ }
23
+ /**
24
+ * Submit requests to the Anthropic Message Batches API
25
+ */
26
+ export async function submitAnthropicBatch(client, requests, providerName, localId) {
27
+ const batchRequests = requests.map((r) => ({
28
+ custom_id: r.customId,
29
+ params: r.params
30
+ }));
31
+ const batch = await client.beta.messages.batches.create({ requests: batchRequests });
32
+ return {
33
+ batchId: batch.id,
34
+ localId,
35
+ provider: providerName,
36
+ requestCount: requests.length,
37
+ status: mapAnthropicStatus(batch.processing_status),
38
+ submittedAt: new Date().toISOString()
39
+ };
40
+ }
41
+ /**
42
+ * Retrieve batch status from Anthropic
43
+ */
44
+ export async function getAnthropicBatchStatus(client, batchId) {
45
+ const batch = await client.beta.messages.batches.retrieve(batchId);
46
+ const counts = batch.request_counts;
47
+ const totalCount = counts.processing + counts.succeeded + counts.errored + counts.canceled + counts.expired;
48
+ return {
49
+ batchId: batch.id,
50
+ completedCount: counts.succeeded,
51
+ failedCount: counts.errored,
52
+ status: mapAnthropicStatus(batch.processing_status),
53
+ totalCount
54
+ };
55
+ }
56
+ /**
57
+ * Retrieve completed batch results from Anthropic
58
+ */
59
+ export async function getAnthropicBatchResults(client, batchId) {
60
+ const results = [];
61
+ for await (const item of await client.beta.messages.batches.results(batchId)) {
62
+ if (item.result.type === 'succeeded') {
63
+ const message = item.result.message;
64
+ const usage = {
65
+ completion_tokens: message.usage.output_tokens,
66
+ prompt_tokens: message.usage.input_tokens,
67
+ total_tokens: message.usage.input_tokens + message.usage.output_tokens
68
+ };
69
+ const raw = message.usage;
70
+ if (typeof raw['cache_creation_input_tokens'] === 'number') {
71
+ usage.cache_creation_input_tokens = raw['cache_creation_input_tokens'];
72
+ }
73
+ if (typeof raw['cache_read_input_tokens'] === 'number') {
74
+ usage.cache_read_input_tokens = raw['cache_read_input_tokens'];
75
+ }
76
+ usage.batch_discount_applied = true;
77
+ const completion = {
78
+ content: message.content
79
+ .filter((b) => b.type === 'text')
80
+ .map((b) => b.text)
81
+ .join(''),
82
+ finish_reason: message.stop_reason ?? undefined,
83
+ role: 'assistant',
84
+ usage
85
+ };
86
+ results.push({ id: item.custom_id, result: completion });
87
+ }
88
+ else if (item.result.type === 'errored') {
89
+ results.push({
90
+ error: item.result.error?.type ?? 'unknown error',
91
+ id: item.custom_id
92
+ });
93
+ }
94
+ else {
95
+ results.push({ error: `unexpected result type: ${item.result.type}`, id: item.custom_id });
96
+ }
97
+ }
98
+ return results;
99
+ }
100
+ /**
101
+ * Cancel a batch job
102
+ */
103
+ export async function cancelAnthropicBatch(client, batchId) {
104
+ await client.beta.messages.batches.cancel(batchId);
105
+ }
106
+ //# sourceMappingURL=anthropic.batch-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.batch-provider.js","sourceRoot":"","sources":["../../../src/batch/providers/anthropic.batch-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Google Vertex AI Batch Prediction helper stubs
3
+ *
4
+ * Full implementation requires `@google-cloud/aiplatform` and a GCS bucket.
5
+ * Install `@google-cloud/aiplatform` and set `vertex_project` in provider config
6
+ * to enable. Until then, `supportsBatch()` returns false and this module is a
7
+ * no-op placeholder.
8
+ */
9
+ import type { BatchResult, BatchStatusInfo, BatchSubmission } from '../batch.types.js';
10
+ /**
11
+ * Check whether Vertex AI batch is configured.
12
+ * Returns true only when a project ID is provided via config.
13
+ */
14
+ export declare function isVertexBatchConfigured(config: Record<string, unknown>): boolean;
15
+ /**
16
+ * Stub: submit a Vertex AI batch job.
17
+ * Requires `@google-cloud/aiplatform` — throws until implemented.
18
+ */
19
+ export declare function submitVertexBatch(_config: Record<string, unknown>, _requests: unknown[], _providerName: string, _localId: string): Promise<BatchSubmission>;
20
+ /**
21
+ * Stub: get Vertex AI batch status.
22
+ */
23
+ export declare function getVertexBatchStatus(_config: Record<string, unknown>, _batchId: string): Promise<BatchStatusInfo>;
24
+ /**
25
+ * Stub: get Vertex AI batch results.
26
+ */
27
+ export declare function getVertexBatchResults(_config: Record<string, unknown>, _batchId: string): Promise<BatchResult[]>;
28
+ /**
29
+ * Stub: cancel a Vertex AI batch job.
30
+ */
31
+ export declare function cancelVertexBatch(_config: Record<string, unknown>, _batchId: string): Promise<void>;
32
+ //# sourceMappingURL=google.batch-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google.batch-provider.d.ts","sourceRoot":"","sources":["../../../src/batch/providers/google.batch-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEvF;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAEhF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,SAAS,EAAE,OAAO,EAAE,EACpB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACd,OAAO,CAAC,eAAe,CAAC,CAM1B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAEjH;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAEhH;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEnG"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Google Vertex AI Batch Prediction helper stubs
3
+ *
4
+ * Full implementation requires `@google-cloud/aiplatform` and a GCS bucket.
5
+ * Install `@google-cloud/aiplatform` and set `vertex_project` in provider config
6
+ * to enable. Until then, `supportsBatch()` returns false and this module is a
7
+ * no-op placeholder.
8
+ */
9
+ /**
10
+ * Check whether Vertex AI batch is configured.
11
+ * Returns true only when a project ID is provided via config.
12
+ */
13
+ export function isVertexBatchConfigured(config) {
14
+ return typeof config['vertex_project'] === 'string' && config['vertex_project'].length > 0;
15
+ }
16
+ /**
17
+ * Stub: submit a Vertex AI batch job.
18
+ * Requires `@google-cloud/aiplatform` — throws until implemented.
19
+ */
20
+ export function submitVertexBatch(_config, _requests, _providerName, _localId) {
21
+ return Promise.reject(new Error('Google Vertex AI batch is not yet implemented. Install @google-cloud/aiplatform and configure vertex_project to enable.'));
22
+ }
23
+ /**
24
+ * Stub: get Vertex AI batch status.
25
+ */
26
+ export function getVertexBatchStatus(_config, _batchId) {
27
+ return Promise.reject(new Error('Google Vertex AI batch is not yet implemented.'));
28
+ }
29
+ /**
30
+ * Stub: get Vertex AI batch results.
31
+ */
32
+ export function getVertexBatchResults(_config, _batchId) {
33
+ return Promise.reject(new Error('Google Vertex AI batch is not yet implemented.'));
34
+ }
35
+ /**
36
+ * Stub: cancel a Vertex AI batch job.
37
+ */
38
+ export function cancelVertexBatch(_config, _batchId) {
39
+ return Promise.reject(new Error('Google Vertex AI batch is not yet implemented.'));
40
+ }
41
+ //# sourceMappingURL=google.batch-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google.batch-provider.js","sourceRoot":"","sources":["../../../src/batch/providers/google.batch-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAA+B;IACtE,OAAO,OAAO,MAAM,CAAC,gBAAgB,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AAC5F,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAChC,OAAgC,EAChC,SAAoB,EACpB,aAAqB,EACrB,QAAgB;IAEhB,OAAO,OAAO,CAAC,MAAM,CACpB,IAAI,KAAK,CACR,yHAAyH,CACzH,CACD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAgC,EAAE,QAAgB;IACtF,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC,CAAC;AACpF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAgC,EAAE,QAAgB;IACvF,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC,CAAC;AACpF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAgC,EAAE,QAAgB;IACnF,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC,CAAC;AACpF,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * OpenAI Batch API helper functions
3
+ *
4
+ * Used by OpenAIProvider to implement BatchableProvider.
5
+ * Handles JSONL serialisation, file upload, and response parsing.
6
+ */
7
+ import type { BatchResult, BatchStatusInfo, BatchStatusValue, BatchSubmission } from '../batch.types.js';
8
+ import type OpenAI from 'openai';
9
+ /**
10
+ * Maps OpenAI batch status → BatchStatusValue
11
+ */
12
+ export declare function mapOpenAIStatus(status: string): BatchStatusValue;
13
+ /**
14
+ * Submit a batch to OpenAI
15
+ */
16
+ export declare function submitOpenAIBatch(client: OpenAI, requests: Array<{
17
+ customId: string;
18
+ params: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming;
19
+ }>, providerName: string, localId: string): Promise<BatchSubmission>;
20
+ /**
21
+ * Get batch status from OpenAI
22
+ */
23
+ export declare function getOpenAIBatchStatus(client: OpenAI, batchId: string): Promise<BatchStatusInfo>;
24
+ /**
25
+ * Retrieve completed batch results from OpenAI
26
+ */
27
+ export declare function getOpenAIBatchResults(client: OpenAI, batchId: string): Promise<BatchResult[]>;
28
+ /**
29
+ * Cancel an OpenAI batch job
30
+ */
31
+ export declare function cancelOpenAIBatch(client: OpenAI, batchId: string): Promise<void>;
32
+ //# sourceMappingURL=openai.batch-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.batch-provider.d.ts","sourceRoot":"","sources":["../../../src/batch/providers/openai.batch-provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzG,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAMjC;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAiBhE;AAYD;;GAEG;AACH,wBAAsB,iBAAiB,CACtC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,KAAK,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,sCAAsC,CAAC;CACvE,CAAC,EACF,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,eAAe,CAAC,CA8B1B;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAcpG;AAiED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CA0BnG;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtF"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * OpenAI Batch API helper functions
3
+ *
4
+ * Used by OpenAIProvider to implement BatchableProvider.
5
+ * Handles JSONL serialisation, file upload, and response parsing.
6
+ */
7
+ import { File } from 'buffer';
8
+ /**
9
+ * Maps OpenAI batch status → BatchStatusValue
10
+ */
11
+ export function mapOpenAIStatus(status) {
12
+ switch (status) {
13
+ case 'cancelled':
14
+ case 'cancelling':
15
+ return 'cancelled';
16
+ case 'completed':
17
+ return 'completed';
18
+ case 'expired':
19
+ return 'expired';
20
+ case 'failed':
21
+ return 'failed';
22
+ case 'finalizing':
23
+ case 'in_progress':
24
+ return 'processing';
25
+ default:
26
+ return 'queued';
27
+ }
28
+ }
29
+ /**
30
+ * Submit a batch to OpenAI
31
+ */
32
+ export async function submitOpenAIBatch(client, requests, providerName, localId) {
33
+ // Serialise requests as JSONL
34
+ const lines = requests.map((r) => ({
35
+ body: r.params,
36
+ custom_id: r.customId,
37
+ method: 'POST',
38
+ url: '/v1/chat/completions'
39
+ }));
40
+ const jsonlContent = lines.map((l) => JSON.stringify(l)).join('\n');
41
+ // Upload the JSONL file — cast as any to accommodate OpenAI SDK's Uploadable type
42
+ const file = new File([jsonlContent], 'batch.jsonl', { type: 'application/jsonl' });
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
44
+ const uploaded = await client.files.create({ file: file, purpose: 'batch' });
45
+ // Create the batch job
46
+ const batch = await client.batches.create({
47
+ completion_window: '24h',
48
+ endpoint: '/v1/chat/completions',
49
+ input_file_id: uploaded.id
50
+ });
51
+ return {
52
+ batchId: batch.id,
53
+ localId,
54
+ provider: providerName,
55
+ requestCount: requests.length,
56
+ status: mapOpenAIStatus(batch.status),
57
+ submittedAt: new Date().toISOString()
58
+ };
59
+ }
60
+ /**
61
+ * Get batch status from OpenAI
62
+ */
63
+ export async function getOpenAIBatchStatus(client, batchId) {
64
+ const batch = await client.batches.retrieve(batchId);
65
+ const counts = batch.request_counts;
66
+ const totalCount = counts?.total ?? 0;
67
+ const completedCount = counts?.completed ?? 0;
68
+ const failedCount = counts?.failed ?? 0;
69
+ return {
70
+ batchId: batch.id,
71
+ completedCount,
72
+ failedCount,
73
+ status: mapOpenAIStatus(batch.status),
74
+ totalCount
75
+ };
76
+ }
77
+ /**
78
+ * Build normalised LLMUsage from an OpenAI CompletionUsage, including cache fields.
79
+ */
80
+ function buildOpenAIUsage(raw) {
81
+ const usage = {
82
+ batch_discount_applied: true,
83
+ completion_tokens: raw.completion_tokens,
84
+ prompt_tokens: raw.prompt_tokens,
85
+ total_tokens: raw.total_tokens
86
+ };
87
+ const details = raw.prompt_tokens_details;
88
+ const cachedTokens = typeof details?.['cached_tokens'] === 'number' ? details['cached_tokens'] : 0;
89
+ if (cachedTokens > 0) {
90
+ usage.cache_read_input_tokens = cachedTokens;
91
+ }
92
+ return usage;
93
+ }
94
+ /**
95
+ * Build an LLMCompletionResult from a single OpenAI chat choice.
96
+ */
97
+ function buildOpenAICompletion(choice, usage) {
98
+ return {
99
+ content: choice.message.content ?? '',
100
+ finish_reason: choice.finish_reason,
101
+ role: 'assistant',
102
+ tool_calls: choice.message.tool_calls?.map((tc) => ({
103
+ arguments: JSON.parse(tc.function.arguments),
104
+ id: tc.id,
105
+ name: tc.function.name
106
+ })),
107
+ usage
108
+ };
109
+ }
110
+ /**
111
+ * Parse a single JSONL line from an OpenAI batch output file into a BatchResult.
112
+ */
113
+ function parseOpenAIBatchLine(parsed) {
114
+ if (parsed.error) {
115
+ return { error: `${parsed.error.code}: ${parsed.error.message}`, id: parsed.custom_id };
116
+ }
117
+ const body = parsed.response?.body;
118
+ const choice = body?.choices?.[0];
119
+ if (!choice) {
120
+ return { error: 'no choices in response', id: parsed.custom_id };
121
+ }
122
+ const usage = body.usage ? buildOpenAIUsage(body.usage) : undefined;
123
+ return { id: parsed.custom_id, result: buildOpenAICompletion(choice, usage) };
124
+ }
125
+ /**
126
+ * Retrieve completed batch results from OpenAI
127
+ */
128
+ export async function getOpenAIBatchResults(client, batchId) {
129
+ const batch = await client.batches.retrieve(batchId);
130
+ if (!batch.output_file_id) {
131
+ throw new Error(`Batch ${batchId} has no output file — status: ${batch.status}`);
132
+ }
133
+ const fileContent = await client.files.content(batch.output_file_id);
134
+ const rawText = await fileContent.text();
135
+ const results = [];
136
+ for (const line of rawText.split('\n')) {
137
+ const trimmed = line.trim();
138
+ if (!trimmed)
139
+ continue;
140
+ const parsed = JSON.parse(trimmed);
141
+ results.push(parseOpenAIBatchLine(parsed));
142
+ }
143
+ return results;
144
+ }
145
+ /**
146
+ * Cancel an OpenAI batch job
147
+ */
148
+ export async function cancelOpenAIBatch(client, batchId) {
149
+ await client.batches.cancel(batchId);
150
+ }
151
+ //# sourceMappingURL=openai.batch-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.batch-provider.js","sourceRoot":"","sources":["../../../src/batch/providers/openai.batch-provider.ts"],"names":[],"mappings":"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"}
@@ -103,6 +103,11 @@ export declare class CommandExecutor {
103
103
  * Calculate detailed token usage breakdown from command result
104
104
  */
105
105
  private calculateTokenUsage;
106
+ /**
107
+ * Compute cost from a token breakdown and append a record to the spending ledger.
108
+ * Returns the cost result for passing through to the result presenter.
109
+ */
110
+ private computeAndRecordSpending;
106
111
  /**
107
112
  * List available commands
108
113
  */
@@ -1 +1 @@
1
- {"version":3,"file":"command-executor.d.ts","sourceRoot":"","sources":["../../src/cli/command-executor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"command-executor.d.ts","sourceRoot":"","sources":["../../src/cli/command-executor.ts"],"names":[],"mappings":"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"}
@@ -18,6 +18,8 @@ import { SessionStore } from '../session/store.js';
18
18
  import { getPromptAdapter } from '../ui/prompt-adapter.interface.js';
19
19
  import { formatErrorMessage } from '../utils/error-utils.js';
20
20
  import { incrementCounter, timeAsync } from '../utils/metrics-collector.js';
21
+ import { getSpendingTracker } from '../utils/spending-tracker.js';
22
+ import { calculateActualCost } from '../utils/token-estimator.js';
21
23
  import { CommandErrorHandler } from './command-error-handler.js';
22
24
  import { CommandResolver } from './command-resolver.js';
23
25
  import { CommandValidator } from './command-validator.js';
@@ -220,6 +222,9 @@ export class CommandExecutor {
220
222
  this.updateSessionState(commandName, options, result, duration, tokenBreakdown, finalSessionManager);
221
223
  // Step 5.5: Restore stashed changes if stash protection was used
222
224
  await this.restoreStashProtection(stashProtection);
225
+ // Compute cost from token breakdown and record to spending ledger
226
+ const model = resolvedCommand.command.model;
227
+ const costResult = this.computeAndRecordSpending(commandName, options, tokenBreakdown, model, duration, result);
223
228
  // Step 6: Handle result (success or failure)
224
229
  if (result.success) {
225
230
  const isDryRun = options.flags['dryRun'] === true || options.flags['dry-run'] === true;
@@ -227,7 +232,9 @@ export class CommandExecutor {
227
232
  const taskId = typeof taskIdFlag === 'string' ? taskIdFlag : undefined;
228
233
  const documentOptions = { ...(options.documentOutput ?? { enabled: true }), taskId };
229
234
  return await this.handleSuccessfulResult({
235
+ cacheSavingsUsd: costResult.cacheSavings,
230
236
  commandName,
237
+ costUsd: costResult.totalCost,
231
238
  documentOptions,
232
239
  duration,
233
240
  isDryRun,
@@ -238,7 +245,7 @@ export class CommandExecutor {
238
245
  totalSessionTokens
239
246
  });
240
247
  }
241
- await this.handleFailedResult(commandName, result, duration, finalSessionManager.getSession().session_id, tokenBreakdown, totalSessionTokens);
248
+ await this.handleFailedResult(commandName, result, duration, finalSessionManager.getSession().session_id, tokenBreakdown, totalSessionTokens, costResult.totalCost, costResult.cacheSavings);
242
249
  return result;
243
250
  }
244
251
  catch (error) {
@@ -326,15 +333,61 @@ export class CommandExecutor {
326
333
  const tokenUsage = result.stages.reduce((acc, stage) => {
327
334
  const usageValue = stage.outputs?.['usage'];
328
335
  if (usageValue && isTokenUsage(usageValue)) {
336
+ const usage = usageValue;
337
+ const cacheRead = typeof usage['cache_read_input_tokens'] === 'number'
338
+ ? usage['cache_read_input_tokens']
339
+ : 0;
340
+ const cacheWrite = typeof usage['cache_creation_input_tokens'] === 'number'
341
+ ? usage['cache_creation_input_tokens']
342
+ : 0;
329
343
  return {
330
- context: acc.context + (usageValue.prompt_tokens ?? 0),
331
- generation: acc.generation + (usageValue.completion_tokens ?? 0),
332
- total: acc.total + (usageValue.total_tokens ?? 0)
344
+ cache_read: acc.cache_read + cacheRead,
345
+ cache_write: acc.cache_write + cacheWrite,
346
+ context: acc.context + (usage.prompt_tokens ?? 0),
347
+ generation: acc.generation + (usage.completion_tokens ?? 0),
348
+ total: acc.total + (usage.total_tokens ?? 0)
333
349
  };
334
350
  }
335
351
  return acc;
336
- }, { context: 0, generation: 0, total: 0 });
337
- return tokenUsage;
352
+ }, { cache_read: 0, cache_write: 0, context: 0, generation: 0, total: 0 });
353
+ // Only include cache fields if they have values
354
+ return {
355
+ ...(tokenUsage.cache_read > 0 ? { cache_read: tokenUsage.cache_read } : {}),
356
+ ...(tokenUsage.cache_write > 0 ? { cache_write: tokenUsage.cache_write } : {}),
357
+ context: tokenUsage.context,
358
+ generation: tokenUsage.generation,
359
+ total: tokenUsage.total
360
+ };
361
+ }
362
+ /**
363
+ * Compute cost from a token breakdown and append a record to the spending ledger.
364
+ * Returns the cost result for passing through to the result presenter.
365
+ */
366
+ computeAndRecordSpending(commandName, options, tokenBreakdown, model, duration, result) {
367
+ const costResult = calculateActualCost({
368
+ cache_creation_input_tokens: tokenBreakdown.cache_write ?? 0,
369
+ cache_read_input_tokens: tokenBreakdown.cache_read ?? 0,
370
+ completion_tokens: tokenBreakdown.generation,
371
+ prompt_tokens: tokenBreakdown.context,
372
+ total_tokens: tokenBreakdown.total
373
+ }, model);
374
+ getSpendingTracker().record({
375
+ batchDiscounted: options.flags['batch'] === true,
376
+ cacheReadTokens: tokenBreakdown.cache_read ?? 0,
377
+ cacheSavingsUsd: costResult.cacheSavings,
378
+ cacheWriteTokens: tokenBreakdown.cache_write ?? 0,
379
+ command: commandName,
380
+ completionTokens: tokenBreakdown.generation,
381
+ costUsd: costResult.totalCost,
382
+ durationMs: duration,
383
+ id: `${Date.now()}-${commandName}`,
384
+ model: model ?? 'unknown',
385
+ promptTokens: tokenBreakdown.context,
386
+ stage: result.stages.map((s) => s.stage).join('+'),
387
+ timestamp: new Date().toISOString(),
388
+ totalTokens: tokenBreakdown.total
389
+ });
390
+ return costResult;
338
391
  }
339
392
  /**
340
393
  * List available commands
@@ -359,7 +412,7 @@ export class CommandExecutor {
359
412
  * Handle successful command result (display and document processing)
360
413
  */
361
414
  async handleSuccessfulResult(ctx) {
362
- this.resultPresenter.displaySuccess(ctx.commandName, ctx.result.outputs, ctx.duration, ctx.sessionManager.getSession().session_id, ctx.resolvedCommand.command.agent, ctx.resolvedCommand.command.model, ctx.tokenBreakdown, ctx.totalSessionTokens);
415
+ this.resultPresenter.displaySuccess(ctx.commandName, ctx.result.outputs, ctx.duration, ctx.sessionManager.getSession().session_id, ctx.resolvedCommand.command.agent, ctx.resolvedCommand.command.model, ctx.tokenBreakdown, ctx.totalSessionTokens, ctx.costUsd, ctx.cacheSavingsUsd);
363
416
  if (ctx.isDryRun) {
364
417
  await this.sessionManager.completeSession();
365
418
  return ctx.result;
@@ -386,8 +439,8 @@ export class CommandExecutor {
386
439
  /**
387
440
  * Handle failed command result (display and lifecycle)
388
441
  */
389
- async handleFailedResult(commandName, result, duration, sessionId, tokenBreakdown, totalSessionTokens) {
390
- this.resultPresenter.displayFailure(commandName, result.error, duration, sessionId, tokenBreakdown, totalSessionTokens);
442
+ async handleFailedResult(commandName, result, duration, sessionId, tokenBreakdown, totalSessionTokens, costUsd, cacheSavingsUsd) {
443
+ this.resultPresenter.displayFailure(commandName, result.error, duration, sessionId, tokenBreakdown, totalSessionTokens, costUsd, cacheSavingsUsd);
391
444
  await this.sessionLifecycle.fail(result.error);
392
445
  }
393
446
  /**
@@ -475,8 +528,7 @@ export class CommandExecutor {
475
528
  const stageOutputs = {};
476
529
  for (const stage of result.stages) {
477
530
  if (stage.success && stage.outputs) {
478
- // Use stage.prompt as the key since it's unique within a command
479
- const stageKey = `${stage.stage}_${stage.prompt}`;
531
+ const stageKey = stage.stage;
480
532
  stageOutputs[stageKey] = stage.outputs;
481
533
  }
482
534
  }