@taico/worker 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +63 -0
  2. package/dist/Coordinator.d.ts +10 -0
  3. package/dist/Coordinator.js +183 -0
  4. package/dist/SocketIOTasksTransport.d.ts +68 -0
  5. package/dist/SocketIOTasksTransport.js +183 -0
  6. package/dist/Taico.d.ts +10 -0
  7. package/dist/Taico.js +69 -0
  8. package/dist/dev.d.ts +1 -0
  9. package/dist/dev.js +29 -0
  10. package/dist/formatters/ADKMessageFormatter.d.ts +4 -0
  11. package/dist/formatters/ADKMessageFormatter.js +32 -0
  12. package/dist/formatters/ClaudeMessageFormatter.d.ts +11 -0
  13. package/dist/formatters/ClaudeMessageFormatter.js +97 -0
  14. package/dist/formatters/OpencodeMessageFormatter.d.ts +8 -0
  15. package/dist/formatters/OpencodeMessageFormatter.js +56 -0
  16. package/dist/helpers/config.d.ts +5 -0
  17. package/dist/helpers/config.js +21 -0
  18. package/dist/helpers/ensureRepo.d.ts +1 -0
  19. package/dist/helpers/ensureRepo.js +27 -0
  20. package/dist/helpers/prepareWorkspace.d.ts +1 -0
  21. package/dist/helpers/prepareWorkspace.js +23 -0
  22. package/dist/helpers/sessionStore.d.ts +2 -0
  23. package/dist/helpers/sessionStore.js +34 -0
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.js +5 -0
  26. package/dist/interfaces/AgentRunResult.d.ts +5 -0
  27. package/dist/interfaces/AgentRunResult.js +2 -0
  28. package/dist/runners/ADKAgentRunner.d.ts +13 -0
  29. package/dist/runners/ADKAgentRunner.js +65 -0
  30. package/dist/runners/AgentRunner.d.ts +43 -0
  31. package/dist/runners/AgentRunner.js +1 -0
  32. package/dist/runners/BaseAgentRunner.d.ts +13 -0
  33. package/dist/runners/BaseAgentRunner.js +27 -0
  34. package/dist/runners/ClaudeAgentRunner.d.ts +11 -0
  35. package/dist/runners/ClaudeAgentRunner.js +68 -0
  36. package/dist/runners/GitHubCopilotAgentRunner.d.ts +12 -0
  37. package/dist/runners/GitHubCopilotAgentRunner.js +81 -0
  38. package/dist/runners/OpenCodeAgentRunner.d.ts +25 -0
  39. package/dist/runners/OpenCodeAgentRunner.js +163 -0
  40. package/package.json +55 -0
