@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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/Opencode2Agent.d.ts +105 -0
  3. package/Opencode2Agent.d.ts.map +1 -0
  4. package/Opencode2Agent.js +72 -0
  5. package/Opencode2Agent.js.map +1 -0
  6. package/OpencodeAgent.d.ts +110 -0
  7. package/OpencodeAgent.d.ts.map +1 -0
  8. package/OpencodeAgent.js +83 -0
  9. package/OpencodeAgent.js.map +1 -0
  10. package/README.md +221 -2
  11. package/index.d.ts +18 -0
  12. package/index.d.ts.map +1 -0
  13. package/index.js +19 -0
  14. package/index.js.map +1 -0
  15. package/internal/agent.d.ts +29 -0
  16. package/internal/agent.d.ts.map +1 -0
  17. package/internal/agent.js +34 -0
  18. package/internal/agent.js.map +1 -0
  19. package/internal/bridge/bunBridge.d.ts +33 -0
  20. package/internal/bridge/bunBridge.d.ts.map +1 -0
  21. package/internal/bridge/bunBridge.js +62 -0
  22. package/internal/bridge/bunBridge.js.map +1 -0
  23. package/internal/bridge/driver.d.ts +81 -0
  24. package/internal/bridge/driver.d.ts.map +1 -0
  25. package/internal/bridge/driver.js +82 -0
  26. package/internal/bridge/driver.js.map +1 -0
  27. package/internal/bridge/hostTools.d.ts +28 -0
  28. package/internal/bridge/hostTools.d.ts.map +1 -0
  29. package/internal/bridge/hostTools.js +41 -0
  30. package/internal/bridge/hostTools.js.map +1 -0
  31. package/internal/bridge/server.d.ts +64 -0
  32. package/internal/bridge/server.d.ts.map +1 -0
  33. package/internal/bridge/server.js +129 -0
  34. package/internal/bridge/server.js.map +1 -0
  35. package/internal/bridge/steps.d.ts +29 -0
  36. package/internal/bridge/steps.d.ts.map +1 -0
  37. package/internal/bridge/steps.js +42 -0
  38. package/internal/bridge/steps.js.map +1 -0
  39. package/internal/bridge/v1/api.d.ts +181 -0
  40. package/internal/bridge/v1/api.d.ts.map +1 -0
  41. package/internal/bridge/v1/api.js +83 -0
  42. package/internal/bridge/v1/api.js.map +1 -0
  43. package/internal/bridge/v1/event.d.ts +597 -0
  44. package/internal/bridge/v1/event.d.ts.map +1 -0
  45. package/internal/bridge/v1/event.js +186 -0
  46. package/internal/bridge/v1/event.js.map +1 -0
  47. package/internal/bridge/v1/main.d.ts +6 -0
  48. package/internal/bridge/v1/main.d.ts.map +1 -0
  49. package/internal/bridge/v1/main.js +8 -0
  50. package/internal/bridge/v1/main.js.map +1 -0
  51. package/internal/bridge/v1/prompt.d.ts +18 -0
  52. package/internal/bridge/v1/prompt.d.ts.map +1 -0
  53. package/internal/bridge/v1/prompt.js +92 -0
  54. package/internal/bridge/v1/prompt.js.map +1 -0
  55. package/internal/bridge/v1/session.d.ts +28 -0
  56. package/internal/bridge/v1/session.d.ts.map +1 -0
  57. package/internal/bridge/v1/session.js +188 -0
  58. package/internal/bridge/v1/session.js.map +1 -0
  59. package/internal/bridge/v1/turn.d.ts +82 -0
  60. package/internal/bridge/v1/turn.d.ts.map +1 -0
  61. package/internal/bridge/v1/turn.js +304 -0
  62. package/internal/bridge/v1/turn.js.map +1 -0
  63. package/internal/bridge/v2/api.d.ts +86 -0
  64. package/internal/bridge/v2/api.d.ts.map +1 -0
  65. package/internal/bridge/v2/api.js +105 -0
  66. package/internal/bridge/v2/api.js.map +1 -0
  67. package/internal/bridge/v2/event.d.ts +539 -0
  68. package/internal/bridge/v2/event.d.ts.map +1 -0
  69. package/internal/bridge/v2/event.js +164 -0
  70. package/internal/bridge/v2/event.js.map +1 -0
  71. package/internal/bridge/v2/main.d.ts +6 -0
  72. package/internal/bridge/v2/main.d.ts.map +1 -0
  73. package/internal/bridge/v2/main.js +8 -0
  74. package/internal/bridge/v2/main.js.map +1 -0
  75. package/internal/bridge/v2/prompt.d.ts +109 -0
  76. package/internal/bridge/v2/prompt.d.ts.map +1 -0
  77. package/internal/bridge/v2/prompt.js +209 -0
  78. package/internal/bridge/v2/prompt.js.map +1 -0
  79. package/internal/bridge/v2/session.d.ts +21 -0
  80. package/internal/bridge/v2/session.d.ts.map +1 -0
  81. package/internal/bridge/v2/session.js +198 -0
  82. package/internal/bridge/v2/session.js.map +1 -0
  83. package/internal/bridge/v2/turn.d.ts +62 -0
  84. package/internal/bridge/v2/turn.d.ts.map +1 -0
  85. package/internal/bridge/v2/turn.js +277 -0
  86. package/internal/bridge/v2/turn.js.map +1 -0
  87. package/internal/models.d.ts +47 -0
  88. package/internal/models.d.ts.map +1 -0
  89. package/internal/models.js +170 -0
  90. package/internal/models.js.map +1 -0
  91. package/internal/template.d.ts +46 -0
  92. package/internal/template.d.ts.map +1 -0
  93. package/internal/template.js +267 -0
  94. package/internal/template.js.map +1 -0
  95. package/package.json +39 -4
