@dsh-enhanced/assistant-goals 0.1.32 → 0.1.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/lib/execution.d.ts +14 -1
- package/lib/execution.d.ts.map +1 -1
- package/lib/execution.js +30 -2
- package/lib/execution.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/service.d.ts +25 -1
- package/lib/service.d.ts.map +1 -1
- package/lib/service.js +164 -22
- package/lib/service.js.map +1 -1
- package/lib/store.d.ts +2 -0
- package/lib/store.d.ts.map +1 -1
- package/lib/store.js +20 -9
- package/lib/store.js.map +1 -1
- package/lib/strategy-store.d.ts +42 -0
- package/lib/strategy-store.d.ts.map +1 -1
- package/lib/strategy-store.js +71 -1
- package/lib/strategy-store.js.map +1 -1
- package/lib/strategy.d.ts +3 -1
- package/lib/strategy.d.ts.map +1 -1
- package/lib/strategy.js +69 -47
- package/lib/strategy.js.map +1 -1
- package/lib/tools.d.ts.map +1 -1
- package/lib/tools.js +15 -6
- package/lib/tools.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +7 -7
package/lib/service.js
CHANGED
|
@@ -61,20 +61,42 @@ function escapeGoalContext(value) {
|
|
|
61
61
|
function excerptGoalContext(value, length) {
|
|
62
62
|
return typeof value === 'string' ? value.slice(0, length) : '';
|
|
63
63
|
}
|
|
64
|
+
/** Check untrusted tool input without invoking getters or inheriting prototype data. */
|
|
65
|
+
function plainJsonData(value) {
|
|
66
|
+
if (value === null || ['string', 'number', 'boolean'].includes(typeof value))
|
|
67
|
+
return Number.isFinite(value) || typeof value !== 'number';
|
|
68
|
+
if (Array.isArray(value)) {
|
|
69
|
+
if (Object.getPrototypeOf(value) !== Array.prototype || Object.getOwnPropertySymbols(value).length !== 0)
|
|
70
|
+
return false;
|
|
71
|
+
const names = Object.getOwnPropertyNames(value);
|
|
72
|
+
if (!names.includes('length') || names.some(name => name !== 'length' && !/^(?:0|[1-9][0-9]*)$/u.test(name)))
|
|
73
|
+
return false;
|
|
74
|
+
for (let index = 0; index < value.length; index++) {
|
|
75
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
76
|
+
if (!descriptor || !descriptor.enumerable || !('value' in descriptor) || !plainJsonData(descriptor.value))
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return names.length === value.length + 1;
|
|
80
|
+
}
|
|
81
|
+
if (!value || typeof value !== 'object' || Object.getPrototypeOf(value) !== Object.prototype || Object.getOwnPropertySymbols(value).length !== 0)
|
|
82
|
+
return false;
|
|
83
|
+
return Object.values(Object.getOwnPropertyDescriptors(value)).every(descriptor => descriptor.enumerable && 'value' in descriptor && plainJsonData(descriptor.value));
|
|
84
|
+
}
|
|
64
85
|
/** A complete, low-volume current-state projection when full history cannot fit. */
|
|
65
|
-
export function renderCompactGoalContext(record, verification, goalAcceptance, maxChars) {
|
|
86
|
+
export function renderCompactGoalContext(record, verification, goalAcceptance, maxChars, roundTiming) {
|
|
66
87
|
const compactRun = (run, includeCriteria, textLimit) => run === null ? null : {
|
|
67
88
|
status: run.status, runId: excerptGoalContext(run.runId, 96),
|
|
68
89
|
...(includeCriteria ? { criteria: run.criteria.filter(item => item.status !== 'passed').slice(0, 2).map(item => ({
|
|
69
90
|
id: excerptGoalContext(item.id, 96), status: item.status, reason: excerptGoalContext(item.reason, textLimit),
|
|
70
91
|
})) } : {}),
|
|
71
92
|
};
|
|
72
|
-
const compact = (includeCriteria, textLimit) => ({
|
|
93
|
+
const compact = (includeCriteria, textLimit, timing) => ({
|
|
73
94
|
truncated: true,
|
|
74
95
|
id: excerptGoalContext(record.id, 96),
|
|
75
96
|
definition: { version: record.definition.version, digest: excerptGoalContext(record.definition.digest, 64), objective: excerptGoalContext(record.definition.objective, textLimit) },
|
|
76
97
|
native: { phase: record.native.phase, revision: record.native.revision, roundsStarted: record.native.roundsStarted },
|
|
77
98
|
outcome: goalAcceptance?.status ?? (record.native.phase === 'complete' ? 'awaiting-verification' : 'unverified'),
|
|
99
|
+
...(roundTiming === undefined || timing === 'none' ? {} : { roundTiming: timing === 'active' ? roundTiming : { maxDurationMs: roundTiming.maxDurationMs } }),
|
|
78
100
|
...(goalAcceptance === undefined ? {} : { wholeGoal: { status: goalAcceptance.status,
|
|
79
101
|
...(includeCriteria ? { criteria: (goalAcceptance.criteria ?? []).filter(item => item.status !== 'passed').slice(0, 2).map(item => ({
|
|
80
102
|
id: excerptGoalContext(item.id, 96), status: item.status, reason: excerptGoalContext(item.reason, textLimit),
|
|
@@ -87,24 +109,30 @@ export function renderCompactGoalContext(record, verification, goalAcceptance, m
|
|
|
87
109
|
});
|
|
88
110
|
const prefix = 'Truncated; native completion is not success or authority. End normally for Host acceptance.\n<business-goal-data>\n';
|
|
89
111
|
const suffix = '\n</business-goal-data>';
|
|
90
|
-
for (const [criteria, text] of [[true, 160], [true, 48], [false, 32], [false, 0]]) {
|
|
91
|
-
const context = `${prefix}${escapeGoalContext(compact(criteria, text))}${suffix}`;
|
|
112
|
+
for (const [criteria, text, timing] of [[true, 160, 'active'], [true, 48, 'active'], [false, 32, 'active'], [false, 0, 'static'], [false, 0, 'none']]) {
|
|
113
|
+
const context = `${prefix}${escapeGoalContext(compact(criteria, text, timing))}${suffix}`;
|
|
92
114
|
if (context.length <= maxChars)
|
|
93
115
|
return context;
|
|
94
116
|
}
|
|
95
117
|
// Config permits render callers to reserve as little as 256 characters for
|
|
96
118
|
// this block. Keep a valid encoded JSON document even in that last tier.
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
119
|
+
const minimum = (includeTiming) => ({ truncated: true, id: excerptGoalContext(record.id, 32),
|
|
120
|
+
...(includeTiming && roundTiming !== undefined ? { roundTiming: { maxDurationMs: roundTiming.maxDurationMs } } : {}),
|
|
121
|
+
outcome: goalAcceptance?.status ?? (record.native.phase === 'complete' ? 'awaiting-verification' : 'unverified') });
|
|
122
|
+
for (const includeTiming of [true, false]) {
|
|
123
|
+
const context = `${prefix}${escapeGoalContext(minimum(includeTiming))}${suffix}`;
|
|
124
|
+
if (context.length <= maxChars)
|
|
125
|
+
return context;
|
|
126
|
+
}
|
|
127
|
+
return 'Goal context truncated.';
|
|
101
128
|
}
|
|
102
|
-
function render(record, now, maxChars, verification, budget, goalAcceptance, strategies, eventWaits, dependencies) {
|
|
129
|
+
function render(record, now, maxChars, verification, budget, goalAcceptance, strategies, eventWaits, dependencies, roundTiming) {
|
|
103
130
|
const data = {
|
|
104
131
|
id: record.id, version: record.version, originalObjective: record.originalObjective,
|
|
105
132
|
currentObjective: record.native.objective, definition: record.definition,
|
|
106
133
|
native: record.native,
|
|
107
134
|
outcome: goalAcceptance?.status ?? (record.native.phase === 'complete' ? 'awaiting-verification' : 'unverified'),
|
|
135
|
+
...(roundTiming === undefined ? {} : { roundTiming }),
|
|
108
136
|
checkpoint: { ...record.checkpoint, dependencyBindings: undefined, assumptions: record.checkpoint.assumptions.map(item => ({ ...item, stale: item.expiresAt <= now })), ...(dependencies === undefined ? {} : { dependencyStatus: dependencies }) },
|
|
109
137
|
...(verification === undefined ? {} : { stepFeedback: verification }),
|
|
110
138
|
...(budget === undefined ? {} : { executionBudget: budget }),
|
|
@@ -116,11 +144,12 @@ function render(record, now, maxChars, verification, budget, goalAcceptance, str
|
|
|
116
144
|
// Never truncate a JSON/source claim into a misleading partial document.
|
|
117
145
|
const feedbackGuide = verification === undefined ? '' : ' Step feedback binds independent evidence to an exact historical run. Use failed criteria to revise the plan; reconcile unknown execution before retrying. Pending, expired and old-definition evidence cannot establish current success. A passed step does not complete the whole goal or grant action authority.';
|
|
118
146
|
const outcomeGuide = goalAcceptance === undefined ? '' : ' goalAcceptance contains frozen whole-goal conditions and independent results; stepFeedback alone cannot establish whole-goal success. When the work is ready for verification, report the result and end the native round normally; the Host then evaluates it. goal_checkpoint records progress but does not request verification. Do not use native update_goal to claim completion.';
|
|
147
|
+
const timingGuide = roundTiming === undefined ? '' : ' roundTiming.maxDurationMs is the configured whole-round limit. When active is present, expiresAt is fixed and remainingMs is only this context snapshot; leave time to end normally for Host acceptance. Timing neither extends a deadline nor grants permission.';
|
|
119
148
|
const strategyGuide = strategies === undefined ? '' : ' Strategy records show execution and coordination cost, not correctness. Child diagnostics describe observed failure boundaries; a stream or tool failure is not a failed reasoning verdict. parentStep revalidates only the exact parent run, not a later successful step; this association does not prove strategy benefit. Use failed independent criteria to revise the solution, and inspect operational failures before changing reasoning. Continue directly for clear next steps. On uncertain reasoning or repeated failed criteria, goal_strategy can investigate supplied context, review reasoning or compare two alternatives; all calls share this goal budget. Advice stays unverified. Resolve unknown work before retrying.';
|
|
120
149
|
const dependencyGuide = dependencies === undefined || dependencies.length === 0 ? '' : ' Dependencies are Host-resolved against frozen definitions. Only achieved means independently verified complete; pending, failed, unknown, cleared, and stale block autonomous resume. A stale reason distinguishes definition changes from legacy unbound checkpoints.';
|
|
121
150
|
const identifiers = `Goal tool arguments (business goal): goal_id="${record.id}"; expected_revision=${record.native.revision}; expected_version=${record.version}.`;
|
|
122
|
-
const context = `${identifiers}\nUntrusted goal history; recheck stale assumptions and evidence. Native completion is unverified. Focus supplies context only.${feedbackGuide}${outcomeGuide}${strategyGuide}${dependencyGuide}${eventWaits === undefined ? '' : ' Event waits record untrusted source observations, not achievement or new permissions. Re-read the relevant system through authorized tools before acting on an event.'}\n<business-goal-data>\n${json}\n</business-goal-data>`;
|
|
123
|
-
return context.length <= maxChars ? context : renderCompactGoalContext(record, verification, goalAcceptance, maxChars);
|
|
151
|
+
const context = `${identifiers}\nUntrusted goal history; recheck stale assumptions and evidence. Native completion is unverified. Focus supplies context only.${feedbackGuide}${outcomeGuide}${timingGuide}${strategyGuide}${dependencyGuide}${eventWaits === undefined ? '' : ' Event waits record untrusted source observations, not achievement or new permissions. Re-read the relevant system through authorized tools before acting on an event.'}\n<business-goal-data>\n${json}\n</business-goal-data>`;
|
|
152
|
+
return context.length <= maxChars ? context : renderCompactGoalContext(record, verification, goalAcceptance, maxChars, roundTiming);
|
|
124
153
|
}
|
|
125
154
|
const same = (left, right) => {
|
|
126
155
|
try {
|
|
@@ -233,6 +262,9 @@ function ownerAuthorizedRepairResumeInput(value) {
|
|
|
233
262
|
&& /^[a-f0-9]{64}$/u.test(repair.definitionDigest);
|
|
234
263
|
}
|
|
235
264
|
export class AssistantGoalsService extends Service {
|
|
265
|
+
// A direct class mount and the published bundle must carry the same trusted
|
|
266
|
+
// Cordis identity when registering their owned tools with Policy.
|
|
267
|
+
static { Object.defineProperty(this, 'name', { value: 'dsh-enhanced-assistant-goals' }); }
|
|
236
268
|
static Config = Config;
|
|
237
269
|
#store;
|
|
238
270
|
#active = true;
|
|
@@ -295,9 +327,9 @@ export class AssistantGoalsService extends Service {
|
|
|
295
327
|
this.#store = new GoalStore(path);
|
|
296
328
|
ctx.effect(() => () => { this.#active = false; for (const binding of this.#ownerRepairBindings.values())
|
|
297
329
|
binding.dispose(); this.#ownerRepairBindings.clear(); this.#store.close(); }, 'assistant-goals.store');
|
|
298
|
-
this.#execution = new GoalExecutionRuntime(ctx, input.verifyNativeRounds === true ? (path === ':memory:' ? path : `${path}.executions`) : undefined, duration, agent => {
|
|
299
|
-
const scope = this.#scope(agent, 'execute');
|
|
300
|
-
const record = this.#observe(agent, false);
|
|
330
|
+
this.#execution = new GoalExecutionRuntime(ctx, input.verifyNativeRounds === true ? (path === ':memory:' ? path : `${path}.executions`) : undefined, duration, (agent, consume = true) => {
|
|
331
|
+
const scope = this.#scope(agent, 'execute', consume);
|
|
332
|
+
const record = this.#observe(agent, false, consume);
|
|
301
333
|
if (record === undefined)
|
|
302
334
|
throw new Error('assistant-goals: current bound goal required');
|
|
303
335
|
return { scope, record };
|
|
@@ -481,8 +513,8 @@ export class AssistantGoalsService extends Service {
|
|
|
481
513
|
objective: goal.objective, phase: goal.phase, roundsStarted: goal.roundsStarted,
|
|
482
514
|
maxGoalRounds: goal.maxGoalRounds, updatedAt: goal.updatedAt };
|
|
483
515
|
}
|
|
484
|
-
#observe(agent, create) {
|
|
485
|
-
const scope = this.#scope(agent, 'observe');
|
|
516
|
+
#observe(agent, create, consume = true) {
|
|
517
|
+
const scope = this.#scope(agent, 'observe', consume);
|
|
486
518
|
const current = this.ctx.get('goals')?.get(agent);
|
|
487
519
|
if (current === undefined)
|
|
488
520
|
return undefined;
|
|
@@ -524,6 +556,65 @@ export class AssistantGoalsService extends Service {
|
|
|
524
556
|
return undefined;
|
|
525
557
|
}
|
|
526
558
|
};
|
|
559
|
+
/** Inspect or focus only existing owner-scoped context; never grants native goal control. */
|
|
560
|
+
preauthorizeContext = (execution) => {
|
|
561
|
+
try {
|
|
562
|
+
if (execution.signal.aborted || !execution.arguments || typeof execution.arguments !== 'object'
|
|
563
|
+
|| Array.isArray(execution.arguments) || Object.getPrototypeOf(execution.arguments) !== Object.prototype
|
|
564
|
+
|| Object.getOwnPropertySymbols(execution.arguments).length !== 0)
|
|
565
|
+
return false;
|
|
566
|
+
const args = execution.arguments;
|
|
567
|
+
if (Object.getOwnPropertyNames(args).some(key => !['goal_id', 'focus'].includes(key))
|
|
568
|
+
|| Object.values(Object.getOwnPropertyDescriptors(args)).some(value => !value.enumerable || !('value' in value))
|
|
569
|
+
|| args.goal_id !== undefined && (typeof args.goal_id !== 'string' || args.goal_id.length === 0 || args.goal_id.length > 512)
|
|
570
|
+
|| args.focus !== undefined && typeof args.focus !== 'boolean'
|
|
571
|
+
|| args.focus === true && args.goal_id === undefined)
|
|
572
|
+
return false;
|
|
573
|
+
const scope = this.#scope(execution.agent, 'inspect', false);
|
|
574
|
+
this.#scope(execution.agent, 'observe', false);
|
|
575
|
+
if (args.focus === true)
|
|
576
|
+
this.#scope(execution.agent, 'focus', false);
|
|
577
|
+
return args.goal_id === undefined || this.#store.get(scope, args.goal_id) !== undefined;
|
|
578
|
+
}
|
|
579
|
+
catch {
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
/** Read-only admission for one exact current-owner checkpoint CAS. */
|
|
584
|
+
preauthorizeCheckpoint = (execution) => {
|
|
585
|
+
try {
|
|
586
|
+
if (!this.#active || execution.signal.aborted || !execution.agent || !execution.arguments || typeof execution.arguments !== 'object'
|
|
587
|
+
|| Array.isArray(execution.arguments) || Object.getPrototypeOf(execution.arguments) !== Object.prototype || Object.getOwnPropertySymbols(execution.arguments).length !== 0)
|
|
588
|
+
return false;
|
|
589
|
+
const args = execution.arguments;
|
|
590
|
+
const names = Object.getOwnPropertyNames(args);
|
|
591
|
+
if (names.length !== 7 || !['goal_id', 'expected_version', 'next_step', 'blockers', 'assumptions', 'evidence_refs', 'dependencies'].every(key => names.includes(key))
|
|
592
|
+
|| !plainJsonData(args))
|
|
593
|
+
return false;
|
|
594
|
+
if (!Array.isArray(args.assumptions) || args.assumptions.some(item => !item || typeof item !== 'object' || Array.isArray(item)
|
|
595
|
+
|| Object.getPrototypeOf(item) !== Object.prototype || Object.getOwnPropertyNames(item).length !== 2
|
|
596
|
+
|| !['statement', 'expires_at'].every(key => Object.hasOwn(item, key))))
|
|
597
|
+
return false;
|
|
598
|
+
const delivery = this.ctx.get('assistantDelivery');
|
|
599
|
+
if (delivery?.preferencePrincipalForAgent(execution.agent) === undefined)
|
|
600
|
+
return false;
|
|
601
|
+
const scope = this.#scope(execution.agent, 'checkpoint', false);
|
|
602
|
+
this.#scope(execution.agent, 'observe', false);
|
|
603
|
+
const checkpoint = {
|
|
604
|
+
nextStep: args.next_step, blockers: args.blockers,
|
|
605
|
+
assumptions: args.assumptions.map(item => ({ statement: item.statement, expiresAt: item.expires_at })),
|
|
606
|
+
evidenceRefs: args.evidence_refs, dependencies: args.dependencies,
|
|
607
|
+
};
|
|
608
|
+
const record = this.#store.preflightCheckpoint(scope, args.goal_id, args.expected_version, checkpoint);
|
|
609
|
+
const native = this.ctx.get('goals')?.get(execution.agent);
|
|
610
|
+
return native !== undefined && record.native.sessionId === String(execution.agent.session.id) && record.native.goalId === String(native.id)
|
|
611
|
+
&& record.native.revision === native.revision && record.native.phase === native.phase && record.native.roundsStarted === native.roundsStarted
|
|
612
|
+
&& record.native.maxGoalRounds === native.maxGoalRounds && record.native.objective === native.objective;
|
|
613
|
+
}
|
|
614
|
+
catch {
|
|
615
|
+
return false;
|
|
616
|
+
}
|
|
617
|
+
};
|
|
527
618
|
preauthorizeSchedule = (execution) => {
|
|
528
619
|
try {
|
|
529
620
|
if (!this.#active || !this.#preauthorizedSchedule || execution.signal.aborted || !execution.agent || !execution.arguments || typeof execution.arguments !== 'object' || Array.isArray(execution.arguments) || Object.getPrototypeOf(execution.arguments) !== Object.prototype || Object.getOwnPropertySymbols(execution.arguments).length !== 0)
|
|
@@ -879,11 +970,21 @@ export class AssistantGoalsService extends Service {
|
|
|
879
970
|
concludeNativeEventWait = (agent) => this.#execution.hasAcceptedPausedEventWait(agent);
|
|
880
971
|
preauthorizeEventWait = (execution) => {
|
|
881
972
|
try {
|
|
882
|
-
if (execution.signal.aborted || this.#eventWait === undefined || !execution.arguments || typeof execution.arguments !== 'object'
|
|
973
|
+
if (execution.signal.aborted || this.#eventWait === undefined || !execution.arguments || typeof execution.arguments !== 'object'
|
|
974
|
+
|| Array.isArray(execution.arguments) || Object.getPrototypeOf(execution.arguments) !== Object.prototype)
|
|
883
975
|
return false;
|
|
884
976
|
const args = execution.arguments;
|
|
885
|
-
if (
|
|
886
|
-
||
|
|
977
|
+
if (Object.getOwnPropertySymbols(args).length !== 0 || Object.values(Object.getOwnPropertyDescriptors(args)).some(value => !value.enumerable || !('value' in value))
|
|
978
|
+
|| typeof args.goal_id !== 'string' || args.goal_id.length === 0 || args.goal_id.length > 512)
|
|
979
|
+
return false;
|
|
980
|
+
if (Object.keys(args).length === 1) {
|
|
981
|
+
const scope = this.#scope(execution.agent, 'inspect', false);
|
|
982
|
+
this.#scope(execution.agent, 'observe', false);
|
|
983
|
+
return this.#store.get(scope, args.goal_id) !== undefined;
|
|
984
|
+
}
|
|
985
|
+
const names = ['goal_id', 'expected_revision', 'trigger_id', 'expires_at', ...(Object.hasOwn(args, 'opportunity_profile') ? ['opportunity_profile'] : [])];
|
|
986
|
+
if (Object.keys(args).length !== names.length || !names.every(key => Object.hasOwn(args, key))
|
|
987
|
+
|| !Number.isSafeInteger(args.expected_revision) || args.expected_revision < 1
|
|
887
988
|
|| typeof args['trigger_id'] !== 'string' || !Number.isSafeInteger(args['expires_at']) || (args['opportunity_profile'] !== undefined && typeof args['opportunity_profile'] !== 'string'))
|
|
888
989
|
return false;
|
|
889
990
|
const scope = this.#scope(execution.agent, 'wait', false);
|
|
@@ -974,6 +1075,22 @@ export class AssistantGoalsService extends Service {
|
|
|
974
1075
|
throw new Error('assistant-goals: goal not found');
|
|
975
1076
|
return record;
|
|
976
1077
|
};
|
|
1078
|
+
/**
|
|
1079
|
+
* Host-only read-only enumeration of recent goal records for an exact, already
|
|
1080
|
+
* validated owner scope. Like inspectGoalLifecycle() it deliberately has no
|
|
1081
|
+
* Agent argument: it never reactivates an ended owner Session and never proves
|
|
1082
|
+
* an outcome by itself. Callers must first anchor the scope through an
|
|
1083
|
+
* authenticated owner route (delivery.validateOwnerRoute); the durable store
|
|
1084
|
+
* re-validates every scope field. Enumeration is discovery only — a surfaced
|
|
1085
|
+
* id still has to pass inspectOwnerVerifiedWorkflowSource() before any success
|
|
1086
|
+
* is trusted.
|
|
1087
|
+
*/
|
|
1088
|
+
inspectOwnerGoals = (scope, limit = 50) => {
|
|
1089
|
+
if (!this.#active)
|
|
1090
|
+
throw new Error('assistant-goals: service is inactive');
|
|
1091
|
+
const bounded = Number.isSafeInteger(limit) && limit > 0 ? Math.min(limit, 50) : 50;
|
|
1092
|
+
return this.#store.list(scope, bounded);
|
|
1093
|
+
};
|
|
977
1094
|
/** Minimal read-only lifecycle projection for exact host-owned source bindings. */
|
|
978
1095
|
inspectGoalLifecycle = (input) => {
|
|
979
1096
|
const record = this.#store.get(input.scope, input.goalId);
|
|
@@ -1010,9 +1127,20 @@ export class AssistantGoalsService extends Service {
|
|
|
1010
1127
|
return '';
|
|
1011
1128
|
const now = Date.now(), budget = record === undefined ? undefined : this.#budget?.preview(record);
|
|
1012
1129
|
const outcomeExpiry = record === undefined ? undefined : this.#outcome?.view(record).conditions?.expiresAt;
|
|
1130
|
+
let verificationReady = true;
|
|
1131
|
+
if (record !== undefined && this.#outcome !== undefined) {
|
|
1132
|
+
try {
|
|
1133
|
+
this.#outcome.preflight(scope, record.definition.objective, record);
|
|
1134
|
+
}
|
|
1135
|
+
catch {
|
|
1136
|
+
verificationReady = false;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1013
1139
|
const sources = source.inspectOwnerSources(scope).filter(item => this.ctx.get('assistantPolicy')?.evaluateAgent(agent, 'wait-for-event', { kind: 'automation', id: item.automationId }).effect === 'allow').slice(0, 16).map(item => {
|
|
1014
1140
|
if (record === undefined || budget === undefined || outcomeExpiry === undefined || this.#wake === undefined)
|
|
1015
1141
|
return item;
|
|
1142
|
+
if (!verificationReady)
|
|
1143
|
+
return { ...item, waitUnavailable: 'verification-unavailable' };
|
|
1016
1144
|
const waitExpiresAt = Math.min(item.expiresAt, budget.limits.expiresAt, outcomeExpiry - 1, now + this.#wake.config.maxDelayMs);
|
|
1017
1145
|
return waitExpiresAt - now >= 1_000 ? { ...item, waitExpiresAt } : { ...item, waitUnavailable: 'deadline-under-1s' };
|
|
1018
1146
|
});
|
|
@@ -1053,7 +1181,8 @@ export class AssistantGoalsService extends Service {
|
|
|
1053
1181
|
// budget. If source prose would leave no valid compact goal document,
|
|
1054
1182
|
// omit it rather than truncating either authority-bearing JSON claim.
|
|
1055
1183
|
const sourcePrefix = this.#maxChars - sources.length >= 256 ? sources : '';
|
|
1056
|
-
|
|
1184
|
+
const now = Date.now();
|
|
1185
|
+
return sourcePrefix + render(record, now, this.#maxChars - sourcePrefix.length, this.#feedback(record), this.#budget?.inspect(record), this.#outcome?.view(record), this.#strategyHistory(record), this.#eventWaitContext(record), this.#dependencies(record), this.#execution.roundTiming(agent, record));
|
|
1057
1186
|
}
|
|
1058
1187
|
catch {
|
|
1059
1188
|
return '';
|
|
@@ -1076,10 +1205,14 @@ export class AssistantGoalsService extends Service {
|
|
|
1076
1205
|
}
|
|
1077
1206
|
return format(goals.length < records.length || records.length === 50);
|
|
1078
1207
|
};
|
|
1079
|
-
describe = (record) => {
|
|
1208
|
+
describe = (record) => {
|
|
1209
|
+
const now = Date.now();
|
|
1210
|
+
return render(record, now, 131072, this.#feedback(record), this.#budget?.inspect(record), this.#outcome?.view(record), this.#strategyHistory(record), this.#eventWaitContext(record), this.#dependencies(record), this.#execution.roundTiming(undefined, undefined));
|
|
1211
|
+
};
|
|
1080
1212
|
describeForAgent = (agent, goalId) => {
|
|
1081
1213
|
const record = this.inspect(agent, goalId);
|
|
1082
|
-
|
|
1214
|
+
const now = Date.now();
|
|
1215
|
+
return render(record, now, 131072, this.#feedback(record), this.#budget?.inspect(record), this.#outcome?.view(record), this.#strategyHistory(record), this.#eventWaitContext(record), this.#dependencies(record), this.#execution.roundTiming(agent, record));
|
|
1083
1216
|
};
|
|
1084
1217
|
#eventWaitContext(record) {
|
|
1085
1218
|
if (this.#eventWait === undefined)
|
|
@@ -1119,6 +1252,15 @@ export class AssistantGoalsService extends Service {
|
|
|
1119
1252
|
return this.#strategy?.list(record.scope, goalId) ?? [];
|
|
1120
1253
|
};
|
|
1121
1254
|
inspectStrategyAssessments = (agent, goalId) => this.#strategyHistory(this.inspect(agent, goalId));
|
|
1255
|
+
/**
|
|
1256
|
+
* Host-only read-only advice-repetition view for the supervised learning
|
|
1257
|
+
* runbook. The strategy ledger exists only when durable strategy execution is
|
|
1258
|
+
* configured; when it is absent there are no advice rows that could repeat,
|
|
1259
|
+
* so an empty summary is the truthful answer rather than an error.
|
|
1260
|
+
*/
|
|
1261
|
+
hostSummarizeAdviceByDefinition = (scope) => {
|
|
1262
|
+
return this.#strategy?.summarizeAdviceByDefinition(scope) ?? [];
|
|
1263
|
+
};
|
|
1122
1264
|
#strategyHistory(record) {
|
|
1123
1265
|
if (!this.#strategy)
|
|
1124
1266
|
return undefined;
|