Skip to content

Commit d903526

Browse files
committed
improve client with retries
1 parent 8f1cb57 commit d903526

File tree

7 files changed

+184
-79
lines changed

7 files changed

+184
-79
lines changed

.changeset/neat-buttons-care.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"opencontrol": patch
3+
---
4+
5+
improve client with retries

bun.lock

Lines changed: 64 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/bun/index.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,27 @@
11
import { create } from "opencontrol"
22
import { tool } from "opencontrol/tool"
3+
import { z } from "zod"
4+
import AWS from "aws-sdk"
5+
6+
const aws = tool({
7+
name: "aws",
8+
description: "Make a call to the AWS SDK for JavaScript v2",
9+
args: z.object({
10+
client: z.string().describe("Class name of the client to use"),
11+
command: z.string().describe("Command to call on the client"),
12+
args: z
13+
.record(z.string(), z.any())
14+
.optional()
15+
.describe("Arguments to pass to the command"),
16+
}),
17+
async run(input) {
18+
// @ts-ignore
19+
const client = new AWS[input.client]()
20+
return await client[input.command](input.args).promise()
21+
},
22+
})
323

424
export default create({
5-
key: "hello",
625
anthropicApiKey: process.env.ANTHROPIC_API_KEY,
7-
tools: [
8-
tool({
9-
name: "hello",
10-
description: "say hello",
11-
run: async () => {
12-
return "Hey there!"
13-
},
14-
}),
15-
],
26+
tools: [aws],
1627
})

examples/bun/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
"private": true,
44
"version": "0.0.9",
55
"dependencies": {
6-
"opencontrol": "workspace:*"
6+
"aws-sdk": "2.1692.0",
7+
"opencontrol": "workspace:*",
8+
"zod": "3.24.2"
79
}
810
}

packages/frontend/src/index.tsx

Lines changed: 89 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import './index.css';
88
import { LanguageModelV1Prompt } from "ai"
99
import { createAnthropic } from "@ai-sdk/anthropic"
1010
import { createOpenAI } from "@ai-sdk/openai"
11+
import { createEffect } from 'solid-js';
1112

1213
const root = document.getElementById('root');
1314

@@ -20,7 +21,7 @@ if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
2021
render(() => <App />, root!);
2122

