dify

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 28, 2026 License: MIT Imports: 10 Imported by: 0

README

dify-go-sdk

Go Reference CI

A Go client for Dify — running apps and managing knowledge bases through the Service API, and deploying apps through the console API. A port of the "using Dify" half of dify-python-sdk, verified against Dify 1.17.1. Go 1.24+, no dependencies beyond the standard library.

The API may still change between 0.x releases; CHANGELOG.md says what did.

go get github.com/langgenius/dify-go-sdk

Start here

app, err := dify.NewApp(dify.WithAPIKey("app-…"), dify.WithUser("alice"))

msg, err := app.Chat.Messages.Create(ctx, "Hello", nil)
fmt.Println(msg.Answer, msg.ConversationID)

run, err := app.Workflows.Runs.Create(ctx, map[string]any{"text": "…"}, nil)
fmt.Println(run.Status, run.Outputs, run.Usage())

A client holds the connection and the credential. What you can do hangs off what it acts on:

app.Chat.Messages Create, Stream, List, Stop, Feedback, Suggested
app.Chat.Conversations List, Rename, Delete, Variables, SetVariable
app.Workflows.Runs Create, Stream, Retrieve, Events, Stop, Logs
app.Completions Create, Stream, Stop
app.Files Upload, Download, PreviewURL
app.Annotations List, Create, Update, Delete, SetReply, ReplyStatus
app.Audio Speak, Transcribe
app.Forms Retrieve, Submit
app Info, Parameters, Site, Meta, Feedbacks, EndUser, ServerInfo

Calls return the thing, carrying the ids the next call needs — run.RunID reads a run back, run.TaskID is what a stop names, and they are not the same id. Required arguments are positional; optional ones go in a *…Params struct, where nil is fine. Every typed result keeps Dify's whole answer on Raw, so a field a newer Dify adds is never lost.

Is this host a Dify?
info, err := dify.Probe(ctx, "http://localhost/v1")  // no credential
// Dify 1.17.1 (v1)

Streams

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, event.Execution.Usage)
	}
}
run := stream.FinalRun()

For a chat, stream.Text() yields just the answer, and FinalMessage() is the message. Things Dify keeps apart, and so does this:

  • Closing the stream stops watching. The run keeps going — stop it with Runs.Stop(ctx, run.TaskID, "").
  • A pause is the run waiting for a person. run.Paused() is true while Succeeded() and Failed() are both false.
  • A dropped connection says nothing about the run. Reopen it with Runs.Events(ctx, run.RunID, nil).
  • An HTTP 200 is not a successful run. Dify reports a mid-stream failure as an error event after the status line; the stream yields it as an *APIError with InStream set.
  • A stream that stopped is not a finished message. msg.Finished is set only when Dify says so.
Waiting for a person
if run.Paused() {
	token, err := dify.FormToken(run)   // explains a pause with no token
	form, _ := app.Forms.Retrieve(ctx, token)
	_ = app.Forms.Submit(ctx, token, map[string]any{"decision": "approve"}, "approve", "")
	resumed, _ := app.Workflows.Runs.Events(ctx, run.RunID, nil)
	for range resumed.Events() {}
	run = resumed.FinalRun()
}

Knowledge

k, err := dify.NewKnowledge(dify.WithAPIKey("dataset-…"))

retrieval, err := dify.RetrievalModel(&dify.RetrievalModelParams{Search: dify.SearchHybrid, TopK: 5})
base, err := k.Datasets.Create(ctx, "handbook", &dify.DatasetCreateParams{
	IndexingTechnique: "high_quality",
	Retrieval:         retrieval,
})

docs := k.Documents(base.ID)
doc, err := docs.CreateFromText(ctx, "policy", "Refunds take five days.", nil)
_, err = docs.WaitUntilIndexed(ctx, doc.Batch, nil)   // not searchable before this

