@pippit-dev/cli 0.0.15 → 0.0.16
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/README.md +3 -3
- package/checksums.txt +6 -6
- package/cmd/short_drama/short_drama.go +0 -1
- package/cmd/short_drama_test.go +8 -18
- package/internal/short_drama/get_thread.go +8 -76
- package/package.json +1 -1
- package/skills/short-drama/SKILL.md +16 -27
- package/internal/short_drama/mock.go +0 -47
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ export XYQ_ACCESS_KEY="<access-key>"
|
|
|
13
13
|
pippit-tool-cli --version
|
|
14
14
|
pippit-tool-cli short-drama +submit-run --message "写一个赛博朋克短剧开头"
|
|
15
15
|
pippit-tool-cli short-drama +upload-file --path ./reference.doc
|
|
16
|
-
pippit-tool-cli short-drama +get-thread --thread-id thread_123 --run-id run_456
|
|
16
|
+
pippit-tool-cli short-drama +get-thread --thread-id thread_123 --run-id run_456
|
|
17
17
|
pippit-tool-cli short-drama +download-result --output-path ./thread_123/results/result.mp4 --url URL
|
|
18
18
|
```
|
|
19
19
|
|
|
@@ -27,14 +27,14 @@ export XYQ_ACCESS_KEY="<access-key>"
|
|
|
27
27
|
go run . --version
|
|
28
28
|
go run . short-drama +submit-run --message "写一个赛博朋克短剧开头"
|
|
29
29
|
go run . short-drama +upload-file --path ./reference.doc
|
|
30
|
-
go run . short-drama +get-thread --thread-id thread_123 --run-id run_456
|
|
30
|
+
go run . short-drama +get-thread --thread-id thread_123 --run-id run_456
|
|
31
31
|
go run . short-drama +download-result --output-path ./thread_123/results/result.mp4 --url URL
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
`+submit-run` calls `/api/biz/v1/skill/submit_run` and prints `thread_id`,
|
|
35
35
|
`run_id`, and `web_thread_link`; `--message` is required.
|
|
36
36
|
`+get-thread` calls
|
|
37
|
-
`/api/biz/v1/skill/get_thread` and prints
|
|
37
|
+
`/api/biz/v1/skill/get_thread` with `version=v2` and prints `readable_text`.
|
|
38
38
|
`+upload-file` calls `/api/biz/v1/skill/upload_file` with
|
|
39
39
|
`multipart/form-data` and prints the returned `asset_id`.
|
|
40
40
|
Only `.doc` and `.txt` file extensions are supported.
|
package/checksums.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
a00ec8d732b4be5994aecb2863d9841cd1afd9008e83122667aad17df84dc0b3 pippit-tool-cli-0.0.16-darwin-amd64.tar.gz
|
|
2
|
+
58ddfc2b146ae34aa5f003664c4f123708d100dd90f61b262201e9c80b011fc6 pippit-tool-cli-0.0.16-darwin-arm64.tar.gz
|
|
3
|
+
ad35f1d3fe7e811e9775d8cd6b2e7a8de649f19c196958c77b54926ae502a288 pippit-tool-cli-0.0.16-linux-amd64.tar.gz
|
|
4
|
+
fda684084fb7b1c2e74ac7c9ffa2a8dec2e35b3efd8326c59ab2599363caaa17 pippit-tool-cli-0.0.16-linux-arm64.tar.gz
|
|
5
|
+
d38681622dcfdd8d318efef6dcb1becebdef355b962c417824b8ce0699565a8d pippit-tool-cli-0.0.16-windows-amd64.zip
|
|
6
|
+
6a62da1a7a6482040c929f1a4f886188a966ae44d645bad18d89eb49f77aa800 pippit-tool-cli-0.0.16-windows-arm64.zip
|
|
@@ -145,7 +145,6 @@ func newShortDramaGetThreadCommand(stdout, stderr io.Writer, runner *common.Runn
|
|
|
145
145
|
cmd.SetErr(stderr)
|
|
146
146
|
cmd.Flags().StringVar(&opts.ThreadID, "thread-id", "", "thread ID to fetch")
|
|
147
147
|
cmd.Flags().StringVar(&opts.RunID, "run-id", "", "run ID to fetch")
|
|
148
|
-
cmd.Flags().IntVar(&opts.AfterSeq, "after-seq", 0, "return messages whose sequence is greater than or equal to this value")
|
|
149
148
|
return cmd
|
|
150
149
|
}
|
|
151
150
|
|
package/cmd/short_drama_test.go
CHANGED
|
@@ -569,10 +569,13 @@ func TestShortDramaGetThread(t *testing.T) {
|
|
|
569
569
|
if body["run_id"] != "run_456" {
|
|
570
570
|
t.Fatalf("run_id = %v, want run_456", body["run_id"])
|
|
571
571
|
}
|
|
572
|
-
if body["after_seq"]
|
|
573
|
-
t.Fatalf("after_seq = %v, want
|
|
572
|
+
if _, ok := body["after_seq"]; ok {
|
|
573
|
+
t.Fatalf("after_seq = %v, want omitted", body["after_seq"])
|
|
574
574
|
}
|
|
575
|
-
|
|
575
|
+
if body["version"] != "v2" {
|
|
576
|
+
t.Fatalf("version = %v, want v2", body["version"])
|
|
577
|
+
}
|
|
578
|
+
_, _ = w.Write([]byte(`{"ret":"0","errmsg":"","data":{"readable_text":"Thread: thread_123\n [assistant] hello"}}`))
|
|
576
579
|
}))
|
|
577
580
|
defer server.Close()
|
|
578
581
|
|
|
@@ -582,7 +585,6 @@ func TestShortDramaGetThread(t *testing.T) {
|
|
|
582
585
|
"short-drama", "+get-thread",
|
|
583
586
|
"--thread-id", "thread_123",
|
|
584
587
|
"--run-id", "run_456",
|
|
585
|
-
"--after-seq", "7",
|
|
586
588
|
})
|
|
587
589
|
|
|
588
590
|
if err := root.Execute(); err != nil {
|
|
@@ -590,20 +592,8 @@ func TestShortDramaGetThread(t *testing.T) {
|
|
|
590
592
|
}
|
|
591
593
|
|
|
592
594
|
got := decodeJSON(t, stdout.Bytes())
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
t.Fatalf("messages = %#v, want two entries", got["messages"])
|
|
596
|
-
}
|
|
597
|
-
first, ok := messages[0].(map[string]any)
|
|
598
|
-
if !ok {
|
|
599
|
-
t.Fatalf("first message = %#v, want object", messages[0])
|
|
600
|
-
}
|
|
601
|
-
if first["id"] != "msg_1" {
|
|
602
|
-
t.Fatalf("first id = %v, want msg_1", first["id"])
|
|
603
|
-
}
|
|
604
|
-
content, ok := first["content"].([]any)
|
|
605
|
-
if !ok || len(content) != 2 {
|
|
606
|
-
t.Fatalf("first content = %#v, want message content plus tool call", first["content"])
|
|
595
|
+
if got["readable_text"] != "Thread: thread_123\n [assistant] hello" {
|
|
596
|
+
t.Fatalf("readable_text = %#v, want API readable text", got["readable_text"])
|
|
607
597
|
}
|
|
608
598
|
}
|
|
609
599
|
|
|
@@ -8,59 +8,27 @@ import (
|
|
|
8
8
|
"github.com/Pippit-dev/pippit-cli/internal/config"
|
|
9
9
|
)
|
|
10
10
|
|
|
11
|
+
const getThreadVersionV2 = "v2"
|
|
12
|
+
|
|
11
13
|
// GetThreadOptions is the stable command-facing request shape for thread lookup.
|
|
12
14
|
type GetThreadOptions struct {
|
|
13
15
|
ThreadID string `json:"thread_id"`
|
|
14
16
|
RunID string `json:"run_id,omitempty"`
|
|
15
|
-
AfterSeq int `json:"after_seq"`
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// ThreadEntry is a compact message or artifact entry inside a thread run.
|
|
19
|
-
type ThreadEntry struct {
|
|
20
|
-
ID string `json:"id"`
|
|
21
|
-
Role string `json:"role"`
|
|
22
|
-
Content []any `json:"content"`
|
|
23
17
|
}
|
|
24
18
|
|
|
25
19
|
// GetThreadResult is the JSON envelope printed by `pippit-tool-cli short-drama +get-thread`.
|
|
26
20
|
type GetThreadResult struct {
|
|
27
|
-
|
|
21
|
+
ReadableText string `json:"readable_text"`
|
|
28
22
|
}
|
|
29
23
|
|
|
30
24
|
type getThreadResponse struct {
|
|
31
25
|
Ret string `json:"ret"`
|
|
32
26
|
Errmsg string `json:"errmsg"`
|
|
33
27
|
Data struct {
|
|
34
|
-
|
|
35
|
-
RunList []getThreadRun `json:"run_list"`
|
|
36
|
-
} `json:"thread"`
|
|
28
|
+
ReadableText string `json:"readable_text"`
|
|
37
29
|
} `json:"data"`
|
|
38
30
|
}
|
|
39
31
|
|
|
40
|
-
type getThreadRun struct {
|
|
41
|
-
State int `json:"state"`
|
|
42
|
-
FailReason string `json:"fail_reason"`
|
|
43
|
-
EntryList []getThreadEntry `json:"entry_list"`
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
type getThreadEntry struct {
|
|
47
|
-
Message *getThreadMessage `json:"message"`
|
|
48
|
-
Artifact *getThreadArtifact `json:"artifact"`
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
type getThreadMessage struct {
|
|
52
|
-
MessageID string `json:"message_id"`
|
|
53
|
-
Role string `json:"role"`
|
|
54
|
-
Content []any `json:"content"`
|
|
55
|
-
ClientToolCalls []any `json:"client_tool_calls"`
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
type getThreadArtifact struct {
|
|
59
|
-
ArtifactID string `json:"artifact_id"`
|
|
60
|
-
Role string `json:"role"`
|
|
61
|
-
Content []any `json:"content"`
|
|
62
|
-
}
|
|
63
|
-
|
|
64
32
|
func GetThread(ctx context.Context, opts *GetThreadOptions, runner *common.Runner) (*GetThreadResult, error) {
|
|
65
33
|
if runner == nil || runner.Client == nil {
|
|
66
34
|
return nil, fmt.Errorf("get_thread runner client is required")
|
|
@@ -68,7 +36,7 @@ func GetThread(ctx context.Context, opts *GetThreadOptions, runner *common.Runne
|
|
|
68
36
|
|
|
69
37
|
body := map[string]any{
|
|
70
38
|
"thread_id": opts.ThreadID,
|
|
71
|
-
"
|
|
39
|
+
"version": getThreadVersionV2,
|
|
72
40
|
}
|
|
73
41
|
if opts.RunID != "" {
|
|
74
42
|
body["run_id"] = opts.RunID
|
|
@@ -84,51 +52,15 @@ func GetThread(ctx context.Context, opts *GetThreadOptions, runner *common.Runne
|
|
|
84
52
|
}
|
|
85
53
|
return nil, fmt.Errorf("get_thread failed: ret=%s errmsg=%s", resp.Ret, resp.Errmsg)
|
|
86
54
|
}
|
|
87
|
-
if
|
|
88
|
-
return nil, fmt.Errorf("get_thread response missing data.
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
run := resp.Data.Thread.RunList[0]
|
|
92
|
-
// 4: failed
|
|
93
|
-
// 5: canceled
|
|
94
|
-
if run.State == 4 {
|
|
95
|
-
if run.FailReason == "" {
|
|
96
|
-
run.FailReason = "unknown failure"
|
|
97
|
-
}
|
|
98
|
-
return nil, fmt.Errorf("get_thread run failed: %s", run.FailReason)
|
|
99
|
-
}
|
|
100
|
-
if run.State == 5 {
|
|
101
|
-
return nil, fmt.Errorf("get_thread run canceled")
|
|
55
|
+
if resp.Data.ReadableText == "" {
|
|
56
|
+
return nil, fmt.Errorf("get_thread response missing data.readable_text")
|
|
102
57
|
}
|
|
103
58
|
|
|
104
59
|
return &GetThreadResult{
|
|
105
|
-
|
|
60
|
+
ReadableText: resp.Data.ReadableText,
|
|
106
61
|
}, nil
|
|
107
62
|
}
|
|
108
63
|
|
|
109
|
-
func extractThreadEntries(run getThreadRun) []*ThreadEntry {
|
|
110
|
-
entries := make([]*ThreadEntry, 0, len(run.EntryList))
|
|
111
|
-
for _, entry := range run.EntryList {
|
|
112
|
-
if entry.Message != nil {
|
|
113
|
-
content := append([]any(nil), entry.Message.Content...)
|
|
114
|
-
content = append(content, entry.Message.ClientToolCalls...)
|
|
115
|
-
entries = append(entries, &ThreadEntry{
|
|
116
|
-
ID: entry.Message.MessageID,
|
|
117
|
-
Role: entry.Message.Role,
|
|
118
|
-
Content: content,
|
|
119
|
-
})
|
|
120
|
-
}
|
|
121
|
-
if entry.Artifact != nil {
|
|
122
|
-
entries = append(entries, &ThreadEntry{
|
|
123
|
-
ID: entry.Artifact.ArtifactID,
|
|
124
|
-
Role: entry.Artifact.Role,
|
|
125
|
-
Content: entry.Artifact.Content,
|
|
126
|
-
})
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return entries
|
|
130
|
-
}
|
|
131
|
-
|
|
132
64
|
func getThreadPath(runner *common.Runner) string {
|
|
133
65
|
if runner != nil && runner.Config != nil && runner.Config.Paths != nil && runner.Config.Paths.GetThread != "" {
|
|
134
66
|
return runner.Config.Paths.GetThread
|
package/package.json
CHANGED
|
@@ -24,7 +24,7 @@ metadata:
|
|
|
24
24
|
## 功能
|
|
25
25
|
|
|
26
26
|
1. **提交短剧 Run 任务** - 创建新会话或向已有会话发送短剧创作需求。
|
|
27
|
-
2. **查询会话进展** - 根据 `thread_id
|
|
27
|
+
2. **查询会话进展** - 根据 `thread_id` 和可选 `run_id` 拉取服务端 v2 `readable_text`,用于展示短剧任务进展、问题和结果。
|
|
28
28
|
3. **上传文件** - 上传本地 `.doc` / `.txt` 参考文件,得到 `asset_id`,供后续任务引用。
|
|
29
29
|
4. **获取会话文件** - 根据 `thread_id` 拉取会话文件列表,得到 `file_path`、`download_url`。这和查询会话进展同等重要。
|
|
30
30
|
5. **下载重要资产** - 使用文件列表中的 `download_url` 下载资源,并按 `file_path` 写入用户本地目标文件路径。
|
|
@@ -57,11 +57,11 @@ pippit-tool-cli short-drama +submit-run --message "参考这个大纲写第一
|
|
|
57
57
|
### 2. 查询短剧任务进展
|
|
58
58
|
|
|
59
59
|
```bash
|
|
60
|
-
#
|
|
61
|
-
pippit-tool-cli short-drama +get-thread --thread-id THREAD_ID --run-id RUN_ID
|
|
60
|
+
# 查询会话可读进展
|
|
61
|
+
pippit-tool-cli short-drama +get-thread --thread-id THREAD_ID --run-id RUN_ID
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
> `thread_id` 和 `run_id` 由 `+submit-run` 返回。`
|
|
64
|
+
> `thread_id` 和 `run_id` 由 `+submit-run` 返回。`run_id` 可省略,省略时返回当前 `thread_id` 下的所有 Run;传入时只看指定 Run。
|
|
65
65
|
|
|
66
66
|
### 3. 上传文件
|
|
67
67
|
|
|
@@ -117,11 +117,11 @@ pippit-tool-cli short-drama +download-result --url DOWNLOAD_URL --output-path FI
|
|
|
117
117
|
→ 拿到 thread_id、run_id 和 web_thread_link
|
|
118
118
|
2. 立即将 web_thread_link 展示给用户
|
|
119
119
|
3. 并行发起,二者同等重要:
|
|
120
|
-
a. pippit-tool-cli short-drama +get-thread --thread-id THREAD_ID --run-id RUN_ID
|
|
120
|
+
a. pippit-tool-cli short-drama +get-thread --thread-id THREAD_ID --run-id RUN_ID
|
|
121
121
|
b. pippit-tool-cli short-drama +list-thread-file --thread-id THREAD_ID --page-num PAGE_NUM --page-size 200
|
|
122
|
-
4. 检查 `get-thread` 返回的
|
|
123
|
-
-
|
|
124
|
-
- 如果后端 Agent
|
|
122
|
+
4. 检查 `get-thread` 返回的 readable_text:
|
|
123
|
+
- 如果任务仍在进行中:展示可读进展,继续查询
|
|
124
|
+
- 如果后端 Agent 提出问题:从 readable_text 中提取问题并展示,等待用户回复
|
|
125
125
|
5. 检查 `list-thread-file` 返回的 files:
|
|
126
126
|
- 对每个文件取 file_path、download_url
|
|
127
127
|
- 将 file_path 作为本地目标文件路径,包含文件名
|
|
@@ -161,7 +161,7 @@ pippit-tool-cli short-drama +download-result --url DOWNLOAD_URL --output-path FI
|
|
|
161
161
|
## 轮询策略
|
|
162
162
|
|
|
163
163
|
- **间隔**:每 10 秒查询一次。
|
|
164
|
-
-
|
|
164
|
+
- **进展查询**:每轮调用 `+get-thread` 查看 `readable_text`。优先带上本轮 `run_id` 聚焦当前任务;需要查看整个会话时可省略 `--run-id`。
|
|
165
165
|
- **并行查询**:每次 `+submit-run` 返回 `thread_id` 后,同时发起 `+get-thread` 和 `+list-thread-file`;二者同等重要,不能只查询会话进展而忽略会话文件。
|
|
166
166
|
- **文件分页**:`+list-thread-file` 使用 `--page-size 200`。如果本轮返回的 `total` 达到 200,下一轮使用 `--page-num` 加 1 查询新一页结果;如果未达到 200,保持当前页继续轮询新增产物。
|
|
167
167
|
- **重要资产识别**:每轮都检查 `+list-thread-file` 返回的文件。剧本设计、场景设计、场景图、人物角色设计、人物图、分集草稿、故事板、最终视频产物都是重要资产。
|
|
@@ -173,9 +173,9 @@ pippit-tool-cli short-drama +download-result --url DOWNLOAD_URL --output-path FI
|
|
|
173
173
|
|
|
174
174
|
## 完成标准
|
|
175
175
|
|
|
176
|
-
一次短剧任务不能只以 `+get-thread`
|
|
176
|
+
一次短剧任务不能只以 `+get-thread` 返回的 `readable_text` 作为结束条件。完成前必须同时检查:
|
|
177
177
|
|
|
178
|
-
1. 已处理 `+get-thread`
|
|
178
|
+
1. 已处理 `+get-thread` 返回的最新 `readable_text`、用户确认问题和最终消息。
|
|
179
179
|
2. 已用 `--page-size 200` 调用 `+list-thread-file` 获取会话文件列表;如果本轮 `total` 达到 200,已在后续轮询中递增 `page-num` 查询新一页。
|
|
180
180
|
3. 对所有带 `download_url` 的重要资产,已调用 `+download-result` 下载到本地 `file_path`。
|
|
181
181
|
4. 对查询失败或下载失败的资产,已在后续轮询中主动重试,并在最终回复中列出仍失败的文件或命令。
|
|
@@ -196,18 +196,7 @@ pippit-tool-cli short-drama +download-result --url DOWNLOAD_URL --output-path FI
|
|
|
196
196
|
|
|
197
197
|
```json
|
|
198
198
|
{
|
|
199
|
-
"
|
|
200
|
-
{
|
|
201
|
-
"id": "message_...",
|
|
202
|
-
"role": "assistant",
|
|
203
|
-
"content": [
|
|
204
|
-
{
|
|
205
|
-
"type": "text",
|
|
206
|
-
"data": {}
|
|
207
|
-
}
|
|
208
|
-
]
|
|
209
|
-
}
|
|
210
|
-
]
|
|
199
|
+
"readable_text": "Thread: thread_...\n 标题: ...\n 状态: ...\n\n -- Run #1 --\n [assistant] ..."
|
|
211
200
|
}
|
|
212
201
|
```
|
|
213
202
|
|
|
@@ -253,7 +242,7 @@ pippit-tool-cli short-drama +download-result --url DOWNLOAD_URL --output-path FI
|
|
|
253
242
|
|
|
254
243
|
### 获取会话文件
|
|
255
244
|
|
|
256
|
-
从 `+list-thread-file` 的 `files` 中逐个读取文件元信息:`file_path`、`download_url
|
|
245
|
+
从 `+list-thread-file` 的 `files` 中逐个读取文件元信息:`file_path`、`file_name`、`download_url`。重点识别剧本设计、场景设计、场景图、人物角色设计、人物图、分集草稿、故事板、最终视频产物等重要资产。
|
|
257
246
|
|
|
258
247
|
```
|
|
259
248
|
1. 有download_url的重要资产
|
|
@@ -293,7 +282,7 @@ pippit-tool-cli short-drama +download-result --url DOWNLOAD_URL --output-path FI
|
|
|
293
282
|
|
|
294
283
|
1. **上传**:如果用户给了本地 `.doc` / `.txt` 参考文件,先调用 `+upload-file`。
|
|
295
284
|
2. **提交任务**:首次创作时把用户原始短剧需求和唯一剧本 `asset_id` 通过 `+submit-run --asset-ids` 发给后端;同一 `thread_id` 后续续写或修改不再追加新的剧本文件。
|
|
296
|
-
3. **传话、取文件、下载资源**:根据 `+get-thread`
|
|
285
|
+
3. **传话、取文件、下载资源**:根据 `+get-thread` 返回的 `readable_text` 展示进展、问题和结果;根据 `+list-thread-file` 获取文件列表;再根据 `download_url` 调用 `+download-result` 把缺失资源下载到用户本地。
|
|
297
286
|
|
|
298
287
|
**不要做的事:**
|
|
299
288
|
|
|
@@ -307,8 +296,8 @@ pippit-tool-cli short-drama +download-result --url DOWNLOAD_URL --output-path FI
|
|
|
307
296
|
## 注意事项
|
|
308
297
|
|
|
309
298
|
- `--message` 是用户的原始短剧需求,不能为空。
|
|
310
|
-
- 查询进展时优先使用 `+submit-run` 返回的 `thread_id` 和 `run_id`。
|
|
311
|
-
-
|
|
299
|
+
- 查询进展时优先使用 `+submit-run` 返回的 `thread_id` 和 `run_id`;如果需要查看整个会话,可以省略 `--run-id`。
|
|
300
|
+
- `+get-thread` 当前固定走服务端 v2 响应,输出字段是 `readable_text`;不要解析旧版 `messages` 数组。
|
|
312
301
|
- `+upload-file` 当前用于短剧场景文件上传链路,只支持本地 `.doc` / `.txt` 文件;`--path` 不能为空,路径必须指向真实文件,不能是目录。
|
|
313
302
|
- `+upload-file` 上传成功后只返回 `asset_id`;把该值原样作为 `+submit-run --asset-ids` 的参数。
|
|
314
303
|
- 单次创作会话中(相同 `thread_id`),`+submit-run` 只支持绑定一个剧本文件。不要在同一 `thread_id` 下重复上传并追加第二个剧本 `asset_id`;用户给多个剧本时,先让用户选择一个,或分别开启新的创作会话。
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
package short_drama
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"context"
|
|
5
|
-
"crypto/sha1"
|
|
6
|
-
"encoding/hex"
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
// MockClient returns deterministic IDs so the demo chain is easy to test.
|
|
10
|
-
type MockClient struct{}
|
|
11
|
-
|
|
12
|
-
func (MockClient) SubmitRun(ctx context.Context, opts SubmitRunOptions) (*SubmitRunResult, error) {
|
|
13
|
-
if err := ctx.Err(); err != nil {
|
|
14
|
-
return nil, err
|
|
15
|
-
}
|
|
16
|
-
key := opts.ThreadID + "\x00" + opts.Message
|
|
17
|
-
id := stableIDMock(key, 12)
|
|
18
|
-
return &SubmitRunResult{
|
|
19
|
-
ThreadID: "thread_mock_" + id[:6],
|
|
20
|
-
RunID: "run_mock_" + id[6:],
|
|
21
|
-
WebThreadLink: "https://xyq.jianying.com/mock/thread_mock_" + id[:6],
|
|
22
|
-
}, nil
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
func (MockClient) GetThread(ctx context.Context, opts GetThreadOptions) (*GetThreadResult, error) {
|
|
26
|
-
if err := ctx.Err(); err != nil {
|
|
27
|
-
return nil, err
|
|
28
|
-
}
|
|
29
|
-
return &GetThreadResult{
|
|
30
|
-
Messages: []*ThreadEntry{
|
|
31
|
-
{
|
|
32
|
-
ID: "message_mock_" + stableIDMock(opts.ThreadID, 8),
|
|
33
|
-
Role: "assistant",
|
|
34
|
-
Content: []any{"mock thread message"},
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
}, nil
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
func stableIDMock(key string, n int) string {
|
|
41
|
-
sum := sha1.Sum([]byte(key))
|
|
42
|
-
id := hex.EncodeToString(sum[:])
|
|
43
|
-
if n > len(id) {
|
|
44
|
-
return id
|
|
45
|
-
}
|
|
46
|
-
return id[:n]
|
|
47
|
-
}
|