2223
const anthropic = createAnthropic({
23-
apiKey: "{ANTHROPIC_API_KEY}",
24+
apiKey: import.meta.env.VITE_ANTHROPIC_API_KEY || "{ANTHROPIC_API_KEY}",
2425
headers: {
2526
"anthropic-dangerous-direct-browser-access": "true"
2627
},
@@ -40,7 +41,7 @@ const providerMetadata = {
4041
},
4142
}
4243

43-
const OPENCONTROL_ENDPOINT = "mcp"
44+
const OPENCONTROL_ENDPOINT = import.meta.env.VITE_OPENCONTROL_ENDPOINT || "mcp"
4445
const toolDefs = await fetch(OPENCONTROL_ENDPOINT, {
4546
method: "POST",
4647
headers: {
@@ -56,6 +57,8 @@ const toolDefs = await fetch(OPENCONTROL_ENDPOINT, {
5657
.then((response) => response.result.tools)
5758

5859
function App() {
60+
let root: HTMLDivElement | undefined
61+
5962
const [store, setStore] = createStore<{
6063
prompt: LanguageModelV1Prompt
6164
}>({
@@ -71,9 +74,27 @@ function App() {
7174
},
7275
},
7376
},
77+
{
78+
role: "system",
79+
content: `The current date is ${new Date().toDateString()}`,
80+
providerMetadata: {
81+
anthropic: {
82+
cacheControl: {
83+
type: "ephemeral",
84+
},
85+
},
86+
},
87+
}
7488
],
7589
})
7690

91+
createEffect(() => {
92+
const messages = store.prompt
93+
console.log("scrolling to bottom")
94+
root?.scrollTo(0, root?.scrollHeight)
95+
return messages.length
96+
}, 0)
97+
7798
async function send(message: string) {
7899
setStore("prompt",
79100
store.prompt.length,
@@ -89,80 +110,85 @@ function App() {
89110
}
90111
)
91112
while (true) {
92-
const result = await provider.doGenerate({
93-
prompt: store.prompt,
94-
mode: {
95-
type: "regular",
96-
tools: toolDefs.map((tool: any) => ({
97-
type: "function",
98-
name: tool.name,
99-
description: tool.description,
100-
parameters: {
101-
...tool.inputSchema,
102-
},
103-
})),
104-
},
105-
inputFormat: "messages",
106-
temperature: 1,
107-
})
108-
console.log(result)
109-
110-
if (result.text) {
111-
setStore("prompt", store.prompt.length, {
112-
role: "assistant",
113-
content: [{
114-
type: "text",
115-
text: result.text,
116-
}]
113+
try {
114+
const result = await provider.doGenerate({
115+
prompt: store.prompt,
116+
mode: {
117+
type: "regular",
118+
tools: toolDefs.map((tool: any) => ({
119+
type: "function",
120+
name: tool.name,
121+
description: tool.description,
122+
parameters: {
123+
...tool.inputSchema,
124+
},
125+
})),
126+
},
127+
inputFormat: "messages",
128+
temperature: 1,
117129
})
118-
}
119130

120-
if (result.finishReason === "stop")
121-
break
122-
if (result.finishReason === "tool-calls") {
123-
for (const item of result.toolCalls!) {
124-
console.log("calling tool", item.toolName, item.args)
131+
if (result.text) {
125132
setStore("prompt", store.prompt.length, {
126133
role: "assistant",
127-
content: result.toolCalls!.map(item => ({
128-
type: "tool-call",
129-
toolName: item.toolName,
130-
args: JSON.parse(item.args),
131-
toolCallId: item.toolCallId,
132-
}))
133-
})
134-
const response = await fetch(OPENCONTROL_ENDPOINT, {
135-
method: "POST",
136-
headers: {
137-
"Content-Type": "application/json",
138-
},
139-
body: JSON.stringify({
140-
jsonrpc: "2.0",
141-
id: "2",
142-
method: "tools/call",
143-
params: {
144-
name: item.toolName,
145-
arguments: JSON.parse(item.args),
146-
},
147-
}),
148-
}).then((response) => response.json())
149-
setStore("prompt", store.prompt.length, {
150-
role: "tool",
151134
content: [{
152-
type: "tool-result",
153-
toolName: item.toolName,
154-
toolCallId: item.toolCallId,
155-
result: response,
156-
}],
135+
type: "text",
136+
text: result.text,
137+
}]
157138
})
158139
}
140+
141+
if (result.finishReason === "stop")
142+
break
143+
if (result.finishReason === "tool-calls") {
144+
for (const item of result.toolCalls!) {
145+
console.log("calling tool", item.toolName, item.args)
146+
setStore("prompt", store.prompt.length, {
147+
role: "assistant",
148+
content: result.toolCalls!.map(item => ({
149+
type: "tool-call",
150+
toolName: item.toolName,
151+
args: JSON.parse(item.args),
152+
toolCallId: item.toolCallId,
153+
}))
154+
})
155+
const response = await fetch(OPENCONTROL_ENDPOINT, {
156+
method: "POST",
157+
headers: {
158+
"Content-Type": "application/json",
159+
},
160+
body: JSON.stringify({
161+
jsonrpc: "2.0",
162+
id: "2",
163+
method: "tools/call",
164+
params: {
165+
name: item.toolName,
166+
arguments: JSON.parse(item.args),
167+
},
168+
}),
169+
}).then((response) => response.json())
170+
setStore("prompt", store.prompt.length, {
171+
role: "tool",
172+
content: [{
173+
type: "tool-result",
174+
toolName: item.toolName,
175+
toolCallId: item.toolCallId,
176+
result: response.result.content,
177+
}],
178+
})
179+
}
180+
}
181+
} catch {
182+
await new Promise(resolve => setTimeout(resolve, 1000))
183+
continue
159184
}
160185
}
161186
}
162187

163188

189+
164190
return (
165-
<div data-component="root">
191+
<div data-component="root" ref={root}>
166192
<div data-component="messages">
167193
<For each={store.prompt}>
168194
{(item) => (

packages/opencontrol/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"zod-to-json-schema": "3.24.3"
3131
},
3232
"devDependencies": {
33-
"opencontrol-frontend": "workspace:*",
34-
"@standard-schema/spec": "1.0.0"
33+
"@standard-schema/spec": "1.0.0",
34+
"opencontrol-frontend": "workspace:*"
3535
}
3636
}

packages/opencontrol/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { Hono } from "hono"
22
import { Tool } from "./tool.js"
33
import { createMcp } from "./mcp.js"
4-
import { basicAuth } from "hono/basic-auth"
54
import { cors } from "hono/cors"
65
import HTML from "opencontrol-frontend/dist/index.html" with { type: "text" }
76
import { setCookie, getCookie } from "hono/cookie"

0 commit comments

Comments
 (0)