API reference @cogover/sdk: Custom Module Action
Trang này thuộc API reference của @cogover/sdk.
Custom Module Action
Custom Module Action là một thao tác ngắn, chạy đồng bộ của project mà Process hoặc
AI Agent có thể gọi. Process Builder đưa mỗi action mở cho "process" thành một node
Custom Module Action, và AI Agent Builder đưa mỗi action mở cho "agent" thành
một tool. Khai báo từng action bằng defineAction và liệt kê kết quả trong named
export actions của project. Default export vẫn là tuỳ chọn với project chỉ khai báo
action, trigger và job.
Ví dụ này giả định workspace.d.ts đã khai báo Object lead và các field dùng bên
dưới.
import { defineAction, s } from "@cogover/sdk";
export const actions = [
defineAction({
key: "score_lead",
label: "Score lead",
description: "Scores a lead from its recent activities and returns a tier.",
exposeTo: ["process", "agent"],
effect: "read",
input: s.object({
leadId: s.recordId("lead").describe("ID of the lead to score"),
strict: s.boolean().optional(),
}),
output: s.object({
found: s.boolean(),
score: s.number(),
tier: s.enum(["A", "B", "C"]),
}),
timeoutMs: 5000,
async handler({ data, invocation, log }, input) {
const lead = await data.object("lead").records.get(input.leadId, { fields: ["rating"] });
if (!lead) return { found: false, score: 0, tier: "C" };
const score = Number(lead.fields.rating ?? 0) * (input.strict ? 8 : 10);
log.info("Lead scored", { leadId: lead.id, source: invocation.source.type });
return { found: true, score, tier: score >= 80 ? "A" : score >= 50 ? "B" : "C" };
},
}),
];
Cogover đọc khai báo action khi một version của project được publish và cung cấp
các action của version đang active: node Process và tool của AI Agent tham chiếu
action bằng slug của project và key của action, và luôn chạy version đang active
tại thời điểm gọi. Version có khai báo không hợp lệ sẽ publish thất bại với
ACTION_MANIFEST_INVALID. Deactivate project sẽ gỡ các action của nó khỏi cả hai
builder. Một project khai báo tối đa 50 action.
Label, mô tả và schema của action hiển thị với mọi thành viên đang hoạt động của Workspace: không đặt secret trong đó.
defineAction(config): ActionDefinition
function defineAction<
TInput extends ObjectSchema<ObjectShape, false>,
TOutput extends ObjectSchema<ObjectShape, false>,
TSchema extends object = EffectiveWorkspaceObjects,
>(config: ActionConfig<TInput, TOutput, TSchema>): ActionDefinition;
type ActionExposure = "process" | "agent";
type ActionEffect = "read" | "write";
interface ActionConfig<
TInput extends ObjectSchema<ObjectShape, false> = ObjectSchema<ObjectShape, false>,
TOutput extends ObjectSchema<ObjectShape, false> = ObjectSchema<ObjectShape, false>,
TSchema extends object = EffectiveWorkspaceObjects,
> {
readonly key: string;
readonly label: string;
readonly description?: string;
readonly exposeTo: readonly ActionExposure[];
readonly effect: ActionEffect;
readonly input: TInput;
readonly output: TOutput;
readonly timeoutMs?: number;
readonly handler: ActionHandler<TInput, TOutput, TSchema>;
}
defineAction kiểm tra cấu hình ngay và ném ValidationError khi có vi phạm, khi
có key cấu hình lạ hoặc khi handler không phải function; khi key đã hợp lệ,
details.actionKey và details.option cho biết action và tuỳ chọn bị sai. Hàm trả về một ActionDefinition
đã freeze. Kiểu của tham số input và kiểu trả về của handler được suy ra từ schema
input và output.
| Tuỳ chọn | Bắt buộc | Quy tắc và ý nghĩa |
|---|---|---|
key |
Có | Định danh action trong project: một chữ thường, theo sau tối đa 63 chữ thường, chữ số hoặc _. Duy nhất trong project. Giữ ổn định giữa các version: node Process và tool của agent dùng key cũ sẽ không tìm thấy action nữa. |
label |
Có | Tên hiển thị trong Process Builder và AI Agent Builder, từ 1 đến 100 ký tự sau khi trim. |
description |
Với agent | Tối đa 1000 ký tự sau khi trim. Bắt buộc khi exposeTo có "agent": AI Agent đọc mô tả này để quyết định khi nào gọi tool. |
exposeTo |
Có | Danh sách khác rỗng gồm "process" và "agent", không trùng: nơi action được dùng. |
effect |
Có | "read": action chạy chỉ đọc, mọi thao tác ghi đều bị từ chối bằng PermissionDeniedError. "write": action được ghi; tool của AI Agent cho action này mặc định cần người phê duyệt. |
input |
Có | Schema của input, tạo bằng s.object. |
output |
Có | Schema của output, tạo bằng s.object. |
timeoutMs |
Không | Số nguyên từ 1000 đến 8000; mặc định 8000. Giới hạn thời gian của một lần gọi. |
handler |
Có | (context, input) => output, đồng bộ hoặc bất đồng bộ. |
Schema builder s
s tạo schema vừa là kiểu TypeScript vừa là JSON Schema. Action dùng nó để khai báo
input và output, và agents.start dùng nó cho resultSchema (xem
Process và AI Agent).
const s: {
string(options?: { minLength?: number; maxLength?: number }): Schema<string>;
enum<const Values extends readonly string[]>(values: Values): Schema<Values[number]>;
number(options?: { minimum?: number; maximum?: number }): Schema<number>;
integer(options?: { minimum?: number; maximum?: number }): Schema<number>;
boolean(): Schema<boolean>;
date(): Schema<string>;
dateTime(): Schema<number>;
recordId(objectSlug: string): Schema<CogoverRecordId>;
array<Item extends Schema<unknown, false>>(item: Item, options?: { maxItems?: number }): Schema<InferSchema<Item>[]>;
object<Shape extends ObjectShape>(shape: Shape): ObjectSchema<Shape>;
};
interface Schema<T = unknown, Optional extends boolean = false> {
optional(): Schema<T, true>;
describe(text: string): Schema<T, Optional>;
toJSON(): JsonSchema;
}
interface ObjectSchema<Shape extends ObjectShape = ObjectShape, Optional extends boolean = false>
extends Schema</* kiểu object của Shape */, Optional> {
optional(): ObjectSchema<Shape, true>;
describe(text: string): ObjectSchema<Shape, Optional>;
}
type ObjectShape = { readonly [property: string]: Schema<unknown, boolean> };
type InferSchema<T> = T extends Schema<infer Value, boolean> ? Value : never;
interface JsonSchema {
readonly [keyword: string]: null | boolean | number | string | readonly unknown[] | JsonSchema;
}| Builder | Giá trị | JSON Schema | Kiểu dữ liệu Process |
|---|---|---|---|
s.string({ minLength?, maxLength? }) |
string |
{"type": "string"} |
Text |
s.enum(["A", "B"]) |
một trong các chuỗi đã liệt kê | {"type": "string", "enum": [...]} |
Text |
s.number({ minimum?, maximum? }) |
number hữu hạn |
{"type": "number"} |
Number |
s.integer({ minimum?, maximum? }) |
số nguyên an toàn | {"type": "integer"} |
Number |
s.boolean() |
boolean |
{"type": "boolean"} |
Boolean |
s.date() |
chuỗi YYYY-MM-DD |
{"type": "string", "format": "date"} |
Date |
s.dateTime() |
Unix millisecond, như field date_time |
{"type": "integer", "format": "x-epoch-ms"} |
Date time |
s.recordId("lead") |
ID của một record thuộc Object, kiểu CogoverRecordId |
{"type": "string", "x-cogover-object": "lead"} |
Text |
s.array(item, { maxItems? }) |
danh sách giá trị item |
{"type": "array", "items": {...}} |
danh sách theo kiểu của item |
s.object({ ... }) |
object có đúng các property này | {"type": "object", "properties": {...}, "required": [...], "additionalProperties": false} |
Record, mỗi property là một field con |
-
Mọi node đều bất biến:
.optional()và.describe(text)trả về node mới..optional()cho phép bỏ property khỏi object chứa nó (không có trongrequired);.describe(text)thêmdescriptiontừ 1 đến 500 ký tự, lưu sau khi trim, được Process Builder hiển thị và AI Agent đọc. -
s.string:maxLengthtừ 1 đến 100000, mặc định 10000;minLengthtừ 0 đếnmaxLength. Không có optionpattern: kiểm tra định dạng, ví dụ mã hay địa chỉ email, trong handler và némValidationErrorkhi không khớp. s.enum: từ 1 đến 100 chuỗi khác nhau, mỗi chuỗi từ 1 đến 200 ký tự.-
s.numbervàs.integer:minimumvàmaximumlà số hữu hạn (số nguyên an toàn vớis.integer), vàminimumkhông lớn hơnmaximum. -
s.recordId: slug của Object bắt đầu bằng chữ cái hoặc_và có tối đa 128 chữ cái, chữ số hoặc_. Giá trị có kiểuCogoverRecordId, nên handler truyền thẳng vàorecords.gethoặcrecords.updatemà không cần ép kiểu, và property output tạo bằng nó nhậnidcủa record mà records API trả về. Lúc chạy nó chỉ là chuỗi: Cogover không kiểm tra record có tồn tại. s.array: item không được optional;maxItemstừ 1 đến 10000, mặc định 1000.-
s.object: tối đa 50 property, mỗi tên có dạng nhưleadId: một chữ cái, theo sau tối đa 63 chữ cái, chữ số hoặc_. Property giữ thứ tự khai báo. -
inputvàoutputcủa action, vàresultSchemacủa agent, là mộts.objectkhông optional, lồng object và array tối đa 3 cấp (object gốc là cấp thứ nhất). JSON Schema của input và output của một action cộng lại, và schema kết quả của agent, tối đa 16384 byte UTF-8 khi mã hoá JSON. -
Chỉ node do
stạo mới là schema: object JSON Schema viết tay bị từ chối bằngValidationError.toJSON(), và do đóJSON.stringify(node), trả về JSON Schema của node.
Schema là node schema mô tả giá trị của một kiểu TypeScript, ObjectSchema là node
tạo bằng s.object, và ObjectShape là bảng ánh xạ tên property sang node mà
s.object nhận. InferSchema cho kiểu TypeScript của một node, và JsonSchema là
JSON Schema dưới dạng dữ liệu JSON thuần:
const leadInput = s.object({ leadId: s.recordId("lead"), note: s.string().optional() });
type LeadInput = InferSchema<typeof leadInput>; // { leadId: string; note?: string }ActionDefinition và ActionManifest
interface ActionManifest {
readonly key: string;
readonly label: string;
readonly description: string;
readonly exposeTo: readonly ActionExposure[];
readonly effect: ActionEffect;
readonly timeoutMs: number;
readonly inputSchema: JsonSchema;
readonly outputSchema: JsonSchema;
}
interface ActionDefinition {
readonly key: string;
readonly config: ActionManifest;
readonly __cogoverActionHandler: (inputJson: string) => Promise<string>;
}
config là cấu hình đã chuẩn hoá dưới dạng JSON thuần đã deep-freeze, đã áp mọi giá
trị mặc định: description là "" khi không khai báo, timeoutMs là 8000 nếu
không đặt, label và description đã trim. Đây là nội dung Process Builder và AI
Agent Builder hiển thị. Nó tách khỏi object đã truyền cho defineAction.
__cogoverActionHandler dành riêng cho Cogover; code của project không gọi nó.
Context của action handler
type ActionHandler<TInput, TOutput, TSchema extends object = EffectiveWorkspaceObjects> = (
context: ActionContext<TSchema>,
input: InferSchema<TInput>,
) => InferSchema<TOutput> | Promise<InferSchema<TOutput>>;
interface ActionContext<TSchema extends object = EffectiveWorkspaceObjects> {
readonly action: ActionInfo;
readonly invocation: ActionInvocationContext;
readonly data: DataApi<TSchema>;
readonly schema: SchemaApi<TSchema>;
readonly log: ScriptLogger;
readonly state: ProjectState;
readonly locks: DistributedLocks;
readonly push: PushApi<TSchema>;
readonly notifications: NotificationsApi;
readonly email: EmailApi<TSchema>;
readonly jobs: JobsApi;
readonly secrets: SecretsApi;
readonly crypto: CryptoApi;
readonly org: OrgApi;
readonly limits: LimitsApi;
readonly processes: ProcessesApi;
readonly agents: AgentsApi;
}
interface ActionInfo {
readonly key: string;
readonly runId: string;
readonly effect: ActionEffect;
}
type ActionInvocationContext = (UserInvocationContext | SystemInvocationContext) & {
readonly executionIdentity: "user" | "system";
readonly source: ActionSource;
};
type ActionSource = ProcessActionSource | AgentActionSource;
interface ProcessActionSource {
readonly type: "process";
readonly processId: string;
readonly processInfoId: string;
readonly instanceId: string;
readonly nodeId: string;
readonly runAs: ProcessActionRunAs | null;
}
type ProcessActionRunAs = "PROCESS_STARTER" | "PERSONNEL" | "SYSTEM";
interface AgentActionSource {
readonly type: "agent";
readonly agentId: string;
readonly sessionId: string | null;
readonly runId: string | null;
readonly interactive: boolean;
readonly initiatorPersonnelId: string | null;
}
data, schema, log, state, locks, push, notifications, email, jobs,
secrets, crypto, org và limits là chính các API mà script nhận được, còn
processes và agents được mô tả ở Process và AI Agent.
Action context không có input, request hay response: input là tham số thứ hai
của handler.
-
action.keyvàaction.effectlặp lại cấu hình.action.runIdđịnh danh lần gọi và giữ nguyên khi bên gọi gửi lại chính lần gọi đó (ví dụ node Process thử lại sau lỗi mạng); lần chạy mới của node hoặc lần gọi tool mới của agent córunIdmới. Dùng nó làm idempotency key cho lời gọi ra ngoài và chojobs.enqueuehoặcprocesses.start. -
invocationlà context invocation của người dùng hoặc system (xem Danh tính invocation và workspace hiện tại) cộng thêmexecutionIdentity, lặp lạiinvocation.identity, vàsource. -
invocation.sourcecho biết bên gọi.ProcessActionSourcecho biết Process (processId), định nghĩa Process (processInfoId), lượt chạy (instanceId), node BPMN (nodeId) vàrunAs, giá trịProcessActionRunAsmà node dùng để chọn danh tính chạy action:"PROCESS_STARTER"(người khởi tạo Process),"PERSONNEL"(nhân sự do node chỉ định, có thể lấy từ dữ liệu của Process) hoặc"SYSTEM"; lànullkhi bên gọi không cho biết.AgentActionSourcecho biết agent, phiên chat và lượt chạy của nó (mỗi giá trị lànullkhi agent không được khởi chạy theo cách đó),interactive, bằngtruekhi có người đang chat với agent, vàinitiatorPersonnelId, ID nhân sự của người đang chat với agent hoặc người khởi chạy lượt chạy agent (nullkhi không có). -
Action do AI Agent gọi chạy bằng danh tính của agent, có thể khác người đang chat: mọi
người dùng agent đều có quyền truy cập của danh tính đó. Khi action chỉ được làm những
gì người đó được phép, hãy kiểm tra
initiatorPersonnelIdtrong handler (ví dụ bằngdata.asUser, identity policy phải cho phép) và từ chối nếu không. VớirunAs: "PERSONNEL", Process có thể đã lấy nhân sự từ dữ liệu do người dùng hoặc hệ thống bên ngoài cung cấp: đừng coi đó là bằng chứng ai đã yêu cầu.
Input và output
-
Cogover kiểm tra input theo schema
inputtrước khi handler chạy. Input không hợp lệ thì handler không chạy: bên gọi nhậnINPUT_INVALIDkèm đường dẫn JSON Pointer và thông báo cho từng lỗi (tối đa 20). Vì vậy handler luôn nhận đúng các property đã khai báo, với giá trị đúng kiểu. -
Handler trả về output. Cogover kiểm tra output theo schema
outputsau khi handler trả về: giá trị không phải dữ liệu JSON, hoặc không khớp schema, được báo cho bên gọi làOUTPUT_INVALID, và các thao tác ghi handler đã làm không được hoàn tác. Hãy trả về một object;undefinedkhông phải output hợp lệ. -
Node Process hoặc AI Agent chỉ nhận mã lỗi và một thông báo an toàn, cố định của lỗi
mà handler ném (xem bên dưới), không bao giờ nhận thông báo riêng của handler. Khi bên
gọi cần biết vì sao một trường hợp dự kiến thất bại, hãy mô tả nó trong output, như
foundtrong ví dụ trên, thay vì ném lỗi.
Quy tắc thực thi action
-
Danh tính. Node Process chạy action dưới danh tính người đã khởi chạy Process,
một nhân sự được chọn, hoặc không có người dùng, theo lựa chọn trên node. AI Agent
chạy action dưới danh tính người mà agent đang thay mặt. Khi có người dùng,
invocation.usermô tả người đó,data.object()dùng quyền của họ, và Cogover kiểm tra trước rằng người đó vẫn là thành viên đang hoạt động của Workspace. Khi không có người dùng,invocation.identitylà"system", và lời gọi bị từ chối trước khi chạy trừ khi identity policy đã duyệt của version đang active đặtallowInternalSystem: true.data.asUser()vàdata.asSystem()tuân theo identity policy như thông thường. Khi version đang active chưa có identity policy được duyệt, action chạy giống route HTTP: lời gọi có người dùng chạy với quyền riêng của người đó và không có quyền nào của policy (data.asSystem(),data.asUser(),email.send(),fetch()tới port khác,processes.start()vàagents.start()bị từ chối), còn lời gọi không có người dùng bị từ chối trước khi chạy. -
Effect. Action
"read"được đọc record, schema vàstate, dùngorg,email.sendersvàcryptotrừ khi dùng key{ secret }, gửifetchvới methodGEThoặcHEADkhông kèm credential, và gọiprocesses.getvàagents.get. Mọi lời gọi khác, như ghi record,locks,push,notifications.send,email.send,jobs.enqueue,secrets.get,processes.starthoặcagents.start, némPermissionDeniedErrorvới thông báoThis action is declared read-only. -
Giới hạn. Action có ngân sách của một HTTP route (xem
Giới hạn của một lần thực thi) và giới
hạn thời gian riêng là
timeoutMs, tính từ lúc handler bắt đầu. Vượt thời gian sẽ kết thúc lần gọi vớiTIMEOUT; handler không bắt được lỗi này. -
Lời gọi lặp lại. Node Process và AI Agent gửi lại lời gọi với cùng
runIdkhi không nhận được câu trả lời. Khi đó, trong 7 ngày, Cogover trả kết quả đã lưu của lần gọi đã xong mà không chạy lại handler, và từ chối cùngrunIdvới input khác. Nếu Cogover bị gián đoạn trong lúc handler chạy, lần thử lại sau có thể chạy lại handler, nên hãy viết action có ghi dữ liệu theo kiểu idempotent, ví dụ dùngaction.runId. -
Vòng lặp luôn kết thúc. Mỗi lời gọi mang ngân sách tự động hoá của lượt chạy
Process hoặc agent đã gọi nó, và thao tác ghi record của action dùng ngân sách này
giống thao tác ghi của trigger. Lời gọi đã hết ngân sách bị từ chối với
MAX_HOP_EXCEEDEDtrước khi chạy.
Cách Process và AI Agent dùng action
-
Process. Node Custom Module Action liệt kê các action mở cho
"process". Node điền từng property cấp một của input từ dữ liệu của Process; property mà node để trống sẽ không được gửi, nên hãy khai báo nó bằng.optional()trừ khi luôn cần. Các node phía sau đọc output của node:status(COMPLETEDhoặcFAILED),result(output của action, mỗi property của output là một field con),errorCode,errorMessage,runIdvàdurationMs. Lời gọi thất bại sẽ dừng lượt chạy Process trừ khi node được đặt tiếp tục khi lỗi. -
AI Agent. Tool thuộc nhóm Custom Module gọi một action mở cho
"agent". Agent thấy mô tả và schema input của action, kể cả các đoạndescribe, và tự sinh input; Cogover kiểm tra input đó như mọi input khác. Agent nhận output dưới dạng JSON, hoặc mã lỗi và thông báo. Tool cho action"write"mặc định cần người phê duyệt; cấu hình của agent có thể đổi điều này.
Lỗi bên gọi nhận được
Lời gọi đã chạy báo COMPLETED kèm output, hoặc FAILED với một trong các mã sau:
| Mã | Ý nghĩa |
|---|---|
INPUT_INVALID |
Input không khớp schema input; handler không chạy. details.errors liệt kê path và message của từng lỗi. |
OUTPUT_INVALID |
Handler trả về giá trị không phải dữ liệu JSON hoặc không khớp schema output. |
SCRIPT_ERROR |
Handler ném lỗi SDK. details.scriptErrorCode là mã của lỗi đó, như VALIDATION_ERROR hoặc NOT_FOUND, kèm cùng thông báo an toàn mà HTTP route trả cho mã đó. Mọi lỗi khác được báo với thông báo The action handler failed. |
TIMEOUT |
Lời gọi vượt timeoutMs; details.timeoutMs là giới hạn đã áp dụng. |
RATE_LIMITED |
Lời gọi vượt một ngân sách của lần thực thi; details.budget mô tả ngân sách đó. |
SCRIPT_ERROR với details.reason là "RESOURCE_LIMIT_EXCEEDED" |
Handler dùng hết một giới hạn tài nguyên của sandbox: số câu lệnh, bộ nhớ hoặc stack. |
PERMISSION_DENIED |
Handler để lọt PermissionDeniedError, ví dụ khi ghi trong action "read". Trong lúc activate version mới, lời gọi có thể thất bại trong chốc lát với details.reason là "PROJECT_POLICY_NOT_APPROVED" trước khi chạy; lần gửi lại của bên gọi sẽ chạy. |
INTERNAL_ERROR |
Lỗi khác. |
Lời gọi cũng có thể bị từ chối trước khi action chạy: không tìm thấy action trong
version đang active hoặc action không mở cho bên gọi đó, người mà action sẽ chạy dưới
danh tính không còn là thành viên đang hoạt động, lời gọi không có người dùng không
được identity policy cho phép, ngân sách tự động hoá đã hết, cùng action.runId đã được
dùng với input khác hoặc bởi bên gọi hay danh tính khác, hoặc Cogover tạm thời không
sẵn sàng (bên gọi sẽ thử lại).
Rate this page
On this page