@@ -0,0 +1,198 @@
1
+ /**
2
+ * A session of opencode 2's session API, as the driver runs it: an opencode session in the
3
+ * session's directory. A turn is a prompt to it, with the prompt's files, on the turn's model, the
4
+ * turn's instructions given beside opencode's own; `Turn` translates the events opencode publishes
5
+ * for the turn as they happen. A session that starts with a conversation from another agent is
6
+ * created holding it, as opencode's own record, as `Prompt` writes it.
7
+ *
8
+ * The host's tools reach opencode through the bridge's `HostToolRelay`, as `HostTools` lists them:
9
+ * opencode 2's model calls them from code it runs. A tool of opencode's own that asks permission
10
+ * waits for `approve`, and `compact` asks opencode to summarize the conversation, which it does
11
+ * without instructions. opencode 2 does not answer in JSON, which fails with `UnsupportedError`.
12
+ */
13
+ import { HarnessError } from "@amends-dev/harness";
14
+ import * as Clock from "effect/Clock";
15
+ import * as Crypto from "effect/Crypto";
16
+ import * as Effect from "effect/Effect";
17
+ import * as FileSystem from "effect/FileSystem";
18
+ import * as Option from "effect/Option";
19
+ import * as Ref from "effect/Ref";
20
+ import * as Schema from "effect/Schema";
21
+ import * as Stream from "effect/Stream";
22
+ import * as Driver from "../driver.js";
23
+ import * as HostTools from "../hostTools.js";
24
+ import * as Server from "../server.js";
25
+ import * as Api from "./api.js";
26
+ import * as Prompt from "./prompt.js";
27
+ import * as Turn from "./turn.js";
28
+ /** What `state` returns, for `createSession` to take back. */
29
+ const State = Schema.Struct({
30
+ sessionID: Schema.String,
31
+ /** The model the session runs its turns on. */
32
+ model: Driver.ModelRef
33
+ });
34
+ const StateJson = Schema.toCodecJson(State);
35
+ /** The key a turn's instructions have among the session's. */
36
+ const instructionsKey = "amends";
37
+ /**
38
+ * How long opencode 2 may take to give its turns an MCP server's tools once they change. It
39
+ * registers them 100 milliseconds after they last changed and announces nothing when it has, so a
40
+ * turn that starts sooner runs without them.
41
+ */
42
+ const toolRegistrationTime = "500 millis";
43
+ /**
44
+ * The function that creates sessions as `Driver.CreateSession` does, each with a session of
45
+ * `relay` for the host's tools: a new opencode session, or the one its `agentState` names, when
46
+ * opencode still has it.
47
+ */
48
+ export const makeCreateSession = (relay) => (server, options, sessionOptions) => Effect.gen(function* () {
49
+ const api = Api.make(server);
50
+ const { directory } = sessionOptions;
51
+ const harnessError = (reason, cause) => Server.harnessError(server.agent, reason, cause);
52
+ // opencode may have lost the session, as when the sandbox lost its data, and then starts one
53
+ // from the conversation.
54
+ const saved = yield* readState(harnessError, sessionOptions.agentState);
55
+ const kept = saved !== undefined && (yield* api.hasSession(saved.sessionID)) ? saved : undefined;
56
+ const state = kept ?? (yield* createOpencodeSession(api, harnessError, directory, options.model, sessionOptions.history));
57
+ const { sessionID } = state;
58
+ const relaySession = yield* relay.open(sessionOptions.id);
59
+ // opencode 2 connects to an MCP server after it answers, lists its tools once it has, and
60
+ // registers them for its turns later still.
61
+ const registered = Effect.andThen(api.awaitMcpServer(directory, HostTools.serverName), Effect.sleep(toolRegistrationTime));
62
+ const listHostTools = yield* HostTools.makeLister(relay.url, relaySession, {
63
+ add: (mcpServer) => Effect.andThen(api.addMcpServer(directory, HostTools.serverName, mcpServer), registered),
64
+ reconnect: Effect.andThen(api.reconnectMcpServer(directory, HostTools.serverName), registered),
65
+ disconnect: Effect.andThen(api.disconnectMcpServer(directory, HostTools.serverName), Effect.sleep(toolRegistrationTime))
66
+ });
67
+ // opencode reports the files a tool changed by their real paths.
68
+ const fs = yield* FileSystem.FileSystem;
69
+ const realDirectory = yield* fs.realPath(directory).pipe(Effect.orElseSucceed(() => directory));
70
+ /** The model the session runs its turns on, switched when a turn names another. */
71
+ const sessionModel = yield* Ref.make(state.model);
72
+ /**
73
+ * The instructions the session's model reads beside opencode's own, or nothing while the
74
+ * session does not know them, as for a session it kept.
75
+ */
76
+ const sessionInstructions = yield* Ref.make(kept === undefined ? {} : undefined);
77
+ /** Gives the session the turn's model and instructions, before its prompt. */
78
+ const prepareTurn = Effect.fnUntraced(function* (turnOptions) {
79
+ if (turnOptions.responseFormat.type === "json") {
80
+ return yield* harnessError(new HarnessError.UnsupportedError({
81
+ description: "opencode 2's session API does not answer in JSON"
82
+ }));
83
+ }
84
+ const model = yield* modelNamed(harnessError, options, turnOptions.model);
85
+ if (!isSameModel(model, yield* Ref.get(sessionModel))) {
86
+ yield* api.switchModel(sessionID, model);
87
+ yield* Ref.set(sessionModel, model);
88
+ }
89
+ const { instructions } = turnOptions;
90
+ const known = yield* Ref.get(sessionInstructions);
91
+ if (known === undefined || known.text !== instructions) {
92
+ yield* instructions === undefined
93
+ ? api.removeInstructions(sessionID, instructionsKey)
94
+ : api.putInstructions(sessionID, instructionsKey, instructions);
95
+ yield* Ref.set(sessionInstructions, instructions === undefined ? {} : { text: instructions });
96
+ }
97
+ yield* listHostTools(turnOptions.tools);
98
+ });
99
+ /**
100
+ * Runs a turn, streaming its parts until its `finish`, with the calls the relay streams of the
101
+ * host's tools. A stream that ends before the turn finishes, as when the bridge aborts the
102
+ * turn, stops the session in opencode.
103
+ */
104
+ const promptTurn = (turnOptions) => Stream.unwrap(Effect.gen(function* () {
105
+ const prompt = yield* Effect.fromResult(Prompt.promptOf(turnOptions.prompt)).pipe(Effect.mapError((reason) => harnessError(reason)));
106
+ const finished = yield* Ref.make(false);
107
+ // Interrupting a session that runs nothing does nothing, so this holds from before
108
+ // opencode takes the prompt.
109
+ yield* Effect.addFinalizer(() => Effect.flatMap(Ref.get(finished), (done) => done ? Effect.void : Effect.ignore(api.interrupt(sessionID))));
110
+ const hostCalls = turnOptions.tools.length === 0 ? Stream.empty : yield* relaySession.offerTools(turnOptions.tools);
111
+ yield* prepareTurn(turnOptions);
112
+ // The turn's events are published only to subscriptions made before them.
113
+ const events = yield* api.subscribe(sessionID);
114
+ const inboxID = yield* api.prompt(sessionID, prompt);
115
+ const translated = yield* Ref.make(Turn.initial({ inboxID, directory: realDirectory }));
116
+ const translate = (event) => Effect.flatMap(Ref.get(translated), (turn) => Effect.fromResult(Turn.translate(turn, event))).pipe(Effect.flatMap(([turn, parts]) => Effect.as(Ref.set(translated, turn), parts)), Effect.mapError((reason) => harnessError(reason)));
117
+ const ended = harnessError(new HarnessError.UnavailableError({
118
+ description: "opencode's events ended before the turn did"
119
+ }));
120
+ const turnParts = events.pipe(Stream.tap((event) => event.type === "form.created"
121
+ ? Effect.ignore(api.cancelForm(sessionID, event.data.form.id, "No one answers forms here"))
122
+ : Effect.void), Stream.concat(Stream.fail(ended)), Stream.mapEffect(translate), Stream.flattenIterable, Stream.takeUntil((part) => part.type === "finish"), Stream.tap((part) => (part.type === "finish" ? Ref.set(finished, true) : Effect.void)));
123
+ return Stream.merge(turnParts, hostCalls, { haltStrategy: "left" });
124
+ }));
125
+ /** Asks opencode to summarize the conversation, and waits for the summary it writes. */
126
+ const compact = Effect.fnUntraced(function* (instructions) {
127
+ if (instructions !== undefined && instructions.trim() !== "") {
128
+ return yield* harnessError(new HarnessError.UnsupportedError({
129
+ description: "opencode 2 summarizes a conversation without instructions"
130
+ }));
131
+ }
132
+ const events = yield* api.subscribe(sessionID);
133
+ yield* api.compact(sessionID);
134
+ const outcome = yield* events.pipe(Stream.filter((event) => (event.type === "session.compaction.ended" || event.type === "session.compaction.failed") &&
135
+ event.data.reason === "manual"), Stream.runHead, Effect.timeoutOrElse({
136
+ duration: "10 minutes",
137
+ orElse: () => Effect.fail(harnessError(new HarnessError.UnavailableError({
138
+ description: "opencode did not summarize the conversation within 10 minutes"
139
+ })))
140
+ }));
141
+ if (Option.isNone(outcome) || outcome.value.type !== "session.compaction.ended") {
142
+ return yield* harnessError(new HarnessError.UnknownError({
143
+ description: `opencode failed to summarize the conversation${Option.isSome(outcome) && outcome.value.type === "session.compaction.failed"
144
+ ? `: ${outcome.value.data.error.message}`
145
+ : ""}`
146
+ }));
147
+ }
148
+ return {
149
+ type: "compaction",
150
+ trigger: "manual",
151
+ summary: outcome.value.data.text
152
+ };
153
+ }, (effect) => Effect.scoped(effect));
154
+ const session = {
155
+ keptConversation: kept !== undefined,
156
+ promptTurn,
157
+ submitToolResult: relaySession.submitToolResult,
158
+ approve: ({ approvalId, approved, reason }) => api.replyPermission(sessionID, approvalId, approved ? "once" : "reject", approved ? undefined : reason),
159
+ compact,
160
+ state: Effect.flatMap(Ref.get(sessionModel), (model) => Effect.orDie(Schema.encodeEffect(StateJson)({ sessionID, model }))),
161
+ destroy: api.deleteSession(sessionID)
162
+ };
163
+ return session;
164
+ });
165
+ /** A new opencode session in `directory` on `model`, holding `history`. */
166
+ const createOpencodeSession = Effect.fnUntraced(function* (api, harnessError, directory, model, history) {
167
+ if (history.content.length === 0) {
168
+ const created = {
169
+ sessionID: yield* api.createSession(directory, model),
170
+ model
171
+ };
172
+ return created;
173
+ }
174
+ // opencode imports a session under the id it is given.
175
+ const crypto = yield* Crypto.Crypto;
176
+ const sessionID = `ses_${(yield* Effect.orDie(crypto.randomUUIDv4)).replaceAll("-", "")}`;
177
+ const now = yield* Clock.currentTimeMillis;
178
+ const messages = yield* Effect.fromResult(Prompt.messagesOf(history, { sessionID, now })).pipe(Effect.mapError((reason) => harnessError(reason)));
179
+ yield* api.importSession({ sessionID, directory, model, now, messages });
180
+ const imported = { sessionID, model };
181
+ return imported;
182
+ });
183
+ /** The model a turn that names `name` runs on, failing for a name the options do not give. */
184
+ const modelNamed = (harnessError, options, name) => {
185
+ if (name === undefined)
186
+ return Effect.succeed(options.model);
187
+ const model = Object.hasOwn(options.models, name) ? options.models[name] : undefined;
188
+ if (model !== undefined)
189
+ return Effect.succeed(model);
190
+ const description = `The opencode 2 agent has no model named ${name}`;
191
+ return Effect.fail(harnessError(new HarnessError.UnsupportedError({ description })));
192
+ };
193
+ const isSameModel = (one, other) => one.providerID === other.providerID && one.id === other.id && one.variant === other.variant;
194
+ /** The state `createSession` was given, if any, as the state `state` returned. */
195
+ const readState = (harnessError, json) => Schema.decodeEffect(Schema.UndefinedOr(StateJson))(json).pipe(Effect.mapError((cause) => harnessError(new HarnessError.AgentContractError({
196
+ description: `opencode cannot read the state it was given: ${cause.message}`
197
+ }), cause)));
198
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../../../src/internal/bridge/v2/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Translates the events of an opencode 2 turn into the parts a harness streams for it, one event at
3
+ * a time, from what the turn has done so far. The translation is pure: the session feeds it the
4
+ * events of its opencode session in order, from before the turn's prompt.
5
+ *
6
+ * The turn starts once opencode delivers its prompt to the session; what came before is earlier
7
+ * work. Text, reasoning, and a tool's input stream as opencode streams them, and every tool runs
8
+ * inside opencode, so its calls and results are `providerExecuted`, a result being what the model
9
+ * read. A file that `write`, `edit`, or `patch` changed is a `file-change`. A tool that asks
10
+ * permission streams a `tool-approval-request`, and a summary opencode writes of the conversation,
11
+ * as when it outgrows the model's context, is a `compaction`.
12
+ *
13
+ * The turn finishes once opencode stops running the session: `finish` then reports the turn's
14
+ * tokens, and the reason its last step ended, or `error` for a turn that failed, was stopped, or
15
+ * took no step.
16
+ */
17
+ import { HarnessError, type StreamPart } from "@amends-dev/harness";
18
+ import type * as Response from "effect/ai/Response";
19
+ import * as Result from "effect/Result";
20
+ import { type Tokens } from "../steps.ts";
21
+ import type { SessionEvent } from "./event.ts";
22
+ /** A text, a reasoning, or a tool's input the turn is streaming, and what it has streamed. */
23
+ interface Writing {
24
+ readonly written: string;
25
+ readonly ended: boolean;
26
+ }
27
+ /** What a turn has done so far, as its events told. */
28
+ export interface Turn {
29
+ /** The prompt that starts the turn, as the session queued it. */
30
+ readonly inboxID: string;
31
+ /** The directory the session works in, which the paths of the files it changes are within. */
32
+ readonly directory: string;
33
+ /** Whether opencode delivered the turn's prompt to the session. */
34
+ readonly started: boolean;
35
+ /** The texts and reasonings of the turn's steps, by part id. */
36
+ readonly writing: ReadonlyMap<string, Writing>;
37
+ /** The inputs of the turn's tool calls, by call id. */
38
+ readonly inputs: ReadonlyMap<string, Writing>;
39
+ /** The tools the turn called, by call id; a call and its result name only the call. */
40
+ readonly toolNames: ReadonlyMap<string, string>;
41
+ /** The tokens of the turn's ended steps, together. */
42
+ readonly tokens: Tokens;
43
+ /** Why the turn's last ended step ended, before any step has. */
44
+ readonly reason: Response.FinishReason | undefined;
45
+ /** Whether a step streamed an `error` part. */
46
+ readonly failedStep: boolean;
47
+ /** Whether the turn streamed its `finish` part. Events after it stream nothing. */
48
+ readonly finished: boolean;
49
+ }
50
+ /** The turn that the prompt `inboxID` starts in `directory`, before any of its events. */
51
+ export declare const initial: (options: {
52
+ readonly inboxID: string;
53
+ readonly directory: string;
54
+ }) => Turn;
55
+ type Translated = Result.Result<readonly [Turn, ReadonlyArray<StreamPart.StreamPart>], HarnessError.AgentContractError>;
56
+ /**
57
+ * The turn after the next event of its session, and the parts that event streams. Fails with
58
+ * `AgentContractError` for a call whose input the turn did not see start.
59
+ */
60
+ export declare const translate: (turn: Turn, event: SessionEvent) => Translated;
61
+ export {};
62
+ //# sourceMappingURL=turn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turn.d.ts","sourceRoot":"","sources":["../../../../src/internal/bridge/v2/turn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACnE,OAAO,KAAK,KAAK,QAAQ,MAAM,oBAAoB,CAAA;AACnD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,EAAuC,KAAK,MAAM,EAAW,MAAM,aAAa,CAAA;AACvF,OAAO,KAAK,EAAgB,YAAY,EAAe,MAAM,YAAY,CAAA;AAEzE,8FAA8F;AAC9F,UAAU,OAAO;IACf,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CACxB;AAED,uDAAuD;AACvD,MAAM,WAAW,IAAI;IACnB,iEAAiE;IACjE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IAExB,8FAA8F;IAC9F,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAE1B,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IAEzB,gEAAgE;IAChE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAE9C,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAE7C,uFAAuF;IACvF,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAE/C,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IAEvB,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,YAAY,GAAG,SAAS,CAAA;IAElD,+CAA+C;IAC/C,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAE5B,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAC3B;AAED,0FAA0F;AAC1F,eAAO,MAAM,OAAO,YAAa;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,KAAG,IAU1F,CAAA;AAEF,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,EAAE,YAAY,CAAC,kBAAkB,CAAC,CAAA;AAIvH;;;GAGG;AACH,eAAO,MAAM,SAAS,SAAU,IAAI,SAAS,YAAY,KAAG,UA+L3D,CAAA"}
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Translates the events of an opencode 2 turn into the parts a harness streams for it, one event at
3
+ * a time, from what the turn has done so far. The translation is pure: the session feeds it the
4
+ * events of its opencode session in order, from before the turn's prompt.
5
+ *
6
+ * The turn starts once opencode delivers its prompt to the session; what came before is earlier
7
+ * work. Text, reasoning, and a tool's input stream as opencode streams them, and every tool runs
8
+ * inside opencode, so its calls and results are `providerExecuted`, a result being what the model
9
+ * read. A file that `write`, `edit`, or `patch` changed is a `file-change`. A tool that asks
10
+ * permission streams a `tool-approval-request`, and a summary opencode writes of the conversation,
11
+ * as when it outgrows the model's context, is a `compaction`.
12
+ *
13
+ * The turn finishes once opencode stops running the session: `finish` then reports the turn's
14
+ * tokens, and the reason its last step ended, or `error` for a turn that failed, was stopped, or
15
+ * took no step.
16
+ */
17
+ import { HarnessError } from "@amends-dev/harness";
18
+ import * as Result from "effect/Result";
19
+ import * as Schema from "effect/Schema";
20
+ import { addTokens, finishReasonOf, noTokens, usageOf } from "../steps.js";
21
+ /** The turn that the prompt `inboxID` starts in `directory`, before any of its events. */
22
+ export const initial = (options) => ({
23
+ ...options,
24
+ started: false,
25
+ writing: new Map(),
26
+ inputs: new Map(),
27
+ toolNames: new Map(),
28
+ tokens: noTokens,
29
+ reason: undefined,
30
+ failedStep: false,
31
+ finished: false
32
+ });
33
+ const unchanged = (turn) => Result.succeed([turn, []]);
34
+ /**
35
+ * The turn after the next event of its session, and the parts that event streams. Fails with
36
+ * `AgentContractError` for a call whose input the turn did not see start.
37
+ */
38
+ export const translate = (turn, event) => {
39
+ if (turn.finished)
40
+ return unchanged(turn);
41
+ if (!turn.started) {
42
+ return event.type === "session.inbox.delivered" && event.data.inboxID === turn.inboxID
43
+ ? Result.succeed([{ ...turn, started: true }, []])
44
+ : unchanged(turn);
45
+ }
46
+ switch (event.type) {
47
+ case "session.step.started":
48
+ return Result.succeed([
49
+ turn,
50
+ [
51
+ {
52
+ type: "response-metadata",
53
+ id: event.data.assistantMessageID,
54
+ modelId: `${event.data.model.providerID}/${event.data.model.id}`,
55
+ timestamp: new Date(event.data.started).toISOString()
56
+ }
57
+ ]
58
+ ]);
59
+ case "session.text.started":
60
+ case "session.reasoning.started": {
61
+ const kind = event.type === "session.text.started" ? "text" : "reasoning";
62
+ const id = writingId(kind, event.data);
63
+ return Result.succeed([
64
+ { ...turn, writing: withEntry(turn.writing, id, { written: "", ended: false }) },
65
+ [{ type: `${kind}-start`, id }]
66
+ ]);
67
+ }
68
+ case "session.text.delta":
69
+ case "session.reasoning.delta": {
70
+ const kind = event.type === "session.text.delta" ? "text" : "reasoning";
71
+ const id = writingId(kind, event.data);
72
+ const [writing, parts] = writeOn(turn.writing.get(id), event.data.delta, (delta) => ({
73
+ type: `${kind}-delta`,
74
+ id,
75
+ delta
76
+ }));
77
+ return Result.succeed([{ ...turn, writing: withEntry(turn.writing, id, writing) }, parts]);
78
+ }
79
+ case "session.text.ended":
80
+ case "session.reasoning.ended": {
81
+ const kind = event.type === "session.text.ended" ? "text" : "reasoning";
82
+ const id = writingId(kind, event.data);
83
+ const [writing, parts] = endWith(turn.writing.get(id), event.data.text, (delta) => ({ type: `${kind}-delta`, id, delta }), { type: `${kind}-end`, id });
84
+ return Result.succeed([{ ...turn, writing: withEntry(turn.writing, id, writing) }, parts]);
85
+ }
86
+ case "session.tool.input.started": {
87
+ const { id, name } = event.data;
88
+ return Result.succeed([
89
+ {
90
+ ...turn,
91
+ inputs: withEntry(turn.inputs, id, { written: "", ended: false }),
92
+ toolNames: withEntry(turn.toolNames, id, name)
93
+ },
94
+ [{ type: "tool-params-start", id, name, providerExecuted: true }]
95
+ ]);
96
+ }
97
+ case "session.tool.input.delta": {
98
+ const { id, delta } = event.data;
99
+ const [input, parts] = writeOn(turn.inputs.get(id), delta, (written) => ({
100
+ type: "tool-params-delta",
101
+ id,
102
+ delta: written
103
+ }));
104
+ return Result.succeed([{ ...turn, inputs: withEntry(turn.inputs, id, input) }, parts]);
105
+ }
106
+ case "session.tool.input.ended": {
107
+ const { id, text } = event.data;
108
+ const [input, parts] = endWith(turn.inputs.get(id), text, (delta) => ({ type: "tool-params-delta", id, delta }), {
109
+ type: "tool-params-end",
110
+ id
111
+ });
112
+ return Result.succeed([{ ...turn, inputs: withEntry(turn.inputs, id, input) }, parts]);
113
+ }
114
+ case "session.tool.called":
115
+ return Result.map(nameOfCall(turn, event.data.id), (name) => [
116
+ turn,
117
+ [
118
+ {
119
+ type: "tool-call",
120
+ id: event.data.id,
121
+ name,
122
+ params: event.data.input,
123
+ providerExecuted: true
124
+ }
125
+ ]
126
+ ]);
127
+ case "session.tool.success":
128
+ return Result.map(nameOfCall(turn, event.data.id), (name) => [
129
+ turn,
130
+ [
131
+ {
132
+ type: "tool-result",
133
+ id: event.data.id,
134
+ name,
135
+ result: event.data.content,
136
+ isFailure: false,
137
+ providerExecuted: true
138
+ },
139
+ ...fileChangesOf(turn.directory, name, event.data.content, event.data.metadata)
140
+ ]
141
+ ]);
142
+ case "session.tool.failed":
143
+ return Result.map(nameOfCall(turn, event.data.id), (name) => [
144
+ turn,
145
+ [
146
+ {
147
+ type: "tool-result",
148
+ id: event.data.id,
149
+ name,
150
+ result: event.data.error.message,
151
+ isFailure: true,
152
+ providerExecuted: true
153
+ }
154
+ ]
155
+ ]);
156
+ case "session.step.ended": {
157
+ const reason = finishReasonOf(event.data.finish);
158
+ return Result.succeed([
159
+ { ...turn, tokens: addTokens(turn.tokens, event.data.tokens), reason },
160
+ [{ type: "finish-step", reason, usage: usageOf(event.data.tokens) }]
161
+ ]);
162
+ }
163
+ case "session.step.failed":
164
+ return Result.succeed([
165
+ { ...turn, reason: "error", failedStep: true },
166
+ [
167
+ { type: "error", error: event.data.error },
168
+ { type: "finish-step", reason: "error", usage: usageOf(noTokens) }
169
+ ]
170
+ ]);
171
+ case "session.compaction.ended":
172
+ return Result.succeed([turn, [{ type: "compaction", trigger: event.data.reason, summary: event.data.text }]]);
173
+ case "permission.asked":
174
+ return Result.succeed([
175
+ turn,
176
+ [
177
+ {
178
+ type: "tool-approval-request",
179
+ approvalId: event.data.id,
180
+ toolCallId: event.data.source?.id ?? event.data.id
181
+ }
182
+ ]
183
+ ]);
184
+ case "session.execution.succeeded":
185
+ return Result.succeed(finish(turn, turn.reason === undefined ? { type: "unknown", message: "opencode ended the turn without a step" } : undefined));
186
+ case "session.execution.failed":
187
+ return Result.succeed(finish(turn, event.data.error));
188
+ case "session.execution.interrupted":
189
+ return Result.succeed(finish(turn, {
190
+ type: "interrupted",
191
+ message: `opencode stopped the turn, interrupted by ${event.data.reason}`
192
+ }));
193
+ // A compaction fails the turn's execution, if it does, with an event of its own, and the
194
+ // session answers forms itself.
195
+ case "session.inbox.delivered":
196
+ case "session.execution.started":
197
+ case "session.compaction.failed":
198
+ case "form.created":
199
+ return unchanged(turn);
200
+ }
201
+ };
202
+ /** The id the turn streams a text or a reasoning by: its kind, step, and number within the step. */
203
+ const writingId = (kind, data) => `${data.assistantMessageID}-${kind}-${data.ordinal}`;
204
+ /** `delta` written on `writing`, streamed as `partOf` makes it unless the writing has ended. */
205
+ const writeOn = (writing, delta, partOf) => {
206
+ const known = writing ?? { written: "", ended: false };
207
+ if (known.ended)
208
+ return [known, []];
209
+ return [{ ...known, written: known.written + delta }, [partOf(delta)]];
210
+ };
211
+ /**
212
+ * `writing` ended as the whole `text`: what its deltas missed streams first, as `partOf` makes it,
213
+ * then `end`.
214
+ */
215
+ const endWith = (writing, text, partOf, end) => {
216
+ const known = writing ?? { written: "", ended: false };
217
+ if (known.ended)
218
+ return [known, []];
219
+ const missed = text.length > known.written.length && text.startsWith(known.written)
220
+ ? [partOf(text.slice(known.written.length))]
221
+ : [];
222
+ return [{ written: text, ended: true }, [...missed, end]];
223
+ };
224
+ const nameOfCall = (turn, id) => {
225
+ const name = turn.toolNames.get(id);
226
+ return name === undefined
227
+ ? Result.fail(new HarnessError.AgentContractError({
228
+ description: `opencode reported the call ${id}, whose input the turn did not see start`
229
+ }))
230
+ : Result.succeed(name);
231
+ };
232
+ /** The files of an edit or a patch, as their tools report them. */
233
+ const ChangedFiles = Schema.Array(Schema.Struct({ file: Schema.String, status: Schema.Literals(["added", "deleted", "modified"]) }));
234
+ const events = { added: "create", deleted: "delete", modified: "modify" };
235
+ /**
236
+ * The files a call of `name` changed, by their paths within `directory`, or as they are when
237
+ * outside it: `edit` and `patch` report them in their metadata, and `write` in what it tells the
238
+ * model. Other tools, such as `shell`, do not say which files they change.
239
+ */
240
+ const fileChangesOf = (directory, name, content, metadata) => {
241
+ const pathOf = (file) => (file.startsWith(`${directory}/`) ? file.slice(directory.length + 1) : file);
242
+ const files = metadata?.["files"];
243
+ if (Schema.is(ChangedFiles)(files)) {
244
+ return files.map(({ file, status }) => ({
245
+ type: "file-change",
246
+ event: events[status],
247
+ path: pathOf(file)
248
+ }));
249
+ }
250
+ const [first] = content;
251
+ if (name !== "write" || first?.type !== "text")
252
+ return [];
253
+ const written = /^(Created|Wrote) file successfully: (.+)$/.exec(first.text);
254
+ if (written === null)
255
+ return [];
256
+ return [
257
+ {
258
+ type: "file-change",
259
+ event: written[1] === "Created" ? "create" : "modify",
260
+ path: pathOf(written[2] ?? "")
261
+ }
262
+ ];
263
+ };
264
+ /** Finishes the turn: with `failure`, unless a step reported its own, then `finish`. */
265
+ const finish = (turn, failure) => {
266
+ const parts = [];
267
+ if (failure !== undefined && !turn.failedStep)
268
+ parts.push({ type: "error", error: failure });
269
+ parts.push({
270
+ type: "finish",
271
+ reason: failure !== undefined || turn.failedStep ? "error" : (turn.reason ?? "other"),
272
+ usage: usageOf(turn.tokens)
273
+ });
274
+ return [{ ...turn, finished: true }, parts];
275
+ };
276
+ const withEntry = (map, key, value) => new Map(map).set(key, value);
277
+ //# sourceMappingURL=turn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turn.js","sourceRoot":"","sources":["../../../../src/internal/bridge/v2/turn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,YAAY,EAAmB,MAAM,qBAAqB,CAAA;AAEnE,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAe,OAAO,EAAE,MAAM,aAAa,CAAA;AA0CvF,0FAA0F;AAC1F,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,OAAiE,EAAQ,EAAE,CAAC,CAAC;IACnG,GAAG,OAAO;IACV,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,IAAI,GAAG,EAAE;IAClB,MAAM,EAAE,IAAI,GAAG,EAAE;IACjB,SAAS,EAAE,IAAI,GAAG,EAAE;IACpB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,SAAS;IACjB,UAAU,EAAE,KAAK;IACjB,QAAQ,EAAE,KAAK;CAChB,CAAC,CAAA;AAIF,MAAM,SAAS,GAAG,CAAC,IAAU,EAAc,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAA;AAExE;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAU,EAAE,KAAmB,EAAc,EAAE;IACvE,IAAI,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC,IAAI,CAAC,CAAA;IACzC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,KAAK,CAAC,IAAI,KAAK,yBAAyB,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO;YACpF,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YAClD,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;IACrB,CAAC;IACD,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,sBAAsB;YACzB,OAAO,MAAM,CAAC,OAAO,CAAC;gBACpB,IAAI;gBACJ;oBACE;wBACE,IAAI,EAAE,mBAAmB;wBACzB,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,kBAAkB;wBACjC,OAAO,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE;wBAChE,SAAS,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE;qBACtD;iBACF;aACF,CAAC,CAAA;QAEJ,KAAK,sBAAsB,CAAC;QAC5B,KAAK,2BAA2B,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,sBAAsB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAA;YACzE,MAAM,EAAE,GAAG,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;YACtC,OAAO,MAAM,CAAC,OAAO,CAAC;gBACpB,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE;gBAChF,CAAC,EAAE,IAAI,EAAE,GAAG,IAAI,QAAQ,EAAE,EAAE,EAAE,CAAC;aAChC,CAAC,CAAA;QACJ,CAAC;QAED,KAAK,oBAAoB,CAAC;QAC1B,KAAK,yBAAyB,EAAE,CAAC;YAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,oBAAoB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAA;YACvE,MAAM,EAAE,GAAG,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;YACtC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBACnF,IAAI,EAAE,GAAG,IAAI,QAAQ;gBACrB,EAAE;gBACF,KAAK;aACN,CAAC,CAAC,CAAA;YACH,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAA;QAC5F,CAAC;QAED,KAAK,oBAAoB,CAAC;QAC1B,KAAK,yBAAyB,EAAE,CAAC;YAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,oBAAoB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAA;YACvE,MAAM,EAAE,GAAG,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;YACtC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,OAAO,CAC9B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EACpB,KAAK,CAAC,IAAI,CAAC,IAAI,EACf,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,IAAI,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EACjD,EAAE,IAAI,EAAE,GAAG,IAAI,MAAM,EAAE,EAAE,EAAE,CAC5B,CAAA;YACD,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAA;QAC5F,CAAC;QAED,KAAK,4BAA4B,EAAE,CAAC;YAClC,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,CAAA;YAC/B,OAAO,MAAM,CAAC,OAAO,CAAC;gBACpB;oBACE,GAAG,IAAI;oBACP,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;oBACjE,SAAS,EAAE,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,EAAE,IAAI,CAAC;iBAC/C;gBACD,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC;aAClE,CAAC,CAAA;QACJ,CAAC;QAED,KAAK,0BAA0B,EAAE,CAAC;YAChC,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,IAAI,CAAA;YAChC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBACvE,IAAI,EAAE,mBAAmB;gBACzB,EAAE;gBACF,KAAK,EAAE,OAAO;aACf,CAAC,CAAC,CAAA;YACH,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAA;QACxF,CAAC;QAED,KAAK,0BAA0B,EAAE,CAAC;YAChC,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,CAAA;YAC/B,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE;gBAC/G,IAAI,EAAE,iBAAiB;gBACvB,EAAE;aACH,CAAC,CAAA;YACF,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAA;QACxF,CAAC;QAED,KAAK,qBAAqB;YACxB,OAAO,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;gBAC3D,IAAI;gBACJ;oBACE;wBACE,IAAI,EAAE,WAAW;wBACjB,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE;wBACjB,IAAI;wBACJ,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK;wBACxB,gBAAgB,EAAE,IAAI;qBACvB;iBACF;aACF,CAAC,CAAA;QAEJ,KAAK,sBAAsB;YACzB,OAAO,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;gBAC3D,IAAI;gBACJ;oBACE;wBACE,IAAI,EAAE,aAAa;wBACnB,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE;wBACjB,IAAI;wBACJ,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO;wBAC1B,SAAS,EAAE,KAAK;wBAChB,gBAAgB,EAAE,IAAI;qBACvB;oBACD,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;iBAChF;aACF,CAAC,CAAA;QAEJ,KAAK,qBAAqB;YACxB,OAAO,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;gBAC3D,IAAI;gBACJ;oBACE;wBACE,IAAI,EAAE,aAAa;wBACnB,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE;wBACjB,IAAI;wBACJ,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO;wBAChC,SAAS,EAAE,IAAI;wBACf,gBAAgB,EAAE,IAAI;qBACvB;iBACF;aACF,CAAC,CAAA;QAEJ,KAAK,oBAAoB,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YAChD,OAAO,MAAM,CAAC,OAAO,CAAC;gBACpB,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE;gBACtE,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;aACrE,CAAC,CAAA;QACJ,CAAC;QAED,KAAK,qBAAqB;YACxB,OAAO,MAAM,CAAC,OAAO,CAAC;gBACpB,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE;gBAC9C;oBACE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE;oBAC1C,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE;iBACnE;aACF,CAAC,CAAA;QAEJ,KAAK,0BAA0B;YAC7B,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;QAE/G,KAAK,kBAAkB;YACrB,OAAO,MAAM,CAAC,OAAO,CAAC;gBACpB,IAAI;gBACJ;oBACE;wBACE,IAAI,EAAE,uBAAuB;wBAC7B,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE;wBACzB,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE;qBACnD;iBACF;aACF,CAAC,CAAA;QAEJ,KAAK,6BAA6B;YAChC,OAAO,MAAM,CAAC,OAAO,CACnB,MAAM,CACJ,IAAI,EACJ,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,wCAAwC,EAAE,CAAC,CAAC,CAAC,SAAS,CAC/G,CACF,CAAA;QAEH,KAAK,0BAA0B;YAC7B,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;QAEvD,KAAK,+BAA+B;YAClC,OAAO,MAAM,CAAC,OAAO,CACnB,MAAM,CAAC,IAAI,EAAE;gBACX,IAAI,EAAE,aAAa;gBACnB,OAAO,EAAE,6CAA6C,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE;aAC1E,CAAC,CACH,CAAA;QAEH,yFAAyF;QACzF,gCAAgC;QAChC,KAAK,yBAAyB,CAAC;QAC/B,KAAK,2BAA2B,CAAC;QACjC,KAAK,2BAA2B,CAAC;QACjC,KAAK,cAAc;YACjB,OAAO,SAAS,CAAC,IAAI,CAAC,CAAA;IAC1B,CAAC;AACH,CAAC,CAAA;AAED,oGAAoG;AACpG,MAAM,SAAS,GAAG,CAChB,IAA0B,EAC1B,IAAuE,EACvE,EAAE,CAAC,GAAG,IAAI,CAAC,kBAAkB,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAA;AAEzD,gGAAgG;AAChG,MAAM,OAAO,GAAG,CACd,OAA4B,EAC5B,KAAa,EACb,MAAgD,EACU,EAAE;IAC5D,MAAM,KAAK,GAAG,OAAO,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;IACtD,IAAI,KAAK,CAAC,KAAK;QAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IACnC,OAAO,CAAC,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,GAAG,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AACxE,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,OAAO,GAAG,CACd,OAA4B,EAC5B,IAAY,EACZ,MAAgD,EAChD,GAA0B,EACgC,EAAE;IAC5D,MAAM,KAAK,GAAG,OAAO,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;IACtD,IAAI,KAAK,CAAC,KAAK;QAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IACnC,MAAM,MAAM,GACV,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC;QAClE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QAC5C,CAAC,CAAC,EAAE,CAAA;IACR,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA;AAC3D,CAAC,CAAA;AAED,MAAM,UAAU,GAAG,CAAC,IAAU,EAAE,EAAU,EAAE,EAAE;IAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IACnC,OAAO,IAAI,KAAK,SAAS;QACvB,CAAC,CAAC,MAAM,CAAC,IAAI,CACT,IAAI,YAAY,CAAC,kBAAkB,CAAC;YAClC,WAAW,EAAE,8BAA8B,EAAE,0CAA0C;SACxF,CAAC,CACH;QACH,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC,CAAA;AAED,mEAAmE;AACnE,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAC/B,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAClG,CAAA;AAED,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAW,CAAA;AAElF;;;;GAIG;AACH,MAAM,aAAa,GAAG,CACpB,SAAiB,EACjB,IAAY,EACZ,OAAmC,EACnC,QAAuD,EACjB,EAAE;IACxC,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;IAC7G,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAA;IACjC,IAAI,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;YACtC,IAAI,EAAE,aAAa;YACnB,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC;YACrB,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC;SACnB,CAAC,CAAC,CAAA;IACL,CAAC;IACD,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAA;IACvB,IAAI,IAAI,KAAK,OAAO,IAAI,KAAK,EAAE,IAAI,KAAK,MAAM;QAAE,OAAO,EAAE,CAAA;IACzD,MAAM,OAAO,GAAG,2CAA2C,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC5E,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,CAAA;IAC/B,OAAO;QACL;YACE,IAAI,EAAE,aAAa;YACnB,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ;YACrD,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SAC/B;KACF,CAAA;AACH,CAAC,CAAA;AAED,wFAAwF;AACxF,MAAM,MAAM,GAAG,CACb,IAAU,EACV,OAAiC,EACsB,EAAE;IACzD,MAAM,KAAK,GAAiC,EAAE,CAAA;IAC9C,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,UAAU;QAAE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;IAC5F,KAAK,CAAC,IAAI,CAAC;QACT,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC;QACrF,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;KAC5B,CAAC,CAAA;IACF,OAAO,CAAC,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,KAAK,CAAC,CAAA;AAC7C,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,CAAO,GAAsB,EAAE,GAAM,EAAE,KAAQ,EAAqB,EAAE,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * The models opencode runs on, made from model endpoints: what opencode's server takes to serve
3
+ * them, its providers and the variables it runs with, and each endpoint's model as opencode names
4
+ * it. opencode serves a model through the endpoint's protocol, at its URL, within its limits, and
5
+ * with the key and headers of its provider. An endpoint's effort is a variant of the model, which
6
+ * the endpoint's model names.
7
+ *
8
+ * opencode 1 and opencode 2 configure providers apart: opencode 1 names them `provider`, and
9
+ * opencode 2 `providers`, each in a shape of its own. Both give a model its AI SDK package and URL,
10
+ * and a variant the AI SDK options that ask for its effort, and both find the providers and models
11
+ * that models.dev lists by their ids, as endpoints name them, knowing the rest of a model from
12
+ * there, such as whether it calls tools.
13
+ */
14
+ import { HarnessError, type ModelEndpoint } from "@amends-dev/harness";
15
+ import * as Result from "effect/Result";
16
+ import type * as Schema from "effect/Schema";
17
+ import type { ModelRef } from "./bridge/driver.ts";
18
+ import type { Version } from "./template.ts";
19
+ type JsonObject = {
20
+ readonly [field: string]: Schema.Json;
21
+ };
22
+ export interface Models {
23
+ /** The fields of opencode's configuration that serve the endpoints' models: its providers. */
24
+ readonly config: JsonObject;
25
+ /** The environment variables opencode's server serves the models with. */
26
+ readonly env: {
27
+ readonly [name: string]: string;
28
+ };
29
+ /** The model a turn runs on when it names none. */
30
+ readonly model: ModelRef;
31
+ /** The models a turn can name, by name. */
32
+ readonly models: {
33
+ readonly [name: string]: ModelRef;
34
+ };
35
+ }
36
+ /**
37
+ * The models opencode `version` runs on for the endpoint `model`, and `models` by name. opencode
38
+ * presents one key, with one set of headers, for each provider, and serves a model through one
39
+ * protocol, at one URL, within one output limit and context window, so endpoints that differ in
40
+ * them fail with `UnsupportedError`.
41
+ */
42
+ export declare const modelsOf: (version: Version, endpoints: {
43
+ readonly model: ModelEndpoint.ModelEndpoint;
44
+ readonly models?: Readonly<Record<string, ModelEndpoint.ModelEndpoint>> | undefined;
45
+ }) => Result.Result<Models, HarnessError.UnsupportedError>;
46
+ export {};
47
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/internal/models.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAItE,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAA;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAI5C,KAAK,UAAU,GAAG;IAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,CAAA;CAAE,CAAA;AAE3D,MAAM,WAAW,MAAM;IACrB,8FAA8F;IAC9F,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;IAE3B,0EAA0E;IAC1E,QAAQ,CAAC,GAAG,EAAE;QAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAA;IAEjD,mDAAmD;IACnD,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;IAExB,2CAA2C;IAC3C,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAA;KAAE,CAAA;CACvD;AAED;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,YACV,OAAO,aACL;IACT,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,aAAa,CAAA;IAC3C,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC,GAAG,SAAS,CAAA;CACpF,KACA,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,gBAAgB,CAqBrD,CAAA"}