ticlawk 0.1.16-dev.14 → 0.1.16-dev.15
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/bin/ticlawk.mjs +5 -0
- package/package.json +1 -1
- package/src/adapters/ticlawk/api.mjs +6 -0
- package/src/adapters/ticlawk/index.mjs +33 -2
- package/src/cli/agent-commands.mjs +21 -1
- package/src/core/agent-cli-handlers.mjs +14 -0
- package/src/core/http.mjs +5 -0
- package/src/runtimes/_shared/standing-prompt.mjs +1 -0
package/bin/ticlawk.mjs
CHANGED
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
runDashboardGetCommand,
|
|
44
44
|
runCredentialRequestCommand,
|
|
45
45
|
runBriefingPublishCommand,
|
|
46
|
+
runBriefingGetCommand,
|
|
46
47
|
runServiceCreateCommand,
|
|
47
48
|
runServiceUpdateCommand,
|
|
48
49
|
runServiceDeleteCommand,
|
|
@@ -549,6 +550,10 @@ async function main() {
|
|
|
549
550
|
process.exitCode = await runBriefingPublishCommand(args);
|
|
550
551
|
return;
|
|
551
552
|
}
|
|
553
|
+
if (sub === 'get') {
|
|
554
|
+
process.exitCode = await runBriefingGetCommand(args);
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
552
557
|
console.error(`unknown briefing subcommand: ${sub}`);
|
|
553
558
|
process.exit(1);
|
|
554
559
|
}
|
package/package.json
CHANGED
|
@@ -612,6 +612,12 @@ export async function callService({ actingAgentId, name, input }) {
|
|
|
612
612
|
|
|
613
613
|
// ── Briefings (CoS publish) ──
|
|
614
614
|
|
|
615
|
+
export async function getBriefing({actingAgentId, briefingId}) {
|
|
616
|
+
const params = new URLSearchParams();
|
|
617
|
+
params.set('acting_as_agent_id', actingAgentId);
|
|
618
|
+
return apiFetch(`/api/agent/briefings/${encodeURIComponent(briefingId)}?${params}`);
|
|
619
|
+
}
|
|
620
|
+
|
|
615
621
|
export async function publishBriefing({actingAgentId, bodyText, bodyHtml}) {
|
|
616
622
|
const body = { acting_as_agent_id: actingAgentId };
|
|
617
623
|
if (bodyText != null) body.body_text = bodyText;
|
|
@@ -180,12 +180,39 @@ function buildCosAddendum(msg) {
|
|
|
180
180
|
return COS_ADDENDUM;
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
+
// Quote block: surfaced just above the user's reply so the agent sees
|
|
184
|
+
// what artifact the reply is *about*. Source of truth is
|
|
185
|
+
// `messages.metadata.quote = { kind, ref, snippet }`. We render a
|
|
186
|
+
// short, prefix-cache-friendly block and tell the agent how to fetch
|
|
187
|
+
// the full content if needed.
|
|
188
|
+
function buildQuoteBlock(msg) {
|
|
189
|
+
const meta = msg.message_metadata || msg.metadata || null;
|
|
190
|
+
const quote = meta && typeof meta === 'object' ? meta.quote : null;
|
|
191
|
+
if (!quote || typeof quote !== 'object') return '';
|
|
192
|
+
const kind = String(quote.kind || '').trim();
|
|
193
|
+
const ref = String(quote.ref || '').trim();
|
|
194
|
+
const snippet = String(quote.snippet || '').trim();
|
|
195
|
+
if (!kind || !ref) return '';
|
|
196
|
+
const fetchHint = kind === 'briefing'
|
|
197
|
+
? `ticlawk briefing get ${ref}`
|
|
198
|
+
: kind === 'dashboard'
|
|
199
|
+
? `ticlawk dashboard get --target "#${ref}"`
|
|
200
|
+
: kind === 'message'
|
|
201
|
+
? `ticlawk message read --around ${ref}`
|
|
202
|
+
: '';
|
|
203
|
+
const lines = ['[quote', ` kind=${kind} ref=${ref}`];
|
|
204
|
+
if (snippet) lines.push(` "${snippet.replace(/"/g, '\\"')}"`);
|
|
205
|
+
if (fetchHint) lines.push(` fetch: ${fetchHint}`);
|
|
206
|
+
lines.push('[/quote]');
|
|
207
|
+
return lines.join('\n');
|
|
208
|
+
}
|
|
209
|
+
|
|
183
210
|
// Wrap each per-turn message with an explicit reply instruction so the
|
|
184
211
|
// runtime LLM never has to remember the standing prompt to figure out
|
|
185
212
|
// HOW to reply. Codex in particular treats the developerInstructions as
|
|
186
213
|
// background and ignores the chat-send pattern without this per-turn
|
|
187
214
|
// nudge.
|
|
188
|
-
function buildWakePromptText({ envelopeHeader, target, rawText, groupContext, charterBlock, cosAddendum }) {
|
|
215
|
+
function buildWakePromptText({ envelopeHeader, target, rawText, groupContext, charterBlock, cosAddendum, quoteBlock }) {
|
|
189
216
|
const body = `${envelopeHeader} ${rawText || ''}`.trim();
|
|
190
217
|
const lines = [];
|
|
191
218
|
if (charterBlock) {
|
|
@@ -194,6 +221,9 @@ function buildWakePromptText({ envelopeHeader, target, rawText, groupContext, ch
|
|
|
194
221
|
if (cosAddendum) {
|
|
195
222
|
lines.push(cosAddendum, '');
|
|
196
223
|
}
|
|
224
|
+
if (quoteBlock) {
|
|
225
|
+
lines.push(quoteBlock, '');
|
|
226
|
+
}
|
|
197
227
|
lines.push('New message received:', '', body);
|
|
198
228
|
if (groupContext) {
|
|
199
229
|
lines.push('', groupContext);
|
|
@@ -230,8 +260,9 @@ export function normalizeInboundMessage(msg) {
|
|
|
230
260
|
const groupContext = buildGroupContextBlock(enriched);
|
|
231
261
|
const charterBlock = buildCharterBlock(enriched);
|
|
232
262
|
const cosAddendum = buildCosAddendum(enriched);
|
|
263
|
+
const quoteBlock = buildQuoteBlock(enriched);
|
|
233
264
|
const text = header
|
|
234
|
-
? buildWakePromptText({ envelopeHeader: header, target, rawText, groupContext, charterBlock, cosAddendum })
|
|
265
|
+
? buildWakePromptText({ envelopeHeader: header, target, rawText, groupContext, charterBlock, cosAddendum, quoteBlock })
|
|
235
266
|
: rawText;
|
|
236
267
|
return {
|
|
237
268
|
bindingId: recipientAgentId,
|
|
@@ -1022,6 +1022,21 @@ export async function runServiceCallCommand(args) {
|
|
|
1022
1022
|
return exitFromStatus(res.statusCode);
|
|
1023
1023
|
}
|
|
1024
1024
|
|
|
1025
|
+
export async function runBriefingGetCommand(args) {
|
|
1026
|
+
const env = requireAgentEnv();
|
|
1027
|
+
const id = args._[2] || getArg(args, 'id');
|
|
1028
|
+
if (!id) { console.error('briefing id required (positional or --id)'); return 2; }
|
|
1029
|
+
const params = new URLSearchParams();
|
|
1030
|
+
params.set('id', id);
|
|
1031
|
+
const res = await daemonRequest({
|
|
1032
|
+
method: 'GET',
|
|
1033
|
+
path: `/agent/briefing/get?${params}`,
|
|
1034
|
+
headers: commonHeaders(env),
|
|
1035
|
+
});
|
|
1036
|
+
printJson(res.body);
|
|
1037
|
+
return exitFromStatus(res.statusCode);
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1025
1040
|
export async function runBriefingPublishCommand(args) {
|
|
1026
1041
|
const env = requireAgentEnv();
|
|
1027
1042
|
const textArg = getArg(args, 'text');
|
|
@@ -1272,13 +1287,18 @@ export const AGENT_COMMAND_HELP = {
|
|
|
1272
1287
|
service call --name X # input from stdin (JSON)
|
|
1273
1288
|
Any agent. Backend proxies to endpoint_config.url. No retry.
|
|
1274
1289
|
`,
|
|
1275
|
-
briefing: `ticlawk briefing publish
|
|
1290
|
+
briefing: `ticlawk briefing <publish|get>
|
|
1291
|
+
briefing publish (--text "..." | --html <path>)
|
|
1276
1292
|
CoS-only. Publish a briefing to the owner's Office → Briefings.
|
|
1277
1293
|
--text short plain text (≤100 chars), use for one-liner pings
|
|
1278
1294
|
--html path to an HTML file; body is rendered as a full-screen card
|
|
1279
1295
|
Briefings are independent of chat — they do NOT appear in the CoS
|
|
1280
1296
|
DM message stream. Use this verb (not \`message send\`) for any
|
|
1281
1297
|
status surface the owner consumes in Office.
|
|
1298
|
+
briefing get <id>
|
|
1299
|
+
Fetch a briefing including body_text/body_html. Use this when a
|
|
1300
|
+
quote (metadata.quote.kind=briefing) points at a briefing whose
|
|
1301
|
+
full body you want to read.
|
|
1282
1302
|
`,
|
|
1283
1303
|
credential: `ticlawk credential request --name <ENV_VAR> [--description Y] [--workstream "#<ws>"]
|
|
1284
1304
|
CoS-only. Pre-allocate a credential slot. Response includes a deep
|
|
@@ -908,6 +908,20 @@ export async function handleServiceCall(req, body, ctx) {
|
|
|
908
908
|
}
|
|
909
909
|
}
|
|
910
910
|
|
|
911
|
+
export async function handleBriefingGet(req, query, ctx) {
|
|
912
|
+
const actingAgentId = getActingAgentId(req, query);
|
|
913
|
+
const v = validateActingAgent(actingAgentId, ctx);
|
|
914
|
+
if (!v.ok) return { status: v.status, body: { error: v.error } };
|
|
915
|
+
const briefingId = String(query?.id || '').trim();
|
|
916
|
+
if (!briefingId) return { status: 400, body: { error: 'id is required' } };
|
|
917
|
+
try {
|
|
918
|
+
const data = await api.getBriefing({ actingAgentId, briefingId });
|
|
919
|
+
return { status: 200, body: data };
|
|
920
|
+
} catch (err) {
|
|
921
|
+
return { status: err?.status || 500, body: { error: err?.message || 'briefing get failed' } };
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
|
|
911
925
|
export async function handleBriefingPublish(req, body, ctx) {
|
|
912
926
|
const actingAgentId = getActingAgentId(req, body);
|
|
913
927
|
const v = validateActingAgent(actingAgentId, ctx);
|
package/src/core/http.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
handleWorkstreamDashboardGet,
|
|
15
15
|
handleCredentialRequest,
|
|
16
16
|
handleBriefingPublish,
|
|
17
|
+
handleBriefingGet,
|
|
17
18
|
handleServiceCreate,
|
|
18
19
|
handleServiceUpdate,
|
|
19
20
|
handleServiceDelete,
|
|
@@ -294,6 +295,10 @@ export function startLocalHttpServer({ port, adapter, ctx }) {
|
|
|
294
295
|
const r = await handleBriefingPublish(req, body, cliCtx);
|
|
295
296
|
return writeJson(res, r.status, r.body);
|
|
296
297
|
}
|
|
298
|
+
if (urlNoQuery === '/agent/briefing/get' && method === 'GET') {
|
|
299
|
+
const r = await handleBriefingGet(req, parseQuery(req.url || ''), cliCtx);
|
|
300
|
+
return writeJson(res, r.status, r.body);
|
|
301
|
+
}
|
|
297
302
|
if (urlNoQuery === '/agent/credential/request' && method === 'POST') {
|
|
298
303
|
const body = await readJsonBody(req);
|
|
299
304
|
if (body === null) return writeJson(res, 400, { error: 'invalid json body' });
|
|
@@ -22,6 +22,7 @@ to users or groups.
|
|
|
22
22
|
- Always claim a task via \`ticlawk task claim\` before doing any substantive work on it. If the claim fails, stop immediately and pick a different task.
|
|
23
23
|
- Use only the provided \`ticlawk\` CLI commands for messaging.
|
|
24
24
|
- If the turn opens with a \`[charter] ... [/charter]\` block, that is the workstream's binding spec (规章制度). Every action you take in this conversation must conform to it. If a request conflicts with the charter, stop and surface the conflict to the Chief of Staff (CoS) — don't silently route around it.
|
|
25
|
+
- If the turn opens with a \`[quote ... [/quote]\` block, the user is replying with a quoted artifact in context. The block carries \`kind=<message|briefing|dashboard>\`, \`ref=<id>\`, a snippet, and a \`fetch:\` command to read the full content if you need it. Treat the user's text as a response *to* that artifact.
|
|
25
26
|
- Shared services are CoS-published tools you can invoke. \`ticlawk service list\` shows available names + descriptions; \`ticlawk service info --name X\` shows the input contract; \`ticlawk service call --name X\` runs it with stdin JSON input. There is no retry — call failure means stop and report; do not loop.
|
|
26
27
|
|
|
27
28
|
## Startup checklist (every turn)
|