Skip to content

Commit 3040d33

Browse files
committed
Add support for Claude integration
Introduced configurations, workflows, and adapter implementation for Claude. Enabled URL pattern matching for flexible sniffing in browser interactions. Adjusted user-data-dir for workspace handling.
1 parent 0be5e9e commit 3040d33

File tree

4 files changed

+134
-2
lines changed

4 files changed

+134
-2
lines changed

internal/adapter/claude.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package adapter
2+
3+
import (
4+
"fmt"
5+
"github.com/tidwall/gjson"
6+
"regexp"
7+
)
8+
9+
func init() {
10+
Adapters["claude"] = &ClaudeAdapter{}
11+
}
12+
13+
type ClaudeAdapter struct {
14+
}
15+
16+
func (g *ClaudeAdapter) HandleResponse(responseBuffer []byte, done bool) (*AdapterResponse, error) {
17+
content := ""
18+
reasoningContent := ""
19+
pattern := `data:(.*?)\n\n`
20+
re := regexp.MustCompile(pattern)
21+
matches := re.FindAllStringSubmatch(string(responseBuffer), -1)
22+
if len(matches) == 0 {
23+
return nil, fmt.Errorf("no match data")
24+
}
25+
thinkStatus := false
26+
for i := 0; i < len(matches); i++ {
27+
match := matches[i]
28+
if len(match) == 2 {
29+
c, d := g.getDataContent(match[1], &thinkStatus)
30+
if !d {
31+
if thinkStatus {
32+
reasoningContent = reasoningContent + c
33+
} else {
34+
content = content + c
35+
}
36+
} else {
37+
done = true
38+
break
39+
}
40+
}
41+
}
42+
43+
return &AdapterResponse{
44+
Content: content,
45+
ReasoningContent: reasoningContent,
46+
ToolCalls: "",
47+
Done: done,
48+
}, nil
49+
50+
}
51+
52+
func (g *ClaudeAdapter) getDataContent(jsonData string, thinkStatus *bool) (string, bool) {
53+
typeResult := gjson.Get(jsonData, "type")
54+
if typeResult.Type != gjson.String {
55+
return "", false
56+
}
57+
content := ""
58+
switch typeResult.String() {
59+
case "content_block_start":
60+
blockTypeResult := gjson.Get(jsonData, "content_block.type")
61+
if blockTypeResult.Type == gjson.String {
62+
if blockTypeResult.String() == "thinking" {
63+
*thinkStatus = true
64+
thinkingResult := gjson.Get(jsonData, "content_block.thinking")
65+
if thinkingResult.Type == gjson.String {
66+
content = thinkingResult.String()
67+
}
68+
} else if blockTypeResult.String() == "text" {
69+
*thinkStatus = false
70+
textResult := gjson.Get(jsonData, "content_block.text")
71+
if textResult.Type == gjson.String {
72+
content = textResult.String()
73+
}
74+
}
75+
}
76+
case "content_block_delta":
77+
blockDeltaTypeResult := gjson.Get(jsonData, "delta.type")
78+
if blockDeltaTypeResult.Type == gjson.String {
79+
if blockDeltaTypeResult.String() == "thinking_delta" {
80+
textResult := gjson.Get(jsonData, "delta.thinking")
81+
if textResult.Type == gjson.String {
82+
content = textResult.String()
83+
}
84+
} else if blockDeltaTypeResult.String() == "text_delta" {
85+
textResult := gjson.Get(jsonData, "delta.text")
86+
if textResult.Type == gjson.String {
87+
content = textResult.String()
88+
}
89+
}
90+
}
91+
case "content_block_stop":
92+
case "message_stop":
93+
return "", true
94+
}
95+
return content, false
96+
}

internal/browser/chrome/page.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func NewPage(browserCtx context.Context, adapterName string, url string, authFil
7373
exec := cdp.WithExecutor(newPageCtx, ctx.Target)
7474

7575
if ev.Request.Method == "POST" {
76-
if utils.InArray(ev.Request.URL, sniffURL) {
76+
if utils.MatchUrl(sniffURL, ev.Request.URL) {
7777
var buf bytes.Buffer
7878

7979
handle, errTakeResponseBodyAsStream := fetch.TakeResponseBodyAsStream(ev.RequestID).Do(exec)

internal/utils/functions.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package utils
22

3+
import (
4+
"net/url"
5+
"path"
6+
)
7+
38
func InArray(needle interface{}, hystack interface{}) bool {
49
switch key := needle.(type) {
510
case string:
@@ -25,3 +30,34 @@ func InArray(needle interface{}, hystack interface{}) bool {
2530
}
2631
return false
2732
}
33+
34+
func MatchUrl(patternUrls []string, targetUrl string) bool {
35+
for _, patternUrl := range patternUrls {
36+
if patternUrl == targetUrl {
37+
return true
38+
}
39+
parsedPatternUrl, err := url.Parse(patternUrl)
40+
if err != nil {
41+
return false
42+
}
43+
patternUrlPath := parsedPatternUrl.Path
44+
45+
parsedTargetUrl, err := url.Parse(targetUrl)
46+
if err != nil {
47+
return false
48+
}
49+
targetUrlPath := parsedTargetUrl.Path
50+
51+
matched, err := path.Match(patternUrlPath, targetUrlPath)
52+
if err != nil {
53+
return false
54+
}
55+
56+
if matched {
57+
if parsedPatternUrl.Scheme == parsedTargetUrl.Scheme && parsedPatternUrl.Host == parsedTargetUrl.Host {
58+
return true
59+
}
60+
}
61+
}
62+
return false
63+
}

0 commit comments

Comments
 (0)