@harness-engineering/orchestrator 0.8.0 → 0.8.2

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/dist/index.js CHANGED
@@ -2887,6 +2887,21 @@ var path21 = __toESM(require("path"));
2887
2887
  var import_node_crypto16 = require("crypto");
2888
2888
  var import_core14 = require("@harness-engineering/core");
2889
2889
 
2890
+ // src/core/stall-detector.ts
2891
+ function detectStalledIssues(running, nowMs, stallTimeoutMs) {
2892
+ if (stallTimeoutMs <= 0) return [];
2893
+ const stalled = [];
2894
+ for (const [runId, entry] of running) {
2895
+ const reference = entry.session?.lastTimestamp ?? entry.startedAt;
2896
+ if (!reference) continue;
2897
+ const silentMs = nowMs - new Date(reference).getTime();
2898
+ if (silentMs >= stallTimeoutMs) {
2899
+ stalled.push(runId);
2900
+ }
2901
+ }
2902
+ return stalled;
2903
+ }
2904
+
2890
2905
  // src/intelligence/pipeline-runner.ts
2891
2906
  var path9 = __toESM(require("path"));
2892
2907
  var import_intelligence = require("@harness-engineering/intelligence");
@@ -4731,7 +4746,7 @@ var OpenAIBackend = class {
4731
4746
  };
4732
4747
 
4733
4748
  // src/agent/backends/gemini.ts
4734
- var import_generative_ai = require("@google/generative-ai");
4749
+ var import_genai = require("@google/genai");
4735
4750
  var import_types13 = require("@harness-engineering/types");
4736
4751
  var import_core6 = require("@harness-engineering/core");
