Documentation
¶
Overview ¶
Package dify is a Go client for Dify: its Service API, and the console API for managing a workspace.
Three clients, because Dify scopes three credentials:
App an app's key (app-…) running one app, its conversations, its files Knowledge a dataset key (dataset-…) knowledge bases, documents, retrieval Management a console session deploying apps, keys, what the workspace has
A client holds the connection and the credential. What you can do hangs off it by what it acts on — app.Chat.Messages, app.Workflows.Runs, knowledge.Datasets — and a call returns the thing, not an HTTP response, carrying the ids the next call needs:
app, err := dify.NewApp(dify.WithAPIKey("app-…"), dify.WithUser("alice"))
run, err := app.Workflows.Runs.Create(ctx, map[string]any{"text": "…"}, nil)
run.RunID // reads the run back later
run.TaskID // what a stop request names — a different id
run.Outputs // what the workflow produced
Configuration ¶
Keys and hosts resolve from options first, then the environment, using the names the difyctl CLI reads: DIFY_API_KEY, DIFY_HOST (the Service API is derived as <host>/v1), and DIFY_API_BASE_URL to override that derivation. Knowledge reads DIFY_DATASET_API_KEY, then DIFY_API_KEY. Management reads DIFY_CONSOLE_TOKEN and DIFY_CONSOLE_CSRF_TOKEN, or logs in with LoginManagement, and talks to <host>/console/api.
Streams ¶
A stream is how a run is observed. Events yields each event as a Go 1.23 iterator; FinalRun and FinalMessage answer what it came to afterwards. Closing a stream stops watching, not the run. A pause is not a failure: WorkflowRun.Paused, Succeeded and Failed are three separate questions. An HTTP 200 is not a successful run: Dify reports a mid-stream failure as an "error" event, which the stream yields as an *APIError.
Errors ¶
Test errors with errors.Is against ErrAuthentication, ErrRateLimited, ErrValidation, ErrNotFound, ErrFileUpload, ErrTimeout and ErrNetwork, and reach Dify's message, code and version with errors.As(err, &apiErr).
Retries and timeouts ¶
A request that failed before it was sent is always retried. One that was sent is retried only for an idempotent method: repeating a timed-out POST /workflows/run can bill the run again. A 429 is waited out for any method, honouring Retry-After up to MaxRateLimitWait.
Each request is bounded by DefaultTimeout unless its context carries a deadline, which replaces it — give one long workflow run twenty minutes with context.WithTimeout rather than raising the timeout for every call. On a stream the timeout bounds the silence between events, not its length.
Example ¶
package main
import (
"context"
"fmt"
"log"
"github.com/langgenius/dify-go-sdk"
)
func main() {
ctx := context.Background()
app, err := dify.NewApp(dify.WithAPIKey("app-…"), dify.WithUser("alice"))
if err != nil {
log.Fatal(err)
}
msg, err := app.Chat.Messages.Create(ctx, "Hello", nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(msg.Answer, msg.ConversationID)
}
Output:
Index ¶
- Constants
- Variables
- func FormToken(run *WorkflowRun) (string, error)
- func MaskSecret(value string) string
- func OpenApp(ctx context.Context, opts ...Option) (*App, *AppInfo, error)
- func RetrievalModel(p *RetrievalModelParams) (map[string]any, error)
- func UserAgent() string
- func Version() string
- func WeightedScore(p WeightedScoreParams) (map[string]any, error)
- type APIError
- type APIKey
- type AgentListParams
- type AgentSummary
- type Agents
- type Amount
- type Annotation
- type AnnotationListParams
- type AnnotationReplyJob
- type Annotations
- type App
- type AppInfo
- type AppKeys
- type AppListParams
- type AppParameters
- type AppSummary
- type Apps
- type ArgumentError
- type Audio
- type Chat
- type ChildChunkListParams
- type CompletionParams
- type Completions
- type Conversation
- type ConversationListParams
- type Conversations
- type Dataset
- type DatasetCreateParams
- type DatasetKeys
- type DatasetListParams
- type DatasetUpdateParams
- type Datasets
- type DatasourcesParams
- type DeployParams
- type Deployment
- type Document
- type DocumentCreateParams
- type DocumentListParams
- type DocumentStatus
- type DocumentUpdateFileParams
- type DocumentUpdateTextParams
- type Documents
- type DraftRunParams
- type EventsParams
- type FeedbackParams
- type Files
- type Form
- type Forms
- type HistoryMessage
- type HistoryParams
- type ImportParams
- type IndexingStatus
- type InputField
- type KeyFunc
- type Knowledge
- type LogParams
- type ManagedApp
- type Management
- type Message
- type MessageParams
- type MessageStream
- type Messages
- type MetadataField
- type Model
- type ModelProvider
- type NodeExecution
- type Option
- func WithAPIKey(key string) Option
- func WithAPIKeyFunc(f KeyFunc) Option
- func WithBaseURL(u string) Option
- func WithCSRFToken(token string) Option
- func WithConsoleToken(token string) Option
- func WithHTTPClient(h *http.Client) Option
- func WithHost(host string) Option
- func WithLogger(l *slog.Logger) Option
- func WithMaxRetries(n int) Option
- func WithRetryDelay(d time.Duration) Option
- func WithTimeout(d time.Duration) Option
- func WithUser(user string) Option
- type Page
- type PageLimitError
- type PageParams
- type Pipeline
- type PipelineDeployParams
- type PipelineDeployment
- type PipelineImportParams
- type PipelineIngestion
- type PipelineRunInput
- type PipelineSummary
- type Pipelines
- type Plugin
- type Rating
- type RenameParams
- type ReplySettings
- type RetrievalHit
- type RetrievalModelParams
- type RunDatasourceParams
- type RunEvent
- type RunParams
- type SearchParams
- type Segment
- type SegmentListParams
- type Segments
- type ServerInfo
- type SiteSettings
- type SkillImportParams
- type Skills
- type SpeakParams
- type Stage
- type StageError
- type Tag
- type Tags
- type Tool
- type ToolParameter
- type ToolProvider
- type Tools
- type TransportError
- type Trigger
- type Triggers
- type Upload
- type UploadedFile
- type Usage
- type VariableParams
- type WaitParams
- type WebhookTrigger
- type WeightedScoreParams
- type WorkflowRun
- type WorkflowRunStream
- type WorkflowRuns
- type Workflows
- type WorkspaceModels
- type WorkspaceSkill
Examples ¶
Constants ¶
const ( DocumentEnable = usecase.DocumentEnable DocumentDisable = usecase.DocumentDisable DocumentArchive = usecase.DocumentArchive DocumentUnarchive = usecase.DocumentUnarchive )
const ( SearchSemantic = usecase.SearchSemantic SearchFullText = usecase.SearchFullText SearchHybrid = usecase.SearchHybrid SearchKeyword = usecase.SearchKeyword )
How Dify may search a knowledge base.
const ( Like = usecase.Like Dislike = usecase.Dislike // NoRating takes a rating back. NoRating = usecase.NoRating )
const ( // EnvHost names the Dify host, e.g. http://localhost. The Service API base // is derived from it as <host>/v1. EnvHost = infra.EnvHost // EnvAPIBaseURL overrides that derivation, for the unusual case where the // Service API does not sit at <host>/v1. EnvAPIBaseURL = infra.EnvAPIBaseURL // EnvAPIKey is an app's Service-API key, read by NewApp. EnvAPIKey = infra.EnvAPIKey // EnvDatasetAPIKey is a knowledge (dataset) key, read by NewKnowledge. // Falls back to EnvAPIKey, which is where a single-purpose program keeps it. EnvDatasetAPIKey = infra.EnvDatasetAPIKey )
Environment variables, the same names the difyctl CLI reads, so a machine set up for one is set up for the other.
const ( // DefaultTimeout bounds a request whose context carries no deadline. A // context with a deadline of its own replaces it, which is how one long // workflow run gets twenty minutes without every call getting them. DefaultTimeout = infra.DefaultTimeout // DefaultMaxRetries is how many times a request is repeated after the // first attempt, when repeating it is safe. DefaultMaxRetries = infra.DefaultMaxRetries // DefaultRetryDelay is the first backoff; each retry doubles it. DefaultRetryDelay = infra.DefaultRetryDelay // MaxRateLimitWait is the longest this client sits out a 429, however long // Dify asks for. A server under maintenance can answer Retry-After: 3600, // and a call that blocks for an hour is indistinguishable from one that // hung — so beyond this the 429 is returned, with RetryAfter set. MaxRateLimitWait = infra.MaxRateLimitWait )
const ( // StageUnknown is a request that went out with no answer back. What Dify // did is unknown, so neither retrying nor cleaning up is obviously right. StageUnknown = entity.StageUnknown // StageNotImported is a document Dify refused, or held for confirmation: // no draft exists. StageNotImported = entity.StageNotImported // StageDrafted is a draft on Dify that nothing runs yet. The Service API // runs the published version. StageDrafted = entity.StageDrafted // StagePublished is a live version with no key in hand to call it with. StagePublished = entity.StagePublished // StageRunnable is published, with a Service-API key in hand. StageRunnable = entity.StageRunnable )
const ( // EnvConsoleToken is a console session's access token, read by // NewManagement. Named apart from difyctl's DIFY_TOKEN, which holds an // /openapi/v1 bearer — a different credential the console refuses. EnvConsoleToken = infra.EnvConsoleToken // EnvConsoleCSRFToken is the CSRF token that goes with it. Since Dify 1.17 // every console request, reads included, needs both. EnvConsoleCSRFToken = infra.EnvConsoleCSRFToken // DefaultConsoleHost is Dify Cloud. DefaultConsoleHost = infra.DefaultConsoleHost )
const DefaultBaseURL = infra.DefaultBaseURL
DefaultBaseURL is Dify Cloud's Service API.
const MaxWalk = codec.MaxWalk
MaxWalk is how many items Page.All walks before it stops and says so.
A walk is a loop the server controls: it ends when Dify stops saying has_more. A server that never stops — a bug, a proxy, a listing growing faster than it is read — would otherwise be an unbounded number of requests inside what reads like an ordinary for loop. Reaching this yields an error rather than quietly truncating, because a walk that stops early without saying so is the bug All exists to fix.
Variables ¶
var ( ErrAuthentication = kernel.ErrAuthentication ErrRateLimited = kernel.ErrRateLimited ErrValidation = kernel.ErrValidation ErrFileUpload = kernel.ErrFileUpload ErrNotFound = kernel.ErrNotFound ErrTimeout = kernel.ErrTimeout ErrNetwork = kernel.ErrNetwork )
Sentinels to test an error against with errors.Is. They classify what went wrong without committing a caller to a concrete type:
errors.Is(err, dify.ErrAuthentication) 401 — the key is wrong or revoked errors.Is(err, dify.ErrRateLimited) 429 — see APIError.RetryAfter errors.Is(err, dify.ErrValidation) 422, or arguments refused before sending errors.Is(err, dify.ErrFileUpload) an upload Dify would not take errors.Is(err, dify.ErrNotFound) 404 errors.Is(err, dify.ErrTimeout) the request ran past its deadline errors.Is(err, dify.ErrNetwork) the connection failed
errors.As(err, &apiErr) reaches the *APIError itself, which carries the server's message, code and version.
var ErrCostUnknown = entity.ErrCostUnknown
ErrCostUnknown is returned by TotalPrice when nothing reported a cost.
Functions ¶
func FormToken ¶
func FormToken(run *WorkflowRun) (string, error)
FormToken picks the token to answer a paused run with — the first of its PendingForms — or explains why there is none.
func MaskSecret ¶
MaskSecret renders a key the way it is safe to print: app-****3f2a.
Dify issues keys with a type prefix (app-, dataset-), which is kept so a masked key is still identifiable.
func OpenApp ¶
OpenApp builds a client and asks Dify what the app is before returning it. Costs one request; worth it when the key comes from configuration and a wrong one should fail here rather than on the first run.
func RetrievalModel ¶
func RetrievalModel(p *RetrievalModelParams) (map[string]any, error)
RetrievalModel builds the retrieval_model block. See RetrievalModelParams for what each setting does and the two reranking modes it refuses to combine.
func UserAgent ¶
func UserAgent() string
UserAgent is what this SDK sends. Dify logs the User-Agent of everything that talks to it; Go's default says only "Go-http-client/1.1", which tells an operator looking at a misbehaving client nothing about which SDK or version it was.
func Version ¶
func Version() string
Version is what this SDK reports itself as, read from the build info of the program it is compiled into rather than written down here, where it would drift from the tag. It is "(devel)" when built from a checkout that is the main module, since there is no tag to read.
func WeightedScore ¶
func WeightedScore(p WeightedScoreParams) (map[string]any, error)
WeightedScore blends vector and keyword scores instead of calling a rerank model:
weights, err := dify.WeightedScore(dify.WeightedScoreParams{Embedding: embeddingModel})
retrieval, err := dify.RetrievalModel(&dify.RetrievalModelParams{Search: dify.SearchHybrid, Weights: weights})
Types ¶
type APIError ¶
APIError is Dify answering, and the answer being an error.
It carries which Dify answered. Every response Dify sends — errors included — has X-Version and X-Env on it, and the first question about a failing call is always which server and which version. By the time someone asks, the error message is usually all that is left, so the version goes in it.
Example ¶
package main
import (
"context"
"errors"
"fmt"
"github.com/langgenius/dify-go-sdk"
)
func main() {
ctx := context.Background()
app, _ := dify.NewApp(dify.WithAPIKey("app-wrong"))
_, err := app.Info(ctx)
var apiErr *dify.APIError
switch {
case errors.Is(err, dify.ErrAuthentication):
fmt.Println("check the key")
case errors.Is(err, dify.ErrRateLimited) && errors.As(err, &apiErr):
fmt.Println("retry after", apiErr.RetryAfter)
case errors.As(err, &apiErr):
fmt.Println(apiErr.Message, apiErr.ServerVersion)
}
}
Output:
type APIKey ¶
APIKey is a Service-API key, for an app or for the workspace's knowledge bases.
Dify shows the whole token when the key is minted. A listing of the workspace's dataset keys shows it masked — "datas...3f2a" — and a masked token authenticates as "Access token is invalid". (Dify 1.17 lists an app's keys in full.)
type AgentListParams ¶
type AgentListParams = usecase.AgentListParams
AgentListParams narrow the roster.
type AgentSummary ¶
type AgentSummary = entity.AgentSummary
AgentSummary is an Agent as the workspace's roster reports it. Agents are kept off the app list.
ID addresses the Agent on the roster, which is where it publishes; AppID is what every app-shaped call wants — export, delete, keys.
type Agents ¶
Agents are the workspace's Agents. Dify keeps them on a roster of their own, off the app list, and an Agent publishes there rather than as a workflow.
type Amount ¶
Amount is a decimal money figure, kept exact. Dify reports prices as decimal strings ("0.000214"); a float64 would add rounding error on every sum, and a budget check is exactly where that is not acceptable.
func ParseAmount ¶
ParseAmount reads a decimal string such as "0.000214".
type Annotation ¶
type Annotation = entity.Annotation
Annotation is a question and the answer you want given for it.
type AnnotationListParams ¶
type AnnotationListParams = usecase.AnnotationListParams
AnnotationListParams narrow the annotations.
type AnnotationReplyJob ¶
type AnnotationReplyJob = entity.AnnotationReplyJob
AnnotationReplyJob is the indexing job that turns annotation reply on or off. Enabling it embeds every annotation, which takes time — so Dify answers with a job rather than a result.
type Annotations ¶
type Annotations = usecase.Annotations
Annotations are this app's annotations, and the reply setting that uses them.
type App ¶
App is one Dify app, addressed by its Service-API key.
The client holds the connection and the credential. What you can do hangs off it by what it acts on:
app, err := dify.NewApp(dify.WithAPIKey("app-…"), dify.WithUser("alice"))
msg, err := app.Chat.Messages.Create(ctx, "Hello", nil)
run, err := app.Workflows.Runs.Create(ctx, map[string]any{"text": "…"}, nil)
An app has one mode, and Dify serves each mode on its own route — so app.Chat on a workflow app, or app.Workflows on a chatflow, answers "check if your app mode matches the right API route". Info reports which this is.
An App is safe for concurrent use.
type AppKeys ¶
AppKeys are an app's Service-API keys.
Dify shows a key once, when it is minted, and an app holds ten. There is no reading one back — the listing masks the token — so mint one, keep it, and revoke it when done; a leaked key fills the cap and the error never says which ones to revoke.
type AppListParams ¶
type AppListParams = usecase.AppListParams
AppListParams narrow the workspace's apps. Zero values take Dify's defaults.
type AppParameters ¶
type AppParameters = entity.AppParameters
AppParameters is what an app declares it takes, and what it has turned on.
type AppSummary ¶
type AppSummary = entity.AppSummary
AppSummary is an app as the workspace lists it.
type Apps ¶
Apps are the workspace's apps, and the steps between a DSL document and a run.
Dify keeps three things apart: importing writes a draft, publishing makes a version live, and the Service API runs the live version with a key. Import, Publish and Keys.Create are those steps; Deploy does all three and reports each as its own fact.
type ArgumentError ¶
type ArgumentError = kernel.ArgumentError
ArgumentError is a call this client refused before spending a request on it. It matches ErrValidation, the same as a 422 from Dify, because to the caller both mean "these arguments will not do".
type ChildChunkListParams ¶
type ChildChunkListParams = usecase.ChildChunkListParams
ChildChunkListParams narrow a segment's child-chunk listing.
type CompletionParams ¶
type CompletionParams = usecase.CompletionParams
CompletionParams are the optional parts of a completion.
type Completions ¶
type Completions = usecase.Completions
Completions are one prompt in, one answer out, no thread. Only a completion-mode app serves these.
type Conversation ¶
type Conversation = entity.Conversation
Conversation is one thread, belonging to one user.
type ConversationListParams ¶
type ConversationListParams = usecase.ConversationListParams
ConversationListParams narrow a user's conversations.
type Conversations ¶
type Conversations = usecase.Conversations
Conversations are a user's threads with this app.
type DatasetCreateParams ¶
type DatasetCreateParams = usecase.DatasetCreateParams
DatasetCreateParams are the optional parts of creating a knowledge base.
type DatasetKeys ¶
type DatasetKeys = usecase.DatasetKeys
DatasetKeys are the workspace's knowledge-base API keys: what dify.NewKnowledge takes. A workspace holds ten, and a listing masks them, so mint one when needed and revoke it when done.
type DatasetListParams ¶
type DatasetListParams = usecase.DatasetListParams
DatasetListParams narrow the workspace's knowledge base listing.
type DatasetUpdateParams ¶
type DatasetUpdateParams = usecase.DatasetUpdateParams
DatasetUpdateParams are the changeable settings of a knowledge base. A nil field is left as it was; only what is set here is sent, since Dify updates only the fields present in the PATCH body.
type DatasourcesParams ¶
type DatasourcesParams = usecase.DatasourcesParams
DatasourcesParams controls whether Datasources reads the published or draft pipeline.
type DeployParams ¶
type DeployParams = usecase.DeployParams
DeployParams choose which of Deploy's steps happen.
type Deployment ¶
type Deployment = entity.Deployment
Deployment is what an app deploy came to: which steps happened, as separate facts, and where it stopped if it stopped early.
d, err := management.Apps.Deploy(ctx, dsl, nil)
if err := d.Err(dify.StageRunnable); err != nil { ... }
A failed step is reported here rather than as the call's error, because a half-done deploy is a state to act on — the app may exist, unpublished — and an error alone would lose which half was done.
type DocumentCreateParams ¶
type DocumentCreateParams = usecase.DocumentCreateParams
DocumentCreateParams are the optional parts of adding a document.
type DocumentListParams ¶
type DocumentListParams = usecase.DocumentListParams
DocumentListParams narrow a knowledge base's document listing.
type DocumentStatus ¶
type DocumentStatus = usecase.DocumentStatus
DocumentStatus is an action Documents.SetStatus performs in bulk.
type DocumentUpdateFileParams ¶
type DocumentUpdateFileParams = usecase.DocumentUpdateFileParams
DocumentUpdateFileParams are the optional parts of replacing a document's file.
type DocumentUpdateTextParams ¶
type DocumentUpdateTextParams = usecase.DocumentUpdateTextParams
DocumentUpdateTextParams are the optional parts of replacing a document's text.
type Documents ¶
Documents are the documents inside one knowledge base.
docs := knowledge.Documents(dataset.ID) doc, err := docs.CreateFromText(ctx, "notes", "…", nil) docs.WaitUntilIndexed(ctx, doc.Batch, nil)
type DraftRunParams ¶
type DraftRunParams = usecase.DraftRunParams
DraftRunParams are the optional parts of running a draft.
type EventsParams ¶
type EventsParams = usecase.EventsParams
EventsParams are the optional parts of reopening a run's stream.
type FeedbackParams ¶
type FeedbackParams = usecase.FeedbackParams
FeedbackParams are the optional parts of rating a message.
type Forms ¶
Forms are the forms a paused run is waiting on.
Waiting is not failing: a run that reaches a human-input node stops, its stream ends, and it resumes when the form comes back. WorkflowRun.Paused says so, and PendingForms carries the token.
type HistoryMessage ¶
type HistoryMessage = entity.HistoryMessage
HistoryMessage is one turn in a conversation, as Dify records it.
Deliberately not a Message. History carries the Query that prompted the answer, the files attached, the feedback left and what it cost — none of which a fresh reply has — and it has no TaskID, because nothing is running to stop. Reusing one type for both dropped the query, leaving a transcript of answers to questions nobody could see.
type HistoryParams ¶
type HistoryParams = usecase.HistoryParams
HistoryParams narrow a conversation's history.
type ImportParams ¶
type ImportParams = usecase.ImportParams
ImportParams are the optional parts of importing a DSL.
type IndexingStatus ¶
type IndexingStatus = entity.IndexingStatus
IndexingStatus is how far the indexing of one batch has got. Uploading a document returns before it is searchable; this is what says when it is.
type InputField ¶
type InputField = entity.InputField
InputField is one field an app declares, as its start node defines it.
Name is the key to put in inputs. Dify spells it "variable" and puts a separate label beside it for display; using the label as the key is the usual first mistake, because for a field created in the UI the two are often the same string and it works until someone renames one.
type KeyFunc ¶
KeyFunc produces an API key on demand. It is called for every request rather than once, which is what lets a key come from a vault and be rotated without rebuilding the client.
type Knowledge ¶
Knowledge is the workspace's knowledge bases, addressed by a dataset API key.
A dataset key is not an app key: it scopes to the workspace's datasets and can do nothing to an app, which is why this is a separate client from App rather than another field on it.
knowledge, err := dify.NewKnowledge(dify.WithAPIKey("dataset-…"))
dataset, err := knowledge.Datasets.Create(ctx, "handbook", nil)
docs := knowledge.Documents(dataset.ID)
doc, err := docs.CreateFromText(ctx, "policy", "…", nil)
docs.WaitUntilIndexed(ctx, doc.Batch, nil)
hits, err := knowledge.Datasets.Search(ctx, dataset.ID, "what is the refund window?", nil)
A Knowledge is safe for concurrent use.
func NewKnowledge ¶
NewKnowledge builds a client for the workspace's knowledge bases. The key comes from WithAPIKey, then DIFY_DATASET_API_KEY, then DIFY_API_KEY — the fallback is where a single-purpose program keeps a dataset key it never distinguishes from an app key. It sends nothing.
type ManagedApp ¶
type ManagedApp = usecase.ManagedApp
ManagedApp is one app from the account's side: what management knows of it, and a way to call it.
type Management ¶
type Management = usecase.Management
Management is the workspace, from an account's side: creating, publishing and deleting apps, minting their keys, and what the workspace has installed.
It talks to the console API, which authenticates as an account rather than as an app — a credential to the whole account, since Dify has nothing narrower. That is why it is a client of its own and not more fields on App:
m, err := dify.LoginManagement(ctx, email, password, dify.WithHost("http://localhost"))
d, err := m.Apps.Deploy(ctx, dsl, nil)
if err := d.Err(dify.StageRunnable); err != nil { ... }
app, err := m.AppClient(d.APIKey, "alice")
A Management is safe for concurrent use. A session from LoginManagement is renewed when it expires; one from tokens is not, since a login is what hands out the refresh token.
func LoginManagement ¶
func LoginManagement(ctx context.Context, email, password string, opts ...Option) (*Management, error)
LoginManagement logs in to the console with an account's email and password, and returns a client holding the session. The session is renewed when it expires, for as long as Dify's refresh token lasts (30 days by default).
Prefer an account made for automation: this is the credential to the whole account, and Dify offers nothing narrower. The password is used for this one request and not kept.
func NewManagement ¶
func NewManagement(opts ...Option) (*Management, error)
NewManagement builds a client for the workspace, from a console session given as tokens: WithConsoleToken and WithCSRFToken, or DIFY_CONSOLE_TOKEN and DIFY_CONSOLE_CSRF_TOKEN. The host comes from WithHost, DIFY_HOST, or Dify Cloud. It sends nothing.
A session given as tokens is not renewed when it expires, since only a login hands out the refresh token; LoginManagement is the one that lasts.
type Message ¶
Message is one message a chat or completion app produced, and the thread it belongs to.
type MessageParams ¶
type MessageParams = usecase.MessageParams
MessageParams are the optional parts of sending a chat message.
type MessageStream ¶
type MessageStream = codec.MessageStream
MessageStream is a chat or completion message, watched as it is written.
stream, err := app.Chat.Messages.Stream(ctx, "Hello", nil)
if err != nil { ... }
defer stream.Close()
for piece, err := range stream.Text() {
if err != nil { ... }
fmt.Print(piece)
}
message := stream.FinalMessage()
type Messages ¶
Messages are the messages in this app's conversations.
Create waits for the whole answer. Stream hands it back as it is written. Both return the thread's ConversationID, which is what continues it.
type MetadataField ¶
type MetadataField = entity.MetadataField
MetadataField is a field documents in one knowledge base may carry.
Two kinds arrive in this shape and the difference is the id: a field you defined has one and can be renamed or deleted by it, while one of Dify's own — filename, upload date — has none, because those are turned on and off rather than managed.
type ModelProvider ¶
type ModelProvider = entity.ModelProvider
ModelProvider is a configured provider, and the models it offers.
type NodeExecution ¶
type NodeExecution = entity.NodeExecution
NodeExecution is one execution of one node.
Distinct from the node itself: a node inside an iteration or a loop runs once per item, and each pass is its own execution with its own usage. Treating the two as the same thing is what made a looped node report only its last pass.
type Option ¶
Option configures a client. The same options serve App and Knowledge.
func WithAPIKey ¶
WithAPIKey sets the key. Left out, it is read from the environment.
func WithAPIKeyFunc ¶
WithAPIKeyFunc fetches the key per request instead of holding it, so a rotating or short-lived key works without rebuilding the client and no long-lived secret sits on it.
func WithBaseURL ¶
WithBaseURL sets the Service API root, e.g. http://localhost/v1. Left out, it is DIFY_API_BASE_URL, then <DIFY_HOST>/v1, then Dify Cloud.
func WithCSRFToken ¶
WithCSRFToken sets the CSRF token that goes with a console access token. Left out, it is read from DIFY_CONSOLE_CSRF_TOKEN. A Dify before 1.17 needs none; since 1.17 every request is refused without it.
func WithConsoleToken ¶
WithConsoleToken sets a console session's access token. Left out, it is read from DIFY_CONSOLE_TOKEN. dify.LoginManagement obtains one from an email and password instead.
func WithHTTPClient ¶
WithHTTPClient sends through your own client — for a proxy, a corporate TLS bundle, a shared connection pool, or a RoundTripper that never leaves the test process.
func WithHost ¶
WithHost sets the Dify host, e.g. http://localhost. NewManagement talks to <host>/console/api; NewApp and NewKnowledge derive <host>/v1 from it unless WithBaseURL says otherwise. Left out, it is DIFY_HOST, then Dify Cloud.
func WithLogger ¶
WithLogger logs each request and response at debug level, and retries at warn. Headers are never logged, so the key does not end up in a log.
func WithMaxRetries ¶
WithMaxRetries changes DefaultMaxRetries. Zero disables retrying.
func WithRetryDelay ¶
WithRetryDelay changes DefaultRetryDelay.
func WithTimeout ¶
WithTimeout changes DefaultTimeout. Zero means no timeout beyond the context's. On a stream it bounds the silence between two events rather than the whole stream, since a run that keeps reporting progress is not hung.
Example ¶
package main
import (
"context"
"time"
"github.com/langgenius/dify-go-sdk"
)
func main() {
// A deadline on the context replaces the client's timeout for that call,
// so one long run gets twenty minutes without every call getting them.
app, _ := dify.NewApp(dify.WithUser("alice"), dify.WithTimeout(30*time.Second))
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Minute)
defer cancel()
_, _ = app.Workflows.Runs.Create(ctx, map[string]any{"batch": "…"}, nil)
}
Output:
type Page ¶
Page is one page of a listing, and how to get the rest.
Dify pages some listings by number and others by cursor (last_id or first_id), and answers a few with a bare array. The difference stays visible in each listing's parameters; what a caller does with the result does not depend on it.
page, err := app.Chat.Conversations.List(ctx, nil)
for _, c := range page.Items { ... } // this page
for c, err := range page.All(ctx) { ... } // every page, fetched as it goes
type PageLimitError ¶
type PageLimitError = codec.PageLimitError
PageLimitError is yielded by Page.All when a listing keeps going past its ceiling. Everything before it was yielded normally.
type PageParams ¶
type PageParams = usecase.PageParams
PageParams pages a numbered listing. Zero values take Dify's defaults.
type Pipeline ¶
Pipeline is a knowledge base's RAG pipeline: how documents get in and get indexed.
A pipeline is a workflow in its own right — datasource nodes that fetch, and processing that chunks and embeds. These methods run it, rather than letting Dify run it on upload.
Not every knowledge base has one. A base created with Datasets.Create indexes on upload and has no pipeline; Dify answers every call here on an ordinary knowledge base with "Pipeline not found", which reads like a bug rather than like an absence — this rewords it. A pipeline comes from creating the base from a pipeline template in the console; there is no route that deletes a pipeline on its own, either — Datasets.Delete removes both, and a pipeline has no listing of its own, only the dataset rows that carry one.
type PipelineDeployParams ¶
type PipelineDeployParams = usecase.PipelineDeployParams
PipelineDeployParams choose which of a pipeline deploy's steps happen.
type PipelineDeployment ¶
type PipelineDeployment = entity.PipelineDeployment
PipelineDeployment is what a knowledge pipeline deploy came to.
A pipeline is not an app, and it carries two ids: PipelineID addresses the graph and DatasetID the knowledge base it fills. Deleting the knowledge base is what deletes the pipeline, which is why cleanup needs the second.
type PipelineImportParams ¶
type PipelineImportParams = usecase.PipelineImportParams
PipelineImportParams are the optional parts of importing a pipeline.
type PipelineIngestion ¶
type PipelineIngestion = entity.PipelineIngestion
PipelineIngestion is what running a published pipeline queued.
A published run does not answer with the work: it enqueues one document per source and answers with the batch they share. The documents are not indexed yet — Documents.IndexingStatus(batch) is how far it has got, and Documents.WaitUntilIndexed waits for it.
type PipelineRunInput ¶
type PipelineRunInput = usecase.PipelineRunInput
PipelineRunInput is what a pipeline run needs, published or draft. Every field but Inputs is required, which is why this is a plain struct rather than a *Params one — there is no sane default for "which datasource, from where".
type PipelineSummary ¶
type PipelineSummary = entity.PipelineSummary
PipelineSummary is a knowledge pipeline as the workspace reports it: read off the knowledge base that owns it, since a pipeline has no listing of its own.
type Pipelines ¶
Pipelines are the workspace's knowledge pipelines.
A pipeline is not an app: Dify serves it from /rag/pipelines, its DSL is kind: rag_pipeline at version 0.1.0, and importing one creates the knowledge base it fills. So two ids come back — the pipeline's and the knowledge base's — and deleting the knowledge base is what deletes both.
type RenameParams ¶
type RenameParams = usecase.RenameParams
RenameParams choose how a thread is renamed.
type ReplySettings ¶
type ReplySettings = usecase.ReplySettings
ReplySettings configure annotation reply. Dify's payload model requires all three fields on enable and on disable alike, so a disable has to name them too; leaving them out answers 422.
type RetrievalHit ¶
type RetrievalHit = entity.RetrievalHit
RetrievalHit is one segment retrieval found, and how well it matched.
type RetrievalModelParams ¶
type RetrievalModelParams = usecase.RetrievalModelParams
RetrievalModelParams builds the retrieval_model block a knowledge base is searched by. How a knowledge base is searched is stored on the base, not passed per call — Datasets.Create's Retrieval field decides what every later retrieval does, a workflow's knowledge node included. Three things about that block are easy to get wrong, and all three are read out of Dify's retrieval code rather than its documentation:
- A score threshold is two fields. score_threshold is ignored unless score_threshold_enabled is true, so a threshold set alone reads as a filter that does nothing. Setting ScoreThreshold turns the flag on; leaving it nil turns it off — those are the two states.
- An "economy" knowledge base is always searched by keyword, whatever Search says: it has no embeddings to compare against. The setting is kept because the base can be switched to "high_quality" later.
- Reranking has two modes and only one calls a model. Dify reads reranking_model only when reranking_enable is true; Weights instead blends the vector and keyword scores arithmetically, with no model call. Setting both Rerank and Weights is not a stronger rerank, it is a contradiction, and is refused here. On a knowledge base's own settings (as opposed to a workflow's knowledge node over several bases), hybrid search reads the weights whatever reranking_enable says, so Weights leaves it off.
type RunDatasourceParams ¶
type RunDatasourceParams = usecase.RunDatasourceParams
RunDatasourceParams are the optional parts of running one datasource node.
type RunEvent ¶
RunEvent is one event from a stream, with the parts this SDK understands pulled out. Payload is always the whole thing Dify sent, so a field this SDK has never heard of still reaches the caller.
type SearchParams ¶
type SearchParams = usecase.SearchParams
SearchParams are the optional parts of a retrieval call.
type SegmentListParams ¶
type SegmentListParams = usecase.SegmentListParams
SegmentListParams narrow a document's segment listing.
type ServerInfo ¶
type ServerInfo = entity.ServerInfo
ServerInfo is what the Service API says about itself, before any credential.
func Probe ¶
func Probe(ctx context.Context, baseURL string) (*ServerInfo, error)
Probe asks a Dify what version it is, with no client and no credential — for finding out whether a host is a Dify at all, since an unreachable host and a wrong key look the same once authenticated calls start. baseURL is the Service API root; empty resolves it the way NewApp does.
type SiteSettings ¶
type SiteSettings = entity.SiteSettings
SiteSettings is the WebApp's own settings: what a visitor sees before typing anything.
type SkillImportParams ¶
type SkillImportParams = usecase.SkillImportParams
SkillImportParams are the optional parts of importing a skill.
type SpeakParams ¶
type SpeakParams = usecase.SpeakParams
SpeakParams choose what is spoken and how.
type Stage ¶
Stage is a one-word summary of how far a deploy got, for printing and for Deployment.Err. It is derived from the separate facts on a Deployment, never stored: an earlier design kept one stage and let a failed import followed by a successful publish read as runnable.
type StageError ¶
type StageError = entity.StageError
StageError is a deploy that stopped short of the stage it was asked for.
type Tags ¶
Tags are tags across the workspace's knowledge bases.
Workspace-level, not per-dataset: a tag exists once and is bound to as many knowledge bases as you like. Datasets.Tags reads the other direction — which tags one base carries.
type ToolParameter ¶
type ToolParameter = entity.ToolParameter
ToolParameter is one parameter a tool takes. Form is "llm" when the model fills it at run time, and "form" when the workflow sets it.
type ToolProvider ¶
type ToolProvider = entity.ToolProvider
ToolProvider is a tool provider installed in the workspace, with its tools.
type TransportError ¶
type TransportError = kernel.TransportError
TransportError is a request that never got an answer — the connection failed, or it ran past its deadline.
Sent reports whether the request had already gone out. A request that was sent and then timed out may have been acted on: a POST /workflows/run that timed out may still have billed a run, which is why it was not retried.
type Trigger ¶
Trigger is a way a published workflow starts by itself. A trigger node in a draft is only a drawing: Dify makes the trigger when the workflow publishes.
type Triggers ¶
Triggers are the ways a published workflow starts by itself: a schedule, a webhook, a plugin event. A trigger node in a draft is only a drawing; Dify makes the trigger, and a webhook's URL, when the workflow publishes.
type Upload ¶
Upload is something to upload: a name, its bytes, and its type.
func FileFromPath ¶
FileFromPath uploads the file at path, under its base name.
type UploadedFile ¶
type UploadedFile = entity.UploadedFile
UploadedFile is a file Dify has taken, and the reference that points at it.
type Usage ¶
Usage is what a run consumed, summed across every model call it made.
Costs are kept per currency rather than as one number, because a workflow may call providers that price in different ones and adding those together would produce a figure that means nothing.
type VariableParams ¶
type VariableParams = usecase.VariableParams
VariableParams narrow a thread's variables.
type WaitParams ¶
type WaitParams = usecase.WaitParams
WaitParams control how long WaitUntilSettled and WaitUntilIndexed poll.
type WebhookTrigger ¶
type WebhookTrigger = entity.WebhookTrigger
WebhookTrigger is the endpoint Dify minted for a webhook trigger node.
type WeightedScoreParams ¶
type WeightedScoreParams = usecase.WeightedScoreParams
WeightedScoreParams builds the weights block for hybrid search.
type WorkflowRun ¶
type WorkflowRun = entity.WorkflowRun
WorkflowRun is one run of a workflow, as Dify reported it.
Succeeded, Paused and Failed are three separate questions: a run waiting for a person has neither succeeded nor failed.
func CollectRun ¶
func CollectRun(r io.Reader) (*WorkflowRun, error)
CollectRun reads a whole Dify event stream into one WorkflowRun — the same accumulation the streams do, for a caller holding the raw SSE bytes.
type WorkflowRunStream ¶
type WorkflowRunStream = codec.WorkflowRunStream
WorkflowRunStream is a workflow run, watched as it happens.
stream, err := app.Workflows.Runs.Stream(ctx, inputs, nil)
if err != nil { ... }
defer stream.Close()
for event, err := range stream.Events() {
if err != nil { ... }
if event.Execution != nil { fmt.Println(event.Execution.NodeID) }
}
run := stream.FinalRun()
type WorkflowRuns ¶
type WorkflowRuns = usecase.WorkflowRuns
WorkflowRuns are runs of this app's workflow.
Create waits for the run and returns it. Stream hands it back as it happens. Retrieve reads one back afterwards, and Stop ends one still going.
type WorkspaceModels ¶
type WorkspaceModels = usecase.WorkspaceModels
WorkspaceModels are what the workspace can call, and whether the credentials for it are in place.
type WorkspaceSkill ¶
type WorkspaceSkill = entity.WorkspaceSkill
WorkspaceSkill is an agent skill installed in the workspace.
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
codec
Package codec turns what Dify sends into entities: JSON answers through the *From decoders, SSE through the event streams and the watcher that accumulates a run, listings through Page.
|
Package codec turns what Dify sends into entities: JSON answers through the *From decoders, SSE through the event streams and the watcher that accumulates a run, listings through Page. |
|
entity
Package entity is what calls return — runs, messages, datasets, usage — and the behaviour that belongs to them.
|
Package entity is what calls return — runs, messages, datasets, usage — and the behaviour that belongs to them. |
|
infra
Package infra implements port.Port over HTTP: options, credentials, retries, rate-limit waits, error mapping and the stream idle timeout.
|
Package infra implements port.Port over HTTP: options, credentials, retries, rate-limit waits, error mapping and the stream idle timeout. |
|
kernel
Package kernel is what every layer may use: lenient reads of Dify's JSON (Object), because its types drift between versions, and the errors a call can end in.
|
Package kernel is what every layer may use: lenient reads of Dify's JSON (Object), because its types drift between versions, and the errors a call can end in. |
|
port
Package port is all a resource may know of the wire: the Port interface it sends through, and the Request it describes a call with.
|
Package port is all a resource may know of the wire: the Port interface it sends through, and the Request it describes a call with. |
|
usecase
Package usecase is the resources and their verbs.
|
Package usecase is the resources and their verbs. |