@mandible-ai/mandible 0.3.13 → 0.4.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 (111) hide show
  1. package/README.md +5 -7
  2. package/dist/src/cli/index.js +6 -0
  3. package/dist/src/cli/index.js.map +1 -1
  4. package/dist/src/cli/init.d.ts +25 -0
  5. package/dist/src/cli/init.d.ts.map +1 -0
  6. package/dist/src/cli/init.js +348 -0
  7. package/dist/src/cli/init.js.map +1 -0
  8. package/dist/src/core/events.d.ts +1 -1
  9. package/dist/src/core/events.d.ts.map +1 -1
  10. package/dist/src/core/events.js.map +1 -1
  11. package/dist/src/core/runtime.d.ts.map +1 -1
  12. package/dist/src/core/runtime.js +25 -2
  13. package/dist/src/core/runtime.js.map +1 -1
  14. package/dist/src/core/types.d.ts +12 -0
  15. package/dist/src/core/types.d.ts.map +1 -1
  16. package/dist/src/core/types.js.map +1 -1
  17. package/dist/src/core/validation.d.ts +7 -0
  18. package/dist/src/core/validation.d.ts.map +1 -1
  19. package/dist/src/core/validation.js +19 -0
  20. package/dist/src/core/validation.js.map +1 -1
  21. package/dist/src/dsl/builder.d.ts +2 -0
  22. package/dist/src/dsl/builder.d.ts.map +1 -1
  23. package/dist/src/dsl/builder.js +5 -0
  24. package/dist/src/dsl/builder.js.map +1 -1
  25. package/dist/src/dsl/mandible.d.ts +1 -1
  26. package/dist/src/dsl/mandible.js +1 -1
  27. package/dist/src/environments/dolt/adapter.d.ts +21 -7
  28. package/dist/src/environments/dolt/adapter.d.ts.map +1 -1
  29. package/dist/src/environments/dolt/adapter.js +319 -59
  30. package/dist/src/environments/dolt/adapter.js.map +1 -1
  31. package/dist/src/environments/dolt/client.d.ts +72 -0
  32. package/dist/src/environments/dolt/client.d.ts.map +1 -0
  33. package/dist/src/environments/dolt/client.js +209 -0
  34. package/dist/src/environments/dolt/client.js.map +1 -0
  35. package/dist/src/environments/dolt/index.d.ts +2 -0
  36. package/dist/src/environments/dolt/index.d.ts.map +1 -1
  37. package/dist/src/environments/dolt/index.js +2 -0
  38. package/dist/src/environments/dolt/index.js.map +1 -1
  39. package/dist/src/environments/dolt/sql-client.d.ts +24 -0
  40. package/dist/src/environments/dolt/sql-client.d.ts.map +1 -0
  41. package/dist/src/environments/dolt/sql-client.js +46 -0
  42. package/dist/src/environments/dolt/sql-client.js.map +1 -0
  43. package/dist/src/environments/filesystem/adapter.d.ts +4 -0
  44. package/dist/src/environments/filesystem/adapter.d.ts.map +1 -1
  45. package/dist/src/environments/filesystem/adapter.js +23 -0
  46. package/dist/src/environments/filesystem/adapter.js.map +1 -1
  47. package/dist/src/environments/github/adapter.d.ts +4 -0
  48. package/dist/src/environments/github/adapter.d.ts.map +1 -1
  49. package/dist/src/environments/github/adapter.js +18 -0
  50. package/dist/src/environments/github/adapter.js.map +1 -1
  51. package/dist/src/hosts/docker.d.ts +52 -37
  52. package/dist/src/hosts/docker.d.ts.map +1 -1
  53. package/dist/src/hosts/docker.js +207 -90
  54. package/dist/src/hosts/docker.js.map +1 -1
  55. package/dist/src/index.d.ts +11 -2
  56. package/dist/src/index.d.ts.map +1 -1
  57. package/dist/src/index.js +6 -1
  58. package/dist/src/index.js.map +1 -1
  59. package/dist/src/patterns/barrier.d.ts +104 -0
  60. package/dist/src/patterns/barrier.d.ts.map +1 -0
  61. package/dist/src/patterns/barrier.js +196 -0
  62. package/dist/src/patterns/barrier.js.map +1 -0
  63. package/dist/src/patterns/gate.d.ts +71 -0
  64. package/dist/src/patterns/gate.d.ts.map +1 -0
  65. package/dist/src/patterns/gate.js +167 -0
  66. package/dist/src/patterns/gate.js.map +1 -0
  67. package/dist/src/patterns/index.d.ts +4 -0
  68. package/dist/src/patterns/index.d.ts.map +1 -1
  69. package/dist/src/patterns/index.js +2 -0
  70. package/dist/src/patterns/index.js.map +1 -1
  71. package/dist/src/providers/claude-code.d.ts.map +1 -1
  72. package/dist/src/providers/claude-code.js +5 -4
  73. package/dist/src/providers/claude-code.js.map +1 -1
  74. package/dist/src/providers/context.d.ts.map +1 -1
  75. package/dist/src/providers/context.js +16 -10
  76. package/dist/src/providers/context.js.map +1 -1
  77. package/dist/src/providers/index.d.ts +14 -1
  78. package/dist/src/providers/index.d.ts.map +1 -1
  79. package/dist/src/providers/index.js +13 -0
  80. package/dist/src/providers/index.js.map +1 -1
  81. package/dist/src/providers/llm.d.ts +17 -0
  82. package/dist/src/providers/llm.d.ts.map +1 -0
  83. package/dist/src/providers/llm.js +225 -0
  84. package/dist/src/providers/llm.js.map +1 -0
  85. package/dist/src/providers/opencode.d.ts +87 -0
  86. package/dist/src/providers/opencode.d.ts.map +1 -0
  87. package/dist/src/providers/opencode.js +170 -0
  88. package/dist/src/providers/opencode.js.map +1 -0
  89. package/dist/src/providers/openhands.d.ts +102 -0
  90. package/dist/src/providers/openhands.d.ts.map +1 -0
  91. package/dist/src/providers/openhands.js +234 -0
  92. package/dist/src/providers/openhands.js.map +1 -0
  93. package/dist/src/providers/qwen-code.d.ts +69 -0
  94. package/dist/src/providers/qwen-code.d.ts.map +1 -0
  95. package/dist/src/providers/qwen-code.js +175 -0
  96. package/dist/src/providers/qwen-code.js.map +1 -0
  97. package/dist/src/providers/skill.d.ts +120 -0
  98. package/dist/src/providers/skill.d.ts.map +1 -0
  99. package/dist/src/providers/skill.js +262 -0
  100. package/dist/src/providers/skill.js.map +1 -0
  101. package/dist/src/providers/tool-loop.d.ts +163 -0
  102. package/dist/src/providers/tool-loop.d.ts.map +1 -0
  103. package/dist/src/providers/tool-loop.js +580 -0
  104. package/dist/src/providers/tool-loop.js.map +1 -0
  105. package/dist/src/providers/types.d.ts +63 -0
  106. package/dist/src/providers/types.d.ts.map +1 -1
  107. package/dist/src/providers/vllm.d.ts +62 -0
  108. package/dist/src/providers/vllm.d.ts.map +1 -0
  109. package/dist/src/providers/vllm.js +262 -0
  110. package/dist/src/providers/vllm.js.map +1 -0
  111. package/package.json +7 -2
