ticlawk 0.1.16-dev.16 → 0.1.16-dev.18
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/package.json +1 -1
- package/src/adapters/ticlawk/api.mjs +2 -1
- package/src/cli/agent-commands.mjs +12 -4
- package/src/core/agent-cli-handlers.mjs +9 -1
- package/src/runtimes/_shared/goal-task-protocol.mjs +41 -10
- package/src/runtimes/_shared/standing-prompt.mjs +13 -4
- package/src/runtimes/_shared/wake-prompt.mjs +4 -4
package/package.json
CHANGED
|
@@ -625,11 +625,12 @@ export async function getBriefing({actingAgentId, briefingId}) {
|
|
|
625
625
|
return apiFetch(`/api/agent/briefings/${encodeURIComponent(briefingId)}?${params}`);
|
|
626
626
|
}
|
|
627
627
|
|
|
628
|
-
export async function publishBriefing({actingAgentId, bodyText, attachmentAssetId, currentConversationId}) {
|
|
628
|
+
export async function publishBriefing({actingAgentId, bodyText, attachmentAssetId, currentConversationId, responseMode}) {
|
|
629
629
|
const body = { acting_as_agent_id: actingAgentId };
|
|
630
630
|
if (bodyText != null) body.body_text = bodyText;
|
|
631
631
|
if (attachmentAssetId != null) body.attachment_asset_id = attachmentAssetId;
|
|
632
632
|
if (currentConversationId != null) body.current_conversation_id = currentConversationId;
|
|
633
|
+
if (responseMode != null) body.response_mode = responseMode;
|
|
633
634
|
return apiFetch('/api/agent/briefings', {
|
|
634
635
|
method: 'POST',
|
|
635
636
|
body: JSON.stringify(body),
|
|
@@ -1067,6 +1067,7 @@ export async function runBriefingPublishCommand(args) {
|
|
|
1067
1067
|
const env = requireAgentEnv();
|
|
1068
1068
|
const textArg = getArg(args, 'text');
|
|
1069
1069
|
const attachPath = getArg(args, 'attach');
|
|
1070
|
+
const mode = String(getArg(args, 'mode') || 'info').trim().toLowerCase();
|
|
1070
1071
|
if (!textArg) {
|
|
1071
1072
|
console.error('--text "<short>" is required');
|
|
1072
1073
|
return 2;
|
|
@@ -1075,6 +1076,10 @@ export async function runBriefingPublishCommand(args) {
|
|
|
1075
1076
|
console.error('--text must be ≤140 chars');
|
|
1076
1077
|
return 2;
|
|
1077
1078
|
}
|
|
1079
|
+
if (!['info', 'approval'].includes(mode)) {
|
|
1080
|
+
console.error('--mode must be info or approval');
|
|
1081
|
+
return 2;
|
|
1082
|
+
}
|
|
1078
1083
|
let attachmentAssetId = null;
|
|
1079
1084
|
if (attachPath) {
|
|
1080
1085
|
const contentType = inferContentType(String(attachPath));
|
|
@@ -1097,6 +1102,7 @@ export async function runBriefingPublishCommand(args) {
|
|
|
1097
1102
|
body_text: textArg,
|
|
1098
1103
|
attachment_asset_id: attachmentAssetId,
|
|
1099
1104
|
current_conversation_id: env.currentConversationId,
|
|
1105
|
+
response_mode: mode,
|
|
1100
1106
|
},
|
|
1101
1107
|
});
|
|
1102
1108
|
printJson(res.body);
|
|
@@ -1242,9 +1248,10 @@ export const AGENT_COMMAND_HELP = {
|
|
|
1242
1248
|
unless --allow-cross-target is passed deliberately.
|
|
1243
1249
|
--kind <kind> tags this message via metadata.kind.
|
|
1244
1250
|
Targets:
|
|
1245
|
-
dm
|
|
1246
|
-
|
|
1247
|
-
#<group
|
|
1251
|
+
dm:<conversation-id> private message by conversation id
|
|
1252
|
+
dm:@<user> private message by user/agent handle
|
|
1253
|
+
#<group> group conversation by name or id
|
|
1254
|
+
#<group>:<msgid> replies under a top-level message in that group
|
|
1248
1255
|
--attach <file> uploads a local file and attaches it to the message
|
|
1249
1256
|
(repeatable; max 10 attachments per message).
|
|
1250
1257
|
ticlawk message read --target "<target>" [--around <msg-id>] [--before-seq N] [--limit N]
|
|
@@ -1325,10 +1332,11 @@ export const AGENT_COMMAND_HELP = {
|
|
|
1325
1332
|
Any agent. Backend proxies to endpoint_config.url. No retry.
|
|
1326
1333
|
`,
|
|
1327
1334
|
briefing: `ticlawk briefing <publish|get>
|
|
1328
|
-
briefing publish --text "..." [--attach <image|video|html path>]
|
|
1335
|
+
briefing publish --text "..." [--mode info|approval] [--attach <image|video|html path>]
|
|
1329
1336
|
Publish a briefing to the owner's Briefings. Allowed from DMs, or
|
|
1330
1337
|
from groups where this agent is admin/owner.
|
|
1331
1338
|
--text short plain text (≤140 chars)
|
|
1339
|
+
--mode owner response mode: info shows ack; approval shows approve
|
|
1332
1340
|
--attach optional image, video, or HTML file when visual context matters
|
|
1333
1341
|
Briefings are independent of chat — they do NOT appear in any DM
|
|
1334
1342
|
message stream. Use this verb (not \`message send\`) for any status
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* and forwards to the ticlawk backend using the connector API key.
|
|
8
8
|
*
|
|
9
9
|
* Targets are parsed in the daemon (not on the wire to backend) so the
|
|
10
|
-
* CLI can speak `#<group>` / `dm:@<user>` /
|
|
10
|
+
* CLI can speak `#<group>` / `dm:<conversation-id>` / `dm:@<user>` /
|
|
11
|
+
* `#<group>:<short-msg-id>`
|
|
11
12
|
* while backend keeps a flat conversation_id contract.
|
|
12
13
|
*/
|
|
13
14
|
|
|
@@ -981,12 +982,18 @@ export async function handleBriefingPublish(req, body, ctx) {
|
|
|
981
982
|
const attachmentAssetId = typeof body?.attachment_asset_id === 'string' && body.attachment_asset_id.trim()
|
|
982
983
|
? body.attachment_asset_id.trim()
|
|
983
984
|
: null;
|
|
985
|
+
const responseMode = typeof body?.response_mode === 'string' && body.response_mode.trim()
|
|
986
|
+
? body.response_mode.trim().toLowerCase()
|
|
987
|
+
: 'info';
|
|
984
988
|
if (!bodyText) {
|
|
985
989
|
return { status: 400, body: { error: 'body_text is required' } };
|
|
986
990
|
}
|
|
987
991
|
if (bodyText && bodyText.length > 140) {
|
|
988
992
|
return { status: 400, body: { error: 'body_text must be ≤140 chars' } };
|
|
989
993
|
}
|
|
994
|
+
if (!['info', 'approval'].includes(responseMode)) {
|
|
995
|
+
return { status: 400, body: { error: 'response_mode must be info or approval' } };
|
|
996
|
+
}
|
|
990
997
|
const currentConversationId = getCurrentConversationId(req, body);
|
|
991
998
|
try {
|
|
992
999
|
const data = await api.publishBriefing({
|
|
@@ -994,6 +1001,7 @@ export async function handleBriefingPublish(req, body, ctx) {
|
|
|
994
1001
|
bodyText,
|
|
995
1002
|
attachmentAssetId,
|
|
996
1003
|
currentConversationId,
|
|
1004
|
+
responseMode,
|
|
997
1005
|
});
|
|
998
1006
|
return { status: 200, body: data };
|
|
999
1007
|
} catch (err) {
|
|
@@ -71,18 +71,45 @@ Core concepts:
|
|
|
71
71
|
- Quote: context showing which message, briefing, or dashboard the user is responding to.
|
|
72
72
|
- Task board: the persistent group task list managed through \`ticlawk task list/create/claim/unclaim/update\`.
|
|
73
73
|
- Claimable task: a task assigned to you or an unclaimed task you are about to execute.
|
|
74
|
-
- Dashboard: an owner-facing HTML report for the conversation goal. It is the visual presentation of the key information associated with the level of achievement of the goal, like a report sent to a CEO for review.
|
|
75
|
-
- Briefing: an active notification to the owner. It tells the owner what happened, why it matters to the goal, and what owner action is needed, if any.
|
|
74
|
+
- Dashboard: an owner-facing HTML report for the conversation goal. It is the visual presentation of the key information associated with the level of achievement of the goal, like a report sent to a CEO for review. It is published or updated with \`ticlawk dashboard set\` as an \`html_template\` plus optional structured \`data_json\`.
|
|
75
|
+
- Briefing: an active notification to the owner. It tells the owner what happened, why it matters to the goal, and what owner action is needed, if any. It is published with \`ticlawk briefing publish --text "..." --mode info\` for updates/notifications, or \`--mode approval\` when the owner needs to approve, optionally with one image, video, or HTML attachment when visual context matters.
|
|
76
|
+
`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function buildOperatingModes() {
|
|
80
|
+
return promptBlock(`
|
|
81
|
+
Operating modes:
|
|
82
|
+
- Before acting, determine the conversation scope, your role, and the goal state from the inbound message, charter, task board, and recent context.
|
|
83
|
+
- In a DM, own the direct ask. Answer one-off asks directly; when durable owner intent is visible, run goal setup, then run the goal loop once the goal exists.
|
|
84
|
+
- In a group where you are admin or owner and a local goal exists, own the group goal loop and task system.
|
|
85
|
+
- In a group where you are admin or owner and no local goal exists, do not invent one. If the owner clearly expresses a durable group/workstream goal, run goal setup; otherwise handle only the current coordination need.
|
|
86
|
+
- In a group where you are not admin or owner, do not drive the group goal. Work only on assigned, claimable, or directly delegated tasks through the task worker loop.
|
|
87
|
+
- Ambient group messages are visible context, not automatic work, unless your role, task ownership, or expertise makes you clearly the right responder.
|
|
76
88
|
`);
|
|
77
89
|
}
|
|
78
90
|
|
|
79
91
|
function buildStateSurfaceRules() {
|
|
80
92
|
return promptBlock(`
|
|
81
93
|
Dashboard and briefing rules:
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
-
|
|
85
|
-
-
|
|
94
|
+
- Create the initial dashboard during goal setup, publish it, and explicitly ask the owner whether the dashboard layout, basic style, and decision view are satisfactory.
|
|
95
|
+
- After the owner accepts the initial dashboard direction, treat its layout and basic style as stable. Routine dashboard updates should update content/data inside that design, not redesign the page.
|
|
96
|
+
- Redesign the dashboard layout or basic style only when the goal, success metrics, or main owner focus changes materially; summarize the change and confirm it before replacing the dashboard design.
|
|
97
|
+
- Keep briefings for active owner notifications: milestone reached, important change, blocker, request for owner input/resources/permission/confirmation/decision, or final result.
|
|
98
|
+
- When creating or materially updating a polished HTML artifact for any ${BRAND_NAME} surface, use \`/vibeshare generate\`. If \`/vibeshare\` is not installed or available in your skills, install it first using the setup instructions at https://vibeshare.page/skill.
|
|
99
|
+
- When using \`/vibeshare generate\` for a briefing HTML attachment, include in the generation request that the HTML will render on mobile and should act as a focused visual aid for understanding the briefing: emphasize the key visual elements, relationships, status, numbers, or choices that clarify the message and owner action, rather than trying to include all supporting detail. Do not build complex gestures, slideshows, carousels, paginated flows, or custom navigation that could conflict with the host mobile surface.
|
|
100
|
+
- For ${BRAND_NAME} dashboards and briefing HTML attachments, \`/vibeshare\` is the HTML generation path only. Publish the generated dashboard HTML with \`ticlawk dashboard set\`, and publish briefing text/attachments with \`ticlawk briefing publish\`; do not use \`/vibeshare publish\` for these ${BRAND_NAME} surfaces.
|
|
101
|
+
`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function buildGoalSetupRules() {
|
|
105
|
+
return promptBlock(`
|
|
106
|
+
Goal setup when no chartered goal exists:
|
|
107
|
+
- Do not turn every one-off request into a durable goal. Answer direct asks normally unless the owner expresses a lasting aspiration, ongoing objective, tracking need, reminder cadence, multi-step roadmap, or resource/coordinator need.
|
|
108
|
+
- When durable intent is visible and no suitable chartered goal exists, propose making it a conversation goal. Clarify whether it belongs in the current DM, an existing group/workstream, or a new workstream before writing state.
|
|
109
|
+
- Clarify only the details needed to proceed: goal definition, success/completion criteria, time range, constraints/boundaries, rough approach or roadmap, the agent's deliverables, owner responsibilities, required files/repos/accounts/credentials/budget/resources, dashboard decision view and metrics, and briefing triggers/cadence.
|
|
110
|
+
- Before setting a charter, summarize the proposed short charter and ask for confirmation. Keep charters to the local goal, roles, success criteria, and boundaries; do not put shared workflow law, dashboard state, task status, or long playbooks in the charter.
|
|
111
|
+
- After confirmation, write the charter if you have scope authority. Then create and publish the initial dashboard as part of goal setup, push it to the owner for review, and ask whether the layout/style/decision view are satisfactory. Create reminders/resources only when useful, and seed group tasks only in group/workstream scope. Then enter the normal goal loop.
|
|
112
|
+
- Treat goal setup as revisable. If the owner changes the goal, metrics, cadence, scope, or boundaries later, summarize the change, confirm if it materially changes the agreement, then update the charter and related surfaces.
|
|
86
113
|
`);
|
|
87
114
|
}
|
|
88
115
|
|
|
@@ -91,6 +118,7 @@ function buildGoalLoopOverlay() {
|
|
|
91
118
|
Goal authority overlay: responsible for this conversation's goal and tasks
|
|
92
119
|
- You are responsible for driving the conversation toward its goal, not only replying to isolated messages.
|
|
93
120
|
- Maintain or infer the current goal from the direct ask, charter, dashboard/briefing quote, task board, and conversation context.
|
|
121
|
+
${buildGoalSetupRules()}
|
|
94
122
|
- Run the goal loop:
|
|
95
123
|
1. Evaluate current facts against the goal.
|
|
96
124
|
2. Identify the concrete gap, if any.
|
|
@@ -101,7 +129,7 @@ Goal authority overlay: responsible for this conversation's goal and tasks
|
|
|
101
129
|
- Stop the loop only when there is no meaningful gap, progress is blocked because the owner needs to provide input/resources/permission/confirmation/decision, or progress depends on an external/time-based wait.
|
|
102
130
|
- If there is no gap, say so briefly. If the goal is complete, report completion.
|
|
103
131
|
- If user input, resources, permission, confirmation, or a decision is needed, publish a briefing with one clear bundled request to the owner.
|
|
104
|
-
- If progress depends on future state, use a reminder or explicit resume condition rather than silently stalling.
|
|
132
|
+
- If progress depends on an external or time-based future state and no agent or owner can act now, use a reminder or explicit resume condition rather than silently stalling. Do not use reminders to defer an executable next step or an owner decision/request.
|
|
105
133
|
- When a task reaches \`in_review\` or \`done\`, re-run the goal loop before dashboard, MEMORY.md, briefing, or wrap-up updates.
|
|
106
134
|
- Keep persistent state surfaces distinct: dashboard for goal-level reporting, MEMORY.md for your local continuity, and briefings for active owner notifications.
|
|
107
135
|
- Publish briefings and update dashboards only from DMs you own or groups where you are admin/owner.
|
|
@@ -136,6 +164,7 @@ function buildGroupGoalScopeOverlay() {
|
|
|
136
164
|
Scope overlay: group with admin or owner role
|
|
137
165
|
- In a group where you are admin or owner, you own both the group goal loop and the task system.
|
|
138
166
|
- Use the group task board for task inventory and assignment.
|
|
167
|
+
- When you delegate substantive work to another agent, make it a group task before or while requesting the work. When results return, update task state and re-run the group goal loop.
|
|
139
168
|
- Group messages coordinate working agents. Dashboard, MEMORY.md, and briefings are tracking/reporting surfaces with distinct roles.
|
|
140
169
|
- As admin/owner, update the group dashboard when the goal-level report the requester would care about has changed.
|
|
141
170
|
- As admin/owner, publish a briefing only when the owner should be actively notified: milestone reached, important change, blocker, request for owner input/resources/permission/confirmation/decision, or final result.
|
|
@@ -182,15 +211,17 @@ export function buildGoalTaskProtocolPrompt(ctx = {}) {
|
|
|
182
211
|
[protocol:${GOAL_TASK_PROTOCOL_MODULE}]
|
|
183
212
|
This is the single source of prompt truth for ${BRAND_NAME} goal/task behavior. Compose universal invariants with exactly one authority overlay and one scope overlay.
|
|
184
213
|
|
|
185
|
-
${buildUniversalInvariants()}
|
|
186
|
-
|
|
187
214
|
${buildCoreConcepts()}
|
|
188
215
|
|
|
189
|
-
${
|
|
216
|
+
${buildUniversalInvariants()}
|
|
217
|
+
|
|
218
|
+
${buildOperatingModes()}
|
|
190
219
|
|
|
191
220
|
${authorityOverlay}
|
|
192
221
|
|
|
193
222
|
${scopeOverlay}
|
|
223
|
+
|
|
224
|
+
${buildStateSurfaceRules()}
|
|
194
225
|
[/protocol:${GOAL_TASK_PROTOCOL_MODULE}]
|
|
195
226
|
`);
|
|
196
227
|
}
|
|
@@ -37,7 +37,7 @@ private activity text; it is not sent to users or groups.
|
|
|
37
37
|
## Per-Turn Routine
|
|
38
38
|
|
|
39
39
|
1. Read \`MEMORY.md\` in your cwd, then only the files/context needed for
|
|
40
|
-
the current turn.
|
|
40
|
+
the current turn. Follow linked notes only when they are relevant.
|
|
41
41
|
2. If there is no concrete inbound message or reminder to handle, stop.
|
|
42
42
|
3. If the message includes \`[charter]\`, treat it as the local
|
|
43
43
|
conversation goal and role spec.
|
|
@@ -56,10 +56,18 @@ private activity text; it is not sent to users or groups.
|
|
|
56
56
|
- \`ticlawk charter get/set\`: inspect or update the current conversation's
|
|
57
57
|
goal and role spec. DM agents may write their DM charter; group charter
|
|
58
58
|
writes require admin/owner role.
|
|
59
|
+
- \`ticlawk dashboard set/get\`: publish or read owner-facing HTML
|
|
60
|
+
dashboards. \`set\` reads JSON from stdin: \`{ html_template, data_json }\`.
|
|
61
|
+
Allowed from DMs, or from groups where this agent is admin/owner.
|
|
62
|
+
- \`ticlawk briefing publish/get\`: publish or read owner-facing briefings.
|
|
63
|
+
Use \`publish --text "..."\` with \`--mode info\` for updates/notifications
|
|
64
|
+
or \`--mode approval\` when the owner needs to approve, plus an optional
|
|
65
|
+
\`--attach <image|video|html>\`.
|
|
66
|
+
Allowed from DMs, or from groups where this agent is admin/owner.
|
|
59
67
|
- \`ticlawk task list/create/claim/unclaim/update\`: use only as allowed by
|
|
60
68
|
the goal/task protocol and backend errors.
|
|
61
|
-
- \`ticlawk reminder schedule/snooze/update/cancel\`: use for
|
|
62
|
-
follow-up that should be visible and persistent in ${BRAND_NAME}.
|
|
69
|
+
- \`ticlawk reminder schedule/snooze/update/cancel\`: use only for external or
|
|
70
|
+
time-based future follow-up that should be visible and persistent in ${BRAND_NAME}.
|
|
63
71
|
- \`ticlawk service list/info/call\`: use shared services when a published
|
|
64
72
|
tool matches the task. If a service call fails, report the failure; do not
|
|
65
73
|
retry in a loop.
|
|
@@ -105,7 +113,8 @@ private activity text; it is not sent to users or groups.
|
|
|
105
113
|
|
|
106
114
|
If a new message arrives while you are busy, finish the current step before
|
|
107
115
|
pivoting unless the new message clearly supersedes the current work. The
|
|
108
|
-
daemon
|
|
116
|
+
daemon wakes agents for new messages and reminders; you do not need to poll.
|
|
117
|
+
When future self-resume is needed, schedule a reminder.`;
|
|
109
118
|
|
|
110
119
|
export function buildStandingPrompt(_ctx = {}) {
|
|
111
120
|
return promptBlock(`
|
|
@@ -105,7 +105,7 @@ ${charter}
|
|
|
105
105
|
// `messages.metadata.quote = { kind, ref, snippet }`. We render a
|
|
106
106
|
// short, prefix-cache-friendly block and tell the agent how to fetch
|
|
107
107
|
// the full content if needed.
|
|
108
|
-
export function buildQuoteBlock(msg) {
|
|
108
|
+
export function buildQuoteBlock(msg, target = '') {
|
|
109
109
|
const meta = msg.message_metadata || msg.metadata || null;
|
|
110
110
|
const quote = meta && typeof meta === 'object' ? meta.quote : null;
|
|
111
111
|
if (!quote || typeof quote !== 'object') return '';
|
|
@@ -116,9 +116,9 @@ export function buildQuoteBlock(msg) {
|
|
|
116
116
|
const fetchHint = kind === 'briefing'
|
|
117
117
|
? `ticlawk briefing get ${ref}`
|
|
118
118
|
: kind === 'dashboard'
|
|
119
|
-
? `ticlawk dashboard get --
|
|
119
|
+
? `ticlawk dashboard get --conversation-id ${ref}`
|
|
120
120
|
: kind === 'message'
|
|
121
|
-
? `ticlawk message read --around ${ref}`
|
|
121
|
+
? `ticlawk message read --target ${JSON.stringify(target)} --around ${ref}`
|
|
122
122
|
: '';
|
|
123
123
|
const snippetLine = snippet ? `\n "${snippet.replace(/"/g, '\\"')}"` : '';
|
|
124
124
|
const fetchLine = fetchHint ? `\n fetch: ${fetchHint}` : '';
|
|
@@ -160,7 +160,7 @@ export function buildInboundWakePrompt(msg) {
|
|
|
160
160
|
const target = buildEnvelopeTarget(msg);
|
|
161
161
|
const groupContext = buildGroupContextBlock(msg);
|
|
162
162
|
const charterBlock = buildCharterBlock(msg);
|
|
163
|
-
const quoteBlock = buildQuoteBlock(msg);
|
|
163
|
+
const quoteBlock = buildQuoteBlock(msg, target);
|
|
164
164
|
const text = header
|
|
165
165
|
? buildWakePromptText({ envelopeHeader: header, target, rawText, groupContext, charterBlock, quoteBlock })
|
|
166
166
|
: rawText;
|