draftgo-cli 4.0.1 → 4.0.23
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 +87 -11
- package/package.json +9 -4
- package/resources/custom-service-sdk/ai.go +520 -0
- package/resources/custom-service-sdk/ai_test.go +156 -0
- package/resources/custom-service-sdk/auth_test.go +56 -0
- package/resources/custom-service-sdk/billing.go +596 -0
- package/resources/custom-service-sdk/billing_test.go +150 -0
- package/resources/custom-service-sdk/go.mod +3 -0
- package/resources/custom-service-sdk/manifest.json +77 -0
- package/resources/custom-service-sdk/platform.go +345 -0
- package/resources/custom-service-sdk/platform_logger_test.go +24 -0
- package/resources/custom-service-sdk/registration_test.go +39 -0
- package/resources/custom-service-sdk/resources.go +246 -0
- package/resources/custom-service-sdk/resources_billing_test.go +115 -0
- package/resources/custom-service-sdk/resources_files_test.go +57 -0
- package/resources/custom-service-sdk/resources_scope_test.go +87 -0
- package/resources/custom-service-sdk/sdk.go +208 -0
- package/resources/skill/SKILL.md +36 -88
- package/resources/skill/init/SKILL.md +4 -4
- package/resources/skill/manifest.json +5 -1
- package/resources/skill/references/aihub.md +25 -2
- package/resources/skill/references/app-api.md +56 -6
- package/resources/skill/references/architecture.md +2 -2
- package/resources/skill/references/chat-sdk.md +4 -2
- package/resources/skill/references/checkout.md +17 -3
- package/resources/skill/references/custom-services.md +112 -47
- package/resources/skill/references/data.md +19 -4
- package/resources/skill/references/delivery.md +33 -0
- package/resources/skill/references/diagnostics.md +51 -0
- package/resources/skill/references/frontend.md +34 -46
- package/resources/skill/references/mcp.md +33 -5
- package/resources/skill/references/methods.md +189 -0
- package/resources/skill/references/modules.md +37 -9
- package/resources/skill/references/runtime.md +23 -1
- package/src/cli.js +24 -0
- package/src/commandRegistry.js +9 -1
- package/src/commands/api.js +21 -10
- package/src/commands/apiKey.js +34 -0
- package/src/commands/capabilities.js +93 -0
- package/src/commands/checkout.js +1 -1
- package/src/commands/commit.js +1 -1
- package/src/commands/components.js +550 -0
- package/src/commands/conflict.js +1 -1
- package/src/commands/connect.js +18 -8
- package/src/commands/customService.js +20 -4
- package/src/commands/dataRange.js +33 -0
- package/src/commands/delete.js +12 -1
- package/src/commands/diff.js +18 -2
- package/src/commands/grant.js +29 -0
- package/src/commands/group.js +38 -0
- package/src/commands/help.js +64 -20
- package/src/commands/init.js +3 -3
- package/src/commands/map.js +145 -17
- package/src/commands/mcp.js +2 -2
- package/src/commands/reconcile.js +1 -1
- package/src/commands/role.js +32 -0
- package/src/commands/space.js +41 -0
- package/src/commands/status.js +110 -7
- package/src/commands/update.js +23 -11
- package/src/commands/verify.js +75 -0
- package/src/commands/worklog.js +6 -2
- package/src/consoleEncoding.js +34 -0
- package/src/contractCompatibility.js +57 -0
- package/src/customServices.js +138 -18
- package/src/diffReport.js +106 -0
- package/src/index.js +2 -0
- package/src/localRuntime/compose.js +14 -17
- package/src/localRuntime/index.js +22 -23
- package/src/localRuntime/services.js +27 -36
- package/src/mcp/client.js +11 -2
- package/src/mcp/protocol.js +22 -2
- package/src/mcp/tools.js +14 -1
- package/src/platforms.js +9 -0
- package/src/projectConfig.js +6 -4
- package/src/releaseInstall.js +105 -0
- package/src/updateCheck.js +48 -28
- package/src/worklog.js +2 -1
- package/src/worktree/backend.js +1 -1
- package/src/worktree/index.js +7 -2
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
package sdk
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"encoding/base64"
|
|
6
|
+
"fmt"
|
|
7
|
+
"net/http"
|
|
8
|
+
"strconv"
|
|
9
|
+
"strings"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
// AIRequest is the future-compatible escape hatch for AI endpoints that have
|
|
13
|
+
// not yet gained a typed helper. Path must target a DraftGo AI API route.
|
|
14
|
+
type AIRequest struct {
|
|
15
|
+
Method string `json:"method"`
|
|
16
|
+
Path string `json:"path"`
|
|
17
|
+
Query map[string]any `json:"query,omitempty"`
|
|
18
|
+
Body any `json:"body,omitempty"`
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type AIChatRequest struct {
|
|
22
|
+
AgentID int64 `json:"agent_id,omitempty"`
|
|
23
|
+
Message string `json:"message,omitempty"`
|
|
24
|
+
Messages []map[string]any `json:"messages,omitempty"`
|
|
25
|
+
Model string `json:"model,omitempty"`
|
|
26
|
+
Context map[string]any `json:"context,omitempty"`
|
|
27
|
+
SessionID string `json:"session_id,omitempty"`
|
|
28
|
+
RunID string `json:"run_id,omitempty"`
|
|
29
|
+
Options map[string]any `json:"options,omitempty"`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type AIImageRequest struct {
|
|
33
|
+
AgentID int64 `json:"agent_id,omitempty"`
|
|
34
|
+
Prompt string `json:"prompt"`
|
|
35
|
+
Model string `json:"model,omitempty"`
|
|
36
|
+
Options map[string]any `json:"options,omitempty"`
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
type AIEmbeddingRequest struct {
|
|
40
|
+
Model string `json:"model"`
|
|
41
|
+
Input any `json:"input"`
|
|
42
|
+
Options map[string]any `json:"options,omitempty"`
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// AIResponsesRequest is the synchronous typed helper for the OpenAI-compatible
|
|
46
|
+
// Responses and Responses Compact APIs. Streaming remains available through
|
|
47
|
+
// AIHub.Request because the custom-service RPC transport returns decoded values.
|
|
48
|
+
type AIResponsesRequest struct {
|
|
49
|
+
Model string `json:"model"`
|
|
50
|
+
Input any `json:"input,omitempty"`
|
|
51
|
+
Instructions string `json:"instructions,omitempty"`
|
|
52
|
+
PreviousResponseID string `json:"previous_response_id,omitempty"`
|
|
53
|
+
Tools []map[string]any `json:"tools,omitempty"`
|
|
54
|
+
Options map[string]any `json:"options,omitempty"`
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
type AIRerankRequest struct {
|
|
58
|
+
Model string `json:"model"`
|
|
59
|
+
Query string `json:"query"`
|
|
60
|
+
Documents []string `json:"documents"`
|
|
61
|
+
TopN int `json:"top_n,omitempty"`
|
|
62
|
+
ReturnDocuments bool `json:"return_documents,omitempty"`
|
|
63
|
+
Options map[string]any `json:"options,omitempty"`
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
type AITTSRequest struct {
|
|
67
|
+
Model string `json:"model"`
|
|
68
|
+
Input string `json:"input"`
|
|
69
|
+
Voice string `json:"voice,omitempty"`
|
|
70
|
+
Instructions string `json:"instructions,omitempty"`
|
|
71
|
+
ResponseFormat string `json:"response_format,omitempty"`
|
|
72
|
+
OptimizeTextPreview bool `json:"optimize_text_preview,omitempty"`
|
|
73
|
+
Options map[string]any `json:"options,omitempty"`
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
type AIAudioResponse struct {
|
|
77
|
+
Content []byte
|
|
78
|
+
MIMEType string
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
type AITranscriptionRequest struct {
|
|
82
|
+
Model string `json:"model"`
|
|
83
|
+
Content []byte `json:"-"`
|
|
84
|
+
MIMEType string `json:"mime_type"`
|
|
85
|
+
Language string `json:"language,omitempty"`
|
|
86
|
+
ResponseFormat string `json:"response_format,omitempty"`
|
|
87
|
+
Options map[string]any `json:"options,omitempty"`
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
type SkillInstallRequest struct {
|
|
91
|
+
Repository string `json:"repo"`
|
|
92
|
+
Ref string `json:"ref,omitempty"`
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
type SkillArchive struct {
|
|
96
|
+
Filename string `json:"filename"`
|
|
97
|
+
Content []byte `json:"-"`
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
type KnowledgeDocumentUpload struct {
|
|
101
|
+
Filename string `json:"filename"`
|
|
102
|
+
MIMEType string `json:"mime_type,omitempty"`
|
|
103
|
+
Content []byte `json:"-"`
|
|
104
|
+
Metadata map[string]any `json:"metadata,omitempty"`
|
|
105
|
+
AutoTag bool `json:"auto_tag,omitempty"`
|
|
106
|
+
TaggingModelID int64 `json:"tagging_model_id,omitempty"`
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// AIHub covers inference plus the complete AI asset and model-management API.
|
|
110
|
+
// Asset CRUD is used for agent, prompt, skill and MCP records.
|
|
111
|
+
type AIHub interface {
|
|
112
|
+
Request(context.Context, AIRequest) (any, error)
|
|
113
|
+
Chat(context.Context, AIChatRequest) (map[string]any, error)
|
|
114
|
+
GenerateImage(context.Context, AIImageRequest) (map[string]any, error)
|
|
115
|
+
Responses(context.Context, AIResponsesRequest) (map[string]any, error)
|
|
116
|
+
CompactResponse(context.Context, AIResponsesRequest) (map[string]any, error)
|
|
117
|
+
Embeddings(context.Context, AIEmbeddingRequest) (map[string]any, error)
|
|
118
|
+
Rerank(context.Context, AIRerankRequest) (map[string]any, error)
|
|
119
|
+
TextToSpeech(context.Context, AITTSRequest) (AIAudioResponse, error)
|
|
120
|
+
Transcribe(context.Context, AITranscriptionRequest) (map[string]any, error)
|
|
121
|
+
|
|
122
|
+
ListCallableAgents(context.Context) ([]map[string]any, error)
|
|
123
|
+
AgentSelectableModels(context.Context, int64) (map[string]any, error)
|
|
124
|
+
PreviewAgentChat(context.Context, int64, AIChatRequest) (map[string]any, error)
|
|
125
|
+
ListAssetTypes(context.Context) ([]map[string]any, error)
|
|
126
|
+
ListAssets(context.Context, map[string]any) (map[string]any, error)
|
|
127
|
+
GetAsset(context.Context, int64) (map[string]any, error)
|
|
128
|
+
CreateAsset(context.Context, map[string]any) ([]map[string]any, error)
|
|
129
|
+
UpdateAsset(context.Context, int64, map[string]any) ([]map[string]any, error)
|
|
130
|
+
UpdateAssets(context.Context, []map[string]any) ([]map[string]any, error)
|
|
131
|
+
DeleteAsset(context.Context, int64, bool) error
|
|
132
|
+
AgentReadiness(context.Context, int64) (map[string]any, error)
|
|
133
|
+
PublishAgent(context.Context, int64) (map[string]any, error)
|
|
134
|
+
DiscoverMCPTools(context.Context, map[string]any) (map[string]any, error)
|
|
135
|
+
|
|
136
|
+
ListProviderKinds(context.Context) (map[string]any, error)
|
|
137
|
+
ListProviders(context.Context, map[string]any) (map[string]any, error)
|
|
138
|
+
GetProvider(context.Context, int64) (map[string]any, error)
|
|
139
|
+
CreateProvider(context.Context, map[string]any) (map[string]any, error)
|
|
140
|
+
UpdateProvider(context.Context, int64, map[string]any) (map[string]any, error)
|
|
141
|
+
DeleteProvider(context.Context, int64) error
|
|
142
|
+
DiscoverProvider(context.Context, int64) (map[string]any, error)
|
|
143
|
+
SyncProvider(context.Context, int64) (map[string]any, error)
|
|
144
|
+
|
|
145
|
+
ListModels(context.Context, map[string]any) (map[string]any, error)
|
|
146
|
+
GetModel(context.Context, int64) (map[string]any, error)
|
|
147
|
+
CreateModel(context.Context, map[string]any) (map[string]any, error)
|
|
148
|
+
UpdateModel(context.Context, int64, map[string]any) (map[string]any, error)
|
|
149
|
+
DeleteModel(context.Context, int64) error
|
|
150
|
+
ProbeModelRoute(context.Context, int64, string) (map[string]any, error)
|
|
151
|
+
UpdateModelRoute(context.Context, int64, map[string]any) (map[string]any, error)
|
|
152
|
+
DeleteModelRoute(context.Context, int64) (map[string]any, error)
|
|
153
|
+
|
|
154
|
+
InstallSkill(context.Context, SkillInstallRequest) (map[string]any, error)
|
|
155
|
+
InstallSkillArchive(context.Context, SkillArchive) (map[string]any, error)
|
|
156
|
+
ListSkillVersions(context.Context, int64) ([]map[string]any, error)
|
|
157
|
+
RollbackSkill(context.Context, int64, int) (map[string]any, error)
|
|
158
|
+
ListRuns(context.Context, map[string]any) (map[string]any, error)
|
|
159
|
+
GetRun(context.Context, string) (map[string]any, error)
|
|
160
|
+
DeleteRuns(context.Context, map[string]any) (map[string]any, error)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
type Knowledge interface {
|
|
164
|
+
List(context.Context, map[string]any) (map[string]any, error)
|
|
165
|
+
Get(context.Context, int64) (map[string]any, error)
|
|
166
|
+
Create(context.Context, map[string]any) (map[string]any, error)
|
|
167
|
+
Update(context.Context, int64, map[string]any) (map[string]any, error)
|
|
168
|
+
Delete(context.Context, int64) error
|
|
169
|
+
ListDocuments(context.Context, int64) ([]map[string]any, error)
|
|
170
|
+
GetDocument(context.Context, int64, int64) (map[string]any, error)
|
|
171
|
+
UploadDocument(context.Context, int64, KnowledgeDocumentUpload) (map[string]any, error)
|
|
172
|
+
UpdateDocument(context.Context, int64, int64, map[string]any) (map[string]any, error)
|
|
173
|
+
DeleteDocument(context.Context, int64, int64) error
|
|
174
|
+
ReindexDocument(context.Context, int64, int64) (map[string]any, error)
|
|
175
|
+
ListChunks(context.Context, int64, map[string]any) ([]map[string]any, error)
|
|
176
|
+
UpdateChunk(context.Context, int64, int64, map[string]any) (map[string]any, error)
|
|
177
|
+
Retrieve(context.Context, int64, map[string]any) (map[string]any, error)
|
|
178
|
+
RebuildIndex(context.Context, int64) (map[string]any, error)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
type Memory interface {
|
|
182
|
+
List(context.Context, map[string]any) (map[string]any, error)
|
|
183
|
+
Get(context.Context, int64) (map[string]any, error)
|
|
184
|
+
Create(context.Context, map[string]any) (map[string]any, error)
|
|
185
|
+
Update(context.Context, int64, map[string]any) (map[string]any, error)
|
|
186
|
+
Delete(context.Context, int64) error
|
|
187
|
+
GetConfig(context.Context) (map[string]any, error)
|
|
188
|
+
UpdateConfig(context.Context, map[string]any) (map[string]any, error)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
func (p aiHubClient) Request(ctx context.Context, request AIRequest) (any, error) {
|
|
192
|
+
return p.call(ctx, "ai.request", request)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
func (p aiHubClient) requestMap(ctx context.Context, method, path string, query map[string]any, body any) (map[string]any, error) {
|
|
196
|
+
value, err := p.Request(ctx, AIRequest{Method: method, Path: path, Query: query, Body: body})
|
|
197
|
+
return mapResult(value), err
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
func (p aiHubClient) Chat(ctx context.Context, request AIChatRequest) (map[string]any, error) {
|
|
201
|
+
value, err := p.call(ctx, "aihub.chat", map[string]any{"agent_id": request.AgentID, "message": request.Message, "messages": request.Messages, "model": request.Model, "context": request.Context, "session_id": request.SessionID, "run_id": request.RunID, "kwargs": request.Options})
|
|
202
|
+
return mapResult(value), err
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
func (p aiHubClient) GenerateImage(ctx context.Context, request AIImageRequest) (map[string]any, error) {
|
|
206
|
+
value, err := p.call(ctx, "aihub.image", map[string]any{"agent_id": request.AgentID, "prompt": request.Prompt, "model": request.Model, "kwargs": request.Options})
|
|
207
|
+
return mapResult(value), err
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
func (p aiHubClient) Responses(ctx context.Context, request AIResponsesRequest) (map[string]any, error) {
|
|
211
|
+
value, err := p.call(ctx, "aihub.responses", responsesRequestBody(request))
|
|
212
|
+
return mapResult(value), err
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
func (p aiHubClient) CompactResponse(ctx context.Context, request AIResponsesRequest) (map[string]any, error) {
|
|
216
|
+
value, err := p.call(ctx, "aihub.responses.compact", responsesRequestBody(request))
|
|
217
|
+
return mapResult(value), err
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
func responsesRequestBody(request AIResponsesRequest) map[string]any {
|
|
221
|
+
body := cloneSDKMap(request.Options)
|
|
222
|
+
body["model"], body["input"] = request.Model, request.Input
|
|
223
|
+
body["stream"] = false
|
|
224
|
+
if request.Instructions != "" {
|
|
225
|
+
body["instructions"] = request.Instructions
|
|
226
|
+
}
|
|
227
|
+
if request.PreviousResponseID != "" {
|
|
228
|
+
body["previous_response_id"] = request.PreviousResponseID
|
|
229
|
+
}
|
|
230
|
+
if len(request.Tools) > 0 {
|
|
231
|
+
body["tools"] = request.Tools
|
|
232
|
+
}
|
|
233
|
+
return body
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
func (p aiHubClient) Embeddings(ctx context.Context, request AIEmbeddingRequest) (map[string]any, error) {
|
|
237
|
+
body := cloneSDKMap(request.Options)
|
|
238
|
+
body["model"], body["input"] = request.Model, request.Input
|
|
239
|
+
value, err := p.call(ctx, "aihub.embeddings", body)
|
|
240
|
+
return mapResult(value), err
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
func (p aiHubClient) Rerank(ctx context.Context, request AIRerankRequest) (map[string]any, error) {
|
|
244
|
+
body := cloneSDKMap(request.Options)
|
|
245
|
+
body["model"], body["query"], body["documents"] = request.Model, request.Query, request.Documents
|
|
246
|
+
if request.TopN > 0 {
|
|
247
|
+
body["top_n"] = request.TopN
|
|
248
|
+
}
|
|
249
|
+
body["return_documents"] = request.ReturnDocuments
|
|
250
|
+
value, err := p.call(ctx, "aihub.rerank", body)
|
|
251
|
+
return mapResult(value), err
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
func (p aiHubClient) TextToSpeech(ctx context.Context, request AITTSRequest) (AIAudioResponse, error) {
|
|
255
|
+
body := cloneSDKMap(request.Options)
|
|
256
|
+
body["model"], body["input"], body["voice"] = request.Model, request.Input, request.Voice
|
|
257
|
+
body["instructions"], body["response_format"] = request.Instructions, request.ResponseFormat
|
|
258
|
+
body["optimize_text_preview"] = request.OptimizeTextPreview
|
|
259
|
+
value, err := p.call(ctx, "aihub.tts", body)
|
|
260
|
+
if err != nil {
|
|
261
|
+
return AIAudioResponse{}, err
|
|
262
|
+
}
|
|
263
|
+
result := mapResult(value)
|
|
264
|
+
content, err := base64.StdEncoding.DecodeString(fmt.Sprint(result["audio_base64"]))
|
|
265
|
+
if err != nil {
|
|
266
|
+
return AIAudioResponse{}, fmt.Errorf("decode TTS audio: %w", err)
|
|
267
|
+
}
|
|
268
|
+
return AIAudioResponse{Content: content, MIMEType: fmt.Sprint(result["mime_type"])}, nil
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
func (p aiHubClient) Transcribe(ctx context.Context, request AITranscriptionRequest) (map[string]any, error) {
|
|
272
|
+
body := cloneSDKMap(request.Options)
|
|
273
|
+
body["model"], body["audio_base64"], body["audio_mime_type"] = request.Model, base64.StdEncoding.EncodeToString(request.Content), request.MIMEType
|
|
274
|
+
body["language"], body["response_format"] = request.Language, request.ResponseFormat
|
|
275
|
+
value, err := p.call(ctx, "aihub.transcribe", body)
|
|
276
|
+
return mapResult(value), err
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
func (p aiHubClient) ListCallableAgents(ctx context.Context) ([]map[string]any, error) {
|
|
280
|
+
value, err := p.Request(ctx, AIRequest{Method: http.MethodGet, Path: "/api/agents"})
|
|
281
|
+
return mapSlice(value), err
|
|
282
|
+
}
|
|
283
|
+
func (p aiHubClient) AgentSelectableModels(ctx context.Context, id int64) (map[string]any, error) {
|
|
284
|
+
return p.requestMap(ctx, http.MethodGet, idPath("/api/agents", id)+"/selectable-models", nil, nil)
|
|
285
|
+
}
|
|
286
|
+
func (p aiHubClient) PreviewAgentChat(ctx context.Context, id int64, request AIChatRequest) (map[string]any, error) {
|
|
287
|
+
body := cloneSDKMap(request.Options)
|
|
288
|
+
body["message"], body["messages"], body["model"], body["context"] = request.Message, request.Messages, request.Model, request.Context
|
|
289
|
+
return p.requestMap(ctx, http.MethodPost, idPath("/api/agents", id)+"/preview-chat", nil, body)
|
|
290
|
+
}
|
|
291
|
+
func (p aiHubClient) ListAssetTypes(ctx context.Context) ([]map[string]any, error) {
|
|
292
|
+
value, err := p.Request(ctx, AIRequest{Method: http.MethodGet, Path: "/api/aihub/types"})
|
|
293
|
+
return mapSlice(value), err
|
|
294
|
+
}
|
|
295
|
+
func (p aiHubClient) ListAssets(ctx context.Context, query map[string]any) (map[string]any, error) {
|
|
296
|
+
return p.requestMap(ctx, http.MethodGet, "/api/aihub", query, nil)
|
|
297
|
+
}
|
|
298
|
+
func (p aiHubClient) GetAsset(ctx context.Context, id int64) (map[string]any, error) {
|
|
299
|
+
return p.requestMap(ctx, http.MethodGet, idPath("/api/aihub", id), nil, nil)
|
|
300
|
+
}
|
|
301
|
+
func (p aiHubClient) CreateAsset(ctx context.Context, data map[string]any) ([]map[string]any, error) {
|
|
302
|
+
value, err := p.Request(ctx, AIRequest{Method: http.MethodPost, Path: "/api/aihub", Body: data})
|
|
303
|
+
return mapSlice(value), err
|
|
304
|
+
}
|
|
305
|
+
func (p aiHubClient) UpdateAsset(ctx context.Context, id int64, data map[string]any) ([]map[string]any, error) {
|
|
306
|
+
value, err := p.Request(ctx, AIRequest{Method: http.MethodPut, Path: idPath("/api/aihub", id), Body: data})
|
|
307
|
+
return mapSlice(value), err
|
|
308
|
+
}
|
|
309
|
+
func (p aiHubClient) UpdateAssets(ctx context.Context, data []map[string]any) ([]map[string]any, error) {
|
|
310
|
+
value, err := p.Request(ctx, AIRequest{Method: http.MethodPatch, Path: "/api/aihub/batch", Body: data})
|
|
311
|
+
return mapSlice(value), err
|
|
312
|
+
}
|
|
313
|
+
func (p aiHubClient) DeleteAsset(ctx context.Context, id int64, force bool) error {
|
|
314
|
+
_, err := p.Request(ctx, AIRequest{Method: http.MethodDelete, Path: idPath("/api/aihub", id), Query: map[string]any{"force": force}})
|
|
315
|
+
return err
|
|
316
|
+
}
|
|
317
|
+
func (p aiHubClient) AgentReadiness(ctx context.Context, id int64) (map[string]any, error) {
|
|
318
|
+
return p.requestMap(ctx, http.MethodGet, idPath("/api/aihub", id)+"/readiness", nil, nil)
|
|
319
|
+
}
|
|
320
|
+
func (p aiHubClient) PublishAgent(ctx context.Context, id int64) (map[string]any, error) {
|
|
321
|
+
return p.requestMap(ctx, http.MethodPost, idPath("/api/aihub", id)+"/publish", nil, nil)
|
|
322
|
+
}
|
|
323
|
+
func (p aiHubClient) DiscoverMCPTools(ctx context.Context, data map[string]any) (map[string]any, error) {
|
|
324
|
+
return p.requestMap(ctx, http.MethodPost, "/api/aihub/mcp/discover-tools", nil, data)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
func (p aiHubClient) ListProviderKinds(ctx context.Context) (map[string]any, error) {
|
|
328
|
+
return p.requestMap(ctx, http.MethodGet, "/api/aihub/provider-kinds", nil, nil)
|
|
329
|
+
}
|
|
330
|
+
func (p aiHubClient) ListProviders(ctx context.Context, query map[string]any) (map[string]any, error) {
|
|
331
|
+
return p.requestMap(ctx, http.MethodGet, "/api/aihub/providers", query, nil)
|
|
332
|
+
}
|
|
333
|
+
func (p aiHubClient) GetProvider(ctx context.Context, id int64) (map[string]any, error) {
|
|
334
|
+
return p.requestMap(ctx, http.MethodGet, idPath("/api/aihub/providers", id), nil, nil)
|
|
335
|
+
}
|
|
336
|
+
func (p aiHubClient) CreateProvider(ctx context.Context, data map[string]any) (map[string]any, error) {
|
|
337
|
+
return p.requestMap(ctx, http.MethodPost, "/api/aihub/providers", nil, data)
|
|
338
|
+
}
|
|
339
|
+
func (p aiHubClient) UpdateProvider(ctx context.Context, id int64, data map[string]any) (map[string]any, error) {
|
|
340
|
+
return p.requestMap(ctx, http.MethodPatch, idPath("/api/aihub/providers", id), nil, data)
|
|
341
|
+
}
|
|
342
|
+
func (p aiHubClient) DeleteProvider(ctx context.Context, id int64) error {
|
|
343
|
+
_, err := p.Request(ctx, AIRequest{Method: http.MethodDelete, Path: idPath("/api/aihub/providers", id)})
|
|
344
|
+
return err
|
|
345
|
+
}
|
|
346
|
+
func (p aiHubClient) DiscoverProvider(ctx context.Context, id int64) (map[string]any, error) {
|
|
347
|
+
return p.requestMap(ctx, http.MethodPost, idPath("/api/aihub/providers", id)+"/discover", nil, nil)
|
|
348
|
+
}
|
|
349
|
+
func (p aiHubClient) SyncProvider(ctx context.Context, id int64) (map[string]any, error) {
|
|
350
|
+
return p.requestMap(ctx, http.MethodPost, idPath("/api/aihub/providers", id)+"/sync", nil, nil)
|
|
351
|
+
}
|
|
352
|
+
func (p aiHubClient) ListModels(ctx context.Context, query map[string]any) (map[string]any, error) {
|
|
353
|
+
return p.requestMap(ctx, http.MethodGet, "/api/aihub/models", query, nil)
|
|
354
|
+
}
|
|
355
|
+
func (p aiHubClient) GetModel(ctx context.Context, id int64) (map[string]any, error) {
|
|
356
|
+
result, err := p.ListModels(ctx, nil)
|
|
357
|
+
if err != nil {
|
|
358
|
+
return nil, err
|
|
359
|
+
}
|
|
360
|
+
for _, model := range mapSlice(result["items"]) {
|
|
361
|
+
if int64(asInt(model["id"])) == id {
|
|
362
|
+
return model, nil
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return nil, fmt.Errorf("AI model %d was not found", id)
|
|
366
|
+
}
|
|
367
|
+
func (p aiHubClient) CreateModel(ctx context.Context, data map[string]any) (map[string]any, error) {
|
|
368
|
+
return p.requestMap(ctx, http.MethodPost, "/api/aihub/models/manual", nil, data)
|
|
369
|
+
}
|
|
370
|
+
func (p aiHubClient) UpdateModel(ctx context.Context, id int64, data map[string]any) (map[string]any, error) {
|
|
371
|
+
return p.requestMap(ctx, http.MethodPatch, idPath("/api/aihub/models", id), nil, data)
|
|
372
|
+
}
|
|
373
|
+
func (p aiHubClient) DeleteModel(ctx context.Context, id int64) error {
|
|
374
|
+
_, err := p.Request(ctx, AIRequest{Method: http.MethodDelete, Path: idPath("/api/aihub/models", id)})
|
|
375
|
+
return err
|
|
376
|
+
}
|
|
377
|
+
func (p aiHubClient) ProbeModelRoute(ctx context.Context, id int64, task string) (map[string]any, error) {
|
|
378
|
+
return p.requestMap(ctx, http.MethodPost, idPath("/api/aihub/model-routes", id)+"/probe", nil, map[string]any{"task": task})
|
|
379
|
+
}
|
|
380
|
+
func (p aiHubClient) UpdateModelRoute(ctx context.Context, id int64, data map[string]any) (map[string]any, error) {
|
|
381
|
+
return p.requestMap(ctx, http.MethodPatch, idPath("/api/aihub/model-routes", id), nil, data)
|
|
382
|
+
}
|
|
383
|
+
func (p aiHubClient) DeleteModelRoute(ctx context.Context, id int64) (map[string]any, error) {
|
|
384
|
+
return p.requestMap(ctx, http.MethodDelete, idPath("/api/aihub/model-routes", id), nil, nil)
|
|
385
|
+
}
|
|
386
|
+
func (p aiHubClient) InstallSkill(ctx context.Context, request SkillInstallRequest) (map[string]any, error) {
|
|
387
|
+
return p.requestMap(ctx, http.MethodPost, "/api/skills/install", nil, map[string]any{"source": "github", "repo": request.Repository, "ref": request.Ref})
|
|
388
|
+
}
|
|
389
|
+
func (p aiHubClient) InstallSkillArchive(ctx context.Context, archive SkillArchive) (map[string]any, error) {
|
|
390
|
+
value, err := p.call(ctx, "ai.skill.install_archive", map[string]any{"filename": archive.Filename, "content_base64": base64.StdEncoding.EncodeToString(archive.Content)})
|
|
391
|
+
return mapResult(value), err
|
|
392
|
+
}
|
|
393
|
+
func (p aiHubClient) ListSkillVersions(ctx context.Context, id int64) ([]map[string]any, error) {
|
|
394
|
+
value, err := p.Request(ctx, AIRequest{Method: http.MethodGet, Path: idPath("/api/skills", id) + "/versions"})
|
|
395
|
+
return mapSlice(value), err
|
|
396
|
+
}
|
|
397
|
+
func (p aiHubClient) RollbackSkill(ctx context.Context, id int64, version int) (map[string]any, error) {
|
|
398
|
+
return p.requestMap(ctx, http.MethodPost, idPath("/api/skills", id)+"/rollback", nil, map[string]any{"version": version})
|
|
399
|
+
}
|
|
400
|
+
func (p aiHubClient) ListRuns(ctx context.Context, query map[string]any) (map[string]any, error) {
|
|
401
|
+
return p.requestMap(ctx, http.MethodGet, "/api/aihub/runs", query, nil)
|
|
402
|
+
}
|
|
403
|
+
func (p aiHubClient) GetRun(ctx context.Context, traceID string) (map[string]any, error) {
|
|
404
|
+
return p.requestMap(ctx, http.MethodGet, "/api/aihub/runs/"+traceID, nil, nil)
|
|
405
|
+
}
|
|
406
|
+
func (p aiHubClient) DeleteRuns(ctx context.Context, query map[string]any) (map[string]any, error) {
|
|
407
|
+
query = cloneSDKMap(query)
|
|
408
|
+
switch values := query["trace_ids"].(type) {
|
|
409
|
+
case []string:
|
|
410
|
+
query["trace_ids"] = strings.Join(values, ",")
|
|
411
|
+
case []any:
|
|
412
|
+
items := make([]string, 0, len(values))
|
|
413
|
+
for _, value := range values {
|
|
414
|
+
items = append(items, fmt.Sprint(value))
|
|
415
|
+
}
|
|
416
|
+
query["trace_ids"] = strings.Join(items, ",")
|
|
417
|
+
}
|
|
418
|
+
return p.requestMap(ctx, http.MethodDelete, "/api/aihub/runs", query, nil)
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
func (p knowledgeClient) requestMap(ctx context.Context, method, path string, query map[string]any, body any) (map[string]any, error) {
|
|
422
|
+
value, err := p.call(ctx, "ai.request", AIRequest{Method: method, Path: path, Query: query, Body: body})
|
|
423
|
+
return mapResult(value), err
|
|
424
|
+
}
|
|
425
|
+
func (p knowledgeClient) requestSlice(ctx context.Context, method, path string, query map[string]any) ([]map[string]any, error) {
|
|
426
|
+
value, err := p.call(ctx, "ai.request", AIRequest{Method: method, Path: path, Query: query})
|
|
427
|
+
if object := mapResult(value); object != nil {
|
|
428
|
+
value = object["items"]
|
|
429
|
+
}
|
|
430
|
+
return mapSlice(value), err
|
|
431
|
+
}
|
|
432
|
+
func (p knowledgeClient) List(ctx context.Context, query map[string]any) (map[string]any, error) {
|
|
433
|
+
return p.requestMap(ctx, http.MethodGet, "/api/knowledge-bases", query, nil)
|
|
434
|
+
}
|
|
435
|
+
func (p knowledgeClient) Get(ctx context.Context, id int64) (map[string]any, error) {
|
|
436
|
+
return p.requestMap(ctx, http.MethodGet, idPath("/api/knowledge-bases", id), nil, nil)
|
|
437
|
+
}
|
|
438
|
+
func (p knowledgeClient) Create(ctx context.Context, data map[string]any) (map[string]any, error) {
|
|
439
|
+
return p.requestMap(ctx, http.MethodPost, "/api/knowledge-bases", nil, data)
|
|
440
|
+
}
|
|
441
|
+
func (p knowledgeClient) Update(ctx context.Context, id int64, data map[string]any) (map[string]any, error) {
|
|
442
|
+
return p.requestMap(ctx, http.MethodPatch, idPath("/api/knowledge-bases", id), nil, data)
|
|
443
|
+
}
|
|
444
|
+
func (p knowledgeClient) Delete(ctx context.Context, id int64) error {
|
|
445
|
+
_, err := p.call(ctx, "ai.request", AIRequest{Method: http.MethodDelete, Path: idPath("/api/knowledge-bases", id)})
|
|
446
|
+
return err
|
|
447
|
+
}
|
|
448
|
+
func (p knowledgeClient) ListDocuments(ctx context.Context, baseID int64) ([]map[string]any, error) {
|
|
449
|
+
return p.requestSlice(ctx, http.MethodGet, idPath("/api/knowledge-bases", baseID)+"/documents", nil)
|
|
450
|
+
}
|
|
451
|
+
func (p knowledgeClient) GetDocument(ctx context.Context, baseID, documentID int64) (map[string]any, error) {
|
|
452
|
+
return p.requestMap(ctx, http.MethodGet, nestedIDPath("/api/knowledge-bases", baseID, "documents", documentID), nil, nil)
|
|
453
|
+
}
|
|
454
|
+
func (p knowledgeClient) UploadDocument(ctx context.Context, baseID int64, upload KnowledgeDocumentUpload) (map[string]any, error) {
|
|
455
|
+
value, err := p.call(ctx, "ai.knowledge.upload", map[string]any{"base_id": baseID, "filename": upload.Filename, "mime_type": upload.MIMEType, "content_base64": base64.StdEncoding.EncodeToString(upload.Content), "metadata": upload.Metadata, "auto_tag": upload.AutoTag, "tagging_model_id": upload.TaggingModelID})
|
|
456
|
+
return mapResult(value), err
|
|
457
|
+
}
|
|
458
|
+
func (p knowledgeClient) UpdateDocument(ctx context.Context, baseID, documentID int64, data map[string]any) (map[string]any, error) {
|
|
459
|
+
return p.requestMap(ctx, http.MethodPatch, nestedIDPath("/api/knowledge-bases", baseID, "documents", documentID), nil, data)
|
|
460
|
+
}
|
|
461
|
+
func (p knowledgeClient) DeleteDocument(ctx context.Context, baseID, documentID int64) error {
|
|
462
|
+
_, err := p.call(ctx, "ai.request", AIRequest{Method: http.MethodDelete, Path: nestedIDPath("/api/knowledge-bases", baseID, "documents", documentID)})
|
|
463
|
+
return err
|
|
464
|
+
}
|
|
465
|
+
func (p knowledgeClient) ReindexDocument(ctx context.Context, baseID, documentID int64) (map[string]any, error) {
|
|
466
|
+
return p.requestMap(ctx, http.MethodPost, nestedIDPath("/api/knowledge-bases", baseID, "documents", documentID)+"/reindex", nil, nil)
|
|
467
|
+
}
|
|
468
|
+
func (p knowledgeClient) ListChunks(ctx context.Context, baseID int64, query map[string]any) ([]map[string]any, error) {
|
|
469
|
+
return p.requestSlice(ctx, http.MethodGet, idPath("/api/knowledge-bases", baseID)+"/chunks", query)
|
|
470
|
+
}
|
|
471
|
+
func (p knowledgeClient) UpdateChunk(ctx context.Context, baseID, chunkID int64, data map[string]any) (map[string]any, error) {
|
|
472
|
+
return p.requestMap(ctx, http.MethodPatch, nestedIDPath("/api/knowledge-bases", baseID, "chunks", chunkID), nil, data)
|
|
473
|
+
}
|
|
474
|
+
func (p knowledgeClient) Retrieve(ctx context.Context, baseID int64, data map[string]any) (map[string]any, error) {
|
|
475
|
+
return p.requestMap(ctx, http.MethodPost, idPath("/api/knowledge-bases", baseID)+"/retrieve", nil, data)
|
|
476
|
+
}
|
|
477
|
+
func (p knowledgeClient) RebuildIndex(ctx context.Context, baseID int64) (map[string]any, error) {
|
|
478
|
+
return p.requestMap(ctx, http.MethodPost, idPath("/api/knowledge-bases", baseID)+"/rebuild-index", nil, nil)
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
func (p memoryClient) requestMap(ctx context.Context, method, path string, query map[string]any, body any) (map[string]any, error) {
|
|
482
|
+
value, err := p.call(ctx, "ai.request", AIRequest{Method: method, Path: path, Query: query, Body: body})
|
|
483
|
+
return mapResult(value), err
|
|
484
|
+
}
|
|
485
|
+
func (p memoryClient) List(ctx context.Context, query map[string]any) (map[string]any, error) {
|
|
486
|
+
return p.requestMap(ctx, http.MethodGet, "/api/memories", query, nil)
|
|
487
|
+
}
|
|
488
|
+
func (p memoryClient) Get(ctx context.Context, id int64) (map[string]any, error) {
|
|
489
|
+
return p.requestMap(ctx, http.MethodGet, idPath("/api/memories", id), nil, nil)
|
|
490
|
+
}
|
|
491
|
+
func (p memoryClient) Create(ctx context.Context, data map[string]any) (map[string]any, error) {
|
|
492
|
+
return p.requestMap(ctx, http.MethodPost, "/api/memories", nil, data)
|
|
493
|
+
}
|
|
494
|
+
func (p memoryClient) Update(ctx context.Context, id int64, data map[string]any) (map[string]any, error) {
|
|
495
|
+
return p.requestMap(ctx, http.MethodPatch, idPath("/api/memories", id), nil, data)
|
|
496
|
+
}
|
|
497
|
+
func (p memoryClient) Delete(ctx context.Context, id int64) error {
|
|
498
|
+
_, err := p.call(ctx, "ai.request", AIRequest{Method: http.MethodDelete, Path: idPath("/api/memories", id)})
|
|
499
|
+
return err
|
|
500
|
+
}
|
|
501
|
+
func (p memoryClient) GetConfig(ctx context.Context) (map[string]any, error) {
|
|
502
|
+
return p.requestMap(ctx, http.MethodGet, "/api/memories/config", nil, nil)
|
|
503
|
+
}
|
|
504
|
+
func (p memoryClient) UpdateConfig(ctx context.Context, data map[string]any) (map[string]any, error) {
|
|
505
|
+
return p.requestMap(ctx, http.MethodPatch, "/api/memories/config", nil, data)
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
func cloneSDKMap(value map[string]any) map[string]any {
|
|
509
|
+
result := make(map[string]any, len(value)+2)
|
|
510
|
+
for key, item := range value {
|
|
511
|
+
result[key] = item
|
|
512
|
+
}
|
|
513
|
+
return result
|
|
514
|
+
}
|
|
515
|
+
func idPath(base string, id int64) string {
|
|
516
|
+
return strings.TrimRight(base, "/") + "/" + strconv.FormatInt(id, 10)
|
|
517
|
+
}
|
|
518
|
+
func nestedIDPath(base string, parentID int64, collection string, id int64) string {
|
|
519
|
+
return fmt.Sprintf("%s/%d/%s/%d", strings.TrimRight(base, "/"), parentID, collection, id)
|
|
520
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
package sdk
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"encoding/base64"
|
|
6
|
+
"encoding/json"
|
|
7
|
+
"testing"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
type recordingClient struct {
|
|
11
|
+
op string
|
|
12
|
+
args map[string]any
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
func (client *recordingClient) Call(_ context.Context, operation string, args any) (any, error) {
|
|
16
|
+
client.op = operation
|
|
17
|
+
raw, _ := json.Marshal(args)
|
|
18
|
+
_ = json.Unmarshal(raw, &client.args)
|
|
19
|
+
switch operation {
|
|
20
|
+
case "aihub.tts":
|
|
21
|
+
return map[string]any{"audio_base64": base64.StdEncoding.EncodeToString([]byte("audio")), "mime_type": "audio/wav"}, nil
|
|
22
|
+
case "aihub.transcribe":
|
|
23
|
+
return map[string]any{"text": "hello"}, nil
|
|
24
|
+
case "ai.request":
|
|
25
|
+
path, _ := client.args["path"].(string)
|
|
26
|
+
if path == "/api/knowledge-bases/7/documents" {
|
|
27
|
+
return map[string]any{"items": []any{map[string]any{"id": float64(3)}}}, nil
|
|
28
|
+
}
|
|
29
|
+
return map[string]any{"ok": true}, nil
|
|
30
|
+
default:
|
|
31
|
+
return map[string]any{"ok": true}, nil
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
func TestAIHubInferenceOperations(t *testing.T) {
|
|
36
|
+
client := &recordingClient{}
|
|
37
|
+
draftgo := NewContext(context.Background(), nil, nil, nil, client)
|
|
38
|
+
|
|
39
|
+
if _, err := draftgo.AIHub.Chat(draftgo.Context(), AIChatRequest{AgentID: 12, Message: "hello", SessionID: "session-1", RunID: "run-1"}); err != nil {
|
|
40
|
+
t.Fatal(err)
|
|
41
|
+
}
|
|
42
|
+
if client.op != "aihub.chat" || client.args["agent_id"] != float64(12) {
|
|
43
|
+
t.Fatalf("unexpected chat call: %s %#v", client.op, client.args)
|
|
44
|
+
}
|
|
45
|
+
if client.args["session_id"] != "session-1" || client.args["run_id"] != "run-1" {
|
|
46
|
+
t.Fatalf("chat session metadata missing: %#v", client.args)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if _, err := draftgo.AIHub.Responses(draftgo.Context(), AIResponsesRequest{
|
|
50
|
+
Model: "responses", Input: "hello", Instructions: "be concise", PreviousResponseID: "resp_previous",
|
|
51
|
+
Tools: []map[string]any{{"type": "web_search"}}, Options: map[string]any{"reasoning": map[string]any{"effort": "high"}, "stream": true},
|
|
52
|
+
}); err != nil {
|
|
53
|
+
t.Fatal(err)
|
|
54
|
+
}
|
|
55
|
+
if client.op != "aihub.responses" || client.args["model"] != "responses" || client.args["stream"] != false || client.args["previous_response_id"] != "resp_previous" || client.args["reasoning"] == nil {
|
|
56
|
+
t.Fatalf("unexpected Responses call: %s %#v", client.op, client.args)
|
|
57
|
+
}
|
|
58
|
+
if _, err := draftgo.AIHub.CompactResponse(draftgo.Context(), AIResponsesRequest{Model: "responses", Input: []any{"one"}}); err != nil {
|
|
59
|
+
t.Fatal(err)
|
|
60
|
+
}
|
|
61
|
+
if client.op != "aihub.responses.compact" || client.args["stream"] != false {
|
|
62
|
+
t.Fatalf("unexpected compact Responses call: %s %#v", client.op, client.args)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if _, err := draftgo.AIHub.Embeddings(draftgo.Context(), AIEmbeddingRequest{Model: "embed", Input: []string{"one"}}); err != nil {
|
|
66
|
+
t.Fatal(err)
|
|
67
|
+
}
|
|
68
|
+
if client.op != "aihub.embeddings" || client.args["model"] != "embed" {
|
|
69
|
+
t.Fatalf("unexpected embeddings call: %s %#v", client.op, client.args)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if _, err := draftgo.AIHub.Rerank(draftgo.Context(), AIRerankRequest{Model: "rerank", Query: "query", Documents: []string{"one", "two"}, TopN: 1, ReturnDocuments: true}); err != nil {
|
|
73
|
+
t.Fatal(err)
|
|
74
|
+
}
|
|
75
|
+
if client.op != "aihub.rerank" || client.args["model"] != "rerank" || client.args["top_n"] != float64(1) || client.args["return_documents"] != true {
|
|
76
|
+
t.Fatalf("unexpected rerank call: %s %#v", client.op, client.args)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
audio, err := draftgo.AIHub.TextToSpeech(draftgo.Context(), AITTSRequest{Model: "tts", Input: "hello", Voice: "Mia"})
|
|
80
|
+
if err != nil || string(audio.Content) != "audio" || audio.MIMEType != "audio/wav" {
|
|
81
|
+
t.Fatalf("unexpected TTS result: %+v %v", audio, err)
|
|
82
|
+
}
|
|
83
|
+
if client.op != "aihub.tts" || client.args["model"] != "tts" {
|
|
84
|
+
t.Fatalf("unexpected TTS call: %s %#v", client.op, client.args)
|
|
85
|
+
}
|
|
86
|
+
transcript, err := draftgo.AIHub.Transcribe(draftgo.Context(), AITranscriptionRequest{Model: "asr", Content: []byte("audio"), MIMEType: "audio/wav", Language: "zh"})
|
|
87
|
+
if err != nil || transcript["text"] != "hello" {
|
|
88
|
+
t.Fatalf("unexpected ASR result: %#v %v", transcript, err)
|
|
89
|
+
}
|
|
90
|
+
if client.op != "aihub.transcribe" || client.args["audio_base64"] != base64.StdEncoding.EncodeToString([]byte("audio")) {
|
|
91
|
+
t.Fatalf("unexpected ASR call: %s %#v", client.op, client.args)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
func TestAIHubChatUsesCanonicalRPCOperationAndLogicalModel(t *testing.T) {
|
|
96
|
+
client := &recordingClient{}
|
|
97
|
+
draftgo := NewContext(context.Background(), nil, nil, nil, client)
|
|
98
|
+
|
|
99
|
+
result, err := draftgo.AIHub.Chat(draftgo.Context(), AIChatRequest{
|
|
100
|
+
Model: "shared-logical-model",
|
|
101
|
+
Messages: []map[string]any{{"role": "user", "content": "hello"}},
|
|
102
|
+
Options: map[string]any{"temperature": 0.2},
|
|
103
|
+
})
|
|
104
|
+
if err != nil {
|
|
105
|
+
t.Fatal(err)
|
|
106
|
+
}
|
|
107
|
+
if result == nil || client.op != "aihub.chat" {
|
|
108
|
+
t.Fatalf("result=%#v operation=%q", result, client.op)
|
|
109
|
+
}
|
|
110
|
+
if client.args["model"] != "shared-logical-model" || client.args["agent_id"] != float64(0) {
|
|
111
|
+
t.Fatalf("canonical chat target = %#v", client.args)
|
|
112
|
+
}
|
|
113
|
+
kwargs, _ := client.args["kwargs"].(map[string]any)
|
|
114
|
+
if kwargs["temperature"] != float64(0.2) {
|
|
115
|
+
t.Fatalf("chat options = %#v", kwargs)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
func TestAdminAIRequestCarriesElevationMarker(t *testing.T) {
|
|
120
|
+
client := &recordingClient{}
|
|
121
|
+
draftgo := NewContext(context.Background(), nil, nil, nil, client)
|
|
122
|
+
if _, err := draftgo.Admin.AIHub.ListModels(draftgo.Context(), map[string]any{"provider_id": 4}); err != nil {
|
|
123
|
+
t.Fatal(err)
|
|
124
|
+
}
|
|
125
|
+
if client.op != "ai.request" || client.args["__draftgo_admin"] != true {
|
|
126
|
+
t.Fatalf("admin marker missing: %s %#v", client.op, client.args)
|
|
127
|
+
}
|
|
128
|
+
if client.args["path"] != "/api/aihub/models" {
|
|
129
|
+
t.Fatalf("unexpected path: %#v", client.args["path"])
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
func TestKnowledgeAndArchiveEncoding(t *testing.T) {
|
|
134
|
+
client := &recordingClient{}
|
|
135
|
+
draftgo := NewContext(context.Background(), nil, nil, nil, client)
|
|
136
|
+
|
|
137
|
+
documents, err := draftgo.Knowledge.ListDocuments(draftgo.Context(), 7)
|
|
138
|
+
if err != nil || len(documents) != 1 || documents[0]["id"] != float64(3) {
|
|
139
|
+
t.Fatalf("unexpected documents: %#v, %v", documents, err)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
content := []byte{0, 1, 2, 255}
|
|
143
|
+
if _, err = draftgo.Knowledge.UploadDocument(draftgo.Context(), 7, KnowledgeDocumentUpload{Filename: "data.pdf", Content: content}); err != nil {
|
|
144
|
+
t.Fatal(err)
|
|
145
|
+
}
|
|
146
|
+
if client.op != "ai.knowledge.upload" || client.args["content_base64"] != base64.StdEncoding.EncodeToString(content) {
|
|
147
|
+
t.Fatalf("document encoding mismatch: %s %#v", client.op, client.args)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if _, err = draftgo.AIHub.InstallSkillArchive(draftgo.Context(), SkillArchive{Filename: "skill.zip", Content: content}); err != nil {
|
|
151
|
+
t.Fatal(err)
|
|
152
|
+
}
|
|
153
|
+
if client.op != "ai.skill.install_archive" || client.args["content_base64"] != base64.StdEncoding.EncodeToString(content) {
|
|
154
|
+
t.Fatalf("archive encoding mismatch: %s %#v", client.op, client.args)
|
|
155
|
+
}
|
|
156
|
+
}
|