skedyul 1.7.30 → 1.7.31
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 +2 -2
- package/dist/.build-stamp +1 -1
- package/dist/cli/index.js +476 -65
- package/dist/config/app-config.d.ts +1 -1
- package/dist/config/types/form.d.ts +13 -1
- package/dist/dedicated/server.js +149 -0
- package/dist/errors.d.ts +18 -0
- package/dist/esm/index.mjs +308 -22
- package/dist/index.d.ts +1 -1
- package/dist/index.js +310 -22
- package/dist/schemas/agent-schema-v3.d.ts +197 -0
- package/dist/schemas/agent-schema-v3.js +152 -22
- package/dist/schemas/agent-schema-v3.mjs +149 -22
- package/dist/schemas/agent-schema.d.ts +2 -2
- package/dist/server/handlers/index.d.ts +1 -0
- package/dist/server/handlers/refresh-token-handler.d.ts +13 -0
- package/dist/server/route-handlers/handlers.d.ts +4 -0
- package/dist/server/route-handlers/index.d.ts +1 -1
- package/dist/server.js +149 -0
- package/dist/serverless/server.mjs +149 -0
- package/dist/skills/types.d.ts +2 -0
- package/dist/skills/types.js +20 -6
- package/dist/skills/types.mjs +20 -6
- package/dist/types/handlers.d.ts +28 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/invocation.d.ts +2 -2
- package/dist/types/tool-response.d.ts +12 -0
- package/dist/types/tool.d.ts +1 -1
- package/package.json +2 -2
package/dist/cli/index.js
CHANGED
|
@@ -3646,6 +3646,14 @@ var AppAuthInvalidError = class extends Error {
|
|
|
3646
3646
|
this.name = "AppAuthInvalidError";
|
|
3647
3647
|
}
|
|
3648
3648
|
};
|
|
3649
|
+
var TokenRefreshRequiredError = class extends Error {
|
|
3650
|
+
constructor(message = "Access token expired", options) {
|
|
3651
|
+
super(message);
|
|
3652
|
+
this.code = "TOKEN_REFRESH_REQUIRED";
|
|
3653
|
+
this.name = "TokenRefreshRequiredError";
|
|
3654
|
+
this.tokenKey = options?.tokenKey;
|
|
3655
|
+
}
|
|
3656
|
+
};
|
|
3649
3657
|
|
|
3650
3658
|
// src/ratelimit/errors.ts
|
|
3651
3659
|
var RateLimitExceededError = class extends Error {
|
|
@@ -3961,6 +3969,24 @@ function createCallToolHandler(registry, state, onMaxRequests) {
|
|
|
3961
3969
|
}
|
|
3962
3970
|
};
|
|
3963
3971
|
}
|
|
3972
|
+
if (error instanceof TokenRefreshRequiredError) {
|
|
3973
|
+
return {
|
|
3974
|
+
success: false,
|
|
3975
|
+
output: null,
|
|
3976
|
+
billing: { credits: 0 },
|
|
3977
|
+
meta: {
|
|
3978
|
+
success: false,
|
|
3979
|
+
message: error.message,
|
|
3980
|
+
toolName
|
|
3981
|
+
},
|
|
3982
|
+
error: {
|
|
3983
|
+
code: error.code,
|
|
3984
|
+
message: error.message,
|
|
3985
|
+
category: "auth",
|
|
3986
|
+
...error.tokenKey ? { details: { tokenKey: error.tokenKey } } : {}
|
|
3987
|
+
}
|
|
3988
|
+
};
|
|
3989
|
+
}
|
|
3964
3990
|
if (error instanceof AppAuthInvalidError) {
|
|
3965
3991
|
return {
|
|
3966
3992
|
output: null,
|
|
@@ -4714,6 +4740,76 @@ async function handleOAuthCallback(parsedBody, hooks) {
|
|
|
4714
4740
|
}
|
|
4715
4741
|
}
|
|
4716
4742
|
|
|
4743
|
+
// src/server/handlers/refresh-token-handler.ts
|
|
4744
|
+
async function handleRefreshToken(parsedBody, hooks) {
|
|
4745
|
+
if (!hooks?.refresh_token) {
|
|
4746
|
+
return {
|
|
4747
|
+
status: 404,
|
|
4748
|
+
body: { error: "Refresh token handler not configured" }
|
|
4749
|
+
};
|
|
4750
|
+
}
|
|
4751
|
+
const body = parsedBody ?? {};
|
|
4752
|
+
if (!body.env || typeof body.env !== "object" || Array.isArray(body.env)) {
|
|
4753
|
+
return {
|
|
4754
|
+
status: 400,
|
|
4755
|
+
body: {
|
|
4756
|
+
error: {
|
|
4757
|
+
code: -32602,
|
|
4758
|
+
message: "Missing envelope format: expected { env }"
|
|
4759
|
+
}
|
|
4760
|
+
}
|
|
4761
|
+
};
|
|
4762
|
+
}
|
|
4763
|
+
const refreshContext = {
|
|
4764
|
+
env: body.env,
|
|
4765
|
+
invocation: body.invocation,
|
|
4766
|
+
log: createContextLogger()
|
|
4767
|
+
};
|
|
4768
|
+
const requestConfig = {
|
|
4769
|
+
baseUrl: body.env.SKEDYUL_API_URL ?? process.env.SKEDYUL_API_URL ?? "",
|
|
4770
|
+
apiToken: body.env.SKEDYUL_API_TOKEN ?? process.env.SKEDYUL_API_TOKEN ?? ""
|
|
4771
|
+
};
|
|
4772
|
+
try {
|
|
4773
|
+
const refreshHook = hooks.refresh_token;
|
|
4774
|
+
const refreshHandler = typeof refreshHook === "function" ? refreshHook : refreshHook.handler;
|
|
4775
|
+
const result = await withRequestEnv(body.env, async () => {
|
|
4776
|
+
return await runWithConfig(requestConfig, async () => {
|
|
4777
|
+
return await runWithLogContext({ invocation: body.invocation }, async () => {
|
|
4778
|
+
return await refreshHandler(refreshContext);
|
|
4779
|
+
});
|
|
4780
|
+
});
|
|
4781
|
+
});
|
|
4782
|
+
return {
|
|
4783
|
+
status: 200,
|
|
4784
|
+
body: {
|
|
4785
|
+
env: result.env ?? {}
|
|
4786
|
+
}
|
|
4787
|
+
};
|
|
4788
|
+
} catch (err) {
|
|
4789
|
+
if (err instanceof AppAuthInvalidError) {
|
|
4790
|
+
return {
|
|
4791
|
+
status: 401,
|
|
4792
|
+
body: {
|
|
4793
|
+
error: {
|
|
4794
|
+
code: err.code,
|
|
4795
|
+
message: err.message
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4798
|
+
};
|
|
4799
|
+
}
|
|
4800
|
+
const errorMessage = err instanceof Error ? err.message : String(err ?? "Unknown error");
|
|
4801
|
+
return {
|
|
4802
|
+
status: 500,
|
|
4803
|
+
body: {
|
|
4804
|
+
error: {
|
|
4805
|
+
code: -32603,
|
|
4806
|
+
message: errorMessage
|
|
4807
|
+
}
|
|
4808
|
+
}
|
|
4809
|
+
};
|
|
4810
|
+
}
|
|
4811
|
+
}
|
|
4812
|
+
|
|
4717
4813
|
// src/types/webhook.ts
|
|
4718
4814
|
function isRuntimeWebhookContext(ctx) {
|
|
4719
4815
|
return "appInstallationId" in ctx && ctx.appInstallationId !== void 0;
|
|
@@ -4817,6 +4913,33 @@ async function executeWebhookHandler(handle, webhookRegistry, data) {
|
|
|
4817
4913
|
});
|
|
4818
4914
|
});
|
|
4819
4915
|
} catch (err) {
|
|
4916
|
+
if (err instanceof TokenRefreshRequiredError) {
|
|
4917
|
+
return {
|
|
4918
|
+
status: 200,
|
|
4919
|
+
body: {
|
|
4920
|
+
success: false,
|
|
4921
|
+
error: {
|
|
4922
|
+
code: err.code,
|
|
4923
|
+
message: err.message,
|
|
4924
|
+
category: "auth",
|
|
4925
|
+
...err.tokenKey ? { details: { tokenKey: err.tokenKey } } : {}
|
|
4926
|
+
}
|
|
4927
|
+
}
|
|
4928
|
+
};
|
|
4929
|
+
}
|
|
4930
|
+
if (err instanceof AppAuthInvalidError) {
|
|
4931
|
+
return {
|
|
4932
|
+
status: 200,
|
|
4933
|
+
body: {
|
|
4934
|
+
success: false,
|
|
4935
|
+
error: {
|
|
4936
|
+
code: err.code,
|
|
4937
|
+
message: err.message,
|
|
4938
|
+
category: "auth"
|
|
4939
|
+
}
|
|
4940
|
+
}
|
|
4941
|
+
};
|
|
4942
|
+
}
|
|
4820
4943
|
console.error(`Webhook handler '${handle}' error:`, err);
|
|
4821
4944
|
return {
|
|
4822
4945
|
status: 500,
|
|
@@ -5019,6 +5142,14 @@ async function handleOAuthCallbackRoute(req, ctx) {
|
|
|
5019
5142
|
const result = await handleOAuthCallback(parseResult.data, ctx.config.hooks);
|
|
5020
5143
|
return { status: result.status, body: result.body };
|
|
5021
5144
|
}
|
|
5145
|
+
async function handleRefreshTokenRoute(req, ctx) {
|
|
5146
|
+
const parseResult = parseJsonBody(req);
|
|
5147
|
+
if (!parseResult.success) {
|
|
5148
|
+
return parseResult.error;
|
|
5149
|
+
}
|
|
5150
|
+
const result = await handleRefreshToken(parseResult.data, ctx.config.hooks);
|
|
5151
|
+
return { status: result.status, body: result.body };
|
|
5152
|
+
}
|
|
5022
5153
|
async function handleWebhookRoute(req, handle, ctx) {
|
|
5023
5154
|
if (!ctx.webhookRegistry) {
|
|
5024
5155
|
return { status: 404, body: { error: `Webhook handler '${handle}' not found` } };
|
|
@@ -5510,6 +5641,21 @@ async function handleBatchOperationRoute(req, ctx) {
|
|
|
5510
5641
|
{ allowed: true, afterMs: err.retryAfterMs }
|
|
5511
5642
|
);
|
|
5512
5643
|
}
|
|
5644
|
+
if (err instanceof TokenRefreshRequiredError) {
|
|
5645
|
+
return softFailureResponse({
|
|
5646
|
+
code: err.code,
|
|
5647
|
+
message: err.message,
|
|
5648
|
+
category: "auth",
|
|
5649
|
+
...err.tokenKey ? { details: { tokenKey: err.tokenKey } } : {}
|
|
5650
|
+
});
|
|
5651
|
+
}
|
|
5652
|
+
if (err instanceof AppAuthInvalidError) {
|
|
5653
|
+
return softFailureResponse({
|
|
5654
|
+
code: err.code,
|
|
5655
|
+
message: err.message,
|
|
5656
|
+
category: "auth"
|
|
5657
|
+
});
|
|
5658
|
+
}
|
|
5513
5659
|
log.error("Batch operation failed", err);
|
|
5514
5660
|
return {
|
|
5515
5661
|
status: 500,
|
|
@@ -5594,6 +5740,9 @@ async function routeRequest(req, ctx) {
|
|
|
5594
5740
|
if (req.path === "/oauth_callback" && req.method === "POST") {
|
|
5595
5741
|
return handleOAuthCallbackRoute(req, ctx);
|
|
5596
5742
|
}
|
|
5743
|
+
if (req.path === "/refresh_token" && req.method === "POST") {
|
|
5744
|
+
return handleRefreshTokenRoute(req, ctx);
|
|
5745
|
+
}
|
|
5597
5746
|
if (req.path === "/health" && req.method === "GET") {
|
|
5598
5747
|
return handleHealthRoute(ctx);
|
|
5599
5748
|
}
|
|
@@ -10632,7 +10781,16 @@ var SkillYAMLSchema = import_v47.z.object({
|
|
|
10632
10781
|
tools: SkillToolsSchema.optional(),
|
|
10633
10782
|
// CRM context - specifies which models/fields to include in schema
|
|
10634
10783
|
crmContext: CRMContextSchema.optional(),
|
|
10784
|
+
/**
|
|
10785
|
+
* Entity field handles this skill is allowed to write while loaded.
|
|
10786
|
+
* Writing outside this list is reported as an unowned write.
|
|
10787
|
+
*/
|
|
10635
10788
|
ownedFields: import_v47.z.array(import_v47.z.string()).optional(),
|
|
10789
|
+
/**
|
|
10790
|
+
* Entity field handles this skill must have written before it replies.
|
|
10791
|
+
* Only handles mapped in the install's AppCrmMap are enforced.
|
|
10792
|
+
*/
|
|
10793
|
+
requiredWrites: import_v47.z.array(import_v47.z.string()).optional(),
|
|
10636
10794
|
// Quality evaluators owned by this skill
|
|
10637
10795
|
evaluators: import_v47.z.array(SkillEvaluatorSchema).optional(),
|
|
10638
10796
|
// Few-shot examples
|
|
@@ -10649,6 +10807,7 @@ var SkillYAMLV2Schema = import_v47.z.object({
|
|
|
10649
10807
|
tools: import_v47.z.array(SkillToolDefinitionSchema).optional(),
|
|
10650
10808
|
crmContext: CRMContextSchema.optional(),
|
|
10651
10809
|
ownedFields: import_v47.z.array(import_v47.z.string()).optional(),
|
|
10810
|
+
requiredWrites: import_v47.z.array(import_v47.z.string()).optional(),
|
|
10652
10811
|
evaluators: import_v47.z.array(SkillEvaluatorSchema).optional(),
|
|
10653
10812
|
examples: import_v47.z.array(SkillExampleSchema).optional()
|
|
10654
10813
|
});
|
|
@@ -10664,8 +10823,8 @@ var SkillRefSchema = import_v47.z.union([
|
|
|
10664
10823
|
description: import_v47.z.string().optional(),
|
|
10665
10824
|
// For AI SDK Agent Skills discovery
|
|
10666
10825
|
/**
|
|
10667
|
-
*
|
|
10668
|
-
*
|
|
10826
|
+
* Pre-seed this skill as loaded before the first model step, so the agent
|
|
10827
|
+
* does not have to call system:skill:load for it.
|
|
10669
10828
|
*/
|
|
10670
10829
|
alwaysLoad: import_v47.z.boolean().optional(),
|
|
10671
10830
|
// Version selection (pick one):
|
|
@@ -10673,10 +10832,14 @@ var SkillRefSchema = import_v47.z.union([
|
|
|
10673
10832
|
// Pin to specific version number
|
|
10674
10833
|
versions: import_v47.z.array(SkillVersionWeightSchema).optional(),
|
|
10675
10834
|
// A/B testing weights
|
|
10676
|
-
|
|
10677
|
-
|
|
10678
|
-
|
|
10679
|
-
|
|
10835
|
+
/**
|
|
10836
|
+
* @deprecated Not implemented. Instructions come from the skill file.
|
|
10837
|
+
*/
|
|
10838
|
+
instructions: import_v47.z.string().optional().describe("Not implemented"),
|
|
10839
|
+
/**
|
|
10840
|
+
* @deprecated Not implemented. Remove the skill from `skills` instead.
|
|
10841
|
+
*/
|
|
10842
|
+
enabled: import_v47.z.boolean().optional().describe("Not implemented")
|
|
10680
10843
|
})
|
|
10681
10844
|
]);
|
|
10682
10845
|
var SkillMetadataSchema = import_v47.z.object({
|
|
@@ -10795,7 +10958,11 @@ var ContextValidationResultSchema = import_v48.z.object({
|
|
|
10795
10958
|
issues: import_v48.z.array(ContextIssueSchema)
|
|
10796
10959
|
});
|
|
10797
10960
|
var SandboxConfigSchema = import_v48.z.object({
|
|
10798
|
-
|
|
10961
|
+
/**
|
|
10962
|
+
* @deprecated Not implemented. Sandbox mode is chosen by the caller
|
|
10963
|
+
* (playground, scenario replay, CLI), never by the agent file.
|
|
10964
|
+
*/
|
|
10965
|
+
enabled: import_v48.z.boolean().optional().describe("Not implemented"),
|
|
10799
10966
|
/** @deprecated Use 'context' instead of 'mockContext' */
|
|
10800
10967
|
mockContext: AgentContextSchema.optional(),
|
|
10801
10968
|
context: AgentContextSchema.optional()
|
|
@@ -10967,24 +11134,87 @@ var ResponsesBehaviorConfigSchema = import_v49.z.object({
|
|
|
10967
11134
|
* @default false
|
|
10968
11135
|
*/
|
|
10969
11136
|
allowSilent: import_v49.z.boolean().optional(),
|
|
11137
|
+
/**
|
|
11138
|
+
* Strip em dashes, smart quotes and bullet leaders from outbound messages.
|
|
11139
|
+
* @default false
|
|
11140
|
+
*/
|
|
11141
|
+
humanize: import_v49.z.boolean().optional(),
|
|
10970
11142
|
/**
|
|
10971
11143
|
* Message splitting configuration.
|
|
10972
|
-
*
|
|
11144
|
+
* @deprecated Not implemented — accepted but never applied at runtime.
|
|
10973
11145
|
*/
|
|
10974
11146
|
messageSplitting: import_v49.z.object({
|
|
11147
|
+
enabled: import_v49.z.boolean(),
|
|
11148
|
+
prompt: import_v49.z.string().optional()
|
|
11149
|
+
}).optional().describe("Not implemented"),
|
|
11150
|
+
/**
|
|
11151
|
+
* Response gate configuration.
|
|
11152
|
+
* Automatically detects acknowledgment messages and recommends skipping
|
|
11153
|
+
* responses when a scheduled follow-up already exists.
|
|
11154
|
+
*/
|
|
11155
|
+
responseGate: import_v49.z.object({
|
|
10975
11156
|
/**
|
|
10976
|
-
* Whether
|
|
10977
|
-
* When true, the
|
|
10978
|
-
*
|
|
11157
|
+
* Whether the response gate is enabled.
|
|
11158
|
+
* When true, the platform evaluates incoming messages for acknowledgment
|
|
11159
|
+
* patterns and may recommend skipping a response if scheduled follow-ups exist.
|
|
11160
|
+
* @default true (when allowSilent is true)
|
|
10979
11161
|
*/
|
|
10980
|
-
enabled: import_v49.z.boolean(),
|
|
11162
|
+
enabled: import_v49.z.boolean().optional(),
|
|
10981
11163
|
/**
|
|
10982
|
-
*
|
|
10983
|
-
*
|
|
11164
|
+
* Whether to hard-block sends when gate recommends skip.
|
|
11165
|
+
* When true, system:message:send is blocked unless overrideGate is provided.
|
|
11166
|
+
* When false (default), returns an error encouraging skip but allows override.
|
|
11167
|
+
* @default false
|
|
10984
11168
|
*/
|
|
10985
|
-
|
|
11169
|
+
strictMode: import_v49.z.boolean().optional(),
|
|
11170
|
+
/**
|
|
11171
|
+
* Minimum confidence threshold for acknowledgment detection.
|
|
11172
|
+
* Only recommend skip when confidence meets this threshold.
|
|
11173
|
+
* @default 0.7
|
|
11174
|
+
*/
|
|
11175
|
+
minAckConfidence: import_v49.z.number().min(0).max(1).optional()
|
|
10986
11176
|
}).optional()
|
|
10987
11177
|
});
|
|
11178
|
+
var ConversationPolicyLevelSchema = import_v49.z.enum(["off", "prompt", "reject"]);
|
|
11179
|
+
var ConversationBehaviorConfigSchema = import_v49.z.object({
|
|
11180
|
+
/** Do not re-ask something the customer already answered. */
|
|
11181
|
+
repeatQuestions: ConversationPolicyLevelSchema.optional(),
|
|
11182
|
+
/** Do not send skill example wording verbatim. */
|
|
11183
|
+
exampleCopy: ConversationPolicyLevelSchema.optional(),
|
|
11184
|
+
/**
|
|
11185
|
+
* A named delay or a promised check-in should produce a scheduled send.
|
|
11186
|
+
* `prompt` reprompts once and accepts the turn either way; `reject` fails
|
|
11187
|
+
* the turn when no scheduled send follows.
|
|
11188
|
+
*/
|
|
11189
|
+
namedDelayFollowUp: ConversationPolicyLevelSchema.optional(),
|
|
11190
|
+
/**
|
|
11191
|
+
* Keep the turn to one message. Prompt-only — the hard count comes from
|
|
11192
|
+
* `behavior.responses.maxImmediate`.
|
|
11193
|
+
*/
|
|
11194
|
+
oneMessagePerTurn: ConversationPolicyLevelSchema.optional(),
|
|
11195
|
+
/**
|
|
11196
|
+
* Skip rather than send filler. Prompt-only, and only stated when
|
|
11197
|
+
* `behavior.responses.allowSilent` is set.
|
|
11198
|
+
*/
|
|
11199
|
+
fillerBan: ConversationPolicyLevelSchema.optional(),
|
|
11200
|
+
/**
|
|
11201
|
+
* A bare acknowledgement does not cancel a pending follow-up. Prompt-only,
|
|
11202
|
+
* and only stated when the thread has pending scheduled messages.
|
|
11203
|
+
*/
|
|
11204
|
+
cancelPendingOnAck: ConversationPolicyLevelSchema.optional(),
|
|
11205
|
+
/**
|
|
11206
|
+
* Ask one thing at a time. `reject` blocks a send that asks more than one
|
|
11207
|
+
* question. Defaults to `off` at runtime: an agent that collects several
|
|
11208
|
+
* answers in one message is a legitimate design.
|
|
11209
|
+
*/
|
|
11210
|
+
oneQuestionPerMessage: ConversationPolicyLevelSchema.optional(),
|
|
11211
|
+
/**
|
|
11212
|
+
* Fallback when every send this turn was rejected by a policy gate.
|
|
11213
|
+
* `send` releases the last rejected message, `skip` records a skip.
|
|
11214
|
+
* @default "send"
|
|
11215
|
+
*/
|
|
11216
|
+
onPolicyRejectExhausted: import_v49.z.enum(["send", "skip"]).optional()
|
|
11217
|
+
});
|
|
10988
11218
|
var SchedulingDelaySchema = import_v49.z.object({
|
|
10989
11219
|
/** Time unit amount */
|
|
10990
11220
|
amount: import_v49.z.number(),
|
|
@@ -11032,15 +11262,53 @@ var BehaviorConfigV3Schema = import_v49.z.object({
|
|
|
11032
11262
|
* Scheduling behavior - controls when the agent schedules follow-up messages.
|
|
11033
11263
|
* Patterns define triggers like "user indicates they'll return later".
|
|
11034
11264
|
*/
|
|
11035
|
-
scheduling: SchedulingBehaviorConfigSchema.optional()
|
|
11265
|
+
scheduling: SchedulingBehaviorConfigSchema.optional(),
|
|
11266
|
+
/**
|
|
11267
|
+
* Conversation policy - which conversational rules this agent wants, and
|
|
11268
|
+
* whether each is stated in the prompt or enforced at runtime.
|
|
11269
|
+
*/
|
|
11270
|
+
conversation: ConversationBehaviorConfigSchema.optional(),
|
|
11271
|
+
/**
|
|
11272
|
+
* Mention a long gap since the last message when one has passed.
|
|
11273
|
+
* @default false
|
|
11274
|
+
*/
|
|
11275
|
+
acknowledgeTimeGaps: import_v49.z.boolean().optional(),
|
|
11276
|
+
/**
|
|
11277
|
+
* Gap that counts as long for `acknowledgeTimeGaps`, e.g. "3 days".
|
|
11278
|
+
*/
|
|
11279
|
+
timeGapThreshold: import_v49.z.string().optional()
|
|
11280
|
+
});
|
|
11281
|
+
var AgentSettingV3Schema = import_v49.z.object({
|
|
11282
|
+
/** Setting key, resolved against the install's AgentConfig and env. */
|
|
11283
|
+
key: import_v49.z.string().min(1),
|
|
11284
|
+
/** Human label shown to the model and in the console. */
|
|
11285
|
+
label: import_v49.z.string().optional(),
|
|
11286
|
+
/**
|
|
11287
|
+
* Prompt guidance for this setting. `{{value}}` interpolates the install
|
|
11288
|
+
* value and `{{workplace}}` the workplace name.
|
|
11289
|
+
*/
|
|
11290
|
+
guidance: import_v49.z.string().optional(),
|
|
11291
|
+
/**
|
|
11292
|
+
* Marks a setting as supplying a platform value rather than prose.
|
|
11293
|
+
* `persona_name` overrides the agent's persona name for this install.
|
|
11294
|
+
*/
|
|
11295
|
+
role: import_v49.z.enum(["persona_name"]).optional()
|
|
11036
11296
|
});
|
|
11037
11297
|
var PromptsConfigV3Schema = import_v49.z.object({
|
|
11038
11298
|
/** Main system prompt with workflow instructions */
|
|
11039
11299
|
system: import_v49.z.string().optional(),
|
|
11040
|
-
/**
|
|
11041
|
-
|
|
11042
|
-
|
|
11043
|
-
|
|
11300
|
+
/**
|
|
11301
|
+
* Injected during second pass when skills were loaded but tools not used.
|
|
11302
|
+
* @deprecated Ignored on the durable turn path; only the legacy stream path
|
|
11303
|
+
* reads it. Put the guidance in `system` instead.
|
|
11304
|
+
*/
|
|
11305
|
+
recovery: import_v49.z.string().optional().describe("Not implemented"),
|
|
11306
|
+
/**
|
|
11307
|
+
* Injected during follow-up passes when context needs updating.
|
|
11308
|
+
* @deprecated Ignored on the durable turn path; only the legacy stream path
|
|
11309
|
+
* reads it. Put the guidance in `system` instead.
|
|
11310
|
+
*/
|
|
11311
|
+
followUp: import_v49.z.string().optional().describe("Not implemented"),
|
|
11044
11312
|
/** Thread list title generation (system + user template with {{var}} placeholders) */
|
|
11045
11313
|
titleEnrichment: import_v49.z.object({
|
|
11046
11314
|
system: import_v49.z.string().optional(),
|
|
@@ -11060,18 +11328,23 @@ var AgentYAMLV3Schema = import_v49.z.object({
|
|
|
11060
11328
|
// Tools - Always-available tools before any skill loads
|
|
11061
11329
|
// Examples: system:settings:business_information:get
|
|
11062
11330
|
tools: import_v49.z.array(AgentToolRefSchema).optional(),
|
|
11331
|
+
/**
|
|
11332
|
+
* Settings - Install-scoped values the agent asks for by key.
|
|
11333
|
+
* Rendered into the prompt with the label and guidance declared here.
|
|
11334
|
+
*/
|
|
11335
|
+
settings: import_v49.z.array(AgentSettingV3Schema).optional(),
|
|
11063
11336
|
/**
|
|
11064
11337
|
* Events - When the agent activates
|
|
11065
11338
|
* @deprecated Not yet implemented - this is a planned feature for event-driven agents.
|
|
11066
11339
|
* Fields are accepted but not used at runtime.
|
|
11067
11340
|
*/
|
|
11068
|
-
events: EventsConfigSchema.optional(),
|
|
11341
|
+
events: EventsConfigSchema.optional().describe("Not implemented"),
|
|
11069
11342
|
/**
|
|
11070
11343
|
* Memory - How the agent remembers
|
|
11071
11344
|
* @deprecated Not yet implemented - this is a planned feature.
|
|
11072
11345
|
* Fields are accepted but not used at runtime.
|
|
11073
11346
|
*/
|
|
11074
|
-
memory: MemoryConfigV3Schema.optional(),
|
|
11347
|
+
memory: MemoryConfigV3Schema.optional().describe("Not implemented"),
|
|
11075
11348
|
// Policies - Business rules for the agent
|
|
11076
11349
|
policies: PoliciesConfigV3Schema.optional(),
|
|
11077
11350
|
// Runtime - Execution configuration (model + personaModel)
|
|
@@ -11125,13 +11398,15 @@ Get Options:
|
|
|
11125
11398
|
--json Output as JSON
|
|
11126
11399
|
|
|
11127
11400
|
Deploy Options:
|
|
11128
|
-
--file, -f Path to agent definition file (.agent.yml or .agent.
|
|
11401
|
+
--file, -f Path to agent definition file (.agent.yml, .agent.json, or .agent-pack.yaml)
|
|
11129
11402
|
--workplace, -w Workplace subdomain (required)
|
|
11130
11403
|
--draft Deploy as draft (not published)
|
|
11404
|
+
--upload Force multipart upload (for large files >500KB)
|
|
11131
11405
|
--json Output as JSON
|
|
11132
11406
|
|
|
11133
|
-
Supports
|
|
11134
|
-
|
|
11407
|
+
Supports v3 (skills-based) agents and agent-pack bundles.
|
|
11408
|
+
Agent-pack files (.agent-pack.yaml) include embedded skills, evaluators, and scenarios.
|
|
11409
|
+
Files larger than 500KB automatically use multipart upload.
|
|
11135
11410
|
|
|
11136
11411
|
Publish Options:
|
|
11137
11412
|
--workplace, -w Workplace subdomain (required)
|
|
@@ -11447,12 +11722,14 @@ async function handleUpdate2(args2) {
|
|
|
11447
11722
|
console.log('Note: "update" is deprecated. Use "deploy" instead.');
|
|
11448
11723
|
await handleDeploy(args2);
|
|
11449
11724
|
}
|
|
11725
|
+
var MULTIPART_THRESHOLD = 500 * 1024;
|
|
11450
11726
|
async function handleDeploy(args2) {
|
|
11451
11727
|
const { flags } = parseArgs(args2);
|
|
11452
11728
|
const filePath = flags.file || flags.f;
|
|
11453
11729
|
const workplace = flags.workplace || flags.w;
|
|
11454
11730
|
const isDraft = Boolean(flags.draft);
|
|
11455
11731
|
const jsonOutput = Boolean(flags.json);
|
|
11732
|
+
const forceUpload = Boolean(flags.upload);
|
|
11456
11733
|
if (!filePath) {
|
|
11457
11734
|
console.error("Error: --file (-f) is required");
|
|
11458
11735
|
console.error("Usage: skedyul agents deploy --file ./agent.yml --workplace gym-demo");
|
|
@@ -11466,11 +11743,25 @@ async function handleDeploy(args2) {
|
|
|
11466
11743
|
let agent;
|
|
11467
11744
|
let content;
|
|
11468
11745
|
let isV3;
|
|
11746
|
+
let isAgentPack = false;
|
|
11469
11747
|
try {
|
|
11470
|
-
const
|
|
11471
|
-
|
|
11472
|
-
|
|
11473
|
-
|
|
11748
|
+
const absolutePath = path22.resolve(filePath);
|
|
11749
|
+
content = fs22.readFileSync(absolutePath, "utf-8");
|
|
11750
|
+
const rawContent = (0, import_yaml2.parse)(content);
|
|
11751
|
+
isAgentPack = rawContent?.kind === "skedyul.agent-pack";
|
|
11752
|
+
if (isAgentPack) {
|
|
11753
|
+
const agentObj = rawContent.agent;
|
|
11754
|
+
if (!agentObj) {
|
|
11755
|
+
throw new Error('Agent-pack missing "agent" field');
|
|
11756
|
+
}
|
|
11757
|
+
agent = agentObj;
|
|
11758
|
+
isV3 = true;
|
|
11759
|
+
} else {
|
|
11760
|
+
const result = await loadAgentFile(filePath);
|
|
11761
|
+
agent = result.agent;
|
|
11762
|
+
content = result.content;
|
|
11763
|
+
isV3 = result.isV3;
|
|
11764
|
+
}
|
|
11474
11765
|
} catch (error) {
|
|
11475
11766
|
if (jsonOutput) {
|
|
11476
11767
|
console.log(JSON.stringify({ error: error instanceof Error ? error.message : String(error) }));
|
|
@@ -11491,37 +11782,46 @@ async function handleDeploy(args2) {
|
|
|
11491
11782
|
}
|
|
11492
11783
|
process.exit(1);
|
|
11493
11784
|
}
|
|
11785
|
+
const fileSize = Buffer.byteLength(content, "utf8");
|
|
11786
|
+
const useMultipart = forceUpload || fileSize > MULTIPART_THRESHOLD || isAgentPack;
|
|
11494
11787
|
if (!jsonOutput) {
|
|
11495
11788
|
let agentType;
|
|
11496
|
-
if (
|
|
11789
|
+
if (isAgentPack) {
|
|
11790
|
+
agentType = "agent-pack (bundled)";
|
|
11791
|
+
} else if (isV3) {
|
|
11497
11792
|
agentType = "v3 (skills-based)";
|
|
11498
11793
|
} else {
|
|
11499
11794
|
agentType = isMultiStageAgent(agent) ? "multi-stage" : "single-stage";
|
|
11500
11795
|
}
|
|
11501
11796
|
console.log("");
|
|
11502
11797
|
console.log(`Deploying ${agentType} agent "${agent.name}" to ${workplace}${isDraft ? " (draft)" : ""}`);
|
|
11798
|
+
if (useMultipart) {
|
|
11799
|
+
console.log(` Using multipart upload (${(fileSize / 1024).toFixed(1)} KB)`);
|
|
11800
|
+
}
|
|
11503
11801
|
console.log("");
|
|
11504
11802
|
}
|
|
11505
11803
|
try {
|
|
11506
|
-
|
|
11507
|
-
|
|
11508
|
-
|
|
11509
|
-
|
|
11510
|
-
|
|
11511
|
-
},
|
|
11512
|
-
body: JSON.stringify({
|
|
11804
|
+
let result;
|
|
11805
|
+
if (useMultipart) {
|
|
11806
|
+
result = await deployAgentMultipart({
|
|
11807
|
+
serverUrl,
|
|
11808
|
+
token,
|
|
11513
11809
|
workplaceId: workplaceToken.workplaceId,
|
|
11514
11810
|
subdomain: workplaceToken.workplaceSubdomain,
|
|
11515
|
-
|
|
11516
|
-
|
|
11811
|
+
filePath,
|
|
11812
|
+
content,
|
|
11517
11813
|
publish: !isDraft
|
|
11518
|
-
})
|
|
11519
|
-
}
|
|
11520
|
-
|
|
11521
|
-
|
|
11522
|
-
|
|
11814
|
+
});
|
|
11815
|
+
} else {
|
|
11816
|
+
result = await deployAgentJson({
|
|
11817
|
+
serverUrl,
|
|
11818
|
+
token,
|
|
11819
|
+
workplaceId: workplaceToken.workplaceId,
|
|
11820
|
+
subdomain: workplaceToken.workplaceSubdomain,
|
|
11821
|
+
content,
|
|
11822
|
+
publish: !isDraft
|
|
11823
|
+
});
|
|
11523
11824
|
}
|
|
11524
|
-
const result = await response.json();
|
|
11525
11825
|
if (!result.success) {
|
|
11526
11826
|
throw new Error(result.error || "Failed to deploy agent");
|
|
11527
11827
|
}
|
|
@@ -11549,6 +11849,12 @@ async function handleDeploy(args2) {
|
|
|
11549
11849
|
console.log(` Tools: ${result.agent.tools.length} bound`);
|
|
11550
11850
|
}
|
|
11551
11851
|
}
|
|
11852
|
+
if (result.deployedSkills?.length) {
|
|
11853
|
+
console.log(` Skills: ${result.deployedSkills.length} deployed`);
|
|
11854
|
+
for (const skill of result.deployedSkills) {
|
|
11855
|
+
console.log(` - ${skill.handle} v${skill.version}`);
|
|
11856
|
+
}
|
|
11857
|
+
}
|
|
11552
11858
|
console.log("");
|
|
11553
11859
|
} catch (error) {
|
|
11554
11860
|
if (jsonOutput) {
|
|
@@ -11559,6 +11865,50 @@ async function handleDeploy(args2) {
|
|
|
11559
11865
|
process.exit(1);
|
|
11560
11866
|
}
|
|
11561
11867
|
}
|
|
11868
|
+
async function deployAgentJson(params) {
|
|
11869
|
+
const response = await fetch(`${params.serverUrl}/api/cli/agents`, {
|
|
11870
|
+
method: "POST",
|
|
11871
|
+
headers: {
|
|
11872
|
+
"Content-Type": "application/json",
|
|
11873
|
+
Authorization: `Bearer ${params.token}`
|
|
11874
|
+
},
|
|
11875
|
+
body: JSON.stringify({
|
|
11876
|
+
workplaceId: params.workplaceId,
|
|
11877
|
+
subdomain: params.subdomain,
|
|
11878
|
+
action: "deploy",
|
|
11879
|
+
yamlContent: params.content,
|
|
11880
|
+
publish: params.publish
|
|
11881
|
+
})
|
|
11882
|
+
});
|
|
11883
|
+
if (!response.ok) {
|
|
11884
|
+
const errorData = await response.json().catch(() => ({}));
|
|
11885
|
+
throw new Error(errorData.error || `Request failed: ${response.statusText}`);
|
|
11886
|
+
}
|
|
11887
|
+
return response.json();
|
|
11888
|
+
}
|
|
11889
|
+
async function deployAgentMultipart(params) {
|
|
11890
|
+
const formData = new FormData();
|
|
11891
|
+
const blob = new Blob([params.content], { type: "text/yaml" });
|
|
11892
|
+
const fileName = path22.basename(params.filePath);
|
|
11893
|
+
formData.append("file", blob, fileName);
|
|
11894
|
+
formData.append("metadata", JSON.stringify({
|
|
11895
|
+
workplaceId: params.workplaceId,
|
|
11896
|
+
subdomain: params.subdomain,
|
|
11897
|
+
publish: params.publish
|
|
11898
|
+
}));
|
|
11899
|
+
const response = await fetch(`${params.serverUrl}/api/cli/agents/upload`, {
|
|
11900
|
+
method: "POST",
|
|
11901
|
+
headers: {
|
|
11902
|
+
Authorization: `Bearer ${params.token}`
|
|
11903
|
+
},
|
|
11904
|
+
body: formData
|
|
11905
|
+
});
|
|
11906
|
+
if (!response.ok) {
|
|
11907
|
+
const errorData = await response.json().catch(() => ({}));
|
|
11908
|
+
throw new Error(errorData.error || `Request failed: ${response.statusText}`);
|
|
11909
|
+
}
|
|
11910
|
+
return response.json();
|
|
11911
|
+
}
|
|
11562
11912
|
async function handlePublish(args2) {
|
|
11563
11913
|
const { flags, positional } = parseArgs(args2);
|
|
11564
11914
|
const handle = positional[0];
|
|
@@ -13211,8 +13561,11 @@ Deploy Options:
|
|
|
13211
13561
|
--workplace, -w Workplace subdomain (required)
|
|
13212
13562
|
--draft Deploy as draft (not published)
|
|
13213
13563
|
--label Version label (e.g., "experiment-shorter-prompts")
|
|
13564
|
+
--upload Force multipart upload (for large files >500KB)
|
|
13214
13565
|
--json Output as JSON
|
|
13215
13566
|
|
|
13567
|
+
Note: Files larger than 500KB automatically use multipart upload.
|
|
13568
|
+
|
|
13216
13569
|
Publish Options:
|
|
13217
13570
|
--workplace, -w Workplace subdomain (required)
|
|
13218
13571
|
--version, -v Version number to publish (required)
|
|
@@ -13419,6 +13772,7 @@ async function handleGet3(args2) {
|
|
|
13419
13772
|
process.exit(1);
|
|
13420
13773
|
}
|
|
13421
13774
|
}
|
|
13775
|
+
var MULTIPART_THRESHOLD2 = 500 * 1024;
|
|
13422
13776
|
async function handleDeploy2(args2) {
|
|
13423
13777
|
const { flags } = parseArgs(args2);
|
|
13424
13778
|
const filePath = flags.file || flags.f;
|
|
@@ -13426,6 +13780,7 @@ async function handleDeploy2(args2) {
|
|
|
13426
13780
|
const isDraft = Boolean(flags.draft);
|
|
13427
13781
|
const versionLabel = flags.label;
|
|
13428
13782
|
const jsonOutput = Boolean(flags.json);
|
|
13783
|
+
const forceUpload = Boolean(flags.upload);
|
|
13429
13784
|
if (!filePath) {
|
|
13430
13785
|
console.error("Error: --file (-f) is required");
|
|
13431
13786
|
console.error("Usage: skedyul skills deploy --file ./skill.yml --workplace crux");
|
|
@@ -13462,36 +13817,38 @@ async function handleDeploy2(args2) {
|
|
|
13462
13817
|
}
|
|
13463
13818
|
process.exit(1);
|
|
13464
13819
|
}
|
|
13820
|
+
const fileSize = Buffer.byteLength(content, "utf8");
|
|
13821
|
+
const useMultipart = forceUpload || fileSize > MULTIPART_THRESHOLD2;
|
|
13465
13822
|
if (!jsonOutput) {
|
|
13466
13823
|
console.log("");
|
|
13467
13824
|
console.log(`Deploying skill "${skill.name}" to ${workplace}${isDraft ? " (draft)" : ""}`);
|
|
13825
|
+
if (useMultipart) {
|
|
13826
|
+
console.log(` Using multipart upload (${(fileSize / 1024).toFixed(1)} KB)`);
|
|
13827
|
+
}
|
|
13468
13828
|
console.log("");
|
|
13469
13829
|
}
|
|
13470
13830
|
try {
|
|
13471
|
-
|
|
13472
|
-
|
|
13473
|
-
|
|
13474
|
-
|
|
13475
|
-
|
|
13476
|
-
},
|
|
13477
|
-
body: JSON.stringify({
|
|
13478
|
-
action: "deploy",
|
|
13831
|
+
let result;
|
|
13832
|
+
if (useMultipart) {
|
|
13833
|
+
result = await deploySkillMultipart({
|
|
13834
|
+
serverUrl,
|
|
13835
|
+
token,
|
|
13479
13836
|
workplaceId: workplaceToken.workplaceId,
|
|
13480
|
-
|
|
13837
|
+
filePath,
|
|
13838
|
+
content,
|
|
13481
13839
|
publish: !isDraft,
|
|
13482
13840
|
versionLabel
|
|
13483
|
-
})
|
|
13484
|
-
}
|
|
13485
|
-
|
|
13486
|
-
|
|
13487
|
-
|
|
13488
|
-
|
|
13489
|
-
|
|
13490
|
-
|
|
13491
|
-
|
|
13492
|
-
|
|
13841
|
+
});
|
|
13842
|
+
} else {
|
|
13843
|
+
result = await deploySkillJson({
|
|
13844
|
+
serverUrl,
|
|
13845
|
+
token,
|
|
13846
|
+
workplaceId: workplaceToken.workplaceId,
|
|
13847
|
+
content,
|
|
13848
|
+
publish: !isDraft,
|
|
13849
|
+
versionLabel
|
|
13850
|
+
});
|
|
13493
13851
|
}
|
|
13494
|
-
const result = await response.json();
|
|
13495
13852
|
if (!result.success) {
|
|
13496
13853
|
throw new Error(result.error || "Failed to deploy skill");
|
|
13497
13854
|
}
|
|
@@ -13518,6 +13875,60 @@ ${detailsStr}`);
|
|
|
13518
13875
|
process.exit(1);
|
|
13519
13876
|
}
|
|
13520
13877
|
}
|
|
13878
|
+
async function deploySkillJson(params) {
|
|
13879
|
+
const response = await fetch(`${params.serverUrl}/api/cli/skills`, {
|
|
13880
|
+
method: "POST",
|
|
13881
|
+
headers: {
|
|
13882
|
+
"Content-Type": "application/json",
|
|
13883
|
+
Authorization: `Bearer ${params.token}`
|
|
13884
|
+
},
|
|
13885
|
+
body: JSON.stringify({
|
|
13886
|
+
action: "deploy",
|
|
13887
|
+
workplaceId: params.workplaceId,
|
|
13888
|
+
yamlContent: params.content,
|
|
13889
|
+
publish: params.publish,
|
|
13890
|
+
versionLabel: params.versionLabel
|
|
13891
|
+
})
|
|
13892
|
+
});
|
|
13893
|
+
if (!response.ok) {
|
|
13894
|
+
const errorData = await response.json().catch(() => ({}));
|
|
13895
|
+
if (errorData.details) {
|
|
13896
|
+
const detailsStr = errorData.details.map((d) => ` - ${d.path}: ${d.message}`).join("\n");
|
|
13897
|
+
throw new Error(`${errorData.error}
|
|
13898
|
+
${detailsStr}`);
|
|
13899
|
+
}
|
|
13900
|
+
throw new Error(errorData.error || `Request failed: ${response.statusText}`);
|
|
13901
|
+
}
|
|
13902
|
+
return response.json();
|
|
13903
|
+
}
|
|
13904
|
+
async function deploySkillMultipart(params) {
|
|
13905
|
+
const formData = new FormData();
|
|
13906
|
+
const blob = new Blob([params.content], { type: "text/yaml" });
|
|
13907
|
+
const fileName = path24.basename(params.filePath);
|
|
13908
|
+
formData.append("file", blob, fileName);
|
|
13909
|
+
formData.append("metadata", JSON.stringify({
|
|
13910
|
+
workplaceId: params.workplaceId,
|
|
13911
|
+
publish: params.publish,
|
|
13912
|
+
versionLabel: params.versionLabel
|
|
13913
|
+
}));
|
|
13914
|
+
const response = await fetch(`${params.serverUrl}/api/cli/skills/upload`, {
|
|
13915
|
+
method: "POST",
|
|
13916
|
+
headers: {
|
|
13917
|
+
Authorization: `Bearer ${params.token}`
|
|
13918
|
+
},
|
|
13919
|
+
body: formData
|
|
13920
|
+
});
|
|
13921
|
+
if (!response.ok) {
|
|
13922
|
+
const errorData = await response.json().catch(() => ({}));
|
|
13923
|
+
if (errorData.details) {
|
|
13924
|
+
const detailsStr = errorData.details.map((d) => ` - ${d.path}: ${d.message}`).join("\n");
|
|
13925
|
+
throw new Error(`${errorData.error}
|
|
13926
|
+
${detailsStr}`);
|
|
13927
|
+
}
|
|
13928
|
+
throw new Error(errorData.error || `Request failed: ${response.statusText}`);
|
|
13929
|
+
}
|
|
13930
|
+
return response.json();
|
|
13931
|
+
}
|
|
13521
13932
|
async function handlePublish2(args2) {
|
|
13522
13933
|
const { flags, positional } = parseArgs(args2);
|
|
13523
13934
|
const handle = positional[0];
|