makaron-cli 0.7.8 → 0.7.10
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 +37 -4
- package/SKILL.md +37 -4
- package/bin/makaron.mjs +111 -11
- package/package.json +1 -1
- package/skills/makaron/SKILL.md +37 -4
package/README.md
CHANGED
|
@@ -136,10 +136,13 @@ Outputs one JSON per line as artifacts appear:
|
|
|
136
136
|
|
|
137
137
|
### Dialogue events for external Agents
|
|
138
138
|
|
|
139
|
-
Use this when another Agent needs to read what Makaron said,
|
|
139
|
+
Use this when another Agent needs to read what Makaron said, handle text checkpoints, and relay artifacts without inventing customer-service wording.
|
|
140
140
|
|
|
141
141
|
```bash
|
|
142
142
|
npx makaron-cli responses events <runId> --jsonl
|
|
143
|
+
# alias: npx makaron-cli responses timeline <runId> --jsonl
|
|
144
|
+
# compact view: npx makaron-cli responses timeline <runId> --jsonl --compact
|
|
145
|
+
# pure Q&A view: npx makaron-cli responses timeline <runId> --jsonl --checkpoint-mode off
|
|
143
146
|
```
|
|
144
147
|
|
|
145
148
|
Events use only three factual types:
|
|
@@ -150,7 +153,7 @@ Events use only three factual types:
|
|
|
150
153
|
{"type":"artifact","kind":"image","status":"completed","url":"https://..."}
|
|
151
154
|
```
|
|
152
155
|
|
|
153
|
-
If a message has `requires_approval: true`, the external Agent must record an approval before continuing to wait for artifacts or claiming completion:
|
|
156
|
+
Makaron uses a conservative checkpoint rule for creative/service Agents: if a run stops with substantive text, has no image/video/music/design artifact, and has no continuing execution action such as a tool call, the message is marked `requires_approval: true`. Pure status text such as queued, rendering, uploading, or completed is not treated as a checkpoint. Pure Q&A flows should pass `--checkpoint-mode off`. If a message has `requires_approval: true`, the external Agent must record an approval before continuing to wait for artifacts or claiming completion:
|
|
154
157
|
|
|
155
158
|
```bash
|
|
156
159
|
npx makaron-cli responses approve msg_1 --run <runId> --note "Proceed."
|
|
@@ -159,12 +162,15 @@ npx makaron-cli responses ask-user msg_1 --run <runId>
|
|
|
159
162
|
npx makaron-cli responses continue msg_1 --run <runId>
|
|
160
163
|
```
|
|
161
164
|
|
|
162
|
-
Wrappers can enforce
|
|
165
|
+
Important: approvals are a local Agent gate in v0. They are recorded by the CLI so wrappers and Skills can fail fast, but they do not pause or resume the remote Makaron runtime yet. Wrappers can enforce the local gate with:
|
|
163
166
|
|
|
164
167
|
```bash
|
|
165
|
-
npx makaron-cli responses events <runId> --jsonl --fail-on-unapproved
|
|
168
|
+
npx makaron-cli responses events <runId> --jsonl --checkpoint-mode service --fail-on-unapproved
|
|
169
|
+
# alias: npx makaron-cli responses timeline <runId> --jsonl --compact --fail-on-unapproved
|
|
166
170
|
```
|
|
167
171
|
|
|
172
|
+
Use `--compact` when relaying to another Agent or chat system; it merges consecutive Makaron content chunks into a single readable message.
|
|
173
|
+
|
|
168
174
|
### Extract specific results
|
|
169
175
|
|
|
170
176
|
```bash
|
|
@@ -294,6 +300,33 @@ type MakaronOutput =
|
|
|
294
300
|
| Motion design | "create an Instagram story with animated text" |
|
|
295
301
|
| Multi-step | "edit the photo then make a video from it" |
|
|
296
302
|
|
|
303
|
+
## Minimal Agent Wrapper
|
|
304
|
+
|
|
305
|
+
A new Agent can use this minimal flow:
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
RUN_JSON=$(npx makaron-cli chat --project auto --json -b "$USER_PROMPT")
|
|
309
|
+
RUN_ID=$(echo "$RUN_JSON" | jq -r .runId)
|
|
310
|
+
PROJECT_URL=$(echo "$RUN_JSON" | jq -r .projectUrl)
|
|
311
|
+
send_message "Project created: $PROJECT_URL"
|
|
312
|
+
|
|
313
|
+
if ! npx makaron-cli responses timeline "$RUN_ID" --jsonl --compact --checkpoint-mode service --fail-on-unapproved > /tmp/makaron-events.jsonl; then
|
|
314
|
+
npx makaron-cli responses timeline "$RUN_ID" --jsonl --compact | while read -r event; do
|
|
315
|
+
TYPE=$(echo "$event" | jq -r .type)
|
|
316
|
+
REQUIRES=$(echo "$event" | jq -r ".requires_approval // false")
|
|
317
|
+
TEXT=$(echo "$event" | jq -r ".text // empty")
|
|
318
|
+
MSG_ID=$(echo "$event" | jq -r ".id // empty")
|
|
319
|
+
if [ "$TYPE" = "message" ] && [ "$REQUIRES" = "true" ]; then
|
|
320
|
+
send_message "$TEXT"
|
|
321
|
+
npx makaron-cli responses ask-user "$MSG_ID" --run "$RUN_ID"
|
|
322
|
+
exit 3
|
|
323
|
+
fi
|
|
324
|
+
done
|
|
325
|
+
fi
|
|
326
|
+
|
|
327
|
+
RESULT=$(npx makaron-cli responses get "$RUN_ID" --wait --json)
|
|
328
|
+
```
|
|
329
|
+
|
|
297
330
|
## Recommended Pattern: Service Flow (Feishu/OpenClaw/Group Chat)
|
|
298
331
|
|
|
299
332
|
When serving end-users in a chat environment (Feishu, Slack, Discord), use this proactive message pattern:
|
package/SKILL.md
CHANGED
|
@@ -128,10 +128,13 @@ Outputs one JSON per line as artifacts appear:
|
|
|
128
128
|
|
|
129
129
|
### Dialogue events for external Agents
|
|
130
130
|
|
|
131
|
-
Use this when another Agent needs to read what Makaron said,
|
|
131
|
+
Use this when another Agent needs to read what Makaron said, handle text checkpoints, and relay artifacts without inventing customer-service wording.
|
|
132
132
|
|
|
133
133
|
```bash
|
|
134
134
|
npx makaron-cli responses events <runId> --jsonl
|
|
135
|
+
# alias: npx makaron-cli responses timeline <runId> --jsonl
|
|
136
|
+
# compact view: npx makaron-cli responses timeline <runId> --jsonl --compact
|
|
137
|
+
# pure Q&A view: npx makaron-cli responses timeline <runId> --jsonl --checkpoint-mode off
|
|
135
138
|
```
|
|
136
139
|
|
|
137
140
|
Events use only three factual types:
|
|
@@ -142,7 +145,7 @@ Events use only three factual types:
|
|
|
142
145
|
{"type":"artifact","kind":"image","status":"completed","url":"https://..."}
|
|
143
146
|
```
|
|
144
147
|
|
|
145
|
-
If a message has `requires_approval: true`, the external Agent must record an approval before continuing to wait for artifacts or claiming completion:
|
|
148
|
+
Makaron uses a conservative checkpoint rule for creative/service Agents: if a run stops with substantive text, has no image/video/music/design artifact, and has no continuing execution action such as a tool call, the message is marked `requires_approval: true`. Pure status text such as queued, rendering, uploading, or completed is not treated as a checkpoint. Pure Q&A flows should pass `--checkpoint-mode off`. If a message has `requires_approval: true`, the external Agent must record an approval before continuing to wait for artifacts or claiming completion:
|
|
146
149
|
|
|
147
150
|
```bash
|
|
148
151
|
npx makaron-cli responses approve msg_1 --run <runId> --note "Proceed."
|
|
@@ -151,12 +154,15 @@ npx makaron-cli responses ask-user msg_1 --run <runId>
|
|
|
151
154
|
npx makaron-cli responses continue msg_1 --run <runId>
|
|
152
155
|
```
|
|
153
156
|
|
|
154
|
-
Wrappers can enforce
|
|
157
|
+
Important: approvals are a local Agent gate in v0. They are recorded by the CLI so wrappers and Skills can fail fast, but they do not pause or resume the remote Makaron runtime yet. Wrappers can enforce the local gate with:
|
|
155
158
|
|
|
156
159
|
```bash
|
|
157
|
-
npx makaron-cli responses events <runId> --jsonl --fail-on-unapproved
|
|
160
|
+
npx makaron-cli responses events <runId> --jsonl --checkpoint-mode service --fail-on-unapproved
|
|
161
|
+
# alias: npx makaron-cli responses timeline <runId> --jsonl --compact --fail-on-unapproved
|
|
158
162
|
```
|
|
159
163
|
|
|
164
|
+
Use `--compact` when relaying to another Agent or chat system; it merges consecutive Makaron content chunks into a single readable message.
|
|
165
|
+
|
|
160
166
|
### Extract specific results
|
|
161
167
|
|
|
162
168
|
```bash
|
|
@@ -283,6 +289,33 @@ type MakaronOutput =
|
|
|
283
289
|
| Motion design | "create an Instagram story with animated text" |
|
|
284
290
|
| Multi-step | "edit the photo then make a video from it" |
|
|
285
291
|
|
|
292
|
+
## Minimal Agent Wrapper
|
|
293
|
+
|
|
294
|
+
A new Agent can use this minimal flow:
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
RUN_JSON=$(npx makaron-cli chat --project auto --json -b "$USER_PROMPT")
|
|
298
|
+
RUN_ID=$(echo "$RUN_JSON" | jq -r .runId)
|
|
299
|
+
PROJECT_URL=$(echo "$RUN_JSON" | jq -r .projectUrl)
|
|
300
|
+
send_message "Project created: $PROJECT_URL"
|
|
301
|
+
|
|
302
|
+
if ! npx makaron-cli responses timeline "$RUN_ID" --jsonl --compact --checkpoint-mode service --fail-on-unapproved > /tmp/makaron-events.jsonl; then
|
|
303
|
+
npx makaron-cli responses timeline "$RUN_ID" --jsonl --compact | while read -r event; do
|
|
304
|
+
TYPE=$(echo "$event" | jq -r .type)
|
|
305
|
+
REQUIRES=$(echo "$event" | jq -r ".requires_approval // false")
|
|
306
|
+
TEXT=$(echo "$event" | jq -r ".text // empty")
|
|
307
|
+
MSG_ID=$(echo "$event" | jq -r ".id // empty")
|
|
308
|
+
if [ "$TYPE" = "message" ] && [ "$REQUIRES" = "true" ]; then
|
|
309
|
+
send_message "$TEXT"
|
|
310
|
+
npx makaron-cli responses ask-user "$MSG_ID" --run "$RUN_ID"
|
|
311
|
+
exit 3
|
|
312
|
+
fi
|
|
313
|
+
done
|
|
314
|
+
fi
|
|
315
|
+
|
|
316
|
+
RESULT=$(npx makaron-cli responses get "$RUN_ID" --wait --json)
|
|
317
|
+
```
|
|
318
|
+
|
|
286
319
|
## Recommended Pattern: Service Flow (Feishu/OpenClaw/Group Chat)
|
|
287
320
|
|
|
288
321
|
When serving end-users in a chat environment (Feishu, Slack, Discord), use this proactive message pattern:
|
package/bin/makaron.mjs
CHANGED
|
@@ -447,11 +447,61 @@ function stableEventId(prefix, runId, seq, fallback) {
|
|
|
447
447
|
return fallback || `${prefix}_${runId}_${seq ?? Date.now()}`;
|
|
448
448
|
}
|
|
449
449
|
|
|
450
|
-
function
|
|
450
|
+
function inferApprovalIntent(text) {
|
|
451
|
+
if (!text) return false;
|
|
452
|
+
const normalized = text.toLowerCase().replace(/\s+/g, ' ').trim();
|
|
453
|
+
const hasEnglishApprovalIntent = /\b(shall i|should i|do you want me to|confirm|approve|approval|permission)\b/.test(normalized);
|
|
454
|
+
const hasEnglishAction = /\b(go ahead|proceed|continue|generate|create|submit|start|run|render)\b/.test(normalized);
|
|
455
|
+
const hasChineseApprovalIntent = /(是否|要不要|是否要|需要我|请确认|确认|同意|批准|可以吗|是否可以)/.test(normalized);
|
|
456
|
+
const hasChineseAction = /(继续|开始|生成|创建|提交|执行|渲染|出图|出视频|制作)/.test(normalized);
|
|
457
|
+
return (hasEnglishApprovalIntent && hasEnglishAction) || (hasChineseApprovalIntent && hasChineseAction);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function isPureStatusMessage(text, sourceType, status) {
|
|
461
|
+
const normalized = String(text || '').toLowerCase().replace(/\s+/g, ' ').trim();
|
|
462
|
+
if (sourceType === 'status') return true;
|
|
463
|
+
if (status && !normalized) return true;
|
|
464
|
+
if (!normalized) return false;
|
|
465
|
+
return /^(queued|running|rendering|uploading|processing|generating|completed|complete|done|failed|aborted|started|submitted|waiting|polling)(\.|…|\.\.\.)?$/.test(normalized)
|
|
466
|
+
|| /^(排队中|队列中|运行中|渲染中|上传中|处理中|生成中|已完成|完成|失败|已失败|已提交|等待中)$/.test(normalized);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function hasExplicitApprovalRequirement(data, text) {
|
|
470
|
+
return Boolean(
|
|
471
|
+
data.requires_approval
|
|
472
|
+
|| data.requiresApproval
|
|
473
|
+
|| data.action_required
|
|
474
|
+
|| data.actionRequired
|
|
475
|
+
|| data.proposal
|
|
476
|
+
|| inferApprovalIntent(text)
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function isPureQaRun(data) {
|
|
481
|
+
const raw = [
|
|
482
|
+
data.intent,
|
|
483
|
+
data.mode,
|
|
484
|
+
data.workflow,
|
|
485
|
+
data.workflow_type,
|
|
486
|
+
data.workflowType,
|
|
487
|
+
data.run_type,
|
|
488
|
+
data.runType,
|
|
489
|
+
data.kind,
|
|
490
|
+
].filter(Boolean).join(' ').toLowerCase();
|
|
491
|
+
return /\b(qa|q&a|question_answer|question-answer|answer|pure_qa|pure-qa)\b/.test(raw);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function normalizeDialogueMessage(runId, projectId, ev, context = {}) {
|
|
451
495
|
const data = ev.data || ev;
|
|
452
496
|
const text = data.text || data.message || data.content || data.statusText || '';
|
|
453
497
|
if (!text && ev.type !== 'tool_call') return null;
|
|
454
|
-
const
|
|
498
|
+
const explicitApproval = hasExplicitApprovalRequirement(data, text);
|
|
499
|
+
const textOnlyCheckpoint = Boolean(
|
|
500
|
+
context.stoppedWithoutArtifacts
|
|
501
|
+
&& !explicitApproval
|
|
502
|
+
&& !isPureStatusMessage(text, ev.type, data.status)
|
|
503
|
+
);
|
|
504
|
+
const requiresApproval = explicitApproval || textOnlyCheckpoint;
|
|
455
505
|
const message = {
|
|
456
506
|
type: 'message',
|
|
457
507
|
id: stableEventId('msg', runId, ev.seq, data.id || ev.id),
|
|
@@ -465,6 +515,7 @@ function normalizeDialogueMessage(runId, projectId, ev) {
|
|
|
465
515
|
if (requiresApproval) {
|
|
466
516
|
message.requires_approval = true;
|
|
467
517
|
message.approval_options = data.approval_options || data.approvalOptions || ['approve', 'revise', 'ask_user', 'continue'];
|
|
518
|
+
if (textOnlyCheckpoint) message.approval_reason = 'text_only_checkpoint';
|
|
468
519
|
}
|
|
469
520
|
if (data.proposal) message.proposal = data.proposal;
|
|
470
521
|
return message;
|
|
@@ -474,6 +525,7 @@ function normalizeDialogueArtifact(runId, projectId, item, seq) {
|
|
|
474
525
|
if (!item) return null;
|
|
475
526
|
const kind = item.type || item.kind || (item.imageUrl ? 'image' : item.videoUrl ? 'video' : undefined);
|
|
476
527
|
if (!kind) return null;
|
|
528
|
+
if (!['image', 'video', 'design', 'music', 'audio', 'file'].includes(kind)) return null;
|
|
477
529
|
const artifact = {
|
|
478
530
|
type: 'artifact',
|
|
479
531
|
id: stableEventId('artifact', runId, seq, item.id || item.snapshotId || item.taskId),
|
|
@@ -491,7 +543,7 @@ function normalizeDialogueArtifact(runId, projectId, item, seq) {
|
|
|
491
543
|
return artifact;
|
|
492
544
|
}
|
|
493
545
|
|
|
494
|
-
function normalizeDialogueEvent(runId, projectId, ev) {
|
|
546
|
+
function normalizeDialogueEvent(runId, projectId, ev, context = {}) {
|
|
495
547
|
const data = ev.data || {};
|
|
496
548
|
if (ev.type === 'message' || ev.type === 'approval' || ev.type === 'artifact') {
|
|
497
549
|
return { ...data, ...ev, runId: ev.runId || runId, projectId: ev.projectId || projectId };
|
|
@@ -501,7 +553,7 @@ function normalizeDialogueEvent(runId, projectId, ev) {
|
|
|
501
553
|
case 'status':
|
|
502
554
|
case 'tool_call':
|
|
503
555
|
case 'error':
|
|
504
|
-
return normalizeDialogueMessage(runId, projectId, ev);
|
|
556
|
+
return normalizeDialogueMessage(runId, projectId, ev, context);
|
|
505
557
|
case 'image':
|
|
506
558
|
return normalizeDialogueArtifact(runId, projectId, { type: 'image', status: data.imageUrl ? 'completed' : 'running', imageUrl: data.imageUrl, snapshotId: data.snapshotId }, ev.seq);
|
|
507
559
|
case 'render':
|
|
@@ -519,8 +571,22 @@ function normalizeDialogueEvent(runId, projectId, ev) {
|
|
|
519
571
|
function buildDialogueEvents(runId, data) {
|
|
520
572
|
const projectId = data.projectId || data.project_id;
|
|
521
573
|
const events = [];
|
|
574
|
+
const hasArtifacts = Boolean(
|
|
575
|
+
(data.output || []).some(item => normalizeDialogueArtifact(runId, projectId, item, item.seq))
|
|
576
|
+
|| (data.events || []).some(ev => normalizeDialogueEvent(runId, projectId, ev, { stoppedWithoutArtifacts: false })?.type === 'artifact')
|
|
577
|
+
);
|
|
578
|
+
const hasContinuationAction = (data.events || []).some(ev => ['tool_call', 'image', 'render', 'animation_task', 'video_snapshot', 'music_task'].includes(ev.type));
|
|
579
|
+
const checkpointMode = data.checkpointMode || 'service';
|
|
580
|
+
const context = {
|
|
581
|
+
stoppedWithoutArtifacts: checkpointMode !== 'off'
|
|
582
|
+
&& !isPureQaRun(data)
|
|
583
|
+
&& !hasArtifacts
|
|
584
|
+
&& !hasContinuationAction
|
|
585
|
+
&& !data.incomplete
|
|
586
|
+
&& ['completed', 'failed', 'aborted', 'waiting', 'needs_input'].includes(data.status),
|
|
587
|
+
};
|
|
522
588
|
for (const ev of data.events || []) {
|
|
523
|
-
const normalized = normalizeDialogueEvent(runId, projectId, ev);
|
|
589
|
+
const normalized = normalizeDialogueEvent(runId, projectId, ev, context);
|
|
524
590
|
if (normalized) events.push(normalized);
|
|
525
591
|
}
|
|
526
592
|
for (const item of data.output || []) {
|
|
@@ -533,6 +599,30 @@ function buildDialogueEvents(runId, data) {
|
|
|
533
599
|
return events;
|
|
534
600
|
}
|
|
535
601
|
|
|
602
|
+
function compactDialogueEvents(events) {
|
|
603
|
+
const compacted = [];
|
|
604
|
+
for (const ev of events) {
|
|
605
|
+
const prev = compacted[compacted.length - 1];
|
|
606
|
+
const canMerge = prev
|
|
607
|
+
&& ev.type === 'message'
|
|
608
|
+
&& prev.type === 'message'
|
|
609
|
+
&& ev.source_type === 'content'
|
|
610
|
+
&& prev.source_type === 'content'
|
|
611
|
+
&& !ev.requires_approval
|
|
612
|
+
&& !prev.requires_approval
|
|
613
|
+
&& !ev.proposal
|
|
614
|
+
&& !prev.proposal;
|
|
615
|
+
if (canMerge) {
|
|
616
|
+
prev.text = `${prev.text}${ev.text}`;
|
|
617
|
+
prev.id = `${prev.id}+${ev.id}`;
|
|
618
|
+
prev.seq_end = ev.seq;
|
|
619
|
+
} else {
|
|
620
|
+
compacted.push({ ...ev });
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
return compacted;
|
|
624
|
+
}
|
|
625
|
+
|
|
536
626
|
function findUnhandledApprovalMessages(events) {
|
|
537
627
|
const approved = new Set(events.filter(ev => ev.type === 'approval').map(ev => ev.messageId || ev.message_id));
|
|
538
628
|
return events.filter(ev => ev.type === 'message' && ev.requires_approval && !approved.has(ev.id));
|
|
@@ -548,12 +638,13 @@ async function fetchRun(baseUrl, headers, runId, opts = {}) {
|
|
|
548
638
|
}
|
|
549
639
|
|
|
550
640
|
async function printDialogueEvents(baseUrl, headers, runId, opts = {}) {
|
|
551
|
-
const { jsonl = false, failOnUnapproved = false, follow = false, interval = 5000 } = opts;
|
|
641
|
+
const { jsonl = false, failOnUnapproved = false, follow = false, interval = 5000, compact = false, checkpointMode = 'service' } = opts;
|
|
552
642
|
const printed = new Set();
|
|
553
643
|
|
|
554
644
|
while (true) {
|
|
555
645
|
const data = await fetchRun(baseUrl, headers, runId, { events: true });
|
|
556
|
-
const
|
|
646
|
+
const dialogueEvents = buildDialogueEvents(runId, { ...data, checkpointMode });
|
|
647
|
+
const events = compact ? compactDialogueEvents(dialogueEvents) : dialogueEvents;
|
|
557
648
|
const unhandled = findUnhandledApprovalMessages(events);
|
|
558
649
|
if (failOnUnapproved && unhandled.length) {
|
|
559
650
|
process.stderr.write(`Unhandled Makaron message requires approval: ${unhandled.map(ev => ev.id).join(', ')}\n`);
|
|
@@ -1226,17 +1317,23 @@ if (command === '--version' || command === '-v' || command === 'version') {
|
|
|
1226
1317
|
}
|
|
1227
1318
|
await watchRun(baseUrl, headers, runId, { interval, jsonl });
|
|
1228
1319
|
|
|
1229
|
-
} else if (sub === 'events') {
|
|
1320
|
+
} else if (sub === 'events' || sub === 'timeline') {
|
|
1230
1321
|
const runId = args[2];
|
|
1231
|
-
if (!runId) { console.error(
|
|
1232
|
-
let interval = 5000, jsonl = false, follow = false, failOnUnapproved = false;
|
|
1322
|
+
if (!runId) { console.error(`Usage: makaron responses ${sub} <runId> [--jsonl] [--compact] [--checkpoint-mode service|off] [--follow] [--interval <ms>] [--fail-on-unapproved]`); process.exit(1); }
|
|
1323
|
+
let interval = 5000, jsonl = false, follow = false, failOnUnapproved = false, compact = false, checkpointMode = 'service';
|
|
1233
1324
|
for (let i = 3; i < args.length; i++) {
|
|
1234
1325
|
if (args[i] === '--jsonl') jsonl = true;
|
|
1326
|
+
else if (args[i] === '--compact') compact = true;
|
|
1327
|
+
else if (args[i] === '--checkpoint-mode' && args[i + 1]) checkpointMode = args[++i];
|
|
1235
1328
|
else if (args[i] === '--follow') follow = true;
|
|
1236
1329
|
else if (args[i] === '--fail-on-unapproved') failOnUnapproved = true;
|
|
1237
1330
|
else if (args[i] === '--interval' && args[i + 1]) interval = parseInt(args[++i]);
|
|
1238
1331
|
}
|
|
1239
|
-
|
|
1332
|
+
if (!['service', 'off'].includes(checkpointMode)) {
|
|
1333
|
+
console.error('--checkpoint-mode must be service or off');
|
|
1334
|
+
process.exit(1);
|
|
1335
|
+
}
|
|
1336
|
+
await printDialogueEvents(baseUrl, headers, runId, { interval, jsonl, follow, failOnUnapproved, compact, checkpointMode });
|
|
1240
1337
|
|
|
1241
1338
|
} else if (['approve', 'revise', 'ask-user', 'continue'].includes(sub)) {
|
|
1242
1339
|
const messageId = args[2];
|
|
@@ -1276,6 +1373,8 @@ if (command === '--version' || command === '-v' || command === 'version') {
|
|
|
1276
1373
|
responses get <runId> --wait Poll until completed
|
|
1277
1374
|
responses get <runId> --pick <field> Extract: first_image_url, first_video_url, project_url, output
|
|
1278
1375
|
responses events <runId> --jsonl Emit message/approval/artifact events for external Agents
|
|
1376
|
+
responses timeline <runId> --jsonl Alias for responses events
|
|
1377
|
+
responses timeline <runId> --checkpoint-mode off Disable text-only checkpoints for pure Q&A
|
|
1279
1378
|
responses approve <messageId> --run <runId> Record approval for a Makaron message
|
|
1280
1379
|
responses revise <messageId> --run <runId> Record revision request for a Makaron message
|
|
1281
1380
|
responses ask-user <messageId> --run <runId> Record that the user must decide
|
|
@@ -1718,6 +1817,7 @@ Commands:
|
|
|
1718
1817
|
responses get <runId> Get run status and results
|
|
1719
1818
|
responses get <runId> --wait Poll until completed
|
|
1720
1819
|
responses events <runId> --jsonl Emit message/approval/artifact events
|
|
1820
|
+
responses timeline <runId> --checkpoint-mode off Disable text-only checkpoints for pure Q&A
|
|
1721
1821
|
responses list --project <id> List runs for a project
|
|
1722
1822
|
abort <runId> Abort a running Agent
|
|
1723
1823
|
|
package/package.json
CHANGED
package/skills/makaron/SKILL.md
CHANGED
|
@@ -128,10 +128,13 @@ Outputs one JSON per line as artifacts appear:
|
|
|
128
128
|
|
|
129
129
|
### Dialogue events for external Agents
|
|
130
130
|
|
|
131
|
-
Use this when another Agent needs to read what Makaron said,
|
|
131
|
+
Use this when another Agent needs to read what Makaron said, handle text checkpoints, and relay artifacts without inventing customer-service wording.
|
|
132
132
|
|
|
133
133
|
```bash
|
|
134
134
|
npx makaron-cli responses events <runId> --jsonl
|
|
135
|
+
# alias: npx makaron-cli responses timeline <runId> --jsonl
|
|
136
|
+
# compact view: npx makaron-cli responses timeline <runId> --jsonl --compact
|
|
137
|
+
# pure Q&A view: npx makaron-cli responses timeline <runId> --jsonl --checkpoint-mode off
|
|
135
138
|
```
|
|
136
139
|
|
|
137
140
|
Events use only three factual types:
|
|
@@ -142,7 +145,7 @@ Events use only three factual types:
|
|
|
142
145
|
{"type":"artifact","kind":"image","status":"completed","url":"https://..."}
|
|
143
146
|
```
|
|
144
147
|
|
|
145
|
-
If a message has `requires_approval: true`, the external Agent must record an approval before continuing to wait for artifacts or claiming completion:
|
|
148
|
+
Makaron uses a conservative checkpoint rule for creative/service Agents: if a run stops with substantive text, has no image/video/music/design artifact, and has no continuing execution action such as a tool call, the message is marked `requires_approval: true`. Pure status text such as queued, rendering, uploading, or completed is not treated as a checkpoint. Pure Q&A flows should pass `--checkpoint-mode off`. If a message has `requires_approval: true`, the external Agent must record an approval before continuing to wait for artifacts or claiming completion:
|
|
146
149
|
|
|
147
150
|
```bash
|
|
148
151
|
npx makaron-cli responses approve msg_1 --run <runId> --note "Proceed."
|
|
@@ -151,12 +154,15 @@ npx makaron-cli responses ask-user msg_1 --run <runId>
|
|
|
151
154
|
npx makaron-cli responses continue msg_1 --run <runId>
|
|
152
155
|
```
|
|
153
156
|
|
|
154
|
-
Wrappers can enforce
|
|
157
|
+
Important: approvals are a local Agent gate in v0. They are recorded by the CLI so wrappers and Skills can fail fast, but they do not pause or resume the remote Makaron runtime yet. Wrappers can enforce the local gate with:
|
|
155
158
|
|
|
156
159
|
```bash
|
|
157
|
-
npx makaron-cli responses events <runId> --jsonl --fail-on-unapproved
|
|
160
|
+
npx makaron-cli responses events <runId> --jsonl --checkpoint-mode service --fail-on-unapproved
|
|
161
|
+
# alias: npx makaron-cli responses timeline <runId> --jsonl --compact --fail-on-unapproved
|
|
158
162
|
```
|
|
159
163
|
|
|
164
|
+
Use `--compact` when relaying to another Agent or chat system; it merges consecutive Makaron content chunks into a single readable message.
|
|
165
|
+
|
|
160
166
|
### Extract specific results
|
|
161
167
|
|
|
162
168
|
```bash
|
|
@@ -283,6 +289,33 @@ type MakaronOutput =
|
|
|
283
289
|
| Motion design | "create an Instagram story with animated text" |
|
|
284
290
|
| Multi-step | "edit the photo then make a video from it" |
|
|
285
291
|
|
|
292
|
+
## Minimal Agent Wrapper
|
|
293
|
+
|
|
294
|
+
A new Agent can use this minimal flow:
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
RUN_JSON=$(npx makaron-cli chat --project auto --json -b "$USER_PROMPT")
|
|
298
|
+
RUN_ID=$(echo "$RUN_JSON" | jq -r .runId)
|
|
299
|
+
PROJECT_URL=$(echo "$RUN_JSON" | jq -r .projectUrl)
|
|
300
|
+
send_message "Project created: $PROJECT_URL"
|
|
301
|
+
|
|
302
|
+
if ! npx makaron-cli responses timeline "$RUN_ID" --jsonl --compact --checkpoint-mode service --fail-on-unapproved > /tmp/makaron-events.jsonl; then
|
|
303
|
+
npx makaron-cli responses timeline "$RUN_ID" --jsonl --compact | while read -r event; do
|
|
304
|
+
TYPE=$(echo "$event" | jq -r .type)
|
|
305
|
+
REQUIRES=$(echo "$event" | jq -r ".requires_approval // false")
|
|
306
|
+
TEXT=$(echo "$event" | jq -r ".text // empty")
|
|
307
|
+
MSG_ID=$(echo "$event" | jq -r ".id // empty")
|
|
308
|
+
if [ "$TYPE" = "message" ] && [ "$REQUIRES" = "true" ]; then
|
|
309
|
+
send_message "$TEXT"
|
|
310
|
+
npx makaron-cli responses ask-user "$MSG_ID" --run "$RUN_ID"
|
|
311
|
+
exit 3
|
|
312
|
+
fi
|
|
313
|
+
done
|
|
314
|
+
fi
|
|
315
|
+
|
|
316
|
+
RESULT=$(npx makaron-cli responses get "$RUN_ID" --wait --json)
|
|
317
|
+
```
|
|
318
|
+
|
|
286
319
|
## Recommended Pattern: Service Flow (Feishu/OpenClaw/Group Chat)
|
|
287
320
|
|
|
288
321
|
When serving end-users in a chat environment (Feishu, Slack, Discord), use this proactive message pattern:
|