@ziggs-ai/agent-sdk 0.11.1 → 0.13.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/CHANGELOG.md +11 -0
- package/dist/AgentHost.d.ts +27 -5
- package/dist/AgentHost.js +110 -15
- package/dist/agent/ClaudeSdkAgent.js +2 -2
- package/dist/agent/claudeSdkProtocol.d.ts +1 -1
- package/dist/agent/claudeSdkProtocol.js +3 -2
- package/dist/agent/claudeSdkTools.js +46 -10
- package/dist/cognition/validateContext.js +4 -1
- package/dist/context/batch.d.ts +3 -0
- package/dist/context/batch.js +8 -5
- package/dist/context/classifyEnvelope.js +4 -5
- package/dist/context/routingLabels.js +2 -3
- package/dist/formatters/AgreementFormatter.d.ts +7 -1
- package/dist/formatters/AgreementFormatter.js +17 -8
- package/dist/formatters/HistoryFormatter.d.ts +5 -0
- package/dist/formatters/HistoryFormatter.js +16 -7
- package/dist/index.d.ts +4 -2
- package/dist/index.js +8 -1
- package/dist/ingress/normalizeIncoming.d.ts +3 -8
- package/dist/runtime/PromptBuilder.js +32 -22
- package/dist/runtime/buildOutcome.js +4 -4
- package/dist/runtime/mandateDeclaration.d.ts +9 -0
- package/dist/runtime/mandateDeclaration.js +62 -0
- package/dist/runtime/runTurn.js +8 -0
- package/dist/server/ConnectionPool.d.ts +19 -0
- package/dist/server/ConnectionPool.js +30 -0
- package/dist/server/OutboxBuffer.d.ts +1 -1
- package/dist/server/ZiggsEffectHandler.d.ts +1 -1
- package/dist/server/ZiggsEffectHandler.js +6 -2
- package/dist/server/agreements/AgreementService.d.ts +19 -10
- package/dist/server/agreements/AgreementService.js +22 -11
- package/dist/server/inboxLoop.d.ts +6 -6
- package/dist/server/inboxLoop.js +31 -18
- package/dist/server/proactive/ProactiveTrigger.d.ts +7 -1
- package/dist/server/proactive/ProactiveTrigger.js +2 -2
- package/dist/server/requestMatch.d.ts +5 -0
- package/dist/server/{questMatch.js → requestMatch.js} +2 -2
- package/dist/server/runLauncher.js +24 -3
- package/dist/server/tools/index.d.ts +2 -2
- package/dist/server/tools/index.js +2 -2
- package/dist/server/tools/tier1/protocolRunner.js +16 -10
- package/dist/server/tools/tier1/protocolTools.js +12 -7
- package/dist/server/tools/tier2/linkTools.d.ts +1 -1
- package/dist/server/tools/tier2/linkTools.js +11 -9
- package/dist/server/tools/tier2/marketplaceTools.js +2 -2
- package/dist/server/tools/tier2/mcpConnectionTools.d.ts +33 -0
- package/dist/server/tools/tier2/mcpConnectionTools.js +138 -6
- package/dist/server/tools/tier2/paymentTools.d.ts +0 -8
- package/dist/server/tools/tier2/paymentTools.js +8 -12
- package/dist/types.d.ts +25 -10
- package/package.json +2 -2
- package/dist/server/questMatch.d.ts +0 -5
|
@@ -17,6 +17,11 @@ export declare class HistoryFormatter {
|
|
|
17
17
|
formatParticipant(participant: AnyObj | null | undefined, agentId: string): string;
|
|
18
18
|
formatOwner(task: AnyObj, agentId: string): string;
|
|
19
19
|
formatExecutor(task: AnyObj, agentId: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* One side of the task's agreement, or `fallback` when the frame carries no
|
|
22
|
+
* parties — a bare resource_changed skeleton has the task ids and nothing else.
|
|
23
|
+
*/
|
|
24
|
+
private _formatSide;
|
|
20
25
|
shortId(id: string | null | undefined): string;
|
|
21
26
|
formatTime(timestamp: string | null | undefined): string;
|
|
22
27
|
formatArgs(args: AnyObj | null | undefined): string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { partySideIds } from '@ziggs-ai/api-client';
|
|
1
2
|
export class HistoryFormatter {
|
|
2
3
|
showTimestamps;
|
|
3
4
|
shortIds;
|
|
@@ -67,7 +68,8 @@ export class HistoryFormatter {
|
|
|
67
68
|
case 'created': {
|
|
68
69
|
const ag = task['agreement'];
|
|
69
70
|
const parties = ag?.['parties'] || {};
|
|
70
|
-
|
|
71
|
+
const proposedTo = partySideIds(parties['proposedTo']).join(' via ');
|
|
72
|
+
return `${timePrefix}Task created under agreement: "${desc}" (${ids})\n Owner: ${this.formatOwner(task, agentId)}\n Executor: ${this.formatExecutor(task, agentId)}\n Proposed to: ${proposedTo || 'N/A'}`;
|
|
71
73
|
}
|
|
72
74
|
case 'state_changed': {
|
|
73
75
|
const prev = service?.['previousState']?.['state'] || '?';
|
|
@@ -140,14 +142,21 @@ export class HistoryFormatter {
|
|
|
140
142
|
return `${id} (${participant['type'] || 'unknown'})`;
|
|
141
143
|
}
|
|
142
144
|
formatOwner(task, agentId) {
|
|
143
|
-
|
|
144
|
-
const creatorId = ag?.['parties']?.['creator'] ?? task['agentId'];
|
|
145
|
-
return creatorId === agentId ? 'You' : String(creatorId ?? 'N/A');
|
|
145
|
+
return this._formatSide(task, 'creator', task['agentId'], agentId);
|
|
146
146
|
}
|
|
147
147
|
formatExecutor(task, agentId) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
return this._formatSide(task, 'provider', task['executorId'], agentId);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* One side of the task's agreement, or `fallback` when the frame carries no
|
|
152
|
+
* parties — a bare resource_changed skeleton has the task ids and nothing else.
|
|
153
|
+
*/
|
|
154
|
+
_formatSide(task, role, fallback, agentId) {
|
|
155
|
+
const parties = task['agreement']?.['parties'];
|
|
156
|
+
const ids = partySideIds(parties?.[role]);
|
|
157
|
+
if (ids.length === 0)
|
|
158
|
+
return fallback === agentId ? 'You' : String(fallback ?? 'N/A');
|
|
159
|
+
return ids.includes(agentId) ? 'You' : ids.join(' via ');
|
|
151
160
|
}
|
|
152
161
|
shortId(id) {
|
|
153
162
|
if (!id)
|
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ export { AgentHost, createAgent, createAgentPool, DEFAULT_MODEL } from './AgentH
|
|
|
17
17
|
export { Agent } from './agent/Agent.js';
|
|
18
18
|
export { ClaudeSdkAgent } from './agent/ClaudeSdkAgent.js';
|
|
19
19
|
export type { CognitionKind } from './agent/ClaudeSdkAgent.js';
|
|
20
|
+
export { CLAUDE_SDK_PROTOCOL } from './agent/claudeSdkProtocol.js';
|
|
21
|
+
export { buildClaudeEventPrompt, summarizeContext } from './agent/claudeCognition.js';
|
|
20
22
|
export { ziggsBrain, claudeBrain, isBrainSelection, isClaudeCognition } from './brain/index.js';
|
|
21
23
|
export type { Brain, BrainSelection, ZiggsBrainConfig, ClaudeBrainConfig, } from './brain/index.js';
|
|
22
24
|
export type { TickInput, TickOutput, AgentOptions } from './agent/Agent.js';
|
|
@@ -38,7 +40,7 @@ export { validateWorkflow, WorkflowValidationError } from './runtime/validateWor
|
|
|
38
40
|
export { outcomeFromEvent, outcomeFromActionResult, applyOutcomeToCtx } from './runtime/buildOutcome.js';
|
|
39
41
|
export { LANE_BOOK_KEY, allCollectedResults, allDelegatedAgreementIds, allPendingSubtasks, } from './runtime/taskBookkeeping.js';
|
|
40
42
|
export { createDeliveryWriteKeys } from './runtime/deliveryWriteKeys.js';
|
|
41
|
-
export type { Outcome, OutcomeKind, Ctx, Identity, HistoryEntry, ToolResultEntry, PendingSubtask, CollectedSubtaskResult, TaskBookkeeping, Workflow, State, ParkedState, ThinkingState, MechanicalState, Action, Transition, PromptDef, ActionPrompt, Produces, ProducesFn, AgreementRef, TaskRef, ProposalRef, AgentConfig, DefineAgentInput, ServicesConfig, Effect, EffectKind, EffectResult, EffectResultMap, EffectHandler, LlmMessage, LlmToolCall, LlmToolSchema, LlmResponse, ContextSnapshot, ReadContextOpts, ToolCallResult, RecordedEntry, DeliveryWriteKeys, } from './types.js';
|
|
43
|
+
export type { Outcome, OutcomeKind, Ctx, Identity, HistoryEntry, ToolResultEntry, PendingSubtask, CollectedSubtaskResult, TaskBookkeeping, Workflow, State, ParkedState, ThinkingState, MechanicalState, Action, Transition, PromptDef, ActionPrompt, Produces, ProducesFn, AgreementRef, TaskRef, ProposalRef, AgentConfig, DefineAgentInput, ServicesConfig, Effect, EffectKind, EffectResult, EffectResultMap, EffectHandler, LlmMessage, LlmToolCall, LlmToolSchema, LlmResponse, ContextSnapshot, SnapshotParticipant, ReadContextOpts, ToolCallResult, RecordedEntry, DeliveryWriteKeys, } from './types.js';
|
|
42
44
|
export { default } from './AgentHost.js';
|
|
43
45
|
export { validateContext, ContextWarning } from './cognition/validateContext.js';
|
|
44
46
|
export { runLauncher } from './server/runLauncher.js';
|
|
@@ -60,7 +62,7 @@ export { HistoryFormatter, historyFormatter, AgreementFormatter, agreementFormat
|
|
|
60
62
|
export { ProactiveTrigger } from './server/proactive/ProactiveTrigger.js';
|
|
61
63
|
export { PollRegistry, declaredPolls, type PollBinding, type PollContext, type PollKind, type PollResult, } from './server/polls/PollKind.js';
|
|
62
64
|
export { PollRunner, type PollRunnerOptions, type WakeTarget } from './server/polls/PollRunner.js';
|
|
63
|
-
export { PROTOCOL_TOOLS, agreementProposeTool, agreementSubcontractTool, agreementRespondTool, agreementClaimTool, agreementCounterTool, agreementGetTool, agreementRevokeTool, agreementFulfillTool, taskCreateTool, taskSetResultTool, taskUpdatePlanStepTool, dispatchProtocolOp, PAYMENT_TOOLS, paymentBalanceTool,
|
|
65
|
+
export { PROTOCOL_TOOLS, agreementProposeTool, agreementSubcontractTool, agreementRespondTool, agreementClaimTool, agreementCounterTool, agreementGetTool, agreementRevokeTool, agreementFulfillTool, taskCreateTool, taskSetResultTool, taskUpdatePlanStepTool, dispatchProtocolOp, PAYMENT_TOOLS, paymentBalanceTool, CONNECTION_TOOLS, connectionProxyTool, connectionListGrantsTool, requestConnectionTool, MCP_CONNECTION_TOOLS, mcpToolCallTool, mcpToolsListTool, DISCOVERY_TOOLS, agentSearchTool, agentGetTool, MARKETPLACE_TOOLS, marketplaceViewTool, CONTEXT_TOOLS, contextReadTool, contextDelegateTool, contextExpandReachTool, contextDiscoverGrantableTool, GRANTS_TOOLS, listGrantsTool, LINK_TOOLS, linkProposeTool, linkListTool, ARTIFACT_TOOLS, recordArtifactTool, CHAT_TOOLS, openConversationTool, } from './server/tools/index.js';
|
|
64
66
|
export { CLAUDE_SDK_TOOLS } from './agent/claudeSdkTools.js';
|
|
65
67
|
export { PROTOCOL_TOOL_NAMES, PROTOCOL_TOOL_TO_OPERATION, mapProtocolToolToOperation, isProtocolToolName } from './tasks/protocolRegistry.js';
|
|
66
68
|
export { InMemoryStore, FileMemoryStore } from './memory/MemoryStore.js';
|
package/dist/index.js
CHANGED
|
@@ -18,6 +18,13 @@ export { loadSkill, readSkillFiles, assertSkillHash } from './skills/loadSkill.j
|
|
|
18
18
|
export { AgentHost, createAgent, createAgentPool, DEFAULT_MODEL } from './AgentHost.js';
|
|
19
19
|
export { Agent } from './agent/Agent.js';
|
|
20
20
|
export { ClaudeSdkAgent } from './agent/ClaudeSdkAgent.js';
|
|
21
|
+
// The exact strings a Claude-brain wake sends: the shared protocol block, the
|
|
22
|
+
// role-independent event prompt, and the one-line context digest. Exported so a
|
|
23
|
+
// caller can answer "what does this agent actually put in front of the model,
|
|
24
|
+
// and what does it cost?" without re-deriving it — a second copy of the prompt
|
|
25
|
+
// is a second answer to that question, and only one of them would be true.
|
|
26
|
+
export { CLAUDE_SDK_PROTOCOL } from './agent/claudeSdkProtocol.js';
|
|
27
|
+
export { buildClaudeEventPrompt, summarizeContext } from './agent/claudeCognition.js';
|
|
21
28
|
export { ziggsBrain, claudeBrain, isBrainSelection, isClaudeCognition } from './brain/index.js';
|
|
22
29
|
export { createZiggsEffectHandler } from './server/ZiggsEffectHandler.js';
|
|
23
30
|
export { EventQueue } from './server/EventQueue.js';
|
|
@@ -69,7 +76,7 @@ export {
|
|
|
69
76
|
// Tier 1 — protocol grammar (framework-managed via taskTools).
|
|
70
77
|
PROTOCOL_TOOLS, agreementProposeTool, agreementSubcontractTool, agreementRespondTool, agreementClaimTool, agreementCounterTool, agreementGetTool, agreementRevokeTool, agreementFulfillTool, taskCreateTool, taskSetResultTool, taskUpdatePlanStepTool, dispatchProtocolOp,
|
|
71
78
|
// Tier 2 — opt-in capability bundles (spread into `tools:`).
|
|
72
|
-
PAYMENT_TOOLS, paymentBalanceTool,
|
|
79
|
+
PAYMENT_TOOLS, paymentBalanceTool, CONNECTION_TOOLS, connectionProxyTool, connectionListGrantsTool, requestConnectionTool, MCP_CONNECTION_TOOLS, mcpToolCallTool, mcpToolsListTool, DISCOVERY_TOOLS, agentSearchTool, agentGetTool, MARKETPLACE_TOOLS, marketplaceViewTool, CONTEXT_TOOLS, contextReadTool, contextDelegateTool, contextExpandReachTool, contextDiscoverGrantableTool, GRANTS_TOOLS, listGrantsTool, LINK_TOOLS, linkProposeTool, linkListTool, ARTIFACT_TOOLS, recordArtifactTool, CHAT_TOOLS, openConversationTool, } from './server/tools/index.js';
|
|
73
80
|
// The always-on toolset for the hosted Claude cognition (parity guard
|
|
74
81
|
// reads this as part of the real SDK registry).
|
|
75
82
|
export { CLAUDE_SDK_TOOLS } from './agent/claudeSdkTools.js';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AgreementParties } from '@ziggs-ai/api-client';
|
|
1
2
|
export interface NormalizedEvent {
|
|
2
3
|
chatId: string | null;
|
|
3
4
|
event: {
|
|
@@ -25,12 +26,6 @@ export interface NormalizedEvent {
|
|
|
25
26
|
text?: string;
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
|
-
interface WireParties {
|
|
29
|
-
creator?: string;
|
|
30
|
-
provider?: string;
|
|
31
|
-
payer?: string;
|
|
32
|
-
proposedTo?: string;
|
|
33
|
-
}
|
|
34
29
|
interface WireTask {
|
|
35
30
|
taskId?: string;
|
|
36
31
|
agentId?: string;
|
|
@@ -42,7 +37,7 @@ interface WireTask {
|
|
|
42
37
|
state?: string;
|
|
43
38
|
proposal?: unknown;
|
|
44
39
|
agreement?: {
|
|
45
|
-
parties?:
|
|
40
|
+
parties?: AgreementParties;
|
|
46
41
|
};
|
|
47
42
|
}
|
|
48
43
|
interface WireMetadata {
|
|
@@ -69,7 +64,7 @@ interface WireMetadata {
|
|
|
69
64
|
proposal?: {
|
|
70
65
|
status?: string;
|
|
71
66
|
};
|
|
72
|
-
parties?:
|
|
67
|
+
parties?: AgreementParties;
|
|
73
68
|
approvals?: Array<{
|
|
74
69
|
partyId?: string;
|
|
75
70
|
status?: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HistoryFormatter, AgreementFormatter } from '../formatters/index.js';
|
|
2
2
|
import { validateContext } from '../cognition/validateContext.js';
|
|
3
|
-
import { isBroadcastTarget, isOpaquePresentationRef } from '@ziggs-ai/api-client';
|
|
3
|
+
import { isBroadcastTarget, isOpaquePresentationRef, partySideIds } from '@ziggs-ai/api-client';
|
|
4
4
|
import { LANE_BOOK_KEY, allCollectedResults, allDelegatedAgreementIds, allPendingSubtasks, } from './taskBookkeeping.js';
|
|
5
5
|
/** Rough chars-per-token ratio for budgeting (English/JSON averages ~4). */
|
|
6
6
|
const CHARS_PER_TOKEN = 4;
|
|
@@ -191,12 +191,13 @@ ${this._renderDecisionSchemaFromActions(actions, senderMeta, ctxObj, omitMessage
|
|
|
191
191
|
const creatorIsYou = task.creatorIsYou;
|
|
192
192
|
const providerIsYou = task.providerIsYou;
|
|
193
193
|
if (ag?.agreementId) {
|
|
194
|
+
const named = (name) => partySideIds(parties[name]).join(' via ');
|
|
194
195
|
lines.push(`Agreement: ${ag.agreementId}${creatorIsYou ? ' (yours)' : ''}`);
|
|
195
|
-
lines.push(` Creator: ${
|
|
196
|
-
lines.push(` Provider: ${
|
|
196
|
+
lines.push(` Creator: ${named('creator') || 'N/A'}${creatorIsYou ? ' (You)' : ''}`);
|
|
197
|
+
lines.push(` Provider: ${named('provider') || 'N/A'}${providerIsYou ? ' (You)' : ''}`);
|
|
197
198
|
const proposal = ag.proposal;
|
|
198
199
|
if (proposal?.status) {
|
|
199
|
-
lines.push(` Proposal: ${proposal.status} (to ${
|
|
200
|
+
lines.push(` Proposal: ${proposal.status} (to ${named('proposedTo')}${task.proposedToIsYou ? ' - You' : ''})`);
|
|
200
201
|
}
|
|
201
202
|
const money = ag.money;
|
|
202
203
|
if (typeof money?.price === 'number' && money.price > 0) {
|
|
@@ -281,29 +282,38 @@ ${this._renderDecisionSchemaFromActions(actions, senderMeta, ctxObj, omitMessage
|
|
|
281
282
|
const name = a.name && a.name !== id ? `${a.name} (${id})` : id;
|
|
282
283
|
agentLabels.set(id, `${name}${desc}`);
|
|
283
284
|
}
|
|
284
|
-
|
|
285
|
+
// The server declares what each participant is (`kind` on the snapshot row),
|
|
286
|
+
// so read that. Which array a row arrived in is a projection detail, and
|
|
287
|
+
// guessing from it mislabels the first participant that is neither a person
|
|
288
|
+
// nor an agent. A backend too old to send `kind` still resolves by array.
|
|
289
|
+
const declaredKinds = new Map();
|
|
290
|
+
for (const row of [...users, ...otherAgents]) {
|
|
291
|
+
const id = (row?.['userId'] ?? row?.['agentId']);
|
|
292
|
+
const kind = row?.['kind'];
|
|
293
|
+
if (id && typeof kind === 'string')
|
|
294
|
+
declaredKinds.set(id, kind);
|
|
295
|
+
}
|
|
296
|
+
const kindOf = (id) => declaredKinds.get(id) ??
|
|
297
|
+
(userIds.has(id) ? 'user' : agentIds.has(id) ? 'agent' : 'unknown');
|
|
285
298
|
const labelOf = (id) => userLabels.get(id) ?? agentLabels.get(id) ?? id;
|
|
286
299
|
const tagged = (id) => `${labelOf(id)} [${kindOf(id)}]`;
|
|
287
300
|
const agreementParties = new Map();
|
|
288
301
|
for (const ag of agreements || []) {
|
|
289
302
|
const agId = ag?.agreementId;
|
|
290
303
|
const parties = ag?.parties || {};
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
[
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (!agreementParties.has(pid))
|
|
305
|
-
agreementParties.set(pid, []);
|
|
306
|
-
agreementParties.get(pid).push({ agreementId: agId ?? '', role });
|
|
304
|
+
for (const role of ['creator', 'provider', 'payer', 'proposedTo']) {
|
|
305
|
+
// Both columns of a side are addressable and carry the same role: the
|
|
306
|
+
// principal is who the deal is with, the actor is who acts on it.
|
|
307
|
+
for (const pid of partySideIds(parties[role])) {
|
|
308
|
+
if (pid === myAgentId)
|
|
309
|
+
continue;
|
|
310
|
+
// Opaque presentation refs are not principal slots.
|
|
311
|
+
if (isOpaquePresentationRef(pid))
|
|
312
|
+
continue;
|
|
313
|
+
if (!agreementParties.has(pid))
|
|
314
|
+
agreementParties.set(pid, []);
|
|
315
|
+
agreementParties.get(pid).push({ agreementId: agId ?? '', role });
|
|
316
|
+
}
|
|
307
317
|
}
|
|
308
318
|
}
|
|
309
319
|
// Chat keeps the full directory — including opaque `rpb_*` / `psn_*` refs
|
|
@@ -368,7 +378,7 @@ ${this._renderDecisionSchemaFromActions(actions, senderMeta, ctxObj, omitMessage
|
|
|
368
378
|
lines.push('Set "action" to exactly one of the action names below.');
|
|
369
379
|
lines.push('Message text is rendered as markdown (CommonMark + GFM). You MAY use **bold**, *italic*, `code`, fenced code blocks, lists, links, and tables when they improve clarity — plain text is also fine.\n');
|
|
370
380
|
const replyTo = senderMeta.defaultReplyReceiverId || '<receiverId>';
|
|
371
|
-
const pendingProposals = (ctxObj.agreements || []).filter((a) => a.proposal?.status === 'pending' && (a.proposedToIsYou || isBroadcastTarget(a.parties?.proposedTo)));
|
|
381
|
+
const pendingProposals = (ctxObj.agreements || []).filter((a) => a.proposal?.status === 'pending' && (a.proposedToIsYou || isBroadcastTarget(a.parties?.proposedTo?.principal)));
|
|
372
382
|
if (pendingProposals.length > 0) {
|
|
373
383
|
lines.push(`PRIORITY: You have ${pendingProposals.length} pending proposal(s) directed at you. Respond BEFORE other actions.`);
|
|
374
384
|
lines.push(`{"thought": "...", "action": "<action_bound_to_agreement_respond>", "args": {"agreementId": "<id>", "action": "approve|reject"}}\n`);
|
|
@@ -92,7 +92,7 @@ function singleEventToOutcome(ev, ownAgentId) {
|
|
|
92
92
|
const parties = ag?.parties || {};
|
|
93
93
|
const state = result.state;
|
|
94
94
|
// Direct assignment to me (provider) — task spawned, citing an active agreement.
|
|
95
|
-
const isAssignedToMe = (result.providerIsYou || parties.provider === ownAgentId) &&
|
|
95
|
+
const isAssignedToMe = (result.providerIsYou || parties.provider?.actor === ownAgentId) &&
|
|
96
96
|
(state === 'active' || state === 'in-progress');
|
|
97
97
|
if (isAssignedToMe) {
|
|
98
98
|
return { kind: 'task-assigned', task };
|
|
@@ -421,7 +421,7 @@ export function applyOutcomeToCtx(ctx, outcome) {
|
|
|
421
421
|
const book = bookForDelegation(ctx);
|
|
422
422
|
if (tid && !(tid in book.pendingSubtasks)) {
|
|
423
423
|
book.pendingSubtasks[tid] = {
|
|
424
|
-
agentId: t.assigneeId ?? t.executorId ?? t.agreement?.parties?.provider ?? null,
|
|
424
|
+
agentId: t.assigneeId ?? t.executorId ?? t.agreement?.parties?.provider?.actor ?? null,
|
|
425
425
|
spawnedAt: Date.now(),
|
|
426
426
|
};
|
|
427
427
|
}
|
|
@@ -465,7 +465,7 @@ export function applyOutcomeToCtx(ctx, outcome) {
|
|
|
465
465
|
if (!existing) {
|
|
466
466
|
book.collectedResults.push({
|
|
467
467
|
taskId,
|
|
468
|
-
agentId: pending?.agentId ?? t?.assigneeId ?? t?.executorId ?? t?.agreement?.parties?.provider ?? null,
|
|
468
|
+
agentId: pending?.agentId ?? t?.assigneeId ?? t?.executorId ?? t?.agreement?.parties?.provider?.actor ?? null,
|
|
469
469
|
status: outcome.status,
|
|
470
470
|
result: payload,
|
|
471
471
|
});
|
|
@@ -479,7 +479,7 @@ export function applyOutcomeToCtx(ctx, outcome) {
|
|
|
479
479
|
existing.status = outcome.status;
|
|
480
480
|
existing.result = payload;
|
|
481
481
|
if (existing.agentId == null) {
|
|
482
|
-
existing.agentId = t?.assigneeId ?? t?.executorId ?? t?.agreement?.parties?.provider ?? null;
|
|
482
|
+
existing.agentId = t?.assigneeId ?? t?.executorId ?? t?.agreement?.parties?.provider?.actor ?? null;
|
|
483
483
|
}
|
|
484
484
|
}
|
|
485
485
|
if (agId) {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ToolManager } from '../tools/ToolManager.js';
|
|
2
|
+
/**
|
|
3
|
+
* Add the wake's own mandate to a tool call that declares one and left it blank.
|
|
4
|
+
*
|
|
5
|
+
* Returns the args unchanged whenever there is nothing to say: the tool takes no
|
|
6
|
+
* declaration, the model already made one, or this wake is not running inside a
|
|
7
|
+
* job at all.
|
|
8
|
+
*/
|
|
9
|
+
export declare function withDeclaredMandate(args: Record<string, unknown>, toolName: string | null | undefined, toolManager: ToolManager | undefined, activeAgreementId: string | null | undefined): Record<string, unknown>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fill in the job an agent is working inside, so it does not have to.
|
|
3
|
+
*
|
|
4
|
+
* The consent gate excuses an agreement an agent forms INSIDE a job its human
|
|
5
|
+
* already approved, and it verifies the claim server-side. What was missing was
|
|
6
|
+
* the claim itself: nothing on the agent surface said "I am doing this as part
|
|
7
|
+
* of job X", so every engagement an agent formed arrived as an outsider and
|
|
8
|
+
* waited on a human — including buying the help the job it was hired for needs.
|
|
9
|
+
*
|
|
10
|
+
* The declaration is made at the CALLER, never resolved on the server: the
|
|
11
|
+
* agreements module must not read the tasks module, and a guessed mandate is a
|
|
12
|
+
* false claim the termination cascade would act on destructively. Here the fact
|
|
13
|
+
* is free — the runtime already knows which task this wake is executing and
|
|
14
|
+
* which agreement that task runs under, which is exactly the answer.
|
|
15
|
+
*
|
|
16
|
+
* The model can still name a job itself (and does, when it is working on
|
|
17
|
+
* something other than its assigned task). An explicit value is never
|
|
18
|
+
* overwritten, including an explicit empty string, which reads as "this belongs
|
|
19
|
+
* to no job" — the difference between saying nothing and saying none.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* The parameter a tool uses to carry the declaration.
|
|
23
|
+
*
|
|
24
|
+
* Two names, because the doors differ and each name is true at its own door: on
|
|
25
|
+
* a tool that CREATES an agreement the job becomes that row's parent, so the
|
|
26
|
+
* field is the parent id; on a tool that claims a row somebody else posted
|
|
27
|
+
* nothing is re-parented — the lineage stays with the publisher — and the job is
|
|
28
|
+
* only an authority. Listed together here so the runtime has one place that
|
|
29
|
+
* knows both, rather than a name test at each call site.
|
|
30
|
+
*/
|
|
31
|
+
const MANDATE_PARAM_NAMES = ['mandateAgreementId', 'parentAgreementId'];
|
|
32
|
+
/** The mandate parameter this tool declares, if it declares one. */
|
|
33
|
+
function mandateParamOf(toolName, toolManager) {
|
|
34
|
+
if (!toolName)
|
|
35
|
+
return null;
|
|
36
|
+
const schema = toolManager?.getTool?.(toolName)?.schema;
|
|
37
|
+
const properties = schema?.function?.parameters?.properties;
|
|
38
|
+
if (!properties)
|
|
39
|
+
return null;
|
|
40
|
+
for (const name of MANDATE_PARAM_NAMES) {
|
|
41
|
+
if (Object.prototype.hasOwnProperty.call(properties, name))
|
|
42
|
+
return name;
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Add the wake's own mandate to a tool call that declares one and left it blank.
|
|
48
|
+
*
|
|
49
|
+
* Returns the args unchanged whenever there is nothing to say: the tool takes no
|
|
50
|
+
* declaration, the model already made one, or this wake is not running inside a
|
|
51
|
+
* job at all.
|
|
52
|
+
*/
|
|
53
|
+
export function withDeclaredMandate(args, toolName, toolManager, activeAgreementId) {
|
|
54
|
+
if (!activeAgreementId)
|
|
55
|
+
return args;
|
|
56
|
+
const param = mandateParamOf(toolName, toolManager);
|
|
57
|
+
if (!param)
|
|
58
|
+
return args;
|
|
59
|
+
if (args[param] !== undefined)
|
|
60
|
+
return args;
|
|
61
|
+
return { ...args, [param]: activeAgreementId };
|
|
62
|
+
}
|
package/dist/runtime/runTurn.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { outcomeFromActionResult } from './buildOutcome.js';
|
|
2
2
|
import { runtimeLog } from '../shared/runtimeLog.js';
|
|
3
3
|
import { safeParseJSON } from '../utils/jsonExtractor.js';
|
|
4
|
+
import { withDeclaredMandate } from './mandateDeclaration.js';
|
|
4
5
|
const MAX_TOOL_LOOP_ITERS = 20;
|
|
5
6
|
const MAX_MSG_CHARS = 3500;
|
|
6
7
|
/**
|
|
@@ -260,6 +261,9 @@ export async function runTurn(input) {
|
|
|
260
261
|
args = JSON.parse(tc.function.arguments || '{}');
|
|
261
262
|
}
|
|
262
263
|
catch { }
|
|
264
|
+
// Say which job this is part of, when the tool asks and the model did
|
|
265
|
+
// not. The runtime knows; the model would have to be told.
|
|
266
|
+
args = withDeclaredMandate(args, toolName, toolManager, ctx.activeAgreementId);
|
|
263
267
|
const decision = { action: matchingAction, tool: toolName, args };
|
|
264
268
|
const result = await executeDecision(decision, actionDef, effWithTrace, sessionId, memory, null, addToolUsage);
|
|
265
269
|
toolCallResults.push({ tc, matchingAction, result, args, actionDef });
|
|
@@ -311,6 +315,10 @@ export async function runTurn(input) {
|
|
|
311
315
|
const decision = parsed.decision;
|
|
312
316
|
const chosenAction = decision.action;
|
|
313
317
|
const actionDef = actions[chosenAction];
|
|
318
|
+
// Same mandate declaration as the tool-call path above. Both routes reach
|
|
319
|
+
// the same tools, so filling it on only one would make the excuse depend on
|
|
320
|
+
// which shape the model happened to answer in.
|
|
321
|
+
decision.args = withDeclaredMandate((decision.args ?? {}), actionDef?.tool, toolManager, ctx.activeAgreementId);
|
|
314
322
|
if (decision.thought)
|
|
315
323
|
await emitThought(decision.thought);
|
|
316
324
|
// 2-call streaming: if this is a respond action (has receiverId, no bound tool),
|
|
@@ -16,6 +16,7 @@ export interface SendToOptions {
|
|
|
16
16
|
export declare class ConnectionPool {
|
|
17
17
|
private readonly manager;
|
|
18
18
|
private readonly configs;
|
|
19
|
+
private readonly hosts;
|
|
19
20
|
private readonly responseListeners;
|
|
20
21
|
/**
|
|
21
22
|
* Register N agent configs. Nothing connects until `connectAll()`; a config
|
|
@@ -29,6 +30,24 @@ export declare class ConnectionPool {
|
|
|
29
30
|
startAgent(agentId: string): Promise<AgentHost>;
|
|
30
31
|
stopAgent(agentId: string): Promise<void>;
|
|
31
32
|
disconnectAll(): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Shut the fleet down without abandoning work: stop taking new deliveries
|
|
35
|
+
* everywhere, THEN wait for in-flight turns to finish.
|
|
36
|
+
*
|
|
37
|
+
* The order is the whole point. Draining one agent while the others still
|
|
38
|
+
* long-poll leaves a window — as long as the drain — in which a host that is
|
|
39
|
+
* on its way out keeps accepting new work. On a rolling deploy the replacement
|
|
40
|
+
* is already live and polling the same inboxes, so that window is where one
|
|
41
|
+
* delivery gets handled twice: two hosts, one request, two answers.
|
|
42
|
+
*
|
|
43
|
+
* `disconnect()` only stops the inbox loop and timers; in-flight ticks live in
|
|
44
|
+
* each host's event queue, which is what `drain()` waits on. So stopping
|
|
45
|
+
* intake first costs nothing that is already running.
|
|
46
|
+
*
|
|
47
|
+
* A host that cannot finish inside `timeoutMs` is left behind rather than
|
|
48
|
+
* holding up the rest — the caller is on a shutdown clock of its own.
|
|
49
|
+
*/
|
|
50
|
+
shutdown(timeoutMs?: number): Promise<void>;
|
|
32
51
|
/**
|
|
33
52
|
* Deliver a message to the named agent and wait for its first outbound
|
|
34
53
|
* `send-message` effect — i.e. the agent's reply. Returns the reply text.
|
|
@@ -19,6 +19,10 @@ import { runtimeLog } from '../shared/runtimeLog.js';
|
|
|
19
19
|
export class ConnectionPool {
|
|
20
20
|
manager = new ConnectionManager();
|
|
21
21
|
configs = new Map();
|
|
22
|
+
// Live hosts, so shutdown can drain them. The manager hands its handles to
|
|
23
|
+
// open/close callbacks and does not expose them, and re-reading one through
|
|
24
|
+
// `startAgent` after a stop would reconnect the agent we are shutting down.
|
|
25
|
+
hosts = new Map();
|
|
22
26
|
// Listeners enqueued by requestFrom — drained on outbound send-message effects.
|
|
23
27
|
responseListeners = new Map();
|
|
24
28
|
/**
|
|
@@ -56,10 +60,12 @@ export class ConnectionPool {
|
|
|
56
60
|
},
|
|
57
61
|
});
|
|
58
62
|
await host.connectAsync();
|
|
63
|
+
this.hosts.set(agentId, host);
|
|
59
64
|
runtimeLog.debug('ConnectionPool', `connected "${agentId}"`);
|
|
60
65
|
return host;
|
|
61
66
|
}, async (host) => {
|
|
62
67
|
host.disconnect();
|
|
68
|
+
this.hosts.delete(agentId);
|
|
63
69
|
runtimeLog.debug('ConnectionPool', `disconnected "${agentId}"`);
|
|
64
70
|
}, metaByAgentId.get(agentId));
|
|
65
71
|
}
|
|
@@ -78,6 +84,30 @@ export class ConnectionPool {
|
|
|
78
84
|
async disconnectAll() {
|
|
79
85
|
return this.manager.stopAll();
|
|
80
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Shut the fleet down without abandoning work: stop taking new deliveries
|
|
89
|
+
* everywhere, THEN wait for in-flight turns to finish.
|
|
90
|
+
*
|
|
91
|
+
* The order is the whole point. Draining one agent while the others still
|
|
92
|
+
* long-poll leaves a window — as long as the drain — in which a host that is
|
|
93
|
+
* on its way out keeps accepting new work. On a rolling deploy the replacement
|
|
94
|
+
* is already live and polling the same inboxes, so that window is where one
|
|
95
|
+
* delivery gets handled twice: two hosts, one request, two answers.
|
|
96
|
+
*
|
|
97
|
+
* `disconnect()` only stops the inbox loop and timers; in-flight ticks live in
|
|
98
|
+
* each host's event queue, which is what `drain()` waits on. So stopping
|
|
99
|
+
* intake first costs nothing that is already running.
|
|
100
|
+
*
|
|
101
|
+
* A host that cannot finish inside `timeoutMs` is left behind rather than
|
|
102
|
+
* holding up the rest — the caller is on a shutdown clock of its own.
|
|
103
|
+
*/
|
|
104
|
+
async shutdown(timeoutMs = 30_000) {
|
|
105
|
+
const hosts = [...this.hosts.values()];
|
|
106
|
+
await this.manager.stopAll();
|
|
107
|
+
await Promise.all(hosts.map((host) => host.drain(timeoutMs).catch((err) => {
|
|
108
|
+
runtimeLog.warn('ConnectionPool', `drain did not finish: ${err.message}`);
|
|
109
|
+
})));
|
|
110
|
+
}
|
|
81
111
|
/**
|
|
82
112
|
* Deliver a message to the named agent and wait for its first outbound
|
|
83
113
|
* `send-message` effect — i.e. the agent's reply. Returns the reply text.
|
|
@@ -24,7 +24,7 @@ export declare class OutboxBuffer {
|
|
|
24
24
|
constructor(options?: OutboxBufferOptions);
|
|
25
25
|
track(chatId: string, msg: {
|
|
26
26
|
text: string;
|
|
27
|
-
receiverId
|
|
27
|
+
receiverId?: string;
|
|
28
28
|
}): void;
|
|
29
29
|
merge(chatId: string, history: HistoryEntryShape[], agentId: string | null): void;
|
|
30
30
|
gc(): void;
|
|
@@ -35,7 +35,7 @@ export interface ZiggsEffectDeps {
|
|
|
35
35
|
contextReadClient: ContextReadClient;
|
|
36
36
|
taskService: TaskService;
|
|
37
37
|
agreementService: AgreementService;
|
|
38
|
-
messageSender: (text: string, receiverId: string, sessionId: string, messageId?: string) => Promise<unknown>;
|
|
38
|
+
messageSender: (text: string, receiverId: string | undefined, sessionId: string, messageId?: string) => Promise<unknown>;
|
|
39
39
|
/** Sends a streaming chunk to a client. Called per-token during stream-text effects. */
|
|
40
40
|
chunkSender?: (sessionId: string, receiverId: string, text: string, messageId: string) => void;
|
|
41
41
|
toolManager: ToolManager;
|
|
@@ -15,7 +15,7 @@ const emptySnapshot = (agentId, chatMissing = false) => ({
|
|
|
15
15
|
history: [],
|
|
16
16
|
agreements: [],
|
|
17
17
|
users: [],
|
|
18
|
-
agents: [{ agentId, role: 'self', isYou: true }],
|
|
18
|
+
agents: [{ agentId, role: 'self', isYou: true, kind: 'agent' }],
|
|
19
19
|
latestSequence: null,
|
|
20
20
|
...(chatMissing ? { chatMissing: true } : {}),
|
|
21
21
|
});
|
|
@@ -26,7 +26,11 @@ async function buildSnapshot(deps, chatId, agentId, opts = {}) {
|
|
|
26
26
|
const snap = await deps.contextReadClient.snapshot(chatId, {
|
|
27
27
|
maxMessages: opts.limit,
|
|
28
28
|
});
|
|
29
|
-
|
|
29
|
+
// Built rather than cast: the roster rows are typed on both sides now (they
|
|
30
|
+
// carry the declared participant kind), and only `history` is loose on the
|
|
31
|
+
// wire, so a whole-object cast would be asserting past the one field that
|
|
32
|
+
// actually needs it.
|
|
33
|
+
return { ...snap, history: snap.history };
|
|
30
34
|
}
|
|
31
35
|
catch (err) {
|
|
32
36
|
// Defensive: server normally signals a dead chat as 200 + chatMissing, but
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Agreement, type ClaimedKind, type ProposeAgreementData, type ProposeDirectInput, type ProposeBroadcastInput, type PublishOfferPayload, type DelegateAgreementData, type CounterAgreementData, type
|
|
1
|
+
import { type Agreement, type ClaimedKind, type ClaimOptions, type ProposeAgreementData, type ProposeDirectInput, type ProposeBroadcastInput, type PublishOfferPayload, type DelegateAgreementData, type CounterAgreementData, type CreateLinkBody, type CreateLinkResult, type ListAgreementsFilters, type GetMyAgreementsFilters, type ChatLinkType, type ArtifactLinkType, type UserRole } from '@ziggs-ai/api-client';
|
|
2
2
|
export declare class AgreementService {
|
|
3
3
|
private creds;
|
|
4
4
|
constructor(operatorKey: string, agentId: string);
|
|
@@ -20,20 +20,27 @@ export declare class AgreementService {
|
|
|
20
20
|
delegate(payload: DelegateAgreementData): Promise<Agreement>;
|
|
21
21
|
respond(agreementId: string, action: 'approve' | 'reject'): Promise<Agreement>;
|
|
22
22
|
/**
|
|
23
|
-
* claim any open broadcast (
|
|
23
|
+
* claim any open broadcast (request, standing offer, hand-off,
|
|
24
24
|
* link invite). Routing (offer vs agreement claim endpoint) is decided in
|
|
25
25
|
* the shared flow; `kind` is the api-client ClaimedKind so this signature
|
|
26
26
|
* can't drift from the flow again (a 'hand-off' addition broke the build).
|
|
27
27
|
*/
|
|
28
|
-
claim(agreementId: string): Promise<{
|
|
28
|
+
claim(agreementId: string, opts?: ClaimOptions): Promise<{
|
|
29
29
|
agreement: Agreement;
|
|
30
30
|
kind: ClaimedKind;
|
|
31
31
|
}>;
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
33
|
+
* Connect with the person an agent answers for.
|
|
34
|
+
*
|
|
35
|
+
* `to` is an email or an agent id. A link is with the PERSON either way: an id
|
|
36
|
+
* is only a way to find its owner, and one that answers to an org is refused.
|
|
37
|
+
*
|
|
38
|
+
* The reply says only that the invitation went. Handing back the agreement for
|
|
39
|
+
* an id target while an address target got a bare acknowledgement told the
|
|
40
|
+
* caller more about one kind of target than the other, which made the id form
|
|
41
|
+
* a way to check who has an account.
|
|
35
42
|
*/
|
|
36
|
-
requestLink(
|
|
43
|
+
requestLink(to: string, description?: string): Promise<CreateLinkResult>;
|
|
37
44
|
counter(agreementId: string, counter: CounterAgreementData): Promise<Agreement>;
|
|
38
45
|
getStatus(agreementId: string): Promise<unknown | null>;
|
|
39
46
|
list(filters?: ListAgreementsFilters): Promise<Agreement[]>;
|
|
@@ -45,10 +52,12 @@ export declare class AgreementService {
|
|
|
45
52
|
*/
|
|
46
53
|
mine(filters?: GetMyAgreementsFilters): Promise<Agreement[]>;
|
|
47
54
|
get(agreementId: string): Promise<Agreement | null>;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Connect with someone — by email, by agent id, or with a share link. Work
|
|
57
|
+
* agreements are created by `propose` / the marketplace claim routes, which
|
|
58
|
+
* run the term normalisation and consent gates this rail never had.
|
|
59
|
+
*/
|
|
60
|
+
createLink(body: CreateLinkBody): Promise<CreateLinkResult>;
|
|
52
61
|
revoke(agreementId: string): Promise<{
|
|
53
62
|
ok: boolean;
|
|
54
63
|
agreement: Agreement;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { proposeAgreement, proposeBroadcast as proposeBroadcastApi, delegateAgreement, respondToAgreement, counterAgreement, claimOpenAgreement, getAgreementStatus, listAgreements, getMyAgreements, getAgreement, publishOffer as publishOfferApi,
|
|
1
|
+
import { proposeAgreement, proposeBroadcast as proposeBroadcastApi, delegateAgreement, respondToAgreement, counterAgreement, claimOpenAgreement, getAgreementStatus, listAgreements, getMyAgreements, getAgreement, publishOffer as publishOfferApi, createLink, revokeAgreement, fulfillAgreement, linkAgreementToChat, getChatsForAgreement, linkArtifactToAgreement, getArtifactsForAgreement, linkUserToAgreement, getUsersForAgreement, } from '@ziggs-ai/api-client';
|
|
2
2
|
export class AgreementService {
|
|
3
3
|
creds;
|
|
4
4
|
constructor(operatorKey, agentId) {
|
|
@@ -38,21 +38,27 @@ export class AgreementService {
|
|
|
38
38
|
return respondToAgreement(agreementId, action, this.creds);
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
|
-
* claim any open broadcast (
|
|
41
|
+
* claim any open broadcast (request, standing offer, hand-off,
|
|
42
42
|
* link invite). Routing (offer vs agreement claim endpoint) is decided in
|
|
43
43
|
* the shared flow; `kind` is the api-client ClaimedKind so this signature
|
|
44
44
|
* can't drift from the flow again (a 'hand-off' addition broke the build).
|
|
45
45
|
*/
|
|
46
|
-
claim(agreementId) {
|
|
47
|
-
return claimOpenAgreement(agreementId, this.creds);
|
|
46
|
+
claim(agreementId, opts = {}) {
|
|
47
|
+
return claimOpenAgreement(agreementId, this.creds, opts);
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
50
|
+
* Connect with the person an agent answers for.
|
|
51
|
+
*
|
|
52
|
+
* `to` is an email or an agent id. A link is with the PERSON either way: an id
|
|
53
|
+
* is only a way to find its owner, and one that answers to an org is refused.
|
|
54
|
+
*
|
|
55
|
+
* The reply says only that the invitation went. Handing back the agreement for
|
|
56
|
+
* an id target while an address target got a bare acknowledgement told the
|
|
57
|
+
* caller more about one kind of target than the other, which made the id form
|
|
58
|
+
* a way to check who has an account.
|
|
52
59
|
*/
|
|
53
|
-
async requestLink(
|
|
54
|
-
|
|
55
|
-
return agreement;
|
|
60
|
+
async requestLink(to, description) {
|
|
61
|
+
return createLink({ to, ...(description ? { description } : {}) }, this.creds);
|
|
56
62
|
}
|
|
57
63
|
counter(agreementId, counter) {
|
|
58
64
|
return counterAgreement(agreementId, counter || {}, this.creds);
|
|
@@ -75,8 +81,13 @@ export class AgreementService {
|
|
|
75
81
|
get(agreementId) {
|
|
76
82
|
return getAgreement(agreementId, this.creds);
|
|
77
83
|
}
|
|
78
|
-
|
|
79
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Connect with someone — by email, by agent id, or with a share link. Work
|
|
86
|
+
* agreements are created by `propose` / the marketplace claim routes, which
|
|
87
|
+
* run the term normalisation and consent gates this rail never had.
|
|
88
|
+
*/
|
|
89
|
+
createLink(body) {
|
|
90
|
+
return createLink(body, this.creds);
|
|
80
91
|
}
|
|
81
92
|
revoke(agreementId) {
|
|
82
93
|
return revokeAgreement(agreementId, this.creds);
|