@@ -0,0 +1,25 @@
1
+ import { BaseAgentRunner } from "./BaseAgentRunner.js";
2
+ import { AgentModelConfig, AgentRunContext } from "./AgentRunner.js";
3
+ export declare class OpencodeAgentRunner extends BaseAgentRunner {
4
+ readonly kind = "opencode";
5
+ private static chdirLock;
6
+ private formatter;
7
+ private client;
8
+ private abortController;
9
+ private close;
10
+ private model;
11
+ constructor(modelConfig?: AgentModelConfig);
12
+ private static readonly CHDIR_TIMEOUT_MS;
13
+ initBullshit({ runId, cwd }: {
14
+ runId: string;
15
+ cwd: string;
16
+ }): Promise<void>;
17
+ private shutdown;
18
+ init({ runId }: {
19
+ runId: string;
20
+ }): Promise<void>;
21
+ protected runInternal(ctx: AgentRunContext, emit: (msg: string) => Promise<void>, setSession: (id: string) => Promise<void>, onError?: (error: {
22
+ message: string;
23
+ rawMessage?: any;
24
+ }) => void | Promise<void>): Promise<string>;
25
+ }
@@ -0,0 +1,163 @@
1
+ // ClaudeAgentRunner.ts
2
+ import { BaseAgentRunner } from "./BaseAgentRunner.js";
3
+ import { createOpencode } from "@opencode-ai/sdk";
4
+ import { OpencodeAsyncMessageFormatter } from "../formatters/OpencodeMessageFormatter.js";
5
+ import { ACCESS_TOKEN, BASE_URL, RUN_ID_HEADER } from "../helpers/config.js";
6
+ export class OpencodeAgentRunner extends BaseAgentRunner {
7
+ kind = 'opencode';
8
+ // Mutex for process.chdir: serializes all instances so only one
9
+ // changes the working directory at a time.
10
+ static chdirLock = Promise.resolve();
11
+ formatter = new OpencodeAsyncMessageFormatter();
12
+ client = null;
13
+ abortController = new AbortController();
14
+ close = () => { };
15
+ model;
16
+ constructor(modelConfig = {}) {
17
+ super();
18
+ const hasCustomModel = Boolean(modelConfig.providerId && modelConfig.modelId);
19
+ this.model = {
20
+ providerId: hasCustomModel ? modelConfig.providerId : 'openai',
21
+ modelId: hasCustomModel ? modelConfig.modelId : 'gpt-5.2-codex',
22
+ };
23
+ }
24
+ static CHDIR_TIMEOUT_MS = 60_000; // 1 min — if we wait longer, something is stuck
25
+ async initBullshit({ runId, cwd }) {
26
+ // Disgusting hack to start the server in the working directory
27
+ // because Opencode has a bug where running a session in a different
28
+ // folder breaks realtime events (???)
29
+ //
30
+ // We serialize via a promise chain so parallel runners don't stomp
31
+ // on each other's cwd. A timeout prevents waiting forever if a
32
+ // previous init hangs.
33
+ let release;
34
+ const acquired = new Promise(resolve => { release = resolve; });
35
+ const prev = OpencodeAgentRunner.chdirLock;
36
+ OpencodeAgentRunner.chdirLock = acquired;
37
+ // Wait for the previous holder, but not forever.
38
+ await Promise.race([
39
+ prev,
40
+ new Promise((_, reject) => setTimeout(() => reject(new Error(`initBullshit: timed out after ${OpencodeAgentRunner.CHDIR_TIMEOUT_MS}ms waiting for chdir lock — a previous init is likely stuck`)), OpencodeAgentRunner.CHDIR_TIMEOUT_MS)),
41
+ ]);
42
+ const originalCwd = process.cwd();
43
+ process.chdir(cwd);
44
+ try {
45
+ await this.init({ runId });
46
+ }
47
+ finally {
48
+ process.chdir(originalCwd);
49
+ release();
50
+ }
51
+ }
52
+ shutdown() {
53
+ // Belt and suspenders: abort signal + close().
54
+ // close() alone is broken (https://github.com/anomalyco/opencode/issues/3841)
55
+ // but we keep it for when they fix it.
56
+ this.abortController.abort();
57
+ this.close();
58
+ }
59
+ async init({ runId }) {
60
+ console.log('Starting Opencode client');
61
+ let lastError;
62
+ const PORT_START = 4000;
63
+ const PORT_END = 4100;
64
+ for (let port = PORT_START; port < PORT_END; port++) {
65
+ try {
66
+ console.log(`Trying port ${port}...`);
67
+ this.abortController = new AbortController();
68
+ const opencode = await createOpencode({
69
+ port,
70
+ timeout: 20 * 3600,
71
+ signal: this.abortController.signal,
72
+ config: {
73
+ mcp: {
74
+ tasks: {
75
+ type: "remote",
76
+ url: `${BASE_URL}/api/v1/tasks/tasks/mcp`,
77
+ headers: {
78
+ Authorization: `Bearer ${ACCESS_TOKEN}`,
79
+ [RUN_ID_HEADER]: runId,
80
+ },
81
+ enabled: true,
82
+ }
83
+ }
84
+ }
85
+ });
86
+ this.client = opencode.client;
87
+ this.close = opencode.server.close;
88
+ console.log(`Opencode started on port ${port}`);
89
+ return;
90
+ }
91
+ catch (err) {
92
+ console.warn(`Port ${port} failed, trying next...`);
93
+ lastError = err;
94
+ }
95
+ }
96
+ throw new Error(`Failed to start Opencode on ports ${PORT_START}–${PORT_END}: ${String(lastError)}`);
97
+ }
98
+ async runInternal(ctx, emit, setSession, onError) {
99
+ // Start client
100
+ await this.initBullshit({ runId: ctx.runId, cwd: ctx.cwd });
101
+ // await this.init({ runId: ctx.runId });
102
+ if (!this.client) {
103
+ throw new Error("Failed to create Opencode client");
104
+ }
105
+ // Create a session for this work
106
+ const { data: session } = await this.client.session.create({
107
+ body: {
108
+ title: `Session ${new Date().toLocaleString()}`,
109
+ },
110
+ query: {
111
+ directory: ctx.cwd,
112
+ },
113
+ });
114
+ if (!session) {
115
+ this.shutdown();
116
+ throw new Error("Failed to create Opencode session");
117
+ }
118
+ console.log(`created session ${session.id} in ${session.directory}`);
119
+ // Session is created in the right dir ✅
120
+ const events = await this.client.event.subscribe(); // SSE stream
121
+ const prompt = {
122
+ type: 'text',
123
+ text: ctx.prompt,
124
+ };
125
+ let finalResult = '';
126
+ this.client.session.promptAsync({
127
+ path: {
128
+ id: session.id,
129
+ },
130
+ // NOTE: adding a directory breaks realtime events 🤷🏻‍♂️: https://github.com/anomalyco/opencode/issues/11522
131
+ // NOTE: Good news is we don't need it because the session carries the dir.
132
+ // NOTE: Acutally we need to. I've implemented a horrible hack to CD before starting the server.
133
+ // query: {
134
+ // directory: ctx.cwd,
135
+ // },
136
+ body: {
137
+ model: {
138
+ providerID: this.model.providerId,
139
+ modelID: this.model.modelId,
140
+ },
141
+ parts: [prompt],
142
+ }
143
+ });
144
+ try {
145
+ for await (const event of events.stream) {
146
+ // Detect end of session
147
+ if (event.type == 'session.idle') {
148
+ console.log('session.idle');
149
+ break;
150
+ }
151
+ const message = this.formatter.format(event);
152
+ if (message) {
153
+ emit(message);
154
+ }
155
+ }
156
+ }
157
+ catch (error) {
158
+ console.error(error);
159
+ }
160
+ this.shutdown();
161
+ return finalResult;
162
+ }
163
+ }
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@taico/worker",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "private": false,
6
+ "license": "MIT",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "bin": {
10
+ "worker": "./dist/index.js"
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "package.json"
15
+ ],
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js",
20
+ "default": "./dist/index.js"
21
+ },
22
+ "./package.json": "./package.json"
23
+ },
24
+ "scripts": {
25
+ "start": "tsx src/index.ts",
26
+ "start:claude": "dotenv -e .env.claude npm run start",
27
+ "start:codex": "dotenv -e .env.codex npm run start",
28
+ "start:reviewer": "dotenv -e .env.reviewer npm run start",
29
+ "start:qwen": "dotenv -e .env.qwen npm run start",
30
+ "start:gemini": "dotenv -e .env.gemini npm run start",
31
+ "start:all": "concurrently -n claude,codex,reviewer,qwen,gemini -c auto \"npm run start:claude\" \"npm run start:codex\" \"npm run start:reviewer\" \"npm run start:qwen\" \"npm run start:gemini\"",
32
+ "dev": "dotenv -e .env.gemini tsx src/dev.ts",
33
+ "build": "tsc -p tsconfig.build.json",
34
+ "pack": "npm run build && npm pack",
35
+ "release": "npm run build && npm publish --access public"
36
+ },
37
+ "engines": {
38
+ "node": ">=24.0.0"
39
+ },
40
+ "dependencies": {
41
+ "@anthropic-ai/claude-agent-sdk": "^0.1.76",
42
+ "@github/copilot-sdk": "0.1.22",
43
+ "@google/adk": "^0.2.4",
44
+ "@opencode-ai/sdk": "^1.1.28",
45
+ "@taico/client": "^0.0.1",
46
+ "@taico/events": "^0.0.2",
47
+ "socket.io-client": "^4.8.3"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^22.10.7",
51
+ "dotenv-cli": "^11.0.0",
52
+ "tsx": "4.21.0",
53
+ "typescript": "^5.7.3"
54
+ }
55
+ }