4737
4752
  var GeminiBackend = class {
@@ -4769,16 +4784,21 @@ var GeminiBackend = class {
4769
4784
  let cacheCreationTokens = 0;
4770
4785
  let cacheReadTokens = 0;
4771
4786
  try {
4772
- const genAI = new import_generative_ai.GoogleGenerativeAI(this.config.apiKey);
4773
- const model = genAI.getGenerativeModel({
4787
+ const genAI = new import_genai.GoogleGenAI({ apiKey: this.config.apiKey });
4788
+ const response = await genAI.models.generateContentStream({
4774
4789
  model: this.config.model,
4790
+ contents: params.prompt,
4775
4791
  ...geminiSession.systemPrompt !== void 0 && {
4776
- systemInstruction: geminiSession.systemPrompt
4792
+ config: { systemInstruction: geminiSession.systemPrompt }
4777
4793
  }
4778
4794
  });
4779
- const result = await model.generateContentStream(params.prompt);
4780
- for await (const chunk of result.stream) {
4781
- const text = chunk.text();
4795
+ for await (const chunk of response) {
4796
+ let text;
4797
+ try {
4798
+ text = chunk.text;
4799
+ } catch {
4800
+ text = void 0;
4801
+ }
4782
4802
  if (text) {
4783
4803
  const event = {
4784
4804
  type: "text",
@@ -4808,7 +4828,13 @@ var GeminiBackend = class {
4808
4828
  return {
4809
4829
  success: false,
4810
4830
  sessionId: session.sessionId,
4811
- usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
4831
+ usage: {
4832
+ inputTokens,
4833
+ outputTokens,
4834
+ totalTokens,
4835
+ cacheCreationTokens,
4836
+ cacheReadTokens
4837
+ },
4812
4838
  error: errorMessage
4813
4839
  };
4814
4840
  }
@@ -4835,9 +4861,14 @@ var GeminiBackend = class {
4835
4861
  return (0, import_types13.Ok)(void 0);
4836
4862
  }
4837
4863
  async healthCheck() {
4864
+ if (!this.config.apiKey) {
4865
+ return (0, import_types13.Err)({
4866
+ category: "agent_not_found",
4867
+ message: "GEMINI_API_KEY is not set"
4868
+ });
4869
+ }
4838
4870
  try {
4839
- const genAI = new import_generative_ai.GoogleGenerativeAI(this.config.apiKey);
4840
- genAI.getGenerativeModel({ model: this.config.model });
4871
+ new import_genai.GoogleGenAI({ apiKey: this.config.apiKey });
4841
4872
  return (0, import_types13.Ok)(void 0);
4842
4873
  } catch (err) {
4843
4874
  return (0, import_types13.Err)({
@@ -6941,7 +6972,7 @@ var ChatRequestSchema = import_zod6.z.object({
6941
6972
  });
6942
6973
  function handleChatProxyRoute(req, res, command = "claude") {
6943
6974
  const { method, url } = req;
6944
- if (method === "POST" && url === "/api/chat") {
6975
+ if (method === "POST" && (url === "/api/chat" || url === "/api/chat-proxy")) {
6945
6976
  void handleChatRequest(req, res, command);
6946
6977
  return true;
6947
6978
  }
@@ -9300,7 +9331,7 @@ function requiredScopeForRoute(method, path24) {
9300
9331
  if (path24.startsWith("/api/maintenance")) return "trigger-job";
9301
9332
  if (path24.startsWith("/api/streams")) return "read-status";
9302
9333
  if (path24.startsWith("/api/sessions")) return "read-status";
9303
- if (path24.startsWith("/api/chat-proxy")) return "trigger-job";
9334
+ if (path24 === "/api/chat" || path24.startsWith("/api/chat-proxy")) return "trigger-job";
9304
9335
  return null;
9305
9336
  }
9306
9337
 
@@ -13011,32 +13042,27 @@ ${messages}`);
13011
13042
  await this.handleEffect(effect);
13012
13043
  }
13013
13044
  const stallTimeoutMs = this.config.agent.stallTimeoutMs;
13014
- if (stallTimeoutMs > 0) {
13015
- const stalledIds = [];
13016
- for (const [runId, runEntry] of this.state.running) {
13017
- const lastTs = runEntry.session?.lastTimestamp;
13018
- if (!lastTs) continue;
13019
- const silentMs = nowMs - new Date(lastTs).getTime();
13020
- if (silentMs >= stallTimeoutMs) {
13021
- stalledIds.push(runId);
13022
- }
13023
- }
13024
- for (const runId of stalledIds) {
13025
- const runEntry = this.state.running.get(runId);
13026
- if (!runEntry) continue;
13027
- this.logger.warn(
13028
- `Agent stalled for ${runEntry.identifier}: ${Math.round((nowMs - new Date(runEntry.session?.lastTimestamp ?? 0).getTime()) / 1e3)}s since last event`,
13029
- { issueId: runId }
13030
- );
13031
- const stallEvent = {
13032
- type: "stall_detected",
13045
+ const stalledIds = detectStalledIssues(this.state.running, nowMs, stallTimeoutMs);
13046
+ for (const runId of stalledIds) {
13047
+ const runEntry = this.state.running.get(runId);
13048
+ if (!runEntry) continue;
13049
+ const reference = runEntry.session?.lastTimestamp ?? runEntry.startedAt;
13050
+ const silentSec = Math.round((nowMs - new Date(reference).getTime()) / 1e3);
13051
+ const sinceWhat = runEntry.session?.lastTimestamp ? "last event" : "dispatch";
13052
+ this.logger.warn(
13053
+ `Agent stalled for ${runEntry.identifier}: ${silentSec}s since ${sinceWhat}`,
13054
+ {
13033
13055
  issueId: runId
13034
- };
13035
- const stallResult = applyEvent(this.state, stallEvent, this.config);
13036
- this.state = stallResult.nextState;
13037
- for (const eff of stallResult.effects) {
13038
- await this.handleEffect(eff);
13039
13056
  }
13057
+ );
13058
+ const stallEvent = {
13059
+ type: "stall_detected",
13060
+ issueId: runId
13061
+ };
13062
+ const stallResult = applyEvent(this.state, stallEvent, this.config);
13063
+ this.state = stallResult.nextState;
13064
+ for (const eff of stallResult.effects) {
13065
+ await this.handleEffect(eff);
13040
13066
  }
13041
13067
  }
13042
13068
  const openPrNumbers = [];
package/dist/index.mjs CHANGED
@@ -2778,6 +2778,21 @@ import * as path21 from "path";
2778
2778
  import { randomUUID as randomUUID5 } from "crypto";
2779
2779
  import { writeTaint } from "@harness-engineering/core";
2780
2780
 
2781
+ // src/core/stall-detector.ts
2782
+ function detectStalledIssues(running, nowMs, stallTimeoutMs) {
2783
+ if (stallTimeoutMs <= 0) return [];
2784
+ const stalled = [];
2785
+ for (const [runId, entry] of running) {
2786
+ const reference = entry.session?.lastTimestamp ?? entry.startedAt;
2787
+ if (!reference) continue;
2788
+ const silentMs = nowMs - new Date(reference).getTime();
2789
+ if (silentMs >= stallTimeoutMs) {
2790
+ stalled.push(runId);
2791
+ }
2792
+ }
2793
+ return stalled;
2794
+ }
2795
+
2781
2796
  // src/intelligence/pipeline-runner.ts
2782
2797
  import * as path9 from "path";
2783
2798
  import { weightedRecommendPersona, refreshProfiles } from "@harness-engineering/intelligence";
@@ -4638,7 +4653,7 @@ var OpenAIBackend = class {
4638
4653
  };
4639
4654
 
4640
4655
  // src/agent/backends/gemini.ts
4641
- import { GoogleGenerativeAI } from "@google/generative-ai";
4656
+ import { GoogleGenAI } from "@google/genai";
4642
4657
  import {
4643
4658
  Ok as Ok13,
4644
4659
  Err as Err10
@@ -4679,16 +4694,21 @@ var GeminiBackend = class {
4679
4694
  let cacheCreationTokens = 0;
4680
4695
  let cacheReadTokens = 0;
4681
4696
  try {
4682
- const genAI = new GoogleGenerativeAI(this.config.apiKey);
4683
- const model = genAI.getGenerativeModel({
4697
+ const genAI = new GoogleGenAI({ apiKey: this.config.apiKey });
4698
+ const response = await genAI.models.generateContentStream({
4684
4699
  model: this.config.model,
4700
+ contents: params.prompt,
4685
4701
  ...geminiSession.systemPrompt !== void 0 && {
4686
- systemInstruction: geminiSession.systemPrompt
4702
+ config: { systemInstruction: geminiSession.systemPrompt }
4687
4703
  }
4688
4704
  });
4689
- const result = await model.generateContentStream(params.prompt);
4690
- for await (const chunk of result.stream) {
4691
- const text = chunk.text();
4705
+ for await (const chunk of response) {
4706
+ let text;
4707
+ try {
4708
+ text = chunk.text;
4709
+ } catch {
4710
+ text = void 0;
4711
+ }
4692
4712
  if (text) {
4693
4713
  const event = {
4694
4714
  type: "text",
@@ -4718,7 +4738,13 @@ var GeminiBackend = class {
4718
4738
  return {
4719
4739
  success: false,
4720
4740
  sessionId: session.sessionId,
4721
- usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
4741
+ usage: {
4742
+ inputTokens,
4743
+ outputTokens,
4744
+ totalTokens,
4745
+ cacheCreationTokens,
4746
+ cacheReadTokens
4747
+ },
4722
4748
  error: errorMessage
4723
4749
  };
4724
4750
  }
@@ -4745,9 +4771,14 @@ var GeminiBackend = class {
4745
4771
  return Ok13(void 0);
4746
4772
  }
4747
4773
  async healthCheck() {
4774
+ if (!this.config.apiKey) {
4775
+ return Err10({
4776
+ category: "agent_not_found",
4777
+ message: "GEMINI_API_KEY is not set"
4778
+ });
4779
+ }
4748
4780
  try {
4749
- const genAI = new GoogleGenerativeAI(this.config.apiKey);
4750
- genAI.getGenerativeModel({ model: this.config.model });
4781
+ new GoogleGenAI({ apiKey: this.config.apiKey });
4751
4782
  return Ok13(void 0);
4752
4783
  } catch (err) {
4753
4784
  return Err10({
@@ -6874,7 +6905,7 @@ var ChatRequestSchema = z6.object({
6874
6905
  });
6875
6906
  function handleChatProxyRoute(req, res, command = "claude") {
6876
6907
  const { method, url } = req;
6877
- if (method === "POST" && url === "/api/chat") {
6908
+ if (method === "POST" && (url === "/api/chat" || url === "/api/chat-proxy")) {
6878
6909
  void handleChatRequest(req, res, command);
6879
6910
  return true;
6880
6911
  }
@@ -9263,7 +9294,7 @@ function requiredScopeForRoute(method, path24) {
9263
9294
  if (path24.startsWith("/api/maintenance")) return "trigger-job";
9264
9295
  if (path24.startsWith("/api/streams")) return "read-status";
9265
9296
  if (path24.startsWith("/api/sessions")) return "read-status";
9266
- if (path24.startsWith("/api/chat-proxy")) return "trigger-job";
9297
+ if (path24 === "/api/chat" || path24.startsWith("/api/chat-proxy")) return "trigger-job";
9267
9298
  return null;
9268
9299
  }
9269
9300
 
@@ -12982,32 +13013,27 @@ ${messages}`);
12982
13013
  await this.handleEffect(effect);
12983
13014
  }
12984
13015
  const stallTimeoutMs = this.config.agent.stallTimeoutMs;
12985
- if (stallTimeoutMs > 0) {
12986
- const stalledIds = [];
12987
- for (const [runId, runEntry] of this.state.running) {
12988
- const lastTs = runEntry.session?.lastTimestamp;
12989
- if (!lastTs) continue;
12990
- const silentMs = nowMs - new Date(lastTs).getTime();
12991
- if (silentMs >= stallTimeoutMs) {
12992
- stalledIds.push(runId);
12993
- }
12994
- }
12995
- for (const runId of stalledIds) {
12996
- const runEntry = this.state.running.get(runId);
12997
- if (!runEntry) continue;
12998
- this.logger.warn(
12999
- `Agent stalled for ${runEntry.identifier}: ${Math.round((nowMs - new Date(runEntry.session?.lastTimestamp ?? 0).getTime()) / 1e3)}s since last event`,
13000
- { issueId: runId }
13001
- );
13002
- const stallEvent = {
13003
- type: "stall_detected",
13016
+ const stalledIds = detectStalledIssues(this.state.running, nowMs, stallTimeoutMs);
13017
+ for (const runId of stalledIds) {
13018
+ const runEntry = this.state.running.get(runId);
13019
+ if (!runEntry) continue;
13020
+ const reference = runEntry.session?.lastTimestamp ?? runEntry.startedAt;
13021
+ const silentSec = Math.round((nowMs - new Date(reference).getTime()) / 1e3);
13022
+ const sinceWhat = runEntry.session?.lastTimestamp ? "last event" : "dispatch";
13023
+ this.logger.warn(
13024
+ `Agent stalled for ${runEntry.identifier}: ${silentSec}s since ${sinceWhat}`,
13025
+ {
13004
13026
  issueId: runId
13005
- };
13006
- const stallResult = applyEvent(this.state, stallEvent, this.config);
13007
- this.state = stallResult.nextState;
13008
- for (const eff of stallResult.effects) {
13009
- await this.handleEffect(eff);
13010
13027
  }
13028
+ );
13029
+ const stallEvent = {
13030
+ type: "stall_detected",
13031
+ issueId: runId
13032
+ };
13033
+ const stallResult = applyEvent(this.state, stallEvent, this.config);
13034
+ this.state = stallResult.nextState;
13035
+ for (const eff of stallResult.effects) {
13036
+ await this.handleEffect(eff);
13011
13037
  }
13012
13038
  }
13013
13039
  const openPrNumbers = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harness-engineering/orchestrator",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "description": "Orchestrator daemon for dispatching coding agents to issues",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -38,7 +38,7 @@
38
38
  "dependencies": {
39
39
  "@anthropic-ai/sdk": "^0.95.1",
40
40
  "@earendil-works/pi-coding-agent": "^0.74.1",
41
- "@google/generative-ai": "^0.24.0",
41
+ "@google/genai": "^2.0.4",
42
42
  "bcryptjs": "^2.4.3",
43
43
  "better-sqlite3": "^12.10.0",
44
44
  "ink": "^4.4.1",
@@ -48,10 +48,10 @@
48
48
  "ws": "^8.21.0",
49
49
  "yaml": "^2.8.3",
50
50
  "zod": "^3.25.76",
51
- "@harness-engineering/core": "0.28.2",
52
- "@harness-engineering/intelligence": "0.2.6",
53
- "@harness-engineering/types": "0.15.0",
54
- "@harness-engineering/graph": "0.10.0"
51
+ "@harness-engineering/core": "0.30.0",
52
+ "@harness-engineering/graph": "0.11.0",
53
+ "@harness-engineering/intelligence": "0.3.0",
54
+ "@harness-engineering/types": "0.16.0"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@asteasolutions/zod-to-openapi": "^7.3.0",