@ziggs-ai/api-client 0.20.0 → 0.21.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/dist/capabilities/agreementVerbs.d.ts +7 -0
- package/dist/capabilities/agreementVerbs.js +84 -1
- package/dist/capabilities/artifacts.js +53 -26
- package/dist/capabilities/chat.d.ts +31 -1
- package/dist/capabilities/chat.js +39 -0
- package/dist/capabilities/context.d.ts +1 -0
- package/dist/capabilities/context.js +42 -1
- package/dist/capabilities/index.d.ts +4 -4
- package/dist/capabilities/index.js +4 -4
- package/dist/capabilities/marketplace.js +15 -6
- package/dist/capabilities/nextCall.js +62 -4
- package/dist/capabilities/tasks.d.ts +68 -1
- package/dist/capabilities/tasks.js +112 -3
- package/dist/engagementGuide.d.ts +148 -0
- package/dist/engagementGuide.js +349 -0
- package/dist/http/AgreementClient.d.ts +2 -1
- package/dist/http/AgreementClient.js +4 -0
- package/dist/http/ChatClient.d.ts +28 -2
- package/dist/http/ChatClient.js +7 -0
- package/dist/http/ContextGrantsClient.d.ts +17 -1
- package/dist/http/ContextGrantsClient.js +26 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/types.d.ts +11 -0
- package/package.json +2 -2
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type TaskWriteConfirm } from '../http/TaskClient.js';
|
|
2
|
+
import { type CapabilityDefinition, type CapabilityEnv } from './types.js';
|
|
3
|
+
import { type NextCall, type NextCallOutcome, type WorkContext } from './nextCall.js';
|
|
2
4
|
/**
|
|
3
5
|
* One list-tasks verb. MCP and the hosted SDK both used to re-declare the
|
|
4
6
|
* same GET /tasks filters; assignedToMe vs assignedTo precedence then
|
|
@@ -6,4 +8,69 @@ import { type CapabilityDefinition } from './types.js';
|
|
|
6
8
|
* those shorthands onto the HTTP query.
|
|
7
9
|
*/
|
|
8
10
|
export declare const listTasksCapability: CapabilityDefinition;
|
|
11
|
+
/**
|
|
12
|
+
* Withdraw a task — including a held graph, which is one cancel on the root.
|
|
13
|
+
* Catalog, not native: this is the pointer AX-07 names, not a new protocol verb.
|
|
14
|
+
*/
|
|
15
|
+
export declare const cancelTaskCapability: CapabilityDefinition;
|
|
16
|
+
/**
|
|
17
|
+
* What a terminal transition actually did, as the server reported it.
|
|
18
|
+
*
|
|
19
|
+
* Mirrors the backend's `effects` block on the task write confirmation. Every
|
|
20
|
+
* field is optional because an older server does not send it, and a fact that
|
|
21
|
+
* did not arrive must not be narrated: silence beats a guess about money.
|
|
22
|
+
*/
|
|
23
|
+
export interface TaskOutcomeEffects {
|
|
24
|
+
resultRecorded?: boolean;
|
|
25
|
+
/** The transition was a de-duplicated replay; no effect ran a second time. */
|
|
26
|
+
replayed?: boolean;
|
|
27
|
+
/** Who a completion wake was QUEUED for — never who read it. */
|
|
28
|
+
notified?: string[];
|
|
29
|
+
settlement?: {
|
|
30
|
+
metered: boolean;
|
|
31
|
+
settled: boolean;
|
|
32
|
+
reason?: string;
|
|
33
|
+
amount?: number;
|
|
34
|
+
transactionId?: string;
|
|
35
|
+
};
|
|
36
|
+
agreement?: {
|
|
37
|
+
agreementId: string;
|
|
38
|
+
billing?: string | null;
|
|
39
|
+
status?: string | null;
|
|
40
|
+
fulfilledNow: boolean;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export interface TaskOutcomePresentation {
|
|
44
|
+
ok: true;
|
|
45
|
+
taskId: string;
|
|
46
|
+
state: string;
|
|
47
|
+
outcome: NextCallOutcome;
|
|
48
|
+
/** Where the outcome now lives, and who can read it. */
|
|
49
|
+
recorded: string;
|
|
50
|
+
/** What was queued for whom — stated as queued, never as received. */
|
|
51
|
+
handoff?: string;
|
|
52
|
+
/** Delivery to the person, which a task result is not. */
|
|
53
|
+
delivery?: string;
|
|
54
|
+
/** What metering did on this completion. Absent when the server said nothing. */
|
|
55
|
+
metering?: string;
|
|
56
|
+
/** What the agreement is now. Absent when the server said nothing. */
|
|
57
|
+
agreement?: string;
|
|
58
|
+
next: NextCall[];
|
|
59
|
+
workContext?: WorkContext;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Present a terminal transition as the four separate facts it produces.
|
|
63
|
+
*
|
|
64
|
+
* `{ ok: true, state: 'completed' }` was the whole answer, and four
|
|
65
|
+
* different claims were read out of it: the work is delivered, the next agent
|
|
66
|
+
* has it, the money moved, the engagement is done. Only the first is in the
|
|
67
|
+
* word. The rest are effects the server ran (or declined to run) beside it, and
|
|
68
|
+
* each one gets its own clause here — including the ones that say nothing
|
|
69
|
+
* happened, because "no settlement ran" is exactly the fact an agent otherwise
|
|
70
|
+
* fills in with an assumption.
|
|
71
|
+
*
|
|
72
|
+
* The lookup route is named rather than described: a completion whose response
|
|
73
|
+
* was lost is recovered by reading the task back, not by completing it twice.
|
|
74
|
+
*/
|
|
75
|
+
export declare function presentTaskOutcome(confirm: TaskWriteConfirm, env: CapabilityEnv): TaskOutcomePresentation;
|
|
9
76
|
export declare const TASK_CAPABILITIES: CapabilityDefinition[];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { listTasks } from '../http/TaskClient.js';
|
|
2
|
-
import { fullCreds } from './types.js';
|
|
1
|
+
import { cancelTask, listTasks } from '../http/TaskClient.js';
|
|
2
|
+
import { fullCreds, rethrowWithContext, } from './types.js';
|
|
3
3
|
import { LIST_FIELDS_PARAM, parseListFields, pickListedRows } from './listedFields.js';
|
|
4
|
+
import { nextCall, workContextFromEnv, } from './nextCall.js';
|
|
4
5
|
/**
|
|
5
6
|
* One list-tasks verb. MCP and the hosted SDK both used to re-declare the
|
|
6
7
|
* same GET /tasks filters; assignedToMe vs assignedTo precedence then
|
|
@@ -63,4 +64,112 @@ export const listTasksCapability = {
|
|
|
63
64
|
: listed;
|
|
64
65
|
},
|
|
65
66
|
};
|
|
66
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Withdraw a task — including a held graph, which is one cancel on the root.
|
|
69
|
+
* Catalog, not native: this is the pointer AX-07 names, not a new protocol verb.
|
|
70
|
+
*/
|
|
71
|
+
export const cancelTaskCapability = {
|
|
72
|
+
key: 'task_cancel',
|
|
73
|
+
names: { sdk: 'task_cancel', mcp: 'ziggs_task_cancel' },
|
|
74
|
+
title: 'Cancel a task',
|
|
75
|
+
descriptions: {
|
|
76
|
+
sdk: 'Cancel one task (PATCH /tasks/:id/cancel). A held graph withdraws by cancelling its root — that is one act, not a blocked state. Cancel ends this task; it does not amend a live hire.',
|
|
77
|
+
mcp: 'Cancel one task (PATCH /tasks/:id/cancel). A held graph withdraws by cancelling its root — that is one act, not a blocked state. Cancel ends this task; it does not amend a live hire.',
|
|
78
|
+
},
|
|
79
|
+
annotation: 'write',
|
|
80
|
+
params: {
|
|
81
|
+
taskId: {
|
|
82
|
+
type: 'string',
|
|
83
|
+
required: true,
|
|
84
|
+
description: 'The task to cancel. For a held graph, pass the root.',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
needsAgentId: true,
|
|
88
|
+
handler: async (args, env) => {
|
|
89
|
+
try {
|
|
90
|
+
return await cancelTask(args['taskId'], fullCreds(env));
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
rethrowWithContext(e, 'task_cancel');
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
/** Why a metered settlement moved nothing, in words rather than a code. */
|
|
98
|
+
const SETTLEMENT_REASONS = {
|
|
99
|
+
not_metered: 'this agreement does not bill per completed task',
|
|
100
|
+
unpriced: 'the agreement carries no price',
|
|
101
|
+
parties_unresolved: 'the paying or providing side is not a resolvable party',
|
|
102
|
+
self_hire: 'payer and provider are the same side — paying yourself is a no-op',
|
|
103
|
+
same_wallet: 'both sides resolve to one wallet',
|
|
104
|
+
wallet_missing: 'a wallet is missing',
|
|
105
|
+
transfer_failed: 'the transfer failed and is left for reconciliation',
|
|
106
|
+
agreement_missing: 'the agreement could not be read',
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Present a terminal transition as the four separate facts it produces.
|
|
110
|
+
*
|
|
111
|
+
* `{ ok: true, state: 'completed' }` was the whole answer, and four
|
|
112
|
+
* different claims were read out of it: the work is delivered, the next agent
|
|
113
|
+
* has it, the money moved, the engagement is done. Only the first is in the
|
|
114
|
+
* word. The rest are effects the server ran (or declined to run) beside it, and
|
|
115
|
+
* each one gets its own clause here — including the ones that say nothing
|
|
116
|
+
* happened, because "no settlement ran" is exactly the fact an agent otherwise
|
|
117
|
+
* fills in with an assumption.
|
|
118
|
+
*
|
|
119
|
+
* The lookup route is named rather than described: a completion whose response
|
|
120
|
+
* was lost is recovered by reading the task back, not by completing it twice.
|
|
121
|
+
*/
|
|
122
|
+
export function presentTaskOutcome(confirm, env) {
|
|
123
|
+
const effects = confirm.effects;
|
|
124
|
+
const workContext = workContextFromEnv(env);
|
|
125
|
+
const taskId = confirm.taskId;
|
|
126
|
+
const state = String(confirm.state);
|
|
127
|
+
const completed = state === 'completed';
|
|
128
|
+
const stored = effects?.resultRecorded ?? confirm.resultRecorded ?? false;
|
|
129
|
+
// MCP delegates read one task by id; the hosted surface lists its own work.
|
|
130
|
+
const lookupKey = env.surface === 'mcp' ? 'task_get' : 'task_list';
|
|
131
|
+
const lookup = nextCall(env, lookupKey, lookupKey === 'task_get' ? { taskId } : { assignedToMe: true }, 'read the recorded outcome back — the route for a completion whose response you never saw, and the one that never completes the task twice');
|
|
132
|
+
const recorded = effects?.replayed
|
|
133
|
+
? `Task ${taskId} was already ${state}: this call matched a transition already applied, so nothing was recorded, queued, metered or fulfilled a second time.`
|
|
134
|
+
: stored
|
|
135
|
+
? `Task ${taskId} is ${state} and its result is stored on the task. That is where the next agent reads it — it stays readable whether or not any notification lands.`
|
|
136
|
+
: `Task ${taskId} is ${state} with no result payload stored. Nothing is waiting there for the next reader.`;
|
|
137
|
+
const notified = effects?.notified;
|
|
138
|
+
const handoff = notified === undefined
|
|
139
|
+
? undefined
|
|
140
|
+
: notified.length > 0
|
|
141
|
+
? `Completion queued for ${notified.join(', ')}. Queued is not read: the wake says it was sent, never that anyone has it.`
|
|
142
|
+
: 'No completion wake was queued — nobody on this agreement was addressable, so the result waits to be read rather than delivered.';
|
|
143
|
+
const delivery = completed
|
|
144
|
+
? 'A task result is how the next AGENT collects the work. If a person set this goal, send it to them as well, in the conversation the work rides on — that delivery is a chat message, not a second record.'
|
|
145
|
+
: undefined;
|
|
146
|
+
const settlement = effects?.settlement;
|
|
147
|
+
const metering = !settlement
|
|
148
|
+
? undefined
|
|
149
|
+
: settlement.settled
|
|
150
|
+
? `Metered per completed task: this completion settled ${settlement.amount ?? 'the agreed rate'}${settlement.transactionId ? ` (tx ${settlement.transactionId})` : ''}. One execution, once — a retry of this same transition does not charge again.`
|
|
151
|
+
: `No payment moved on this completion — ${SETTLEMENT_REASONS[settlement.reason ?? ''] ?? settlement.reason ?? 'settlement did not run'}. Do not report this task as paid.`;
|
|
152
|
+
const agreementFacts = effects?.agreement;
|
|
153
|
+
const agreement = !agreementFacts
|
|
154
|
+
? undefined
|
|
155
|
+
: agreementFacts.fulfilledNow
|
|
156
|
+
? `Agreement ${agreementFacts.agreementId} reached its execution quota and is now fulfilled — the engagement is over, and its grants went with it.`
|
|
157
|
+
: `Agreement ${agreementFacts.agreementId} is still ${agreementFacts.status ?? 'in force'}${agreementFacts.billing === 'per_task' ? ', charging per completed task' : agreementFacts.billing === 'total' ? ', priced as one total for the engagement' : ''}. Finishing a task does not end a hire; ending one is its own deliberate call.`;
|
|
158
|
+
return {
|
|
159
|
+
ok: true,
|
|
160
|
+
taskId,
|
|
161
|
+
state,
|
|
162
|
+
outcome: 'ok',
|
|
163
|
+
recorded,
|
|
164
|
+
...(handoff ? { handoff } : {}),
|
|
165
|
+
...(delivery ? { delivery } : {}),
|
|
166
|
+
...(metering ? { metering } : {}),
|
|
167
|
+
...(agreement ? { agreement } : {}),
|
|
168
|
+
next: [lookup],
|
|
169
|
+
...(workContext ? { workContext } : {}),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
export const TASK_CAPABILITIES = [
|
|
173
|
+
listTasksCapability,
|
|
174
|
+
cancelTaskCapability,
|
|
175
|
+
];
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What to do with a piece of engagement, from records the caller already has.
|
|
3
|
+
*
|
|
4
|
+
* This is a receipt and a next-call pointer. It does not invent a worker
|
|
5
|
+
* protocol, a wake store, or a blocked task state. Waiting-on-person is a
|
|
6
|
+
* field on the receipt so a later human view can show waiting instead of
|
|
7
|
+
* active. A held graph is not work until deps release; failed or cancelled
|
|
8
|
+
* deps are not inputs. Withdraw is cancel on the root. A live hire does not
|
|
9
|
+
* take a second hire or an in-place amend.
|
|
10
|
+
*/
|
|
11
|
+
import type { InboxDeliveryRef, InboxEnvelope, InboxTaskRef, Task } from './types.js';
|
|
12
|
+
import { type NextCall } from './capabilities/nextCall.js';
|
|
13
|
+
import type { CapabilityEnv } from './capabilities/types.js';
|
|
14
|
+
import type { SessionContinuation } from './sessionOrientation.js';
|
|
15
|
+
export type EngagementGuideKind = 'work_order' | 'duplicate' | 'held' | 'waiting' | 'contact' | 'stranger_brief' | 'hire_terms' | 'reminder' | 'reuse' | 'claim' | 'request' | 'direct' | 'subcontract';
|
|
16
|
+
export type EngagementOutcome = 'ok' | 'pending' | 'noop' | 'unavailable';
|
|
17
|
+
export type WaitingOn = {
|
|
18
|
+
kind: 'user' | 'agent';
|
|
19
|
+
id: string;
|
|
20
|
+
};
|
|
21
|
+
export interface GraphHonesty {
|
|
22
|
+
ready: boolean;
|
|
23
|
+
heldByDeps: boolean;
|
|
24
|
+
failedDepsAreNotInputs: true;
|
|
25
|
+
failedDepCount: number;
|
|
26
|
+
}
|
|
27
|
+
export interface HireTermsHonesty {
|
|
28
|
+
secondHire: 'refused';
|
|
29
|
+
amendLive: 'unavailable';
|
|
30
|
+
}
|
|
31
|
+
export interface EngagementGuide {
|
|
32
|
+
kind: EngagementGuideKind;
|
|
33
|
+
outcome: EngagementOutcome;
|
|
34
|
+
summary: string;
|
|
35
|
+
/** Room the brief arrived in — never a substitute for agreementId. */
|
|
36
|
+
chatId?: string | null;
|
|
37
|
+
agreementId?: string | null;
|
|
38
|
+
taskId?: string | null;
|
|
39
|
+
waitingOn?: WaitingOn | null;
|
|
40
|
+
graph?: GraphHonesty;
|
|
41
|
+
hireTerms?: HireTermsHonesty;
|
|
42
|
+
next?: NextCall;
|
|
43
|
+
}
|
|
44
|
+
export interface EngagementTaskHint {
|
|
45
|
+
taskId: string;
|
|
46
|
+
agreementId?: string | null;
|
|
47
|
+
rootTaskId?: string | null;
|
|
48
|
+
heldByDeps?: boolean;
|
|
49
|
+
waitsOn?: string[];
|
|
50
|
+
/** Known terminal states for named deps, when the caller has them. */
|
|
51
|
+
depStates?: Record<string, string>;
|
|
52
|
+
dueAt?: string | null;
|
|
53
|
+
checkBack?: {
|
|
54
|
+
everyMinutes: number;
|
|
55
|
+
maxReminders: number;
|
|
56
|
+
} | null;
|
|
57
|
+
lastAct?: 'question';
|
|
58
|
+
waitingOn?: WaitingOn | null;
|
|
59
|
+
}
|
|
60
|
+
export interface ContactPathInput {
|
|
61
|
+
partyKind: 'person' | 'agent';
|
|
62
|
+
partyId: string;
|
|
63
|
+
/** Active Ziggs link (or same-org membership) to that person. */
|
|
64
|
+
linked: boolean;
|
|
65
|
+
/** The agent has a take-it-or-leave-it listing. */
|
|
66
|
+
listed?: boolean;
|
|
67
|
+
sameOrg?: boolean;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* How to form (or refuse to form) an engagement from facts the caller
|
|
71
|
+
* already has. The ladder is reuse → claim → request → direct. A parent
|
|
72
|
+
* subcontract is its own rail. A listing is never countered.
|
|
73
|
+
*/
|
|
74
|
+
export interface FormationInput {
|
|
75
|
+
/** Active agreement that already covers this work on matching terms. */
|
|
76
|
+
matchingActive?: {
|
|
77
|
+
agreementId: string;
|
|
78
|
+
} | null;
|
|
79
|
+
/** Live hire with this counterparty, whether or not terms still match. */
|
|
80
|
+
liveHire?: {
|
|
81
|
+
agreementId: string;
|
|
82
|
+
} | null;
|
|
83
|
+
/** Caller wants different terms than the live hire. */
|
|
84
|
+
wantsChangedTerms?: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* A posted listing to claim. `true` means listings exist and the caller
|
|
87
|
+
* still has to pick the id. An object with an id is that listing.
|
|
88
|
+
*/
|
|
89
|
+
listing?: {
|
|
90
|
+
agreementId?: string;
|
|
91
|
+
} | true | null;
|
|
92
|
+
/** Active parent under which this slice would be a subcontract. */
|
|
93
|
+
parentAgreementId?: string | null;
|
|
94
|
+
/** Named counterparty for a direct proposal. */
|
|
95
|
+
counterparty?: string | null;
|
|
96
|
+
/** `doors.acceptsProposals` — most published agents are claim-only. */
|
|
97
|
+
acceptsProposals?: boolean;
|
|
98
|
+
/** They work (buy) vs you work (bid). */
|
|
99
|
+
direction?: 'buy' | 'bid';
|
|
100
|
+
}
|
|
101
|
+
export interface InboxEngagementInput {
|
|
102
|
+
env: CapabilityEnv;
|
|
103
|
+
agentId: string;
|
|
104
|
+
inbox: Pick<InboxEnvelope, 'deliveries' | 'tasksAwaitingMe'>;
|
|
105
|
+
tasks?: EngagementTaskHint[];
|
|
106
|
+
continuation?: Pick<SessionContinuation, 'canScheduleWake' | 'kind'>;
|
|
107
|
+
}
|
|
108
|
+
/** Same event twice, or a hire-room brief that already has an open task. */
|
|
109
|
+
export declare function isEchoOrDuplicate(inbox: Pick<InboxEnvelope, 'deliveries' | 'tasksAwaitingMe'>, agentId: string): boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Assigned message under a live hire. Missing chat is not a skip — a fresh
|
|
112
|
+
* hire without a room still runs after access to that agreement is proven.
|
|
113
|
+
* An agrn- notification lane is not treated as a chat row.
|
|
114
|
+
*/
|
|
115
|
+
export declare function isHireWorkOrder(delivery: InboxDeliveryRef, agentId: string, tasksAwaitingMe?: readonly InboxTaskRef[]): boolean;
|
|
116
|
+
export declare function waitingOnFromTask(task: EngagementTaskHint): WaitingOn | null;
|
|
117
|
+
export declare function graphReleaseHonesty(task: EngagementTaskHint): GraphHonesty;
|
|
118
|
+
export declare function liveHireChangedTerms(env: CapabilityEnv): EngagementGuide;
|
|
119
|
+
/** Map a hire-formation 409 onto the refuse-second-hire receipt. */
|
|
120
|
+
export declare function liveHireConflictFromStatus(env: CapabilityEnv, status: number): EngagementGuide | null;
|
|
121
|
+
export declare function withdrawHeldGraph(env: CapabilityEnv, rootTaskId: string): EngagementGuide;
|
|
122
|
+
export declare function reminderHonesty(task: EngagementTaskHint, continuation?: Pick<SessionContinuation, 'canScheduleWake' | 'kind'>): EngagementGuide;
|
|
123
|
+
/**
|
|
124
|
+
* Formation receipt. Reuse a matching active agreement. Claim a listing
|
|
125
|
+
* and never counter it. Request when nothing listed fits. Direct only when
|
|
126
|
+
* they accept proposals. Subcontract under a parent you already hold.
|
|
127
|
+
* A second formation on a live hire is refused.
|
|
128
|
+
*/
|
|
129
|
+
export declare function formationGuide(env: CapabilityEnv, input: FormationInput): EngagementGuide;
|
|
130
|
+
/** Browse result: claim when rows exist, request when the board is empty. */
|
|
131
|
+
export declare function marketplaceFormation(env: CapabilityEnv, input: {
|
|
132
|
+
listingAgreementIds: readonly string[];
|
|
133
|
+
}): EngagementGuide;
|
|
134
|
+
/**
|
|
135
|
+
* Contact path. Same-org people are reachable under the scoped identity.
|
|
136
|
+
* An outside person needs an active link. A link is not a roster. An agent
|
|
137
|
+
* with a listing is claimed, not chatted into a hire.
|
|
138
|
+
*/
|
|
139
|
+
export declare function contactPath(env: CapabilityEnv, input: ContactPathInput): EngagementGuide;
|
|
140
|
+
export declare function hireWorkOrderGuide(env: CapabilityEnv, delivery: InboxDeliveryRef): EngagementGuide;
|
|
141
|
+
export declare function strangerBriefGuide(env: CapabilityEnv, chatId: string | null): EngagementGuide;
|
|
142
|
+
export declare function duplicateGuide(): EngagementGuide;
|
|
143
|
+
/**
|
|
144
|
+
* First engagement that matters on this envelope. Empty mail with no held
|
|
145
|
+
* tasks returns null so an empty inbox result stays a pass-through.
|
|
146
|
+
*/
|
|
147
|
+
export declare function inboxEngagement(input: InboxEngagementInput): EngagementGuide | null;
|
|
148
|
+
export declare function hintsFromTasks(tasks: Task[] | undefined): EngagementTaskHint[];
|