hits, err := k.Datasets.Search(ctx, base.ID, "what is the refund window?", nil)

k.Tags, k.Pipeline(datasetID), k.Models(ctx, "text-embedding") and docs.Segments(documentID) cover the rest. How a base is searched is stored on the base, so RetrievalModel decides every later retrieval; it refuses a reranking model and weights together, and a score threshold sets both of the fields Dify needs. A published pipeline run (Pipeline.Run) is queued and answers with a batch of documents; a draft run (RunDraft) executes the graph and answers with a WorkflowRun.

Management

Creating, publishing and deleting apps is the console API's, and it authenticates as an account rather than as an app:

m, err := dify.LoginManagement(ctx, email, password, dify.WithHost("http://localhost"))

d, err := m.Apps.Deploy(ctx, dsl, nil)            // import, publish, mint a key
if err := d.Err(dify.StageRunnable); err != nil {  // where it stopped, and what is left
	return err
}
app, err := m.AppClient(d.APIKey, "alice")        // an App on the same Dify

A deploy reports each step as its own fact — Imported, Published, APIKey — plus NeedsConfirmation for an import Dify holds over a DSL version difference, and Indeterminate for one whose answer never arrived, since that app may exist. Apps.Import, Publish, Confirm and RunDraft (run the draft without publishing it) are the steps on their own; Apps.Temporary deploys an app for a test and cleans up if it stops short.

m.Apps.Keys, m.Apps.Triggers, m.Agents, m.Pipelines, m.Models, m.Tools, m.Skills and m.DatasetKeys cover the rest.

A session from LoginManagement is renewed when it expires, and is the credential to the whole account for as long as its refresh token lasts — 30 days by default — so end it with m.Logout(ctx) when done. m.SessionTokens() hands the current tokens to another process; NewManagement takes them back as DIFY_CONSOLE_TOKEN and, since Dify 1.17, DIFY_CONSOLE_CSRF_TOKEN, which every console request needs, reads included.

Listings

Every listing returns a *Page[T], whether Dify pages it by number, by cursor, or not at all:

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
all, err := page.Collect(ctx)                 // or all of them at once

All walks a loop the server controls, so it stops at dify.MaxWalk (10,000) items with a *PageLimitError rather than fetching forever; pass a ceiling to raise it. A cursor that comes back unchanged ends the walk too.

Errors

var apiErr *dify.APIError
switch {
case errors.Is(err, dify.ErrAuthentication):   // 401
case errors.Is(err, dify.ErrRateLimited):      // 429 — apiErr.RetryAfter
case errors.Is(err, dify.ErrValidation):       // 422, or refused before sending
case errors.Is(err, dify.ErrNotFound):         // 404
case errors.Is(err, dify.ErrTimeout), errors.Is(err, dify.ErrNetwork):
case errors.As(err, &apiErr):
	fmt.Println(apiErr.Message, apiErr.Code, apiErr.ServerVersion)
}

An error Dify answered carries the server it came from: dify: Access token is invalid (unauthorized) [Dify 1.17.1].

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 same run again. A 429 was refused, so it is waited out for any method, honouring Retry-After, unless the server asks for more than a minute.

Each request is bounded by WithTimeout (default 60s) unless its context carries a deadline, which replaces it:

ctx, cancel := context.WithTimeout(ctx, 20*time.Minute)   // one long run
defer cancel()
run, err := app.Workflows.Runs.Create(ctx, inputs, nil)

On a stream the timeout bounds the silence between events, not the length of the stream.

Configuration

Variable What it is
DIFY_HOST the Dify host, e.g. http://localhost; the Service API is <host>/v1
DIFY_API_BASE_URL overrides that derivation
DIFY_API_KEY an app's key, read by NewApp
DIFY_DATASET_API_KEY a knowledge key, read by NewKnowledge (falls back to DIFY_API_KEY)
DIFY_CONSOLE_TOKEN a console access token, read by NewManagement
DIFY_CONSOLE_CSRF_TOKEN the CSRF token that goes with it

