agent-accelerator 0.5.8 → 0.6.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 +26 -5
- package/examples/prompts/SYSTEM_PROMPT.md +2 -0
- package/examples/prompts/SYSTEM_PROMPT_AGENT.md +4 -0
- package/examples/prompts/SYSTEM_PROMPT_TOOLS.md +1 -0
- package/package.json +4 -1
- package/src/agent/agent.ts +374 -167
- package/src/agent/architecture.md +14 -12
- package/src/agent/config-blocks.ts +39 -12
- package/src/agent/context.ts +8 -3
- package/src/agent/delegation.ts +82 -29
- package/src/agent/loop.ts +449 -373
- package/src/agent/subagent.ts +1 -3
- package/src/agent/subagents-tool.ts +45 -7
- package/src/agent/subagents.md +3 -0
- package/src/agent/turns.ts +3 -1
- package/src/agent/worker.ts +58 -28
- package/src/agent/workers.ts +113 -20
- package/src/architecture.md +16 -15
- package/src/index.ts +34 -10
- package/src/models/architecture.md +4 -3
- package/src/models/catalog-cache.ts +6 -5
- package/src/models/catalog.ts +46 -49
- package/src/providers/architecture.md +10 -8
- package/src/providers/google.ts +150 -62
- package/src/providers/openai-compat.ts +60 -58
- package/src/providers/openai.ts +57 -39
- package/src/providers/openrouter.ts +87 -32
- package/src/providers/registry.ts +12 -26
- package/src/providers/shared.ts +89 -39
- package/src/providers.ts +56 -115
- package/src/scheduler/architecture.md +9 -8
- package/src/scheduler/scheduled-actions.md +4 -0
- package/src/scheduler/scheduler.ts +186 -60
- package/src/scheduler/store.ts +23 -10
- package/src/scheduler/time.ts +17 -3
- package/src/scheduler/tool.ts +33 -7
- package/src/session/architecture.md +7 -6
- package/src/session/journal.ts +38 -12
- package/src/session/store.ts +122 -61
- package/src/session/usage.ts +58 -9
- package/src/streaming/architecture.md +4 -3
- package/src/streaming/event-stream.ts +26 -12
- package/src/telemetry.ts +6 -2
- package/src/tools/architecture.md +8 -7
- package/src/tools/executor.ts +50 -48
- package/src/tools/schema.ts +10 -6
- package/src/tools/subagent-result.ts +6 -1
- package/src/tools/tool.ts +9 -11
- package/src/types/agent.ts +2 -21
- package/src/types/architecture.md +11 -10
- package/src/types/core.ts +1 -9
- package/src/types/errors.ts +26 -4
- package/src/types/model.ts +0 -4
- package/src/types/tool.ts +12 -2
- package/src/update-models.ts +5 -5
- package/src/utils/architecture.md +16 -15
- package/src/utils/cache.ts +1 -3
- package/src/utils/durable.ts +17 -5
- package/src/utils/env.ts +9 -7
- package/src/utils/errors.ts +50 -44
- package/src/utils/headers.ts +3 -10
- package/src/utils/media.ts +23 -8
- package/src/utils/raw-capture.ts +9 -2
- package/src/utils/retry.ts +17 -31
- package/src/utils/safe-io.ts +29 -7
- package/src/utils/serialization.ts +1 -4
- package/src/utils/session.ts +1 -2
package/src/providers.ts
CHANGED
|
@@ -18,12 +18,7 @@ import { TRUNCATED_ARGS_KEY } from "./types/tool.ts";
|
|
|
18
18
|
import { telemetryBus } from "./telemetry.ts";
|
|
19
19
|
|
|
20
20
|
/** Classification of a canonical capability on a given provider. */
|
|
21
|
-
export type ProviderCapabilityStatus =
|
|
22
|
-
| "NATIVE"
|
|
23
|
-
| "TRANSLATED"
|
|
24
|
-
| "AUTOMATIC"
|
|
25
|
-
| "EMULATED"
|
|
26
|
-
| "UNSUPPORTED";
|
|
21
|
+
export type ProviderCapabilityStatus = "NATIVE" | "TRANSLATED" | "AUTOMATIC" | "EMULATED" | "UNSUPPORTED";
|
|
27
22
|
|
|
28
23
|
/**
|
|
29
24
|
* Single warning mechanism for provider capability differences.
|
|
@@ -65,8 +60,12 @@ export function emitProviderWarning(options: {
|
|
|
65
60
|
reason: options.reason,
|
|
66
61
|
fallback: options.fallback,
|
|
67
62
|
});
|
|
68
|
-
try {
|
|
69
|
-
|
|
63
|
+
try {
|
|
64
|
+
(globalThis as any).__agentAccelWarnSink?.(msg, options);
|
|
65
|
+
} catch {}
|
|
66
|
+
try {
|
|
67
|
+
console.warn(msg);
|
|
68
|
+
} catch {}
|
|
70
69
|
}
|
|
71
70
|
|
|
72
71
|
/** Clears deduped-warning state (mainly for tests). */
|
|
@@ -124,9 +123,7 @@ export function clearSessionRouting(sessionId?: string): void {
|
|
|
124
123
|
* Maps a canonical ThinkingLevel onto Google Interactions `thinking_level`.
|
|
125
124
|
* Google values: minimal|low|medium|high (no off switch, no xhigh/max).
|
|
126
125
|
*/
|
|
127
|
-
export function mapThinkingLevelToGoogle(
|
|
128
|
-
level: ThinkingLevel | string | undefined
|
|
129
|
-
): { thinkingLevel?: string } {
|
|
126
|
+
export function mapThinkingLevelToGoogle(level: ThinkingLevel | string | undefined): { thinkingLevel?: string } {
|
|
130
127
|
if (!level) return {};
|
|
131
128
|
const norm = String(level).toLowerCase().trim();
|
|
132
129
|
if (norm === "dynamic") return {}; // server dynamic default (NATIVE)
|
|
@@ -171,9 +168,7 @@ export function mapServiceTierToGoogle(tier: ServiceTier | undefined): "flex" |
|
|
|
171
168
|
* the discontinued Responses skin, which clamped `xhigh` — everything passes
|
|
172
169
|
* through. `max` rides the same verbatim path. `dynamic` omits (server default).
|
|
173
170
|
*/
|
|
174
|
-
export function mapThinkingLevelToOpenRouterChat(
|
|
175
|
-
level: ThinkingLevel | string | undefined
|
|
176
|
-
): { effort?: string } {
|
|
171
|
+
export function mapThinkingLevelToOpenRouterChat(level: ThinkingLevel | string | undefined): { effort?: string } {
|
|
177
172
|
if (!level) return {};
|
|
178
173
|
const norm = String(level).toLowerCase().trim();
|
|
179
174
|
if (norm === "dynamic") return {}; // server default
|
|
@@ -216,9 +211,16 @@ export function resolveCache(
|
|
|
216
211
|
}
|
|
217
212
|
|
|
218
213
|
/** Warns once per provider/model that per-media `resolution` is ignored (no such control on that wire for the given kinds of media); in: an adapter's request messages, out: telemetry bus only. */
|
|
219
|
-
export function warnIgnoredMediaResolution(
|
|
214
|
+
export function warnIgnoredMediaResolution(
|
|
215
|
+
provider: string,
|
|
216
|
+
messages: Message[],
|
|
217
|
+
modelRef: string,
|
|
218
|
+
kinds: Array<"image" | "video"> = ["image", "video"]
|
|
219
|
+
): void {
|
|
220
220
|
const used = messages.some(
|
|
221
|
-
(m) =>
|
|
221
|
+
(m) =>
|
|
222
|
+
Array.isArray(m.content) &&
|
|
223
|
+
m.content.some((p) => (p.type === "image" || p.type === "video") && kinds.includes(p.type) && p.resolution)
|
|
222
224
|
);
|
|
223
225
|
if (!used) return;
|
|
224
226
|
emitProviderWarning({
|
|
@@ -231,11 +233,7 @@ export function warnIgnoredMediaResolution(provider: string, messages: Message[]
|
|
|
231
233
|
}
|
|
232
234
|
|
|
233
235
|
/** OpenRouter Chat Completions `tool_choice` wire values. */
|
|
234
|
-
export type OpenRouterChatToolChoice =
|
|
235
|
-
| "auto"
|
|
236
|
-
| "none"
|
|
237
|
-
| "required"
|
|
238
|
-
| { type: "function"; function: { name: string } };
|
|
236
|
+
export type OpenRouterChatToolChoice = "auto" | "none" | "required" | { type: "function"; function: { name: string } };
|
|
239
237
|
|
|
240
238
|
/**
|
|
241
239
|
* Maps canonical toolChoice onto Chat Completions `tool_choice`.
|
|
@@ -260,9 +258,7 @@ export function mapToolChoiceToOpenRouterChat(
|
|
|
260
258
|
* medium). Unlike OpenRouter (which clamps xhigh), OpenAI documents xhigh
|
|
261
259
|
* and max natively so they pass through verbatim. `dynamic` omits (server default).
|
|
262
260
|
*/
|
|
263
|
-
export function mapThinkingLevelToOpenAI(
|
|
264
|
-
level: ThinkingLevel | string | undefined
|
|
265
|
-
): { effort?: string } {
|
|
261
|
+
export function mapThinkingLevelToOpenAI(level: ThinkingLevel | string | undefined): { effort?: string } {
|
|
266
262
|
if (!level) return {};
|
|
267
263
|
const norm = String(level).toLowerCase().trim();
|
|
268
264
|
if (norm === "dynamic") return {}; // server default
|
|
@@ -386,98 +382,36 @@ export function selectRawArguments(startText: string, deltaText: string): string
|
|
|
386
382
|
}
|
|
387
383
|
|
|
388
384
|
// ---------------------------------------------------------------------------
|
|
389
|
-
// Generation controls (maxOutputTokens
|
|
385
|
+
// Generation controls (maxOutputTokens)
|
|
390
386
|
// ---------------------------------------------------------------------------
|
|
391
387
|
|
|
392
388
|
/** Canonical generation controls as carried on `ProviderRequestOptions`. */
|
|
393
389
|
export interface GenerationParams {
|
|
394
390
|
maxOutputTokens?: number;
|
|
395
|
-
stop?: string[];
|
|
396
|
-
seed?: number;
|
|
397
391
|
}
|
|
398
392
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
/** Normalizes the public `stop` option (`string | string[]`) to a clean array, or undefined. */
|
|
405
|
-
export function normalizeStop(stop: string | string[] | undefined): string[] | undefined {
|
|
406
|
-
const list = (Array.isArray(stop) ? stop : stop === undefined ? [] : [stop]).filter(
|
|
407
|
-
(s): s is string => typeof s === "string" && s.length > 0
|
|
408
|
-
);
|
|
409
|
-
return list.length > 0 ? list : undefined;
|
|
393
|
+
// The output-token cap as a whole number above zero, else undefined; in: the three generation-param mappers, out: their wire field.
|
|
394
|
+
function outputTokenCap(params: GenerationParams | undefined): number | undefined {
|
|
395
|
+
const n = params?.maxOutputTokens;
|
|
396
|
+
return typeof n === "number" && Number.isFinite(n) && n > 0 ? Math.floor(n) : undefined;
|
|
410
397
|
}
|
|
411
398
|
|
|
412
|
-
/**
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
*/
|
|
417
|
-
export function mapGenerationParamsToChat(params: GenerationParams | undefined, provider = "chat", modelRef = ""): Record<string, unknown> {
|
|
418
|
-
const out: Record<string, unknown> = {};
|
|
419
|
-
if (!params) return out;
|
|
420
|
-
if (finiteNumber(params.maxOutputTokens) && params.maxOutputTokens > 0) out["max_tokens"] = Math.floor(params.maxOutputTokens);
|
|
421
|
-
if (params.stop && params.stop.length > 0) {
|
|
422
|
-
out["stop"] = params.stop.slice(0, MAX_CHAT_STOP);
|
|
423
|
-
if (params.stop.length > MAX_CHAT_STOP) {
|
|
424
|
-
emitProviderWarning({
|
|
425
|
-
provider,
|
|
426
|
-
capability: "stop sequences",
|
|
427
|
-
requested: `${params.stop.length} sequences (${modelRef})`,
|
|
428
|
-
reason: `Chat Completions allows at most ${MAX_CHAT_STOP} stop sequences.`,
|
|
429
|
-
fallback: `the first ${MAX_CHAT_STOP}`,
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
if (finiteNumber(params.seed)) out["seed"] = Math.floor(params.seed);
|
|
434
|
-
return out;
|
|
399
|
+
/** Chat Completions (OpenRouter + generic compat endpoints): `max_tokens`, only when the caller set it, so strict endpoints never see anything unasked. */
|
|
400
|
+
export function mapGenerationParamsToChat(params: GenerationParams | undefined): { max_tokens?: number } {
|
|
401
|
+
const cap = outputTokenCap(params);
|
|
402
|
+
return cap === undefined ? {} : { max_tokens: cap };
|
|
435
403
|
}
|
|
436
404
|
|
|
437
|
-
|
|
438
|
-
function
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
provider,
|
|
442
|
-
capability: "stop sequences",
|
|
443
|
-
requested: `${params.stop.join("|")} (${modelRef})`,
|
|
444
|
-
reason: `the ${reasonSuffix} defines no stop-sequence parameter.`,
|
|
445
|
-
fallback: "no stop sequences (the model decides when to stop)",
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
if (finiteNumber(params.seed)) {
|
|
449
|
-
emitProviderWarning({
|
|
450
|
-
provider,
|
|
451
|
-
capability: "seed",
|
|
452
|
-
requested: `${params.seed} (${modelRef})`,
|
|
453
|
-
reason: `the ${reasonSuffix} defines no seed parameter.`,
|
|
454
|
-
fallback: "non-deterministic sampling",
|
|
455
|
-
});
|
|
456
|
-
}
|
|
405
|
+
/** OpenAI Responses: `max_output_tokens`. */
|
|
406
|
+
export function mapGenerationParamsToOpenAI(params: GenerationParams | undefined): { max_output_tokens?: number } {
|
|
407
|
+
const cap = outputTokenCap(params);
|
|
408
|
+
return cap === undefined ? {} : { max_output_tokens: cap };
|
|
457
409
|
}
|
|
458
410
|
|
|
459
|
-
/**
|
|
460
|
-
export function
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
): { max_output_tokens?: number } {
|
|
464
|
-
if (!params) return {};
|
|
465
|
-
warnUnsupportedStopSeed("openai", modelRef, params, "OpenAI Responses API");
|
|
466
|
-
return finiteNumber(params.maxOutputTokens) && params.maxOutputTokens > 0
|
|
467
|
-
? { max_output_tokens: Math.floor(params.maxOutputTokens) }
|
|
468
|
-
: {};
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
/** Google Interactions `generation_config`: `max_output_tokens` is documented; `stop` and `seed` are not (warn + drop). */
|
|
472
|
-
export function mapGenerationParamsToGoogle(
|
|
473
|
-
params: GenerationParams | undefined,
|
|
474
|
-
modelRef: string
|
|
475
|
-
): { max_output_tokens?: number } {
|
|
476
|
-
if (!params) return {};
|
|
477
|
-
warnUnsupportedStopSeed("google", modelRef, params, "Gemini Interactions API");
|
|
478
|
-
return finiteNumber(params.maxOutputTokens) && params.maxOutputTokens > 0
|
|
479
|
-
? { max_output_tokens: Math.floor(params.maxOutputTokens) }
|
|
480
|
-
: {};
|
|
411
|
+
/** Google Interactions `generation_config`: `max_output_tokens`. */
|
|
412
|
+
export function mapGenerationParamsToGoogle(params: GenerationParams | undefined): { max_output_tokens?: number } {
|
|
413
|
+
const cap = outputTokenCap(params);
|
|
414
|
+
return cap === undefined ? {} : { max_output_tokens: cap };
|
|
481
415
|
}
|
|
482
416
|
|
|
483
417
|
// ---------------------------------------------------------------------------
|
|
@@ -488,12 +422,7 @@ export function mapGenerationParamsToGoogle(
|
|
|
488
422
|
function isZodLike(value: unknown): boolean {
|
|
489
423
|
if (!value || typeof value !== "object") return false;
|
|
490
424
|
const v = value as Record<string, unknown>;
|
|
491
|
-
return
|
|
492
|
-
typeof v["safeParse"] === "function" ||
|
|
493
|
-
typeof v["parse"] === "function" ||
|
|
494
|
-
"_def" in v ||
|
|
495
|
-
"~standard" in v
|
|
496
|
-
);
|
|
425
|
+
return typeof v["safeParse"] === "function" || typeof v["parse"] === "function" || "_def" in v || "~standard" in v;
|
|
497
426
|
}
|
|
498
427
|
|
|
499
428
|
// True when a plain object has JSON Schema keywords; in: structured-output normalization, out: a boolean.
|
|
@@ -575,7 +504,9 @@ export function normalizeStructuredOutput(output: unknown): StructuredOutputSpec
|
|
|
575
504
|
* present (bare Zod schema or `{ schema: Zod }`). Used by the loop for
|
|
576
505
|
* post-parse validation; `undefined` means JSON-parse only.
|
|
577
506
|
*/
|
|
578
|
-
export function extractOutputValidator(
|
|
507
|
+
export function extractOutputValidator(
|
|
508
|
+
output: unknown
|
|
509
|
+
): { safeParse: (v: unknown) => { success: boolean; data?: unknown; error?: { message: string } } } | undefined {
|
|
579
510
|
if (!output) return undefined;
|
|
580
511
|
if (isZodLike(output) && typeof (output as { safeParse?: unknown }).safeParse === "function") {
|
|
581
512
|
return output as { safeParse: (v: unknown) => { success: boolean; data?: unknown; error?: { message: string } } };
|
|
@@ -637,9 +568,17 @@ export function parseStructuredOutput(text: string, output: unknown): unknown {
|
|
|
637
568
|
* Maps a normalized spec onto OpenAI Responses `text.format`.
|
|
638
569
|
* `{ type: json_schema, name, schema, strict }` (docs: responses/create).
|
|
639
570
|
*/
|
|
640
|
-
export function mapOutputToOpenAI(
|
|
641
|
-
|
|
642
|
-
|
|
571
|
+
export function mapOutputToOpenAI(spec: StructuredOutputSpec | undefined):
|
|
572
|
+
| {
|
|
573
|
+
format: {
|
|
574
|
+
type: "json_schema";
|
|
575
|
+
name: string;
|
|
576
|
+
schema: Record<string, unknown>;
|
|
577
|
+
strict: boolean;
|
|
578
|
+
description?: string;
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
| undefined {
|
|
643
582
|
if (!spec) return undefined;
|
|
644
583
|
return {
|
|
645
584
|
format: {
|
|
@@ -670,8 +609,10 @@ export function mapOutputToGoogle(
|
|
|
670
609
|
}
|
|
671
610
|
|
|
672
611
|
/** Chat Completions `response_format` wire shape (OpenRouter + compat). */
|
|
673
|
-
export type ChatCompletionsResponseFormat =
|
|
674
|
-
|
|
612
|
+
export type ChatCompletionsResponseFormat = {
|
|
613
|
+
type: "json_schema";
|
|
614
|
+
json_schema: { name: string; schema: Record<string, unknown>; strict: boolean; description?: string };
|
|
615
|
+
};
|
|
675
616
|
|
|
676
617
|
/**
|
|
677
618
|
* Maps a normalized spec onto Chat Completions `response_format`.
|
|
@@ -2,20 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
Scheduled actions: a worker that runs later (once or repeating) and saves its answer to a file. Off unless `dynamicSubagents.allowScheduledActions` is set.
|
|
4
4
|
|
|
5
|
-
| File
|
|
6
|
-
|
|
|
7
|
-
| `scheduler.ts`
|
|
8
|
-
| `store.ts`
|
|
9
|
-
| `time.ts`
|
|
10
|
-
| `tool.ts` + `scheduled-actions.md` | The model-facing `scheduled_actions` tool and `get_datetime`; the `.md` is the tool description.
|
|
5
|
+
| File | What it is |
|
|
6
|
+
| :--------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| `scheduler.ts` | One `Scheduler` per home folder: a 1 s unref'd clock that runs only while something is pending, startup sweep, dead-owner recovery, heartbeats, cook/deliver state machine, and the public functions (`createScheduledAction`, `list/update/run/skip/deleteScheduledAction`). |
|
|
8
|
+
| `store.ts` | Disk layer under `<home>/scheduled/`: `<id>/task.json`, `<id>/delivery.json`, run files, one short mutex per action; validation of records. |
|
|
9
|
+
| `time.ts` | Pure `DD:HH:MM` and local-clock maths. No timezone, DST or `Intl`; `now` is always passed in. |
|
|
10
|
+
| `tool.ts` + `scheduled-actions.md` | The model-facing `scheduled_actions` tool and `get_datetime`; the `.md` is the tool description. |
|
|
11
11
|
|
|
12
12
|
## Invariants
|
|
13
|
+
|
|
13
14
|
- The files are the truth: every write re-reads first and goes through the durable writer. The file format is a stable public contract: see `docs/scheduled-action-files.md` and add a changelog row for any change.
|
|
14
|
-
- Write order when a run ends: run file, then `<id>/delivery.json`, then `<id>/task.json`.
|
|
15
|
+
- Write order when a run ends: run file, then `<id>/delivery.json`, then `<id>/task.json`. A crash in between is repaired by the dead-owner recovery (`recoverCooking`, at start and every 15 s): the delivery is rebuilt from the run file, or the run is marked `missed` when no run file exists.
|
|
15
16
|
- `startCook` advances the next times BEFORE the run starts; a run still cooking when the next is due is skipped, never stacked.
|
|
16
17
|
- Runs are fresh stateless workers built by `buildDynamicWorkerConfig`; their spending guardrail is `workerBudget` only.
|
|
17
18
|
- The Agent registry holds `WeakRef`s by name: keep every Agent that owns actions referenced, or its runs become `missed`.
|
|
18
|
-
- Several processes may share a home
|
|
19
|
+
- Several processes may share a home: scheduled actions take no home lock, only the short per-action mutex (`<id>/.mutex`); the one-process lock is on session folders only. Ownership: a process only starts, delivers or recovers actions whose Agent it registered. An action nobody here owns is left alone until its delivery time passed with no run started, then marked `missed` (`no_agent`).
|
|
19
20
|
- Exactly once: a scheduled start re-checks under the action's mutex that it is still `waiting` and due; `markMissed` only changes the state the caller saw; a delivery is emitted only by the process that removed its entry from `delivery.json`.
|
|
20
21
|
- A run in flight keeps `<id>/.heartbeat` (pid, host, token; mtime refreshed every 5 s, stale after 60 s), written before the record shows `cooking`. A cooking action whose owner is dead (pid gone, stale, or none) is recovered by a live process that owns its Agent, at start and every 15 s. `delete` of a run another live process is cooking is refused, even with `force`.
|
|
21
22
|
- Times come from `Date`, local clock only. Tests inject `scheduler.now` / `tickMs` and call `tick()`.
|
|
@@ -3,6 +3,7 @@ Schedules a sub-agent (a "scheduled action") to run LATER, once or on repeat, on
|
|
|
3
3
|
Call get_datetime first whenever you create or reschedule, then pick DD from today's date.
|
|
4
4
|
|
|
5
5
|
COMMANDS (one tool, the `command` field)
|
|
6
|
+
|
|
6
7
|
- create: schedule a new action. Needs instructions, task and scheduled_action.{name, id, timeToDeliver, meridiem, startCookingInAdvance}. Optional: role, tools, timeoutMs, scheduled_action.repeatEvery, scheduled_action.retries, scheduled_action.onMissed.
|
|
7
8
|
- list: every action with its metadata and state (waiting, cooking, missed, done).
|
|
8
9
|
- get: one action by `id`, with its latest run result.
|
|
@@ -12,6 +13,7 @@ COMMANDS (one tool, the `command` field)
|
|
|
12
13
|
- skip: ignore a missed run of `id` and wait for the next scheduled time.
|
|
13
14
|
|
|
14
15
|
SCHEDULED_ACTION FIELDS
|
|
16
|
+
|
|
15
17
|
- name: human label.
|
|
16
18
|
- id: lowercase kebab-case, at most 48 characters, e.g. "daily-ai-brief". The SDK appends 6 characters ("daily-ai-brief-d64aj2"); use that full id in every later command.
|
|
17
19
|
- timeToDeliver: "DD:HH:MM". DD = days from today (00 today, 01 tomorrow, 55 = 55 days ahead). HH:MM = clock time on a 12-hour clock, HH 01-12.
|
|
@@ -30,12 +32,14 @@ Weekly report, every Monday at 9:00 AM (use get_datetime to count the days to th
|
|
|
30
32
|
{"command":"create","instructions":"You review a codebase and report its health.","task":"Report test health, open risks and notable changes this week.","scheduled_action":{"name":"Weekly Codebase Health Report","id":"weekly-code-health","timeToDeliver":"03:09:00","meridiem":"AM","startCookingInAdvance":"00:02:00","repeatEvery":"07:00:00"}}
|
|
31
33
|
|
|
32
34
|
TIMING ADVICE (do not guess; talk to the user)
|
|
35
|
+
|
|
33
36
|
- A run must finish before the next one is due, so startCookingInAdvance must be shorter than repeatEvery.
|
|
34
37
|
- Pick the lead time from the job: a quick lookup fits the 10-minute lead ("00:00:10"); research with many tools needs much more.
|
|
35
38
|
- If the job looks too heavy for the gap the user asked for, do not schedule it blindly. Say so and suggest a wider gap, an earlier start, or a lighter task.
|
|
36
39
|
- A run still cooking when the next one is due is skipped, never stacked, so a gap that is too small means lost runs.
|
|
37
40
|
|
|
38
41
|
RULES
|
|
42
|
+
|
|
39
43
|
- Each run starts blank and remembers nothing from earlier runs: put everything the worker needs in instructions and task.
|
|
40
44
|
- Results go to files, not into this chat. Tell the user the action is scheduled and when it will be delivered.
|
|
41
45
|
- Never put secrets in instructions or task: they are stored as plain text.
|