@mindstudio-ai/agent 0.1.105 → 0.1.107
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -3
- package/dist/cli.js +76 -13
- package/dist/index.d.ts +49 -3
- package/dist/index.js +67 -4
- package/dist/index.js.map +1 -1
- package/dist/postinstall.js +76 -13
- package/llms.txt +2 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -2811,6 +2811,15 @@ interface CrawlerHit {
|
|
|
2811
2811
|
interface Analytics {
|
|
2812
2812
|
/** The general read: metrics × dimensions × filters × time. */
|
|
2813
2813
|
query(spec: AnalyticsQuerySpec): Promise<AnalyticsQueryResponse>;
|
|
2814
|
+
/**
|
|
2815
|
+
* Up to 10 queries in one round trip, results in request order — the right
|
|
2816
|
+
* shape for a page composed of several reads (KPIs + timeseries + a few
|
|
2817
|
+
* breakdowns), instead of a parallel burst of `query()` calls competing
|
|
2818
|
+
* with each other against the per-app rate limit. Each query in the batch
|
|
2819
|
+
* counts as one read against the limit. One invalid query fails the whole
|
|
2820
|
+
* batch (the error names its index).
|
|
2821
|
+
*/
|
|
2822
|
+
batch(specs: AnalyticsQuerySpec[]): Promise<AnalyticsQueryResponse[]>;
|
|
2814
2823
|
/** Who's on the app right now (Redis presence, no time window). */
|
|
2815
2824
|
live(): Promise<LiveNow>;
|
|
2816
2825
|
/**
|
|
@@ -2963,9 +2972,12 @@ interface SchemaValidationError {
|
|
|
2963
2972
|
* - `{ method }`: SDK method name with default input overrides.
|
|
2964
2973
|
* - `{ appMethod }`: one of your own app's methods, called as the invoking
|
|
2965
2974
|
* user with their roles.
|
|
2975
|
+
* - `{ name, execute }`: an inline function tool, executed right here in your
|
|
2976
|
+
* process. No platform dispatch, no billing — just your code.
|
|
2966
2977
|
*
|
|
2967
2978
|
* Defaults win over whatever the model passes for the same field, including
|
|
2968
2979
|
* nested fields — the model decides what to do, you pin how it's done.
|
|
2980
|
+
* Function tools take no defaults: close over what you need instead.
|
|
2969
2981
|
*/
|
|
2970
2982
|
type TaskToolConfig = string | {
|
|
2971
2983
|
method: string;
|
|
@@ -2980,6 +2992,22 @@ type TaskToolConfig = string | {
|
|
|
2980
2992
|
*/
|
|
2981
2993
|
description?: string;
|
|
2982
2994
|
defaults?: Record<string, unknown>;
|
|
2995
|
+
} | {
|
|
2996
|
+
/** Tool name the model sees. Letters, digits, `_`, `-`; max 64 chars. */
|
|
2997
|
+
name: string;
|
|
2998
|
+
/** What the tool does and when to reach for it — all the model gets. */
|
|
2999
|
+
description: string;
|
|
3000
|
+
/** JSON Schema for the input (tool-definition dialect). Omitted means
|
|
3001
|
+
* the tool takes no arguments. */
|
|
3002
|
+
inputSchema?: JsonObjectSchema;
|
|
3003
|
+
/**
|
|
3004
|
+
* Runs in this process when the model calls the tool. A thrown error is
|
|
3005
|
+
* fed back to the model as `{ error }` tool output to work around — it
|
|
3006
|
+
* never fails the task. Note: calling `runTask` from inside a function
|
|
3007
|
+
* tool is not depth-capped (the server cap rides the method's token,
|
|
3008
|
+
* which a function tool reuses) — recursion is yours to bound.
|
|
3009
|
+
*/
|
|
3010
|
+
execute: (input: Record<string, unknown>) => Promise<unknown> | unknown;
|
|
2983
3011
|
};
|
|
2984
3012
|
/** Options shared by both output modes of {@link MindStudioAgent.runTask}. */
|
|
2985
3013
|
interface RunTaskOptionsBase {
|
|
@@ -2987,7 +3015,8 @@ interface RunTaskOptionsBase {
|
|
|
2987
3015
|
prompt: string;
|
|
2988
3016
|
/** Structured input for this task instance. Passed as the user message. */
|
|
2989
3017
|
input: Record<string, unknown>;
|
|
2990
|
-
/** SDK actions and/or
|
|
3018
|
+
/** SDK actions, app methods, and/or inline function tools to make
|
|
3019
|
+
* available to the model. */
|
|
2991
3020
|
tools: TaskToolConfig[];
|
|
2992
3021
|
/**
|
|
2993
3022
|
* Model ID for the task agent. Must support tool use. Tuned model lines
|
|
@@ -3205,8 +3234,12 @@ declare class MindStudioAgent$1 {
|
|
|
3205
3234
|
* to produce structured output. The model receives the prompt and tools,
|
|
3206
3235
|
* calls actions as needed, and returns structured JSON.
|
|
3207
3236
|
*
|
|
3208
|
-
* Tools can be SDK actions, your own app's methods, or
|
|
3209
|
-
*
|
|
3237
|
+
* Tools can be SDK actions, your own app's methods, and/or inline functions
|
|
3238
|
+
* defined right in your code, in any combination. App methods run as the
|
|
3239
|
+
* user who invoked the method that started the task, with their roles.
|
|
3240
|
+
* Function tools run in this process — a thrown error is fed back to the
|
|
3241
|
+
* model as tool output, and there are no `defaults` (close over what you
|
|
3242
|
+
* need instead).
|
|
3210
3243
|
*
|
|
3211
3244
|
* Prefer `outputSchema` (plain JSON Schema, tool-definition dialect):
|
|
3212
3245
|
* output is validated every turn with automatic repair, `result.output` is
|
|
@@ -3222,6 +3255,12 @@ declare class MindStudioAgent$1 {
|
|
|
3222
3255
|
* 'searchGoogle',
|
|
3223
3256
|
* 'fetchUrl',
|
|
3224
3257
|
* { appMethod: 'saveRestaurant', description: 'Persist the researched restaurant.' },
|
|
3258
|
+
* {
|
|
3259
|
+
* name: 'checkExisting',
|
|
3260
|
+
* description: 'Look up whether we already track this restaurant.',
|
|
3261
|
+
* inputSchema: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'] },
|
|
3262
|
+
* execute: async (input) => Restaurants.findByName(String(input.name)),
|
|
3263
|
+
* },
|
|
3225
3264
|
* ],
|
|
3226
3265
|
* outputSchema: {
|
|
3227
3266
|
* type: 'object',
|
|
@@ -3534,6 +3573,12 @@ declare class MindStudioAgent$1 {
|
|
|
3534
3573
|
/**
|
|
3535
3574
|
* @internal Transport for the `analytics` namespace —
|
|
3536
3575
|
* POST /_internal/v2/analytics/<op> with the raw hook token.
|
|
3576
|
+
*
|
|
3577
|
+
* Retries a single 429 after a short jittered backoff: analytics reads are
|
|
3578
|
+
* idempotent and a 429 means the read never executed, so one retry lets a
|
|
3579
|
+
* momentary burst (a page's fan-out racing a live poller) self-heal instead
|
|
3580
|
+
* of surfacing as empty data. Deliberately single-shot and scoped to this
|
|
3581
|
+
* namespace — the other brokered transports keep their semantics.
|
|
3537
3582
|
*/
|
|
3538
3583
|
private _analyticsRequest;
|
|
3539
3584
|
/**
|
|
@@ -10058,6 +10103,7 @@ interface StepMethods {
|
|
|
10058
10103
|
* - The special connectionId "trigger_email" uses the email address that triggered the workflow.
|
|
10059
10104
|
* - Sends default to category "marketing": every message carries a one-click unsubscribe header pointing at the app's own domain, and recipients who previously unsubscribed from this app are skipped and returned in "suppressed". Because the unsubscribe link is per-recipient, a marketing send delivers one separate message per recipient and cc/bcc are folded into that list.
|
|
10060
10105
|
* - Set category to "transactional" for receipts, alerts, password resets and anything a recipient must not be able to opt out of. Transactional sends carry no unsubscribe header, ignore the unsubscribe list, and keep cc/bcc on a single message — use it whenever cc/bcc semantics matter.
|
|
10106
|
+
* - The subject is stored verbatim in the app's delivery log, which every workspace member can read for 90 days. Never put a secret in the subject — no one-time codes, no magic-link tokens, no password-reset tokens. Put those in the body, which is never stored.
|
|
10061
10107
|
*
|
|
10062
10108
|
* @example
|
|
10063
10109
|
* ```typescript
|
package/dist/index.js
CHANGED
|
@@ -2784,6 +2784,10 @@ function createAnalytics(call) {
|
|
|
2784
2784
|
query(spec) {
|
|
2785
2785
|
return call("query", spec);
|
|
2786
2786
|
},
|
|
2787
|
+
async batch(specs) {
|
|
2788
|
+
const res = await call("query-batch", { queries: specs });
|
|
2789
|
+
return res.results;
|
|
2790
|
+
},
|
|
2787
2791
|
live() {
|
|
2788
2792
|
return call("live", {});
|
|
2789
2793
|
},
|
|
@@ -3793,7 +3797,8 @@ var stepMetadata = {
|
|
|
3793
3797
|
- connectionId can be a comma-separated list to send to multiple recipients.
|
|
3794
3798
|
- The special connectionId "trigger_email" uses the email address that triggered the workflow.
|
|
3795
3799
|
- Sends default to category "marketing": every message carries a one-click unsubscribe header pointing at the app's own domain, and recipients who previously unsubscribed from this app are skipped and returned in "suppressed". Because the unsubscribe link is per-recipient, a marketing send delivers one separate message per recipient and cc/bcc are folded into that list.
|
|
3796
|
-
- Set category to "transactional" for receipts, alerts, password resets and anything a recipient must not be able to opt out of. Transactional sends carry no unsubscribe header, ignore the unsubscribe list, and keep cc/bcc on a single message \u2014 use it whenever cc/bcc semantics matter
|
|
3800
|
+
- Set category to "transactional" for receipts, alerts, password resets and anything a recipient must not be able to opt out of. Transactional sends carry no unsubscribe header, ignore the unsubscribe list, and keep cc/bcc on a single message \u2014 use it whenever cc/bcc semantics matter.
|
|
3801
|
+
- The subject is stored verbatim in the app's delivery log, which every workspace member can read for 90 days. Never put a secret in the subject \u2014 no one-time codes, no magic-link tokens, no password-reset tokens. Put those in the body, which is never stored.`,
|
|
3797
3802
|
inputSchema: { "type": "object", "properties": { "subject": { "type": "string", "description": "Email subject line" }, "body": { "type": "string", "description": "Email body content (plain text, markdown, HTML, or a CDN URL to an HTML file)" }, "to": { "anyOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }] }, "cc": { "anyOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }] }, "bcc": { "anyOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }] }, "connectionId": { "type": "string", "description": "OAuth connection ID(s) for the recipient(s), comma-separated for multiple" }, "generateHtml": { "type": "boolean", "description": "When true, auto-convert the body text into a styled HTML email using AI" }, "generateHtmlInstructions": { "type": "string", "description": "Natural language instructions for the HTML generation style" }, "generateHtmlModelOverride": { "type": "object", "properties": { "model": { "type": "string", "description": 'Model identifier (e.g. "gpt-4", "claude-3-opus")' }, "temperature": { "type": "number", "description": "Sampling temperature for the model (0-2)" }, "maxResponseTokens": { "type": "number", "description": "Maximum number of tokens in the model's response" }, "ignorePreamble": { "type": "boolean", "description": "Whether to skip the system preamble/instructions" }, "userMessagePreprocessor": { "type": "object", "properties": { "dataSource": { "type": "string", "description": "Data source identifier for the preprocessor" }, "messageTemplate": { "type": "string", "description": "Template string applied to user messages before sending to the model" }, "maxResults": { "type": "number", "description": "Maximum number of results to include from the data source" }, "enabled": { "type": "boolean", "description": "Whether the preprocessor is active" }, "shouldInherit": { "type": "boolean", "description": "Whether child steps should inherit this preprocessor configuration" } }, "description": "Preprocessor applied to user messages before sending to the model" }, "preamble": { "type": "string", "description": "System preamble/instructions for the model" }, "multiModelEnabled": { "type": "boolean", "description": "Whether multi-model candidate generation is enabled" }, "editResponseEnabled": { "type": "boolean", "description": "Whether the user can edit the model's response" }, "config": { "type": "object", "properties": {}, "required": [], "description": "Additional model-specific configuration" } }, "required": ["model", "temperature", "maxResponseTokens"], "description": "Model settings override for HTML generation" }, "attachments": { "type": "array", "items": { "anyOf": [{ "type": "string" }, { "type": "object", "properties": { "url": { "type": "string" }, "filename": { "type": "string" }, "contentType": { "type": "string" } }, "required": ["url"] }] }, "description": "Files to attach: each entry is a URL string, or an object `{ url, filename?, contentType? }` to control the displayed filename and MIME type." }, "from": { "type": "string", "description": "Custom sender handle \u2014 only for apps with a custom domain or subdomain. Bare handle (`support`), full `support@your-domain.com`, or `Name <support@your-domain.com>`. Must resolve to a domain the app owns." }, "bodyType": { "enum": ["auto", "html", "markdown", "text"], "type": "string", "description": "How to interpret `body`: `auto` (default \u2014 detect HTML, else render markdown), `html` (send as-is), `markdown` (render to HTML), or `text` (send as plain text only, no HTML part). Every send includes a text/plain alternative." }, "text": { "type": "string", "description": "Explicit text/plain alternative body. Auto-derived from `body` if omitted." }, "replyTo": { "type": "string", "description": "Reply-To address for the email." }, "inReplyTo": { "type": "string", "description": "Message-ID this email replies to, for inbox threading (In-Reply-To header)." }, "references": { "type": "array", "items": { "type": "string" }, "description": "Prior Message-IDs in the thread, for inbox threading (References header)." }, "category": { "enum": ["transactional", "marketing"], "type": "string", "description": "`marketing` (default) adds one-click unsubscribe headers and skips recipients who unsubscribed from this app. Use `transactional` for receipts, alerts and password resets: no unsubscribe header, never suppressed, and cc/bcc preserved on a single message." } }, "required": ["subject", "body"] },
|
|
3798
3803
|
outputSchema: { "type": "object", "properties": { "recipients": { "type": "array", "items": { "type": "string" }, "description": "To addresses the message was sent to." }, "cc": { "type": "array", "items": { "type": "string" }, "description": "Cc addresses on the message (empty if none)." }, "bcc": { "type": "array", "items": { "type": "string" }, "description": "Bcc addresses on the message (empty if none)." }, "from": { "type": "string", "description": "The resolved sender address the message went out as (auto-selected when no `from` is given)." }, "suppressed": { "type": "array", "items": { "type": "string" }, "description": "Recipients skipped because they unsubscribed from this app. Always empty for a `transactional` send." } }, "required": ["recipients", "cc", "bcc", "from", "suppressed"] }
|
|
3799
3804
|
},
|
|
@@ -4241,6 +4246,13 @@ function resolveStepType(name) {
|
|
|
4241
4246
|
}
|
|
4242
4247
|
function mapTools(tools) {
|
|
4243
4248
|
return tools.map((t) => {
|
|
4249
|
+
if (typeof t === "object" && "execute" in t) {
|
|
4250
|
+
return {
|
|
4251
|
+
name: t.name,
|
|
4252
|
+
description: t.description,
|
|
4253
|
+
inputSchema: t.inputSchema ?? { type: "object", properties: {} }
|
|
4254
|
+
};
|
|
4255
|
+
}
|
|
4244
4256
|
if (typeof t === "object" && "appMethod" in t) {
|
|
4245
4257
|
return {
|
|
4246
4258
|
appMethod: t.appMethod,
|
|
@@ -4686,10 +4698,18 @@ ${structuredOutputExample}
|
|
|
4686
4698
|
const wireTools = mapTools(options.tools);
|
|
4687
4699
|
const toolKinds = /* @__PURE__ */ new Map();
|
|
4688
4700
|
const toolDefaults = /* @__PURE__ */ new Map();
|
|
4701
|
+
const functionTools = /* @__PURE__ */ new Map();
|
|
4702
|
+
for (const t of options.tools) {
|
|
4703
|
+
if (typeof t === "object" && "execute" in t) {
|
|
4704
|
+
functionTools.set(t.name, t.execute);
|
|
4705
|
+
}
|
|
4706
|
+
}
|
|
4689
4707
|
for (const t of wireTools) {
|
|
4690
4708
|
if ("appMethod" in t) {
|
|
4691
4709
|
toolKinds.set(t.appMethod, "method");
|
|
4692
4710
|
if (t.defaults) toolDefaults.set(t.appMethod, t.defaults);
|
|
4711
|
+
} else if ("name" in t) {
|
|
4712
|
+
toolKinds.set(t.name, "function");
|
|
4693
4713
|
} else {
|
|
4694
4714
|
toolKinds.set(t.stepType, "step");
|
|
4695
4715
|
if (t.defaults) toolDefaults.set(t.stepType, t.defaults);
|
|
@@ -4818,8 +4838,27 @@ ${structuredOutputExample}
|
|
|
4818
4838
|
const startTime = Date.now();
|
|
4819
4839
|
const defaults = toolDefaults.get(toolCall.name) || {};
|
|
4820
4840
|
const mergedInput = mergeToolInput(toolCall.input, defaults);
|
|
4821
|
-
const
|
|
4822
|
-
|
|
4841
|
+
const kind = toolKinds.get(toolCall.name);
|
|
4842
|
+
let result;
|
|
4843
|
+
if (kind === "function") {
|
|
4844
|
+
try {
|
|
4845
|
+
const output3 = await functionTools.get(toolCall.name)(
|
|
4846
|
+
mergedInput
|
|
4847
|
+
);
|
|
4848
|
+
result = { output: output3 ?? null, billingCost: 0, isError: false };
|
|
4849
|
+
} catch (err) {
|
|
4850
|
+
result = {
|
|
4851
|
+
output: {
|
|
4852
|
+
error: err instanceof Error ? err.message : "Function tool execution failed"
|
|
4853
|
+
},
|
|
4854
|
+
billingCost: 0,
|
|
4855
|
+
isError: true
|
|
4856
|
+
};
|
|
4857
|
+
}
|
|
4858
|
+
} else {
|
|
4859
|
+
const execute = kind === "method" ? deps.executeMethodTool : deps.executeStepTool;
|
|
4860
|
+
result = await execute(toolCall.name, mergedInput);
|
|
4861
|
+
}
|
|
4823
4862
|
toolCallLog.push({
|
|
4824
4863
|
name: toolCall.name,
|
|
4825
4864
|
success: !result.isError,
|
|
@@ -6070,6 +6109,13 @@ var MindStudioAgent = class {
|
|
|
6070
6109
|
);
|
|
6071
6110
|
} catch (err) {
|
|
6072
6111
|
if (err instanceof MindStudioError && err.code === TURN_UNAVAILABLE_CODE) {
|
|
6112
|
+
if (options.tools.some((t) => typeof t === "object" && "execute" in t)) {
|
|
6113
|
+
throw new MindStudioError(
|
|
6114
|
+
"[task] This server does not support the per-turn task endpoint required for function tools.",
|
|
6115
|
+
"task_function_tools_unsupported",
|
|
6116
|
+
404
|
|
6117
|
+
);
|
|
6118
|
+
}
|
|
6073
6119
|
const body = buildTaskRequestBody(options);
|
|
6074
6120
|
const result = options.onEvent ? await runTaskStream(httpConfig, body, options.onEvent) : await runTaskPoll(httpConfig, body);
|
|
6075
6121
|
if (options.outputSchema) {
|
|
@@ -6655,12 +6701,29 @@ var MindStudioAgent = class {
|
|
|
6655
6701
|
/**
|
|
6656
6702
|
* @internal Transport for the `analytics` namespace —
|
|
6657
6703
|
* POST /_internal/v2/analytics/<op> with the raw hook token.
|
|
6704
|
+
*
|
|
6705
|
+
* Retries a single 429 after a short jittered backoff: analytics reads are
|
|
6706
|
+
* idempotent and a 429 means the read never executed, so one retry lets a
|
|
6707
|
+
* momentary burst (a page's fan-out racing a live poller) self-heal instead
|
|
6708
|
+
* of surfacing as empty data. Deliberately single-shot and scoped to this
|
|
6709
|
+
* namespace — the other brokered transports keep their semantics.
|
|
6658
6710
|
*/
|
|
6659
6711
|
async _analyticsRequest(op, body) {
|
|
6660
|
-
|
|
6712
|
+
const call = () => this._brokeredRequest("analytics", op, body, {
|
|
6661
6713
|
fallbackMessage: "Analytics read failed",
|
|
6662
6714
|
fallbackCode: "analytics_error"
|
|
6663
6715
|
});
|
|
6716
|
+
try {
|
|
6717
|
+
return await call();
|
|
6718
|
+
} catch (err) {
|
|
6719
|
+
if (err instanceof MindStudioError && err.status === 429) {
|
|
6720
|
+
await new Promise(
|
|
6721
|
+
(resolve) => setTimeout(resolve, 750 + Math.random() * 750)
|
|
6722
|
+
);
|
|
6723
|
+
return call();
|
|
6724
|
+
}
|
|
6725
|
+
throw err;
|
|
6726
|
+
}
|
|
6664
6727
|
}
|
|
6665
6728
|
/**
|
|
6666
6729
|
* @internal Shared shape for the brokered `/_internal/v2/<ns>/<op>` data
|