Options win over the environment. An explicitly empty WithAPIKey("") is an error, not a fallback. WithAPIKeyFunc fetches the key per request, for a vault or a rotating key. The key is masked wherever the client is printed. WithHTTPClient sends through your own *http.Client; WithLogger logs at debug level and never logs headers.

Where this differs from the Python SDK

Each checked against Dify's controllers:

  • Annotations.SetReply requires the embedding provider, model and threshold on disable too; Dify rejects an empty disable.
  • MessageParams exposes WorkflowID (pin a chatflow version) and NoAutoName.
  • Documents.DownloadURL returns the signed URL Dify answers with; the Python download() treats that JSON as the file's bytes.
  • Updating a document by text takes no embedding fields; only the file update does, as in Dify's payload models.
  • The console session sends its CSRF token on reads too, finds its cookies under the __Host- names Dify uses behind https, and renews itself with the refresh token a login hands out.
  • A skill is deleted with its display name as confirmation, the field Dify checks, and only when something references it.

Not ported: workflow and agent definitions (built on the Python-only graphon engine) — Management deploys DSL text — and OpenApiClient.

Development

go test -race ./...                         # offline
export DIFY_HOST=… DIFY_CONSOLE_EMAIL=… DIFY_CONSOLE_PASSWORD=…
go test -run Live -v ./tests                # against a running Dify

The live harness creates its apps and a dataset key through the console, runs template-only workflows (no model cost), and deletes everything afterwards. See CONTRIBUTING.md and AGENTS.md.

Security

Report vulnerabilities privately, as SECURITY.md describes — not in a public issue.

License

MIT

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)
}

Index

Examples

Constants

View Source
const (
	DocumentEnable    = usecase.DocumentEnable
	DocumentDisable   = usecase.DocumentDisable
	DocumentArchive   = usecase.DocumentArchive
	DocumentUnarchive = usecase.DocumentUnarchive
)
View Source
const (
	SearchSemantic = usecase.SearchSemantic
	SearchFullText = usecase.SearchFullText
	SearchHybrid   = usecase.SearchHybrid
	SearchKeyword  = usecase.SearchKeyword
)

How Dify may search a knowledge base.

View Source
const (
	Like    = usecase.Like
	Dislike = usecase.Dislike
	// NoRating takes a rating back.
	NoRating = usecase.NoRating
)
View Source
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.

View Source
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
)
View Source
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
)
View Source
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
)
View Source
const DefaultBaseURL = infra.DefaultBaseURL

DefaultBaseURL is Dify Cloud's Service API.

View Source
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

View Source
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.

View Source
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

func MaskSecret(value string) string

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

func OpenApp(ctx context.Context, opts ...Option) (*App, *AppInfo, error)

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

type APIError = kernel.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)
	}
}

type APIKey

type APIKey = entity.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

type Agents = usecase.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

type Amount = entity.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

func ParseAmount(s string) (Amount, error)

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

type App = usecase.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.

func NewApp

func NewApp(opts ...Option) (*App, error)

NewApp builds a client for one app. The key comes from WithAPIKey, or DIFY_API_KEY; the base URL from WithBaseURL, DIFY_API_BASE_URL, or <DIFY_HOST>/v1. It sends nothing.

type AppInfo

type AppInfo = entity.AppInfo

AppInfo is what Dify says an app is.

type AppKeys

type AppKeys = usecase.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

type Apps = usecase.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 Audio

type Audio = usecase.Audio

Audio is text to speech, and speech to text, for this app.

type Chat

type Chat = usecase.Chat

Chat is the conversational half of an app: messages and the threads they form.

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 Dataset

type Dataset = entity.Dataset

Dataset is a knowledge base.

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 Datasets

type Datasets = usecase.Datasets

Datasets are the workspace's knowledge bases.

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 Document

