@wiro-ai/wiro-mcp 1.4.0 → 1.5.0
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 +50 -17
- package/dist/client.d.ts +25 -6
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +129 -29
- package/dist/client.js.map +1 -1
- package/dist/instructions.d.ts.map +1 -1
- package/dist/instructions.js +24 -17
- package/dist/instructions.js.map +1 -1
- package/dist/playbooks.d.ts.map +1 -1
- package/dist/playbooks.js +61 -48
- package/dist/playbooks.js.map +1 -1
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +4 -3
- package/dist/prompts.js.map +1 -1
- package/dist/server.d.ts +6 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +3 -4
- package/dist/server.js.map +1 -1
- package/dist/tools/apply-agent-skills.d.ts.map +1 -1
- package/dist/tools/apply-agent-skills.js +400 -88
- package/dist/tools/apply-agent-skills.js.map +1 -1
- package/dist/tools/bind-agent-project.d.ts +4 -0
- package/dist/tools/bind-agent-project.d.ts.map +1 -0
- package/dist/tools/bind-agent-project.js +403 -0
- package/dist/tools/bind-agent-project.js.map +1 -0
- package/dist/tools/cancel-agent-message.d.ts.map +1 -1
- package/dist/tools/cancel-agent-message.js +6 -3
- package/dist/tools/cancel-agent-message.js.map +1 -1
- package/dist/tools/cancel-task.js +3 -3
- package/dist/tools/cancel-task.js.map +1 -1
- package/dist/tools/clone-workflow.d.ts.map +1 -1
- package/dist/tools/clone-workflow.js +5 -4
- package/dist/tools/clone-workflow.js.map +1 -1
- package/dist/tools/connect-agent-oauth.d.ts.map +1 -1
- package/dist/tools/connect-agent-oauth.js +144 -44
- package/dist/tools/connect-agent-oauth.js.map +1 -1
- package/dist/tools/control-agent.d.ts.map +1 -1
- package/dist/tools/control-agent.js +133 -45
- package/dist/tools/control-agent.js.map +1 -1
- package/dist/tools/create-workflow.d.ts +9 -6
- package/dist/tools/create-workflow.d.ts.map +1 -1
- package/dist/tools/create-workflow.js +13 -13
- package/dist/tools/create-workflow.js.map +1 -1
- package/dist/tools/delete-agent-session.d.ts.map +1 -1
- package/dist/tools/delete-agent-session.js +20 -14
- package/dist/tools/delete-agent-session.js.map +1 -1
- package/dist/tools/delete-agent.d.ts.map +1 -1
- package/dist/tools/delete-agent.js +14 -10
- package/dist/tools/delete-agent.js.map +1 -1
- package/dist/tools/delete-workflow.d.ts.map +1 -1
- package/dist/tools/delete-workflow.js +6 -5
- package/dist/tools/delete-workflow.js.map +1 -1
- package/dist/tools/deploy-agent.d.ts.map +1 -1
- package/dist/tools/deploy-agent.js +215 -47
- package/dist/tools/deploy-agent.js.map +1 -1
- package/dist/tools/disconnect-agent-oauth.d.ts.map +1 -1
- package/dist/tools/disconnect-agent-oauth.js +32 -12
- package/dist/tools/disconnect-agent-oauth.js.map +1 -1
- package/dist/tools/get-account.d.ts.map +1 -1
- package/dist/tools/get-account.js +157 -49
- package/dist/tools/get-account.js.map +1 -1
- package/dist/tools/get-agent-activity.d.ts.map +1 -1
- package/dist/tools/get-agent-activity.js +186 -36
- package/dist/tools/get-agent-activity.js.map +1 -1
- package/dist/tools/get-agent-conversation.d.ts.map +1 -1
- package/dist/tools/get-agent-conversation.js +65 -39
- package/dist/tools/get-agent-conversation.js.map +1 -1
- package/dist/tools/get-agent-message.d.ts.map +1 -1
- package/dist/tools/get-agent-message.js +6 -4
- package/dist/tools/get-agent-message.js.map +1 -1
- package/dist/tools/get-agent-template.d.ts.map +1 -1
- package/dist/tools/get-agent-template.js +33 -17
- package/dist/tools/get-agent-template.js.map +1 -1
- package/dist/tools/get-model-schema.d.ts.map +1 -1
- package/dist/tools/get-model-schema.js +7 -5
- package/dist/tools/get-model-schema.js.map +1 -1
- package/dist/tools/get-my-agent.d.ts.map +1 -1
- package/dist/tools/get-my-agent.js +54 -11
- package/dist/tools/get-my-agent.js.map +1 -1
- package/dist/tools/get-playbook.d.ts.map +1 -1
- package/dist/tools/get-playbook.js +3 -2
- package/dist/tools/get-playbook.js.map +1 -1
- package/dist/tools/get-task-price.d.ts +1 -1
- package/dist/tools/get-task-price.d.ts.map +1 -1
- package/dist/tools/get-task-price.js +29 -8
- package/dist/tools/get-task-price.js.map +1 -1
- package/dist/tools/get-task.d.ts.map +1 -1
- package/dist/tools/get-task.js +25 -9
- package/dist/tools/get-task.js.map +1 -1
- package/dist/tools/get-workflow.d.ts.map +1 -1
- package/dist/tools/get-workflow.js +46 -21
- package/dist/tools/get-workflow.js.map +1 -1
- package/dist/tools/index.d.ts +4 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +10 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/kill-task.js +3 -3
- package/dist/tools/kill-task.js.map +1 -1
- package/dist/tools/list-agent-skills.d.ts.map +1 -1
- package/dist/tools/list-agent-skills.js +5 -4
- package/dist/tools/list-agent-skills.js.map +1 -1
- package/dist/tools/list-agent-templates.js +4 -4
- package/dist/tools/list-agent-templates.js.map +1 -1
- package/dist/tools/list-my-agents.d.ts.map +1 -1
- package/dist/tools/list-my-agents.js +14 -8
- package/dist/tools/list-my-agents.js.map +1 -1
- package/dist/tools/list-projects.d.ts +4 -0
- package/dist/tools/list-projects.d.ts.map +1 -0
- package/dist/tools/list-projects.js +141 -0
- package/dist/tools/list-projects.js.map +1 -0
- package/dist/tools/list-studio-results.js +3 -3
- package/dist/tools/list-studio-results.js.map +1 -1
- package/dist/tools/list-tasks.js +3 -3
- package/dist/tools/list-tasks.js.map +1 -1
- package/dist/tools/list-workflow-runs.d.ts.map +1 -1
- package/dist/tools/list-workflow-runs.js +6 -4
- package/dist/tools/list-workflow-runs.js.map +1 -1
- package/dist/tools/list-workflows.d.ts.map +1 -1
- package/dist/tools/list-workflows.js +7 -6
- package/dist/tools/list-workflows.js.map +1 -1
- package/dist/tools/manage-agent-billing.d.ts.map +1 -1
- package/dist/tools/manage-agent-billing.js +259 -87
- package/dist/tools/manage-agent-billing.js.map +1 -1
- package/dist/tools/manage-agent-custom-skill.d.ts.map +1 -1
- package/dist/tools/manage-agent-custom-skill.js +91 -21
- package/dist/tools/manage-agent-custom-skill.js.map +1 -1
- package/dist/tools/recommend-model.js +3 -3
- package/dist/tools/recommend-model.js.map +1 -1
- package/dist/tools/resume-workflow-run.d.ts.map +1 -1
- package/dist/tools/resume-workflow-run.js +3 -2
- package/dist/tools/resume-workflow-run.js.map +1 -1
- package/dist/tools/run-model.js +5 -5
- package/dist/tools/run-model.js.map +1 -1
- package/dist/tools/run-workflow.d.ts.map +1 -1
- package/dist/tools/run-workflow.js +3 -2
- package/dist/tools/run-workflow.js.map +1 -1
- package/dist/tools/save-workflow-from-agent.d.ts.map +1 -1
- package/dist/tools/save-workflow-from-agent.js +22 -20
- package/dist/tools/save-workflow-from-agent.js.map +1 -1
- package/dist/tools/schemas.d.ts +150 -127
- package/dist/tools/schemas.d.ts.map +1 -1
- package/dist/tools/schemas.js +76 -3
- package/dist/tools/schemas.js.map +1 -1
- package/dist/tools/search-docs.js +3 -3
- package/dist/tools/search-docs.js.map +1 -1
- package/dist/tools/search-models.d.ts.map +1 -1
- package/dist/tools/search-models.js +7 -4
- package/dist/tools/search-models.js.map +1 -1
- package/dist/tools/send-agent-message.d.ts.map +1 -1
- package/dist/tools/send-agent-message.js +32 -11
- package/dist/tools/send-agent-message.js.map +1 -1
- package/dist/tools/set-agent-credentials.d.ts.map +1 -1
- package/dist/tools/set-agent-credentials.js +60 -59
- package/dist/tools/set-agent-credentials.js.map +1 -1
- package/dist/tools/update-agent.d.ts.map +1 -1
- package/dist/tools/update-agent.js +59 -21
- package/dist/tools/update-agent.js.map +1 -1
- package/dist/tools/update-workflow.d.ts +205 -6
- package/dist/tools/update-workflow.d.ts.map +1 -1
- package/dist/tools/update-workflow.js +20 -7
- package/dist/tools/update-workflow.js.map +1 -1
- package/dist/tools/upload-file.d.ts.map +1 -1
- package/dist/tools/upload-file.js +13 -9
- package/dist/tools/upload-file.js.map +1 -1
- package/dist/tools/wait-for-task.d.ts.map +1 -1
- package/dist/tools/wait-for-task.js +23 -5
- package/dist/tools/wait-for-task.js.map +1 -1
- package/dist/tools/wait-for-workflow-run.d.ts +18 -18
- package/dist/tools/wait-for-workflow-run.d.ts.map +1 -1
- package/dist/tools/wait-for-workflow-run.js +7 -6
- package/dist/tools/wait-for-workflow-run.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/agent-catalog.d.ts +168 -139
- package/dist/utils/agent-catalog.d.ts.map +1 -1
- package/dist/utils/agent-catalog.js +34 -14
- package/dist/utils/agent-catalog.js.map +1 -1
- package/dist/utils/agent-config.d.ts +111 -8
- package/dist/utils/agent-config.d.ts.map +1 -1
- package/dist/utils/agent-config.js +290 -40
- package/dist/utils/agent-config.js.map +1 -1
- package/dist/utils/agent-message.d.ts +41 -22
- package/dist/utils/agent-message.d.ts.map +1 -1
- package/dist/utils/agent-message.js +94 -31
- package/dist/utils/agent-message.js.map +1 -1
- package/dist/utils/agent-targets.d.ts +8 -4
- package/dist/utils/agent-targets.d.ts.map +1 -1
- package/dist/utils/agent-targets.js +51 -35
- package/dist/utils/agent-targets.js.map +1 -1
- package/dist/utils/agent-turns.d.ts +31 -24
- package/dist/utils/agent-turns.d.ts.map +1 -1
- package/dist/utils/agent-turns.js +154 -35
- package/dist/utils/agent-turns.js.map +1 -1
- package/dist/utils/api.d.ts +6 -0
- package/dist/utils/api.d.ts.map +1 -1
- package/dist/utils/api.js +22 -1
- package/dist/utils/api.js.map +1 -1
- package/dist/utils/format.d.ts +27 -1
- package/dist/utils/format.d.ts.map +1 -1
- package/dist/utils/format.js +429 -82
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/json-schema-dialect.d.ts +8 -1
- package/dist/utils/json-schema-dialect.d.ts.map +1 -1
- package/dist/utils/json-schema-dialect.js +27 -1
- package/dist/utils/json-schema-dialect.js.map +1 -1
- package/dist/utils/media.d.ts +8 -0
- package/dist/utils/media.d.ts.map +1 -1
- package/dist/utils/media.js +29 -0
- package/dist/utils/media.js.map +1 -1
- package/dist/utils/poll.d.ts +5 -2
- package/dist/utils/poll.d.ts.map +1 -1
- package/dist/utils/poll.js +10 -9
- package/dist/utils/poll.js.map +1 -1
- package/dist/utils/quoted-text.d.ts +28 -0
- package/dist/utils/quoted-text.d.ts.map +1 -0
- package/dist/utils/quoted-text.js +64 -0
- package/dist/utils/quoted-text.js.map +1 -0
- package/dist/utils/structured.d.ts +2 -0
- package/dist/utils/structured.d.ts.map +1 -1
- package/dist/utils/structured.js +15 -2
- package/dist/utils/structured.js.map +1 -1
- package/dist/utils/studio-runs.d.ts +4 -4
- package/dist/utils/studio-runs.d.ts.map +1 -1
- package/dist/utils/studio-runs.js +11 -8
- package/dist/utils/studio-runs.js.map +1 -1
- package/dist/utils/user-agent.d.ts +376 -241
- package/dist/utils/user-agent.d.ts.map +1 -1
- package/dist/utils/user-agent.js +302 -89
- package/dist/utils/user-agent.js.map +1 -1
- package/dist/utils/wiro-project.d.ts +45 -0
- package/dist/utils/wiro-project.d.ts.map +1 -0
- package/dist/utils/wiro-project.js +66 -0
- package/dist/utils/wiro-project.js.map +1 -0
- package/dist/utils/workflow-agent.d.ts +4 -4
- package/dist/utils/workflow-save.d.ts +23 -5
- package/dist/utils/workflow-save.d.ts.map +1 -1
- package/dist/utils/workflow-save.js +130 -38
- package/dist/utils/workflow-save.js.map +1 -1
- package/dist/utils/workflow.d.ts +79 -61
- package/dist/utils/workflow.d.ts.map +1 -1
- package/dist/utils/workflow.js +149 -19
- package/dist/utils/workflow.js.map +1 -1
- package/dist/utils/workspace.d.ts +64 -0
- package/dist/utils/workspace.d.ts.map +1 -0
- package/dist/utils/workspace.js +173 -0
- package/dist/utils/workspace.js.map +1 -0
- package/package.json +6 -4
package/dist/utils/user-agent.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { WiroApiError } from '../client.js';
|
|
3
|
-
import { ApiResultError, asString, isPlainObject, requireApiSuccess, toNumber, truncate, unixToIso, } from './api.js';
|
|
3
|
+
import { AGENT_NOT_FOUND_TEXT, ApiResultError, asString, isPlainObject, requireApiSuccess, toNumber, truncate, unixToIso, } from './api.js';
|
|
4
4
|
import { pollUntil, reportProgress } from './poll.js';
|
|
5
|
-
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// allowlist instead of being passed through.
|
|
5
|
+
import { quotedSpan } from './quoted-text.js';
|
|
6
|
+
// Deployed agents and the agent catalog. Results are rebuilt from an
|
|
7
|
+
// allowlist: only states, labels, prices and settings are returned.
|
|
9
8
|
export const AGENT_DASHBOARD_URL = 'https://wiro.ai/panel/agents';
|
|
10
9
|
export function agentDashboardUrl(guid) {
|
|
11
10
|
return `${AGENT_DASHBOARD_URL}/${encodeURIComponent(guid)}`;
|
|
@@ -60,8 +59,24 @@ export function describeAgentStatus(status) {
|
|
|
60
59
|
? STATUS_TEXT[label]
|
|
61
60
|
: `${STATUS_TEXT[label]} (${status})`;
|
|
62
61
|
}
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
// On a team agent a team admin or the person who deployed it starts, changes
|
|
63
|
+
// and pays for it (the organization's owner can also pay for it). Other members
|
|
64
|
+
// can read it and message it, so their hints say who can act instead of naming
|
|
65
|
+
// a call they cannot make.
|
|
66
|
+
const TEAM_AGENT_MANAGERS = 'a team admin or the person who deployed it';
|
|
67
|
+
// Connected accounts are the exception: Wiro lets only the person who
|
|
68
|
+
// deployed the agent connect them (connect_agent_oauth).
|
|
69
|
+
export const MEMBER_SETUP_HELP = `On this team agent, ${TEAM_AGENT_MANAGERS} saves credentials and pays for the plan. `
|
|
70
|
+
+ 'Only the person who deployed it can connect accounts, such as Instagram or Google Ads.';
|
|
71
|
+
const MEMBER_STATUS_HINT = {
|
|
72
|
+
stopped: `It is not running. On this team agent, ${TEAM_AGENT_MANAGERS} can start it.`,
|
|
73
|
+
error: `The start failed or the agent stopped unexpectedly. On this team agent, ${TEAM_AGENT_MANAGERS} can start it again and read its logs.`,
|
|
74
|
+
setup_required: `${STATUS_HINT.setup_required} ${MEMBER_SETUP_HELP}`,
|
|
75
|
+
};
|
|
76
|
+
/** plainMember: the connection acts as a member of the agent's team without admin rights. */
|
|
77
|
+
export function agentStatusHint(status, plainMember = false) {
|
|
78
|
+
const label = agentStatusLabel(status);
|
|
79
|
+
return (plainMember ? MEMBER_STATUS_HINT[label] : undefined) ?? STATUS_HINT[label];
|
|
65
80
|
}
|
|
66
81
|
/** Stopping, queued and starting move on by themselves; every other status stays until someone acts. */
|
|
67
82
|
export function isTransitionalStatus(status) {
|
|
@@ -122,24 +137,47 @@ export const subscriptionSchema = z.object({
|
|
|
122
137
|
status: z.string(),
|
|
123
138
|
billing: z.enum(['wallet', 'card']),
|
|
124
139
|
switchingToWallet: z.boolean(),
|
|
125
|
-
amountUsd: z.number().nullable()
|
|
140
|
+
amountUsd: z.number().nullable()
|
|
141
|
+
.describe('What the plan costs every 30 days. For a plan that has ended, the agent\'s monthly price, which is what a renew charges.'),
|
|
126
142
|
periodEndsAt: z.string().optional(),
|
|
127
143
|
daysRemaining: z.number().nullable(),
|
|
128
144
|
cancelAtPeriodEnd: z.boolean(),
|
|
145
|
+
atPeriodEnd: z.enum(['renews', 'ends', 'unknown']).optional()
|
|
146
|
+
.describe('For an active plan, what happens at periodEndsAt: it renews, it ends, or unknown for a card plan whose renewal is managed in the Wiro dashboard.'),
|
|
129
147
|
});
|
|
130
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Whether a plan ends with its current period: true when it ends, false when
|
|
150
|
+
* it renews, null when that is not known. A wallet plan says so itself, and a
|
|
151
|
+
* card plan moving to wallet billing renews from the wallet, even though its
|
|
152
|
+
* card subscription is set to end with the period. Any other card plan is
|
|
153
|
+
* known only when the row carries its card state (cardEnds).
|
|
154
|
+
*/
|
|
155
|
+
export function planEndsWithPeriod(subscription, cardEnds) {
|
|
156
|
+
if (subscription.pendingdowngrade === 'cancel')
|
|
157
|
+
return true;
|
|
158
|
+
if (subscription.provider === 'prepaid' || subscription.nextprovider === 'prepaid')
|
|
159
|
+
return false;
|
|
160
|
+
if (cardEnds === true)
|
|
161
|
+
return true;
|
|
162
|
+
return cardEnds === false ? false : null;
|
|
163
|
+
}
|
|
164
|
+
export function toSubscription(value, cardEnds) {
|
|
131
165
|
if (!isPlainObject(value))
|
|
132
166
|
return null;
|
|
133
167
|
const provider = asString(value.provider) ?? 'stripe';
|
|
134
168
|
const periodEndsAt = unixToIso(value.currentperiodend);
|
|
169
|
+
const status = asString(value.status) ?? 'expired';
|
|
170
|
+
const ends = planEndsWithPeriod(value, cardEnds);
|
|
135
171
|
return {
|
|
136
|
-
status
|
|
172
|
+
status,
|
|
137
173
|
billing: provider === 'prepaid' ? 'wallet' : 'card',
|
|
138
174
|
switchingToWallet: provider !== 'prepaid' && value.nextprovider === 'prepaid',
|
|
139
175
|
amountUsd: toNumber(value.amount),
|
|
140
176
|
...(periodEndsAt ? { periodEndsAt } : {}),
|
|
141
177
|
daysRemaining: toNumber(value.daysremaining),
|
|
142
|
-
|
|
178
|
+
// True only when the plan is known to end; atPeriodEnd also tells a plan that renews from an unknown one.
|
|
179
|
+
cancelAtPeriodEnd: ends === true,
|
|
180
|
+
...(status === 'active' ? { atPeriodEnd: ends === true ? 'ends' : ends === false ? 'renews' : 'unknown' } : {}),
|
|
143
181
|
};
|
|
144
182
|
}
|
|
145
183
|
/** How a new charge for this plan is paid right now. */
|
|
@@ -151,7 +189,10 @@ export function chargeRoute(subscription) {
|
|
|
151
189
|
return 'card';
|
|
152
190
|
}
|
|
153
191
|
export const creditsSchema = z.object({
|
|
154
|
-
monthly: z.number()
|
|
192
|
+
monthly: z.number()
|
|
193
|
+
.describe('The monthly credits this period grants. A plan change inside a period moves it for the time left, so it can differ from renewal.'),
|
|
194
|
+
renewal: z.number().optional()
|
|
195
|
+
.describe('The monthly credits each renewal grants.'),
|
|
155
196
|
extra: z.number(),
|
|
156
197
|
used: z.number(),
|
|
157
198
|
remaining: z.number(),
|
|
@@ -159,14 +200,22 @@ export const creditsSchema = z.object({
|
|
|
159
200
|
});
|
|
160
201
|
export function toCredits(row) {
|
|
161
202
|
const period = asString(row.creditperiod);
|
|
203
|
+
const renewal = toNumber(row.renewalcredits);
|
|
162
204
|
return {
|
|
163
205
|
monthly: toNumber(row.monthlycredits) ?? 0,
|
|
206
|
+
...(renewal !== null ? { renewal } : {}),
|
|
164
207
|
extra: toNumber(row.extracredits) ?? 0,
|
|
165
208
|
used: toNumber(row.usedcredits) ?? 0,
|
|
166
209
|
remaining: toNumber(row.remainingcredits) ?? 0,
|
|
167
210
|
...(period ? { period } : {}),
|
|
168
211
|
};
|
|
169
212
|
}
|
|
213
|
+
/** The monthly credits as said in a line: those of this period, and those of each renewal when they differ. */
|
|
214
|
+
export function monthlyCreditsText(credits) {
|
|
215
|
+
return credits.renewal !== undefined && credits.renewal !== credits.monthly
|
|
216
|
+
? `${formatCredits(credits.monthly)} credits this period, ${formatCredits(credits.renewal)} from each renewal`
|
|
217
|
+
: `monthly ${formatCredits(credits.monthly)}`;
|
|
218
|
+
}
|
|
170
219
|
// ---------------------------------------------------------------------------
|
|
171
220
|
// Text helpers
|
|
172
221
|
// ---------------------------------------------------------------------------
|
|
@@ -229,7 +278,7 @@ export const credentialStatusSchema = z.object({
|
|
|
229
278
|
filled: z.boolean(),
|
|
230
279
|
requiredMissing: z.boolean(),
|
|
231
280
|
});
|
|
232
|
-
/**
|
|
281
|
+
/** The state of each credential: whether it is filled, connected or missing. */
|
|
233
282
|
export function summarizeCredentials(credentials, skipKeys = new Set()) {
|
|
234
283
|
if (!isPlainObject(credentials))
|
|
235
284
|
return [];
|
|
@@ -273,10 +322,14 @@ export function summarizeChannels(value) {
|
|
|
273
322
|
};
|
|
274
323
|
});
|
|
275
324
|
}
|
|
325
|
+
/** The scheduled task a custom build starts with. It runs only once its text has been written. */
|
|
326
|
+
export const STARTER_TASK_KEY = 'cs-cron-my-scheduled-task';
|
|
276
327
|
export const agentTaskSchema = z.object({
|
|
277
328
|
key: z.string(),
|
|
278
329
|
description: z.string().optional(),
|
|
279
330
|
enabled: z.boolean(),
|
|
331
|
+
notWritten: z.boolean().optional()
|
|
332
|
+
.describe('The starter task whose text was never written. It does not run, even when it shows on, until its text is saved with manage_agent_custom_skill.'),
|
|
280
333
|
interval: z.string().nullable().optional(),
|
|
281
334
|
source: z.enum(['template', 'skill', 'user']).optional(),
|
|
282
335
|
instructions: z.string().optional(),
|
|
@@ -301,6 +354,7 @@ export function summarizeTasks(value, maxInstructionLength = 300) {
|
|
|
301
354
|
key: asString(task.key) ?? '',
|
|
302
355
|
...(description ? { description } : {}),
|
|
303
356
|
enabled: task.enabled !== false,
|
|
357
|
+
...(asString(task.key) === STARTER_TASK_KEY && task._edited === false ? { notWritten: true } : {}),
|
|
304
358
|
...(interval !== undefined ? { interval: interval || null } : {}),
|
|
305
359
|
...(source ? { source } : {}),
|
|
306
360
|
...(shortened ? { instructions: shortened } : {}),
|
|
@@ -339,7 +393,8 @@ export const agentSummarySchema = z.object({
|
|
|
339
393
|
title: z.string(),
|
|
340
394
|
status: z.number().int().nullable(),
|
|
341
395
|
statusLabel: agentStatusLabelSchema,
|
|
342
|
-
setupRequired: z.boolean()
|
|
396
|
+
setupRequired: z.boolean()
|
|
397
|
+
.describe('Whether the agent waits for setup. list_my_agents goes by the status (6). get_my_agent also checks each required credential and names what is missing.'),
|
|
343
398
|
workspace: z.enum(['personal', 'team']),
|
|
344
399
|
template: agentTemplateRefSchema,
|
|
345
400
|
tier: z.string().optional(),
|
|
@@ -351,13 +406,16 @@ export const agentSummarySchema = z.object({
|
|
|
351
406
|
skills: z.array(z.string()),
|
|
352
407
|
createdAt: z.string().optional(),
|
|
353
408
|
updatedAt: z.string().optional(),
|
|
409
|
+
lastActivityAt: z.string().optional()
|
|
410
|
+
.describe('When the agent\'s newest message was written, on any channel, scheduled runs included. Left out when it has none.'),
|
|
354
411
|
});
|
|
355
412
|
export const agentDetailSchema = agentSummarySchema.extend({
|
|
356
413
|
description: z.string().optional(),
|
|
357
414
|
cover: z.string().optional(),
|
|
358
415
|
categories: z.array(z.string()),
|
|
359
416
|
pricing: tierPricingSchema.nullable(),
|
|
360
|
-
extraCreditPacks: z.array(extraCreditPackSchema)
|
|
417
|
+
extraCreditPacks: z.array(extraCreditPackSchema)
|
|
418
|
+
.describe('The extra credit packs this plan can buy. Only an active Pro plan can buy them, so any other plan lists none.'),
|
|
361
419
|
models: modelSettingsSchema.optional(),
|
|
362
420
|
selectableModels: z.array(selectableModelSchema).optional(),
|
|
363
421
|
enabledCommands: z.array(z.string()).nullable(),
|
|
@@ -406,6 +464,15 @@ function timestamps(row, map) {
|
|
|
406
464
|
}
|
|
407
465
|
return out;
|
|
408
466
|
}
|
|
467
|
+
/**
|
|
468
|
+
* The plan as it is shown. A plan that has ended renews at the agent's monthly
|
|
469
|
+
* price, not at the amount of its last period, so that is its one price.
|
|
470
|
+
*/
|
|
471
|
+
function planOf(row) {
|
|
472
|
+
const plan = toSubscription(row.subscription, row.stripecancelatperiodend);
|
|
473
|
+
const price = toNumber(row.monthlypriceusd);
|
|
474
|
+
return plan && plan.status !== 'active' && price !== null && price > 0 ? { ...plan, amountUsd: price } : plan;
|
|
475
|
+
}
|
|
409
476
|
/** The compact row used by list_my_agents. */
|
|
410
477
|
export function toAgentSummary(row) {
|
|
411
478
|
const status = readAgentStatus(row);
|
|
@@ -423,11 +490,11 @@ export function toAgentSummary(row) {
|
|
|
423
490
|
...(tier ? { tier } : {}),
|
|
424
491
|
monthlyPriceUsd: toNumber(row.monthlypriceusd),
|
|
425
492
|
credits: toCredits(row),
|
|
426
|
-
subscription:
|
|
493
|
+
subscription: planOf(row),
|
|
427
494
|
...(timezone !== undefined ? { timezone } : {}),
|
|
428
495
|
...(sessionMode ? { teamSessionMode: sessionMode } : {}),
|
|
429
496
|
skills: toStringArray(row.skills ?? row.enabledSkills),
|
|
430
|
-
...timestamps(row, { createdAt: 'createdat', updatedAt: 'updatedat' }),
|
|
497
|
+
...timestamps(row, { createdAt: 'createdat', updatedAt: 'updatedat', lastActivityAt: 'lastactivityat' }),
|
|
431
498
|
};
|
|
432
499
|
}
|
|
433
500
|
/** The models an agent can switch to, with their credits per 1M input and output tokens when Wiro lists them. */
|
|
@@ -454,29 +521,54 @@ export function selectableModelSlugs(row) {
|
|
|
454
521
|
return new Set(selectableModels(row.tokenRates).map(model => model.slug));
|
|
455
522
|
}
|
|
456
523
|
/**
|
|
457
|
-
* The
|
|
458
|
-
*
|
|
459
|
-
*
|
|
524
|
+
* The keys of the credentials an agent's setup waits for: a credential with a
|
|
525
|
+
* required field empty, a required credential that holds no value yet, or a
|
|
526
|
+
* required sign-in that is not connected. A custom build's setup waits only for
|
|
527
|
+
* the main credential of each active skill, which skillsmeta lists. Its chat
|
|
528
|
+
* channels are never among them.
|
|
529
|
+
*/
|
|
530
|
+
export function credentialKeysSetupWaitsFor(row) {
|
|
531
|
+
const channelKeys = new Set(summarizeChannels(row.communicationChannels).map(channel => channel.credentialKey));
|
|
532
|
+
const activeKeys = templateRef(row).custom && isPlainObject(row.skillsmeta)
|
|
533
|
+
? new Set(Object.values(row.skillsmeta).filter(isPlainObject)
|
|
534
|
+
.filter(meta => meta.requires_credentials === true)
|
|
535
|
+
.map(meta => asString(meta.credential_key))
|
|
536
|
+
.filter((key) => Boolean(key)))
|
|
537
|
+
: null;
|
|
538
|
+
return new Set(summarizeCredentials(row.credentials, channelKeys)
|
|
539
|
+
// A required credential whose fields are all optional has no empty required
|
|
540
|
+
// field to show, and the setup still waits until it holds a value.
|
|
541
|
+
.filter(credential => credential.requiredMissing
|
|
542
|
+
|| (!credential.optional && !credential.connected && (credential.oauth || (row.setuprequired === true && !credential.filled))))
|
|
543
|
+
.filter(credential => !activeKeys || activeKeys.has(credential.key))
|
|
544
|
+
// A group with no optional flag has no template row and no skill behind it, only saved values left over.
|
|
545
|
+
.filter((credential) => {
|
|
546
|
+
const group = isPlainObject(row.credentials) ? row.credentials[credential.key] : undefined;
|
|
547
|
+
return isPlainObject(group) && typeof group.optional === 'boolean';
|
|
548
|
+
})
|
|
549
|
+
.map(credential => credential.key));
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* The full view of one deployed agent (Detail, Deploy and Update rows): its
|
|
553
|
+
* status, plan, prices, credits and settings, and the state of each
|
|
554
|
+
* credential and channel.
|
|
460
555
|
*/
|
|
461
556
|
export function toAgentDetail(row) {
|
|
462
557
|
const summary = toAgentSummary(row);
|
|
463
558
|
const agent = isPlainObject(row.agent) ? row.agent : {};
|
|
464
559
|
const channels = summarizeChannels(row.communicationChannels);
|
|
465
560
|
const channelKeys = new Set(channels.map(channel => channel.credentialKey));
|
|
466
|
-
|
|
561
|
+
// A credential is required and missing exactly when the setup waits for it, so its row and the setup line agree.
|
|
562
|
+
const setupWaitsFor = credentialKeysSetupWaitsFor(row);
|
|
563
|
+
const credentials = summarizeCredentials(row.credentials, channelKeys)
|
|
564
|
+
.map(credential => ({ ...credential, requiredMissing: setupWaitsFor.has(credential.key) }));
|
|
467
565
|
const description = asString(row.description);
|
|
468
566
|
const cover = asString(row.cover) || asString(agent.cover);
|
|
469
567
|
const agentModel = isPlainObject(row.agentModel) ? row.agentModel : undefined;
|
|
470
568
|
const models = selectableModels(row.tokenRates);
|
|
471
|
-
//
|
|
472
|
-
|
|
473
|
-
const
|
|
474
|
-
? new Set(Object.values(row.skillsmeta).filter(isPlainObject)
|
|
475
|
-
.filter(meta => meta.requires_credentials === true)
|
|
476
|
-
.map(meta => asString(meta.credential_key))
|
|
477
|
-
.filter((key) => Boolean(key)))
|
|
478
|
-
: null;
|
|
479
|
-
const packs = Array.isArray(agent.extracreditpacks)
|
|
569
|
+
// Packs are bought only on an active Pro plan, so only that plan lists them.
|
|
570
|
+
const canBuyPacks = summary.tier === 'pro' && summary.subscription?.status === 'active';
|
|
571
|
+
const packs = canBuyPacks && Array.isArray(agent.extracreditpacks)
|
|
480
572
|
? agent.extracreditpacks.filter(isPlainObject).filter(pack => pack.enabled !== false)
|
|
481
573
|
: [];
|
|
482
574
|
return {
|
|
@@ -504,11 +596,8 @@ export function toAgentDetail(row) {
|
|
|
504
596
|
...(models.length > 0 ? { selectableModels: models } : {}),
|
|
505
597
|
enabledCommands: Array.isArray(row.enabledCommands) ? toStringArray(row.enabledCommands) : null,
|
|
506
598
|
credentials,
|
|
507
|
-
// A required sign-in that is not connected also holds back the setup, so it
|
|
508
|
-
// is listed as missing too.
|
|
509
599
|
missingCredentials: credentials
|
|
510
|
-
.filter(credential => credential.requiredMissing
|
|
511
|
-
.filter(credential => !activeKeys || activeKeys.has(credential.key))
|
|
600
|
+
.filter(credential => credential.requiredMissing)
|
|
512
601
|
.map(({ key, title, oauth }) => ({ key, title, oauth })),
|
|
513
602
|
channels,
|
|
514
603
|
scheduledTasks: summarizeTasks(row.scheduledskills),
|
|
@@ -523,41 +612,94 @@ export function toAgentDetail(row) {
|
|
|
523
612
|
dashboardUrl: agentDashboardUrl(summary.guid),
|
|
524
613
|
};
|
|
525
614
|
}
|
|
526
|
-
export function formatSubscriptionLine(subscription) {
|
|
527
|
-
if (!subscription)
|
|
528
|
-
return
|
|
615
|
+
export function formatSubscriptionLine(subscription, plainMember = false) {
|
|
616
|
+
if (!subscription) {
|
|
617
|
+
return plainMember
|
|
618
|
+
? 'No plan. On this team agent, a team admin, the organization\'s owner or the person who deployed it can start one.'
|
|
619
|
+
: 'No plan. manage_agent_billing with action subscribe starts one.';
|
|
620
|
+
}
|
|
529
621
|
const parts = [`${subscription.status}, billed ${subscription.billing === 'wallet' ? 'from the wallet' : 'by card'}`];
|
|
530
|
-
if (subscription.amountUsd !== null)
|
|
531
|
-
parts.push(
|
|
622
|
+
if (subscription.amountUsd !== null) {
|
|
623
|
+
parts.push(subscription.status === 'expired' && subscription.billing === 'wallet'
|
|
624
|
+
? `a renew charges ${formatUsd(subscription.amountUsd)} per 30 days`
|
|
625
|
+
: `${formatUsd(subscription.amountUsd)} per 30 days`);
|
|
626
|
+
}
|
|
532
627
|
if (subscription.periodEndsAt) {
|
|
628
|
+
const atPeriodEnd = subscription.atPeriodEnd ?? (subscription.cancelAtPeriodEnd ? 'ends' : 'renews');
|
|
533
629
|
if (subscription.status !== 'active') {
|
|
534
630
|
parts.push(`period ended ${subscription.periodEndsAt}`);
|
|
535
631
|
}
|
|
632
|
+
else if (atPeriodEnd === 'ends') {
|
|
633
|
+
parts.push(`cancelled, ends after ${subscription.periodEndsAt}`);
|
|
634
|
+
}
|
|
635
|
+
else if (atPeriodEnd === 'renews') {
|
|
636
|
+
parts.push(`renews after ${subscription.periodEndsAt}`);
|
|
637
|
+
}
|
|
536
638
|
else {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
: `renews after ${subscription.periodEndsAt}`);
|
|
639
|
+
// Whether this card plan renews is not known here.
|
|
640
|
+
parts.push(`paid through ${subscription.periodEndsAt}`);
|
|
540
641
|
}
|
|
541
642
|
}
|
|
542
643
|
if (subscription.switchingToWallet)
|
|
543
644
|
parts.push('switching to wallet billing at period end');
|
|
544
645
|
return parts.join(', ');
|
|
545
646
|
}
|
|
546
|
-
|
|
647
|
+
/** Without an active plan, an agent starts only on the extra credits it has left. */
|
|
648
|
+
export function startNeedsPlan(agent) {
|
|
649
|
+
return agent.subscription?.status !== 'active' && agent.credits.extra <= 0;
|
|
650
|
+
}
|
|
651
|
+
/** renew brings back an expired wallet plan; any other agent without an active plan takes a new one. */
|
|
652
|
+
function planActionForStart(agent) {
|
|
653
|
+
return agent.subscription?.status === 'expired' && agent.subscription.billing === 'wallet' ? 'renew' : 'subscribe';
|
|
654
|
+
}
|
|
655
|
+
function noPlanStartHint(agent) {
|
|
656
|
+
return 'It has no active plan and no extra credits left, so it cannot start. '
|
|
657
|
+
+ (planActionForStart(agent) === 'renew'
|
|
658
|
+
? 'Its wallet plan has expired; manage_agent_billing with action renew restarts it.'
|
|
659
|
+
: 'manage_agent_billing with action subscribe pays for a plan and starts the agent.');
|
|
660
|
+
}
|
|
661
|
+
/** An agent's title inside a line of this server's own text: on one line, in a code span it cannot close. */
|
|
662
|
+
export function agentTitleSpan(title) {
|
|
663
|
+
return title.trim() ? quotedSpan(title) : 'Untitled agent';
|
|
664
|
+
}
|
|
665
|
+
export function formatAgentSummaryLines(agent, plainMember = false) {
|
|
547
666
|
const template = agent.template.custom
|
|
548
667
|
? 'custom build'
|
|
549
668
|
: `template ${agent.template.title ?? agent.template.slug ?? agent.template.guid}`;
|
|
669
|
+
const hint = !plainMember && (agent.status === 0 || agent.status === 5) && startNeedsPlan(agent)
|
|
670
|
+
? `${agent.status === 5 ? 'The start failed or the agent stopped unexpectedly.' : 'It is not running.'} ${noPlanStartHint(agent)}`
|
|
671
|
+
: agentStatusHint(agent.status, plainMember);
|
|
550
672
|
return [
|
|
551
|
-
`**Agent:** ${agent.title} (\`${agent.guid}\`), ${template}, ${agent.workspace} workspace`,
|
|
552
|
-
`**Status:** ${describeAgentStatus(agent.status)}. ${
|
|
553
|
-
`**Plan:** ${agent.tier ?? 'no tier'}; ${formatSubscriptionLine(agent.subscription)}`,
|
|
554
|
-
`**Credits:** ${formatCredits(agent.credits.remaining)} left (
|
|
673
|
+
`**Agent:** ${agentTitleSpan(agent.title)} (\`${agent.guid}\`), ${template}, ${agent.workspace} workspace`,
|
|
674
|
+
`**Status:** ${describeAgentStatus(agent.status)}. ${hint}`,
|
|
675
|
+
`**Plan:** ${agent.tier ?? 'no tier'}; ${formatSubscriptionLine(agent.subscription, plainMember)}`,
|
|
676
|
+
`**Credits:** ${formatCredits(agent.credits.remaining)} left (${monthlyCreditsText(agent.credits)}, extra ${formatCredits(agent.credits.extra)}, used ${formatCredits(agent.credits.used)})`,
|
|
555
677
|
];
|
|
556
678
|
}
|
|
557
|
-
|
|
679
|
+
/** Where an entry the list shortens is read in full. */
|
|
680
|
+
function shortenedNote(key) {
|
|
681
|
+
return ` (its text is long; get_my_agent with entry "${key}" shows it in full)`;
|
|
682
|
+
}
|
|
683
|
+
/** A scheduled task as a list line: key, on or off, schedule and description, then shortenedNote if its text was cut. */
|
|
684
|
+
export function formatScheduledTaskLine(task, shortenedNote = '') {
|
|
685
|
+
return `- \`${task.key}\` ${task.enabled ? 'on' : 'off'}${task.notWritten ? ' (its text is not written yet, so it does not run)' : ''}${task.interval ? `, ${task.interval}` : ''}${task.description ? `: ${quotedSpan(task.description)}` : ''}${task.instructionsTruncated ? shortenedNote : ''}`;
|
|
686
|
+
}
|
|
687
|
+
/** A custom instruction as a list line: key, on or off and description, then shortenedNote if its text was cut. */
|
|
688
|
+
export function formatCustomInstructionLine(task, shortenedNote = '') {
|
|
689
|
+
return `- \`${task.key}\` ${task.enabled ? 'on' : 'off'}${task.description ? `: ${quotedSpan(task.description)}` : ''}${task.instructionsTruncated ? shortenedNote : ''}`;
|
|
690
|
+
}
|
|
558
691
|
function formatRate(credits) {
|
|
559
692
|
return credits.toLocaleString('en-US', { maximumFractionDigits: 3 });
|
|
560
693
|
}
|
|
694
|
+
/** Each model with its credits per 1M input and output tokens, separated by semicolons. */
|
|
695
|
+
export function formatModelRates(models) {
|
|
696
|
+
return models.map(model => {
|
|
697
|
+
const name = model.label ? `${model.label} (${model.slug})` : model.slug;
|
|
698
|
+
return model.inputCreditsPer1M !== undefined && model.outputCreditsPer1M !== undefined
|
|
699
|
+
? `${name} ${formatRate(model.inputCreditsPer1M)} and ${formatRate(model.outputCreditsPer1M)}`
|
|
700
|
+
: `${name} rate unknown`;
|
|
701
|
+
}).join('; ');
|
|
702
|
+
}
|
|
561
703
|
/** The chat and scheduled-task models, then every model the agent can switch to with its rates. */
|
|
562
704
|
function formatModelsLine(agent) {
|
|
563
705
|
const choices = agent.selectableModels ?? [];
|
|
@@ -566,22 +708,19 @@ function formatModelsLine(agent) {
|
|
|
566
708
|
if (agent.models)
|
|
567
709
|
parts.push(`chat ${nameOf(agent.models.chat)}, scheduled tasks ${nameOf(agent.models.cron)}.`);
|
|
568
710
|
if (choices.length > 0) {
|
|
569
|
-
|
|
570
|
-
const name = model.label ? `${model.label} (${model.slug})` : model.slug;
|
|
571
|
-
return model.inputCreditsPer1M !== undefined && model.outputCreditsPer1M !== undefined
|
|
572
|
-
? `${name} ${formatRate(model.inputCreditsPer1M)} and ${formatRate(model.outputCreditsPer1M)}`
|
|
573
|
-
: `${name} rate unknown`;
|
|
574
|
-
});
|
|
575
|
-
parts.push(`Models you can switch to, in credits per 1M input and output tokens: ${rates.join('; ')}.`);
|
|
711
|
+
parts.push(`Models you can switch to, in credits per 1M input and output tokens: ${formatModelRates(choices)}.`);
|
|
576
712
|
}
|
|
577
713
|
return parts.length > 0 ? `**Models:** ${parts.join(' ')}` : null;
|
|
578
714
|
}
|
|
579
|
-
export function formatAgentDetail(agent) {
|
|
580
|
-
const lines = formatAgentSummaryLines(agent);
|
|
715
|
+
export function formatAgentDetail(agent, plainMember = false) {
|
|
716
|
+
const lines = formatAgentSummaryLines(agent, plainMember);
|
|
717
|
+
if (agent.lastActivityAt)
|
|
718
|
+
lines.push(`**Last activity:** ${agent.lastActivityAt}`);
|
|
581
719
|
if (agent.pricing) {
|
|
582
|
-
//
|
|
720
|
+
// Today's Starter and Pro prices for this agent's own skills, which can
|
|
721
|
+
// differ from its template's and from the price its plan pays.
|
|
583
722
|
const { starter, pro } = agent.pricing;
|
|
584
|
-
lines.push(`**Prices now:** Starter ${formatUsd(starter.priceUsd)} per 30 days with ${formatCredits(starter.monthlyCredits)} credits per month; Pro ${formatUsd(pro.priceUsd)} per 30 days with ${formatCredits(pro.monthlyCredits)} credits per month. A new plan or an upgrade uses these.`);
|
|
723
|
+
lines.push(`**Prices now:** Starter ${formatUsd(starter.priceUsd)} per 30 days with ${formatCredits(starter.monthlyCredits)} credits per month; Pro ${formatUsd(pro.priceUsd)} per 30 days with ${formatCredits(pro.monthlyCredits)} credits per month. A new plan or an upgrade uses these, and a skill change moves the plan to today's prices for all its skills.`);
|
|
585
724
|
}
|
|
586
725
|
const models = formatModelsLine(agent);
|
|
587
726
|
if (models)
|
|
@@ -604,25 +743,23 @@ export function formatAgentDetail(agent) {
|
|
|
604
743
|
for (const credential of agent.credentials) {
|
|
605
744
|
const state = credential.connected
|
|
606
745
|
? 'connected'
|
|
607
|
-
: credential.
|
|
608
|
-
? '
|
|
609
|
-
: credential.
|
|
610
|
-
? '
|
|
746
|
+
: credential.requiredMissing
|
|
747
|
+
? (credential.oauth ? 'not connected (required)' : 'missing (required)')
|
|
748
|
+
: credential.filled
|
|
749
|
+
? 'filled'
|
|
611
750
|
: 'not set';
|
|
612
751
|
lines.push(`- ${credential.title} (\`${credential.key}\`): ${state}${credential.optional ? ', optional' : ''}`);
|
|
613
752
|
}
|
|
614
753
|
}
|
|
615
754
|
if (agent.scheduledTasks.length > 0) {
|
|
616
755
|
lines.push('', '### Scheduled tasks', '');
|
|
617
|
-
for (const task of agent.scheduledTasks)
|
|
618
|
-
lines.push(
|
|
619
|
-
}
|
|
756
|
+
for (const task of agent.scheduledTasks)
|
|
757
|
+
lines.push(formatScheduledTaskLine(task, shortenedNote(task.key)));
|
|
620
758
|
}
|
|
621
759
|
if (agent.customInstructions.length > 0) {
|
|
622
760
|
lines.push('', '### Custom instructions', '');
|
|
623
|
-
for (const task of agent.customInstructions)
|
|
624
|
-
lines.push(
|
|
625
|
-
}
|
|
761
|
+
for (const task of agent.customInstructions)
|
|
762
|
+
lines.push(formatCustomInstructionLine(task, shortenedNote(task.key)));
|
|
626
763
|
}
|
|
627
764
|
lines.push('', `Dashboard: ${agent.dashboardUrl}`);
|
|
628
765
|
return lines.join('\n');
|
|
@@ -661,12 +798,12 @@ const GUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{
|
|
|
661
798
|
export function isGuid(value) {
|
|
662
799
|
return GUID_PATTERN.test(value.trim());
|
|
663
800
|
}
|
|
664
|
-
/**
|
|
801
|
+
/** Reads one agent's Detail row; tool results are built from it with toAgentDetail or toAgentSummary. */
|
|
665
802
|
export async function readAgentDetail(client, guid, signal) {
|
|
666
803
|
const body = requireApiSuccess(await client.post('/UserAgent/Detail', { guid }, signal), 'The agent could not be read.');
|
|
667
804
|
const rows = Array.isArray(body.useragents) ? body.useragents.filter(isPlainObject) : [];
|
|
668
805
|
if (!rows[0])
|
|
669
|
-
throw new Error(
|
|
806
|
+
throw new Error(AGENT_NOT_FOUND_TEXT);
|
|
670
807
|
return rows[0];
|
|
671
808
|
}
|
|
672
809
|
// Every Detail read prices the agent, so polling stays slower than for tasks.
|
|
@@ -685,16 +822,30 @@ export async function waitForAgentToSettle(client, guid, waitSeconds, extra, fal
|
|
|
685
822
|
});
|
|
686
823
|
return {
|
|
687
824
|
row: result.value ?? fallbackRow,
|
|
825
|
+
fresh: result.value !== undefined,
|
|
688
826
|
settled: result.done,
|
|
689
827
|
elapsedMs: result.elapsedMs,
|
|
690
828
|
};
|
|
691
829
|
}
|
|
830
|
+
/** The credential that holds the Wiro project an agent runs models with. */
|
|
831
|
+
export const WIRO_PROJECT_CREDENTIAL = 'wiro';
|
|
832
|
+
/** The call that connects a Wiro project to an agent. It shows the project first; lead says why it comes now. */
|
|
833
|
+
export function bindProjectStep(agentGuid, lead) {
|
|
834
|
+
return {
|
|
835
|
+
tool: 'bind_agent_project',
|
|
836
|
+
arguments: { agent_guid: agentGuid },
|
|
837
|
+
reason: `${lead} This shows the project first and changes nothing without confirm: true, and no key is needed.`,
|
|
838
|
+
};
|
|
839
|
+
}
|
|
692
840
|
/** The call that starts on the first missing credential, with every argument it needs. */
|
|
693
841
|
export function missingCredentialStep(agent) {
|
|
694
842
|
const missing = agent.missingCredentials[0];
|
|
695
843
|
if (!missing)
|
|
696
844
|
return undefined;
|
|
697
845
|
const keys = agent.missingCredentials.map(item => item.key).join(', ');
|
|
846
|
+
if (missing.key === WIRO_PROJECT_CREDENTIAL) {
|
|
847
|
+
return bindProjectStep(agent.guid, `Provide the missing credentials (${keys}), starting with ${missing.title}.`);
|
|
848
|
+
}
|
|
698
849
|
return missing.oauth
|
|
699
850
|
? {
|
|
700
851
|
tool: 'connect_agent_oauth',
|
|
@@ -707,8 +858,21 @@ export function missingCredentialStep(agent) {
|
|
|
707
858
|
reason: `Provide the missing credentials (${keys}). This lists the ${missing.title} fields to ask the user for.`,
|
|
708
859
|
};
|
|
709
860
|
}
|
|
710
|
-
/**
|
|
711
|
-
|
|
861
|
+
/**
|
|
862
|
+
* The most useful next call for an agent in this state, if any. For a team
|
|
863
|
+
* member without admin rights it is only the wait for a status that moves on
|
|
864
|
+
* by itself.
|
|
865
|
+
*/
|
|
866
|
+
export function nextStepForAgent(agent, waitSeconds, plainMember = false) {
|
|
867
|
+
const wait = isTransitionalStatus(agent.status)
|
|
868
|
+
? {
|
|
869
|
+
tool: 'get_my_agent',
|
|
870
|
+
arguments: { agent_guid: agent.guid, wait_seconds: waitSeconds },
|
|
871
|
+
reason: 'Wait until the agent has settled. Do not repeat the action that started it.',
|
|
872
|
+
}
|
|
873
|
+
: undefined;
|
|
874
|
+
if (plainMember)
|
|
875
|
+
return wait;
|
|
712
876
|
if (agent.status === 6 && agent.subscription?.status !== 'active') {
|
|
713
877
|
return {
|
|
714
878
|
tool: 'manage_agent_billing',
|
|
@@ -719,11 +883,13 @@ export function nextStepForAgent(agent, waitSeconds) {
|
|
|
719
883
|
const missing = agent.missingCredentials[0];
|
|
720
884
|
if (missing)
|
|
721
885
|
return missingCredentialStep(agent);
|
|
722
|
-
if (
|
|
886
|
+
if (wait)
|
|
887
|
+
return wait;
|
|
888
|
+
if ((agent.status === 0 || agent.status === 5) && startNeedsPlan(agent)) {
|
|
723
889
|
return {
|
|
724
|
-
tool: '
|
|
725
|
-
arguments: { agent_guid: agent.guid,
|
|
726
|
-
reason: '
|
|
890
|
+
tool: 'manage_agent_billing',
|
|
891
|
+
arguments: { agent_guid: agent.guid, action: planActionForStart(agent) },
|
|
892
|
+
reason: 'The agent has no active plan and no extra credits left, so it cannot start. This returns the price; nothing is charged without confirm: true.',
|
|
727
893
|
};
|
|
728
894
|
}
|
|
729
895
|
if (agent.status === 0 || agent.status === 5) {
|
|
@@ -735,13 +901,18 @@ export function nextStepForAgent(agent, waitSeconds) {
|
|
|
735
901
|
}
|
|
736
902
|
return undefined;
|
|
737
903
|
}
|
|
738
|
-
// Refusals
|
|
739
|
-
// everything it wrote. Only these are known to come before any charge, so any
|
|
740
|
-
// other result:false answer to a paid call leaves the outcome open.
|
|
904
|
+
// Refusals known to leave the wallet untouched.
|
|
741
905
|
const PRE_CHARGE_CODES = new Set([95, 96, 97, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109]);
|
|
906
|
+
const WALLET_NOT_READ = /could not retrieve wallet balance/i;
|
|
907
|
+
/** Whether a refusal says the wallet could not be read, which says nothing about what it holds. */
|
|
908
|
+
export function isWalletNotRead(error) {
|
|
909
|
+
return error instanceof ApiResultError && WALLET_NOT_READ.test(error.message);
|
|
910
|
+
}
|
|
911
|
+
/** The words after such a refusal. No funds are asked for: the wallet may hold plenty. */
|
|
912
|
+
export const WALLET_NOT_READ_NOTE = 'Wiro could not read the balance just now. That is not a low balance, and nothing was charged. Try again in a moment; if it keeps saying so, get_account shows the wallet.';
|
|
742
913
|
const PRE_CHARGE_REFUSALS = [
|
|
743
914
|
/insufficient wallet balance/i,
|
|
744
|
-
|
|
915
|
+
WALLET_NOT_READ,
|
|
745
916
|
/wallet deduction failed/i,
|
|
746
917
|
/subscription (is )?already active/i,
|
|
747
918
|
/already on (the )?(pro|starter) tier/i,
|
|
@@ -758,11 +929,14 @@ const PRE_CHARGE_REFUSALS = [
|
|
|
758
929
|
/switch to (the )?(team|personal) context|belongs to a different team/i,
|
|
759
930
|
/^request parameter \[/i,
|
|
760
931
|
/mutually exclusive|agent terms acceptance|customskills must be|skill key may only contain/i,
|
|
932
|
+
/^unknown skill: /i,
|
|
933
|
+
/^the tier change could not be saved\./i,
|
|
934
|
+
/^we couldn't (schedule|undo) the cancellation\./i,
|
|
761
935
|
/enabledchannels is not accepted|credentials must be an object|credential field|is missing required fields/i,
|
|
762
936
|
/chat mode is not accepted|is managed by (wiro|the connection flow)|^agent-[a-z-]+$/i,
|
|
763
937
|
/^failed to deploy agent|failed to save communication channel settings|failed to save custom skill/i,
|
|
764
938
|
];
|
|
765
|
-
/** Whether a result:false answer is one
|
|
939
|
+
/** Whether a result:false answer is one of the refusals known to leave the wallet untouched. */
|
|
766
940
|
export function isPreChargeRefusal(error) {
|
|
767
941
|
if (!(error instanceof ApiResultError))
|
|
768
942
|
return false;
|
|
@@ -770,22 +944,51 @@ export function isPreChargeRefusal(error) {
|
|
|
770
944
|
return true;
|
|
771
945
|
return PRE_CHARGE_REFUSALS.some(pattern => pattern.test(error.message.trim()));
|
|
772
946
|
}
|
|
947
|
+
const CHARGED_START = 'The wallet was charged ';
|
|
948
|
+
const CHARGED_END = /, but the (tier change|renewal) did not finish\. Please contact support and do not try again\.$/;
|
|
949
|
+
/**
|
|
950
|
+
* Whether a result:false answer says what the wallet paid. Its sentence is the
|
|
951
|
+
* whole outcome: it is shown as it is, and the call is not repeated.
|
|
952
|
+
*/
|
|
953
|
+
export function isKnownPaidOutcome(error) {
|
|
954
|
+
if (!(error instanceof ApiResultError))
|
|
955
|
+
return false;
|
|
956
|
+
const message = error.message.trim();
|
|
957
|
+
return message.startsWith(CHARGED_START) && CHARGED_END.test(message);
|
|
958
|
+
}
|
|
959
|
+
/**
|
|
960
|
+
* Whether a result:false answer carries code 110. Its answer is the whole outcome:
|
|
961
|
+
* the change is reported as failed, what the agent and the wallet show is read by
|
|
962
|
+
* hand, and the call is not repeated.
|
|
963
|
+
*/
|
|
964
|
+
export function isKnownFailedChange(error) {
|
|
965
|
+
return error instanceof ApiResultError && error.codes.some(code => Number(code) === 110);
|
|
966
|
+
}
|
|
773
967
|
/**
|
|
774
968
|
* After a paid request was sent, whether it may still have gone through.
|
|
775
|
-
* Only the known refusals
|
|
776
|
-
*
|
|
777
|
-
* leaves it open.
|
|
969
|
+
* Only the known refusals, an answer that says what the wallet paid or carries
|
|
970
|
+
* code 110, and client errors (other than a timeout or rate limit) settle it; any
|
|
971
|
+
* other answer, a network failure or a server error leaves it open.
|
|
778
972
|
*/
|
|
779
973
|
export function outcomeUnknown(error) {
|
|
780
974
|
if (error instanceof ApiResultError)
|
|
781
|
-
return !isPreChargeRefusal(error);
|
|
975
|
+
return !isPreChargeRefusal(error) && !isKnownPaidOutcome(error) && !isKnownFailedChange(error);
|
|
782
976
|
if (error instanceof WiroApiError) {
|
|
783
977
|
return error.status >= 500 || error.status === 408 || error.status === 429;
|
|
784
978
|
}
|
|
785
979
|
return true;
|
|
786
980
|
}
|
|
787
|
-
/** Advice for a status reached after a start, renew or deploy. */
|
|
788
|
-
export function settledStatusAdvice(status) {
|
|
981
|
+
/** Advice for a status reached after a start, renew or deploy. With the agent, a failed agent without a plan or extra credits is sent to billing. */
|
|
982
|
+
export function settledStatusAdvice(status, plainMember = false, agent) {
|
|
983
|
+
if (!plainMember && agent && status === 5 && startNeedsPlan(agent)) {
|
|
984
|
+
return `The agent failed to start. ${noPlanStartHint(agent)}`;
|
|
985
|
+
}
|
|
986
|
+
if (plainMember && status === 5) {
|
|
987
|
+
return `The agent failed to start. On this team agent, ${TEAM_AGENT_MANAGERS} can start it again and read its logs.`;
|
|
988
|
+
}
|
|
989
|
+
if (plainMember && status === 6) {
|
|
990
|
+
return `The agent needs setup: it has no paid plan, or required credentials are missing. ${MEMBER_SETUP_HELP}`;
|
|
991
|
+
}
|
|
789
992
|
switch (status) {
|
|
790
993
|
case 4:
|
|
791
994
|
return 'The agent is running. send_agent_message with agent set to its guid talks to it.';
|
|
@@ -796,7 +999,17 @@ export function settledStatusAdvice(status) {
|
|
|
796
999
|
case 6:
|
|
797
1000
|
return 'The agent needs setup: it has no paid plan, or required credentials are missing.';
|
|
798
1001
|
default:
|
|
799
|
-
return agentStatusHint(status);
|
|
1002
|
+
return agentStatusHint(status, plainMember);
|
|
800
1003
|
}
|
|
801
1004
|
}
|
|
1005
|
+
/** Advice for a read, which cannot tell whether a start came first: a stopped agent gets what holds now. */
|
|
1006
|
+
export function readStatusAdvice(agent, plainMember = false) {
|
|
1007
|
+
if (agent.status !== 0)
|
|
1008
|
+
return settledStatusAdvice(agent.status, plainMember, agent);
|
|
1009
|
+
if (plainMember)
|
|
1010
|
+
return `The agent is stopped. On this team agent, ${TEAM_AGENT_MANAGERS} can start it.`;
|
|
1011
|
+
return startNeedsPlan(agent)
|
|
1012
|
+
? `The agent is stopped. ${noPlanStartHint(agent)}`
|
|
1013
|
+
: 'The agent is stopped. control_agent with action start starts it.';
|
|
1014
|
+
}
|
|
802
1015
|
//# sourceMappingURL=user-agent.js.map
|