@amends-dev/harness-opencode 0.0.0-stage → 0.1.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.
- package/LICENSE +21 -0
- package/Opencode2Agent.d.ts +105 -0
- package/Opencode2Agent.d.ts.map +1 -0
- package/Opencode2Agent.js +72 -0
- package/Opencode2Agent.js.map +1 -0
- package/OpencodeAgent.d.ts +110 -0
- package/OpencodeAgent.d.ts.map +1 -0
- package/OpencodeAgent.js +83 -0
- package/OpencodeAgent.js.map +1 -0
- package/README.md +221 -2
- package/index.d.ts +18 -0
- package/index.d.ts.map +1 -0
- package/index.js +19 -0
- package/index.js.map +1 -0
- package/internal/agent.d.ts +29 -0
- package/internal/agent.d.ts.map +1 -0
- package/internal/agent.js +34 -0
- package/internal/agent.js.map +1 -0
- package/internal/bridge/bunBridge.d.ts +33 -0
- package/internal/bridge/bunBridge.d.ts.map +1 -0
- package/internal/bridge/bunBridge.js +62 -0
- package/internal/bridge/bunBridge.js.map +1 -0
- package/internal/bridge/driver.d.ts +81 -0
- package/internal/bridge/driver.d.ts.map +1 -0
- package/internal/bridge/driver.js +82 -0
- package/internal/bridge/driver.js.map +1 -0
- package/internal/bridge/hostTools.d.ts +28 -0
- package/internal/bridge/hostTools.d.ts.map +1 -0
- package/internal/bridge/hostTools.js +41 -0
- package/internal/bridge/hostTools.js.map +1 -0
- package/internal/bridge/server.d.ts +64 -0
- package/internal/bridge/server.d.ts.map +1 -0
- package/internal/bridge/server.js +129 -0
- package/internal/bridge/server.js.map +1 -0
- package/internal/bridge/steps.d.ts +29 -0
- package/internal/bridge/steps.d.ts.map +1 -0
- package/internal/bridge/steps.js +42 -0
- package/internal/bridge/steps.js.map +1 -0
- package/internal/bridge/v1/api.d.ts +181 -0
- package/internal/bridge/v1/api.d.ts.map +1 -0
- package/internal/bridge/v1/api.js +83 -0
- package/internal/bridge/v1/api.js.map +1 -0
- package/internal/bridge/v1/event.d.ts +597 -0
- package/internal/bridge/v1/event.d.ts.map +1 -0
- package/internal/bridge/v1/event.js +186 -0
- package/internal/bridge/v1/event.js.map +1 -0
- package/internal/bridge/v1/main.d.ts +6 -0
- package/internal/bridge/v1/main.d.ts.map +1 -0
- package/internal/bridge/v1/main.js +8 -0
- package/internal/bridge/v1/main.js.map +1 -0
- package/internal/bridge/v1/prompt.d.ts +18 -0
- package/internal/bridge/v1/prompt.d.ts.map +1 -0
- package/internal/bridge/v1/prompt.js +92 -0
- package/internal/bridge/v1/prompt.js.map +1 -0
- package/internal/bridge/v1/session.d.ts +28 -0
- package/internal/bridge/v1/session.d.ts.map +1 -0
- package/internal/bridge/v1/session.js +188 -0
- package/internal/bridge/v1/session.js.map +1 -0
- package/internal/bridge/v1/turn.d.ts +82 -0
- package/internal/bridge/v1/turn.d.ts.map +1 -0
- package/internal/bridge/v1/turn.js +304 -0
- package/internal/bridge/v1/turn.js.map +1 -0
- package/internal/bridge/v2/api.d.ts +86 -0
- package/internal/bridge/v2/api.d.ts.map +1 -0
- package/internal/bridge/v2/api.js +105 -0
- package/internal/bridge/v2/api.js.map +1 -0
- package/internal/bridge/v2/event.d.ts +539 -0
- package/internal/bridge/v2/event.d.ts.map +1 -0
- package/internal/bridge/v2/event.js +164 -0
- package/internal/bridge/v2/event.js.map +1 -0
- package/internal/bridge/v2/main.d.ts +6 -0
- package/internal/bridge/v2/main.d.ts.map +1 -0
- package/internal/bridge/v2/main.js +8 -0
- package/internal/bridge/v2/main.js.map +1 -0
- package/internal/bridge/v2/prompt.d.ts +109 -0
- package/internal/bridge/v2/prompt.d.ts.map +1 -0
- package/internal/bridge/v2/prompt.js +209 -0
- package/internal/bridge/v2/prompt.js.map +1 -0
- package/internal/bridge/v2/session.d.ts +21 -0
- package/internal/bridge/v2/session.d.ts.map +1 -0
- package/internal/bridge/v2/session.js +198 -0
- package/internal/bridge/v2/session.js.map +1 -0
- package/internal/bridge/v2/turn.d.ts +62 -0
- package/internal/bridge/v2/turn.d.ts.map +1 -0
- package/internal/bridge/v2/turn.js +277 -0
- package/internal/bridge/v2/turn.js.map +1 -0
- package/internal/models.d.ts +47 -0
- package/internal/models.d.ts.map +1 -0
- package/internal/models.js +170 -0
- package/internal/models.js.map +1 -0
- package/internal/template.d.ts +46 -0
- package/internal/template.d.ts.map +1 -0
- package/internal/template.js +267 -0
- package/internal/template.js.map +1 -0
- package/package.json +39 -4
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* opencode's server, which the bridge starts in its sandbox. One server serves every session in the
|
|
3
|
+
* sandbox, each in its own directory. `start` runs the server until the scope closes, listening
|
|
4
|
+
* only on 127.0.0.1, behind a password that `start` makes and gives the server in its environment.
|
|
5
|
+
* `start` picks a free port for it, since opencode takes port 0 as its default port, 4096, where
|
|
6
|
+
* the server of a bridge with other options may listen already. The bridge is the server's only
|
|
7
|
+
* client and lives exactly as long as it, so the password is kept nowhere else. The requests the
|
|
8
|
+
* bridge makes of the server are those of the API its version of opencode speaks, in `v1/api.ts`
|
|
9
|
+
* and `v2/api.ts`, over the client `start` returns.
|
|
10
|
+
*
|
|
11
|
+
* opencode reads the configuration `start` is given from a directory that `start` makes for it and
|
|
12
|
+
* removes when the scope closes, in place of the global configuration of the sandbox's user, which
|
|
13
|
+
* opencode would read from under the home directory. A project's own configuration, in the
|
|
14
|
+
* directory a session works in, applies over it.
|
|
15
|
+
*
|
|
16
|
+
* opencode's tools run with the server's environment, so the agent can read the password; it keeps
|
|
17
|
+
* out everything else on the machine. A failed request fails with the `HarnessError` the driver
|
|
18
|
+
* reports, naming the agent, as `requestError` maps it.
|
|
19
|
+
*/
|
|
20
|
+
import { HarnessError } from "@amends-dev/harness";
|
|
21
|
+
import * as Crypto from "effect/Crypto";
|
|
22
|
+
import * as Deferred from "effect/Deferred";
|
|
23
|
+
import * as Effect from "effect/Effect";
|
|
24
|
+
import * as Hex from "effect/encoding/Hex";
|
|
25
|
+
import * as FileSystem from "effect/FileSystem";
|
|
26
|
+
import { flow } from "effect/Function";
|
|
27
|
+
import * as HttpClient from "effect/http/HttpClient";
|
|
28
|
+
import * as HttpClientRequest from "effect/http/HttpClientRequest";
|
|
29
|
+
import * as Match from "effect/Match";
|
|
30
|
+
import * as Path from "effect/Path";
|
|
31
|
+
import * as Predicate from "effect/Predicate";
|
|
32
|
+
import * as ChildProcess from "effect/process/ChildProcess";
|
|
33
|
+
import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
|
|
34
|
+
import * as Redacted from "effect/Redacted";
|
|
35
|
+
import * as Stream from "effect/Stream";
|
|
36
|
+
/** Starts the server, which runs until the scope closes, and waits until it listens. */
|
|
37
|
+
export const start = Effect.fn("Server.start")(function* (options) {
|
|
38
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
39
|
+
const httpClient = yield* HttpClient.HttpClient;
|
|
40
|
+
const crypto = yield* Crypto.Crypto;
|
|
41
|
+
const fs = yield* FileSystem.FileSystem;
|
|
42
|
+
const path = yield* Path.Path;
|
|
43
|
+
const password = Redacted.make(Hex.encode(yield* crypto.randomBytes(32)));
|
|
44
|
+
// opencode reads its configuration from files alone, as here from the directory
|
|
45
|
+
// `OPENCODE_CONFIG_DIR` names. The configuration holds the models' keys, so only the sandbox's
|
|
46
|
+
// user can read it, as only they can read the directory.
|
|
47
|
+
const configDirectory = yield* fs.makeTempDirectoryScoped({ prefix: "opencode-config-" });
|
|
48
|
+
yield* fs.writeFileString(path.join(configDirectory, "opencode.json"), JSON.stringify(options.config), {
|
|
49
|
+
mode: 0o600
|
|
50
|
+
});
|
|
51
|
+
const port = yield* freePort;
|
|
52
|
+
const process = yield* spawner.spawn(ChildProcess.make(options.command, ["serve", "--hostname=127.0.0.1", `--port=${port}`], {
|
|
53
|
+
extendEnv: true,
|
|
54
|
+
env: {
|
|
55
|
+
...options.env,
|
|
56
|
+
OPENCODE_CONFIG_DIR: configDirectory,
|
|
57
|
+
OPENCODE_SERVER_PASSWORD: Redacted.value(password)
|
|
58
|
+
},
|
|
59
|
+
stdin: "ignore",
|
|
60
|
+
stdout: "pipe",
|
|
61
|
+
stderr: "inherit",
|
|
62
|
+
// opencode's server does not always stop when it is asked to, so one that has not stopped
|
|
63
|
+
// soon after is killed.
|
|
64
|
+
forceKillAfter: "3 seconds"
|
|
65
|
+
}));
|
|
66
|
+
const url = yield* awaitListening(options.agent, process);
|
|
67
|
+
const client = httpClient.pipe(HttpClient.mapRequest(flow(HttpClientRequest.prependUrl(url), HttpClientRequest.basicAuth("opencode", password))));
|
|
68
|
+
const server = {
|
|
69
|
+
agent: options.agent,
|
|
70
|
+
exited: Effect.ignore(process.exitCode),
|
|
71
|
+
client,
|
|
72
|
+
clientOk: HttpClient.filterStatusOk(client)
|
|
73
|
+
};
|
|
74
|
+
return server;
|
|
75
|
+
}, (effect, options) => effect.pipe(Effect.catchTag("PlatformError", (error) => Effect.fail(harnessError(options.agent, new HarnessError.UnknownError({ description: error.message }), error)))));
|
|
76
|
+
/**
|
|
77
|
+
* A port nothing listens on at 127.0.0.1 right now, which the server listens on next. Another
|
|
78
|
+
* process taking it meanwhile leaves the server unable to listen, which fails the start.
|
|
79
|
+
*/
|
|
80
|
+
const freePort = Effect.sync(() => {
|
|
81
|
+
const listener = Bun.listen({ hostname: "127.0.0.1", port: 0, socket: { data: () => { } } });
|
|
82
|
+
const { port } = listener;
|
|
83
|
+
listener.stop(true);
|
|
84
|
+
return port;
|
|
85
|
+
});
|
|
86
|
+
/**
|
|
87
|
+
* The URL the server announces on its output once it listens. Fails when the server exits first,
|
|
88
|
+
* or does not listen within 30 seconds. The output is read to its end, so that it never fills.
|
|
89
|
+
*/
|
|
90
|
+
const awaitListening = Effect.fnUntraced(function* (agent, process) {
|
|
91
|
+
const listening = yield* Deferred.make();
|
|
92
|
+
yield* process.stdout.pipe(Stream.decodeText(), Stream.splitLines, Stream.runForEach((line) => {
|
|
93
|
+
const url = /^(?:opencode )?server listening on (\S+)/.exec(line)?.[1];
|
|
94
|
+
return url === undefined ? Effect.void : Deferred.succeed(listening, url);
|
|
95
|
+
}), Effect.ignore, Effect.forkScoped);
|
|
96
|
+
const unavailable = (description) => harnessError(agent, new HarnessError.UnavailableError({ description }));
|
|
97
|
+
const exited = Effect.flatMap(process.exitCode, (code) => Effect.fail(unavailable(`opencode's server exited with code ${code} before it listened`)));
|
|
98
|
+
return yield* Deferred.await(listening).pipe(Effect.raceFirst(exited), Effect.timeoutOrElse({
|
|
99
|
+
duration: "30 seconds",
|
|
100
|
+
orElse: () => Effect.fail(unavailable("opencode's server did not listen within 30 seconds"))
|
|
101
|
+
}));
|
|
102
|
+
});
|
|
103
|
+
/** The error that `agent` reports for `reason`. */
|
|
104
|
+
export const harnessError = (agent, reason, cause) => new HarnessError.HarnessError({ agent, reason, cause });
|
|
105
|
+
/**
|
|
106
|
+
* The error `agent` reports for a request that failed with `error`: `UnavailableError` for a server
|
|
107
|
+
* it cannot reach, one that asks to be retried, or one that failed; `NotFoundError` for what the
|
|
108
|
+
* server has no record of; `AgentContractError` for an answer the agent cannot read; and
|
|
109
|
+
* `UnknownError` for the rest.
|
|
110
|
+
*/
|
|
111
|
+
export const requestError = (agent) => (error) => Match.valueTags(error, {
|
|
112
|
+
HttpClientError: (error) => {
|
|
113
|
+
const { reason } = error;
|
|
114
|
+
const description = error.message;
|
|
115
|
+
if (Predicate.isTagged(reason, "TransportError")) {
|
|
116
|
+
return harnessError(agent, new HarnessError.UnavailableError({ description }), error);
|
|
117
|
+
}
|
|
118
|
+
const status = Predicate.isTagged(reason, "StatusCodeError") ? reason.response.status : undefined;
|
|
119
|
+
return harnessError(agent, status === 404
|
|
120
|
+
? new HarnessError.NotFoundError({ description })
|
|
121
|
+
: status === 429 || (status !== undefined && status >= 500)
|
|
122
|
+
? new HarnessError.UnavailableError({ description })
|
|
123
|
+
: new HarnessError.UnknownError({ description }), error);
|
|
124
|
+
},
|
|
125
|
+
SchemaError: (error) => harnessError(agent, new HarnessError.AgentContractError({ description: error.message }), error),
|
|
126
|
+
SseError: (error) => harnessError(agent, new HarnessError.AgentContractError({ description: error.message }), error),
|
|
127
|
+
Retry: () => harnessError(agent, new HarnessError.UnavailableError({ description: "opencode's server asked to be retried" }))
|
|
128
|
+
});
|
|
129
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/internal/bridge/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What both versions of opencode report of a step the same way: the tokens it used, and why it
|
|
3
|
+
* ended, which become the usage and the finish reason of the harness's `finish-step` and `finish`
|
|
4
|
+
* parts.
|
|
5
|
+
*/
|
|
6
|
+
import * as Response from "effect/ai/Response";
|
|
7
|
+
import * as Schema from "effect/Schema";
|
|
8
|
+
/** The tokens of a step, as opencode counts them. */
|
|
9
|
+
export declare const Tokens: Schema.Struct<{
|
|
10
|
+
readonly input: Schema.Int;
|
|
11
|
+
readonly output: Schema.Int;
|
|
12
|
+
readonly reasoning: Schema.Int;
|
|
13
|
+
readonly cache: Schema.Struct<{
|
|
14
|
+
readonly read: Schema.Int;
|
|
15
|
+
readonly write: Schema.Int;
|
|
16
|
+
}>;
|
|
17
|
+
}>;
|
|
18
|
+
export type Tokens = typeof Tokens.Type;
|
|
19
|
+
/** The tokens of no step. */
|
|
20
|
+
export declare const noTokens: Tokens;
|
|
21
|
+
export declare const addTokens: (a: Tokens, b: Tokens) => Tokens;
|
|
22
|
+
/**
|
|
23
|
+
* Tokens as Effect AI counts them. opencode counts input without cached tokens, and output
|
|
24
|
+
* without reasoning.
|
|
25
|
+
*/
|
|
26
|
+
export declare const usageOf: (tokens: Tokens) => typeof Response.Usage.Encoded;
|
|
27
|
+
/** A finish reason as Effect AI names it, which opencode's share; any other reads as `other`. */
|
|
28
|
+
export declare const finishReasonOf: (finish: string) => Response.FinishReason;
|
|
29
|
+
//# sourceMappingURL=steps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../../../src/internal/bridge/steps.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,QAAQ,MAAM,oBAAoB,CAAA;AAC9C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,qDAAqD;AACrD,eAAO,MAAM,MAAM;;;;;;;;EAKjB,CAAA;AAEF,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AAEvC,6BAA6B;AAC7B,eAAO,MAAM,QAAQ,EAAE,MAA4E,CAAA;AAEnG,eAAO,MAAM,SAAS,MAAO,MAAM,KAAK,MAAM,KAAG,MAK/C,CAAA;AAEF;;;GAGG;AACH,eAAO,MAAM,OAAO,WAAY,MAAM,KAAG,OAAO,QAAQ,CAAC,KAAK,CAAC,OAY7D,CAAA;AAEF,iGAAiG;AACjG,eAAO,MAAM,cAAc,WAAY,MAAM,KAAG,QAAQ,CAAC,YACI,CAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What both versions of opencode report of a step the same way: the tokens it used, and why it
|
|
3
|
+
* ended, which become the usage and the finish reason of the harness's `finish-step` and `finish`
|
|
4
|
+
* parts.
|
|
5
|
+
*/
|
|
6
|
+
import * as Response from "effect/ai/Response";
|
|
7
|
+
import * as Schema from "effect/Schema";
|
|
8
|
+
/** The tokens of a step, as opencode counts them. */
|
|
9
|
+
export const Tokens = Schema.Struct({
|
|
10
|
+
input: Schema.Int,
|
|
11
|
+
output: Schema.Int,
|
|
12
|
+
reasoning: Schema.Int,
|
|
13
|
+
cache: Schema.Struct({ read: Schema.Int, write: Schema.Int })
|
|
14
|
+
});
|
|
15
|
+
/** The tokens of no step. */
|
|
16
|
+
export const noTokens = { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } };
|
|
17
|
+
export const addTokens = (a, b) => ({
|
|
18
|
+
input: a.input + b.input,
|
|
19
|
+
output: a.output + b.output,
|
|
20
|
+
reasoning: a.reasoning + b.reasoning,
|
|
21
|
+
cache: { read: a.cache.read + b.cache.read, write: a.cache.write + b.cache.write }
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* Tokens as Effect AI counts them. opencode counts input without cached tokens, and output
|
|
25
|
+
* without reasoning.
|
|
26
|
+
*/
|
|
27
|
+
export const usageOf = (tokens) => ({
|
|
28
|
+
inputTokens: {
|
|
29
|
+
uncached: tokens.input,
|
|
30
|
+
total: tokens.input + tokens.cache.read + tokens.cache.write,
|
|
31
|
+
cacheRead: tokens.cache.read,
|
|
32
|
+
cacheWrite: tokens.cache.write
|
|
33
|
+
},
|
|
34
|
+
outputTokens: {
|
|
35
|
+
total: tokens.output + tokens.reasoning,
|
|
36
|
+
text: tokens.output,
|
|
37
|
+
reasoning: tokens.reasoning
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
/** A finish reason as Effect AI names it, which opencode's share; any other reads as `other`. */
|
|
41
|
+
export const finishReasonOf = (finish) => Schema.is(Response.FinishReason)(finish) ? finish : "other";
|
|
42
|
+
//# sourceMappingURL=steps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"steps.js","sourceRoot":"","sources":["../../../src/internal/bridge/steps.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,QAAQ,MAAM,oBAAoB,CAAA;AAC9C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,qDAAqD;AACrD,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC,GAAG;IACjB,MAAM,EAAE,MAAM,CAAC,GAAG;IAClB,SAAS,EAAE,MAAM,CAAC,GAAG;IACrB,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC;CAC9D,CAAC,CAAA;AAIF,6BAA6B;AAC7B,MAAM,CAAC,MAAM,QAAQ,GAAW,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAA;AAEnG,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAS,EAAE,CAAS,EAAU,EAAE,CAAC,CAAC;IAC1D,KAAK,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK;IACxB,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM;IAC3B,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS;IACpC,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE;CACnF,CAAC,CAAA;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,MAAc,EAAiC,EAAE,CAAC,CAAC;IACzE,WAAW,EAAE;QACX,QAAQ,EAAE,MAAM,CAAC,KAAK;QACtB,KAAK,EAAE,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK;QAC5D,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI;QAC5B,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK;KAC/B;IACD,YAAY,EAAE;QACZ,KAAK,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,SAAS;QACvC,IAAI,EAAE,MAAM,CAAC,MAAM;QACnB,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B;CACF,CAAC,CAAA;AAEF,iGAAiG;AACjG,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAc,EAAyB,EAAE,CACtE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAA"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The requests the driver makes of opencode's server over opencode 1's session API, for the
|
|
3
|
+
* sessions of one directory: opencode 1 keeps an instance for each directory, which every request
|
|
4
|
+
* names, and publishes the events of its sessions on one stream, live only. `make` gives them over
|
|
5
|
+
* the client of a started server. A failed request fails with the `HarnessError` the driver
|
|
6
|
+
* reports.
|
|
7
|
+
*/
|
|
8
|
+
import type { HarnessError } from "@amends-dev/harness";
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import * as Schema from "effect/Schema";
|
|
11
|
+
import type * as Scope from "effect/Scope";
|
|
12
|
+
import * as Stream from "effect/Stream";
|
|
13
|
+
import type { RemoteMcpServer } from "../hostTools.ts";
|
|
14
|
+
import * as Server from "../server.ts";
|
|
15
|
+
import { type MessageModel, SessionEvent } from "./event.ts";
|
|
16
|
+
/** A part of a prompt: text, or a file the model reads, at a URL such as a `data:` URL. */
|
|
17
|
+
export type PromptPart = {
|
|
18
|
+
readonly type: "text";
|
|
19
|
+
readonly text: string;
|
|
20
|
+
readonly synthetic?: boolean;
|
|
21
|
+
} | {
|
|
22
|
+
readonly type: "file";
|
|
23
|
+
readonly mime: string;
|
|
24
|
+
readonly url: string;
|
|
25
|
+
readonly filename?: string;
|
|
26
|
+
};
|
|
27
|
+
/** What a prompt gives the session, beside its parts. */
|
|
28
|
+
export interface PromptOptions {
|
|
29
|
+
readonly model: MessageModel;
|
|
30
|
+
/** A variant of the model, such as one that asks for an effort. */
|
|
31
|
+
readonly variant?: string;
|
|
32
|
+
/** Instructions for the turn, as the system prompt the model reads for it. */
|
|
33
|
+
readonly system?: string;
|
|
34
|
+
/** Asks the model to answer in JSON that matches `schema`. */
|
|
35
|
+
readonly format?: {
|
|
36
|
+
readonly type: "json_schema";
|
|
37
|
+
readonly schema: Schema.Json;
|
|
38
|
+
};
|
|
39
|
+
/** Enables or disables opencode's own tools by name for the turn. */
|
|
40
|
+
readonly tools?: Readonly<Record<string, boolean>>;
|
|
41
|
+
readonly parts: ReadonlyArray<PromptPart>;
|
|
42
|
+
}
|
|
43
|
+
/** How a tool goes on after asking the user's permission: this once, always, or not at all. */
|
|
44
|
+
export type PermissionReply = "once" | "always" | "reject";
|
|
45
|
+
/** A message of a session as opencode keeps it: its state and its parts. */
|
|
46
|
+
export declare const MessageWithParts: Schema.Struct<{
|
|
47
|
+
readonly info: Schema.toTaggedUnion<"role", readonly [Schema.Struct<{
|
|
48
|
+
readonly id: Schema.String;
|
|
49
|
+
readonly sessionID: Schema.String;
|
|
50
|
+
readonly role: Schema.tag<"assistant">;
|
|
51
|
+
readonly providerID: Schema.String;
|
|
52
|
+
readonly modelID: Schema.String;
|
|
53
|
+
readonly time: Schema.Struct<{
|
|
54
|
+
readonly created: Schema.Finite;
|
|
55
|
+
readonly completed: Schema.optional<Schema.Finite>;
|
|
56
|
+
}>;
|
|
57
|
+
readonly error: Schema.optional<Schema.Struct<{
|
|
58
|
+
readonly name: Schema.String;
|
|
59
|
+
readonly data: Schema.optional<Schema.Struct<{
|
|
60
|
+
readonly message: Schema.optional<Schema.String>;
|
|
61
|
+
}>>;
|
|
62
|
+
}>>;
|
|
63
|
+
readonly summary: Schema.optional<Schema.Boolean>;
|
|
64
|
+
readonly tokens: Schema.optional<Schema.Struct<{
|
|
65
|
+
readonly input: Schema.Int;
|
|
66
|
+
readonly output: Schema.Int;
|
|
67
|
+
readonly reasoning: Schema.Int;
|
|
68
|
+
readonly cache: Schema.Struct<{
|
|
69
|
+
readonly read: Schema.Int;
|
|
70
|
+
readonly write: Schema.Int;
|
|
71
|
+
}>;
|
|
72
|
+
}>>;
|
|
73
|
+
readonly structured: Schema.optional<Schema.Unknown>;
|
|
74
|
+
readonly finish: Schema.optional<Schema.String>;
|
|
75
|
+
}>, Schema.Struct<{
|
|
76
|
+
readonly id: Schema.String;
|
|
77
|
+
readonly sessionID: Schema.String;
|
|
78
|
+
readonly role: Schema.tag<"user">;
|
|
79
|
+
}>]>;
|
|
80
|
+
readonly parts: Schema.$Array<Schema.Union<readonly [Schema.Struct<{
|
|
81
|
+
readonly id: Schema.String;
|
|
82
|
+
readonly sessionID: Schema.String;
|
|
83
|
+
readonly messageID: Schema.String;
|
|
84
|
+
readonly type: Schema.tag<"text">;
|
|
85
|
+
readonly text: Schema.String;
|
|
86
|
+
readonly time: Schema.optional<Schema.Struct<{
|
|
87
|
+
readonly start: Schema.optional<Schema.Finite>;
|
|
88
|
+
readonly end: Schema.optional<Schema.Finite>;
|
|
89
|
+
}>>;
|
|
90
|
+
}>, Schema.Struct<{
|
|
91
|
+
readonly id: Schema.String;
|
|
92
|
+
readonly sessionID: Schema.String;
|
|
93
|
+
readonly messageID: Schema.String;
|
|
94
|
+
readonly type: Schema.tag<"reasoning">;
|
|
95
|
+
readonly text: Schema.String;
|
|
96
|
+
readonly time: Schema.optional<Schema.Struct<{
|
|
97
|
+
readonly start: Schema.optional<Schema.Finite>;
|
|
98
|
+
readonly end: Schema.optional<Schema.Finite>;
|
|
99
|
+
}>>;
|
|
100
|
+
readonly metadata: Schema.optional<Schema.$Record<Schema.String, Schema.Unknown>>;
|
|
101
|
+
}>, Schema.Struct<{
|
|
102
|
+
readonly id: Schema.String;
|
|
103
|
+
readonly sessionID: Schema.String;
|
|
104
|
+
readonly messageID: Schema.String;
|
|
105
|
+
readonly type: Schema.tag<"tool">;
|
|
106
|
+
readonly callID: Schema.String;
|
|
107
|
+
readonly tool: Schema.String;
|
|
108
|
+
readonly state: Schema.toTaggedUnion<"status", readonly [Schema.Struct<{
|
|
109
|
+
readonly status: Schema.tag<"pending">;
|
|
110
|
+
}>, Schema.Struct<{
|
|
111
|
+
readonly status: Schema.tag<"running">;
|
|
112
|
+
readonly input: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
113
|
+
}>, Schema.Struct<{
|
|
114
|
+
readonly status: Schema.tag<"completed">;
|
|
115
|
+
readonly input: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
116
|
+
readonly output: Schema.String;
|
|
117
|
+
readonly metadata: Schema.optional<Schema.$Record<Schema.String, Schema.Unknown>>;
|
|
118
|
+
}>, Schema.Struct<{
|
|
119
|
+
readonly status: Schema.tag<"error">;
|
|
120
|
+
readonly input: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
121
|
+
readonly error: Schema.String;
|
|
122
|
+
}>]>;
|
|
123
|
+
}>, Schema.Struct<{
|
|
124
|
+
readonly id: Schema.String;
|
|
125
|
+
readonly sessionID: Schema.String;
|
|
126
|
+
readonly messageID: Schema.String;
|
|
127
|
+
readonly type: Schema.String;
|
|
128
|
+
}>]>>;
|
|
129
|
+
}>;
|
|
130
|
+
export type MessageWithParts = typeof MessageWithParts.Type;
|
|
131
|
+
export interface Api {
|
|
132
|
+
/** Creates a session working in the directory, returning its id. */
|
|
133
|
+
readonly createSession: Effect.Effect<string, HarnessError.HarnessError>;
|
|
134
|
+
/** Whether the server has the session, as it does unless the sandbox lost opencode's data. */
|
|
135
|
+
readonly hasSession: (sessionID: string) => Effect.Effect<boolean, HarnessError.HarnessError>;
|
|
136
|
+
/** Deletes the session and its messages. Deleting a deleted session succeeds. */
|
|
137
|
+
readonly deleteSession: (sessionID: string) => Effect.Effect<void, HarnessError.HarnessError>;
|
|
138
|
+
/**
|
|
139
|
+
* Gives the session a prompt, which starts a turn, returning as soon as opencode has it. The
|
|
140
|
+
* turn's events follow on the stream `subscribe` returns.
|
|
141
|
+
*/
|
|
142
|
+
readonly prompt: (sessionID: string, options: PromptOptions) => Effect.Effect<void, HarnessError.HarnessError>;
|
|
143
|
+
/**
|
|
144
|
+
* Adds a message of the user to the session that the model reads with the next prompt and does
|
|
145
|
+
* not answer now, returning once the session has it.
|
|
146
|
+
*/
|
|
147
|
+
readonly addMessage: (sessionID: string, model: MessageModel, parts: ReadonlyArray<PromptPart>) => Effect.Effect<void, HarnessError.HarnessError>;
|
|
148
|
+
/** Ends the session's running turn. Aborting a session that runs none does nothing. */
|
|
149
|
+
readonly abort: (sessionID: string) => Effect.Effect<void, HarnessError.HarnessError>;
|
|
150
|
+
/**
|
|
151
|
+
* Asks the session to replace its conversation so far with a summary written by `model`. The
|
|
152
|
+
* summary is a message of the session, and `session.compacted` follows it on `events`.
|
|
153
|
+
*/
|
|
154
|
+
readonly summarize: (sessionID: string, model: MessageModel) => Effect.Effect<void, HarnessError.HarnessError>;
|
|
155
|
+
/** Whether opencode is working on a turn of the session. */
|
|
156
|
+
readonly isRunning: (sessionID: string) => Effect.Effect<boolean, HarnessError.HarnessError>;
|
|
157
|
+
/** The session's messages, oldest first, each with its parts. */
|
|
158
|
+
readonly messages: (sessionID: string) => Effect.Effect<ReadonlyArray<MessageWithParts>, HarnessError.HarnessError>;
|
|
159
|
+
/**
|
|
160
|
+
* Subscribes to the events of the directory's sessions, returning once opencode publishes them to
|
|
161
|
+
* the subscription, with the stream of them from then on, which ends when the scope closes. The
|
|
162
|
+
* stream does not end by itself. Events of types the adapter does not read are left out.
|
|
163
|
+
*/
|
|
164
|
+
readonly subscribe: Effect.Effect<Stream.Stream<SessionEvent, HarnessError.HarnessError>, HarnessError.HarnessError, Scope.Scope>;
|
|
165
|
+
/** Answers a tool's request for permission. */
|
|
166
|
+
readonly replyPermission: (requestID: string, reply: PermissionReply, message?: string) => Effect.Effect<void, HarnessError.HarnessError>;
|
|
167
|
+
/** Refuses the model's questions to the user, which the model reads as refused. */
|
|
168
|
+
readonly rejectQuestion: (requestID: string) => Effect.Effect<void, HarnessError.HarnessError>;
|
|
169
|
+
/**
|
|
170
|
+
* Adds the MCP server `name` to the directory's instance, connecting to it and listing its tools
|
|
171
|
+
* for the model as `<name>_<tool>`. Adding a name again replaces the server.
|
|
172
|
+
*/
|
|
173
|
+
readonly addMcpServer: (name: string, server: RemoteMcpServer) => Effect.Effect<void, HarnessError.HarnessError>;
|
|
174
|
+
/** Connects to the MCP server `name` again, listing its tools anew. */
|
|
175
|
+
readonly reconnectMcpServer: (name: string) => Effect.Effect<void, HarnessError.HarnessError>;
|
|
176
|
+
/** Disconnects from the MCP server `name`, taking its tools from the model. */
|
|
177
|
+
readonly disconnectMcpServer: (name: string) => Effect.Effect<void, HarnessError.HarnessError>;
|
|
178
|
+
}
|
|
179
|
+
/** The requests of opencode 1's session API for the sessions of `directory`, made of `server`. */
|
|
180
|
+
export declare const make: (server: Server.Server, directory: string) => Api;
|
|
181
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../src/internal/bridge/v1/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The requests the driver makes of opencode's server over opencode 1's session API, for the
|
|
3
|
+
* sessions of one directory: opencode 1 keeps an instance for each directory, which every request
|
|
4
|
+
* names, and publishes the events of its sessions on one stream, live only. `make` gives them over
|
|
5
|
+
* the client of a started server. A failed request fails with the `HarnessError` the driver
|
|
6
|
+
* reports.
|
|
7
|
+
*/
|
|
8
|
+
import * as Effect from "effect/Effect";
|
|
9
|
+
import * as Sse from "effect/encoding/Sse";
|
|
10
|
+
import * as HttpClient from "effect/http/HttpClient";
|
|
11
|
+
import * as HttpClientRequest from "effect/http/HttpClientRequest";
|
|
12
|
+
import * as HttpClientResponse from "effect/http/HttpClientResponse";
|
|
13
|
+
import * as Schema from "effect/Schema";
|
|
14
|
+
import * as Stream from "effect/Stream";
|
|
15
|
+
import * as Server from "../server.js";
|
|
16
|
+
import { Message, Part, SessionEvent } from "./event.js";
|
|
17
|
+
/** A message of a session as opencode keeps it: its state and its parts. */
|
|
18
|
+
export const MessageWithParts = Schema.Struct({ info: Message, parts: Schema.Array(Part) });
|
|
19
|
+
/** The requests of opencode 1's session API for the sessions of `directory`, made of `server`. */
|
|
20
|
+
export const make = (server, directory) => {
|
|
21
|
+
const { client, clientOk } = server;
|
|
22
|
+
const fromRequestError = Server.requestError(server.agent);
|
|
23
|
+
const urlParams = { directory };
|
|
24
|
+
const sessionPath = (sessionID, rest = "") => `/session/${encodeURIComponent(sessionID)}${rest}`;
|
|
25
|
+
const send = (request) => clientOk
|
|
26
|
+
.execute(HttpClientRequest.appendUrlParams(request, urlParams))
|
|
27
|
+
.pipe(Effect.asVoid, Effect.mapError(fromRequestError));
|
|
28
|
+
/** Whether a request about something the server may not have answers 200 rather than 404. */
|
|
29
|
+
const exists = (request) => client.execute(HttpClientRequest.appendUrlParams(request, urlParams)).pipe(Effect.flatMap(HttpClientResponse.filterStatus((status) => status === 200 || status === 404)), Effect.map((response) => response.status === 200), Effect.mapError(fromRequestError));
|
|
30
|
+
return {
|
|
31
|
+
createSession: HttpClientRequest.post("/session").pipe(HttpClientRequest.appendUrlParams(urlParams), HttpClientRequest.bodyJsonUnsafe({}), clientOk.execute, Effect.flatMap(HttpClientResponse.schemaBodyJson(CreatedSession)), Effect.map((created) => created.id), Effect.mapError(fromRequestError)),
|
|
32
|
+
hasSession: (sessionID) => exists(HttpClientRequest.get(sessionPath(sessionID))),
|
|
33
|
+
deleteSession: (sessionID) => Effect.asVoid(exists(HttpClientRequest.delete(sessionPath(sessionID)))),
|
|
34
|
+
prompt: (sessionID, options) => send(HttpClientRequest.post(sessionPath(sessionID, "/prompt_async")).pipe(HttpClientRequest.bodyJsonUnsafe({
|
|
35
|
+
model: options.model,
|
|
36
|
+
...(options.variant === undefined ? {} : { variant: options.variant }),
|
|
37
|
+
...(options.system === undefined ? {} : { system: options.system }),
|
|
38
|
+
...(options.format === undefined ? {} : { format: options.format }),
|
|
39
|
+
...(options.tools === undefined ? {} : { tools: options.tools }),
|
|
40
|
+
parts: options.parts
|
|
41
|
+
}))),
|
|
42
|
+
addMessage: (sessionID, model, parts) => send(HttpClientRequest.post(sessionPath(sessionID, "/message")).pipe(HttpClientRequest.bodyJsonUnsafe({ model, noReply: true, parts }))),
|
|
43
|
+
abort: (sessionID) => send(HttpClientRequest.post(sessionPath(sessionID, "/abort"))),
|
|
44
|
+
summarize: (sessionID, model) => send(HttpClientRequest.post(sessionPath(sessionID, "/summarize")).pipe(HttpClientRequest.bodyJsonUnsafe({
|
|
45
|
+
providerID: model.providerID,
|
|
46
|
+
modelID: model.modelID
|
|
47
|
+
}))),
|
|
48
|
+
isRunning: (sessionID) => clientOk.get("/session/status", { urlParams }).pipe(Effect.flatMap(HttpClientResponse.schemaBodyJson(SessionStatuses)), Effect.map((statuses) => {
|
|
49
|
+
const status = Object.hasOwn(statuses, sessionID) ? statuses[sessionID] : undefined;
|
|
50
|
+
return status !== undefined && status.type !== "idle";
|
|
51
|
+
}), Effect.mapError(fromRequestError)),
|
|
52
|
+
messages: (sessionID) => clientOk
|
|
53
|
+
.get(sessionPath(sessionID, "/message"), { urlParams })
|
|
54
|
+
.pipe(Effect.flatMap(HttpClientResponse.schemaBodyJson(Schema.Array(MessageWithParts))), Effect.mapError(fromRequestError)),
|
|
55
|
+
subscribe: HttpClient.withScope(clientOk)
|
|
56
|
+
.get("/event", { urlParams })
|
|
57
|
+
.pipe(Effect.map((response) => response.stream.pipe(Stream.decodeText(), Stream.pipeThroughChannel(Sse.decodeDataSchema(StreamedEvent)), Stream.map((event) => event.data), Stream.filter(Schema.is(SessionEvent)), Stream.mapError(fromRequestError))), Effect.mapError(fromRequestError)),
|
|
58
|
+
replyPermission: (requestID, reply, message) => send(HttpClientRequest.post(`/permission/${encodeURIComponent(requestID)}/reply`).pipe(HttpClientRequest.bodyJsonUnsafe({
|
|
59
|
+
reply,
|
|
60
|
+
...(message === undefined ? {} : { message })
|
|
61
|
+
}))),
|
|
62
|
+
rejectQuestion: (requestID) => send(HttpClientRequest.post(`/question/${encodeURIComponent(requestID)}/reject`)),
|
|
63
|
+
addMcpServer: (name, mcpServer) => send(HttpClientRequest.post("/mcp").pipe(HttpClientRequest.bodyJsonUnsafe({
|
|
64
|
+
name,
|
|
65
|
+
config: { type: "remote", url: mcpServer.url, headers: mcpServer.headers }
|
|
66
|
+
}))),
|
|
67
|
+
reconnectMcpServer: (name) => send(HttpClientRequest.post(`/mcp/${encodeURIComponent(name)}/connect`)),
|
|
68
|
+
disconnectMcpServer: (name) => send(HttpClientRequest.post(`/mcp/${encodeURIComponent(name)}/disconnect`))
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
const CreatedSession = Schema.Struct({ id: Schema.String });
|
|
72
|
+
/** The status of each session the server is working on, by id. */
|
|
73
|
+
const SessionStatuses = Schema.Record(Schema.String, Schema.Struct({ type: Schema.String }));
|
|
74
|
+
/** An event of a type the adapter does not read, which `events` leaves out. */
|
|
75
|
+
const OtherEvent = Schema.Struct({
|
|
76
|
+
type: Schema.String.check(Schema.makeFilter((type) => !Object.hasOwn(SessionEvent.cases, type)))
|
|
77
|
+
});
|
|
78
|
+
/**
|
|
79
|
+
* An event as the server streams it. A known type that does not decode fails, rather than being
|
|
80
|
+
* left out as an event of another type.
|
|
81
|
+
*/
|
|
82
|
+
const StreamedEvent = Schema.Union([SessionEvent, OtherEvent]);
|
|
83
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../../src/internal/bridge/v1/api.ts"],"names":[],"mappings":"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"}
|