summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--js/src/bus/index.ts11
-rw-r--r--js/src/index.ts8
-rw-r--r--js/src/server/server.ts1
-rw-r--r--js/src/session/message.ts11
-rw-r--r--js/src/session/session.ts25
-rw-r--r--pkg/client/event.go4
-rw-r--r--pkg/client/gen/event.json26
-rw-r--r--pkg/client/generated-event.go52
8 files changed, 116 insertions, 22 deletions
diff --git a/js/src/bus/index.ts b/js/src/bus/index.ts
index 82bc614e0..15d2b1107 100644
--- a/js/src/bus/index.ts
+++ b/js/src/bus/index.ts
@@ -30,17 +30,6 @@ export namespace Bus {
return result;
}
- export function payloads() {
- return registry
- .entries()
- .map(([type, def]) =>
- z.object({
- type: z.string("hey"),
- }),
- )
- .toArray();
- }
-
export function specs() {
const children = {} as any;
for (const [type, def] of registry.entries()) {
diff --git a/js/src/index.ts b/js/src/index.ts
index d5b388166..380ea64cd 100644
--- a/js/src/index.ts
+++ b/js/src/index.ts
@@ -1,3 +1,4 @@
+import "zod-openapi/extend";
import { App } from "./app";
import { Server } from "./server/server";
import fs from "fs/promises";
@@ -15,13 +16,6 @@ cli.command("", "Start the opencode in interactive mode").action(async () => {
await App.provide({ directory: process.cwd() }, async () => {
await Share.init();
Server.listen();
-
- Bun.spawnSync({
- stderr: "inherit",
- stdout: "inherit",
- stdin: "inherit",
- cmd: ["go", "run", "cmd/main.go"],
- });
});
});
diff --git a/js/src/server/server.ts b/js/src/server/server.ts
index 2f388a183..f56c87283 100644
--- a/js/src/server/server.ts
+++ b/js/src/server/server.ts
@@ -6,7 +6,6 @@ import { streamSSE } from "hono/streaming";
import { Session } from "../session/session";
import { resolver, validator as zValidator } from "hono-openapi/zod";
import { z } from "zod";
-import "zod-openapi/extend";
import { Config } from "../app/config";
import { LLM } from "../llm/llm";
import { Message } from "../session/message";
diff --git a/js/src/session/message.ts b/js/src/session/message.ts
index 75c22ef0b..91bcd19b4 100644
--- a/js/src/session/message.ts
+++ b/js/src/session/message.ts
@@ -1,6 +1,17 @@
import z from "zod";
+import { z as zv4 } from "zod/v4";
+import { Bus } from "../bus";
export namespace Message {
+ export const Event = {
+ Updated: Bus.event(
+ "message.updated",
+ zv4.object({
+ sessionID: zv4.string(),
+ messageID: zv4.string(),
+ }),
+ ),
+ };
export const ToolCall = z
.object({
state: z.literal("call"),
diff --git a/js/src/session/session.ts b/js/src/session/session.ts
index abeb29842..a876976bd 100644
--- a/js/src/session/session.ts
+++ b/js/src/session/session.ts
@@ -11,6 +11,7 @@ import {
streamText,
} from "ai";
import { z } from "zod";
+import { z as zv4 } from "zod/v4";
import * as tools from "../tool";
import { Decimal } from "decimal.js";
@@ -18,7 +19,8 @@ import PROMPT_ANTHROPIC from "./prompt/anthropic.txt";
import PROMPT_TITLE from "./prompt/title.txt";
import { Share } from "../share/share";
-import type { Message } from "./message";
+import { Message } from "./message";
+import { Bus } from "../bus";
export namespace Session {
const log = Log.create({ service: "session" });
@@ -30,6 +32,15 @@ export namespace Session {
});
export type Info = z.output<typeof Info>;
+ export const Event = {
+ Updated: Bus.event(
+ "session.updated",
+ zv4.object({
+ sessionID: zv4.string(),
+ }),
+ ),
+ };
+
const state = App.state("session", () => {
const sessions = new Map<string, Info>();
const messages = new Map<string, Message.Info[]>();
@@ -49,6 +60,9 @@ export namespace Session {
state().sessions.set(result.id, result);
await Storage.writeJSON("session/info/" + result.id, result);
await share(result.id);
+ Bus.publish(Event.Updated, {
+ sessionID: result.id,
+ });
return result;
}
@@ -80,6 +94,9 @@ export namespace Session {
editor(session);
sessions.set(id, session);
await Storage.writeJSON("session/info/" + id, session);
+ Bus.publish(Event.Updated, {
+ sessionID: id,
+ });
return session;
}
@@ -126,10 +143,14 @@ export namespace Session {
const model = await LLM.findModel(input.providerID, input.modelID);
const msgs = await messages(input.sessionID);
async function write(msg: Message.Info) {
- return Storage.writeJSON(
+ await Storage.writeJSON(
"session/message/" + input.sessionID + "/" + msg.id,
msg,
);
+ Bus.publish(Message.Event.Updated, {
+ sessionID: input.sessionID,
+ messageID: msg.id,
+ });
}
const app = await App.use();
if (msgs.length === 0) {
diff --git a/pkg/client/event.go b/pkg/client/event.go
index 8873bdf7b..a43c4c8ea 100644
--- a/pkg/client/event.go
+++ b/pkg/client/event.go
@@ -10,7 +10,9 @@ import (
)
var EventMap = map[string]any{
- "storage.write": EventStorageWrite{},
+ "storage.write": EventStorageWrite{},
+ "session.updated": EventSessionUpdated{},
+ "message.updated": EventMessageUpdated{},
}
type EventMessage struct {
diff --git a/pkg/client/gen/event.json b/pkg/client/gen/event.json
index e9b9256e9..e40f1308f 100644
--- a/pkg/client/gen/event.json
+++ b/pkg/client/gen/event.json
@@ -29,6 +29,32 @@
"serverID",
"path"
]
+ },
+ "event.message.updated": {
+ "type": "object",
+ "properties": {
+ "sessionID": {
+ "type": "string"
+ },
+ "messageID": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "sessionID",
+ "messageID"
+ ]
+ },
+ "event.session.updated": {
+ "type": "object",
+ "properties": {
+ "sessionID": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "sessionID"
+ ]
}
}
} \ No newline at end of file
diff --git a/pkg/client/generated-event.go b/pkg/client/generated-event.go
index 0d8e67eb7..12485b648 100644
--- a/pkg/client/generated-event.go
+++ b/pkg/client/generated-event.go
@@ -34,6 +34,58 @@ func (j *EventLspClientDiagnostics) UnmarshalJSON(value []byte) error {
return nil
}
+type EventMessageUpdated struct {
+ // MessageID corresponds to the JSON schema field "messageID".
+ MessageID string `json:"messageID" yaml:"messageID" mapstructure:"messageID"`
+
+ // SessionID corresponds to the JSON schema field "sessionID".
+ SessionID string `json:"sessionID" yaml:"sessionID" mapstructure:"sessionID"`
+}
+
+// UnmarshalJSON implements json.Unmarshaler.
+func (j *EventMessageUpdated) UnmarshalJSON(value []byte) error {
+ var raw map[string]interface{}
+ if err := json.Unmarshal(value, &raw); err != nil {
+ return err
+ }
+ if _, ok := raw["messageID"]; raw != nil && !ok {
+ return fmt.Errorf("field messageID in EventMessageUpdated: required")
+ }
+ if _, ok := raw["sessionID"]; raw != nil && !ok {
+ return fmt.Errorf("field sessionID in EventMessageUpdated: required")
+ }
+ type Plain EventMessageUpdated
+ var plain Plain
+ if err := json.Unmarshal(value, &plain); err != nil {
+ return err
+ }
+ *j = EventMessageUpdated(plain)
+ return nil
+}
+
+type EventSessionUpdated struct {
+ // SessionID corresponds to the JSON schema field "sessionID".
+ SessionID string `json:"sessionID" yaml:"sessionID" mapstructure:"sessionID"`
+}
+
+// UnmarshalJSON implements json.Unmarshaler.
+func (j *EventSessionUpdated) UnmarshalJSON(value []byte) error {
+ var raw map[string]interface{}
+ if err := json.Unmarshal(value, &raw); err != nil {
+ return err
+ }
+ if _, ok := raw["sessionID"]; raw != nil && !ok {
+ return fmt.Errorf("field sessionID in EventSessionUpdated: required")
+ }
+ type Plain EventSessionUpdated
+ var plain Plain
+ if err := json.Unmarshal(value, &plain); err != nil {
+ return err
+ }
+ *j = EventSessionUpdated(plain)
+ return nil
+}
+
type EventStorageWrite struct {
// Content corresponds to the JSON schema field "content".
Content interface{} `json:"content" yaml:"content" mapstructure:"content"`