@@ -0,0 +1,170 @@
1
+ // PURPOSE: withOpenCode — Provider-agnostic agentic coding via OpenCode SDK.
2
+ // PURPOSE: Wraps the OpenCode Go server's TypeScript SDK for multi-provider LLM access.
3
+ // ----------------------------------------------------------
4
+ // Provider factory
5
+ // ----------------------------------------------------------
6
+ /**
7
+ * Creates an action handler powered by the OpenCode SDK.
8
+ *
9
+ * The SDK must be installed separately:
10
+ * npm install @opencode-ai/sdk
11
+ *
12
+ * The OpenCode server must be running:
13
+ * opencode serve
14
+ *
15
+ * The handler:
16
+ * 1. Connects to the OpenCode server via the SDK
17
+ * 2. Creates a session with the specified agent and model
18
+ * 3. Optionally injects a system prompt as a noReply message
19
+ * 4. Sends the main prompt (with optional structured output schema)
20
+ * 5. Extracts text and structured output from the response
21
+ * 6. Maps the output to signal deposits
22
+ * 7. Cleans up the session
23
+ */
24
+ export function withOpenCode(config) {
25
+ const { serverUrl = 'http://localhost:4096', model, agent = 'build', prompt, systemPrompt, workingDirectory, timeout = 600_000, schema, onEvent, output, autoWithdraw = true, } = config;
26
+ return async (signal, ctx) => {
27
+ const startTime = Date.now();
28
+ // 1. Resolve prompt
29
+ const resolvedPrompt = typeof prompt === 'function'
30
+ ? await prompt(signal)
31
+ : prompt;
32
+ // 2. Resolve working directory
33
+ const cwd = typeof workingDirectory === 'function'
34
+ ? workingDirectory(signal)
35
+ : workingDirectory;
36
+ // 3. Dynamic import + full SDK interaction in try/catch
37
+ // Catches MODULE_NOT_FOUND from both the import() and the SDK usage.
38
+ let client;
39
+ let sessionId;
40
+ try {
41
+ const sdk = await import('@opencode-ai/sdk');
42
+ const createOpencodeClient = sdk.createOpencodeClient;
43
+ // 4. Create client
44
+ client = createOpencodeClient({ baseUrl: serverUrl });
45
+ // 5. Create session
46
+ const sessionBody = {};
47
+ if (model)
48
+ sessionBody.model = model;
49
+ if (agent)
50
+ sessionBody.agent = agent;
51
+ if (cwd)
52
+ sessionBody.path = cwd;
53
+ const session = await client.session.create({ body: sessionBody });
54
+ sessionId = session.data.id;
55
+ }
56
+ catch (err) {
57
+ if (err.code === 'ERR_MODULE_NOT_FOUND' || err.code === 'MODULE_NOT_FOUND') {
58
+ throw new Error('withOpenCode requires @opencode-ai/sdk. Install it:\n' +
59
+ ' npm install @opencode-ai/sdk');
60
+ }
61
+ throw err;
62
+ }
63
+ ctx.log(`OpenCode session ${sessionId} created (agent=${agent}${model ? `, model=${model}` : ''})`);
64
+ try {
65
+ // 6. Subscribe to events (fire-and-forget, errors swallowed)
66
+ if (onEvent) {
67
+ consumeEvents(client, onEvent).catch(() => { });
68
+ }
69
+ // 7. Inject system prompt as noReply message
70
+ if (systemPrompt) {
71
+ await client.session.prompt({
72
+ path: { id: sessionId },
73
+ body: {
74
+ parts: [{ type: 'text', text: systemPrompt }],
75
+ noReply: true,
76
+ },
77
+ });
78
+ }
79
+ // 8. Send main prompt
80
+ const promptBody = {
81
+ parts: [{ type: 'text', text: resolvedPrompt }],
82
+ };
83
+ if (schema) {
84
+ promptBody.format = {
85
+ type: 'json_schema',
86
+ schema: schema.schema,
87
+ };
88
+ }
89
+ const response = await client.session.prompt({
90
+ path: { id: sessionId },
91
+ body: promptBody,
92
+ signal: AbortSignal.timeout(timeout),
93
+ });
94
+ // 9. Extract result
95
+ const durationMs = Date.now() - startTime;
96
+ const parts = response.data?.parts ?? [];
97
+ const textParts = parts.filter((p) => p.type === 'text');
98
+ const text = textParts.map((p) => p.text).join('\n');
99
+ const structuredOutput = response.data?.info?.structured_output;
100
+ const result = {
101
+ text,
102
+ structuredOutput,
103
+ durationMs,
104
+ sessionId: sessionId,
105
+ };
106
+ ctx.log(`OpenCode completed in ${durationMs}ms (session=${sessionId})`);
107
+ // 10. Deposit output signals
108
+ const deposits = resolveOutput(output, result, signal);
109
+ for (const deposit of deposits) {
110
+ await ctx.deposit(deposit.type, deposit.payload ?? { ...result }, {
111
+ causedBy: [signal.id],
112
+ tags: deposit.tags,
113
+ ttl: deposit.ttl,
114
+ });
115
+ }
116
+ // 11. Auto-withdraw
117
+ if (autoWithdraw) {
118
+ await ctx.withdraw(signal.id);
119
+ }
120
+ }
121
+ finally {
122
+ // 12. Clean up session
123
+ if (sessionId) {
124
+ await client.session.delete({ path: { id: sessionId } }).catch(() => { });
125
+ }
126
+ }
127
+ };
128
+ }
129
+ // ----------------------------------------------------------
130
+ // Default system prompt
131
+ // ----------------------------------------------------------
132
+ export function buildOpenCodeSystemPrompt(colonyName) {
133
+ return [
134
+ `You are an agent in the "${colonyName}" colony.`,
135
+ 'Complete the task described in the prompt.',
136
+ 'Be thorough but concise. Focus on the specific task at hand.',
137
+ 'If you create or modify files, ensure they compile/pass tests.',
138
+ ].join('\n');
139
+ }
140
+ // ----------------------------------------------------------
141
+ // Event consumer (background, non-blocking)
142
+ // ----------------------------------------------------------
143
+ async function consumeEvents(client, onEvent) {
144
+ const events = await client.event.subscribe();
145
+ for await (const event of events.stream) {
146
+ try {
147
+ onEvent(event);
148
+ }
149
+ catch { /* swallow callback errors */ }
150
+ }
151
+ }
152
+ // ----------------------------------------------------------
153
+ // Output mapping (same 3-pattern as withClaudeCode/withQwenCode)
154
+ // ----------------------------------------------------------
155
+ function resolveOutput(output, result, signal) {
156
+ if (!output) {
157
+ return [{ type: `${signal.type}:completed`, payload: result }];
158
+ }
159
+ if (typeof output === 'function') {
160
+ const mapped = output(result, signal);
161
+ return Array.isArray(mapped) ? mapped : [mapped];
162
+ }
163
+ return [{
164
+ type: output.type,
165
+ payload: result,
166
+ tags: output.tags,
167
+ ttl: output.ttl,
168
+ }];
169
+ }
170
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../../src/providers/opencode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ import type { Signal } from '../core/types.js';
2
+ import type { ActionHandler, OutputMapping } from './types.js';
3
+ export interface OpenHandsConfig<T = Record<string, unknown>> {
4
+ /**
5
+ * OpenHands agent server URL.
6
+ * Default: 'http://localhost:3000'.
7
+ */
8
+ serverUrl?: string;
9
+ /**
10
+ * Bearer token for V1 API authentication.
11
+ * Sent as `Authorization: Bearer {apiKey}` when provided.
12
+ */
13
+ apiKey?: string;
14
+ /**
15
+ * Model in "provider/model" format for the OpenHands agent.
16
+ * e.g. 'openai/qwen3-coder', 'anthropic/claude-sonnet-4-5-20250929'
17
+ */
18
+ model?: string;
19
+ /**
20
+ * Git repository URL for the sandbox.
21
+ * Can be a static string or derived from the signal.
22
+ */
23
+ repository?: string | ((signal: Signal<T>) => string);
24
+ /**
25
+ * Build the prompt from the incoming signal.
26
+ * Can be a static string, or a function that receives the signal.
27
+ *
28
+ * For context assembly, capture the environment in a closure:
29
+ * prompt: async (signal) => {
30
+ * const ctx = await assembleContext(signal, env, { includeLineage: true });
31
+ * return `${ctx}\n\nInvestigate this CI failure:\n${signal.payload.logs}`;
32
+ * }
33
+ */
34
+ prompt: string | ((signal: Signal<T>) => string | Promise<string>);
35
+ /**
36
+ * Working directory for the OpenHands sandbox.
37
+ * Can be static or derived from the signal.
38
+ */
39
+ workingDirectory?: string | ((signal: Signal<T>) => string);
40
+ /**
41
+ * Timeout in ms for the entire conversation. Default: 900_000 (15 min).
42
+ * CI investigation can take a while — reproducing failures, installing deps, running tests.
43
+ */
44
+ timeout?: number;
45
+ /**
46
+ * Event callback for observability.
47
+ * Called with synthetic events derived from poll status changes.
48
+ * Errors in this callback are caught and do not crash the agent.
49
+ */
50
+ onEvent?: (event: OpenHandsEvent) => void;
51
+ /** Map output to signal deposits. */
52
+ output?: OutputMapping<T>;
53
+ /** Auto-withdraw the triggering signal. Default: true. */
54
+ autoWithdraw?: boolean;
55
+ }
56
+ /** Synthetic event emitted from poll status changes. */
57
+ export interface OpenHandsEvent {
58
+ id: number;
59
+ source: 'agent' | 'user' | 'environment';
60
+ action?: string;
61
+ observation?: string;
62
+ message?: string;
63
+ args?: Record<string, unknown>;
64
+ content?: string;
65
+ extras?: Record<string, unknown>;
66
+ timestamp?: string;
67
+ }
68
+ /** Result of an OpenHands agent conversation. */
69
+ export interface OpenHandsResult {
70
+ /** Final status of the conversation. */
71
+ status: 'finished' | 'error' | 'timeout' | 'stopped' | 'stuck';
72
+ /** Summary text from the agent's final message. */
73
+ text: string;
74
+ /** Conversation ID for debugging/tracing. */
75
+ conversationId: string;
76
+ /** Wall-clock duration in ms. */
77
+ durationMs: number;
78
+ /** Events received during the conversation. */
79
+ events: OpenHandsEvent[];
80
+ }
81
+ /**
82
+ * Creates an action handler powered by the OpenHands agent server (V1 API).
83
+ *
84
+ * OpenHands provides sandboxed terminal access inside Docker containers,
85
+ * which is ideal for CI investigation tasks that need to:
86
+ * - Fetch and parse CI logs
87
+ * - Reproduce build failures in isolation
88
+ * - Install dependencies and run tests
89
+ * - Propose fixes without affecting the host
90
+ *
91
+ * V1 Lifecycle:
92
+ * 1. POST /api/v1/app-conversations — create with initial message
93
+ * 2. GET /api/v1/app-conversations/start-tasks — poll until READY
94
+ * 3. GET /api/v1/app-conversations — poll until terminal state
95
+ */
96
+ export declare function withOpenHands<T = Record<string, unknown>>(config: OpenHandsConfig<T>): ActionHandler<T>;
97
+ export type OpenHandsErrorCode = 'CONVERSATION_CREATE_FAILED' | 'STARTUP_FAILED' | 'STARTUP_TIMEOUT';
98
+ export declare class OpenHandsError extends Error {
99
+ readonly code: OpenHandsErrorCode;
100
+ constructor(code: OpenHandsErrorCode, message: string);
101
+ }
102
+ //# sourceMappingURL=openhands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openhands.d.ts","sourceRoot":"","sources":["../../../src/providers/openhands.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,kBAAkB,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAiB,MAAM,YAAY,CAAC;AAM9E,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1D;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;IAEtD;;;;;;;;;OASG;IACH,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAEnE;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;IAE5D;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAE1C,qCAAqC;IACrC,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IAE1B,0DAA0D;IAC1D,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAMD,wDAAwD;AACxD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,aAAa,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC9B,wCAAwC;IACxC,MAAM,EAAE,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IAC/D,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,cAAc,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,+CAA+C;IAC/C,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvD,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,GACzB,aAAa,CAAC,CAAC,CAAC,CA6HlB;AAiMD,MAAM,MAAM,kBAAkB,GAC1B,4BAA4B,GAC5B,gBAAgB,GAChB,iBAAiB,CAAC;AAEtB,qBAAa,cAAe,SAAQ,KAAK;aAErB,IAAI,EAAE,kBAAkB;gBAAxB,IAAI,EAAE,kBAAkB,EACxC,OAAO,EAAE,MAAM;CAKlB"}
@@ -0,0 +1,234 @@
1
+ // PURPOSE: withOpenHands — Sandboxed agentic coding via OpenHands agent server (V1 API).
2
+ // PURPOSE: REST client for CI investigation and DevOps tasks in isolated containers.
3
+ // ----------------------------------------------------------
4
+ // Provider factory
5
+ // ----------------------------------------------------------
6
+ /**
7
+ * Creates an action handler powered by the OpenHands agent server (V1 API).
8
+ *
9
+ * OpenHands provides sandboxed terminal access inside Docker containers,
10
+ * which is ideal for CI investigation tasks that need to:
11
+ * - Fetch and parse CI logs
12
+ * - Reproduce build failures in isolation
13
+ * - Install dependencies and run tests
14
+ * - Propose fixes without affecting the host
15
+ *
16
+ * V1 Lifecycle:
17
+ * 1. POST /api/v1/app-conversations — create with initial message
18
+ * 2. GET /api/v1/app-conversations/start-tasks — poll until READY
19
+ * 3. GET /api/v1/app-conversations — poll until terminal state
20
+ */
21
+ export function withOpenHands(config) {
22
+ const { serverUrl = 'http://localhost:3000', apiKey, model, repository, prompt, workingDirectory, timeout = 900_000, onEvent, output, autoWithdraw = true, } = config;
23
+ return async (signal, ctx) => {
24
+ const startTime = Date.now();
25
+ const baseUrl = serverUrl.replace(/\/$/, '');
26
+ // Build shared headers
27
+ const headers = {
28
+ 'Content-Type': 'application/json',
29
+ };
30
+ if (apiKey) {
31
+ headers['Authorization'] = `Bearer ${apiKey}`;
32
+ }
33
+ // 1. Resolve prompt
34
+ const resolvedPrompt = typeof prompt === 'function'
35
+ ? await prompt(signal)
36
+ : prompt;
37
+ // 2. Resolve working directory
38
+ const cwd = typeof workingDirectory === 'function'
39
+ ? workingDirectory(signal)
40
+ : workingDirectory;
41
+ // 3. Resolve repository
42
+ const repo = typeof repository === 'function'
43
+ ? repository(signal)
44
+ : repository;
45
+ // 4. Create conversation with initial message
46
+ const events = [];
47
+ const createBody = {
48
+ initial_message: resolvedPrompt,
49
+ };
50
+ if (repo !== undefined)
51
+ createBody.repository = repo;
52
+ if (model !== undefined)
53
+ createBody.selected_model = model;
54
+ if (cwd !== undefined)
55
+ createBody.initial_cwd = cwd;
56
+ const createRes = await fetchWithTimeout(`${baseUrl}/api/v1/app-conversations`, {
57
+ method: 'POST',
58
+ headers,
59
+ body: JSON.stringify(createBody),
60
+ }, 30_000);
61
+ if (!createRes.ok) {
62
+ const errorText = await createRes.text().catch(() => 'unknown error');
63
+ throw new OpenHandsError('CONVERSATION_CREATE_FAILED', `Failed to create OpenHands conversation: ${createRes.status} ${errorText}`);
64
+ }
65
+ const createData = await createRes.json();
66
+ const conversationId = createData.conversation_id;
67
+ if (!conversationId) {
68
+ throw new OpenHandsError('CONVERSATION_CREATE_FAILED', 'OpenHands returned no conversation ID');
69
+ }
70
+ ctx.log(`OpenHands conversation ${conversationId} created`);
71
+ // 5. Wait for startup
72
+ await waitForStartup(baseUrl, conversationId, headers, 60_000, ctx);
73
+ // 6. Wait for completion
74
+ const result = await waitForCompletion(baseUrl, conversationId, headers, timeout, events, onEvent, ctx);
75
+ const durationMs = Date.now() - startTime;
76
+ const openHandsResult = {
77
+ status: result.status,
78
+ text: result.text,
79
+ conversationId,
80
+ durationMs,
81
+ events,
82
+ };
83
+ ctx.log(`OpenHands ${result.status} in ${durationMs}ms ` +
84
+ `(conversation=${conversationId}, events=${events.length})`);
85
+ // 7. Deposit output signals
86
+ const deposits = resolveOutput(output, openHandsResult, signal);
87
+ for (const deposit of deposits) {
88
+ await ctx.deposit(deposit.type, deposit.payload ?? { ...openHandsResult }, {
89
+ causedBy: [signal.id],
90
+ tags: deposit.tags,
91
+ ttl: deposit.ttl,
92
+ });
93
+ }
94
+ // 8. Auto-withdraw
95
+ if (autoWithdraw) {
96
+ await ctx.withdraw(signal.id);
97
+ }
98
+ };
99
+ }
100
+ // ----------------------------------------------------------
101
+ // Startup polling
102
+ // ----------------------------------------------------------
103
+ /**
104
+ * Wait for the OpenHands conversation sandbox to be ready.
105
+ * Polls the start-tasks endpoint until READY or ERROR.
106
+ */
107
+ async function waitForStartup(baseUrl, conversationId, headers, startupTimeout, ctx) {
108
+ const deadline = Date.now() + startupTimeout;
109
+ const pollInterval = 2_000;
110
+ while (Date.now() < deadline) {
111
+ const res = await fetchWithTimeout(`${baseUrl}/api/v1/app-conversations/start-tasks?ids=${encodeURIComponent(conversationId)}`, { method: 'GET', headers }, 10_000).catch(() => null);
112
+ if (res?.ok) {
113
+ const data = await res.json().catch(() => ({}));
114
+ const tasks = data.tasks;
115
+ if (tasks && tasks.length > 0) {
116
+ const task = tasks[0];
117
+ const status = task.status;
118
+ if (status === 'READY') {
119
+ return;
120
+ }
121
+ if (status === 'ERROR') {
122
+ throw new OpenHandsError('STARTUP_FAILED', `OpenHands startup failed for conversation ${conversationId}`);
123
+ }
124
+ }
125
+ }
126
+ await sleep(pollInterval);
127
+ }
128
+ throw new OpenHandsError('STARTUP_TIMEOUT', `OpenHands startup timed out after ${startupTimeout}ms for conversation ${conversationId}`);
129
+ }
130
+ // ----------------------------------------------------------
131
+ // Completion polling
132
+ // ----------------------------------------------------------
133
+ /**
134
+ * Wait for the OpenHands conversation to reach a terminal state.
135
+ * Polls the conversations endpoint and emits synthetic events on status changes.
136
+ */
137
+ async function waitForCompletion(baseUrl, conversationId, headers, timeout, events, onEvent, ctx) {
138
+ const deadline = Date.now() + timeout;
139
+ const pollInterval = 5_000;
140
+ let lastStatus = '';
141
+ while (Date.now() < deadline) {
142
+ const statusRes = await fetchWithTimeout(`${baseUrl}/api/v1/app-conversations?ids=${encodeURIComponent(conversationId)}`, { method: 'GET', headers }, 10_000).catch(() => null);
143
+ if (statusRes?.ok) {
144
+ const statusData = await statusRes.json().catch((err) => {
145
+ ctx.log(`Warning: failed to parse poll response: ${err.message}`, 'warn');
146
+ return {};
147
+ });
148
+ const conversations = statusData.conversations;
149
+ if (conversations && conversations.length > 0) {
150
+ const conv = conversations[0];
151
+ const executionStatus = conv.execution_status;
152
+ const sandboxStatus = conv.sandbox_status;
153
+ const lastMessage = conv.last_message;
154
+ // Emit synthetic event on status change
155
+ const currentStatus = `${executionStatus}:${sandboxStatus}`;
156
+ if (currentStatus !== lastStatus) {
157
+ lastStatus = currentStatus;
158
+ const event = {
159
+ id: events.length + 1,
160
+ source: 'environment',
161
+ observation: 'status_change',
162
+ message: `execution=${executionStatus} sandbox=${sandboxStatus}`,
163
+ timestamp: new Date().toISOString(),
164
+ };
165
+ events.push(event);
166
+ if (onEvent) {
167
+ try {
168
+ onEvent(event);
169
+ }
170
+ catch { /* swallow callback errors */ }
171
+ }
172
+ }
173
+ // Check terminal states
174
+ if (executionStatus === 'FINISHED') {
175
+ return { status: 'finished', text: lastMessage ?? '' };
176
+ }
177
+ if (executionStatus === 'ERROR') {
178
+ return { status: 'error', text: lastMessage ?? 'Agent encountered an error' };
179
+ }
180
+ if (executionStatus === 'STUCK') {
181
+ return { status: 'stuck', text: lastMessage ?? 'Agent is stuck' };
182
+ }
183
+ if (sandboxStatus === 'ERROR') {
184
+ return { status: 'error', text: lastMessage ?? 'Sandbox error' };
185
+ }
186
+ if (executionStatus === 'PAUSED' && sandboxStatus === 'STOPPED') {
187
+ return { status: 'stopped', text: lastMessage ?? 'Agent was stopped' };
188
+ }
189
+ }
190
+ }
191
+ await sleep(pollInterval);
192
+ }
193
+ return { status: 'timeout', text: 'Agent timed out' };
194
+ }
195
+ // ----------------------------------------------------------
196
+ // Helpers
197
+ // ----------------------------------------------------------
198
+ /** fetch() with AbortSignal.timeout. */
199
+ async function fetchWithTimeout(url, init, timeoutMs) {
200
+ return fetch(url, {
201
+ ...init,
202
+ signal: AbortSignal.timeout(timeoutMs),
203
+ });
204
+ }
205
+ function sleep(ms) {
206
+ return new Promise(resolve => setTimeout(resolve, ms));
207
+ }
208
+ // ----------------------------------------------------------
209
+ // Output mapping (same 3-pattern as withOpenCode/withClaudeCode)
210
+ // ----------------------------------------------------------
211
+ function resolveOutput(output, result, signal) {
212
+ if (!output) {
213
+ return [{ type: `${signal.type}:completed`, payload: result }];
214
+ }
215
+ if (typeof output === 'function') {
216
+ const mapped = output(result, signal);
217
+ return Array.isArray(mapped) ? mapped : [mapped];
218
+ }
219
+ return [{
220
+ type: output.type,
221
+ payload: result,
222
+ tags: output.tags,
223
+ ttl: output.ttl,
224
+ }];
225
+ }
226
+ export class OpenHandsError extends Error {
227
+ code;
228
+ constructor(code, message) {
229
+ super(message);
230
+ this.code = code;
231
+ this.name = 'OpenHandsError';
232
+ }
233
+ }
234
+ //# sourceMappingURL=openhands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openhands.js","sourceRoot":"","sources":["../../../src/providers/openhands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import type { Signal } from '../core/types.js';
2
+ import type { ActionHandler, OutputMapping } from './types.js';
3
+ export interface QwenCodeConfig<T = Record<string, unknown>> {
4
+ /** vLLM endpoint — sets OPENAI_BASE_URL for qwen-code. */
5
+ endpoint: string;
6
+ /** Model name. Default: 'Qwen3-Coder-Next'. */
7
+ model?: string;
8
+ /** Optional API key — sets OPENAI_API_KEY for qwen-code. */
9
+ apiKey?: string;
10
+ /** Build the prompt from the incoming signal. */
11
+ prompt: string | ((signal: Signal<T>) => string | Promise<string>);
12
+ /**
13
+ * Working directory for the qwen-code session.
14
+ * Can be static or derived from the signal.
15
+ */
16
+ workingDirectory?: string | ((signal: Signal<T>) => string);
17
+ /**
18
+ * Maximum conversation turns for qwen-code. Default: 20.
19
+ * Maps to qwen-code's --max-turns flag.
20
+ */
21
+ maxTurns?: number;
22
+ /** Timeout in ms for the entire session. Default: 600_000 (10 min). */
23
+ timeout?: number;
24
+ /**
25
+ * Shell commands the agent is allowed to run.
26
+ * If not set, qwen-code uses its default allowed commands.
27
+ */
28
+ allowedCommands?: string[];
29
+ /**
30
+ * Additional environment variables to pass to the subprocess.
31
+ */
32
+ env?: Record<string, string>;
33
+ /**
34
+ * Path to the qwen-code binary. Default: 'qwen-code' (from PATH).
35
+ */
36
+ binary?: string;
37
+ /**
38
+ * Map the output to signal deposits.
39
+ * If not provided, deposits the raw result.
40
+ */
41
+ output?: OutputMapping<T>;
42
+ /** Whether to auto-withdraw the triggering signal. Default: true. */
43
+ autoWithdraw?: boolean;
44
+ /**
45
+ * Observability hook — called with chunks of stdout as they arrive.
46
+ * Use for real-time logging or progress tracking.
47
+ */
48
+ onOutput?: (chunk: string) => void;
49
+ }
50
+ export interface QwenCodeResult {
51
+ /** Combined stdout from the qwen-code session. */
52
+ text: string;
53
+ /** stderr output (usually progress/debug info). */
54
+ stderr: string;
55
+ /** Process exit code. 0 = success. */
56
+ exitCode: number;
57
+ /** Wall-clock duration in ms. */
58
+ durationMs: number;
59
+ /** Whether the session completed successfully (exit code 0). */
60
+ success: boolean;
61
+ /** Whether the session was killed by timeout. */
62
+ timedOut: boolean;
63
+ }
64
+ /**
65
+ * Creates an action handler that spawns a qwen-code subprocess.
66
+ * The subprocess runs against local vLLM and executes agentic coding tasks.
67
+ */
68
+ export declare function withQwenCode<T = Record<string, unknown>>(config: QwenCodeConfig<T>): ActionHandler<T>;
69
+ //# sourceMappingURL=qwen-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qwen-code.d.ts","sourceRoot":"","sources":["../../../src/providers/qwen-code.ts"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,kBAAkB,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAiB,MAAM,YAAY,CAAC;AAM9E,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACzD,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IAEjB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,iDAAiD;IACjD,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAEnE;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;IAE5D;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAE3B;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE7B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IAE1B,qEAAqE;IACrE,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAMD,MAAM,WAAW,cAAc;IAC7B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IAEb,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IAEf,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IAEjB,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;IAEnB,gEAAgE;IAChE,OAAO,EAAE,OAAO,CAAC;IAEjB,iDAAiD;IACjD,QAAQ,EAAE,OAAO,CAAC;CACnB;AAMD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtD,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GACxB,aAAa,CAAC,CAAC,CAAC,CAuElB"}