type Document = entity.Document

Document is one document inside a dataset.

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

type Documents = usecase.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 Files

type Files = usecase.Files

Files are the files this app's runs and messages can reference.

type Form

type Form = entity.Form

Form is a paused run's human-input form, as it should be shown to whoever fills it in.

type Forms

type Forms = usecase.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

type KeyFunc = infra.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

type Knowledge = usecase.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

func NewKnowledge(opts ...Option) (*Knowledge, error)

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 LogParams

type LogParams = usecase.LogParams

LogParams narrow the run history.

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

type Message = entity.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

type Messages = usecase.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 Model

type Model = entity.Model

Model is one model this workspace can call.

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

type Option = infra.Option

Option configures a client. The same options serve App and Knowledge.

func WithAPIKey

func WithAPIKey(key string) Option

WithAPIKey sets the key. Left out, it is read from the environment.

func WithAPIKeyFunc

func WithAPIKeyFunc(f KeyFunc) Option

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

func WithBaseURL(u string) Option

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

func WithCSRFToken(token string) Option

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

func WithConsoleToken(token string) Option

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

func WithHTTPClient(h *http.Client) Option

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

func WithHost(host string) Option

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

func WithLogger(l *slog.Logger) Option

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

func WithMaxRetries(n int) Option

WithMaxRetries changes DefaultMaxRetries. Zero disables retrying.

func WithRetryDelay

func WithRetryDelay(d time.Duration) Option

WithRetryDelay changes DefaultRetryDelay.

func WithTimeout

func WithTimeout(d time.Duration) Option

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)
}

func WithUser

func WithUser(user string) Option

WithUser sets the end-user identifier sent when a call does not name one. Dify wants one on nearly every app request; setting it here is the usual case, passing it per call is for a server acting for many users.

type Page

type Page[T any] = codec.Page[T]

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

type Pipeline = usecase.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

type Pipelines = usecase.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 Plugin

type Plugin = entity.Plugin

Plugin is a plugin installed in the workspace.

type Rating

type Rating = usecase.Rating

Rating is feedback on a message.

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

type RunEvent = codec.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 RunParams

type RunParams = usecase.RunParams

RunParams are the optional parts of starting a workflow run.

type SearchParams

type SearchParams = usecase.SearchParams

SearchParams are the optional parts of a retrieval call.

type Segment

type Segment = entity.Segment

Segment is a chunk of a document, as retrieval sees it.

type SegmentListParams

type SegmentListParams = usecase.SegmentListParams

SegmentListParams narrow a document's segment listing.

type Segments

type Segments = usecase.Segments

Segments are the chunks of one document, and the child chunks beneath them.

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 Skills

type Skills = usecase.Skills

Skills are the workspace's agent skills.

type SpeakParams

type SpeakParams = usecase.SpeakParams

SpeakParams choose what is spoken and how.

type Stage

type Stage = entity.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 Tag

type Tag = entity.Tag

Tag is a label across the workspace's knowledge bases.

type Tags

type Tags = usecase.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 Tool

type Tool = entity.Tool

Tool is one tool a provider offers.

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 Tools

type Tools = usecase.Tools

Tools are the tool providers and plugins installed in the workspace.

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

type Trigger = entity.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

type Triggers = usecase.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

type Upload = usecase.Upload

Upload is something to upload: a name, its bytes, and its type.

func FileFromPath

func FileFromPath(path string) Upload

FileFromPath uploads the file at path, under its base name.

func FileFromReader

func FileFromReader(name string, r io.Reader) Upload

FileFromReader uploads what r yields, recorded as name.

type UploadedFile

type UploadedFile = entity.UploadedFile

UploadedFile is a file Dify has taken, and the reference that points at it.

type Usage

type Usage = entity.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 Workflows

type Workflows = usecase.Workflows

Workflows is the workflow half of an app: runs, and what they did.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL